From 88c11fa77f081eefd2477e5d42f4507457f6a073 Mon Sep 17 00:00:00 2001 From: Petr Hanzl <84449820+petr-hanzl@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:00:04 +0100 Subject: [PATCH] Revert "Rpc-Iterator clean up (#793)" (#802) This reverts commit 54f147c0cfbcfff46c8c7261ab2e501ce771c7dc. --- cmd/aida-rpc/rpc_test.go | 24 ++-- cmd/aida-rpc/run_rpc.go | 2 +- .../extension/validator/rpc_comparator.go | 134 ++++++++++-------- .../validator/rpc_comparator_test.go | 116 +++++++++------ executor/rpc_request_provider.go | 13 +- executor/rpc_request_provider_test.go | 32 +++-- rpc/execute.go | 49 ++++--- rpc/header.go | 8 +- rpc/iterator.go | 17 ++- rpc/request.go | 32 ++++- 10 files changed, 267 insertions(+), 160 deletions(-) diff --git a/cmd/aida-rpc/rpc_test.go b/cmd/aida-rpc/rpc_test.go index 9acb91682..259943b5c 100644 --- a/cmd/aida-rpc/rpc_test.go +++ b/cmd/aida-rpc/rpc_test.go @@ -21,12 +21,12 @@ func TestRPC_TransactionsAreExecutedForCorrectRange(t *testing.T) { archive := state.NewMockNonCommittableStateDB(ctrl) var err error - emptyReqA.Response, err = json.Marshal("0x1") + emptyReqA.Response.Result, err = json.Marshal("0x1") if err != nil { t.Errorf("unexpected error while marshalling result; %v", err) } - emptyReqB.Response, err = json.Marshal("0x0") + emptyReqB.Response.Result, err = json.Marshal("0x0") if err != nil { t.Errorf("unexpected error while marshalling result; %v", err) } @@ -93,8 +93,6 @@ func TestRPC_TransactionsAreExecutedForCorrectRange(t *testing.T) { } var emptyReqA = &rpc.RequestAndResults{ - Block: 10, - Timestamp: 10, Query: &rpc.Body{ Version: "2.0", ID: json.RawMessage{1}, @@ -103,14 +101,18 @@ var emptyReqA = &rpc.RequestAndResults{ Namespace: "eth", MethodBase: "getBalance", }, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Version: "2.0", + ID: json.RawMessage{1}, + BlockID: 10, + Timestamp: 10, + }, + StateDB: &rpc.StateDBData{ Result: new(big.Int).SetInt64(1), }, } var emptyReqB = &rpc.RequestAndResults{ - Block: 11, - Timestamp: 11, Query: &rpc.Body{ Version: "2.0", ID: json.RawMessage{1}, @@ -119,7 +121,13 @@ var emptyReqB = &rpc.RequestAndResults{ Namespace: "eth", MethodBase: "getBalance", }, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Version: "2.0", + ID: json.RawMessage{1}, + BlockID: 11, + Timestamp: 11, + }, + StateDB: &rpc.StateDBData{ Result: new(big.Int).SetInt64(0), }, } diff --git a/cmd/aida-rpc/run_rpc.go b/cmd/aida-rpc/run_rpc.go index f6870c2e2..661326919 100644 --- a/cmd/aida-rpc/run_rpc.go +++ b/cmd/aida-rpc/run_rpc.go @@ -43,7 +43,7 @@ type rpcProcessor struct { } func (p rpcProcessor) Process(state executor.State[*rpc.RequestAndResults], ctx *executor.Context) error { - state.Data.ReturnState = rpc.Execute(uint64(state.Block), state.Data, ctx.Archive, p.cfg) + state.Data.StateDB = rpc.Execute(uint64(state.Block), state.Data, ctx.Archive, p.cfg) return nil } diff --git a/executor/extension/validator/rpc_comparator.go b/executor/extension/validator/rpc_comparator.go index bf7559f60..67f3197cd 100644 --- a/executor/extension/validator/rpc_comparator.go +++ b/executor/extension/validator/rpc_comparator.go @@ -174,7 +174,15 @@ func tryRecovery(state executor.State[*rpc.RequestAndResults]) *comparatorError return newComparatorError(nil, nil, state.Data, state.Block, cannotUnmarshalResult) } - state.Data.Response = result + state.Data.Response = &rpc.Response{ + Version: state.Data.Error.Version, + ID: state.Data.Error.Id, + BlockID: state.Data.Error.BlockID, + Timestamp: state.Data.Error.Timestamp, + Result: result, + Payload: state.Data.Error.Payload, + } + state.Data.Error = nil return compare(state) @@ -182,29 +190,29 @@ func tryRecovery(state executor.State[*rpc.RequestAndResults]) *comparatorError // compareBalance compares getBalance data recorded on API server with data returned by StateDB func compareBalance(data *rpc.RequestAndResults, block int) *comparatorError { - stateBalance, ok := data.ReturnState.Result.(*big.Int) + stateBalance, ok := data.StateDB.Result.(*big.Int) if !ok { return newUnexpectedDataTypeErr(data) } if data.Error != nil { - if data.Error.Code == internalErrorCode { - return newComparatorError(stateBalance.Text(16), data.Error.Message, data, block, internalError) + if data.Error.Error.Code == internalErrorCode { + return newComparatorError(stateBalance.Text(16), data.Error.Error.Message, data, block, internalError) } - return newComparatorError(stateBalance.Text(16), data.Error.Message, data, block, expectedErrorGotResult) + return newComparatorError(stateBalance.Text(16), data.Error.Error.Message, data, block, expectedErrorGotResult) } // no error var recordedString string - err := json.Unmarshal(data.Response, &recordedString) + err := json.Unmarshal(data.Response.Result, &recordedString) if err != nil { - return newComparatorError(stateBalance.Text(16), string(data.Response), data, block, cannotUnmarshalResult) + return newComparatorError(stateBalance.Text(16), string(data.Response.Result), data, block, cannotUnmarshalResult) } recordedString = strings.TrimPrefix(recordedString, "0x") recordedBalance, ok := new(big.Int).SetString(recordedString, 16) if !ok { - return newComparatorError(stateBalance.Text(16), string(data.Response), data, block, cannotUnmarshalResult) + return newComparatorError(stateBalance.Text(16), string(data.Response.Result), data, block, cannotUnmarshalResult) } if stateBalance.Cmp(recordedBalance) != 0 { @@ -217,7 +225,7 @@ func compareBalance(data *rpc.RequestAndResults, block int) *comparatorError { // compareTransactionCount compares getTransactionCount data recorded on API server with data returned by StateDB func compareTransactionCount(data *rpc.RequestAndResults, block int) *comparatorError { - stateNonce, ok := data.ReturnState.Result.(uint64) + stateNonce, ok := data.StateDB.Result.(uint64) if !ok { return newUnexpectedDataTypeErr(data) } @@ -225,22 +233,22 @@ func compareTransactionCount(data *rpc.RequestAndResults, block int) *comparator var err error if data.Error != nil { - if data.Error.Code == internalErrorCode { - return newComparatorError(stateNonce, data.Error.Message, data, block, internalError) + if data.Error.Error.Code == internalErrorCode { + return newComparatorError(stateNonce, data.Error.Error.Message, data, block, internalError) } - return newComparatorError(stateNonce, data.Error.Message, data, block, expectedErrorGotResult) + return newComparatorError(stateNonce, data.Error.Error.Message, data, block, expectedErrorGotResult) } var recordedString string // no error - err = json.Unmarshal(data.Response, &recordedString) + err = json.Unmarshal(data.Response.Result, &recordedString) if err != nil { - return newComparatorError(stateNonce, string(data.Response), data, block, cannotUnmarshalResult) + return newComparatorError(stateNonce, string(data.Response.Result), data, block, cannotUnmarshalResult) } recordedNonce, err := hexutil.DecodeUint64(recordedString) if err != nil { - return newComparatorError(recordedNonce, string(data.Response), data, block, cannotUnmarshalResult) + return newComparatorError(recordedNonce, string(data.Response.Result), data, block, cannotUnmarshalResult) } if stateNonce != recordedNonce { @@ -253,12 +261,12 @@ func compareTransactionCount(data *rpc.RequestAndResults, block int) *comparator // compareCall compares call data recorded on API server with data returned by StateDB func compareCall(data *rpc.RequestAndResults, block int) *comparatorError { // do we have an error from StateDB? - if data.ReturnState.Error != nil { + if data.StateDB.Error != nil { return compareEVMStateDBError(data, block) } // did StateDB return a valid result? - if data.ReturnState.Result != nil { + if data.StateDB.Result != nil { return compareCallStateDbResult(data, block) } @@ -267,13 +275,13 @@ func compareCall(data *rpc.RequestAndResults, block int) *comparatorError { // compareCallStateDbResult compares valid call result recorded on API server with valid result returned by StateDb func compareCallStateDbResult(data *rpc.RequestAndResults, block int) *comparatorError { - dbString := hexutil.Encode(data.ReturnState.Result.([]byte)) + dbString := hexutil.Encode(data.StateDB.Result.([]byte)) if data.Error == nil { var recordedString string - err := json.Unmarshal(data.Response, &recordedString) + err := json.Unmarshal(data.Response.Result, &recordedString) if err != nil { - return newComparatorError(dbString, string(data.Response), data, block, cannotUnmarshalResult) + return newComparatorError(dbString, string(data.Response.Result), data, block, cannotUnmarshalResult) } // results do not match @@ -290,22 +298,22 @@ func compareCallStateDbResult(data *rpc.RequestAndResults, block int) *comparato } // internal error? - if data.Error.Code == internalErrorCode { - return newComparatorError(dbString, data.Error, data, block, internalError) + if data.Error.Error.Code == internalErrorCode { + return newComparatorError(dbString, data.Error.Error, data, block, internalError) } var msg string // do we know the error? - errs, ok := EvmErrors[data.Error.Code] + errs, ok := EvmErrors[data.Error.Error.Code] if !ok { - msg = fmt.Sprintf("unknown error code: %v", data.Error.Code) + msg = fmt.Sprintf("unknown error code: %v", data.Error.Error.Code) } else { // we could have potentially recorded a request with invalid arguments // - this is not checked in execution, hence StateDB returns a valid result. // For this we exclude any invalid requests when getting unmatched results - if data.Error.Code == invalidArgumentErrCode { + if data.Error.Error.Code == invalidArgumentErrCode { return nil } @@ -333,30 +341,30 @@ func compareCallStateDbResult(data *rpc.RequestAndResults, block int) *comparato func compareEVMStateDBError(data *rpc.RequestAndResults, block int) *comparatorError { if data.Error == nil { return newComparatorError( - data.ReturnState.Error, - data.Response, + data.StateDB.Error, + data.Response.Result, data, block, expectedResultGotError) } - for _, e := range EvmErrors[data.Error.Code] { - if strings.Contains(data.ReturnState.Error.Error(), e) { + for _, e := range EvmErrors[data.Error.Error.Code] { + if strings.Contains(data.StateDB.Error.Error(), e) { return nil } } - if data.Error.Code == internalErrorCode { - return newComparatorError(data.ReturnState.Error, data.Error, data, block, internalError) + if data.Error.Error.Code == internalErrorCode { + return newComparatorError(data.StateDB.Error, data.Error.Error, data, block, internalError) } builder := new(strings.Builder) builder.WriteString("one of these error messages: ") - for i, e := range EvmErrors[data.Error.Code] { + for i, e := range EvmErrors[data.Error.Error.Code] { builder.WriteString(e) - if i < len(EvmErrors[data.Error.Code]) { + if i < len(EvmErrors[data.Error.Error.Code]) { builder.WriteString(" or ") } } @@ -364,7 +372,7 @@ func compareEVMStateDBError(data *rpc.RequestAndResults, block int) *comparatorE msg := builder.String() return newComparatorError( - data.ReturnState.Error, + data.StateDB.Error, msg, data, block, @@ -375,12 +383,12 @@ func compareEVMStateDBError(data *rpc.RequestAndResults, block int) *comparatorE func compareEstimateGas(data *rpc.RequestAndResults, block int) *comparatorError { // StateDB returned an error - if data.ReturnState.Error != nil { + if data.StateDB.Error != nil { return compareEVMStateDBError(data, block) } // StateDB returned a result - if data.ReturnState.Result != nil { + if data.StateDB.Result != nil { return compareEstimateGasStateDBResult(data, block) } @@ -389,7 +397,7 @@ func compareEstimateGas(data *rpc.RequestAndResults, block int) *comparatorError // compareEstimateGasStateDBResult compares estimateGas data recorded on API server with data returned by StateDB func compareEstimateGasStateDBResult(data *rpc.RequestAndResults, block int) *comparatorError { - stateDBGas, ok := data.ReturnState.Result.(hexutil.Uint64) + stateDBGas, ok := data.StateDB.Result.(hexutil.Uint64) if !ok { return newUnexpectedDataTypeErr(data) } @@ -397,13 +405,13 @@ func compareEstimateGasStateDBResult(data *rpc.RequestAndResults, block int) *co // did we receive an error if data.Error != nil { // internal error? - if data.Error.Code == internalErrorCode { - return newComparatorError(stateDBGas, data.Error, data, block, internalError) + if data.Error.Error.Code == internalErrorCode { + return newComparatorError(stateDBGas, data.Error.Error, data, block, internalError) } return newComparatorError( stateDBGas, - EvmErrors[data.Error.Code], + EvmErrors[data.Error.Error.Code], data, block, expectedErrorGotResult) @@ -415,14 +423,14 @@ func compareEstimateGasStateDBResult(data *rpc.RequestAndResults, block int) *co ) // no error - err = json.Unmarshal(data.Response, &recordedString) + err = json.Unmarshal(data.Response.Result, &recordedString) if err != nil { - return newComparatorError(stateDBGas, string(data.Response), data, block, cannotUnmarshalResult) + return newComparatorError(stateDBGas, string(data.Response.Result), data, block, cannotUnmarshalResult) } recordedResult, err := hexutil.DecodeUint64(recordedString) if err != nil { - return newComparatorError(recordedResult, string(data.Response), data, block, cannotUnmarshalResult) + return newComparatorError(recordedResult, string(data.Response.Result), data, block, cannotUnmarshalResult) } if uint64(stateDBGas) != recordedResult { @@ -434,23 +442,23 @@ func compareEstimateGasStateDBResult(data *rpc.RequestAndResults, block int) *co // compareCode compares getCode data recorded on API server with data returned by StateDB func compareCode(data *rpc.RequestAndResults, block int) *comparatorError { - dbString := hexutil.Encode(data.ReturnState.Result.([]byte)) + dbString := hexutil.Encode(data.StateDB.Result.([]byte)) // did we data an error? if data.Error != nil { // internal error? - if data.Error.Code == internalErrorCode { - return newComparatorError(dbString, data.Error, data, block, internalError) + if data.Error.Error.Code == internalErrorCode { + return newComparatorError(dbString, data.Error.Error, data, block, internalError) } - return newComparatorError(dbString, data.Error, data, block, expectedErrorGotResult) + return newComparatorError(dbString, data.Error.Error, data, block, expectedErrorGotResult) } var recordedString string // no error - err := json.Unmarshal(data.Response, &recordedString) + err := json.Unmarshal(data.Response.Result, &recordedString) if err != nil { - return newComparatorError(dbString, string(data.Response), data, block, cannotUnmarshalResult) + return newComparatorError(dbString, string(data.Response.Result), data, block, cannotUnmarshalResult) } if !strings.EqualFold(recordedString, dbString) { @@ -462,22 +470,22 @@ func compareCode(data *rpc.RequestAndResults, block int) *comparatorError { // compareStorageAt compares getStorageAt data recorded on API server with data returned by StateDB func compareStorageAt(data *rpc.RequestAndResults, block int) *comparatorError { - dbString := hexutil.Encode(data.ReturnState.Result.([]byte)) + dbString := hexutil.Encode(data.StateDB.Result.([]byte)) if data.Error != nil { // internal error? - if data.Error.Code == internalErrorCode { - return newComparatorError(dbString, data.Error, data, block, internalError) + if data.Error.Error.Code == internalErrorCode { + return newComparatorError(dbString, data.Error.Error, data, block, internalError) } - return newComparatorError(dbString, data.Error, data, block, internalError) + return newComparatorError(dbString, data.Error.Error, data, block, internalError) } var recordedString string // no error - err := json.Unmarshal(data.Response, &recordedString) + err := json.Unmarshal(data.Response.Result, &recordedString) if err != nil { - return newComparatorError(dbString, string(data.Response), data, block, cannotUnmarshalResult) + return newComparatorError(dbString, string(data.Response.Result), data, block, cannotUnmarshalResult) } if !strings.EqualFold(recordedString, dbString) { @@ -524,7 +532,7 @@ func newCannotSendRPCRequestErr(data *rpc.RequestAndResults, block int) *compara "\n\tStateDB err: %v"+ "\n\tExpected result: %v"+ "\n\tExpected err: %v"+ - "\n\nParams: %v", data.Query.Method, strconv.FormatInt(int64(block), 16), data.ReturnState.Result, data.ReturnState.Error, data.Response, data.Error, string(data.ParamsRaw)), + "\n\nParams: %v", data.Query.Method, strconv.FormatInt(int64(block), 16), data.StateDB.Result, data.StateDB.Error, data.Response.Result, data.Error.Error, string(data.ParamsRaw)), typ: cannotSendRpcRequest, } } @@ -534,20 +542,20 @@ func newCannotSendRPCRequestErr(data *rpc.RequestAndResults, block int) *compara // is not related to StateDB func newInternalError(data *rpc.RequestAndResults, block int) *comparatorError { var stateDbRes string - if data.ReturnState.Result != nil { - stateDbRes = fmt.Sprintf("%v", data.ReturnState.Result) + if data.StateDB.Result != nil { + stateDbRes = fmt.Sprintf("%v", data.StateDB.Result) } else { - stateDbRes = fmt.Sprintf("%v", data.ReturnState.Error) + stateDbRes = fmt.Sprintf("%v", data.StateDB.Error) } var recordedRes string if data.Response != nil { - err := json.Unmarshal(data.Response, &recordedRes) + err := json.Unmarshal(data.Response.Result, &recordedRes) if err != nil { - return newComparatorError(data.Response, string(data.Response), data, block, cannotUnmarshalResult) + return newComparatorError(data.Response.Result, string(data.Response.Result), data, block, cannotUnmarshalResult) } } else { - recordedRes = fmt.Sprintf("err: %v", data.Error) + recordedRes = fmt.Sprintf("err: %v", data.Error.Error) } return &comparatorError{ @@ -572,7 +580,7 @@ func newCannotUnmarshalResult(data *rpc.RequestAndResults, block int) *comparato "\n\tStateDB err: %v"+ "\n\tRecorded result: %v"+ "\n\tRecorded err: %v"+ - "\n\nParams: %v", data.Query.Method, strconv.FormatInt(int64(block), 16), data.ReturnState.Result, data.ReturnState.Error, data.Response, data.Error, string(data.ParamsRaw)), + "\n\nParams: %v", data.Query.Method, strconv.FormatInt(int64(block), 16), data.StateDB.Result, data.StateDB.Error, data.Response.Result, data.Error.Error, string(data.ParamsRaw)), typ: cannotUnmarshalResult, } } diff --git a/executor/extension/validator/rpc_comparator_test.go b/executor/extension/validator/rpc_comparator_test.go index 76e02e5f4..bc4630f52 100644 --- a/executor/extension/validator/rpc_comparator_test.go +++ b/executor/extension/validator/rpc_comparator_test.go @@ -53,8 +53,10 @@ func TestRPCComparator_PostTransactionDoesNotFailAndAppendsAndLogsErrorIfContinu Query: &rpc.Body{ MethodBase: "getBalance", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: bigRes, }, } @@ -92,8 +94,10 @@ func TestRPCComparator_PostTransactionFailsWhenContinueOnFailureIsNotEnabled(t * Query: &rpc.Body{ MethodBase: "getBalance", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: bigRes, }, } @@ -120,8 +124,10 @@ func Test_compareBalanceOK(t *testing.T) { Query: &rpc.Body{ Method: "ftm_getBalance", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: bigRes, }, } @@ -143,8 +149,10 @@ func Test_compareBalanceErrorNoMatchingResult(t *testing.T) { Query: &rpc.Body{ Method: "ftm_getBalance", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: bigRes, }, } @@ -170,8 +178,10 @@ func Test_compareTransactionCountOK(t *testing.T) { Query: &rpc.Body{ Method: "ftm_getTransactionCount", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: uint64(1), }, } @@ -193,8 +203,10 @@ func Test_compareTransactionCountErrorNoMatchingResult(t *testing.T) { Query: &rpc.Body{ Method: "ftm_getTransactionCount", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: uint64(1), }, } @@ -220,8 +232,10 @@ func Test_compareCallOK(t *testing.T) { Query: &rpc.Body{ Method: "ftm_call", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: hexutils.HexToBytes(strings.TrimPrefix(longHexOne, "0x")), }, } @@ -241,8 +255,10 @@ func Test_compareCallErrorNoMatchingResult(t *testing.T) { Query: &rpc.Body{ Method: "ftm_call", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: hexutils.HexToBytes(strings.TrimPrefix(longHexZero, "0x")), }, } @@ -266,8 +282,10 @@ func Test_compareCallErrorExpectedResultGotErr(t *testing.T) { Query: &rpc.Body{ Method: "eth_call", }, - Response: []byte(hexOne), - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: []byte(hexOne), + }, + StateDB: &rpc.StateDBData{ Error: errors.New("err"), }, } @@ -291,11 +309,13 @@ func Test_compareCallErrorExpectedErrGotResult(t *testing.T) { Query: &rpc.Body{ Method: "eth_call", }, - Error: &rpc.Error{ - Code: -32000, - Message: "error", + Error: &rpc.ErrorResponse{ + Error: rpc.ErrorMessage{ + Code: -32000, + Message: "error", + }, }, - ReturnState: &rpc.ReturnState{ + StateDB: &rpc.StateDBData{ Result: hexutils.HexToBytes(strings.TrimPrefix(longHexZero, "0x")), }, } @@ -321,8 +341,10 @@ func Test_compareEstimateGasOK(t *testing.T) { Query: &rpc.Body{ Method: "eth_estimateGas", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: hexutil.Uint64(1), }, } @@ -342,8 +364,10 @@ func Test_compareEstimateGasErrorNoMatchingResult(t *testing.T) { Query: &rpc.Body{ Method: "eth_estimateGas", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: hexutil.Uint64(0), }, } @@ -367,8 +391,10 @@ func Test_compareEstimateGasErrorExpectedResultGotErr(t *testing.T) { Query: &rpc.Body{ Method: "eth_estimateGas", }, - Response: []byte(hexOne), - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: []byte(hexOne), + }, + StateDB: &rpc.StateDBData{ Error: errors.New("error"), }, } @@ -391,11 +417,13 @@ func Test_compareEstimateGasErrorExpectedErrGotResult(t *testing.T) { Query: &rpc.Body{ Method: "eth_estimateGas", }, - Error: &rpc.Error{ - Code: 1000, - Message: "error", + Error: &rpc.ErrorResponse{ + Error: rpc.ErrorMessage{ + Code: 1000, + Message: "error", + }, }, - ReturnState: &rpc.ReturnState{ + StateDB: &rpc.StateDBData{ Result: hexutil.Uint64(0), }, } @@ -421,8 +449,10 @@ func Test_compareCodeOK(t *testing.T) { Query: &rpc.Body{ Method: "eth_getCode", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: hexutils.HexToBytes(strings.TrimPrefix(longHexOne, "0x")), }, } @@ -442,8 +472,10 @@ func Test_compareCodeErrorNoMatchingResult(t *testing.T) { Query: &rpc.Body{ Method: "eth_getCode", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: hexutils.HexToBytes(strings.TrimPrefix(longHexZero, "0x")), }, } @@ -469,8 +501,10 @@ func Test_compareStorageAtOK(t *testing.T) { Query: &rpc.Body{ Method: "eth_getStorageAt", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: hexutils.HexToBytes(strings.TrimPrefix(longHexOne, "0x")), }, } @@ -490,8 +524,10 @@ func Test_compareStorageAtErrorNoMatchingResult(t *testing.T) { Query: &rpc.Body{ Method: "eth_getStorageAt", }, - Response: rec, - ReturnState: &rpc.ReturnState{ + Response: &rpc.Response{ + Result: rec, + }, + StateDB: &rpc.StateDBData{ Result: hexutils.HexToBytes(strings.TrimPrefix(longHexZero, "0x")), }, } diff --git a/executor/rpc_request_provider.go b/executor/rpc_request_provider.go index a59a75e11..f38863375 100644 --- a/executor/rpc_request_provider.go +++ b/executor/rpc_request_provider.go @@ -31,6 +31,7 @@ type rpcRequestProvider struct { } func (r rpcRequestProvider) Run(from int, to int, consumer Consumer[*rpc.RequestAndResults]) error { + var blockNumber int for r.iter.Next() { if r.iter.Error() != nil { @@ -43,16 +44,22 @@ func (r rpcRequestProvider) Run(from int, to int, consumer Consumer[*rpc.Request return nil } + if req.Response != nil { + blockNumber = int(req.Response.BlockID) + } else { + blockNumber = int(req.Error.BlockID) + } + // are we skipping requests? - if req.Block < from { + if blockNumber < from { continue } - if req.Block >= to { + if blockNumber >= to { return nil } - if err := consumer(TransactionInfo[*rpc.RequestAndResults]{req.Block, 0, req}); err != nil { + if err := consumer(TransactionInfo[*rpc.RequestAndResults]{blockNumber, 0, req}); err != nil { return err } } diff --git a/executor/rpc_request_provider_test.go b/executor/rpc_request_provider_test.go index cfc8bbb47..01f862769 100644 --- a/executor/rpc_request_provider_test.go +++ b/executor/rpc_request_provider_test.go @@ -111,23 +111,33 @@ func TestRPCRequestProvider_ErrorReturnedByIteratorEndsTheApp(t *testing.T) { } var validResp = &rpc.RequestAndResults{ - Block: 10, - Timestamp: 10, - Query: nil, - Response: json.RawMessage{}, + Query: nil, + Response: &rpc.Response{ + Version: "2.0", + ID: json.RawMessage{1}, + BlockID: 10, + Timestamp: 10, + Result: nil, + Payload: nil, + }, Error: nil, ParamsRaw: nil, ResponseRaw: nil, } var errResp = &rpc.RequestAndResults{ - Block: 10, - Timestamp: 10, - Query: nil, - Response: nil, - Error: &rpc.Error{ - Code: -1, - Message: "err", + Query: nil, + Response: nil, + Error: &rpc.ErrorResponse{ + Version: "2.0", + Id: json.RawMessage{1}, + BlockID: 10, + Timestamp: 10, + Error: rpc.ErrorMessage{ + Code: -1, + Message: "err", + }, + Payload: nil, }, ParamsRaw: nil, ResponseRaw: nil, diff --git a/rpc/execute.go b/rpc/execute.go index 6fc94a5b3..aefcda7b2 100644 --- a/rpc/execute.go +++ b/rpc/execute.go @@ -2,6 +2,7 @@ package rpc import ( "math/big" + "time" "github.com/Fantom-foundation/Aida/state" "github.com/Fantom-foundation/Aida/utils" @@ -9,15 +10,15 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// ReturnState represents data that StateDB returned for requests recorded on API server +// StateDBData represents data that StateDB returned for requests recorded on API server // This is sent to Comparator and compared with RecordedData -type ReturnState struct { +type StateDBData struct { Result any Error error isRecovered bool } -func Execute(block uint64, rec *RequestAndResults, archive state.NonCommittableStateDB, cfg *utils.Config) *ReturnState { +func Execute(block uint64, rec *RequestAndResults, archive state.NonCommittableStateDB, cfg *utils.Config) *StateDBData { switch rec.Query.MethodBase { case "getBalance": return executeGetBalance(rec.Query.Params[0], archive) @@ -26,11 +27,25 @@ func Execute(block uint64, rec *RequestAndResults, archive state.NonCommittableS return executeGetTransactionCount(rec.Query.Params[0], archive) case "call": - if rec.Timestamp == 0 { + var timestamp uint64 + + // first try to extract timestamp from response + if rec.Response != nil { + if rec.Response.Timestamp != 0 { + timestamp = uint64(time.Unix(0, int64(rec.Response.Timestamp)).Unix()) + } + } else if rec.Error != nil { + if rec.Error.Timestamp != 0 { + + timestamp = uint64(time.Unix(0, int64(rec.Error.Timestamp)).Unix()) + } + } + + if timestamp == 0 { return nil } - evm := newEvmExecutor(block, archive, cfg, rec.Query.Params[0].(map[string]interface{}), rec.Timestamp) + evm := newEvmExecutor(block, archive, cfg, rec.Query.Params[0].(map[string]interface{}), timestamp) return executeCall(evm) case "estimateGas": @@ -49,12 +64,12 @@ func Execute(block uint64, rec *RequestAndResults, archive state.NonCommittableS } // executeGetBalance request into given archive and send result to comparator -func executeGetBalance(param interface{}, archive state.VmStateDB) (out *ReturnState) { +func executeGetBalance(param interface{}, archive state.VmStateDB) (out *StateDBData) { var ( address common.Address ) - out = new(ReturnState) + out = new(StateDBData) out.Result = new(big.Int) // decode requested address @@ -67,12 +82,12 @@ func executeGetBalance(param interface{}, archive state.VmStateDB) (out *ReturnS } // executeGetTransactionCount request into given archive and send result to comparator -func executeGetTransactionCount(param interface{}, archive state.VmStateDB) (out *ReturnState) { +func executeGetTransactionCount(param interface{}, archive state.VmStateDB) (out *StateDBData) { var ( address common.Address ) - out = new(ReturnState) + out = new(StateDBData) // decode requested address address = common.HexToAddress(param.(string)) @@ -84,13 +99,13 @@ func executeGetTransactionCount(param interface{}, archive state.VmStateDB) (out } // executeCall into EvmExecutor and return the result -func executeCall(evm *EvmExecutor) (out *ReturnState) { +func executeCall(evm *EvmExecutor) (out *StateDBData) { var ( result *evmcore.ExecutionResult err error ) - out = new(ReturnState) + out = new(StateDBData) // get the result from EvmExecutor result, err = evm.sendCall() @@ -106,8 +121,8 @@ func executeCall(evm *EvmExecutor) (out *ReturnState) { } // executeEstimateGas into EvmExecutor which calculates gas needed for a transaction -func executeEstimateGas(evm *EvmExecutor) (out *ReturnState) { - out = new(ReturnState) +func executeEstimateGas(evm *EvmExecutor) (out *StateDBData) { + out = new(StateDBData) out.Result, out.Error = evm.sendEstimateGas() @@ -115,12 +130,12 @@ func executeEstimateGas(evm *EvmExecutor) (out *ReturnState) { } // executeGetCode request into given archive and send result to comparator -func executeGetCode(param interface{}, archive state.VmStateDB) (out *ReturnState) { +func executeGetCode(param interface{}, archive state.VmStateDB) (out *StateDBData) { var ( address common.Address ) - out = new(ReturnState) + out = new(StateDBData) // decode requested address address = common.HexToAddress(param.(string)) @@ -132,13 +147,13 @@ func executeGetCode(param interface{}, archive state.VmStateDB) (out *ReturnStat } // executeGetStorageAt request into given archive and send result to comparator -func executeGetStorageAt(params []interface{}, archive state.VmStateDB) (out *ReturnState) { +func executeGetStorageAt(params []interface{}, archive state.VmStateDB) (out *StateDBData) { var ( address common.Address hash, res common.Hash ) - out = new(ReturnState) + out = new(StateDBData) // decode requested address and position in storage address = common.HexToAddress(params[0].(string)) diff --git a/rpc/header.go b/rpc/header.go index 1fc70711f..95f67ca85 100644 --- a/rpc/header.go +++ b/rpc/header.go @@ -62,7 +62,7 @@ type Header struct { isLongResult bool querySize int32 resultCodeSize int32 // also used for error code; see ERR flag - blockID int + blockID uint64 blockTimestamp uint64 } @@ -155,12 +155,12 @@ func (h *Header) Method() (string, error) { } // SetBlockID configures the ID of a block context the query was executed under. -func (h *Header) SetBlockID(id int) { +func (h *Header) SetBlockID(id uint64) { h.blockID = id } // BlockID returns the block ID of the data. -func (h *Header) BlockID() int { +func (h *Header) BlockID() uint64 { return h.blockID } @@ -385,7 +385,7 @@ func (h *Header) decodeFields(hdr []byte) { offset += 2 } - h.blockID = int(binary.BigEndian.Uint32(hdr[offset : offset+4])) + h.blockID = uint64(binary.BigEndian.Uint32(hdr[offset : offset+4])) switch h.version { case 1: diff --git a/rpc/iterator.go b/rpc/iterator.go index d187a40b6..99f4c8f47 100644 --- a/rpc/iterator.go +++ b/rpc/iterator.go @@ -161,19 +161,24 @@ func (i *iterator) decode(hdr *Header, namespace, method string) (*RequestAndRes return nil, err } - req.Response = req.ResponseRaw + req.Response = &Response{ + BlockID: hdr.BlockID(), + Result: req.ResponseRaw, + Timestamp: hdr.BlockTimestamp(), + } } // error? if hdr.IsError() { - req.Error = &Error{ - Code: hdr.ErrorCode(), + req.Error = &ErrorResponse{ + BlockID: hdr.BlockID(), + Timestamp: hdr.BlockTimestamp(), + Error: ErrorMessage{ + Code: hdr.ErrorCode(), + }, } } - req.Timestamp = hdr.BlockTimestamp() - req.Block = hdr.BlockID() - return &req, nil } diff --git a/rpc/request.go b/rpc/request.go index 5c70f08e9..993e9ef97 100644 --- a/rpc/request.go +++ b/rpc/request.go @@ -5,13 +5,11 @@ import "encoding/json" // RequestAndResults encapsulates request query and response for post-processing. type RequestAndResults struct { Query *Body - Response json.RawMessage - Error *Error + Response *Response + Error *ErrorResponse ParamsRaw []byte ResponseRaw []byte - ReturnState *ReturnState // ReturnState is attached after execution is completed - Timestamp uint64 - Block int + StateDB *StateDBData } // Body represents a decoded payload of a balancer. @@ -25,8 +23,28 @@ type Body struct { MethodBase string } -// Error represents the detailed error information inside an error response. -type Error struct { +// Response represents decoded request response body. +type Response struct { + Version string `json:"jsonrpc,omitempty"` + ID json.RawMessage `json:"id,omitempty"` + BlockID uint64 `json:"blockid,omitempty"` + Timestamp uint64 `json:"timestamp,omitempty"` + Result json.RawMessage `json:"result,omitempty"` + Payload []byte `json:"-"` +} + +// ErrorResponse represents a structure of error response from the remote server +type ErrorResponse struct { + Version string `json:"jsonrpc,omitempty"` + Id json.RawMessage `json:"id,omitempty"` + BlockID uint64 `json:"blockid,omitempty"` + Timestamp uint64 `json:"timestamp,omitempty"` + Error ErrorMessage `json:"error,omitempty"` + Payload []byte `json:"-"` +} + +// ErrorMessage represents the detailed error information inside an error response. +type ErrorMessage struct { Code int `json:"code,omitempty"` Message string `json:"message,omitempty"` }