diff --git a/.github/workflows/workflow-self-hosted-ubuntu-upload.yml b/.github/workflows/workflow-self-hosted-ubuntu-upload.yml index 6a67536cb3..00fe276f68 100644 --- a/.github/workflows/workflow-self-hosted-ubuntu-upload.yml +++ b/.github/workflows/workflow-self-hosted-ubuntu-upload.yml @@ -77,7 +77,7 @@ jobs: export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" cd build && cmake -DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DTESTS=OFF -DCOVERAGE=OFF -DWITH_LIGHTNODE=ON -DWITH_CPPSDK=ON -DWITH_TIKV=OFF -DWITH_TARS_SERVICES=OFF -DTOOLS=OFF -DBUILD_STATIC=ON -DALLOCATOR=default .. || cat *.log make -j6 - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: fisco-bcos.tar.gz path: build/fisco-bcos-air/fisco-bcos \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b5e6bf017..281917525f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ endif() list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) -set(VERSION "3.13.0") +set(VERSION "3.14.0") set(VERSION_SUFFIX "") include(Options) configure_project() diff --git a/bcos-executor/src/executive/TransactionExecutive.cpp b/bcos-executor/src/executive/TransactionExecutive.cpp index 577c72a76d..cb70e4643d 100644 --- a/bcos-executor/src/executive/TransactionExecutive.cpp +++ b/bcos-executor/src/executive/TransactionExecutive.cpp @@ -77,8 +77,33 @@ 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; @@ -310,32 +335,50 @@ CallParameters::UniquePtr TransactionExecutive::execute(CallParameters::UniquePt } } - if (!callParameters->staticCall && - m_blockContext.features().get(ledger::Features::Flag::feature_evm_address)) [[unlikely]] + if (m_blockContext.features().get( + ledger::Features::Flag::bugfix_nonce_not_increase_when_revert)) { - // 如果是EOA发起交易,那么必须要更新nonce; - // 如果是合约调用合约,那么只有在create场景下才更新nonce。 - // If it is an EOA initiating a transaction, the nonce must be updated; if it is a contract - // calling a contract, the nonce is updated only in the creation scenario. - if ((callParameters->origin == callParameters->senderAddress && - callParameters->transactionType != 0) || - (callParameters->create && !callParameters->internalCreate)) + // only update contract's nonce when contract create contract + if (callParameters->origin != callParameters->senderAddress && callParameters->create && + !callParameters->internalCreate) { - // TODO)): set nonce here will be better ledger::account::EVMAccount address(*m_blockContext.storage(), callParameters->senderAddress, 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); - // FIXME)) : only web3 tx use this - 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), callParameters->nonce)); + task::wait([](decltype(address) addr) -> task::Task { + co_await ledger::account::increaseNonce(addr); + }(std::move(address))); + } + } + else + { + if (!callParameters->staticCall && + m_blockContext.features().get(ledger::Features::Flag::feature_evm_address)) [[unlikely]] + { + // 如果是EOA发起交易,那么必须要更新nonce; + // 如果是合约调用合约,那么只有在create场景下才更新nonce。 + // If it is an EOA initiating a transaction, the nonce must be updated; if it is a + // contract calling a contract, the nonce is updated only in the creation scenario. + if ((callParameters->origin == callParameters->senderAddress && + callParameters->transactionType != 0) || + (callParameters->create && !callParameters->internalCreate)) + { + // TODO)): set nonce here will be better + ledger::account::EVMAccount address(*m_blockContext.storage(), + callParameters->senderAddress, + 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); + // FIXME)) : only web3 tx use this + 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), callParameters->nonce)); + } } } @@ -751,6 +794,17 @@ std::tuple, CallParameters::UniquePtr> TransactionE << LOG_KV("value", callParameters->value); } + if (m_blockContext.features().get( + ledger::Features::Flag::bugfix_set_contract_nonce_when_create)) [[unlikely]] + { + // set nonce to 1 when create contract + ledger::account::EVMAccount account( + *m_blockContext.storage(), callParameters->codeAddress, false); + task::wait([](decltype(account) contract_account) -> task::Task { + co_await ledger::account::setNonce(contract_account, "1"); + }(std::move(account))); + } + if (m_blockContext.features().get(ledger::Features::Flag::feature_sharding)) { if (callParameters->origin != callParameters->senderAddress) diff --git a/bcos-executor/src/vm/HostContext.cpp b/bcos-executor/src/vm/HostContext.cpp index ad4b9b5f3c..20f1d1bad5 100644 --- a/bcos-executor/src/vm/HostContext.cpp +++ b/bcos-executor/src/vm/HostContext.cpp @@ -239,6 +239,8 @@ evmc_result HostContext::externalRequest(const evmc_message* _msg) } } + request->transactionType = m_callParameters->transactionType; + if (request->create && features().get(ledger::Features::Flag::feature_evm_address)) [[unlikely]] { // account must exist diff --git a/bcos-executor/test/unittest/fixture/TransactionFixture.h b/bcos-executor/test/unittest/fixture/TransactionFixture.h new file mode 100644 index 0000000000..a011f58f96 --- /dev/null +++ b/bcos-executor/test/unittest/fixture/TransactionFixture.h @@ -0,0 +1,485 @@ +/** + * 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 TransactionFixture.h + * @author: kyonGuo + * @date 2025/2/13 + */ + +/** + * Copyright (C) 2021 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 TransactionFixture.h + * @author: kyonRay + * @date 2021-06-19 + */ + +#pragma once +#include "bcos-codec/scale/Scale.h" +#include "bcos-framework/ledger/Features.h" +#include "bcos-framework/storage/LegacyStorageMethods.h" +#include "executor/TransactionExecutorFactory.h" +#include "libtask/bcos-task/Wait.h" +#include "mock/MockKeyPageStorage.h" +#include "mock/MockLedger.h" +#include "mock/MockTransactionalStorage.h" +#include "mock/MockTxPool.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace bcos; +using namespace bcos::precompiled; +using namespace bcos::executor; +using namespace bcos::storage; +using namespace bcos::ledger; +using namespace bcos::crypto; + +namespace bcos::test +{ +class TransactionFixture : public TestPromptFixture +{ +public: + TransactionFixture() + { + hashImpl = std::make_shared(); + assert(hashImpl); + smHashImpl = std::make_shared(); + auto signatureImpl = std::make_shared(); + auto sm2Sign = std::make_shared(); + assert(signatureImpl); + cryptoSuite = std::make_shared(hashImpl, signatureImpl, nullptr); + assert(cryptoSuite); + smCryptoSuite = std::make_shared(smHashImpl, sm2Sign, nullptr); + txpool = std::make_shared(); + } + + ~TransactionFixture() override = default; + + /// must set isWasm + void setIsWasm(bool _isWasm, bool _isCheckAuth = false, bool _isKeyPage = false, + protocol::BlockVersion version = DEFAULT_VERSION, + std::shared_ptr>> _ignoreTables = nullptr) + { + isWasm = _isWasm; + storage = std::make_shared(hashImpl); + if (_isKeyPage) + { + if (_ignoreTables != nullptr) + { + storage = std::make_shared( + hashImpl, (uint32_t)m_blockVersion, _ignoreTables); + } + else + { + storage = std::make_shared(hashImpl); + } + } + blockFactory = createBlockFactory(cryptoSuite); + auto header = blockFactory->blockHeaderFactory()->createBlockHeader(1); + header->setNumber(1); + ledger = std::make_shared(storage); + ledger->setBlockNumber(header->number() - 1); + std::promise p; + Entry authEntry; + authEntry.setObject(SystemConfigEntry(_isCheckAuth ? "1" : "0", 0)); + storage->asyncSetRow(ledger::SYS_CONFIG, ledger::SYSTEM_KEY_AUTH_CHECK_STATUS, + std::move(authEntry), [&p](auto&& e) { p.set_value(true); }); + p.get_future().get(); + + const auto executionResultFactory = std::make_shared(); + const auto stateStorageFactory = std::make_shared(0); + executor = bcos::executor::TransactionExecutorFactory::build(ledger, txpool, nullptr, + storage, executionResultFactory, stateStorageFactory, hashImpl, _isWasm, _isCheckAuth, + std::string("executor")); + if (_ignoreTables != nullptr) + { + executor->setKeyPageIgnoreTable(_ignoreTables); + } + + codec = std::make_shared(hashImpl, _isWasm); + keyPair = cryptoSuite->signatureImpl()->generateKeyPair(); + memcpy(keyPair->secretKey()->mutableData(), + fromHexString("ff6f30856ad3bae00b1169808488502786a13e3c174d85682135ffd51310310e") + ->data(), + 32); + memcpy(keyPair->publicKey()->mutableData(), + fromHexString( + "ccd8de502ac45462767e649b462b5f4ca7eadd69c7e1f1b410bdf754359be29b1b88ffd79744" + "03f56e250af52b25682014554f7b3297d6152401e85d426a06ae") + ->data(), + 64); + boost::log::core::get()->set_logging_enabled(false); + createSysTable(version); + boost::log::core::get()->set_logging_enabled(true); + if (_isCheckAuth) + { + boost::log::core::get()->set_logging_enabled(false); + deployAuthSolidity(1); + boost::log::core::get()->set_logging_enabled(true); + } + } + +protected: + void nextBlock(int64_t const blockNumber, + protocol::BlockVersion version = protocol::DEFAULT_VERSION, + Features const enableFeatures = {}) + { + if (blockNumber < 0) [[unlikely]] + { + // for parallel test + return; + } + auto const blockHeader = std::make_shared( + [m_blockHeader = bcostars::BlockHeader()]() mutable { return &m_blockHeader; }); + blockHeader->setNumber(blockNumber); + Features features; + for (auto [flag, _, value] : enableFeatures.flags()) + { + if (value) + { + features.set(flag); + } + } + + features.setUpgradeFeatures(BlockVersion::V3_0_VERSION, version); + + task::syncWait(ledger::writeToStorage(features, *storage, blockNumber)); + + bcos::protocol::ParentInfo p{ + .blockNumber = blockNumber - 1, .blockHash = h256(blockNumber - 1)}; + std::vector parentInfos{p}; + blockHeader->setParentInfo(parentInfos); + + blockHeader->setVersion((uint32_t)version); + ledger->setBlockNumber(blockNumber - 1); + blockHeader->calculateHash(*cryptoSuite->hashImpl()); + std::promise nextPromise; + executor->nextBlockHeader( + 0, blockHeader, [&](bcos::Error::Ptr&& error) { nextPromise.set_value(); }); + nextPromise.get_future().get(); + } + + void commitBlock(protocol::BlockNumber blockNumber) + { + if (blockNumber < 0) [[unlikely]] + { + // for parallel test + return; + } + + TwoPCParams commitParams{}; + commitParams.number = blockNumber; + + std::promise preparePromise; + executor->prepare( + commitParams, [&](bcos::Error::Ptr&& error) { preparePromise.set_value(); }); + preparePromise.get_future().get(); + + std::promise commitPromise; + executor->commit( + commitParams, [&](bcos::Error::Ptr&& error) { commitPromise.set_value(); }); + commitPromise.get_future().get(); + } + +private: + void createSysTable(protocol::BlockVersion version, + std::vector features = {"feature_sharding", "bugfix_event_log_order"}) + { + // create sys table + { + std::promise> promise1; + storage->asyncCreateTable(std::string{ledger::SYS_CONFIG}, "value", + [&](Error::UniquePtr&& _error, std::optional&& _table) { + BOOST_CHECK(!_error); + promise1.set_value(std::move(_table)); + }); + auto table = promise1.get_future().get(); + auto entry = table->newEntry(); + entry.setObject(SystemConfigEntry{"3000000", 0}); + table->setRow(SYSTEM_KEY_TX_GAS_LIMIT, std::move(entry)); + + // for each feature + for (auto& feature : features) + { + Entry featureEntry; + featureEntry.setObject(SystemConfigEntry{"1", 0}); + table->setRow(feature, std::move(featureEntry)); + } + } + + m_blockVersion = version; + if (m_blockVersion >= protocol::BlockVersion::V3_1_VERSION) + { + initBfs(1); + } + else + { + // create / table + { + std::promise> promise2; + storage->asyncCreateTable( + "/", "value", [&](Error::UniquePtr&& _error, std::optional
&& _table) { + BOOST_CHECK(!_error); + promise2.set_value(std::move(_table)); + }); + auto rootTable = promise2.get_future().get(); + storage::Entry tEntry, newSubEntry, aclTypeEntry, aclWEntry, aclBEntry, extraEntry; + std::map newSubMap; + newSubMap.insert(std::make_pair("apps", executor::FS_TYPE_DIR)); + newSubMap.insert(std::make_pair("sys", executor::FS_TYPE_DIR)); + newSubMap.insert(std::make_pair("tables", executor::FS_TYPE_DIR)); + tEntry.importFields({executor::FS_TYPE_DIR}); + newSubEntry.importFields({asString(codec::scale::encode(newSubMap))}); + aclTypeEntry.importFields({"0"}); + aclWEntry.importFields({""}); + aclBEntry.importFields({""}); + extraEntry.importFields({""}); + rootTable->setRow(executor::FS_KEY_TYPE, std::move(tEntry)); + rootTable->setRow(executor::FS_KEY_SUB, std::move(newSubEntry)); + rootTable->setRow(executor::FS_ACL_TYPE, std::move(aclTypeEntry)); + rootTable->setRow(executor::FS_ACL_WHITE, std::move(aclWEntry)); + rootTable->setRow(executor::FS_ACL_BLACK, std::move(aclBEntry)); + rootTable->setRow(executor::FS_KEY_EXTRA, std::move(extraEntry)); + } + + // create /tables table + { + std::promise> promise3; + storage->asyncCreateTable("/tables", "value", + [&](Error::UniquePtr&& _error, std::optional
&& _table) { + BOOST_CHECK(!_error); + promise3.set_value(std::move(_table)); + }); + auto tablesTable = promise3.get_future().get(); + storage::Entry tEntry, newSubEntry, aclTypeEntry, aclWEntry, aclBEntry, extraEntry; + std::map newSubMap; + tEntry.importFields({executor::FS_TYPE_DIR}); + newSubEntry.importFields({asString(codec::scale::encode(newSubMap))}); + aclTypeEntry.importFields({"0"}); + aclWEntry.importFields({""}); + aclBEntry.importFields({""}); + extraEntry.importFields({""}); + tablesTable->setRow(executor::FS_KEY_TYPE, std::move(tEntry)); + tablesTable->setRow(executor::FS_KEY_SUB, std::move(newSubEntry)); + tablesTable->setRow(executor::FS_ACL_TYPE, std::move(aclTypeEntry)); + tablesTable->setRow(executor::FS_ACL_WHITE, std::move(aclWEntry)); + tablesTable->setRow(executor::FS_ACL_BLACK, std::move(aclBEntry)); + tablesTable->setRow(executor::FS_KEY_EXTRA, std::move(extraEntry)); + } + + // create /apps table + { + std::promise> promise4; + storage->asyncCreateTable("/apps", "value", + [&](Error::UniquePtr&& _error, std::optional
&& _table) { + BOOST_CHECK(!_error); + promise4.set_value(std::move(_table)); + }); + auto appsTable = promise4.get_future().get(); + storage::Entry tEntry, newSubEntry, aclTypeEntry, aclWEntry, aclBEntry, extraEntry; + std::map newSubMap; + tEntry.importFields({executor::FS_TYPE_DIR}); + newSubEntry.importFields({asString(codec::scale::encode(newSubMap))}); + aclTypeEntry.importFields({"0"}); + aclWEntry.importFields({""}); + aclBEntry.importFields({""}); + extraEntry.importFields({""}); + appsTable->setRow(executor::FS_KEY_TYPE, std::move(tEntry)); + appsTable->setRow(executor::FS_KEY_SUB, std::move(newSubEntry)); + appsTable->setRow(executor::FS_ACL_TYPE, std::move(aclTypeEntry)); + appsTable->setRow(executor::FS_ACL_WHITE, std::move(aclWEntry)); + appsTable->setRow(executor::FS_ACL_BLACK, std::move(aclBEntry)); + appsTable->setRow(executor::FS_KEY_EXTRA, std::move(extraEntry)); + } + + // create /sys table + { + std::promise> promise4; + storage->asyncCreateTable( + "/sys", "value", [&](Error::UniquePtr&& _error, std::optional
&& _table) { + BOOST_CHECK(!_error); + promise4.set_value(std::move(_table)); + }); + auto appsTable = promise4.get_future().get(); + storage::Entry tEntry, newSubEntry, aclTypeEntry, aclWEntry, aclBEntry, extraEntry; + std::map newSubMap; + newSubMap.insert({"auth", "contract"}); + tEntry.importFields({executor::FS_TYPE_DIR}); + newSubEntry.importFields({asString(codec::scale::encode(newSubMap))}); + aclTypeEntry.importFields({"0"}); + aclWEntry.importFields({""}); + aclBEntry.importFields({""}); + extraEntry.importFields({""}); + appsTable->setRow(executor::FS_KEY_TYPE, std::move(tEntry)); + appsTable->setRow(executor::FS_KEY_SUB, std::move(newSubEntry)); + appsTable->setRow(executor::FS_ACL_TYPE, std::move(aclTypeEntry)); + appsTable->setRow(executor::FS_ACL_WHITE, std::move(aclWEntry)); + appsTable->setRow(executor::FS_ACL_BLACK, std::move(aclBEntry)); + appsTable->setRow(executor::FS_KEY_EXTRA, std::move(extraEntry)); + } + } + } + + void deployAuthSolidity(protocol::BlockNumber blockNumber) + { + static const char* committeeBin = bcos::initializer::committeeBin; + + // deploy CommitteeManager + + // hex bin code to bytes + bytes code; + boost::algorithm::unhex(committeeBin, std::back_inserter(code)); + + // constructor (address[] initGovernors, = [authAdminAddress] + // uint32[] memory weights, = [0] + // uint8 participatesRate, = 0 + // uint8 winRate) = 0 + std::vector
initGovernors({Address(admin)}); + std::vector weights({bcos::codec::toString32(h256(uint8_t(1)))}); + // bytes code + abi encode constructor params + codec::abi::ContractABICodec abi(*hashImpl); + bytes constructor = abi.abiIn("", initGovernors, weights, + codec::toString32(h256(uint8_t(0))), codec::toString32(h256(uint8_t(0)))); + bytes input = code + constructor; + + auto sender = admin; + + auto params = std::make_unique(); + params->setContextID(99); + params->setSeq(1000); + params->setDepth(0); + + params->setOrigin(sender); + params->setFrom(sender); + + // toChecksumAddress(addressString, hashImpl); + params->setTo(std::string(precompiled::AUTH_COMMITTEE_ADDRESS)); + params->setStaticCall(false); + params->setGasAvailable(gas); + params->setData(input); + params->setType(NativeExecutionMessage::MESSAGE); + params->setCreate(true); + params->setData(input); + + nextBlock(blockNumber); + // -------------------------------- + // Create contract + // -------------------------------- + + // deploy CommitteeManager + std::promise executePromise; + executor->executeTransaction( + std::move(params), [&](bcos::Error::UniquePtr&& error, + bcos::protocol::ExecutionMessage::UniquePtr&& result) { + BOOST_CHECK(!error); + executePromise.set_value(std::move(result)); + }); + + auto result = executePromise.get_future().get(); + + BOOST_CHECK_EQUAL(result->type(), ExecutionMessage::FINISHED); + BOOST_CHECK_EQUAL(result->create(), false); + BOOST_CHECK_EQUAL(result->origin(), sender); + BOOST_CHECK_EQUAL(result->from(), precompiled::AUTH_COMMITTEE_ADDRESS); + + commitBlock(blockNumber); + } + + ExecutionMessage::UniquePtr initBfs(protocol::BlockNumber _number, int _errorCode = 0) + { + bytes in = codec->encodeWithSig("initBfs()"); + auto tx = + fakeTransaction(cryptoSuite, keyPair, "", in, std::to_string(101), 100001, "1", "1"); + auto sender = boost::algorithm::hex_lower(std::string(tx->sender())); + auto hash = tx->hash(); + txpool->hash2Transaction.emplace(hash, tx); + auto params2 = std::make_unique(); + params2->setTransactionHash(hash); + params2->setContextID(1000); + params2->setSeq(1000); + params2->setDepth(0); + params2->setFrom(sender); + params2->setTo(std::string(isWasm ? BFS_NAME : BFS_ADDRESS)); + params2->setOrigin(sender); + params2->setStaticCall(false); + params2->setGasAvailable(gas); + params2->setData(std::move(in)); + params2->setType(NativeExecutionMessage::TXHASH); + nextBlock(_number, m_blockVersion); + + std::promise executePromise2; + executor->dmcExecuteTransaction(std::move(params2), + [&](bcos::Error::UniquePtr&& error, ExecutionMessage::UniquePtr&& result) { + BOOST_CHECK(!error); + executePromise2.set_value(std::move(result)); + }); + auto result2 = executePromise2.get_future().get(); + if (_errorCode != 0) + { + BOOST_CHECK(result2->data().toBytes() == codec->encode(s256(_errorCode))); + } + + commitBlock(_number); + return result2; + }; + +public: + CodecWrapper::Ptr codec; + crypto::Hash::Ptr hashImpl; + crypto::Hash::Ptr smHashImpl; + protocol::BlockFactory::Ptr blockFactory; + CryptoSuite::Ptr cryptoSuite = nullptr; + CryptoSuite::Ptr smCryptoSuite = nullptr; + + TransactionalStorageInterface::Ptr storage; + TransactionExecutor::Ptr executor; + std::shared_ptr txpool{}; + std::shared_ptr ledger{}; + KeyPairInterface::Ptr keyPair; + + int64_t gas = MockLedger::TX_GAS_LIMIT; + bool isWasm = false; + std::string admin = "1111654b49838bd3e9466c85a4cc3428c9601111"; + protocol::BlockVersion m_blockVersion = protocol::DEFAULT_VERSION; +}; +} // namespace bcos::test diff --git a/bcos-executor/test/unittest/libvm/TestTransactionExecutive.cpp b/bcos-executor/test/unittest/libvm/TestTransactionExecutive.cpp index 318eae17ce..188125e211 100644 --- a/bcos-executor/test/unittest/libvm/TestTransactionExecutive.cpp +++ b/bcos-executor/test/unittest/libvm/TestTransactionExecutive.cpp @@ -1,19 +1,329 @@ #include "../../src/executive/TransactionExecutive.h" +#include "fixture/TransactionFixture.h" + +#include +#include +#include + #include +#include namespace bcos::test { -class TransactionExecutiveFixture +class TransactionExecutiveFixture : public TransactionFixture { public: - TransactionExecutiveFixture() {} + TransactionExecutiveFixture() : TransactionFixture() + { + setIsWasm(false); + web3Features.set(Features::Flag::feature_balance); + web3Features.set(Features::Flag::feature_balance_precompiled); + web3Features.set(Features::Flag::feature_evm_address); + web3Features.set(Features::Flag::feature_evm_cancun); + web3Features.set(Features::Flag::feature_evm_timestamp); + } + + auto deployTestContract(uint blockNumber, TransactionType type) + { + nextBlock(blockNumber, protocol::BlockVersion::MAX_VERSION, web3Features); + auto nonce = blockNumber + 100; + bytes in = fromHex(deployAddressBin); + auto tx = fakeTransaction( + cryptoSuite, keyPair, "", in, std::to_string(nonce), 100001, "1", "1", ""); + auto hash = tx->hash(); + txpool->hash2Transaction[hash] = tx; + + + auto const sender = keyPair->address(hashImpl); + auto const address = newLegacyEVMAddress(sender.ref(), u256(nonce)); + + bcos::ledger::account::EVMAccount eoa(*storage, sender.hex(), false); + task::syncWait(bcos::ledger::account::create(eoa)); + task::syncWait(bcos::ledger::account::setBalance(eoa, u256(1000000000000000ULL))); + + auto params = std::make_unique(); + params->setNonce(toQuantity(nonce)); + params->setTransactionHash(hash); + params->setContextID(blockNumber); + params->setSeq(0); + params->setDepth(0); + params->setFrom(sender.hex()); + params->setTo(address); + params->setOrigin(sender.hex()); + params->setStaticCall(false); + params->setGasAvailable(gas); + params->setCreate(true); + params->setData(std::move(in)); + params->setType(NativeExecutionMessage::TXHASH); + params->setTxType(static_cast(type)); + + std::promise executePromise; + executor->executeTransaction(std::move(params), [&](auto&& error, auto&& result) { + BOOST_CHECK(!error); + executePromise.set_value(std::move(result)); + }); + + auto result = executePromise.get_future().get(); + + BOOST_CHECK_EQUAL(result->status(), 0); + commitBlock(blockNumber); + + auto const nonceOfEoa = task::syncWait(bcos::ledger::account::nonce(eoa)); + + bcos::ledger::account::EVMAccount contractAddress(*storage, address, false); + 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"); + } + else + { + BOOST_CHECK_EQUAL(nonceOfEoa.value(), std::to_string(nonce + 1)); + BOOST_CHECK_EQUAL(nonceOfContract.value(), "1"); + } + return address; + } + + auto newHelloWorld(uint blockNumber, TransactionType type, std::string contractAddress, + uint expectContractNonce) + { + nextBlock(blockNumber, protocol::BlockVersion::MAX_VERSION, web3Features); + auto nonce = blockNumber + 100; + bytes in = codec->encodeWithSig("newHello()"); + auto tx = fakeTransaction( + cryptoSuite, keyPair, "", in, std::to_string(nonce), 100001, "1", "1", ""); + auto hash = tx->hash(); + txpool->hash2Transaction[hash] = tx; + + auto const sender = keyPair->address(hashImpl); + + bcos::ledger::account::EVMAccount eoa(*storage, sender.hex(), false); + task::syncWait(bcos::ledger::account::create(eoa)); + task::syncWait(bcos::ledger::account::setBalance(eoa, u256(1000000000000000ULL))); + + auto params = std::make_unique(); + params->setNonce(toQuantity(nonce)); + params->setTransactionHash(hash); + params->setContextID(blockNumber); + params->setSeq(0); + params->setDepth(0); + params->setFrom(sender.hex()); + params->setTo(contractAddress); + params->setOrigin(sender.hex()); + params->setStaticCall(false); + params->setGasAvailable(gas); + params->setCreate(false); + params->setData(std::move(in)); + params->setType(NativeExecutionMessage::TXHASH); + params->setTxType(static_cast(type)); + + std::promise executePromise; + executor->executeTransaction(std::move(params), [&](auto&& error, auto&& result) { + BOOST_CHECK(!error); + executePromise.set_value(std::move(result)); + }); + + auto result = executePromise.get_future().get(); + + BOOST_CHECK_EQUAL(result->status(), 0); + commitBlock(blockNumber); + + auto const nonceOfEoa = task::syncWait(bcos::ledger::account::nonce(eoa)); + + bcos::ledger::account::EVMAccount contractAccount(*storage, contractAddress, false); + auto const nonceOfContract = task::syncWait(bcos::ledger::account::nonce(contractAccount)); + if (type == TransactionType::BCOSTransaction) + { + BOOST_CHECK_EQUAL(nonceOfContract.has_value(), true); + BOOST_CHECK_EQUAL(nonceOfContract.value(), std::to_string(expectContractNonce)); + } + else + { + BOOST_CHECK_EQUAL(nonceOfEoa.value(), std::to_string(nonce + 1)); + BOOST_CHECK_EQUAL(nonceOfContract.value(), std::to_string(expectContractNonce)); + } + } + + auto newRevertHello(uint blockNumber, TransactionType type, std::string contractAddress, + uint expectContractNonce) + { + nextBlock(blockNumber, protocol::BlockVersion::MAX_VERSION, web3Features); + auto nonce = blockNumber + 100; + bytes in = codec->encodeWithSig("newRevertHello()"); + auto tx = fakeTransaction( + cryptoSuite, keyPair, "", in, std::to_string(nonce), 100001, "1", "1", ""); + auto hash = tx->hash(); + txpool->hash2Transaction[hash] = tx; + + auto const sender = keyPair->address(hashImpl); + + bcos::ledger::account::EVMAccount eoa(*storage, sender.hex(), false); + task::syncWait(bcos::ledger::account::create(eoa)); + task::syncWait(bcos::ledger::account::setBalance(eoa, u256(1000000000000000ULL))); + + auto params = std::make_unique(); + params->setNonce(toQuantity(nonce)); + params->setTransactionHash(hash); + params->setContextID(blockNumber); + params->setSeq(0); + params->setDepth(0); + params->setFrom(sender.hex()); + params->setTo(contractAddress); + params->setOrigin(sender.hex()); + params->setStaticCall(false); + params->setGasAvailable(gas); + params->setCreate(false); + params->setData(std::move(in)); + params->setType(NativeExecutionMessage::TXHASH); + params->setTxType(static_cast(type)); + + std::promise executePromise; + executor->executeTransaction(std::move(params), [&](auto&& error, auto&& result) { + BOOST_CHECK(!error); + executePromise.set_value(std::move(result)); + }); + + auto result = executePromise.get_future().get(); + + BOOST_CHECK_EQUAL(result->status(), 16); + commitBlock(blockNumber); + + auto const nonceOfEoa = task::syncWait(bcos::ledger::account::nonce(eoa)); + + bcos::ledger::account::EVMAccount contractAccount(*storage, contractAddress, false); + auto const nonceOfContract = task::syncWait(bcos::ledger::account::nonce(contractAccount)); + if (type == TransactionType::BCOSTransaction) + { + BOOST_CHECK_EQUAL(nonceOfContract.has_value(), true); + BOOST_CHECK_EQUAL(nonceOfContract.value(), std::to_string(expectContractNonce)); + } + else + { + BOOST_CHECK_EQUAL(nonceOfEoa.value(), std::to_string(nonce + 1)); + BOOST_CHECK_EQUAL(nonceOfContract.value(), std::to_string(expectContractNonce)); + } + } + + 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; + + keyPair = cryptoSuite->signatureImpl()->generateKeyPair(); + auto tx = fakeTransaction(cryptoSuite, keyPair, "", {}, std::to_string(nonce), 100001, "1", + "1", "", 0, transferValue); + auto hash = tx->hash(); + txpool->hash2Transaction[hash] = tx; + + auto sender = keyPair->address(hashImpl).hex(); + + bcos::ledger::account::EVMAccount eoa(*storage, sender, false); + task::syncWait(bcos::ledger::account::create(eoa)); + task::syncWait(bcos::ledger::account::setBalance(eoa, u256(initBalance))); + + auto params = std::make_unique(); + params->setTransactionHash(hash); + params->setNonce(toQuantity(nonce)); + params->setContextID(blockNumber); + params->setSeq(0); + params->setDepth(0); + params->setFrom(sender); + params->setTo(std::move(toAddress)); + params->setOrigin(sender); + params->setStaticCall(false); + params->setGasAvailable(gas); + params->setCreate(false); + params->setValue(toQuantity(transferValue)); + params->setType(NativeExecutionMessage::TXHASH); + params->setTxType(static_cast(type)); + + std::promise executePromise; + executor->executeTransaction(std::move(params), [&](auto&& error, auto&& result) { + BOOST_CHECK(!error); + executePromise.set_value(std::forward(result)); + }); + + auto result = executePromise.get_future().get(); + + commitBlock(blockNumber); + + auto const nonceOfEoa = task::syncWait(bcos::ledger::account::nonce(eoa)); + + if (type == TransactionType::BCOSTransaction) + { + if (nonceOfEoa.has_value()) + { + BOOST_CHECK_EQUAL(nonceOfEoa.value(), std::to_string(nonce)); + } + } + else + { + BOOST_CHECK_EQUAL(nonceOfEoa.value(), std::to_string(nonce + 1)); + } + + return result; + } + + Features web3Features{}; + // clang-format off + static constexpr std::string_view deployAddressBin = "608060405234801561001057600080fd5b506109c3806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806319ff1d21146100515780637567e6711461006f5780639ac4d2e614610079578063cb2ade2d14610097575b600080fd5b6100596100a1565b6040516100669190610258565b60405180910390f35b6100776100c5565b005b61008161012f565b60405161008e9190610294565b60405180910390f35b61009f610155565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040516100d1906101c0565b604051809103906000f0801580156100ed573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b604051610161906101cd565b604051809103906000f08015801561017d573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b61061d806102b083390190565b60c1806108cd83390190565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061021e610219610214846101d9565b6101f9565b6101d9565b9050919050565b600061023082610203565b9050919050565b600061024282610225565b9050919050565b61025281610237565b82525050565b600060208201905061026d6000830184610249565b92915050565b600061027e82610225565b9050919050565b61028e81610273565b82525050565b60006020820190506102a96000830184610285565b9291505056fe608060405234801561001057600080fd5b506040518060400160405280600d81526020017f48656c6c6f2c20576f726c6421000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610166565b82805461006e90610134565b90600052602060002090601f01602090048101928261009057600085556100d7565b82601f106100a957805160ff19168380011785556100d7565b828001600101855582156100d7579182015b828111156100d65782518255916020019190600101906100bb565b5b5090506100e491906100e8565b5090565b5b808211156101015760008160009055506001016100e9565b5090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061014c57607f821691505b602082108114156101605761015f610105565b5b50919050565b6104a8806101756000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80634ed3885e1461003b5780636d4ce63c14610057575b600080fd5b6100556004803603810190610050919061031e565b610075565b005b61005f61008f565b60405161006c91906103ef565b60405180910390f35b806000908051906020019061008b929190610121565b5050565b60606000805461009e90610440565b80601f01602080910402602001604051908101604052809291908181526020018280546100ca90610440565b80156101175780601f106100ec57610100808354040283529160200191610117565b820191906000526020600020905b8154815290600101906020018083116100fa57829003601f168201915b5050505050905090565b82805461012d90610440565b90600052602060002090601f01602090048101928261014f5760008555610196565b82601f1061016857805160ff1916838001178555610196565b82800160010185558215610196579182015b8281111561019557825182559160200191906001019061017a565b5b5090506101a391906101a7565b5090565b5b808211156101c05760008160009055506001016101a8565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022b826101e2565b810181811067ffffffffffffffff8211171561024a576102496101f3565b5b80604052505050565b600061025d6101c4565b90506102698282610222565b919050565b600067ffffffffffffffff821115610289576102886101f3565b5b610292826101e2565b9050602081019050919050565b82818337600083830152505050565b60006102c16102bc8461026e565b610253565b9050828152602081018484840111156102dd576102dc6101dd565b5b6102e884828561029f565b509392505050565b600082601f830112610305576103046101d8565b5b81356103158482602086016102ae565b91505092915050565b600060208284031215610334576103336101ce565b5b600082013567ffffffffffffffff811115610352576103516101d3565b5b61035e848285016102f0565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156103a1578082015181840152602081019050610386565b838111156103b0576000848401525b50505050565b60006103c182610367565b6103cb8185610372565b93506103db818560208601610383565b6103e4816101e2565b840191505092915050565b6000602082019050818103600083015261040981846103b6565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061045857607f821691505b6020821081141561046c5761046b610411565b5b5091905056fea2646970667358221220fc2b2f46c09486df7da2ceda6c91e6ec6a82d3f4580f53886923b172269e72a264736f6c634300080b00336080604052348015600f57600080fd5b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260040160409060a2565b60405180910390fd5b600082825260208201905092915050565b7f52657665727448656c6c6f000000000000000000000000000000000000000000600082015250565b6000608e600b836049565b9150609782605a565b602082019050919050565b6000602082019050818103600083015260b9816083565b905091905056fea2646970667358221220e53006013391463b1160cd453611e0f55dde2ae96ad5beb21bcaa6c25715d14964736f6c634300080b0033"; + // clang-format on }; BOOST_FIXTURE_TEST_SUITE(testTransactionExecutive, TransactionExecutiveFixture) -BOOST_AUTO_TEST_CASE(test) +BOOST_AUTO_TEST_CASE(testNonceInTransaction) { - BOOST_CHECK(true); + deployTestContract(1, TransactionType::BCOSTransaction); + deployTestContract(2, TransactionType::Web3Transaction); +} + +BOOST_AUTO_TEST_CASE(testNonceInNewContract) +{ + uint64_t blockNumber = 1; + deployTestContract(blockNumber++, TransactionType::BCOSTransaction); + auto const address = deployTestContract(blockNumber++, TransactionType::Web3Transaction); + newHelloWorld(blockNumber++, TransactionType::BCOSTransaction, address, 2); + newHelloWorld(blockNumber++, TransactionType::Web3Transaction, address, 3); + newHelloWorld(blockNumber++, TransactionType::Web3Transaction, address, 4); + newHelloWorld(blockNumber++, TransactionType::Web3Transaction, address, 5); + newHelloWorld(blockNumber++, TransactionType::BCOSTransaction, address, 6); +} + +BOOST_AUTO_TEST_CASE(testNonceInRevertContract) +{ + uint64_t blockNumber = 1; + deployTestContract(blockNumber++, TransactionType::BCOSTransaction); + auto const address = deployTestContract(blockNumber++, TransactionType::Web3Transaction); + newRevertHello(blockNumber++, TransactionType::BCOSTransaction, address, 1); + newRevertHello(blockNumber++, TransactionType::Web3Transaction, address, 1); + newRevertHello(blockNumber++, TransactionType::Web3Transaction, address, 1); + newRevertHello(blockNumber++, TransactionType::Web3Transaction, address, 1); + newHelloWorld(blockNumber++, TransactionType::Web3Transaction, address, 2); + newRevertHello(blockNumber++, TransactionType::BCOSTransaction, address, 2); + newHelloWorld(blockNumber++, TransactionType::BCOSTransaction, address, 3); + newRevertHello(blockNumber++, TransactionType::Web3Transaction, address, 3); +} + + +BOOST_AUTO_TEST_CASE(testNonceInTransfer) +{ + uint64_t blockNumber = 1; + auto result = transfer( + blockNumber++, TransactionType::BCOSTransaction, "0x1234567890", 1000000000UL, 10000UL, 0); + BOOST_CHECK_EQUAL(result->status(), 0); + // transfer balance not enough, and nonce will still update + result = transfer( + blockNumber++, TransactionType::Web3Transaction, "0x1234567890", 1000UL, 10000000UL, 0); + BOOST_CHECK_EQUAL(result->status(), 7); + + result = transfer( + blockNumber++, TransactionType::Web3Transaction, "0x1234567890", 10000000UL, 10000000UL, 0); + BOOST_CHECK_EQUAL(result->status(), 0); } BOOST_AUTO_TEST_SUITE_END() diff --git a/bcos-framework/bcos-framework/ledger/Account.h b/bcos-framework/bcos-framework/ledger/Account.h index a9339718ef..c6f6554c2a 100644 --- a/bcos-framework/bcos-framework/ledger/Account.h +++ b/bcos-framework/bcos-framework/ledger/Account.h @@ -16,9 +16,9 @@ inline constexpr struct Exists inline constexpr struct Create { - auto operator()(auto& account, - auto&&... args) const -> task::Task(args)...))>> + auto operator()(auto& account, auto&&... args) const + -> task::Task(args)...))>> { co_return co_await tag_invoke(*this, account, std::forward(args)...); } @@ -26,9 +26,9 @@ inline constexpr struct Create inline constexpr struct Code { - auto operator()(auto& account, - auto&&... args) const -> task::Task(args)...))>> + auto operator()(auto& account, auto&&... args) const + -> task::Task(args)...))>> { co_return co_await tag_invoke(*this, account, std::forward(args)...); } @@ -45,9 +45,9 @@ inline constexpr struct SetCode inline constexpr struct CodeHash { - auto operator()(auto& account, - auto&&... args) const -> task::Task(args)...))>> + auto operator()(auto& account, auto&&... args) const + -> task::Task(args)...))>> { co_return co_await tag_invoke(*this, account, std::forward(args)...); } @@ -55,9 +55,9 @@ inline constexpr struct CodeHash inline constexpr struct ABI { - auto operator()(auto& account, - auto&&... args) const -> task::Task(args)...))>> + auto operator()(auto& account, auto&&... args) const + -> task::Task(args)...))>> { co_return co_await tag_invoke(*this, account, std::forward(args)...); } @@ -74,9 +74,9 @@ inline constexpr struct SetABI inline constexpr struct Balance { - auto operator()(auto& account, - auto&&... args) const -> task::Task(args)...))>> + auto operator()(auto& account, auto&&... args) const + -> task::Task(args)...))>> { co_return co_await tag_invoke(*this, account, std::forward(args)...); } @@ -108,6 +108,14 @@ inline constexpr struct SetNonce } } setNonce{}; +inline constexpr struct IncreaseNonce +{ + task::Task operator()(auto& account, auto&&... args) const + { + co_await tag_invoke(*this, account, std::forward(args)...); + } +} increaseNonce{}; + inline constexpr struct Storage { auto operator()(auto& account, auto&& key, auto&&... args) const @@ -133,9 +141,9 @@ inline constexpr struct SetStorage inline constexpr struct Path { - auto operator()(auto& account, - auto&&... args) const -> task::Task(args)...))>> + auto operator()(auto& account, auto&&... args) const + -> task::Task(args)...))>> { co_return co_await tag_invoke(*this, account, std::forward(args)...); } diff --git a/bcos-framework/bcos-framework/ledger/EVMAccount.h b/bcos-framework/bcos-framework/ledger/EVMAccount.h index dee7940220..ccc7ea9dbf 100644 --- a/bcos-framework/bcos-framework/ledger/EVMAccount.h +++ b/bcos-framework/bcos-framework/ledger/EVMAccount.h @@ -174,6 +174,15 @@ class EVMAccount std::move(nonceEntry)); } + friend task::Task tag_invoke(tag_t, EVMAccount& account) + { + if (auto nonce = co_await ::bcos::ledger::account::nonce(account)) + { + const auto newNonce = u256(nonce.value()) + 1; + co_await ::bcos::ledger::account::setNonce(account, newNonce.convert_to()); + } + } + friend task::Task tag_invoke( tag_t /*unused*/, EVMAccount& account, const evmc_bytes32& key) { diff --git a/bcos-framework/bcos-framework/ledger/Features.h b/bcos-framework/bcos-framework/ledger/Features.h index b0a47dc285..d06425af07 100644 --- a/bcos-framework/bcos-framework/ledger/Features.h +++ b/bcos-framework/bcos-framework/ledger/Features.h @@ -44,6 +44,8 @@ class Features bugfix_delete_account_code, bugfix_policy1_empty_code_address, bugfix_precompiled_gasused, + bugfix_nonce_not_increase_when_revert, + bugfix_set_contract_nonce_when_create, feature_dmc2serial, feature_sharding, feature_rpbft, @@ -242,10 +244,23 @@ class Features Flag::bugfix_eoa_match_failed, }}, {.to = protocol::BlockVersion::V3_12_0_VERSION, - .flags = {Flag::bugfix_rpbft_vrf_blocknumber_input}}, + .flags = + { + Flag::bugfix_rpbft_vrf_blocknumber_input, + }}, {.to = protocol::BlockVersion::V3_13_0_VERSION, - .flags = {Flag::bugfix_delete_account_code, Flag::bugfix_policy1_empty_code_address, - Flag::bugfix_precompiled_gasused}}, + .flags = + { + Flag::bugfix_delete_account_code, + Flag::bugfix_policy1_empty_code_address, + Flag::bugfix_precompiled_gasused, + }}, + {.to = protocol::BlockVersion::V3_14_0_VERSION, + .flags = + { + Flag::bugfix_nonce_not_increase_when_revert, + Flag::bugfix_set_contract_nonce_when_create, + }}, }); for (const auto& upgradeFeatures : upgradeRoadmap) { diff --git a/bcos-framework/bcos-framework/protocol/Protocol.h b/bcos-framework/bcos-framework/protocol/Protocol.h index 6183bb6fb9..acda03708b 100644 --- a/bcos-framework/bcos-framework/protocol/Protocol.h +++ b/bcos-framework/bcos-framework/protocol/Protocol.h @@ -115,6 +115,7 @@ enum ProtocolVersion : uint32_t enum class BlockVersion : uint32_t { + V3_14_0_VERSION = 0x030e0000, // 3.14.0 V3_13_0_VERSION = 0x030d0000, // 3.13.0 V3_12_4_VERSION = 0x030c0400, // 3.12.4 V3_12_3_VERSION = 0x030c0300, // 3.12.3 @@ -148,7 +149,7 @@ enum class BlockVersion : uint32_t V3_0_VERSION = 0x03000000, RC4_VERSION = 4, MIN_VERSION = RC4_VERSION, - MAX_VERSION = V3_13_0_VERSION, // 3.13.0 + MAX_VERSION = V3_14_0_VERSION, // 3.14.0 }; enum class TransactionVersion : uint32_t @@ -163,7 +164,7 @@ const std::string RC4_VERSION_STR = "3.0.0-rc4"; const std::string RC_VERSION_PREFIX = "3.0.0-rc"; const std::string V3_9_VERSION_STR = "3.9.0"; -constexpr BlockVersion DEFAULT_VERSION = bcos::protocol::BlockVersion::V3_12_0_VERSION; +constexpr BlockVersion DEFAULT_VERSION = bcos::protocol::BlockVersion::V3_14_0_VERSION; // 3.14.0 const std::string DEFAULT_VERSION_STR = V3_9_VERSION_STR; constexpr uint8_t MAX_MAJOR_VERSION = std::numeric_limits::max(); constexpr uint8_t MIN_MAJOR_VERSION = 3; diff --git a/bcos-framework/bcos-framework/testutils/faker/FakeTransaction.h b/bcos-framework/bcos-framework/testutils/faker/FakeTransaction.h index c857ca4d60..5655907492 100644 --- a/bcos-framework/bcos-framework/testutils/faker/FakeTransaction.h +++ b/bcos-framework/bcos-framework/testutils/faker/FakeTransaction.h @@ -41,7 +41,7 @@ namespace test inline auto fakeTransaction(CryptoSuite::Ptr _cryptoSuite, KeyPairInterface::Ptr _keyPair, const std::string_view& _to, bytes const& _input, std::string const& _nonce, int64_t _blockLimit, std::string const& _chainId, std::string const& _groupId, - std::string const& _abi = "") + std::string const& _abi = "", const uint _type = 0, const uint64_t value = 0) { bcostars::Transaction transaction; transaction.data.to = _to; @@ -51,6 +51,8 @@ inline auto fakeTransaction(CryptoSuite::Ptr _cryptoSuite, KeyPairInterface::Ptr transaction.data.chainID = _chainId; transaction.data.groupID = _groupId; transaction.data.abi = _abi; + transaction.data.value = std::to_string(value); + transaction.type = _type; auto pbTransaction = std::make_shared( [m_transaction = std::move(transaction)]() mutable { return &m_transaction; }); // set signature diff --git a/bcos-framework/test/unittests/interfaces/FeaturesTest.cpp b/bcos-framework/test/unittests/interfaces/FeaturesTest.cpp index 3f33ff791f..15889fbb1a 100644 --- a/bcos-framework/test/unittests/interfaces/FeaturesTest.cpp +++ b/bcos-framework/test/unittests/interfaces/FeaturesTest.cpp @@ -151,6 +151,8 @@ BOOST_AUTO_TEST_CASE(feature) "bugfix_delete_account_code", "bugfix_policy1_empty_code_address", "bugfix_precompiled_gasused", + "bugfix_nonce_not_increase_when_revert", + "bugfix_set_contract_nonce_when_create", "feature_dmc2serial", "feature_sharding", "feature_rpbft", diff --git a/bcos-gateway/test/unittests/SessionTest.cpp b/bcos-gateway/test/unittests/SessionTest.cpp index 2671288f40..29f72a37e6 100644 --- a/bcos-gateway/test/unittests/SessionTest.cpp +++ b/bcos-gateway/test/unittests/SessionTest.cpp @@ -299,61 +299,66 @@ BOOST_AUTO_TEST_CASE(doReadTest) { auto totalPacketNum = 500; FakeMessagesBuilder messageBuilder(totalPacketNum); - auto fakeAsio = std::make_shared(); auto fakeMessageFactory = std::make_shared(); auto hashImpl = std::make_shared(); - auto fakeHost = std::make_shared(hashImpl, fakeAsio, nullptr, fakeMessageFactory); auto fakeSocket = std::make_shared(); std::atomic recvPacketCnt = 0; std::atomic recvBufferSize = 0; std::atomic lastReadTime = utcSteadyTime(); + { + auto fakeAsio = std::make_shared(); + auto fakeHost = std::make_shared(hashImpl, fakeAsio, nullptr, fakeMessageFactory); + + auto session = std::make_shared(fakeSocket, *fakeHost, 2, true); + session->setMessageFactory(fakeHost->messageFactory()); + + session->setMessageHandler( + [&recvPacketCnt, &recvBufferSize, &lastReadTime]( + NetworkException e, SessionFace::Ptr sessionFace, Message::Ptr message) { + // doRead() call this function after reading a message + lastReadTime = utcSteadyTime(); + if (e.errorCode() != P2PExceptionType::Success) + { + std::cout << "error: " << e.errorCode() << " " << e.what() << std::endl; + } + { + static bcos::SharedMutex x_mutex; + bcos::WriteGuard guard(x_mutex); + BOOST_CHECK_EQUAL(e.errorCode(), P2PExceptionType::Success); + BOOST_CHECK(message); + BOOST_CHECK(message->lengthDirect() > 0); + } + + recvBufferSize += message->lengthDirect(); + recvPacketCnt++; + }); - auto session = std::make_shared(fakeSocket, *fakeHost, 2, true); - session->setMessageFactory(fakeHost->messageFactory()); + session->start(); + std::dynamic_pointer_cast(fakeHost->asioInterface())->triggerRead(); - session->setMessageHandler([&recvPacketCnt, &recvBufferSize, &lastReadTime](NetworkException e, - SessionFace::Ptr sessionFace, Message::Ptr message) { - // doRead() call this function after reading a message - lastReadTime = utcSteadyTime(); - if (e.errorCode() != P2PExceptionType::Success) + // send packets + while (auto packet = messageBuilder.nextPacket()) { - std::cout << "error: " << e.errorCode() << " " << e.what() << std::endl; + std::dynamic_pointer_cast(fakeHost->asioInterface()) + ->asyncAppendRecvPacket(packet); } + + size_t retryTimes = 0; + while (auto restPacket = totalPacketNum - recvPacketCnt) { - static bcos::SharedMutex x_mutex; - bcos::WriteGuard guard(x_mutex); - BOOST_CHECK_EQUAL(e.errorCode(), P2PExceptionType::Success); - BOOST_CHECK(message); - BOOST_CHECK(message->lengthDirect() > 0); + std::cout << "waiting " << restPacket << " packets" << std::endl; + retryTimes++; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + BOOST_CHECK(retryTimes < 100); } - recvBufferSize += message->lengthDirect(); - recvPacketCnt++; - }); - - session->start(); - std::dynamic_pointer_cast(fakeHost->asioInterface())->triggerRead(); - - // send packets - while (auto packet = messageBuilder.nextPacket()) - { - std::dynamic_pointer_cast(fakeHost->asioInterface()) - ->asyncAppendRecvPacket(packet); - } - - size_t retryTimes = 0; - while (auto restPacket = totalPacketNum - recvPacketCnt) - { - std::cout << "waiting " << restPacket << " packets" << std::endl; - retryTimes++; - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - BOOST_CHECK(retryTimes < 100); + BOOST_CHECK_EQUAL(recvPacketCnt, totalPacketNum); + BOOST_CHECK_EQUAL(recvBufferSize, messageBuilder.sendBufferSize()); + session->setSocket(nullptr); } - BOOST_CHECK_EQUAL(recvPacketCnt, totalPacketNum); - BOOST_CHECK_EQUAL(recvBufferSize, messageBuilder.sendBufferSize()); - session->setSocket(nullptr); + fakeSocket->close(); } BOOST_AUTO_TEST_CASE(SessionRecvBufferTest) diff --git a/bcos-sync/bcos-sync/state/DownloadingQueue.cpp b/bcos-sync/bcos-sync/state/DownloadingQueue.cpp index 21db494afd..3b4d37d40e 100644 --- a/bcos-sync/bcos-sync/state/DownloadingQueue.cpp +++ b/bcos-sync/bcos-sync/state/DownloadingQueue.cpp @@ -611,6 +611,8 @@ void DownloadingQueue::commitBlockState(bcos::protocol::Block::Ptr _block) << LOG_KV("commitBlockTimeCost", (utcTime() - startT)) << LOG_KV("node", downloadingQueue->m_config->nodeID()->shortHex()) << LOG_KV("txsSize", _block->transactionsSize()) + << LOG_KV("highestNumber", + downloadingQueue->m_config->knownHighestNumber()) << LOG_KV("sealer", blockHeader->sealer()); } catch (std::exception const& e) diff --git a/bcos-utilities/testutils/TestPromptFixture.h b/bcos-utilities/testutils/TestPromptFixture.h index 9a7859f9ca..c3f1aae2cd 100644 --- a/bcos-utilities/testutils/TestPromptFixture.h +++ b/bcos-utilities/testutils/TestPromptFixture.h @@ -95,6 +95,6 @@ class TestPromptFixture // init test-suite fixture TestPromptFixture() { TestPrompt::get().initTest(); } // release test-suite fixture - ~TestPromptFixture() { TestPrompt::get().finishTest(); } + virtual ~TestPromptFixture() { TestPrompt::get().finishTest(); } }; } // namespace bcos::test diff --git a/tools/BcosBuilder/max/conf/config-build-example.toml b/tools/BcosBuilder/max/conf/config-build-example.toml index e09d87883d..9bdab470e5 100644 --- a/tools/BcosBuilder/max/conf/config-build-example.toml +++ b/tools/BcosBuilder/max/conf/config-build-example.toml @@ -36,7 +36,7 @@ consensus_type = "pbft" # transaction gas limit gas_limit = "3000000000" # compatible version, can be dynamically upgraded through setSystemConfig -compatibility_version = "3.13.0" +compatibility_version = "3.14.0" [[agency]] name = "agencyA" diff --git a/tools/BcosBuilder/max/conf/config-deploy-example.toml b/tools/BcosBuilder/max/conf/config-deploy-example.toml index 2d994be7ce..457c36f319 100644 --- a/tools/BcosBuilder/max/conf/config-deploy-example.toml +++ b/tools/BcosBuilder/max/conf/config-deploy-example.toml @@ -36,7 +36,7 @@ consensus_type = "pbft" # transaction gas limit gas_limit = "3000000000" # compatible version, can be dynamically upgraded through setSystemConfig -compatibility_version = "3.13.0" +compatibility_version = "3.14.0" [[agency]] name = "agencyA" diff --git a/tools/BcosBuilder/pro/conf/config-build-example.toml b/tools/BcosBuilder/pro/conf/config-build-example.toml index aebde7ff61..d4ac19be04 100644 --- a/tools/BcosBuilder/pro/conf/config-build-example.toml +++ b/tools/BcosBuilder/pro/conf/config-build-example.toml @@ -34,7 +34,7 @@ consensus_type = "pbft" # transaction gas limit gas_limit = "3000000000" # compatible version, can be dynamically upgraded through setSystemConfig -compatibility_version = "3.13.0" +compatibility_version = "3.14.0" [[agency]] name = "agencyA" diff --git a/tools/BcosBuilder/pro/conf/config-deploy-example.toml b/tools/BcosBuilder/pro/conf/config-deploy-example.toml index 96a503a903..06bb124ed2 100644 --- a/tools/BcosBuilder/pro/conf/config-deploy-example.toml +++ b/tools/BcosBuilder/pro/conf/config-deploy-example.toml @@ -36,7 +36,7 @@ consensus_type = "pbft" # transaction gas limit gas_limit = "3000000000" # compatible version, can be dynamically upgraded through setSystemConfig -compatibility_version = "3.13.0" +compatibility_version = "3.14.0" [[agency]] name = "agencyA" diff --git a/tools/BcosBuilder/src/common/utilities.py b/tools/BcosBuilder/src/common/utilities.py index cb596264c1..6d5b8c0f04 100644 --- a/tools/BcosBuilder/src/common/utilities.py +++ b/tools/BcosBuilder/src/common/utilities.py @@ -99,7 +99,7 @@ class CommandInfo: network_add_vxlan = "add-vxlan" download_binary = "download_binary" download_type = ["cdn", "git"] - default_binary_version = "v3.13.0" + default_binary_version = "v3.14.0" command_list = [gen_config, upload, deploy, upgrade, undeploy, expand, start, stop] service_command_list_str = ', '.join(command_list) diff --git a/tools/BcosBuilder/src/tpl/config.genesis b/tools/BcosBuilder/src/tpl/config.genesis index 2a37309484..599b5d6dc3 100644 --- a/tools/BcosBuilder/src/tpl/config.genesis +++ b/tools/BcosBuilder/src/tpl/config.genesis @@ -22,7 +22,7 @@ [version] ; compatible version, can be dynamically upgraded through setSystemConfig - compatibility_version=3.13.0 + compatibility_version=3.14.0 [tx] ; transaction gas limit diff --git a/vcpkg.json b/vcpkg.json index c759ec92f8..655ecf53a5 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,6 +1,6 @@ { "name": "fiscobcos", - "version-string": "3.13.0", + "version-string": "3.14.0", "homepage": "https://github.com/FISCO-BCOS/FISCO-BCOS", "description": "FISCO BCOS", "dependencies": [