Skip to content

Commit ef0af12

Browse files
committed
[api] fix estimateGas for migrateStake (#4377)
1 parent d2f813b commit ef0af12

File tree

7 files changed

+97
-20
lines changed

7 files changed

+97
-20
lines changed

action/protocol/managers.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,16 @@ type (
9393
Reset()
9494
}
9595
)
96+
97+
type (
98+
SimulateOption func(*SimulateOptionConfig)
99+
SimulateOptionConfig struct {
100+
PreOpt func(StateManager) error
101+
}
102+
)
103+
104+
func WithSimulatePreOpt(fn func(StateManager) error) SimulateOption {
105+
return func(so *SimulateOptionConfig) {
106+
so.PreOpt = fn
107+
}
108+
}

api/coreservice.go

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ type (
138138
// EstimateGasForNonExecution estimates action gas except execution
139139
EstimateGasForNonExecution(action.Action) (uint64, error)
140140
// EstimateExecutionGasConsumption estimate gas consumption for execution action
141-
EstimateExecutionGasConsumption(ctx context.Context, sc *action.Execution, callerAddr address.Address) (uint64, error)
141+
EstimateExecutionGasConsumption(ctx context.Context, sc *action.Execution, callerAddr address.Address, opts ...protocol.SimulateOption) (uint64, error)
142142
// LogsInBlockByHash filter logs in the block by hash
143143
LogsInBlockByHash(filter *logfilter.LogFilter, blockHash hash.Hash256) ([]*action.Log, error)
144144
// LogsInRange filter logs among [start, end] blocks
@@ -1513,11 +1513,22 @@ func (core *coreService) EstimateMigrateStakeGasConsumption(ctx context.Context,
15131513
GasLimit: g.BlockGasLimitByHeight(header.Height() + 1),
15141514
Producer: zeroAddr,
15151515
})
1516+
15161517
exec, err := staking.FindProtocol(core.registry).ConstructExecution(ctx, ms, core.sf)
15171518
if err != nil {
15181519
return 0, err
15191520
}
1520-
gas, err := core.EstimateExecutionGasConsumption(ctx, exec, caller)
1521+
gas, err := core.EstimateExecutionGasConsumption(ctx, exec, caller, protocol.WithSimulatePreOpt(func(sm protocol.StateManager) error {
1522+
// add amount to the sender account
1523+
sender, err := accountutil.LoadAccount(sm, caller)
1524+
if err != nil {
1525+
return err
1526+
}
1527+
if err = sender.AddBalance(exec.Amount()); err != nil {
1528+
return err
1529+
}
1530+
return accountutil.StoreAccount(sm, caller, sender)
1531+
}))
15211532
if err != nil {
15221533
return 0, err
15231534
}
@@ -1529,7 +1540,7 @@ func (core *coreService) EstimateMigrateStakeGasConsumption(ctx context.Context,
15291540
}
15301541

15311542
// EstimateExecutionGasConsumption estimate gas consumption for execution action
1532-
func (core *coreService) EstimateExecutionGasConsumption(ctx context.Context, sc *action.Execution, callerAddr address.Address) (uint64, error) {
1543+
func (core *coreService) EstimateExecutionGasConsumption(ctx context.Context, sc *action.Execution, callerAddr address.Address, opts ...protocol.SimulateOption) (uint64, error) {
15331544
ctx = genesis.WithGenesisContext(ctx, core.bc.Genesis())
15341545
state, err := accountutil.AccountState(ctx, core.sf, callerAddr)
15351546
if err != nil {
@@ -1552,7 +1563,7 @@ func (core *coreService) EstimateExecutionGasConsumption(ctx context.Context, sc
15521563
blockGasLimit = g.BlockGasLimitByHeight(core.bc.TipHeight())
15531564
)
15541565
sc.SetGasLimit(blockGasLimit)
1555-
enough, receipt, err := core.isGasLimitEnough(ctx, callerAddr, sc)
1566+
enough, receipt, err := core.isGasLimitEnough(ctx, callerAddr, sc, opts...)
15561567
if err != nil {
15571568
return 0, status.Error(codes.Internal, err.Error())
15581569
}
@@ -1564,7 +1575,7 @@ func (core *coreService) EstimateExecutionGasConsumption(ctx context.Context, sc
15641575
}
15651576
estimatedGas := receipt.GasConsumed
15661577
sc.SetGasLimit(estimatedGas)
1567-
enough, _, err = core.isGasLimitEnough(ctx, callerAddr, sc)
1578+
enough, _, err = core.isGasLimitEnough(ctx, callerAddr, sc, opts...)
15681579
if err != nil && err != action.ErrInsufficientFunds {
15691580
return 0, status.Error(codes.Internal, err.Error())
15701581
}
@@ -1574,7 +1585,7 @@ func (core *coreService) EstimateExecutionGasConsumption(ctx context.Context, sc
15741585
for low <= high {
15751586
mid := (low + high) / 2
15761587
sc.SetGasLimit(mid)
1577-
enough, _, err = core.isGasLimitEnough(ctx, callerAddr, sc)
1588+
enough, _, err = core.isGasLimitEnough(ctx, callerAddr, sc, opts...)
15781589
if err != nil && err != action.ErrInsufficientFunds {
15791590
return 0, status.Error(codes.Internal, err.Error())
15801591
}
@@ -1594,6 +1605,7 @@ func (core *coreService) isGasLimitEnough(
15941605
ctx context.Context,
15951606
caller address.Address,
15961607
sc *action.Execution,
1608+
opts ...protocol.SimulateOption,
15971609
) (bool, *action.Receipt, error) {
15981610
ctx, span := tracer.NewSpan(ctx, "Server.isGasLimitEnough")
15991611
defer span.End()
@@ -1602,7 +1614,7 @@ func (core *coreService) isGasLimitEnough(
16021614
return false, nil, err
16031615
}
16041616

1605-
_, receipt, err := core.simulateExecution(ctx, caller, sc, core.dao.GetBlockHash, core.getBlockTime)
1617+
_, receipt, err := core.simulateExecution(ctx, caller, sc, core.dao.GetBlockHash, core.getBlockTime, opts...)
16061618
if err != nil {
16071619
return false, nil, err
16081620
}
@@ -1908,14 +1920,14 @@ func (core *coreService) traceTx(ctx context.Context, txctx *tracers.Context, co
19081920
return retval, receipt, tracer, err
19091921
}
19101922

1911-
func (core *coreService) simulateExecution(ctx context.Context, addr address.Address, exec *action.Execution, getBlockHash evm.GetBlockHash, getBlockTime evm.GetBlockTime) ([]byte, *action.Receipt, error) {
1923+
func (core *coreService) simulateExecution(ctx context.Context, addr address.Address, exec *action.Execution, getBlockHash evm.GetBlockHash, getBlockTime evm.GetBlockTime, opts ...protocol.SimulateOption) ([]byte, *action.Receipt, error) {
19121924
ctx = evm.WithHelperCtx(ctx, evm.HelperContext{
19131925
GetBlockHash: getBlockHash,
19141926
GetBlockTime: getBlockTime,
19151927
DepositGasFunc: rewarding.DepositGasWithSGD,
19161928
Sgd: core.sgdIndexer,
19171929
})
1918-
return core.sf.SimulateExecution(ctx, addr, exec)
1930+
return core.sf.SimulateExecution(ctx, addr, exec, opts...)
19191931
}
19201932

19211933
func filterReceipts(receipts []*action.Receipt, actHash hash.Hash256) *action.Receipt {

e2etest/native_staking_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,7 @@ func TestCandidateTransferOwnership(t *testing.T) {
851851
return data
852852
}
853853
deployCode := append(bytecode, mustCallData("", minAmount)...)
854+
poorID := 30
854855
test.run([]*testcase{
855856
{
856857
name: "deploy staking contract",
@@ -1020,6 +1021,28 @@ func TestCandidateTransferOwnership(t *testing.T) {
10201021
})
10211022
require.NoError(err)
10221023
require.Equal(uint64(194912), resp.Gas)
1024+
require.Len(receipt.Logs(), 1)
1025+
topic := receipt.Logs()[0].Topics[1][:]
1026+
bktIdx := byteutil.BytesToUint64BigEndian(topic[len(topic)-8:])
1027+
require.Equal(uint64(6), bktIdx)
1028+
}}},
1029+
},
1030+
{
1031+
name: "estimateGasPoorAcc",
1032+
act: &actionWithTime{mustNoErr(action.SignedTransferStake(test.nonceMgr.pop(identityset.Address(stakerID).String()), identityset.Address(poorID).String(), 6, nil, gasLimit, gasPrice, identityset.PrivateKey(stakerID), action.WithChainID(chainID))), time.Now()},
1033+
expect: []actionExpect{&functionExpect{func(test *e2etest, act *action.SealedEnvelope, receipt *action.Receipt, err error) {
1034+
resp1, err := test.api.GetAccount(context.Background(), &iotexapi.GetAccountRequest{Address: identityset.Address(poorID).String()})
1035+
require.NoError(err)
1036+
require.Equal("0", resp1.GetAccountMeta().Balance)
1037+
ms, err := action.NewMigrateStake(0, 6, gasLimit, gasPrice)
1038+
require.NoError(err)
1039+
resp, err := test.api.EstimateActionGasConsumption(context.Background(), &iotexapi.EstimateActionGasConsumptionRequest{
1040+
Action: &iotexapi.EstimateActionGasConsumptionRequest_StakeMigrate{StakeMigrate: ms.Proto()},
1041+
CallerAddress: identityset.Address(poorID).String(),
1042+
GasPrice: gasPrice.String(),
1043+
})
1044+
require.NoError(err)
1045+
require.Equal(uint64(194912), resp.Gas)
10231046
}}},
10241047
},
10251048
})

state/factory/factory.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ type (
8686
Validate(context.Context, *block.Block) error
8787
// NewBlockBuilder creates block builder
8888
NewBlockBuilder(context.Context, actpool.ActPool, func(action.Envelope) (*action.SealedEnvelope, error)) (*block.Builder, error)
89-
SimulateExecution(context.Context, address.Address, *action.Execution) ([]byte, *action.Receipt, error)
89+
SimulateExecution(context.Context, address.Address, *action.Execution, ...protocol.SimulateOption) ([]byte, *action.Receipt, error)
9090
ReadContractStorage(context.Context, address.Address, []byte) ([]byte, error)
9191
PutBlock(context.Context, *block.Block) error
9292
DeleteTipBlock(context.Context, *block.Block) error
@@ -387,6 +387,7 @@ func (sf *factory) SimulateExecution(
387387
ctx context.Context,
388388
caller address.Address,
389389
ex *action.Execution,
390+
opts ...protocol.SimulateOption,
390391
) ([]byte, *action.Receipt, error) {
391392
ctx, span := tracer.NewSpan(ctx, "factory.SimulateExecution")
392393
defer span.End()
@@ -397,7 +398,15 @@ func (sf *factory) SimulateExecution(
397398
if err != nil {
398399
return nil, nil, errors.Wrap(err, "failed to obtain working set from state factory")
399400
}
400-
401+
cfg := &protocol.SimulateOptionConfig{}
402+
for _, opt := range opts {
403+
opt(cfg)
404+
}
405+
if cfg.PreOpt != nil {
406+
if err := cfg.PreOpt(ws); err != nil {
407+
return nil, nil, err
408+
}
409+
}
401410
return evm.SimulateExecution(ctx, ws, caller, ex)
402411
}
403412

state/factory/statedb.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ func (sdb *stateDB) SimulateExecution(
267267
ctx context.Context,
268268
caller address.Address,
269269
ex *action.Execution,
270+
opts ...protocol.SimulateOption,
270271
) ([]byte, *action.Receipt, error) {
271272
ctx, span := tracer.NewSpan(ctx, "stateDB.SimulateExecution")
272273
defer span.End()
@@ -278,7 +279,15 @@ func (sdb *stateDB) SimulateExecution(
278279
if err != nil {
279280
return nil, nil, err
280281
}
281-
282+
cfg := &protocol.SimulateOptionConfig{}
283+
for _, opt := range opts {
284+
opt(cfg)
285+
}
286+
if cfg.PreOpt != nil {
287+
if err := cfg.PreOpt(ws); err != nil {
288+
return nil, nil, err
289+
}
290+
}
282291
return evm.SimulateExecution(ctx, ws, caller, ex)
283292
}
284293

test/mock/mock_apicoreservice/mock_apicoreservice.go

Lines changed: 10 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/mock/mock_factory/mock_factory.go

Lines changed: 9 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)