Compare commits

...

59 Commits

Author SHA1 Message Date
greg7mdp 19290db10d Merge branch 'main' of github.com:AntelopeIO/leap into gh-822 2023-03-24 13:25:18 -04:00
greg7mdp 657b3df4bf simplify cond wait - greatly inspired from Kevin's branch 2023-03-24 13:24:27 -04:00
greg7mdp a35a0bef2d Fix test issue (uninitialized variables) 2023-03-24 09:22:53 -04:00
Kevin Heifner 291cd11cd4 Merge pull request #888 from AntelopeIO/fix-clang-warn
Fix clang warning
2023-03-23 18:42:06 -05:00
Kevin Heifner 15b271a98a Fix clang warning 2023-03-23 17:58:45 -05:00
greg7mdp 4ec1281918 Merge branch 'main' of github.com:AntelopeIO/leap into gh-822 2023-03-23 16:26:08 -04:00
Lin Huang 318e1e4533 Merge pull request #884 from AntelopeIO/merge_4_0_0_rc_2_bump
[4.0 -> main] Merge 4.0.0-rc2 bump changes to main
2023-03-23 14:33:45 -04:00
Lin Huang ccdaa64392 correct version after merging from 4.0.0-rc2 2023-03-23 13:28:43 -04:00
Kevin Heifner 150fe5de8f Merge pull request #882 from AntelopeIO/GH-871-test-fix-main
[4.0 -> main] Test fix: Add max-transaction-time -1
2023-03-23 12:10:00 -05:00
Lin Huang 59cf021b08 Merge pull request #881 from AntelopeIO/bump_to_4_0_0_rc2
Bump release/4.0.0 to rc2
2023-03-23 12:40:56 -04:00
Kevin Heifner 8b52aac579 Merge remote-tracking branch 'origin/release/4.0' into GH-871-test-fix-main 2023-03-23 11:39:53 -05:00
ClaytonCalabrese 1dd3f89555 Merge pull request #880 from AntelopeIO/restore_lost_node_py_changes_main
[4.0 -> main] Restore Node.py Changes that were lost
2023-03-23 11:38:09 -05:00
Lin Huang 5969e8b6fe Bump release/4.0.0 to rc2 2023-03-23 12:11:40 -04:00
Kevin Heifner 8cbd7decca Merge pull request #872 from AntelopeIO/GH-871-test-fix-4.0
[4.0] Test fix: Add max-transaction-time -1
2023-03-23 11:07:33 -05:00
Clayton Calabrese 25915c3510 merge release/4.0 into main to get missing Node.py changes 2023-03-23 11:04:19 -05:00
Kevin Heifner 2299d0b626 Merge pull request #878 from AntelopeIO/GH-854-fix-test-main
[4.0 -> main] Test Fix: Use max-transaction-time -1
2023-03-23 10:38:40 -05:00
ClaytonCalabrese c9fcb2ac2c Merge pull request #875 from AntelopeIO/restore_lost_node_py_changes
[4.0] Return Lost Changes to Node.py Functions
2023-03-23 10:10:32 -05:00
Kevin Heifner 40576f5416 Merge remote-tracking branch 'origin/release/4.0' into GH-854-fix-test-main 2023-03-23 10:06:16 -05:00
Kevin Heifner b5232f0eaf Merge pull request #864 from AntelopeIO/GH-854-fix-test-4.0
[4.0] Test Fix: Use max-transaction-time -1
2023-03-23 10:05:43 -05:00
Huang-Ming Huang 8134e5394a Merge pull request #877 from AntelopeIO/huangminghuang/unshare-import-fix
[4.0->main] unshare import fix & SHiP: Send until queue is empty
2023-03-23 10:05:23 -05:00
Huang-Ming Huang 6176fa323c Merge remote-tracking branch 'origin/release/4.0' into huangminghuang/unshare-import-fix 2023-03-23 09:43:27 -05:00
Vlad 5d1ab0c0bb Merge pull request #873 from AntelopeIO/increase-snapshot-test-robustness-main
[4.0 -> main] Increase robustness of snapshot diff python test
2023-03-23 10:37:35 -04:00
Huang-Ming Huang ac1a035b5e Merge pull request #869 from AntelopeIO/huangminghuang/unshare-import-fix-4.0
[4.0] unshare import fix
2023-03-23 09:36:49 -05:00
Kevin Heifner 191aafc8f6 Merge pull request #876 from AntelopeIO/GH-861-ship-fix-4.0
[4.0] SHiP: Send until queue is empty
2023-03-22 22:22:24 -05:00
Kevin Heifner 405ac4178d GH-861 Make sure to keep sending as long as there are items queued up to send. 2023-03-22 21:01:17 -05:00
Clayton Calabrese 41bb796d77 add forgotten piece of changing default time limit for cleosLimit 2023-03-22 19:52:15 -05:00
Clayton Calabrese 1e80205270 remove hardcoded 999 time limit for getTable and depend on version. Change from 99999 to 999 for non v2 nodeos 2023-03-22 18:29:22 -05:00
Clayton Calabrese 483b462717 restore lost changes due to splitting of Node.py and moving of functions 2023-03-22 18:23:57 -05:00
766C6164 1b04bdf71c Rolled back queries.py changes in this pr 2023-03-22 18:38:06 -04:00
766C6164 9e2593cc16 Merge branch 'release/4.0' into increase-snapshot-test-robustness-main 2023-03-22 17:45:31 -04:00
Kevin Heifner ec471ad8e5 GH-871 Use max-transaction-time=-1 for consistency 2023-03-22 15:36:17 -05:00
Kevin Heifner 3dbc0baeeb GH-871 Add max-transaction-time -1 for loading of contract 2023-03-22 15:03:57 -05:00
greg7mdp ff4b20388b Merge branch 'main' of github.com:AntelopeIO/leap into gh-822 2023-03-22 15:41:11 -04:00
Huang-Ming Huang f3c424ef90 huangminghuang/unshare-import-fix 2023-03-22 13:39:57 -05:00
Vlad 2829420ecb Merge pull request #856 from AntelopeIO/increase-snapshot-test-robustness
[4.0] Increase robustness of snapshot diff python test
2023-03-22 11:51:46 -04:00
greg7mdp 43d462a8e0 Replace option to turn off checking with a static variable. 2023-03-22 10:35:30 -04:00
Kevin Heifner 87c7480656 Merge pull request #852 from AntelopeIO/GH-850-test-fix
[4.0] Test Fix: Pass a large time limit to get table call
2023-03-22 09:25:02 -05:00
Kevin Heifner 971102e243 GH-854 Use max-transaction-time -1 like other integration tests 2023-03-22 09:20:34 -05:00
greg7mdp e79f6781c0 Address PR comments 2023-03-22 10:19:19 -04:00
greg7mdp afeecdb533 Add extra test with 1 readonly thread 2023-03-22 08:44:11 -04:00
greg7mdp 847d82f5ba Implement code review comments. 2023-03-22 08:43:44 -04:00
greg7mdp d3b227a982 Merge branch 'main' of github.com:AntelopeIO/leap into gh-822 2023-03-21 18:12:24 -04:00
greg7mdp a4582b5ba7 Notify condition_variable under the lock.
(see https://github.com/isocpp/CppCoreGuidelines/issues/925#issuecomment-302269850)
2023-03-21 17:22:36 -04:00
greg7mdp 517f1cb987 Deal with possible spurious wakeups from wait(). 2023-03-21 17:00:58 -04:00
766C6164 cb64c3fb38 schedule snapshot at exact block num of another one 2023-03-21 15:43:31 -04:00
Kevin Heifner 446a04a607 GH-850 Pass a large time limit so python does not have to handle more=true case. 2023-03-21 13:09:26 -05:00
greg7mdp ffefb30a36 No need to check for option's presence since it has a default value 2023-03-21 13:54:38 -04:00
greg7mdp e482676d42 Merge branch 'main' of github.com:AntelopeIO/leap into gh-822 2023-03-21 13:45:19 -04:00
greg7mdp cce1b8d29a simplify capture list 2023-03-21 13:10:24 -04:00
greg7mdp def0d0df6d Add C++ test exercizing readonly transactions in read window. 2023-03-21 13:05:55 -04:00
greg7mdp 98464fef96 Fix a couple issues - now tests pass! 2023-03-21 11:11:45 -04:00
greg7mdp da9addcaba Add two assert() checks. 2023-03-20 13:39:16 -04:00
greg7mdp 87c34e86f4 Small cleanups and comments. 2023-03-20 13:33:00 -04:00
greg7mdp bb0490ceb9 Small cleanups. 2023-03-20 11:40:24 -04:00
greg7mdp a47032b189 Merge branch 'main' of github.com:AntelopeIO/leap into gh-822 2023-03-20 10:46:39 -04:00
greg7mdp 6761f93385 Consistent exit when read_window_deadline is reached, and encapsulate exit criteria in ro_trx_queue_t 2023-03-20 10:43:53 -04:00
greg7mdp 8a0ded9374 Update comment 2023-03-17 15:11:23 -04:00
greg7mdp 10df2bbf55 Forgot one notify_one call. 2023-03-17 14:58:37 -04:00
greg7mdp 2a4c37c13f Cleanup and prevent thread starvation while in the read window. 2023-03-17 14:51:21 -04:00
13 changed files with 196 additions and 80 deletions
+13 -13
View File
@@ -679,16 +679,16 @@ namespace IR
}
//paranoia for future platforms
static_assert(sizeof(IR::OpcodeAndImm<IR::NoImm>) == 2);
static_assert(sizeof(IR::OpcodeAndImm<IR::MemoryImm>) == 2);
static_assert(sizeof(IR::OpcodeAndImm<IR::ControlStructureImm>) == 3);
static_assert(sizeof(IR::OpcodeAndImm<IR::BranchImm>) == 6);
static_assert(sizeof(IR::OpcodeAndImm<IR::BranchTableImm>) == 18);
static_assert(sizeof(IR::OpcodeAndImm<IR::LiteralImm<I32>>) == 6);
static_assert(sizeof(IR::OpcodeAndImm<IR::LiteralImm<I64>>) == 10);
static_assert(sizeof(IR::OpcodeAndImm<IR::LiteralImm<F32>>) == 6);
static_assert(sizeof(IR::OpcodeAndImm<IR::LiteralImm<F64>>) == 10);
static_assert(sizeof(IR::OpcodeAndImm<IR::GetOrSetVariableImm<false>>) == 6);
static_assert(sizeof(IR::OpcodeAndImm<IR::CallImm>) == 6);
static_assert(sizeof(IR::OpcodeAndImm<IR::CallIndirectImm>) == 6);
static_assert(sizeof(IR::OpcodeAndImm<IR::LoadOrStoreImm<0>>) == 10);
static_assert(sizeof(IR::OpcodeAndImm<IR::NoImm>) == 2, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::MemoryImm>) == 2, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::ControlStructureImm>) == 3, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::BranchImm>) == 6, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::BranchTableImm>) == 18, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::LiteralImm<I32>>) == 6, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::LiteralImm<I64>>) == 10, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::LiteralImm<F32>>) == 6, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::LiteralImm<F64>>) == 10, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::GetOrSetVariableImm<false>>) == 6, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::CallImm>) == 6, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::CallIndirectImm>) == 6, "unexpected size");
static_assert(sizeof(IR::OpcodeAndImm<IR::LoadOrStoreImm<0>>) == 10, "unexpected size");
@@ -204,9 +204,12 @@ public:
// thread-safe, called when a new block is received
void received_block();
const std::set<account_name>& producer_accounts() const;
const std::set<account_name>& producer_accounts() const;
static void set_test_mode(bool m) { test_mode_ = m; }
private:
inline static bool test_mode_{false}; // to be moved into appbase (application_base)
std::shared_ptr<class producer_plugin_impl> my;
};
+96 -26
View File
@@ -417,11 +417,85 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
packed_transaction_ptr trx;
next_func_t next;
};
// The queue storing read-only transactions to be executed by read-only threads
struct ro_trx_queue_t {
std::mutex mtx;
std::deque<ro_trx_t> queue;
class ro_trx_queue_t {
public:
void push_back(ro_trx_t&& trx) {
std::unique_lock<std::mutex> g( mtx );
queue.push_back(std::move(trx));
if (num_waiting)
cond.notify_one();
}
void push_front(ro_trx_t&& trx) {
std::unique_lock<std::mutex> g( mtx );
queue.push_front(std::move(trx));
if (num_waiting)
cond.notify_one();
}
bool empty() const {
std::lock_guard<std::mutex> g( mtx );
return queue.empty();
}
// may wait if the queue is empty, and not all other threads are already waiting.
// returns true if a transaction was dequeued and should be executed, or false
// if conditions are met to stop processing transactions.
bool pop_front(ro_trx_t& trx) {
std::unique_lock<std::mutex> g( mtx );
++num_waiting;
cond.wait(g, [this]() {
if (queue.empty()) {
if (num_waiting == max_waiting && !exiting_read_window) {
cond.notify_all();
exiting_read_window = true;
}
return should_exit();
}
return true;
});
--num_waiting;
if (should_exit())
return false;
trx = std::move(queue.front());
queue.pop_front();
return true;
}
// We exit the read window when either:
// - all threads would be idle
// - or the net_plugin received a block.
// - or we have reached the read_window_deadline
void set_exit_criteria(uint32_t num_tasks, std::atomic<bool>* received_block, fc::time_point deadline) {
std::lock_guard<std::mutex> g( mtx ); // not strictly necessary with current usage from single thread
assert(num_tasks > 0 && num_waiting == 0 && received_block != nullptr);
assert(received_block && *received_block == false);
max_waiting = num_tasks;
num_waiting = 0;
received_block_ptr = received_block;
read_window_deadline = deadline;
exiting_read_window = false;
}
private:
bool should_exit() {
return exiting_read_window || fc::time_point::now() >= read_window_deadline || *received_block_ptr;
}
mutable std::mutex mtx;
std::condition_variable cond;
deque<ro_trx_t> queue;
uint32_t num_waiting{0};
uint32_t max_waiting{0};
bool exiting_read_window{false};
std::atomic<bool>* received_block_ptr{nullptr};
fc::time_point read_window_deadline;
};
uint16_t _ro_thread_pool_size{ 0 };
static constexpr uint16_t _ro_max_eos_vm_oc_threads_allowed{ 8 }; // Due to uncertainty to get total virtual memory size on a 5-level paging system, set a hard limit
named_thread_pool<struct read> _ro_thread_pool;
@@ -433,13 +507,13 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
boost::asio::deadline_timer _ro_read_window_timer;
fc::microseconds _ro_max_trx_time_us{ 0 }; // calculated during option initialization
ro_trx_queue_t _ro_trx_queue;
std::atomic<uint32_t> _ro_num_active_trx_exec_tasks{ 0 };
std::atomic<uint32_t> _ro_num_active_trx_exec_tasks{ 0 };
std::vector<std::future<bool>> _ro_trx_exec_tasks_fut;
void start_write_window();
void switch_to_write_window();
void switch_to_read_window();
bool read_only_trx_execution_task();
bool read_only_trx_execution_task(fc::time_point start);
bool process_read_only_transaction(const packed_transaction_ptr& trx,
const next_function<transaction_trace_ptr>& next,
const fc::time_point& read_window_start_time);
@@ -643,8 +717,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
// Parallel read-only trx execution enabled.
// Store the transaction in read-only-trx queue so that it is
// executed in read window
std::lock_guard<std::mutex> g( _ro_trx_queue.mtx );
_ro_trx_queue.queue.push_back({trx, std::move(next)});
_ro_trx_queue.push_back({trx, std::move(next)});
return;
}
@@ -1076,8 +1149,9 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_
my->_ro_thread_pool_size = options.at( "read-only-threads" ).as<uint16_t>();
// only initialize other read-only options when read-only thread pool is enabled
if ( my->_ro_thread_pool_size > 0 ) {
EOS_ASSERT( my->_producers.empty(), plugin_config_exception, "--read-only-threads not allowed on producer node" );
if (!test_mode_)
EOS_ASSERT( my->_producers.empty(), plugin_config_exception, "--read-only-threads not allowed on producer node" );
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
if (chain.is_eos_vm_oc_enabled()) {
// EOS VM OC requires 4.2TB Virtual for each executing thread. Make sure the memory
@@ -2811,7 +2885,7 @@ void producer_plugin_impl::switch_to_read_window() {
// we are in write window, so no read-only trx threads are processing transactions.
// _ro_trx_queue is not being accessed. No need to lock.
if ( _ro_trx_queue.queue.empty() ) { // no read-only trxs to process. stay in write window
if ( _ro_trx_queue.empty() ) { // no read-only trxs to process. stay in write window
start_write_window(); // restart write window timer for next round
return;
}
@@ -2822,9 +2896,11 @@ void producer_plugin_impl::switch_to_read_window() {
// start a read-only transaction execution task in each thread in the thread pool
_ro_num_active_trx_exec_tasks = _ro_thread_pool_size;
auto start_time = fc::time_point::now();
_ro_trx_queue.set_exit_criteria(_ro_thread_pool_size, &_received_block, start_time + _ro_read_window_effective_time_us);
for (auto i = 0; i < _ro_thread_pool_size; ++i ) {
_ro_trx_exec_tasks_fut.emplace_back( post_async_task( _ro_thread_pool.get_executor(), [self = this] () {
return self->read_only_trx_execution_task();
_ro_trx_exec_tasks_fut.emplace_back( post_async_task( _ro_thread_pool.get_executor(), [this, start_time] () {
return read_only_trx_execution_task(start_time);
}) );
}
@@ -2849,27 +2925,21 @@ void producer_plugin_impl::switch_to_read_window() {
}
// Called from a read only trx thread. Run in parallel with app and other read only trx threads
bool producer_plugin_impl::read_only_trx_execution_task() {
auto start = fc::time_point::now();
auto read_window_deadline = start + _ro_read_window_effective_time_us;
bool producer_plugin_impl::read_only_trx_execution_task(fc::time_point start) {
// We have 4 ways to break out the while loop:
// 1. pass read window deadline
// 2. Net_plugin receives a block
// 3. No more transactions in the read-only trx queue
// 4. A transaction execution is exhaused
while ( fc::time_point::now() < read_window_deadline && !_received_block ) {
std::unique_lock<std::mutex> lck( _ro_trx_queue.mtx );
if ( _ro_trx_queue.queue.empty() ) {
break;
}
auto trx = _ro_trx_queue.queue.front();
_ro_trx_queue.queue.pop_front();
lck.unlock();
ro_trx_t trx;
while ( _ro_trx_queue.pop_front(trx) ) {
// If the queue is empty, pop_front() waits on condition variable, and returns false
// when and only when all tasks must exit (i.e queue is empty and all tasks are idle, or
// we have reached the end of the read window, or net plugin received a block)
auto retry = process_read_only_transaction( trx.trx, trx.next, start );
if ( retry ) {
lck.lock();
_ro_trx_queue.queue.push_front(trx);
_ro_trx_queue.push_front(std::move(trx));
// Do not schedule new execution
break;
}
@@ -94,6 +94,7 @@ void test_trxs_common(std::vector<const char*>& specific_args) {
auto[prod_plug, chain_plug] = plugin_fut.get();
auto chain_id = chain_plug->get_chain_id();
prod_plug->set_test_mode(true);
std::atomic<size_t> next_calls = 0;
std::atomic<size_t> num_posts = 0;
@@ -150,4 +151,27 @@ BOOST_AUTO_TEST_CASE(no_read_only_threads) {
test_trxs_common(specific_args);
}
// test read-only trxs on 1 threads (with --read-only-threads)
BOOST_AUTO_TEST_CASE(with_1_read_only_threads) {
std::vector<const char*> specific_args = { "-p", "eosio", "-e",
"--read-only-threads=1",
"--max-transaction-time=10",
"--read-only-write-window-time-us=100000",
"--read-only-read-window-time-us=40000",
"--disable-subjective-billing=true" };
test_trxs_common(specific_args);
}
// test read-only trxs on 16 separate threads (with --read-only-threads)
BOOST_AUTO_TEST_CASE(with_16_read_only_threads) {
std::vector<const char*> specific_args = { "-p", "eosio", "-e",
"--read-only-threads=16",
"--max-transaction-time=10",
"--read-only-write-window-time-us=100000",
"--read-only-read-window-time-us=40000",
"--disable-subjective-billing=true" };
test_trxs_common(specific_args);
}
BOOST_AUTO_TEST_SUITE_END()
@@ -103,7 +103,7 @@ public:
void pop_entry(bool call_send = true) {
send_queue.erase(send_queue.begin());
sending = false;
if (call_send)
if (call_send || !send_queue.empty())
send();
}
+9 -3
View File
@@ -22,8 +22,11 @@ from .Node import BlockType
from .Node import Node
from .WalletMgr import WalletMgr
from .launch_transaction_generators import TransactionGeneratorsLauncher, TpsTrxGensConfig
from .libc import unshare, CLONE_NEWNET
from .interfaces import getInterfaceFlags, setInterfaceUp, IFF_LOOPBACK
try:
from .libc import unshare, CLONE_NEWNET
from .interfaces import getInterfaceFlags, setInterfaceUp, IFF_LOOPBACK
except:
pass
# Protocol Feature Setup Policy
class PFSetupPolicy:
@@ -1727,4 +1730,7 @@ class Cluster(object):
for line in f:
firstTrxs.append(line.rstrip('\n'))
Utils.Print(f"first transactions: {firstTrxs}")
node.waitForTransactionsInBlock(firstTrxs)
status = node.waitForTransactionsInBlock(firstTrxs)
if status is None:
Utils.Print('ERROR: Failed to spin up transaction generators: never received first transactions')
return status
+1 -1
View File
@@ -61,7 +61,7 @@ class Node(Transactions):
self.fetchBlock = lambda blockNum: self.processUrllibRequest("trace_api", "get_block", {"block_num":blockNum}, silentErrors=False, exitOnError=True)
self.fetchKeyCommand = lambda: "[transaction][transaction_header][ref_block_num]"
self.fetchRefBlock = lambda trans: trans["transaction_header"]["ref_block_num"]
self.cleosLimit = "--time-limit 99999"
self.cleosLimit = "--time-limit 999"
self.fetchHeadBlock = lambda node, headBlock: node.processUrllibRequest("chain", "get_block_info", {"block_num":headBlock}, silentErrors=False, exitOnError=True)
def __str__(self):
+11 -10
View File
@@ -118,10 +118,10 @@ class NodeosQueries:
# could be a transaction response
if cntxt.hasKey("processed"):
cntxt.add("processed")
cntxt.add("action_traces")
cntxt.index(0)
if not cntxt.isSectionNull("except"):
return "no_block"
cntxt.add("action_traces")
cntxt.index(0)
return cntxt.add("block_num")
# or what the trace api plugin returns
@@ -242,7 +242,7 @@ class NodeosQueries:
assert(isinstance(transId, str))
exitOnErrorForDelayed=not delayedRetry and exitOnError
timeout=3
cmdDesc="get transaction_trace"
cmdDesc=self.fetchTransactionCommand()
cmd="%s %s" % (cmdDesc, transId)
msg="(transaction id=%s)" % (transId);
for i in range(0,(int(60/timeout) - 1)):
@@ -295,8 +295,8 @@ class NodeosQueries:
refBlockNum=None
key=""
try:
key="[transaction][transaction_header][ref_block_num]"
refBlockNum=trans["transaction_header"]["ref_block_num"]
key = self.fetchKeyCommand()
refBlockNum = self.fetchRefBlock(trans)
refBlockNum=int(refBlockNum)+1
except (TypeError, ValueError, KeyError) as _:
Utils.Print("transaction%s not found. Transaction: %s" % (key, trans))
@@ -347,8 +347,8 @@ class NodeosQueries:
def getTable(self, contract, scope, table, exitOnError=False):
cmdDesc = "get table"
cmd="%s %s %s %s" % (cmdDesc, contract, scope, table)
msg="contract=%s, scope=%s, table=%s" % (contract, scope, table);
cmd=f"{cmdDesc} {self.cleosLimit} {contract} {scope} {table}"
msg=f"contract={contract}, scope={scope}, table={table}"
return self.processCleosCmd(cmd, cmdDesc, exitOnError=exitOnError, exitMsg=msg)
def getTableAccountBalance(self, contract, scope):
@@ -529,7 +529,7 @@ class NodeosQueries:
return m.group(1)
except subprocess.CalledProcessError as ex:
end=time.perf_counter()
msg=ex.output.decode("utf-8")
msg=ex.stderr.decode("utf-8")
Utils.Print("ERROR: Exception during code hash retrieval. cmd Duration: %.3f sec. %s" % (end-start, msg))
return None
@@ -580,8 +580,9 @@ class NodeosQueries:
except subprocess.CalledProcessError as ex:
if not silentErrors:
end=time.perf_counter()
msg=ex.output.decode("utf-8")
errorMsg="Exception during \"%s\". Exception message: %s. cmd Duration=%.3f sec. %s" % (cmdDesc, msg, end-start, exitMsg)
out=ex.output.decode("utf-8")
msg=ex.stderr.decode("utf-8")
errorMsg="Exception during \"%s\". Exception message: %s. stdout: %s. cmd Duration=%.3f sec. %s" % (cmdDesc, msg, out, end-start, exitMsg)
if exitOnError:
Utils.cmdError(errorMsg)
Utils.errorExit(errorMsg)
+6 -7
View File
@@ -107,7 +107,7 @@ class Transactions(NodeosQueries):
self.trackCmdTransaction(trans, reportStatus=reportStatus)
except subprocess.CalledProcessError as ex:
end=time.perf_counter()
msg=ex.output.decode("utf-8")
msg=ex.stderr.decode("utf-8")
Utils.Print("ERROR: Exception during funds transfer. cmd Duration: %.3f sec. %s" % (end-start, msg))
if exitOnError:
Utils.cmdError("could not transfer \"%s\" from %s to %s" % (amountStr, source, destination))
@@ -131,7 +131,7 @@ class Transactions(NodeosQueries):
Utils.Print("cmd Duration: %.3f sec" % (end-start))
except subprocess.CalledProcessError as ex:
end=time.perf_counter()
msg=ex.output.decode("utf-8")
msg=ex.stderr.decode("utf-8")
Utils.Print("ERROR: Exception during spawn of funds transfer. cmd Duration: %.3f sec. %s" % (end-start, msg))
if exitOnError:
Utils.cmdError("could not transfer \"%s\" from %s to %s" % (amountStr, source, destination))
@@ -158,15 +158,15 @@ class Transactions(NodeosQueries):
except subprocess.CalledProcessError as ex:
if not shouldFail:
end=time.perf_counter()
msg=ex.output.decode("utf-8")
Utils.Print("ERROR: Exception during set contract. cmd Duration: %.3f sec. %s" % (end-start, msg))
out=ex.output.decode("utf-8")
msg=ex.stderr.decode("utf-8")
Utils.Print("ERROR: Exception during set contract. stderr: %s. stdout: %s. cmd Duration: %.3f sec." % (msg, out, end-start))
return None
else:
retMap={}
retMap["returncode"]=ex.returncode
retMap["cmd"]=ex.cmd
retMap["output"]=ex.output
retMap["stdout"]=ex.stdout
retMap["stderr"]=ex.stderr
return retMap
@@ -213,7 +213,7 @@ class Transactions(NodeosQueries):
Utils.Print("cmd Duration: %.3f sec" % (end-start))
return (NodeosQueries.getTransStatus(retTrans) == 'executed', retTrans)
except subprocess.CalledProcessError as ex:
msg=ex.output.decode("utf-8")
msg=ex.stderr.decode("utf-8")
if not silentErrors:
end=time.perf_counter()
Utils.Print("ERROR: Exception during push transaction. cmd Duration=%.3f sec. %s" % (end - start, msg))
@@ -245,7 +245,6 @@ class Transactions(NodeosQueries):
except subprocess.CalledProcessError as ex:
msg=ex.stderr.decode("utf-8")
output=ex.output.decode("utf-8")
msg=ex.output.decode("utf-8")
if not silentErrors:
end=time.perf_counter()
Utils.Print("ERROR: Exception during push message. stderr: %s. stdout: %s. cmd Duration=%.3f sec." % (msg, output, end - start))
+1 -1
View File
@@ -352,7 +352,7 @@ def abi_file_with_nodeos_test():
os.makedirs(data_dir, exist_ok=True)
walletMgr = WalletMgr(True)
walletMgr.launch()
node = Node('localhost', 8888, nodeId, cmd="./programs/nodeos/nodeos -e -p eosio --plugin eosio::trace_api_plugin --trace-no-abis --plugin eosio::producer_plugin --plugin eosio::producer_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::chain_plugin --plugin eosio::http_plugin --access-control-allow-origin=* --http-validate-host=false --resource-monitor-not-shutdown-on-threshold-exceeded " + "--data-dir " + data_dir + " --config-dir " + data_dir, walletMgr=walletMgr)
node = Node('localhost', 8888, nodeId, cmd="./programs/nodeos/nodeos -e -p eosio --plugin eosio::trace_api_plugin --trace-no-abis --plugin eosio::producer_plugin --plugin eosio::producer_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::chain_plugin --plugin eosio::http_plugin --access-control-allow-origin=* --http-validate-host=false --max-transaction-time=-1 --resource-monitor-not-shutdown-on-threshold-exceeded " + "--data-dir " + data_dir + " --config-dir " + data_dir, walletMgr=walletMgr)
node.verifyAlive() # Setting node state to not alive
node.relaunch(newChain=True, cachePopen=True)
node.waitForBlock(1)
+27 -15
View File
@@ -126,13 +126,15 @@ try:
waitForBlock(node0, blockNum, blockType=BlockType.lib)
Print("Configure and launch txn generators")
targetTpsPerGenerator = 10
testTrxGenDurationSec=60*30
cluster.launchTrxGenerators(contractOwnerAcctName=cluster.eosioAccount.name, acctNamesList=[account1Name, account2Name],
acctPrivKeysList=[account1PrivKey,account2PrivKey], nodeId=snapshotNodeId, tpsPerGenerator=targetTpsPerGenerator,
numGenerators=trxGeneratorCnt, durationSec=testTrxGenDurationSec, waitToComplete=False)
cluster.waitForTrxGeneratorsSpinup(nodeId=snapshotNodeId, numGenerators=trxGeneratorCnt)
status = cluster.waitForTrxGeneratorsSpinup(nodeId=snapshotNodeId, numGenerators=trxGeneratorCnt)
assert status is not None, "ERROR: Failed to spinup Transaction Generators"
blockNum=node0.getBlockNum(BlockType.head)
timePerBlock=500
@@ -156,12 +158,8 @@ try:
minReqPctLeeway=0.60
minRequiredTransactions=minReqPctLeeway*transactionsPerBlock
assert steadyStateAvg>=minRequiredTransactions, "Expected to at least receive %s transactions per block, but only getting %s" % (minRequiredTransactions, steadyStateAvg)
Print("Create snapshot")
blockNumSnap=nodeSnap.getBlockNum(BlockType.head)
ret = nodeProg.scheduleSnapshotAt(blockNumSnap)
assert ret is not None, "Snapshot creation failed"
Print("Create snapshot (node 0)")
ret = nodeSnap.createSnapshot()
assert ret is not None, "Snapshot creation failed"
ret_head_block_num = ret["payload"]["head_block_num"]
@@ -178,6 +176,29 @@ try:
Utils.processLeapUtilCmd("snapshot to-json --input-file {}".format(snapshotFile), "snapshot to-json", silentErrors=False)
snapshotFile = snapshotFile + ".json"
Print("Trim programmable blocklog to snapshot head block num and relaunch programmable node")
nodeProg.kill(signal.SIGTERM)
output=cluster.getBlockLog(progNodeId, blockLogAction=BlockLogAction.trim, first=0, last=ret_head_block_num, throwException=True)
removeState(progNodeId)
Utils.rmFromFile(Utils.getNodeConfigDir(progNodeId, "config.ini"), "p2p-peer-address")
isRelaunchSuccess = nodeProg.relaunch(chainArg="--replay", addSwapFlags={}, timeout=relaunchTimeout, cachePopen=True)
assert isRelaunchSuccess, "Failed to relaunch programmable node"
Print("Schedule snapshot (node 2)")
ret = nodeProg.scheduleSnapshotAt(ret_head_block_num)
assert ret is not None, "Snapshot scheduling failed"
Print("Wait for programmable node lib to advance")
waitForBlock(nodeProg, ret_head_block_num+1, blockType=BlockType.lib)
Print("Kill programmable node")
nodeProg.kill(signal.SIGTERM)
Print("Convert snapshot to JSON")
progSnapshotFile = getLatestSnapshot(progNodeId)
Utils.processLeapUtilCmd("snapshot to-json --input-file {}".format(progSnapshotFile), "snapshot to-json", silentErrors=False)
progSnapshotFile = progSnapshotFile + ".json"
Print("Trim irreversible blocklog to snapshot head block num")
nodeIrr.kill(signal.SIGTERM)
output=cluster.getBlockLog(irrNodeId, blockLogAction=BlockLogAction.trim, first=0, last=ret_head_block_num, throwException=True)
@@ -205,15 +226,6 @@ try:
irrSnapshotFile = irrSnapshotFile + ".json"
assert Utils.compareFiles(snapshotFile, irrSnapshotFile), f"Snapshot files differ {snapshotFile} != {irrSnapshotFile}"
Print("Kill programmable node")
nodeProg.kill(signal.SIGTERM)
Print("Convert snapshot to JSON")
progSnapshotFile = getLatestSnapshot(progNodeId)
Utils.processLeapUtilCmd("snapshot to-json --input-file {}".format(progSnapshotFile), "snapshot to-json", silentErrors=False)
progSnapshotFile = progSnapshotFile + ".json"
assert Utils.compareFiles(progSnapshotFile, irrSnapshotFile), f"Snapshot files differ {progSnapshotFile} != {irrSnapshotFile}"
testSuccessful=True
+2 -1
View File
@@ -118,7 +118,8 @@ try:
tpsPerGenerator=targetTpsPerGenerator, numGenerators=trxGeneratorCnt, durationSec=testTrxGenDurationSec,
waitToComplete=False)
cluster.waitForTrxGeneratorsSpinup(nodeId=node0.nodeId, numGenerators=trxGeneratorCnt)
status = cluster.waitForTrxGeneratorsSpinup(nodeId=node0.nodeId, numGenerators=trxGeneratorCnt)
assert status is not None, "ERROR: Failed to spinup Transaction Generators"
blockNum=head(node0)
timePerBlock=500
+1 -1
View File
@@ -56,7 +56,7 @@ class PluginHttpTest(unittest.TestCase):
"http_plugin", "db_size_api_plugin", "prometheus_plugin"]
nodeos_plugins = "--plugin eosio::" + " --plugin eosio::".join(plugin_names)
nodeos_flags = (" --data-dir=%s --config-dir=%s --trace-dir=%s --trace-no-abis --access-control-allow-origin=%s "
"--contracts-console --http-validate-host=%s --verbose-http-errors --abi-serializer-max-time-ms 30000 --http-max-response-time-ms 30000 "
"--contracts-console --http-validate-host=%s --verbose-http-errors --max-transaction-time -1 --abi-serializer-max-time-ms 30000 --http-max-response-time-ms 30000 "
"--p2p-peer-address localhost:9011 --resource-monitor-not-shutdown-on-threshold-exceeded ") % (self.data_dir, self.config_dir, self.data_dir, "\'*\'", "false")
start_nodeos_cmd = ("%s -e -p eosio %s %s ") % (Utils.EosServerPath, nodeos_plugins, nodeos_flags)
self.nodeos.launchCmd(start_nodeos_cmd, self.node_id)