diff --git a/libweb3jsonrpc/CMakeLists.txt b/libweb3jsonrpc/CMakeLists.txt index b1b50a770..00a748f89 100644 --- a/libweb3jsonrpc/CMakeLists.txt +++ b/libweb3jsonrpc/CMakeLists.txt @@ -36,6 +36,10 @@ set(sources Web3Face.h WhisperFace.h + Tracing.h + Tracing.cpp + TracingFace.h + SkalePerformanceTracker.h SkalePerformanceTracker.cpp SkalePerformanceTrackerFace.h diff --git a/libweb3jsonrpc/Debug.cpp b/libweb3jsonrpc/Debug.cpp index dc7de9e52..10d01f4a3 100644 --- a/libweb3jsonrpc/Debug.cpp +++ b/libweb3jsonrpc/Debug.cpp @@ -26,246 +26,8 @@ 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" ) ); - } -} - -void Debug::checkHistoricStateEnabled() const { -#ifndef HISTORIC_STATE - BOOST_THROW_EXCEPTION( - jsonrpc::JsonRpcException( "This API call is available on archive nodes only" ) ); -#endif -} - -Debug::Debug( eth::Client& _eth, SkaleDebugInterface* _debugInterface, const string& argv, - bool _enablePrivilegedApis ) - : m_eth( _eth ), - m_debugInterface( _debugInterface ), - m_argvOptions( argv ), - m_blockTraceCache( MAX_BLOCK_TRACES_CACHE_ITEMS, MAX_BLOCK_TRACES_CACHE_SIZE ), - m_enablePrivilegedApis( _enablePrivilegedApis ) {} - - -h256 Debug::blockHash( string const& _blockNumberOrHash ) const { - checkPrivilegedAccess(); - if ( isHash< h256 >( _blockNumberOrHash ) ) - return h256( _blockNumberOrHash.substr( _blockNumberOrHash.size() - 64, 64 ) ); - try { - return m_eth.blockChain().numberHash( stoul( _blockNumberOrHash ) ); - } catch ( ... ) { - THROW_TRACE_JSON_EXCEPTION( "Invalid argument" ); - } -} - -Json::Value Debug::debug_traceBlockByNumber( const string& -#ifdef HISTORIC_STATE - _blockNumber -#endif - , - Json::Value const& -#ifdef HISTORIC_STATE - _jsonTraceConfig -#endif -) { - Json::Value ret; - checkHistoricStateEnabled(); -#ifdef HISTORIC_STATE - auto bN = jsToBlockNumber( _blockNumber ); - - if ( bN == LatestBlock || bN == PendingBlock ) { - bN = m_eth.number(); - } - - if ( !m_eth.isKnown( bN ) ) { - THROW_TRACE_JSON_EXCEPTION( "Unknown block number:" + _blockNumber ); - } - - if ( bN == 0 ) { - THROW_TRACE_JSON_EXCEPTION( "Block number must be more than zero" ); - } - - try { - return m_eth.traceBlock( bN, _jsonTraceConfig ); - } catch ( std::exception const& _e ) { - THROW_TRACE_JSON_EXCEPTION( _e.what() ); - } catch ( ... ) { - THROW_TRACE_JSON_EXCEPTION( "Unknown server error" ); - } -#else - THROW_TRACE_JSON_EXCEPTION( "This API call is only supported on archive nodes" ); -#endif -} - -Json::Value Debug::debug_traceBlockByHash( string const& -#ifdef HISTORIC_STATE - _blockHash -#endif - , - Json::Value const& -#ifdef HISTORIC_STATE - _jsonTraceConfig -#endif -) { - checkHistoricStateEnabled(); - -#ifdef HISTORIC_STATE - h256 h = jsToFixed< 32 >( _blockHash ); - - if ( !m_eth.isKnown( h ) ) { - THROW_TRACE_JSON_EXCEPTION( "Unknown block hash" + _blockHash ); - } - - BlockNumber bN = m_eth.numberFromHash( h ); - - if ( bN == 0 ) { - THROW_TRACE_JSON_EXCEPTION( "Block number must be more than zero" ); - } - - try { - return m_eth.traceBlock( bN, _jsonTraceConfig ); - } catch ( std::exception const& _e ) { - THROW_TRACE_JSON_EXCEPTION( _e.what() ); - } catch ( ... ) { - THROW_TRACE_JSON_EXCEPTION( "Unknown server error" ); - } -#else - THROW_TRACE_JSON_EXCEPTION( "This API call is only supported on archive nodes" ); -#endif -} - - -Json::Value Debug::debug_traceTransaction( string const& -#ifdef HISTORIC_STATE - _txHashStr -#endif - , - Json::Value const& -#ifdef HISTORIC_STATE - _jsonTraceConfig -#endif -) { - - checkHistoricStateEnabled(); -#ifdef HISTORIC_STATE - auto txHash = h256( _txHashStr ); - - LocalisedTransaction localisedTransaction = m_eth.localisedTransaction( txHash ); - - if ( localisedTransaction.blockHash() == h256( 0 ) ) { - THROW_TRACE_JSON_EXCEPTION( - "Can't find committed transaction with this hash:" + _txHashStr ); - } - - auto blockNumber = localisedTransaction.blockNumber(); - - - if ( !m_eth.isKnown( blockNumber ) ) { - THROW_TRACE_JSON_EXCEPTION( "Unknown block number:" + to_string( blockNumber ) ); - } - - if ( blockNumber == 0 ) { - 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() ) - - - string lowerCaseTxStr = _txHashStr; - for ( auto& c : lowerCaseTxStr ) { - c = std::tolower( static_cast< unsigned char >( c ) ); - } - - - for ( Json::Value::ArrayIndex i = 0; i < tracedBlock.size(); i++ ) { - Json::Value& transactionTrace = tracedBlock[i]; - STATE_CHECK( transactionTrace.isObject() ); - STATE_CHECK( transactionTrace.isMember( "txHash" ) ); - if ( transactionTrace["txHash"] == lowerCaseTxStr ) { - STATE_CHECK( transactionTrace.isMember( "result" ) ); - return transactionTrace["result"]; - } - } - - THROW_TRACE_JSON_EXCEPTION( "Transaction not found in block" ); - - } 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( - jsonrpc::JsonRpcException( "This API call is only supported on archive nodes" ) ); -#endif -} - -Json::Value Debug::debug_traceCall( Json::Value const& -#ifdef HISTORIC_STATE - _call -#endif - , - std::string const& -#ifdef HISTORIC_STATE - _blockNumber -#endif - , - Json::Value const& -#ifdef HISTORIC_STATE - _jsonTraceConfig -#endif -) { - - Json::Value ret; - checkHistoricStateEnabled(); - -#ifdef HISTORIC_STATE - - try { - auto bN = jsToBlockNumber( _blockNumber ); - - if ( bN == LatestBlock || bN == PendingBlock ) { - bN = m_eth.number(); - } - - if ( !m_eth.isKnown( bN ) ) { - THROW_TRACE_JSON_EXCEPTION( "Unknown block number:" + _blockNumber ); - } - - if ( bN == 0 ) { - 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 ( 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( - jsonrpc::JsonRpcException( "This API call is only supported on archive nodes" ) ); -#endif -} +Debug::Debug( eth::Client& _eth, SkaleDebugInterface* _debugInterface, const string& argv ) + : m_eth( _eth ), m_debugInterface( _debugInterface ), m_argvOptions( argv ) {} Json::Value Debug::debug_accountRangeAt( string const&, int, string const&, int ) { @@ -280,22 +42,17 @@ string Debug::debug_preimage( string const& ) { BOOST_THROW_EXCEPTION( jsonrpc::JsonRpcException( "This API call is not supported" ) ); } - void Debug::debug_pauseBroadcast( bool _pause ) { - checkPrivilegedAccess(); m_eth.skaleHost()->pauseBroadcast( _pause ); } void Debug::debug_pauseConsensus( bool _pause ) { - checkPrivilegedAccess(); m_eth.skaleHost()->pauseConsensus( _pause ); } void Debug::debug_forceBlock() { - checkPrivilegedAccess(); m_eth.skaleHost()->forceEmptyBlock(); } void Debug::debug_forceBroadcast( const string& _transactionHash ) { - checkPrivilegedAccess(); try { h256 h = jsToFixed< 32 >( _transactionHash ); if ( !m_eth.isKnownTransaction( h ) ) @@ -311,32 +68,26 @@ void Debug::debug_forceBroadcast( const string& _transactionHash ) { } string Debug::debug_interfaceCall( const string& _arg ) { - checkPrivilegedAccess(); return m_debugInterface->call( _arg ); } string Debug::debug_getVersion() { - checkPrivilegedAccess(); return Version; } string Debug::debug_getArguments() { - checkPrivilegedAccess(); return m_argvOptions; } string Debug::debug_getConfig() { - checkPrivilegedAccess(); return m_eth.chainParams().getOriginalJson(); } string Debug::debug_getSchainName() { - checkPrivilegedAccess(); return m_eth.chainParams().sChain.name; } uint64_t Debug::debug_getSnapshotCalculationTime() { - checkPrivilegedAccess(); return m_eth.getSnapshotCalculationTime(); } @@ -345,7 +96,6 @@ uint64_t Debug::debug_getSnapshotHashCalculationTime() { } uint64_t Debug::debug_doStateDbCompaction() { - checkPrivilegedAccess(); auto t1 = boost::chrono::high_resolution_clock::now(); m_eth.doStateDbCompaction(); auto t2 = boost::chrono::high_resolution_clock::now(); @@ -354,7 +104,6 @@ uint64_t Debug::debug_doStateDbCompaction() { } uint64_t Debug::debug_doBlocksDbCompaction() { - checkPrivilegedAccess(); auto t1 = boost::chrono::high_resolution_clock::now(); m_eth.doBlocksDbCompaction(); auto t2 = boost::chrono::high_resolution_clock::now(); diff --git a/libweb3jsonrpc/Debug.h b/libweb3jsonrpc/Debug.h index 63c88405a..bc94d38d7 100644 --- a/libweb3jsonrpc/Debug.h +++ b/libweb3jsonrpc/Debug.h @@ -19,13 +19,10 @@ class Client; namespace rpc { class SessionManager; -constexpr size_t MAX_BLOCK_TRACES_CACHE_SIZE = 64 * 1024 * 1024; -constexpr size_t MAX_BLOCK_TRACES_CACHE_ITEMS = 1024 * 1024; - class Debug : public DebugFace { public: explicit Debug( eth::Client& _eth, SkaleDebugInterface* _debugInterface = nullptr, - const std::string& argv = std::string(), bool _enablePrivilegedApis = false ); + const std::string& argv = std::string() ); virtual RPCModules implementedModules() const override { return RPCModules{ RPCModule{ "debug", "1.0" } }; @@ -33,14 +30,6 @@ class Debug : public DebugFace { virtual Json::Value debug_accountRangeAt( std::string const& _blockHashOrNumber, int _txIndex, std::string const& _addressHash, int _maxResults ) override; - virtual Json::Value debug_traceTransaction( - std::string const& _txHash, Json::Value const& _json ) override; - virtual Json::Value debug_traceCall( Json::Value const& _call, std::string const& _blockNumber, - Json::Value const& _options ) override; - virtual Json::Value debug_traceBlockByNumber( - std::string const& _blockNumber, Json::Value const& _json ) override; - virtual Json::Value debug_traceBlockByHash( - std::string const& _blockHash, Json::Value const& _json ) override; virtual Json::Value debug_storageRangeAt( std::string const& _blockHashOrNumber, int _txIndex, std::string const& _address, std::string const& _begin, int _maxResults ) override; virtual std::string debug_preimage( std::string const& _hashedKey ) override; @@ -68,15 +57,6 @@ class Debug : public DebugFace { eth::Client& m_eth; SkaleDebugInterface* m_debugInterface = nullptr; std::string m_argvOptions; - cache::lru_ordered_memory_constrained_cache< std::string, Json::Value > m_blockTraceCache; - bool m_enablePrivilegedApis; - - - h256 blockHash( std::string const& _blockHashOrNumber ) const; - - void checkPrivilegedAccess() const; - - void checkHistoricStateEnabled() const; }; } // namespace rpc diff --git a/libweb3jsonrpc/DebugFace.h b/libweb3jsonrpc/DebugFace.h index cfee3b7cb..6c57c383c 100644 --- a/libweb3jsonrpc/DebugFace.h +++ b/libweb3jsonrpc/DebugFace.h @@ -19,10 +19,6 @@ class DebugFace : public ServerInterface< DebugFace > { jsonrpc::JSON_STRING, "param4", jsonrpc::JSON_INTEGER, NULL ), &dev::rpc::DebugFace::debug_accountRangeAtI ); - - this->bindAndAddMethod( jsonrpc::Procedure( "debug_traceTransaction", - jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, NULL ), - &dev::rpc::DebugFace::debug_traceTransactionI ); this->bindAndAddMethod( jsonrpc::Procedure( "debug_storageRangeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1", jsonrpc::JSON_STRING, "param2", @@ -32,16 +28,6 @@ class DebugFace : public ServerInterface< DebugFace > { this->bindAndAddMethod( jsonrpc::Procedure( "debug_preimage", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1", jsonrpc::JSON_STRING, NULL ), &dev::rpc::DebugFace::debug_preimageI ); - this->bindAndAddMethod( jsonrpc::Procedure( "debug_traceBlockByNumber", - jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, NULL ), - &dev::rpc::DebugFace::debug_traceBlockByNumberI ); - this->bindAndAddMethod( jsonrpc::Procedure( "debug_traceBlockByHash", - jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, NULL ), - &dev::rpc::DebugFace::debug_traceBlockByHashI ); - this->bindAndAddMethod( jsonrpc::Procedure( "debug_traceCall", jsonrpc::PARAMS_BY_POSITION, - jsonrpc::JSON_OBJECT, "param1", jsonrpc::JSON_OBJECT, "param2", - jsonrpc::JSON_STRING, "param3", jsonrpc::JSON_OBJECT, NULL ), - &dev::rpc::DebugFace::debug_traceCallI ); this->bindAndAddMethod( jsonrpc::Procedure( "debug_pauseConsensus", jsonrpc::PARAMS_BY_POSITION, @@ -108,24 +94,6 @@ class DebugFace : public ServerInterface< DebugFace > { request[2u].asString(), request[3u].asInt() ); } - inline virtual Json::Value getTracer( const Json::Value& request ) { - if ( !request.isArray() || request.empty() || request.size() > 2 ) { - BOOST_THROW_EXCEPTION( - jsonrpc::JsonRpcException( jsonrpc::Errors::ERROR_RPC_INVALID_PARAMS ) ); - } - if ( request.size() == 2 ) { - if ( !request[1u].isObject() ) { - BOOST_THROW_EXCEPTION( - jsonrpc::JsonRpcException( jsonrpc::Errors::ERROR_RPC_INVALID_PARAMS ) ); - } - return request[1u]; - - } else { - return { Json::objectValue }; - } - } - - inline virtual void debug_storageRangeAtI( const Json::Value& request, Json::Value& response ) { response = this->debug_storageRangeAt( request[0u].asString(), request[1u].asInt(), request[2u].asString(), request[3u].asString(), request[4u].asInt() ); @@ -134,23 +102,6 @@ class DebugFace : public ServerInterface< DebugFace > { response = this->debug_preimage( request[0u].asString() ); } - inline virtual void debug_traceTransactionI( - const Json::Value& request, Json::Value& response ) { - response = this->debug_traceTransaction( request[0u].asString(), getTracer( request ) ); - } - - inline virtual void debug_traceBlockByNumberI( - const Json::Value& request, Json::Value& response ) { - response = this->debug_traceBlockByNumber( request[0u].asString(), getTracer( request ) ); - } - inline virtual void debug_traceBlockByHashI( - const Json::Value& request, Json::Value& response ) { - response = this->debug_traceBlockByHash( request[0u].asString(), getTracer( request ) ); - } - inline virtual void debug_traceCallI( const Json::Value& request, Json::Value& response ) { - response = this->debug_traceCall( request[0u], request[1u].asString(), request[2u] ); - } - virtual void debug_pauseBroadcastI( const Json::Value& request, Json::Value& response ) { this->debug_pauseBroadcast( request[0u].asBool() ); response = true; // TODO make void @@ -210,17 +161,9 @@ class DebugFace : public ServerInterface< DebugFace > { virtual Json::Value debug_accountRangeAt( const std::string& param1, int param2, const std::string& param3, int param4 ) = 0; - virtual Json::Value debug_traceTransaction( - const std::string& param1, const Json::Value& param2 ) = 0; virtual Json::Value debug_storageRangeAt( const std::string& param1, int param2, const std::string& param3, const std::string& param4, int param5 ) = 0; virtual std::string debug_preimage( const std::string& param1 ) = 0; - virtual Json::Value debug_traceBlockByNumber( - const std::string& param1, const Json::Value& param2 ) = 0; - virtual Json::Value debug_traceBlockByHash( - const std::string& param1, const Json::Value& param2 ) = 0; - virtual Json::Value debug_traceCall( Json::Value const& _call, std::string const& _blockNumber, - Json::Value const& _options ) = 0; virtual void debug_pauseBroadcast( bool pause ) = 0; virtual void debug_pauseConsensus( bool pause ) = 0; virtual void debug_forceBlock() = 0; diff --git a/libweb3jsonrpc/Tracing.cpp b/libweb3jsonrpc/Tracing.cpp new file mode 100644 index 000000000..59f924760 --- /dev/null +++ b/libweb3jsonrpc/Tracing.cpp @@ -0,0 +1,246 @@ +#include "Tracing.h" + +#include +#include +#include + +#ifdef HISTORIC_STATE + +#include +#include +#endif + +using namespace std; +using namespace dev; +using namespace dev::rpc; +using namespace dev::eth; + + +#define THROW_TRACE_JSON_EXCEPTION( __MSG__ ) \ + throw jsonrpc::JsonRpcException( std::string( __FUNCTION__ ) + ":" + \ + std::to_string( __LINE__ ) + ":" + std::string( __MSG__ ) ) + +void Tracing::checkHistoricStateEnabled() const { +#ifndef HISTORIC_STATE + BOOST_THROW_EXCEPTION( + jsonrpc::JsonRpcException( "This API call is available on archive nodes only" ) ); +#endif +} + +Tracing::Tracing( eth::Client& _eth, const string& argv ) + : m_eth( _eth ), + m_argvOptions( argv ), + m_blockTraceCache( MAX_BLOCK_TRACES_CACHE_ITEMS, MAX_BLOCK_TRACES_CACHE_SIZE ) {} + +h256 Tracing::blockHash( string const& _blockNumberOrHash ) const { + if ( isHash< h256 >( _blockNumberOrHash ) ) + return h256( _blockNumberOrHash.substr( _blockNumberOrHash.size() - 64, 64 ) ); + try { + return m_eth.blockChain().numberHash( stoul( _blockNumberOrHash ) ); + } catch ( ... ) { + THROW_TRACE_JSON_EXCEPTION( "Invalid argument" ); + } +} + +Json::Value Tracing::tracing_traceBlockByNumber( const string& +#ifdef HISTORIC_STATE + _blockNumber +#endif + , + Json::Value const& +#ifdef HISTORIC_STATE + _jsonTraceConfig +#endif +) { + Json::Value ret; + checkHistoricStateEnabled(); +#ifdef HISTORIC_STATE + auto bN = jsToBlockNumber( _blockNumber ); + + if ( bN == LatestBlock || bN == PendingBlock ) { + bN = m_eth.number(); + } + + if ( !m_eth.isKnown( bN ) ) { + THROW_TRACE_JSON_EXCEPTION( "Unknown block number:" + _blockNumber ); + } + + if ( bN == 0 ) { + THROW_TRACE_JSON_EXCEPTION( "Block number must be more than zero" ); + } + + try { + return m_eth.traceBlock( bN, _jsonTraceConfig ); + } catch ( std::exception const& _e ) { + THROW_TRACE_JSON_EXCEPTION( _e.what() ); + } catch ( ... ) { + THROW_TRACE_JSON_EXCEPTION( "Unknown server error" ); + } +#else + THROW_TRACE_JSON_EXCEPTION( "This API call is only supported on archive nodes" ); +#endif +} + +Json::Value Tracing::tracing_traceBlockByHash( string const& +#ifdef HISTORIC_STATE + _blockHash +#endif + , + Json::Value const& +#ifdef HISTORIC_STATE + _jsonTraceConfig +#endif +) { + checkHistoricStateEnabled(); + +#ifdef HISTORIC_STATE + h256 h = jsToFixed< 32 >( _blockHash ); + + if ( !m_eth.isKnown( h ) ) { + THROW_TRACE_JSON_EXCEPTION( "Unknown block hash" + _blockHash ); + } + + BlockNumber bN = m_eth.numberFromHash( h ); + + if ( bN == 0 ) { + THROW_TRACE_JSON_EXCEPTION( "Block number must be more than zero" ); + } + + try { + return m_eth.traceBlock( bN, _jsonTraceConfig ); + } catch ( std::exception const& _e ) { + THROW_TRACE_JSON_EXCEPTION( _e.what() ); + } catch ( ... ) { + THROW_TRACE_JSON_EXCEPTION( "Unknown server error" ); + } +#else + THROW_TRACE_JSON_EXCEPTION( "This API call is only supported on archive nodes" ); +#endif +} + + +Json::Value Tracing::tracing_traceTransaction( string const& +#ifdef HISTORIC_STATE + _txHashStr +#endif + , + Json::Value const& +#ifdef HISTORIC_STATE + _jsonTraceConfig +#endif +) { + + checkHistoricStateEnabled(); +#ifdef HISTORIC_STATE + auto txHash = h256( _txHashStr ); + + LocalisedTransaction localisedTransaction = m_eth.localisedTransaction( txHash ); + + if ( localisedTransaction.blockHash() == h256( 0 ) ) { + THROW_TRACE_JSON_EXCEPTION( + "Can't find committed transaction with this hash:" + _txHashStr ); + } + + auto blockNumber = localisedTransaction.blockNumber(); + + + if ( !m_eth.isKnown( blockNumber ) ) { + THROW_TRACE_JSON_EXCEPTION( "Unknown block number:" + to_string( blockNumber ) ); + } + + if ( blockNumber == 0 ) { + 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() ) + + + string lowerCaseTxStr = _txHashStr; + for ( auto& c : lowerCaseTxStr ) { + c = std::tolower( static_cast< unsigned char >( c ) ); + } + + + for ( Json::Value::ArrayIndex i = 0; i < tracedBlock.size(); i++ ) { + Json::Value& transactionTrace = tracedBlock[i]; + STATE_CHECK( transactionTrace.isObject() ); + STATE_CHECK( transactionTrace.isMember( "txHash" ) ); + if ( transactionTrace["txHash"] == lowerCaseTxStr ) { + STATE_CHECK( transactionTrace.isMember( "result" ) ); + return transactionTrace["result"]; + } + } + + THROW_TRACE_JSON_EXCEPTION( "Transaction not found in block" ); + + } 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( + jsonrpc::JsonRpcException( "This API call is only supported on archive nodes" ) ); +#endif +} + +Json::Value Tracing::tracing_traceCall( Json::Value const& +#ifdef HISTORIC_STATE + _call +#endif + , + std::string const& +#ifdef HISTORIC_STATE + _blockNumber +#endif + , + Json::Value const& +#ifdef HISTORIC_STATE + _jsonTraceConfig +#endif +) { + + Json::Value ret; + checkHistoricStateEnabled(); + +#ifdef HISTORIC_STATE + + try { + auto bN = jsToBlockNumber( _blockNumber ); + + if ( bN == LatestBlock || bN == PendingBlock ) { + bN = m_eth.number(); + } + + if ( !m_eth.isKnown( bN ) ) { + THROW_TRACE_JSON_EXCEPTION( "Unknown block number:" + _blockNumber ); + } + + if ( bN == 0 ) { + 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 ( 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( + jsonrpc::JsonRpcException( "This API call is only supported on archive nodes" ) ); +#endif +} diff --git a/libweb3jsonrpc/Tracing.h b/libweb3jsonrpc/Tracing.h new file mode 100644 index 000000000..73b262187 --- /dev/null +++ b/libweb3jsonrpc/Tracing.h @@ -0,0 +1,60 @@ +#ifndef TRACING_H +#define TRACING_H + +#include "TracingFace.h" +#include "test/tools/libtestutils/FixedClient.h" + +#include +#include +#include +#include + +class SkaleHost; +class SkaleDebugInterface; + +namespace dev { +namespace eth { +class Client; + +} // namespace eth +namespace rpc { +class SessionManager; + +constexpr size_t MAX_BLOCK_TRACES_CACHE_SIZE = 64 * 1024 * 1024; +constexpr size_t MAX_BLOCK_TRACES_CACHE_ITEMS = 1024 * 1024; + +class Tracing : public TracingFace { +public: + explicit Tracing( eth::Client& _eth, const std::string& argv = std::string() ); + + virtual RPCModules implementedModules() const override { + return RPCModules{ RPCModule{ "debug", "1.0" } }; + } + + virtual Json::Value tracing_traceTransaction( + std::string const& _txHash, Json::Value const& _json ) override; + virtual Json::Value tracing_traceCall( Json::Value const& _call, + std::string const& _blockNumber, Json::Value const& _options ) override; + virtual Json::Value tracing_traceBlockByNumber( + std::string const& _blockNumber, Json::Value const& _json ) override; + virtual Json::Value tracing_traceBlockByHash( + std::string const& _blockHash, Json::Value const& _json ) override; + +private: + eth::Client& m_eth; + std::string m_argvOptions; + cache::lru_ordered_memory_constrained_cache< std::string, Json::Value > m_blockTraceCache; + bool m_enablePrivilegedApis; + + h256 blockHash( std::string const& _blockHashOrNumber ) const; + + void checkPrivilegedAccess() const; + + void checkHistoricStateEnabled() const; +}; + +} // namespace rpc +} // namespace dev + + +#endif // TRACING_H diff --git a/libweb3jsonrpc/TracingFace.h b/libweb3jsonrpc/TracingFace.h new file mode 100644 index 000000000..a4296ec21 --- /dev/null +++ b/libweb3jsonrpc/TracingFace.h @@ -0,0 +1,75 @@ +#ifndef TRACINGFACE_H +#define TRACINGFACE_H + +#include "ModularServer.h" +#include "boost/throw_exception.hpp" + +namespace dev { +namespace rpc { +class TracingFace : public ServerInterface< TracingFace > { +public: + TracingFace() { + this->bindAndAddMethod( jsonrpc::Procedure( "debug_traceTransaction", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, NULL ), + &dev::rpc::TracingFace::tracing_traceTransactionI ); + this->bindAndAddMethod( jsonrpc::Procedure( "debug_traceBlockByNumber", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, NULL ), + &dev::rpc::TracingFace::tracing_traceBlockByNumberI ); + this->bindAndAddMethod( jsonrpc::Procedure( "debug_traceBlockByHash", + jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, NULL ), + &dev::rpc::TracingFace::tracing_traceBlockByHashI ); + this->bindAndAddMethod( jsonrpc::Procedure( "debug_traceCall", jsonrpc::PARAMS_BY_POSITION, + jsonrpc::JSON_OBJECT, "param1", jsonrpc::JSON_OBJECT, "param2", + jsonrpc::JSON_STRING, "param3", jsonrpc::JSON_OBJECT, NULL ), + &dev::rpc::TracingFace::tracing_traceCallI ); + } + + inline virtual Json::Value getTracer( const Json::Value& request ) { + if ( !request.isArray() || request.empty() || request.size() > 2 ) { + BOOST_THROW_EXCEPTION( + jsonrpc::JsonRpcException( jsonrpc::Errors::ERROR_RPC_INVALID_PARAMS ) ); + } + if ( request.size() == 2 ) { + if ( !request[1u].isObject() ) { + BOOST_THROW_EXCEPTION( + jsonrpc::JsonRpcException( jsonrpc::Errors::ERROR_RPC_INVALID_PARAMS ) ); + } + return request[1u]; + + } else { + return { Json::objectValue }; + } + } + + inline virtual void tracing_traceTransactionI( + const Json::Value& request, Json::Value& response ) { + response = this->tracing_traceTransaction( request[0u].asString(), getTracer( request ) ); + } + + inline virtual void tracing_traceBlockByNumberI( + const Json::Value& request, Json::Value& response ) { + response = this->tracing_traceBlockByNumber( request[0u].asString(), getTracer( request ) ); + } + inline virtual void tracing_traceBlockByHashI( + const Json::Value& request, Json::Value& response ) { + response = this->tracing_traceBlockByHash( request[0u].asString(), getTracer( request ) ); + } + inline virtual void tracing_traceCallI( const Json::Value& request, Json::Value& response ) { + response = this->tracing_traceCall( request[0u], request[1u].asString(), request[2u] ); + } + + virtual Json::Value tracing_traceTransaction( + const std::string& param1, const Json::Value& param2 ) = 0; + virtual Json::Value tracing_traceBlockByNumber( + const std::string& param1, const Json::Value& param2 ) = 0; + virtual Json::Value tracing_traceBlockByHash( + const std::string& param1, const Json::Value& param2 ) = 0; + virtual Json::Value tracing_traceCall( Json::Value const& _call, + std::string const& _blockNumber, Json::Value const& _options ) = 0; +}; + +} // namespace rpc +} // namespace dev + + +#endif // TRACINGFACE_H diff --git a/skaled/main.cpp b/skaled/main.cpp index 9382c6dda..015f81eac 100644 --- a/skaled/main.cpp +++ b/skaled/main.cpp @@ -75,6 +75,7 @@ #include #include #include +#include #include #include @@ -1943,7 +1944,7 @@ int main( int argc, char** argv ) try { rpc::SkaleStats, /// skaleStats rpc::NetFace, rpc::Web3Face, rpc::PersonalFace, rpc::AdminEthFace, // SKALE rpc::AdminNetFace, - rpc::DebugFace, rpc::SkalePerformanceTracker, rpc::TestFace >; + rpc::DebugFace, rpc::SkalePerformanceTracker, rpc::TracingFace, rpc::TestFace >; sessionManager.reset( new rpc::SessionManager() ); accountHolder.reset( new SimpleAccountHolder( @@ -1980,16 +1981,16 @@ int main( int argc, char** argv ) try { auto pAdminEthFace = bEnabledAPIs_admin ? new rpc::AdminEth( *g_client, *gasPricer.get(), keyManager, *sessionManager.get() ) : nullptr; -#ifdef HISTORIC_STATE - // debug interface is always enabled in historic state, but - // non-tracing calls are only available if bEnabledAPIs_debug is true - auto pDebugFace = - new rpc::Debug( *g_client, &debugInterface, argv_string, bEnabledAPIs_debug ); -#else - // debug interface is enabled on core node if bEnabledAPIs_debug is true auto pDebugFace = bEnabledAPIs_debug ? - new rpc::Debug( *g_client, &debugInterface, argv_string, true ) : + new rpc::Debug( *g_client, &debugInterface, argv_string ) : nullptr; + +#ifdef HISTORIC_STATE + // tracing interface is always enabled for the historic state nodes + auto pTracingFace = new rpc::Tracing( *g_client, argv_string ); +#else + // tracing interface is only enabled for the historic state nodes + auto pTracingFace = nullptr; #endif @@ -1997,9 +1998,9 @@ int main( int argc, char** argv ) try { new rpc::SkalePerformanceTracker( configPath.string() ) : nullptr; - g_jsonrpcIpcServer.reset( - new FullServer( pEthFace, pSkaleFace, pSkaleStatsFace, pNetFace, pWeb3Face, - pPersonalFace, pAdminEthFace, pDebugFace, pPerformanceTrackerFace, nullptr ) ); + g_jsonrpcIpcServer.reset( new FullServer( pEthFace, pSkaleFace, pSkaleStatsFace, pNetFace, + pWeb3Face, pPersonalFace, pAdminEthFace, pDebugFace, pPerformanceTrackerFace, + pTracingFace, nullptr ) ); if ( is_ipc ) { try { diff --git a/test/historicstate/configs/basic_config.json b/test/historicstate/configs/basic_config.json index a108a100f..1fd278d37 100644 --- a/test/historicstate/configs/basic_config.json +++ b/test/historicstate/configs/basic_config.json @@ -317,7 +317,8 @@ "collectionQueueSize": 2, "collectionDuration": 10, "transactionQueueSize": 100, - "maxOpenLeveldbFiles": 25 + "maxOpenLeveldbFiles": 25, + "testSignatures": true }, "sChain": { diff --git a/test/historicstate/hardhat/README.md b/test/historicstate/hardhat/README.md index 74fca7e30..f8c70a4a4 100644 --- a/test/historicstate/hardhat/README.md +++ b/test/historicstate/hardhat/README.md @@ -30,12 +30,12 @@ npm install Now run test against skaled ```shell -npx hardhat run scripts/trace.js --network skaled +npx hardhat run scripts/trace.ts --network skaled ``` To run the same test against geth ```shell -npx hardhat run scripts/trace.js --network geth +npx hardhat run scripts/trace.ts --network geth ``` diff --git a/test/historicstate/hardhat/scripts/trace.ts b/test/historicstate/hardhat/scripts/trace.ts index d6280a68b..f6de806c9 100644 --- a/test/historicstate/hardhat/scripts/trace.ts +++ b/test/historicstate/hardhat/scripts/trace.ts @@ -371,10 +371,7 @@ async function callDebugTraceCall(_deployedContract: any, _tracer: string, _trac data: _deployedContract.interface.encodeFunctionData("getBalance", []) }; - const returnData = await ethers.provider.call(transaction, currentBlock - 1); - - const result = _deployedContract.interface.decodeFunctionResult("getBalance", returnData); - + let returnData = await ethers.provider.call(transaction, currentBlock - 1); console.log("Calling debug_traceCall to generate " + _traceFileName); diff --git a/test/unittests/libweb3jsonrpc/jsonrpc.cpp b/test/unittests/libweb3jsonrpc/jsonrpc.cpp index 66e643b68..86945f627 100644 --- a/test/unittests/libweb3jsonrpc/jsonrpc.cpp +++ b/test/unittests/libweb3jsonrpc/jsonrpc.cpp @@ -358,7 +358,7 @@ JsonRpcFixture( const std::string& _config = "", bool _owner = true, rpcServer.reset( new FullServer( ethFace , new rpc::Net( chainParams ), new rpc::Web3(), // TODO Add version parameter here? new rpc::AdminEth( *client, *gasPricer, keyManager, *sessionManager ), - new rpc::Debug( *client, nullptr, "", true), + new rpc::Debug( *client, nullptr, ""), new rpc::Test( *client ) ) ); //