-
Notifications
You must be signed in to change notification settings - Fork 1
/
eth.go
executable file
·578 lines (479 loc) · 20.2 KB
/
eth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
package ante
import (
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/palantir/stacktrace"
treasurenet "github.com/maoaixiao1314/treasureapp/types"
evmtypes "github.com/maoaixiao1314/treasureapp/x/evm/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
)
// EVMKeeper defines the expected keeper interface used on the Eth AnteHandler
type EVMKeeper interface {
vm.StateDB
ChainID() *big.Int
GetParams(ctx sdk.Context) evmtypes.Params
WithContext(ctx sdk.Context)
ResetRefundTransient(ctx sdk.Context)
GetCoinbaseAddress() (common.Address, error)
NewEVM(msg core.Message, config *params.ChainConfig, params evmtypes.Params, coinbase common.Address, tracer vm.Tracer) *vm.EVM
GetCodeHash(addr common.Address) common.Hash
}
// EthSigVerificationDecorator validates an ethereum signatures
type EthSigVerificationDecorator struct {
evmKeeper EVMKeeper
}
// NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator
func NewEthSigVerificationDecorator(ek EVMKeeper) EthSigVerificationDecorator {
return EthSigVerificationDecorator{
evmKeeper: ek,
}
}
// AnteHandle validates checks that the registered chain id is the same as the one on the message, and
// that the signer address matches the one defined on the message.
// It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work.
// Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user
// won't see the error message.
func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if tx == nil || len(tx.GetMsgs()) != 1 {
return ctx, stacktrace.Propagate(
sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx"),
"",
)
}
chainID := esvd.evmKeeper.ChainID()
params := esvd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(chainID)
blockNum := big.NewInt(ctx.BlockHeight())
signer := ethtypes.MakeSigner(ethCfg, blockNum)
msg := tx.GetMsgs()[0]
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
"failed to cast transaction",
)
}
sender, err := signer.Sender(msgEthTx.AsTransaction())
if err != nil {
return ctx, stacktrace.Propagate(
sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, err.Error()),
"couldn't retrieve sender address ('%s') from the ethereum transaction",
msgEthTx.From,
)
}
// set up the sender to the transaction field if not already
msgEthTx.From = sender.Hex()
return next(ctx, msgEthTx, simulate)
}
// EthAccountVerificationDecorator validates an account balance checks
type EthAccountVerificationDecorator struct {
ak AccountKeeper
bankKeeper BankKeeper
evmKeeper EVMKeeper
}
// NewEthAccountVerificationDecorator creates a new EthAccountVerificationDecorator
func NewEthAccountVerificationDecorator(ak AccountKeeper, bankKeeper BankKeeper, ek EVMKeeper) EthAccountVerificationDecorator {
return EthAccountVerificationDecorator{
ak: ak,
bankKeeper: bankKeeper,
evmKeeper: ek,
}
}
// AnteHandle validates checks that the sender balance is greater than the total transaction cost.
// The account will be set to store if it doesn't exis, i.e cannot be found on store.
// This AnteHandler decorator will fail if:
// - any of the msgs is not a MsgEthereumTx
// - from address is empty
// - account balance is lower than the transaction cost
func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if !ctx.IsCheckTx() {
return next(ctx, tx, simulate)
}
avd.evmKeeper.WithContext(ctx)
evmDenom := avd.evmKeeper.GetParams(ctx).EvmDenom
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
"failed to cast transaction %d", i,
)
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, stacktrace.Propagate(err, "failed to unpack tx data any for tx %d", i)
}
// sender address should be in the tx cache from the previous AnteHandle call
from := msgEthTx.GetFrom()
if from.Empty() {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "from address cannot be empty"),
"sender address should have been in the tx field from the previous AnteHandle call",
)
}
// check whether the sender address is EOA
fromAddr := common.BytesToAddress(from)
codeHash := avd.evmKeeper.GetCodeHash(fromAddr)
if codeHash != common.BytesToHash(evmtypes.EmptyCodeHash) {
return ctx, stacktrace.Propagate(sdkerrors.Wrapf(sdkerrors.ErrInvalidType,
"the sender is not EOA: address <%v>, codeHash <%s>", fromAddr, codeHash), "")
}
acc := avd.ak.GetAccount(ctx, from)
if acc == nil {
acc = avd.ak.NewAccountWithAddress(ctx, from)
avd.ak.SetAccount(ctx, acc)
}
// validate sender has enough funds to pay for tx cost
balance := avd.bankKeeper.GetBalance(ctx, from, evmDenom)
cost := txData.Cost()
if balance.Amount.BigInt().Cmp(cost) < 0 {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFunds,
"sender balance < tx cost (%s < %s%s)", balance, txData.Cost(), evmDenom,
),
"sender should have had enough funds to pay for tx cost = fee + amount (%s = %s + %s)", cost, txData.Fee(), txData.GetValue(),
)
}
}
// recover the original gas meter
avd.evmKeeper.WithContext(ctx)
return next(ctx, tx, simulate)
}
// EthNonceVerificationDecorator checks that the account nonce from the transaction matches
// the sender account sequence.
type EthNonceVerificationDecorator struct {
ak AccountKeeper
}
// NewEthNonceVerificationDecorator creates a new EthNonceVerificationDecorator
func NewEthNonceVerificationDecorator(ak AccountKeeper) EthNonceVerificationDecorator {
return EthNonceVerificationDecorator{
ak: ak,
}
}
// AnteHandle validates that the transaction nonces are valid and equivalent to the sender account’s
// current nonce.
func (nvd EthNonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// no need to check the nonce on ReCheckTx
if ctx.IsReCheckTx() {
return next(ctx, tx, simulate)
}
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
"failed to cast transaction %d", i,
)
}
// sender address should be in the tx cache from the previous AnteHandle call
seq, err := nvd.ak.GetSequence(ctx, msgEthTx.GetFrom())
if err != nil {
return ctx, stacktrace.Propagate(err, "sequence not found for address %s", msgEthTx.From)
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, stacktrace.Propagate(err, "failed to unpack tx data")
}
// if multiple transactions are submitted in succession with increasing nonces,
// all will be rejected except the first, since the first needs to be included in a block
// before the sequence increments
if txData.GetNonce() != seq {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(
sdkerrors.ErrInvalidSequence,
"invalid nonce; got %d, expected %d", txData.GetNonce(), seq,
),
"",
)
}
}
return next(ctx, tx, simulate)
}
// EthGasConsumeDecorator validates enough intrinsic gas for the transaction and
// gas consumption.
type EthGasConsumeDecorator struct {
ak AccountKeeper
bankKeeper BankKeeper
evmKeeper EVMKeeper
}
// NewEthGasConsumeDecorator creates a new EthGasConsumeDecorator
func NewEthGasConsumeDecorator(ak AccountKeeper, bankKeeper BankKeeper, ek EVMKeeper) EthGasConsumeDecorator {
return EthGasConsumeDecorator{
ak: ak,
bankKeeper: bankKeeper,
evmKeeper: ek,
}
}
// AnteHandle validates that the Ethereum tx message has enough to cover intrinsic gas
// (during CheckTx only) and that the sender has enough balance to pay for the gas cost.
//
// Intrinsic gas for a transaction is the amount of gas that the transaction uses before the
// transaction is executed. The gas is a constant value plus any cost inccured by additional bytes
// of data supplied with the transaction.
//
// This AnteHandler decorator will fail if:
// - the transaction contains more than one message
// - the message is not a MsgEthereumTx
// - sender account cannot be found
// - transaction's gas limit is lower than the intrinsic gas
// - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
// - transaction or block gas meter runs out of gas
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// reset the refund gas value in the keeper for the current transaction
egcd.evmKeeper.ResetRefundTransient(ctx)
params := egcd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(egcd.evmKeeper.ChainID())
blockHeight := big.NewInt(ctx.BlockHeight())
homestead := ethCfg.IsHomestead(blockHeight)
istanbul := ethCfg.IsIstanbul(blockHeight)
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
"failed to cast transaction %d", i,
)
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, stacktrace.Propagate(err, "failed to unpack tx data")
}
isContractCreation := txData.GetTo() == nil
// fetch sender account from signature
signerAcc, err := authante.GetSignerAcc(ctx, egcd.ak, msgEthTx.GetFrom())
if err != nil {
return ctx, stacktrace.Propagate(err, "account not found for sender %s", msgEthTx.From)
}
gasLimit := txData.GetGas()
var accessList ethtypes.AccessList
if txData.GetAccessList() != nil {
accessList = txData.GetAccessList()
}
intrinsicGas, err := core.IntrinsicGas(txData.GetData(), accessList, isContractCreation, homestead, istanbul)
if err != nil {
return ctx, stacktrace.Propagate(
sdkerrors.Wrap(err, "failed to compute intrinsic gas cost"),
"failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t", isContractCreation, homestead, istanbul)
}
// intrinsic gas verification during CheckTx
if ctx.IsCheckTx() && gasLimit < intrinsicGas {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrOutOfGas, "gas limit too low: %d (gas limit) < %d (intrinsic gas)", gasLimit, intrinsicGas)
}
// calculate the fees paid to validators based on gas limit and price
feeAmt := txData.Fee() // fee = gas limit * gas price
evmDenom := egcd.evmKeeper.GetParams(ctx).EvmDenom
fees := sdk.Coins{sdk.NewCoin(evmDenom, sdk.NewIntFromBigInt(feeAmt))}
// deduct the full gas cost from the user balance
if err := authante.DeductFees(egcd.bankKeeper, ctx, signerAcc, fees); err != nil {
return ctx, stacktrace.Propagate(
err,
"failed to deduct full gas cost %s from the user %s balance", fees, msgEthTx.From,
)
}
}
// TODO: deprecate after https://github.com/cosmos/cosmos-sdk/issues/9514 is fixed on SDK
blockGasLimit := treasurenet.BlockGasLimit(ctx)
// NOTE: safety check
if blockGasLimit > 0 {
// generate a copy of the gas pool (i.e block gas meter) to see if we've run out of gas for this block
// if current gas consumed is greater than the limit, this funcion panics and the error is recovered on the Baseapp
gasPool := sdk.NewGasMeter(blockGasLimit)
gasPool.ConsumeGas(ctx.GasMeter().GasConsumedToLimit(), "gas pool check")
}
// we know that we have enough gas on the pool to cover the intrinsic gas
// set up the updated context to the evm Keeper
egcd.evmKeeper.WithContext(ctx)
return next(ctx, tx, simulate)
}
// CanTransferDecorator checks if the sender is allowed to transfer funds according to the EVM block
// context rules.
type CanTransferDecorator struct {
evmKeeper EVMKeeper
}
// NewCanTransferDecorator creates a new CanTransferDecorator instance.
func NewCanTransferDecorator(evmKeeper EVMKeeper) CanTransferDecorator {
return CanTransferDecorator{
evmKeeper: evmKeeper,
}
}
// AnteHandle creates an EVM from the message and calls the BlockContext CanTransfer function to
// see if the address can execute the transaction.
func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
ctd.evmKeeper.WithContext(ctx)
params := ctd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(ctd.evmKeeper.ChainID())
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight()))
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
"failed to cast transaction %d", i,
)
}
coreMsg, err := msgEthTx.AsMessage(signer)
if err != nil {
return ctx, stacktrace.Propagate(
err,
"failed to create an ethereum core.Message from signer %T", signer,
)
}
// NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below
evm := ctd.evmKeeper.NewEVM(coreMsg, ethCfg, params, common.Address{}, nil)
// check that caller has enough balance to cover asset transfer for **topmost** call
// NOTE: here the gas consumed is from the context with the infinite gas meter
if coreMsg.Value().Sign() > 0 && !evm.Context.CanTransfer(ctd.evmKeeper, coreMsg.From(), coreMsg.Value()) {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "address %s", coreMsg.From()),
"failed to transfer %s using the EVM block context transfer function", coreMsg.Value(),
)
}
}
ctd.evmKeeper.WithContext(ctx)
// set the original gas meter
return next(ctx, tx, simulate)
}
// AccessListDecorator prepare an access list for the sender if Yolov3/Berlin/EIPs 2929 and 2930 are
// applicable at the current block number.
type AccessListDecorator struct {
evmKeeper EVMKeeper
}
// NewAccessListDecorator creates a new AccessListDecorator.
func NewAccessListDecorator(evmKeeper EVMKeeper) AccessListDecorator {
return AccessListDecorator{
evmKeeper: evmKeeper,
}
}
// AnteHandle handles the preparatory steps for executing an EVM state transition with
// regards to both EIP-2929 and EIP-2930:
//
// - Add sender to access list (2929)
// - Add destination to access list (2929)
// - Add precompiles to access list (2929)
// - Add the contents of the optional tx access list (2930)
//
// The AnteHandler will only prepare the access list if Yolov3/Berlin/EIPs 2929 and 2930 are applicable at the current number.
func (ald AccessListDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
params := ald.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(ald.evmKeeper.ChainID())
rules := ethCfg.Rules(big.NewInt(ctx.BlockHeight()))
// we don't need to prepare the access list if the chain is not currently on the Berlin upgrade
if !rules.IsBerlin {
return next(ctx, tx, simulate)
}
// setup the keeper context before setting the access list
ald.evmKeeper.WithContext(ctx)
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
"failed to cast transaction %d", i,
)
}
sender := common.BytesToAddress(msgEthTx.GetFrom())
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, stacktrace.Propagate(err, "failed to unpack tx data")
}
ald.evmKeeper.PrepareAccessList(sender, txData.GetTo(), vm.ActivePrecompiles(rules), txData.GetAccessList())
}
// set the original gas meter
ald.evmKeeper.WithContext(ctx)
return next(ctx, tx, simulate)
}
// EthIncrementSenderSequenceDecorator increments the sequence of the signers.
type EthIncrementSenderSequenceDecorator struct {
ak AccountKeeper
}
// NewEthIncrementSenderSequenceDecorator creates a new EthIncrementSenderSequenceDecorator.
func NewEthIncrementSenderSequenceDecorator(ak AccountKeeper) EthIncrementSenderSequenceDecorator {
return EthIncrementSenderSequenceDecorator{
ak: ak,
}
}
// AnteHandle handles incrementing the sequence of the signer (i.e sender). If the transaction is a
// contract creation, the nonce will be incremented during the transaction execution and not within
// this AnteHandler decorator.
func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
"failed to cast transaction %d", i,
)
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, stacktrace.Propagate(err, "failed to unpack tx data")
}
// NOTE: on contract creation, the nonce is incremented within the EVM Create function during tx execution
// and not previous to the state transition ¯\_(ツ)_/¯
if txData.GetTo() == nil {
// contract creation, don't increment sequence on AnteHandler but on tx execution
// continue to the next item
continue
}
// increment sequence of all signers
for _, addr := range msg.GetSigners() {
acc := issd.ak.GetAccount(ctx, addr)
if acc == nil {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(
sdkerrors.ErrUnknownAddress,
"account %s (%s) is nil", common.BytesToAddress(addr.Bytes()), addr,
),
"signer account not found",
)
}
if err := acc.SetSequence(acc.GetSequence() + 1); err != nil {
return ctx, stacktrace.Propagate(err, "failed to set sequence to %d", acc.GetSequence()+1)
}
issd.ak.SetAccount(ctx, acc)
}
}
// set the original gas meter
return next(ctx, tx, simulate)
}
// EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures
type EthValidateBasicDecorator struct{}
// NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator
func NewEthValidateBasicDecorator() EthValidateBasicDecorator {
return EthValidateBasicDecorator{}
}
// AnteHandle handles basic validation of tx
func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// no need to validate basic on recheck tx, call next antehandler
if ctx.IsReCheckTx() {
return next(ctx, tx, simulate)
}
err := tx.ValidateBasic()
// ErrNoSignatures is fine with eth tx
if err != nil && err != sdkerrors.ErrNoSignatures {
return ctx, stacktrace.Propagate(err, "tx basic validation failed")
}
return next(ctx, tx, simulate)
}
// EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption
// by setting the gas meter to infinite
type EthSetupContextDecorator struct{}
func NewEthSetUpContextDecorator() EthSetupContextDecorator {
return EthSetupContextDecorator{}
}
func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// all transactions must implement GasTx
_, ok := tx.(authante.GasTx)
if !ok {
return newCtx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
}
newCtx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
return next(newCtx, tx, simulate)
}