diff --git a/bcos-framework/bcos-framework/transaction-scheduler/TransactionScheduler.h b/bcos-framework/bcos-framework/transaction-scheduler/TransactionScheduler.h index 7264bcb5b8..c56eb9409c 100644 --- a/bcos-framework/bcos-framework/transaction-scheduler/TransactionScheduler.h +++ b/bcos-framework/bcos-framework/transaction-scheduler/TransactionScheduler.h @@ -1,9 +1,9 @@ #pragma once -#include "../protocol/Block.h" +#include "../protocol/BlockHeader.h" +#include "../protocol/TransactionReceipt.h" #include "bcos-task/Task.h" #include "bcos-task/Trait.h" -#include "bcos-utilities/Ranges.h" namespace bcos::transaction_scheduler { diff --git a/bcos-rpc/bcos-rpc/web3jsonrpc/endpoints/EthEndpoint.cpp b/bcos-rpc/bcos-rpc/web3jsonrpc/endpoints/EthEndpoint.cpp index 62d509dd81..ea2d2e8098 100644 --- a/bcos-rpc/bcos-rpc/web3jsonrpc/endpoints/EthEndpoint.cpp +++ b/bcos-rpc/bcos-rpc/web3jsonrpc/endpoints/EthEndpoint.cpp @@ -36,6 +36,7 @@ #include #include #include +#include using namespace bcos; using namespace bcos::rpc; @@ -475,71 +476,68 @@ task::Task EthEndpoint::call(const Json::Value& request, Json::Value& resp BOOST_THROW_EXCEPTION( JsonRpcException(JsonRpcError::InternalError, "Scheduler not available!")); } - auto [valid, call] = decodeCallRequest(request[0u]); + auto [valid, call] = decodeCallRequest(request[0U]); if (!valid) { BOOST_THROW_EXCEPTION(JsonRpcException(InvalidParams, "Invalid call request!")); } - auto const blockTag = toView(request[1u]); + auto const blockTag = toView(request[1U]); auto [blockNumber, _] = co_await getBlockNumberByTag(blockTag); if (c_fileLogLevel == TRACE) { WEB3_LOG(TRACE) << LOG_DESC("eth_call") << LOG_KV("call", call) << LOG_KV("blockTag", blockTag) << LOG_KV("blockNumber", blockNumber); } - auto const tx = call.takeToTransaction(m_nodeService->blockFactory()->transactionFactory()); - // TODO: ignore params blockNumber here, use it after historical data is available - std::variant variantResult{}; - // MOVE it into a new file + auto tx = call.takeToTransaction(m_nodeService->blockFactory()->transactionFactory()); struct Awaitable { bcos::scheduler::SchedulerInterface& m_scheduler; - bcos::protocol::Transaction::Ptr m_tx; - std::variant& m_result; + bcos::protocol::Transaction::Ptr& m_tx; + Error::Ptr m_error; + Json::Value& m_response; + constexpr static bool await_ready() noexcept { return false; } - void await_suspend(std::coroutine_handle<> handle) noexcept + void await_suspend(std::coroutine_handle<> handle) { m_scheduler.call(m_tx, [this, handle](Error::Ptr&& error, auto&& result) { if (error) { - m_result.emplace(std::move(error)); + m_error = std::move(error); } else { - m_result.emplace(std::move(result)); + auto output = toHexStringWithPrefix(result->output()); + if (result->status() == static_cast(protocol::TransactionStatus::None)) + { + m_response["jsonrpc"] = "2.0"; + m_response["result"] = output; + } + else + { + // https://docs.infura.io/api/networks/ethereum/json-rpc-methods/eth_call#returns + Json::Value jsonResult = Json::objectValue; + jsonResult["code"] = result->status(); + jsonResult["message"] = result->message(); + jsonResult["data"] = output; + m_response["jsonrpc"] = "2.0"; + m_response["error"] = std::move(jsonResult); + } } + handle.resume(); }); } - protocol::TransactionReceipt::Ptr await_resume() + void await_resume() { - if (std::holds_alternative(m_result)) + if (m_error) { - BOOST_THROW_EXCEPTION(*std::get(m_result)); + BOOST_THROW_EXCEPTION(*m_error); } - return std::get(m_result); } }; - auto const result = - co_await Awaitable{.m_scheduler = *scheduler, .m_tx = tx, .m_result = variantResult}; - - auto output = toHexStringWithPrefix(result->output()); - if (result->status() == static_cast(protocol::TransactionStatus::None)) - { - response["jsonrpc"] = "2.0"; - response["result"] = std::move(output); - } - else - { - // https://docs.infura.io/api/networks/ethereum/json-rpc-methods/eth_call#returns - Json::Value jsonResult = Json::objectValue; - jsonResult["code"] = result->status(); - jsonResult["message"] = result->message(); - jsonResult["data"] = std::move(output); - response["jsonrpc"] = "2.0"; - response["error"] = std::move(jsonResult); - } - co_return; + Awaitable awaitable{ + .m_scheduler = *scheduler, .m_tx = tx, .m_error = {}, .m_response = response}; + co_await awaitable; } task::Task EthEndpoint::estimateGas(const Json::Value& request, Json::Value& response) { diff --git a/transaction-executor/bcos-transaction-executor/vm/HostContext.cpp b/transaction-executor/bcos-transaction-executor/vm/HostContext.cpp index 5e5f4abe55..95e34a5cf8 100644 --- a/transaction-executor/bcos-transaction-executor/vm/HostContext.cpp +++ b/transaction-executor/bcos-transaction-executor/vm/HostContext.cpp @@ -58,3 +58,19 @@ std::variant bcos::transaction_executor::getM } return message; } + +bcos::transaction_executor::CacheExecutables& bcos::transaction_executor::getCacheExecutables() +{ + struct CacheExecutables + { + bcos::transaction_executor::CacheExecutables m_cachedExecutables; + + CacheExecutables() + { + constexpr static auto maxContracts = 100; + m_cachedExecutables.setMaxCapacity(sizeof(std::shared_ptr) * maxContracts); + } + } static cachedExecutables; + + return cachedExecutables.m_cachedExecutables; +} diff --git a/transaction-executor/bcos-transaction-executor/vm/HostContext.h b/transaction-executor/bcos-transaction-executor/vm/HostContext.h index e9a552c9ab..cac96102b6 100644 --- a/transaction-executor/bcos-transaction-executor/vm/HostContext.h +++ b/transaction-executor/bcos-transaction-executor/vm/HostContext.h @@ -75,35 +75,34 @@ std::variant getMessage(const evmc_message& i struct Executable { - explicit Executable(storage::Entry code, evmc_revision revision) + Executable(storage::Entry code, evmc_revision revision) : m_code(std::make_optional(std::move(code))), - m_revision(revision), m_vmInstance(VMFactory::create(VMKind::evmone, bytesConstRef(reinterpret_cast(m_code->data()), m_code->size()), - m_revision)) + revision)) {} explicit Executable(bytesConstRef code, evmc_revision revision) : m_vmInstance(VMFactory::create(VMKind::evmone, code, revision)) {} std::optional m_code; - evmc_revision m_revision; VMInstance m_vmInstance; }; template using Account = ledger::account::EVMAccount; -inline task::Task> getExecutable( - auto& storage, const evmc_address& address, const evmc_revision& revision) -{ - static storage2::memory_storage::MemoryStorage, +using CacheExecutables = + storage2::memory_storage::MemoryStorage, storage2::memory_storage::Attribute( storage2::memory_storage::LRU | storage2::memory_storage::CONCURRENT), - std::hash> - cachedExecutables; + std::hash>; +CacheExecutables& getCacheExecutables(); - if (auto executable = co_await storage2::readOne(cachedExecutables, address)) +inline task::Task> getExecutable( + auto& storage, const evmc_address& address, const evmc_revision& revision) +{ + if (auto executable = co_await storage2::readOne(getCacheExecutables(), address)) { co_return std::move(*executable); } @@ -111,9 +110,8 @@ inline task::Task> getExecutable( Account> account(storage, address); if (auto codeEntry = co_await ledger::account::code(account)) { - auto executable = - std::make_shared(Executable(std::move(*codeEntry), std::move(revision))); - co_await storage2::writeOne(cachedExecutables, address, executable); + auto executable = std::make_shared(Executable(std::move(*codeEntry), revision)); + co_await storage2::writeOne(getCacheExecutables(), address, executable); co_return executable; } co_return std::shared_ptr{}; diff --git a/transaction-scheduler/bcos-transaction-scheduler/BaselineScheduler.h b/transaction-scheduler/bcos-transaction-scheduler/BaselineScheduler.h index 7df398a7da..a70f798464 100644 --- a/transaction-scheduler/bcos-transaction-scheduler/BaselineScheduler.h +++ b/transaction-scheduler/bcos-transaction-scheduler/BaselineScheduler.h @@ -661,7 +661,7 @@ class BaselineScheduler : public scheduler::SchedulerInterface callback(nullptr); } - void stop() override{}; + void stop() override {}; void registerTransactionNotifier(std::function)>