diff --git a/bcos-boostssl/bcos-boostssl/websocket/WsMessage.h b/bcos-boostssl/bcos-boostssl/websocket/WsMessage.h index f6e4890cff..7701ada86c 100644 --- a/bcos-boostssl/bcos-boostssl/websocket/WsMessage.h +++ b/bcos-boostssl/bcos-boostssl/websocket/WsMessage.h @@ -31,7 +31,7 @@ #include #include -inline void CHECK_OFFSET(uint16_t offset, uint16_t length) +inline void CHECK_OFFSET(uint64_t offset, uint64_t length) { if (offset > length) { diff --git a/bcos-framework/bcos-framework/testutils/faker/FakeLedger.h b/bcos-framework/bcos-framework/testutils/faker/FakeLedger.h index dee5557e35..8d9395ee12 100644 --- a/bcos-framework/bcos-framework/testutils/faker/FakeLedger.h +++ b/bcos-framework/bcos-framework/testutils/faker/FakeLedger.h @@ -317,6 +317,16 @@ class FakeLedger : public LedgerInterface, public std::enable_shared_from_this> getStorageState( + std::string_view _address, protocol::BlockNumber) override + { + if (eoaInLedger == _address) + { + ledger::StorageState state{.nonce = eoaInLedgerNonce, .balance = ""}; + co_return state; + } + co_return std::nullopt; + } void setStatus(bool _normal) { m_statusNormal = _normal; } void setTotalTxCount(size_t _totalTxCount) { m_totalTxCount = _totalTxCount; } void setSystemConfig(std::string_view _key, std::string const& _value) @@ -381,6 +391,12 @@ class FakeLedger : public LedgerInterface, public std::enable_shared_from_thiseoaInLedger = std::move(eoaInLedger); + eoaInLedgerNonce = std::move(nonce); + } + private: BlockFactory::Ptr m_blockFactory; std::vector m_keyPairVec; @@ -399,6 +415,8 @@ class FakeLedger : public LedgerInterface, public std::enable_shared_from_this> m_systemConfig; std::vector m_sealerList; std::shared_ptr m_worker = nullptr; + std::string eoaInLedger; + std::string eoaInLedgerNonce; }; } // namespace test } // namespace bcos \ No newline at end of file diff --git a/bcos-framework/bcos-framework/testutils/faker/FakeTransaction.h b/bcos-framework/bcos-framework/testutils/faker/FakeTransaction.h index 5c3422c647..1b422145d3 100644 --- a/bcos-framework/bcos-framework/testutils/faker/FakeTransaction.h +++ b/bcos-framework/bcos-framework/testutils/faker/FakeTransaction.h @@ -149,6 +149,34 @@ inline Transaction::Ptr fakeTransaction(CryptoSuite::Ptr _cryptoSuite, const std return fakeTransaction(_cryptoSuite, keyPair, std::string_view((char*)_to.data(), _to.size()), input, nonce, blockLimit, chainId, groupId); } + +inline Transaction::Ptr fakeWeb3Tx(CryptoSuite::Ptr _cryptoSuite, std::string nonce, + crypto::KeyPairInterface::UniquePtr const& key) +{ + bcostars::Transaction transaction; + + transaction.data.to = key->address(_cryptoSuite->hashImpl()).hex(); + std::string inputStr = "testTransaction"; + transaction.data.input.assign(inputStr.begin(), inputStr.end()); + transaction.data.nonce = std::move(nonce); + transaction.type = static_cast(TransactionType::Web3Transacion); + std::mt19937 random(std::random_device{}()); + std::string extraData = "extraData" + std::to_string(random()); + auto hash = _cryptoSuite->hash(extraData); + transaction.extraTransactionBytes.assign(extraData.begin(), extraData.end()); + transaction.extraTransactionHash.assign(hash.begin(), hash.end()); + auto tx = std::make_shared( + [m_transaction = std::move(transaction)]() mutable { return &m_transaction; }); + // set signature + tx->calculateHash(*_cryptoSuite->hashImpl()); + + auto signData = _cryptoSuite->signatureImpl()->sign(*key, tx->hash(), true); + tx->setSignatureData(*signData); + tx->forceSender(key->address(_cryptoSuite->hashImpl()).asBytes()); + tx->calculateHash(*_cryptoSuite->hashImpl()); + return tx; +} + inline TransactionsPtr fakeTransactions(int _size) { auto hashImpl = std::make_shared(); diff --git a/bcos-rpc/bcos-rpc/tarsRPC/RPCServer.h b/bcos-rpc/bcos-rpc/tarsRPC/RPCServer.h index d41dd27e63..0128f64d6d 100644 --- a/bcos-rpc/bcos-rpc/tarsRPC/RPCServer.h +++ b/bcos-rpc/bcos-rpc/tarsRPC/RPCServer.h @@ -1,5 +1,7 @@ #pragma once - +#ifdef _WIN32 +#include +#endif #include "../groupmgr/NodeService.h" #include #include diff --git a/bcos-rpc/bcos-rpc/web3jsonrpc/model/Web3Transaction.cpp b/bcos-rpc/bcos-rpc/web3jsonrpc/model/Web3Transaction.cpp index ad4f0e86fc..7550c5aa4e 100644 --- a/bcos-rpc/bcos-rpc/web3jsonrpc/model/Web3Transaction.cpp +++ b/bcos-rpc/bcos-rpc/web3jsonrpc/model/Web3Transaction.cpp @@ -144,7 +144,7 @@ bcostars::Transaction Web3Transaction::takeToTarsTransaction() auto signRef = bcos::bytesConstRef( reinterpret_cast(tarsTx.signature.data()), tarsTx.signature.size()); auto [_, sender] = signatureImpl.recoverAddress(hashImpl, hashForSign, signRef); - tarsTx.data.nonce = toHexStringWithPrefix(sender) + toQuantity(this->nonce); + tarsTx.data.nonce = toQuantity(this->nonce); tarsTx.data.chainID = std::to_string(this->chainId.value_or(0)); tarsTx.dataHash.reserve(crypto::HashType::SIZE); RANGES::move(hashForSign, std::back_inserter(tarsTx.dataHash)); diff --git a/bcos-scheduler/src/SchedulerImpl.cpp b/bcos-scheduler/src/SchedulerImpl.cpp index 785fd5af41..b5d32c7b04 100644 --- a/bcos-scheduler/src/SchedulerImpl.cpp +++ b/bcos-scheduler/src/SchedulerImpl.cpp @@ -67,9 +67,7 @@ SchedulerImpl::SchedulerImpl(ExecutorManager::Ptr executorManager, m_txPool(txPool), m_transactionSubmitResultFactory(std::move(transactionSubmitResultFactory)), m_hashImpl(std::move(hashImpl)), - m_isAuthCheck(isAuthCheck), m_isWasm(isWasm), - m_isSerialExecute(isSerialExecute), m_schedulerTermId(schedulerTermId), m_preExeWorker("preExeScheduler", 2), // assume that preExe is no slower than exe speed/2 m_exeWorker("exeScheduler", 1) diff --git a/bcos-scheduler/src/SchedulerImpl.h b/bcos-scheduler/src/SchedulerImpl.h index 8efd666104..5d74a917ac 100644 --- a/bcos-scheduler/src/SchedulerImpl.h +++ b/bcos-scheduler/src/SchedulerImpl.h @@ -218,9 +218,7 @@ class SchedulerImpl : public SchedulerInterface, public std::enable_shared_from_ bcos::txpool::TxPoolInterface::Ptr m_txPool; bcos::protocol::TransactionSubmitResultFactory::Ptr m_transactionSubmitResultFactory; bcos::crypto::Hash::Ptr m_hashImpl; - bool m_isAuthCheck = false; bool m_isWasm = false; - bool m_isSerialExecute = false; std::function m_blockNumberReceiver; std::function +#endif #include "bcos-framework/protocol/Transaction.h" #include "bcos-framework/protocol/TransactionReceipt.h" #include "bcos-tars-protocol/tars/RPC.h" diff --git a/bcos-sdk/bcos-cpp-sdk/tarsRPC/detail/TarsCallback.h b/bcos-sdk/bcos-cpp-sdk/tarsRPC/detail/TarsCallback.h index 0750cf86f2..9367e065c3 100644 --- a/bcos-sdk/bcos-cpp-sdk/tarsRPC/detail/TarsCallback.h +++ b/bcos-sdk/bcos-cpp-sdk/tarsRPC/detail/TarsCallback.h @@ -1,4 +1,7 @@ #pragma once +#ifdef _WIN32 +#include +#endif #include "bcos-framework/protocol/TransactionReceipt.h" #include "bcos-tars-protocol/tars/RPC.h" #include diff --git a/bcos-tars-protocol/bcos-tars-protocol/impl/TarsHashable.h b/bcos-tars-protocol/bcos-tars-protocol/impl/TarsHashable.h index fb6cf8cbb0..c29931663a 100644 --- a/bcos-tars-protocol/bcos-tars-protocol/impl/TarsHashable.h +++ b/bcos-tars-protocol/bcos-tars-protocol/impl/TarsHashable.h @@ -1,4 +1,7 @@ #pragma once +#ifdef _WIN32 +#include +#endif #include "bcos-concepts/ByteBuffer.h" #include "bcos-concepts/Hash.h" #include "bcos-crypto/hasher/Hasher.h" diff --git a/bcos-txpool/bcos-txpool/TxPoolFactory.cpp b/bcos-txpool/bcos-txpool/TxPoolFactory.cpp index e6be432651..18078c6915 100644 --- a/bcos-txpool/bcos-txpool/TxPoolFactory.cpp +++ b/bcos-txpool/bcos-txpool/TxPoolFactory.cpp @@ -22,6 +22,7 @@ #include "bcos-txpool/sync/TransactionSync.h" #include "bcos-txpool/sync/protocol/PB/TxsSyncMsgFactoryImpl.h" #include "bcos-txpool/txpool/validator/TxValidator.h" +#include "bcos-txpool/txpool/validator/Web3NonceChecker.h" #include "txpool/storage/MemoryStorage.h" #include "txpool/validator/TxPoolNonceChecker.h" @@ -54,8 +55,9 @@ TxPool::Ptr TxPoolFactory::createTxPool( { TXPOOL_LOG(INFO) << LOG_DESC("create transaction validator"); auto txpoolNonceChecker = std::make_shared(); - auto validator = - std::make_shared(txpoolNonceChecker, m_cryptoSuite, m_groupId, m_chainId); + auto web3NonceChecker = std::make_shared(m_ledger); + auto validator = std::make_shared( + txpoolNonceChecker, std::move(web3NonceChecker), m_cryptoSuite, m_groupId, m_chainId); TXPOOL_LOG(INFO) << LOG_DESC("create transaction config"); auto txpoolConfig = std::make_shared(validator, m_txResultFactory, m_blockFactory, diff --git a/bcos-txpool/bcos-txpool/txpool/interfaces/NonceCheckerInterface.h b/bcos-txpool/bcos-txpool/txpool/interfaces/NonceCheckerInterface.h index 4cd42749df..58555ecfc0 100644 --- a/bcos-txpool/bcos-txpool/txpool/interfaces/NonceCheckerInterface.h +++ b/bcos-txpool/bcos-txpool/txpool/interfaces/NonceCheckerInterface.h @@ -36,7 +36,7 @@ class NonceCheckerInterface virtual ~NonceCheckerInterface() = default; virtual bcos::protocol::TransactionStatus checkNonce( - bcos::protocol::Transaction::ConstPtr _tx, bool _shouldUpdate = false) = 0; + bcos::protocol::Transaction::ConstPtr _tx) = 0; virtual bool exists(bcos::protocol::NonceType const& _nonce) = 0; virtual void batchInsert( bcos::protocol::BlockNumber _batchId, bcos::protocol::NonceListPtr const& _nonceList) = 0; diff --git a/bcos-txpool/bcos-txpool/txpool/interfaces/TxValidatorInterface.h b/bcos-txpool/bcos-txpool/txpool/interfaces/TxValidatorInterface.h index 924ae02221..ab895e14cb 100644 --- a/bcos-txpool/bcos-txpool/txpool/interfaces/TxValidatorInterface.h +++ b/bcos-txpool/bcos-txpool/txpool/interfaces/TxValidatorInterface.h @@ -21,6 +21,7 @@ #pragma once #include "bcos-txpool/txpool/interfaces/NonceCheckerInterface.h" #include "bcos-txpool/txpool/validator/LedgerNonceChecker.h" +#include "bcos-txpool/txpool/validator/Web3NonceChecker.h" #include #include namespace bcos::txpool @@ -33,11 +34,16 @@ class TxValidatorInterface virtual ~TxValidatorInterface() = default; virtual bcos::protocol::TransactionStatus verify(bcos::protocol::Transaction::ConstPtr _tx) = 0; + virtual bcos::protocol::TransactionStatus checkTransaction( + bcos::protocol::Transaction::ConstPtr _tx, bool onlyCheckLedgerNonce = false) = 0; virtual bcos::protocol::TransactionStatus checkLedgerNonceAndBlockLimit( bcos::protocol::Transaction::ConstPtr _tx) = 0; virtual bcos::protocol::TransactionStatus checkTxpoolNonce( bcos::protocol::Transaction::ConstPtr _tx) = 0; + virtual bcos::protocol::TransactionStatus checkWeb3Nonce( + bcos::protocol::Transaction::ConstPtr _tx) = 0; virtual LedgerNonceChecker::Ptr ledgerNonceChecker() = 0; + virtual Web3NonceChecker::Ptr web3NonceChecker() = 0; virtual void setLedgerNonceChecker(LedgerNonceChecker::Ptr _ledgerNonceChecker) = 0; }; } // namespace bcos::txpool \ No newline at end of file diff --git a/bcos-txpool/bcos-txpool/txpool/storage/MemoryStorage.cpp b/bcos-txpool/bcos-txpool/txpool/storage/MemoryStorage.cpp index 245d5c88e5..4429dd65e7 100644 --- a/bcos-txpool/bcos-txpool/txpool/storage/MemoryStorage.cpp +++ b/bcos-txpool/bcos-txpool/txpool/storage/MemoryStorage.cpp @@ -287,11 +287,8 @@ TransactionStatus MemoryStorage::enforceSubmitTransaction(Transaction::Ptr _tx) { // check txpool nonce // check ledger tx - auto result = m_config->txValidator()->checkTxpoolNonce(_tx); - if (result == TransactionStatus::None) - { - result = m_config->txValidator()->checkLedgerNonceAndBlockLimit(_tx); - } + // check web3 tx + auto result = m_config->txValidator()->checkTransaction(_tx); Transaction::ConstPtr tx = nullptr; { TxsMap::ReadAccessor::Ptr accessor; @@ -618,7 +615,6 @@ void MemoryStorage::batchRemove(BlockNumber batchId, TransactionSubmitResults co uint64_t lockT = 0; m_blockNumberUpdatedTime = recordT; size_t succCount = 0; - NonceList nonceList; auto range = txsResult | RANGES::views::transform([](TransactionSubmitResult::Ptr const& _txResult) { @@ -669,20 +665,35 @@ void MemoryStorage::batchRemove(BlockNumber batchId, TransactionSubmitResults co notifyUnsealedTxsSize(); // update the ledger nonce - auto nonceListRange = results | RANGES::views::filter([](auto const& _result) { - const auto& tx = _result.second.first; - const auto& txResult = _result.second.second; - return tx == nullptr ? !txResult->nonce().empty() : true; - }) | RANGES::views::transform([](auto const& _result) { - const auto& tx = _result.second.first; - const auto& txResult = _result.second.second; - return tx != nullptr ? tx->nonce() : txResult->nonce(); - }); - - auto nonceListPtr = std::make_shared(nonceListRange.begin(), nonceListRange.end()); + auto nonceListPtr = std::make_shared(); + std::unordered_map web3NonceMap; + for (auto&& [_, txPair] : results) + { + auto const& [tx, txResult] = txPair; + if (tx) + { + if (tx->type() == TransactionType::Web3Transacion) [[unlikely]] + { + web3NonceMap[std::string(tx->sender())] = tx->nonce(); + } + else + { + nonceListPtr->emplace_back(tx->nonce()); + } + } + else if (!txResult->nonce().empty()) + { + nonceListPtr->emplace_back(txResult->nonce()); + } + } m_config->txValidator()->ledgerNonceChecker()->batchInsert(batchId, nonceListPtr); auto updateLedgerNonceT = utcTime() - startT; + startT = utcTime(); + m_config->txValidator()->web3NonceChecker()->batchInsert( + RANGES::views::keys(web3NonceMap), RANGES::views::values(web3NonceMap)); + auto updateWeb3NonceT = utcTime() - startT; + startT = utcTime(); // update the txpool nonce m_config->txPoolNonceChecker()->batchRemove(*nonceListPtr); @@ -705,6 +716,7 @@ void MemoryStorage::batchRemove(BlockNumber batchId, TransactionSubmitResults co << LOG_KV("batchId", batchId) << LOG_KV("timecost", (utcTime() - recordT)) << LOG_KV("lockT", lockT) << LOG_KV("removeT", removeT) << LOG_KV("updateLedgerNonceT", updateLedgerNonceT) + << LOG_KV("updateWeb3NonceT", updateLedgerNonceT) << LOG_KV("updateTxPoolNonceT", updateTxPoolNonceT); } @@ -808,7 +820,7 @@ void MemoryStorage::batchFetchTxs(Block::Ptr _txsList, Block::Ptr _sysTxsList, s // txPool, the txs with duplicated nonce here are already-committed, but have not been // dropped // check txpool txs, no need to check txpool nonce - auto result = m_config->txValidator()->checkLedgerNonceAndBlockLimit(tx); + auto result = m_config->txValidator()->checkTransaction(tx, true); if (result == TransactionStatus::NonceCheckFail) { // in case of the same tx notified more than once @@ -1265,7 +1277,7 @@ HashListPtr MemoryStorage::getTxsHash(int _limit) return true; } // check txpool txs, no need to check txpool nonce - auto result = m_config->txValidator()->checkLedgerNonceAndBlockLimit(tx); + auto result = m_config->txValidator()->checkTransaction(tx, true); if (result != TransactionStatus::None) { TxsMap::WriteAccessor::Ptr writeAccessor; @@ -1346,7 +1358,8 @@ void MemoryStorage::cleanUpExpiredTransactions() } } // check txpool txs, no need to check txpool nonce - auto result = m_config->txValidator()->checkLedgerNonceAndBlockLimit(tx); + auto validator = m_config->txValidator(); + auto result = validator->checkTransaction(tx, true); // blockLimit expired if (result != TransactionStatus::None) { diff --git a/bcos-txpool/bcos-txpool/txpool/storage/MemoryStorage.h b/bcos-txpool/bcos-txpool/txpool/storage/MemoryStorage.h index e4ba9e2441..868ab3322f 100644 --- a/bcos-txpool/bcos-txpool/txpool/storage/MemoryStorage.h +++ b/bcos-txpool/bcos-txpool/txpool/storage/MemoryStorage.h @@ -23,6 +23,7 @@ #include "bcos-task/Task.h" #include "bcos-txpool/TxPoolConfig.h" #include "bcos-txpool/txpool/utilities/Common.h" +#include "bcos-txpool/txpool/validator/Web3NonceChecker.h" #include #include #include diff --git a/bcos-txpool/bcos-txpool/txpool/validator/LedgerNonceChecker.cpp b/bcos-txpool/bcos-txpool/txpool/validator/LedgerNonceChecker.cpp index 5612236433..7db1141058 100644 --- a/bcos-txpool/bcos-txpool/txpool/validator/LedgerNonceChecker.cpp +++ b/bcos-txpool/bcos-txpool/txpool/validator/LedgerNonceChecker.cpp @@ -33,10 +33,10 @@ void LedgerNonceChecker::initNonceCache( } } -TransactionStatus LedgerNonceChecker::checkNonce(Transaction::ConstPtr _tx, bool _shouldUpdate) +TransactionStatus LedgerNonceChecker::checkNonce(Transaction::ConstPtr _tx) { // check nonce - auto status = TxPoolNonceChecker::checkNonce(_tx, _shouldUpdate); + auto status = TxPoolNonceChecker::checkNonce(_tx); if (status != TransactionStatus::None) { return status; diff --git a/bcos-txpool/bcos-txpool/txpool/validator/LedgerNonceChecker.h b/bcos-txpool/bcos-txpool/txpool/validator/LedgerNonceChecker.h index d48180192d..082db40013 100644 --- a/bcos-txpool/bcos-txpool/txpool/validator/LedgerNonceChecker.h +++ b/bcos-txpool/bcos-txpool/txpool/validator/LedgerNonceChecker.h @@ -41,7 +41,7 @@ class LedgerNonceChecker : public TxPoolNonceChecker } } bcos::protocol::TransactionStatus checkNonce( - bcos::protocol::Transaction::ConstPtr _tx, bool _shouldUpdate = false) override; + bcos::protocol::Transaction::ConstPtr _tx) override; void batchInsert(bcos::protocol::BlockNumber _batchId, bcos::protocol::NonceListPtr const& _nonceList) override; diff --git a/bcos-txpool/bcos-txpool/txpool/validator/TxPoolNonceChecker.cpp b/bcos-txpool/bcos-txpool/txpool/validator/TxPoolNonceChecker.cpp index 7429b3639a..71b294cb94 100644 --- a/bcos-txpool/bcos-txpool/txpool/validator/TxPoolNonceChecker.cpp +++ b/bcos-txpool/bcos-txpool/txpool/validator/TxPoolNonceChecker.cpp @@ -30,7 +30,7 @@ bool TxPoolNonceChecker::exists(NonceType const& _nonce) return m_nonces.contains(_nonce); } -TransactionStatus TxPoolNonceChecker::checkNonce(Transaction::ConstPtr _tx, bool _shouldUpdate) +TransactionStatus TxPoolNonceChecker::checkNonce(Transaction::ConstPtr _tx) { auto nonce = _tx->nonce(); @@ -38,12 +38,6 @@ TransactionStatus TxPoolNonceChecker::checkNonce(Transaction::ConstPtr _tx, bool { return TransactionStatus::NonceCheckFail; } - - if (_shouldUpdate) - { - NonceSet::WriteAccessor::Ptr accessor; - m_nonces.insert(accessor, std::move(nonce)); - } return TransactionStatus::None; } diff --git a/bcos-txpool/bcos-txpool/txpool/validator/TxPoolNonceChecker.h b/bcos-txpool/bcos-txpool/txpool/validator/TxPoolNonceChecker.h index b1880fc80a..0f5a4ea2a1 100644 --- a/bcos-txpool/bcos-txpool/txpool/validator/TxPoolNonceChecker.h +++ b/bcos-txpool/bcos-txpool/txpool/validator/TxPoolNonceChecker.h @@ -31,7 +31,7 @@ class TxPoolNonceChecker : public NonceCheckerInterface public: TxPoolNonceChecker() : m_nonces(256){}; bcos::protocol::TransactionStatus checkNonce( - bcos::protocol::Transaction::ConstPtr _tx, bool _shouldUpdate = false) override; + bcos::protocol::Transaction::ConstPtr _tx) override; void batchInsert(bcos::protocol::BlockNumber _batchId, bcos::protocol::NonceListPtr const& _nonceList) override; void batchRemove(bcos::protocol::NonceList const& _nonceList) override; diff --git a/bcos-txpool/bcos-txpool/txpool/validator/TxValidator.cpp b/bcos-txpool/bcos-txpool/txpool/validator/TxValidator.cpp index 03e7226562..8249966b45 100644 --- a/bcos-txpool/bcos-txpool/txpool/validator/TxValidator.cpp +++ b/bcos-txpool/bcos-txpool/txpool/validator/TxValidator.cpp @@ -41,15 +41,7 @@ TransactionStatus TxValidator::verify(bcos::protocol::Transaction::ConstPtr _tx) { return TransactionStatus::InvalidChainId; } - // compare with nonces cached in memory, only check nonce in txpool - auto status = checkTxpoolNonce(_tx); - if (status != TransactionStatus::None) - { - return status; - } - // check ledger nonce and block limit - status = checkLedgerNonceAndBlockLimit(_tx); - if (status != TransactionStatus::None) + if (const auto status = checkTransaction(_tx); status != TransactionStatus::None) { return status; } @@ -71,6 +63,34 @@ TransactionStatus TxValidator::verify(bcos::protocol::Transaction::ConstPtr _tx) return TransactionStatus::None; } +bcos::protocol::TransactionStatus TxValidator::checkTransaction( + bcos::protocol::Transaction::ConstPtr _tx, bool onlyCheckLedgerNonce) +{ + if (_tx->type() == static_cast(TransactionType::Web3Transacion)) [[unlikely]] + { + auto const status = checkWeb3Nonce(_tx); + if (status != TransactionStatus::None) + { + return status; + } + return TransactionStatus::None; + } + // compare with nonces cached in memory, only check nonce in txpool + auto status = TransactionStatus::None; + if (!onlyCheckLedgerNonce) + { + status = checkTxpoolNonce(_tx); + if (status != TransactionStatus::None) + { + return status; + } + } + // check ledger nonce and block limit + status = checkLedgerNonceAndBlockLimit(_tx); + return status; +} + + TransactionStatus TxValidator::checkLedgerNonceAndBlockLimit( bcos::protocol::Transaction::ConstPtr _tx) { @@ -89,5 +109,15 @@ TransactionStatus TxValidator::checkLedgerNonceAndBlockLimit( TransactionStatus TxValidator::checkTxpoolNonce(bcos::protocol::Transaction::ConstPtr _tx) { - return m_txPoolNonceChecker->checkNonce(_tx, false); + return m_txPoolNonceChecker->checkNonce(_tx); +} + +bcos::protocol::TransactionStatus TxValidator::checkWeb3Nonce( + bcos::protocol::Transaction::ConstPtr _tx) +{ + if (_tx->type() != static_cast(TransactionType::Web3Transacion)) [[likely]] + { + return TransactionStatus::None; + } + return task::syncWait(m_web3NonceChecker->checkWeb3Nonce(std::move(_tx))); } diff --git a/bcos-txpool/bcos-txpool/txpool/validator/TxValidator.h b/bcos-txpool/bcos-txpool/txpool/validator/TxValidator.h index 722e3f5544..37c1e850bd 100644 --- a/bcos-txpool/bcos-txpool/txpool/validator/TxValidator.h +++ b/bcos-txpool/bcos-txpool/txpool/validator/TxValidator.h @@ -22,6 +22,7 @@ #include "bcos-txpool/txpool/interfaces/NonceCheckerInterface.h" #include "bcos-txpool/txpool/interfaces/TxValidatorInterface.h" #include +#include #include #include @@ -32,20 +33,27 @@ class TxValidator : public TxValidatorInterface public: using Ptr = std::shared_ptr; TxValidator(NonceCheckerInterface::Ptr _txPoolNonceChecker, - bcos::crypto::CryptoSuite::Ptr _cryptoSuite, std::string const& _groupId, - std::string const& _chainId) + Web3NonceChecker::Ptr _web3NonceChecker, bcos::crypto::CryptoSuite::Ptr _cryptoSuite, + std::string _groupId, std::string _chainId) : m_txPoolNonceChecker(std::move(_txPoolNonceChecker)), + m_web3NonceChecker(std::move(_web3NonceChecker)), m_cryptoSuite(std::move(_cryptoSuite)), - m_groupId(_groupId), - m_chainId(_chainId) + m_groupId(std::move(_groupId)), + m_chainId(std::move(_chainId)) {} ~TxValidator() override = default; bcos::protocol::TransactionStatus verify(bcos::protocol::Transaction::ConstPtr _tx) override; + bcos::protocol::TransactionStatus checkTransaction( + bcos::protocol::Transaction::ConstPtr _tx, bool onlyCheckLedgerNonce = false) override; bcos::protocol::TransactionStatus checkLedgerNonceAndBlockLimit( bcos::protocol::Transaction::ConstPtr _tx) override; bcos::protocol::TransactionStatus checkTxpoolNonce( bcos::protocol::Transaction::ConstPtr _tx) override; + bcos::protocol::TransactionStatus checkWeb3Nonce( + bcos::protocol::Transaction::ConstPtr _tx) override; + + Web3NonceChecker::Ptr web3NonceChecker() override { return m_web3NonceChecker; } LedgerNonceChecker::Ptr ledgerNonceChecker() override { return m_ledgerNonceChecker; } void setLedgerNonceChecker(LedgerNonceChecker::Ptr _ledgerNonceChecker) override @@ -65,6 +73,8 @@ class TxValidator : public TxValidatorInterface // check the transaction nonce in ledger, maintenance block number to nonce list mapping, and // nonce list which already committed to ledger LedgerNonceChecker::Ptr m_ledgerNonceChecker; + // only check nonce for web3 transaction + Web3NonceChecker::Ptr m_web3NonceChecker; bcos::crypto::CryptoSuite::Ptr m_cryptoSuite; std::string m_groupId; std::string m_chainId; diff --git a/bcos-txpool/bcos-txpool/txpool/validator/Web3NonceChecker.cpp b/bcos-txpool/bcos-txpool/txpool/validator/Web3NonceChecker.cpp new file mode 100644 index 0000000000..cd63a422ee --- /dev/null +++ b/bcos-txpool/bcos-txpool/txpool/validator/Web3NonceChecker.cpp @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2024 FISCO BCOS. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @file Web3NonceChecker.cpp + * @author: kyonGuo + * @date 2024/8/26 + */ + +#include "Web3NonceChecker.h" +#include + +using namespace bcos; +using namespace bcos::txpool; +using namespace bcos::protocol; + +task::Task Web3NonceChecker::checkWeb3Nonce(Transaction::ConstPtr _tx) +{ + // sender is bytes view + auto sender = std::string(_tx->sender()); + auto nonce = u256(_tx->nonce()); + + if (auto const nonceInMem = co_await bcos::storage2::readOne(m_nonces, sender)) + { + if (u256(nonceInMem.value()) >= nonce) + { + co_return TransactionStatus::NonceCheckFail; + } + // else + // { + // // update memory if nonce bigger than memory's + // co_await storage2::writeOne(m_nonces, sender, nonce); + // co_return TransactionStatus::None; + // } + } + // not in memory, check from ledger + // TODO)): block number not use nowadays + auto const senderHex = toHex(sender); + auto const storageState = co_await m_ledger->getStorageState(senderHex, 0); + if (storageState.has_value()) + { + auto const nonceInLedger = boost::lexical_cast(storageState.value().nonce); + // update memory first + co_await storage2::writeOne(m_nonces, sender, storageState.value().nonce); + if (nonceInLedger >= nonce) + { + co_return TransactionStatus::NonceCheckFail; + } + } + // TODO)): check balance? + // 在这里仍然不更新内存,因为这个nonce可能是未来的nonce。会在未来交易落盘时再更新。 + // Still not update memory here, because this nonce may be the nonce in the future. Will update + // when the transaction is written to the disk in the future. + co_return TransactionStatus::None; +} + +void Web3NonceChecker::batchInsert( + RANGES::input_range auto&& senders, RANGES::input_range auto&& nonces) +{ + task::wait(storage2::writeSome(m_nonces, senders, nonces)); +} + +void Web3NonceChecker::insert(std::string sender, std::string nonce) +{ + task::wait(storage2::writeOne(m_nonces, sender, nonce)); +} diff --git a/bcos-txpool/bcos-txpool/txpool/validator/Web3NonceChecker.h b/bcos-txpool/bcos-txpool/txpool/validator/Web3NonceChecker.h new file mode 100644 index 0000000000..656eed1571 --- /dev/null +++ b/bcos-txpool/bcos-txpool/txpool/validator/Web3NonceChecker.h @@ -0,0 +1,61 @@ +/** + * Copyright (C) 2024 FISCO BCOS. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @file Web3NonceChecker.h + * @author: kyonGuo + * @date 2024/8/26 + */ + +#pragma once +#include +#include + +namespace bcos::txpool +{ +/** + * Implementation for web3 nonce-checker + */ +class Web3NonceChecker +{ +public: + using Ptr = std::shared_ptr; + explicit Web3NonceChecker(bcos::ledger::LedgerInterface::Ptr ledger) + : m_nonces(256), m_ledger(std::move(ledger)) + {} + ~Web3NonceChecker() = default; + Web3NonceChecker(const Web3NonceChecker&) = delete; + Web3NonceChecker& operator=(const Web3NonceChecker&) = delete; + Web3NonceChecker(Web3NonceChecker&&) = default; + Web3NonceChecker& operator=(Web3NonceChecker&&) = default; + /** + * check nonce for web3 transaction + * @param _tx: the transaction to be checked + * @return TransactionStatus: the status of the transaction + */ + task::Task checkWeb3Nonce( + bcos::protocol::Transaction::ConstPtr _tx); + + void batchInsert(RANGES::input_range auto&& senders, RANGES::input_range auto&& nonces); + // for test + void insert(std::string sender, std::string nonce); + +private: + // sender address (bytes string) -> nonce + using NonceMap = bcos::storage2::memory_storage::MemoryStorage; + NonceMap m_nonces; + bcos::ledger::LedgerInterface::Ptr m_ledger; +}; +} // namespace bcos::txpool diff --git a/bcos-txpool/test/unittests/txpool/TxPoolFixture.h b/bcos-txpool/test/unittests/txpool/TxPoolFixture.h index 6f3b94350b..2136b99809 100644 --- a/bcos-txpool/test/unittests/txpool/TxPoolFixture.h +++ b/bcos-txpool/test/unittests/txpool/TxPoolFixture.h @@ -412,7 +412,7 @@ inline void checkTxSubmit(TxPoolInterface::Ptr _txpool, TxPoolStorageInterface:: std::this_thread::sleep_for(std::chrono::milliseconds(2)); } } - BOOST_CHECK(_storage->size() == expectedTxSize); + BOOST_CHECK_EQUAL(_storage->size(), expectedTxSize); } } // namespace test } // namespace bcos \ No newline at end of file diff --git a/bcos-txpool/test/unittests/txpool/TxPoolTest.cpp b/bcos-txpool/test/unittests/txpool/TxPoolTest.cpp index 9dc040310f..0fa6ead517 100644 --- a/bcos-txpool/test/unittests/txpool/TxPoolTest.cpp +++ b/bcos-txpool/test/unittests/txpool/TxPoolTest.cpp @@ -186,7 +186,8 @@ void testAsyncFillBlock(TxPoolFixture::Ptr _faker, TxPoolInterface::Ptr _txpool, } void testAsyncSealTxs(TxPoolFixture::Ptr _faker, TxPoolInterface::Ptr _txpool, - TxPoolStorageInterface::Ptr _txpoolStorage, int64_t _blockLimit, CryptoSuite::Ptr _cryptoSuite) + TxPoolStorageInterface::Ptr _txpoolStorage, int64_t _blockLimit, CryptoSuite::Ptr _cryptoSuite, + std::function cleanWeb3Func = nullptr) { // asyncSealTxs auto originTxsSize = _txpoolStorage->size(); @@ -271,8 +272,8 @@ void testAsyncSealTxs(TxPoolFixture::Ptr _faker, TxPoolInterface::Ptr _txpool, 100000, nullptr, [&](Error::Ptr _error, Block::Ptr _txsMetaDataList, Block::Ptr) { BOOST_CHECK(_error == nullptr); auto size = _txsMetaDataList->transactionsMetaDataSize(); - BOOST_CHECK(_txsMetaDataList->transactionsMetaDataSize() == 0); - BOOST_CHECK(_txsMetaDataList->transactionsHashSize() == 0); + BOOST_CHECK_EQUAL(size, 0); + BOOST_CHECK_EQUAL(_txsMetaDataList->transactionsHashSize(), 0); promise.set_value(); }); promise.get_future().get(); @@ -385,7 +386,9 @@ void testAsyncSealTxs(TxPoolFixture::Ptr _faker, TxPoolInterface::Ptr _txpool, auto validator = std::dynamic_pointer_cast(_faker->txpool()->txpoolConfig()->txValidator()); auto ledgerNonceChecker = validator->ledgerNonceChecker(); - for (auto tx : *notifiedTxs) + for (auto tx : *notifiedTxs | RANGES::views::filter([](auto const& tx) { + return tx->type() != static_cast(TransactionType::Web3Transacion); + })) { BOOST_CHECK(txPoolNonceChecker->checkNonce(tx) == TransactionStatus::None); BOOST_CHECK(ledgerNonceChecker->checkNonce(tx) == TransactionStatus::NonceCheckFail); @@ -399,22 +402,23 @@ void testAsyncSealTxs(TxPoolFixture::Ptr _faker, TxPoolInterface::Ptr _txpool, } // case: the other left txs expired for invalid blockLimit - finish = false; std::cout << "######### asyncSealTxs with invalid blocklimit" << std::endl; std::cout << "##### origin txsSize:" << _txpoolStorage->size() << std::endl; + if (cleanWeb3Func) + { + cleanWeb3Func(); + } _txpool->asyncResetTxPool(nullptr); + std::promise promise; _txpool->asyncSealTxs( 100000, nullptr, [&](Error::Ptr _error, Block::Ptr _txsMetaDataList, Block::Ptr) { BOOST_CHECK(_error == nullptr); - BOOST_CHECK(_txsMetaDataList->transactionsMetaDataSize() == 0); - BOOST_CHECK(_txsMetaDataList->transactionsHashSize() == 0); - finish = true; + BOOST_CHECK_EQUAL(_txsMetaDataList->transactionsMetaDataSize(), 0); + BOOST_CHECK_EQUAL(_txsMetaDataList->transactionsHashSize(), 0); + promise.set_value(); }); - while (!finish || (_txpoolStorage->size() > 0)) - { - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - } + promise.get_future().get(); BOOST_CHECK(_txpoolStorage->size() == 0); } @@ -587,6 +591,132 @@ void txPoolInitAndSubmitTransactionTest(bool _sm, CryptoSuite::Ptr _cryptoSuite) std::cout << "#### txPoolInitAndSubmitTransactionTest finish" << std::endl; } +void txPoolInitAndSubmitWeb3TransactionTest(CryptoSuite::Ptr _cryptoSuite, bool multiTx = false) +{ + auto signatureImpl = _cryptoSuite->signatureImpl(); + auto hashImpl = _cryptoSuite->hashImpl(); + auto keyPair = signatureImpl->generateKeyPair(); + std::string groupId = "group_test_for_txpool"; + std::string chainId = "chain_test_for_txpool"; + int64_t blockLimit = 10; + auto fakeGateWay = std::make_shared(); + auto faker = std::make_shared(keyPair->publicKey(), _cryptoSuite, groupId, + chainId, blockLimit, fakeGateWay, false, false); + faker->init(); + + auto txpoolConfig = faker->txpool()->txpoolConfig(); + auto txpool = faker->txpool(); + auto txpoolStorage = txpool->txpoolStorage(); + auto ledger = faker->ledger(); + + auto const eoaKey = _cryptoSuite->signatureImpl()->generateKeyPair(); + // case3: transaction with invalid nonce(conflict with the ledger nonce) + auto const& blockData = ledger->ledgerData(); + size_t importedTxNum = 1; + + auto duplicatedNonce = + blockData[ledger->blockNumber() - blockLimit + 1]->transaction(0)->nonce(); + auto tx = fakeWeb3Tx(_cryptoSuite, duplicatedNonce, eoaKey); + // bcos nonce not effect web3 nonce + checkTxSubmit(txpool, txpoolStorage, tx, tx->hash(), (uint32_t)TransactionStatus::None, + importedTxNum, false, true, true); + + duplicatedNonce = "123456"; + tx = fakeWeb3Tx(_cryptoSuite, duplicatedNonce, eoaKey); + faker->ledger()->initEoaContext( + eoaKey->address(_cryptoSuite->hashImpl()).hex(), duplicatedNonce); + checkTxSubmit(txpool, txpoolStorage, tx, tx->hash(), + (uint32_t)TransactionStatus::NonceCheckFail, importedTxNum); + + + // case: nonce store in memory + std::string fakeNonce = "123457"; + tx = fakeWeb3Tx(_cryptoSuite, fakeNonce, keyPair); + txpool->txpoolConfig()->txValidator()->web3NonceChecker()->insert( + std::string(tx->sender()), fakeNonce); + checkTxSubmit(txpool, txpoolStorage, tx, tx->hash(), + (uint32_t)TransactionStatus::NonceCheckFail, importedTxNum); + + // case7: submit success + importedTxNum++; + tx = fakeWeb3Tx(_cryptoSuite, duplicatedNonce + "1", eoaKey); + checkTxSubmit(txpool, txpoolStorage, tx, tx->hash(), (uint32_t)TransactionStatus::None, + importedTxNum, false, true, true); + // case8: submit duplicated tx + checkTxSubmit(txpool, txpoolStorage, tx, tx->hash(), + (uint32_t)TransactionStatus::AlreadyInTxPool, importedTxNum); + + // batch import transactions + + Transactions transactions; + for (auto i = 0; i < 40; i++) + { + auto tmpTx = fakeTransaction(_cryptoSuite, std::to_string(utcTime() + 1000 + i), + ledger->blockNumber() + blockLimit - 4, faker->chainId(), faker->groupId()); + transactions.push_back(tmpTx); + } + + for (auto i = 0; i < 40; i++) + { + auto tmpTx = fakeWeb3Tx(_cryptoSuite, duplicatedNonce + "1" + std::to_string(i), eoaKey); + transactions.push_back(tmpTx); + } + + for (size_t i = 0; i < transactions.size(); i++) + { + auto tmpTx = transactions[i]; + checkTxSubmit(txpool, txpoolStorage, tmpTx, tmpTx->hash(), + (uint32_t)TransactionStatus::None, 0, false, true, true); + } + importedTxNum += transactions.size(); + auto startT = utcTime(); + while ((txpoolStorage->size() < importedTxNum) && (utcTime() - startT <= 10000)) + { + std::cout << "#### txpoolStorage->size:" << txpoolStorage->size() << std::endl; + std::cout << "#### importedTxNum:" << importedTxNum << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(2)); + } + std::cout << "#### txpoolStorage size:" << txpoolStorage->size() << std::endl; + std::cout << "#### importedTxNum:" << importedTxNum << std::endl; + + // case9: the txpool is full + txpoolConfig->setPoolLimit(importedTxNum); + checkTxSubmit(txpool, txpoolStorage, tx, tx->hash(), (uint32_t)TransactionStatus::TxPoolIsFull, + importedTxNum); + + // case10: malformed transaction + bcos::bytes encodedData; + tx->encode(encodedData); + auto txData = std::make_shared(encodedData.begin(), encodedData.end()); + // fake invalid txData + for (size_t i = 0; i < txData->size(); i++) + { + (*txData)[i] += 100; + } + try + { + auto _result = bcos::task::syncWait(txpool->submitTransaction(tx)); + } + catch (bcos::Error& e) + { + // TODO: Put TransactionStatus::Malformed into bcos::Error + // BOOST_CHECK(e.errorCode() == _result->status()); + std::cout << "#### error info:" << e.errorMessage() << std::endl; + // BOOST_CHECK(_result->txHash() == HashType()); + // BOOST_CHECK(_result->status() == (uint32_t)(TransactionStatus::Malform)); + } + std::cout << "#### testAsyncFillBlock" << std::endl; + testAsyncFillBlock(faker, txpool, txpoolStorage, _cryptoSuite); + std::cout << "#### testAsyncSealTxs" << std::endl; + testAsyncSealTxs(faker, txpool, txpoolStorage, blockLimit, _cryptoSuite, [&]() { + faker->ledger()->initEoaContext( + eoaKey->address(_cryptoSuite->hashImpl()).hex(), "9999999999999999"); + }); + // clear all the txs before exit + txpool->txpoolStorage()->clear(); + std::cout << "#### txPoolInitAndSubmitTransactionTest finish" << std::endl; +} + BOOST_AUTO_TEST_CASE(testTxPoolInitAndSubmitTransaction) { auto hashImpl = std::make_shared(); @@ -603,6 +733,14 @@ BOOST_AUTO_TEST_CASE(testSMTxPoolInitAndSubmitTransaction) txPoolInitAndSubmitTransactionTest(true, cryptoSuite); } +BOOST_AUTO_TEST_CASE(testWeb3Tx) +{ + auto hashImpl = std::make_shared(); + auto signatureImpl = std::make_shared(); + auto cryptoSuite = std::make_shared(hashImpl, signatureImpl, nullptr); + txPoolInitAndSubmitWeb3TransactionTest(cryptoSuite); +} + BOOST_AUTO_TEST_CASE(fillWithSubmit) { // auto hashImpl = std::make_shared(); diff --git a/bcos-utilities/bcos-utilities/BoostLog.h b/bcos-utilities/bcos-utilities/BoostLog.h index 6696e1d543..7ea3058bfb 100644 --- a/bcos-utilities/bcos-utilities/BoostLog.h +++ b/bcos-utilities/bcos-utilities/BoostLog.h @@ -75,6 +75,12 @@ enum LogLevel extern LogLevel c_fileLogLevel; extern LogLevel c_statLogLevel; +constexpr auto operator<=>(LogLevel const& _lhs, auto const& _rhs) + requires(std::same_as || std::unsigned_integral) +{ + return static_cast(_lhs) <=> static_cast(_rhs); +} + void setFileLogLevel(LogLevel const& _level); void setStatLogLevel(LogLevel const& _level);