Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug/1744 handle custom errors outside evm #1747

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions libdevcore/CommonData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
*/

#include "CommonData.h"
#include <random>

#include "Exceptions.h"

#include <random>

using namespace std;
using namespace dev;

Expand Down Expand Up @@ -116,3 +116,38 @@
ret.push_back( _s[i] );
return ret;
}

std::string dev::customErrorMessageToString( const bytes& _b ) {
return toHexPrefixed( _b );

Check warning on line 121 in libdevcore/CommonData.cpp

View check run for this annotation

Codecov / codecov/patch

libdevcore/CommonData.cpp#L120-L121

Added lines #L120 - L121 were not covered by tests
}

std::string dev::revertMessageToString( const bytes& b ) {

Check warning on line 124 in libdevcore/CommonData.cpp

View check run for this annotation

Codecov / codecov/patch

libdevcore/CommonData.cpp#L124

Added line #L124 was not covered by tests
// first 4 bytes are function selector (revert - 0x08c379a0)
// then goes offset - 32 bytes
// then goes string length - 32 bytes
// then goes string data
u256 offset = 4 + 32 + fromBigEndian< u256 >( bytes( b.begin() + 4, b.begin() + 32 + 4 ) );

Check warning on line 129 in libdevcore/CommonData.cpp

View check run for this annotation

Codecov / codecov/patch

libdevcore/CommonData.cpp#L129

Added line #L129 was not covered by tests
// offset for any revert message should be 4 + 32 + 32 = 68
if ( offset != 68 ) {
BOOST_THROW_EXCEPTION(

Check warning on line 132 in libdevcore/CommonData.cpp

View check run for this annotation

Codecov / codecov/patch

libdevcore/CommonData.cpp#L131-L132

Added lines #L131 - L132 were not covered by tests
std::runtime_error( "Unexpected offset length in revertMessageToString" ) );
}
u256 length = fromBigEndian< u256 >(
bytes( b.begin() + 4 + 32, b.begin() + offset.convert_to< unsigned >() ) );
if ( offset + length > b.size() ) {
BOOST_THROW_EXCEPTION( std::runtime_error(

Check warning on line 138 in libdevcore/CommonData.cpp

View check run for this annotation

Codecov / codecov/patch

libdevcore/CommonData.cpp#L136-L138

Added lines #L136 - L138 were not covered by tests
"Unexpected length in revertMessageToString: 4 + offset + length > b.size()" ) );
}
return asString( bytes( b.begin() + offset.convert_to< unsigned >(),
b.begin() + offset.convert_to< unsigned >() + length.convert_to< unsigned >() ) );

Check warning on line 142 in libdevcore/CommonData.cpp

View check run for this annotation

Codecov / codecov/patch

libdevcore/CommonData.cpp#L141-L142

Added lines #L141 - L142 were not covered by tests
}

std::string dev::errorMessageToString( const bytes& b ) {
if ( b.empty() ) {
return "";
}
// check if the message is a revert message
if ( b.size() > 4 + 32 + 32 && b[0] == 0x08 && b[1] == 0xc3 && b[2] == 0x79 && b[3] == 0xa0 )
return revertMessageToString( b );
return customErrorMessageToString( b );

Check warning on line 152 in libdevcore/CommonData.cpp

View check run for this annotation

Codecov / codecov/patch

libdevcore/CommonData.cpp#L150-L152

Added lines #L150 - L152 were not covered by tests
}
8 changes: 8 additions & 0 deletions libdevcore/CommonData.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ inline bytes asBytes( std::string const& _b ) {
/// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1
bytes asNibbles( bytesConstRef const& _s );

// converts byte array containing a custom error message thrown by EVM to string
std::string customErrorMessageToString( const bytes& _b );

// converts byte array containing a revert message thrown by EVM to string
std::string revertMessageToString( const bytes& _b );

// converts byte array containing an error message thrown by EVM to string
std::string errorMessageToString( const bytes& _b );

// Big-endian to/from host endian conversion functions.

Expand Down
2 changes: 1 addition & 1 deletion libskale/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,7 @@ std::pair< ExecutionResult, TransactionReceipt > State::execute( EnvInfo const&

std::string strRevertReason;
if ( res.excepted == dev::eth::TransactionException::RevertInstruction ) {
strRevertReason = skutils::eth::call_error_message_2_str( res.output );
strRevertReason = dev::errorMessageToString( res.output );
if ( strRevertReason.empty() )
strRevertReason = "EVM revert instruction without description message";
std::string strOut = cc::fatal( "Error message from eth_call():" ) + cc::error( " " ) +
Expand Down
109 changes: 108 additions & 1 deletion test/unittests/libweb3jsonrpc/jsonrpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2368,7 +2368,114 @@
txPOW2["gasPrice"] = "0xc5002ab03e1e7e196b3d0ffa9801e783fcd48d4c6d972f1389ab63f4e2d0bef0"; // gas 1m
txPOW2["value"] = 100;
BOOST_REQUIRE_THROW( fixture.rpcClient->eth_sendTransaction( txPOW2 ), jsonrpc::JsonRpcException ); // block gas limit reached
}
}

Check warning on line 2371 in test/unittests/libweb3jsonrpc/jsonrpc.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/libweb3jsonrpc/jsonrpc.cpp#L2371

Added line #L2371 was not covered by tests

BOOST_AUTO_TEST_CASE( revertReason ) {
JsonRpcFixture fixture;
dev::eth::simulateMining( *( fixture.client ), 1000 );

Check warning on line 2375 in test/unittests/libweb3jsonrpc/jsonrpc.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/libweb3jsonrpc/jsonrpc.cpp#L2373-L2375

Added lines #L2373 - L2375 were not covered by tests
// // SPDX-License-Identifier: UNLICENSED

// pragma solidity ^0.8.4;

// error CustomError();
// error CustomErrorWithArg(uint256 arg1);
// error CustomErrorWithArgs(uint256 arg1, bytes32 arg2);

// contract Error {
// function customError() external pure {
// revert CustomError();
// }

// function customErrorwithArg(uint256 x) external pure {
// revert CustomErrorWithArg(x);
// }

// function customErrorwithArgs(uint256 x, bytes32 b) external pure {
// revert CustomErrorWithArgs(x, b);
// }

// function throwRevertWithoutErrorMessage() external pure {
// revert();
// }

// function throwRevertWithErrorMessage() external pure {
// revert("error message");
// }
// }
std::string bytecode = "608060405234801561001057600080fd5b50610386806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80631ccb2cb41461005c5780633155edc8146100785780634de1fb0f14610094578063dda3a7bd1461009e578063f006fd35146100a8575b600080fd5b610076600480360381019061007191906101f3565b6100b2565b005b610092600480360381019061008d91906101ca565b6100f1565b005b61009c61012e565b005b6100a6610133565b005b6100b0610165565b005b81816040517f0594f0fe0000000000000000000000000000000000000000000000000000000081526004016100e89291906102ab565b60405180910390fd5b806040517fe372fe1e0000000000000000000000000000000000000000000000000000000081526004016101259190610290565b60405180910390fd5b600080fd5b6040517f09caebf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161019790610270565b60405180910390fd5b6000813590506101af81610322565b92915050565b6000813590506101c481610339565b92915050565b6000602082840312156101dc57600080fd5b60006101ea848285016101b5565b91505092915050565b6000806040838503121561020657600080fd5b6000610214858286016101b5565b9250506020610225858286016101a0565b9150509250929050565b610238816102e5565b82525050565b600061024b600d836102d4565b9150610256826102f9565b602082019050919050565b61026a816102ef565b82525050565b600060208201905081810360008301526102898161023e565b9050919050565b60006020820190506102a56000830184610261565b92915050565b60006040820190506102c06000830185610261565b6102cd602083018461022f565b9392505050565b600082825260208201905092915050565b6000819050919050565b6000819050919050565b7f6572726f72206d65737361676500000000000000000000000000000000000000600082015250565b61032b816102e5565b811461033657600080fd5b50565b610342816102ef565b811461034d57600080fd5b5056fea2646970667358221220dfeb247eec1a9f2092ccf93f00996637cb773621c86b66125e5089370c9ebe2764736f6c63430008040033";
auto senderAddress = fixture.coinbase.address();

Check warning on line 2406 in test/unittests/libweb3jsonrpc/jsonrpc.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/libweb3jsonrpc/jsonrpc.cpp#L2405-L2406

Added lines #L2405 - L2406 were not covered by tests

Json::Value create;
create["from"] = toJS( senderAddress );
create["data"] = bytecode;
create["gas"] = "1800000";
string txHash = fixture.rpcClient->eth_sendTransaction( create );
dev::eth::mineTransaction( *( fixture.client ), 1 );

Check warning on line 2413 in test/unittests/libweb3jsonrpc/jsonrpc.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/libweb3jsonrpc/jsonrpc.cpp#L2408-L2413

Added lines #L2408 - L2413 were not covered by tests

Json::Value receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
BOOST_REQUIRE( receipt["status"] == string( "0x1" ) );
string contractAddress = receipt["contractAddress"].asString();

Check warning on line 2417 in test/unittests/libweb3jsonrpc/jsonrpc.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/libweb3jsonrpc/jsonrpc.cpp#L2415-L2417

Added lines #L2415 - L2417 were not covered by tests

// call customError()
Json::Value txCustomError;
txCustomError["to"] = contractAddress;
txCustomError["data"] = "0xdda3a7bd";
txCustomError["from"] = senderAddress.hex();
txCustomError["gasPrice"] = fixture.rpcClient->eth_gasPrice();
txHash = fixture.rpcClient->eth_sendTransaction( txCustomError );
dev::eth::mineTransaction( *( fixture.client ), 1 );
receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
BOOST_REQUIRE( receipt["status"] == string( "0x0" ) );
BOOST_REQUIRE( receipt["revertReason"] == "0x09caebf3" );

Check warning on line 2429 in test/unittests/libweb3jsonrpc/jsonrpc.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/libweb3jsonrpc/jsonrpc.cpp#L2420-L2429

Added lines #L2420 - L2429 were not covered by tests

// call customErrorWithArg(1)
Json::Value txCustomErrorWithArg;
txCustomErrorWithArg["to"] = contractAddress;
txCustomErrorWithArg["data"] = "0x3155edc80000000000000000000000000000000000000000000000000000000000000001";
txCustomErrorWithArg["from"] = senderAddress.hex();
txCustomErrorWithArg["gasPrice"] = fixture.rpcClient->eth_gasPrice();
txHash = fixture.rpcClient->eth_sendTransaction( txCustomErrorWithArg );
dev::eth::mineTransaction( *( fixture.client ), 1 );
receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
BOOST_REQUIRE( receipt["status"] == string( "0x0" ) );
BOOST_REQUIRE( receipt["revertReason"] == "0xe372fe1e0000000000000000000000000000000000000000000000000000000000000001" );

Check warning on line 2441 in test/unittests/libweb3jsonrpc/jsonrpc.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/libweb3jsonrpc/jsonrpc.cpp#L2432-L2441

Added lines #L2432 - L2441 were not covered by tests

// call customErrorWithArgs(1, 0xa449dcaf2bca14e6bd0ac650eed9555008363002b2fc3a4c8422b7a9525a8135)
Json::Value txCustomErrorWithArgs;
txCustomErrorWithArgs["to"] = contractAddress;
txCustomErrorWithArgs["data"] = "0x1ccb2cb40000000000000000000000000000000000000000000000000000000000000001a449dcaf2bca14e6bd0ac650eed9555008363002b2fc3a4c8422b7a9525a8135";
txCustomErrorWithArgs["from"] = senderAddress.hex();
txCustomErrorWithArgs["gasPrice"] = fixture.rpcClient->eth_gasPrice();
txHash = fixture.rpcClient->eth_sendTransaction( txCustomErrorWithArgs );
dev::eth::mineTransaction( *( fixture.client ), 1 );
receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
BOOST_REQUIRE( receipt["status"] == string( "0x0" ) );
BOOST_REQUIRE( receipt["revertReason"] == "0x0594f0fe0000000000000000000000000000000000000000000000000000000000000001a449dcaf2bca14e6bd0ac650eed9555008363002b2fc3a4c8422b7a9525a8135" );

Check warning on line 2453 in test/unittests/libweb3jsonrpc/jsonrpc.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/libweb3jsonrpc/jsonrpc.cpp#L2444-L2453

Added lines #L2444 - L2453 were not covered by tests

// call to throwRevertWithErrorMessage()
Json::Value txThrowRevertWithErrorMessage;
txThrowRevertWithErrorMessage["to"] = contractAddress;
txThrowRevertWithErrorMessage["data"] = "0xf006fd35";
txThrowRevertWithErrorMessage["from"] = senderAddress.hex();
txThrowRevertWithErrorMessage["gasPrice"] = fixture.rpcClient->eth_gasPrice();
txHash = fixture.rpcClient->eth_sendTransaction( txThrowRevertWithErrorMessage );
dev::eth::mineTransaction( *( fixture.client ), 1 );
receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
BOOST_REQUIRE( receipt["status"] == string( "0x0" ) );
BOOST_REQUIRE( receipt["revertReason"] == "error message" );

Check warning on line 2465 in test/unittests/libweb3jsonrpc/jsonrpc.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/libweb3jsonrpc/jsonrpc.cpp#L2456-L2465

Added lines #L2456 - L2465 were not covered by tests

// call to throwRevertWithoutErrorMessage()
Json::Value txThrowRevertWithoutErrorMessage;
txThrowRevertWithoutErrorMessage["to"] = contractAddress;
txThrowRevertWithoutErrorMessage["data"] = "0x4de1fb0f";
txThrowRevertWithoutErrorMessage["from"] = senderAddress.hex();
txThrowRevertWithoutErrorMessage["gasPrice"] = fixture.rpcClient->eth_gasPrice();
txHash = fixture.rpcClient->eth_sendTransaction( txThrowRevertWithoutErrorMessage );
dev::eth::mineTransaction( *( fixture.client ), 1 );
receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash );
BOOST_REQUIRE( receipt["status"] == string( "0x0" ) );
BOOST_REQUIRE( receipt["revertReason"] == "EVM revert instruction without description message" );
}

Check warning on line 2478 in test/unittests/libweb3jsonrpc/jsonrpc.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/libweb3jsonrpc/jsonrpc.cpp#L2468-L2478

Added lines #L2468 - L2478 were not covered by tests

BOOST_AUTO_TEST_CASE( EIP1898Calls ) {
JsonRpcFixture fixture;
Expand Down
Loading