Skip to content

Commit

Permalink
<feat>(ledger,executor): add eoa and contract nonce calculate. (FISCO…
Browse files Browse the repository at this point in the history
…-BCOS#4597)

Co-authored-by: MO NAN <[email protected]>
  • Loading branch information
kyonRay and morebtcg authored Aug 29, 2024
1 parent d70c2c6 commit 5e17db7
Show file tree
Hide file tree
Showing 23 changed files with 296 additions and 25 deletions.
19 changes: 19 additions & 0 deletions bcos-executor/src/vm/HostContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "bcos-table/src/StateStorage.h"
#include "evmc/evmc.hpp"
#include <bcos-framework/executor/ExecutionMessage.h>
#include <bcos-framework/ledger/EVMAccount.h>
#include <bcos-framework/protocol/Protocol.h>
#include <bcos-utilities/Common.h>
#include <evmc/evmc.h>
Expand Down Expand Up @@ -243,6 +244,24 @@ evmc_result HostContext::externalRequest(const evmc_message* _msg)
}
}

if (request->create && features().get(ledger::Features::Flag::feature_evm_address)) [[unlikely]]
{
// account must exist
ledger::account::EVMAccount account(
*m_executive->storage().getRawStorage(), request->senderAddress);
task::wait([](decltype(account) account) -> task::Task<void> {
if (auto const nonceString = co_await ledger::account::nonce(account))
{
auto const nonce = std::stoull(nonceString.value());
co_await ledger::account::setNonce(account, std::to_string(nonce + 1));
}
else
{
co_await ledger::account::setNonce(account, "1");
}
}(std::move(account)));
}

auto response = m_executive->externalCall(std::move(request));

// Convert CallParameters to evmc_resultx
Expand Down
19 changes: 19 additions & 0 deletions bcos-executor/test/unittest/libexecutor/TestEVMExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <bcos-crypto/interfaces/crypto/Hash.h>
#include <bcos-crypto/signature/secp256k1/Secp256k1Crypto.h>
#include <bcos-framework/executor/NativeExecutionMessage.h>
#include <bcos-framework/ledger/EVMAccount.h>
#include <bcos-framework/protocol/Protocol.h>
#include <boost/algorithm/hex.hpp>
#include <boost/algorithm/string.hpp>
Expand Down Expand Up @@ -95,12 +96,14 @@ struct TransactionExecutorFixture
fromHexString("ff6f30856ad3bae00b1169808488502786a13e3c174d85682135ffd51310310e")
->data(),
32);
// address: "11ac3ca85a307ae2aff614e83949ab691ba019c5"
memcpy(keyPair->publicKey()->mutableData(),
fromHexString(
"ccd8de502ac45462767e649b462b5f4ca7eadd69c7e1f1b410bdf754359be29b1b88ffd79744"
"03f56e250af52b25682014554f7b3297d6152401e85d426a06ae")
->data(),
64);
eoa = keyPair->address(hashImpl).hex();

codec = std::make_unique<bcos::CodecWrapper>(hashImpl, false);
}
Expand All @@ -112,6 +115,7 @@ struct TransactionExecutorFixture
std::shared_ptr<MockTransactionalStorage> backend;
std::shared_ptr<MockLedger> ledger;
std::shared_ptr<Keccak256> hashImpl;
std::string eoa;

KeyPairInterface::Ptr keyPair;
int64_t gas = 3000000;
Expand Down Expand Up @@ -368,6 +372,10 @@ BOOST_AUTO_TEST_CASE(externalCall)
// Solidity source code from test_external_call.sol, using remix
// 0.6.10+commit.00c0fcaf

ledger::SystemConfigEntry se = {"1", 0};
storage::Entry entry;
entry.setObject(se);
backend->setRow(ledger::SYS_CONFIG, "feature_evm_address", entry);
std::string ABin =
"608060405234801561001057600080fd5b5061037f806100206000396000f3fe60806040523480156100105760"
"0080fd5b506004361061002b5760003560e01c80635b975a7314610030575b600080fd5b61005c600480360360"
Expand Down Expand Up @@ -712,6 +720,17 @@ BOOST_AUTO_TEST_CASE(externalCall)

auto expectResult2 = codec->encode(s256(1000));
BOOST_CHECK(callResult2->data().toBytes() == expectResult);

std::string tableName;
tableName.append(ledger::SYS_DIRECTORY::USER_APPS);
tableName.append(address);

{
auto [e, nonceEntry] = backend->getRow(tableName, ledger::ACCOUNT_TABLE_FIELDS::NONCE);
BOOST_CHECK(!e);
BOOST_CHECK(nonceEntry);
BOOST_CHECK_EQUAL(nonceEntry->get(), "1");
}
}

BOOST_AUTO_TEST_CASE(performance)
Expand Down
3 changes: 2 additions & 1 deletion bcos-executor/test/unittest/mock/MockLedger.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class MockLedger : public bcos::ledger::LedgerInterface

void asyncPrewriteBlock(bcos::storage::StorageInterface::Ptr storage,
bcos::protocol::ConstTransactionsPtr _blockTxs, bcos::protocol::Block::ConstPtr block,
std::function<void(std::string, Error::Ptr&&)> callback, bool writeTxsAndReceipts) override
std::function<void(std::string, Error::Ptr&&)> callback, bool writeTxsAndReceipts,
std::optional<bcos::ledger::Features> features) override
{
BOOST_CHECK(false); // Need implementations
};
Expand Down
8 changes: 8 additions & 0 deletions bcos-executor/test/unittest/mock/MockTransactionalStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ class MockTransactionalStorage : public bcos::storage::TransactionalStorageInter
m_inner->asyncSetRow(table, key, std::move(entry), std::move(callback));
}

void setRow(std::string_view table, std::string_view key, storage::Entry entry) noexcept
{
std::promise<Error::UniquePtr> promise;
m_inner->asyncSetRow(table, key, std::move(entry),
[&](auto&& error) { promise.set_value(std::move(error)); });
promise.get_future().get();
}

void asyncOpenTable(std::string_view tableName,
std::function<void(Error::UniquePtr, std::optional<storage::Table>)> callback) noexcept
override
Expand Down
25 changes: 25 additions & 0 deletions bcos-framework/bcos-framework/ledger/Account.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
namespace bcos::ledger::account
{

inline constexpr struct IsExist
{
task::Task<bool> operator()(auto& account, auto&&... args) const
{
co_return co_await tag_invoke(*this, account, std::forward<decltype(args)>(args)...);
}
} isExist{};

inline constexpr struct Create
{
auto operator()(auto& account, auto&&... args) const
Expand Down Expand Up @@ -82,6 +90,23 @@ inline constexpr struct SetBalance
}
} setBalance{};

inline constexpr struct Nonce
{
auto operator()(auto& account, auto&&... args) const -> task::Task<std::optional<std::string>>
{
co_return co_await tag_invoke(*this, account, std::forward<decltype(args)>(args)...);
}
} nonce{};

inline constexpr struct SetNonce
{
task::Task<void> operator()(auto& account, auto&& nonce, auto&&... args) const
{
co_await tag_invoke(*this, account, std::forward<decltype(nonce)>(nonce),
std::forward<decltype(args)>(args)...);
}
} setNonce{};

inline constexpr struct Storage
{
auto operator()(auto& account, auto&& key, auto&&... args) const
Expand Down
46 changes: 46 additions & 0 deletions bcos-framework/bcos-framework/ledger/EVMAccount.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ class EVMAccount
std::reference_wrapper<Storage> m_storage;
std::string m_tableName;

friend task::Task<bool> tag_invoke(tag_t<isExist> /*unused*/, EVMAccount& account)
{
co_return co_await storage2::existsOne(account.m_storage.get(),
transaction_executor::StateKeyView(SYS_TABLES, account.m_tableName));
}

friend task::Task<void> tag_invoke(tag_t<create> /*unused*/, EVMAccount& account)
{
co_await storage2::writeOne(account.m_storage.get(),
Expand Down Expand Up @@ -146,6 +152,28 @@ class EVMAccount
std::move(balanceEntry));
}

friend task::Task<std::optional<std::string>> tag_invoke(
tag_t<nonce> /*unused*/, EVMAccount& account)
{
if (auto entry = co_await storage2::readOne(
account.m_storage.get(), transaction_executor::StateKeyView{
account.m_tableName, ACCOUNT_TABLE_FIELDS::NONCE}))
{
auto view = entry->get();
co_return std::string(view);
}
co_return std::nullopt;
}

friend task::Task<void> tag_invoke(
tag_t<setNonce> /*unused*/, EVMAccount& account, std::string nonce)
{
storage::Entry nonceEntry(std::move(nonce));
co_await storage2::writeOne(account.m_storage.get(),
transaction_executor::StateKey{account.m_tableName, ACCOUNT_TABLE_FIELDS::NONCE},
std::move(nonceEntry));
}

friend task::Task<evmc_bytes32> tag_invoke(
tag_t<storage> /*unused*/, EVMAccount& account, const evmc_bytes32& key)
{
Expand Down Expand Up @@ -202,6 +230,24 @@ class EVMAccount
}
m_tableName.append(std::string_view(table.data(), table.size()));
}

/**
* @brief Construct a new EVMAccount object
* @param storage storage instance
* @param address address of the account, hex string, should not contain 0x prefix
*/
EVMAccount(Storage& storage, bcos::concepts::StringLike auto address) : m_storage(storage)
{
if (bcos::precompiled::c_systemTxsAddress.contains(address))
{
m_tableName.append(ledger::SYS_DIRECTORY::SYS_APPS);
}
else
{
m_tableName.append(ledger::SYS_DIRECTORY::USER_APPS);
}
m_tableName.append(address);
}
~EVMAccount() noexcept = default;
};

Expand Down
2 changes: 2 additions & 0 deletions bcos-framework/bcos-framework/ledger/Features.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class Features
feature_balance_policy1,
feature_paillier_add_raw,
feature_evm_cancun,
feature_evm_address,
feature_ethereum_compatible, // will enbale all bugfixes, all features about evm
};

private:
Expand Down
18 changes: 17 additions & 1 deletion bcos-framework/bcos-framework/ledger/LedgerInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "../protocol/Transaction.h"
#include "../protocol/TransactionReceipt.h"
#include "../storage/StorageInterface.h"
#include "Features.h"
#include "LedgerTypeDef.h"
#include <bcos-crypto/interfaces/crypto/CommonType.h>
#include <bcos-task/Task.h>
Expand All @@ -50,7 +51,8 @@ class LedgerInterface
*/
virtual void asyncPrewriteBlock(bcos::storage::StorageInterface::Ptr storage,
bcos::protocol::ConstTransactionsPtr _blockTxs, bcos::protocol::Block::ConstPtr block,
std::function<void(std::string, Error::Ptr&&)> callback, bool writeTxsAndReceipts) = 0;
std::function<void(std::string, Error::Ptr&&)> callback, bool writeTxsAndReceipts,
std::optional<bcos::ledger::Features> features) = 0;

/**
* @brief async store txs in block when tx pool verify
Expand Down Expand Up @@ -195,6 +197,20 @@ class LedgerInterface
{
co_return std::nullopt;
}


virtual task::Task<void> batchInsertEoaNonce(bcos::storage::StorageInterface::Ptr storage,
std::unordered_map<std::string, uint64_t> eoa2Nonce,
std::unordered_map<std::string, uint64_t> fbEoa2Nonce)
{
co_return;
}

virtual task::Task<std::optional<ledger::StorageState>> getStorageState(
std::string_view _address, protocol::BlockNumber _blockNumber)
{
co_return std::nullopt;
}
};

} // namespace bcos::ledger
4 changes: 4 additions & 0 deletions bcos-framework/bcos-framework/ledger/LedgerTypeDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,8 @@ enum LedgerError : int32_t
EmptyEntry = 3009,
UnknownError = 3010,
};
struct StorageState{
std::string nonce;
std::string balance;
};
} // namespace bcos::ledger
3 changes: 2 additions & 1 deletion bcos-framework/bcos-framework/testutils/faker/FakeLedger.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ class FakeLedger : public LedgerInterface, public std::enable_shared_from_this<F

void asyncPrewriteBlock(bcos::storage::StorageInterface::Ptr storage,
bcos::protocol::ConstTransactionsPtr, bcos::protocol::Block::ConstPtr block,
std::function<void(std::string, Error::Ptr&&)> callback, bool writeTxsAndReceipts) override
std::function<void(std::string, Error::Ptr&&)> callback, bool writeTxsAndReceipts,
std::optional<bcos::ledger::Features> features) override
{
(void)storage;
(void)block;
Expand Down
4 changes: 3 additions & 1 deletion bcos-framework/test/unittests/interfaces/FeaturesTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ BOOST_AUTO_TEST_CASE(feature)
"feature_balance_precompiled",
"feature_balance_policy1",
"feature_paillier_add_raw",
"feature_evm_cancun"
"feature_evm_cancun",
"feature_evm_address",
"feature_ethereum_compatible",
};
// clang-format on
for (size_t i = 0; i < keys.size(); ++i)
Expand Down
Loading

0 comments on commit 5e17db7

Please sign in to comment.