From e56a50aba18edd3acbed303947582cfa9fa4dac0 Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 17 Jun 2024 17:58:34 +0800 Subject: [PATCH] not set nonce in staking --- action/protocol/execution/protocol.go | 20 ------ .../protocol/staking/handler_stake_migrate.go | 26 ++++---- .../staking/handler_stake_migrate_test.go | 6 +- action/protocol/staking/protocol.go | 65 ++++++++++++------- state/account.go | 13 ---- 5 files changed, 59 insertions(+), 71 deletions(-) diff --git a/action/protocol/execution/protocol.go b/action/protocol/execution/protocol.go index b6a86df908..f6d77295e9 100644 --- a/action/protocol/execution/protocol.go +++ b/action/protocol/execution/protocol.go @@ -15,7 +15,6 @@ import ( "github.com/iotexproject/iotex-core/action" "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/pkg/log" ) @@ -84,25 +83,6 @@ func (p *Protocol) Handle(ctx context.Context, act action.Action, sm protocol.St return receipt, nil } -// HandleCrossProtocol handles an execution from another protocol -func (p *Protocol) HandleCrossProtocol(ctx context.Context, act action.Action, sm protocol.StateManager) (*action.Receipt, error) { - receipt, err := p.Handle(ctx, act, sm) - if err != nil { - return nil, errors.Wrap(err, "failed to execute contract") - } - - // reset caller nonce - acc, err := accountutil.AccountState(ctx, sm, protocol.MustGetActionCtx(ctx).Caller) - if err != nil { - log.L().Panic("failed to get account state", zap.Error(err)) - } - acc.DecreaseNonce() - if err := accountutil.StoreAccount(sm, protocol.MustGetActionCtx(ctx).Caller, acc); err != nil { - log.L().Panic("failed to store account", zap.Error(err)) - } - return receipt, nil -} - // Validate validates an execution func (p *Protocol) Validate(ctx context.Context, act action.Action, _ protocol.StateReader) error { exec, ok := act.(*action.Execution) diff --git a/action/protocol/staking/handler_stake_migrate.go b/action/protocol/staking/handler_stake_migrate.go index cfe762496c..e1d4d5c367 100644 --- a/action/protocol/staking/handler_stake_migrate.go +++ b/action/protocol/staking/handler_stake_migrate.go @@ -20,9 +20,10 @@ import ( "github.com/iotexproject/iotex-core/state" ) -func (p *Protocol) handleStakeMigrate(ctx context.Context, act *action.MigrateStake, csm CandidateStateManager) ([]*action.Log, []*action.TransactionLog, uint64, error) { +func (p *Protocol) handleStakeMigrate(ctx context.Context, act *action.MigrateStake, csm CandidateStateManager) ([]*action.Log, []*action.TransactionLog, uint64, bool, error) { actLogs := make([]*action.Log, 0) transferLogs := make([]*action.TransactionLog, 0) + nonceUpdated := false si := csm.SM().Snapshot() revertSM := func() { if revertErr := csm.SM().Revert(si); revertErr != nil { @@ -31,30 +32,30 @@ func (p *Protocol) handleStakeMigrate(ctx context.Context, act *action.MigrateSt } insGas, err := act.IntrinsicGas() if err != nil { - return nil, nil, 0, err + return nil, nil, 0, nonceUpdated, err } // validate bucket index bucket, rErr := p.fetchBucket(csm, act.BucketIndex()) if rErr != nil { - return nil, nil, 0, rErr + return nil, nil, 0, nonceUpdated, rErr } if err := p.validateStakeMigrate(ctx, bucket, csm); err != nil { - return nil, nil, 0, err + return nil, nil, 0, nonceUpdated, err } // force-withdraw native bucket staker, rerr := fetchCaller(ctx, csm, big.NewInt(0)) if rerr != nil { - return nil, nil, 0, errors.Wrap(rerr, "failed to fetch caller") + return nil, nil, 0, nonceUpdated, errors.Wrap(rerr, "failed to fetch caller") } candidate := csm.GetByIdentifier(bucket.Candidate) if candidate == nil { - return nil, nil, 0, errCandNotExist + return nil, nil, 0, nonceUpdated, errCandNotExist } actLog, tLog, err := p.withdrawBucket(ctx, staker, bucket, candidate, csm) if err != nil { - return nil, nil, 0, err + return nil, nil, 0, nonceUpdated, err } actLogs = append(actLogs, actLog.Build(ctx, nil)) transferLogs = append(transferLogs, tLog) @@ -64,21 +65,22 @@ func (p *Protocol) handleStakeMigrate(ctx context.Context, act *action.MigrateSt exec, err := p.constructExecution(candidate.GetIdentifier(), bucket.StakedAmount, duration, act.Nonce(), act.GasLimit(), act.GasPrice()) if err != nil { revertSM() - return nil, nil, 0, errors.Wrap(err, "failed to construct execution") + return nil, nil, 0, nonceUpdated, errors.Wrap(err, "failed to construct execution") } excReceipt, err := p.createNFTBucket(ctx, exec, csm.SM()) if err != nil { revertSM() - return nil, nil, 0, errors.Wrap(err, "failed to handle execution action") + return nil, nil, 0, nonceUpdated, errors.Wrap(err, "failed to handle execution action") } + nonceUpdated = true if excReceipt.Status != uint64(iotextypes.ReceiptStatus_Success) { revertSM() - return nil, nil, 0, errors.Errorf("execution failed with status %d", excReceipt.Status) + return nil, nil, 0, nonceUpdated, errors.Errorf("execution failed with status %d", excReceipt.Status) } // add sub-receipts logs actLogs = append(actLogs, excReceipt.Logs()...) transferLogs = append(transferLogs, excReceipt.TransactionLogs()...) - return actLogs, transferLogs, excReceipt.GasConsumed + insGas, nil + return actLogs, transferLogs, excReceipt.GasConsumed + insGas, nonceUpdated, nil } func (p *Protocol) validateStakeMigrate(ctx context.Context, bucket *VoteBucket, csm CandidateStateManager) error { @@ -195,7 +197,7 @@ func (p *Protocol) createNFTBucket(ctx context.Context, exeAct *action.Execution if exctPtl == nil { return nil, errors.New("execution protocol is not registered") } - excReceipt, err := exctPtl.HandleCrossProtocol(ctx, exeAct, sm) + excReceipt, err := exctPtl.Handle(ctx, exeAct, sm) if err != nil { return nil, errors.Wrap(err, "failed to handle execution action") } diff --git a/action/protocol/staking/handler_stake_migrate_test.go b/action/protocol/staking/handler_stake_migrate_test.go index d7e431126d..3cfa538968 100644 --- a/action/protocol/staking/handler_stake_migrate_test.go +++ b/action/protocol/staking/handler_stake_migrate_test.go @@ -219,7 +219,7 @@ func TestHandleStakeMigrate(t *testing.T) { pa := NewPatches() defer pa.Reset() sm.EXPECT().Revert(gomock.Any()).Return(nil).AnyTimes() - pa.ApplyMethodReturn(excPrtl, "HandleCrossProtocol", &action.Receipt{ + pa.ApplyMethodReturn(excPrtl, "Handle", &action.Receipt{ Status: uint64(iotextypes.ReceiptStatus_Failure), }, nil) receipts, errs := runBlock(ctx, p, sm, 8, timeBlock, @@ -231,7 +231,7 @@ func TestHandleStakeMigrate(t *testing.T) { t.Run("error from contract call", func(t *testing.T) { pa := NewPatches() defer pa.Reset() - pa.ApplyMethodFunc(excPrtl, "HandleCrossProtocol", func(ctx context.Context, act action.Action, sm protocol.StateManager) (*action.Receipt, error) { + pa.ApplyMethodFunc(excPrtl, "Handle", func(ctx context.Context, act action.Action, sm protocol.StateManager) (*action.Receipt, error) { return nil, errors.New("execution failed error") }) sm.EXPECT().Revert(gomock.Any()).Return(nil).AnyTimes() @@ -275,7 +275,7 @@ func TestHandleStakeMigrate(t *testing.T) { Type: iotextypes.TransactionLogType_IN_CONTRACT_TRANSFER, Amount: big.NewInt(100), }) - pa.ApplyMethodReturn(excPrtl, "HandleCrossProtocol", receipt, nil) + pa.ApplyMethodReturn(excPrtl, "Handle", receipt, nil) act := assertions.MustNoErrorV(action.SignedMigrateStake(popNonce(&stakerNonce), bktIdx, gasLimit, gasPrice, identityset.PrivateKey(stakerID))) receipts, _ = runBlock(ctx, p, sm, 11, timeBlock, act, diff --git a/action/protocol/staking/protocol.go b/action/protocol/staking/protocol.go index af71aecf0a..c793d0ddc2 100644 --- a/action/protocol/staking/protocol.go +++ b/action/protocol/staking/protocol.go @@ -156,7 +156,10 @@ func NewProtocol( // new vote reviser, revise ate greenland voteReviser := NewVoteReviser(cfg.Staking.VoteWeightCalConsts, correctCandsHeight, reviseHeights...) - + migrateContractAddress := "" + if contractStakingIndexerV2 != nil { + migrateContractAddress = contractStakingIndexerV2.ContractAddress() + } return &Protocol{ addr: addr, config: Configuration{ @@ -170,6 +173,7 @@ func NewProtocol( BootstrapCandidates: cfg.Staking.BootstrapCandidates, PersistStakingPatchBlock: cfg.PersistStakingPatchBlock, EndorsementWithdrawWaitingBlocks: cfg.Staking.EndorsementWithdrawWaitingBlocks, + MigrateContractAddress: migrateContractAddress, }, candBucketsIndexer: candBucketsIndexer, voteReviser: voteReviser, @@ -415,12 +419,13 @@ func (p *Protocol) constructCandidateStateManager(ctx context.Context, sm protoc func (p *Protocol) handle(ctx context.Context, act action.Action, csm CandidateStateManager) (*action.Receipt, error) { var ( - rLog *receiptLog - tLogs []*action.TransactionLog - err error - logs []*action.Log - actionCtx = protocol.MustGetActionCtx(ctx) - gasConsumed = actionCtx.IntrinsicGas + rLog *receiptLog + tLogs []*action.TransactionLog + err error + logs []*action.Log + nonceUpdateOption = updateNonce + actionCtx = protocol.MustGetActionCtx(ctx) + gasConsumed = actionCtx.IntrinsicGas ) switch act := act.(type) { @@ -449,7 +454,11 @@ func (p *Protocol) handle(ctx context.Context, act action.Action, csm CandidateS case *action.CandidateTransferOwnership: rLog, tLogs, err = p.handleCandidateTransferOwnership(ctx, act, csm) case *action.MigrateStake: - logs, tLogs, gasConsumed, err = p.handleStakeMigrate(ctx, act, csm) + var nonceUpdated bool + logs, tLogs, gasConsumed, nonceUpdated, err = p.handleStakeMigrate(ctx, act, csm) + if nonceUpdated { + nonceUpdateOption = noUpdateNonce + } default: return nil, nil } @@ -459,14 +468,14 @@ func (p *Protocol) handle(ctx context.Context, act action.Action, csm CandidateS } } if err == nil { - return p.settleAction(ctx, csm.SM(), uint64(iotextypes.ReceiptStatus_Success), logs, tLogs, gasConsumed) + return p.settleAction(ctx, csm.SM(), uint64(iotextypes.ReceiptStatus_Success), logs, tLogs, gasConsumed, nonceUpdateOption) } if receiptErr, ok := err.(ReceiptError); ok { actionCtx := protocol.MustGetActionCtx(ctx) log.L().With( zap.String("actionHash", hex.EncodeToString(actionCtx.ActionHash[:]))).Debug("Failed to commit staking action", zap.Error(err)) - return p.settleAction(ctx, csm.SM(), receiptErr.ReceiptStatus(), logs, tLogs, gasConsumed) + return p.settleAction(ctx, csm.SM(), receiptErr.ReceiptStatus(), logs, tLogs, gasConsumed, nonceUpdateOption) } return nil, err } @@ -677,6 +686,13 @@ func (p *Protocol) calculateVoteWeight(v *VoteBucket, selfStake bool) *big.Int { return CalculateVoteWeight(p.config.VoteWeightCalConsts, v, selfStake) } +type nonceUpdateType bool + +const ( + updateNonce nonceUpdateType = true + noUpdateNonce nonceUpdateType = false +) + // settleAction deposits gas fee and updates caller's nonce func (p *Protocol) settleAction( ctx context.Context, @@ -685,6 +701,7 @@ func (p *Protocol) settleAction( logs []*action.Log, tLogs []*action.TransactionLog, gasConsumed uint64, + updateNonce nonceUpdateType, ) (*action.Receipt, error) { actionCtx := protocol.MustGetActionCtx(ctx) blkCtx := protocol.MustGetBlockCtx(ctx) @@ -693,19 +710,21 @@ func (p *Protocol) settleAction( if err != nil { return nil, errors.Wrap(err, "failed to deposit gas") } - accountCreationOpts := []state.AccountCreationOption{} - if protocol.MustGetFeatureCtx(ctx).CreateLegacyNonceAccount { - accountCreationOpts = append(accountCreationOpts, state.LegacyNonceAccountTypeOption()) - } - acc, err := accountutil.LoadAccount(sm, actionCtx.Caller, accountCreationOpts...) - if err != nil { - return nil, err - } - if err := acc.SetPendingNonce(actionCtx.Nonce + 1); err != nil { - return nil, errors.Wrap(err, "failed to set nonce") - } - if err := accountutil.StoreAccount(sm, actionCtx.Caller, acc); err != nil { - return nil, errors.Wrap(err, "failed to update nonce") + if updateNonce { + accountCreationOpts := []state.AccountCreationOption{} + if protocol.MustGetFeatureCtx(ctx).CreateLegacyNonceAccount { + accountCreationOpts = append(accountCreationOpts, state.LegacyNonceAccountTypeOption()) + } + acc, err := accountutil.LoadAccount(sm, actionCtx.Caller, accountCreationOpts...) + if err != nil { + return nil, err + } + if err := acc.SetPendingNonce(actionCtx.Nonce + 1); err != nil { + return nil, errors.Wrap(err, "failed to set nonce") + } + if err := accountutil.StoreAccount(sm, actionCtx.Caller, acc); err != nil { + return nil, errors.Wrap(err, "failed to update nonce") + } } r := action.Receipt{ Status: status, diff --git a/state/account.go b/state/account.go index aa2abb0f63..93af2b4350 100644 --- a/state/account.go +++ b/state/account.go @@ -188,19 +188,6 @@ func (st *Account) ConvertFreshAccountToZeroNonceType(nonce uint64) bool { return false } -// DecreaseNonce decrements the nonce of the account -func (st *Account) DecreaseNonce() { - switch st.accountType { - case 0, 1: - if st.nonce == 0 { - panic("nonce underflow") - } - st.nonce-- - default: - panic(errors.Wrapf(ErrUnknownAccountType, "account type %d", st.accountType)) - } -} - // PendingNonce returns the pending nonce of the account func (st *Account) PendingNonce() uint64 { switch st.accountType {