Skip to content

Commit

Permalink
Add pipeline transaction executor (FISCO-BCOS#4145)
Browse files Browse the repository at this point in the history
  • Loading branch information
morebtcg authored Dec 27, 2023
1 parent 66ba27e commit 2f9b2d0
Show file tree
Hide file tree
Showing 12 changed files with 361 additions and 238 deletions.
79 changes: 31 additions & 48 deletions bcos-framework/bcos-framework/transaction-executor/StateKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ class StateKeyView;

class StateKey
{
private:
friend class StateKeyView;
public:
std::string m_tableAndKey;
size_t m_split{};

public:
StateKey() = default;
StateKey(std::string_view table, std::string_view key)
{
Expand Down Expand Up @@ -63,8 +61,8 @@ class StateKey
stream << stateKey.m_tableAndKey;
return stream;
}
const char* data() const& { return m_tableAndKey.data(); }
size_t size() const { return m_tableAndKey.size(); }
const char* data() const& noexcept { return m_tableAndKey.data(); }
size_t size() const noexcept { return m_tableAndKey.size(); }
};

class StateKeyView
Expand All @@ -74,59 +72,46 @@ class StateKeyView
std::string_view m_key;
friend class StateKey;

constexpr friend std::optional<std::string_view> continuousView(StateKeyView const& view)
{
if ((view.m_table.data() + view.m_table.size() + 1) == view.m_key.data())
{
return std::string_view(
view.m_table.data(), view.m_table.size() + 1 + view.m_key.size());
}
return {};
}

public:
explicit StateKeyView(const StateKey& stateKey)
{
std::string_view view(stateKey.m_tableAndKey);
m_table = view.substr(0, stateKey.m_split);
m_key = view.substr(stateKey.m_split + 1);
}
StateKeyView(std::string_view table, std::string_view key) : m_table(table), m_key(key) {}
explicit StateKeyView(const StateKey& stateKey) noexcept
: m_table(stateKey.data(), stateKey.m_split),
m_key(stateKey.data() + stateKey.m_split + 1, stateKey.size() - stateKey.m_split - 1)
{}
StateKeyView(std::string_view table, std::string_view key) noexcept : m_table(table), m_key(key)
{}

friend std::strong_ordering operator<=>(
const StateKeyView& lhs, const StateKeyView& rhs) noexcept
{
auto lhsContinuousView = continuousView(lhs);
auto rhsContinuousView = continuousView(rhs);
if (lhsContinuousView && rhsContinuousView)
{
return *lhsContinuousView <=> *rhsContinuousView;
}

auto cmp = lhs.m_table <=> rhs.m_table;
if (std::is_eq(cmp))
{
cmp = lhs.m_key <=> rhs.m_key;
}
return cmp;
}
friend bool operator==(const StateKeyView& lhs, const StateKeyView& rhs) = default;
friend std::strong_ordering operator<=>(const StateKeyView& lhs, const StateKey& rhs) noexcept
{
StateKeyView rhsView(rhs);
return lhs <=> rhsView;
}
friend bool operator==(const StateKeyView& lhs, const StateKeyView& rhs) noexcept = default;
friend ::std::ostream& operator<<(::std::ostream& stream, const StateKeyView& stateKeyView)
{
stream << stateKeyView.m_table << ":" << stateKeyView.m_key;
return stream;
}

size_t hash() const
size_t hash() const noexcept
{
auto result = std::hash<std::string_view>{}(m_table);
boost::hash_combine(result, std::hash<std::string_view>{}(m_key));
return result;
}

std::tuple<std::string_view, std::string_view> getTableAndKey() const
std::tuple<std::string_view, std::string_view> getTableAndKey() const noexcept
{
return std::make_tuple(m_table, m_key);
return {m_table, m_key};
}
};

Expand All @@ -138,19 +123,17 @@ template <>
struct std::less<bcos::transaction_executor::StateKey>
{
auto operator()(bcos::transaction_executor::StateKey const& left,
bcos::transaction_executor::StateKeyView const& rightView) const -> bool
bcos::transaction_executor::StateKeyView const& rightView) const noexcept -> bool
{
auto leftView = bcos::transaction_executor::StateKeyView(left);
return leftView < rightView;
return left < rightView;
}
auto operator()(bcos::transaction_executor::StateKeyView const& leftView,
bcos::transaction_executor::StateKey const& right) const -> bool
bcos::transaction_executor::StateKey const& right) const noexcept -> bool
{
auto rightView = bcos::transaction_executor::StateKeyView(right);
return leftView < rightView;
return leftView < right;
}
auto operator()(bcos::transaction_executor::StateKey const& lhs,
bcos::transaction_executor::StateKey const& rhs) const -> bool
bcos::transaction_executor::StateKey const& rhs) const noexcept -> bool
{
return lhs < rhs;
}
Expand All @@ -159,7 +142,7 @@ struct std::less<bcos::transaction_executor::StateKey>
template <>
struct std::hash<bcos::transaction_executor::StateKeyView>
{
size_t operator()(const bcos::transaction_executor::StateKeyView& stateKeyView) const
size_t operator()(const bcos::transaction_executor::StateKeyView& stateKeyView) const noexcept
{
return stateKeyView.hash();
}
Expand All @@ -168,7 +151,7 @@ struct std::hash<bcos::transaction_executor::StateKeyView>
template <>
struct boost::hash<bcos::transaction_executor::StateKeyView>
{
size_t operator()(const bcos::transaction_executor::StateKeyView& stateKeyView) const
size_t operator()(const bcos::transaction_executor::StateKeyView& stateKeyView) const noexcept
{
return stateKeyView.hash();
}
Expand All @@ -177,12 +160,12 @@ struct boost::hash<bcos::transaction_executor::StateKeyView>
template <>
struct std::hash<bcos::transaction_executor::StateKey>
{
size_t operator()(const bcos::transaction_executor::StateKey& stateKey) const
size_t operator()(const bcos::transaction_executor::StateKey& stateKey) const noexcept
{
auto view = bcos::transaction_executor::StateKeyView(stateKey);
return std::hash<bcos::transaction_executor::StateKeyView>{}(view);
}
size_t operator()(const bcos::transaction_executor::StateKeyView& stateKeyView) const
size_t operator()(const bcos::transaction_executor::StateKeyView& stateKeyView) const noexcept
{
return stateKeyView.hash();
}
Expand All @@ -191,11 +174,11 @@ struct std::hash<bcos::transaction_executor::StateKey>
template <>
struct boost::hash<bcos::transaction_executor::StateKey>
{
size_t operator()(const bcos::transaction_executor::StateKey& stateKey) const
size_t operator()(const bcos::transaction_executor::StateKey& stateKey) const noexcept
{
return std::hash<bcos::transaction_executor::StateKey>{}(stateKey);
}
size_t operator()(const bcos::transaction_executor::StateKeyView& stateKeyView) const
size_t operator()(const bcos::transaction_executor::StateKeyView& stateKeyView) const noexcept
{
return stateKeyView.hash();
}
Expand All @@ -205,12 +188,12 @@ template <>
struct std::equal_to<bcos::transaction_executor::StateKey>
{
bool operator()(bcos::transaction_executor::StateKey const& lhs,
bcos::transaction_executor::StateKey const& rhs) const
bcos::transaction_executor::StateKey const& rhs) const noexcept
{
return std::is_eq(lhs <=> rhs);
}
bool operator()(bcos::transaction_executor::StateKeyView const& lhsView,
bcos::transaction_executor::StateKey const& rhs) const
bcos::transaction_executor::StateKey const& rhs) const noexcept
{
auto rhsView = bcos::transaction_executor::StateKeyView(rhs);
return std::is_eq(lhsView <=> rhsView);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
namespace bcos::transaction_executor
{

struct ExecuteTransaction
inline constexpr struct ExecuteTransaction
{
/**
* @brief Executes a transaction and returns a task that resolves to a transaction receipt.
Expand All @@ -38,8 +38,37 @@ struct ExecuteTransaction
co_return co_await tag_invoke(*this, executor, storage, blockHeader, transaction,
std::forward<decltype(args)>(args)...);
}
};
inline constexpr ExecuteTransaction executeTransaction{};
} executeTransaction{};

inline constexpr struct Execute3Step
{
/**
* @brief Executes a transaction in three steps.
*
* This function is a friend function of the TransactionExecutorImpl class.
* It executes a transaction in three steps and returns a generator that yields
* transaction receipts.
*
* 分三个步骤执行交易,可流水线执行
* Transaction are executed in three steps, which can be pipelined
*
* @param executor The reference to the TransactionExecutorImpl object.
* @param storage The reference to the storage object.
* @param blockHeader The reference to the block header object.
* @param transaction The reference to the transaction object.
* @param contextID The context ID.
* @param ledgerConfig The reference to the ledger configuration object.
* @param waitOperator The wait operator.
*
* @return A generator that yields transaction receipts.
*/
auto operator()(auto& executor, auto& storage, protocol::BlockHeader const& blockHeader,
protocol::Transaction const& transaction, auto&&... args) const
{
return tag_invoke(*this, executor, storage, blockHeader, transaction,
std::forward<decltype(args)>(args)...);
}
} execute3Step{};

template <auto& Tag>
using tag_t = std::decay_t<decltype(Tag)>;
Expand Down
1 change: 1 addition & 0 deletions transaction-executor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ find_package(jsoncpp REQUIRED)
add_library(transaction-executor
bcos-transaction-executor/vm/VMInstance.cpp
bcos-transaction-executor/precompiled/PrecompiledManager.cpp
bcos-transaction-executor/vm/HostContext.cpp
)
target_include_directories(transaction-executor PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
Expand Down
1 change: 0 additions & 1 deletion transaction-executor/bcos-transaction-executor/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

namespace bcos::transaction_executor
{

class EVMCResult : public evmc_result
{
public:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#pragma once

#include "RollbackableStorage.h"
#include "bcos-framework/protocol/BlockHeader.h"
#include "bcos-framework/protocol/TransactionReceiptFactory.h"
#include "bcos-framework/storage2/MemoryStorage.h"
#include "bcos-table/src/StateStorage.h"
#include "bcos-framework/storage2/Storage.h"
#include "bcos-framework/transaction-executor/TransactionExecutor.h"
#include "bcos-task/Generator.h"
#include "bcos-transaction-executor/vm/VMFactory.h"
#include "precompiled/PrecompiledManager.h"
#include "transaction-executor/bcos-transaction-executor/RollbackableStorage.h"
#include "transaction-executor/bcos-transaction-executor/vm/VMInstance.h"
#include "vm/HostContext.h"
#include <bcos-framework/protocol/BlockHeader.h>
#include <bcos-framework/protocol/TransactionReceiptFactory.h>
#include <bcos-framework/storage2/Storage.h>
#include <bcos-framework/transaction-executor/TransactionExecutor.h>
#include "vm/VMInstance.h"
#include <evmc/evmc.h>
#include <boost/algorithm/hex.hpp>
#include <boost/exception/diagnostic_information.hpp>
Expand All @@ -36,17 +36,19 @@ class TransactionExecutorImpl
m_precompiledManager(m_hashImpl)
{}


private:
VMFactory m_vmFactory;
protocol::TransactionReceiptFactory const& m_receiptFactory;
crypto::Hash::Ptr m_hashImpl;
PrecompiledManager m_precompiledManager;

friend task::Task<protocol::TransactionReceipt::Ptr> tag_invoke(
tag_t<executeTransaction> /*unused*/, TransactionExecutorImpl& executor, auto& storage,
friend task::Generator<protocol::TransactionReceipt::Ptr> tag_invoke(
tag_t<execute3Step> /*unused*/, TransactionExecutorImpl& executor, auto& storage,
protocol::BlockHeader const& blockHeader, protocol::Transaction const& transaction,
int contextID, ledger::LedgerConfig const& ledgerConfig, auto&& waitOperator)
{
protocol::TransactionReceipt::Ptr receipt;
try
{
if (c_fileLogLevel <= LogLevel::TRACE)
Expand Down Expand Up @@ -78,18 +80,23 @@ class TransactionExecutorImpl
.create2_salt = {},
.code_address = toAddress};

if (ledgerConfig.authCheckStatus() != 0 && blockHeader.number() == 0 &&
if (blockHeader.number() == 0 &&
transaction.to() == precompiled::AUTH_COMMITTEE_ADDRESS)
{
evmcMessage.kind = EVMC_CREATE;
}

int64_t seq = 0;
HostContext<decltype(rollbackableStorage)> hostContext(executor.m_vmFactory,
rollbackableStorage, blockHeader, evmcMessage, evmcMessage.sender,
transaction.abi(), contextID, seq, executor.m_precompiledManager, ledgerConfig,
*executor.m_hashImpl, std::forward<decltype(waitOperator)>(waitOperator));
auto evmcResult = co_await hostContext.execute();
HostContext<decltype(rollbackableStorage)> hostContext(rollbackableStorage, blockHeader,
evmcMessage, evmcMessage.sender, transaction.abi(), contextID, seq,
executor.m_precompiledManager, ledgerConfig, *executor.m_hashImpl,
std::forward<decltype(waitOperator)>(waitOperator));

waitOperator(hostContext.prepare());
co_yield receipt; // 完成第一步 Complete the first step

auto evmcResult = waitOperator(hostContext.execute());
co_yield receipt; // 完成第二步 Complete the second step

bcos::bytesConstRef output;
std::string newContractAddress;
Expand All @@ -111,22 +118,45 @@ class TransactionExecutorImpl
}

auto const& logEntries = hostContext.logs();
auto receipt = executor.m_receiptFactory.createReceipt(gasLimit - evmcResult.gas_left,
receipt = executor.m_receiptFactory.createReceipt(gasLimit - evmcResult.gas_left,
std::move(newContractAddress), logEntries, evmcResult.status_code, output,
blockHeader.number(), false);
blockHeader.number());
}
catch (NotFoundCodeError& e)
{
TRANSACTION_EXECUTOR_LOG(DEBUG)
<< "Not found code exception: " << boost::diagnostic_information(e);

co_return receipt;
receipt = executor.m_receiptFactory.createReceipt(
0, {}, {}, EVMC_REVERT, {}, blockHeader.number());
receipt->setMessage(boost::diagnostic_information(e));
}
catch (std::exception& e)
{
TRANSACTION_EXECUTOR_LOG(DEBUG)
<< "Execute exception: " << boost::diagnostic_information(e);

auto receipt = executor.m_receiptFactory.createReceipt(
receipt = executor.m_receiptFactory.createReceipt(
0, {}, {}, EVMC_INTERNAL_ERROR, {}, blockHeader.number());
receipt->setMessage(boost::diagnostic_information(e));
co_return receipt;
}
co_yield receipt; // 完成第三步 Complete the third step
}

friend task::Task<protocol::TransactionReceipt::Ptr> tag_invoke(
tag_t<executeTransaction> /*unused*/, TransactionExecutorImpl& executor, auto& storage,
protocol::BlockHeader const& blockHeader, protocol::Transaction const& transaction,
int contextID, ledger::LedgerConfig const& ledgerConfig, auto&& waitOperator)
{
for (auto receipt : execute3Step(executor, storage, blockHeader, transaction, contextID,
ledgerConfig, std::forward<decltype(waitOperator)>(waitOperator)))
{
if (receipt)
{
co_return receipt;
}
}
co_return protocol::TransactionReceipt::Ptr{};
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ inline auto buildLegacyExecutive(auto& storage, protocol::BlockHeader const& blo
using Precompiled =
std::variant<executor::PrecompiledContract, std::shared_ptr<precompiled::Precompiled>>;

inline EVMCResult call(Precompiled const& precompiled, auto& storage,
inline EVMCResult callPrecompiled(Precompiled const& precompiled, auto& storage,
protocol::BlockHeader const& blockHeader, evmc_message const& message,
evmc_address const& origin, ExternalCaller auto&& externalCaller,
auto const& precompiledManager)
Expand Down
10 changes: 10 additions & 0 deletions transaction-executor/bcos-transaction-executor/vm/HostContext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "HostContext.h"

evmc_bytes32 bcos::transaction_executor::evm_hash_fn(const uint8_t* data, size_t size)
{
return toEvmC(executor::GlobalHashImpl::g_hashImpl->hash(bytesConstRef(data, size)));
}
bcos::executor::VMSchedule const& bcos::transaction_executor::vmSchedule()
{
return executor::FiscoBcosScheduleV320;
}
Loading

0 comments on commit 2f9b2d0

Please sign in to comment.