diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index f81b725e6..a85b6a7bd 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -104,47 +104,41 @@ func (p Precompile) RequiredGas(input []byte) uint64 { // Run executes the precompiled contract bank query methods defined in the ABI. func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, snapshot, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } // This handles any out of gas errors that may occur during the execution of a precompile query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err, stateDB, snapshot)() - - return p.RunAtomic( - snapshot, - stateDB, - func() ([]byte, error) { - switch method.Name { - // Bank queries - case BalancesMethod: - bz, err = p.Balances(ctx, contract, method, args) - case TotalSupplyMethod: - bz, err = p.TotalSupply(ctx, contract, method, args) - case SupplyOfMethod: - bz, err = p.SupplyOf(ctx, contract, method, args) - default: - return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) - } - - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - if err := p.AddJournalEntries(stateDB, snapshot); err != nil { - return nil, err - } - - return bz, nil - }, - ) + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + switch method.Name { + // Bank queries + case BalancesMethod: + bz, err = p.Balances(ctx, contract, method, args) + case TotalSupplyMethod: + bz, err = p.TotalSupply(ctx, contract, method, args) + case SupplyOfMethod: + bz, err = p.SupplyOf(ctx, contract, method, args) + default: + return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) + } + + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + if err = p.AddJournalEntries(stateDB); err != nil { + return nil, err + } + + return bz, nil } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/common/precompile.go b/precompiles/common/precompile.go index 4d1436a44..3252f48d4 100644 --- a/precompiles/common/precompile.go +++ b/precompiles/common/precompile.go @@ -45,14 +45,6 @@ func NewBalanceChangeEntry(acc common.Address, amt *uint256.Int, op Operation) B return BalanceChangeEntry{acc, amt, op} } -// Snapshot contains all state and events previous to the precompile call -// This is needed to allow us to revert the changes -// during the EVM execution -type Snapshot struct { - MultiStore storetypes.CacheMultiStore - Events sdk.Events -} - // RequiredGas calculates the base minimum required gas for a transaction or a query. // It uses the method ID to determine if the input is a transaction or a query and // uses the Cosmos SDK gas config flat cost and the flat per byte cost * len(argBz) to calculate the gas. @@ -66,18 +58,6 @@ func (p Precompile) RequiredGas(input []byte, isTransaction bool) uint64 { return p.KvGasConfig.ReadCostFlat + (p.KvGasConfig.ReadCostPerByte * uint64(len(argsBz))) } -// RunAtomic is used within the Run function of each Precompile implementation. -// It handles rolling back to the provided snapshot if an error is returned from the core precompile logic. -// Note: This is only required for stateful precompiles. -func (p Precompile) RunAtomic(s Snapshot, stateDB *statedb.StateDB, fn func() ([]byte, error)) ([]byte, error) { - bz, err := fn() - if err != nil { - // revert to snapshot on error - stateDB.RevertMultiStore(s.MultiStore, s.Events) - } - return bz, err -} - // RunSetup runs the initial setup required to run a transaction or a query. // It returns the sdk Context, EVM stateDB, ABI method, initial gas and calling arguments. func (p Precompile) RunSetup( @@ -85,27 +65,34 @@ func (p Precompile) RunSetup( contract *vm.Contract, readOnly bool, isTransaction func(name *abi.Method) bool, -) (ctx sdk.Context, stateDB *statedb.StateDB, s Snapshot, method *abi.Method, gasConfig storetypes.Gas, args []interface{}, err error) { +) (ctx sdk.Context, stateDB *statedb.StateDB, method *abi.Method, gasConfig storetypes.Gas, args []interface{}, err error) { stateDB, ok := evm.StateDB.(*statedb.StateDB) if !ok { - return sdk.Context{}, nil, s, nil, uint64(0), nil, errors.New(ErrNotRunInEvm) + return sdk.Context{}, nil, nil, uint64(0), nil, errors.New(ErrNotRunInEvm) } // get the stateDB cache ctx ctx, err = stateDB.GetCacheContext() if err != nil { - return sdk.Context{}, nil, s, nil, uint64(0), nil, err + return sdk.Context{}, nil, nil, uint64(0), nil, err } // take a snapshot of the current state before any changes // to be able to revert the changes - s.MultiStore = stateDB.MultiStoreSnapshot() - s.Events = ctx.EventManager().Events() + snapshot := stateDB.MultiStoreSnapshot() + events := ctx.EventManager().Events() + + // add precompileCall entry on the stateDB journal + // this allows to revert the changes within an evm txAdd commentMore actions + err = stateDB.AddPrecompileFn(p.Address(), snapshot, events) + if err != nil { + return sdk.Context{}, nil, nil, uint64(0), nil, err + } // commit the current changes in the cache ctx // to get the updated state for the precompile call if err := stateDB.CommitWithCacheCtx(); err != nil { - return sdk.Context{}, nil, s, nil, uint64(0), nil, err + return sdk.Context{}, nil, nil, uint64(0), nil, err } // NOTE: This is a special case where the calling transaction does not specify a function name. @@ -131,12 +118,12 @@ func (p Precompile) RunSetup( } if err != nil { - return sdk.Context{}, nil, s, nil, uint64(0), nil, err + return sdk.Context{}, nil, nil, uint64(0), nil, err } // return error if trying to write to state during a read-only call if readOnly && isTransaction(method) { - return sdk.Context{}, nil, s, nil, uint64(0), nil, vm.ErrWriteProtection + return sdk.Context{}, nil, nil, uint64(0), nil, vm.ErrWriteProtection } // if the method type is `function` continue looking for arguments @@ -144,13 +131,13 @@ func (p Precompile) RunSetup( argsBz := contract.Input[4:] args, err = method.Inputs.Unpack(argsBz) if err != nil { - return sdk.Context{}, nil, s, nil, uint64(0), nil, err + return sdk.Context{}, nil, nil, uint64(0), nil, err } } initialGas := ctx.GasMeter().GasConsumed() - defer HandleGasError(ctx, contract, initialGas, &err, stateDB, s)() + defer HandleGasError(ctx, contract, initialGas, &err)() // set the default SDK gas configuration to track gas usage // we are changing the gas meter type, so it panics gracefully when out of gas @@ -160,20 +147,16 @@ func (p Precompile) RunSetup( // we need to consume the gas that was already used by the EVM ctx.GasMeter().ConsumeGas(initialGas, "creating a new gas meter") - return ctx, stateDB, s, method, initialGas, args, nil + return ctx, stateDB, method, initialGas, args, nil } // HandleGasError handles the out of gas panic by resetting the gas meter and returning an error. // This is used in order to avoid panics and to allow for the EVM to continue cleanup if the tx or query run out of gas. -func HandleGasError(ctx sdk.Context, contract *vm.Contract, initialGas storetypes.Gas, err *error, stateDB *statedb.StateDB, snapshot Snapshot) func() { +func HandleGasError(ctx sdk.Context, contract *vm.Contract, initialGas storetypes.Gas, err *error) func() { return func() { if r := recover(); r != nil { switch r.(type) { case storetypes.ErrorOutOfGas: - - // revert to snapshot on error - stateDB.RevertMultiStore(snapshot.MultiStore, snapshot.Events) - // update contract gas usedGas := ctx.GasMeter().GasConsumed() - initialGas _ = contract.UseGas(usedGas, nil, tracing.GasChangeCallFailedExecution) @@ -190,9 +173,7 @@ func HandleGasError(ctx sdk.Context, contract *vm.Contract, initialGas storetype } // AddJournalEntries adds the balanceChange (if corresponds) -// and precompileCall entries on the stateDB journal -// This allows to revert the call changes within an evm tx -func (p Precompile) AddJournalEntries(stateDB *statedb.StateDB, s Snapshot) error { +func (p Precompile) AddJournalEntries(stateDB *statedb.StateDB) error { for _, entry := range p.journalEntries { switch entry.Op { case Sub: @@ -204,7 +185,7 @@ func (p Precompile) AddJournalEntries(stateDB *statedb.StateDB, s Snapshot) erro } } - return stateDB.AddPrecompileFn(p.Address(), s.MultiStore, s.Events) + return nil } // SetBalanceChangeEntries sets the balanceChange entries diff --git a/precompiles/distribution/distribution.go b/precompiles/distribution/distribution.go index e111a72cb..921a66df6 100644 --- a/precompiles/distribution/distribution.go +++ b/precompiles/distribution/distribution.go @@ -85,68 +85,66 @@ func (p Precompile) RequiredGas(input []byte) uint64 { // Run executes the precompiled contract distribution methods defined in the ABI. func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, snapshot, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err, stateDB, snapshot)() - - return p.RunAtomic(snapshot, stateDB, func() ([]byte, error) { - switch method.Name { - // Custom transactions - case ClaimRewardsMethod: - bz, err = p.ClaimRewards(ctx, contract, stateDB, method, args) - // Distribution transactions - case SetWithdrawAddressMethod: - bz, err = p.SetWithdrawAddress(ctx, contract, stateDB, method, args) - case WithdrawDelegatorRewardMethod: - bz, err = p.WithdrawDelegatorReward(ctx, contract, stateDB, method, args) - case WithdrawValidatorCommissionMethod: - bz, err = p.WithdrawValidatorCommission(ctx, contract, stateDB, method, args) - case FundCommunityPoolMethod: - bz, err = p.FundCommunityPool(ctx, contract, stateDB, method, args) - case DepositValidatorRewardsPoolMethod: - bz, err = p.DepositValidatorRewardsPool(ctx, contract, stateDB, method, args) - // Distribution queries - case ValidatorDistributionInfoMethod: - bz, err = p.ValidatorDistributionInfo(ctx, contract, method, args) - case ValidatorOutstandingRewardsMethod: - bz, err = p.ValidatorOutstandingRewards(ctx, contract, method, args) - case ValidatorCommissionMethod: - bz, err = p.ValidatorCommission(ctx, contract, method, args) - case ValidatorSlashesMethod: - bz, err = p.ValidatorSlashes(ctx, contract, method, args) - case DelegationRewardsMethod: - bz, err = p.DelegationRewards(ctx, contract, method, args) - case DelegationTotalRewardsMethod: - bz, err = p.DelegationTotalRewards(ctx, contract, method, args) - case DelegatorValidatorsMethod: - bz, err = p.DelegatorValidators(ctx, contract, method, args) - case DelegatorWithdrawAddressMethod: - bz, err = p.DelegatorWithdrawAddress(ctx, contract, method, args) - case CommunityPoolMethod: - bz, err = p.CommunityPool(ctx, contract, method, args) - } - - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - if err := p.AddJournalEntries(stateDB, snapshot); err != nil { - return nil, err - } - - return bz, nil - }) + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + switch method.Name { + // Custom transactions + case ClaimRewardsMethod: + bz, err = p.ClaimRewards(ctx, contract, stateDB, method, args) + // Distribution transactions + case SetWithdrawAddressMethod: + bz, err = p.SetWithdrawAddress(ctx, contract, stateDB, method, args) + case WithdrawDelegatorRewardMethod: + bz, err = p.WithdrawDelegatorReward(ctx, contract, stateDB, method, args) + case WithdrawValidatorCommissionMethod: + bz, err = p.WithdrawValidatorCommission(ctx, contract, stateDB, method, args) + case FundCommunityPoolMethod: + bz, err = p.FundCommunityPool(ctx, contract, stateDB, method, args) + case DepositValidatorRewardsPoolMethod: + bz, err = p.DepositValidatorRewardsPool(ctx, contract, stateDB, method, args) + // Distribution queries + case ValidatorDistributionInfoMethod: + bz, err = p.ValidatorDistributionInfo(ctx, contract, method, args) + case ValidatorOutstandingRewardsMethod: + bz, err = p.ValidatorOutstandingRewards(ctx, contract, method, args) + case ValidatorCommissionMethod: + bz, err = p.ValidatorCommission(ctx, contract, method, args) + case ValidatorSlashesMethod: + bz, err = p.ValidatorSlashes(ctx, contract, method, args) + case DelegationRewardsMethod: + bz, err = p.DelegationRewards(ctx, contract, method, args) + case DelegationTotalRewardsMethod: + bz, err = p.DelegationTotalRewards(ctx, contract, method, args) + case DelegatorValidatorsMethod: + bz, err = p.DelegatorValidators(ctx, contract, method, args) + case DelegatorWithdrawAddressMethod: + bz, err = p.DelegatorWithdrawAddress(ctx, contract, method, args) + case CommunityPoolMethod: + bz, err = p.CommunityPool(ctx, contract, method, args) + } + + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + + if err = p.AddJournalEntries(stateDB); err != nil { + return nil, err + } + + return bz, nil } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/erc20/erc20.go b/precompiles/erc20/erc20.go index 2028d8994..a8f543d2d 100644 --- a/precompiles/erc20/erc20.go +++ b/precompiles/erc20/erc20.go @@ -144,31 +144,29 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ return nil, fmt.Errorf(ErrCannotReceiveFunds, contract.Value().String()) } - ctx, stateDB, snapshot, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err, stateDB, snapshot)() - - return p.RunAtomic(snapshot, stateDB, func() ([]byte, error) { - bz, err = p.HandleMethod(ctx, contract, stateDB, method, args) - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - if err := p.AddJournalEntries(stateDB, snapshot); err != nil { - return nil, err - } - return bz, nil - }) + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + bz, err = p.HandleMethod(ctx, contract, stateDB, method, args) + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + if err = p.AddJournalEntries(stateDB); err != nil { + return nil, err + } + return bz, nil } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/evidence/evidence.go b/precompiles/evidence/evidence.go index 86398396f..36320e4c1 100644 --- a/precompiles/evidence/evidence.go +++ b/precompiles/evidence/evidence.go @@ -82,45 +82,43 @@ func (p Precompile) RequiredGas(input []byte) uint64 { // Run executes the precompiled contract evidence methods defined in the ABI. func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, snapshot, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err, stateDB, snapshot)() - - return p.RunAtomic(snapshot, stateDB, func() ([]byte, error) { - switch method.Name { - // evidence transactions - case SubmitEvidenceMethod: - bz, err = p.SubmitEvidence(ctx, contract, stateDB, method, args) - // evidence queries - case EvidenceMethod: - bz, err = p.Evidence(ctx, method, args) - case GetAllEvidenceMethod: - bz, err = p.GetAllEvidence(ctx, method, args) - default: - return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) - } - - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - if err := p.AddJournalEntries(stateDB, snapshot); err != nil { - return nil, err - } - - return bz, nil - }) + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + switch method.Name { + // evidence transactions + case SubmitEvidenceMethod: + bz, err = p.SubmitEvidence(ctx, contract, stateDB, method, args) + // evidence queries + case EvidenceMethod: + bz, err = p.Evidence(ctx, method, args) + case GetAllEvidenceMethod: + bz, err = p.GetAllEvidence(ctx, method, args) + default: + return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) + } + + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + + if err = p.AddJournalEntries(stateDB); err != nil { + return nil, err + } + + return bz, nil } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/gov/gov.go b/precompiles/gov/gov.go index 7005f9542..9e66c9262 100644 --- a/precompiles/gov/gov.go +++ b/precompiles/gov/gov.go @@ -86,68 +86,66 @@ func (p Precompile) RequiredGas(input []byte) uint64 { // Run executes the precompiled contract gov methods defined in the ABI. func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, snapshot, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err, stateDB, snapshot)() - - return p.RunAtomic(snapshot, stateDB, func() ([]byte, error) { - switch method.Name { - // gov transactions - case VoteMethod: - bz, err = p.Vote(ctx, contract, stateDB, method, args) - case VoteWeightedMethod: - bz, err = p.VoteWeighted(ctx, contract, stateDB, method, args) - case SubmitProposalMethod: - bz, err = p.SubmitProposal(ctx, contract, stateDB, method, args) - case DepositMethod: - bz, err = p.Deposit(ctx, contract, stateDB, method, args) - case CancelProposalMethod: - bz, err = p.CancelProposal(ctx, contract, stateDB, method, args) - - // gov queries - case GetVoteMethod: - bz, err = p.GetVote(ctx, method, contract, args) - case GetVotesMethod: - bz, err = p.GetVotes(ctx, method, contract, args) - case GetDepositMethod: - bz, err = p.GetDeposit(ctx, method, contract, args) - case GetDepositsMethod: - bz, err = p.GetDeposits(ctx, method, contract, args) - case GetTallyResultMethod: - bz, err = p.GetTallyResult(ctx, method, contract, args) - case GetProposalMethod: - bz, err = p.GetProposal(ctx, method, contract, args) - case GetProposalsMethod: - bz, err = p.GetProposals(ctx, method, contract, args) - case GetParamsMethod: - bz, err = p.GetParams(ctx, method, contract, args) - case GetConstitutionMethod: - bz, err = p.GetConstitution(ctx, method, contract, args) - default: - return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) - } - - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - if err := p.AddJournalEntries(stateDB, snapshot); err != nil { - return nil, err - } - - return bz, nil - }) + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + switch method.Name { + // gov transactions + case VoteMethod: + bz, err = p.Vote(ctx, contract, stateDB, method, args) + case VoteWeightedMethod: + bz, err = p.VoteWeighted(ctx, contract, stateDB, method, args) + case SubmitProposalMethod: + bz, err = p.SubmitProposal(ctx, contract, stateDB, method, args) + case DepositMethod: + bz, err = p.Deposit(ctx, contract, stateDB, method, args) + case CancelProposalMethod: + bz, err = p.CancelProposal(ctx, contract, stateDB, method, args) + + // gov queries + case GetVoteMethod: + bz, err = p.GetVote(ctx, method, contract, args) + case GetVotesMethod: + bz, err = p.GetVotes(ctx, method, contract, args) + case GetDepositMethod: + bz, err = p.GetDeposit(ctx, method, contract, args) + case GetDepositsMethod: + bz, err = p.GetDeposits(ctx, method, contract, args) + case GetTallyResultMethod: + bz, err = p.GetTallyResult(ctx, method, contract, args) + case GetProposalMethod: + bz, err = p.GetProposal(ctx, method, contract, args) + case GetProposalsMethod: + bz, err = p.GetProposals(ctx, method, contract, args) + case GetParamsMethod: + bz, err = p.GetParams(ctx, method, contract, args) + case GetConstitutionMethod: + bz, err = p.GetConstitution(ctx, method, contract, args) + default: + return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) + } + + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + + if err = p.AddJournalEntries(stateDB); err != nil { + return nil, err + } + + return bz, nil } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/ics20/ics20.go b/precompiles/ics20/ics20.go index 8c8b5adbc..28613971c 100644 --- a/precompiles/ics20/ics20.go +++ b/precompiles/ics20/ics20.go @@ -89,47 +89,45 @@ func (p Precompile) RequiredGas(input []byte) uint64 { // Run executes the precompiled contract IBC transfer methods defined in the ABI. func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, snapshot, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err, stateDB, snapshot)() - - return p.RunAtomic(snapshot, stateDB, func() ([]byte, error) { - switch method.Name { - // ICS20 transactions - case TransferMethod: - bz, err = p.Transfer(ctx, contract, stateDB, method, args) - // ICS20 queries - case DenomMethod: - bz, err = p.Denom(ctx, contract, method, args) - case DenomsMethod: - bz, err = p.Denoms(ctx, contract, method, args) - case DenomHashMethod: - bz, err = p.DenomHash(ctx, contract, method, args) - default: - return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) - } - - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - if err := p.AddJournalEntries(stateDB, snapshot); err != nil { - return nil, err - } - - return bz, nil - }) + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + switch method.Name { + // ICS20 transactions + case TransferMethod: + bz, err = p.Transfer(ctx, contract, stateDB, method, args) + // ICS20 queries + case DenomMethod: + bz, err = p.Denom(ctx, contract, method, args) + case DenomsMethod: + bz, err = p.Denoms(ctx, contract, method, args) + case DenomHashMethod: + bz, err = p.DenomHash(ctx, contract, method, args) + default: + return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) + } + + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + + if err = p.AddJournalEntries(stateDB); err != nil { + return nil, err + } + + return bz, nil } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/slashing/slashing.go b/precompiles/slashing/slashing.go index d053e3094..04132d7b5 100644 --- a/precompiles/slashing/slashing.go +++ b/precompiles/slashing/slashing.go @@ -82,45 +82,43 @@ func (p Precompile) RequiredGas(input []byte) uint64 { // Run executes the precompiled contract slashing methods defined in the ABI. func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, snapshot, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err, stateDB, snapshot)() - - return p.RunAtomic(snapshot, stateDB, func() ([]byte, error) { - switch method.Name { - // slashing transactions - case UnjailMethod: - bz, err = p.Unjail(ctx, method, stateDB, contract, args) - // slashing queries - case GetSigningInfoMethod: - bz, err = p.GetSigningInfo(ctx, method, contract, args) - case GetSigningInfosMethod: - bz, err = p.GetSigningInfos(ctx, method, contract, args) - default: - return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) - } - - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - if err := p.AddJournalEntries(stateDB, snapshot); err != nil { - return nil, err - } - - return bz, nil - }) + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + switch method.Name { + // slashing transactions + case UnjailMethod: + bz, err = p.Unjail(ctx, method, stateDB, contract, args) + // slashing queries + case GetSigningInfoMethod: + bz, err = p.GetSigningInfo(ctx, method, contract, args) + case GetSigningInfosMethod: + bz, err = p.GetSigningInfos(ctx, method, contract, args) + default: + return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) + } + + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + + if err = p.AddJournalEntries(stateDB); err != nil { + return nil, err + } + + return bz, nil } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go index 88ab9eef9..1439ac94d 100644 --- a/precompiles/staking/staking.go +++ b/precompiles/staking/staking.go @@ -81,61 +81,59 @@ func (p Precompile) RequiredGas(input []byte) uint64 { // Run executes the precompiled contract staking methods defined in the ABI. func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, snapshot, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } // This handles any out of gas errors that may occur during the execution of a precompile tx or query. // It avoids panics and returns the out of gas error so the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err, stateDB, snapshot)() - - return p.RunAtomic(snapshot, stateDB, func() ([]byte, error) { - switch method.Name { - // Staking transactions - case CreateValidatorMethod: - bz, err = p.CreateValidator(ctx, contract, stateDB, method, args) - case EditValidatorMethod: - bz, err = p.EditValidator(ctx, contract, stateDB, method, args) - case DelegateMethod: - bz, err = p.Delegate(ctx, contract, stateDB, method, args) - case UndelegateMethod: - bz, err = p.Undelegate(ctx, contract, stateDB, method, args) - case RedelegateMethod: - bz, err = p.Redelegate(ctx, contract, stateDB, method, args) - case CancelUnbondingDelegationMethod: - bz, err = p.CancelUnbondingDelegation(ctx, contract, stateDB, method, args) - // Staking queries - case DelegationMethod: - bz, err = p.Delegation(ctx, contract, method, args) - case UnbondingDelegationMethod: - bz, err = p.UnbondingDelegation(ctx, contract, method, args) - case ValidatorMethod: - bz, err = p.Validator(ctx, method, contract, args) - case ValidatorsMethod: - bz, err = p.Validators(ctx, method, contract, args) - case RedelegationMethod: - bz, err = p.Redelegation(ctx, method, contract, args) - case RedelegationsMethod: - bz, err = p.Redelegations(ctx, method, contract, args) - } - - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - if err := p.AddJournalEntries(stateDB, snapshot); err != nil { - return nil, err - } - - return bz, nil - }) + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + switch method.Name { + // Staking transactions + case CreateValidatorMethod: + bz, err = p.CreateValidator(ctx, contract, stateDB, method, args) + case EditValidatorMethod: + bz, err = p.EditValidator(ctx, contract, stateDB, method, args) + case DelegateMethod: + bz, err = p.Delegate(ctx, contract, stateDB, method, args) + case UndelegateMethod: + bz, err = p.Undelegate(ctx, contract, stateDB, method, args) + case RedelegateMethod: + bz, err = p.Redelegate(ctx, contract, stateDB, method, args) + case CancelUnbondingDelegationMethod: + bz, err = p.CancelUnbondingDelegation(ctx, contract, stateDB, method, args) + // Staking queries + case DelegationMethod: + bz, err = p.Delegation(ctx, contract, method, args) + case UnbondingDelegationMethod: + bz, err = p.UnbondingDelegation(ctx, contract, method, args) + case ValidatorMethod: + bz, err = p.Validator(ctx, method, contract, args) + case ValidatorsMethod: + bz, err = p.Validators(ctx, method, contract, args) + case RedelegationMethod: + bz, err = p.Redelegation(ctx, method, contract, args) + case RedelegationsMethod: + bz, err = p.Redelegations(ctx, method, contract, args) + } + + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + + if err = p.AddJournalEntries(stateDB); err != nil { + return nil, err + } + + return bz, nil } // IsTransaction checks if the given method name corresponds to a transaction or query. diff --git a/precompiles/werc20/werc20.go b/precompiles/werc20/werc20.go index 85dc7d695..d8827b165 100644 --- a/precompiles/werc20/werc20.go +++ b/precompiles/werc20/werc20.go @@ -107,7 +107,7 @@ func (p Precompile) RequiredGas(input []byte) uint64 { // Run executes the precompiled contract WERC20 methods defined in the ABI. func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { - ctx, stateDB, snapshot, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) if err != nil { return nil, err } @@ -115,36 +115,34 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ // This handles any out of gas errors that may occur during the execution of // a precompile tx or query. It avoids panics and returns the out of gas error so // the EVM can continue gracefully. - defer cmn.HandleGasError(ctx, contract, initialGas, &err, stateDB, snapshot)() - - return p.RunAtomic(snapshot, stateDB, func() ([]byte, error) { - switch { - case method.Type == abi.Fallback, - method.Type == abi.Receive, - method.Name == DepositMethod: - bz, err = p.Deposit(ctx, contract, stateDB) - case method.Name == WithdrawMethod: - bz, err = p.Withdraw(ctx, contract, stateDB, args) - default: - // ERC20 transactions and queries - bz, err = p.HandleMethod(ctx, contract, stateDB, method, args) - } - - if err != nil { - return nil, err - } - - cost := ctx.GasMeter().GasConsumed() - initialGas - - if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { - return nil, vm.ErrOutOfGas - } - - if err := p.AddJournalEntries(stateDB, snapshot); err != nil { - return nil, err - } - return bz, nil - }) + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + switch { + case method.Type == abi.Fallback, + method.Type == abi.Receive, + method.Name == DepositMethod: + bz, err = p.Deposit(ctx, contract, stateDB) + case method.Name == WithdrawMethod: + bz, err = p.Withdraw(ctx, contract, stateDB, args) + default: + // ERC20 transactions and queries + bz, err = p.HandleMethod(ctx, contract, stateDB, method, args) + } + + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) { + return nil, vm.ErrOutOfGas + } + + if err = p.AddJournalEntries(stateDB); err != nil { + return nil, err + } + return bz, nil } // IsTransaction returns true if the given method name correspond to a