Skip to content

Commit 25b89f3

Browse files
committed
refactor(precompiles): separate common logic
1 parent 46cd527 commit 25b89f3

File tree

10 files changed

+246
-237
lines changed

10 files changed

+246
-237
lines changed

precompiles/common/precompile.go

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,49 @@ func (p Precompile) RequiredGas(input []byte, isTransaction bool) uint64 {
5858
return p.KvGasConfig.ReadCostFlat + (p.KvGasConfig.ReadCostPerByte * uint64(len(argsBz)))
5959
}
6060

61+
// SetupAndRun wraps the execution of a precompile method with
62+
// the necessary setup, balance handling and gas accounting logic.
63+
// Precompile implementations can use this helper to avoid repetitive boilerplate
64+
// in their `Run` methods.
65+
func (p Precompile) SetupAndRun(
66+
evm *vm.EVM,
67+
contract *vm.Contract,
68+
readOnly bool,
69+
isTransaction func(*abi.Method) bool,
70+
handleMethod HandleMethodFunc,
71+
) (bz []byte, err error) {
72+
// Setup precompile method execution
73+
ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, isTransaction)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
// Handles the out of gas panic by resetting the gas meter and returning an error
79+
defer HandleGasError(ctx, contract, initialGas, &err)()
80+
81+
// Record the length of events emitted before precompile method execution
82+
p.GetBalanceHandler().BeforeBalanceChange(ctx)
83+
84+
// Executes precompile method
85+
bz, err = handleMethod(ctx, contract, stateDB, method, args)
86+
if err != nil {
87+
return nil, err
88+
}
89+
90+
// Handles native balance changes parsed from sdk.Events
91+
if err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil {
92+
return nil, err
93+
}
94+
95+
// Consume Gas
96+
cost := ctx.GasMeter().GasConsumed() - initialGas
97+
if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) {
98+
return nil, vm.ErrOutOfGas
99+
}
100+
101+
return bz, nil
102+
}
103+
61104
// RunSetup runs the initial setup required to run a transaction or a query.
62105
// It returns the sdk Context, EVM stateDB, ABI method, initial gas and calling arguments.
63106
func (p Precompile) RunSetup(
@@ -231,41 +274,3 @@ func (p *Precompile) GetBalanceHandler() *BalanceHandler {
231274
}
232275
return p.balanceHandler
233276
}
234-
235-
// ExecuteWithBalanceHandling wraps the execution of a precompile method with
236-
// the necessary balance handling and gas accounting logic. Precompile
237-
// implementations can use this helper to avoid repetitive boilerplate in their
238-
// `Run` methods.
239-
func (p Precompile) ExecuteWithBalanceHandling(
240-
evm *vm.EVM,
241-
contract *vm.Contract,
242-
readOnly bool,
243-
isTransaction func(*abi.Method) bool,
244-
handle func(ctx sdk.Context, contract *vm.Contract, stateDB *statedb.StateDB, method *abi.Method, args []interface{}) ([]byte, error),
245-
) (bz []byte, err error) {
246-
ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, isTransaction)
247-
if err != nil {
248-
return nil, err
249-
}
250-
251-
p.GetBalanceHandler().BeforeBalanceChange(ctx)
252-
253-
defer HandleGasError(ctx, contract, initialGas, &err)()
254-
255-
bz, err = handle(ctx, contract, stateDB, method, args)
256-
if err != nil {
257-
return nil, err
258-
}
259-
260-
cost := ctx.GasMeter().GasConsumed() - initialGas
261-
262-
if !contract.UseGas(cost, nil, tracing.GasChangeCallPrecompiledContract) {
263-
return nil, vm.ErrOutOfGas
264-
}
265-
266-
if err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB); err != nil {
267-
return nil, err
268-
}
269-
270-
return bz, nil
271-
}

precompiles/common/types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,22 @@ import (
88
"cosmossdk.io/math"
99

1010
sdk "github.com/cosmos/cosmos-sdk/types"
11+
"github.com/ethereum/go-ethereum/accounts/abi"
12+
"github.com/ethereum/go-ethereum/core/vm"
1113
)
1214

1315
// TrueValue is the byte array representing a true value in solidity.
1416
var TrueValue = []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}
1517

18+
// HandleMethodFunc defines precompile method handler fuction type.
19+
type HandleMethodFunc func(
20+
ctx sdk.Context,
21+
contract *vm.Contract,
22+
stateDB vm.StateDB,
23+
method *abi.Method,
24+
args []interface{},
25+
) ([]byte, error)
26+
1627
// ICS20Allocation defines the spend limit for a particular port and channel.
1728
// We need this to be able to unpack to big.Int instead of math.Int.
1829
type ICS20Allocation struct {

precompiles/distribution/distribution.go

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package distribution
33
import (
44
"embed"
55
"fmt"
6+
67
sdk "github.com/cosmos/cosmos-sdk/types"
7-
"github.com/cosmos/evm/x/vm/statedb"
88

99
"github.com/ethereum/go-ethereum/accounts/abi"
1010
"github.com/ethereum/go-ethereum/common"
@@ -86,47 +86,48 @@ func (p Precompile) RequiredGas(input []byte) uint64 {
8686

8787
// Run executes the precompiled contract distribution methods defined in the ABI.
8888
func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]byte, error) {
89-
return p.ExecuteWithBalanceHandling(
90-
evm, contract, readOnly, p.IsTransaction,
91-
func(ctx sdk.Context, contract *vm.Contract, stateDB *statedb.StateDB, method *abi.Method, args []interface{}) ([]byte, error) {
92-
switch method.Name {
93-
// Custom transactions
94-
case ClaimRewardsMethod:
95-
return p.ClaimRewards(ctx, contract, stateDB, method, args)
96-
// Distribution transactions
97-
case SetWithdrawAddressMethod:
98-
return p.SetWithdrawAddress(ctx, contract, stateDB, method, args)
99-
case WithdrawDelegatorRewardMethod:
100-
return p.WithdrawDelegatorReward(ctx, contract, stateDB, method, args)
101-
case WithdrawValidatorCommissionMethod:
102-
return p.WithdrawValidatorCommission(ctx, contract, stateDB, method, args)
103-
case FundCommunityPoolMethod:
104-
return p.FundCommunityPool(ctx, contract, stateDB, method, args)
105-
case DepositValidatorRewardsPoolMethod:
106-
return p.DepositValidatorRewardsPool(ctx, contract, stateDB, method, args)
107-
// Distribution queries
108-
case ValidatorDistributionInfoMethod:
109-
return p.ValidatorDistributionInfo(ctx, contract, method, args)
110-
case ValidatorOutstandingRewardsMethod:
111-
return p.ValidatorOutstandingRewards(ctx, contract, method, args)
112-
case ValidatorCommissionMethod:
113-
return p.ValidatorCommission(ctx, contract, method, args)
114-
case ValidatorSlashesMethod:
115-
return p.ValidatorSlashes(ctx, contract, method, args)
116-
case DelegationRewardsMethod:
117-
return p.DelegationRewards(ctx, contract, method, args)
118-
case DelegationTotalRewardsMethod:
119-
return p.DelegationTotalRewards(ctx, contract, method, args)
120-
case DelegatorValidatorsMethod:
121-
return p.DelegatorValidators(ctx, contract, method, args)
122-
case DelegatorWithdrawAddressMethod:
123-
return p.DelegatorWithdrawAddress(ctx, contract, method, args)
124-
case CommunityPoolMethod:
125-
return p.CommunityPool(ctx, contract, method, args)
126-
}
127-
return nil, nil
128-
},
129-
)
89+
return p.SetupAndRun(evm, contract, readOnly, p.IsTransaction, p.HandleMethod)
90+
}
91+
92+
// HandleMethod handles the execution of each method
93+
func (p Precompile) HandleMethod(ctx sdk.Context, contract *vm.Contract, stateDB vm.StateDB, method *abi.Method, args []interface{}) ([]byte, error) {
94+
switch method.Name {
95+
// Custom transactions
96+
case ClaimRewardsMethod:
97+
return p.ClaimRewards(ctx, contract, stateDB, method, args)
98+
// Distribution transactions
99+
case SetWithdrawAddressMethod:
100+
return p.SetWithdrawAddress(ctx, contract, stateDB, method, args)
101+
case WithdrawDelegatorRewardMethod:
102+
return p.WithdrawDelegatorReward(ctx, contract, stateDB, method, args)
103+
case WithdrawValidatorCommissionMethod:
104+
return p.WithdrawValidatorCommission(ctx, contract, stateDB, method, args)
105+
case FundCommunityPoolMethod:
106+
return p.FundCommunityPool(ctx, contract, stateDB, method, args)
107+
case DepositValidatorRewardsPoolMethod:
108+
return p.DepositValidatorRewardsPool(ctx, contract, stateDB, method, args)
109+
// Distribution queries
110+
case ValidatorDistributionInfoMethod:
111+
return p.ValidatorDistributionInfo(ctx, contract, method, args)
112+
case ValidatorOutstandingRewardsMethod:
113+
return p.ValidatorOutstandingRewards(ctx, contract, method, args)
114+
case ValidatorCommissionMethod:
115+
return p.ValidatorCommission(ctx, contract, method, args)
116+
case ValidatorSlashesMethod:
117+
return p.ValidatorSlashes(ctx, contract, method, args)
118+
case DelegationRewardsMethod:
119+
return p.DelegationRewards(ctx, contract, method, args)
120+
case DelegationTotalRewardsMethod:
121+
return p.DelegationTotalRewards(ctx, contract, method, args)
122+
case DelegatorValidatorsMethod:
123+
return p.DelegatorValidators(ctx, contract, method, args)
124+
case DelegatorWithdrawAddressMethod:
125+
return p.DelegatorWithdrawAddress(ctx, contract, method, args)
126+
case CommunityPoolMethod:
127+
return p.CommunityPool(ctx, contract, method, args)
128+
default:
129+
return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name)
130+
}
130131
}
131132

132133
// IsTransaction checks if the given method name corresponds to a transaction or query.

precompiles/erc20/erc20.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package erc20
33
import (
44
"embed"
55
"fmt"
6-
"github.com/cosmos/evm/x/vm/statedb"
76

87
"github.com/ethereum/go-ethereum/accounts/abi"
98
"github.com/ethereum/go-ethereum/core/vm"
@@ -144,12 +143,7 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]by
144143
return nil, fmt.Errorf(ErrCannotReceiveFunds, contract.Value().String())
145144
}
146145

147-
return p.ExecuteWithBalanceHandling(
148-
evm, contract, readOnly, p.IsTransaction,
149-
func(ctx sdk.Context, contract *vm.Contract, stateDB *statedb.StateDB, method *abi.Method, args []interface{}) ([]byte, error) {
150-
return p.HandleMethod(ctx, contract, stateDB, method, args)
151-
},
152-
)
146+
return p.SetupAndRun(evm, contract, readOnly, p.IsTransaction, p.HandleMethod)
153147
}
154148

155149
// IsTransaction checks if the given method name corresponds to a transaction or query.

precompiles/evidence/evidence.go

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package evidence
33
import (
44
"embed"
55
"fmt"
6-
"github.com/cosmos/evm/x/vm/statedb"
76

87
"github.com/ethereum/go-ethereum/accounts/abi"
98
"github.com/ethereum/go-ethereum/common"
@@ -82,23 +81,23 @@ func (p Precompile) RequiredGas(input []byte) uint64 {
8281

8382
// Run executes the precompiled contract evidence methods defined in the ABI.
8483
func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]byte, error) {
85-
return p.ExecuteWithBalanceHandling(
86-
evm, contract, readOnly, p.IsTransaction,
87-
func(ctx sdk.Context, contract *vm.Contract, stateDB *statedb.StateDB, method *abi.Method, args []interface{}) ([]byte, error) {
88-
switch method.Name {
89-
// evidence transactions
90-
case SubmitEvidenceMethod:
91-
return p.SubmitEvidence(ctx, contract, stateDB, method, args)
92-
// evidence queries
93-
case EvidenceMethod:
94-
return p.Evidence(ctx, method, args)
95-
case GetAllEvidenceMethod:
96-
return p.GetAllEvidence(ctx, method, args)
97-
default:
98-
return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name)
99-
}
100-
},
101-
)
84+
return p.SetupAndRun(evm, contract, readOnly, p.IsTransaction, p.HandleMethod)
85+
}
86+
87+
// HandleMethod handles the execution of each method
88+
func (p Precompile) HandleMethod(ctx sdk.Context, contract *vm.Contract, stateDB vm.StateDB, method *abi.Method, args []interface{}) ([]byte, error) {
89+
switch method.Name {
90+
// evidence transactions
91+
case SubmitEvidenceMethod:
92+
return p.SubmitEvidence(ctx, contract, stateDB, method, args)
93+
// evidence queries
94+
case EvidenceMethod:
95+
return p.Evidence(ctx, method, args)
96+
case GetAllEvidenceMethod:
97+
return p.GetAllEvidence(ctx, method, args)
98+
default:
99+
return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name)
100+
}
102101
}
103102

104103
// IsTransaction checks if the given method name corresponds to a transaction or query.

precompiles/gov/gov.go

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package gov
33
import (
44
"embed"
55
"fmt"
6-
"github.com/cosmos/evm/x/vm/statedb"
76

87
"github.com/ethereum/go-ethereum/accounts/abi"
98
"github.com/ethereum/go-ethereum/common"
@@ -86,46 +85,46 @@ func (p Precompile) RequiredGas(input []byte) uint64 {
8685

8786
// Run executes the precompiled contract gov methods defined in the ABI.
8887
func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]byte, error) {
89-
return p.ExecuteWithBalanceHandling(
90-
evm, contract, readOnly, p.IsTransaction,
91-
func(ctx sdk.Context, contract *vm.Contract, stateDB *statedb.StateDB, method *abi.Method, args []interface{}) ([]byte, error) {
92-
switch method.Name {
93-
// gov transactions
94-
case VoteMethod:
95-
return p.Vote(ctx, contract, stateDB, method, args)
96-
case VoteWeightedMethod:
97-
return p.VoteWeighted(ctx, contract, stateDB, method, args)
98-
case SubmitProposalMethod:
99-
return p.SubmitProposal(ctx, contract, stateDB, method, args)
100-
case DepositMethod:
101-
return p.Deposit(ctx, contract, stateDB, method, args)
102-
case CancelProposalMethod:
103-
return p.CancelProposal(ctx, contract, stateDB, method, args)
104-
105-
// gov queries
106-
case GetVoteMethod:
107-
return p.GetVote(ctx, method, contract, args)
108-
case GetVotesMethod:
109-
return p.GetVotes(ctx, method, contract, args)
110-
case GetDepositMethod:
111-
return p.GetDeposit(ctx, method, contract, args)
112-
case GetDepositsMethod:
113-
return p.GetDeposits(ctx, method, contract, args)
114-
case GetTallyResultMethod:
115-
return p.GetTallyResult(ctx, method, contract, args)
116-
case GetProposalMethod:
117-
return p.GetProposal(ctx, method, contract, args)
118-
case GetProposalsMethod:
119-
return p.GetProposals(ctx, method, contract, args)
120-
case GetParamsMethod:
121-
return p.GetParams(ctx, method, contract, args)
122-
case GetConstitutionMethod:
123-
return p.GetConstitution(ctx, method, contract, args)
124-
default:
125-
return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name)
126-
}
127-
},
128-
)
88+
return p.SetupAndRun(evm, contract, readOnly, p.IsTransaction, p.HandleMethod)
89+
}
90+
91+
// HandleMethod handles the execution of each method
92+
func (p Precompile) HandleMethod(ctx sdk.Context, contract *vm.Contract, stateDB vm.StateDB, method *abi.Method, args []interface{}) ([]byte, error) {
93+
switch method.Name {
94+
// gov transactions
95+
case VoteMethod:
96+
return p.Vote(ctx, contract, stateDB, method, args)
97+
case VoteWeightedMethod:
98+
return p.VoteWeighted(ctx, contract, stateDB, method, args)
99+
case SubmitProposalMethod:
100+
return p.SubmitProposal(ctx, contract, stateDB, method, args)
101+
case DepositMethod:
102+
return p.Deposit(ctx, contract, stateDB, method, args)
103+
case CancelProposalMethod:
104+
return p.CancelProposal(ctx, contract, stateDB, method, args)
105+
106+
// gov queries
107+
case GetVoteMethod:
108+
return p.GetVote(ctx, method, contract, args)
109+
case GetVotesMethod:
110+
return p.GetVotes(ctx, method, contract, args)
111+
case GetDepositMethod:
112+
return p.GetDeposit(ctx, method, contract, args)
113+
case GetDepositsMethod:
114+
return p.GetDeposits(ctx, method, contract, args)
115+
case GetTallyResultMethod:
116+
return p.GetTallyResult(ctx, method, contract, args)
117+
case GetProposalMethod:
118+
return p.GetProposal(ctx, method, contract, args)
119+
case GetProposalsMethod:
120+
return p.GetProposals(ctx, method, contract, args)
121+
case GetParamsMethod:
122+
return p.GetParams(ctx, method, contract, args)
123+
case GetConstitutionMethod:
124+
return p.GetConstitution(ctx, method, contract, args)
125+
default:
126+
return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name)
127+
}
129128
}
130129

131130
// IsTransaction checks if the given method name corresponds to a transaction or query.

0 commit comments

Comments
 (0)