mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
internal/ethapi: return revert reason for eth_call (#21083)
This commit is contained in:
parent
ef80645f90
commit
593fe53519
5 changed files with 224 additions and 115 deletions
|
|
@ -34,6 +34,7 @@ import (
|
|||
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
|
||||
"github.com/XinFinOrg/XDPoSChain/accounts/keystore"
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||
|
|
@ -432,6 +433,36 @@ func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Ad
|
|||
return b.pendingState.GetCode(contract), nil
|
||||
}
|
||||
|
||||
func newRevertError(result *core.ExecutionResult) *revertError {
|
||||
reason, errUnpack := abi.UnpackRevert(result.Revert())
|
||||
err := errors.New("execution reverted")
|
||||
if errUnpack == nil {
|
||||
err = fmt.Errorf("execution reverted: %v", reason)
|
||||
}
|
||||
return &revertError{
|
||||
error: err,
|
||||
reason: hexutil.Encode(result.Revert()),
|
||||
}
|
||||
}
|
||||
|
||||
// revertError is an API error that encompassas an EVM revertal with JSON error
|
||||
// code and a binary data blob.
|
||||
type revertError struct {
|
||||
error
|
||||
reason string // revert reason hex encoded
|
||||
}
|
||||
|
||||
// ErrorCode returns the JSON error code for a revertal.
|
||||
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
|
||||
func (e *revertError) ErrorCode() int {
|
||||
return 3
|
||||
}
|
||||
|
||||
// ErrorData returns the hex encoded revert reason.
|
||||
func (e *revertError) ErrorData() interface{} {
|
||||
return e.reason
|
||||
}
|
||||
|
||||
// CallContract executes a contract call.
|
||||
func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
|
||||
b.mu.Lock()
|
||||
|
|
@ -448,7 +479,11 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res.Return(), nil
|
||||
// If the result contains a revert reason, try to unpack and return it.
|
||||
if len(res.Revert()) > 0 {
|
||||
return nil, newRevertError(res)
|
||||
}
|
||||
return res.Return(), res.Err
|
||||
}
|
||||
|
||||
// PendingCallContract executes a contract call on the pending state.
|
||||
|
|
@ -461,7 +496,11 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereu
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res.Return(), nil
|
||||
// If the result contains a revert reason, try to unpack and return it.
|
||||
if len(res.Revert()) > 0 {
|
||||
return nil, newRevertError(res)
|
||||
}
|
||||
return res.Return(), res.Err
|
||||
}
|
||||
|
||||
// PendingNonceAt implements PendingStateReader.PendingNonceAt, retrieving
|
||||
|
|
@ -548,16 +587,10 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
|||
}
|
||||
if failed {
|
||||
if result != nil && result.Err != vm.ErrOutOfGas {
|
||||
errMsg := fmt.Sprintf("always failing transaction (%v)", result.Err)
|
||||
if len(result.Revert()) > 0 {
|
||||
ret, err := abi.UnpackRevert(result.Revert())
|
||||
if err != nil {
|
||||
errMsg += fmt.Sprintf(" (%#x)", result.Revert())
|
||||
} else {
|
||||
errMsg += fmt.Sprintf(" (%s)", ret)
|
||||
}
|
||||
return 0, newRevertError(result)
|
||||
}
|
||||
return 0, errors.New(errMsg)
|
||||
return 0, result.Err
|
||||
}
|
||||
// Otherwise, the specified gas cap is too low
|
||||
return 0, fmt.Errorf("gas required exceeds allowance (%d)", cap)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -106,14 +107,18 @@ const deployedCode = `60806040526004361061003b576000357c010000000000000000000000
|
|||
// expected return value contains "hello world"
|
||||
var expectedReturn = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
func simTestBackend(testAddr common.Address) *SimulatedBackend {
|
||||
return NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
}, 10000000,
|
||||
)
|
||||
}
|
||||
|
||||
func TestNewSimulatedBackend(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
expectedBal := big.NewInt(10000000000)
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: expectedBal},
|
||||
}, 10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
|
||||
if sim.config != params.AllEthashProtocolChanges {
|
||||
|
|
@ -152,11 +157,7 @@ func TestSimulatedBackend_AdjustTime(t *testing.T) {
|
|||
func TestSimulatedBackend_BalanceAt(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
expectedBal := big.NewInt(10000000000)
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: expectedBal},
|
||||
}, 10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
|
||||
|
|
@ -229,11 +230,7 @@ func TestSimulatedBackend_BlockByNumber(t *testing.T) {
|
|||
func TestSimulatedBackend_NonceAt(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
}, 10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
|
||||
|
|
@ -283,11 +280,7 @@ func TestSimulatedBackend_NonceAt(t *testing.T) {
|
|||
func TestSimulatedBackend_SendTransaction(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
}, 10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
|
||||
|
|
@ -394,7 +387,6 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
},
|
||||
},
|
||||
})
|
||||
|
||||
defer sim.Close()
|
||||
|
||||
parsed, _ := abi.JSON(strings.NewReader(contractAbi))
|
||||
|
|
@ -406,6 +398,7 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
message ethereum.CallMsg
|
||||
expect uint64
|
||||
expectError error
|
||||
expectData interface{}
|
||||
}{
|
||||
{"plain transfer(valid)", ethereum.CallMsg{
|
||||
From: addr,
|
||||
|
|
@ -414,7 +407,7 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
GasPrice: big.NewInt(0),
|
||||
Value: big.NewInt(1),
|
||||
Data: nil,
|
||||
}, params.TxGas, nil},
|
||||
}, params.TxGas, nil, nil},
|
||||
|
||||
{"plain transfer(invalid)", ethereum.CallMsg{
|
||||
From: addr,
|
||||
|
|
@ -423,7 +416,7 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
GasPrice: big.NewInt(0),
|
||||
Value: big.NewInt(1),
|
||||
Data: nil,
|
||||
}, 0, errors.New("always failing transaction (execution reverted)")},
|
||||
}, 0, errors.New("execution reverted"), nil},
|
||||
|
||||
{"Revert", ethereum.CallMsg{
|
||||
From: addr,
|
||||
|
|
@ -432,7 +425,8 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
GasPrice: big.NewInt(0),
|
||||
Value: nil,
|
||||
Data: common.Hex2Bytes("d8b98391"),
|
||||
}, 0, errors.New("always failing transaction (execution reverted) (revert reason)")},
|
||||
}, 0, errors.New("execution reverted: revert reason"),
|
||||
"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d72657665727420726561736f6e00000000000000000000000000000000000000"},
|
||||
|
||||
{"PureRevert", ethereum.CallMsg{
|
||||
From: addr,
|
||||
|
|
@ -441,7 +435,7 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
GasPrice: big.NewInt(0),
|
||||
Value: nil,
|
||||
Data: common.Hex2Bytes("aa8b1d30"),
|
||||
}, 0, errors.New("always failing transaction (execution reverted)")},
|
||||
}, 0, errors.New("execution reverted"), nil},
|
||||
|
||||
{"OOG", ethereum.CallMsg{
|
||||
From: addr,
|
||||
|
|
@ -450,7 +444,7 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
GasPrice: big.NewInt(0),
|
||||
Value: nil,
|
||||
Data: common.Hex2Bytes("50f6fe34"),
|
||||
}, 0, errors.New("gas required exceeds allowance (100000)")},
|
||||
}, 0, errors.New("gas required exceeds allowance (100000)"), nil},
|
||||
|
||||
{"Assert", ethereum.CallMsg{
|
||||
From: addr,
|
||||
|
|
@ -459,7 +453,7 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
GasPrice: big.NewInt(0),
|
||||
Value: nil,
|
||||
Data: common.Hex2Bytes("b9b046f9"),
|
||||
}, 0, errors.New("always failing transaction (invalid opcode: INVALID)")},
|
||||
}, 0, errors.New("invalid opcode: INVALID"), nil},
|
||||
|
||||
{"Valid", ethereum.CallMsg{
|
||||
From: addr,
|
||||
|
|
@ -468,7 +462,7 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
GasPrice: big.NewInt(0),
|
||||
Value: nil,
|
||||
Data: common.Hex2Bytes("e09fface"),
|
||||
}, 21483, nil},
|
||||
}, 21483, nil, nil},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got, err := sim.EstimateGas(context.Background(), c.message)
|
||||
|
|
@ -479,6 +473,13 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
if c.expectError.Error() != err.Error() {
|
||||
t.Fatalf("Expect error, want %v, got %v", c.expectError, err)
|
||||
}
|
||||
if c.expectData != nil {
|
||||
if err, ok := err.(*revertError); !ok {
|
||||
t.Fatalf("Expect revert error, got %T", err)
|
||||
} else if !reflect.DeepEqual(err.ErrorData(), c.expectData) {
|
||||
t.Fatalf("Error data mismatch, want %v, got %v", c.expectData, err.ErrorData())
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if got != c.expect {
|
||||
|
|
@ -490,11 +491,7 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
|
|||
func TestSimulatedBackend_HeaderByHash(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
}, 10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
|
||||
|
|
@ -515,11 +512,7 @@ func TestSimulatedBackend_HeaderByHash(t *testing.T) {
|
|||
func TestSimulatedBackend_HeaderByNumber(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
}, 10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
|
||||
|
|
@ -566,11 +559,7 @@ func TestSimulatedBackend_HeaderByNumber(t *testing.T) {
|
|||
func TestSimulatedBackend_TransactionCount(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
}, 10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
currentBlock, err := sim.BlockByNumber(bgCtx, nil)
|
||||
|
|
@ -620,11 +609,7 @@ func TestSimulatedBackend_TransactionCount(t *testing.T) {
|
|||
func TestSimulatedBackend_TransactionInBlock(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
}, 10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
|
||||
|
|
@ -687,11 +672,7 @@ func TestSimulatedBackend_TransactionInBlock(t *testing.T) {
|
|||
func TestSimulatedBackend_PendingNonceAt(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
}, 10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
|
||||
|
|
@ -803,12 +784,7 @@ func TestSimulatedBackend_SuggestGasPrice(t *testing.T) {
|
|||
|
||||
func TestSimulatedBackend_PendingCodeAt(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
},
|
||||
10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
code, err := sim.CodeAt(bgCtx, testAddr, nil)
|
||||
|
|
@ -844,12 +820,7 @@ func TestSimulatedBackend_PendingCodeAt(t *testing.T) {
|
|||
|
||||
func TestSimulatedBackend_CodeAt(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
},
|
||||
10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
code, err := sim.CodeAt(bgCtx, testAddr, nil)
|
||||
|
|
@ -889,12 +860,7 @@ func TestSimulatedBackend_CodeAt(t *testing.T) {
|
|||
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
|
||||
func TestSimulatedBackend_PendingAndCallContract(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
sim := NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
testAddr: {Balance: big.NewInt(10000000000)},
|
||||
},
|
||||
10000000,
|
||||
)
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
|
||||
|
|
@ -910,7 +876,7 @@ func TestSimulatedBackend_PendingAndCallContract(t *testing.T) {
|
|||
|
||||
input, err := parsed.Pack("receive", []byte("X"))
|
||||
if err != nil {
|
||||
t.Errorf("could pack receive function on contract: %v", err)
|
||||
t.Errorf("could not pack receive function on contract: %v", err)
|
||||
}
|
||||
|
||||
// make sure you can call the contract in pending state
|
||||
|
|
@ -950,3 +916,114 @@ func TestSimulatedBackend_PendingAndCallContract(t *testing.T) {
|
|||
t.Errorf("response from calling contract was expected to be 'hello world' instead received %v", string(res))
|
||||
}
|
||||
}
|
||||
|
||||
// This test is based on the following contract:
|
||||
/*
|
||||
contract Reverter {
|
||||
function revertString() public pure{
|
||||
require(false, "some error");
|
||||
}
|
||||
function revertNoString() public pure {
|
||||
require(false, "");
|
||||
}
|
||||
function revertASM() public pure {
|
||||
assembly {
|
||||
revert(0x0, 0x0)
|
||||
}
|
||||
}
|
||||
function noRevert() public pure {
|
||||
assembly {
|
||||
// Assembles something that looks like require(false, "some error") but is not reverted
|
||||
mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
|
||||
mstore(0x4, 0x0000000000000000000000000000000000000000000000000000000000000020)
|
||||
mstore(0x24, 0x000000000000000000000000000000000000000000000000000000000000000a)
|
||||
mstore(0x44, 0x736f6d65206572726f7200000000000000000000000000000000000000000000)
|
||||
return(0x0, 0x64)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
func TestSimulatedBackend_CallContractRevert(t *testing.T) {
|
||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
// sim := simTestBackend(testAddr)
|
||||
sim := NewXDCSimulatedBackend(core.GenesisAlloc{testAddr: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
|
||||
defer sim.Close()
|
||||
bgCtx := context.Background()
|
||||
|
||||
reverterABI := `[{"inputs": [],"name": "noRevert","outputs": [],"stateMutability": "pure","type": "function"},{"inputs": [],"name": "revertASM","outputs": [],"stateMutability": "pure","type": "function"},{"inputs": [],"name": "revertNoString","outputs": [],"stateMutability": "pure","type": "function"},{"inputs": [],"name": "revertString","outputs": [],"stateMutability": "pure","type": "function"}]`
|
||||
reverterBin := "608060405234801561001057600080fd5b506101d3806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80634b409e01146100515780639b340e361461005b5780639bd6103714610065578063b7246fc11461006f575b600080fd5b610059610079565b005b6100636100ca565b005b61006d6100cf565b005b610077610145565b005b60006100c8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526000815260200160200191505060405180910390fd5b565b600080fd5b6000610143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600a8152602001807f736f6d65206572726f720000000000000000000000000000000000000000000081525060200191505060405180910390fd5b565b7f08c379a0000000000000000000000000000000000000000000000000000000006000526020600452600a6024527f736f6d65206572726f720000000000000000000000000000000000000000000060445260646000f3fea2646970667358221220cdd8af0609ec4996b7360c7c780bad5c735740c64b1fffc3445aa12d37f07cb164736f6c63430006070033"
|
||||
|
||||
parsed, err := abi.JSON(strings.NewReader(reverterABI))
|
||||
if err != nil {
|
||||
t.Errorf("could not get code at test addr: %v", err)
|
||||
}
|
||||
contractAuth := bind.NewKeyedTransactor(testKey)
|
||||
addr, _, _, err := bind.DeployContract(contractAuth, parsed, common.FromHex(reverterBin), sim)
|
||||
if err != nil {
|
||||
t.Errorf("could not deploy contract: %v", err)
|
||||
}
|
||||
|
||||
inputs := make(map[string]interface{}, 3)
|
||||
inputs["revertASM"] = nil
|
||||
inputs["revertNoString"] = ""
|
||||
inputs["revertString"] = "some error"
|
||||
|
||||
call := make([]func([]byte) ([]byte, error), 2)
|
||||
call[0] = func(input []byte) ([]byte, error) {
|
||||
return sim.PendingCallContract(bgCtx, ethereum.CallMsg{
|
||||
From: testAddr,
|
||||
To: &addr,
|
||||
Data: input,
|
||||
})
|
||||
}
|
||||
call[1] = func(input []byte) ([]byte, error) {
|
||||
return sim.CallContract(bgCtx, ethereum.CallMsg{
|
||||
From: testAddr,
|
||||
To: &addr,
|
||||
Data: input,
|
||||
}, nil)
|
||||
}
|
||||
|
||||
// Run pending calls then commit
|
||||
for _, cl := range call {
|
||||
for key, val := range inputs {
|
||||
input, err := parsed.Pack(key)
|
||||
if err != nil {
|
||||
t.Errorf("could not pack %v function on contract: %v", key, err)
|
||||
}
|
||||
|
||||
res, err := cl(input)
|
||||
if err == nil {
|
||||
t.Errorf("call to %v was not reverted", key)
|
||||
}
|
||||
if res != nil {
|
||||
t.Errorf("result from %v was not nil: %v", key, res)
|
||||
}
|
||||
if val != nil {
|
||||
rerr, ok := err.(*revertError)
|
||||
if !ok {
|
||||
t.Errorf("expect revert error")
|
||||
}
|
||||
if rerr.Error() != "execution reverted: "+val.(string) {
|
||||
t.Errorf("error was malformed: got %v want %v", rerr.Error(), val)
|
||||
}
|
||||
} else {
|
||||
// revert(0x0,0x0)
|
||||
if err.Error() != "execution reverted" {
|
||||
t.Errorf("error was malformed: got %v want %v", err, "execution reverted")
|
||||
}
|
||||
}
|
||||
}
|
||||
input, err := parsed.Pack("noRevert")
|
||||
if err != nil {
|
||||
t.Errorf("could not pack noRevert function on contract: %v", err)
|
||||
}
|
||||
res, err := cl(input)
|
||||
if err != nil {
|
||||
t.Error("call to noRevert was reverted")
|
||||
}
|
||||
if res == nil {
|
||||
t.Errorf("result from noRevert was nil")
|
||||
}
|
||||
sim.Commit()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1466,7 +1466,7 @@ var bindTests = []struct {
|
|||
F2: [32]byte{0x01, 0x02, 0x03},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("Failed to invoke function")
|
||||
t.Fatal("Failed to invoke function, err:", err)
|
||||
}
|
||||
_, _, c2, err := DeployContractTwo(transactOpts, sim)
|
||||
if err != nil {
|
||||
|
|
@ -1478,7 +1478,7 @@ var bindTests = []struct {
|
|||
F2: [32]byte{0x01, 0x02, 0x03},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("Failed to invoke function")
|
||||
t.Fatal("Failed to invoke function, err:", err)
|
||||
}
|
||||
`,
|
||||
nil,
|
||||
|
|
|
|||
|
|
@ -351,9 +351,7 @@ func (b *bridge) Send(call jsre.Call) (goja.Value, error) {
|
|||
resp.Set("id", req.ID)
|
||||
|
||||
var result json.RawMessage
|
||||
err = b.client.Call(&result, req.Method, req.Params...)
|
||||
switch err := err.(type) {
|
||||
case nil:
|
||||
if err = b.client.Call(&result, req.Method, req.Params...); err == nil {
|
||||
if result == nil {
|
||||
// Special case null because it is decoded as an empty
|
||||
// raw message for some reason.
|
||||
|
|
@ -366,19 +364,24 @@ func (b *bridge) Send(call jsre.Call) (goja.Value, error) {
|
|||
}
|
||||
resultVal, err := parse(goja.Null(), call.VM.ToValue(string(result)))
|
||||
if err != nil {
|
||||
setError(resp, -32603, err.Error())
|
||||
setError(resp, -32603, err.Error(), nil)
|
||||
} else {
|
||||
resp.Set("result", resultVal)
|
||||
}
|
||||
}
|
||||
case rpc.Error:
|
||||
setError(resp, err.ErrorCode(), err.Error())
|
||||
default:
|
||||
setError(resp, -32603, err.Error())
|
||||
} else {
|
||||
code := -32603
|
||||
var data interface{}
|
||||
if err, ok := err.(rpc.Error); ok {
|
||||
code = err.ErrorCode()
|
||||
}
|
||||
if err, ok := err.(rpc.DataError); ok {
|
||||
data = err.ErrorData()
|
||||
}
|
||||
setError(resp, code, err.Error(), data)
|
||||
}
|
||||
resps = append(resps, resp)
|
||||
}
|
||||
|
||||
// Return the responses either to the callback (if supplied)
|
||||
// or directly as the return value.
|
||||
var result goja.Value
|
||||
|
|
@ -394,8 +397,14 @@ func (b *bridge) Send(call jsre.Call) (goja.Value, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func setError(resp *goja.Object, code int, msg string) {
|
||||
resp.Set("error", map[string]interface{}{"code": code, "message": msg})
|
||||
func setError(resp *goja.Object, code int, msg string, data interface{}) {
|
||||
err := make(map[string]interface{})
|
||||
err["code"] = code
|
||||
err["message"] = msg
|
||||
if data != nil {
|
||||
err["data"] = data
|
||||
}
|
||||
resp.Set("error", err)
|
||||
}
|
||||
|
||||
// isNumber returns true if input value is a JS number.
|
||||
|
|
|
|||
|
|
@ -1382,19 +1382,19 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
|||
return result, err
|
||||
}
|
||||
|
||||
func newRevertError(res []byte) *revertError {
|
||||
reason, errUnpack := abi.UnpackRevert(res)
|
||||
func newRevertError(result *core.ExecutionResult) *revertError {
|
||||
reason, errUnpack := abi.UnpackRevert(result.Revert())
|
||||
err := errors.New("execution reverted")
|
||||
if errUnpack == nil {
|
||||
err = fmt.Errorf("execution reverted: %v", reason)
|
||||
}
|
||||
return &revertError{
|
||||
error: err,
|
||||
reason: hexutil.Encode(res),
|
||||
reason: hexutil.Encode(result.Revert()),
|
||||
}
|
||||
}
|
||||
|
||||
// revertError is an API error that encompasses an EVM revertal with JSON error
|
||||
// revertError is an API error that encompassas an EVM revertal with JSON error
|
||||
// code and a binary data blob.
|
||||
type revertError struct {
|
||||
error
|
||||
|
|
@ -1428,10 +1428,10 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, bl
|
|||
return nil, err
|
||||
}
|
||||
// If the result contains a revert reason, try to unpack and return it.
|
||||
if result.Failed() {
|
||||
return nil, newRevertError(result.Return())
|
||||
if len(result.Revert()) > 0 {
|
||||
return nil, newRevertError(result)
|
||||
}
|
||||
return result.Return(), nil
|
||||
return result.Return(), result.Err
|
||||
}
|
||||
|
||||
type estimateGasError struct {
|
||||
|
|
@ -1546,23 +1546,13 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
|||
|
||||
if failed {
|
||||
if result != nil && result.Err != vm.ErrOutOfGas {
|
||||
var revert string
|
||||
if len(result.Revert()) > 0 {
|
||||
ret, err := abi.UnpackRevert(result.Revert())
|
||||
if err != nil {
|
||||
revert = hexutil.Encode(result.Revert())
|
||||
} else {
|
||||
revert = ret
|
||||
}
|
||||
}
|
||||
return 0, estimateGasError{
|
||||
error: "always failing transaction",
|
||||
vmerr: result.Err,
|
||||
revert: revert,
|
||||
return 0, newRevertError(result)
|
||||
}
|
||||
return 0, result.Err
|
||||
}
|
||||
// Otherwise, the specified gas cap is too low
|
||||
return 0, estimateGasError{error: fmt.Sprintf("gas required exceeds allowance (%d)", cap)}
|
||||
return 0, fmt.Errorf("gas required exceeds allowance (%d)", cap)
|
||||
}
|
||||
}
|
||||
return hexutil.Uint64(hi), nil
|
||||
|
|
|
|||
Loading…
Reference in a new issue