Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[api] eth_getBalance by height #4271

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/coreservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
150 changes: 150 additions & 0 deletions api/coreservice_with_height.go
Original file line number Diff line number Diff line change
@@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be core.getProtocolAccount?

}
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)
dustinxie marked this conversation as resolved.
Show resolved Hide resolved
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
}
47 changes: 23 additions & 24 deletions api/grpcserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,14 @@ 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"
)

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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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")
Expand All @@ -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"),
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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(),
Expand Down Expand Up @@ -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"),
Expand All @@ -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}}
Expand All @@ -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{
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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{
Expand All @@ -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{
Expand All @@ -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{
Expand All @@ -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()
Expand All @@ -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)
Expand All @@ -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)
Expand Down
Loading
Loading