Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/contest/grader/grader.cpp b/contest/grader/grader.cpp
- index 7c309179..99676f64 100644
- --- a/contest/grader/grader.cpp
- +++ b/contest/grader/grader.cpp
- @@ -38,6 +38,8 @@ class ContestGrader : public td::actor::Actor {
- }
- void start_up() override {
- + vm::detail::push_thread_pool::tpool_init();
- +
- vm::init_vm().ensure();
- scan_tests_dir();
- run_next_test();
- @@ -262,4 +264,4 @@ int main(int argc, char* argv[]) {
- }
- return 0;
- -}
- \ No newline at end of file
- +}
- diff --git a/contest/solution/contest-validate-query.cpp b/contest/solution/contest-validate-query.cpp
- index 3559f64d..c57533b3 100644
- --- a/contest/solution/contest-validate-query.cpp
- +++ b/contest/solution/contest-validate-query.cpp
- @@ -1799,7 +1799,11 @@ bool ContestValidateQuery::unpack_precheck_value_flow(Ref<vm::Cell> value_flow_r
- return reject_query("ValueFlow of block "s + id_.to_str() +
- " is invalid (non-zero fees_imported in a non-masterchain block)");
- }
- - auto accounts_extra = ps_.account_dict_->get_root_extra();
- + Ref<vm::CellSlice> accounts_extra;
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + accounts_extra = ps_.account_dict_->get_root_extra();
- + }
- block::CurrencyCollection cc;
- if (!(accounts_extra.write().advance(5) && cc.unpack(std::move(accounts_extra)))) {
- return reject_query("cannot unpack CurrencyCollection from the root of old accounts dictionary");
- @@ -1848,8 +1852,11 @@ bool ContestValidateQuery::compute_minted_amount(block::CurrencyCollection& to_m
- bool ContestValidateQuery::postcheck_one_account_update(td::ConstBitPtr acc_id, Ref<vm::CellSlice> old_value,
- Ref<vm::CellSlice> new_value) {
- LOG(DEBUG) << "checking update of account " << acc_id.to_hex(256);
- - old_value = ps_.account_dict_->extract_value(std::move(old_value));
- - new_value = ns_.account_dict_->extract_value(std::move(new_value));
- + {
- + //WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + old_value = ps_.account_dict_->extract_value(std::move(old_value));
- + new_value = ns_.account_dict_->extract_value(std::move(new_value));
- + }
- auto acc_blk_root = account_blocks_dict_->lookup(acc_id, 256);
- if (acc_blk_root.is_null()) {
- return reject_query("the state of account "s + acc_id.to_hex(256) +
- @@ -1896,16 +1903,19 @@ bool ContestValidateQuery::postcheck_one_account_update(td::ConstBitPtr acc_id,
- bool ContestValidateQuery::postcheck_account_updates() {
- LOG(INFO) << "pre-checking all Account updates between the old and the new state";
- try {
- - CHECK(ps_.account_dict_ && ns_.account_dict_);
- - if (!ps_.account_dict_->scan_diff(
- - *ns_.account_dict_,
- - [this](td::ConstBitPtr key, int key_len, Ref<vm::CellSlice> old_val_extra,
- - Ref<vm::CellSlice> new_val_extra) {
- - CHECK(key_len == 256);
- - return postcheck_one_account_update(key, std::move(old_val_extra), std::move(new_val_extra));
- - },
- - 2 /* check augmentation of changed nodes in the new dict */)) {
- - return reject_query("invalid ShardAccounts dictionary in the new state");
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + CHECK(ps_.account_dict_ && ns_.account_dict_);
- + if (!ps_.account_dict_->scan_diff(
- + *ns_.account_dict_,
- + [this](td::ConstBitPtr key, int key_len, Ref<vm::CellSlice> old_val_extra,
- + Ref<vm::CellSlice> new_val_extra) {
- + CHECK(key_len == 256);
- + return postcheck_one_account_update(key, std::move(old_val_extra), std::move(new_val_extra));
- + },
- + 2 /* check augmentation of changed nodes in the new dict */)) {
- + return reject_query("invalid ShardAccounts dictionary in the new state");
- + }
- }
- } catch (vm::VmError& err) {
- return reject_query("invalid ShardAccount dictionary difference between the old and the new state: "s +
- @@ -2021,8 +2031,11 @@ bool ContestValidateQuery::precheck_one_account_block(td::ConstBitPtr acc_id, Re
- acc_blk.account_addr.to_hex());
- }
- block::tlb::ShardAccount::Record old_state;
- - if (!old_state.unpack(ps_.account_dict_->lookup(acc_id, 256))) {
- - return reject_query("cannot extract Account from the ShardAccount of "s + acc_id.to_hex(256));
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + if (!old_state.unpack(ps_.account_dict_->lookup(acc_id, 256))) {
- + return reject_query("cannot extract Account from the ShardAccount of "s + acc_id.to_hex(256));
- + }
- }
- if (hash_upd.old_hash != old_state.account->get_hash().bits()) {
- return reject_query("(HASH_UPDATE Account) from the AccountBlock of "s + acc_id.to_hex(256) +
- @@ -4459,8 +4472,16 @@ std::unique_ptr<block::Account> ContestValidateQuery::make_account_from(td::Cons
- * Returns nullptr if an error occured.
- */
- std::unique_ptr<block::Account> ContestValidateQuery::unpack_account(td::ConstBitPtr addr) {
- - auto dict_entry = ps_.account_dict_->lookup_extra(addr, 256);
- - auto new_acc = make_account_from(addr, std::move(dict_entry.first));
- + Ref<vm::CellSlice> efirst;
- + {
- + std::pair<Ref<vm::CellSlice>, Ref<vm::CellSlice>> dict_entry;
- +
- + WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + dict_entry = ps_.account_dict_->lookup_extra(addr, 256);
- + efirst = std::move(dict_entry.first);
- + }
- +
- + auto new_acc = make_account_from(addr, efirst);
- if (!new_acc) {
- reject_query("cannot load state of account "s + addr.to_hex(256) + " from previous shardchain state");
- return {};
- @@ -4473,6 +4494,19 @@ std::unique_ptr<block::Account> ContestValidateQuery::unpack_account(td::ConstBi
- return new_acc;
- }
- +
- +
- +/*void ContestValidateQuery::check_one_transaction_wrapper(block::Account& account, ton::LogicalTime lt, Ref<vm::Cell> trans_root,
- + bool is_first, bool is_last)
- +{
- + //here set flag when finished, set "error" flag is check_one_transaction returned false
- +
- + if(check_one_transaction(account, lt, trans_root, is_first, is_last) == false)
- + {
- +
- + }
- +}*/
- +
- /**
- * Checks the validity of a single transaction for a given account.
- * Performs transaction execution.
- @@ -4505,18 +4539,18 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- if (in_msg_root.not_null()) {
- auto in_descr_cs = in_msg_dict_->lookup(in_msg_root->get_hash().as_bitslice());
- if (in_descr_cs.is_null()) {
- - return reject_query(PSTRING() << "inbound message with hash " << in_msg_root->get_hash().to_hex()
- + return false;/*return reject_query(PSTRING() << "inbound message with hash " << in_msg_root->get_hash().to_hex()
- << " of transaction " << lt << " of account " << addr.to_hex()
- - << " does not have a corresponding InMsg record");
- + << " does not have a corresponding InMsg record");*/
- }
- auto in_msg_tag = block::gen::t_InMsg.get_tag(*in_descr_cs);
- if (in_msg_tag != block::gen::InMsg::msg_import_ext && in_msg_tag != block::gen::InMsg::msg_import_fin &&
- in_msg_tag != block::gen::InMsg::msg_import_imm && in_msg_tag != block::gen::InMsg::msg_import_ihr &&
- in_msg_tag != block::gen::InMsg::msg_import_deferred_fin) {
- - return reject_query(PSTRING() << "inbound message with hash " << in_msg_root->get_hash().to_hex()
- + return false;/*return reject_query(PSTRING() << "inbound message with hash " << in_msg_root->get_hash().to_hex()
- << " of transaction " << lt << " of account " << addr.to_hex()
- << " has an invalid InMsg record (not one of msg_import_ext, msg_import_fin, "
- - "msg_import_imm, msg_import_ihr or msg_import_deferred_fin)");
- + "msg_import_imm, msg_import_ihr or msg_import_deferred_fin)");*/
- }
- is_special_tx = is_special_in_msg(*in_descr_cs);
- // once we know there is a InMsg with correct hash, we already know that it contains a message with this hash (by the verification of InMsg), so it is our message
- @@ -4532,18 +4566,18 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- block::gen::CommonMsgInfo::Record_int_msg_info info;
- CHECK(tlb::unpack_cell_inexact(in_msg_root, info));
- if (info.created_lt >= lt) {
- - return reject_query(PSTRING() << "transaction " << lt << " of " << addr.to_hex()
- + return false;/*return reject_query(PSTRING() << "transaction " << lt << " of " << addr.to_hex()
- << " processed inbound message created later at logical time "
- - << info.created_lt);
- + << info.created_lt);*/
- }
- LogicalTime emitted_lt = info.created_lt; // See ContestValidateQuery::check_message_processing_order
- if (in_msg_tag == block::gen::InMsg::msg_import_imm || in_msg_tag == block::gen::InMsg::msg_import_fin ||
- in_msg_tag == block::gen::InMsg::msg_import_deferred_fin) {
- block::tlb::MsgEnvelope::Record_std msg_env;
- if (!block::tlb::unpack_cell(in_descr_cs->prefetch_ref(), msg_env)) {
- - return reject_query(PSTRING() << "InMsg record for inbound message with hash "
- + return false;/*return reject_query(PSTRING() << "InMsg record for inbound message with hash "
- << in_msg_root->get_hash().to_hex() << " of transaction " << lt
- - << " of account " << addr.to_hex() << " does not have a valid MsgEnvelope");
- + << " of account " << addr.to_hex() << " does not have a valid MsgEnvelope");*/
- }
- in_msg_metadata = std::move(msg_env.metadata);
- if (msg_env.emitted_lt) {
- @@ -4565,15 +4599,15 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- StdSmcAddress d_addr;
- CHECK(block::tlb::t_MsgAddressInt.extract_std_address(dest, d_wc, d_addr));
- if (d_wc != workchain() || d_addr != addr) {
- - return reject_query(PSTRING() << "inbound message of transaction " << lt << " of account " << addr.to_hex()
- - << " has a different destination address " << d_wc << ":" << d_addr.to_hex());
- + return false;/*return reject_query(PSTRING() << "inbound message of transaction " << lt << " of account " << addr.to_hex()
- + << " has a different destination address " << d_wc << ":" << d_addr.to_hex());*/
- }
- auto in_msg_trans = in_descr_cs->prefetch_ref(1); // trans:^Transaction
- CHECK(in_msg_trans.not_null());
- if (in_msg_trans->get_hash() != trans_root->get_hash()) {
- - return reject_query(PSTRING() << "InMsg record for inbound message with hash " << in_msg_root->get_hash().to_hex()
- + return false;/*return reject_query(PSTRING() << "InMsg record for inbound message with hash " << in_msg_root->get_hash().to_hex()
- << " of transaction " << lt << " of account " << addr.to_hex()
- - << " refers to a different processing transaction");
- + << " refers to a different processing transaction");*/
- }
- }
- // check output messages
- @@ -4590,20 +4624,25 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- for (int i = 0; i < trans.outmsg_cnt; i++) {
- auto out_msg_root = out_dict.lookup_ref(td::BitArray<15>{i});
- CHECK(out_msg_root.not_null()); // we have pre-checked this
- - auto out_descr_cs = out_msg_dict_->lookup(out_msg_root->get_hash().as_bitslice());
- +
- + Ref<vm::CellSlice> out_descr_cs;
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(out_msg_dict_mtx);
- + out_descr_cs = out_msg_dict_->lookup(out_msg_root->get_hash().as_bitslice());
- + }
- if (out_descr_cs.is_null()) {
- - return reject_query(PSTRING() << "outbound message #" << i + 1 << " with hash "
- + return false;/*return reject_query(PSTRING() << "outbound message #" << i + 1 << " with hash "
- << out_msg_root->get_hash().to_hex() << " of transaction " << lt << " of account "
- - << addr.to_hex() << " does not have a corresponding OutMsg record");
- + << addr.to_hex() << " does not have a corresponding OutMsg record");*/
- }
- auto tag = block::gen::t_OutMsg.get_tag(*out_descr_cs);
- if (tag != block::gen::OutMsg::msg_export_ext && tag != block::gen::OutMsg::msg_export_new &&
- tag != block::gen::OutMsg::msg_export_imm && tag != block::gen::OutMsg::msg_export_new_defer) {
- - return reject_query(PSTRING() << "outbound message #" << i + 1 << " with hash "
- + return false;/*return reject_query(PSTRING() << "outbound message #" << i + 1 << " with hash "
- << out_msg_root->get_hash().to_hex() << " of transaction " << lt << " of account "
- << addr.to_hex()
- << " has an invalid OutMsg record (not one of msg_export_ext, msg_export_new, "
- - "msg_export_imm or msg_export_new_defer)");
- + "msg_export_imm or msg_export_new_defer)");*/
- }
- // once we know there is an OutMsg with correct hash, we already know that it contains a message with this hash
- // (by the verification of OutMsg), so it is our message
- @@ -4631,46 +4670,46 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- CHECK(msg_export_value.is_valid());
- money_exported += msg_export_value;
- if (msg_env.metadata != new_msg_metadata) {
- - return reject_query(PSTRING() << "outbound message #" << i + 1 << " with hash "
- + return false;/*return reject_query(PSTRING() << "outbound message #" << i + 1 << " with hash "
- << out_msg_root->get_hash().to_hex() << " of transaction " << lt << " of account "
- << addr.to_hex() << " has invalid metadata in an OutMsg record: expected "
- << (new_msg_metadata ? new_msg_metadata.value().to_str() : "<none>") << ", found "
- - << (msg_env.metadata ? msg_env.metadata.value().to_str() : "<none>"));
- + << (msg_env.metadata ? msg_env.metadata.value().to_str() : "<none>"));*/
- }
- }
- WorkchainId s_wc;
- StdSmcAddress ss_addr; // s_addr is some macros in Windows
- CHECK(block::tlb::t_MsgAddressInt.extract_std_address(src, s_wc, ss_addr));
- if (s_wc != workchain() || ss_addr != addr) {
- - return reject_query(PSTRING() << "outbound message #" << i + 1 << " of transaction " << lt << " of account "
- + return false;/*return reject_query(PSTRING() << "outbound message #" << i + 1 << " of transaction " << lt << " of account "
- << addr.to_hex() << " has a different source address " << s_wc << ":"
- - << ss_addr.to_hex());
- + << ss_addr.to_hex());*/
- }
- auto out_msg_trans = out_descr_cs->prefetch_ref(1); // trans:^Transaction
- CHECK(out_msg_trans.not_null());
- if (out_msg_trans->get_hash() != trans_root->get_hash()) {
- - return reject_query(PSTRING() << "OutMsg record for outbound message #" << i + 1 << " with hash "
- + return false;/*return reject_query(PSTRING() << "OutMsg record for outbound message #" << i + 1 << " with hash "
- << out_msg_root->get_hash().to_hex() << " of transaction " << lt << " of account "
- - << addr.to_hex() << " refers to a different processing transaction");
- + << addr.to_hex() << " refers to a different processing transaction");*/
- }
- if (tag != block::gen::OutMsg::msg_export_ext) {
- bool is_deferred = tag == block::gen::OutMsg::msg_export_new_defer;
- if (account_expected_defer_all_messages_.count(ss_addr) && !is_deferred) {
- - return reject_query(
- + return false;/*return reject_query(
- PSTRING() << "outbound message #" << i + 1 << " on account " << workchain() << ":" << ss_addr.to_hex()
- - << " must be deferred because this account has earlier messages in DispatchQueue");
- + << " must be deferred because this account has earlier messages in DispatchQueue");*/
- }
- if (is_deferred) {
- LOG(INFO) << "message from account " << workchain() << ":" << ss_addr.to_hex() << " with lt " << message_lt
- << " was deferred";
- if (!deferring_messages_enabled_ && !account_expected_defer_all_messages_.count(ss_addr)) {
- - return reject_query(PSTRING() << "outbound message #" << i + 1 << " on account " << workchain() << ":"
- - << ss_addr.to_hex() << " is deferred, but deferring messages is disabled");
- + return false;/*return reject_query(PSTRING() << "outbound message #" << i + 1 << " on account " << workchain() << ":"
- + << ss_addr.to_hex() << " is deferred, but deferring messages is disabled");*/
- }
- if (i == 0 && !account_expected_defer_all_messages_.count(ss_addr)) {
- - return reject_query(PSTRING() << "outbound message #1 on account " << workchain() << ":" << ss_addr.to_hex()
- + return false;/*return reject_query(PSTRING() << "outbound message #1 on account " << workchain() << ":" << ss_addr.to_hex()
- << " must not be deferred (the first message cannot be deferred unless some "
- - "prevoius messages are deferred)");
- + "prevoius messages are deferred)");*/
- }
- account_expected_defer_all_messages_.insert(ss_addr);
- }
- @@ -4686,45 +4725,45 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- bool split = (tag == block::gen::TransactionDescr::trans_split_prepare ||
- tag == block::gen::TransactionDescr::trans_split_install);
- if (split && !before_split_) {
- - return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- - << " is a split prepare/install transaction, but this block is not before a split");
- + return false;/*return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- + << " is a split prepare/install transaction, but this block is not before a split");*/
- }
- if (split && !is_last) {
- - return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- + return false;/*return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- << " is a split prepare/install transaction, but it is not the last transaction "
- - "for this account in this block");
- + "for this account in this block");*/
- }
- if (!split && !after_merge_) {
- - return reject_query(
- + return false;/*return reject_query(
- PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- - << " is a merge prepare/install transaction, but this block is not immediately after a merge");
- + << " is a merge prepare/install transaction, but this block is not immediately after a merge");*/
- }
- if (!split && !is_first) {
- - return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- + return false;/*return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- << " is a merge prepare/install transaction, but it is not the first transaction "
- - "for this account in this block");
- + "for this account in this block");*/
- }
- // check later a global configuration flag in config_.global_flags_
- // (for now, split/merge transactions are always globally disabled)
- - return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- - << " is a split/merge prepare/install transaction, which are globally disabled");
- + return false;/*return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- + << " is a split/merge prepare/install transaction, which are globally disabled");*/
- }
- if (tag == block::gen::TransactionDescr::trans_tick_tock) {
- - return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- - << " is a tick-tock transaction, which is impossible outside a masterchain block");
- + return false;/*return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- + << " is a tick-tock transaction, which is impossible outside a masterchain block");*/
- }
- if (tag == block::gen::TransactionDescr::trans_storage && !is_first) {
- - return reject_query(
- + return false;/*return reject_query(
- PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- - << " is a storage transaction, but it is not the first transaction for this account in this block");
- + << " is a storage transaction, but it is not the first transaction for this account in this block");*/
- }
- // check that the original account state has correct hash
- CHECK(account.total_state.not_null());
- if (hash_upd.old_hash != account.total_state->get_hash().bits()) {
- - return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- + return false;/*return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
- << " claims that the original account state hash must be "
- << hash_upd.old_hash.to_hex() << " but the actual value is "
- - << account.total_state->get_hash().to_hex());
- + << account.total_state->get_hash().to_hex());*/
- }
- // some type-specific checks
- int trans_type = block::transaction::Transaction::tr_none;
- @@ -4732,8 +4771,8 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- case block::gen::TransactionDescr::trans_ord: {
- trans_type = block::transaction::Transaction::tr_ord;
- if (in_msg_root.is_null()) {
- - return reject_query(PSTRING() << "ordinary transaction " << lt << " of account " << addr.to_hex()
- - << " has no inbound message");
- + return false;/*return reject_query(PSTRING() << "ordinary transaction " << lt << " of account " << addr.to_hex()
- + << " has no inbound message");*/
- }
- need_credit_phase = !external;
- break;
- @@ -4741,78 +4780,78 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- case block::gen::TransactionDescr::trans_storage: {
- trans_type = block::transaction::Transaction::tr_storage;
- if (in_msg_root.not_null()) {
- - return reject_query(PSTRING() << "storage transaction " << lt << " of account " << addr.to_hex()
- - << " has an inbound message");
- + return false;/*return reject_query(PSTRING() << "storage transaction " << lt << " of account " << addr.to_hex()
- + << " has an inbound message");*/
- }
- if (trans.outmsg_cnt) {
- - return reject_query(PSTRING() << "storage transaction " << lt << " of account " << addr.to_hex()
- - << " has at least one outbound message");
- + return false;/*return reject_query(PSTRING() << "storage transaction " << lt << " of account " << addr.to_hex()
- + << " has at least one outbound message");*/
- }
- // FIXME
- - return reject_query(PSTRING() << "unable to verify storage transaction " << lt << " of account "
- - << addr.to_hex());
- + return false;/*return reject_query(PSTRING() << "unable to verify storage transaction " << lt << " of account "
- + << addr.to_hex());*/
- break;
- }
- case block::gen::TransactionDescr::trans_tick_tock: {
- bool is_tock = (td_cs.prefetch_ulong(4) & 1);
- trans_type = is_tock ? block::transaction::Transaction::tr_tock : block::transaction::Transaction::tr_tick;
- if (in_msg_root.not_null()) {
- - return reject_query(PSTRING() << (is_tock ? "tock" : "tick") << " transaction " << lt << " of account "
- - << addr.to_hex() << " has an inbound message");
- + return false;/*return reject_query(PSTRING() << (is_tock ? "tock" : "tick") << " transaction " << lt << " of account "
- + << addr.to_hex() << " has an inbound message");*/
- }
- break;
- }
- case block::gen::TransactionDescr::trans_merge_prepare: {
- trans_type = block::transaction::Transaction::tr_merge_prepare;
- if (in_msg_root.not_null()) {
- - return reject_query(PSTRING() << "merge prepare transaction " << lt << " of account " << addr.to_hex()
- - << " has an inbound message");
- + return false;/*return reject_query(PSTRING() << "merge prepare transaction " << lt << " of account " << addr.to_hex()
- + << " has an inbound message");*/
- }
- if (trans.outmsg_cnt != 1) {
- - return reject_query(PSTRING() << "merge prepare transaction " << lt << " of account " << addr.to_hex()
- - << " must have exactly one outbound message");
- + return false;/*return reject_query(PSTRING() << "merge prepare transaction " << lt << " of account " << addr.to_hex()
- + << " must have exactly one outbound message");*/
- }
- // FIXME
- - return reject_query(PSTRING() << "unable to verify merge prepare transaction " << lt << " of account "
- - << addr.to_hex());
- + return false;/*return reject_query(PSTRING() << "unable to verify merge prepare transaction " << lt << " of account "
- + << addr.to_hex());*/
- break;
- }
- case block::gen::TransactionDescr::trans_merge_install: {
- trans_type = block::transaction::Transaction::tr_merge_install;
- if (in_msg_root.is_null()) {
- - return reject_query(PSTRING() << "merge install transaction " << lt << " of account " << addr.to_hex()
- - << " has no inbound message");
- + return false;/*return reject_query(PSTRING() << "merge install transaction " << lt << " of account " << addr.to_hex()
- + << " has no inbound message");*/
- }
- need_credit_phase = true;
- // FIXME
- - return reject_query(PSTRING() << "unable to verify merge install transaction " << lt << " of account "
- - << addr.to_hex());
- + return false;/*return reject_query(PSTRING() << "unable to verify merge install transaction " << lt << " of account "
- + << addr.to_hex());*/
- break;
- }
- case block::gen::TransactionDescr::trans_split_prepare: {
- trans_type = block::transaction::Transaction::tr_split_prepare;
- if (in_msg_root.not_null()) {
- - return reject_query(PSTRING() << "split prepare transaction " << lt << " of account " << addr.to_hex()
- - << " has an inbound message");
- + return false;/*return reject_query(PSTRING() << "split prepare transaction " << lt << " of account " << addr.to_hex()
- + << " has an inbound message");*/
- }
- if (trans.outmsg_cnt > 1) {
- - return reject_query(PSTRING() << "split prepare transaction " << lt << " of account " << addr.to_hex()
- - << " must have exactly one outbound message");
- + return false;/*return reject_query(PSTRING() << "split prepare transaction " << lt << " of account " << addr.to_hex()
- + << " must have exactly one outbound message");*/
- }
- // FIXME
- - return reject_query(PSTRING() << "unable to verify split prepare transaction " << lt << " of account "
- - << addr.to_hex());
- + return false;/*return reject_query(PSTRING() << "unable to verify split prepare transaction " << lt << " of account "
- + << addr.to_hex());*/
- break;
- }
- case block::gen::TransactionDescr::trans_split_install: {
- trans_type = block::transaction::Transaction::tr_split_install;
- if (in_msg_root.is_null()) {
- - return reject_query(PSTRING() << "split install transaction " << lt << " of account " << addr.to_hex()
- - << " has no inbound message");
- + return false;/*return reject_query(PSTRING() << "split install transaction " << lt << " of account " << addr.to_hex()
- + << " has no inbound message");*/
- }
- // FIXME
- - return reject_query(PSTRING() << "unable to verify split install transaction " << lt << " of account "
- - << addr.to_hex());
- + return false;/*return reject_query(PSTRING() << "unable to verify split install transaction " << lt << " of account "
- + << addr.to_hex());*/
- break;
- }
- }
- @@ -4825,61 +4864,67 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- if (in_msg_root.not_null()) {
- if (!trs->unpack_input_msg(ihr_delivered, &action_phase_cfg_)) {
- // inbound external message was not accepted
- - return reject_query(PSTRING() << "could not unpack inbound " << (external ? "external" : "internal")
- + return false;/*return reject_query(PSTRING() << "could not unpack inbound " << (external ? "external" : "internal")
- << " message processed by ordinary transaction " << lt << " of account "
- - << addr.to_hex());
- + << addr.to_hex());*/
- }
- }
- if (trs->bounce_enabled) {
- - if (!trs->prepare_storage_phase(storage_phase_cfg_, true)) {
- - return reject_query(PSTRING() << "cannot re-create storage phase of transaction " << lt << " for smart contract "
- - << addr.to_hex());
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(strg_cfg_mtx);
- + if (!trs->prepare_storage_phase(storage_phase_cfg_, true)) {
- + return false;//return reject_query(PSTRING() << "cannot re-create storage phase of transaction " << lt << " for smart contract " << addr.to_hex());
- + }
- }
- if (need_credit_phase && !trs->prepare_credit_phase()) {
- - return reject_query(PSTRING() << "cannot create re-credit phase of transaction " << lt << " for smart contract "
- - << addr.to_hex());
- + return false;/*reject_query(PSTRING() << "cannot create re-credit phase of transaction " << lt << " for smart contract "
- + << addr.to_hex());*/
- }
- } else {
- if (need_credit_phase && !trs->prepare_credit_phase()) {
- - return reject_query(PSTRING() << "cannot re-create credit phase of transaction " << lt << " for smart contract "
- - << addr.to_hex());
- + return false;/*return false;return reject_query(PSTRING() << "cannot re-create credit phase of transaction " << lt << " for smart contract "
- + << addr.to_hex());*/
- }
- - if (!trs->prepare_storage_phase(storage_phase_cfg_, true, need_credit_phase)) {
- - return reject_query(PSTRING() << "cannot re-create storage phase of transaction " << lt << " for smart contract "
- - << addr.to_hex());
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(strg_cfg_mtx);
- + if (!trs->prepare_storage_phase(storage_phase_cfg_, true, need_credit_phase)) {
- + return false;/*return reject_query(PSTRING() << "cannot re-create storage phase of transaction " << lt << " for smart contract "
- + << addr.to_hex());*/
- + }
- }
- }
- - if (!trs->prepare_compute_phase(compute_phase_cfg_)) {
- - return reject_query(PSTRING() << "cannot re-create compute phase of transaction " << lt << " for smart contract "
- - << addr.to_hex());
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(comp_cfg_mtx);
- + if (!trs->prepare_compute_phase(compute_phase_cfg_)) {
- + return false;/*return reject_query(PSTRING() << "cannot re-create compute phase of transaction " << lt << " for smart contract "
- + << addr.to_hex());*/
- + }
- }
- if (!trs->compute_phase->accepted) {
- if (external) {
- - return reject_query(PSTRING() << "inbound external message claimed to be processed by ordinary transaction " << lt
- - << " of account " << addr.to_hex()
- - << " was in fact rejected (such transaction cannot appear in valid blocks)");
- + return false;//return reject_query(PSTRING() << "inbound external message claimed to be processed by ordinary transaction " << lt << " of account " << addr.to_hex() << " was in fact rejected (such transaction cannot appear in valid blocks)");
- } else if (trs->compute_phase->skip_reason == block::ComputePhase::sk_none) {
- - return reject_query(PSTRING() << "inbound internal message processed by ordinary transaction " << lt
- - << " of account " << addr.to_hex() << " was not processed without any reason");
- + return false;//return reject_query(PSTRING() << "inbound internal message processed by ordinary transaction " << lt << " of account " << addr.to_hex() << " was not processed without any reason");
- }
- }
- - if (trs->compute_phase->success && !trs->prepare_action_phase(action_phase_cfg_)) {
- - return reject_query(PSTRING() << "cannot re-create action phase of transaction " << lt << " for smart contract "
- - << addr.to_hex());
- - }
- - if (trs->bounce_enabled &&
- - (!trs->compute_phase->success || trs->action_phase->state_exceeds_limits || trs->action_phase->bounce) &&
- - !trs->prepare_bounce_phase(action_phase_cfg_)) {
- - return reject_query(PSTRING() << "cannot re-create bounce phase of transaction " << lt << " for smart contract "
- - << addr.to_hex());
- +
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(actp_cfg_mtx);
- + if (trs->compute_phase->success && !trs->prepare_action_phase(action_phase_cfg_)) {
- + return false;//return reject_query(PSTRING() << "cannot re-create action phase of transaction " << lt << " for smart contract " << addr.to_hex());
- + }
- + if (trs->bounce_enabled &&
- + (!trs->compute_phase->success || trs->action_phase->state_exceeds_limits || trs->action_phase->bounce) &&
- + !trs->prepare_bounce_phase(action_phase_cfg_)) {
- + return false;//return reject_query(PSTRING() << "cannot re-create bounce phase of transaction " << lt << " for smart contract " << addr.to_hex());
- + }
- }
- if (!trs->serialize()) {
- - return reject_query(PSTRING() << "cannot re-create the serialization of transaction " << lt
- - << " for smart contract " << addr.to_hex());
- + return false;//return reject_query(PSTRING() << "cannot re-create the serialization of transaction " << lt << " for smart contract " << addr.to_hex());
- }
- if (!trs->update_limits(*block_limit_status_, /* with_gas = */ false, /* with_size = */ false)) {
- - return fatal_error(PSTRING() << "cannot update block limit status to include transaction " << lt << " of account "
- - << addr.to_hex());
- + return false;/*return fatal_error(PSTRING() << "cannot update block limit status to include transaction " << lt << " of account "
- + << addr.to_hex());*/
- }
- // Collator should stop if total gas usage exceeds limits, including transactions on special accounts, but without
- @@ -4888,24 +4933,30 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- if (!is_special_tx && !trs->gas_limit_overridden && trans_type == block::transaction::Transaction::tr_ord) {
- (account.is_special ? total_special_gas_used_ : total_gas_used_) += trs->gas_used();
- }
- - if (total_gas_used_ > block_limits_->gas.hard() + compute_phase_cfg_.gas_limit) {
- - return reject_query(PSTRING() << "gas block limits are exceeded: total_gas_used > gas_limit_hard + trx_gas_limit ("
- - << "total_gas_used=" << total_gas_used_
- - << ", gas_limit_hard=" << block_limits_->gas.hard()
- - << ", trx_gas_limit=" << compute_phase_cfg_.gas_limit << ")");
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(comp_cfg_mtx);
- + if (total_gas_used_ > block_limits_->gas.hard() + compute_phase_cfg_.gas_limit) {
- + return false;/*return reject_query(PSTRING() << "gas block limits are exceeded: total_gas_used > gas_limit_hard + trx_gas_limit ("
- + << "total_gas_used=" << total_gas_used_
- + << ", gas_limit_hard=" << block_limits_->gas.hard()
- + << ", trx_gas_limit=" << compute_phase_cfg_.gas_limit << ")");*/
- + }
- }
- - if (total_special_gas_used_ > block_limits_->gas.hard() + compute_phase_cfg_.special_gas_limit) {
- - return reject_query(
- - PSTRING() << "gas block limits are exceeded: total_special_gas_used > gas_limit_hard + special_gas_limit ("
- - << "total_special_gas_used=" << total_special_gas_used_
- - << ", gas_limit_hard=" << block_limits_->gas.hard()
- - << ", special_gas_limit=" << compute_phase_cfg_.special_gas_limit << ")");
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(comp_cfg_mtx);
- + if (total_special_gas_used_ > block_limits_->gas.hard() + compute_phase_cfg_.special_gas_limit) {
- + return false;/*return reject_query(
- + PSTRING() << "gas block limits are exceeded: total_special_gas_used > gas_limit_hard + special_gas_limit ("
- + << "total_special_gas_used=" << total_special_gas_used_
- + << ", gas_limit_hard=" << block_limits_->gas.hard()
- + << ", special_gas_limit=" << compute_phase_cfg_.special_gas_limit << ")");*/
- + }
- }
- auto trans_root2 = trs->commit(account);
- if (trans_root2.is_null()) {
- - return reject_query(PSTRING() << "the re-created transaction " << lt << " for smart contract " << addr.to_hex()
- - << " could not be committed");
- + return false;/*return reject_query(PSTRING() << "the re-created transaction " << lt << " for smart contract " << addr.to_hex()
- + << " could not be committed");*/
- }
- // now compare the re-created transaction with the one we have
- if (trans_root2->get_hash() != trans_root->get_hash()) {
- @@ -4915,58 +4966,69 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- std::cerr << "re-created transaction " << lt << " of " << addr.to_hex() << ": ";
- block::gen::t_Transaction.print_ref(std::cerr, trans_root2);
- }
- - return reject_query(PSTRING() << "the transaction " << lt << " of " << addr.to_hex() << " has hash "
- + return false;/*return reject_query(PSTRING() << "the transaction " << lt << " of " << addr.to_hex() << " has hash "
- << trans_root->get_hash().to_hex()
- << " different from that of the recreated transaction "
- - << trans_root2->get_hash().to_hex());
- + << trans_root2->get_hash().to_hex());*/
- }
- block::gen::Transaction::Record trans2;
- block::gen::HASH_UPDATE::Record hash_upd2;
- if (!(tlb::unpack_cell(trans_root2, trans2) &&
- tlb::type_unpack_cell(std::move(trans2.state_update), block::gen::t_HASH_UPDATE_Account, hash_upd2))) {
- - return fatal_error(PSTRING() << "cannot unpack the re-created transaction " << lt << " of " << addr.to_hex());
- + return false;/*return fatal_error(PSTRING() << "cannot unpack the re-created transaction " << lt << " of " << addr.to_hex());*/
- }
- if (hash_upd2.old_hash != hash_upd.old_hash) {
- - return fatal_error(PSTRING() << "the re-created transaction " << lt << " of " << addr.to_hex()
- - << " is invalid: it starts from account state with different hash");
- + return false;/*return fatal_error(PSTRING() << "the re-created transaction " << lt << " of " << addr.to_hex()
- + << " is invalid: it starts from account state with different hash");*/
- }
- if (hash_upd2.new_hash != account.total_state->get_hash().bits()) {
- - return fatal_error(
- + return false;/*return fatal_error(
- PSTRING() << "the re-created transaction " << lt << " of " << addr.to_hex()
- - << " is invalid: its claimed new account hash differs from the actual new account state");
- + << " is invalid: its claimed new account hash differs from the actual new account state");*/
- }
- if (hash_upd.new_hash != account.total_state->get_hash().bits()) {
- - return reject_query(PSTRING() << "transaction " << lt << " of " << addr.to_hex()
- + return false;/*return reject_query(PSTRING() << "transaction " << lt << " of " << addr.to_hex()
- << " is invalid: it claims that the new account state hash is "
- << hash_upd.new_hash.to_hex() << " but the re-computed value is "
- - << hash_upd2.new_hash.to_hex());
- + << hash_upd2.new_hash.to_hex());*/
- }
- if (!trans.r1.out_msgs->contents_equal(*trans2.r1.out_msgs)) {
- - return reject_query(
- + return false;/*return reject_query(
- PSTRING()
- << "transaction " << lt << " of " << addr.to_hex()
- - << " is invalid: it has produced a set of outbound messages different from that listed in the transaction");
- + << " is invalid: it has produced a set of outbound messages different from that listed in the transaction");*/
- }
- total_burned_ += trs->blackhole_burned;
- // check new balance and value flow
- auto new_balance = account.get_balance();
- block::CurrencyCollection total_fees;
- if (!total_fees.validate_unpack(trans.total_fees)) {
- - return reject_query(PSTRING() << "transaction " << lt << " of " << addr.to_hex()
- - << " has an invalid total_fees value");
- + return false;/*return reject_query(PSTRING() << "transaction " << lt << " of " << addr.to_hex()
- + << " has an invalid total_fees value");*/
- }
- if (old_balance + money_imported != new_balance + money_exported + total_fees + trs->blackhole_burned) {
- - return reject_query(
- + return false;/*return reject_query(
- PSTRING() << "transaction " << lt << " of " << addr.to_hex()
- << " violates the currency flow condition: old balance=" << old_balance.to_str()
- << " + imported=" << money_imported.to_str() << " does not equal new balance=" << new_balance.to_str()
- << " + exported=" << money_exported.to_str() << " + total_fees=" << total_fees.to_str()
- << (trs->blackhole_burned.is_zero() ? ""
- - : PSTRING() << " burned=" << trs->blackhole_burned.to_str()));
- + : PSTRING() << " burned=" << trs->blackhole_burned.to_str()));*/
- }
- return true;
- }
- +
- +/*void ContestValidateQuery::check_account_transactions_wrapper(const StdSmcAddress& acc_addr, Ref<vm::CellSlice> acc_blk_root)
- +{
- + if(check_account_transactions(acc_addr, acc_blk_root) == false)
- + {
- + flag_encountered_invalid.store(1, std::memory_order_relaxed);
- + }
- +
- + accs_count_processed.fetch_add(1, std::memory_order_relaxed);
- +}*/
- +
- /**
- * Checks the validity of transactions for a given account block.
- * NB: may be run in parallel for different accounts
- @@ -4978,10 +5040,16 @@ bool ContestValidateQuery::check_one_transaction(block::Account& account, ton::L
- */
- bool ContestValidateQuery::check_account_transactions(const StdSmcAddress& acc_addr, Ref<vm::CellSlice> acc_blk_root) {
- block::gen::AccountBlock::Record acc_blk;
- - CHECK(tlb::csr_unpack(std::move(acc_blk_root), acc_blk) && acc_blk.account_addr == acc_addr);
- +
- + {
- + std::lock_guard<std::mutex> unpacklock(unpack_mtx);
- + CHECK(tlb::csr_unpack(std::move(acc_blk_root), acc_blk));
- + CHECK(acc_blk.account_addr == acc_addr);
- + }
- auto account_p = unpack_account(acc_addr.cbits());
- if (!account_p) {
- - return reject_query("cannot unpack old state of account "s + acc_addr.to_hex());
- + printf("1\n");
- + return false;//return reject_query("cannot unpack old state of account "s + acc_addr.to_hex());
- }
- auto& account = *account_p;
- CHECK(account.addr == acc_addr);
- @@ -4998,7 +5066,8 @@ bool ContestValidateQuery::check_account_transactions(const StdSmcAddress& acc_a
- extra.clear();
- return check_one_transaction(account, lt, value->prefetch_ref(), lt == min_trans_lt, lt == max_trans_lt);
- })) {
- - return reject_query("at least one Transaction of account "s + acc_addr.to_hex() + " is invalid");
- + printf("2\n");
- + return false;//return reject_query("at least one Transaction of account "s + acc_addr.to_hex() + " is invalid");
- }
- // See Collator::combine_account_trabsactions
- @@ -5008,12 +5077,19 @@ bool ContestValidateQuery::check_account_transactions(const StdSmcAddress& acc_a
- // account created
- CHECK(account.status != block::Account::acc_nonexist);
- vm::CellBuilder cb;
- - if (!(cb.store_ref_bool(account.total_state) // account_descr$_ account:^Account
- - && cb.store_bits_bool(account.last_trans_hash_) // last_trans_hash:bits256
- - && cb.store_long_bool(account.last_trans_lt_, 64) // last_trans_lt:uint64
- - && ns_.account_dict_->set_builder(account.addr, cb, vm::Dictionary::SetMode::Add))) {
- - return fatal_error(std::string{"cannot add newly-created account "} + account.addr.to_hex() +
- - " into ShardAccounts");
- + bool write_res = (cb.store_ref_bool(account.total_state) // account_descr$_ account:^Account
- + && cb.store_bits_bool(account.last_trans_hash_) // last_trans_hash:bits256
- + && cb.store_long_bool(account.last_trans_lt_, 64)); // last_trans_lt:uint64
- +
- + if(write_res)
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + write_res = ns_.account_dict_->set_builder(account.addr, cb, vm::Dictionary::SetMode::Add);
- + }
- +
- + if (!write_res) {
- + printf("3\n");
- + return false;//return fatal_error(std::string{"cannot add newly-created account "} + account.addr.to_hex() + " into ShardAccounts");
- }
- } else if (account.status == block::Account::acc_nonexist) {
- // account deleted
- @@ -5021,8 +5097,13 @@ bool ContestValidateQuery::check_account_transactions(const StdSmcAddress& acc_a
- std::cerr << "deleting account " << account.addr.to_hex() << " with empty new value ";
- block::gen::t_Account.print_ref(std::cerr, account.total_state);
- }
- - if (ns_.account_dict_->lookup_delete(account.addr).is_null()) {
- - return fatal_error(std::string{"cannot delete account "} + account.addr.to_hex() + " from ShardAccounts");
- +
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + if (ns_.account_dict_->lookup_delete(account.addr).is_null()) {
- + printf("4\n");
- + return false;//return fatal_error(std::string{"cannot delete account "} + account.addr.to_hex() + " from ShardAccounts");
- + }
- }
- } else {
- // existing account modified
- @@ -5031,32 +5112,47 @@ bool ContestValidateQuery::check_account_transactions(const StdSmcAddress& acc_a
- block::gen::t_Account.print_ref(std::cerr, account.total_state);
- }
- vm::CellBuilder cb;
- - if (!(cb.store_ref_bool(account.total_state) // account_descr$_ account:^Account
- - && cb.store_bits_bool(account.last_trans_hash_) // last_trans_hash:bits256
- - && cb.store_long_bool(account.last_trans_lt_, 64) // last_trans_lt:uint64
- - && ns_.account_dict_->set_builder(account.addr, cb, vm::Dictionary::SetMode::Replace))) {
- - return fatal_error(std::string{"cannot modify existing account "} + account.addr.to_hex() +
- - " in ShardAccounts");
- +
- + bool write_res = (cb.store_ref_bool(account.total_state) // account_descr$_ account:^Account
- + && cb.store_bits_bool(account.last_trans_hash_) // last_trans_hash:bits256
- + && cb.store_long_bool(account.last_trans_lt_, 64)); // last_trans_lt:uint64
- +
- + if(write_res)
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + write_res = ns_.account_dict_->set_builder(account.addr, cb, vm::Dictionary::SetMode::Replace);
- + }
- +
- + if (!write_res) {
- + printf("5\n");
- + return false;//return fatal_error(std::string{"cannot modify existing account "} + account.addr.to_hex() + " in ShardAccounts");
- }
- }
- }
- block::gen::HASH_UPDATE::Record hash_upd;
- if (!tlb::type_unpack_cell(std::move(acc_blk.state_update), block::gen::t_HASH_UPDATE_Account, hash_upd)) {
- - return reject_query("cannot extract (HASH_UPDATE Account) from the AccountBlock of "s + account.addr.to_hex());
- + printf("6\n");
- + return false;//return reject_query("cannot extract (HASH_UPDATE Account) from the AccountBlock of "s + account.addr.to_hex());
- }
- block::tlb::ShardAccount::Record old_state, new_state;
- - if (!(old_state.unpack(ps_.account_dict_->lookup(account.addr)) &&
- - new_state.unpack(ns_.account_dict_->lookup(account.addr)))) {
- - return reject_query("cannot extract Account from the ShardAccount of "s + account.addr.to_hex());
- +
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + if (!(old_state.unpack(ps_.account_dict_->lookup(account.addr)) &&
- + new_state.unpack(ns_.account_dict_->lookup(account.addr)))) {
- + printf("7\n");
- + return false;//return reject_query("cannot extract Account from the ShardAccount of "s + account.addr.to_hex());
- + }
- }
- +
- if (hash_upd.old_hash != old_state.account->get_hash().bits()) {
- - return reject_query("(HASH_UPDATE Account) from the AccountBlock of "s + account.addr.to_hex() +
- - " has incorrect old hash");
- + printf("8\n");
- + return false;//return reject_query("(HASH_UPDATE Account) from the AccountBlock of "s + account.addr.to_hex() + " has incorrect old hash");
- }
- if (hash_upd.new_hash != new_state.account->get_hash().bits()) {
- - return reject_query("(HASH_UPDATE Account) from the AccountBlock of "s + account.addr.to_hex() +
- - " has incorrect new hash");
- + printf("9\n");
- + return false;//return reject_query("(HASH_UPDATE Account) from the AccountBlock of "s + account.addr.to_hex() + " has incorrect new hash");
- }
- return true;
- @@ -5069,15 +5165,75 @@ bool ContestValidateQuery::check_account_transactions(const StdSmcAddress& acc_a
- */
- bool ContestValidateQuery::check_transactions() {
- LOG(INFO) << "checking all transactions";
- - ns_.account_dict_ =
- - std::make_unique<vm::AugmentedDictionary>(ps_.account_dict_->get_root(), 256, block::tlb::aug_ShardAccounts);
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + ns_.account_dict_ = std::make_unique<vm::AugmentedDictionary>(ps_.account_dict_->get_root(), 256, block::tlb::aug_ShardAccounts);
- + }
- +
- + //int pushed_jobs_cnt = 0; //account_dict_
- +
- + //this needs to be reset or something as after 1 thread works in slot it always is marked as done
- + vm::detail::thread_pool_out_data t_out_data[8];
- + uint8_t t_thread_was_used[8];
- + memset(t_thread_was_used, 0, 8);
- + flag_encountered_invalid.store(0, std::memory_order_relaxed);
- +
- bool ok = account_blocks_dict_->check_for_each_extra(
- - [this](Ref<vm::CellSlice> value, Ref<vm::CellSlice> extra, td::ConstBitPtr key, int key_len) {
- + [this, &t_out_data, &t_thread_was_used](Ref<vm::CellSlice> value, Ref<vm::CellSlice> extra, td::ConstBitPtr key, int key_len) {
- + //++pushed_jobs_cnt;
- CHECK(key_len == 256);
- - return check_account_transactions(key, std::move(value));
- +
- + //waiting_for_count_proc.fetch_add(1, std::memory_order_relaxed);
- +
- + std::array<unsigned char, 32> key_array;
- + std::memcpy(key_array.data(), key.ptr, 32);
- +
- + auto value_copy = Ref<vm::CellSlice>{true, value->clone()};
- + std::function<void()> proc_func = [this, value = std::move(value_copy), key_array = key_array](){
- +
- + auto value_arg = value;
- + if(check_account_transactions(td::ConstBitPtr(key_array.data()), std::move(value_arg)) == false)
- + {
- + printf("setting encountered invalid\n");
- + flag_encountered_invalid.store(1, std::memory_order_relaxed);
- + }
- +
- + //accs_count_processed.fetch_add(1, std::memory_order_relaxed);
- + };
- +
- + //uint32_t pushed_thread_idx = 0xFF; //for single threaded test
- + uint32_t pushed_thread_idx = vm::detail::push_thread_pool::try_find_and_set_thread_work(proc_func, t_out_data);
- + if(pushed_thread_idx == 0xFF) //pool is busy
- + {
- + proc_func();
- + }
- + else
- + {
- + t_thread_was_used[pushed_thread_idx] = 1;
- + }
- + return true;//return check_account_transactions(key, std::move(value));
- });
- +
- + //waiting_for_count_proc.store(pushed_jobs_cnt, std::memory_order_release);
- + vm::detail::push_thread_pool::tpool_wait_for_all_threads(t_out_data, t_thread_was_used);//waits for all sems / flags
- + //here we're done
- +
- + //here we wait sem and check counter
- +
- + bool res = false;
- + int flag_val = flag_encountered_invalid.load(std::memory_order_acquire);
- +
- + if(flag_val)
- + {
- + printf("returning false\n");
- + res = false;
- + }
- + else
- + {
- + res = true;
- + }
- - return ok;
- + return res;
- }
- /**
- @@ -5177,7 +5333,11 @@ bool ContestValidateQuery::check_new_state() {
- * @returns True if the value flow is valid, False otherwise.
- */
- bool ContestValidateQuery::postcheck_value_flow() {
- - auto accounts_extra = ns_.account_dict_->get_root_extra();
- + Ref<vm::CellSlice> accounts_extra;
- + {
- + WriteLockGuard<NonRecursiveRWLock> lock(account_dict_mtx);
- + accounts_extra = ns_.account_dict_->get_root_extra();
- + }
- block::CurrencyCollection cc;
- if (!(accounts_extra.write().advance(5) && cc.unpack(std::move(accounts_extra)))) {
- return reject_query("cannot unpack CurrencyCollection from the root of new accounts dictionary");
- @@ -5359,27 +5519,38 @@ bool ContestValidateQuery::build_state_update() {
- vm::CellBuilder cb, cb2;
- // See Collator::create_shard_state
- - if (!(cb.store_long_bool(0x9023afe2, 32) // shard_state#9023afe2
- - && cb.store_long_bool(global_id_, 32) // global_id:int32
- - && block::ShardId{shard_}.serialize(cb) // shard_id:ShardIdent
- - && cb.store_long_bool(id_.seqno(), 32) // seq_no:uint32
- - && cb.store_long_bool(vert_seqno_, 32) // vert_seq_no:#
- - && cb.store_long_bool(now_, 32) // gen_utime:uint32
- - && cb.store_long_bool(ns_.lt_, 64) // gen_lt:uint64
- - && cb.store_long_bool(ns_.min_ref_mc_seqno_, 32) // min_ref_mc_seqno:uint32
- - && cb.store_ref_bool(msg_q_info) // out_msg_queue_info:^OutMsgQueueInfo
- - && cb.store_long_bool(before_split_, 1) // before_split:Bool
- - && ns_.account_dict_->append_dict_to_bool(cb2) // accounts:^ShardAccounts
- - && cb.store_ref_bool(cb2.finalize()) // ...
- - && cb2.store_long_bool(ns_.overload_history_, 64) // ^[ overload_history:uint64
- - && cb2.store_long_bool(ns_.underload_history_, 64) // underload_history:uint64
- - && ns_.total_balance_.store(cb2) // total_balance:CurrencyCollection
- - && ns_.total_validator_fees_.store(cb2) // total_validator_fees:CurrencyCollection
- - && cb2.store_bool_bool(false) // libraries:(HashmapE 256 LibDescr)
- - && cb2.store_bool_bool(true) && store_master_ref(cb2) // master_ref:(Maybe BlkMasterInfo)
- - && cb.store_ref_bool(cb2.finalize()) // ]
- - && cb.store_bool_bool(false) // custom:(Maybe ^McStateExtra)
- - && cb.finalize_to(state_root))) {
- + bool shwrite_ok = (cb.store_long_bool(0x9023afe2, 32) // shard_state#9023afe2
- + && cb.store_long_bool(global_id_, 32) // global_id:int32
- + && block::ShardId{shard_}.serialize(cb) // shard_id:ShardIdent
- + && cb.store_long_bool(id_.seqno(), 32) // seq_no:uint32
- + && cb.store_long_bool(vert_seqno_, 32) // vert_seq_no:#
- + && cb.store_long_bool(now_, 32) // gen_utime:uint32
- + && cb.store_long_bool(ns_.lt_, 64) // gen_lt:uint64
- + && cb.store_long_bool(ns_.min_ref_mc_seqno_, 32) // min_ref_mc_seqno:uint32
- + && cb.store_ref_bool(msg_q_info) // out_msg_queue_info:^OutMsgQueueInfo
- + && cb.store_long_bool(before_split_, 1)); // before_split:Bool
- +
- + if(shwrite_ok){
- + shwrite_ok = ns_.account_dict_->append_dict_to_bool(cb2);// accounts:^ShardAccounts
- + }
- +
- + if(shwrite_ok){
- + shwrite_ok = (cb.store_ref_bool(cb2.finalize()) // ...
- + && cb2.store_long_bool(ns_.overload_history_, 64) // ^[ overload_history:uint64
- + && cb2.store_long_bool(ns_.underload_history_, 64) // underload_history:uint64
- + && ns_.total_balance_.store(cb2) // total_balance:CurrencyCollection
- + && ns_.total_validator_fees_.store(cb2) // total_validator_fees:CurrencyCollection
- + && cb2.store_bool_bool(false) // libraries:(HashmapE 256 LibDescr)
- + && cb2.store_bool_bool(true) && store_master_ref(cb2) // master_ref:(Maybe BlkMasterInfo)
- + && cb.store_ref_bool(cb2.finalize()) // ]
- + && cb.store_bool_bool(false) // custom:(Maybe ^McStateExtra)
- + && cb.finalize_to(state_root));
- + }
- +
- +
- +
- + if(!shwrite_ok)
- + {
- return fatal_error("cannot create new ShardState");
- }
- diff --git a/contest/solution/contest-validate-query.hpp b/contest/solution/contest-validate-query.hpp
- index 7a43c244..6dde9baa 100644
- --- a/contest/solution/contest-validate-query.hpp
- +++ b/contest/solution/contest-validate-query.hpp
- @@ -12,6 +12,7 @@
- #include <map>
- #include "common/global-version.h"
- #include "tonlib/tonlib/ExtClient.h"
- +//#include "vm/cells/MerkleProof.h"
- namespace solution {
- @@ -81,6 +82,225 @@ inline ErrorCtxSet ErrorCtx::set_guard(std::vector<std::string> str_list) {
- return ErrorCtxSet(*this, std::move(str_list));
- }
- +
- +
- +#ifndef __CPP11OM_RWLOCK_H__
- +#define __CPP11OM_RWLOCK_H__
- +
- +#include <cassert>
- +#include <atomic>
- +//#include <random>
- +#include "bitfield.h"
- +
- +
- +//---------------------------------------------------------
- +// LightweightSemaphore
- +//---------------------------------------------------------
- +class LightweightSemaphore
- +{
- +private:
- + std::atomic<int> m_count;
- + vm::Semaphore m_sema;
- +
- + void waitWithPartialSpinning()
- + {
- + int oldCount;
- + // Is there a better way to set the initial spin count?
- + // If we lower it to 1000, testBenaphore becomes 15x slower on my Core i7-5930K Windows PC,
- + // as threads start hitting the kernel semaphore.
- + int spin = 10000;
- + while (spin--)
- + {
- + oldCount = m_count.load(std::memory_order_relaxed);
- + if ((oldCount > 0) && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire))
- + return;
- + std::atomic_signal_fence(std::memory_order_acquire); // Prevent the compiler from collapsing the loop.
- + }
- + oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
- + if (oldCount <= 0)
- + {
- + m_sema.wait();
- + }
- + }
- +
- +public:
- + LightweightSemaphore(int initialCount = 0) : m_count(initialCount)
- + {
- + assert(initialCount >= 0);
- + }
- +
- + bool tryWait()
- + {
- + int oldCount = m_count.load(std::memory_order_relaxed);
- + return (oldCount > 0 && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire));
- + }
- +
- + void wait()
- + {
- + if (!tryWait())
- + waitWithPartialSpinning();
- + }
- +
- + void signal(int count = 1)
- + {
- + int oldCount = m_count.fetch_add(count, std::memory_order_release);
- + int toRelease = -oldCount < count ? -oldCount : count;
- + if (toRelease > 0)
- + {
- + m_sema.signal(toRelease);
- + }
- + }
- +};
- +
- +
- +typedef LightweightSemaphore DefaultSemaphoreType;
- +
- +//---------------------------------------------------------
- +// NonRecursiveRWLock
- +//---------------------------------------------------------
- +class NonRecursiveRWLock
- +{
- +private:
- + BEGIN_BITFIELD_TYPE(Status, uint32_t)
- + ADD_BITFIELD_MEMBER(readers, 0, 10)
- + ADD_BITFIELD_MEMBER(waitToRead, 10, 10)
- + ADD_BITFIELD_MEMBER(writers, 20, 10)
- + END_BITFIELD_TYPE()
- +
- + std::atomic<uint32_t> m_status;
- + DefaultSemaphoreType m_readSema;
- + DefaultSemaphoreType m_writeSema;
- +
- +public:
- + NonRecursiveRWLock() : m_status(0) {}
- +
- + void lockReader()
- + {
- + Status oldStatus = m_status.load(std::memory_order_relaxed);
- + Status newStatus;
- + do
- + {
- + newStatus = oldStatus;
- + if (oldStatus.writers > 0)
- + {
- + newStatus.waitToRead++;
- + }
- + else
- + {
- + newStatus.readers++;
- + }
- + // CAS until successful. On failure, oldStatus will be updated with the latest value.
- + }
- + while (!m_status.compare_exchange_weak(oldStatus, newStatus,
- + std::memory_order_acquire, std::memory_order_relaxed));
- +
- + if (oldStatus.writers > 0)
- + {
- + m_readSema.wait();
- + }
- + }
- +
- + void unlockReader()
- + {
- + Status oldStatus = m_status.fetch_sub(Status().readers.one(), std::memory_order_release);
- + assert(oldStatus.readers > 0);
- + if (oldStatus.readers == 1 && oldStatus.writers > 0)
- + {
- + m_writeSema.signal();
- + }
- + }
- +
- + void lockWriter()
- + {
- + Status oldStatus = m_status.fetch_add(Status().writers.one(), std::memory_order_acquire);
- + assert(oldStatus.writers + 1 <= Status().writers.maximum());
- + if (oldStatus.readers > 0 || oldStatus.writers > 0)
- + {
- + m_writeSema.wait();
- + }
- + }
- +
- + void unlockWriter()
- + {
- + Status oldStatus = m_status.load(std::memory_order_relaxed);
- + Status newStatus;
- + uint32_t waitToRead = 0;
- + do
- + {
- + assert(oldStatus.readers == 0);
- + newStatus = oldStatus;
- + newStatus.writers--;
- + waitToRead = oldStatus.waitToRead;
- + if (waitToRead > 0)
- + {
- + newStatus.waitToRead = 0;
- + newStatus.readers = waitToRead;
- + }
- + // CAS until successful. On failure, oldStatus will be updated with the latest value.
- + }
- + while (!m_status.compare_exchange_weak(oldStatus, newStatus,
- + std::memory_order_release, std::memory_order_relaxed));
- +
- + if (waitToRead > 0)
- + {
- + m_readSema.signal(waitToRead);
- + }
- + else if (oldStatus.writers > 1)
- + {
- + m_writeSema.signal();
- + }
- + }
- +};
- +
- +
- +//---------------------------------------------------------
- +// ReadLockGuard
- +//---------------------------------------------------------
- +template <class LockType>
- +class ReadLockGuard
- +{
- +private:
- + LockType& m_lock;
- +
- +public:
- + ReadLockGuard(LockType& lock) : m_lock(lock)
- + {
- + m_lock.lockReader();
- + }
- +
- + ~ReadLockGuard()
- + {
- + m_lock.unlockReader();
- + }
- +};
- +
- +
- +//---------------------------------------------------------
- +// WriteLockGuard
- +//---------------------------------------------------------
- +template <class LockType>
- +class WriteLockGuard
- +{
- +private:
- + LockType& m_lock;
- +
- +public:
- + WriteLockGuard(LockType& lock) : m_lock(lock)
- + {
- + m_lock.lockWriter();
- + }
- +
- + ~WriteLockGuard()
- + {
- + m_lock.unlockWriter();
- + }
- +};
- +
- +
- +#endif // __CPP11OM_RWLOCK_H__
- +
- +
- +
- class ContestValidateQuery : public td::actor::Actor {
- static constexpr int supported_version() {
- return SUPPORTED_VERSION;
- @@ -113,6 +333,8 @@ class ContestValidateQuery : public td::actor::Actor {
- bool prev_key_block_exists_{false};
- bool debug_checks_{false};
- bool outq_cleanup_partial_{false};
- + std::mutex unpack_mtx;
- + NonRecursiveRWLock account_dict_mtx;
- BlockSeqno prev_key_seqno_{~0u};
- int stage_{0};
- td::BitArray<64> shard_pfx_;
- @@ -166,6 +388,9 @@ class ContestValidateQuery : public td::actor::Actor {
- std::vector<block::StoragePrices> storage_prices_;
- block::StoragePhaseConfig storage_phase_cfg_{&storage_prices_};
- block::ComputePhaseConfig compute_phase_cfg_;
- + NonRecursiveRWLock comp_cfg_mtx;
- + NonRecursiveRWLock strg_cfg_mtx;
- + NonRecursiveRWLock actp_cfg_mtx;
- block::ActionPhaseConfig action_phase_cfg_;
- td::RefInt256 masterchain_create_fee_, basechain_create_fee_;
- @@ -181,7 +406,13 @@ class ContestValidateQuery : public td::actor::Actor {
- std::map<td::Bits256, int> block_create_count_;
- unsigned block_create_total_{0};
- + //std::atomic<int> accs_count_processed = {0};
- + std::atomic<int> flag_encountered_invalid = {0};
- + //std::atomic<int> waiting_for_count_proc = {0};
- + //std::atomic<int> pushed_all_jobs_flag = {0};
- +
- std::unique_ptr<vm::AugmentedDictionary> in_msg_dict_, out_msg_dict_, account_blocks_dict_;
- + NonRecursiveRWLock out_msg_dict_mtx;
- block::ValueFlow value_flow_;
- block::CurrencyCollection import_created_, transaction_fees_, total_burned_{0}, fees_burned_{0};
- td::RefInt256 import_fees_;
- @@ -338,4 +569,4 @@ class ContestValidateQuery : public td::actor::Actor {
- bool build_state_update();
- };
- -} // namespace solution
- \ No newline at end of file
- +} // namespace solution
- diff --git a/crypto/block/check-proof.cpp b/crypto/block/check-proof.cpp
- index 431a03fe..c0e88924 100644
- --- a/crypto/block/check-proof.cpp
- +++ b/crypto/block/check-proof.cpp
- @@ -612,6 +612,8 @@ td::Status check_block_signatures(const std::vector<ton::ValidatorDescr>& nodes,
- if (signatures.empty()) {
- return td::Status::Error("empty validator signature set");
- }
- +
- + printf("DEBUG: check_block_signatures called\n");
- // compute the string to be signed and its hash
- unsigned char to_sign[68];
- td::as<td::uint32>(to_sign) = 0xc50b6e70; // ton.blockId root_cell_hash:int256 file_hash:int256 = ton.BlockId;
- @@ -626,8 +628,12 @@ td::Status check_block_signatures(const std::vector<ton::ValidatorDescr>& nodes,
- total_weight += nodes[i].weight;
- node_map.emplace_back(compute_node_id_short(nodes[i].key), i);
- }
- +
- + printf("DEBUG: total_weight = %llu\n", total_weight);
- std::sort(node_map.begin(), node_map.end());
- std::vector<unsigned> seen;
- +
- + printf("DEBUG: signatures len: %llu\n", signatures.size());
- for (auto& sig : signatures) {
- // lookup node in validator set
- auto& id = sig.node;
- @@ -641,6 +647,10 @@ td::Status check_block_signatures(const std::vector<ton::ValidatorDescr>& nodes,
- // check one signature
- td::Ed25519::PublicKey pub_key{td::SecureString{nodes.at(i).key.as_slice()}};
- auto res = pub_key.verify_signature(td::Slice{to_sign, 68}, sig.signature.as_slice());
- +
- + td::MutableSlice sigsl = const_cast<td::BufferSlice&>(sig.signature).as_slice();
- + td::StringBuilder sig_strb(sigsl);
- + printf("\tnodeidshort: %s\n\tpubkey: %s\n\tsignature: %s\n\tweight: %llu\n\n\n", id.to_hex().c_str(), nodes.at(i).key._pubkey.to_hex().c_str(), sig_strb.as_cslice().c_str(), nodes[i].weight);
- if (res.is_error()) {
- return res;
- }
- @@ -649,6 +659,8 @@ td::Status check_block_signatures(const std::vector<ton::ValidatorDescr>& nodes,
- break;
- }
- }
- +
- + printf("DEBUG: signed_weight = %llu\n", signed_weight);
- std::sort(seen.begin(), seen.end());
- for (std::size_t i = 1; i < seen.size(); i++) {
- if (seen[i] == seen[i - 1]) {
- @@ -656,6 +668,9 @@ td::Status check_block_signatures(const std::vector<ton::ValidatorDescr>& nodes,
- compute_node_id_short(nodes.at(seen[i]).key).to_hex());
- }
- }
- +
- + printf("DEBUG: checking 3 * %llu <= 2 * %llu \n", signed_weight, total_weight);
- + printf("DEBUG: checking %llu <= %llu \n", 3 * signed_weight, 2 * total_weight);
- if (3 * signed_weight <= 2 * total_weight) {
- return td::Status::Error(PSTRING() << "insufficient total signature weight: only " << signed_weight << " out of "
- << total_weight);
- diff --git a/crypto/vm/cells/CellUsageTree.cpp b/crypto/vm/cells/CellUsageTree.cpp
- index 410b3fcd..eee26c1a 100644
- --- a/crypto/vm/cells/CellUsageTree.cpp
- +++ b/crypto/vm/cells/CellUsageTree.cpp
- @@ -23,6 +23,8 @@ namespace vm {
- // CellUsageTree::NodePtr
- //
- bool CellUsageTree::NodePtr::on_load(const td::Ref<vm::DataCell>& cell) const {
- + //WriteLockGuard<NonRecursiveRWLock> lock(tree_mtx);
- +
- auto tree = tree_weak_.lock();
- if (!tree) {
- return false;
- @@ -32,6 +34,8 @@ bool CellUsageTree::NodePtr::on_load(const td::Ref<vm::DataCell>& cell) const {
- }
- CellUsageTree::NodePtr CellUsageTree::NodePtr::create_child(unsigned ref_id) const {
- + //WriteLockGuard<NonRecursiveRWLock> lock(tree_mtx);
- +
- auto tree = tree_weak_.lock();
- if (!tree) {
- return {};
- @@ -40,6 +44,8 @@ CellUsageTree::NodePtr CellUsageTree::NodePtr::create_child(unsigned ref_id) con
- }
- bool CellUsageTree::NodePtr::is_from_tree(const CellUsageTree* master_tree) const {
- + //WriteLockGuard<NonRecursiveRWLock> lock(tree_mtx);
- +
- DCHECK(master_tree);
- auto tree = tree_weak_.lock();
- if (tree.get() != master_tree) {
- @@ -49,6 +55,8 @@ bool CellUsageTree::NodePtr::is_from_tree(const CellUsageTree* master_tree) cons
- }
- bool CellUsageTree::NodePtr::mark_path(CellUsageTree* master_tree) const {
- + //WriteLockGuard<NonRecursiveRWLock> lock(tree_mtx);
- +
- DCHECK(master_tree);
- auto tree = tree_weak_.lock();
- if (tree.get() != master_tree) {
- @@ -62,25 +70,29 @@ bool CellUsageTree::NodePtr::mark_path(CellUsageTree* master_tree) const {
- // CellUsageTree
- //
- CellUsageTree::NodePtr CellUsageTree::root_ptr() {
- + //WriteLockGuard<NonRecursiveRWLock> lock(nodes_mtx);
- return {shared_from_this(), 1};
- }
- -CellUsageTree::NodeId CellUsageTree::root_id() const {
- +CellUsageTree::NodeId CellUsageTree::root_id() {
- return 1;
- };
- -bool CellUsageTree::is_loaded(NodeId node_id) const {
- +bool CellUsageTree::is_loaded(NodeId node_id) {
- + std::lock_guard<std::recursive_mutex> lock(nodes_mtx);
- if (use_mark_) {
- return nodes_[node_id].has_mark;
- }
- return nodes_[node_id].is_loaded;
- }
- -bool CellUsageTree::has_mark(NodeId node_id) const {
- +bool CellUsageTree::has_mark(NodeId node_id) {
- + std::lock_guard<std::recursive_mutex> lock(nodes_mtx);
- return nodes_[node_id].has_mark;
- }
- void CellUsageTree::set_mark(NodeId node_id, bool mark) {
- + std::lock_guard<std::recursive_mutex> lock(nodes_mtx);
- if (node_id == 0) {
- return;
- }
- @@ -88,6 +100,7 @@ void CellUsageTree::set_mark(NodeId node_id, bool mark) {
- }
- void CellUsageTree::mark_path(NodeId node_id) {
- + std::lock_guard<std::recursive_mutex> lock(nodes_mtx);
- auto cur_node_id = get_parent(node_id);
- while (cur_node_id != 0) {
- if (has_mark(cur_node_id)) {
- @@ -99,19 +112,23 @@ void CellUsageTree::mark_path(NodeId node_id) {
- }
- CellUsageTree::NodeId CellUsageTree::get_parent(NodeId node_id) {
- + std::lock_guard<std::recursive_mutex> lock(nodes_mtx);
- return nodes_[node_id].parent;
- }
- CellUsageTree::NodeId CellUsageTree::get_child(NodeId node_id, unsigned ref_id) {
- + std::lock_guard<std::recursive_mutex> lock(nodes_mtx);
- DCHECK(ref_id < CellTraits::max_refs);
- return nodes_[node_id].children[ref_id];
- }
- void CellUsageTree::set_use_mark_for_is_loaded(bool use_mark) {
- + std::lock_guard<std::recursive_mutex> lock(nodes_mtx);
- use_mark_ = use_mark;
- }
- void CellUsageTree::on_load(NodeId node_id, const td::Ref<vm::DataCell>& cell) {
- + std::lock_guard<std::recursive_mutex> lock(nodes_mtx);
- if (nodes_[node_id].is_loaded) {
- return;
- }
- @@ -122,6 +139,7 @@ void CellUsageTree::on_load(NodeId node_id, const td::Ref<vm::DataCell>& cell) {
- }
- CellUsageTree::NodeId CellUsageTree::create_child(NodeId node_id, unsigned ref_id) {
- + std::lock_guard<std::recursive_mutex> lock(nodes_mtx);
- DCHECK(ref_id < CellTraits::max_refs);
- NodeId res = nodes_[node_id].children[ref_id];
- if (res) {
- @@ -133,6 +151,7 @@ CellUsageTree::NodeId CellUsageTree::create_child(NodeId node_id, unsigned ref_i
- }
- CellUsageTree::NodeId CellUsageTree::create_node(NodeId parent) {
- + std::lock_guard<std::recursive_mutex> lock(nodes_mtx);
- NodeId res = static_cast<NodeId>(nodes_.size());
- nodes_.emplace_back();
- nodes_.back().parent = parent;
- diff --git a/crypto/vm/cells/CellUsageTree.h b/crypto/vm/cells/CellUsageTree.h
- index af0f21f5..03af746e 100644
- --- a/crypto/vm/cells/CellUsageTree.h
- +++ b/crypto/vm/cells/CellUsageTree.h
- @@ -24,8 +24,372 @@
- #include "td/utils/logging.h"
- #include <functional>
- +
- +
- +
- namespace vm {
- +
- +#include <cassert>
- +#include <atomic>
- +//#include <random>
- +//#include "trbitfield.h"
- +
- +//preshing's semaphore
- +
- +#if defined(_WIN32)
- +//---------------------------------------------------------
- +// Semaphore (Windows)
- +//---------------------------------------------------------
- +
- +#include <windows.h>
- +#undef min
- +#undef max
- +
- +class Semaphore
- +{
- +private:
- + HANDLE m_hSema;
- +
- + Semaphore(const Semaphore& other) = delete;
- + Semaphore& operator=(const Semaphore& other) = delete;
- +
- +public:
- + Semaphore(int initialCount = 0)
- + {
- + assert(initialCount >= 0);
- + m_hSema = CreateSemaphore(NULL, initialCount, MAXLONG, NULL);
- + }
- +
- + ~Semaphore()
- + {
- + CloseHandle(m_hSema);
- + }
- +
- + void wait()
- + {
- + WaitForSingleObject(m_hSema, INFINITE);
- + }
- +
- + void signal(int count = 1)
- + {
- + ReleaseSemaphore(m_hSema, count, NULL);
- + }
- +};
- +
- +
- +#elif defined(__MACH__)
- +//---------------------------------------------------------
- +// Semaphore (Apple iOS and OSX)
- +// Can't use POSIX semaphores due to http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html
- +//---------------------------------------------------------
- +
- +#include <mach/mach.h>
- +
- +class Semaphore
- +{
- +private:
- + semaphore_t m_sema;
- +
- + Semaphore(const Semaphore& other) = delete;
- + Semaphore& operator=(const Semaphore& other) = delete;
- +
- +public:
- + Semaphore(int initialCount = 0)
- + {
- + assert(initialCount >= 0);
- + semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
- + }
- +
- + ~Semaphore()
- + {
- + semaphore_destroy(mach_task_self(), m_sema);
- + }
- +
- + void wait()
- + {
- + semaphore_wait(m_sema);
- + }
- +
- + void signal()
- + {
- + semaphore_signal(m_sema);
- + }
- +
- + void signal(int count)
- + {
- + while (count-- > 0)
- + {
- + semaphore_signal(m_sema);
- + }
- + }
- +};
- +
- +
- +#elif defined(__unix__)
- +//---------------------------------------------------------
- +// Semaphore (POSIX, Linux)
- +//---------------------------------------------------------
- +
- +#include <semaphore.h>
- +
- +class Semaphore
- +{
- +private:
- + sem_t m_sema;
- +
- + Semaphore(const Semaphore& other) = delete;
- + Semaphore& operator=(const Semaphore& other) = delete;
- +
- +public:
- + Semaphore(int initialCount = 0)
- + {
- + assert(initialCount >= 0);
- + sem_init(&m_sema, 0, initialCount);
- + }
- +
- + ~Semaphore()
- + {
- + sem_destroy(&m_sema);
- + }
- +
- + void wait()
- + {
- + // http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error
- + int rc;
- + do
- + {
- + rc = sem_wait(&m_sema);
- + }
- + while (rc == -1 && errno == EINTR);
- + }
- +
- + void signal()
- + {
- + sem_post(&m_sema);
- + }
- +
- + void signal(int count)
- + {
- + while (count-- > 0)
- + {
- + sem_post(&m_sema);
- + }
- + }
- +};
- +
- +
- +#else
- +
- +#error Unsupported platform!
- +
- +#endif
- +
- +
- +//---------------------------------------------------------
- +// LightweightSemaphore
- +//---------------------------------------------------------
- +class LightweightSemaphore
- +{
- +private:
- + std::atomic<int> m_count;
- + Semaphore m_sema;
- +
- + void waitWithPartialSpinning()
- + {
- + int oldCount;
- + // Is there a better way to set the initial spin count?
- + // If we lower it to 1000, testBenaphore becomes 15x slower on my Core i7-5930K Windows PC,
- + // as threads start hitting the kernel semaphore.
- + int spin = 10000;
- + while (spin--)
- + {
- + oldCount = m_count.load(std::memory_order_relaxed);
- + if ((oldCount > 0) && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire))
- + return;
- + std::atomic_signal_fence(std::memory_order_acquire); // Prevent the compiler from collapsing the loop.
- + }
- + oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
- + if (oldCount <= 0)
- + {
- + m_sema.wait();
- + }
- + }
- +
- +public:
- + LightweightSemaphore(int initialCount = 0) : m_count(initialCount)
- + {
- + assert(initialCount >= 0);
- + }
- +
- + bool tryWait()
- + {
- + int oldCount = m_count.load(std::memory_order_relaxed);
- + return (oldCount > 0 && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire));
- + }
- +
- + void wait()
- + {
- + if (!tryWait())
- + waitWithPartialSpinning();
- + }
- +
- + void signal(int count = 1)
- + {
- + int oldCount = m_count.fetch_add(count, std::memory_order_release);
- + int toRelease = -oldCount < count ? -oldCount : count;
- + if (toRelease > 0)
- + {
- + m_sema.signal(toRelease);
- + }
- + }
- +};
- +
- +
- +typedef LightweightSemaphore DefaultSemaphoreType;
- +/*
- +//---------------------------------------------------------
- +// NonRecursiveRWLock
- +//---------------------------------------------------------
- +class NonRecursiveRWLock
- +{
- +private:
- + BEGIN_BITFIELD_TYPE(Status, uint32_t)
- + ADD_BITFIELD_MEMBER(readers, 0, 10)
- + ADD_BITFIELD_MEMBER(waitToRead, 10, 10)
- + ADD_BITFIELD_MEMBER(writers, 20, 10)
- + END_BITFIELD_TYPE()
- +
- + std::atomic<uint32_t> m_status;
- + DefaultSemaphoreType m_readSema;
- + DefaultSemaphoreType m_writeSema;
- +
- +public:
- + NonRecursiveRWLock() : m_status(0) {}
- +
- + void lockReader()
- + {
- + Status oldStatus = m_status.load(std::memory_order_relaxed);
- + Status newStatus;
- + do
- + {
- + newStatus = oldStatus;
- + if (oldStatus.writers > 0)
- + {
- + newStatus.waitToRead++;
- + }
- + else
- + {
- + newStatus.readers++;
- + }
- + // CAS until successful. On failure, oldStatus will be updated with the latest value.
- + }
- + while (!m_status.compare_exchange_weak(oldStatus, newStatus,
- + std::memory_order_acquire, std::memory_order_relaxed));
- +
- + if (oldStatus.writers > 0)
- + {
- + m_readSema.wait();
- + }
- + }
- +
- + void unlockReader()
- + {
- + Status oldStatus = m_status.fetch_sub(Status().readers.one(), std::memory_order_release);
- + assert(oldStatus.readers > 0);
- + if (oldStatus.readers == 1 && oldStatus.writers > 0)
- + {
- + m_writeSema.signal();
- + }
- + }
- +
- + void lockWriter()
- + {
- + Status oldStatus = m_status.fetch_add(Status().writers.one(), std::memory_order_acquire);
- + assert(oldStatus.writers + 1 <= Status().writers.maximum());
- + if (oldStatus.readers > 0 || oldStatus.writers > 0)
- + {
- + m_writeSema.wait();
- + }
- + }
- +
- + void unlockWriter()
- + {
- + Status oldStatus = m_status.load(std::memory_order_relaxed);
- + Status newStatus;
- + uint32_t waitToRead = 0;
- + do
- + {
- + assert(oldStatus.readers == 0);
- + newStatus = oldStatus;
- + newStatus.writers--;
- + waitToRead = oldStatus.waitToRead;
- + if (waitToRead > 0)
- + {
- + newStatus.waitToRead = 0;
- + newStatus.readers = waitToRead;
- + }
- + // CAS until successful. On failure, oldStatus will be updated with the latest value.
- + }
- + while (!m_status.compare_exchange_weak(oldStatus, newStatus,
- + std::memory_order_release, std::memory_order_relaxed));
- +
- + if (waitToRead > 0)
- + {
- + m_readSema.signal(waitToRead);
- + }
- + else if (oldStatus.writers > 1)
- + {
- + m_writeSema.signal();
- + }
- + }
- +};
- +
- +
- +//---------------------------------------------------------
- +// ReadLockGuard
- +//---------------------------------------------------------
- +template <class LockType>
- +class ReadLockGuard
- +{
- +private:
- + LockType& m_lock;
- +
- +public:
- + ReadLockGuard(LockType& lock) : m_lock(lock)
- + {
- + m_lock.lockReader();
- + }
- +
- + ~ReadLockGuard()
- + {
- + m_lock.unlockReader();
- + }
- +};
- +
- +
- +//---------------------------------------------------------
- +// WriteLockGuard
- +//---------------------------------------------------------
- +template <class LockType>
- +class WriteLockGuard
- +{
- +private:
- + LockType& m_lock;
- +
- +public:
- + WriteLockGuard(LockType& lock) : m_lock(lock)
- + {
- + m_lock.lockWriter();
- + }
- +
- + ~WriteLockGuard()
- + {
- + m_lock.unlockWriter();
- + }
- +};*/
- +
- +
- class DataCell;
- class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> {
- @@ -53,9 +417,9 @@ class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> {
- };
- NodePtr root_ptr();
- - NodeId root_id() const;
- - bool is_loaded(NodeId node_id) const;
- - bool has_mark(NodeId node_id) const;
- + NodeId root_id();
- + bool is_loaded(NodeId node_id);
- + bool has_mark(NodeId node_id);
- void set_mark(NodeId node_id, bool mark = true);
- void mark_path(NodeId node_id);
- NodeId get_parent(NodeId node_id);
- @@ -77,6 +441,8 @@ class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> {
- bool use_mark_{false};
- std::vector<Node> nodes_{2};
- std::function<void(const td::Ref<vm::DataCell>&)> cell_load_callback_;
- +
- + std::recursive_mutex nodes_mtx;
- void on_load(NodeId node_id, const td::Ref<vm::DataCell>& cell);
- NodeId create_node(NodeId parent);
- diff --git a/crypto/vm/cells/MerkleProof.cpp b/crypto/vm/cells/MerkleProof.cpp
- index 26dff787..8e74ed0f 100644
- --- a/crypto/vm/cells/MerkleProof.cpp
- +++ b/crypto/vm/cells/MerkleProof.cpp
- @@ -23,17 +23,187 @@
- #include "td/utils/HashMap.h"
- #include "td/utils/HashSet.h"
- +#include <mutex>
- +#include <queue>
- +#include <thread>
- +
- +//#define PUSH_THREAD_POOL_DBG_ENABLED
- +
- +class ContestValidateQuery;
- namespace vm {
- namespace detail {
- -class MerkleProofImpl {
- - public:
- - explicit MerkleProofImpl(MerkleProof::IsPrunnedFunction is_prunned) : is_prunned_(std::move(is_prunned)) {
- +
- +push_thread_pool_data push_thread_pool::task_pushed_data[8];
- +std::atomic<int> push_thread_pool::thread_ready_bitset = { 0xFF }; //reset to all threads available
- +std::thread push_thread_pool::worker_threads[8];
- +
- +
- +uint32_t push_thread_pool::try_find_and_set_thread_work(std::function<void()> in_data_exec_lambda, thread_pool_out_data* out_data_arr)
- +{
- + int old_bitset = thread_ready_bitset.load(std::memory_order_relaxed);
- +
- + int thread_idx = 0;
- + for(;;) //bit search in a CAS loop
- + {
- + if(old_bitset == 0)
- + {
- + return 0xFF; //no ready threads
- + }
- +
- + thread_idx = __builtin_ctz(old_bitset);
- + int new_bitset = old_bitset & ~( 1 << thread_idx );
- +
- + //acq rel on success to make sure there is no reordering of data modification going after the cas
- + if(thread_ready_bitset.compare_exchange_weak(old_bitset, new_bitset, std::memory_order_acq_rel, std::memory_order_relaxed))
- + {
- + break;
- + }
- +
- + //compare exchange failed, likely because bitset has changed in the meantime, retry operation
- + }
- +
- + //TODO: push data for dfs
- + task_pushed_data[thread_idx].in_data_exec_lambda = in_data_exec_lambda;
- + //task_pushed_data[thread_idx].in_data_cell = in_dat_cell;
- + //task_pushed_data[thread_idx].in_data_merkle_depth = in_dat_merkle_depth;
- +
- + //it's assumed that we won't delete memory it points to until this function is done, which is reasonable
- + task_pushed_data[thread_idx].out_data_memptr = out_data_arr + thread_idx;
- +
- + //now that we pushed data, set flag and notify thread
- +
- + //also reset out flag, store after acts as a barrier for it to not go under
- + out_data_arr[thread_idx].out_data_flag.store(0, std::memory_order_relaxed);
- + task_pushed_data[thread_idx].flag.store(1, std::memory_order_release); //release to make sure data is flushed, no reorder
- + task_pushed_data[thread_idx].sema.signal();
- +
- +#ifdef PUSH_THREAD_POOL_DBG_ENABLED
- + printf("successfully pushed work, t_idx: %d\n", thread_idx);
- +#endif
- + return thread_idx; //success
- +}
- +
- +
- +void push_thread_pool::tpool_thread_main(uint32_t thread_idx)
- +{
- + int flag_expected = 1;
- +
- + while (true) {
- + //TODO: potentially some spinning before wait to reduce switching
- +
- + flag_expected = 1;
- +
- + if(task_pushed_data[thread_idx].flag.compare_exchange_strong(flag_expected, 0, std::memory_order_acquire))
- + {
- + //flag was 1, execute func, because of acquire - release semantics we can be sure that in_data is visible here
- +
- + //ContestValidateQuery* context_obj = task_pushed_data[thread_idx].in_data_context_obj;
- + //Ref<Cell> ret_cell = context_obj->dfs(task_pushed_data[thread_idx].in_data_cell, task_pushed_data[thread_idx].in_data_merkle_depth);
- +
- + std::function<void()> cur_work = task_pushed_data[thread_idx].in_data_exec_lambda;
- + cur_work();
- +
- + thread_pool_out_data* out_data_ptr = task_pushed_data[thread_idx].out_data_memptr;
- + //out_data_ptr->out_data_cell = ret_cell;
- + out_data_ptr->out_data_flag.store(1, std::memory_order_release); //release to make sure data is flushed, no reorder from before to after
- + out_data_ptr->out_data_sema.signal();
- +
- + //TODO: semaphore reinit?
- + }
- + else
- + {
- + //was 0, wait for signal
- + thread_ready_bitset.fetch_or( 1 << thread_idx, std::memory_order_release);
- +
- + task_pushed_data[thread_idx].sema.wait();
- + }
- +
- + }
- +}
- +
- +void push_thread_pool::tpool_init()
- +{
- +#ifdef PUSH_THREAD_POOL_DBG_ENABLED
- + printf("initializing push_thread_pool\n");
- +#endif
- + thread_ready_bitset.store(0xFF, std::memory_order_relaxed);
- +
- + for(int idx = 0; idx < 8; ++idx)
- + {
- + std::thread worker_th(tpool_thread_main, idx);
- +
- + worker_threads[idx] = std::move(worker_th);
- + }
- +}
- +
- +void push_thread_pool::tpool_prepare()
- +{
- +#ifdef PUSH_THREAD_POOL_DBG_ENABLED
- + printf("preparing push_thread_pool for reuse\n");
- +#endif
- + thread_ready_bitset.store(0xFF, std::memory_order_relaxed);
- +
- + for(int idx = 0; idx < 8; ++idx)
- + {
- + //task_pushed_data[idx].in_data_context_obj = 0;
- + //task_pushed_data[idx].in_data_merkle_depth = 0;
- + //task_pushed_data[idx].out_data_memptr = 0;
- + task_pushed_data[idx].flag.store(0, std::memory_order_relaxed);
- + }
- +}
- +
- +
- +//Ref<Cell> out_data_cell;
- +//std::atomic<int> out_data_flag = { 0 };
- +//Semaphore out_data_sema;
- +
- +void push_thread_pool::tpool_thread_wait_for_out_data(thread_pool_out_data* out_data_ptr)
- +{
- + int flag_expected = 1;
- +
- + while (true) {
- + //TODO: initial spin to reduce switches
- +
- + flag_expected = 1;
- +
- + if(out_data_ptr->out_data_flag.compare_exchange_strong(flag_expected, 0, std::memory_order_acquire))
- + {
- + //out data flag was 1, meaning that because of release->acquire sync we definitely got out_data that was written before flag release store
- +
- + return; //out_data_ptr->out_data_cell;
- + }
- + else
- + {
- + //printf("thread is not done..\n");
- + out_data_ptr->out_data_sema.wait();
- + }
- +
- + }
- +}
- +
- +void push_thread_pool::tpool_wait_for_all_threads(thread_pool_out_data* out_data, uint8_t* thread_was_used)
- +{
- + for(int idx = 0; idx < 8; ++idx)
- + {
- + if(thread_was_used[idx])
- + {
- + tpool_thread_wait_for_out_data(out_data + idx);
- + }
- }
- - explicit MerkleProofImpl(CellUsageTree *usage_tree) : usage_tree_(usage_tree) {
- +}
- +
- +
- +
- +
- + MerkleProofImpl::MerkleProofImpl(MerkleProof::IsPrunnedFunction is_prunned) : is_prunned_(std::move(is_prunned)) {
- + push_thread_pool::tpool_prepare();
- + }
- + MerkleProofImpl::MerkleProofImpl(CellUsageTree *usage_tree) : usage_tree_(usage_tree) {
- + push_thread_pool::tpool_prepare();
- }
- - Ref<Cell> create_from(Ref<Cell> cell) {
- + Ref<Cell> MerkleProofImpl::create_from(Ref<Cell> cell) {
- if (!is_prunned_) {
- CHECK(usage_tree_);
- dfs_usage_tree(cell, usage_tree_->root_id());
- @@ -48,28 +218,57 @@ class MerkleProofImpl {
- }
- }
- - private:
- - using Key = std::pair<Cell::Hash, int>;
- - td::HashMap<Key, Ref<Cell>> cells_;
- - td::HashSet<Cell::Hash> visited_cells_;
- - CellUsageTree *usage_tree_{nullptr};
- - MerkleProof::IsPrunnedFunction is_prunned_;
- - void dfs_usage_tree(Ref<Cell> cell, CellUsageTree::NodeId node_id) {
- + void MerkleProofImpl::dfs_usage_tree(Ref<Cell> cell, CellUsageTree::NodeId node_id) {
- if (!usage_tree_->is_loaded(node_id)) {
- return;
- }
- visited_cells_.insert(cell->get_hash());
- CellSlice cs(NoVm(), cell);
- + //printf("dfs_tree_refs: %d\n", cs.size_refs()); //2,3, havent seen more in logs
- for (unsigned i = 0; i < cs.size_refs(); i++) {
- dfs_usage_tree(cs.prefetch_ref(i), usage_tree_->get_child(node_id, i));
- }
- }
- - Ref<Cell> dfs(Ref<Cell> cell, int merkle_depth) {
- +//ORIG DFS
- +Ref<Cell> MerkleProofImpl::dfs(Ref<Cell> cell, int merkle_depth) {
- + CHECK(cell.not_null());
- + Key key{cell->get_hash(), merkle_depth};
- + {
- + auto it = cells_.find(key);
- + if (it != cells_.end()) {
- + CHECK(it->second.not_null());
- + return it->second;
- + }
- + }
- +
- + if (is_prunned_(cell)) {
- + auto res = CellBuilder::create_pruned_branch(cell, merkle_depth + 1);
- + CHECK(res.not_null());
- + cells_.emplace(key, res);
- + return res;
- + }
- + CellSlice cs(NoVm(), cell);
- + int children_merkle_depth = cs.child_merkle_depth(merkle_depth);
- + CellBuilder cb;
- + cb.store_bits(cs.fetch_bits(cs.size()));
- + for (unsigned i = 0; i < cs.size_refs(); i++) {
- + cb.store_ref(dfs(cs.prefetch_ref(i), children_merkle_depth));
- + }
- + auto res = cb.finalize(cs.is_special());
- + CHECK(res.not_null());
- + cells_.emplace(key, res);
- + return res;
- +}
- +//DFS END
- +
- +/*
- + Ref<Cell> MerkleProofImpl::dfs(Ref<Cell> cell, int merkle_depth) {
- CHECK(cell.not_null());
- Key key{cell->get_hash(), merkle_depth};
- {
- + std::lock_guard<std::mutex> clock(cells_hm_mutex);
- auto it = cells_.find(key);
- if (it != cells_.end()) {
- CHECK(it->second.not_null());
- @@ -80,22 +279,82 @@ class MerkleProofImpl {
- if (is_prunned_(cell)) {
- auto res = CellBuilder::create_pruned_branch(cell, merkle_depth + 1);
- CHECK(res.not_null());
- - cells_.emplace(key, res);
- + {
- + std::lock_guard<std::mutex> clock(cells_hm_mutex);
- + cells_.emplace(key, res);
- + }
- return res;
- }
- CellSlice cs(NoVm(), cell);
- int children_merkle_depth = cs.child_merkle_depth(merkle_depth);
- CellBuilder cb;
- cb.store_bits(cs.fetch_bits(cs.size()));
- - for (unsigned i = 0; i < cs.size_refs(); i++) {
- - cb.store_ref(dfs(cs.prefetch_ref(i), children_merkle_depth));
- +
- + //printf("dfs_refs: %d, children_merkle_depth: %d\n", cs.size_refs(), children_merkle_depth);
- + //for (unsigned i = 0; i < cs.size_refs(); i++) {
- + //for (unsigned i = 1; i < cs.size_refs(); i++) {
- + //should be dispatched to other threads
- + //after 0s dfs we put wait for signal from other threads (so after it finishes it waits for other threads)
- +
- + //we stop forking if we reached hardware concurrency, so we're not destroying performance with switches
- + //cb.store_ref(dfs(cs.prefetch_ref(i), children_merkle_depth));
- + //}
- +
- + if(cs.size_refs() > 0)
- + {
- + unsigned forked_cell_futures_len = cs.size_refs() - 1;
- +
- +#ifdef PUSH_THREAD_POOL_DBG_ENABLED
- + printf("creating %u forks\n", forked_cell_futures_len);
- +#endif
- + thread_pool_out_data forked_cell_futures[forked_cell_futures_len];
- + bool forked_cell_futures_success_bools[forked_cell_futures_len];
- +
- + for (unsigned i = 1; i < cs.size_refs(); i++) {
- +#ifdef PUSH_THREAD_POOL_DBG_ENABLED
- + printf("dispatched %u\n", i - 1);
- +#endif
- +
- + forked_cell_futures_success_bools[i - 1] = push_thread_pool::try_find_and_set_thread_work(this, cs.prefetch_ref(i), children_merkle_depth, forked_cell_futures + (i - 1));
- + //if failed to push into pool, no free threads
- + //do it in this thread later
- +
- + //forked_cell_futures[i - 1] = tpool.submit(&MerkleProofImpl::dfs, this, cs.prefetch_ref(i), children_merkle_depth);
- + }
- + cb.store_ref(dfs(cs.prefetch_ref(0), children_merkle_depth));
- + //when we get those tasks back, store refs
- + for(unsigned ix = 0; ix < forked_cell_futures_len; ++ix)
- + {
- + bool has_work_been_delegated = forked_cell_futures_success_bools[ix];
- + if(has_work_been_delegated)
- + {
- +#ifdef PUSH_THREAD_POOL_DBG_ENABLED
- + printf("waiting for result from out_data_memptr[%d]..\n", ix);
- +#endif
- + cb.store_ref(push_thread_pool::tpool_thread_wait_for_out_data(forked_cell_futures + ix));
- +#ifdef PUSH_THREAD_POOL_DBG_ENABLED
- + printf("got result from out_data_memptr %u\n", ix);
- +#endif
- + }
- + else
- + {
- + cb.store_ref(dfs(cs.prefetch_ref(ix + 1), children_merkle_depth));
- +#ifdef PUSH_THREAD_POOL_DBG_ENABLED
- + printf("calculated result in current thread, %u\n", ix);
- +#endif
- + }
- + }
- }
- +
- auto res = cb.finalize(cs.is_special());
- CHECK(res.not_null());
- - cells_.emplace(key, res);
- +
- + {
- + std::lock_guard<std::mutex> clock(cells_hm_mutex);
- + cells_.emplace(key, res);
- + }
- return res;
- - }
- -};
- + }*/
- } // namespace detail
- Ref<Cell> MerkleProof::generate_raw(Ref<Cell> cell, IsPrunnedFunction is_prunned) {
- diff --git a/crypto/vm/cells/MerkleProof.h b/crypto/vm/cells/MerkleProof.h
- index fc2cb6eb..f84bb7df 100644
- --- a/crypto/vm/cells/MerkleProof.h
- +++ b/crypto/vm/cells/MerkleProof.h
- @@ -20,8 +20,12 @@
- #include "vm/cells/Cell.h"
- #include "td/utils/buffer.h"
- +#include "td/utils/HashMap.h"
- +#include "td/utils/HashSet.h"
- +
- #include <utility>
- #include <functional>
- +#include <thread>
- namespace vm {
- @@ -51,6 +55,85 @@ class MerkleProof {
- static Ref<Cell> combine_fast_raw(Ref<Cell> a, Ref<Cell> b);
- };
- +namespace detail {
- +
- +
- +
- +class ContestValidateQuery;
- +
- +class alignas(128) thread_pool_out_data
- +{
- +public:
- + //Ref<Cell> out_data_cell;
- +
- + std::atomic<int> out_data_flag = { 0 };
- + Semaphore out_data_sema;
- +};
- +
- +
- +//64 is based on x86's hardware destructive interference size, should also be 128 for arm
- +class alignas(128) push_thread_pool_data
- +{
- +public:
- +
- + //we know we will do dfs, just store data
- + //ContestValidateQuery* in_data_context_obj = 0;
- + //const StdSmcAddress& in_data_acc_addr;
- + //Ref<vm::CellSlice> in_data_acc_blk_root = 0;
- +
- + thread_pool_out_data* out_data_memptr = 0;
- + std::function<void()> in_data_exec_lambda;
- +
- + std::atomic<int> flag = { 0 };
- + Semaphore sema;
- +};
- +
- +class push_thread_pool
- +{
- +public:
- + static push_thread_pool_data task_pushed_data[8];
- +
- + static std::atomic<int> thread_ready_bitset; //we use this for search from pusher's perspective and we use separated flag values for false sharing prevention
- +
- + //find first bit set
- + //set bit through | 1 << bit_num_from_zero
- + //check bit through __builtin_ctz(bitset), if bitset is 0 it would be ub
- +
- + static std::thread worker_threads[8];
- +
- + static uint32_t try_find_and_set_thread_work(std::function<void()> in_data_exec_lambda, thread_pool_out_data* out_data_arr);
- + static void tpool_thread_main(uint32_t thread_idx);
- +
- + static void tpool_init();
- + static void tpool_prepare(); //for reuse
- +
- + static void tpool_thread_wait_for_out_data(thread_pool_out_data* out_data_ptr);
- + static void tpool_wait_for_all_threads(thread_pool_out_data* out_data, uint8_t* thread_was_used);
- +};
- +
- +class MerkleProofImpl {
- +public:
- + explicit MerkleProofImpl(MerkleProof::IsPrunnedFunction is_prunned);
- + explicit MerkleProofImpl(CellUsageTree *usage_tree);
- +
- + Ref<Cell> create_from(Ref<Cell> cell);
- +
- + using Key = std::pair<Cell::Hash, int>;
- + td::HashMap<Key, Ref<Cell>> cells_;
- + td::HashSet<Cell::Hash> visited_cells_;
- + CellUsageTree *usage_tree_{nullptr};
- + MerkleProof::IsPrunnedFunction is_prunned_;
- +
- + std::mutex cells_hm_mutex;
- + std::mutex visited_cells_mutex;
- + std::mutex usage_tree_mutex;
- +
- + void dfs_usage_tree(Ref<Cell> cell, CellUsageTree::NodeId node_id);
- +
- + Ref<Cell> dfs(Ref<Cell> cell, int merkle_depth);
- +};
- +}
- +
- class MerkleProofBuilder {
- std::shared_ptr<CellUsageTree> usage_tree;
- Ref<vm::Cell> orig_root, usage_root;
Advertisement
Add Comment
Please, Sign In to add comment