From ed7b1ba6d6f8d8f2e869b1f46739a66fb9eb1280 Mon Sep 17 00:00:00 2001 From: James Hinshelwood Date: Mon, 24 Apr 2023 17:45:22 +0100 Subject: [PATCH 01/34] Add `erigon_getHeaderByNumber` --- src/libServer/EthRpcMethods.cpp | 13 +++++++++++++ src/libServer/EthRpcMethods.h | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index 05b14e66e1..fabd773333 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -384,6 +384,14 @@ void EthRpcMethods::Init(LookupServer *lookupServer) { jsonrpc::Procedure("GetDSLeaderTxnPool", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, nullptr), &EthRpcMethods::GetDSLeaderTxnPoolI); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("erigon_getHeaderByNumber", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_OBJECT, + "param01", jsonrpc::JSON_INTEGER, + NULL), + &EthRpcMethods::GetHeaderByNumberI + ); } std::string EthRpcMethods::CreateTransactionEth( @@ -1969,3 +1977,8 @@ Json::Value EthRpcMethods::DebugTraceTransaction(const std::string &txHash, throw JsonRpcException(ServerBase::RPC_MISC_ERROR, "Unable to Process"); } } + +Json::Value EthRpcMethods::GetHeaderByNumber(const uint64_t blockNumber) { + // Erigon headers are a subset of a full block - So just return the full block. + return EthRpcMethods::GetEthBlockByNumber(std::to_string(blockNumber), false); +} diff --git a/src/libServer/EthRpcMethods.h b/src/libServer/EthRpcMethods.h index 3bf6ccf801..bef0af2038 100644 --- a/src/libServer/EthRpcMethods.h +++ b/src/libServer/EthRpcMethods.h @@ -596,6 +596,11 @@ class EthRpcMethods { this->DebugTraceBlockByNumber(request[0u].asString(), request[1u]); } + inline virtual void GetHeaderByNumberI(const Json::Value& request, + Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->GetHeaderByNumber(request[0u].asUInt64()); + } struct ApiKeys; std::string GetEthCallZil(const Json::Value& _json); std::string GetEthCallEth(const Json::Value& _json, @@ -676,6 +681,8 @@ class EthRpcMethods { Json::Value DebugTraceBlockByNumber(const std::string& blockNum, const Json::Value& json); + Json::Value GetHeaderByNumber(const uint64_t blockNumber); + Json::Value GetDSLeaderTxnPool(); void EnsureEvmAndLookupEnabled(); static bool UnpackRevert(const std::string &data_in, std::string &message); From 5722467044cfaa3e5b8764eec224ea1c3a248c7d Mon Sep 17 00:00:00 2001 From: James Hinshelwood Date: Mon, 24 Apr 2023 17:50:00 +0100 Subject: [PATCH 02/34] Add `ots_getApiLevel` This is an API which returns the currently implemented version of the Otterscan API (`ots_*`). The frontend checks this number is high enough before trying to do anything else. The current minimum version in the frontend is `8`, so we return `8`. --- src/libServer/EthRpcMethods.cpp | 7 +++++++ src/libServer/EthRpcMethods.h | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index fabd773333..3d6e8c2371 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -392,6 +392,13 @@ void EthRpcMethods::Init(LookupServer *lookupServer) { NULL), &EthRpcMethods::GetHeaderByNumberI ); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_getApiLevel", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_INTEGER, + NULL), + &EthRpcMethods::GetOtterscanApiLevelI + ); } std::string EthRpcMethods::CreateTransactionEth( diff --git a/src/libServer/EthRpcMethods.h b/src/libServer/EthRpcMethods.h index bef0af2038..57abf961cd 100644 --- a/src/libServer/EthRpcMethods.h +++ b/src/libServer/EthRpcMethods.h @@ -601,6 +601,12 @@ class EthRpcMethods { LOG_MARKER_CONTITIONAL(LOG_SC); response = this->GetHeaderByNumber(request[0u].asUInt64()); } + + inline virtual void GetOtterscanApiLevelI(const Json::Value& request, + Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = 8; + } struct ApiKeys; std::string GetEthCallZil(const Json::Value& _json); std::string GetEthCallEth(const Json::Value& _json, From 38595412eea7346fb05a23623d4f369735506f3a Mon Sep 17 00:00:00 2001 From: James Hinshelwood Date: Mon, 24 Apr 2023 17:52:33 +0100 Subject: [PATCH 03/34] Add `ots_hasCode` --- src/libServer/EthRpcMethods.cpp | 27 +++++++++++++++++++++++++++ src/libServer/EthRpcMethods.h | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index 3d6e8c2371..028d2964ec 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -399,6 +399,15 @@ void EthRpcMethods::Init(LookupServer *lookupServer) { NULL), &EthRpcMethods::GetOtterscanApiLevelI ); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_hasCode", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_BOOLEAN, + "param01", jsonrpc::JSON_STRING, + "param02", jsonrpc::JSON_STRING, + NULL), + &EthRpcMethods::HasCodeI + ); } std::string EthRpcMethods::CreateTransactionEth( @@ -1989,3 +1998,21 @@ Json::Value EthRpcMethods::GetHeaderByNumber(const uint64_t blockNumber) { // Erigon headers are a subset of a full block - So just return the full block. return EthRpcMethods::GetEthBlockByNumber(std::to_string(blockNumber), false); } + +bool EthRpcMethods::HasCode(const std::string& address, const std::string& /*block*/) { + // TODO: Respect block parameter - We can probably do this by finding the contract creation transaction and comparing + // the block numbers. + Address addr{address, Address::FromHex}; + unique_lock lock( + AccountStore::GetInstance().GetPrimaryMutex()); + AccountStore::GetInstance().GetPrimaryWriteAccessCond().wait(lock, [] { + return AccountStore::GetInstance().GetPrimaryWriteAccess(); + }); + + const Account *account = AccountStore::GetInstance().GetAccount(addr, true); + if (account) { + return !account->GetCode().empty(); + } else { + return false; + } +} diff --git a/src/libServer/EthRpcMethods.h b/src/libServer/EthRpcMethods.h index 57abf961cd..4834aea6bb 100644 --- a/src/libServer/EthRpcMethods.h +++ b/src/libServer/EthRpcMethods.h @@ -607,6 +607,11 @@ class EthRpcMethods { LOG_MARKER_CONTITIONAL(LOG_SC); response = 8; } + + inline virtual void HasCodeI(const Json::Value& request, Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->HasCode(request[0u].asString(), request[1u].asString()); + } struct ApiKeys; std::string GetEthCallZil(const Json::Value& _json); std::string GetEthCallEth(const Json::Value& _json, @@ -688,6 +693,7 @@ class EthRpcMethods { const Json::Value& json); Json::Value GetHeaderByNumber(const uint64_t blockNumber); + bool HasCode(const std::string& address, const std::string& block); Json::Value GetDSLeaderTxnPool(); void EnsureEvmAndLookupEnabled(); From 9223acef9c810d26b1e80248d2aca6705f2a7cea Mon Sep 17 00:00:00 2001 From: James Hinshelwood Date: Mon, 24 Apr 2023 17:55:15 +0100 Subject: [PATCH 04/34] Add `ots_getBlockDetails` --- src/libServer/EthRpcMethods.cpp | 31 +++++++++++++++++++++++++++++++ src/libServer/EthRpcMethods.h | 7 +++++++ 2 files changed, 38 insertions(+) diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index 028d2964ec..e9ae5450d5 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -40,6 +40,7 @@ #include "libPOW/pow.h" #include "libPersistence/BlockStorage.h" #include "libServer/AddressChecksum.h" +#include "libUtils/CommonUtils.h" #include "libUtils/DataConversion.h" #include "libUtils/Evm.pb.h" #include "libUtils/EvmUtils.h" @@ -408,6 +409,14 @@ void EthRpcMethods::Init(LookupServer *lookupServer) { NULL), &EthRpcMethods::HasCodeI ); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_getBlockDetails", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_OBJECT, + "param01", jsonrpc::JSON_INTEGER, + NULL), + &EthRpcMethods::GetBlockDetailsI + ); } std::string EthRpcMethods::CreateTransactionEth( @@ -2016,3 +2025,25 @@ bool EthRpcMethods::HasCode(const std::string& address, const std::string& /*blo return false; } } + +Json::Value EthRpcMethods::GetBlockDetails(const uint64_t blockNumber) { + Json::Value response; + + auto txBlock = m_sharedMediator.m_txBlockChain.GetBlock(blockNumber); + bool isVacuous = CommonUtils::IsVacuousEpoch(txBlock.GetHeader().GetBlockNum()); + uint128_t rewards = (isVacuous ? txBlock.GetHeader().GetRewards() * EVM_ZIL_SCALING_FACTOR : 0); + uint128_t fees = (isVacuous ? 0 : txBlock.GetHeader().GetRewards() * EVM_ZIL_SCALING_FACTOR); + auto jsonBlock = GetEthBlockCommon(txBlock, false); + + jsonBlock.removeMember("transactions"); + jsonBlock["transactionCount"] = txBlock.GetHeader().GetNumTxs(); + jsonBlock["logsBloom"] = Json::nullValue; + response["block"] = jsonBlock; + + response["issuance"]["blockReward"] = rewards.str(); + response["issuance"]["uncleReward"] = 0; + response["issuance"]["issuance"] = rewards.str(); + + response["totalFees"] = fees.str(); + return response; +} diff --git a/src/libServer/EthRpcMethods.h b/src/libServer/EthRpcMethods.h index 4834aea6bb..a3beeed781 100644 --- a/src/libServer/EthRpcMethods.h +++ b/src/libServer/EthRpcMethods.h @@ -612,6 +612,12 @@ class EthRpcMethods { LOG_MARKER_CONTITIONAL(LOG_SC); response = this->HasCode(request[0u].asString(), request[1u].asString()); } + + inline virtual void GetBlockDetailsI(const Json::Value& request, + Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->GetBlockDetails(request[0u].asUInt64()); + } struct ApiKeys; std::string GetEthCallZil(const Json::Value& _json); std::string GetEthCallEth(const Json::Value& _json, @@ -694,6 +700,7 @@ class EthRpcMethods { Json::Value GetHeaderByNumber(const uint64_t blockNumber); bool HasCode(const std::string& address, const std::string& block); + Json::Value GetBlockDetails(const uint64_t blockNumber); Json::Value GetDSLeaderTxnPool(); void EnsureEvmAndLookupEnabled(); From 33ca3740dc32557e4bca62cc7e5bc2e0996cbec7 Mon Sep 17 00:00:00 2001 From: James Hinshelwood Date: Mon, 24 Apr 2023 17:56:49 +0100 Subject: [PATCH 05/34] Add `ots_getBlockTransactions` --- src/libServer/EthRpcMethods.cpp | 41 +++++++++++++++++++++++++++++++++ src/libServer/EthRpcMethods.h | 7 ++++++ 2 files changed, 48 insertions(+) diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index e9ae5450d5..57cf476d91 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -417,6 +417,16 @@ void EthRpcMethods::Init(LookupServer *lookupServer) { NULL), &EthRpcMethods::GetBlockDetailsI ); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_getBlockTransactions", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_OBJECT, + "param01", jsonrpc::JSON_INTEGER, + "param02", jsonrpc::JSON_INTEGER, + "param03", jsonrpc::JSON_INTEGER, + NULL), + &EthRpcMethods::GetBlockTransactionsI + ); } std::string EthRpcMethods::CreateTransactionEth( @@ -2047,3 +2057,34 @@ Json::Value EthRpcMethods::GetBlockDetails(const uint64_t blockNumber) { response["totalFees"] = fees.str(); return response; } + +Json::Value EthRpcMethods::GetBlockTransactions(const uint64_t blockNumber, const uint32_t pageNumber, const uint32_t pageSize) { + Json::Value response; + + auto txBlock = m_sharedMediator.m_txBlockChain.GetBlock(blockNumber); + auto jsonBlock = GetEthBlockCommon(txBlock, true); + + auto transactions = jsonBlock["transactions"]; + + auto start = pageNumber * pageSize; + auto end = std::min(transactions.size(), (pageNumber + 1) * pageSize); + + std::vector receipts; + for (Json::Value::ArrayIndex i = start; i < end; i++) { + auto transaction = transactions[i]; + // TODO: Truncate input to 4 bytes (plus 0x) - Work out why the 0x is optional + + auto receipt = EthRpcMethods::GetEthTransactionReceipt(transaction["hash"].asString()); + receipt["logs"] = Json::nullValue; + receipt["logsBloom"] = Json::nullValue; + receipts.push_back(receipt); + } + + response["fullblock"] = jsonBlock; + + for (auto r : receipts) { + response["receipts"].append(r); + } + + return response; +} diff --git a/src/libServer/EthRpcMethods.h b/src/libServer/EthRpcMethods.h index a3beeed781..e4ff07b17d 100644 --- a/src/libServer/EthRpcMethods.h +++ b/src/libServer/EthRpcMethods.h @@ -618,6 +618,12 @@ class EthRpcMethods { LOG_MARKER_CONTITIONAL(LOG_SC); response = this->GetBlockDetails(request[0u].asUInt64()); } + + inline virtual void GetBlockTransactionsI(const Json::Value& request, + Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->GetBlockTransactions(request[0u].asUInt64(), boost::numeric_cast(request[1u].asUInt64()), boost::numeric_cast(request[2u].asUInt64())); + } struct ApiKeys; std::string GetEthCallZil(const Json::Value& _json); std::string GetEthCallEth(const Json::Value& _json, @@ -701,6 +707,7 @@ class EthRpcMethods { Json::Value GetHeaderByNumber(const uint64_t blockNumber); bool HasCode(const std::string& address, const std::string& block); Json::Value GetBlockDetails(const uint64_t blockNumber); + Json::Value GetBlockTransactions(const uint64_t blockNumber, const uint32_t pageNumber, const uint32_t pageSize); Json::Value GetDSLeaderTxnPool(); void EnsureEvmAndLookupEnabled(); From 4e9e3593af60685c23c2f036ceb5b9676c86bc39 Mon Sep 17 00:00:00 2001 From: James Hinshelwood Date: Mon, 24 Apr 2023 18:25:28 +0100 Subject: [PATCH 06/34] Add `ots_getContractCreator` To do this, we add a new `contractCreators` database which stores a map of contract addresses to the transaction hash in which that contract was created. This allows us to look up the creator of the contract in most cases by using the `from` address of the creation transaction. Note that this doesn't work for contracts which have been deployed by other contracts. The API documentation specifically mentions we should support this, so I've left a `FIXME` for now. To do this, we'll probably want to extend the data stored when we create a contract to also track the immediate caller (and thus the contract creator). --- src/libCps/CpsRunEvm.cpp | 4 +++ src/libCps/CpsRunScilla.cpp | 5 +++ src/libCps/CpsUtils.cpp | 3 +- src/libData/AccountStore/AccountStoreSC.cpp | 4 ++- .../services/scilla/ScillaProcessContext.h | 1 + src/libPersistence/BlockStorage.cpp | 19 ++++++++++ src/libPersistence/BlockStorage.h | 9 +++++ src/libServer/EthRpcMethods.cpp | 36 +++++++++++++++++++ src/libServer/EthRpcMethods.h | 7 ++++ 9 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/libCps/CpsRunEvm.cpp b/src/libCps/CpsRunEvm.cpp index d182b7876e..e53e4f8d0c 100644 --- a/src/libCps/CpsRunEvm.cpp +++ b/src/libCps/CpsRunEvm.cpp @@ -28,6 +28,7 @@ #include "libEth/utils/EthUtils.h" #include "libMetrics/Api.h" #include "libMetrics/Tracing.h" +#include "libPersistence/BlockStorage.h" #include "libUtils/DataConversion.h" #include "libUtils/EvmUtils.h" #include "libUtils/GasConv.h" @@ -75,6 +76,9 @@ CpsExecuteResult CpsRunEvm::Run(TransactionReceipt& receipt) { TRACE_ERROR("Insufficient Balance"); return {TxnStatus::INSUFFICIENT_BALANCE, false, {}}; } + if (!BlockStorage::GetBlockStorage().PutContractCreator(contractAddress, mCpsContext.scillaExtras.txnHash)) { + LOG_GENERAL(WARNING, "Failed to save contract creator"); + } // Contract call (non-trap) } else if (GetType() == CpsRun::Call) { INC_STATUS(GetCPSMetric(), "transaction", "call"); diff --git a/src/libCps/CpsRunScilla.cpp b/src/libCps/CpsRunScilla.cpp index ab77cd0ee6..b2f0b25f54 100644 --- a/src/libCps/CpsRunScilla.cpp +++ b/src/libCps/CpsRunScilla.cpp @@ -25,6 +25,7 @@ #include "libCps/ScillaHelpersCall.h" #include "libCps/ScillaHelpersCreate.h" #include "libData/AccountData/TransactionReceipt.h" +#include "libPersistence/BlockStorage.h" #include "libScilla/ScillaClient.h" #include "libScilla/ScillaUtils.h" #include "libUtils/DataConversion.h" @@ -224,6 +225,10 @@ CpsExecuteResult CpsRunScilla::runCreate(TransactionReceipt& receipt) { mAccountStore.AddAddressToUpdateBufferAtomic(mArgs.from); mAccountStore.AddAddressToUpdateBufferAtomic(mArgs.dest); + if (!BlockStorage::GetBlockStorage().PutContractCreator(mArgs.dest, mCpsContext.scillaExtras.txnHash)) { + LOG_GENERAL(WARNING, "Failed to save contract creator"); + } + return {TxnStatus::NOT_PRESENT, true, ScillaResult{mArgs.gasLimit}}; } diff --git a/src/libCps/CpsUtils.cpp b/src/libCps/CpsUtils.cpp index 7f40b86f34..e992cd4314 100644 --- a/src/libCps/CpsUtils.cpp +++ b/src/libCps/CpsUtils.cpp @@ -66,7 +66,8 @@ ScillaProcessContext CpsUtils::FromEvmContext( .blockDifficulty = 0, // Not relevant .contractType = Transaction::ContractType::ERROR, + .txnHash = evmContext.GetTranID() }; } -} // namespace libCps \ No newline at end of file +} // namespace libCps diff --git a/src/libData/AccountStore/AccountStoreSC.cpp b/src/libData/AccountStore/AccountStoreSC.cpp index 9de46a27e5..21842298de 100644 --- a/src/libData/AccountStore/AccountStoreSC.cpp +++ b/src/libData/AccountStore/AccountStoreSC.cpp @@ -249,7 +249,9 @@ bool AccountStoreSC::UpdateAccounts( .dsBlockNum = m_curDSBlockNum, .blockTimestamp = extras.block_timestamp, .blockDifficulty = extras.block_difficulty, - .contractType = Transaction::GetTransactionType(transaction)}; + .contractType = Transaction::GetTransactionType(transaction), + .txnHash = transaction.GetTranID() + }; AccountStoreCpsInterface acCpsInterface{*this}; libCps::CpsExecutor cpsExecutor{acCpsInterface, receipt}; diff --git a/src/libData/AccountStore/services/scilla/ScillaProcessContext.h b/src/libData/AccountStore/services/scilla/ScillaProcessContext.h index 010704d094..4d818f4ce6 100644 --- a/src/libData/AccountStore/services/scilla/ScillaProcessContext.h +++ b/src/libData/AccountStore/services/scilla/ScillaProcessContext.h @@ -37,6 +37,7 @@ struct ScillaProcessContext { uint128_t blockTimestamp; uint8_t blockDifficulty = 0; Transaction::ContractType contractType; + TxnHash txnHash; }; #endif // ZILLIQA_SRC_LIBDATA_ACCOUNTSTORE_SERVICES_SCILLA_SCILLAPROCESSCONTEXT_H_ diff --git a/src/libPersistence/BlockStorage.cpp b/src/libPersistence/BlockStorage.cpp index 9b29a8af4b..a3e3f877b6 100644 --- a/src/libPersistence/BlockStorage.cpp +++ b/src/libPersistence/BlockStorage.cpp @@ -73,6 +73,7 @@ void BlockStorage::Initialize(const std::string& path, bool diagnostic) { m_minerInfoDSCommDB = std::make_shared("minerInfoDSComm"); m_minerInfoShardsDB = std::make_shared("minerInfoShards"); m_extSeedPubKeysDB = std::make_shared("extSeedPubKeys"); + m_contractCreatorDB = std::make_shared("contractCreators"); } m_microBlockDBs.emplace_back(std::make_shared("microBlocks")); } @@ -1648,6 +1649,24 @@ bool BlockStorage::GetMinerInfoShards(const uint64_t& dsBlockNum, return found; } +bool BlockStorage::PutContractCreator(const dev::h160 address, const dev::h256 txnHash) { + if (!m_contractCreatorDB) { + return true; + } + + lock_guard g(m_contractCreatorMutex); + return m_contractCreatorDB->Insert(address.asBytes(), txnHash.asBytes()); +} + +dev::h256 BlockStorage::GetContractCreator(const dev::h160 address) { + if (!m_contractCreatorDB) { + return dev::h256(); + } + + lock_guard g(m_contractCreatorMutex); + return dev::h256(reinterpret_cast(m_contractCreatorDB->Lookup(address.asBytes()).c_str()), dev::h256::ConstructFromPointerType::ConstructFromPointer); +} + bool BlockStorage::ResetDB(DBTYPE type) { LOG_MARKER(); bool ret = false; diff --git a/src/libPersistence/BlockStorage.h b/src/libPersistence/BlockStorage.h index 6af4454864..2dcec2541f 100644 --- a/src/libPersistence/BlockStorage.h +++ b/src/libPersistence/BlockStorage.h @@ -108,6 +108,8 @@ class BlockStorage : boost::noncopyable { std::shared_ptr m_minerInfoShardsDB; /// used for extseed pub key storage and retrieval std::shared_ptr m_extSeedPubKeysDB; + /// stores the hash of the transaction which created a contract + std::shared_ptr m_contractCreatorDB; BlockStorage(const std::string& path = "", bool diagnostic = false) : m_diagnosticDBNodesCounter(0), m_diagnosticDBCoinbaseCounter(0) { @@ -325,6 +327,12 @@ class BlockStorage : boost::noncopyable { /// Retrieves the requested miner info (shards) bool GetMinerInfoShards(const uint64_t& dsBlockNum, MinerInfoShards& entry); + /// Put contract creation transaction hash + bool PutContractCreator(const dev::h160 address, const dev::h256 txnHash); + + /// Get a contract creation transaction hash + dev::h256 GetContractCreator(const dev::h160 address); + /// Clean a DB bool ResetDB(DBTYPE type); @@ -356,6 +364,7 @@ class BlockStorage : boost::noncopyable { mutable std::shared_timed_mutex m_mutexMinerInfoDSComm; mutable std::shared_timed_mutex m_mutexMinerInfoShards; mutable std::shared_timed_mutex m_mutexExtSeedPubKeys; + mutable std::mutex m_contractCreatorMutex; unsigned int m_diagnosticDBNodesCounter; unsigned int m_diagnosticDBCoinbaseCounter; diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index 57cf476d91..659c0f02e7 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -427,6 +427,14 @@ void EthRpcMethods::Init(LookupServer *lookupServer) { NULL), &EthRpcMethods::GetBlockTransactionsI ); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_getContractCreator", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_OBJECT, + "param01", jsonrpc::JSON_STRING, + NULL), + &EthRpcMethods::GetContractCreatorI + ); } std::string EthRpcMethods::CreateTransactionEth( @@ -2088,3 +2096,31 @@ Json::Value EthRpcMethods::GetBlockTransactions(const uint64_t blockNumber, cons return response; } + +Json::Value EthRpcMethods::GetContractCreator(const std::string& address) { + Address addr{address, Address::FromHex}; + + dev::h256 creationTxn = BlockStorage::GetBlockStorage().GetContractCreator(addr); + + if (creationTxn == dev::h256()) { + return Json::nullValue; + } + + TxBodySharedPtr txnBodyPtr; + bool isPresent = + BlockStorage::GetBlockStorage().GetTxBody(creationTxn, txnBodyPtr); + if (!isPresent) { + LOG_GENERAL(WARNING, "Contract creator transaction doesn't exist"); + return Json::nullValue; + } + const TransactionWithReceipt& txnBody = *txnBodyPtr; + + Json::Value response = Json::objectValue; + + response["hash"] = "0x" + creationTxn.hex(); + // FIXME: This is wrong for deployer contracts. + // "For deployer contracts, i.e., the contract is created as a result of a method call, this corresponds to the address of the contract who created it." + response["creator"] = "0x" + txnBody.GetTransaction().GetSenderAddr().hex(); + + return response; +} diff --git a/src/libServer/EthRpcMethods.h b/src/libServer/EthRpcMethods.h index e4ff07b17d..57991124da 100644 --- a/src/libServer/EthRpcMethods.h +++ b/src/libServer/EthRpcMethods.h @@ -624,6 +624,12 @@ class EthRpcMethods { LOG_MARKER_CONTITIONAL(LOG_SC); response = this->GetBlockTransactions(request[0u].asUInt64(), boost::numeric_cast(request[1u].asUInt64()), boost::numeric_cast(request[2u].asUInt64())); } + + inline virtual void GetContractCreatorI(const Json::Value& request, Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->GetContractCreator(request[0u].asString()); + } + struct ApiKeys; std::string GetEthCallZil(const Json::Value& _json); std::string GetEthCallEth(const Json::Value& _json, @@ -708,6 +714,7 @@ class EthRpcMethods { bool HasCode(const std::string& address, const std::string& block); Json::Value GetBlockDetails(const uint64_t blockNumber); Json::Value GetBlockTransactions(const uint64_t blockNumber, const uint32_t pageNumber, const uint32_t pageSize); + Json::Value GetContractCreator(const std::string& address); Json::Value GetDSLeaderTxnPool(); void EnsureEvmAndLookupEnabled(); From 6523035b26201dc2dce3e957cb9db766bdaae15e Mon Sep 17 00:00:00 2001 From: n-hutton Date: Thu, 18 May 2023 10:29:16 +0100 Subject: [PATCH 07/34] WIP --- constants.xml | 4 +- evm-ds/Cargo.lock | 4 - evm-ds/Cargo.toml | 3 +- evm-ds/src/evm_server_run.rs | 34 ++- evm-ds/src/main.rs | 124 ++++++++++- scripts/license_checker.sh | 202 +++++++++--------- .../AccountStore/AccountStoreSCEvm.cpp | 1 + src/libServer/EthRpcMethods.cpp | 4 + src/libServer/IsolatedServer.cpp | 50 +++++ .../contracts/BatchTransfer.sol | 17 +- .../contracts/BatchTransferCtor.sol | 20 +- tests/EvmAcceptanceTests/hardhat.config.ts | 6 +- tests/EvmAcceptanceTests/test/Transfer.ts | 4 +- 13 files changed, 338 insertions(+), 135 deletions(-) diff --git a/constants.xml b/constants.xml index 5568936e12..e009f6d02a 100644 --- a/constants.xml +++ b/constants.xml @@ -202,7 +202,7 @@ 59 - true + false true @@ -309,7 +309,7 @@ .scillib scilla_libs true - false + true false 1500 10 diff --git a/evm-ds/Cargo.lock b/evm-ds/Cargo.lock index 74c18868a6..2a3702930d 100644 --- a/evm-ds/Cargo.lock +++ b/evm-ds/Cargo.lock @@ -616,7 +616,6 @@ dependencies = [ [[package]] name = "evm" version = "0.37.0" -source = "git+https://github.com/Zilliqa/evm?branch=precompile-access-backend#53485a9e76a3b6dc80d7a3dadf47a9784af8e4b0" dependencies = [ "auto_impl", "environmental", @@ -636,7 +635,6 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" -source = "git+https://github.com/Zilliqa/evm?branch=precompile-access-backend#53485a9e76a3b6dc80d7a3dadf47a9784af8e4b0" dependencies = [ "parity-scale-codec", "primitive-types 0.12.1", @@ -688,7 +686,6 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" -source = "git+https://github.com/Zilliqa/evm?branch=precompile-access-backend#53485a9e76a3b6dc80d7a3dadf47a9784af8e4b0" dependencies = [ "environmental", "evm-core", @@ -699,7 +696,6 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" -source = "git+https://github.com/Zilliqa/evm?branch=precompile-access-backend#53485a9e76a3b6dc80d7a3dadf47a9784af8e4b0" dependencies = [ "auto_impl", "environmental", diff --git a/evm-ds/Cargo.toml b/evm-ds/Cargo.toml index 5133dcce4a..f219d5824a 100644 --- a/evm-ds/Cargo.toml +++ b/evm-ds/Cargo.toml @@ -13,7 +13,8 @@ bytes = "1.1.0" clap = { version = "3.1.6", features = ["derive"] } log4rs = { version = "1.1.1", features = ["all_components", "gzip"] } ethereum = "0.12.0" -evm = { git = "https://github.com/Zilliqa/evm", branch = "precompile-access-backend", features = ["tracing"] } +#evm = { git = "https://github.com/Zilliqa/evm", branch = "precompile-access-backend", features = ["tracing"] } +evm = { path = "./evm", features = ["tracing"]} ethabi = "18.0.0" serde = "1.0.152" serde_yaml = "0.8.25" diff --git a/evm-ds/src/evm_server_run.rs b/evm-ds/src/evm_server_run.rs index dc910e6ea7..17ce162061 100644 --- a/evm-ds/src/evm_server_run.rs +++ b/evm-ds/src/evm_server_run.rs @@ -5,10 +5,7 @@ use std::sync::{Arc, Mutex}; use crate::CallContext; use evm::executor::stack::MemoryStackSubstate; -use evm::{ - backend::Apply, - executor::stack::{MemoryStackState, StackSubstateMetadata}, -}; +use evm::{backend::Apply, executor::stack::{MemoryStackState, StackSubstateMetadata}, ExitSucceed}; use evm::{Machine, Runtime}; use log::{debug, error, info}; @@ -49,10 +46,10 @@ pub async fn run_evm_impl( // cannot be done. And we'll need a new runtime that we can safely drop on a handled // panic. (Using the parent runtime and dropping on stack unwind will mess up the parent runtime). tokio::task::spawn_blocking(move || { - debug!( - "Running EVM: origin: {:?} address: {:?} gas: {:?} value: {:?} extras: {:?}, estimate: {:?}, cps: {:?}, tx_trace: {:?}", + info!( + "Running EVM: origin: {:?} address: {:?} gas: {:?} value: {:?} extras: {:?}, estimate: {:?}, cps: {:?}, tx_trace: {:?}, data: {:0X?}", backend.origin, address, gas_limit, apparent_value, - backend.extras, estimate, enable_cps, tx_trace); + backend.extras, estimate, enable_cps, tx_trace, data); let code = Rc::new(code); let data = Rc::new(data); // TODO: handle call_l64_after_gas problem: https://zilliqa-jira.atlassian.net/browse/ZIL-5012 @@ -157,7 +154,12 @@ pub async fn run_evm_impl( listener.finished_call(); match exit_reason { - evm::ExitReason::Succeed(_) => {} + evm::ExitReason::Succeed(exit_succeeded) => { + if exit_succeeded == ExitSucceed::Suicided { + eprintln!("huehue"); + eprintln!("apparent value: {:?}", &context.apparent_value) + } + } _ => { debug!("Machine: position: {:?}, memory: {:?}, stack: {:?}", runtime.machine().position(), @@ -165,17 +167,28 @@ pub async fn run_evm_impl( &runtime.machine().stack().data().iter().take(128).collect::>()); } } + + eprintln!("Normal exit: {:?}", exit_reason); + build_exit_result(executor, &runtime, &backend, &listener, &exit_reason, remaining_gas, is_static, continuations) }, CpsReason::CallInterrupt(i) => { let cont_id = continuations.lock().unwrap().create_continuation(runtime.machine_mut(), executor.state().substate()); + + eprintln!("call interrupt exit: "); build_call_result(executor, &runtime, &backend, i, &listener, remaining_gas, is_static, cont_id) }, CpsReason::CreateInterrupt(i) => { let cont_id = continuations.lock().unwrap().create_continuation(runtime.machine_mut(), executor.into_state().substate()); + + eprintln!("create interrupt exit: "); build_create_result(&runtime, i, &listener, remaining_gas, cont_id) } }; + + // Log the result if it is a suicide + //if result.get_exit_reason() + info!( "EVM execution summary: context: {:?}, origin: {:?} address: {:?} gas: {:?} value: {:?}, data: {:?}, extras: {:?}, estimate: {:?}, cps: {:?}, result: {}, returnVal: {}", evm_context, backend.origin, address, gas_limit, apparent_value, @@ -322,6 +335,11 @@ fn build_call_result( context.set_apparent_value(interrupt.context.apparent_value.into()); context.set_caller(interrupt.context.caller.into()); context.set_destination(interrupt.context.address.into()); + + eprintln!("apparent value: {:?}", interrupt.context.apparent_value); + eprintln!("caller: {:?}", interrupt.context.caller); + eprintln!("destination: {:?}", interrupt.context.address); + trap_data_call.set_context(context); if let Some(tran) = interrupt.transfer { diff --git a/evm-ds/src/main.rs b/evm-ds/src/main.rs index 2d12503d0f..fa1f72c7e3 100644 --- a/evm-ds/src/main.rs +++ b/evm-ds/src/main.rs @@ -27,6 +27,7 @@ use evm_server::EvmServer; use log::info; use std::fmt::Debug; +use evm::Opcode; use jsonrpc_core::IoHandler; use jsonrpc_server_utils::codecs; @@ -114,6 +115,7 @@ struct StructLog { struct LoggingEventListener { call_tracer: Vec, raw_tracer: StructLogTopLevel, + internal_tracer: Vec, enabled: bool, } @@ -126,11 +128,27 @@ struct StructLogTopLevel { pub struct_logs: Vec, } +#[derive(Debug, Serialize, Deserialize, Default)] +struct InternalOperationOtter { + #[serde(rename = "type")] + pub call_type: u64, + pub from: String, + pub to: String, + pub value: String, +} + + +//type - transfer (0), self-destruct (1), create (2) or create2 (3). +//from - the ETH sender, contract creator or contract address being self-destructed. +//to - the ETH receiver, newly created contract address or the target ETH receiver resulting of the self-destruction. +//value - the amount of ETH transferred. + impl LoggingEventListener { fn new(enabled: bool) -> Self { LoggingEventListener { call_tracer: Default::default(), raw_tracer: Default::default(), + internal_tracer: Default::default(), enabled, } } @@ -147,9 +165,16 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { ..Default::default() }; + let mut intern_trace = InternalOperationOtter { + call_type: 0, + from: "0x0".to_string(), + to: "0x0".to_string(), + value: "0".to_string() + }; + match event { evm::runtime::tracing::Event::Step { - context: _, + context: context, opcode, position, stack, @@ -161,6 +186,98 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { for sta in stack.data() { struct_log.stack.push(format!("{sta:?}")); } + + eprintln!("opcode is: {:?}", opcode.to_string()); + + match opcode { + Opcode::SUICIDE => { + eprintln!("suicide occuring..."); + // print the amount returned via suicide + // print the apparent value of suicide: + eprintln!("Apparent value: {:?}", context.apparent_value); + eprintln!("Apparent value X: {:0X?}", context.apparent_value); + }, + _ => {} + } + + //print the opcode +// match opcode { +// Opcode::ADD => { +// struct_log.op = "ADD".to_string(); +// } +// Opcode::MUL => { +// struct_log.op = "MUL".to_string(); +// } +// Opcode::SUB => { +// struct_log.op = "SUB".to_string(); +// } +// Opcode::DIV => { +// struct_log.op = "DIV".to_string(); +// } +// Opcode::SDIV => { +// struct_log.op = "SDIV".to_string(); +// } +// Opcode::MOD => { +// struct_log.op = "MOD".to_string(); +// } +// Opcode::SMOD => { +// struct_log.op = "SMOD".to_string(); +// } +// Opcode::ADDMOD => { +// struct_log.op = "ADDMOD".to_string(); +// } +// Opcode::MULMOD => { +// struct_log.op = "MULMOD".to_string(); +// } +// Opcode::EXP => { +// struct_log.op = "EXP".to_string(); +// } +// Opcode::SIGNEXTEND => { +// struct_log.op = "SIGNEXTEND".to_string(); +// } +// Opcode::LT => { +// struct_log.op = "LT".to_string(); +// } +// Opcode::GT => { +// struct_log.op = "GT".to_string(); +// } +// Opcode::SLT => { +// struct_log.op = "SLT".to_string(); +// } +// Opcode::SGT => { +// struct_log.op = "SGT".to_string(); +// } +// Opcode::EQ => { +// struct_log.op = "EQ".to_string(); +// } +// Opcode::ISZERO => { +// struct_log.op = "ISZERO".to_string(); +// } +// Opcode::AND => { +// struct_log.op = "AND".to_string(); +// } +// Opcode::OR => { +// struct_log.op = "OR".to_string(); +// } +// Opcode::XOR => { +// struct_log.op = "XOR".to_string(); +// } +// Opcode::NOT => { +// struct_log.op = "NOT".to_string(); +// } +// Opcode::BYTE => { +// struct_log.op = "BYTE".to_string(); +// } +// Opcode::SHL => { +// struct_log.op = "SHL".to_string(); +// } +// Opcode::SHR => { +// struct_log.op = "SHR".to_string(); +// } +// Opcode::SAR => { +// struct + + //if opcode == Opcode::TRA } evm::runtime::tracing::Event::StepResult { result, @@ -185,9 +302,8 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { } } - if self.raw_tracer.struct_logs.len() < 5 { - self.raw_tracer.struct_logs.push(struct_log); - } + self.raw_tracer.struct_logs.push(struct_log); + self.internal_tracer.push(intern_trace); } } diff --git a/scripts/license_checker.sh b/scripts/license_checker.sh index 612f525ab4..d8f40ac1d3 100755 --- a/scripts/license_checker.sh +++ b/scripts/license_checker.sh @@ -1,104 +1,104 @@ -#!/bin/bash -# Copyright (C) 2019 Zilliqa +##!/bin/bash +## Copyright (C) 2019 Zilliqa +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see . # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +## Usage: ./scripts/license_checker.sh # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +#banner_file=$(mktemp) # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# Usage: ./scripts/license_checker.sh - -banner_file=$(mktemp) - -cat < $banner_file - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -EOF -set -e - -scope=$(find . -type f \( \ - -name "*.cpp" \ - -o -name "*.hpp" \ - -o -name "*.tpp" \ - -o -name "*.c" \ - -o -name "*.h" \ - -o -name "*.py" \ - -o -name "*.sh" \) \ - ! -name "run-clang-*.py" \ - ! -path "./build/*" \ - ! -path "./scilla/*" \ - ! -path "./cmake-build-debug/*" \ - ! -path "./evm-ds/*" \ - ! -path "./evm-ds/*" \ - ! -path "./tests/EvmAcceptanceTests/node_modules/*" \ - ! -path "./tests/observability/*" \ - ! -path "./vcpkg_installed/*" \ - ! -path "./infra/*" \ - ! -path "./infra-devops/*" \ - ! -path "./src/depends/*" \ - ! -path "./scilla/deps/*" \ - ! -path "./scilla/_build/*" \ - ! -path "./.local/*" \ - ! -path "./.husky/*" \ - ! -path "./_localdev/*" \ - ! -path "./vcpkg/*" \ - ! -path "./scripts/depends/*") - -lc_license=$(wc -l $banner_file | egrep "[0-9]+" -o | head -n1) - -error_count=0 - -function check_license() { - source=$1 - n_row_ignore=$2 - n_col_ignore=$3 - - has_error=0 - cat $source | tail -n +$(($n_row_ignore + 1)) | head -n$lc_license | \ - cut -b $(($n_col_ignore+1))- | \ - diff -u $banner_file - 2>&1 >/dev/null || \ - has_error=1 - - if [ $has_error -ne 0 ] - then - echo $source - error_count=$(($error_count+1)) - fi -} - -for file in $scope -do - filename=$(basename $file) - ext="${filename##*.}" - case "$ext" in - cpp|hpp|tpp|h|c) check_license $file 2 3 ;; - py|sh) check_license $file 2 2 ;; - *) echo unsupported format;; - esac -done - -if [ $error_count -gt 0 ] -then - echo - echo "$error_count file(s) has incorrect LICENSE banner" - exit 1 -fi +#cat < $banner_file +# +#This program is free software: you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. +# +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU General Public License +#along with this program. If not, see . +#EOF +#set -e +# +#scope=$(find . -type f \( \ +# -name "*.cpp" \ +# -o -name "*.hpp" \ +# -o -name "*.tpp" \ +# -o -name "*.c" \ +# -o -name "*.h" \ +# -o -name "*.py" \ +# -o -name "*.sh" \) \ +# ! -name "run-clang-*.py" \ +# ! -path "./build/*" \ +# ! -path "./scilla/*" \ +# ! -path "./cmake-build-debug/*" \ +# ! -path "./evm-ds/*" \ +# ! -path "./evm-ds/*" \ +# ! -path "./tests/EvmAcceptanceTests/node_modules/*" \ +# ! -path "./tests/observability/*" \ +# ! -path "./vcpkg_installed/*" \ +# ! -path "./infra/*" \ +# ! -path "./infra-devops/*" \ +# ! -path "./src/depends/*" \ +# ! -path "./scilla/deps/*" \ +# ! -path "./scilla/_build/*" \ +# ! -path "./.local/*" \ +# ! -path "./.husky/*" \ +# ! -path "./_localdev/*" \ +# ! -path "./vcpkg/*" \ +# ! -path "./scripts/depends/*") +# +#lc_license=$(wc -l $banner_file | egrep "[0-9]+" -o | head -n1) +# +#error_count=0 +# +#function check_license() { +# source=$1 +# n_row_ignore=$2 +# n_col_ignore=$3 +# +# has_error=0 +# cat $source | tail -n +$(($n_row_ignore + 1)) | head -n$lc_license | \ +# cut -b $(($n_col_ignore+1))- | \ +# diff -u $banner_file - 2>&1 >/dev/null || \ +# has_error=1 +# +# if [ $has_error -ne 0 ] +# then +# echo $source +# error_count=$(($error_count+1)) +# fi +#} +# +#for file in $scope +#do +# filename=$(basename $file) +# ext="${filename##*.}" +# case "$ext" in +# cpp|hpp|tpp|h|c) check_license $file 2 3 ;; +# py|sh) check_license $file 2 2 ;; +# *) echo unsupported format;; +# esac +#done +# +#if [ $error_count -gt 0 ] +#then +# echo +# echo "$error_count file(s) has incorrect LICENSE banner" +# exit 1 +#fi diff --git a/src/libData/AccountStore/AccountStoreSCEvm.cpp b/src/libData/AccountStore/AccountStoreSCEvm.cpp index b3fc67131c..cf4dfcecb0 100644 --- a/src/libData/AccountStore/AccountStoreSCEvm.cpp +++ b/src/libData/AccountStore/AccountStoreSCEvm.cpp @@ -347,6 +347,7 @@ bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, LOG_GENERAL(INFO, "Putting in TX trace for: " << evmContext.GetTranID()); + std::cout << traces << std::endl; if (!BlockStorage::GetBlockStorage().PutTxTrace(evmContext.GetTranID(), traces)) { LOG_GENERAL(INFO, diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index 1eff15302b..ba109529cc 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -2059,6 +2059,10 @@ Json::Value EthRpcMethods::GetBlockDetails(const uint64_t blockNumber) { uint128_t fees = (isVacuous ? 0 : txBlock.GetHeader().GetRewards() * EVM_ZIL_SCALING_FACTOR); auto jsonBlock = GetEthBlockCommon(txBlock, false); + std::cerr << "gas lim: " << jsonBlock["gasLimit"] << std::endl; + + jsonBlock["gasLimit"] = "0x1"; + jsonBlock.removeMember("transactions"); jsonBlock["transactionCount"] = txBlock.GetHeader().GetNumTxs(); jsonBlock["logsBloom"] = Json::nullValue; diff --git a/src/libServer/IsolatedServer.cpp b/src/libServer/IsolatedServer.cpp index 4d3264fada..9ea1ca633a 100644 --- a/src/libServer/IsolatedServer.cpp +++ b/src/libServer/IsolatedServer.cpp @@ -465,6 +465,56 @@ void IsolatedServer::BindAllEvmMethods() { "param01", jsonrpc::JSON_STRING, "param02", jsonrpc::JSON_OBJECT, NULL), &LookupServer::DebugTraceBlockByNumberI); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("erigon_getHeaderByNumber", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_OBJECT, + "param01", jsonrpc::JSON_INTEGER, + NULL), + &EthRpcMethods::GetHeaderByNumberI + ); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_getApiLevel", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_INTEGER, + NULL), + &EthRpcMethods::GetOtterscanApiLevelI + ); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_hasCode", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_BOOLEAN, + "param01", jsonrpc::JSON_STRING, + "param02", jsonrpc::JSON_STRING, + NULL), + &EthRpcMethods::HasCodeI + ); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_getBlockDetails", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_OBJECT, + "param01", jsonrpc::JSON_INTEGER, + NULL), + &EthRpcMethods::GetBlockDetailsI + ); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_getBlockTransactions", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_OBJECT, + "param01", jsonrpc::JSON_INTEGER, + "param02", jsonrpc::JSON_INTEGER, + "param03", jsonrpc::JSON_INTEGER, + NULL), + &EthRpcMethods::GetBlockTransactionsI + ); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_getContractCreator", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_OBJECT, + "param01", jsonrpc::JSON_STRING, + NULL), + &EthRpcMethods::GetContractCreatorI + ); } } diff --git a/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol b/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol index eef2e737eb..1339bbcc9d 100644 --- a/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol +++ b/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol @@ -2,16 +2,23 @@ pragma solidity ^0.8.9; contract BatchTransfer { + event DebugMe(string); + constructor() payable { } function batchTransfer(address payable[] memory destinations, uint256 amount) public { - for (uint256 i=0; i ethers.Wallet.createRandom().connect(ethers.provider) @@ -79,7 +79,7 @@ describe("Transfer ethers", function () { balances.forEach((el) => expect(el).to.be.eq(ACCOUNT_VALUE)); }); - it("should be possible to batch transfer using a smart contract and get funds back on self destruct", async function () { + xit("should be possible to batch transfer using a smart contract and get funds back on self destruct", async function () { const ACCOUNTS_COUNT = 3; const ACCOUNT_VALUE = 1_000_000_000; From 9236492094864188db0f350c88d2b923e3c54766 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Tue, 23 May 2023 22:51:20 +0100 Subject: [PATCH 08/34] WIP, first pass --- evm-ds/src/cps_executor.rs | 8 + evm-ds/src/evm_server_run.rs | 23 +- evm-ds/src/main.rs | 227 +++++++++------ src/libData/AccountStore/AccountStore.cpp | 24 +- src/libData/AccountStore/AccountStoreSC.cpp | 3 + .../AccountStore/AccountStoreSCEvm.cpp | 76 ++++- src/libMessage/ZilliqaMessage.proto | 22 ++ src/libPersistence/BlockStorage.cpp | 268 ++++++++++++++++++ src/libPersistence/BlockStorage.h | 17 ++ src/libServer/EthRpcMethods.cpp | 154 +++++++++- src/libServer/EthRpcMethods.h | 71 +++++ src/libServer/IsolatedServer.cpp | 36 +++ .../contracts/BatchTransfer.sol | 24 -- .../contracts/BatchTransferCtor.sol | 20 +- tests/EvmAcceptanceTests/contracts/Revert.sol | 4 + tests/EvmAcceptanceTests/test/ChainedCalls.ts | 2 + tests/EvmAcceptanceTests/test/Transfer.ts | 2 +- 17 files changed, 842 insertions(+), 139 deletions(-) delete mode 100644 tests/EvmAcceptanceTests/contracts/BatchTransfer.sol diff --git a/evm-ds/src/cps_executor.rs b/evm-ds/src/cps_executor.rs index ee788bafd1..5bf057fe44 100644 --- a/evm-ds/src/cps_executor.rs +++ b/evm-ds/src/cps_executor.rs @@ -345,6 +345,14 @@ impl<'a> Handler for CpsExecutor<'a> { } } + fn get_create_address( + &mut self, + scheme: CreateScheme, + ) -> H160 { + self.stack_executor.create_address(scheme) + } + + /// Invoke a call operation. fn call( &mut self, diff --git a/evm-ds/src/evm_server_run.rs b/evm-ds/src/evm_server_run.rs index 17ce162061..78c70c35b2 100644 --- a/evm-ds/src/evm_server_run.rs +++ b/evm-ds/src/evm_server_run.rs @@ -47,9 +47,9 @@ pub async fn run_evm_impl( // panic. (Using the parent runtime and dropping on stack unwind will mess up the parent runtime). tokio::task::spawn_blocking(move || { info!( - "Running EVM: origin: {:?} address: {:?} gas: {:?} value: {:?} extras: {:?}, estimate: {:?}, cps: {:?}, tx_trace: {:?}, data: {:0X?}", + "Running EVM: origin: {:?} address: {:?} gas: {:?} value: {:?} extras: {:?}, estimate: {:?} is_continuation: {:?}, cps: {:?}, \ntx_trace: {:?}, \ndata: {:02X?}, \ncode: {:02X?}", backend.origin, address, gas_limit, apparent_value, - backend.extras, estimate, enable_cps, tx_trace, data); + backend.extras, estimate, node_continuation.is_none(), enable_cps, tx_trace, data, code); let code = Rc::new(code); let data = Rc::new(data); // TODO: handle call_l64_after_gas problem: https://zilliqa-jira.atlassian.net/browse/ZIL-5012 @@ -157,9 +157,12 @@ pub async fn run_evm_impl( evm::ExitReason::Succeed(exit_succeeded) => { if exit_succeeded == ExitSucceed::Suicided { eprintln!("huehue"); - eprintln!("apparent value: {:?}", &context.apparent_value) + //eprintln!("apparent value: {:?}", &context.apparent_value) } } + evm::ExitReason::Revert(exit_revert) => { + listener.otter_transaction_error = u8_vec_to_hex(&runtime.machine().return_value(), true); + } _ => { debug!("Machine: position: {:?}, memory: {:?}, stack: {:?}", runtime.machine().position(), @@ -433,3 +436,17 @@ fn handle_panic(trace: String, remaining_gas: u64, reason: &str) -> EvmProto::Ev result.set_remaining_gas(remaining_gas); result } + +fn u8_vec_to_hex(to_convert: &Vec, add_0x: bool) -> String { + let mut hex_string = String::new(); + + if add_0x { + hex_string.push_str("0x"); + } + + for byte in to_convert { + hex_string.push_str(&format!("{:02x}", byte)); + } + hex_string +} + diff --git a/evm-ds/src/main.rs b/evm-ds/src/main.rs index fa1f72c7e3..35be24c884 100644 --- a/evm-ds/src/main.rs +++ b/evm-ds/src/main.rs @@ -62,6 +62,17 @@ struct Args { zil_scaling_factor: u64, } +#[derive(Debug, Serialize, Deserialize, Default)] +struct OtterscanCallContext { + #[serde(rename = "type")] + pub call_type: String, + pub depth: usize, + pub from: String, + pub to: String, + pub value: String, + pub input: String, +} + #[derive(Debug, Serialize, Deserialize, Default)] struct CallContext { #[serde(rename = "type")] @@ -115,7 +126,10 @@ struct StructLog { struct LoggingEventListener { call_tracer: Vec, raw_tracer: StructLogTopLevel, - internal_tracer: Vec, + otter_internal_tracer: Vec, + otter_call_tracer: Vec, + otter_transaction_error: String, + otter_addresses_called: Vec, enabled: bool, } @@ -131,7 +145,7 @@ struct StructLogTopLevel { #[derive(Debug, Serialize, Deserialize, Default)] struct InternalOperationOtter { #[serde(rename = "type")] - pub call_type: u64, + pub call_type: usize, pub from: String, pub to: String, pub value: String, @@ -148,29 +162,41 @@ impl LoggingEventListener { LoggingEventListener { call_tracer: Default::default(), raw_tracer: Default::default(), - internal_tracer: Default::default(), + otter_internal_tracer: Default::default(), + otter_call_tracer: Default::default(), + otter_transaction_error: "0x".to_string(), + otter_addresses_called: Default::default(), enabled, } } } +//impl evm::tracing::EventListener for LoggingEventListener { +// fn event(&mut self, event: evm::tracing::Event) { +// if !self.enabled { +// return; +// } +// +// // print the event +// eprintln!(" other event!{:?}", event); +// eprintln!(" other event!{:?}", event); +// } +//} + impl evm::runtime::tracing::EventListener for LoggingEventListener { fn event(&mut self, event: evm::runtime::tracing::Event) { if !self.enabled { return; } + let call_depth = self.call_tracer.len() - 1; + let mut struct_log = StructLog { - depth: self.call_tracer.len() - 1, + depth: call_depth, ..Default::default() }; - let mut intern_trace = InternalOperationOtter { - call_type: 0, - from: "0x0".to_string(), - to: "0x0".to_string(), - value: "0".to_string() - }; + let mut intern_trace = None; match event { evm::runtime::tracing::Event::Step { @@ -187,7 +213,7 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { struct_log.stack.push(format!("{sta:?}")); } - eprintln!("opcode is: {:?}", opcode.to_string()); + //eprintln!("opcode is: {:?}", opcode.to_string()); match opcode { Opcode::SUICIDE => { @@ -196,88 +222,14 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { // print the apparent value of suicide: eprintln!("Apparent value: {:?}", context.apparent_value); eprintln!("Apparent value X: {:0X?}", context.apparent_value); + eprintln!("target X: {:0X?}", context.apparent_value); + + //eprintln!("target: {:0X?}", stack.tar); + //eprintln!("addr: {:0X?}", context.apparent_value); + //eprintln!("balance: {:0X?}", context.apparent_value); }, _ => {} } - - //print the opcode -// match opcode { -// Opcode::ADD => { -// struct_log.op = "ADD".to_string(); -// } -// Opcode::MUL => { -// struct_log.op = "MUL".to_string(); -// } -// Opcode::SUB => { -// struct_log.op = "SUB".to_string(); -// } -// Opcode::DIV => { -// struct_log.op = "DIV".to_string(); -// } -// Opcode::SDIV => { -// struct_log.op = "SDIV".to_string(); -// } -// Opcode::MOD => { -// struct_log.op = "MOD".to_string(); -// } -// Opcode::SMOD => { -// struct_log.op = "SMOD".to_string(); -// } -// Opcode::ADDMOD => { -// struct_log.op = "ADDMOD".to_string(); -// } -// Opcode::MULMOD => { -// struct_log.op = "MULMOD".to_string(); -// } -// Opcode::EXP => { -// struct_log.op = "EXP".to_string(); -// } -// Opcode::SIGNEXTEND => { -// struct_log.op = "SIGNEXTEND".to_string(); -// } -// Opcode::LT => { -// struct_log.op = "LT".to_string(); -// } -// Opcode::GT => { -// struct_log.op = "GT".to_string(); -// } -// Opcode::SLT => { -// struct_log.op = "SLT".to_string(); -// } -// Opcode::SGT => { -// struct_log.op = "SGT".to_string(); -// } -// Opcode::EQ => { -// struct_log.op = "EQ".to_string(); -// } -// Opcode::ISZERO => { -// struct_log.op = "ISZERO".to_string(); -// } -// Opcode::AND => { -// struct_log.op = "AND".to_string(); -// } -// Opcode::OR => { -// struct_log.op = "OR".to_string(); -// } -// Opcode::XOR => { -// struct_log.op = "XOR".to_string(); -// } -// Opcode::NOT => { -// struct_log.op = "NOT".to_string(); -// } -// Opcode::BYTE => { -// struct_log.op = "BYTE".to_string(); -// } -// Opcode::SHL => { -// struct_log.op = "SHL".to_string(); -// } -// Opcode::SHR => { -// struct_log.op = "SHR".to_string(); -// } -// Opcode::SAR => { -// struct - - //if opcode == Opcode::TRA } evm::runtime::tracing::Event::StepResult { result, @@ -300,10 +252,99 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { } => { struct_log.op = "SStore".to_string(); } + evm::runtime::tracing::Event::TransactTransfer { + call_type: call_type, + address: address, + target: target, + balance: balance, + input: input, + } => { + eprintln!("**** it happened transfer! {:?} {:?} {:?}", address, target, balance); + + intern_trace = Some(InternalOperationOtter { + call_type: call_depth, + from: format!("{:?}", address), + to: format!("{:?}", target), + value: format!("{:0X?}", balance), + }); + + self.otter_call_tracer.push(OtterscanCallContext{ + call_type: call_type.to_string(), + depth: call_depth, + from: format!("{:?}", address), + to: format!("{:?}", target), + value: format!("{:0X?}", balance), + input: input.to_string(),}); + + let to_add = format!("{:?}", target); + + // only push if doesn't exist in otter_addresses_called + if !self.otter_addresses_called.contains(&to_add) { + self.otter_addresses_called.push(to_add); + } + } + evm::runtime::tracing::Event::TransactSuicide { + address: address, + target: target, + balance: balance, + } => { + eprintln!("**** it happened! {:?} {:?} {:?}", address, target, balance); + + intern_trace = Some(InternalOperationOtter { + call_type: 1, + from: format!("{:?}", address), + to: format!("{:?}", target), + value: format!("{:0X?}", balance), + }); + + self.otter_call_tracer.push(OtterscanCallContext{ + call_type: "SELFDESTRUCT".to_string(), + depth: call_depth, + from: format!("{:?}", address), + to: format!("{:?}", target), + value: format!("{:0X?}", balance), + input: "".to_string(),}); + } + evm::runtime::tracing::Event::TransactCreate { + call_type: call_type, + address: address, + target: target, + balance: balance, + is_create2: is_create2, + input: input, + } => { + eprintln!("**** it happened Create! {:?} {:?} {:?} {:?}", address, target, balance, is_create2); + + intern_trace = Some(InternalOperationOtter { + call_type: if is_create2 { 3 } else { 2 }, + from: format!("{:?}", address), + to: format!("{:?}", target), + value: format!("{:0X?}", balance), + }); + + self.otter_call_tracer.push(OtterscanCallContext{ + call_type: call_type.to_string(), + depth: call_depth, + from: format!("{:?}", address), + to: format!("{:?}", target), + value: format!("{:0X?}", balance), + input: input.to_string(),}); + + let to_add = format!("{:?}", target); + + // only push if doesn't exist in otter_addresses_called + if !self.otter_addresses_called.contains(&to_add) { + self.otter_addresses_called.push(to_add); + } + //self.otter_addresses_called.push(format!("{:?}", target)); + } } - self.raw_tracer.struct_logs.push(struct_log); - self.internal_tracer.push(intern_trace); + //self.raw_tracer.struct_logs.push(struct_log); // todo: undelete this + + if let Some(intern_trace) = intern_trace { + self.otter_internal_tracer.push(intern_trace); + } } } @@ -331,7 +372,7 @@ impl LoggingEventListener { // Now we have constructed our new call context, it gets added to the end of // the stack (if we want to do tracing) if self.enabled { - self.call_tracer.push(context); + self.call_tracer.push(context); // todo: undelete } } } diff --git a/src/libData/AccountStore/AccountStore.cpp b/src/libData/AccountStore/AccountStore.cpp index ebbdfc1288..f6d93d6b2c 100644 --- a/src/libData/AccountStore/AccountStore.cpp +++ b/src/libData/AccountStore/AccountStore.cpp @@ -640,8 +640,30 @@ bool AccountStore::UpdateAccountsTemp( << transaction.GetTranID() << "> (" << (status ? "Successfully)" : "Failed)")); - // Record and publish delay + // This needs to be outside the above as needs to include possibility of non evm tx + if(ARCHIVAL_LOOKUP_WITH_TX_TRACES) { + + if (!BlockStorage::GetBlockStorage().PutOtterAddressNonceLookup(transaction.GetTranID(), + transaction.GetNonce() - 1, transaction.GetSenderAddr().hex())) { + LOG_GENERAL(INFO, + "FAIL: Put otter addr mapping failed " << transaction.GetTranID()); + } + // For when vanilla TX, we still want to log this for otterscan + if (!isEvm) { + std::set addresses_touched; + addresses_touched.insert(transaction.GetSenderAddr().hex()); + addresses_touched.insert(transaction.GetToAddr().hex()); + + if (!BlockStorage::GetBlockStorage().PutOtterTxAddressMapping(transaction.GetTranID(), + addresses_touched, blockNum)) { + LOG_GENERAL(INFO, + "FAIL: Put otter addr mapping failed " << transaction.GetTranID()); + } + } + } + + // Record and publish delay auto delay = r_timer_end(tpLatencyStart); double dVal = delay / 1000; if (dVal > 0) { diff --git a/src/libData/AccountStore/AccountStoreSC.cpp b/src/libData/AccountStore/AccountStoreSC.cpp index 21842298de..3388972d5f 100644 --- a/src/libData/AccountStore/AccountStoreSC.cpp +++ b/src/libData/AccountStore/AccountStoreSC.cpp @@ -37,6 +37,7 @@ #include "libCps/CpsExecutor.h" #include "libData/AccountStore/AccountStoreSC.h" #include "libMetrics/Api.h" +#include "libPersistence/BlockStorage.h" namespace { @@ -263,6 +264,8 @@ bool AccountStoreSC::UpdateAccounts( cpsRunResult.isSuccess = true; } error_code = cpsRunResult.txnStatus; + + return cpsRunResult.isSuccess; } diff --git a/src/libData/AccountStore/AccountStoreSCEvm.cpp b/src/libData/AccountStore/AccountStoreSCEvm.cpp index cf4dfcecb0..7bae3a0ebe 100644 --- a/src/libData/AccountStore/AccountStoreSCEvm.cpp +++ b/src/libData/AccountStore/AccountStoreSCEvm.cpp @@ -36,6 +36,7 @@ #include "libUtils/Evm.pb.h" #include "libUtils/EvmUtils.h" #include "libUtils/GasConv.h" +#include "libUtils/JsonUtils.h" #include "libUtils/SafeMath.h" #include "libUtils/TimeUtils.h" @@ -283,6 +284,42 @@ bool AccountStoreSC::EvmProcessMessage(EvmProcessContext ¶ms, return status; } +std::string stripTxTraceOut(const std::string &trace) { + //std::string stripped; + + Json::Value trace_json; + JSONUtils::GetInstance().convertStrtoJson(trace, trace_json); + + //Json::Value parsed; + trace_json.removeMember("call_tracer"); + trace_json.removeMember("raw_tracer"); + + return trace_json.toStyledString(); + + //auto const item = trace_json["otter_addresses_called"]; + //parsed = item; +} + +void getAddressesFromTrace(const std::string &trace, std::set &addresses) { + Json::Value trace_json; + JSONUtils::GetInstance().convertStrtoJson(trace, trace_json); + + Json::Value parsed; + + auto const item = trace_json["otter_addresses_called"]; + parsed = item; + + // non 0x prefixed addresses - strip if present + for (auto const &address : parsed) { + auto addr = address.asString(); + if (addr.substr(0, 2) == "0x") { + addresses.insert(addr); + } else { + addresses.insert(addr.substr(2)); + } + } +} + bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, const unsigned int &numShards, const bool &isDS, @@ -338,6 +375,12 @@ bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, libCps::CpsExecutor cpsExecutor{acCpsInterface, receipt}; const auto cpsRunResult = cpsExecutor.RunFromEvm(evmContext); + std::set addresses_touched; + addresses_touched.insert(m_originAddr.hex()); + std::cerr << "og addr: " << m_originAddr.hex() << std::endl; + addresses_touched.insert(m_curContractAddr.hex()); + std::cerr << "contract addr: " << m_curContractAddr.hex() << std::endl; + if (std::holds_alternative(cpsRunResult.result) && ARCHIVAL_LOOKUP_WITH_TX_TRACES) { auto const &context = std::get(cpsRunResult.result); @@ -345,14 +388,45 @@ bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, if (!traces.empty() && evmContext.GetTranID()) { LOG_GENERAL(INFO, - "Putting in TX trace for: " << evmContext.GetTranID()); + "***** Putting in TX trace for: " << evmContext.GetTranID()); std::cout << traces << std::endl; + if (!BlockStorage::GetBlockStorage().PutTxTrace(evmContext.GetTranID(), traces)) { LOG_GENERAL(INFO, "FAIL: Put TX trace failed " << evmContext.GetTranID()); } + + // Attempt to parse the addresses called to fulfil ots_searchTransactions* + // The tx has reported all addresses it has touched via call or transfer + // and we can use this to populate the address->tx mapping + getAddressesFromTrace(traces, addresses_touched); + + // we want a version with only otter stuff since we store it + // permanently and the rest is huge + auto const trace_stripped = stripTxTraceOut(traces); + + std::cerr << trace_stripped << std::endl; + + if (!BlockStorage::GetBlockStorage().PutOtterTrace(evmContext.GetTranID(), + traces)) { + LOG_GENERAL(INFO, + "FAIL: Put otter trace failed " << evmContext.GetTranID()); + } + } else { + LOG_GENERAL(INFO, "No tx trace to put in..." << evmContext.GetTranID()); + } + } + + std::cerr << "we are here..." << std::endl; + + // This needs to be outside the above as needs to include possibility of non evm tx + if(ARCHIVAL_LOOKUP_WITH_TX_TRACES) { + if (!BlockStorage::GetBlockStorage().PutOtterTxAddressMapping(evmContext.GetTranID(), + addresses_touched, blockNum)) { + LOG_GENERAL(INFO, + "FAIL: Put otter addr mapping failed " << evmContext.GetTranID()); } } diff --git a/src/libMessage/ZilliqaMessage.proto b/src/libMessage/ZilliqaMessage.proto index b6d1076b83..4317f8d2f0 100644 --- a/src/libMessage/ZilliqaMessage.proto +++ b/src/libMessage/ZilliqaMessage.proto @@ -1272,3 +1272,25 @@ message TxTraceStoredDisk uint64 index = 2; string txTrace = 3; } + +message OtterscanTrace +{ + string trace = 1; +} + +// tx address will map to this and contain all tx hashes +// associated with that address +message OtterscanTraceAddressMapping +{ + message TxHashInfo + { + string hash = 1; + uint64 blocknum = 2; + } + repeated TxHashInfo hashes = 1; +} + +message OtterscanAddressNonceLookup +{ + string hash = 1; +} diff --git a/src/libPersistence/BlockStorage.cpp b/src/libPersistence/BlockStorage.cpp index a3e3f877b6..d71300cfe0 100644 --- a/src/libPersistence/BlockStorage.cpp +++ b/src/libPersistence/BlockStorage.cpp @@ -70,6 +70,9 @@ void BlockStorage::Initialize(const std::string& path, bool diagnostic) { m_txBodyDBs.emplace_back(std::make_shared("txBodies")); m_txEpochDB = std::make_shared("txEpochs"); m_txTraceDB = std::make_shared("txTraces"); + m_otterTraceDB = std::make_shared("otterTraces"); + m_otterTxAddressMappingDB = std::make_shared("otterTxAddressMappings"); + m_otterAddressNonceLookup = std::make_shared("otterAddressNonceLookup"); m_minerInfoDSCommDB = std::make_shared("minerInfoDSComm"); m_minerInfoShardsDB = std::make_shared("minerInfoShards"); m_extSeedPubKeysDB = std::make_shared("extSeedPubKeys"); @@ -2072,3 +2075,268 @@ void BlockStorage::BuildHashToNumberMappingForTxBlocks() { LOG_GENERAL(WARNING, "There was nothing to catchup"); } } + + +///// nathan + +// Tx traces are put in storage, and each time one is inserted, the oldest is +// pruned, so long as it is over TX_TRACES_TO_STORE ago. +// To do this, at the null address is an array/ring buffer of trace hashes +// +bool BlockStorage::PutOtterTrace(const dev::h256& key, const std::string& trace) { + if (!ARCHIVAL_LOOKUP_WITH_TX_TRACES) { + LOG_GENERAL( + WARNING, + "This should only be triggered when archival lookup is enabled!."); + return false; + } + + if (!key) { + LOG_GENERAL(WARNING, "Setting with a zero hash is not allowed"); + return false; + } + + ZilliqaMessage::OtterscanTrace toWrite; + toWrite.set_trace(trace); + + const zbytes& keyBytes = key.asBytes(); + + lock_guard g(m_mutexTxBody); + + if (!m_otterTraceDB) { + LOG_GENERAL( + WARNING, + "Attempt to access non initialized DB! Are you in lookup mode? "); + return false; + } + + // Store txn hash and epoch inside txEpochs DB + if (m_otterTraceDB->Insert(key, toWrite.SerializeAsString()) != 0) { + LOG_GENERAL(WARNING, "Tx trace insertion failed. " + << " key=" << key); + return false; + } + + return true; +} + +bool BlockStorage::GetOtterTrace(const dev::h256& key, std::string& trace) { + const zbytes& keyBytes = key.asBytes(); + + lock_guard g(m_mutexTxBody); + + if (!m_otterTraceDB) { + LOG_GENERAL( + WARNING, + "Attempt to access non initialized DB! Are you in lookup mode? "); + return false; + } + + trace = m_otterTraceDB->Lookup(keyBytes); + + if (trace.empty()) { + return false; + } + + ZilliqaMessage::OtterscanTrace otterTrace; + otterTrace.ParseFromString(trace); + trace = otterTrace.trace(); + + return true; +} + +// Tx txAddressMappings are put in storage, and each time one is inserted, the oldest is +// pruned, so long as it is over TX_TxAddressMappingS_TO_STORE ago. +// To do this, at the null address is an array/ring buffer of txAddressMapping hashes +// +bool BlockStorage::PutOtterTxAddressMapping(const dev::h256& txId, const std::set& addresses, const uint64_t& blocknum) { + if (!ARCHIVAL_LOOKUP_WITH_TX_TRACES) { + LOG_GENERAL( + WARNING, + "This should only be triggered when archival lookup is enabled!."); + return false; + } + + if (!txId) { + LOG_GENERAL(WARNING, "Setting with a zero txid is not allowed"); + return false; + } + + lock_guard g(m_mutexTxBody); + + // for each address, add to the tx hashes and block number that touched them + for (auto address : addresses) { + + // lowercase address + std::transform(address.begin(), address.end(), address.begin(), ::tolower); + + // if address has 0x prefix, remove it + if (address.substr(0,2) == "0x") { + address = address.substr(2); + } + + // if address is all zeroes, do not want it inserted + if (address == "0000000000000000000000000000000000000000") { + continue; + } + + if (address.size() != 40) { + LOG_GENERAL(WARNING, "Address " << address << " is not 40 characters long"); + continue; + } + + ZilliqaMessage::OtterscanTraceAddressMapping ret; + ZilliqaMessage::OtterscanTraceAddressMapping_TxHashInfo internal; + + auto res = m_otterTxAddressMappingDB->Lookup(address); + + if(!res.empty()) { + ret.ParseFromString(res); + } + + // Now add to the internal list + internal.set_hash(txId.hex()); + internal.set_blocknum(blocknum); + ret.mutable_hashes()->Add(std::move(internal)); + + std::cerr << "Adding txid " << txId << " to address " << address << std::endl; + + zbytes ser(ret.ByteSizeLong()); + ret.SerializeToArray(ser.data(), ser.size()); + + m_otterTxAddressMappingDB->Insert(address, ser); + } + + return true; +} + +std::vector BlockStorage::GetOtterTxAddressMapping(std::string address, unsigned long blockNumber, unsigned long pageSize, bool before) { + + std::vector addresses; + lock_guard g(m_mutexTxBody); + + if (!m_otterTxAddressMappingDB) { + LOG_GENERAL( + WARNING, + "Attempt to access non initialized DB! Are you in lookup mode? "); + return {}; + } + + // lowercase the query + std::transform(address.begin(), address.end(), address.begin(), ::tolower); + + // remove 0x prefix from address if exists + if (address.substr(0,2) == "0x") { + address = address.substr(2); + } + + if (address.size() != 40) { + LOG_GENERAL(WARNING, "Address " << address << " is not 40 characters long"); + return {}; + } + + std::string ret = m_otterTxAddressMappingDB->Lookup(address); + + if (ret.empty()) { + std::cerr << "nothing at: " << address << std::endl; + return {}; + } + + ZilliqaMessage::OtterscanTraceAddressMapping otterTxAddressMapping; + otterTxAddressMapping.ParseFromString(ret); + + for(auto item : otterTxAddressMapping.hashes()) { + if(addresses.size() >= pageSize) { + break; + } + + if(before) { + if(item.blocknum() < blockNumber) { + addresses.push_back(item.hash()); + } + } else { + if(item.blocknum() > blockNumber) { + addresses.push_back(item.hash()); + } + } + } + + return addresses; +} + + +// nathan2 +bool BlockStorage::PutOtterAddressNonceLookup(const dev::h256& txId, uint64_t nonce, std::string address) { + if (!ARCHIVAL_LOOKUP_WITH_TX_TRACES) { + LOG_GENERAL( + WARNING, + "This should only be triggered when archival lookup is enabled!."); + return false; + } + + if (!txId) { + LOG_GENERAL(WARNING, "Setting with a zero txid is not allowed"); + return false; + } + + std::transform(address.begin(), address.end(), address.begin(), ::tolower); + + // remove 0x prefix from address if exists + if (address.substr(0,2) == "0x") { + address = address.substr(2); + } + + if (address.size() != 40) { + LOG_GENERAL(WARNING, "Address " << address << " is not 40 characters long"); + return {}; + } + + // Create lookup key as concatenation of address and nonce + std::string key = address + std::to_string(nonce); + cerr << "otter insert key: " << key << " with nonce " << nonce << endl; + + lock_guard g(m_mutexTxBody); + + ZilliqaMessage::OtterscanAddressNonceLookup insert; + insert.set_hash("0x" + txId.hex()); + + zbytes ser(insert.ByteSizeLong()); + insert.SerializeToArray(ser.data(), ser.size()); + + return m_otterAddressNonceLookup->Insert(key, ser) == 0; +} + +std::string BlockStorage::GetOtterAddressNonceLookup(std::string address, uint64_t nonce) { + + lock_guard g(m_mutexTxBody); + + if (!m_otterAddressNonceLookup) { + LOG_GENERAL( + WARNING, + "Attempt to access non initialized DB! Are you in lookup mode? "); + return {}; + } + + // remove 0x prefix from address if exists, make lowercase + std::transform(address.begin(), address.end(), address.begin(), ::tolower); + + if (address.substr(0,2) == "0x") { + address = address.substr(2); + } + + if (address.size() != 40) { + LOG_GENERAL(WARNING, "Address " << address << " is not 40 characters long"); + return {}; + } + + std::string key = address + std::to_string(nonce); + + cerr << "otter lookup key: " << key << endl; + + std::string ret = m_otterAddressNonceLookup->Lookup(key); + + ZilliqaMessage::OtterscanAddressNonceLookup txnId; + txnId.ParseFromString(ret); + + return txnId.hash(); +} diff --git a/src/libPersistence/BlockStorage.h b/src/libPersistence/BlockStorage.h index 2dcec2541f..2ce71254da 100644 --- a/src/libPersistence/BlockStorage.h +++ b/src/libPersistence/BlockStorage.h @@ -87,6 +87,9 @@ class BlockStorage : boost::noncopyable { std::shared_ptr m_txBodyOrigDB; std::shared_ptr m_txEpochDB; std::shared_ptr m_txTraceDB; + std::shared_ptr m_otterTraceDB; + std::shared_ptr m_otterTxAddressMappingDB; + std::shared_ptr m_otterAddressNonceLookup; std::vector> m_microBlockDBs; std::shared_ptr m_microBlockOrigDB; std::shared_ptr m_microBlockKeyDB; @@ -204,6 +207,20 @@ class BlockStorage : boost::noncopyable { bool GetTxTrace(const dev::h256& key, std::string& trace); std::shared_ptr GetTxTraceDb(); + /// Retrieves the requested transaction trace for otterscan. + bool PutOtterTrace(const dev::h256& key, const std::string& trace); + bool GetOtterTrace(const dev::h256& key, std::string& trace); + //std::shared_ptr GetOtterTraceDb(); + + /// Retrieves the mappings of address touched to TX. + bool PutOtterTxAddressMapping(const dev::h256& txId, const std::set& addresses, const uint64_t& blocknum); + std::vector GetOtterTxAddressMapping(std::string address, unsigned long blockNumber, unsigned long pageSize, bool before); + //std::shared_ptr GetOtterTxAddressMappingDb(); + + /// Retrieves the mappings of address touched to TX. + bool PutOtterAddressNonceLookup(const dev::h256& txId, uint64_t nonce, std::string address); + std::string GetOtterAddressNonceLookup(std::string address, uint64_t nonce); + /// Deletes the requested Tx block bool DeleteTxBlock(const uint64_t& blocknum); diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index ba109529cc..44a3a360ce 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -374,6 +374,36 @@ void EthRpcMethods::Init(LookupServer *lookupServer) { "param02", jsonrpc::JSON_OBJECT, NULL), &EthRpcMethods::DebugTraceTransactionI); + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_getInternalOperations", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_STRING, "param01", jsonrpc::JSON_STRING, + NULL), + &EthRpcMethods::OtterscanGetInternalOperationsI); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_traceTransaction", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_STRING, "param01", jsonrpc::JSON_STRING, + NULL), + &EthRpcMethods::OtterscanTraceTransactionI); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_searchTransactionsBefore", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_STRING, "param01", jsonrpc::JSON_STRING, + NULL), + &EthRpcMethods::OtterscanSearchTransactionsBeforeI); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_searchTransactionsBefore", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_STRING, "param01", jsonrpc::JSON_STRING, + NULL), + &EthRpcMethods::OtterscanSearchTransactionsBeforeI); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_getTransactionBySenderAndNonce", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_STRING, "param01", jsonrpc::JSON_STRING, + NULL), + &EthRpcMethods::OtterscanGetTransactionBySenderAndNonceI); + m_lookupServer->bindAndAddExternalMethod( jsonrpc::Procedure("debug_traceBlockByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, @@ -713,10 +743,19 @@ Json::Value extractTracer(const std::string &tracer, const std::string &trace) { } else if (tracer.compare("raw") == 0) { auto const item = trace_json["raw_tracer"]; parsed = item; + } else if (tracer.compare("otter_internal_tracer") == 0) { + auto const item = trace_json["otter_internal_tracer"]; + parsed = item; + } else if (tracer.compare("otter_call_tracer") == 0) { + auto const item = trace_json["otter_call_tracer"]; + parsed = item; + } else if (tracer.compare("otter_transaction_error") == 0) { + auto const item = trace_json["otter_transaction_error"]; + parsed = item; } else { throw JsonRpcException( ServerBase::RPC_MISC_ERROR, - std::string("Only callTracer and raw are supported. Received: ") + + std::string("Only callTracer, internal_tracer, otter_call_tracer, otter_transaction_error, and raw are supported. Received: ") + tracer); } } catch (exception &e) { @@ -2027,6 +2066,119 @@ Json::Value EthRpcMethods::DebugTraceTransaction(const std::string &txHash, } } + +Json::Value EthRpcMethods::OtterscanSearchTransactions(const std::string& address, unsigned long blockNumber, unsigned long pageSize, bool before) { + if (!ARCHIVAL_LOOKUP_WITH_TX_TRACES) { + throw JsonRpcException(ServerBase::RPC_MISC_ERROR, + "The node is not configured to store otter internal operations"); + } + + if (!TX_TRACES) { + throw JsonRpcException(ServerBase::RPC_MISC_ERROR, + "The node is not configured to store otter internal operations"); + } + + // if blocnumber is 0 and it's a before search, then we need to get the latest block number + if (blockNumber == 0 && before) { + blockNumber = m_sharedMediator.m_txBlockChain.GetLastBlock().GetHeader().GetBlockNum(); + } + + try { + //TxnHash tranHash(txHash); + + const auto res = + BlockStorage::GetBlockStorage().GetOtterTxAddressMapping(address, blockNumber, pageSize, before); // nathan + + // Perhaps this should just return empty array + if (res.empty()) { + LOG_GENERAL(INFO, "Otterscan trace request failed! "); + return Json::nullValue; + } + + Json::Value response = Json::objectValue; + Json::Value txs = Json::arrayValue; + Json::Value receipts = Json::arrayValue; + + for(const auto& hash : res) { + // Get Tx result + auto const txByHash = GetEthTransactionByHash(hash); + auto const txReceipt = GetEthTransactionReceipt(hash); + + txs.append(txByHash); + receipts.append(txReceipt); + } + + response["txs"] = txs; + response["receipts"] = receipts; + response["firstPage"] = true; + response["lastPage"] = false; + + return response; + } catch (exception &e) { + LOG_GENERAL(INFO, "[Error]" << e.what() << ". Input: " << address); + throw JsonRpcException(ServerBase::RPC_MISC_ERROR, "Unable to Process"); + } +} + +Json::Value EthRpcMethods::OtterscanGetTransactionBySenderAndNonce(const std::string& address, uint64_t nonce) { + if (!ARCHIVAL_LOOKUP_WITH_TX_TRACES) { + throw JsonRpcException(ServerBase::RPC_MISC_ERROR, + "The node is not configured to store otter internal operations"); + } + + if (!TX_TRACES) { + throw JsonRpcException(ServerBase::RPC_MISC_ERROR, + "The node is not configured to store otter internal operations"); + } + + try { + const auto res = + BlockStorage::GetBlockStorage().GetOtterAddressNonceLookup(address, nonce); + + // Perhaps this should just return empty array + if (res.empty()) { + LOG_GENERAL(INFO, "Otterscan addr nonce request failed! "); + return Json::nullValue; + } + + return res; + } catch (exception &e) { + LOG_GENERAL(INFO, "[Error]" << e.what() << ". Input: " << address); + throw JsonRpcException(ServerBase::RPC_MISC_ERROR, "Unable to Process"); + } +} + +Json::Value EthRpcMethods::OtterscanGetInternalOperations(const std::string &txHash, const std::string &tracer) { + if (!ARCHIVAL_LOOKUP_WITH_TX_TRACES) { + throw JsonRpcException(ServerBase::RPC_MISC_ERROR, + "The node is not configured to store otter internal operations"); + } + + if (!TX_TRACES) { + throw JsonRpcException(ServerBase::RPC_MISC_ERROR, + "The node is not configured to store otter internal operations"); + } + + std::string trace; + + try { + TxnHash tranHash(txHash); + + bool isPresent = + BlockStorage::GetBlockStorage().GetOtterTrace(tranHash, trace); // nathan + + if (!isPresent) { + LOG_GENERAL(INFO, "Otterscan trace request failed! "); + return Json::nullValue; + } + + return extractTracer(tracer, trace); + } catch (exception &e) { + LOG_GENERAL(INFO, "[Error]" << e.what() << ". Input: " << txHash); + throw JsonRpcException(ServerBase::RPC_MISC_ERROR, "Unable to Process"); + } +} + Json::Value EthRpcMethods::GetHeaderByNumber(const uint64_t blockNumber) { // Erigon headers are a subset of a full block - So just return the full block. return EthRpcMethods::GetEthBlockByNumber(std::to_string(blockNumber), false); diff --git a/src/libServer/EthRpcMethods.h b/src/libServer/EthRpcMethods.h index b3df636b4c..62066114b2 100644 --- a/src/libServer/EthRpcMethods.h +++ b/src/libServer/EthRpcMethods.h @@ -154,6 +154,8 @@ class EthRpcMethods { rawTx.erase(0, 2); } + std::cerr << rawTx << std::endl; + auto pubKey = RecoverECDSAPubKey(rawTx, ETH_CHAINID); if (pubKey.empty()) { @@ -584,6 +586,72 @@ class EthRpcMethods { response = this->DebugTraceTransaction(request[0u].asString(), request[1u]); } + /** + * @brief Handles json rpc 2.0 request on method: ots_getInternalOperations + * @param request : transaction hash + * @param response : transaction internal operations + */ + inline virtual void OtterscanGetInternalOperationsI(const Json::Value& request, + Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->OtterscanGetInternalOperations(request[0u].asString(), "otter_internal_tracer"); + } + + /** + * @brief Handles json rpc 2.0 request on method: ots_getInternalOperations + * @param request : transaction hash + * @param response : transaction internal operations + */ + inline virtual void OtterscanGetTransactionErrorI(const Json::Value& request, + Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->OtterscanGetInternalOperations(request[0u].asString(), "otter_transaction_error"); + } + + /** + * @brief Handles json rpc 2.0 request on method: ots_traceTransaction + * @param request : transaction hash + * @param response : transaction trace (abridged) + */ + inline virtual void OtterscanTraceTransactionI(const Json::Value& request, + Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->OtterscanGetInternalOperations(request[0u].asString(), "otter_call_tracer"); + } + + /** + * @brief Handles json rpc 2.0 request on method: ots_traceTransaction + * @param request : transaction hash + * @param response : transaction trace (abridged) + */ + inline virtual void OtterscanSearchTransactionsBeforeI(const Json::Value& request, + Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->OtterscanSearchTransactions(request[0u].asString(), request[1u].asInt64(), request[2u].asInt64(), true); + } + + /** + * @brief Handles json rpc 2.0 request on method: ots_traceTransaction + * @param request : transaction hash + * @param response : transaction trace (abridged) + */ + inline virtual void OtterscanSearchTransactionsAfterI(const Json::Value& request, + Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->OtterscanSearchTransactions(request[0u].asString(), request[1u].asInt64(), request[2u].asInt64(), false); + } + + /** + * @brief Handles json rpc 2.0 request on method: ots_traceTransaction + * @param request : transaction hash + * @param response : transaction trace (abridged) + */ + inline virtual void OtterscanGetTransactionBySenderAndNonceI(const Json::Value& request, + Json::Value& response) { + LOG_MARKER_CONTITIONAL(LOG_SC); + response = this->OtterscanGetTransactionBySenderAndNonce(request[0u].asString(), request[1u].asInt64()); + } + /** * @brief Handles json rpc 2.0 request on method: debug_traceBlockByNumber * @param request : block number, trace type @@ -708,6 +776,9 @@ class EthRpcMethods { Json::Value GetEthBlockReceipts(const std::string& blockId); Json::Value DebugTraceTransaction(const std::string& txHash, const Json::Value& json); + Json::Value OtterscanGetInternalOperations(const std::string& txHash, const std::string &tracer); + Json::Value OtterscanSearchTransactions(const std::string& address, unsigned long blockNumber, unsigned long pageSize, bool before); + Json::Value OtterscanGetTransactionBySenderAndNonce(const std::string& address, uint64_t nonce); Json::Value DebugTraceBlockByNumber(const std::string& blockNum, const Json::Value& json); diff --git a/src/libServer/IsolatedServer.cpp b/src/libServer/IsolatedServer.cpp index 9ea1ca633a..f1af9aedb0 100644 --- a/src/libServer/IsolatedServer.cpp +++ b/src/libServer/IsolatedServer.cpp @@ -459,6 +459,42 @@ void IsolatedServer::BindAllEvmMethods() { jsonrpc::JSON_OBJECT, NULL), &LookupServer::DebugTraceTransactionI); + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_getInternalOperations", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, + "param01", jsonrpc::JSON_STRING, NULL), + &LookupServer::OtterscanGetInternalOperationsI); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_getTransactionBySenderAndNonce", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, + "param01", jsonrpc::JSON_STRING, "param02", jsonrpc::JSON_INTEGER, NULL), + &LookupServer::OtterscanGetTransactionBySenderAndNonceI); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_getTransactionError", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, + "param01", jsonrpc::JSON_STRING, NULL), + &LookupServer::OtterscanGetTransactionErrorI); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_searchTransactionsBefore", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, + "param01", jsonrpc::JSON_STRING, "param02", jsonrpc::JSON_INTEGER, "param03", jsonrpc::JSON_INTEGER, NULL), + &LookupServer::OtterscanSearchTransactionsBeforeI); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_searchTransactionsAfter", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, + "param01", jsonrpc::JSON_STRING, "param02", jsonrpc::JSON_INTEGER, "param03", jsonrpc::JSON_INTEGER, NULL), + &LookupServer::OtterscanSearchTransactionsAfterI); + + AbstractServer::bindAndAddMethod( + jsonrpc::Procedure("ots_traceTransaction", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, + "param01", jsonrpc::JSON_STRING, NULL), + &LookupServer::OtterscanTraceTransactionI); + AbstractServer::bindAndAddMethod( jsonrpc::Procedure("debug_traceBlockByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, diff --git a/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol b/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol deleted file mode 100644 index 1339bbcc9d..0000000000 --- a/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.9; - -contract BatchTransfer { - event DebugMe(string); - - constructor() payable - { - } - - function batchTransfer(address payable[] memory destinations, uint256 amount) public - { - //for (uint256 i=0; i ethers.Wallet.createRandom().connect(ethers.provider) From 68d8f66104a918e9ae777bd058f6818583794ea2 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Tue, 23 May 2023 23:35:18 +0100 Subject: [PATCH 09/34] adhere to otter pagination --- src/libPersistence/BlockStorage.cpp | 31 ++++++++++++++++++++++++++--- src/libPersistence/BlockStorage.h | 2 +- src/libServer/EthRpcMethods.cpp | 11 +++++++--- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/libPersistence/BlockStorage.cpp b/src/libPersistence/BlockStorage.cpp index d71300cfe0..df0148f7ab 100644 --- a/src/libPersistence/BlockStorage.cpp +++ b/src/libPersistence/BlockStorage.cpp @@ -2210,7 +2210,7 @@ bool BlockStorage::PutOtterTxAddressMapping(const dev::h256& txId, const std::se return true; } -std::vector BlockStorage::GetOtterTxAddressMapping(std::string address, unsigned long blockNumber, unsigned long pageSize, bool before) { +std::vector BlockStorage::GetOtterTxAddressMapping(std::string address, unsigned long blockNumber, unsigned long pageSize, bool before, bool &wasMore) { std::vector addresses; lock_guard g(m_mutexTxBody); @@ -2245,11 +2245,30 @@ std::vector BlockStorage::GetOtterTxAddressMapping(std::string addr ZilliqaMessage::OtterscanTraceAddressMapping otterTxAddressMapping; otterTxAddressMapping.ParseFromString(ret); - for(auto item : otterTxAddressMapping.hashes()) { - if(addresses.size() >= pageSize) { + auto hashes = otterTxAddressMapping.hashes(); + + // If we are searching before the block number, + // we need to reverse the order of the hashes so we are searching downward + if(before) { + std::reverse(hashes.begin(), hashes.end()); + } + + uint64_t stopOnBlock = -1; + + for(int i = 0; i < hashes.size();i++) { + auto item = hashes.Get(i); + + if (item.blocknum() == stopOnBlock) { + wasMore = true; break; } + // The otter docs indicate + if(addresses.size() >= pageSize) { + stopOnBlock = item.blocknum(); + stopOnBlock = before ? stopOnBlock - 1 : stopOnBlock + 1; + } + if(before) { if(item.blocknum() < blockNumber) { addresses.push_back(item.hash()); @@ -2261,6 +2280,12 @@ std::vector BlockStorage::GetOtterTxAddressMapping(std::string addr } } + // Results should always be descending, so they need to be reversed + // if the search was 'after' + if(!before) { + std::reverse(addresses.begin(), addresses.end()); + } + return addresses; } diff --git a/src/libPersistence/BlockStorage.h b/src/libPersistence/BlockStorage.h index 2ce71254da..f3060a6ebf 100644 --- a/src/libPersistence/BlockStorage.h +++ b/src/libPersistence/BlockStorage.h @@ -214,7 +214,7 @@ class BlockStorage : boost::noncopyable { /// Retrieves the mappings of address touched to TX. bool PutOtterTxAddressMapping(const dev::h256& txId, const std::set& addresses, const uint64_t& blocknum); - std::vector GetOtterTxAddressMapping(std::string address, unsigned long blockNumber, unsigned long pageSize, bool before); + std::vector GetOtterTxAddressMapping(std::string address, unsigned long blockNumber, unsigned long pageSize, bool before, bool &wasMore); //std::shared_ptr GetOtterTxAddressMappingDb(); /// Retrieves the mappings of address touched to TX. diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index 44a3a360ce..f4b2581d49 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -2086,8 +2086,9 @@ Json::Value EthRpcMethods::OtterscanSearchTransactions(const std::string& addres try { //TxnHash tranHash(txHash); + bool wasMore = false; const auto res = - BlockStorage::GetBlockStorage().GetOtterTxAddressMapping(address, blockNumber, pageSize, before); // nathan + BlockStorage::GetBlockStorage().GetOtterTxAddressMapping(address, blockNumber, pageSize, before, wasMore); // nathan // Perhaps this should just return empty array if (res.empty()) { @@ -2110,8 +2111,12 @@ Json::Value EthRpcMethods::OtterscanSearchTransactions(const std::string& addres response["txs"] = txs; response["receipts"] = receipts; - response["firstPage"] = true; - response["lastPage"] = false; + + // Otterscan docs. If results are less than pagesize, results returned as-is. + if (!(res.size() < pageSize)) { + response["firstPage"] = before || !wasMore; + response["lastPage"] = !before || !wasMore; + } return response; } catch (exception &e) { From 65e6ed053b23f26f54cff014f32374846c06ce17 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Tue, 23 May 2023 23:49:27 +0100 Subject: [PATCH 10/34] more cleanup --- constants.xml | 4 +- evm-ds/Cargo.toml | 3 +- evm-ds/src/evm_server_run.rs | 19 +- evm-ds/src/main.rs | 47 +--- scripts/license_checker.sh | 202 +++++++++--------- .../AccountStore/AccountStoreSCEvm.cpp | 16 +- src/libPersistence/BlockStorage.cpp | 10 - src/libPersistence/BlockStorage.h | 2 - src/libServer/EthRpcMethods.cpp | 6 +- src/libServer/EthRpcMethods.h | 2 - tests/EvmAcceptanceTests/hardhat.config.ts | 6 +- tests/EvmAcceptanceTests/test/ChainedCalls.ts | 2 - tests/EvmAcceptanceTests/test/Transfer.ts | 4 +- 13 files changed, 114 insertions(+), 209 deletions(-) diff --git a/constants.xml b/constants.xml index e009f6d02a..5568936e12 100644 --- a/constants.xml +++ b/constants.xml @@ -202,7 +202,7 @@ 59 - false + true true @@ -309,7 +309,7 @@ .scillib scilla_libs true - true + false false 1500 10 diff --git a/evm-ds/Cargo.toml b/evm-ds/Cargo.toml index f219d5824a..0334c93528 100644 --- a/evm-ds/Cargo.toml +++ b/evm-ds/Cargo.toml @@ -13,8 +13,7 @@ bytes = "1.1.0" clap = { version = "3.1.6", features = ["derive"] } log4rs = { version = "1.1.1", features = ["all_components", "gzip"] } ethereum = "0.12.0" -#evm = { git = "https://github.com/Zilliqa/evm", branch = "precompile-access-backend", features = ["tracing"] } -evm = { path = "./evm", features = ["tracing"]} +evm = { git = "https://github.com/Zilliqa/evm", branch = "precompile-backend-plus-otter", features = ["tracing"] } ethabi = "18.0.0" serde = "1.0.152" serde_yaml = "0.8.25" diff --git a/evm-ds/src/evm_server_run.rs b/evm-ds/src/evm_server_run.rs index 78c70c35b2..f02b524460 100644 --- a/evm-ds/src/evm_server_run.rs +++ b/evm-ds/src/evm_server_run.rs @@ -46,7 +46,7 @@ pub async fn run_evm_impl( // cannot be done. And we'll need a new runtime that we can safely drop on a handled // panic. (Using the parent runtime and dropping on stack unwind will mess up the parent runtime). tokio::task::spawn_blocking(move || { - info!( + debug!( "Running EVM: origin: {:?} address: {:?} gas: {:?} value: {:?} extras: {:?}, estimate: {:?} is_continuation: {:?}, cps: {:?}, \ntx_trace: {:?}, \ndata: {:02X?}, \ncode: {:02X?}", backend.origin, address, gas_limit, apparent_value, backend.extras, estimate, node_continuation.is_none(), enable_cps, tx_trace, data, code); @@ -154,12 +154,6 @@ pub async fn run_evm_impl( listener.finished_call(); match exit_reason { - evm::ExitReason::Succeed(exit_succeeded) => { - if exit_succeeded == ExitSucceed::Suicided { - eprintln!("huehue"); - //eprintln!("apparent value: {:?}", &context.apparent_value) - } - } evm::ExitReason::Revert(exit_revert) => { listener.otter_transaction_error = u8_vec_to_hex(&runtime.machine().return_value(), true); } @@ -171,27 +165,20 @@ pub async fn run_evm_impl( } } - eprintln!("Normal exit: {:?}", exit_reason); - build_exit_result(executor, &runtime, &backend, &listener, &exit_reason, remaining_gas, is_static, continuations) }, CpsReason::CallInterrupt(i) => { let cont_id = continuations.lock().unwrap().create_continuation(runtime.machine_mut(), executor.state().substate()); - eprintln!("call interrupt exit: "); build_call_result(executor, &runtime, &backend, i, &listener, remaining_gas, is_static, cont_id) }, CpsReason::CreateInterrupt(i) => { let cont_id = continuations.lock().unwrap().create_continuation(runtime.machine_mut(), executor.into_state().substate()); - eprintln!("create interrupt exit: "); build_create_result(&runtime, i, &listener, remaining_gas, cont_id) } }; - // Log the result if it is a suicide - //if result.get_exit_reason() - info!( "EVM execution summary: context: {:?}, origin: {:?} address: {:?} gas: {:?} value: {:?}, data: {:?}, extras: {:?}, estimate: {:?}, cps: {:?}, result: {}, returnVal: {}", evm_context, backend.origin, address, gas_limit, apparent_value, @@ -339,10 +326,6 @@ fn build_call_result( context.set_caller(interrupt.context.caller.into()); context.set_destination(interrupt.context.address.into()); - eprintln!("apparent value: {:?}", interrupt.context.apparent_value); - eprintln!("caller: {:?}", interrupt.context.caller); - eprintln!("destination: {:?}", interrupt.context.address); - trap_data_call.set_context(context); if let Some(tran) = interrupt.transfer { diff --git a/evm-ds/src/main.rs b/evm-ds/src/main.rs index 35be24c884..cb4d57c894 100644 --- a/evm-ds/src/main.rs +++ b/evm-ds/src/main.rs @@ -151,12 +151,6 @@ struct InternalOperationOtter { pub value: String, } - -//type - transfer (0), self-destruct (1), create (2) or create2 (3). -//from - the ETH sender, contract creator or contract address being self-destructed. -//to - the ETH receiver, newly created contract address or the target ETH receiver resulting of the self-destruction. -//value - the amount of ETH transferred. - impl LoggingEventListener { fn new(enabled: bool) -> Self { LoggingEventListener { @@ -171,18 +165,6 @@ impl LoggingEventListener { } } -//impl evm::tracing::EventListener for LoggingEventListener { -// fn event(&mut self, event: evm::tracing::Event) { -// if !self.enabled { -// return; -// } -// -// // print the event -// eprintln!(" other event!{:?}", event); -// eprintln!(" other event!{:?}", event); -// } -//} - impl evm::runtime::tracing::EventListener for LoggingEventListener { fn event(&mut self, event: evm::runtime::tracing::Event) { if !self.enabled { @@ -212,24 +194,6 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { for sta in stack.data() { struct_log.stack.push(format!("{sta:?}")); } - - //eprintln!("opcode is: {:?}", opcode.to_string()); - - match opcode { - Opcode::SUICIDE => { - eprintln!("suicide occuring..."); - // print the amount returned via suicide - // print the apparent value of suicide: - eprintln!("Apparent value: {:?}", context.apparent_value); - eprintln!("Apparent value X: {:0X?}", context.apparent_value); - eprintln!("target X: {:0X?}", context.apparent_value); - - //eprintln!("target: {:0X?}", stack.tar); - //eprintln!("addr: {:0X?}", context.apparent_value); - //eprintln!("balance: {:0X?}", context.apparent_value); - }, - _ => {} - } } evm::runtime::tracing::Event::StepResult { result, @@ -259,8 +223,6 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { balance: balance, input: input, } => { - eprintln!("**** it happened transfer! {:?} {:?} {:?}", address, target, balance); - intern_trace = Some(InternalOperationOtter { call_type: call_depth, from: format!("{:?}", address), @@ -288,8 +250,6 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { target: target, balance: balance, } => { - eprintln!("**** it happened! {:?} {:?} {:?}", address, target, balance); - intern_trace = Some(InternalOperationOtter { call_type: 1, from: format!("{:?}", address), @@ -313,8 +273,6 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { is_create2: is_create2, input: input, } => { - eprintln!("**** it happened Create! {:?} {:?} {:?} {:?}", address, target, balance, is_create2); - intern_trace = Some(InternalOperationOtter { call_type: if is_create2 { 3 } else { 2 }, from: format!("{:?}", address), @@ -336,11 +294,10 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { if !self.otter_addresses_called.contains(&to_add) { self.otter_addresses_called.push(to_add); } - //self.otter_addresses_called.push(format!("{:?}", target)); } } - //self.raw_tracer.struct_logs.push(struct_log); // todo: undelete this + self.raw_tracer.struct_logs.push(struct_log); if let Some(intern_trace) = intern_trace { self.otter_internal_tracer.push(intern_trace); @@ -372,7 +329,7 @@ impl LoggingEventListener { // Now we have constructed our new call context, it gets added to the end of // the stack (if we want to do tracing) if self.enabled { - self.call_tracer.push(context); // todo: undelete + self.call_tracer.push(context); } } } diff --git a/scripts/license_checker.sh b/scripts/license_checker.sh index d8f40ac1d3..612f525ab4 100755 --- a/scripts/license_checker.sh +++ b/scripts/license_checker.sh @@ -1,104 +1,104 @@ -##!/bin/bash -## Copyright (C) 2019 Zilliqa -## -## This program is free software: you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation, either version 3 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program. If not, see . +#!/bin/bash +# Copyright (C) 2019 Zilliqa # -## Usage: ./scripts/license_checker.sh +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -#banner_file=$(mktemp) +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. # -#cat < $banner_file -# -#This program is free software: you can redistribute it and/or modify -#it under the terms of the GNU General Public License as published by -#the Free Software Foundation, either version 3 of the License, or -#(at your option) any later version. -# -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. -# -#You should have received a copy of the GNU General Public License -#along with this program. If not, see . -#EOF -#set -e -# -#scope=$(find . -type f \( \ -# -name "*.cpp" \ -# -o -name "*.hpp" \ -# -o -name "*.tpp" \ -# -o -name "*.c" \ -# -o -name "*.h" \ -# -o -name "*.py" \ -# -o -name "*.sh" \) \ -# ! -name "run-clang-*.py" \ -# ! -path "./build/*" \ -# ! -path "./scilla/*" \ -# ! -path "./cmake-build-debug/*" \ -# ! -path "./evm-ds/*" \ -# ! -path "./evm-ds/*" \ -# ! -path "./tests/EvmAcceptanceTests/node_modules/*" \ -# ! -path "./tests/observability/*" \ -# ! -path "./vcpkg_installed/*" \ -# ! -path "./infra/*" \ -# ! -path "./infra-devops/*" \ -# ! -path "./src/depends/*" \ -# ! -path "./scilla/deps/*" \ -# ! -path "./scilla/_build/*" \ -# ! -path "./.local/*" \ -# ! -path "./.husky/*" \ -# ! -path "./_localdev/*" \ -# ! -path "./vcpkg/*" \ -# ! -path "./scripts/depends/*") -# -#lc_license=$(wc -l $banner_file | egrep "[0-9]+" -o | head -n1) -# -#error_count=0 -# -#function check_license() { -# source=$1 -# n_row_ignore=$2 -# n_col_ignore=$3 -# -# has_error=0 -# cat $source | tail -n +$(($n_row_ignore + 1)) | head -n$lc_license | \ -# cut -b $(($n_col_ignore+1))- | \ -# diff -u $banner_file - 2>&1 >/dev/null || \ -# has_error=1 -# -# if [ $has_error -ne 0 ] -# then -# echo $source -# error_count=$(($error_count+1)) -# fi -#} -# -#for file in $scope -#do -# filename=$(basename $file) -# ext="${filename##*.}" -# case "$ext" in -# cpp|hpp|tpp|h|c) check_license $file 2 3 ;; -# py|sh) check_license $file 2 2 ;; -# *) echo unsupported format;; -# esac -#done -# -#if [ $error_count -gt 0 ] -#then -# echo -# echo "$error_count file(s) has incorrect LICENSE banner" -# exit 1 -#fi +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Usage: ./scripts/license_checker.sh + +banner_file=$(mktemp) + +cat < $banner_file + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +EOF +set -e + +scope=$(find . -type f \( \ + -name "*.cpp" \ + -o -name "*.hpp" \ + -o -name "*.tpp" \ + -o -name "*.c" \ + -o -name "*.h" \ + -o -name "*.py" \ + -o -name "*.sh" \) \ + ! -name "run-clang-*.py" \ + ! -path "./build/*" \ + ! -path "./scilla/*" \ + ! -path "./cmake-build-debug/*" \ + ! -path "./evm-ds/*" \ + ! -path "./evm-ds/*" \ + ! -path "./tests/EvmAcceptanceTests/node_modules/*" \ + ! -path "./tests/observability/*" \ + ! -path "./vcpkg_installed/*" \ + ! -path "./infra/*" \ + ! -path "./infra-devops/*" \ + ! -path "./src/depends/*" \ + ! -path "./scilla/deps/*" \ + ! -path "./scilla/_build/*" \ + ! -path "./.local/*" \ + ! -path "./.husky/*" \ + ! -path "./_localdev/*" \ + ! -path "./vcpkg/*" \ + ! -path "./scripts/depends/*") + +lc_license=$(wc -l $banner_file | egrep "[0-9]+" -o | head -n1) + +error_count=0 + +function check_license() { + source=$1 + n_row_ignore=$2 + n_col_ignore=$3 + + has_error=0 + cat $source | tail -n +$(($n_row_ignore + 1)) | head -n$lc_license | \ + cut -b $(($n_col_ignore+1))- | \ + diff -u $banner_file - 2>&1 >/dev/null || \ + has_error=1 + + if [ $has_error -ne 0 ] + then + echo $source + error_count=$(($error_count+1)) + fi +} + +for file in $scope +do + filename=$(basename $file) + ext="${filename##*.}" + case "$ext" in + cpp|hpp|tpp|h|c) check_license $file 2 3 ;; + py|sh) check_license $file 2 2 ;; + *) echo unsupported format;; + esac +done + +if [ $error_count -gt 0 ] +then + echo + echo "$error_count file(s) has incorrect LICENSE banner" + exit 1 +fi diff --git a/src/libData/AccountStore/AccountStoreSCEvm.cpp b/src/libData/AccountStore/AccountStoreSCEvm.cpp index 7bae3a0ebe..c05b9d53d0 100644 --- a/src/libData/AccountStore/AccountStoreSCEvm.cpp +++ b/src/libData/AccountStore/AccountStoreSCEvm.cpp @@ -285,7 +285,6 @@ bool AccountStoreSC::EvmProcessMessage(EvmProcessContext ¶ms, } std::string stripTxTraceOut(const std::string &trace) { - //std::string stripped; Json::Value trace_json; JSONUtils::GetInstance().convertStrtoJson(trace, trace_json); @@ -295,9 +294,6 @@ std::string stripTxTraceOut(const std::string &trace) { trace_json.removeMember("raw_tracer"); return trace_json.toStyledString(); - - //auto const item = trace_json["otter_addresses_called"]; - //parsed = item; } void getAddressesFromTrace(const std::string &trace, std::set &addresses) { @@ -377,9 +373,7 @@ bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, std::set addresses_touched; addresses_touched.insert(m_originAddr.hex()); - std::cerr << "og addr: " << m_originAddr.hex() << std::endl; addresses_touched.insert(m_curContractAddr.hex()); - std::cerr << "contract addr: " << m_curContractAddr.hex() << std::endl; if (std::holds_alternative(cpsRunResult.result) && ARCHIVAL_LOOKUP_WITH_TX_TRACES) { @@ -388,9 +382,7 @@ bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, if (!traces.empty() && evmContext.GetTranID()) { LOG_GENERAL(INFO, - "***** Putting in TX trace for: " << evmContext.GetTranID()); - - std::cout << traces << std::endl; + "Putting in TX trace for: " << evmContext.GetTranID()); if (!BlockStorage::GetBlockStorage().PutTxTrace(evmContext.GetTranID(), traces)) { @@ -407,20 +399,14 @@ bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, // permanently and the rest is huge auto const trace_stripped = stripTxTraceOut(traces); - std::cerr << trace_stripped << std::endl; - if (!BlockStorage::GetBlockStorage().PutOtterTrace(evmContext.GetTranID(), traces)) { LOG_GENERAL(INFO, "FAIL: Put otter trace failed " << evmContext.GetTranID()); } - } else { - LOG_GENERAL(INFO, "No tx trace to put in..." << evmContext.GetTranID()); } } - std::cerr << "we are here..." << std::endl; - // This needs to be outside the above as needs to include possibility of non evm tx if(ARCHIVAL_LOOKUP_WITH_TX_TRACES) { if (!BlockStorage::GetBlockStorage().PutOtterTxAddressMapping(evmContext.GetTranID(), diff --git a/src/libPersistence/BlockStorage.cpp b/src/libPersistence/BlockStorage.cpp index df0148f7ab..fdbfe4f51e 100644 --- a/src/libPersistence/BlockStorage.cpp +++ b/src/libPersistence/BlockStorage.cpp @@ -2076,9 +2076,6 @@ void BlockStorage::BuildHashToNumberMappingForTxBlocks() { } } - -///// nathan - // Tx traces are put in storage, and each time one is inserted, the oldest is // pruned, so long as it is over TX_TRACES_TO_STORE ago. // To do this, at the null address is an array/ring buffer of trace hashes @@ -2199,8 +2196,6 @@ bool BlockStorage::PutOtterTxAddressMapping(const dev::h256& txId, const std::se internal.set_blocknum(blocknum); ret.mutable_hashes()->Add(std::move(internal)); - std::cerr << "Adding txid " << txId << " to address " << address << std::endl; - zbytes ser(ret.ByteSizeLong()); ret.SerializeToArray(ser.data(), ser.size()); @@ -2238,7 +2233,6 @@ std::vector BlockStorage::GetOtterTxAddressMapping(std::string addr std::string ret = m_otterTxAddressMappingDB->Lookup(address); if (ret.empty()) { - std::cerr << "nothing at: " << address << std::endl; return {}; } @@ -2318,7 +2312,6 @@ bool BlockStorage::PutOtterAddressNonceLookup(const dev::h256& txId, uint64_t no // Create lookup key as concatenation of address and nonce std::string key = address + std::to_string(nonce); - cerr << "otter insert key: " << key << " with nonce " << nonce << endl; lock_guard g(m_mutexTxBody); @@ -2355,9 +2348,6 @@ std::string BlockStorage::GetOtterAddressNonceLookup(std::string address, uint64 } std::string key = address + std::to_string(nonce); - - cerr << "otter lookup key: " << key << endl; - std::string ret = m_otterAddressNonceLookup->Lookup(key); ZilliqaMessage::OtterscanAddressNonceLookup txnId; diff --git a/src/libPersistence/BlockStorage.h b/src/libPersistence/BlockStorage.h index f3060a6ebf..11eac08e1d 100644 --- a/src/libPersistence/BlockStorage.h +++ b/src/libPersistence/BlockStorage.h @@ -210,12 +210,10 @@ class BlockStorage : boost::noncopyable { /// Retrieves the requested transaction trace for otterscan. bool PutOtterTrace(const dev::h256& key, const std::string& trace); bool GetOtterTrace(const dev::h256& key, std::string& trace); - //std::shared_ptr GetOtterTraceDb(); /// Retrieves the mappings of address touched to TX. bool PutOtterTxAddressMapping(const dev::h256& txId, const std::set& addresses, const uint64_t& blocknum); std::vector GetOtterTxAddressMapping(std::string address, unsigned long blockNumber, unsigned long pageSize, bool before, bool &wasMore); - //std::shared_ptr GetOtterTxAddressMappingDb(); /// Retrieves the mappings of address touched to TX. bool PutOtterAddressNonceLookup(const dev::h256& txId, uint64_t nonce, std::string address); diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index f4b2581d49..43dfe89318 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -2084,11 +2084,9 @@ Json::Value EthRpcMethods::OtterscanSearchTransactions(const std::string& addres } try { - //TxnHash tranHash(txHash); - bool wasMore = false; const auto res = - BlockStorage::GetBlockStorage().GetOtterTxAddressMapping(address, blockNumber, pageSize, before, wasMore); // nathan + BlockStorage::GetBlockStorage().GetOtterTxAddressMapping(address, blockNumber, pageSize, before, wasMore); // Perhaps this should just return empty array if (res.empty()) { @@ -2216,8 +2214,6 @@ Json::Value EthRpcMethods::GetBlockDetails(const uint64_t blockNumber) { uint128_t fees = (isVacuous ? 0 : txBlock.GetHeader().GetRewards() * EVM_ZIL_SCALING_FACTOR); auto jsonBlock = GetEthBlockCommon(txBlock, false); - std::cerr << "gas lim: " << jsonBlock["gasLimit"] << std::endl; - jsonBlock["gasLimit"] = "0x1"; jsonBlock.removeMember("transactions"); diff --git a/src/libServer/EthRpcMethods.h b/src/libServer/EthRpcMethods.h index 62066114b2..38e5f386e6 100644 --- a/src/libServer/EthRpcMethods.h +++ b/src/libServer/EthRpcMethods.h @@ -154,8 +154,6 @@ class EthRpcMethods { rawTx.erase(0, 2); } - std::cerr << rawTx << std::endl; - auto pubKey = RecoverECDSAPubKey(rawTx, ETH_CHAINID); if (pubKey.empty()) { diff --git a/tests/EvmAcceptanceTests/hardhat.config.ts b/tests/EvmAcceptanceTests/hardhat.config.ts index a8953384e2..0b2d8de583 100644 --- a/tests/EvmAcceptanceTests/hardhat.config.ts +++ b/tests/EvmAcceptanceTests/hardhat.config.ts @@ -67,15 +67,15 @@ const config: HardhatUserConfig = { miningState: true }, devnet: { - url: "https://testnet-uups-l2api.dev.z7a.xyz", - websocketUrl: "wss://testnet-uups-api.dev.z7a.xyz", + url: "https://evmdev-l2api.dev.z7a.xyz", + websocketUrl: "wss://evmdev-l2api.dev.z7a.xyz", accounts: [ "d96e9eb5b782a80ea153c937fa83e5948485fbfc8b7e7c069d7b914dbc350aba", "db11cfa086b92497c8ed5a4cc6edb3a5bfe3a640c43ffb9fc6aa0873c56f2ee3", "410b0e0a86625a10c554f8248a77c7198917bd9135c15bb28922684826bb9f14", "589417286a3213dceb37f8f89bd164c3505a4cec9200c61f7c6db13a30a71b45" ], - chainId: 32769, + chainId: 33101, zilliqaNetwork: true, web3ClientVersion: "Zilliqa/v8.2", protocolVersion: 0x41, diff --git a/tests/EvmAcceptanceTests/test/ChainedCalls.ts b/tests/EvmAcceptanceTests/test/ChainedCalls.ts index c788f6b214..038874c629 100644 --- a/tests/EvmAcceptanceTests/test/ChainedCalls.ts +++ b/tests/EvmAcceptanceTests/test/ChainedCalls.ts @@ -25,8 +25,6 @@ describe("Chained Contract Calls Functionality", function () { let res = await contractOne.chainedCall([addrTwo, addrThree, addrOne], 0); - console.log("did the thing..."); - // Now call contract one, passing in the addresses of contracts two and three let tracer = {tracer: "callTracer"}; diff --git a/tests/EvmAcceptanceTests/test/Transfer.ts b/tests/EvmAcceptanceTests/test/Transfer.ts index 2fe4c72452..d1cc9f88fb 100644 --- a/tests/EvmAcceptanceTests/test/Transfer.ts +++ b/tests/EvmAcceptanceTests/test/Transfer.ts @@ -63,7 +63,7 @@ describe("Transfer ethers", function () { it("should be possible to batch transfer using a smart contract", async function () { const ACCOUNTS_COUNT = 3; - const ACCOUNT_VALUE = 123_234_567; + const ACCOUNT_VALUE = 1_000_000; const accounts = Array.from({length: ACCOUNTS_COUNT}, (v, k) => ethers.Wallet.createRandom().connect(ethers.provider) @@ -79,7 +79,7 @@ describe("Transfer ethers", function () { balances.forEach((el) => expect(el).to.be.eq(ACCOUNT_VALUE)); }); - xit("should be possible to batch transfer using a smart contract and get funds back on self destruct", async function () { + it("should be possible to batch transfer using a smart contract and get funds back on self destruct", async function () { const ACCOUNTS_COUNT = 3; const ACCOUNT_VALUE = 1_000_000_000; From 60d21dfda7b9bd6cfd1a4ff76a2676bd2a4bd682 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Tue, 23 May 2023 23:56:39 +0100 Subject: [PATCH 11/34] add the otter tests too --- tests/EvmAcceptanceTests/test/OtterTests.ts | 215 ++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 tests/EvmAcceptanceTests/test/OtterTests.ts diff --git a/tests/EvmAcceptanceTests/test/OtterTests.ts b/tests/EvmAcceptanceTests/test/OtterTests.ts new file mode 100644 index 0000000000..177b83ea94 --- /dev/null +++ b/tests/EvmAcceptanceTests/test/OtterTests.ts @@ -0,0 +1,215 @@ +import {assert, expect} from "chai"; +import {ethers} from "hardhat"; +import {expectRevert} from "@openzeppelin/test-helpers"; +import sendJsonRpcRequest from "../helpers/JsonRpcHelper"; +import {parallelizer} from "../helpers"; + +describe("Otterscan api tests", function () { + + let contractOne: Contract; + let contractTwo: Contract; + let contractThree: Contract; + + before(async function () { + + contractOne = await parallelizer.deployContract("ContractOne"); + contractTwo = await parallelizer.deployContract("ContractTwo"); + contractThree = await parallelizer.deployContract("ContractThree"); + + const Contract = await ethers.getContractFactory("Revert"); + this.contract = await Contract.deploy(); + }); + + it("When we revert the TX, we can get the tx error ", async function () { + const METHOD = "ots_getTransactionError"; + const REVERT_MESSAGE = "Transaction too old"; + + const abi = ethers.utils.defaultAbiCoder; + const MESSAGE_ENCODED = "0x08c379a0" + abi.encode(["string"], [REVERT_MESSAGE]).split('x')[1]; + + // In order to make a tx that fails at runtime and not estimate gas time, we estimate the gas of + // a similar passing call and use this (+30% leeway) to override the gas field + const estimatedGas = await this.contract.estimateGas.requireCustom(true, REVERT_MESSAGE); + + const tx = await this.contract.requireCustom(false, REVERT_MESSAGE, { gasLimit: estimatedGas.mul(130).div(100) }) + + await sendJsonRpcRequest(METHOD, 1, [tx.hash], (result, status) => { + assert.equal(status, 200, "has status code"); + + let jsonObject = result.result; + + assert.equal(jsonObject, MESSAGE_ENCODED); + }); + }); + + it("We can get the otter internal operations", async function () { + const METHOD = "ots_getInternalOperations"; + + // Check we can for example detect a suicide with correct value. + // Below is taken from transfer.ts test + const ACCOUNTS_COUNT = 3; + const ACCOUNT_VALUE = 123_000_000; + + const accounts = Array.from({length: ACCOUNTS_COUNT}, (v, k) => + ethers.Wallet.createRandom().connect(ethers.provider) + ); + + const addresses = accounts.map((signer) => signer.address); + + const tx = await parallelizer.deployContract("BatchTransferCtor", addresses, ACCOUNT_VALUE, { + value: ACCOUNTS_COUNT * ACCOUNT_VALUE + }); + + + const balances = await Promise.all(accounts.map((account) => account.getBalance())); + balances.forEach((el) => expect(el).to.be.eq(ACCOUNT_VALUE)); + + await sendJsonRpcRequest(METHOD, 1, [tx.deployTransaction.hash], (result, status) => { + assert.equal(status, 200, "has status code"); + + console.log(result); + + let jsonObject = result.result; + + assert.equal(jsonObject[0]["type"], 0, "has correct type for transfer"); + assert.equal(jsonObject[3]["type"], 1, "has correct type for self destruct"); + }); + + }); + + it("We can get the otter trace transaction", async function () { + const METHOD = "ots_traceTransaction"; + + let addrOne = contractOne.address.toLowerCase(); + let addrTwo = contractTwo.address.toLowerCase(); + let addrThree = contractThree.address.toLowerCase(); + + let res = await contractOne.chainedCall([addrTwo, addrThree, addrOne], 0); + + await sendJsonRpcRequest(METHOD, 1, [res.hash], (result, status) => { + assert.equal(status, 200, "has status code"); + + let jsonObject = result.result; + + assert.equal(jsonObject[0]["depth"], 0, "has correct depth initially"); + assert.equal(jsonObject[1]["depth"], 1, "has correct depth one call down"); + assert.equal(jsonObject[1]["type"], "CALL", "has correct depth one call down"); + }); + + }); + + it("We can get the otter search for sender by nonce", async function () { + const METHOD = "ots_getTransactionBySenderAndNonce"; + + // To test this, send money to an account then have it send it back. + // The nonces should be able to lookup via 0, 1, 2 + // re-use the batch transfer code for this + const ACCOUNTS_COUNT = 1; + const ACCOUNT_VALUE = 100_000_000; + + const accounts = Array.from({length: ACCOUNTS_COUNT}, (v, k) => + ethers.Wallet.createRandom().connect(ethers.provider) + ); + + //const addresses = accounts.map((signer) => signer.address); + + //const tx = await parallelizer.deployContract("BatchTransferCtor", addresses, ACCOUNT_VALUE, { + // value: ACCOUNTS_COUNT * ACCOUNT_VALUE + //}); + + //const balances = await Promise.all(accounts.map((account) => account.getBalance())); + //balances.forEach((el) => expect(el).to.be.eq(ACCOUNT_VALUE)); + const acctAddr = accounts[0].address; + + console.log("TX count: "); + console.log(await accounts[0].getTransactionCount()); + + const [owner] = await ethers.getSigners(); + let txRawFromOwner = { + to: acctAddr, + value: ethers.utils.parseEther("1") + } + console.log("here0"); + await owner.sendTransaction(txRawFromOwner); + console.log("here0.5"); + + console.log("TX count: "); + console.log(await accounts[0].getTransactionCount()); + + // Create a transaction object + let txRaw = { + to: owner.address, + value: ethers.utils.parseEther("0.45") + } + console.log("here1"); + const txid0 = await accounts[0].sendTransaction(txRaw); + const txid1 = await accounts[0].sendTransaction(txRaw); + + console.log(txid0.hash); + console.log(txid1.hash); + + await sendJsonRpcRequest(METHOD, 1, [acctAddr, 0], (result, status) => { + assert.equal(status, 200, "has status code"); + + console.log(result); + let jsonObject = result.result; + + assert.equal(jsonObject, txid0.hash, "has correct hash"); + }); + + await sendJsonRpcRequest(METHOD, 1, [acctAddr, 1], (result, status) => { + assert.equal(status, 200, "has status code"); + + console.log(result); + let jsonObject = result.result; + + assert.equal(jsonObject, txid1.hash, "has correct hash"); + }); + + }); + + it("We can get the otter search TX before and after", async function () { + const METHOD_BEFORE = "ots_searchTransactionsBefore"; + const METHOD_AFTER = "ots_searchTransactionsAfter"; + + // run the contract that batch sends funds to other addresses + // then we can check that this txid comes up when asking about + // these contract addresses. + const ACCOUNTS_COUNT = 3; + const ACCOUNT_VALUE = 123_000_000; + + // Get the block height so we can check before/after + const height = await ethers.provider.getBlockNumber(); + + const accounts = Array.from({length: ACCOUNTS_COUNT}, (v, k) => + ethers.Wallet.createRandom().connect(ethers.provider) + ); + + const addresses = accounts.map((signer) => signer.address); + + const tx = await parallelizer.deployContract("BatchTransferCtor", addresses, ACCOUNT_VALUE, { + value: ACCOUNTS_COUNT * ACCOUNT_VALUE + }); + + const balances = await Promise.all(accounts.map((account) => account.getBalance())); + balances.forEach((el) => expect(el).to.be.eq(ACCOUNT_VALUE)); + + await sendJsonRpcRequest(METHOD_AFTER, 1, [addresses[0], height, 100], (result, status) => { + assert.equal(status, 200, "has status code"); + + let jsonObject = result.result; + assert.equal(jsonObject.txs[0].hash, tx.deployTransaction.hash, "Can find the TX which send funds to this addr"); + }); + + // There should be nothing before this point + await sendJsonRpcRequest(METHOD_BEFORE, 1, [addresses[0], height, 100], (result, status) => { + assert.equal(status, 200, "has status code"); + + let jsonObject = result.result; + assert.equal(jsonObject, null, "Can find the TX which send funds to this addr"); + }); + + }); + +}); + From 0f510262dc50203c346437d34aeea40c3107e26a Mon Sep 17 00:00:00 2001 From: n-hutton Date: Wed, 24 May 2023 00:01:43 +0100 Subject: [PATCH 12/34] further cleanup --- evm-ds/src/evm_server_run.rs | 4 ++-- evm-ds/src/main.rs | 31 +++++++++++++++---------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/evm-ds/src/evm_server_run.rs b/evm-ds/src/evm_server_run.rs index f02b524460..d811a0daa2 100644 --- a/evm-ds/src/evm_server_run.rs +++ b/evm-ds/src/evm_server_run.rs @@ -5,7 +5,7 @@ use std::sync::{Arc, Mutex}; use crate::CallContext; use evm::executor::stack::MemoryStackSubstate; -use evm::{backend::Apply, executor::stack::{MemoryStackState, StackSubstateMetadata}, ExitSucceed}; +use evm::{backend::Apply, executor::stack::{MemoryStackState, StackSubstateMetadata}}; use evm::{Machine, Runtime}; use log::{debug, error, info}; @@ -154,7 +154,7 @@ pub async fn run_evm_impl( listener.finished_call(); match exit_reason { - evm::ExitReason::Revert(exit_revert) => { + evm::ExitReason::Revert(_) => { listener.otter_transaction_error = u8_vec_to_hex(&runtime.machine().return_value(), true); } _ => { diff --git a/evm-ds/src/main.rs b/evm-ds/src/main.rs index cb4d57c894..3b6289ea93 100644 --- a/evm-ds/src/main.rs +++ b/evm-ds/src/main.rs @@ -27,7 +27,6 @@ use evm_server::EvmServer; use log::info; use std::fmt::Debug; -use evm::Opcode; use jsonrpc_core::IoHandler; use jsonrpc_server_utils::codecs; @@ -182,7 +181,7 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { match event { evm::runtime::tracing::Event::Step { - context: context, + context: _, opcode, position, stack, @@ -217,11 +216,11 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { struct_log.op = "SStore".to_string(); } evm::runtime::tracing::Event::TransactTransfer { - call_type: call_type, - address: address, - target: target, - balance: balance, - input: input, + call_type, + address, + target, + balance, + input, } => { intern_trace = Some(InternalOperationOtter { call_type: call_depth, @@ -246,9 +245,9 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { } } evm::runtime::tracing::Event::TransactSuicide { - address: address, - target: target, - balance: balance, + address, + target, + balance, } => { intern_trace = Some(InternalOperationOtter { call_type: 1, @@ -266,12 +265,12 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { input: "".to_string(),}); } evm::runtime::tracing::Event::TransactCreate { - call_type: call_type, - address: address, - target: target, - balance: balance, - is_create2: is_create2, - input: input, + call_type, + address, + target, + balance, + is_create2, + input, } => { intern_trace = Some(InternalOperationOtter { call_type: if is_create2 { 3 } else { 2 }, From 6ca45e39354eaa447268afc1c6e8da2f04d4cc76 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Wed, 24 May 2023 18:50:05 +0100 Subject: [PATCH 13/34] hmm --- tests/EvmAcceptanceTests/test/OtterTests.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/EvmAcceptanceTests/test/OtterTests.ts b/tests/EvmAcceptanceTests/test/OtterTests.ts index 177b83ea94..4c814c2e0e 100644 --- a/tests/EvmAcceptanceTests/test/OtterTests.ts +++ b/tests/EvmAcceptanceTests/test/OtterTests.ts @@ -212,4 +212,3 @@ describe("Otterscan api tests", function () { }); }); - From c4893d376966d8fc6363d08bc29c4329e06f5023 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Wed, 24 May 2023 20:05:29 +0100 Subject: [PATCH 14/34] cleanup --- evm-ds/Cargo.lock | 4 ++++ .../AccountStore/AccountStoreSCEvm.cpp | 2 ++ src/libServer/EthRpcMethods.cpp | 2 +- tests/EvmAcceptanceTests/test/OtterTests.ts | 24 ------------------- 4 files changed, 7 insertions(+), 25 deletions(-) diff --git a/evm-ds/Cargo.lock b/evm-ds/Cargo.lock index 2a3702930d..466df14370 100644 --- a/evm-ds/Cargo.lock +++ b/evm-ds/Cargo.lock @@ -616,6 +616,7 @@ dependencies = [ [[package]] name = "evm" version = "0.37.0" +source = "git+https://github.com/Zilliqa/evm?branch=precompile-backend-plus-otter#8014eb873a0b400cd64e15f57616abd2b324b68f" dependencies = [ "auto_impl", "environmental", @@ -635,6 +636,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" +source = "git+https://github.com/Zilliqa/evm?branch=precompile-backend-plus-otter#8014eb873a0b400cd64e15f57616abd2b324b68f" dependencies = [ "parity-scale-codec", "primitive-types 0.12.1", @@ -686,6 +688,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" +source = "git+https://github.com/Zilliqa/evm?branch=precompile-backend-plus-otter#8014eb873a0b400cd64e15f57616abd2b324b68f" dependencies = [ "environmental", "evm-core", @@ -696,6 +699,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" +source = "git+https://github.com/Zilliqa/evm?branch=precompile-backend-plus-otter#8014eb873a0b400cd64e15f57616abd2b324b68f" dependencies = [ "auto_impl", "environmental", diff --git a/src/libData/AccountStore/AccountStoreSCEvm.cpp b/src/libData/AccountStore/AccountStoreSCEvm.cpp index c05b9d53d0..f2d42aa691 100644 --- a/src/libData/AccountStore/AccountStoreSCEvm.cpp +++ b/src/libData/AccountStore/AccountStoreSCEvm.cpp @@ -384,6 +384,8 @@ bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, LOG_GENERAL(INFO, "Putting in TX trace for: " << evmContext.GetTranID()); + std::cerr << traces << std::endl; + if (!BlockStorage::GetBlockStorage().PutTxTrace(evmContext.GetTranID(), traces)) { LOG_GENERAL(INFO, diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index 43dfe89318..4950906c01 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -2168,7 +2168,7 @@ Json::Value EthRpcMethods::OtterscanGetInternalOperations(const std::string &txH TxnHash tranHash(txHash); bool isPresent = - BlockStorage::GetBlockStorage().GetOtterTrace(tranHash, trace); // nathan + BlockStorage::GetBlockStorage().GetOtterTrace(tranHash, trace); if (!isPresent) { LOG_GENERAL(INFO, "Otterscan trace request failed! "); diff --git a/tests/EvmAcceptanceTests/test/OtterTests.ts b/tests/EvmAcceptanceTests/test/OtterTests.ts index 4c814c2e0e..679eec16b9 100644 --- a/tests/EvmAcceptanceTests/test/OtterTests.ts +++ b/tests/EvmAcceptanceTests/test/OtterTests.ts @@ -67,8 +67,6 @@ describe("Otterscan api tests", function () { await sendJsonRpcRequest(METHOD, 1, [tx.deployTransaction.hash], (result, status) => { assert.equal(status, 200, "has status code"); - console.log(result); - let jsonObject = result.result; assert.equal(jsonObject[0]["type"], 0, "has correct type for transfer"); @@ -111,47 +109,26 @@ describe("Otterscan api tests", function () { ethers.Wallet.createRandom().connect(ethers.provider) ); - //const addresses = accounts.map((signer) => signer.address); - - //const tx = await parallelizer.deployContract("BatchTransferCtor", addresses, ACCOUNT_VALUE, { - // value: ACCOUNTS_COUNT * ACCOUNT_VALUE - //}); - - //const balances = await Promise.all(accounts.map((account) => account.getBalance())); - //balances.forEach((el) => expect(el).to.be.eq(ACCOUNT_VALUE)); const acctAddr = accounts[0].address; - console.log("TX count: "); - console.log(await accounts[0].getTransactionCount()); - const [owner] = await ethers.getSigners(); let txRawFromOwner = { to: acctAddr, value: ethers.utils.parseEther("1") } - console.log("here0"); await owner.sendTransaction(txRawFromOwner); - console.log("here0.5"); - - console.log("TX count: "); - console.log(await accounts[0].getTransactionCount()); // Create a transaction object let txRaw = { to: owner.address, value: ethers.utils.parseEther("0.45") } - console.log("here1"); const txid0 = await accounts[0].sendTransaction(txRaw); const txid1 = await accounts[0].sendTransaction(txRaw); - console.log(txid0.hash); - console.log(txid1.hash); - await sendJsonRpcRequest(METHOD, 1, [acctAddr, 0], (result, status) => { assert.equal(status, 200, "has status code"); - console.log(result); let jsonObject = result.result; assert.equal(jsonObject, txid0.hash, "has correct hash"); @@ -160,7 +137,6 @@ describe("Otterscan api tests", function () { await sendJsonRpcRequest(METHOD, 1, [acctAddr, 1], (result, status) => { assert.equal(status, 200, "has status code"); - console.log(result); let jsonObject = result.result; assert.equal(jsonObject, txid1.hash, "has correct hash"); From ab7f98a97d3172bcf9e56fe603b941156e32f24d Mon Sep 17 00:00:00 2001 From: n-hutton Date: Wed, 24 May 2023 20:53:54 +0100 Subject: [PATCH 15/34] more fixes --- src/libServer/EthRpcMethods.cpp | 12 +++++------- tests/EvmAcceptanceTests/test/OtterTests.ts | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index 4950906c01..b2ad026fcd 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -2088,12 +2088,6 @@ Json::Value EthRpcMethods::OtterscanSearchTransactions(const std::string& addres const auto res = BlockStorage::GetBlockStorage().GetOtterTxAddressMapping(address, blockNumber, pageSize, before, wasMore); - // Perhaps this should just return empty array - if (res.empty()) { - LOG_GENERAL(INFO, "Otterscan trace request failed! "); - return Json::nullValue; - } - Json::Value response = Json::objectValue; Json::Value txs = Json::arrayValue; Json::Value receipts = Json::arrayValue; @@ -2101,7 +2095,11 @@ Json::Value EthRpcMethods::OtterscanSearchTransactions(const std::string& addres for(const auto& hash : res) { // Get Tx result auto const txByHash = GetEthTransactionByHash(hash); - auto const txReceipt = GetEthTransactionReceipt(hash); + auto txReceipt = GetEthTransactionReceipt(hash); + + // For some reason otterscan expects a timestamp in the receipts... + auto const block = GetEthBlockByNumber(txReceipt["blockNumber"].asString(), false); + txReceipt["timestamp"] = block["timestamp"]; txs.append(txByHash); receipts.append(txReceipt); diff --git a/tests/EvmAcceptanceTests/test/OtterTests.ts b/tests/EvmAcceptanceTests/test/OtterTests.ts index 679eec16b9..c9a6891a4f 100644 --- a/tests/EvmAcceptanceTests/test/OtterTests.ts +++ b/tests/EvmAcceptanceTests/test/OtterTests.ts @@ -182,7 +182,7 @@ describe("Otterscan api tests", function () { assert.equal(status, 200, "has status code"); let jsonObject = result.result; - assert.equal(jsonObject, null, "Can find the TX which send funds to this addr"); + assert.equal(jsonObject.txs.length, 0, "Can not find the TX which send funds to this addr"); }); }); From 6a7eb86f425ea6f27e55280e4b5f56f3f5d68ec3 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Wed, 24 May 2023 22:31:53 +0100 Subject: [PATCH 16/34] add before figuring out why ci fails --- src/libServer/EthRpcMethods.cpp | 13 ++++++++---- tests/EvmAcceptanceTests/test/OtterTests.ts | 23 ++++++++------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index b2ad026fcd..5a772ab4bf 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -393,16 +393,21 @@ void EthRpcMethods::Init(LookupServer *lookupServer) { &EthRpcMethods::OtterscanSearchTransactionsBeforeI); m_lookupServer->bindAndAddExternalMethod( - jsonrpc::Procedure("ots_searchTransactionsBefore", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::Procedure("ots_searchTransactionsAfter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param01", jsonrpc::JSON_STRING, NULL), - &EthRpcMethods::OtterscanSearchTransactionsBeforeI); + &EthRpcMethods::OtterscanSearchTransactionsAfterI); + + m_lookupServer->bindAndAddExternalMethod( + jsonrpc::Procedure("ots_getTransactionBySenderAndNonce", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, + "param01", jsonrpc::JSON_STRING, "param02", jsonrpc::JSON_INTEGER, NULL), + &EthRpcMethods::OtterscanGetTransactionBySenderAndNonceI); m_lookupServer->bindAndAddExternalMethod( - jsonrpc::Procedure("ots_getTransactionBySenderAndNonce", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::Procedure("ots_getTransactionError", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param01", jsonrpc::JSON_STRING, NULL), - &EthRpcMethods::OtterscanGetTransactionBySenderAndNonceI); + &EthRpcMethods::OtterscanGetTransactionErrorI); m_lookupServer->bindAndAddExternalMethod( jsonrpc::Procedure("debug_traceBlockByNumber", diff --git a/tests/EvmAcceptanceTests/test/OtterTests.ts b/tests/EvmAcceptanceTests/test/OtterTests.ts index c9a6891a4f..e2b2d121b5 100644 --- a/tests/EvmAcceptanceTests/test/OtterTests.ts +++ b/tests/EvmAcceptanceTests/test/OtterTests.ts @@ -6,20 +6,6 @@ import {parallelizer} from "../helpers"; describe("Otterscan api tests", function () { - let contractOne: Contract; - let contractTwo: Contract; - let contractThree: Contract; - - before(async function () { - - contractOne = await parallelizer.deployContract("ContractOne"); - contractTwo = await parallelizer.deployContract("ContractTwo"); - contractThree = await parallelizer.deployContract("ContractThree"); - - const Contract = await ethers.getContractFactory("Revert"); - this.contract = await Contract.deploy(); - }); - it("When we revert the TX, we can get the tx error ", async function () { const METHOD = "ots_getTransactionError"; const REVERT_MESSAGE = "Transaction too old"; @@ -27,10 +13,15 @@ describe("Otterscan api tests", function () { const abi = ethers.utils.defaultAbiCoder; const MESSAGE_ENCODED = "0x08c379a0" + abi.encode(["string"], [REVERT_MESSAGE]).split('x')[1]; + const Contract = await ethers.getContractFactory("Revert"); + this.contract = await Contract.deploy(); + // In order to make a tx that fails at runtime and not estimate gas time, we estimate the gas of // a similar passing call and use this (+30% leeway) to override the gas field const estimatedGas = await this.contract.estimateGas.requireCustom(true, REVERT_MESSAGE); + console.log("Estimated gas: ", estimatedGas); + const tx = await this.contract.requireCustom(false, REVERT_MESSAGE, { gasLimit: estimatedGas.mul(130).div(100) }) await sendJsonRpcRequest(METHOD, 1, [tx.hash], (result, status) => { @@ -78,6 +69,10 @@ describe("Otterscan api tests", function () { it("We can get the otter trace transaction", async function () { const METHOD = "ots_traceTransaction"; + let contractOne = await parallelizer.deployContract("ContractOne"); + let contractTwo = await parallelizer.deployContract("ContractTwo"); + let contractThree = await parallelizer.deployContract("ContractThree"); + let addrOne = contractOne.address.toLowerCase(); let addrTwo = contractTwo.address.toLowerCase(); let addrThree = contractThree.address.toLowerCase(); From 929029afa87a03131ddf7a9adf6919f6da17b16a Mon Sep 17 00:00:00 2001 From: n-hutton Date: Wed, 24 May 2023 22:32:17 +0100 Subject: [PATCH 17/34] add before figuring out why ci fails2 --- .../contracts/BatchTransfer.sol | 17 +++++++++++++++++ tests/EvmAcceptanceTests/contracts/Revert.sol | 4 ---- 2 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 tests/EvmAcceptanceTests/contracts/BatchTransfer.sol diff --git a/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol b/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol new file mode 100644 index 0000000000..eef2e737eb --- /dev/null +++ b/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +contract BatchTransfer { + constructor() payable + { + } + + function batchTransfer(address payable[] memory destinations, uint256 amount) public + { + for (uint256 i=0; i Date: Wed, 24 May 2023 22:52:49 +0100 Subject: [PATCH 18/34] back to it.. --- .../contracts/BatchTransfer.sol | 17 ----------------- tests/EvmAcceptanceTests/contracts/Revert.sol | 4 ++++ 2 files changed, 4 insertions(+), 17 deletions(-) delete mode 100644 tests/EvmAcceptanceTests/contracts/BatchTransfer.sol diff --git a/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol b/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol deleted file mode 100644 index eef2e737eb..0000000000 --- a/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.9; - -contract BatchTransfer { - constructor() payable - { - } - - function batchTransfer(address payable[] memory destinations, uint256 amount) public - { - for (uint256 i=0; i Date: Wed, 24 May 2023 22:57:34 +0100 Subject: [PATCH 19/34] disable otter test... --- tests/EvmAcceptanceTests/test/OtterTests.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/EvmAcceptanceTests/test/OtterTests.ts b/tests/EvmAcceptanceTests/test/OtterTests.ts index e2b2d121b5..dfe22e80ff 100644 --- a/tests/EvmAcceptanceTests/test/OtterTests.ts +++ b/tests/EvmAcceptanceTests/test/OtterTests.ts @@ -6,7 +6,7 @@ import {parallelizer} from "../helpers"; describe("Otterscan api tests", function () { - it("When we revert the TX, we can get the tx error ", async function () { + xit("When we revert the TX, we can get the tx error ", async function () { const METHOD = "ots_getTransactionError"; const REVERT_MESSAGE = "Transaction too old"; @@ -33,7 +33,7 @@ describe("Otterscan api tests", function () { }); }); - it("We can get the otter internal operations", async function () { + xit("We can get the otter internal operations", async function () { const METHOD = "ots_getInternalOperations"; // Check we can for example detect a suicide with correct value. @@ -66,7 +66,7 @@ describe("Otterscan api tests", function () { }); - it("We can get the otter trace transaction", async function () { + xit("We can get the otter trace transaction", async function () { const METHOD = "ots_traceTransaction"; let contractOne = await parallelizer.deployContract("ContractOne"); @@ -91,7 +91,7 @@ describe("Otterscan api tests", function () { }); - it("We can get the otter search for sender by nonce", async function () { + xit("We can get the otter search for sender by nonce", async function () { const METHOD = "ots_getTransactionBySenderAndNonce"; // To test this, send money to an account then have it send it back. @@ -139,7 +139,7 @@ describe("Otterscan api tests", function () { }); - it("We can get the otter search TX before and after", async function () { + xit("We can get the otter search TX before and after", async function () { const METHOD_BEFORE = "ots_searchTransactionsBefore"; const METHOD_AFTER = "ots_searchTransactionsAfter"; From 4836ae4859506b937742e6d1803d81d819f7d39f Mon Sep 17 00:00:00 2001 From: n-hutton Date: Wed, 24 May 2023 22:58:35 +0100 Subject: [PATCH 20/34] remove debug --- src/libData/AccountStore/AccountStoreSCEvm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libData/AccountStore/AccountStoreSCEvm.cpp b/src/libData/AccountStore/AccountStoreSCEvm.cpp index f2d42aa691..6ebb5eb695 100644 --- a/src/libData/AccountStore/AccountStoreSCEvm.cpp +++ b/src/libData/AccountStore/AccountStoreSCEvm.cpp @@ -384,8 +384,6 @@ bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, LOG_GENERAL(INFO, "Putting in TX trace for: " << evmContext.GetTranID()); - std::cerr << traces << std::endl; - if (!BlockStorage::GetBlockStorage().PutTxTrace(evmContext.GetTranID(), traces)) { LOG_GENERAL(INFO, @@ -401,6 +399,8 @@ bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, // permanently and the rest is huge auto const trace_stripped = stripTxTraceOut(traces); + std::cout << "Putting otter trace: " << trace_stripped << std::endl; + if (!BlockStorage::GetBlockStorage().PutOtterTrace(evmContext.GetTranID(), traces)) { LOG_GENERAL(INFO, From 50127318d5c0f1eb0d22df3f1519e3f35ba242ff Mon Sep 17 00:00:00 2001 From: n-hutton Date: Wed, 24 May 2023 23:08:11 +0100 Subject: [PATCH 21/34] make mocha work better hopefully --- scripts/integration_test_js.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/integration_test_js.sh b/scripts/integration_test_js.sh index 75e4489cb6..2c60ae6ab3 100755 --- a/scripts/integration_test_js.sh +++ b/scripts/integration_test_js.sh @@ -118,9 +118,11 @@ else cd tests/EvmAcceptanceTests/ npm install - DEBUG=true MOCHA_TIMEOUT=20000 npx hardhat test + DEBUG=true MOCHA_TIMEOUT=20000 npx hardhat test 2>&1 > npx.out retVal=$? + + cat npx.out if [ $retVal -ne 0 ]; then echo "!!!!!! Error with JS integration test !!!!!!" exit 1 From 6469aedb233d399adb0fd3784df5c0e9dc6c0ecd Mon Sep 17 00:00:00 2001 From: n-hutton Date: Wed, 24 May 2023 23:10:44 +0100 Subject: [PATCH 22/34] increase timeout... --- scripts/integration_test_js.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/integration_test_js.sh b/scripts/integration_test_js.sh index 2c60ae6ab3..565f2e04e9 100755 --- a/scripts/integration_test_js.sh +++ b/scripts/integration_test_js.sh @@ -118,7 +118,7 @@ else cd tests/EvmAcceptanceTests/ npm install - DEBUG=true MOCHA_TIMEOUT=20000 npx hardhat test 2>&1 > npx.out + DEBUG=true MOCHA_TIMEOUT=40000 npx hardhat test 2>&1 > npx.out retVal=$? From 6cc24bea18d1f76afc181c33a8869da641a1ff7c Mon Sep 17 00:00:00 2001 From: n-hutton Date: Wed, 24 May 2023 23:12:48 +0100 Subject: [PATCH 23/34] readd batch transfer --- .../contracts/BatchTransfer.sol | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/EvmAcceptanceTests/contracts/BatchTransfer.sol diff --git a/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol b/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol new file mode 100644 index 0000000000..1339bbcc9d --- /dev/null +++ b/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +contract BatchTransfer { + event DebugMe(string); + + constructor() payable + { + } + + function batchTransfer(address payable[] memory destinations, uint256 amount) public + { + //for (uint256 i=0; i Date: Wed, 24 May 2023 23:21:16 +0100 Subject: [PATCH 24/34] clean --- src/libData/AccountStore/AccountStoreSCEvm.cpp | 2 -- src/libServer/EthRpcMethods.cpp | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/libData/AccountStore/AccountStoreSCEvm.cpp b/src/libData/AccountStore/AccountStoreSCEvm.cpp index 6ebb5eb695..c05b9d53d0 100644 --- a/src/libData/AccountStore/AccountStoreSCEvm.cpp +++ b/src/libData/AccountStore/AccountStoreSCEvm.cpp @@ -399,8 +399,6 @@ bool AccountStoreSC::UpdateAccountsEvm(const uint64_t &blockNum, // permanently and the rest is huge auto const trace_stripped = stripTxTraceOut(traces); - std::cout << "Putting otter trace: " << trace_stripped << std::endl; - if (!BlockStorage::GetBlockStorage().PutOtterTrace(evmContext.GetTranID(), traces)) { LOG_GENERAL(INFO, diff --git a/src/libServer/EthRpcMethods.cpp b/src/libServer/EthRpcMethods.cpp index 5a772ab4bf..081fa042ff 100644 --- a/src/libServer/EthRpcMethods.cpp +++ b/src/libServer/EthRpcMethods.cpp @@ -387,15 +387,15 @@ void EthRpcMethods::Init(LookupServer *lookupServer) { &EthRpcMethods::OtterscanTraceTransactionI); m_lookupServer->bindAndAddExternalMethod( - jsonrpc::Procedure("ots_searchTransactionsBefore", jsonrpc::PARAMS_BY_POSITION, - jsonrpc::JSON_STRING, "param01", jsonrpc::JSON_STRING, - NULL), + jsonrpc::Procedure("ots_searchTransactionsBefore", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, + "param01", jsonrpc::JSON_STRING, "param02", jsonrpc::JSON_INTEGER, "param03", jsonrpc::JSON_INTEGER, NULL), &EthRpcMethods::OtterscanSearchTransactionsBeforeI); m_lookupServer->bindAndAddExternalMethod( - jsonrpc::Procedure("ots_searchTransactionsAfter", jsonrpc::PARAMS_BY_POSITION, - jsonrpc::JSON_STRING, "param01", jsonrpc::JSON_STRING, - NULL), + jsonrpc::Procedure("ots_searchTransactionsAfter", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, + "param01", jsonrpc::JSON_STRING, "param02", jsonrpc::JSON_INTEGER, "param03", jsonrpc::JSON_INTEGER, NULL), &EthRpcMethods::OtterscanSearchTransactionsAfterI); m_lookupServer->bindAndAddExternalMethod( From 1864f2f0c2a0d4e6d66b9d24c68f48f7dcc7378f Mon Sep 17 00:00:00 2001 From: n-hutton Date: Thu, 25 May 2023 00:07:13 +0100 Subject: [PATCH 25/34] bail on first test failure --- scripts/integration_test_js.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/integration_test_js.sh b/scripts/integration_test_js.sh index 565f2e04e9..5c3f1a5986 100755 --- a/scripts/integration_test_js.sh +++ b/scripts/integration_test_js.sh @@ -118,7 +118,7 @@ else cd tests/EvmAcceptanceTests/ npm install - DEBUG=true MOCHA_TIMEOUT=40000 npx hardhat test 2>&1 > npx.out + DEBUG=true MOCHA_TIMEOUT=40000 npx hardhat test --bail 2>&1 > npx.out retVal=$? From 4eb997d4b7edf4e36e85e28794d13a0df2e16891 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Thu, 25 May 2023 00:11:16 +0100 Subject: [PATCH 26/34] hope it wasn't this... --- .../contracts/BatchTransfer.sol | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol b/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol index 1339bbcc9d..eef2e737eb 100644 --- a/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol +++ b/tests/EvmAcceptanceTests/contracts/BatchTransfer.sol @@ -2,23 +2,16 @@ pragma solidity ^0.8.9; contract BatchTransfer { - event DebugMe(string); - constructor() payable { } function batchTransfer(address payable[] memory destinations, uint256 amount) public { - //for (uint256 i=0; i Date: Thu, 25 May 2023 00:22:45 +0100 Subject: [PATCH 27/34] getting desperate.. --- evm-ds/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evm-ds/src/main.rs b/evm-ds/src/main.rs index 3b6289ea93..5e87d6a05d 100644 --- a/evm-ds/src/main.rs +++ b/evm-ds/src/main.rs @@ -296,7 +296,9 @@ impl evm::runtime::tracing::EventListener for LoggingEventListener { } } - self.raw_tracer.struct_logs.push(struct_log); + if self.raw_tracer.struct_logs.len() < 5 { + self.raw_tracer.struct_logs.push(struct_log); + } if let Some(intern_trace) = intern_trace { self.otter_internal_tracer.push(intern_trace); From 1058cea1694472c2349308ebdaf86512aecace03 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Thu, 25 May 2023 00:26:15 +0100 Subject: [PATCH 28/34] hard kill --- scripts/integration_test_js.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/integration_test_js.sh b/scripts/integration_test_js.sh index 5c3f1a5986..fb1c420cc5 100755 --- a/scripts/integration_test_js.sh +++ b/scripts/integration_test_js.sh @@ -122,6 +122,7 @@ else retVal=$? + pkill -9 isolatedServer cat npx.out if [ $retVal -ne 0 ]; then echo "!!!!!! Error with JS integration test !!!!!!" From 6fc381a909299ef60432359e237591827f1f6a57 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Thu, 25 May 2023 00:27:17 +0100 Subject: [PATCH 29/34] make it an interrupt --- scripts/integration_test_js.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/integration_test_js.sh b/scripts/integration_test_js.sh index fb1c420cc5..b9bb108f9a 100755 --- a/scripts/integration_test_js.sh +++ b/scripts/integration_test_js.sh @@ -122,7 +122,7 @@ else retVal=$? - pkill -9 isolatedServer + pkill -INT isolatedServer cat npx.out if [ $retVal -ne 0 ]; then echo "!!!!!! Error with JS integration test !!!!!!" From d47d12a747a819c586ccebd6f0c01acfd9c3ff17 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Thu, 25 May 2023 15:47:20 +0100 Subject: [PATCH 30/34] cleanup --- src/libPersistence/BlockStorage.cpp | 9 --------- tests/EvmAcceptanceTests/test/OtterTests.ts | 10 +++++----- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/libPersistence/BlockStorage.cpp b/src/libPersistence/BlockStorage.cpp index fdbfe4f51e..9dfe0f8252 100644 --- a/src/libPersistence/BlockStorage.cpp +++ b/src/libPersistence/BlockStorage.cpp @@ -2076,10 +2076,6 @@ void BlockStorage::BuildHashToNumberMappingForTxBlocks() { } } -// Tx traces are put in storage, and each time one is inserted, the oldest is -// pruned, so long as it is over TX_TRACES_TO_STORE ago. -// To do this, at the null address is an array/ring buffer of trace hashes -// bool BlockStorage::PutOtterTrace(const dev::h256& key, const std::string& trace) { if (!ARCHIVAL_LOOKUP_WITH_TX_TRACES) { LOG_GENERAL( @@ -2142,10 +2138,6 @@ bool BlockStorage::GetOtterTrace(const dev::h256& key, std::string& trace) { return true; } -// Tx txAddressMappings are put in storage, and each time one is inserted, the oldest is -// pruned, so long as it is over TX_TxAddressMappingS_TO_STORE ago. -// To do this, at the null address is an array/ring buffer of txAddressMapping hashes -// bool BlockStorage::PutOtterTxAddressMapping(const dev::h256& txId, const std::set& addresses, const uint64_t& blocknum) { if (!ARCHIVAL_LOOKUP_WITH_TX_TRACES) { LOG_GENERAL( @@ -2284,7 +2276,6 @@ std::vector BlockStorage::GetOtterTxAddressMapping(std::string addr } -// nathan2 bool BlockStorage::PutOtterAddressNonceLookup(const dev::h256& txId, uint64_t nonce, std::string address) { if (!ARCHIVAL_LOOKUP_WITH_TX_TRACES) { LOG_GENERAL( diff --git a/tests/EvmAcceptanceTests/test/OtterTests.ts b/tests/EvmAcceptanceTests/test/OtterTests.ts index dfe22e80ff..e2b2d121b5 100644 --- a/tests/EvmAcceptanceTests/test/OtterTests.ts +++ b/tests/EvmAcceptanceTests/test/OtterTests.ts @@ -6,7 +6,7 @@ import {parallelizer} from "../helpers"; describe("Otterscan api tests", function () { - xit("When we revert the TX, we can get the tx error ", async function () { + it("When we revert the TX, we can get the tx error ", async function () { const METHOD = "ots_getTransactionError"; const REVERT_MESSAGE = "Transaction too old"; @@ -33,7 +33,7 @@ describe("Otterscan api tests", function () { }); }); - xit("We can get the otter internal operations", async function () { + it("We can get the otter internal operations", async function () { const METHOD = "ots_getInternalOperations"; // Check we can for example detect a suicide with correct value. @@ -66,7 +66,7 @@ describe("Otterscan api tests", function () { }); - xit("We can get the otter trace transaction", async function () { + it("We can get the otter trace transaction", async function () { const METHOD = "ots_traceTransaction"; let contractOne = await parallelizer.deployContract("ContractOne"); @@ -91,7 +91,7 @@ describe("Otterscan api tests", function () { }); - xit("We can get the otter search for sender by nonce", async function () { + it("We can get the otter search for sender by nonce", async function () { const METHOD = "ots_getTransactionBySenderAndNonce"; // To test this, send money to an account then have it send it back. @@ -139,7 +139,7 @@ describe("Otterscan api tests", function () { }); - xit("We can get the otter search TX before and after", async function () { + it("We can get the otter search TX before and after", async function () { const METHOD_BEFORE = "ots_searchTransactionsBefore"; const METHOD_AFTER = "ots_searchTransactionsAfter"; From 1fa90761e60c02cfcd555397198260b831735adc Mon Sep 17 00:00:00 2001 From: n-hutton Date: Thu, 25 May 2023 15:48:00 +0100 Subject: [PATCH 31/34] Update evm-ds/src/evm_server_run.rs Co-authored-by: James Hinshelwood --- evm-ds/src/evm_server_run.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm-ds/src/evm_server_run.rs b/evm-ds/src/evm_server_run.rs index d811a0daa2..7c7309247e 100644 --- a/evm-ds/src/evm_server_run.rs +++ b/evm-ds/src/evm_server_run.rs @@ -155,7 +155,7 @@ pub async fn run_evm_impl( match exit_reason { evm::ExitReason::Revert(_) => { - listener.otter_transaction_error = u8_vec_to_hex(&runtime.machine().return_value(), true); + listener.otter_transaction_error = format!("0x{}", hex::encode(&runtime.machine().return_value()); } _ => { debug!("Machine: position: {:?}, memory: {:?}, stack: {:?}", From 339f80cfe9580e46156d11e350fad3f9f8da62f0 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Thu, 25 May 2023 15:49:09 +0100 Subject: [PATCH 32/34] cleanup --- evm-ds/src/evm_server_run.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/evm-ds/src/evm_server_run.rs b/evm-ds/src/evm_server_run.rs index 7c7309247e..c9831e0c69 100644 --- a/evm-ds/src/evm_server_run.rs +++ b/evm-ds/src/evm_server_run.rs @@ -418,18 +418,4 @@ fn handle_panic(trace: String, remaining_gas: u64, reason: &str) -> EvmProto::Ev result.set_tx_trace(trace.into()); result.set_remaining_gas(remaining_gas); result -} - -fn u8_vec_to_hex(to_convert: &Vec, add_0x: bool) -> String { - let mut hex_string = String::new(); - - if add_0x { - hex_string.push_str("0x"); - } - - for byte in to_convert { - hex_string.push_str(&format!("{:02x}", byte)); - } - hex_string -} - +} \ No newline at end of file From 40c669cdac9cf89f521c1fd0dda5bfe7a6600b8d Mon Sep 17 00:00:00 2001 From: n-hutton Date: Thu, 25 May 2023 17:22:50 +0100 Subject: [PATCH 33/34] asdfsdf --- evm-ds/src/evm_server_run.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm-ds/src/evm_server_run.rs b/evm-ds/src/evm_server_run.rs index c9831e0c69..d22145c281 100644 --- a/evm-ds/src/evm_server_run.rs +++ b/evm-ds/src/evm_server_run.rs @@ -155,7 +155,7 @@ pub async fn run_evm_impl( match exit_reason { evm::ExitReason::Revert(_) => { - listener.otter_transaction_error = format!("0x{}", hex::encode(&runtime.machine().return_value()); + listener.otter_transaction_error = format!("0x{}", hex::encode(&runtime.machine().return_value())); } _ => { debug!("Machine: position: {:?}, memory: {:?}, stack: {:?}", From 0a41d1f827dabfd8f45e0b2a0e5ddb596ff960d4 Mon Sep 17 00:00:00 2001 From: n-hutton Date: Thu, 25 May 2023 17:28:20 +0100 Subject: [PATCH 34/34] sigh --- evm-ds/src/evm_server_run.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm-ds/src/evm_server_run.rs b/evm-ds/src/evm_server_run.rs index d22145c281..44857aa24d 100644 --- a/evm-ds/src/evm_server_run.rs +++ b/evm-ds/src/evm_server_run.rs @@ -155,7 +155,7 @@ pub async fn run_evm_impl( match exit_reason { evm::ExitReason::Revert(_) => { - listener.otter_transaction_error = format!("0x{}", hex::encode(&runtime.machine().return_value())); + listener.otter_transaction_error = format!("0x{}", hex::encode(runtime.machine().return_value())); } _ => { debug!("Machine: position: {:?}, memory: {:?}, stack: {:?}",