mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
fix error codes
This commit is contained in:
parent
ed378218a6
commit
f5ac0393e2
4 changed files with 109 additions and 48 deletions
|
|
@ -1232,7 +1232,7 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts mcOpts, blockNrOrH
|
|||
if len(opts.BlockStateCalls) == 0 {
|
||||
return nil, &invalidParamsError{message: "empty input"}
|
||||
} else if len(opts.BlockStateCalls) > maxMulticallBlocks {
|
||||
return nil, &invalidParamsError{message: "too many blocks"}
|
||||
return nil, &clientLimitExceededError{message: "too many blocks"}
|
||||
}
|
||||
if blockNrOrHash == nil {
|
||||
n := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||
|
|
|
|||
|
|
@ -1092,10 +1092,6 @@ func TestMulticallV1(t *testing.T) {
|
|||
From: &randomAccounts[1].addr,
|
||||
To: &randomAccounts[2].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
}, {
|
||||
From: &randomAccounts[3].addr,
|
||||
To: &randomAccounts[2].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
},
|
||||
},
|
||||
}},
|
||||
|
|
@ -1125,12 +1121,45 @@ func TestMulticallV1(t *testing.T) {
|
|||
GasUsed: "0x5208",
|
||||
Logs: []log{},
|
||||
Status: "0x1",
|
||||
}},
|
||||
}},
|
||||
}, {
|
||||
// insufficient funds
|
||||
name: "insufficient-funds",
|
||||
tag: latest,
|
||||
blocks: []mcBlock{{
|
||||
Calls: []TransactionArgs{{
|
||||
From: &randomAccounts[0].addr,
|
||||
To: &randomAccounts[1].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
}},
|
||||
}},
|
||||
want: nil,
|
||||
expectErr: &invalidTxError{Message: fmt.Sprintf("err: insufficient funds for gas * price + value: address %s have 0 want 1000 (supplied gas 4712388)", randomAccounts[0].addr.String()), Code: errCodeInsufficientFunds},
|
||||
}, {
|
||||
// EVM error
|
||||
name: "evm-error",
|
||||
tag: latest,
|
||||
blocks: []mcBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[2].addr: OverrideAccount{Code: hex2Bytes("f3")},
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
From: &randomAccounts[0].addr,
|
||||
To: &randomAccounts[2].addr,
|
||||
}},
|
||||
}},
|
||||
want: []blockRes{{
|
||||
Number: "0xb",
|
||||
GasLimit: "0x47e7c4",
|
||||
GasUsed: "0x47e7c4",
|
||||
FeeRecipient: coinbase,
|
||||
Calls: []callRes{{
|
||||
ReturnValue: "0x",
|
||||
GasUsed: "0x0",
|
||||
Error: callErr{Message: "stack underflow (0 <=> 2)", Code: errCodeVMError},
|
||||
GasUsed: "0x47e7c4",
|
||||
Logs: []log{},
|
||||
Status: "0x0",
|
||||
Error: callErr{Message: fmt.Sprintf("err: insufficient funds for gas * price + value: address %s have 0 want 1000 (supplied gas 4691388)", randomAccounts[3].addr.String()), Code: errCodeInsufficientFunds},
|
||||
}},
|
||||
}},
|
||||
}, {
|
||||
|
|
@ -1219,7 +1248,7 @@ func TestMulticallV1(t *testing.T) {
|
|||
}},
|
||||
}},
|
||||
want: []blockRes{},
|
||||
expectErr: errors.New("block numbers must be in order"),
|
||||
expectErr: &invalidBlockNumberError{message: fmt.Sprintf("block numbers must be in order: 11 <= 12")},
|
||||
},
|
||||
// Test on solidity storage example. Set value in one call, read in next.
|
||||
{
|
||||
|
|
@ -1558,19 +1587,8 @@ func TestMulticallV1(t *testing.T) {
|
|||
}},
|
||||
}},
|
||||
validation: &validation,
|
||||
want: []blockRes{{
|
||||
Number: "0xb",
|
||||
GasLimit: "0x47e7c4",
|
||||
GasUsed: "0x0",
|
||||
FeeRecipient: coinbase,
|
||||
Calls: []callRes{{
|
||||
ReturnValue: "0x",
|
||||
GasUsed: "0x0",
|
||||
Logs: []log{},
|
||||
Status: "0x0",
|
||||
Error: callErr{Message: fmt.Sprintf("err: nonce too high: address %s, tx: 2 state: 0 (supplied gas 4712388)", accounts[2].addr), Code: errCodeNonceTooHigh},
|
||||
}},
|
||||
}},
|
||||
want: nil,
|
||||
expectErr: &invalidTxError{Message: fmt.Sprintf("err: nonce too high: address %s, tx: 2 state: 0 (supplied gas 4712388)", accounts[2].addr), Code: errCodeNonceTooHigh},
|
||||
},
|
||||
// Clear storage.
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,43 +27,60 @@ type callError struct {
|
|||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
type invalidTxError struct {
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
func (e *invalidTxError) Error() string { return e.Message }
|
||||
func (e *invalidTxError) ErrorCode() int { return e.Code }
|
||||
|
||||
const (
|
||||
errCodeNonceTooHigh = -38011
|
||||
errCodeNonceTooLow = -38010
|
||||
errCodeInsufficientFunds = -38014
|
||||
errCodeIntrinsicGas = -38013
|
||||
errCodeInsufficientFunds = -38014
|
||||
errCodeBlockGasLimitReached = -38015
|
||||
errCodeBlockNumberInvalid = -38020
|
||||
errCodeBlockTimestampInvalid = -38021
|
||||
errCodeSenderIsNotEOA = -38024
|
||||
errCodeMaxInitCodeSizeExceeded = -38025
|
||||
errCodeClientLimitExceeded = -38026
|
||||
errCodeInternalError = -32603
|
||||
errCodeInvalidParams = -32602
|
||||
errCodeReverted = -32000
|
||||
errCodeVMError = -32015
|
||||
)
|
||||
|
||||
func callErrorFromError(err error) *callError {
|
||||
func txValidationError(err error) *invalidTxError {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
switch {
|
||||
case errors.Is(err, core.ErrNonceTooHigh):
|
||||
return &callError{Message: err.Error(), Code: errCodeNonceTooHigh}
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeNonceTooHigh}
|
||||
case errors.Is(err, core.ErrNonceTooLow):
|
||||
return &callError{Message: err.Error(), Code: errCodeNonceTooLow}
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeNonceTooLow}
|
||||
case errors.Is(err, core.ErrSenderNoEOA):
|
||||
// TODO
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeSenderIsNotEOA}
|
||||
case errors.Is(err, core.ErrFeeCapVeryHigh):
|
||||
return &callError{Message: err.Error(), Code: errCodeInvalidParams}
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
|
||||
case errors.Is(err, core.ErrTipVeryHigh):
|
||||
return &callError{Message: err.Error(), Code: errCodeInvalidParams}
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
|
||||
case errors.Is(err, core.ErrTipAboveFeeCap):
|
||||
return &callError{Message: err.Error(), Code: errCodeInvalidParams}
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
|
||||
case errors.Is(err, core.ErrFeeCapTooLow):
|
||||
// TODO
|
||||
return &callError{Message: err.Error(), Code: errCodeInvalidParams}
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
|
||||
case errors.Is(err, core.ErrInsufficientFunds):
|
||||
return &callError{Message: err.Error(), Code: errCodeInsufficientFunds}
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeInsufficientFunds}
|
||||
case errors.Is(err, core.ErrIntrinsicGas):
|
||||
return &callError{Message: err.Error(), Code: errCodeIntrinsicGas}
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeIntrinsicGas}
|
||||
case errors.Is(err, core.ErrInsufficientFundsForTransfer):
|
||||
return &callError{Message: err.Error(), Code: errCodeInsufficientFunds}
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeInsufficientFunds}
|
||||
case errors.Is(err, core.ErrMaxInitCodeSizeExceeded):
|
||||
return &invalidTxError{Message: err.Error(), Code: errCodeMaxInitCodeSizeExceeded}
|
||||
}
|
||||
return &callError{
|
||||
return &invalidTxError{
|
||||
Message: err.Error(),
|
||||
Code: errCodeInternalError,
|
||||
}
|
||||
|
|
@ -73,3 +90,23 @@ type invalidParamsError struct{ message string }
|
|||
|
||||
func (e *invalidParamsError) Error() string { return e.message }
|
||||
func (e *invalidParamsError) ErrorCode() int { return errCodeInvalidParams }
|
||||
|
||||
type clientLimitExceededError struct{ message string }
|
||||
|
||||
func (e *clientLimitExceededError) Error() string { return e.message }
|
||||
func (e *clientLimitExceededError) ErrorCode() int { return errCodeClientLimitExceeded }
|
||||
|
||||
type invalidBlockNumberError struct{ message string }
|
||||
|
||||
func (e *invalidBlockNumberError) Error() string { return e.message }
|
||||
func (e *invalidBlockNumberError) ErrorCode() int { return errCodeBlockNumberInvalid }
|
||||
|
||||
type invalidBlockTimestampError struct{ message string }
|
||||
|
||||
func (e *invalidBlockTimestampError) Error() string { return e.message }
|
||||
func (e *invalidBlockTimestampError) ErrorCode() int { return errCodeBlockTimestampInvalid }
|
||||
|
||||
type blockGasLimitReachedError struct{ message string }
|
||||
|
||||
func (e *blockGasLimitReachedError) Error() string { return e.message }
|
||||
func (e *blockGasLimitReachedError) ErrorCode() int { return errCodeBlockGasLimitReached }
|
||||
|
|
|
|||
|
|
@ -164,6 +164,13 @@ func (mc *multicall) execute(ctx context.Context, opts mcOpts) ([]mcBlockResult,
|
|||
nonce := state.GetNonce(call.from())
|
||||
call.Nonce = (*hexutil.Uint64)(&nonce)
|
||||
}
|
||||
var gas uint64
|
||||
if call.Gas != nil {
|
||||
gas = uint64(*call.Gas)
|
||||
}
|
||||
if gasUsed+gas > blockContext.GasLimit {
|
||||
return nil, &blockGasLimitReachedError{fmt.Sprintf("block gas limit reached: %d >= %d", gasUsed, blockContext.GasLimit)}
|
||||
}
|
||||
// Let the call run wild unless explicitly specified.
|
||||
if call.Gas == nil {
|
||||
remaining := blockContext.GasLimit - gasUsed
|
||||
|
|
@ -187,9 +194,8 @@ func (mc *multicall) execute(ctx context.Context, opts mcOpts) ([]mcBlockResult,
|
|||
}
|
||||
result, err := applyMessage(ctx, mc.b, call, state, header, timeout, gp, &blockContext, vmConfig, precompiles, opts.Validation)
|
||||
if err != nil {
|
||||
callErr := callErrorFromError(err)
|
||||
callResults[i] = mcCallResult{Error: callErr, Status: hexutil.Uint64(types.ReceiptStatusFailed)}
|
||||
continue
|
||||
txErr := txValidationError(err)
|
||||
return nil, txErr
|
||||
}
|
||||
// If the result contains a revert reason, try to unpack it.
|
||||
if len(result.Revert()) > 0 {
|
||||
|
|
@ -200,9 +206,9 @@ func (mc *multicall) execute(ctx context.Context, opts mcOpts) ([]mcBlockResult,
|
|||
if result.Failed() {
|
||||
callRes.Status = hexutil.Uint64(types.ReceiptStatusFailed)
|
||||
if errors.Is(result.Err, vm.ErrExecutionReverted) {
|
||||
callRes.Error = &callError{Message: result.Err.Error(), Code: -32000}
|
||||
callRes.Error = &callError{Message: result.Err.Error(), Code: errCodeReverted}
|
||||
} else {
|
||||
callRes.Error = &callError{Message: result.Err.Error(), Code: -32015}
|
||||
callRes.Error = &callError{Message: result.Err.Error(), Code: errCodeVMError}
|
||||
}
|
||||
} else {
|
||||
callRes.Status = hexutil.Uint64(types.ReceiptStatusSuccessful)
|
||||
|
|
@ -327,7 +333,7 @@ func makeHeaders(config *params.ChainConfig, blocks []mcBlock, base *types.Heade
|
|||
n := new(big.Int).Add(big.NewInt(int64(prevNumber)), big.NewInt(1))
|
||||
overrides.Number = (*hexutil.Big)(n)
|
||||
} else if overrides.Number.ToInt().Uint64() <= prevNumber {
|
||||
return nil, fmt.Errorf("block numbers must be in order")
|
||||
return nil, &invalidBlockNumberError{fmt.Sprintf("block numbers must be in order: %d <= %d", overrides.Number.ToInt().Uint64(), prevNumber)}
|
||||
}
|
||||
prevNumber = overrides.Number.ToInt().Uint64()
|
||||
|
||||
|
|
@ -335,7 +341,7 @@ func makeHeaders(config *params.ChainConfig, blocks []mcBlock, base *types.Heade
|
|||
t := prevTimestamp + 1
|
||||
overrides.Time = (*hexutil.Uint64)(&t)
|
||||
} else if time := (*uint64)(overrides.Time); *time <= prevTimestamp {
|
||||
return nil, fmt.Errorf("timestamps must be in order")
|
||||
return nil, &invalidBlockTimestampError{fmt.Sprintf("block timestamps must be in order: %d <= %d", *time, prevTimestamp)}
|
||||
}
|
||||
prevTimestamp = uint64(*overrides.Time)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue