diff --git a/libethereum/Block.cpp b/libethereum/Block.cpp
index 0ce672045..61f198810 100644
--- a/libethereum/Block.cpp
+++ b/libethereum/Block.cpp
@@ -795,36 +795,56 @@ u256 Block::enact( VerifiedBlockRef const& _block, BlockChain const& _bc ) {
#ifdef HISTORIC_STATE
ExecutionResult Block::executeHistoricCall( LastBlockHashesFace const& _lh, Transaction const& _t,
std::shared_ptr< AlethStandardTrace > _tracer, uint64_t _transactionIndex ) {
- auto onOp = OnOpFunc();
+ try {
+ auto onOp = OnOpFunc();
- if ( _tracer ) {
- onOp = _tracer->functionToExecuteOnEachOperation();
- }
+ if ( _tracer ) {
+ onOp = _tracer->functionToExecuteOnEachOperation();
+ }
- if ( isSealed() )
- BOOST_THROW_EXCEPTION( InvalidOperationOnSealedBlock() );
+ if ( isSealed() )
+ BOOST_THROW_EXCEPTION( InvalidOperationOnSealedBlock() );
- // Uncommitting is a non-trivial operation - only do it once we've verified as much of the
- // transaction as possible.
- uncommitToSeal();
+ uncommitToSeal();
- u256 const gasUsed =
- _transactionIndex ? receipt( _transactionIndex - 1 ).cumulativeGasUsed() : 0;
+ STATE_CHECK( _transactionIndex <= m_receipts.size() )
- EnvInfo const envInfo{ info(), _lh, gasUsed, m_sealEngine->chainParams().chainID };
+ u256 const gasUsed =
+ _transactionIndex ? receipt( _transactionIndex - 1 ).cumulativeGasUsed() : 0;
- if ( _tracer ) {
- HistoricState stateBefore( m_state.mutableHistoricState() );
- auto resultReceipt = m_state.mutableHistoricState().execute(
- envInfo, *m_sealEngine, _t, skale::Permanence::Uncommitted, onOp );
- HistoricState stateAfter( m_state.mutableHistoricState() );
- _tracer->finalizeTrace( resultReceipt.first, stateBefore, stateAfter );
- return resultReceipt.first;
- } else {
- auto resultReceipt = m_state.mutableHistoricState().execute(
- envInfo, *m_sealEngine, _t, skale::Permanence::Reverted, onOp );
- return resultReceipt.first;
+ EnvInfo const envInfo{ info(), _lh, gasUsed, m_sealEngine->chainParams().chainID };
+
+ if ( _tracer ) {
+ try {
+ HistoricState stateBefore( m_state.mutableHistoricState() );
+
+ auto resultReceipt = m_state.mutableHistoricState().execute(
+ envInfo, *m_sealEngine, _t, skale::Permanence::Uncommitted, onOp );
+ HistoricState stateAfter( m_state.mutableHistoricState() );
+ _tracer->finalizeAndPrintTrace( resultReceipt.first, stateBefore, stateAfter );
+ // for tracing the entire block is traced therefore, we save transaction receipt
+ // as it is used for execution of the next transaction
+ m_receipts.push_back( resultReceipt.second );
+ return resultReceipt.first;
+ } catch ( std::exception& e ) {
+ throw dev::eth::VMTracingError( "Exception doing trace for transaction index:" +
+ std::to_string( _transactionIndex ) + ":" +
+ e.what() );
+ }
+ } else {
+ auto resultReceipt = m_state.mutableHistoricState().execute(
+ envInfo, *m_sealEngine, _t, skale::Permanence::Reverted, onOp );
+ return resultReceipt.first;
+ }
+ } catch ( std::exception& e ) {
+ BOOST_THROW_EXCEPTION(
+ std::runtime_error( "Could not execute historic call for transactionIndex:" +
+ to_string( _transactionIndex ) + ":" + e.what() ) );
+ } catch ( ... ) {
+ BOOST_THROW_EXCEPTION(
+ std::runtime_error( "Could not execute historic call for transactionIndex:" +
+ to_string( _transactionIndex ) + ": unknown error" ) );
}
}
#endif
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index f82f3e194..bd013a914 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -1346,43 +1346,48 @@ Transaction Client::createTransactionForCallOrTraceCall( const Address& _from, c
Json::Value Client::traceBlock( BlockNumber _blockNumber, Json::Value const& _jsonTraceConfig ) {
- Block previousBlock = blockByNumber( _blockNumber - 1 );
- Block historicBlock = blockByNumber( _blockNumber );
+ try {
+ Block previousBlock = blockByNumber( _blockNumber - 1 );
+ Block historicBlock = blockByNumber( _blockNumber );
- Json::Value traces( Json::arrayValue );
+ Json::Value traces( Json::arrayValue );
- auto hash = ClientBase::hashFromNumber( _blockNumber );
- Transactions transactions = this->transactions( hash );
+ auto hash = ClientBase::hashFromNumber( _blockNumber );
+ Transactions transactions = this->transactions( hash );
- auto traceOptions = TraceOptions::make( _jsonTraceConfig );
+ auto traceOptions = TraceOptions::make( _jsonTraceConfig );
- // cache results for better peformance
- string key = to_string( _blockNumber ) + traceOptions.toString();
+ // cache results for better peformance
+ string key = to_string( _blockNumber ) + traceOptions.toString();
- auto cachedResult = m_blockTraceCache.getIfExists( key );
- if ( cachedResult.has_value() ) {
- return std::any_cast< Json::Value >( cachedResult );
- }
+ auto cachedResult = m_blockTraceCache.getIfExists( key );
+ if ( cachedResult.has_value() ) {
+ return std::any_cast< Json::Value >( cachedResult );
+ }
- for ( unsigned k = 0; k < transactions.size(); k++ ) {
- Json::Value transactionLog( Json::objectValue );
- Transaction tx = transactions.at( k );
- auto hashString = toHexPrefixed( tx.sha3() );
- transactionLog["txHash"] = hashString;
- tx.checkOutExternalGas( chainParams().externalGasDifficulty );
- auto tracer =
- std::make_shared< AlethStandardTrace >( tx, historicBlock.author(), traceOptions );
- auto executionResult =
- previousBlock.executeHistoricCall( bc().lastBlockHashes(), tx, tracer, k );
- auto result = tracer->getJSONResult();
- transactionLog["result"] = result;
- traces.append( transactionLog );
- }
+ for ( unsigned k = 0; k < transactions.size(); k++ ) {
+ Json::Value transactionLog( Json::objectValue );
+ Transaction tx = transactions.at( k );
+ auto hashString = toHexPrefixed( tx.sha3() );
+ transactionLog["txHash"] = hashString;
+ tx.checkOutExternalGas( chainParams().externalGasDifficulty );
+ auto tracer =
+ std::make_shared< AlethStandardTrace >( tx, historicBlock.author(), traceOptions );
+ auto executionResult =
+ previousBlock.executeHistoricCall( bc().lastBlockHashes(), tx, tracer, k );
+ auto result = tracer->getJSONResult();
+ transactionLog["result"] = result;
+ traces.append( transactionLog );
+ }
- auto tracesSize = traces.toStyledString().size();
- m_blockTraceCache.put( key, traces, tracesSize );
+ auto tracesSize = traces.toStyledString().size();
+ m_blockTraceCache.put( key, traces, tracesSize );
- return traces;
+ return traces;
+ } catch ( std::exception& e ) {
+ BOOST_THROW_EXCEPTION( std::runtime_error(
+ "Could not trace block:" + to_string( _blockNumber ) + ":" + e.what() ) );
+ }
}
#endif
diff --git a/libhistoric/AlethStandardTrace.cpp b/libhistoric/AlethStandardTrace.cpp
index 01ca179db..ea04315c5 100644
--- a/libhistoric/AlethStandardTrace.cpp
+++ b/libhistoric/AlethStandardTrace.cpp
@@ -27,6 +27,7 @@ along with skaled. If not, see .
namespace dev::eth {
TraceOptions eth::AlethStandardTrace::getOptions() const {
+ STATE_CHECK( m_isFinalized )
return m_options;
}
@@ -35,6 +36,7 @@ void AlethStandardTrace::analyzeInstructionAndRecordNeededInformation( uint64_t,
const LegacyVM* _vm ) {
STATE_CHECK( _face )
STATE_CHECK( _vm )
+ STATE_CHECK( !m_isFinalized )
// check if instruction depth changed. This means a function has been called or has returned
processFunctionCallOrReturnIfHappened( _ext, _vm, ( uint64_t ) _gasRemaining );
@@ -105,6 +107,7 @@ void AlethStandardTrace::analyzeInstructionAndRecordNeededInformation( uint64_t,
// record the instruction
m_lastOpRecord = OpExecutionRecord( _ext.depth, _inst, _gasRemaining, _lastOpGas );
}
+
void AlethStandardTrace::processFunctionCallOrReturnIfHappened(
const AlethExtVM& _ext, const LegacyVM* _vm, uint64_t _gasRemaining ) {
STATE_CHECK( !m_isFinalized )
@@ -128,6 +131,7 @@ void AlethStandardTrace::processFunctionCallOrReturnIfHappened(
}
}
const Address& AlethStandardTrace::getFrom() const {
+ STATE_CHECK( m_isFinalized )
return m_from;
}
@@ -147,7 +151,6 @@ vector< uint8_t > AlethStandardTrace::extractSmartContractMemoryByteArrayFromSta
return result;
}
-
void AlethStandardTrace::recordFunctionIsCalled( const Address& _from, const Address& _to,
uint64_t _gasLimit, const vector< uint8_t >& _inputData, const u256& _value ) {
STATE_CHECK( !m_isFinalized )
@@ -178,6 +181,7 @@ void AlethStandardTrace::recordFunctionIsCalled( const Address& _from, const Add
void AlethStandardTrace::setTopFunctionCall(
const shared_ptr< FunctionCallRecord >& _topFunctionCall ) {
STATE_CHECK( _topFunctionCall )
+ STATE_CHECK( !m_isFinalized )
m_topFunctionCall = _topFunctionCall;
}
@@ -185,6 +189,7 @@ void AlethStandardTrace::recordFunctionReturned(
evmc_status_code _status, const vector< uint8_t >& _returnData, uint64_t _gasUsed ) {
STATE_CHECK( m_lastOpRecord.m_gasRemaining >= m_lastOpRecord.m_opGas )
STATE_CHECK( m_currentlyExecutingFunctionCall )
+ STATE_CHECK( !m_isFinalized )
// record return values
getCurrentlyExecutingFunctionCall()->setReturnValues( _status, _returnData, _gasUsed );
@@ -203,7 +208,6 @@ void AlethStandardTrace::recordFunctionReturned(
// the getter functions are called by printer classes after the trace has been generated
const shared_ptr< FunctionCallRecord >& AlethStandardTrace::getTopFunctionCall() const {
STATE_CHECK( m_isFinalized )
- STATE_CHECK( m_topFunctionCall );
return m_topFunctionCall;
}
@@ -214,6 +218,11 @@ Json::Value AlethStandardTrace::getJSONResult() const {
return m_jsonTrace;
}
+uint64_t AlethStandardTrace::getTotalGasUsed() const {
+ STATE_CHECK( m_isFinalized )
+ return m_totalGasUsed;
+}
+
AlethStandardTrace::AlethStandardTrace(
Transaction& _t, const Address& _blockAuthor, const TraceOptions& _options, bool _isCall )
: m_defaultOpTrace{ std::make_shared< Json::Value >() },
@@ -243,12 +252,22 @@ AlethStandardTrace::AlethStandardTrace(
{ TraceType::FOUR_BYTE_TRACER, m_fourByteTracePrinter },
{ TraceType::NOOP_TRACER, m_noopTracePrinter } },
m_blockAuthor( _blockAuthor ),
- m_isCall( _isCall ) {
+ m_isCall( _isCall ),
+ m_value( _t.value() ),
+ m_gasLimit( _t.gas() ),
+ m_inputData( _t.data() ),
+ m_gasPrice( _t.gasPrice() ) {
// mark from and to accounts as accessed
m_accessedAccounts.insert( m_from );
m_accessedAccounts.insert( m_to );
}
+
+const u256& AlethStandardTrace::getGasLimit() const {
+ STATE_CHECK( m_isFinalized )
+ return m_gasLimit;
+}
void AlethStandardTrace::setOriginalFromBalance( const u256& _originalFromBalance ) {
+ STATE_CHECK( !m_isFinalized )
m_originalFromBalance = _originalFromBalance;
}
@@ -361,24 +380,30 @@ string AlethStandardTrace::toGethCompatibleCompactHexPrefixed( const u256& _valu
return "0x" + hexStr;
}
-// execution completed. Now use the tracer that the user requested
-// to print the resulting trace
-void eth::AlethStandardTrace::finalizeTrace(
+// execution completed. Now finalize the trace and use the tracer that the user requested
+// to print the resulting trace to json
+void eth::AlethStandardTrace::finalizeAndPrintTrace(
ExecutionResult& _er, HistoricState& _statePre, HistoricState& _statePost ) {
- auto totalGasUsed = ( uint64_t ) _er.gasUsed;
- auto statusCode = AlethExtVM::transactionExceptionToEvmcStatusCode( _er.excepted );
+ m_totalGasUsed = ( uint64_t ) _er.gasUsed;
- // we are done. Set the trace to finalized.
- STATE_CHECK( !m_isFinalized.exchange( true ) )
+ auto statusCode = AlethExtVM::transactionExceptionToEvmcStatusCode( _er.excepted );
- STATE_CHECK( m_topFunctionCall )
STATE_CHECK( m_topFunctionCall == m_currentlyExecutingFunctionCall )
+ // if transaction is not just ETH transfer
// record return of the top function.
- recordFunctionReturned( statusCode, _er.output, totalGasUsed );
+ if ( m_topFunctionCall ) {
+ recordFunctionReturned( statusCode, _er.output, m_totalGasUsed );
+ }
+ // we are done. Set the trace to finalized
+ STATE_CHECK( !m_isFinalized.exchange( true ) )
+ // now print trace
+ printTrace( _er, _statePre, _statePost );
+}
+void eth::AlethStandardTrace::printTrace( ExecutionResult& _er, const HistoricState& _statePre,
+ const HistoricState& _statePost ) { // now print the trace
m_jsonTrace = Json::Value( Json::objectValue );
-
// now run the trace that the user wants based on options provided
if ( m_tracePrinters.count( m_options.tracerType ) > 0 ) {
m_tracePrinters.at( m_options.tracerType ).print( m_jsonTrace, _er, _statePre, _statePost );
@@ -427,33 +452,63 @@ const shared_ptr< Json::Value >& AlethStandardTrace::getDefaultOpTrace() const {
const shared_ptr< FunctionCallRecord >& AlethStandardTrace::getCurrentlyExecutingFunctionCall()
const {
+ STATE_CHECK( !m_isFinalized )
STATE_CHECK( m_currentlyExecutingFunctionCall )
return m_currentlyExecutingFunctionCall;
}
void AlethStandardTrace::setCurrentlyExecutingFunctionCall(
const shared_ptr< FunctionCallRecord >& _currentlyExecutingFunctionCall ) {
+ STATE_CHECK( !m_isFinalized )
STATE_CHECK( _currentlyExecutingFunctionCall )
m_currentlyExecutingFunctionCall = _currentlyExecutingFunctionCall;
}
+
const Address& AlethStandardTrace::getBlockAuthor() const {
+ STATE_CHECK( m_isFinalized )
return m_blockAuthor;
}
+
const u256& AlethStandardTrace::getMinerPayment() const {
+ STATE_CHECK( m_isFinalized )
return m_minerPayment;
}
+
void AlethStandardTrace::recordMinerPayment( u256 _minerGasPayment ) {
- this->m_minerPayment = _minerGasPayment;
+ STATE_CHECK( !m_isFinalized )
+ m_minerPayment = _minerGasPayment;
// add miner to the list of accessed accounts, since the miner is paid
// transaction fee
- this->m_accessedAccounts.insert( m_blockAuthor );
+ m_accessedAccounts.insert( m_blockAuthor );
}
+
bool AlethStandardTrace::isCall() const {
+ STATE_CHECK( m_isFinalized )
return m_isCall;
}
+
const u256& AlethStandardTrace::getOriginalFromBalance() const {
+ STATE_CHECK( m_isFinalized )
return m_originalFromBalance;
}
+
+const bytes& AlethStandardTrace::getInputData() const {
+ STATE_CHECK( m_isFinalized )
+ return m_inputData;
+}
+const u256& AlethStandardTrace::getValue() const {
+ STATE_CHECK( m_isFinalized )
+ return m_value;
+}
+const Address& AlethStandardTrace::getTo() const {
+ STATE_CHECK( m_isFinalized )
+ return m_to;
+}
+
+const u256& AlethStandardTrace::getGasPrice() const {
+ STATE_CHECK( m_isFinalized )
+ return m_gasPrice;
+}
} // namespace dev::eth
#endif
diff --git a/libhistoric/AlethStandardTrace.h b/libhistoric/AlethStandardTrace.h
index 1d9eea6bc..ddd448fdb 100644
--- a/libhistoric/AlethStandardTrace.h
+++ b/libhistoric/AlethStandardTrace.h
@@ -64,7 +64,15 @@ class AlethStandardTrace {
}
// this function will be called at the end of executions
- void finalizeTrace( ExecutionResult& _er, HistoricState& _statePre, HistoricState& _statePost );
+ void finalizeAndPrintTrace(
+ ExecutionResult& _er, HistoricState& _statePre, HistoricState& _statePost );
+
+
+ // this is to set original from balance for calls
+ // in a geth call, the from account balance is always incremented to
+ // make sure account has enough funds for block gas limit of gas
+ // we need to save original from account balance since it is printed in trace
+ void setOriginalFromBalance( const u256& _originalFromBalance );
[[nodiscard]] Json::Value getJSONResult() const;
[[nodiscard]] const std::shared_ptr< FunctionCallRecord >& getTopFunctionCall() const;
@@ -75,27 +83,27 @@ class AlethStandardTrace {
[[nodiscard]] const h256& getTxHash() const;
[[nodiscard]] const std::shared_ptr< Json::Value >& getDefaultOpTrace() const;
-
- void setCurrentlyExecutingFunctionCall(
- const std::shared_ptr< FunctionCallRecord >& _currentlyExecutingFunctionCall );
-
[[nodiscard]] const std::shared_ptr< FunctionCallRecord >& getCurrentlyExecutingFunctionCall()
const;
- void setTopFunctionCall( const std::shared_ptr< FunctionCallRecord >& _topFunctionCall );
-
[[nodiscard]] const Address& getBlockAuthor() const;
[[nodiscard]] const u256& getMinerPayment() const;
- void setOriginalFromBalance( const u256& _originalFromBalance );
-
[[nodiscard]] const u256& getOriginalFromBalance() const;
-
[[nodiscard]] bool isCall() const;
-
+ [[nodiscard]] const Address& getFrom() const;
+ [[nodiscard]] uint64_t getTotalGasUsed() const;
+ [[nodiscard]] const u256& getGasLimit() const;
+ [[nodiscard]] const u256& getValue() const;
+ [[nodiscard]] const bytes& getInputData() const;
+ [[nodiscard]] const Address& getTo() const;
static string toGethCompatibleCompactHexPrefixed( const u256& _value );
- const Address& getFrom() const;
+
private:
+ void setCurrentlyExecutingFunctionCall(
+ const std::shared_ptr< FunctionCallRecord >& _currentlyExecutingFunctionCall );
+ void setTopFunctionCall( const std::shared_ptr< FunctionCallRecord >& _topFunctionCall );
+
// this operator will be executed by skaled on each EVM instruction
void operator()( uint64_t _steps, uint64_t _pc, Instruction _inst, bigint _newMemSize,
bigint _gasOpGas, bigint _gasRemaining, VMFace const* _vm, ExtVMFace const* _voidExt );
@@ -152,6 +160,7 @@ class AlethStandardTrace {
// std::map of all storage addresses accessed (read or write) during execution
// for each storage address the current value if recorded
std::map< Address, std::map< dev::u256, dev::u256 > > m_accessedStorageValues;
+
OpExecutionRecord m_lastOpRecord;
std::atomic< bool > m_isFinalized = false;
NoopTracePrinter m_noopTracePrinter;
@@ -167,5 +176,18 @@ class AlethStandardTrace {
u256 m_minerPayment;
u256 m_originalFromBalance;
bool m_isCall;
+
+public:
+ const u256& getGasPrice() const;
+
+private:
+ uint64_t m_totalGasUsed;
+ u256 m_value;
+ u256 m_gasLimit;
+ bytes m_inputData;
+ u256 m_gasPrice;
+
+ void printTrace(
+ ExecutionResult& _er, const HistoricState& _statePre, const HistoricState& _statePost );
};
} // namespace dev::eth
diff --git a/libhistoric/CallTracePrinter.cpp b/libhistoric/CallTracePrinter.cpp
index 75f436a9a..7486b9f38 100644
--- a/libhistoric/CallTracePrinter.cpp
+++ b/libhistoric/CallTracePrinter.cpp
@@ -31,11 +31,41 @@ namespace dev::eth {
void CallTracePrinter::print(
Json::Value& _jsonTrace, const ExecutionResult&, const HistoricState&, const HistoricState& ) {
STATE_CHECK( _jsonTrace.isObject() )
- m_trace.getTopFunctionCall()->printTrace( _jsonTrace, 0, m_trace.getOptions() );
+
+ auto topFunctionCallRecord = m_trace.getTopFunctionCall();
+ if ( !topFunctionCallRecord ) {
+ // no bytecodes were executed
+ printTransferTrace( _jsonTrace );
+ } else {
+ topFunctionCallRecord->printTrace( _jsonTrace, 0, m_trace.getOptions() );
+ }
}
CallTracePrinter::CallTracePrinter( AlethStandardTrace& _standardTrace )
: TracePrinter( _standardTrace, "callTrace" ) {}
+
+
+void CallTracePrinter::printTransferTrace( Json::Value& _jsonTrace ) {
+ STATE_CHECK( _jsonTrace.isObject() )
+
+ _jsonTrace["type"] = "CALL";
+ _jsonTrace["from"] = toHexPrefixed( m_trace.getFrom() );
+ _jsonTrace["to"] = toHexPrefixed( m_trace.getTo() );
+
+ _jsonTrace["gas"] =
+ AlethStandardTrace::toGethCompatibleCompactHexPrefixed( m_trace.getGasLimit() );
+ _jsonTrace["gasUsed"] =
+ AlethStandardTrace::toGethCompatibleCompactHexPrefixed( m_trace.getTotalGasUsed() );
+
+
+ _jsonTrace["value"] =
+ AlethStandardTrace::toGethCompatibleCompactHexPrefixed( m_trace.getValue() );
+
+ _jsonTrace["input"] = toHexPrefixed( m_trace.getInputData() );
+}
+
+
} // namespace dev::eth
+
#endif
\ No newline at end of file
diff --git a/libhistoric/CallTracePrinter.h b/libhistoric/CallTracePrinter.h
index 83239c2bb..a12d29de9 100644
--- a/libhistoric/CallTracePrinter.h
+++ b/libhistoric/CallTracePrinter.h
@@ -36,5 +36,8 @@ class CallTracePrinter : public TracePrinter {
void print( Json::Value& _jsonTrace, const ExecutionResult&, const HistoricState&,
const HistoricState& ) override;
+
+private:
+ void printTransferTrace( Json::Value& _jsonTrace );
};
} // namespace dev::eth
diff --git a/libhistoric/DefaultTracePrinter.cpp b/libhistoric/DefaultTracePrinter.cpp
index 745e926bc..9cda7342b 100644
--- a/libhistoric/DefaultTracePrinter.cpp
+++ b/libhistoric/DefaultTracePrinter.cpp
@@ -34,7 +34,13 @@ void DefaultTracePrinter::print( Json::Value& _jsonTrace, const ExecutionResult&
_jsonTrace["gas"] = ( uint64_t ) _er.gasUsed;
auto defaultOpTrace = m_trace.getDefaultOpTrace();
STATE_CHECK( defaultOpTrace );
- _jsonTrace["structLogs"] = *defaultOpTrace;
+ if ( defaultOpTrace->empty() ) {
+ // make it compatible with geth in cases where
+ // no contract was called so there is no trace
+ _jsonTrace["structLogs"] = Json::Value( Json::arrayValue );
+ } else {
+ _jsonTrace["structLogs"] = *defaultOpTrace;
+ }
auto failed = _er.excepted != TransactionException::None;
_jsonTrace["failed"] = failed;
if ( !failed ) {
diff --git a/libhistoric/FourByteTracePrinter.cpp b/libhistoric/FourByteTracePrinter.cpp
index 165163e0e..b57dc8c03 100644
--- a/libhistoric/FourByteTracePrinter.cpp
+++ b/libhistoric/FourByteTracePrinter.cpp
@@ -33,7 +33,14 @@ void FourByteTracePrinter::print(
STATE_CHECK( _jsonTrace.isObject() )
std::map< string, uint64_t > callMap;
- m_trace.getTopFunctionCall()->collectFourByteTrace( callMap );
+ auto topFunctionCallRecord = m_trace.getTopFunctionCall();
+ if ( !topFunctionCallRecord ) {
+ // no bytecodes were executed, this was purely ETH transfer
+ // print nothing
+ return;
+ }
+
+ topFunctionCallRecord->collectFourByteTrace( callMap );
for ( auto&& key : callMap ) {
_jsonTrace[key.first] = key.second;
}
diff --git a/libhistoric/PrestateTracePrinter.cpp b/libhistoric/PrestateTracePrinter.cpp
index 92b6b057c..cf85a993d 100644
--- a/libhistoric/PrestateTracePrinter.cpp
+++ b/libhistoric/PrestateTracePrinter.cpp
@@ -32,28 +32,19 @@ void PrestateTracePrinter::print( Json::Value& _jsonTrace, const ExecutionResult
if ( m_trace.getOptions().prestateDiffMode ) {
printDiff( _jsonTrace, _er, _statePre, _statePost );
} else {
- printPre( _jsonTrace, _statePre );
+ printPre( _jsonTrace, _statePre, _statePost );
}
}
-void PrestateTracePrinter::printPre( Json::Value& _jsonTrace, const HistoricState& _statePre ) {
+void PrestateTracePrinter::printPre(
+ Json::Value& _jsonTrace, const HistoricState& _statePre, const HistoricState& _statePost ) {
for ( auto&& item : m_trace.getAccessedAccounts() ) {
- printAllAccessedAccountPreValues( _jsonTrace, _statePre, item );
+ printAllAccessedAccountPreValues( _jsonTrace, _statePre, _statePost, item );
};
+ // geth always prints the balance of block miner balance
- if ( !m_trace.isCall() )
- return;
-
- // when in call trace geth always prints the balance of block miner balance
-
- auto minerAddress = m_trace.getBlockAuthor();
- auto minerBalance = _statePre.balance( minerAddress );
-
- if ( minerAddress == m_trace.getFrom() ) {
- // take into account that for calls balance is modified in the state before execution
- minerBalance = m_trace.getOriginalFromBalance();
- }
-
+ Address minerAddress = m_trace.getBlockAuthor();
+ u256 minerBalance = getMinerBalancePre( _statePre );
_jsonTrace[toHexPrefixed( minerAddress )]["balance"] =
AlethStandardTrace::toGethCompatibleCompactHexPrefixed( minerBalance );
}
@@ -71,14 +62,34 @@ void PrestateTracePrinter::printDiff( Json::Value& _jsonTrace, const ExecutionRe
printAccountPostDiff( postDiff, _statePre, _statePost, item );
};
+
+ // now deal with miner balance change as a result of transaction
+ // geth always prints miner balance change when NOT in call
+ if ( !m_trace.isCall() ) {
+ printMinerBalanceChange( _statePre, preDiff, postDiff );
+ }
+
+ // we are done, complete the trace JSON
+
_jsonTrace["pre"] = preDiff;
_jsonTrace["post"] = postDiff;
}
+void PrestateTracePrinter::printMinerBalanceChange(
+ const HistoricState& _statePre, Json::Value& preDiff, Json::Value& postDiff ) const {
+ Address minerAddress = m_trace.getBlockAuthor();
+ u256 minerBalancePre = getMinerBalancePre( _statePre );
+ u256 minerBalancePost = getMinerBalancePost( _statePre );
+
+ preDiff[toHexPrefixed( minerAddress )]["balance"] =
+ AlethStandardTrace::toGethCompatibleCompactHexPrefixed( minerBalancePre );
+ postDiff[toHexPrefixed( minerAddress )]["balance"] =
+ AlethStandardTrace::toGethCompatibleCompactHexPrefixed( minerBalancePost );
+}
// this function returns original values (pre) to result
-void PrestateTracePrinter::printAllAccessedAccountPreValues(
- Json::Value& _jsonTrace, const HistoricState& _statePre, const Address& _address ) {
+void PrestateTracePrinter::printAllAccessedAccountPreValues( Json::Value& _jsonTrace,
+ const HistoricState& _statePre, const HistoricState& _statePost, const Address& _address ) {
STATE_CHECK( _jsonTrace.isObject() )
@@ -89,12 +100,22 @@ void PrestateTracePrinter::printAllAccessedAccountPreValues(
auto balance = _statePre.balance( _address );
+ // take into account that for calls balance is modified in the state before execution
if ( m_trace.isCall() && _address == m_trace.getFrom() ) {
- // take into account that for calls balance is modified in the state before execution
balance = m_trace.getOriginalFromBalance();
- } else {
- // geth does not print nonce for from address in debug_traceCall;
- accountPreValues["nonce"] = ( uint64_t ) _statePre.getNonce( _address );
+ }
+
+
+ // geth does not print nonce for from address in debug_traceCall;
+ bool dontPrintNonce = m_trace.isCall() && _address == m_trace.getFrom();
+
+ if ( !dontPrintNonce ) {
+ auto preNonce = ( uint64_t ) _statePre.getNonce( _address );
+ auto postNonce = ( uint64_t ) _statePost.getNonce( _address );
+ // in calls nonce is always printed by geth
+ if ( postNonce != preNonce || m_trace.isCall() ) {
+ accountPreValues["nonce"] = preNonce;
+ }
}
accountPreValues["balance"] = AlethStandardTrace::toGethCompatibleCompactHexPrefixed( balance );
@@ -276,6 +297,24 @@ PrestateTracePrinter::PrestateTracePrinter( AlethStandardTrace& standardTrace )
: TracePrinter( standardTrace, "prestateTrace" ) {}
+u256 PrestateTracePrinter::getMinerBalancePre( const HistoricState& _statePre ) const {
+ auto minerAddress = m_trace.getBlockAuthor();
+ auto minerBalance = _statePre.balance( minerAddress );
+
+ if ( m_trace.isCall() && minerAddress == m_trace.getFrom() ) {
+ // take into account that for calls balance is modified in the state before execution
+ minerBalance = m_trace.getOriginalFromBalance();
+ }
+
+ return minerBalance;
+}
+
+u256 PrestateTracePrinter::getMinerBalancePost( const HistoricState& _statePre ) const {
+ auto minerBalance =
+ getMinerBalancePre( _statePre ) + m_trace.getTotalGasUsed() * m_trace.getGasPrice();
+ return minerBalance;
+}
+
} // namespace dev::eth
#endif
\ No newline at end of file
diff --git a/libhistoric/PrestateTracePrinter.h b/libhistoric/PrestateTracePrinter.h
index e859b50ee..f9e8d9fed 100644
--- a/libhistoric/PrestateTracePrinter.h
+++ b/libhistoric/PrestateTracePrinter.h
@@ -38,12 +38,15 @@ class PrestateTracePrinter : public TracePrinter {
explicit PrestateTracePrinter( AlethStandardTrace& standardTrace );
+ [[nodiscard]] u256 getMinerBalancePre( const HistoricState& _statePre ) const;
+ [[nodiscard]] u256 getMinerBalancePost( const HistoricState& _statePre ) const;
+
private:
void printDiff( Json::Value& _jsonTrace, const ExecutionResult&, const HistoricState& _statePre,
const HistoricState& _statePost );
- void printAllAccessedAccountPreValues(
- Json::Value& _jsonTrace, const HistoricState& _statePre, const Address& _address );
+ void printAllAccessedAccountPreValues( Json::Value& _jsonTrace, const HistoricState& _statePre,
+ const HistoricState& _statePost, const Address& _address );
void printAccountPreDiff( Json::Value& _preDiffTrace, const HistoricState& _statePre,
const HistoricState& _statePost, const Address& _address );
@@ -54,6 +57,10 @@ class PrestateTracePrinter : public TracePrinter {
uint64_t m_storageValuesReturnedPre = 0;
uint64_t m_storageValuesReturnedPost = 0;
uint64_t m_storageValuesReturnedAll = 0;
- void printPre( Json::Value& _jsonTrace, const HistoricState& _statePre );
+ void printPre(
+ Json::Value& _jsonTrace, const HistoricState& _statePre, const HistoricState& _statePost );
+
+ void printMinerBalanceChange(
+ const HistoricState& _statePre, Json::Value& preDiff, Json::Value& postDiff ) const;
};
} // namespace dev::eth
diff --git a/libhistoric/ReplayTracePrinter.cpp b/libhistoric/ReplayTracePrinter.cpp
index 5d465ef56..f6d08f78d 100644
--- a/libhistoric/ReplayTracePrinter.cpp
+++ b/libhistoric/ReplayTracePrinter.cpp
@@ -45,7 +45,15 @@ void ReplayTracePrinter::print( Json::Value& _jsonTrace, const ExecutionResult&
Json::Value functionTraceArray( Json::arrayValue );
Json::Value emptyAddress( Json::arrayValue );
- m_trace.getTopFunctionCall()->printParityFunctionTrace( functionTraceArray, emptyAddress );
+ auto topFunctionCallRecord = m_trace.getTopFunctionCall();
+
+
+ // if topFunctionCallRecord is null
+ // it means that no bytecodes were executed, this was purely ETH transfer
+ // print nothing
+ if ( topFunctionCallRecord ) {
+ topFunctionCallRecord->printParityFunctionTrace( functionTraceArray, emptyAddress );
+ }
_jsonTrace["trace"] = functionTraceArray;
}
diff --git a/libhistoric/TraceOptions.h b/libhistoric/TraceOptions.h
index 51fa8923a..92e8c4d66 100644
--- a/libhistoric/TraceOptions.h
+++ b/libhistoric/TraceOptions.h
@@ -49,6 +49,7 @@ class TraceOptions {
[[nodiscard]] std::string toString() {
std::stringstream s;
+ s << ( uint64_t ) tracerType;
s << disableStorage;
s << enableMemory;
s << disableStack;
diff --git a/libhistoric/TracePrinter.h b/libhistoric/TracePrinter.h
index eb29ddd00..61047a183 100644
--- a/libhistoric/TracePrinter.h
+++ b/libhistoric/TracePrinter.h
@@ -35,7 +35,7 @@ class AlethStandardTrace;
class TracePrinter {
public:
- TracePrinter( AlethStandardTrace& mStandardTrace, const std::string jsonName );
+ TracePrinter( AlethStandardTrace& _standardTrace, const std::string jsonName );
virtual void print( Json::Value& _jsonTrace, const ExecutionResult&, const HistoricState&,
const HistoricState& ) = 0;
diff --git a/libweb3jsonrpc/Debug.cpp b/libweb3jsonrpc/Debug.cpp
index 4f7e97839..47128b129 100644
--- a/libweb3jsonrpc/Debug.cpp
+++ b/libweb3jsonrpc/Debug.cpp
@@ -23,6 +23,12 @@ using namespace dev::rpc;
using namespace dev::eth;
using namespace skale;
+
+#define THROW_TRACE_JSON_EXCEPTION( __MSG__ ) \
+ throw jsonrpc::JsonRpcException( std::string( __FUNCTION__ ) + ":" + \
+ std::to_string( __LINE__ ) + ":" + std::string( __MSG__ ) )
+
+
void Debug::checkPrivilegedAccess() const {
if ( !m_enablePrivilegedApis ) {
BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( "This API call is not enabled" ) );
@@ -52,7 +58,7 @@ h256 Debug::blockHash( string const& _blockNumberOrHash ) const {
try {
return m_eth.blockChain().numberHash( stoul( _blockNumberOrHash ) );
} catch ( ... ) {
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( "Invalid argument" ) );
+ THROW_TRACE_JSON_EXCEPTION( "Invalid argument" );
}
}
@@ -76,22 +82,22 @@ Json::Value Debug::debug_traceBlockByNumber( const string&
}
if ( !m_eth.isKnown( bN ) ) {
- BOOST_THROW_EXCEPTION(
- jsonrpc::JsonRpcException( "Unknown block number:" + _blockNumber ) );
+ THROW_TRACE_JSON_EXCEPTION( "Unknown block number:" + _blockNumber );
}
if ( bN == 0 ) {
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( "Block number must be more than zero" ) );
+ THROW_TRACE_JSON_EXCEPTION( "Block number must be more than zero" );
}
try {
return m_eth.traceBlock( bN, _jsonTraceConfig );
- } catch ( Exception const& _e ) {
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( _e.what() ) );
+ } catch ( std::exception const& _e ) {
+ THROW_TRACE_JSON_EXCEPTION( _e.what() );
+ } catch ( ... ) {
+ THROW_TRACE_JSON_EXCEPTION( "Unknown server error" );
}
#else
- BOOST_THROW_EXCEPTION(
- jsonrpc::JsonRpcException( "This API call is only supported on archive nodes" ) );
+ THROW_TRACE_JSON_EXCEPTION( "This API call is only supported on archive nodes" );
#endif
}
@@ -111,23 +117,24 @@ Json::Value Debug::debug_traceBlockByHash( string const&
h256 h = jsToFixed< 32 >( _blockHash );
if ( !m_eth.isKnown( h ) ) {
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( "Unknown block hash" ) );
+ THROW_TRACE_JSON_EXCEPTION( "Unknown block hash" + _blockHash );
}
BlockNumber bN = m_eth.numberFromHash( h );
if ( bN == 0 ) {
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( "Block number must be more than zero" ) );
+ THROW_TRACE_JSON_EXCEPTION( "Block number must be more than zero" );
}
try {
return m_eth.traceBlock( bN, _jsonTraceConfig );
- } catch ( Exception const& _e ) {
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( _e.what() ) );
+ } catch ( std::exception const& _e ) {
+ THROW_TRACE_JSON_EXCEPTION( _e.what() );
+ } catch ( ... ) {
+ THROW_TRACE_JSON_EXCEPTION( "Unknown server error" );
}
#else
- BOOST_THROW_EXCEPTION(
- jsonrpc::JsonRpcException( "This API call is only supported on archive nodes" ) );
+ THROW_TRACE_JSON_EXCEPTION( "This API call is only supported on archive nodes" );
#endif
}
@@ -150,23 +157,24 @@ Json::Value Debug::debug_traceTransaction( string const&
LocalisedTransaction localisedTransaction = m_eth.localisedTransaction( txHash );
if ( localisedTransaction.blockHash() == h256( 0 ) ) {
- BOOST_THROW_EXCEPTION(
- jsonrpc::JsonRpcException( "no committed transaction with this hash" ) );
+ THROW_TRACE_JSON_EXCEPTION(
+ "Can't find committed transaction with this hash:" + _txHashStr );
}
auto blockNumber = localisedTransaction.blockNumber();
+
if ( !m_eth.isKnown( blockNumber ) ) {
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( "Unknown block number" ) );
+ THROW_TRACE_JSON_EXCEPTION( "Unknown block number:" + to_string( blockNumber ) );
}
if ( blockNumber == 0 ) {
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( "Block number must be more than zero" ) );
+ THROW_TRACE_JSON_EXCEPTION( "Block number must be more than zero" );
}
-
try {
Json::Value tracedBlock;
+
tracedBlock = m_eth.traceBlock( blockNumber, _jsonTraceConfig );
STATE_CHECK( tracedBlock.isArray() )
STATE_CHECK( !tracedBlock.empty() )
@@ -188,10 +196,14 @@ Json::Value Debug::debug_traceTransaction( string const&
}
}
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( "No transaction in block" ) );
+ THROW_TRACE_JSON_EXCEPTION( "Transaction not found in block" );
- } catch ( Exception const& _e ) {
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( _e.what() ) );
+ } catch ( jsonrpc::JsonRpcException& ) {
+ throw;
+ } catch ( std::exception const& _e ) {
+ THROW_TRACE_JSON_EXCEPTION( _e.what() );
+ } catch ( ... ) {
+ THROW_TRACE_JSON_EXCEPTION( "Unknown server error" );
}
#else
BOOST_THROW_EXCEPTION(
@@ -228,21 +240,23 @@ Json::Value Debug::debug_traceCall( Json::Value const&
}
if ( !m_eth.isKnown( bN ) ) {
- BOOST_THROW_EXCEPTION(
- jsonrpc::JsonRpcException( "Unknown block number:" + _blockNumber ) );
+ THROW_TRACE_JSON_EXCEPTION( "Unknown block number:" + _blockNumber );
}
if ( bN == 0 ) {
- BOOST_THROW_EXCEPTION(
- jsonrpc::JsonRpcException( "Block number must be more than zero" ) );
+ THROW_TRACE_JSON_EXCEPTION( "Block number must be more than zero" );
}
TransactionSkeleton ts = toTransactionSkeleton( _call );
return m_eth.traceCall(
ts.from, ts.value, ts.to, ts.data, ts.gas, ts.gasPrice, bN, _jsonTraceConfig );
- } catch ( Exception const& _e ) {
- BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( _e.what() ) );
+ } catch ( jsonrpc::JsonRpcException& ) {
+ throw;
+ } catch ( std::exception const& _e ) {
+ THROW_TRACE_JSON_EXCEPTION( _e.what() );
+ } catch ( ... ) {
+ THROW_TRACE_JSON_EXCEPTION( "Unknown server error" );
}
#else
diff --git a/test/historicstate/configs/basic_config.json b/test/historicstate/configs/basic_config.json
index aa5915277..d34997231 100644
--- a/test/historicstate/configs/basic_config.json
+++ b/test/historicstate/configs/basic_config.json
@@ -326,6 +326,7 @@
"schainOwner": "0x907cd0881E50d359bb9Fd120B1A5A143b1C97De6",
"contractStorageLimit": 10000000000,
"emptyBlockIntervalMs": 10000,
+ "multiTransactionMode": true,
"nodes": [
{ "nodeID": 1112, "ip": "127.0.0.1", "basePort": 1231, "schainIndex" : 1, "publicKey":""}
]
diff --git a/test/historicstate/hardhat/scripts/geth_traces/Tracer.getBalance.prestateTracer.json b/test/historicstate/hardhat/scripts/geth_traces/Tracer.getBalance.prestateTracer.json
index 42700d1ff..d154d2087 100644
--- a/test/historicstate/hardhat/scripts/geth_traces/Tracer.getBalance.prestateTracer.json
+++ b/test/historicstate/hardhat/scripts/geth_traces/Tracer.getBalance.prestateTracer.json
@@ -1,6 +1,6 @@
{
"0x0000000000000000000000000000000000000000": {
- "balance": "0x1085583"
+ "balance": "0x439f07a"
},
"Tracer.address": {
"balance": "0x0",
diff --git a/test/historicstate/hardhat/scripts/geth_traces/Tracer.getBalance.replayTracer.json b/test/historicstate/hardhat/scripts/geth_traces/Tracer.getBalance.replayTracer.json
new file mode 100644
index 000000000..0c33b42dd
--- /dev/null
+++ b/test/historicstate/hardhat/scripts/geth_traces/Tracer.getBalance.replayTracer.json
@@ -0,0 +1,25 @@
+{
+ "output": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "stateDiff": null,
+ "trace": [
+ {
+ "action": {
+ "callType": "call",
+ "from": "CALL.address",
+ "gas": "0x0000000000000000000000000000000000000000000000000000000ffffface7",
+ "input": "0x12065fe0",
+ "to": "Tracer.address",
+ "value": "0x0000000000000000000000000000000000000000000000000000000000000000"
+ },
+ "result": {
+ "gasUsed": "0x000000000000000000000000000000000000000000000000000000000000551b",
+ "output": "0x0000000000000000000000000000000000000000000000000000000000000000"
+ },
+ "subtraces": 0,
+ "traceAddress": [],
+ "type": "call"
+ }
+ ],
+ "transactionHash": "0x58aa03e29bf344b31f0e65d3f28ce2d5cab1159795083ad942f1d57f42a5e6f2",
+ "vmTrace": null
+}
\ No newline at end of file
diff --git a/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.4byteTracer.json b/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.4byteTracer.json
new file mode 100644
index 000000000..9e26dfeeb
--- /dev/null
+++ b/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.4byteTracer.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.callTracer.json b/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.callTracer.json
new file mode 100644
index 000000000..bd28f6087
--- /dev/null
+++ b/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.callTracer.json
@@ -0,0 +1,9 @@
+{
+ "from": "0x907cd0881e50d359bb9fd120b1a5a143b1c97de6",
+ "gas": "0x5208",
+ "gasUsed": "0x5208",
+ "to": "0x388c818ca8b9251b393131c08a736a67ccb19297",
+ "input": "0x",
+ "value": "0x16345785d8a0000",
+ "type": "CALL"
+}
\ No newline at end of file
diff --git a/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.defaultTracer.json b/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.defaultTracer.json
new file mode 100644
index 000000000..9b0ab9d23
--- /dev/null
+++ b/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.defaultTracer.json
@@ -0,0 +1,6 @@
+{
+ "gas": 21000,
+ "failed": false,
+ "returnValue": "",
+ "structLogs": []
+}
\ No newline at end of file
diff --git a/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.prestateDiffTracer.json b/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.prestateDiffTracer.json
new file mode 100644
index 000000000..006f60d67
--- /dev/null
+++ b/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.prestateDiffTracer.json
@@ -0,0 +1,26 @@
+{
+ "post": {
+ "0x0000000000000000000000000000000000000000": {
+ "balance": "0x439f07a"
+ },
+ "0x388c818ca8b9251b393131c08a736a67ccb19297": {
+ "balance": "0x14d1120d7b160000"
+ },
+ "0x907cd0881e50d359bb9fd120b1a5a143b1c97de6": {
+ "balance": "0x35a999048b57805303",
+ "nonce": 359
+ }
+ },
+ "pre": {
+ "0x0000000000000000000000000000000000000000": {
+ "balance": "0x4399e72"
+ },
+ "0x388c818ca8b9251b393131c08a736a67ccb19297": {
+ "balance": "0x136dcc951d8c0000"
+ },
+ "0x907cd0881e50d359bb9fd120b1a5a143b1c97de6": {
+ "balance": "0x35aafc4a03b50d354b",
+ "nonce": 358
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.prestateTracer.json b/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.prestateTracer.json
new file mode 100644
index 000000000..0749f6dab
--- /dev/null
+++ b/test/historicstate/hardhat/scripts/geth_traces/Tracer.transfer.prestateTracer.json
@@ -0,0 +1,12 @@
+{
+ "0x0000000000000000000000000000000000000000": {
+ "balance": "0x4399e72"
+ },
+ "0x388c818ca8b9251b393131c08a736a67ccb19297": {
+ "balance": "0x136dcc951d8c0000"
+ },
+ "0x907cd0881e50d359bb9fd120b1a5a143b1c97de6": {
+ "balance": "0x35aafc4a03b50d354b",
+ "nonce": 358
+ }
+}
\ No newline at end of file
diff --git a/test/historicstate/hardhat/scripts/trace.ts b/test/historicstate/hardhat/scripts/trace.ts
index a443bef56..b4a8cc4a6 100644
--- a/test/historicstate/hardhat/scripts/trace.ts
+++ b/test/historicstate/hardhat/scripts/trace.ts
@@ -6,6 +6,7 @@ import deepDiff, {diff} from 'deep-diff';
import {expect} from "chai";
import * as path from 'path';
import {int, string} from "hardhat/internal/core/params/argumentTypes";
+import internal from "node:stream";
const OWNER_ADDRESS: string = "0x907cd0881E50d359bb9Fd120B1A5A143b1C97De6";
const CALL_ADDRESS: string = "0xCe5c7ca85F8cB94FA284a303348ef42ADD23f5e7";
@@ -23,7 +24,7 @@ let DEFAULT_TRACER = "defaultTracer";
let CALL_TRACER = "callTracer";
let PRESTATE_TRACER = "prestateTracer";
let PRESTATEDIFF_TRACER = "prestateDiffTracer";
-let FOUR_BYTE_TRACER = "4byteTracer";
+let FOURBYTE_TRACER = "4byteTracer";
let REPLAY_TRACER = "replayTracer"
@@ -41,6 +42,13 @@ async function getTraceJsonOptions(_tracer: string): Promise