diff --git a/api/coreservice.go b/api/coreservice.go index 62448ab37d..fb870a36ca 100644 --- a/api/coreservice.go +++ b/api/coreservice.go @@ -78,6 +78,7 @@ const ( type ( // CoreService provides api interface for user to interact with blockchain data CoreService interface { + WithHeight(uint64) CoreServiceReaderWithHeight // Account returns the metadata of an account Account(addr address.Address) (*iotextypes.AccountMeta, *iotextypes.BlockIdentifier, error) // ChainMeta returns blockchain metadata @@ -1831,6 +1832,10 @@ func (core *coreService) Track(ctx context.Context, start time.Time, method stri }, size) } +func (core *coreService) WithHeight(height uint64) CoreServiceReaderWithHeight { + return newCoreServiceWithHeight(core, height) +} + func (core *coreService) traceTx(ctx context.Context, txctx *tracers.Context, config *tracers.TraceConfig, simulateFn func(ctx context.Context) ([]byte, *action.Receipt, error)) ([]byte, *action.Receipt, any, error) { var ( tracer vm.EVMLogger diff --git a/api/coreservice_with_height.go b/api/coreservice_with_height.go new file mode 100644 index 0000000000..0b7ff09022 --- /dev/null +++ b/api/coreservice_with_height.go @@ -0,0 +1,150 @@ +package api + +import ( + "context" + "encoding/hex" + "fmt" + "math/big" + + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-proto/golang/iotexapi" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/pkg/errors" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + + "github.com/iotexproject/iotex-core/action/protocol" + accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util" + "github.com/iotexproject/iotex-core/action/protocol/execution/evm" + "github.com/iotexproject/iotex-core/blockchain/genesis" + "github.com/iotexproject/iotex-core/pkg/tracer" +) + +type ( + CoreServiceReaderWithHeight interface { + Account(addr address.Address) (*iotextypes.AccountMeta, *iotextypes.BlockIdentifier, error) + } + + coreServiceReaderWithHeight struct { + cs *coreService + height uint64 + } +) + +func newCoreServiceWithHeight(cs *coreService, height uint64) *coreServiceReaderWithHeight { + return &coreServiceReaderWithHeight{ + cs: cs, + height: height, + } +} + +func (core *coreServiceReaderWithHeight) Account(addr address.Address) (*iotextypes.AccountMeta, *iotextypes.BlockIdentifier, error) { + ctx, span := tracer.NewSpan(context.Background(), "coreService.Account") + defer span.End() + addrStr := addr.String() + if addrStr == address.RewardingPoolAddr || addrStr == address.StakingBucketPoolAddr { + return core.cs.getProtocolAccount(ctx, addrStr) + } + span.AddEvent("accountutil.AccountStateWithHeight") + ctx = genesis.WithGenesisContext(ctx, core.cs.bc.Genesis()) + stateReader := newStateReaderWithHeight(core.cs.sf, core.height) + state, tipHeight, err := accountutil.AccountStateWithHeight(ctx, stateReader, addr) + if err != nil { + return nil, nil, status.Error(codes.NotFound, err.Error()) + } + var pendingNonce uint64 + ctx = protocol.WithFeatureCtx(protocol.WithBlockCtx(ctx, protocol.BlockCtx{ + BlockHeight: core.height, + })) + if protocol.MustGetFeatureCtx(ctx).RefactorFreshAccountConversion { + pendingNonce = state.PendingNonceConsideringFreshAccount() + } else { + pendingNonce = state.PendingNonce() + } + span.AddEvent("indexer.GetActionCount") + // TODO: get action count from indexer + numActions := uint64(0) + // numActions, err := core.cs.indexer.GetActionCountByAddress(hash.BytesToHash160(addr.Bytes())) + // if err != nil { + // return nil, nil, status.Error(codes.NotFound, err.Error()) + // } + // TODO: deprecate nonce field in account meta + accountMeta := &iotextypes.AccountMeta{ + Address: addrStr, + Balance: state.Balance.String(), + Nonce: pendingNonce, + NumActions: numActions, + IsContract: state.IsContract(), + } + if state.IsContract() { + var code protocol.SerializableBytes + _, err = stateReader.State(&code, protocol.NamespaceOption(evm.CodeKVNameSpace), protocol.KeyOption(state.CodeHash)) + if err != nil { + return nil, nil, status.Error(codes.NotFound, err.Error()) + } + accountMeta.ContractByteCode = code + } + span.AddEvent("bc.BlockHeaderByHeight") + header, err := core.cs.bc.BlockHeaderByHeight(core.height) + if err != nil { + return nil, nil, status.Error(codes.NotFound, err.Error()) + } + hash := header.HashBlock() + span.AddEvent("coreService.Account.End") + return accountMeta, &iotextypes.BlockIdentifier{ + Hash: hex.EncodeToString(hash[:]), + Height: tipHeight, + }, nil +} + +func (core *coreServiceReaderWithHeight) getProtocolAccount(ctx context.Context, addr string) (*iotextypes.AccountMeta, *iotextypes.BlockIdentifier, error) { + span := tracer.SpanFromContext(ctx) + defer span.End() + var ( + balance string + out *iotexapi.ReadStateResponse + err error + ) + heightStr := fmt.Sprintf("%d", core.height) + switch addr { + case address.RewardingPoolAddr: + if out, err = core.cs.ReadState("rewarding", heightStr, []byte("TotalBalance"), nil); err != nil { + return nil, nil, err + } + val, ok := new(big.Int).SetString(string(out.GetData()), 10) + if !ok { + return nil, nil, errors.New("balance convert error") + } + balance = val.String() + case address.StakingBucketPoolAddr: + methodName, err := proto.Marshal(&iotexapi.ReadStakingDataMethod{ + Method: iotexapi.ReadStakingDataMethod_TOTAL_STAKING_AMOUNT, + }) + if err != nil { + return nil, nil, err + } + arg, err := proto.Marshal(&iotexapi.ReadStakingDataRequest{ + Request: &iotexapi.ReadStakingDataRequest_TotalStakingAmount_{ + TotalStakingAmount: &iotexapi.ReadStakingDataRequest_TotalStakingAmount{}, + }, + }) + if err != nil { + return nil, nil, err + } + if out, err = core.cs.ReadState("staking", heightStr, methodName, [][]byte{arg}); err != nil { + return nil, nil, err + } + acc := iotextypes.AccountMeta{} + if err := proto.Unmarshal(out.GetData(), &acc); err != nil { + return nil, nil, errors.Wrap(err, "failed to unmarshal account meta") + } + balance = acc.GetBalance() + default: + return nil, nil, errors.Errorf("invalid address %s", addr) + } + return &iotextypes.AccountMeta{ + Address: addr, + Balance: balance, + }, out.GetBlockIdentifier(), nil +} diff --git a/api/grpcserver_test.go b/api/grpcserver_test.go index 73d1ea85f8..042361eda8 100644 --- a/api/grpcserver_test.go +++ b/api/grpcserver_test.go @@ -24,7 +24,6 @@ import ( "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/pkg/version" "github.com/iotexproject/iotex-core/test/identityset" - "github.com/iotexproject/iotex-core/test/mock/mock_apicoreservice" mock_apitypes "github.com/iotexproject/iotex-core/test/mock/mock_apiresponder" ) @@ -32,7 +31,7 @@ func TestGrpcServer_GetAccount(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) t.Run("get acccount", func(t *testing.T) { @@ -80,7 +79,7 @@ func TestGrpcServer_GetActions(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) t.Run("get actions by address tests", func(t *testing.T) { @@ -248,7 +247,7 @@ func TestGrpcServer_GetBlockMetas(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) errStr := "get block metas mock test error" @@ -302,7 +301,7 @@ func TestGrpcServer_GetChainMeta(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) chainMeta := &iotextypes.ChainMeta{ Height: 1000, @@ -323,7 +322,7 @@ func TestGrpcServer_SendAction(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) for _, test := range _sendActionTests { @@ -339,7 +338,7 @@ func TestGrpcServer_StreamBlocks(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) t.Run("addResponder failed", func(t *testing.T) { @@ -368,7 +367,7 @@ func TestGrpcServer_StreamLogs(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) t.Run("StreamLogsEmptyFilter", func(t *testing.T) { @@ -400,7 +399,7 @@ func TestGrpcServer_GetReceiptByAction(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) receipt := &action.Receipt{ Status: 1, @@ -448,7 +447,7 @@ func TestGrpcServer_GetServerMeta(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) core.EXPECT().ServerMeta().Return("packageVersion", "packageCommitID", "gitStatus", "goVersion", "buildTime") @@ -465,7 +464,7 @@ func TestGrpcServer_ReadContract(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) response := &iotextypes.Receipt{ ActHash: []byte("08b0066e10b5607e47159c2cf7ba36e36d0c980f5108dfca0ec20547a7adace4"), @@ -549,7 +548,7 @@ func TestGrpcServer_SuggestGasPrice(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) core.EXPECT().SuggestGasPrice().Return(uint64(1), nil) @@ -566,7 +565,7 @@ func TestGrpcServer_EstimateGasForAction(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) core.EXPECT().EstimateGasForAction(gomock.Any(), gomock.Any()).Return(uint64(10000), nil) @@ -583,7 +582,7 @@ func TestGrpcServer_EstimateActionGasConsumption(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) request := &iotexapi.EstimateActionGasConsumptionRequest{ CallerAddress: identityset.Address(0).String(), @@ -743,7 +742,7 @@ func TestGrpcServer_ReadState(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) core.EXPECT().ReadState(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&iotexapi.ReadStateResponse{ Data: []byte("10100"), @@ -760,7 +759,7 @@ func TestGrpcServer_GetEpochMeta(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) epochData := &iotextypes.EpochData{Num: 7000} blockProducersInfo := []*iotexapi.BlockProducerInfo{{Production: 8000}} @@ -778,7 +777,7 @@ func TestGrpcServer_GetRawBlocks(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) blocks := []*iotexapi.BlockInfo{ @@ -822,7 +821,7 @@ func TestGrpcServer_GetLogs(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) request := &iotexapi.GetLogsRequest{ Filter: &iotexapi.LogsFilter{ @@ -908,7 +907,7 @@ func TestGrpcServer_GetElectionBuckets(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) buckets := []*iotextypes.ElectionBucket{ @@ -929,7 +928,7 @@ func TestGrpcServer_GetTransactionLogByActionHash(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) txLog := &iotextypes.TransactionLog{ @@ -948,7 +947,7 @@ func TestGrpcServer_GetTransactionLogByBlockHeight(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) blockIdentifier := &iotextypes.BlockIdentifier{ @@ -975,7 +974,7 @@ func TestGrpcServer_GetActPoolActions(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) addr1 := identityset.Address(28).String() @@ -1001,7 +1000,7 @@ func TestGrpcServer_ReadContractStorage(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) core.EXPECT().ReadContractStorage(gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte("_data"), nil) @@ -1017,7 +1016,7 @@ func TestGrpcServer_TraceTransactionStructLogs(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) grpcSvr := newGRPCHandler(core) core.EXPECT().TraceTransaction(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil, logger.NewStructLogger(nil), nil) diff --git a/test/mock/mock_apicoreservice/mock_apicoreservice.go b/api/mock_apicoreservice.go similarity index 96% rename from test/mock/mock_apicoreservice/mock_apicoreservice.go rename to api/mock_apicoreservice.go index 4ebb8bd255..ea6342054f 100644 --- a/test/mock/mock_apicoreservice/mock_apicoreservice.go +++ b/api/mock_apicoreservice.go @@ -1,8 +1,8 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./api/coreservice.go -// Package mock_apicoreservice is a generated GoMock package. -package mock_apicoreservice +// Package api is a generated GoMock package. +package api import ( context "context" @@ -16,7 +16,7 @@ import ( address "github.com/iotexproject/iotex-address/address" action "github.com/iotexproject/iotex-core/action" logfilter "github.com/iotexproject/iotex-core/api/logfilter" - apitypes "github.com/iotexproject/iotex-core/api/types" + types "github.com/iotexproject/iotex-core/api/types" block "github.com/iotexproject/iotex-core/blockchain/block" genesis "github.com/iotexproject/iotex-core/blockchain/genesis" iotexapi "github.com/iotexproject/iotex-proto/golang/iotexapi" @@ -140,10 +140,10 @@ func (mr *MockCoreServiceMockRecorder) ActionsInActPool(actHashes interface{}) * } // BlockByHash mocks base method. -func (m *MockCoreService) BlockByHash(arg0 string) (*apitypes.BlockWithReceipts, error) { +func (m *MockCoreService) BlockByHash(arg0 string) (*types.BlockWithReceipts, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlockByHash", arg0) - ret0, _ := ret[0].(*apitypes.BlockWithReceipts) + ret0, _ := ret[0].(*types.BlockWithReceipts) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -155,10 +155,10 @@ func (mr *MockCoreServiceMockRecorder) BlockByHash(arg0 interface{}) *gomock.Cal } // BlockByHeight mocks base method. -func (m *MockCoreService) BlockByHeight(arg0 uint64) (*apitypes.BlockWithReceipts, error) { +func (m *MockCoreService) BlockByHeight(arg0 uint64) (*types.BlockWithReceipts, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlockByHeight", arg0) - ret0, _ := ret[0].(*apitypes.BlockWithReceipts) + ret0, _ := ret[0].(*types.BlockWithReceipts) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -170,10 +170,10 @@ func (mr *MockCoreServiceMockRecorder) BlockByHeight(arg0 interface{}) *gomock.C } // BlockByHeightRange mocks base method. -func (m *MockCoreService) BlockByHeightRange(arg0, arg1 uint64) ([]*apitypes.BlockWithReceipts, error) { +func (m *MockCoreService) BlockByHeightRange(arg0, arg1 uint64) ([]*types.BlockWithReceipts, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlockByHeightRange", arg0, arg1) - ret0, _ := ret[0].([]*apitypes.BlockWithReceipts) + ret0, _ := ret[0].([]*types.BlockWithReceipts) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -214,10 +214,10 @@ func (mr *MockCoreServiceMockRecorder) ChainID() *gomock.Call { } // ChainListener mocks base method. -func (m *MockCoreService) ChainListener() apitypes.Listener { +func (m *MockCoreService) ChainListener() types.Listener { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ChainListener") - ret0, _ := ret[0].(apitypes.Listener) + ret0, _ := ret[0].(types.Listener) return ret0 } @@ -713,6 +713,20 @@ func (mr *MockCoreServiceMockRecorder) UnconfirmedActionsByAddress(address, star return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnconfirmedActionsByAddress", reflect.TypeOf((*MockCoreService)(nil).UnconfirmedActionsByAddress), address, start, count) } +// WithHeight mocks base method. +func (m *MockCoreService) WithHeight(arg0 uint64) CoreServiceReaderWithHeight { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WithHeight", arg0) + ret0, _ := ret[0].(CoreServiceReaderWithHeight) + return ret0 +} + +// WithHeight indicates an expected call of WithHeight. +func (mr *MockCoreServiceMockRecorder) WithHeight(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WithHeight", reflect.TypeOf((*MockCoreService)(nil).WithHeight), arg0) +} + // MockintrinsicGasCalculator is a mock of intrinsicGasCalculator interface. type MockintrinsicGasCalculator struct { ctrl *gomock.Controller diff --git a/api/serverV2_test.go b/api/serverV2_test.go index 00e4f338cd..36833fdece 100644 --- a/api/serverV2_test.go +++ b/api/serverV2_test.go @@ -14,7 +14,6 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/time/rate" - "github.com/iotexproject/iotex-core/test/mock/mock_apicoreservice" "github.com/iotexproject/iotex-core/testutil" ) @@ -22,7 +21,7 @@ func TestServerV2(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3Handler := NewWeb3Handler(core, "", _defaultBatchRequestLimit) svr := &ServerV2{ core: core, diff --git a/api/statereader.go b/api/statereader.go new file mode 100644 index 0000000000..88b8b8bfe6 --- /dev/null +++ b/api/statereader.go @@ -0,0 +1,35 @@ +package api + +import ( + "github.com/pkg/errors" + + "github.com/iotexproject/iotex-core/action/protocol" + "github.com/iotexproject/iotex-core/state" + "github.com/iotexproject/iotex-core/state/factory" +) + +type stateReaderWithHeight struct { + f factory.Factory + height uint64 +} + +func newStateReaderWithHeight(f factory.Factory, height uint64) *stateReaderWithHeight { + return &stateReaderWithHeight{f: f, height: height} +} + +func (sr *stateReaderWithHeight) State(obj interface{}, opts ...protocol.StateOption) (uint64, error) { + return sr.height, sr.f.StateAtHeight(sr.height, obj, opts...) +} + +func (sr *stateReaderWithHeight) States(opts ...protocol.StateOption) (uint64, state.Iterator, error) { + iter, err := sr.f.StatesAtHeight(sr.height, opts...) + return sr.height, iter, err +} + +func (sr *stateReaderWithHeight) Height() (uint64, error) { + return sr.height, nil +} + +func (sr *stateReaderWithHeight) ReadView(string) (interface{}, error) { + return nil, errors.New(" ReadView is not supported in stateReaderWithHeight") +} diff --git a/api/web3server.go b/api/web3server.go index ce4076b663..5c42be37d0 100644 --- a/api/web3server.go +++ b/api/web3server.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/rpc" "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/go-pkgs/hash" "github.com/iotexproject/go-pkgs/util" @@ -332,7 +333,18 @@ func (svr *web3Handler) getBalance(in *gjson.Result) (interface{}, error) { if err != nil { return nil, err } - accountMeta, _, err := svr.coreService.Account(ioAddr) + heightParam := in.Get("params.1") + height, err := parseBlockNumber(&heightParam) + if err != nil { + return nil, err + } + var accountMeta *iotextypes.AccountMeta + if height == rpc.LatestBlockNumber { + accountMeta, _, err = svr.coreService.Account(ioAddr) + } else { + accountMeta, _, err = svr.coreService.WithHeight(uint64(height.Int64())).Account(ioAddr) + } + if err != nil { return nil, err } diff --git a/api/web3server_test.go b/api/web3server_test.go index dde1b5783a..b56bd92d0c 100644 --- a/api/web3server_test.go +++ b/api/web3server_test.go @@ -30,7 +30,6 @@ import ( apitypes "github.com/iotexproject/iotex-core/api/types" "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/test/identityset" - "github.com/iotexproject/iotex-core/test/mock/mock_apicoreservice" mock_apitypes "github.com/iotexproject/iotex-core/test/mock/mock_apiresponder" "github.com/iotexproject/iotex-core/testutil" ) @@ -100,7 +99,7 @@ func TestHandlePost(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) core.EXPECT().Track(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return().AnyTimes() svr := newHTTPHandler(NewWeb3Handler(core, "", _defaultBatchRequestLimit)) getServerResp := func(svr *hTTPHandler, req *http.Request) *httptest.ResponseRecorder { @@ -169,7 +168,7 @@ func TestGasPrice(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} core.EXPECT().SuggestGasPrice().Return(uint64(1), nil) ret, err := web3svr.gasPrice() @@ -185,7 +184,7 @@ func TestGetChainID(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} core.EXPECT().EVMNetworkID().Return(uint32(1)) ret, err := web3svr.getChainID() @@ -197,7 +196,7 @@ func TestGetBlockNumber(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} core.EXPECT().TipHeight().Return(uint64(1)) ret, err := web3svr.getBlockNumber() @@ -209,7 +208,7 @@ func TestGetBlockByNumber(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} tsf, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(27), uint64(1), big.NewInt(10), []byte{}, uint64(100000), big.NewInt(0)) @@ -260,7 +259,7 @@ func TestGetBalance(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} balance := "111111111111111111" core.EXPECT().Account(gomock.Any()).Return(&iotextypes.AccountMeta{Balance: balance}, nil, nil) @@ -277,7 +276,7 @@ func TestGetTransactionCount(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} core.EXPECT().PendingNonce(gomock.Any()).Return(uint64(2), nil) @@ -295,7 +294,7 @@ func TestCall(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} t.Run("to is StakingProtocol addr", func(t *testing.T) { @@ -386,7 +385,7 @@ func TestEstimateGas(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} core.EXPECT().ChainID().Return(uint32(1)).Times(2) @@ -431,7 +430,7 @@ func TestSendRawTransaction(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} core.EXPECT().EVMNetworkID().Return(uint32(1)) core.EXPECT().ChainID().Return(uint32(1)) @@ -456,7 +455,7 @@ func TestGetCode(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} code := "608060405234801561001057600080fd5b50610150806100206contractbytecode" data, _ := hex.DecodeString(code) @@ -480,7 +479,7 @@ func TestGetNodeInfo(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} core.EXPECT().ServerMeta().Return("111", "", "", "222", "") ret, err := web3svr.getNodeInfo() @@ -492,7 +491,7 @@ func TestGetNetworkID(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} core.EXPECT().EVMNetworkID().Return(uint32(123)) ret, err := web3svr.getNetworkID() @@ -504,7 +503,7 @@ func TestIsSyncing(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} core.EXPECT().SyncingProgress().Return(uint64(1), uint64(2), uint64(3)) ret, err := web3svr.isSyncing() @@ -520,7 +519,7 @@ func TestGetBlockTransactionCountByHash(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} tsf, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(27), uint64(1), big.NewInt(10), []byte{}, uint64(100000), big.NewInt(0)) @@ -556,7 +555,7 @@ func TestGetBlockByHash(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} tsf, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(27), uint64(1), big.NewInt(10), []byte{}, uint64(100000), big.NewInt(0)) @@ -608,7 +607,7 @@ func TestGetTransactionByHash(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} selp, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(27), uint64(1), big.NewInt(10), []byte{}, uint64(100000), big.NewInt(0)) @@ -678,7 +677,7 @@ func TestGetLogs(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} logs := []*action.Log{ @@ -727,7 +726,7 @@ func TestGetTransactionReceipt(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} selp, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(27), uint64(1), big.NewInt(10), []byte{}, uint64(100000), big.NewInt(0)) @@ -775,7 +774,7 @@ func TestGetBlockTransactionCountByNumber(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} tsf, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(27), uint64(1), big.NewInt(10), []byte{}, uint64(100000), big.NewInt(0)) @@ -810,7 +809,7 @@ func TestGetTransactionByBlockHashAndIndex(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} tsf, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(27), uint64(1), big.NewInt(10), []byte{}, uint64(100000), big.NewInt(0)) @@ -857,7 +856,7 @@ func TestGetTransactionByBlockNumberAndIndex(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} tsf, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(27), uint64(1), big.NewInt(10), []byte{}, uint64(100000), big.NewInt(0)) @@ -903,7 +902,7 @@ func TestGetStorageAt(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} val := []byte("test") core.EXPECT().ReadContractStorage(gomock.Any(), gomock.Any(), gomock.Any()).Return(val, nil) @@ -918,7 +917,7 @@ func TestNewfilter(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, newAPICache(1*time.Second, ""), _defaultBatchRequestLimit} ret, err := web3svr.newFilter(&filterObject{ @@ -935,7 +934,7 @@ func TestNewBlockFilter(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, newAPICache(1*time.Second, ""), _defaultBatchRequestLimit} core.EXPECT().TipHeight().Return(uint64(123)) @@ -948,7 +947,7 @@ func TestUninstallFilter(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, newAPICache(1*time.Second, ""), _defaultBatchRequestLimit} require.NoError(web3svr.cache.Set("123456789abc", []byte("test"))) @@ -971,7 +970,7 @@ func TestGetFilterChanges(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, newAPICache(1*time.Second, ""), _defaultBatchRequestLimit} core.EXPECT().TipHeight().Return(uint64(0)).Times(3) @@ -1056,7 +1055,7 @@ func TestGetFilterLogs(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, newAPICache(1*time.Second, ""), _defaultBatchRequestLimit} logs := []*action.Log{ @@ -1112,7 +1111,7 @@ func TestSubscribe(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} listener := mock_apitypes.NewMockListener(ctrl) @@ -1158,7 +1157,7 @@ func TestUnsubscribe(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} listener := mock_apitypes.NewMockListener(ctrl) @@ -1198,7 +1197,7 @@ func TestDebugTraceTransaction(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} ctx := context.Background() @@ -1237,7 +1236,7 @@ func TestDebugTraceCall(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} ctx := context.Background() @@ -1268,7 +1267,7 @@ func TestResponseIDMatchTypeWithRequest(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) core.EXPECT().TipHeight().Return(uint64(1)).AnyTimes() core.EXPECT().Track(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return().AnyTimes() svr := newHTTPHandler(NewWeb3Handler(core, "", _defaultBatchRequestLimit)) diff --git a/api/web3server_utils.go b/api/web3server_utils.go index 773eaff04e..4be39685af 100644 --- a/api/web3server_utils.go +++ b/api/web3server_utils.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/rpc" "github.com/go-redis/redis/v8" "github.com/iotexproject/go-pkgs/cache/ttl" "github.com/iotexproject/go-pkgs/hash" @@ -327,6 +328,17 @@ func parseCallObject(in *gjson.Result) (address.Address, string, uint64, *big.In return from, to, gasLimit, gasPrice, value, data, nil } +func parseBlockNumber(in *gjson.Result) (rpc.BlockNumber, error) { + if !in.Exists() { + return rpc.LatestBlockNumber, nil + } + var height rpc.BlockNumber + if err := height.UnmarshalJSON([]byte(in.String())); err != nil { + return 0, err + } + return height, nil +} + func (svr *web3Handler) getLogQueryRange(fromStr, toStr string, logHeight uint64) (from uint64, to uint64, hasNewLogs bool, err error) { if from, to, err = svr.parseBlockRange(fromStr, toStr); err != nil { return diff --git a/api/web3server_utils_test.go b/api/web3server_utils_test.go index 2d281e09e8..2cb3596477 100644 --- a/api/web3server_utils_test.go +++ b/api/web3server_utils_test.go @@ -6,7 +6,6 @@ import ( "github.com/golang/mock/gomock" "github.com/iotexproject/iotex-address/address" - "github.com/iotexproject/iotex-core/test/mock/mock_apicoreservice" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" ) @@ -114,7 +113,7 @@ func TestParseBlockNumber(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - core := mock_apicoreservice.NewMockCoreService(ctrl) + core := NewMockCoreService(ctrl) web3svr := &web3Handler{core, nil, _defaultBatchRequestLimit} t.Run("earliest block number", func(t *testing.T) { diff --git a/misc/scripts/mockgen.sh b/misc/scripts/mockgen.sh index d52c72a29b..ce372ce13a 100755 --- a/misc/scripts/mockgen.sh +++ b/misc/scripts/mockgen.sh @@ -131,9 +131,9 @@ mockgen -destination=./test/mock/mock_apiserver/mock_apiserver.go \ StreamBlocksServer mkdir -p ./test/mock/mock_apicoreservice -mockgen -destination=./test/mock/mock_apicoreservice/mock_apicoreservice.go \ +mockgen -destination=./api/mock_apicoreservice.go \ -source=./api/coreservice.go \ - -package=mock_apicoreservice \ + -package=api \ CoreService mkdir -p ./test/mock/mock_blockindex