diff --git a/crypto/block/transaction.cpp b/crypto/block/transaction.cpp index b19f92c9..e968cc8e 100644 --- a/crypto/block/transaction.cpp +++ b/crypto/block/transaction.cpp @@ -24,6 +24,7 @@ #include "td/utils/uint128.h" #include "ton/ton-shard.h" #include "vm/vm.h" +#include "td/utils/Timer.h" namespace { class StringLoggerTail : public td::LogInterface { @@ -345,7 +346,7 @@ bool Account::unpack(Ref shard_account, Ref extra, block::gen::AccountStorage::Record storage; if (!(tlb::unpack_exact(acc_cs, acc) && (my_addr = acc.addr).not_null() && unpack_address(acc.addr.write()) && compute_my_addr() && unpack_storage_info(acc.storage_stat.write()) && - tlb::csr_unpack(std::move(acc.storage), storage) && + tlb::csr_unpack(this->storage = std::move(acc.storage), storage) && std::max(storage.last_trans_lt, 1ULL) > acc_info.last_trans_lt && balance.unpack(std::move(storage.balance)))) { return false; } @@ -1049,7 +1050,9 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) { LOG(DEBUG) << "starting VM"; cp.vm_init_state_hash = vm.get_state_hash(); + td::Timer timer; cp.exit_code = ~vm.run(); + double elapsed = timer.elapsed(); LOG(DEBUG) << "VM terminated with exit code " << cp.exit_code; cp.out_of_gas = (cp.exit_code == ~(int)vm::Excno::out_of_gas); cp.vm_final_state_hash = vm.get_final_state_hash(cp.exit_code); @@ -1065,7 +1068,8 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) { } LOG(INFO) << "steps: " << vm.get_steps_count() << " gas: used=" << gas.gas_consumed() << ", max=" << gas.gas_max << ", limit=" << gas.gas_limit << ", credit=" << gas.gas_credit; - LOG(INFO) << "out_of_gas=" << cp.out_of_gas << ", accepted=" << cp.accepted << ", success=" << cp.success; + LOG(INFO) << "out_of_gas=" << cp.out_of_gas << ", accepted=" << cp.accepted << ", success=" << cp.success + << ", time=" << elapsed << "s"; if (logger != nullptr) { cp.vm_log = logger->get_log(); } @@ -1930,6 +1934,32 @@ bool Account::store_acc_status(vm::CellBuilder& cb, int acc_status) const { return cb.store_long_bool(v, 2); } +static td::optional try_update_storage_stat(const vm::CellStorageStat& old_stat, + td::Ref old_cs, + td::Ref new_cell) { + if (old_stat.cells == 0 || old_cs.is_null()) { + return {}; + } + vm::CellSlice new_cs = vm::CellSlice(vm::NoVm(), new_cell); + if (old_cs->size_refs() != new_cs.size_refs()) { + return {}; + } + for (unsigned i = 0; i < old_cs->size_refs(); ++i) { + if (old_cs->prefetch_ref(i)->get_hash() != new_cs.prefetch_ref(i)->get_hash()) { + return {}; + } + } + if (old_stat.bits < old_cs->size()) { + return {}; + } + + vm::CellStorageStat new_stat; + new_stat.cells = old_stat.cells; + new_stat.bits = old_stat.bits - old_cs->size() + new_cs.size(); + new_stat.public_cells = old_stat.public_cells; + return new_stat; +} + bool Transaction::compute_state() { if (new_total_state.not_null()) { return true; @@ -1991,6 +2021,7 @@ bool Transaction::compute_state() { // code:(Maybe ^Cell) data:(Maybe ^Cell) library:(HashmapE 256 SimpleLib) } auto storage = cb.finalize(); + new_storage = td::Ref(true, vm::NoVm(), storage); if (si_pos) { auto cs_ref = load_cell_slice_ref(storage); CHECK(cs_ref.unique_write().skip_ext(si_pos)); @@ -1999,7 +2030,16 @@ bool Transaction::compute_state() { new_inner_state.clear(); } vm::CellStorageStat& stats = new_storage_stat; - CHECK(stats.compute_used_storage(Ref(storage))); + auto new_stats = try_update_storage_stat(account.storage_stat, account.storage, storage); + if (new_stats) { + stats = new_stats.unwrap(); + } else { + td::Timer timer; + CHECK(stats.compute_used_storage(Ref(storage))); + if (timer.elapsed() > 0.1) { + LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s"; + } + } CHECK(cb.store_long_bool(1, 1) // account$1 && cb.append_cellslice_bool(account.my_addr) // addr:MsgAddressInt && block::store_UInt7(cb, stats.cells) // storage_used$_ cells:(VarUInteger 7) @@ -2308,6 +2348,7 @@ Ref Transaction::commit(Account& acc) { acc.last_trans_hash_ = root->get_hash().bits(); acc.last_paid = last_paid; acc.storage_stat = new_storage_stat; + acc.storage = new_storage; acc.balance = std::move(balance); acc.due_payment = std::move(due_payment); acc.total_state = std::move(new_total_state); diff --git a/crypto/block/transaction.h b/crypto/block/transaction.h index 75f524ec..6c9b9772 100644 --- a/crypto/block/transaction.h +++ b/crypto/block/transaction.h @@ -237,6 +237,7 @@ struct Account { td::RefInt256 due_payment; Ref orig_total_state; // ^Account Ref total_state; // ^Account + Ref storage; // AccountStorage Ref inner_state; // StateInit ton::Bits256 state_hash; // hash of StateInit for frozen accounts Ref code, data, library, orig_library; @@ -324,6 +325,7 @@ struct Transaction { ton::UnixTime last_paid; Ref root; Ref new_total_state; + Ref new_storage; Ref new_inner_state; Ref new_code, new_data, new_library; Ref in_msg, in_msg_state;