From 80f42b181ef60ee015f5c4334e327b3acde5ccad Mon Sep 17 00:00:00 2001 From: kyonRay Date: Mon, 24 Feb 2025 17:36:34 +0800 Subject: [PATCH] (executor,scheduler): move update eoa nonce logic to scheduler. --- .../src/executive/TransactionExecutive.cpp | 25 ---------- .../src/executor/SwitchExecutorManager.h | 49 ++++++++++++------- .../src/executor/TransactionExecutor.cpp | 18 +++++++ .../src/executor/TransactionExecutor.h | 2 + .../libvm/TestTransactionExecutive.cpp | 31 +++++++++++- .../ParallelTransactionExecutorInterface.h | 2 + .../bcos-framework/ledger/LedgerInterface.h | 7 --- bcos-ledger/bcos-ledger/Ledger.cpp | 37 -------------- bcos-ledger/bcos-ledger/Ledger.h | 4 -- bcos-scheduler/src/BlockExecutive.cpp | 32 +++++++++++- bcos-scheduler/src/BlockExecutive.h | 2 + bcos-scheduler/src/SerialBlockExecutive.cpp | 3 ++ bcos-scheduler/test/mock/MockDmcExecutor.h | 3 +- bcos-scheduler/test/mock/MockExecutor.h | 2 + .../test/mock/MockExecutorForMessageDAG.h | 2 + .../client/ExecutorServiceClient.cpp | 7 ++- .../client/ExecutorServiceClient.h | 2 + 17 files changed, 132 insertions(+), 96 deletions(-) diff --git a/bcos-executor/src/executive/TransactionExecutive.cpp b/bcos-executor/src/executive/TransactionExecutive.cpp index cb70e4643d..cad239e7ef 100644 --- a/bcos-executor/src/executive/TransactionExecutive.cpp +++ b/bcos-executor/src/executive/TransactionExecutive.cpp @@ -77,33 +77,8 @@ CallParameters::UniquePtr TransactionExecutive::start(CallParameters::UniquePtr auto& callParameters = input; - bool updateEoaNonce = !callParameters->staticCall && callParameters->seq == 0 && - callParameters->transactionType != TransactionType::BCOSTransaction && - callParameters->origin == callParameters->senderAddress && - m_blockContext.features().get( - ledger::Features::Flag::bugfix_nonce_not_increase_when_revert); - auto origin = callParameters->origin; - auto nonce = callParameters->nonce; - auto message = execute(std::move(callParameters)); - if (updateEoaNonce) - { - // only increase the nonce of EOA - ledger::account::EVMAccount address(*m_blockContext.storage(), std::move(origin), - m_blockContext.features().get(ledger::Features::Flag::feature_raw_address)); - task::wait([](decltype(address) addr, u256 callNonce) -> task::Task { - if (!co_await ledger::account::exists(addr)) - { - co_await ledger::account::create(addr); - } - auto const nonceInStorage = co_await ledger::account::nonce(addr); - auto const storageNonce = u256(nonceInStorage.value_or("0")); - auto const newNonce = std::max(callNonce, storageNonce) + 1; - co_await ledger::account::setNonce(addr, newNonce.convert_to()); - }(std::move(address), nonce)); - } - message->contextID = contextID(); message->seq = seq(); message->hasContractTableChanged = m_hasContractTableChanged; diff --git a/bcos-executor/src/executor/SwitchExecutorManager.h b/bcos-executor/src/executor/SwitchExecutorManager.h index 791c585d28..4e0393a83d 100644 --- a/bcos-executor/src/executor/SwitchExecutorManager.h +++ b/bcos-executor/src/executor/SwitchExecutorManager.h @@ -255,25 +255,26 @@ class SwitchExecutorManager : public executor::ParallelTransactionExecutorInterf inputsVec->emplace_back(std::move(inputs[i])); } auto queryTime = utcTime(); - m_pool.enqueue([queryTime, executor = m_executor, contractAddress = std::move(contractAddress), - inputsVec, callback = std::move(callback)] { - auto waitInPoolCost = utcTime() - queryTime; - // create a holder - auto _holdExecutorCallback = - [queryTime, waitInPoolCost ,executorHolder = executor, callback = std::move(callback)]( - bcos::Error::UniquePtr error, - std::vector outputs) { - EXECUTOR_LOG(TRACE) << "Release executor holder executeTransactions" - << LOG_KV("ptr count", executorHolder.use_count()) - << LOG_KV("waitInPoolCost", waitInPoolCost) - << LOG_KV("costFromQuery", utcTime() - queryTime); - callback(std::move(error), std::move(outputs)); - }; + m_pool.enqueue( + [queryTime, executor = m_executor, contractAddress = std::move(contractAddress), + inputsVec, callback = std::move(callback)] { + auto waitInPoolCost = utcTime() - queryTime; + // create a holder + auto _holdExecutorCallback = + [queryTime, waitInPoolCost, executorHolder = executor, + callback = std::move(callback)](bcos::Error::UniquePtr error, + std::vector outputs) { + EXECUTOR_LOG(TRACE) << "Release executor holder executeTransactions" + << LOG_KV("ptr count", executorHolder.use_count()) + << LOG_KV("waitInPoolCost", waitInPoolCost) + << LOG_KV("costFromQuery", utcTime() - queryTime); + callback(std::move(error), std::move(outputs)); + }; - // execute the function - executor->executeTransactions( - contractAddress, *inputsVec, std::move(_holdExecutorCallback)); - }); + // execute the function + executor->executeTransactions( + contractAddress, *inputsVec, std::move(_holdExecutorCallback)); + }); } void preExecuteTransactions(int64_t schedulerTermId, @@ -685,6 +686,18 @@ class SwitchExecutorManager : public executor::ParallelTransactionExecutorInterf }); } + void updateEoaNonce(std::unordered_map const& nonceMap) override + { + if (hasStopped()) + { + std::string message = "updateEoaNonce: executor has been stopped"; + EXECUTOR_LOG(DEBUG) << message; + return; + } + + getAndNewExecutorIfNotExists()->updateEoaNonce(std::move(nonceMap)); + } + void stop() override { EXECUTOR_LOG(INFO) << "Try to stop SwitchExecutorManager"; diff --git a/bcos-executor/src/executor/TransactionExecutor.cpp b/bcos-executor/src/executor/TransactionExecutor.cpp index f3011730fc..ad71f897af 100644 --- a/bcos-executor/src/executor/TransactionExecutor.cpp +++ b/bcos-executor/src/executor/TransactionExecutor.cpp @@ -1169,6 +1169,24 @@ void TransactionExecutor::getHash(bcos::protocol::BlockNumber number, callback(nullptr, std::move(hash)); } +void TransactionExecutor::updateEoaNonce(std::unordered_map const& eoa2Nonce) +{ + if (m_blockContext->features().get( + ledger::Features::Flag::bugfix_nonce_not_increase_when_revert)) + { + for (auto&& [sender, nonce] : eoa2Nonce) + { + LEDGER_LOG(TRACE) << METRIC << LOG_DESC("updateEoaNonce") << LOG_KV("sender", sender) + << LOG_KV("nonce", nonce); + auto eoa = ledger::account::EVMAccount(*m_blockContext->storage(), sender, + m_blockContext->features().get(ledger::Features::Flag::feature_raw_address)); + auto nonceInStorage = task::syncWait(ledger::account::nonce(eoa)); + auto nonceToUpdate = std::max(u256(nonceInStorage.value_or("0")), u256(nonce)) + 1; + task::syncWait(ledger::account::setNonce(eoa, nonceToUpdate.convert_to())); + } + } +} + void TransactionExecutor::dagExecuteTransactions( gsl::span inputs, std::function callback) override; + void updateEoaNonce(std::unordered_map const& nonceMap) override; + void start() override { m_isRunning = true; } void stop() override; diff --git a/bcos-executor/test/unittest/libvm/TestTransactionExecutive.cpp b/bcos-executor/test/unittest/libvm/TestTransactionExecutive.cpp index 188125e211..1be231a188 100644 --- a/bcos-executor/test/unittest/libvm/TestTransactionExecutive.cpp +++ b/bcos-executor/test/unittest/libvm/TestTransactionExecutive.cpp @@ -66,6 +66,14 @@ class TransactionExecutiveFixture : public TransactionFixture auto result = executePromise.get_future().get(); BOOST_CHECK_EQUAL(result->status(), 0); + + if (type != TransactionType::BCOSTransaction) + { + std::unordered_map eoaNonceMap; + eoaNonceMap.emplace(sender.hex(), toQuantity(nonce)); + executor->updateEoaNonce(std::move(eoaNonceMap)); + } + commitBlock(blockNumber); auto const nonceOfEoa = task::syncWait(bcos::ledger::account::nonce(eoa)); @@ -74,7 +82,6 @@ class TransactionExecutiveFixture : public TransactionFixture auto const nonceOfContract = task::syncWait(bcos::ledger::account::nonce(contractAddress)); if (type == TransactionType::BCOSTransaction) { - BOOST_CHECK_EQUAL(nonceOfEoa.has_value(), false); BOOST_CHECK_EQUAL(nonceOfContract.has_value(), true); BOOST_CHECK_EQUAL(nonceOfContract.value(), "1"); } @@ -128,6 +135,13 @@ class TransactionExecutiveFixture : public TransactionFixture auto result = executePromise.get_future().get(); BOOST_CHECK_EQUAL(result->status(), 0); + + if (type != TransactionType::BCOSTransaction) + { + std::unordered_map eoaNonceMap; + eoaNonceMap.emplace(sender.hex(), toQuantity(nonce)); + executor->updateEoaNonce(std::move(eoaNonceMap)); + } commitBlock(blockNumber); auto const nonceOfEoa = task::syncWait(bcos::ledger::account::nonce(eoa)); @@ -188,6 +202,13 @@ class TransactionExecutiveFixture : public TransactionFixture auto result = executePromise.get_future().get(); BOOST_CHECK_EQUAL(result->status(), 16); + + if (type != TransactionType::BCOSTransaction) + { + std::unordered_map eoaNonceMap; + eoaNonceMap.emplace(sender.hex(), toQuantity(nonce)); + executor->updateEoaNonce(std::move(eoaNonceMap)); + } commitBlock(blockNumber); auto const nonceOfEoa = task::syncWait(bcos::ledger::account::nonce(eoa)); @@ -208,7 +229,6 @@ class TransactionExecutiveFixture : public TransactionFixture auto transfer(uint blockNumber, TransactionType type, std::string toAddress, uint64_t initBalance, uint64_t transferValue, uint64_t initNonce) - { nextBlock(blockNumber, protocol::BlockVersion::MAX_VERSION, web3Features); auto nonce = initNonce; @@ -249,6 +269,13 @@ class TransactionExecutiveFixture : public TransactionFixture auto result = executePromise.get_future().get(); + if (type != TransactionType::BCOSTransaction) + { + std::unordered_map eoaNonceMap; + eoaNonceMap.emplace(sender, toQuantity(nonce)); + executor->updateEoaNonce(std::move(eoaNonceMap)); + } + commitBlock(blockNumber); auto const nonceOfEoa = task::syncWait(bcos::ledger::account::nonce(eoa)); diff --git a/bcos-framework/bcos-framework/executor/ParallelTransactionExecutorInterface.h b/bcos-framework/bcos-framework/executor/ParallelTransactionExecutorInterface.h index 690dc03b22..7933dcb488 100644 --- a/bcos-framework/bcos-framework/executor/ParallelTransactionExecutorInterface.h +++ b/bcos-framework/bcos-framework/executor/ParallelTransactionExecutorInterface.h @@ -105,6 +105,8 @@ class ParallelTransactionExecutorInterface virtual void getHash(bcos::protocol::BlockNumber number, std::function callback) = 0; + virtual void updateEoaNonce(std::unordered_map const& nonceMap) = 0; + /* ----- XA Transaction interface Start ----- */ // Write data to storage uncommitted diff --git a/bcos-framework/bcos-framework/ledger/LedgerInterface.h b/bcos-framework/bcos-framework/ledger/LedgerInterface.h index 0488e53523..55f8ef4bd4 100644 --- a/bcos-framework/bcos-framework/ledger/LedgerInterface.h +++ b/bcos-framework/bcos-framework/ledger/LedgerInterface.h @@ -197,13 +197,6 @@ class LedgerInterface co_return std::nullopt; } - virtual task::Task batchInsertEoaNonce(bcos::storage::StorageInterface::Ptr storage, - std::unordered_map eoa2Nonce, - std::unordered_map fbEoa2Nonce) - { - co_return; - } - virtual task::Task> getStorageState( std::string_view _address, protocol::BlockNumber _blockNumber) { diff --git a/bcos-ledger/bcos-ledger/Ledger.cpp b/bcos-ledger/bcos-ledger/Ledger.cpp index 6ed8c82472..0207fa5932 100644 --- a/bcos-ledger/bcos-ledger/Ledger.cpp +++ b/bcos-ledger/bcos-ledger/Ledger.cpp @@ -228,8 +228,6 @@ void Ledger::asyncPrewriteBlock(bcos::storage::StorageInterface::Ptr storage, // number 2 nonce auto nonceBlock = m_blockFactory->createBlock(); protocol::NonceList nonceList; - std::unordered_map web3NonceMap{}; - std::unordered_map bcosNonceMap{}; // get nonce from _blockTxs if (_blockTxs) { @@ -396,41 +394,6 @@ void Ledger::asyncPrewriteBlock(bcos::storage::StorageInterface::Ptr storage, }); } -task::Task Ledger::batchInsertEoaNonce(bcos::storage::StorageInterface::Ptr storage, - std::unordered_map eoa2Nonce, - std::unordered_map fbEoa2Nonce) -{ - auto features = co_await ledger::getFeatures(*this); - - for (auto&& [sender, nonce] : fbEoa2Nonce) - { - if (eoa2Nonce.contains(sender)) - { - eoa2Nonce[sender] += nonce; - continue; - } - // write in storage - ledger::account::EVMAccount eoa( - *storage, sender, features.get(Features::Flag::feature_raw_address)); - if (!co_await ledger::account::exists(eoa)) - { - co_await ledger::account::create(eoa); - } - auto nonceInStorage = co_await ledger::account::nonce(eoa); - auto const newNonce = nonce + std::stoull(nonceInStorage.value_or("0")); - co_await ledger::account::setNonce(eoa, std::to_string(newNonce)); - } - - co_await bcos::storage2::writeSome( - *storage, ::ranges::views::transform(eoa2Nonce, [&](auto& item) { - auto&& [sender, nonce] = item; - return std::make_tuple( - transaction_executor::StateKey( - getContractTableName(SYS_DIRECTORY::USER_APPS, sender), "nonce"), - storage::Entry(std::to_string(nonce + 1))); - })); -} - task::Task> Ledger::getStorageState( std::string_view _address, protocol::BlockNumber _blockNumber) { diff --git a/bcos-ledger/bcos-ledger/Ledger.h b/bcos-ledger/bcos-ledger/Ledger.h index 090fc59b3e..5b1a14f153 100644 --- a/bcos-ledger/bcos-ledger/Ledger.h +++ b/bcos-ledger/bcos-ledger/Ledger.h @@ -195,10 +195,6 @@ class Ledger : public LedgerInterface return _s.substr(_s.find_last_of('/') + 1); } - task::Task batchInsertEoaNonce(bcos::storage::StorageInterface::Ptr storage, - std::unordered_map eoa2Nonce, - std::unordered_map fbEoa2Nonce) override; - task::Task> getStorageState( std::string_view _address, protocol::BlockNumber _blockNumber) override; diff --git a/bcos-scheduler/src/BlockExecutive.cpp b/bcos-scheduler/src/BlockExecutive.cpp index 1745676cbc..08ce02793b 100644 --- a/bcos-scheduler/src/BlockExecutive.cpp +++ b/bcos-scheduler/src/BlockExecutive.cpp @@ -134,7 +134,6 @@ bcos::protocol::ExecutionMessage::UniquePtr BlockExecutive::buildMessage( if (tx->to().empty()) { message->setCreate(true); - message->setNonce(std::string(tx->nonce())); } else { @@ -147,6 +146,7 @@ bcos::protocol::ExecutionMessage::UniquePtr BlockExecutive::buildMessage( message->setTo(preprocessAddress(tx->to())); } } + message->setNonce(std::string(tx->nonce())); message->setDepth(0); message->setGasAvailable(m_gasLimit); auto toAddress = tx->to(); @@ -691,9 +691,27 @@ void BlockExecutive::asyncNotify( void BlockExecutive::saveMessage( std::string address, protocol::ExecutionMessage::UniquePtr message, bool withDAG) { + updateWeb3NonceMap(message); registerAndGetDmcExecutor(std::move(address))->submit(std::move(message), withDAG); } +void BlockExecutive::updateWeb3NonceMap(protocol::ExecutionMessage::UniquePtr const& msg) +{ + if (msg->txType() != protocol::TransactionType::BCOSTransaction) + { + if (c_fileLogLevel == TRACE) + { + SCHEDULER_LOG(TRACE) << METRIC << LOG_DESC("fillNonceMap") + << LOG_KV("sender", msg->from()) << LOG_KV("nonce", msg->nonce()); + } + auto sender = std::string(msg->from()); + if (auto const nonce = u256(msg->nonce()); m_web3NonceMap[sender] < nonce) + { + m_web3NonceMap.emplace(sender, nonce); + } + } +} + void BlockExecutive::DAGExecute(std::function callback) { if (!m_isRunning) @@ -1026,6 +1044,18 @@ void BlockExecutive::onDmcExecuteFinish( << LOG_BADGE("DMCRecorder") << " DMCExecute for transaction finished " << LOG_KV("checksum", dmcChecksum); } + std::unordered_map> executorUpdateMap = {}; + if (m_scheduler->m_executorManager->size() == 1) + for (auto&& [sender, nonce] : m_web3NonceMap) + { + auto const info = m_scheduler->m_executorManager->getExecutorInfo(sender); + executorUpdateMap[info->name][sender] = nonce; + } + for (auto&& [name, map] : executorUpdateMap) + { + m_scheduler->m_executorManager->getExecutorInfoByName(name)->executor->updateEoaNonce( + std::move(map)); + } onExecuteFinish(std::move(callback)); } diff --git a/bcos-scheduler/src/BlockExecutive.h b/bcos-scheduler/src/BlockExecutive.h index a60046ef88..7e12741cf3 100644 --- a/bcos-scheduler/src/BlockExecutive.h +++ b/bcos-scheduler/src/BlockExecutive.h @@ -164,9 +164,11 @@ class BlockExecutive : public std::enable_shared_from_this bcos::protocol::ConstTransactionsPtr fetchBlockTxsFromTxPool( bcos::protocol::Block::Ptr block, bcos::txpool::TxPoolInterface::Ptr txPool); std::string preprocessAddress(const std::string_view& address); + void updateWeb3NonceMap(protocol::ExecutionMessage::UniquePtr const& msg); std::map, std::less<>> m_dmcExecutors; std::shared_ptr m_dmcRecorder; + std::unordered_map m_web3NonceMap; std::vector m_executiveResults; diff --git a/bcos-scheduler/src/SerialBlockExecutive.cpp b/bcos-scheduler/src/SerialBlockExecutive.cpp index c991bcff16..40e9c4a7ec 100644 --- a/bcos-scheduler/src/SerialBlockExecutive.cpp +++ b/bcos-scheduler/src/SerialBlockExecutive.cpp @@ -37,6 +37,7 @@ void SerialBlockExecutive::prepare() << LOG_KV("block number", m_block->blockHeaderConst()->number()); } m_transactions.resize(txSize); + m_web3NonceMap.clear(); if (m_executor == nullptr) { @@ -196,6 +197,7 @@ void SerialBlockExecutive::serialExecute( } } + updateWeb3NonceMap(tx); SERIAL_EXECUTE_LOG(DEBUG) << BLOCK_NUMBER(number()) << "0.Send:\t >>>> [" << m_executorInfo->name << "]: " << tx->toString(); } @@ -285,5 +287,6 @@ void SerialBlockExecutive::onExecuteFinish( << LOG_KV("receiptsSize", m_executiveResults.size()) << LOG_KV("blockNumber", number()); } + m_executor->updateEoaNonce(m_web3NonceMap); BlockExecutive::onExecuteFinish(std::move(callback)); } diff --git a/bcos-scheduler/test/mock/MockDmcExecutor.h b/bcos-scheduler/test/mock/MockDmcExecutor.h index 2f08fe671b..26278887e6 100644 --- a/bcos-scheduler/test/mock/MockDmcExecutor.h +++ b/bcos-scheduler/test/mock/MockDmcExecutor.h @@ -160,7 +160,7 @@ class MockDmcExecutor : public bcos::executor::ParallelTransactionExecutorInterf void preExecuteTransactions(int64_t schedulerTermId, const bcos::protocol::BlockHeader::ConstPtr& blockHeader, std::string contractAddress, gsl::span inputs, - std::function callback) override{}; + std::function callback) override {}; void dagExecuteTransactions(gsl::span inputs, std::function callback) override { callback(nullptr); } + void updateEoaNonce(std::unordered_map const&) override {} std::string m_name; bcos::protocol::BlockNumber m_blockNumber = 0; diff --git a/bcos-scheduler/test/mock/MockExecutor.h b/bcos-scheduler/test/mock/MockExecutor.h index 9d9438519f..6e7a8a944c 100644 --- a/bcos-scheduler/test/mock/MockExecutor.h +++ b/bcos-scheduler/test/mock/MockExecutor.h @@ -181,6 +181,8 @@ class MockParallelExecutor : public bcos::executor::ParallelTransactionExecutorI } void reset(std::function callback) override {} + void updateEoaNonce(std::unordered_map const&) override {} + void clear() { m_dagHashes.clear(); } std::string m_name; diff --git a/bcos-scheduler/test/mock/MockExecutorForMessageDAG.h b/bcos-scheduler/test/mock/MockExecutorForMessageDAG.h index 9e80956010..002db8e625 100644 --- a/bcos-scheduler/test/mock/MockExecutorForMessageDAG.h +++ b/bcos-scheduler/test/mock/MockExecutorForMessageDAG.h @@ -153,6 +153,8 @@ class MockParallelExecutorByMessage : public bcos::executor::ParallelTransaction { callback(nullptr, {}); } + + void updateEoaNonce(std::unordered_map const&) override {} void clear() { m_dagHashes.clear(); } std::string m_name; diff --git a/bcos-tars-protocol/bcos-tars-protocol/client/ExecutorServiceClient.cpp b/bcos-tars-protocol/bcos-tars-protocol/client/ExecutorServiceClient.cpp index 6e896a178a..75923c3eab 100644 --- a/bcos-tars-protocol/bcos-tars-protocol/client/ExecutorServiceClient.cpp +++ b/bcos-tars-protocol/bcos-tars-protocol/client/ExecutorServiceClient.cpp @@ -630,4 +630,9 @@ void ExecutorServiceClient::getABI( // timeout is 30s m_prx->tars_set_timeout(30000)->async_getABI( new Callback(m_callbackPool, std::move(callback)), std::string(contract)); -} \ No newline at end of file +} + +void ExecutorServiceClient::updateEoaNonce(std::unordered_map const&) +{ + BOOST_THROW_EXCEPTION(std::runtime_error("Unimplemented")); +} diff --git a/bcos-tars-protocol/bcos-tars-protocol/client/ExecutorServiceClient.h b/bcos-tars-protocol/bcos-tars-protocol/client/ExecutorServiceClient.h index 33c5c9b8a2..efa4817e22 100644 --- a/bcos-tars-protocol/bcos-tars-protocol/client/ExecutorServiceClient.h +++ b/bcos-tars-protocol/bcos-tars-protocol/client/ExecutorServiceClient.h @@ -103,6 +103,8 @@ class ExecutorServiceClient : public bcos::executor::ParallelTransactionExecutor void getABI(std::string_view contract, std::function callback) override; + void updateEoaNonce(std::unordered_map const&) override; + private: ExecutorServicePrx m_prx; bcos::ThreadPool::Ptr m_callbackPool;