Skip to content

Commit

Permalink
[api] add EstimateGasForNonExecution in coreservice (#3174)
Browse files Browse the repository at this point in the history
* add EstimateGasForNonExecution in coreservice
  • Loading branch information
Liuhaai authored Mar 17, 2022
1 parent 76bd834 commit 2febef9
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 43 deletions.
18 changes: 13 additions & 5 deletions api/coreservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ type (
ActPoolActions(actHashes []string) ([]*iotextypes.Action, error)
// UnconfirmedActionsByAddress returns all unconfirmed actions in actpool associated with an address
UnconfirmedActionsByAddress(address string, start uint64, count uint64) ([]*iotexapi.ActionInfo, error)
// CalculateGasConsumption estimate gas consumption for actions except execution
CalculateGasConsumption(intrinsicGas, payloadGas, payloadSize uint64) (uint64, error)
// EstimateGasForNonExecution estimates action gas except execution
EstimateGasForNonExecution(action.Action) (uint64, error)
// EstimateExecutionGasConsumption estimate gas consumption for execution action
EstimateExecutionGasConsumption(ctx context.Context, sc *action.Execution, callerAddr address.Address) (uint64, error)
// BlockMetas returns blockmetas response within the height range
Expand Down Expand Up @@ -160,6 +160,10 @@ type (
}
)

type intrinsicGasCalculator interface {
IntrinsicGas() (uint64, error)
}

// newcoreService creates a api server that contains major blockchain components
func newCoreService(
cfg config.API,
Expand Down Expand Up @@ -1416,9 +1420,13 @@ func (core *coreService) correctLogsRange(start, end uint64) (uint64, uint64, er
return start, end, nil
}

// CalculateGasConsumption estimate gas consumption for actions except execution
func (core *coreService) CalculateGasConsumption(intrinsicGas, payloadGas, payloadSize uint64) (uint64, error) {
return action.CalculateIntrinsicGas(intrinsicGas, payloadGas, payloadSize)
// EstimateGasForNonExecution estimates action gas except execution
func (core *coreService) EstimateGasForNonExecution(actType action.Action) (uint64, error) {
act, ok := actType.(intrinsicGasCalculator)
if !ok {
return 0, errors.Errorf("invalid action type not supported")
}
return act.IntrinsicGas()
}

// EstimateExecutionGasConsumption estimate gas consumption for execution action
Expand Down
66 changes: 53 additions & 13 deletions api/grpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,36 +294,76 @@ func (svr *GRPCServer) EstimateActionGasConsumption(ctx context.Context, in *iot
}
return &iotexapi.EstimateActionGasConsumptionResponse{Gas: ret}, nil
}
var intrinsicGas, payloadGas, payloadSize uint64
var act action.Action
switch {
case in.GetTransfer() != nil:
intrinsicGas, payloadGas, payloadSize = action.TransferBaseIntrinsicGas, action.TransferPayloadGas, uint64(len(in.GetTransfer().Payload))
tmpAct := &action.Transfer{}
if err := tmpAct.LoadProto(in.GetTransfer()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
act = tmpAct
case in.GetStakeCreate() != nil:
intrinsicGas, payloadGas, payloadSize = action.CreateStakeBaseIntrinsicGas, action.CreateStakePayloadGas, uint64(len(in.GetStakeCreate().Payload))
tmpAct := &action.CreateStake{}
if err := tmpAct.LoadProto(in.GetStakeCreate()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
act = tmpAct
case in.GetStakeUnstake() != nil:
intrinsicGas, payloadGas, payloadSize = action.ReclaimStakeBaseIntrinsicGas, action.ReclaimStakePayloadGas, uint64(len(in.GetStakeUnstake().Payload))
tmpAct := &action.Unstake{}
if err := tmpAct.LoadProto(in.GetStakeUnstake()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
act = tmpAct
case in.GetStakeWithdraw() != nil:
intrinsicGas, payloadGas, payloadSize = action.ReclaimStakeBaseIntrinsicGas, action.ReclaimStakePayloadGas, uint64(len(in.GetStakeWithdraw().Payload))
tmpAct := &action.WithdrawStake{}
if err := tmpAct.LoadProto(in.GetStakeWithdraw()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
act = tmpAct
case in.GetStakeAddDeposit() != nil:
intrinsicGas, payloadGas, payloadSize = action.DepositToStakeBaseIntrinsicGas, action.DepositToStakePayloadGas, uint64(len(in.GetStakeAddDeposit().Payload))
tmpAct := &action.DepositToStake{}
if err := tmpAct.LoadProto(in.GetStakeAddDeposit()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
act = tmpAct
case in.GetStakeRestake() != nil:
intrinsicGas, payloadGas, payloadSize = action.RestakeBaseIntrinsicGas, action.RestakePayloadGas, uint64(len(in.GetStakeRestake().Payload))
tmpAct := &action.Restake{}
if err := tmpAct.LoadProto(in.GetStakeRestake()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
act = tmpAct
case in.GetStakeChangeCandidate() != nil:
intrinsicGas, payloadGas, payloadSize = action.MoveStakeBaseIntrinsicGas, action.MoveStakePayloadGas, uint64(len(in.GetStakeChangeCandidate().Payload))
tmpAct := &action.ChangeCandidate{}
if err := tmpAct.LoadProto(in.GetStakeChangeCandidate()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
act = tmpAct
case in.GetStakeTransferOwnership() != nil:
intrinsicGas, payloadGas, payloadSize = action.MoveStakeBaseIntrinsicGas, action.MoveStakePayloadGas, uint64(len(in.GetStakeTransferOwnership().Payload))
tmpAct := &action.TransferStake{}
if err := tmpAct.LoadProto(in.GetStakeTransferOwnership()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
act = tmpAct
case in.GetCandidateRegister() != nil:
intrinsicGas, payloadGas, payloadSize = action.CandidateRegisterBaseIntrinsicGas, action.CandidateRegisterPayloadGas, uint64(len(in.GetCandidateRegister().Payload))
tmpAct := &action.CandidateRegister{}
if err := tmpAct.LoadProto(in.GetCandidateRegister()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
act = tmpAct
case in.GetCandidateUpdate() != nil:
intrinsicGas, payloadGas, payloadSize = action.CandidateUpdateBaseIntrinsicGas, 0, 0
tmpAct := &action.CandidateUpdate{}
if err := tmpAct.LoadProto(in.GetCandidateUpdate()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
act = tmpAct
default:
return nil, status.Error(codes.InvalidArgument, "invalid argument")
}
gas, err := svr.coreService.CalculateGasConsumption(intrinsicGas, payloadGas, payloadSize)
estimatedGas, err := svr.coreService.EstimateGasForNonExecution(act)
if err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
return &iotexapi.EstimateActionGasConsumptionResponse{Gas: gas}, nil
return &iotexapi.EstimateActionGasConsumptionResponse{Gas: estimatedGas}, nil
}

// GetEpochMeta gets epoch metadata
Expand Down
32 changes: 22 additions & 10 deletions api/web3server.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strconv"
"time"

"github.com/ethereum/go-ethereum/core/types"
"github.com/iotexproject/go-pkgs/hash"
"github.com/iotexproject/go-pkgs/util"
"github.com/iotexproject/iotex-address/address"
Expand All @@ -24,6 +25,7 @@ import (

"github.com/iotexproject/iotex-core/action"
"github.com/iotexproject/iotex-core/pkg/log"
"github.com/iotexproject/iotex-core/pkg/util/addrutil"
)

const (
Expand Down Expand Up @@ -426,19 +428,29 @@ func (svr *Web3Server) estimateGas(in interface{}) (interface{}, error) {
return nil, err
}

var estimatedGas uint64
if isContract, _ := svr.isContractAddr(to); isContract {
exec, _ := action.NewExecution(to, 0, value, gasLimit, big.NewInt(0), data)
estimatedGas, err = svr.coreService.EstimateExecutionGasConsumption(context.Background(), exec, from)
if err != nil {
return nil, err
}
var tx *types.Transaction
if len(to) == 0 {
tx = types.NewContractCreation(0, value, gasLimit, big.NewInt(0), data)
} else {
// TODO: support staking actions
estimatedGas, err = svr.coreService.CalculateGasConsumption(action.TransferBaseIntrinsicGas, action.TransferPayloadGas, uint64(len(data)))
toAddr, err := addrutil.IoAddrToEvmAddr(to)
if err != nil {
return nil, err
return "", err
}
tx = types.NewTransaction(0, toAddr, value, gasLimit, big.NewInt(0), data)
}
act, err := svr.ethTxToAction(tx)
if err != nil {
return nil, err
}

var estimatedGas uint64
if exec, ok := act.(*action.Execution); ok {
estimatedGas, err = svr.coreService.EstimateExecutionGasConsumption(context.Background(), exec, from)
} else {
estimatedGas, err = svr.coreService.EstimateGasForNonExecution(act)
}
if err != nil {
return nil, err
}
if estimatedGas < 21000 {
estimatedGas = 21000
Expand Down
26 changes: 26 additions & 0 deletions api/web3server_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/go-redis/redis/v8"
"github.com/iotexproject/go-pkgs/cache/ttl"
"github.com/iotexproject/go-pkgs/hash"
Expand All @@ -21,6 +22,7 @@ import (
"github.com/tidwall/gjson"
"go.uber.org/zap"

"github.com/iotexproject/iotex-core/action"
"github.com/iotexproject/iotex-core/action/protocol/account"
"github.com/iotexproject/iotex-core/action/protocol/poll"
"github.com/iotexproject/iotex-core/action/protocol/rewarding"
Expand Down Expand Up @@ -328,6 +330,30 @@ func (svr *Web3Server) isContractAddr(addr string) (bool, error) {
return accountMeta.IsContract, nil
}

func (svr *Web3Server) ethTxToAction(tx *types.Transaction) (action.Action, error) {
to := ""
if tx.To() != nil {
ioAddr, _ := address.FromBytes(tx.To().Bytes())
to = ioAddr.String()
}
switch to {
case "":
return action.NewExecution(to, tx.Nonce(), tx.Value(), tx.Gas(), tx.GasPrice(), tx.Data())
case address.StakingProtocolAddr:
return action.NewStakingActionFromABIBinary(tx.Data())
default:
ioAddr, err := address.FromString(to)
if err != nil {
return nil, err
}
accountMeta, _, err := svr.coreService.Account(ioAddr)
if err == nil && accountMeta.IsContract {
return action.NewExecution(to, tx.Nonce(), tx.Value(), tx.Gas(), tx.GasPrice(), tx.Data())
}
return action.NewTransfer(tx.Nonce(), tx.Value(), to, tx.Data(), tx.Gas(), tx.GasPrice())
}
}

func (svr *Web3Server) getLogsWithFilter(from uint64, to uint64, addrs []string, topics [][]string) ([]logsObject, error) {
// construct filter topics and addresses
var filter iotexapi.LogsFilter
Expand Down
30 changes: 15 additions & 15 deletions test/mock/mock_apicoreservice/mock_apicoreservice.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2febef9

Please sign in to comment.