From 1391fb336441d6d1ced9231c7c1d518d985065c5 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Tue, 5 Aug 2025 14:59:48 +0200 Subject: [PATCH 01/61] feat(erc20factory): erc20factory precompile --- evmd/precompiles.go | 7 + local_node.sh | 2 +- precompiles/common/interfaces.go | 2 + precompiles/erc20factory/IERC20Factory.sol | 57 +++++ precompiles/erc20factory/abi.json | 139 +++++++++++ precompiles/erc20factory/erc20factory.go | 155 ++++++++++++ precompiles/erc20factory/erc20factory_test.go | 62 +++++ precompiles/erc20factory/events.go | 57 +++++ precompiles/erc20factory/events_test.go | 70 ++++++ precompiles/erc20factory/interfaces.go | 25 ++ precompiles/erc20factory/query.go | 29 +++ precompiles/erc20factory/query_test.go | 75 ++++++ precompiles/erc20factory/setup_test.go | 61 +++++ precompiles/erc20factory/tx.go | 140 +++++++++++ precompiles/erc20factory/tx_test.go | 172 ++++++++++++++ precompiles/erc20factory/types.go | 101 ++++++++ precompiles/erc20factory/types_test.go | 223 ++++++++++++++++++ precompiles/erc20factory/utils_test.go | 56 +++++ tests/solidity/init-node.sh | 2 +- .../suites/precompiles/test/erc20factory.js | 62 +++++ x/precisebank/keeper/keeper.go | 9 + 21 files changed, 1504 insertions(+), 2 deletions(-) create mode 100644 precompiles/erc20factory/IERC20Factory.sol create mode 100644 precompiles/erc20factory/abi.json create mode 100644 precompiles/erc20factory/erc20factory.go create mode 100644 precompiles/erc20factory/erc20factory_test.go create mode 100644 precompiles/erc20factory/events.go create mode 100644 precompiles/erc20factory/events_test.go create mode 100644 precompiles/erc20factory/interfaces.go create mode 100644 precompiles/erc20factory/query.go create mode 100644 precompiles/erc20factory/query_test.go create mode 100644 precompiles/erc20factory/setup_test.go create mode 100644 precompiles/erc20factory/tx.go create mode 100644 precompiles/erc20factory/tx_test.go create mode 100644 precompiles/erc20factory/types.go create mode 100644 precompiles/erc20factory/types_test.go create mode 100644 precompiles/erc20factory/utils_test.go create mode 100644 tests/solidity/suites/precompiles/test/erc20factory.js diff --git a/evmd/precompiles.go b/evmd/precompiles.go index 49fcdab1a9..252e5de226 100644 --- a/evmd/precompiles.go +++ b/evmd/precompiles.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/evm/precompiles/bech32" cmn "github.com/cosmos/evm/precompiles/common" distprecompile "github.com/cosmos/evm/precompiles/distribution" + "github.com/cosmos/evm/precompiles/erc20factory" evidenceprecompile "github.com/cosmos/evm/precompiles/evidence" govprecompile "github.com/cosmos/evm/precompiles/gov" ics20precompile "github.com/cosmos/evm/precompiles/ics20" @@ -104,6 +105,11 @@ func NewAvailableStaticPrecompiles( panic(fmt.Errorf("failed to instantiate evidence precompile: %w", err)) } + erc20FactoryPrecompile, err := erc20factory.NewPrecompile(&erc20Keeper, bankKeeper) + if err != nil { + panic(fmt.Errorf("failed to instantiate erc20 factory precompile: %w", err)) + } + // Stateless precompiles precompiles[bech32Precompile.Address()] = bech32Precompile precompiles[p256Precompile.Address()] = p256Precompile @@ -116,6 +122,7 @@ func NewAvailableStaticPrecompiles( precompiles[govPrecompile.Address()] = govPrecompile precompiles[slashingPrecompile.Address()] = slashingPrecompile precompiles[evidencePrecompile.Address()] = evidencePrecompile + precompiles[erc20FactoryPrecompile.Address()] = erc20FactoryPrecompile return precompiles } diff --git a/local_node.sh b/local_node.sh index 2c33464033..5aaff475d3 100755 --- a/local_node.sh +++ b/local_node.sh @@ -136,7 +136,7 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then jq '.app_state["bank"]["denom_metadata"]=[{"description":"The native staking token for evmd.","denom_units":[{"denom":"atest","exponent":0,"aliases":["attotest"]},{"denom":"test","exponent":18,"aliases":[]}],"base":"atest","display":"test","name":"Test Token","symbol":"TEST","uri":"","uri_hash":""}]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" # Enable precompiles in EVM params - jq '.app_state["evm"]["params"]["active_static_precompiles"]=["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804","0x0000000000000000000000000000000000000805"]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + jq '.app_state["evm"]["params"]["active_static_precompiles"]=["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804","0x0000000000000000000000000000000000000805", "0x0000000000000000000000000000000000000900"]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" # Set EVM config jq '.app_state["evm"]["params"]["evm_denom"]="atest"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" diff --git a/precompiles/common/interfaces.go b/precompiles/common/interfaces.go index 631f913449..c1d8fb30ec 100644 --- a/precompiles/common/interfaces.go +++ b/precompiles/common/interfaces.go @@ -16,4 +16,6 @@ type BankKeeper interface { GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin SendCoins(ctx context.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error SpendableCoin(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin + MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error } diff --git a/precompiles/erc20factory/IERC20Factory.sol b/precompiles/erc20factory/IERC20Factory.sol new file mode 100644 index 0000000000..1a2be905a4 --- /dev/null +++ b/precompiles/erc20factory/IERC20Factory.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.17; + +/** + * @dev The ERC20 Factory contract's address. + */ +address constant ERC20_FACTORY_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000900; + +/** + * @dev The ERC20 Factory contract's instance. + */ +IERC20Factory constant ERC20_FACTORY_CONTRACT = IERC20Factory(ERC20_FACTORY_PRECOMPILE_ADDRESS); + +interface IERC20Factory { + /** + * @dev Emitted when a new ERC20 token is created. + * @param tokenAddress The address of the ERC20 token. + * @param tokenPairType The type of token pair. + * @param salt The salt used for deployment. + * @param name The name of the token. + * @param symbol The symbol of the token. + * @param decimals The decimals of the token. + */ + event Create( + address indexed tokenAddress, + uint8 tokenPairType, + bytes32 salt, + string name, + string symbol, + uint8 decimals + ); + + /** + * @dev Defines a method for creating an ERC20 token. + * @param tokenPairType Token Pair type + * @param salt Salt used for deployment + * @param name The name of the token. + * @param symbol The symbol of the token. + * @param decimals the decimals of the token. + * @return tokenAddress The ERC20 token address. + */ + function create( + uint8 tokenPairType, + bytes32 salt, + string memory name, + string memory symbol, + uint8 decimals + ) external returns (address tokenAddress); + + /** + * @dev Calculates the deterministic address for a new token. + * @param tokenPairType Token Pair type + * @param salt Salt used for deployment + * @return tokenAddress The calculated ERC20 token address. + */ + function calculateAddress(uint8 tokenPairType, bytes32 salt) external view returns (address tokenAddress); +} \ No newline at end of file diff --git a/precompiles/erc20factory/abi.json b/precompiles/erc20factory/abi.json new file mode 100644 index 0000000000..d3db7dc537 --- /dev/null +++ b/precompiles/erc20factory/abi.json @@ -0,0 +1,139 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "IERC20Factory", + "sourceName": "solidity/precompiles/erc20factory/IERC20Factory.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "uint8", + "name": "tokenPairType", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "calculateAddress", + "outputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "tokenPairType", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals", + "type": "uint8" + }, + { + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "premintedSupply", + "type": "uint256" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "tokenPairType", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "decimals", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "premintedSupply", + "type": "uint256" + } + ], + "name": "Create", + "type": "event" + } + ], + "bytecode": "0x", + "deployedBytecode": "0x", + "linkReferences": {}, + "deployedLinkReferences": {} +} \ No newline at end of file diff --git a/precompiles/erc20factory/erc20factory.go b/precompiles/erc20factory/erc20factory.go new file mode 100644 index 0000000000..0205e7a543 --- /dev/null +++ b/precompiles/erc20factory/erc20factory.go @@ -0,0 +1,155 @@ +package erc20factory + +import ( + "embed" + "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/vm" + + cmn "github.com/cosmos/evm/precompiles/common" + + storetypes "cosmossdk.io/store/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + Erc20FactoryAddress = "0x0000000000000000000000000000000000000900" + // GasCreate defines the gas required to create a new ERC20 Token Pair calculated from a ERC20 deploy transaction + GasCreate = 3_000_000 + // GasCalculateAddress defines the gas required to calculate the address of a new ERC20 Token Pair + GasCalculateAddress = 3_000 +) + +var _ vm.PrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +// Precompile defines the precompiled contract for Bech32 encoding. +type Precompile struct { + cmn.Precompile + erc20Keeper ERC20Keeper + bankKeeper BankKeeper +} + +// NewPrecompile creates a new bech32 Precompile instance as a +// PrecompiledContract interface. +func NewPrecompile(erc20Keeper ERC20Keeper, bankKeeper BankKeeper) (*Precompile, error) { + newABI, err := cmn.LoadABI(f, "abi.json") + if err != nil { + return nil, err + } + + p := &Precompile{ + Precompile: cmn.Precompile{ + ABI: newABI, + KvGasConfig: storetypes.KVGasConfig(), + TransientKVGasConfig: storetypes.TransientGasConfig(), + }, + erc20Keeper: erc20Keeper, + bankKeeper: bankKeeper, + } + + // SetAddress defines the address of the distribution compile contract. + p.SetAddress(common.HexToAddress(Erc20FactoryAddress)) + return p, nil +} + +// Address defines the address of the bech32 precompiled contract. +func (Precompile) Address() common.Address { + return common.HexToAddress(Erc20FactoryAddress) +} + +// RequiredGas calculates the contract gas use. +func (p Precompile) RequiredGas(input []byte) uint64 { + // NOTE: This check avoid panicking when trying to decode the method ID + if len(input) < 4 { + return 0 + } + + methodID := input[:4] + method, err := p.MethodById(methodID) + if err != nil { + return 0 + } + + switch method.Name { + // ERC-20 transactions + case CreateMethod: + return GasCreate + case CalculateAddressMethod: + return GasCalculateAddress + default: + return 0 + } +} + +// Run executes the precompiled contract bech32 methods defined in the ABI. +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { + 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)() + + 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 + } + + // Process the native balance changes after the method execution. + err = p.GetBalanceHandler().AfterBalanceChange(ctx, stateDB) + if err != nil { + return nil, err + } + + return bz, nil +} + +// IsTransaction checks if the given method name corresponds to a transaction or query. +// +// Available ERC20 Factory transactions are: +// - Create +func (Precompile) IsTransaction(method *abi.Method) bool { + switch method.Name { + case CreateMethod: + return true + default: + return false + } +} + +// HandleMethod handles the execution of each of the ERC-20 Factory methods. +func (p *Precompile) HandleMethod( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) (bz []byte, err error) { + switch method.Name { + // ERC-20 Factory transactions + case CreateMethod: + bz, err = p.Create(ctx, stateDB, method, contract.Caller(), args) + // ERC-20 Factory queries + case CalculateAddressMethod: + bz, err = p.CalculateAddress(method, contract.Caller(), args) + default: + return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) + } + return bz, err +} \ No newline at end of file diff --git a/precompiles/erc20factory/erc20factory_test.go b/precompiles/erc20factory/erc20factory_test.go new file mode 100644 index 0000000000..6bb6c28650 --- /dev/null +++ b/precompiles/erc20factory/erc20factory_test.go @@ -0,0 +1,62 @@ +package erc20factory_test + +import ( + "math/big" + + "github.com/cosmos/evm/precompiles/erc20factory" + utiltx "github.com/cosmos/evm/testutil/tx" +) + +func (s *PrecompileTestSuite) TestIsTransaction() { + s.SetupTest() + + // Queries + method := s.precompile.Methods[erc20factory.CalculateAddressMethod] + s.Require().False(s.precompile.IsTransaction(&method)) + + // Transactions + method = s.precompile.Methods[erc20factory.CreateMethod] + s.Require().True(s.precompile.IsTransaction(&method)) +} + +func (s *PrecompileTestSuite) TestRequiredGas() { + s.SetupTest() + + mintAddr := utiltx.GenerateAddress() + decimals := uint8(18) + amount := big.NewInt(1000000) + name := "Test" + symbol := "TEST" + + testcases := []struct { + name string + malleate func() []byte + expGas uint64 + }{ + { + name: erc20factory.CalculateAddressMethod, + malleate: func() []byte { + bz, err := s.precompile.Pack(erc20factory.CalculateAddressMethod, uint8(0), [32]uint8{}) + s.Require().NoError(err, "expected no error packing ABI") + return bz + }, + expGas: erc20factory.GasCalculateAddress, + }, + { + name: erc20factory.CreateMethod, + malleate: func() []byte { + bz, err := s.precompile.Pack(erc20factory.CreateMethod, uint8(0), [32]uint8{}, name, symbol, decimals, mintAddr, amount) + s.Require().NoError(err, "expected no error packing ABI") + return bz + }, + expGas: erc20factory.GasCreate, + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + gas := s.precompile.RequiredGas(tc.malleate()) + s.Require().Equal(tc.expGas, gas) + }) + } +} \ No newline at end of file diff --git a/precompiles/erc20factory/events.go b/precompiles/erc20factory/events.go new file mode 100644 index 0000000000..912189512c --- /dev/null +++ b/precompiles/erc20factory/events.go @@ -0,0 +1,57 @@ +package erc20factory + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + + cmn "github.com/cosmos/evm/precompiles/common" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // EventTypeCreate is the event type for the Create event. + EventTypeCreate = "Create" +) + +// EmitCreateEvent emits the Create event. +func (p Precompile) EmitCreateEvent(ctx sdk.Context, stateDB vm.StateDB, tokenAddress common.Address, tokenType uint8, salt [32]uint8, name string, symbol string, decimals uint8, minter common.Address, premintedSupply *big.Int) error { + event := p.Events[EventTypeCreate] + topics := make([]common.Hash, 2) // Only 2 topics: event ID + tokenAddress + + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(tokenAddress) + if err != nil { + return err + } + + // Pack the non-indexed event parameters into the data field + arguments := abi.Arguments{ + event.Inputs[1], // tokenType + event.Inputs[2], // salt + event.Inputs[3], // name + event.Inputs[4], // symbol + event.Inputs[5], // decimals + event.Inputs[6], // minter + event.Inputs[7], // premintedSupply + } + packed, err := arguments.Pack(tokenType, salt, name, symbol, decimals, minter, premintedSupply) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), //nolint:gosec // G115 // block height won't exceed uint64 + }) + + return nil +} \ No newline at end of file diff --git a/precompiles/erc20factory/events_test.go b/precompiles/erc20factory/events_test.go new file mode 100644 index 0000000000..1420562d72 --- /dev/null +++ b/precompiles/erc20factory/events_test.go @@ -0,0 +1,70 @@ +package erc20factory_test + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + cmn "github.com/cosmos/evm/precompiles/common" + "github.com/cosmos/evm/precompiles/erc20factory" + utiltx "github.com/cosmos/evm/testutil/tx" +) + +func (s *PrecompileTestSuite) TestEmitCreateEvent() { + testcases := []struct { + testName string + tokenAddress common.Address + tokenType uint8 + salt [32]uint8 + name string + symbol string + decimals uint8 + minter common.Address + premintedSupply *big.Int + }{ + { + testName: "pass", + tokenAddress: utiltx.GenerateAddress(), + tokenType: 0, + salt: [32]uint8{0}, + name: "Test", + symbol: "TEST", + decimals: 18, + minter: utiltx.GenerateAddress(), + premintedSupply: big.NewInt(1000000), + }, + } + + for _, tc := range testcases { + s.Run(tc.testName, func() { + s.SetupTest() + stateDB := s.network.GetStateDB() + + err := s.precompile.EmitCreateEvent(s.network.GetContext(), stateDB, tc.tokenAddress, tc.tokenType, tc.salt, tc.name, tc.symbol, tc.decimals, tc.minter, tc.premintedSupply) + s.Require().NoError(err, "expected create event to be emitted successfully") + + log := stateDB.Logs()[0] + s.Require().Equal(log.Address, s.precompile.Address()) + + // Check event signature matches the one emitted + event := s.precompile.ABI.Events[erc20factory.EventTypeCreate] + s.Require().Equal(crypto.Keccak256Hash([]byte(event.Sig)), common.HexToHash(log.Topics[0].Hex())) + s.Require().Equal(log.BlockNumber, uint64(s.network.GetContext().BlockHeight())) //nolint:gosec // G115 + + // Check event parameters + var createEvent erc20factory.EventCreate + err = cmn.UnpackLog(s.precompile.ABI, &createEvent, erc20factory.EventTypeCreate, *log) + s.Require().NoError(err, "unable to unpack log into create event") + + s.Require().Equal(tc.tokenAddress, createEvent.TokenAddress, "expected different token address") + s.Require().Equal(tc.tokenType, createEvent.TokenPairType, "expected different token type") + s.Require().Equal(tc.salt, createEvent.Salt, "expected different salt") + s.Require().Equal(tc.name, createEvent.Name, "expected different name") + s.Require().Equal(tc.symbol, createEvent.Symbol, "expected different symbol") + s.Require().Equal(tc.decimals, createEvent.Decimals, "expected different decimals") + s.Require().Equal(tc.minter, createEvent.Minter, "expected different minter") + s.Require().Equal(tc.premintedSupply, createEvent.PremintedSupply, "expected different preminted supply") + }) + } +} \ No newline at end of file diff --git a/precompiles/erc20factory/interfaces.go b/precompiles/erc20factory/interfaces.go new file mode 100644 index 0000000000..920af5b419 --- /dev/null +++ b/precompiles/erc20factory/interfaces.go @@ -0,0 +1,25 @@ +package erc20factory + +import ( + "context" + + "github.com/ethereum/go-ethereum/common" + + erc20types "github.com/cosmos/evm/x/erc20/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +type ERC20Keeper interface { + SetToken(ctx sdk.Context, token erc20types.TokenPair) error + EnableDynamicPrecompile(ctx sdk.Context, address common.Address) error + IsDenomRegistered(ctx sdk.Context, denom string) bool +} + +type BankKeeper interface { + GetDenomMetaData(ctx context.Context, denom string) (banktypes.Metadata, bool) + SetDenomMetaData(ctx context.Context, denomMetaData banktypes.Metadata) + MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error +} \ No newline at end of file diff --git a/precompiles/erc20factory/query.go b/precompiles/erc20factory/query.go new file mode 100644 index 0000000000..15dbcbf822 --- /dev/null +++ b/precompiles/erc20factory/query.go @@ -0,0 +1,29 @@ +package erc20factory + +import ( + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +const ( + // CalculateAddressMethod defines the ABI method name for the CalculateAddress + // query. + CalculateAddressMethod = "calculateAddress" +) + +// CalculateAddress calculates the address of a new ERC20 Token Pair +func (p Precompile) CalculateAddress( + method *abi.Method, + caller common.Address, + args []interface{}, +) ([]byte, error) { + tokenType, salt, err := ParseCalculateAddressArgs(args) + if err != nil { + return nil, err + } + + address := crypto.CreateAddress2(caller, salt, calculateCodeHash(tokenType)) + + return method.Outputs.Pack(address) +} \ No newline at end of file diff --git a/precompiles/erc20factory/query_test.go b/precompiles/erc20factory/query_test.go new file mode 100644 index 0000000000..155af3a0ca --- /dev/null +++ b/precompiles/erc20factory/query_test.go @@ -0,0 +1,75 @@ +package erc20factory_test + +import ( + "github.com/cosmos/evm/precompiles/erc20factory" + "github.com/ethereum/go-ethereum/common" +) + +func (s *PrecompileTestSuite) TestCalculateAddress() { + defaultCaller := common.HexToAddress("0xDc411BaFB148ebDA2B63EBD5f3D8669DD4383Af5") + + testcases := []struct { + name string + caller common.Address + args []interface{} + expPass bool + errContains string + expAddress common.Address + }{ + { + name: "pass - correct arguments", + caller: defaultCaller, + args: []interface{}{ + uint8(0), + [32]uint8(common.HexToHash("0x4f5b6f778b28c4d67a9c12345678901234567890123456789012345678901234").Bytes()), + }, + expPass: true, + expAddress: common.HexToAddress("0x188a919f3583f8e02183332E6c73E944E002C553"), + }, + { + name: "fail - invalid tokenType", + caller: defaultCaller, + args: []interface{}{ + "invalid tokenType", + "invalid salt", + }, + errContains: "invalid tokenType", + }, + { + name: "fail - invalid salt", + caller: defaultCaller, + args: []interface{}{ + uint8(0), + "invalid salt", + }, + errContains: "invalid salt", + }, + { + name: "fail - invalid number of arguments", + caller: defaultCaller, + args: []interface{}{ + 1, 2, 3, + }, + errContains: "invalid number of arguments", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + + precompile := s.setupERC20FactoryPrecompile() + + method := precompile.Methods[erc20factory.CalculateAddressMethod] + + bz, err := precompile.CalculateAddress( + &method, + tc.caller, + tc.args, + ) + + // NOTE: all output and error checking happens in here + s.requireOut(bz, err, method, tc.expPass, tc.errContains, tc.expAddress) + }) + } +} \ No newline at end of file diff --git a/precompiles/erc20factory/setup_test.go b/precompiles/erc20factory/setup_test.go new file mode 100644 index 0000000000..f241dd75d8 --- /dev/null +++ b/precompiles/erc20factory/setup_test.go @@ -0,0 +1,61 @@ +package erc20factory_test + +import ( + "github.com/cosmos/evm/precompiles/erc20factory" + "github.com/cosmos/evm/testutil/integration/os/factory" + "github.com/cosmos/evm/testutil/integration/os/grpc" + testkeyring "github.com/cosmos/evm/testutil/integration/os/keyring" + "github.com/cosmos/evm/testutil/integration/os/network" + "github.com/stretchr/testify/suite" +) + +// PrecompileTestSuite is the implementation of the TestSuite interface for ERC20 Factory precompile +// unit tests. +type PrecompileTestSuite struct { + suite.Suite + + create network.UnitTestNetwork + options []network.ConfigOption + bondDenom string + network *network.UnitTestNetwork + factory factory.TxFactory + grpcHandler grpc.Handler + keyring testkeyring.Keyring + + precompile *erc20factory.Precompile +} + +func NewPrecompileTestSuite(create network.UnitTestNetwork, options ...network.ConfigOption) *PrecompileTestSuite { + return &PrecompileTestSuite{ + create: create, + options: options, + } +} + +func (s *PrecompileTestSuite) SetupTest() { + keyring := testkeyring.New(2) + options := []network.ConfigOption{ + network.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), + } + options = append(options, s.options...) + integrationNetwork := network.NewUnitTestNetwork(options...) + grpcHandler := grpc.NewIntegrationHandler(integrationNetwork) + txFactory := factory.New(integrationNetwork, grpcHandler) + + ctx := integrationNetwork.GetContext() + sk := integrationNetwork.App.StakingKeeper + bondDenom, err := sk.BondDenom(ctx) + s.Require().NoError(err) + s.Require().NotEmpty(bondDenom, "bond denom cannot be empty") + + s.bondDenom = bondDenom + s.factory = txFactory + s.grpcHandler = grpcHandler + s.keyring = keyring + s.network = integrationNetwork + + // Instantiate the precompile with an exemplary token denomination. + // + // NOTE: This has to be done AFTER assigning the suite fields. + s.precompile = s.setupERC20FactoryPrecompile() +} diff --git a/precompiles/erc20factory/tx.go b/precompiles/erc20factory/tx.go new file mode 100644 index 0000000000..a2fc8a00b2 --- /dev/null +++ b/precompiles/erc20factory/tx.go @@ -0,0 +1,140 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package erc20factory + +import ( + "encoding/binary" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + + erc20types "github.com/cosmos/evm/x/erc20/types" + + "cosmossdk.io/errors" + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +const ( + // CreateMethod defines the ABI method name to create a new ERC20 Token Pair + CreateMethod = "create" +) + +// Create CreateERC20Precompile creates a new ERC20 TokenPair +func (p Precompile) Create( + ctx sdk.Context, + stateDB vm.StateDB, + method *abi.Method, + caller common.Address, + args []interface{}, +) ([]byte, error) { + tokenType, salt, name, symbol, decimals, minter, premintedSupply, err := ParseCreateArgs(args) + if err != nil { + return nil, err + } + + address := crypto.CreateAddress2(caller, salt, calculateCodeHash(tokenType)) + + metadata, err := p.createCoinMetadata(ctx, address, name, symbol, decimals) + if err != nil { + return nil, errors.Wrap( + err, "failed to create wrapped coin denom metadata for ERC20", + ) + } + + if err := metadata.Validate(); err != nil { + return nil, errors.Wrapf( + err, "ERC20 token data is invalid for contract %s", address.String(), + ) + } + + p.bankKeeper.SetDenomMetaData(ctx, *metadata) + + pair := erc20types.NewTokenPair(address, metadata.Name, erc20types.OWNER_EXTERNAL) + + p.erc20Keeper.SetToken(ctx, pair) + + err = p.erc20Keeper.EnableDynamicPrecompile(ctx, pair.GetERC20Contract()) + if err != nil { + return nil, err + } + + coins := sdk.NewCoins(sdk.NewCoin(metadata.Base, math.NewIntFromBigInt(premintedSupply))) + if err := p.bankKeeper.MintCoins(ctx, erc20types.ModuleName, coins); err != nil { + return nil, err + } + if err := p.bankKeeper.SendCoinsFromModuleToAccount(ctx, erc20types.ModuleName, sdk.AccAddress(minter.Bytes()), coins); err != nil { + return nil, err + } + + if err = p.EmitCreateEvent(ctx, stateDB, address, tokenType, salt, name, symbol, decimals, minter, premintedSupply); err != nil { + return nil, err + } + + return method.Outputs.Pack(address) +} + +func (p Precompile) createCoinMetadata(ctx sdk.Context, address common.Address, name string, symbol string, decimals uint8) (*banktypes.Metadata, error) { + addressString := address.String() + denom := erc20types.CreateDenom(addressString) + + _, found := p.bankKeeper.GetDenomMetaData(ctx, denom) + if found { + return nil, errors.Wrap( + erc20types.ErrInternalTokenPair, "denom metadata already registered", + ) + } + + if p.erc20Keeper.IsDenomRegistered(ctx, denom) { + return nil, errors.Wrapf( + erc20types.ErrInternalTokenPair, "coin denomination already registered: %s", name, + ) + } + + // base denomination + base := erc20types.CreateDenom(addressString) + + // create a bank denom metadata based on the ERC20 token ABI details + // metadata name is should always be the contract since it's the key + // to the bank store + metadata := banktypes.Metadata{ + Description: erc20types.CreateDenomDescription(addressString), + Base: base, + // NOTE: Denom units MUST be increasing + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: base, + Exponent: 0, + }, + }, + Name: base, + Symbol: symbol, + Display: base, + } + + // only append metadata if decimals > 0, otherwise validation fails + if decimals > 0 { + nameSanitized := erc20types.SanitizeERC20Name(name) + metadata.DenomUnits = append( + metadata.DenomUnits, + &banktypes.DenomUnit{ + Denom: nameSanitized, + Exponent: uint32(decimals), //#nosec G115 + }, + ) + metadata.Display = nameSanitized + } + + return &metadata, nil +} + +func calculateCodeHash(tokenType uint8) []byte { + tokenTypeBytes := make([]byte, 4) + binary.LittleEndian.PutUint32(tokenTypeBytes, uint32(tokenType)) + return tokenTypeBytes +} diff --git a/precompiles/erc20factory/tx_test.go b/precompiles/erc20factory/tx_test.go new file mode 100644 index 0000000000..21b46998b6 --- /dev/null +++ b/precompiles/erc20factory/tx_test.go @@ -0,0 +1,172 @@ +package erc20factory_test + +import ( + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + + "github.com/cosmos/evm/precompiles/erc20factory" + erc20types "github.com/cosmos/evm/x/erc20/types" +) + +func (s *PrecompileTestSuite) TestCreate() { + caller := common.HexToAddress("0x2c7882f69Cd115F470aAEde121f57F932936a56f") + mintAddr := common.HexToAddress("0x73657398D483143AF7db7899757e5E7037fB713d") + expectedAddress := common.HexToAddress("0x30E56567F73403eD713dA0b0419e4A5330A16896") + amount := big.NewInt(1000000) + decimals := uint8(18) + name := "Test" + symbol := "TEST" + + method := s.precompile.Methods[erc20factory.CreateMethod] + + testcases := []struct { + name string + args []interface{} + expPass bool + postExpPass func(output []byte) + errContains string + expAddress common.Address + }{ + { + name: "pass - correct arguments", + args: []interface{}{uint8(0), [32]uint8(common.HexToHash("0x4f5b6f778b28c4d67a9c12345678901234567890123456789012345678901234").Bytes()), name, symbol, decimals, mintAddr, amount}, + expPass: true, + postExpPass: func(output []byte) { + res, err := method.Outputs.Unpack(output) + s.Require().NoError(err, "expected no error unpacking output") + s.Require().Len(res, 1, "expected one output") + address, ok := res[0].(common.Address) + s.Require().True(ok, "expected address type") + + // Check the balance of the token for the mintAddr + balance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), sdk.AccAddress(mintAddr.Bytes()), erc20types.CreateDenom(address.String())) + s.Require().Equal(amount, balance.Amount.BigInt(), "expected balance to match preminted amount") + + s.Require().Equal(address.String(), expectedAddress, "expected address to match") + + }, + expAddress: expectedAddress, + }, + { + name: "fail - invalid tokenType", + args: []interface{}{ + "invalid tokenType", + [32]uint8{}, + name, + symbol, + decimals, + mintAddr, + amount, + }, + errContains: "invalid tokenType", + }, + { + name: "fail - invalid salt", + args: []interface{}{ + uint8(0), + "invalid salt", + name, + symbol, + decimals, + mintAddr, + amount, + }, + errContains: "invalid salt", + }, + { + name: "fail - invalid name", + args: []interface{}{ + uint8(0), + [32]uint8{}, + "", + symbol, + decimals, + mintAddr, + amount, + }, + errContains: "invalid name", + }, + { + name: "fail - invalid symbol", + args: []interface{}{ + uint8(0), + [32]uint8{}, + name, + "is", + decimals, + mintAddr, + amount, + }, + errContains: "invalid symbol", + }, + { + name: "fail - invalid decimals", + args: []interface{}{ + uint8(0), + [32]uint8{}, + name, + symbol, + "invalid decimals", + mintAddr, + amount, + }, + errContains: "invalid decimals", + }, + { + name: "fail - invalid minter", + args: []interface{}{ + uint8(0), + [32]uint8{}, + name, + symbol, + decimals, + "invalid address", + amount, + }, + errContains: "invalid minter", + }, + { + name: "fail - invalid preminted supply", + args: []interface{}{ + uint8(0), + [32]uint8{}, + name, + symbol, + decimals, + mintAddr, + "invalid amount", + }, + errContains: "invalid premintedSupply", + }, + { + name: "fail - invalid number of arguments", + args: []interface{}{ + 1, 2, 3, + }, + errContains: "invalid number of arguments", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + + precompile := s.setupERC20FactoryPrecompile() + + method := precompile.Methods[erc20factory.CreateMethod] + + bz, err := precompile.Create( + s.network.GetContext(), + s.network.GetStateDB(), + &method, + caller, + tc.args, + ) + + // NOTE: all output and error checking happens in here + s.requireOut(bz, err, method, tc.expPass, tc.errContains, tc.expAddress) + }) + } +} diff --git a/precompiles/erc20factory/types.go b/precompiles/erc20factory/types.go new file mode 100644 index 0000000000..fa186d342e --- /dev/null +++ b/precompiles/erc20factory/types.go @@ -0,0 +1,101 @@ +package erc20factory + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + + cmn "github.com/cosmos/evm/precompiles/common" +) + +// EventCreate defines the event data for the ERC20 Factory Create event. +type EventCreate struct { + TokenAddress common.Address + TokenPairType uint8 + Salt [32]uint8 + Name string + Symbol string + Decimals uint8 + Minter common.Address + PremintedSupply *big.Int +} + +// ParseCreateArgs parses the arguments from the create method and returns +// the token type, salt, name, symbol, decimals, minter, and preminted supply. +func ParseCreateArgs(args []interface{}) (tokenType uint8, salt [32]uint8, name string, symbol string, decimals uint8, minter common.Address, premintedSupply *big.Int, err error) { + if len(args) != 7 { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 7, len(args)) + } + + tokenType, ok := args[0].(uint8) + if !ok { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid tokenType") + } + + salt, ok = args[1].([32]uint8) + if !ok { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid salt") + } + + name, ok = args[2].(string) + if !ok || len(name) < 3 || len(name) > 128 { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid name") + } + + symbol, ok = args[3].(string) + if !ok || len(symbol) < 3 || len(symbol) > 16 { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid symbol") + } + + decimals, ok = args[4].(uint8) + if !ok { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid decimals") + } + + minter, ok = args[5].(common.Address) + if !ok { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid minter") + } + + // Validate that minter is not the zero address + if minter == (common.Address{}) { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid minter: cannot be zero address") + } + + premintedSupply, ok = args[6].(*big.Int) + if !ok { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid premintedSupply: expected *big.Int") + } + + if premintedSupply.Sign() < 0 { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid premintedSupply: cannot be negative") + } + + maxUint256 := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) + if premintedSupply.Cmp(maxUint256) > 0 { + return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("premintedSupply exceeds uint256 maximum") + } + + return tokenType, salt, name, symbol, decimals, minter, premintedSupply, nil +} + +// ParseCalculateAddressArgs parses the arguments from the calculateAddress method and returns +// the token type and salt. +func ParseCalculateAddressArgs(args []interface{}) (tokenType uint8, salt [32]uint8, err error) { + if len(args) != 2 { + return uint8(0), [32]uint8{}, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 2, len(args)) + } + + tokenType, ok := args[0].(uint8) + if !ok { + return uint8(0), [32]uint8{}, fmt.Errorf("invalid tokenType") + } + + salt, ok = args[1].([32]uint8) + if !ok { + return uint8(0), [32]uint8{}, fmt.Errorf("invalid salt") + } + + return tokenType, salt, nil +} \ No newline at end of file diff --git a/precompiles/erc20factory/types_test.go b/precompiles/erc20factory/types_test.go new file mode 100644 index 0000000000..9c0d458dfa --- /dev/null +++ b/precompiles/erc20factory/types_test.go @@ -0,0 +1,223 @@ +package erc20factory_test + +import ( + "math/big" + + "github.com/cosmos/evm/precompiles/erc20factory" + utiltx "github.com/cosmos/evm/testutil/tx" + "github.com/ethereum/go-ethereum/common" +) + +func (s *PrecompileTestSuite) TestParseCalculateAddressArgs() { + s.SetupTest() + + testcases := []struct { + name string + args []interface{} + expPass bool + errContains string + }{ + { + name: "pass - correct arguments", + args: []interface{}{ + uint8(0), + [32]uint8{}, + }, + expPass: true, + }, + { + name: "fail - invalid tokenType", + args: []interface{}{ + "invalid tokenType", + [32]uint8{}, + }, + errContains: "invalid tokenType", + }, + { + name: "fail - invalid salt", + args: []interface{}{ + uint8(0), + "invalid salt", + }, + }, + { + name: "fail - invalid number of arguments", + args: []interface{}{ + 1, 2, 3, + }, + errContains: "invalid number of arguments", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + tokenType, salt, err := erc20factory.ParseCalculateAddressArgs(tc.args) + if tc.expPass { + s.Require().NoError(err, "unexpected error parsing the calculate address arguments") + s.Require().Equal(tokenType, tc.args[0], "expected different token type") + s.Require().Equal(salt, tc.args[1], "expected different salt") + } else { + s.Require().Error(err, "expected an error parsing the calculate address arguments") + s.Require().ErrorContains(err, tc.errContains, "expected different error message") + } + }) + } +} + +func (s *PrecompileTestSuite) TestParseCreateArgs() { + addr := utiltx.GenerateAddress() + decimals := uint8(18) + amount := big.NewInt(1000000) + name := "Test" + symbol := "TEST" + + s.SetupTest() + + testcases := []struct { + name string + args []interface{} + expPass bool + errContains string + }{ + { + name: "pass - correct arguments", + args: []interface{}{ + uint8(0), + [32]uint8{}, + name, + symbol, + decimals, + addr, + amount, + }, + expPass: true, + }, + { + name: "fail - invalid tokenType", + args: []interface{}{ + "invalid tokenType", + [32]uint8{}, + name, + symbol, + decimals, + addr, + big.NewInt(1000000), + }, + }, + { + name: "fail - invalid salt", + args: []interface{}{ + uint8(0), + "invalid salt", + name, + symbol, + decimals, + addr, + big.NewInt(1000000), + }, + }, + { + name: "fail - invalid name", + args: []interface{}{ + uint8(0), + [32]uint8{}, + uint8(0), + symbol, + decimals, + addr, + big.NewInt(1000000), + }, + errContains: "invalid name", + }, + { + name: "fail - invalid symbol", + args: []interface{}{ + uint8(0), + [32]uint8{}, + name, + "is", + decimals, + addr, + big.NewInt(1000000), + }, + errContains: "invalid symbol", + }, + { + name: "fail - invalid decimals", + args: []interface{}{ + uint8(0), + [32]uint8{}, + name, + symbol, + "invalid decimals", + addr, + big.NewInt(1000000), + }, + errContains: "invalid decimals", + }, + { + name: "fail - invalid minter", + args: []interface{}{ + uint8(0), + [32]uint8{}, + name, + symbol, + decimals, + "invalid address", + big.NewInt(1000000), + }, + errContains: "invalid minter", + }, + { + name: "fail - zero address minter", + args: []interface{}{ + uint8(0), + [32]uint8{}, + name, + symbol, + decimals, + common.Address{}, // Zero address + big.NewInt(1000000), + }, + errContains: "invalid minter: cannot be zero address", + }, + { + name: "fail - invalid preminted supply", + args: []interface{}{ + uint8(0), + [32]uint8{}, + name, + symbol, + decimals, + addr, + big.NewInt(-1), + }, + errContains: "invalid premintedSupply: cannot be negative", + }, + { + name: "fail - invalid number of arguments", + args: []interface{}{ + 1, 2, 3, 4, 5, + }, + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + tokenType, salt, name, symbol, decimals, minter, premintedSupply, err := erc20factory.ParseCreateArgs(tc.args) + if tc.expPass { + s.Require().NoError(err, "unexpected error parsing the create arguments") + s.Require().Equal(tokenType, tc.args[0], "expected different token type") + s.Require().Equal(salt, tc.args[1], "expected different salt") + s.Require().Equal(name, tc.args[2], "expected different name") + s.Require().Equal(symbol, tc.args[3], "expected different symbol") + s.Require().Equal(decimals, tc.args[4], "expected different decimals") + s.Require().Equal(minter, tc.args[5], "expected different minter") + s.Require().Equal(premintedSupply, tc.args[6], "expected different preminted supply") + } else { + s.Require().Error(err, "expected an error parsing the create arguments") + s.Require().ErrorContains(err, tc.errContains, "expected different error message") + } + }) + } +} \ No newline at end of file diff --git a/precompiles/erc20factory/utils_test.go b/precompiles/erc20factory/utils_test.go new file mode 100644 index 0000000000..c38f68273f --- /dev/null +++ b/precompiles/erc20factory/utils_test.go @@ -0,0 +1,56 @@ +package erc20factory_test + +import ( + "math/big" + + "github.com/cosmos/evm/precompiles/erc20factory" + "github.com/ethereum/go-ethereum/accounts/abi" +) + +func (s *PrecompileTestSuite) setupERC20FactoryPrecompile() *erc20factory.Precompile { + precompile, err := erc20factory.NewPrecompile( + &s.network.App.Erc20Keeper, + s.network.App.BankKeeper) + s.Require().NoError(err, "failed to create erc20factory precompile") + + return precompile +} + +// requireOut is a helper utility to reduce the amount of boilerplate code in the query tests. +// +// It requires the output bytes and error to match the expected values. Additionally, the method outputs +// are unpacked and the first value is compared to the expected value. +// +// NOTE: It's sufficient to only check the first value because all methods in the ERC20 precompile only +// return a single value. +func (s *PrecompileTestSuite) requireOut( + bz []byte, + err error, + method abi.Method, + expPass bool, + errContains string, + expValue interface{}, +) { + if expPass { + s.Require().NoError(err, "expected no error") + s.Require().NotEmpty(bz, "expected bytes not to be empty") + + // Unpack the name into a string + out, err := method.Outputs.Unpack(bz) + s.Require().NoError(err, "expected no error unpacking") + + // Check if expValue is a big.Int. Because of a difference in uninitialized/empty values for big.Ints, + // this comparison is often not working as expected, so we convert to Int64 here and compare those values. + bigExp, ok := expValue.(*big.Int) + if ok { + bigOut, ok := out[0].(*big.Int) + s.Require().True(ok, "expected output to be a big.Int") + s.Require().Equal(bigExp.Int64(), bigOut.Int64(), "expected different value") + } else { + s.Require().Equal(expValue, out[0], "expected different value") + } + } else { + s.Require().Error(err, "expected error") + s.Require().Contains(err.Error(), errContains, "expected different error") + } +} \ No newline at end of file diff --git a/tests/solidity/init-node.sh b/tests/solidity/init-node.sh index 152f942768..09ba72aa92 100755 --- a/tests/solidity/init-node.sh +++ b/tests/solidity/init-node.sh @@ -76,7 +76,7 @@ jq '.app_state["evm"]["params"]["evm_denom"]="atest"' "$GENESIS" >"$TMP_GENESIS" jq '.app_state["mint"]["params"]["mint_denom"]="atest"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" # Enable precompiles in EVM params -jq '.app_state["evm"]["params"]["active_static_precompiles"]=["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804"]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +jq '.app_state["evm"]["params"]["active_static_precompiles"]=["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804", "0x0000000000000000000000000000000000000900"]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" # Change proposal periods to pass within a reasonable time for local testing sed -i.bak 's/"max_deposit_period": "172800s"/"max_deposit_period": "30s"/g' "$GENESIS" diff --git a/tests/solidity/suites/precompiles/test/erc20factory.js b/tests/solidity/suites/precompiles/test/erc20factory.js new file mode 100644 index 0000000000..079c18fb50 --- /dev/null +++ b/tests/solidity/suites/precompiles/test/erc20factory.js @@ -0,0 +1,62 @@ +const { expect } = require('chai') +const hre = require('hardhat') + +const abi = [ + "function create(uint8 tokenPairType, bytes32 salt, string memory name, string memory symbol, uint8 decimals, address minter, uint256 premintedSupply) external returns (address)", + "function calculateAddress(uint8 tokenPairType, bytes32 salt) external view returns (address)", + "event Create(address indexed tokenAddress, uint8 tokenPairType, bytes32 salt, string name, string symbol, uint8 decimals, address minter, uint256 premintedSupply)" +] + +describe('ERC20Factory', function () { + + it('should calculate the correct address', async function () { + const salt = '0x4f5b6f778b28c4d67a9c12345678901234567890123456789012345678901234' + const tokenPairType = 0 + const erc20Factory = await hre.ethers.getContractAt('IERC20Factory', '0x0000000000000000000000000000000000000900') + const expectedAddress = await erc20Factory.calculateAddress(tokenPairType, salt) + expect(expectedAddress).to.equal('0x6a040655fE545126cD341506fCD4571dB3A444F9') + }) + + it('should create a new ERC20 token', async function () { + const salt = '0x4f5b6f778b28c4d67a9c12345678901234567890123456789012345678901234' + const name = 'Test' + const symbol = 'TEST' + const decimals = 18 + const tokenPairType = 0 + const premintedSupply = hre.ethers.parseEther("1000000") // 1M tokens + + const [signer] = await hre.ethers.getSigners() + const minter = signer.address + + // Calculate the expected token address before deployment + const erc20Factory = await hre.ethers.getContractAt('IERC20Factory', '0x0000000000000000000000000000000000000900') + + const tokenAddress = await erc20Factory.calculateAddress(tokenPairType, salt) + const tx = await erc20Factory.connect(signer).create(tokenPairType, salt, name, symbol, decimals, minter, premintedSupply) + + // Get the token address from the transaction receipt + const receipt = await tx.wait() + expect(receipt.status).to.equal(1) // Check transaction was successful + + // Create a contract instance with the full ABI including events for event filtering + const erc20FactoryWithEvents = new hre.ethers.Contract('0x0000000000000000000000000000000000000900', abi, signer) + + // Get the Create event from the transaction receipt + const createEvents = await erc20FactoryWithEvents.queryFilter(erc20FactoryWithEvents.filters.Create(), receipt.blockNumber, receipt.blockNumber) + expect(createEvents.length).to.equal(1) + expect(createEvents[0].args.tokenAddress).to.equal(tokenAddress) + expect(createEvents[0].args.tokenPairType).to.equal(tokenPairType) + expect(createEvents[0].args.salt).to.equal(salt) + expect(createEvents[0].args.name).to.equal(name) + expect(createEvents[0].args.symbol).to.equal(symbol) + expect(createEvents[0].args.decimals).to.equal(decimals) + expect(createEvents[0].args.minter).to.equal(minter) + expect(createEvents[0].args.premintedSupply).to.equal(premintedSupply) + + // Get the token contract instance + const erc20Token = await hre.ethers.getContractAt('contracts/cosmos/erc20/IERC20.sol:IERC20', tokenAddress) + + // Verify token details through IERC20 queries + expect(await erc20Token.totalSupply()).to.equal(premintedSupply) + }) +}) \ No newline at end of file diff --git a/x/precisebank/keeper/keeper.go b/x/precisebank/keeper/keeper.go index 1185ea5188..7bbd1b840f 100644 --- a/x/precisebank/keeper/keeper.go +++ b/x/precisebank/keeper/keeper.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) // Enforce that Keeper implements the expected keeper interfaces @@ -48,3 +49,11 @@ func (k Keeper) IterateTotalSupply(ctx context.Context, cb func(coin sdk.Coin) b func (k Keeper) GetSupply(ctx context.Context, denom string) sdk.Coin { return k.bk.GetSupply(ctx, denom) } + +func (k Keeper) GetDenomMetaData(ctx context.Context, denom string) (banktypes.Metadata, bool) { + return k.bk.GetDenomMetaData(ctx, denom) +} + +func (k Keeper) SetDenomMetaData(ctx context.Context, denomMetaData banktypes.Metadata) { + k.bk.SetDenomMetaData(ctx, denomMetaData) +} \ No newline at end of file From 3c5808fab4a7423118cb4f8defdb1cd6cfd10dd3 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Tue, 5 Aug 2025 15:09:12 +0200 Subject: [PATCH 02/61] refactor(erc20factory): integration tests --- .../erc20factory/test_erc20factory.go | 2 +- .../precompiles/erc20factory/test_events.go | 2 +- .../precompiles/erc20factory/test_query.go | 2 +- .../precompiles/erc20factory/test_setup.go | 18 +++++++++--------- .../precompiles/erc20factory/test_tx.go | 4 ++-- .../precompiles/erc20factory/test_types.go | 2 +- .../precompiles/erc20factory/test_utils.go | 6 +++--- 7 files changed, 18 insertions(+), 18 deletions(-) rename precompiles/erc20factory/erc20factory_test.go => tests/integration/precompiles/erc20factory/test_erc20factory.go (98%) rename precompiles/erc20factory/events_test.go => tests/integration/precompiles/erc20factory/test_events.go (99%) rename precompiles/erc20factory/query_test.go => tests/integration/precompiles/erc20factory/test_query.go (98%) rename precompiles/erc20factory/setup_test.go => tests/integration/precompiles/erc20factory/test_setup.go (72%) rename precompiles/erc20factory/tx_test.go => tests/integration/precompiles/erc20factory/test_tx.go (95%) rename precompiles/erc20factory/types_test.go => tests/integration/precompiles/erc20factory/test_types.go (99%) rename precompiles/erc20factory/utils_test.go => tests/integration/precompiles/erc20factory/test_utils.go (95%) diff --git a/precompiles/erc20factory/erc20factory_test.go b/tests/integration/precompiles/erc20factory/test_erc20factory.go similarity index 98% rename from precompiles/erc20factory/erc20factory_test.go rename to tests/integration/precompiles/erc20factory/test_erc20factory.go index 6bb6c28650..00c02a078b 100644 --- a/precompiles/erc20factory/erc20factory_test.go +++ b/tests/integration/precompiles/erc20factory/test_erc20factory.go @@ -1,4 +1,4 @@ -package erc20factory_test +package erc20factory import ( "math/big" diff --git a/precompiles/erc20factory/events_test.go b/tests/integration/precompiles/erc20factory/test_events.go similarity index 99% rename from precompiles/erc20factory/events_test.go rename to tests/integration/precompiles/erc20factory/test_events.go index 1420562d72..2ecddec342 100644 --- a/precompiles/erc20factory/events_test.go +++ b/tests/integration/precompiles/erc20factory/test_events.go @@ -1,4 +1,4 @@ -package erc20factory_test +package erc20factory import ( "math/big" diff --git a/precompiles/erc20factory/query_test.go b/tests/integration/precompiles/erc20factory/test_query.go similarity index 98% rename from precompiles/erc20factory/query_test.go rename to tests/integration/precompiles/erc20factory/test_query.go index 155af3a0ca..0e376deebd 100644 --- a/precompiles/erc20factory/query_test.go +++ b/tests/integration/precompiles/erc20factory/test_query.go @@ -1,4 +1,4 @@ -package erc20factory_test +package erc20factory import ( "github.com/cosmos/evm/precompiles/erc20factory" diff --git a/precompiles/erc20factory/setup_test.go b/tests/integration/precompiles/erc20factory/test_setup.go similarity index 72% rename from precompiles/erc20factory/setup_test.go rename to tests/integration/precompiles/erc20factory/test_setup.go index f241dd75d8..b0d25ccb8e 100644 --- a/precompiles/erc20factory/setup_test.go +++ b/tests/integration/precompiles/erc20factory/test_setup.go @@ -1,11 +1,11 @@ -package erc20factory_test +package erc20factory import ( "github.com/cosmos/evm/precompiles/erc20factory" - "github.com/cosmos/evm/testutil/integration/os/factory" - "github.com/cosmos/evm/testutil/integration/os/grpc" - testkeyring "github.com/cosmos/evm/testutil/integration/os/keyring" - "github.com/cosmos/evm/testutil/integration/os/network" + "github.com/cosmos/evm/testutil/integration/evm/factory" + "github.com/cosmos/evm/testutil/integration/evm/grpc" + "github.com/cosmos/evm/testutil/integration/evm/network" + testkeyring "github.com/cosmos/evm/testutil/keyring" "github.com/stretchr/testify/suite" ) @@ -14,7 +14,7 @@ import ( type PrecompileTestSuite struct { suite.Suite - create network.UnitTestNetwork + create network.CreateEvmApp options []network.ConfigOption bondDenom string network *network.UnitTestNetwork @@ -25,7 +25,7 @@ type PrecompileTestSuite struct { precompile *erc20factory.Precompile } -func NewPrecompileTestSuite(create network.UnitTestNetwork, options ...network.ConfigOption) *PrecompileTestSuite { +func NewPrecompileTestSuite(create network.CreateEvmApp, options ...network.ConfigOption) *PrecompileTestSuite { return &PrecompileTestSuite{ create: create, options: options, @@ -38,12 +38,12 @@ func (s *PrecompileTestSuite) SetupTest() { network.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), } options = append(options, s.options...) - integrationNetwork := network.NewUnitTestNetwork(options...) + integrationNetwork := network.NewUnitTestNetwork(s.create, options...) grpcHandler := grpc.NewIntegrationHandler(integrationNetwork) txFactory := factory.New(integrationNetwork, grpcHandler) ctx := integrationNetwork.GetContext() - sk := integrationNetwork.App.StakingKeeper + sk := integrationNetwork.App.GetStakingKeeper() bondDenom, err := sk.BondDenom(ctx) s.Require().NoError(err) s.Require().NotEmpty(bondDenom, "bond denom cannot be empty") diff --git a/precompiles/erc20factory/tx_test.go b/tests/integration/precompiles/erc20factory/test_tx.go similarity index 95% rename from precompiles/erc20factory/tx_test.go rename to tests/integration/precompiles/erc20factory/test_tx.go index 21b46998b6..562d1f8080 100644 --- a/precompiles/erc20factory/tx_test.go +++ b/tests/integration/precompiles/erc20factory/test_tx.go @@ -1,4 +1,4 @@ -package erc20factory_test +package erc20factory import ( "math/big" @@ -41,7 +41,7 @@ func (s *PrecompileTestSuite) TestCreate() { s.Require().True(ok, "expected address type") // Check the balance of the token for the mintAddr - balance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), sdk.AccAddress(mintAddr.Bytes()), erc20types.CreateDenom(address.String())) + balance := s.network.App.GetBankKeeper().GetBalance(s.network.GetContext(), sdk.AccAddress(mintAddr.Bytes()), erc20types.CreateDenom(address.String())) s.Require().Equal(amount, balance.Amount.BigInt(), "expected balance to match preminted amount") s.Require().Equal(address.String(), expectedAddress, "expected address to match") diff --git a/precompiles/erc20factory/types_test.go b/tests/integration/precompiles/erc20factory/test_types.go similarity index 99% rename from precompiles/erc20factory/types_test.go rename to tests/integration/precompiles/erc20factory/test_types.go index 9c0d458dfa..470ef0f61b 100644 --- a/precompiles/erc20factory/types_test.go +++ b/tests/integration/precompiles/erc20factory/test_types.go @@ -1,4 +1,4 @@ -package erc20factory_test +package erc20factory import ( "math/big" diff --git a/precompiles/erc20factory/utils_test.go b/tests/integration/precompiles/erc20factory/test_utils.go similarity index 95% rename from precompiles/erc20factory/utils_test.go rename to tests/integration/precompiles/erc20factory/test_utils.go index c38f68273f..fc1381a671 100644 --- a/precompiles/erc20factory/utils_test.go +++ b/tests/integration/precompiles/erc20factory/test_utils.go @@ -1,4 +1,4 @@ -package erc20factory_test +package erc20factory import ( "math/big" @@ -9,8 +9,8 @@ import ( func (s *PrecompileTestSuite) setupERC20FactoryPrecompile() *erc20factory.Precompile { precompile, err := erc20factory.NewPrecompile( - &s.network.App.Erc20Keeper, - s.network.App.BankKeeper) + s.network.App.GetErc20Keeper(), + s.network.App.GetBankKeeper()) s.Require().NoError(err, "failed to create erc20factory precompile") return precompile From 08670ca76ca15acbaa685ab1eebb3fc3479c225f Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Tue, 5 Aug 2025 15:12:20 +0200 Subject: [PATCH 03/61] fix(precisebank): remove already declared methods --- x/precisebank/keeper/keeper.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/x/precisebank/keeper/keeper.go b/x/precisebank/keeper/keeper.go index 7bbd1b840f..1185ea5188 100644 --- a/x/precisebank/keeper/keeper.go +++ b/x/precisebank/keeper/keeper.go @@ -10,7 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) // Enforce that Keeper implements the expected keeper interfaces @@ -49,11 +48,3 @@ func (k Keeper) IterateTotalSupply(ctx context.Context, cb func(coin sdk.Coin) b func (k Keeper) GetSupply(ctx context.Context, denom string) sdk.Coin { return k.bk.GetSupply(ctx, denom) } - -func (k Keeper) GetDenomMetaData(ctx context.Context, denom string) (banktypes.Metadata, bool) { - return k.bk.GetDenomMetaData(ctx, denom) -} - -func (k Keeper) SetDenomMetaData(ctx context.Context, denomMetaData banktypes.Metadata) { - k.bk.SetDenomMetaData(ctx, denomMetaData) -} \ No newline at end of file From 0625e33b0ac0a3f07dfb4430f2bd1c3d744e9b3d Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Tue, 19 Aug 2025 09:56:17 +0200 Subject: [PATCH 04/61] fix: update branch with main changes --- .../tests/integration/mempool/mempool_test.go | 3 +- go.mod | 5 +++ go.sum | 10 +++++ local_node.sh | 2 +- precompiles/common/mocks/BankKeeper.go | 39 ++++++++++++++++++- precompiles/erc20factory/erc20factory.go | 2 +- precompiles/erc20factory/events.go | 2 +- precompiles/erc20factory/interfaces.go | 2 +- precompiles/erc20factory/query.go | 2 +- precompiles/erc20factory/tx.go | 5 ++- precompiles/erc20factory/types.go | 2 +- .../erc20factory/test_erc20factory.go | 11 ++++-- .../precompiles/erc20factory/test_events.go | 2 +- .../precompiles/erc20factory/test_query.go | 5 ++- .../precompiles/erc20factory/test_setup.go | 3 +- .../precompiles/erc20factory/test_tx.go | 4 +- .../precompiles/erc20factory/test_types.go | 5 ++- .../precompiles/erc20factory/test_utils.go | 5 ++- tests/jsonrpc/simulator/namespaces/eth.go | 5 --- tests/jsonrpc/simulator/report/report.go | 1 - tests/jsonrpc/simulator/types/context.go | 2 - tests/jsonrpc/simulator/utils/test_helpers.go | 1 - .../suites/precompiles/test/erc20factory.js | 4 +- 23 files changed, 90 insertions(+), 32 deletions(-) diff --git a/evmd/tests/integration/mempool/mempool_test.go b/evmd/tests/integration/mempool/mempool_test.go index 3714c9afc3..8c3830dba8 100644 --- a/evmd/tests/integration/mempool/mempool_test.go +++ b/evmd/tests/integration/mempool/mempool_test.go @@ -1,9 +1,10 @@ package mempool import ( - "github.com/cosmos/evm/evmd/tests/integration" "testing" + "github.com/cosmos/evm/evmd/tests/integration" + "github.com/stretchr/testify/suite" "github.com/cosmos/evm/tests/integration/mempool" diff --git a/go.mod b/go.mod index 7bbd55c08b..11e2b68764 100644 --- a/go.mod +++ b/go.mod @@ -92,6 +92,7 @@ require ( github.com/bytedance/sonic/loader v0.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/chigopher/pathlib v0.19.1 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.5 // indirect github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect @@ -171,11 +172,13 @@ require ( github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/huandu/skiplist v1.2.1 // indirect + github.com/huandu/xstrings v1.4.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/jinzhu/copier v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/klauspost/compress v1.18.0 // indirect @@ -234,6 +237,7 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ulikunitz/xz v0.5.11 // indirect + github.com/vektra/mockery/v2 v2.53.4 // indirect github.com/zeebo/errs v1.4.0 // indirect github.com/zondax/ledger-go v0.14.3 // indirect go.etcd.io/bbolt v1.4.0-alpha.1 // indirect @@ -252,6 +256,7 @@ require ( go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/arch v0.17.0 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect + golang.org/x/mod v0.26.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sys v0.35.0 // indirect golang.org/x/term v0.34.0 // indirect diff --git a/go.sum b/go.sum index 6321d356dd..3813b5ae88 100644 --- a/go.sum +++ b/go.sum @@ -783,6 +783,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chigopher/pathlib v0.19.1 h1:RoLlUJc0CqBGwq239cilyhxPNLXTK+HXoASGyGznx5A= +github.com/chigopher/pathlib v0.19.1/go.mod h1:tzC1dZLW8o33UQpWkNkhvPwL5n4yyFRFm/jL1YGWFvY= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= @@ -1281,6 +1283,8 @@ github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3 github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= github.com/huandu/skiplist v1.2.1 h1:dTi93MgjwErA/8idWTzIw4Y1kZsMWx35fmI2c8Rij7w= github.com/huandu/skiplist v1.2.1/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= @@ -1309,6 +1313,8 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= +github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= +github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -1708,6 +1714,8 @@ github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/vektra/mockery/v2 v2.53.4 h1:abBWJLUQppM7T/VsLasBwgl7XXQRWH6lC3bnbJpOCLk= +github.com/vektra/mockery/v2 v2.53.4/go.mod h1:hIFFb3CvzPdDJJiU7J4zLRblUMv7OuezWsHPmswriwo= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= @@ -1879,6 +1887,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/local_node.sh b/local_node.sh index 6d3d0ba7c3..6547fbf751 100755 --- a/local_node.sh +++ b/local_node.sh @@ -240,7 +240,7 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then jq '.app_state["bank"]["denom_metadata"]=[{"description":"The native staking token for evmd.","denom_units":[{"denom":"atest","exponent":0,"aliases":["attotest"]},{"denom":"test","exponent":18,"aliases":[]}],"base":"atest","display":"test","name":"Test Token","symbol":"TEST","uri":"","uri_hash":""}]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - jq '.app_state["evm"]["params"]["active_static_precompiles"]=["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804","0x0000000000000000000000000000000000000805", "0x0000000000000000000000000000000000000806", "0x0000000000000000000000000000000000000807"]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + jq '.app_state["evm"]["params"]["active_static_precompiles"]=["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804","0x0000000000000000000000000000000000000805", "0x0000000000000000000000000000000000000806", "0x0000000000000000000000000000000000000807", "0x0000000000000000000000000000000000000900"]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state["evm"]["params"]["evm_denom"]="atest"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" diff --git a/precompiles/common/mocks/BankKeeper.go b/precompiles/common/mocks/BankKeeper.go index a3c72593ca..2ad57e0997 100644 --- a/precompiles/common/mocks/BankKeeper.go +++ b/precompiles/common/mocks/BankKeeper.go @@ -150,12 +150,49 @@ func (_m *BankKeeper) SpendableCoin(ctx context.Context, addr types.AccAddress, return r0 } +// MintCoins provides a mock function with given fields: ctx, moduleName, amt +func (_m *BankKeeper) MintCoins(ctx context.Context, moduleName string, amt types.Coins) error { + ret := _m.Called(ctx, moduleName, amt) + + if len(ret) == 0 { + panic("no return value specified for MintCoins") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, types.Coins) error); ok { + r0 = rf(ctx, moduleName, amt) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SendCoinsFromModuleToAccount provides a mock function with given fields: ctx, senderModule, recipientAddr, amt +func (_m *BankKeeper) SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr types.AccAddress, amt types.Coins) error { + ret := _m.Called(ctx, senderModule, recipientAddr, amt) + + if len(ret) == 0 { + panic("no return value specified for SendCoinsFromModuleToAccount") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, types.AccAddress, types.Coins) error); ok { + r0 = rf(ctx, senderModule, recipientAddr, amt) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // NewBankKeeper creates a new instance of BankKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewBankKeeper(t interface { mock.TestingT Cleanup(func()) -}) *BankKeeper { +}, +) *BankKeeper { mock := &BankKeeper{} mock.Mock.Test(t) diff --git a/precompiles/erc20factory/erc20factory.go b/precompiles/erc20factory/erc20factory.go index 0205e7a543..d7e38eff16 100644 --- a/precompiles/erc20factory/erc20factory.go +++ b/precompiles/erc20factory/erc20factory.go @@ -152,4 +152,4 @@ func (p *Precompile) HandleMethod( return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) } return bz, err -} \ No newline at end of file +} diff --git a/precompiles/erc20factory/events.go b/precompiles/erc20factory/events.go index 912189512c..e9dd15d352 100644 --- a/precompiles/erc20factory/events.go +++ b/precompiles/erc20factory/events.go @@ -54,4 +54,4 @@ func (p Precompile) EmitCreateEvent(ctx sdk.Context, stateDB vm.StateDB, tokenAd }) return nil -} \ No newline at end of file +} diff --git a/precompiles/erc20factory/interfaces.go b/precompiles/erc20factory/interfaces.go index 920af5b419..abe08bced9 100644 --- a/precompiles/erc20factory/interfaces.go +++ b/precompiles/erc20factory/interfaces.go @@ -22,4 +22,4 @@ type BankKeeper interface { SetDenomMetaData(ctx context.Context, denomMetaData banktypes.Metadata) MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error -} \ No newline at end of file +} diff --git a/precompiles/erc20factory/query.go b/precompiles/erc20factory/query.go index 15dbcbf822..5128ee205b 100644 --- a/precompiles/erc20factory/query.go +++ b/precompiles/erc20factory/query.go @@ -26,4 +26,4 @@ func (p Precompile) CalculateAddress( address := crypto.CreateAddress2(caller, salt, calculateCodeHash(tokenType)) return method.Outputs.Pack(address) -} \ No newline at end of file +} diff --git a/precompiles/erc20factory/tx.go b/precompiles/erc20factory/tx.go index a2fc8a00b2..2ee0a2315c 100644 --- a/precompiles/erc20factory/tx.go +++ b/precompiles/erc20factory/tx.go @@ -57,7 +57,10 @@ func (p Precompile) Create( pair := erc20types.NewTokenPair(address, metadata.Name, erc20types.OWNER_EXTERNAL) - p.erc20Keeper.SetToken(ctx, pair) + err = p.erc20Keeper.SetToken(ctx, pair) + if err != nil { + return nil, err + } err = p.erc20Keeper.EnableDynamicPrecompile(ctx, pair.GetERC20Contract()) if err != nil { diff --git a/precompiles/erc20factory/types.go b/precompiles/erc20factory/types.go index fa186d342e..9059a2989c 100644 --- a/precompiles/erc20factory/types.go +++ b/precompiles/erc20factory/types.go @@ -98,4 +98,4 @@ func ParseCalculateAddressArgs(args []interface{}) (tokenType uint8, salt [32]ui } return tokenType, salt, nil -} \ No newline at end of file +} diff --git a/tests/integration/precompiles/erc20factory/test_erc20factory.go b/tests/integration/precompiles/erc20factory/test_erc20factory.go index 00c02a078b..4f4afdd0a6 100644 --- a/tests/integration/precompiles/erc20factory/test_erc20factory.go +++ b/tests/integration/precompiles/erc20factory/test_erc20factory.go @@ -7,6 +7,11 @@ import ( utiltx "github.com/cosmos/evm/testutil/tx" ) +const ( + tokenName = "Test" + tokenSymbol = "TEST" +) + func (s *PrecompileTestSuite) TestIsTransaction() { s.SetupTest() @@ -25,8 +30,8 @@ func (s *PrecompileTestSuite) TestRequiredGas() { mintAddr := utiltx.GenerateAddress() decimals := uint8(18) amount := big.NewInt(1000000) - name := "Test" - symbol := "TEST" + name := tokenName + symbol := tokenSymbol testcases := []struct { name string @@ -59,4 +64,4 @@ func (s *PrecompileTestSuite) TestRequiredGas() { s.Require().Equal(tc.expGas, gas) }) } -} \ No newline at end of file +} diff --git a/tests/integration/precompiles/erc20factory/test_events.go b/tests/integration/precompiles/erc20factory/test_events.go index 2ecddec342..0f012724e8 100644 --- a/tests/integration/precompiles/erc20factory/test_events.go +++ b/tests/integration/precompiles/erc20factory/test_events.go @@ -67,4 +67,4 @@ func (s *PrecompileTestSuite) TestEmitCreateEvent() { s.Require().Equal(tc.premintedSupply, createEvent.PremintedSupply, "expected different preminted supply") }) } -} \ No newline at end of file +} diff --git a/tests/integration/precompiles/erc20factory/test_query.go b/tests/integration/precompiles/erc20factory/test_query.go index 0e376deebd..f4fcef4c55 100644 --- a/tests/integration/precompiles/erc20factory/test_query.go +++ b/tests/integration/precompiles/erc20factory/test_query.go @@ -1,8 +1,9 @@ package erc20factory import ( - "github.com/cosmos/evm/precompiles/erc20factory" "github.com/ethereum/go-ethereum/common" + + "github.com/cosmos/evm/precompiles/erc20factory" ) func (s *PrecompileTestSuite) TestCalculateAddress() { @@ -72,4 +73,4 @@ func (s *PrecompileTestSuite) TestCalculateAddress() { s.requireOut(bz, err, method, tc.expPass, tc.errContains, tc.expAddress) }) } -} \ No newline at end of file +} diff --git a/tests/integration/precompiles/erc20factory/test_setup.go b/tests/integration/precompiles/erc20factory/test_setup.go index b0d25ccb8e..e8f07c504a 100644 --- a/tests/integration/precompiles/erc20factory/test_setup.go +++ b/tests/integration/precompiles/erc20factory/test_setup.go @@ -1,12 +1,13 @@ package erc20factory import ( + "github.com/stretchr/testify/suite" + "github.com/cosmos/evm/precompiles/erc20factory" "github.com/cosmos/evm/testutil/integration/evm/factory" "github.com/cosmos/evm/testutil/integration/evm/grpc" "github.com/cosmos/evm/testutil/integration/evm/network" testkeyring "github.com/cosmos/evm/testutil/keyring" - "github.com/stretchr/testify/suite" ) // PrecompileTestSuite is the implementation of the TestSuite interface for ERC20 Factory precompile diff --git a/tests/integration/precompiles/erc20factory/test_tx.go b/tests/integration/precompiles/erc20factory/test_tx.go index 562d1f8080..a741694702 100644 --- a/tests/integration/precompiles/erc20factory/test_tx.go +++ b/tests/integration/precompiles/erc20factory/test_tx.go @@ -3,11 +3,12 @@ package erc20factory import ( "math/big" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/cosmos/evm/precompiles/erc20factory" erc20types "github.com/cosmos/evm/x/erc20/types" + + sdk "github.com/cosmos/cosmos-sdk/types" ) func (s *PrecompileTestSuite) TestCreate() { @@ -45,7 +46,6 @@ func (s *PrecompileTestSuite) TestCreate() { s.Require().Equal(amount, balance.Amount.BigInt(), "expected balance to match preminted amount") s.Require().Equal(address.String(), expectedAddress, "expected address to match") - }, expAddress: expectedAddress, }, diff --git a/tests/integration/precompiles/erc20factory/test_types.go b/tests/integration/precompiles/erc20factory/test_types.go index 470ef0f61b..1a3233e93d 100644 --- a/tests/integration/precompiles/erc20factory/test_types.go +++ b/tests/integration/precompiles/erc20factory/test_types.go @@ -3,9 +3,10 @@ package erc20factory import ( "math/big" + "github.com/ethereum/go-ethereum/common" + "github.com/cosmos/evm/precompiles/erc20factory" utiltx "github.com/cosmos/evm/testutil/tx" - "github.com/ethereum/go-ethereum/common" ) func (s *PrecompileTestSuite) TestParseCalculateAddressArgs() { @@ -220,4 +221,4 @@ func (s *PrecompileTestSuite) TestParseCreateArgs() { } }) } -} \ No newline at end of file +} diff --git a/tests/integration/precompiles/erc20factory/test_utils.go b/tests/integration/precompiles/erc20factory/test_utils.go index fc1381a671..45b9985536 100644 --- a/tests/integration/precompiles/erc20factory/test_utils.go +++ b/tests/integration/precompiles/erc20factory/test_utils.go @@ -3,8 +3,9 @@ package erc20factory import ( "math/big" - "github.com/cosmos/evm/precompiles/erc20factory" "github.com/ethereum/go-ethereum/accounts/abi" + + "github.com/cosmos/evm/precompiles/erc20factory" ) func (s *PrecompileTestSuite) setupERC20FactoryPrecompile() *erc20factory.Precompile { @@ -53,4 +54,4 @@ func (s *PrecompileTestSuite) requireOut( s.Require().Error(err, "expected error") s.Require().Contains(err.Error(), errContains, "expected different error") } -} \ No newline at end of file +} diff --git a/tests/jsonrpc/simulator/namespaces/eth.go b/tests/jsonrpc/simulator/namespaces/eth.go index f1922bc4ce..d1e469b7c9 100644 --- a/tests/jsonrpc/simulator/namespaces/eth.go +++ b/tests/jsonrpc/simulator/namespaces/eth.go @@ -1671,7 +1671,6 @@ func EthEstimateGas(rCtx *types.RPCContext) (*types.RpcResult, error) { func EthFeeHistory(rCtx *types.RPCContext) (*types.RpcResult, error) { var result interface{} err := rCtx.Evmd.RPCClient().Call(&result, string(MethodNameEthFeeHistory), "0x2", "latest", []float64{25.0, 50.0, 75.0}) - if err != nil { if err.Error() == "the method "+string(MethodNameEthFeeHistory)+" does not exist/is not available" || err.Error() == types.ErrorMethodNotFound { @@ -1926,7 +1925,6 @@ func EthGetHeaderByHash(rCtx *types.RPCContext) (*types.RpcResult, error) { var header any err = rCtx.Evmd.RPCClient().Call(&header, string(MethodNameEthGetHeaderByHash), receipt.BlockHash.Hex()) - if err != nil { if strings.Contains(err.Error(), "does not exist/is not available") || strings.Contains(err.Error(), "Method not found") { @@ -2004,7 +2002,6 @@ func EthGetHeaderByNumber(rCtx *types.RPCContext) (*types.RpcResult, error) { var header any err = rCtx.Evmd.RPCClient().Call(&header, string(MethodNameEthGetHeaderByNumber), blockNumberHex) - if err != nil { if strings.Contains(err.Error(), "does not exist/is not available") || strings.Contains(err.Error(), "Method not found") { @@ -2091,7 +2088,6 @@ func EthSimulateV1(rCtx *types.RPCContext) (*types.RpcResult, error) { var result any err := rCtx.Evmd.RPCClient().Call(&result, string(MethodNameEthSimulateV1), simulationReq) - if err != nil { if strings.Contains(err.Error(), "does not exist/is not available") || strings.Contains(err.Error(), "Method not found") || @@ -2158,7 +2154,6 @@ func EthPendingTransactions(rCtx *types.RPCContext) (*types.RpcResult, error) { var pendingTxs any err := rCtx.Evmd.RPCClient().Call(&pendingTxs, string(MethodNameEthPendingTransactions)) - if err != nil { if strings.Contains(err.Error(), "does not exist/is not available") || strings.Contains(err.Error(), "Method not found") || diff --git a/tests/jsonrpc/simulator/report/report.go b/tests/jsonrpc/simulator/report/report.go index d1f668bc7d..20b664b2ea 100644 --- a/tests/jsonrpc/simulator/report/report.go +++ b/tests/jsonrpc/simulator/report/report.go @@ -359,7 +359,6 @@ func PrintCategoryMatrix(summary *types.TestSummary) { catSummary.Total) } } - } func PrintSummary(summary *types.TestSummary) { diff --git a/tests/jsonrpc/simulator/types/context.go b/tests/jsonrpc/simulator/types/context.go index 79d0c2203c..3a65245a22 100644 --- a/tests/jsonrpc/simulator/types/context.go +++ b/tests/jsonrpc/simulator/types/context.go @@ -77,7 +77,6 @@ type RPCContext struct { // Dual API testing fields EnableComparison bool // Enable dual API comparison ComparisonResults []*ComparisonResult // Store comparison results - } func NewRPCContext(conf *config.Config) (*RPCContext, error) { @@ -134,7 +133,6 @@ func (rCtx *RPCContext) AlreadyTested(rpc RpcName) *RpcResult { } } return nil - } // CompareRPCCall performs a dual API call and compares response structures diff --git a/tests/jsonrpc/simulator/utils/test_helpers.go b/tests/jsonrpc/simulator/utils/test_helpers.go index d584b116dc..ea0bda5def 100644 --- a/tests/jsonrpc/simulator/utils/test_helpers.go +++ b/tests/jsonrpc/simulator/utils/test_helpers.go @@ -390,7 +390,6 @@ func Legacy(rCtx *types.RPCContext, methodName types.RpcName, category string, r // First test if the API is actually implemented var result interface{} err := rCtx.Evmd.RPCClient().Call(&result, string(methodName)) - if err != nil { // Check if it's a "method not found" error (API not implemented) if err.Error() == "the method "+string(methodName)+" does not exist/is not available" || diff --git a/tests/solidity/suites/precompiles/test/erc20factory.js b/tests/solidity/suites/precompiles/test/erc20factory.js index 079c18fb50..616f7cd9d1 100644 --- a/tests/solidity/suites/precompiles/test/erc20factory.js +++ b/tests/solidity/suites/precompiles/test/erc20factory.js @@ -13,7 +13,9 @@ describe('ERC20Factory', function () { const salt = '0x4f5b6f778b28c4d67a9c12345678901234567890123456789012345678901234' const tokenPairType = 0 const erc20Factory = await hre.ethers.getContractAt('IERC20Factory', '0x0000000000000000000000000000000000000900') + console.log("erc20Factory contract loaded") const expectedAddress = await erc20Factory.calculateAddress(tokenPairType, salt) + console.log("erc20factory calculateAddress") expect(expectedAddress).to.equal('0x6a040655fE545126cD341506fCD4571dB3A444F9') }) @@ -24,7 +26,7 @@ describe('ERC20Factory', function () { const decimals = 18 const tokenPairType = 0 const premintedSupply = hre.ethers.parseEther("1000000") // 1M tokens - + 0x0000000000000000000000000000000000000900 const [signer] = await hre.ethers.getSigners() const minter = signer.address From 417987bfeccb1322821b3ab8287bdb0a45dde8d6 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Tue, 19 Aug 2025 11:44:45 +0200 Subject: [PATCH 05/61] fix(precompiles/erc20factory): add BalanceHandler to erc20factory precompile --- precompiles/erc20factory/IERC20Factory.sol | 8 +- precompiles/erc20factory/abi.json | 78 +++++++++---------- precompiles/erc20factory/erc20factory.go | 8 +- .../suites/precompiles/test/erc20factory.js | 1 - 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/precompiles/erc20factory/IERC20Factory.sol b/precompiles/erc20factory/IERC20Factory.sol index 1a2be905a4..20af2bc5d6 100644 --- a/precompiles/erc20factory/IERC20Factory.sol +++ b/precompiles/erc20factory/IERC20Factory.sol @@ -27,7 +27,9 @@ interface IERC20Factory { bytes32 salt, string name, string symbol, - uint8 decimals + uint8 decimals, + address minter, + uint256 premintedSupply ); /** @@ -44,7 +46,9 @@ interface IERC20Factory { bytes32 salt, string memory name, string memory symbol, - uint8 decimals + uint8 decimals, + address minter, + uint256 premintedSupply ) external returns (address tokenAddress); /** diff --git a/precompiles/erc20factory/abi.json b/precompiles/erc20factory/abi.json index d3db7dc537..998c8881a3 100644 --- a/precompiles/erc20factory/abi.json +++ b/precompiles/erc20factory/abi.json @@ -4,68 +4,74 @@ "sourceName": "solidity/precompiles/erc20factory/IERC20Factory.sol", "abi": [ { + "anonymous": false, "inputs": [ { - "internalType": "uint8", - "name": "tokenPairType", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - } - ], - "name": "calculateAddress", - "outputs": [ - { + "indexed": true, "internalType": "address", "name": "tokenAddress", "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ + }, { + "indexed": false, "internalType": "uint8", "name": "tokenPairType", "type": "uint8" }, { + "indexed": false, "internalType": "bytes32", "name": "salt", "type": "bytes32" }, { + "indexed": false, "internalType": "string", "name": "name", "type": "string" }, { + "indexed": false, "internalType": "string", "name": "symbol", "type": "string" }, { + "indexed": false, "internalType": "uint8", "name": "decimals", "type": "uint8" }, { + "indexed": false, "internalType": "address", "name": "minter", "type": "address" }, { + "indexed": false, "internalType": "uint256", "name": "premintedSupply", "type": "uint256" } ], - "name": "create", + "name": "Create", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "tokenPairType", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "calculateAddress", "outputs": [ { "internalType": "address", @@ -73,67 +79,61 @@ "type": "address" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "tokenAddress", - "type": "address" - }, - { - "indexed": false, "internalType": "uint8", "name": "tokenPairType", "type": "uint8" }, { - "indexed": false, "internalType": "bytes32", "name": "salt", "type": "bytes32" }, { - "indexed": false, "internalType": "string", "name": "name", "type": "string" }, { - "indexed": false, "internalType": "string", "name": "symbol", "type": "string" }, { - "indexed": false, "internalType": "uint8", "name": "decimals", "type": "uint8" }, { - "indexed": false, "internalType": "address", "name": "minter", "type": "address" }, { - "indexed": false, "internalType": "uint256", "name": "premintedSupply", "type": "uint256" } ], - "name": "Create", - "type": "event" + "name": "create", + "outputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" } ], "bytecode": "0x", "deployedBytecode": "0x", "linkReferences": {}, "deployedLinkReferences": {} -} \ No newline at end of file +} diff --git a/precompiles/erc20factory/erc20factory.go b/precompiles/erc20factory/erc20factory.go index d7e38eff16..4225adeb47 100644 --- a/precompiles/erc20factory/erc20factory.go +++ b/precompiles/erc20factory/erc20factory.go @@ -40,7 +40,7 @@ type Precompile struct { // NewPrecompile creates a new bech32 Precompile instance as a // PrecompiledContract interface. -func NewPrecompile(erc20Keeper ERC20Keeper, bankKeeper BankKeeper) (*Precompile, error) { +func NewPrecompile(erc20Keeper ERC20Keeper, bankKeeper cmn.BankKeeper) (*Precompile, error) { newABI, err := cmn.LoadABI(f, "abi.json") if err != nil { return nil, err @@ -58,6 +58,8 @@ func NewPrecompile(erc20Keeper ERC20Keeper, bankKeeper BankKeeper) (*Precompile, // SetAddress defines the address of the distribution compile contract. p.SetAddress(common.HexToAddress(Erc20FactoryAddress)) + + p.SetBalanceHandler(bankKeeper) return p, nil } @@ -96,6 +98,10 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ if err != nil { return nil, err } + + // Start the balance change handler before executing the precompile + p.GetBalanceHandler().BeforeBalanceChange(ctx) + // 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)() diff --git a/tests/solidity/suites/precompiles/test/erc20factory.js b/tests/solidity/suites/precompiles/test/erc20factory.js index 616f7cd9d1..3ef085b162 100644 --- a/tests/solidity/suites/precompiles/test/erc20factory.js +++ b/tests/solidity/suites/precompiles/test/erc20factory.js @@ -26,7 +26,6 @@ describe('ERC20Factory', function () { const decimals = 18 const tokenPairType = 0 const premintedSupply = hre.ethers.parseEther("1000000") // 1M tokens - 0x0000000000000000000000000000000000000900 const [signer] = await hre.ethers.getSigners() const minter = signer.address From 144922a5360f473fe4c255f386ede011ec9540d6 Mon Sep 17 00:00:00 2001 From: Cordt Hanson <96965330+Cordtus@users.noreply.github.com> Date: Tue, 19 Aug 2025 08:28:41 -0600 Subject: [PATCH 06/61] revert auto-fix for markdown linting (#483) --- .github/workflows/lint.yml | 43 +++++++------------------------------- 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7bb3c3e392..f533364771 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -52,23 +52,14 @@ jobs: make lint-go markdown-lint: - name: markdownlint (cli2, minimal, non-blocking) + name: markdownlint (cli2, minimal) runs-on: ubuntu-latest timeout-minutes: 10 permissions: - contents: write # allows auto-fix pushes on same-repo PRs; forks stay read-only + contents: read # read-only permissions steps: - # Same-repo PRs: checkout the head branch so fixes can be pushed back - - name: Checkout PR head (same-repo) - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - ref: ${{ github.event.pull_request.head.ref }} - - # Fork PRs, merge queue, and any other case: default checkout (safe merge ref) - - name: Checkout (default) - if: github.event_name == 'merge_group' || github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository + # Standard checkout for all cases + - name: Checkout uses: actions/checkout@v4 # Only run if markdown or configs changed @@ -85,32 +76,12 @@ jobs: with: node-version: "20" - # Lint (non-blocking): auto-fix on same-repo PRs, never fail the job - - name: markdownlint (check or fix) + # Lint: check only, fail on errors + - name: markdownlint (check only) id: md_lint if: env.GIT_DIFF - continue-on-error: true uses: DavidAnson/markdownlint-cli2-action@v16 with: globs: "**/*.md" config: .markdownlint.yml - fix: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository }} - - # If fixes applied, commit & push (same-repo PRs only, not merge queue) - - name: Push auto-fixes (same-repo PRs only) - if: env.GIT_DIFF && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository - run: | - if [[ -n $(git status -s) ]]; then - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot]" - git add -A - git commit -m "Auto-fix markdown lint issues" - git push - fi - - # Warn if any issues remain after auto-fix (or on forks) - - name: Report remaining markdown issues (non-blocking) - if: env.GIT_DIFF && steps.md_lint.outcome == 'failure' - run: | - echo "::warning::Markdown lint issues remain after the check/fix step. For local fixes, run:" - echo " npx markdownlint-cli2 --config .markdownlint.yml --fix '**/*.md'" + fix: false From 47b43b477f6ae9fe6f34b51838a14b0ef640dd99 Mon Sep 17 00:00:00 2001 From: Abdul Malek Date: Tue, 19 Aug 2025 13:18:44 -0400 Subject: [PATCH 07/61] add comments (#489) --- api/cosmos/evm/erc20/v1/erc20.pulsar.go | 4 ++-- api/cosmos/evm/erc20/v1/genesis.pulsar.go | 2 +- api/cosmos/evm/erc20/v1/query_grpc.pb.go | 8 ++++---- proto/cosmos/evm/erc20/v1/erc20.proto | 4 ++-- proto/cosmos/evm/erc20/v1/genesis.proto | 2 +- proto/cosmos/evm/erc20/v1/query.proto | 4 ++-- x/erc20/types/erc20.pb.go | 4 ++-- x/erc20/types/genesis.pb.go | 2 +- x/erc20/types/query.pb.go | 8 ++++---- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/api/cosmos/evm/erc20/v1/erc20.pulsar.go b/api/cosmos/evm/erc20/v1/erc20.pulsar.go index d582bb6c15..3881171507 100644 --- a/api/cosmos/evm/erc20/v1/erc20.pulsar.go +++ b/api/cosmos/evm/erc20/v1/erc20.pulsar.go @@ -3550,8 +3550,8 @@ func (Owner) EnumDescriptor() ([]byte, []int) { return file_cosmos_evm_erc20_v1_erc20_proto_rawDescGZIP(), []int{0} } -// TokenPair defines an instance that records a pairing consisting of a native -// Cosmos Coin and an ERC20 token address. +// TokenPair defines an instance that records a pairing (mapping) consisting of a native +// Cosmos Coin and an ERC20 token address. The "pair" does not imply an asset swap exchange. type TokenPair struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/api/cosmos/evm/erc20/v1/genesis.pulsar.go b/api/cosmos/evm/erc20/v1/genesis.pulsar.go index 2a8af313b1..f10f894c9c 100644 --- a/api/cosmos/evm/erc20/v1/genesis.pulsar.go +++ b/api/cosmos/evm/erc20/v1/genesis.pulsar.go @@ -1458,7 +1458,7 @@ type GenesisState struct { // params are the erc20 module parameters at genesis Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` - // token_pairs is a slice of the registered token pairs at genesis + // token_pairs is a slice of the registered token pairs (mappings) at genesis TokenPairs []*TokenPair `protobuf:"bytes,2,rep,name=token_pairs,json=tokenPairs,proto3" json:"token_pairs,omitempty"` // allowances is a slice of the registered allowances at genesis Allowances []*Allowance `protobuf:"bytes,3,rep,name=allowances,proto3" json:"allowances,omitempty"` diff --git a/api/cosmos/evm/erc20/v1/query_grpc.pb.go b/api/cosmos/evm/erc20/v1/query_grpc.pb.go index 14fa6fbd23..c313554912 100644 --- a/api/cosmos/evm/erc20/v1/query_grpc.pb.go +++ b/api/cosmos/evm/erc20/v1/query_grpc.pb.go @@ -28,9 +28,9 @@ const ( // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type QueryClient interface { - // TokenPairs retrieves registered token pairs + // TokenPairs retrieves registered token pairs (mappings)x TokenPairs(ctx context.Context, in *QueryTokenPairsRequest, opts ...grpc.CallOption) (*QueryTokenPairsResponse, error) - // TokenPair retrieves a registered token pair + // TokenPair retrieves a registered token pair (mapping) TokenPair(ctx context.Context, in *QueryTokenPairRequest, opts ...grpc.CallOption) (*QueryTokenPairResponse, error) // Params retrieves the erc20 module params Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) @@ -75,9 +75,9 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . // All implementations must embed UnimplementedQueryServer // for forward compatibility type QueryServer interface { - // TokenPairs retrieves registered token pairs + // TokenPairs retrieves registered token pairs (mappings)x TokenPairs(context.Context, *QueryTokenPairsRequest) (*QueryTokenPairsResponse, error) - // TokenPair retrieves a registered token pair + // TokenPair retrieves a registered token pair (mapping) TokenPair(context.Context, *QueryTokenPairRequest) (*QueryTokenPairResponse, error) // Params retrieves the erc20 module params Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) diff --git a/proto/cosmos/evm/erc20/v1/erc20.proto b/proto/cosmos/evm/erc20/v1/erc20.proto index 5ead3be52c..d7cd29d2dd 100644 --- a/proto/cosmos/evm/erc20/v1/erc20.proto +++ b/proto/cosmos/evm/erc20/v1/erc20.proto @@ -17,8 +17,8 @@ enum Owner { OWNER_EXTERNAL = 2; } -// TokenPair defines an instance that records a pairing consisting of a native -// Cosmos Coin and an ERC20 token address. +// TokenPair defines an instance that records a pairing (mapping) consisting of a native +// Cosmos Coin and an ERC20 token address. The "pair" does not imply an asset swap exchange. message TokenPair { option (gogoproto.equal) = true; // erc20_address is the hex address of ERC20 contract token diff --git a/proto/cosmos/evm/erc20/v1/genesis.proto b/proto/cosmos/evm/erc20/v1/genesis.proto index 2e21021365..cacf592834 100644 --- a/proto/cosmos/evm/erc20/v1/genesis.proto +++ b/proto/cosmos/evm/erc20/v1/genesis.proto @@ -13,7 +13,7 @@ message GenesisState { // params are the erc20 module parameters at genesis Params params = 1 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ]; - // token_pairs is a slice of the registered token pairs at genesis + // token_pairs is a slice of the registered token pairs (mappings) at genesis repeated TokenPair token_pairs = 2 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ]; // allowances is a slice of the registered allowances at genesis diff --git a/proto/cosmos/evm/erc20/v1/query.proto b/proto/cosmos/evm/erc20/v1/query.proto index b1d2061f4e..c6ca01d86d 100644 --- a/proto/cosmos/evm/erc20/v1/query.proto +++ b/proto/cosmos/evm/erc20/v1/query.proto @@ -13,12 +13,12 @@ option go_package = "github.com/cosmos/evm/x/erc20/types"; // Query defines the gRPC querier service. service Query { - // TokenPairs retrieves registered token pairs + // TokenPairs retrieves registered token pairs (mappings)x rpc TokenPairs(QueryTokenPairsRequest) returns (QueryTokenPairsResponse) { option (google.api.http).get = "/cosmos/evm/erc20/v1/token_pairs"; } - // TokenPair retrieves a registered token pair + // TokenPair retrieves a registered token pair (mapping) rpc TokenPair(QueryTokenPairRequest) returns (QueryTokenPairResponse) { option (google.api.http).get = "/cosmos/evm/erc20/v1/token_pairs/{token}"; } diff --git a/x/erc20/types/erc20.pb.go b/x/erc20/types/erc20.pb.go index 5089cc87b3..9370f63d2c 100644 --- a/x/erc20/types/erc20.pb.go +++ b/x/erc20/types/erc20.pb.go @@ -57,8 +57,8 @@ func (Owner) EnumDescriptor() ([]byte, []int) { return fileDescriptor_1164958b5b106e92, []int{0} } -// TokenPair defines an instance that records a pairing consisting of a native -// Cosmos Coin and an ERC20 token address. +// TokenPair defines an instance that records a pairing (mapping) consisting of a native +// Cosmos Coin and an ERC20 token address. The "pair" does not imply an asset swap exchange. type TokenPair struct { // erc20_address is the hex address of ERC20 contract token Erc20Address string `protobuf:"bytes,1,opt,name=erc20_address,json=erc20Address,proto3" json:"erc20_address,omitempty"` diff --git a/x/erc20/types/genesis.pb.go b/x/erc20/types/genesis.pb.go index 45741d13e7..b923d43792 100644 --- a/x/erc20/types/genesis.pb.go +++ b/x/erc20/types/genesis.pb.go @@ -28,7 +28,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type GenesisState struct { // params are the erc20 module parameters at genesis Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` - // token_pairs is a slice of the registered token pairs at genesis + // token_pairs is a slice of the registered token pairs (mappings) at genesis TokenPairs []TokenPair `protobuf:"bytes,2,rep,name=token_pairs,json=tokenPairs,proto3" json:"token_pairs"` // allowances is a slice of the registered allowances at genesis Allowances []Allowance `protobuf:"bytes,3,rep,name=allowances,proto3" json:"allowances"` diff --git a/x/erc20/types/query.pb.go b/x/erc20/types/query.pb.go index 7c396c1606..56fbb3ef21 100644 --- a/x/erc20/types/query.pb.go +++ b/x/erc20/types/query.pb.go @@ -373,9 +373,9 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type QueryClient interface { - // TokenPairs retrieves registered token pairs + // TokenPairs retrieves registered token pairs (mappings)x TokenPairs(ctx context.Context, in *QueryTokenPairsRequest, opts ...grpc.CallOption) (*QueryTokenPairsResponse, error) - // TokenPair retrieves a registered token pair + // TokenPair retrieves a registered token pair (mapping) TokenPair(ctx context.Context, in *QueryTokenPairRequest, opts ...grpc.CallOption) (*QueryTokenPairResponse, error) // Params retrieves the erc20 module params Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) @@ -418,9 +418,9 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . // QueryServer is the server API for Query service. type QueryServer interface { - // TokenPairs retrieves registered token pairs + // TokenPairs retrieves registered token pairs (mappings)x TokenPairs(context.Context, *QueryTokenPairsRequest) (*QueryTokenPairsResponse, error) - // TokenPair retrieves a registered token pair + // TokenPair retrieves a registered token pair (mapping) TokenPair(context.Context, *QueryTokenPairRequest) (*QueryTokenPairResponse, error) // Params retrieves the erc20 module params Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) From 1d8b9e1e3903761ab7a3482aaabfd4438c6b3139 Mon Sep 17 00:00:00 2001 From: Sujong Lee Date: Wed, 20 Aug 2025 02:30:07 +0900 Subject: [PATCH 08/61] feat: remove allow-unprotected-txs(non eip-155) from x/vm params (#415) * feat: remove allow-unprotected-txs(non eip-155) from x/vm params * fix: build --------- Co-authored-by: Vlad J Co-authored-by: Alex | Interchain Labs --- ante/evm/05_signature_verification.go | 20 +- ante/evm/mono_decorator.go | 1 - api/cosmos/evm/vm/v1/evm.pulsar.go | 625 +++++++++++------------- proto/cosmos/evm/vm/v1/evm.proto | 6 +- tests/integration/ante/test_evm_ante.go | 24 +- tests/integration/x/vm/test_params.go | 15 - x/vm/types/evm.pb.go | 293 +++++------ x/vm/types/params.go | 17 - x/vm/types/params_legacy.go | 12 +- x/vm/types/params_test.go | 6 +- 10 files changed, 423 insertions(+), 596 deletions(-) diff --git a/ante/evm/05_signature_verification.go b/ante/evm/05_signature_verification.go index a845c75c5d..4c2dd9146e 100644 --- a/ante/evm/05_signature_verification.go +++ b/ante/evm/05_signature_verification.go @@ -32,11 +32,9 @@ func NewEthSigVerificationDecorator(ek anteinterfaces.EVMKeeper) EthSigVerificat // 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) { - evmParams := esvd.evmKeeper.GetParams(ctx) ethCfg := evmtypes.GetEthChainConfig() blockNum := big.NewInt(ctx.BlockHeight()) signer := ethtypes.MakeSigner(ethCfg, blockNum, uint64(ctx.BlockTime().Unix())) //#nosec G115 -- int overflow is not a concern here - allowUnprotectedTxs := evmParams.GetAllowUnprotectedTxs() msgs := tx.GetMsgs() if msgs == nil { @@ -49,7 +47,7 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil)) } - err := SignatureVerification(msgEthTx, msgEthTx.AsTransaction(), signer, allowUnprotectedTxs) + err := SignatureVerification(msgEthTx, msgEthTx.AsTransaction(), signer) if err != nil { return ctx, err } @@ -66,23 +64,7 @@ func SignatureVerification( msg *evmtypes.MsgEthereumTx, ethTx *ethtypes.Transaction, signer ethtypes.Signer, - allowUnprotectedTxs bool, ) error { - ethCfg := evmtypes.GetEthChainConfig() - - if !allowUnprotectedTxs { - if !ethTx.Protected() { - return errorsmod.Wrapf( - errortypes.ErrNotSupported, - "rejected unprotected ethereum transaction; please sign your transaction according to EIP-155 to protect it against replay-attacks") - } - if ethTx.ChainId().Uint64() != ethCfg.ChainID.Uint64() { - return errorsmod.Wrapf( - errortypes.ErrInvalidChainID, - "rejected ethereum transaction with incorrect chain-id; expected %d, got %d", ethCfg.ChainID, ethTx.ChainId()) - } - } - if err := msg.VerifySender(signer); err != nil { return errorsmod.Wrapf(errortypes.ErrorInvalidSigner, "signature verification failed: %s", err.Error()) } diff --git a/ante/evm/mono_decorator.go b/ante/evm/mono_decorator.go index 3277fbc76d..982336cf27 100644 --- a/ante/evm/mono_decorator.go +++ b/ante/evm/mono_decorator.go @@ -157,7 +157,6 @@ func (md MonoDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne ethMsg, ethTx, decUtils.Signer, - decUtils.EvmParams.AllowUnprotectedTxs, ); err != nil { return ctx, err } diff --git a/api/cosmos/evm/vm/v1/evm.pulsar.go b/api/cosmos/evm/vm/v1/evm.pulsar.go index 8d1585d6b6..f7e079e38a 100644 --- a/api/cosmos/evm/vm/v1/evm.pulsar.go +++ b/api/cosmos/evm/vm/v1/evm.pulsar.go @@ -156,7 +156,6 @@ var ( md_Params protoreflect.MessageDescriptor fd_Params_evm_denom protoreflect.FieldDescriptor fd_Params_extra_eips protoreflect.FieldDescriptor - fd_Params_allow_unprotected_txs protoreflect.FieldDescriptor fd_Params_evm_channels protoreflect.FieldDescriptor fd_Params_access_control protoreflect.FieldDescriptor fd_Params_active_static_precompiles protoreflect.FieldDescriptor @@ -167,7 +166,6 @@ func init() { md_Params = File_cosmos_evm_vm_v1_evm_proto.Messages().ByName("Params") fd_Params_evm_denom = md_Params.Fields().ByName("evm_denom") fd_Params_extra_eips = md_Params.Fields().ByName("extra_eips") - fd_Params_allow_unprotected_txs = md_Params.Fields().ByName("allow_unprotected_txs") fd_Params_evm_channels = md_Params.Fields().ByName("evm_channels") fd_Params_access_control = md_Params.Fields().ByName("access_control") fd_Params_active_static_precompiles = md_Params.Fields().ByName("active_static_precompiles") @@ -250,12 +248,6 @@ func (x *fastReflection_Params) Range(f func(protoreflect.FieldDescriptor, proto return } } - if x.AllowUnprotectedTxs != false { - value := protoreflect.ValueOfBool(x.AllowUnprotectedTxs) - if !f(fd_Params_allow_unprotected_txs, value) { - return - } - } if len(x.EvmChannels) != 0 { value := protoreflect.ValueOfList(&_Params_7_list{list: &x.EvmChannels}) if !f(fd_Params_evm_channels, value) { @@ -293,8 +285,6 @@ func (x *fastReflection_Params) Has(fd protoreflect.FieldDescriptor) bool { return x.EvmDenom != "" case "cosmos.evm.vm.v1.Params.extra_eips": return len(x.ExtraEips) != 0 - case "cosmos.evm.vm.v1.Params.allow_unprotected_txs": - return x.AllowUnprotectedTxs != false case "cosmos.evm.vm.v1.Params.evm_channels": return len(x.EvmChannels) != 0 case "cosmos.evm.vm.v1.Params.access_control": @@ -321,8 +311,6 @@ func (x *fastReflection_Params) Clear(fd protoreflect.FieldDescriptor) { x.EvmDenom = "" case "cosmos.evm.vm.v1.Params.extra_eips": x.ExtraEips = nil - case "cosmos.evm.vm.v1.Params.allow_unprotected_txs": - x.AllowUnprotectedTxs = false case "cosmos.evm.vm.v1.Params.evm_channels": x.EvmChannels = nil case "cosmos.evm.vm.v1.Params.access_control": @@ -354,9 +342,6 @@ func (x *fastReflection_Params) Get(descriptor protoreflect.FieldDescriptor) pro } listValue := &_Params_4_list{list: &x.ExtraEips} return protoreflect.ValueOfList(listValue) - case "cosmos.evm.vm.v1.Params.allow_unprotected_txs": - value := x.AllowUnprotectedTxs - return protoreflect.ValueOfBool(value) case "cosmos.evm.vm.v1.Params.evm_channels": if len(x.EvmChannels) == 0 { return protoreflect.ValueOfList(&_Params_7_list{}) @@ -398,8 +383,6 @@ func (x *fastReflection_Params) Set(fd protoreflect.FieldDescriptor, value proto lv := value.List() clv := lv.(*_Params_4_list) x.ExtraEips = *clv.list - case "cosmos.evm.vm.v1.Params.allow_unprotected_txs": - x.AllowUnprotectedTxs = value.Bool() case "cosmos.evm.vm.v1.Params.evm_channels": lv := value.List() clv := lv.(*_Params_7_list) @@ -455,8 +438,6 @@ func (x *fastReflection_Params) Mutable(fd protoreflect.FieldDescriptor) protore return protoreflect.ValueOfList(value) case "cosmos.evm.vm.v1.Params.evm_denom": panic(fmt.Errorf("field evm_denom of message cosmos.evm.vm.v1.Params is not mutable")) - case "cosmos.evm.vm.v1.Params.allow_unprotected_txs": - panic(fmt.Errorf("field allow_unprotected_txs of message cosmos.evm.vm.v1.Params is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Params")) @@ -475,8 +456,6 @@ func (x *fastReflection_Params) NewField(fd protoreflect.FieldDescriptor) protor case "cosmos.evm.vm.v1.Params.extra_eips": list := []int64{} return protoreflect.ValueOfList(&_Params_4_list{list: &list}) - case "cosmos.evm.vm.v1.Params.allow_unprotected_txs": - return protoreflect.ValueOfBool(false) case "cosmos.evm.vm.v1.Params.evm_channels": list := []string{} return protoreflect.ValueOfList(&_Params_7_list{list: &list}) @@ -566,9 +545,6 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { } n += 1 + runtime.Sov(uint64(l)) + l } - if x.AllowUnprotectedTxs { - n += 2 - } if len(x.EvmChannels) > 0 { for _, s := range x.EvmChannels { l = len(s) @@ -646,16 +622,6 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { dAtA[i] = 0x3a } } - if x.AllowUnprotectedTxs { - i-- - if x.AllowUnprotectedTxs { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x28 - } if len(x.ExtraEips) > 0 { var pksize2 int for _, num := range x.ExtraEips { @@ -841,26 +807,6 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { } else { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ExtraEips", wireType) } - case 5: - if wireType != 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field AllowUnprotectedTxs", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow - } - if iNdEx >= l { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - x.AllowUnprotectedTxs = bool(v != 0) case 7: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field EvmChannels", wireType) @@ -8785,9 +8731,6 @@ type Params struct { EvmDenom string `protobuf:"bytes,1,opt,name=evm_denom,json=evmDenom,proto3" json:"evm_denom,omitempty"` // extra_eips defines the additional EIPs for the vm.Config ExtraEips []int64 `protobuf:"varint,4,rep,packed,name=extra_eips,json=extraEips,proto3" json:"extra_eips,omitempty"` - // allow_unprotected_txs defines if replay-protected (i.e non EIP155 - // signed) transactions can be executed on the state machine. - AllowUnprotectedTxs bool `protobuf:"varint,5,opt,name=allow_unprotected_txs,json=allowUnprotectedTxs,proto3" json:"allow_unprotected_txs,omitempty"` // evm_channels is the list of channel identifiers from EVM compatible chains EvmChannels []string `protobuf:"bytes,7,rep,name=evm_channels,json=evmChannels,proto3" json:"evm_channels,omitempty"` // access_control defines the permission policy of the EVM @@ -8831,13 +8774,6 @@ func (x *Params) GetExtraEips() []int64 { return nil } -func (x *Params) GetAllowUnprotectedTxs() bool { - if x != nil { - return x.AllowUnprotectedTxs - } - return false -} - func (x *Params) GetEvmChannels() []string { if x != nil { return x.EvmChannels @@ -9746,7 +9682,7 @@ var file_cosmos_evm_vm_v1_evm_proto_rawDesc = []byte{ 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, - 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb0, 0x03, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, + 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x82, 0x03, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x31, 0x0a, 0x09, 0x65, 0x76, 0x6d, 0x5f, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x14, 0xf2, 0xde, 0x1f, 0x10, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, 0x76, 0x6d, 0x5f, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x22, 0x52, 0x08, 0x65, 0x76, 0x6d, @@ -9754,295 +9690,292 @@ var file_cosmos_evm_vm_v1_evm_proto_rawDesc = []byte{ 0x69, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x03, 0x42, 0x22, 0xe2, 0xde, 0x1f, 0x09, 0x45, 0x78, 0x74, 0x72, 0x61, 0x45, 0x49, 0x50, 0x73, 0xf2, 0xde, 0x1f, 0x11, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x65, 0x69, 0x70, 0x73, 0x22, 0x52, 0x09, 0x65, - 0x78, 0x74, 0x72, 0x61, 0x45, 0x69, 0x70, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x61, 0x6c, 0x6c, 0x6f, - 0x77, 0x5f, 0x75, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x78, - 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x55, 0x6e, - 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x78, 0x73, 0x12, 0x32, 0x0a, 0x0c, - 0x65, 0x76, 0x6d, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x03, - 0x28, 0x09, 0x42, 0x0f, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x56, 0x4d, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x52, 0x0b, 0x65, 0x76, 0x6d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, - 0x12, 0x5d, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x42, 0x15, 0xc8, 0xde, 0x1f, 0x00, 0xe2, - 0xde, 0x1f, 0x0d, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, - 0x3a, 0x0a, 0x19, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, - 0x5f, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x17, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, - 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x73, 0x3a, 0x1b, 0x8a, 0xe7, 0xb0, - 0x2a, 0x16, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x78, 0x2f, 0x76, - 0x6d, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, - 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0x91, 0x01, 0x0a, 0x0d, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x41, 0x0a, 0x06, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x54, 0x79, 0x70, - 0x65, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, - 0x3d, 0x0a, 0x04, 0x63, 0x61, 0x6c, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, - 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x54, 0x79, - 0x70, 0x65, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x04, 0x63, 0x61, 0x6c, 0x6c, 0x22, 0xdd, - 0x01, 0x0a, 0x11, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x63, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x42, 0x24, 0xe2, 0xde, 0x1f, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, 0x6c, 0x3a, - 0x22, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x52, 0x0a, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x63, 0x0a, 0x13, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x6c, 0x69, 0x73, 0x74, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x33, 0xe2, 0xde, 0x1f, 0x11, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, 0x73, 0x74, 0xf2, 0xde, 0x1f, - 0x1a, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x52, 0x11, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, 0x73, 0x74, 0x22, 0xa8, - 0x10, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5c, - 0x0a, 0x0f, 0x68, 0x6f, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, + 0x78, 0x74, 0x72, 0x61, 0x45, 0x69, 0x70, 0x73, 0x12, 0x32, 0x0a, 0x0c, 0x65, 0x76, 0x6d, 0x5f, + 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0f, + 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x56, 0x4d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x52, + 0x0b, 0x65, 0x76, 0x6d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x5d, 0x0a, 0x0e, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, + 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x42, 0x15, 0xc8, 0xde, 0x1f, 0x00, 0xe2, 0xde, 0x1f, 0x0d, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x0d, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x3a, 0x0a, 0x19, 0x61, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x70, 0x72, 0x65, + 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x50, 0x72, 0x65, 0x63, + 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x73, 0x3a, 0x1b, 0x8a, 0xe7, 0xb0, 0x2a, 0x16, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x78, 0x2f, 0x76, 0x6d, 0x2f, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, + 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0x91, 0x01, 0x0a, + 0x0d, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x41, + 0x0a, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x54, + 0x79, 0x70, 0x65, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x63, 0x61, 0x6c, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x54, 0x79, 0x70, 0x65, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x04, 0x63, 0x61, 0x6c, 0x6c, + 0x22, 0xdd, 0x01, 0x0a, 0x11, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x63, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x42, 0x24, 0xe2, 0xde, 0x1f, 0x0a, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, + 0x6c, 0x3a, 0x22, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x52, + 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x63, 0x0a, 0x13, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x6c, 0x69, + 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x33, 0xe2, 0xde, 0x1f, 0x11, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, 0x73, 0x74, 0xf2, + 0xde, 0x1f, 0x1a, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x52, 0x11, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, 0x73, 0x74, + 0x22, 0xa8, 0x10, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x12, 0x5c, 0x0a, 0x0f, 0x68, 0x6f, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xda, 0xde, 0x1f, 0x15, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, + 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x16, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x68, 0x6f, + 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0e, + 0x68, 0x6f, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x68, + 0x0a, 0x0e, 0x64, 0x61, 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x42, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, + 0x74, 0xe2, 0xde, 0x1f, 0x0c, 0x44, 0x41, 0x4f, 0x46, 0x6f, 0x72, 0x6b, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0xf2, 0xde, 0x1f, 0x15, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x64, 0x61, 0x6f, 0x5f, 0x66, + 0x6f, 0x72, 0x6b, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0c, 0x64, 0x61, 0x6f, 0x46, + 0x6f, 0x72, 0x6b, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x57, 0x0a, 0x10, 0x64, 0x61, 0x6f, 0x5f, + 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x08, 0x42, 0x2d, 0xe2, 0xde, 0x1f, 0x0e, 0x44, 0x41, 0x4f, 0x46, 0x6f, 0x72, 0x6b, 0x53, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0xf2, 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, + 0x64, 0x61, 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x22, 0x52, 0x0e, 0x64, 0x61, 0x6f, 0x46, 0x6f, 0x72, 0x6b, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x12, 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, 0x31, 0x35, 0x30, 0x5f, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, - 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x16, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x68, 0x6f, 0x6d, 0x65, - 0x73, 0x74, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0e, 0x68, 0x6f, - 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x68, 0x0a, 0x0e, - 0x64, 0x61, 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x42, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, - 0xde, 0x1f, 0x0c, 0x44, 0x41, 0x4f, 0x46, 0x6f, 0x72, 0x6b, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0xf2, - 0xde, 0x1f, 0x15, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x64, 0x61, 0x6f, 0x5f, 0x66, 0x6f, 0x72, - 0x6b, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0c, 0x64, 0x61, 0x6f, 0x46, 0x6f, 0x72, - 0x6b, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x57, 0x0a, 0x10, 0x64, 0x61, 0x6f, 0x5f, 0x66, 0x6f, - 0x72, 0x6b, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x42, 0x2d, 0xe2, 0xde, 0x1f, 0x0e, 0x44, 0x41, 0x4f, 0x46, 0x6f, 0x72, 0x6b, 0x53, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0xf2, 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x64, 0x61, - 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x52, - 0x0e, 0x64, 0x61, 0x6f, 0x46, 0x6f, 0x72, 0x6b, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, - 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, 0x31, 0x35, 0x30, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, 0x50, 0x31, 0x35, 0x30, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, 0x69, 0x70, 0x31, 0x35, + 0x30, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x65, 0x69, 0x70, 0x31, 0x35, 0x30, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, 0x31, 0x35, 0x35, 0x5f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3f, 0xda, 0xde, 0x1f, + 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, + 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, 0x50, 0x31, 0x35, 0x35, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, + 0x69, 0x70, 0x31, 0x35, 0x35, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x65, 0x69, + 0x70, 0x31, 0x35, 0x35, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, + 0x31, 0x35, 0x38, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x3f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, + 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, + 0x50, 0x31, 0x35, 0x38, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, + 0x6c, 0x3a, 0x22, 0x65, 0x69, 0x70, 0x31, 0x35, 0x38, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, + 0x52, 0x0b, 0x65, 0x69, 0x70, 0x31, 0x35, 0x38, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x5c, 0x0a, + 0x0f, 0x62, 0x79, 0x7a, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, + 0x74, 0xf2, 0xde, 0x1f, 0x16, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x62, 0x79, 0x7a, 0x61, 0x6e, + 0x74, 0x69, 0x75, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0e, 0x62, 0x79, 0x7a, + 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x6b, 0x0a, 0x14, 0x63, + 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x65, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x38, 0xda, 0xde, 0x1f, 0x15, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, + 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x1b, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x6f, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x65, 0x5f, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x22, 0x52, 0x13, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, + 0x70, 0x6c, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x5f, 0x0a, 0x10, 0x70, 0x65, 0x74, 0x65, + 0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x34, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, + 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, + 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x70, 0x65, 0x74, 0x65, 0x72, 0x73, 0x62, 0x75, 0x72, + 0x67, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0f, 0x70, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x62, 0x75, 0x72, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x59, 0x0a, 0x0e, 0x69, 0x73, 0x74, + 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x32, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, + 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x15, + 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x5f, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0d, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x64, 0x0a, 0x12, 0x6d, 0x75, 0x69, 0x72, 0x5f, 0x67, 0x6c, 0x61, + 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x36, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, + 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x19, 0x79, + 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6d, 0x75, 0x69, 0x72, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, + 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x10, 0x6d, 0x75, 0x69, 0x72, 0x47, 0x6c, + 0x61, 0x63, 0x69, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x53, 0x0a, 0x0c, 0x62, 0x65, + 0x72, 0x6c, 0x69, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x30, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, + 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x13, 0x79, + 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x62, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x22, 0x52, 0x0b, 0x62, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, + 0x53, 0x0a, 0x0c, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, + 0x11, 0x20, 0x01, 0x28, 0x09, 0x42, 0x30, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, - 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, 0x50, 0x31, 0x35, 0x30, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0xf2, - 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, 0x69, 0x70, 0x31, 0x35, 0x30, 0x5f, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x65, 0x69, 0x70, 0x31, 0x35, 0x30, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, 0x31, 0x35, 0x35, 0x5f, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3f, 0xda, 0xde, 0x1f, 0x15, 0x63, + 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, + 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x67, 0x0a, 0x13, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x5f, 0x67, 0x6c, + 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x12, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x37, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, + 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x1a, + 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x5f, 0x67, 0x6c, 0x61, 0x63, + 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x11, 0x61, 0x72, 0x72, 0x6f, + 0x77, 0x47, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x64, 0x0a, + 0x12, 0x67, 0x72, 0x61, 0x79, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x42, 0x36, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, - 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, 0x50, 0x31, 0x35, 0x35, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, 0x69, 0x70, - 0x31, 0x35, 0x35, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x65, 0x69, 0x70, 0x31, - 0x35, 0x35, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, 0x31, 0x35, - 0x38, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3f, 0xda, - 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, - 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, 0x50, 0x31, - 0x35, 0x38, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, - 0x22, 0x65, 0x69, 0x70, 0x31, 0x35, 0x38, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, - 0x65, 0x69, 0x70, 0x31, 0x35, 0x38, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x5c, 0x0a, 0x0f, 0x62, - 0x79, 0x7a, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, - 0xde, 0x1f, 0x16, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x62, 0x79, 0x7a, 0x61, 0x6e, 0x74, 0x69, - 0x75, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0e, 0x62, 0x79, 0x7a, 0x61, 0x6e, - 0x74, 0x69, 0x75, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x6b, 0x0a, 0x14, 0x63, 0x6f, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x38, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, - 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x1b, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x6f, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x22, 0x52, 0x13, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x70, 0x6c, - 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x5f, 0x0a, 0x10, 0x70, 0x65, 0x74, 0x65, 0x72, 0x73, - 0x62, 0x75, 0x72, 0x67, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x34, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, - 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x17, 0x79, - 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x70, 0x65, 0x74, 0x65, 0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x5f, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0f, 0x70, 0x65, 0x74, 0x65, 0x72, 0x73, 0x62, 0x75, - 0x72, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x59, 0x0a, 0x0e, 0x69, 0x73, 0x74, 0x61, 0x6e, - 0x62, 0x75, 0x6c, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x32, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, - 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x15, 0x79, 0x61, - 0x6d, 0x6c, 0x3a, 0x22, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x5f, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x22, 0x52, 0x0d, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x12, 0x64, 0x0a, 0x12, 0x6d, 0x75, 0x69, 0x72, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, - 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x42, 0x36, - 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, - 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x19, 0x79, 0x61, 0x6d, - 0x6c, 0x3a, 0x22, 0x6d, 0x75, 0x69, 0x72, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x10, 0x6d, 0x75, 0x69, 0x72, 0x47, 0x6c, 0x61, 0x63, - 0x69, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x53, 0x0a, 0x0c, 0x62, 0x65, 0x72, 0x6c, - 0x69, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x30, - 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, - 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, - 0x6c, 0x3a, 0x22, 0x62, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, - 0x52, 0x0b, 0x62, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x53, 0x0a, - 0x0c, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x11, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x30, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, + 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x19, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x67, 0x72, + 0x61, 0x79, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x22, 0x52, 0x10, 0x67, 0x72, 0x61, 0x79, 0x47, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x12, 0x6a, 0x0a, 0x14, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x6e, 0x65, 0x74, + 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x15, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x38, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, + 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x1b, + 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x6e, 0x65, 0x74, 0x73, + 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x12, 0x6d, 0x65, 0x72, + 0x67, 0x65, 0x4e, 0x65, 0x74, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, + 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, + 0x6e, 0x6f, 0x6d, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x65, 0x6e, 0x6f, 0x6d, + 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x18, 0x1a, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x12, 0x56, 0x0a, 0x0d, + 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1b, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x31, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, - 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x5f, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x12, 0x67, 0x0a, 0x13, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x5f, 0x67, 0x6c, 0x61, 0x63, - 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x37, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, - 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x1a, 0x79, 0x61, - 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, - 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x11, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x47, - 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x64, 0x0a, 0x12, 0x67, - 0x72, 0x61, 0x79, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x42, 0x36, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, - 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x19, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x67, 0x72, 0x61, 0x79, - 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, - 0x10, 0x67, 0x72, 0x61, 0x79, 0x47, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x12, 0x6a, 0x0a, 0x14, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x6e, 0x65, 0x74, 0x73, 0x70, - 0x6c, 0x69, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x38, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, - 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x1b, 0x79, 0x61, - 0x6d, 0x6c, 0x3a, 0x22, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x6e, 0x65, 0x74, 0x73, 0x70, 0x6c, - 0x69, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x12, 0x6d, 0x65, 0x72, 0x67, 0x65, - 0x4e, 0x65, 0x74, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x19, 0x0a, - 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6e, 0x6f, - 0x6d, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x12, 0x1a, - 0x0a, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x12, 0x56, 0x0a, 0x0d, 0x73, 0x68, - 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1b, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x31, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, - 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x14, - 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x54, 0x69, - 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x63, 0x75, 0x6e, 0x5f, 0x74, 0x69, 0x6d, - 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, - 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x61, 0x6e, 0x63, - 0x75, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x63, 0x75, 0x6e, - 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x70, 0x72, 0x61, 0x67, 0x75, 0x65, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, 0xde, 0x1f, 0x15, 0x63, + 0x1f, 0x14, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, + 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x63, 0x75, 0x6e, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, - 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x70, 0x72, - 0x61, 0x67, 0x75, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x70, 0x72, 0x61, 0x67, - 0x75, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x6b, 0x6c, 0x65, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, 0xde, 0x1f, + 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x61, + 0x6e, 0x63, 0x75, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x63, + 0x75, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x70, 0x72, 0x61, 0x67, 0x75, 0x65, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, - 0x76, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x76, 0x65, - 0x72, 0x6b, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x6f, 0x73, 0x61, 0x6b, - 0x61, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2e, 0xda, 0xde, - 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, - 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x11, 0x79, 0x61, 0x6d, 0x6c, 0x3a, - 0x22, 0x6f, 0x73, 0x61, 0x6b, 0x61, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x09, 0x6f, 0x73, - 0x61, 0x6b, 0x61, 0x54, 0x69, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, - 0x16, 0x10, 0x17, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x22, 0x2f, 0x0a, 0x05, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x50, 0x0a, 0x0f, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x12, 0x0a, - 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, - 0x68, 0x12, 0x29, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x22, 0xca, 0x02, 0x0a, - 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, - 0x0a, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, - 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x0c, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, - 0x42, 0x0f, 0xea, 0xde, 0x1f, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2c, - 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x13, 0xea, 0xde, 0x1f, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2f, 0x0a, 0x08, - 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x42, 0x14, - 0xea, 0xde, 0x1f, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x6e, 0x64, 0x65, 0x78, 0x52, 0x07, 0x74, 0x78, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2c, 0x0a, - 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x0d, 0xea, 0xde, 0x1f, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x05, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0c, 0xea, 0xde, 0x1f, 0x08, - 0x6c, 0x6f, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, - 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x90, 0x02, 0x0a, 0x08, 0x54, 0x78, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, - 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x1b, 0xf2, 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x52, 0x0f, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, - 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, - 0x6c, 0x6f, 0x6f, 0x6d, 0x12, 0x57, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, - 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x73, 0x42, 0x1b, 0xc8, 0xde, 0x1f, 0x00, 0xf2, 0xde, - 0x1f, 0x0e, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x74, 0x78, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x22, - 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x74, 0x78, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x10, 0x0a, - 0x03, 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12, - 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x67, - 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x67, - 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, 0x61, 0x0a, 0x0b, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0f, 0xea, 0xde, 0x1f, - 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x0b, 0x73, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, - 0xa0, 0x04, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x16, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, - 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x12, 0x35, 0x0a, 0x0d, 0x64, 0x69, 0x73, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, - 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x61, - 0x63, 0x6b, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, - 0x12, 0x3b, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x42, 0x12, 0xea, 0xde, 0x1f, 0x0e, 0x64, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x0e, 0x64, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x64, 0x65, - 0x62, 0x75, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x3b, 0x0a, 0x09, 0x6f, 0x76, 0x65, - 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x6f, 0x76, 0x65, - 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x42, 0x10, 0xea, - 0xde, 0x1f, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x52, - 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x42, 0x0a, - 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x42, 0x14, 0xea, 0xde, 0x1f, 0x10, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x70, 0x72, 0x61, 0x67, 0x75, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x70, 0x72, + 0x61, 0x67, 0x75, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x6b, + 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, + 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, + 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, 0x6c, + 0x3a, 0x22, 0x76, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, + 0x76, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x6f, 0x73, + 0x61, 0x6b, 0x61, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2e, + 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, + 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x11, 0x79, 0x61, 0x6d, + 0x6c, 0x3a, 0x22, 0x6f, 0x73, 0x61, 0x6b, 0x61, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x09, + 0x6f, 0x73, 0x61, 0x6b, 0x61, 0x54, 0x69, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, + 0x04, 0x08, 0x16, 0x10, 0x17, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x22, 0x2f, 0x0a, 0x05, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x50, 0x0a, 0x0f, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x22, 0xca, + 0x02, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x0c, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x04, 0x42, 0x0f, 0xea, 0xde, 0x1f, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x12, 0x2c, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x13, 0xea, 0xde, 0x1f, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2f, + 0x0a, 0x08, 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, + 0x42, 0x14, 0xea, 0xde, 0x1f, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x07, 0x74, 0x78, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, + 0x2c, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x0d, 0xea, 0xde, 0x1f, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, + 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0c, 0xea, 0xde, + 0x1f, 0x08, 0x6c, 0x6f, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x90, 0x02, 0x0a, 0x08, + 0x54, 0x78, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x1b, 0xf2, 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x52, + 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x05, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x12, 0x57, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x6c, 0x6f, 0x67, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x73, 0x42, 0x1b, 0xc8, 0xde, 0x1f, 0x00, + 0xf2, 0xde, 0x1f, 0x0e, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x74, 0x78, 0x5f, 0x6c, 0x6f, 0x67, + 0x73, 0x22, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x74, 0x78, 0x4c, 0x6f, 0x67, 0x73, 0x12, + 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x65, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x12, 0x19, 0x0a, + 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, 0x61, + 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0f, 0xea, + 0xde, 0x1f, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x0b, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x3a, 0x04, 0x88, 0xa0, 0x1f, + 0x00, 0x22, 0xa0, 0x04, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x12, 0x35, 0x0a, 0x0d, 0x64, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x61, + 0x63, 0x6b, 0x12, 0x3b, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x42, 0x12, 0xea, 0xde, 0x1f, + 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, + 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, + 0x64, 0x65, 0x62, 0x75, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x3b, 0x0a, 0x09, 0x6f, + 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, + 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x6f, + 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x42, + 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, + 0x79, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, + 0x42, 0x0a, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x42, 0x14, 0xea, 0xde, 0x1f, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, 0x61, 0x74, - 0x61, 0x12, 0x3e, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xea, - 0xde, 0x1f, 0x0c, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x10, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x4a, 0x73, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x52, 0x0e, 0x64, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x13, 0x64, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, 0x64, 0x61, - 0x74, 0x61, 0x22, 0x4e, 0x0a, 0x0a, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, - 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, - 0x64, 0x65, 0x2a, 0xc0, 0x01, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x3c, 0x0a, 0x1a, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x4c, 0x45, 0x53, 0x53, 0x10, - 0x00, 0x1a, 0x1c, 0x8a, 0x9d, 0x20, 0x18, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, - 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x6c, 0x65, 0x73, 0x73, 0x12, - 0x34, 0x0a, 0x16, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, - 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x01, 0x1a, 0x18, 0x8a, 0x9d, 0x20, - 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x74, 0x72, - 0x69, 0x63, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x45, - 0x44, 0x10, 0x02, 0x1a, 0x1a, 0x8a, 0x9d, 0x20, 0x16, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, - 0x79, 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x1a, - 0x04, 0x88, 0xa3, 0x1e, 0x00, 0x42, 0xab, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x42, 0x08, - 0x45, 0x76, 0x6d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x6d, - 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x56, 0xaa, 0x02, 0x10, 0x43, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x56, 0x6d, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, 0x43, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, 0x56, 0x31, 0xe2, 0x02, - 0x1c, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, 0x56, - 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, - 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x56, 0x6d, 0x3a, - 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x52, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, + 0x61, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x5f, 0x6a, 0x73, + 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x10, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x4a, 0x73, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x52, + 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x52, + 0x13, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x4e, 0x0a, 0x0a, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x63, 0x6f, 0x64, 0x65, 0x2a, 0xc0, 0x01, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x1a, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x4c, 0x45, 0x53, + 0x53, 0x10, 0x00, 0x1a, 0x1c, 0x8a, 0x9d, 0x20, 0x18, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, + 0x79, 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x6c, 0x65, 0x73, + 0x73, 0x12, 0x34, 0x0a, 0x16, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x01, 0x1a, 0x18, 0x8a, + 0x9d, 0x20, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, + 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x41, 0x43, 0x43, 0x45, 0x53, + 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, + 0x4e, 0x45, 0x44, 0x10, 0x02, 0x1a, 0x1a, 0x8a, 0x9d, 0x20, 0x16, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x54, 0x79, 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x64, 0x1a, 0x04, 0x88, 0xa3, 0x1e, 0x00, 0x42, 0xab, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, + 0x42, 0x08, 0x45, 0x76, 0x6d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x3b, + 0x76, 0x6d, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x56, 0xaa, 0x02, 0x10, 0x43, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x56, 0x6d, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, + 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, 0x56, 0x31, + 0xe2, 0x02, 0x1c, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, + 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x56, + 0x6d, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/cosmos/evm/vm/v1/evm.proto b/proto/cosmos/evm/vm/v1/evm.proto index fc0c7b3fe9..e338c493bb 100644 --- a/proto/cosmos/evm/vm/v1/evm.proto +++ b/proto/cosmos/evm/vm/v1/evm.proto @@ -20,9 +20,9 @@ message Params { (gogoproto.customname) = "ExtraEIPs", (gogoproto.moretags) = "yaml:\"extra_eips\"" ]; - // allow_unprotected_txs defines if replay-protected (i.e non EIP155 - // signed) transactions can be executed on the state machine. - bool allow_unprotected_txs = 5; + // Acceptance of non-protected transactions (i.e non EIP-155 signed) + // is managed independently by each node. + reserved 5; // renamed active_precompiles to active_static_precompiles reserved 6; // evm_channels is the list of channel identifiers from EVM compatible chains diff --git a/tests/integration/ante/test_evm_ante.go b/tests/integration/ante/test_evm_ante.go index 776641e099..be0fec7520 100644 --- a/tests/integration/ante/test_evm_ante.go +++ b/tests/integration/ante/test_evm_ante.go @@ -1264,14 +1264,13 @@ func (s *EvmAnteTestSuite) TestEthSigVerificationDecorator() { s.Require().NoError(err) testCases := []struct { - name string - tx sdk.Tx - allowUnprotectedTxs bool - reCheckTx bool - expPass bool + name string + tx sdk.Tx + reCheckTx bool + expPass bool }{ - {"ReCheckTx", &utiltx.InvalidTx{}, false, true, false}, - {"invalid transaction type", &utiltx.InvalidTx{}, false, false, false}, + {"ReCheckTx", &utiltx.InvalidTx{}, true, false}, + {"invalid transaction type", &utiltx.InvalidTx{}, false, false}, { "invalid sender", evmtypes.NewTx(&evmtypes.EvmTxArgs{ @@ -1281,20 +1280,16 @@ func (s *EvmAnteTestSuite) TestEthSigVerificationDecorator() { GasLimit: 1000, GasPrice: big.NewInt(1), }), - true, false, false, }, - {"successful signature verification", signedTx, false, false, true}, - {"invalid, reject unprotected txs", unprotectedTx, false, false, false}, - {"successful, allow unprotected txs", unprotectedTx, true, false, true}, + {"successful signature verification", signedTx, false, true}, + {"invalid, reject unprotected txs", unprotectedTx, false, false}, + {"successful, allow unprotected txs", unprotectedTx, false, true}, } for _, tc := range testCases { s.Run(tc.name, func() { - s.WithEvmParamsOptions(func(params *evmtypes.Params) { - params.AllowUnprotectedTxs = tc.allowUnprotectedTxs - }) s.SetupTest() dec := ethante.NewEthSigVerificationDecorator(s.GetNetwork().App.GetEVMKeeper()) _, err := dec.AnteHandle(s.GetNetwork().GetContext().WithIsReCheckTx(tc.reCheckTx), tc.tx, false, testutil.NoOpNextFn) @@ -1306,7 +1301,6 @@ func (s *EvmAnteTestSuite) TestEthSigVerificationDecorator() { } }) } - s.WithEvmParamsOptions(nil) } func (s *EvmAnteTestSuite) TestSignatures() { diff --git a/tests/integration/x/vm/test_params.go b/tests/integration/x/vm/test_params.go index 9f54025032..4381a81160 100644 --- a/tests/integration/x/vm/test_params.go +++ b/tests/integration/x/vm/test_params.go @@ -63,21 +63,6 @@ func (s *KeeperTestSuite) TestParams() { }, true, }, - { - "success - Check AllowUnprotectedTxs param is set to false and can be retrieved correctly", - func() interface{} { - params := defaultChainEVMParams - params.AllowUnprotectedTxs = false - err := s.Network.App.GetEVMKeeper().SetParams(s.Network.GetContext(), params) - s.Require().NoError(err) - return params.AllowUnprotectedTxs - }, - func() interface{} { - evmParams := s.Network.App.GetEVMKeeper().GetParams(s.Network.GetContext()) - return evmParams.GetAllowUnprotectedTxs() - }, - true, - }, { name: "success - Active precompiles are sorted when setting params", paramsFun: func() interface{} { diff --git a/x/vm/types/evm.pb.go b/x/vm/types/evm.pb.go index 567e4d4720..5580012e2d 100644 --- a/x/vm/types/evm.pb.go +++ b/x/vm/types/evm.pb.go @@ -64,9 +64,6 @@ type Params struct { EvmDenom string `protobuf:"bytes,1,opt,name=evm_denom,json=evmDenom,proto3" json:"evm_denom,omitempty" yaml:"evm_denom"` // extra_eips defines the additional EIPs for the vm.Config ExtraEIPs []int64 `protobuf:"varint,4,rep,packed,name=extra_eips,json=extraEips,proto3" json:"extra_eips,omitempty" yaml:"extra_eips"` - // allow_unprotected_txs defines if replay-protected (i.e non EIP155 - // signed) transactions can be executed on the state machine. - AllowUnprotectedTxs bool `protobuf:"varint,5,opt,name=allow_unprotected_txs,json=allowUnprotectedTxs,proto3" json:"allow_unprotected_txs,omitempty"` // evm_channels is the list of channel identifiers from EVM compatible chains EVMChannels []string `protobuf:"bytes,7,rep,name=evm_channels,json=evmChannels,proto3" json:"evm_channels,omitempty"` // access_control defines the permission policy of the EVM @@ -123,13 +120,6 @@ func (m *Params) GetExtraEIPs() []int64 { return nil } -func (m *Params) GetAllowUnprotectedTxs() bool { - if m != nil { - return m.AllowUnprotectedTxs - } - return false -} - func (m *Params) GetEVMChannels() []string { if m != nil { return m.EVMChannels @@ -942,132 +932,130 @@ func init() { func init() { proto.RegisterFile("cosmos/evm/vm/v1/evm.proto", fileDescriptor_d1129b8db63d55c7) } var fileDescriptor_d1129b8db63d55c7 = []byte{ - // 1988 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0x5d, 0x6f, 0x1b, 0xc7, - 0xd5, 0x16, 0xc5, 0x95, 0xb4, 0x1c, 0x52, 0xd4, 0x7a, 0x44, 0xc9, 0x34, 0xed, 0x68, 0xf9, 0xee, - 0xdb, 0x0b, 0xd5, 0x48, 0x25, 0x4b, 0x8e, 0x5a, 0xc3, 0xe9, 0x07, 0x44, 0x99, 0x69, 0xa5, 0xda, - 0x0e, 0x31, 0x54, 0x12, 0xa4, 0x68, 0xb1, 0x18, 0xee, 0x8e, 0x97, 0x1b, 0xee, 0xee, 0x10, 0x3b, - 0x4b, 0x86, 0xea, 0x2f, 0x08, 0x7c, 0x95, 0xfe, 0x00, 0x03, 0x01, 0x7a, 0x93, 0x4b, 0xff, 0x84, - 0x5e, 0x06, 0xbd, 0xca, 0x65, 0x51, 0xa0, 0x8b, 0x82, 0xbe, 0x08, 0xa0, 0x4b, 0xfd, 0x82, 0x62, - 0x3e, 0xf8, 0x29, 0x85, 0x55, 0x01, 0xc1, 0x9e, 0xe7, 0xcc, 0x39, 0xcf, 0x73, 0x66, 0xe6, 0xec, - 0xec, 0x59, 0x82, 0x8a, 0x43, 0x59, 0x48, 0xd9, 0x3e, 0xe9, 0x87, 0xfb, 0xfc, 0xef, 0x80, 0x8f, - 0xf6, 0xba, 0x31, 0x4d, 0x28, 0x34, 0xe4, 0xdc, 0x1e, 0xb7, 0xf0, 0xbf, 0x83, 0xca, 0x1d, 0x1c, - 0xfa, 0x11, 0xdd, 0x17, 0xff, 0x4a, 0xa7, 0x4a, 0xc9, 0xa3, 0x1e, 0x15, 0xc3, 0x7d, 0x3e, 0x92, - 0x56, 0xeb, 0x6d, 0x16, 0xac, 0x36, 0x70, 0x8c, 0x43, 0x06, 0x0f, 0x40, 0x8e, 0xf4, 0x43, 0xdb, - 0x25, 0x11, 0x0d, 0xcb, 0x99, 0x6a, 0x66, 0x37, 0x57, 0x2b, 0x5d, 0xa5, 0xa6, 0x71, 0x81, 0xc3, - 0xe0, 0xa9, 0x35, 0x9e, 0xb2, 0x90, 0x4e, 0xfa, 0xe1, 0x33, 0x3e, 0x84, 0xc7, 0x00, 0x90, 0x41, - 0x12, 0x63, 0x9b, 0xf8, 0x5d, 0x56, 0xd6, 0xaa, 0xd9, 0xdd, 0x6c, 0xcd, 0x1a, 0xa6, 0x66, 0xae, - 0xce, 0xad, 0xf5, 0xd3, 0x06, 0xbb, 0x4a, 0xcd, 0x3b, 0x8a, 0x60, 0xec, 0x68, 0xa1, 0x9c, 0x00, - 0x75, 0xbf, 0xcb, 0xe0, 0x21, 0xd8, 0xc2, 0x41, 0x40, 0xbf, 0xb4, 0x7b, 0x11, 0xcf, 0x88, 0x38, - 0x09, 0x71, 0xed, 0x64, 0xc0, 0xca, 0x2b, 0xd5, 0xcc, 0xae, 0x8e, 0x36, 0xc5, 0xe4, 0x27, 0x93, - 0xb9, 0xf3, 0x01, 0x8f, 0x29, 0xf0, 0x74, 0x9c, 0x36, 0x8e, 0x22, 0x12, 0xb0, 0xf2, 0x5a, 0x35, - 0xbb, 0x9b, 0xab, 0x6d, 0x0c, 0x53, 0x33, 0x5f, 0xff, 0xf4, 0xc5, 0x89, 0x32, 0xa3, 0x3c, 0xe9, - 0x87, 0x23, 0x00, 0xff, 0x04, 0x8a, 0xd8, 0x71, 0x08, 0x63, 0xb6, 0x43, 0xa3, 0x24, 0xa6, 0x41, - 0x59, 0xaf, 0x66, 0x76, 0xf3, 0x87, 0xe6, 0xde, 0xfc, 0xe6, 0xed, 0x1d, 0x0b, 0xbf, 0x13, 0xe9, - 0x56, 0xdb, 0xfa, 0x2e, 0x35, 0x97, 0x86, 0xa9, 0xb9, 0x3e, 0x63, 0x46, 0xeb, 0x78, 0x1a, 0xc2, - 0xa7, 0xe0, 0x1e, 0x76, 0x12, 0xbf, 0x4f, 0x6c, 0x96, 0xe0, 0xc4, 0x77, 0xec, 0x6e, 0x4c, 0x1c, - 0x1a, 0x76, 0xfd, 0x80, 0xb0, 0x72, 0x8e, 0xe7, 0x87, 0xee, 0x4a, 0x87, 0xa6, 0x98, 0x6f, 0x4c, - 0xa6, 0x9f, 0xde, 0x7f, 0xfd, 0xc3, 0xdb, 0x87, 0xdb, 0x53, 0xe7, 0x3b, 0xe0, 0x27, 0x2c, 0x4f, - 0xe5, 0x4c, 0xd3, 0x97, 0x8d, 0xec, 0x99, 0xa6, 0x67, 0x0d, 0xed, 0x4c, 0xd3, 0x57, 0x8d, 0x35, - 0xeb, 0x2f, 0x19, 0x30, 0x9b, 0x0b, 0x3c, 0x06, 0xab, 0x4e, 0x4c, 0x70, 0x42, 0xc4, 0xb1, 0xe5, - 0x0f, 0xff, 0xff, 0xbf, 0xac, 0xe9, 0xfc, 0xa2, 0x4b, 0x6a, 0x1a, 0x5f, 0x17, 0x52, 0x81, 0xf0, - 0x57, 0x40, 0x73, 0x70, 0x10, 0x94, 0x97, 0xff, 0x57, 0x02, 0x11, 0x66, 0xfd, 0x2b, 0x03, 0xee, - 0x5c, 0xf3, 0x80, 0x0e, 0xc8, 0xab, 0x3d, 0x4f, 0x2e, 0xba, 0x32, 0xb9, 0xe2, 0xe1, 0x83, 0x1f, - 0xe3, 0x16, 0xa4, 0x3f, 0x19, 0xa6, 0x26, 0x98, 0xe0, 0xab, 0xd4, 0x84, 0xb2, 0x7c, 0xa6, 0x88, - 0x2c, 0x04, 0xf0, 0xd8, 0x03, 0x3a, 0x60, 0x73, 0xf6, 0x60, 0xed, 0xc0, 0x67, 0x49, 0x79, 0x59, - 0xd4, 0xc4, 0xe3, 0x61, 0x6a, 0xce, 0x26, 0xf6, 0xdc, 0x67, 0xc9, 0x55, 0x6a, 0x56, 0x66, 0x58, - 0xa7, 0x23, 0x2d, 0x74, 0x07, 0xcf, 0x07, 0x58, 0xdf, 0x1a, 0x20, 0x7f, 0xd2, 0xc6, 0x7e, 0x74, - 0x42, 0xa3, 0x57, 0xbe, 0x07, 0xff, 0x08, 0x36, 0xda, 0x34, 0x24, 0x2c, 0x21, 0xd8, 0xb5, 0x5b, - 0x01, 0x75, 0x3a, 0xea, 0x89, 0x79, 0xfc, 0xcf, 0xd4, 0xdc, 0x92, 0x0b, 0x64, 0x6e, 0x67, 0xcf, - 0xa7, 0xfb, 0x21, 0x4e, 0xda, 0x7b, 0xa7, 0x11, 0x17, 0xdd, 0x96, 0xa2, 0x73, 0x91, 0x16, 0x2a, - 0x8e, 0x2d, 0x35, 0x6e, 0x80, 0x6d, 0x50, 0x74, 0x31, 0xb5, 0x5f, 0xd1, 0xb8, 0xa3, 0xc8, 0x97, - 0x05, 0x79, 0xed, 0x47, 0xc9, 0x87, 0xa9, 0x59, 0x78, 0x76, 0xfc, 0xf1, 0x47, 0x34, 0xee, 0x08, - 0x8a, 0xab, 0xd4, 0xdc, 0x92, 0x62, 0xb3, 0x44, 0x16, 0x2a, 0xb8, 0x98, 0x8e, 0xdd, 0xe0, 0x67, - 0xc0, 0x18, 0x3b, 0xb0, 0x5e, 0xb7, 0x4b, 0xe3, 0xa4, 0x9c, 0xe5, 0x0f, 0x5e, 0xed, 0x67, 0xc3, - 0xd4, 0x2c, 0x2a, 0xca, 0xa6, 0x9c, 0xb9, 0x4a, 0xcd, 0xbb, 0x73, 0xa4, 0x2a, 0xc6, 0x42, 0x45, - 0x45, 0xab, 0x5c, 0x61, 0x0b, 0x14, 0x88, 0xdf, 0x3d, 0x38, 0x7a, 0xa4, 0x16, 0xa0, 0x89, 0x05, - 0xfc, 0x66, 0xd1, 0x02, 0xf2, 0xf5, 0xd3, 0xc6, 0xc1, 0xd1, 0xa3, 0x51, 0xfe, 0x9b, 0xea, 0xda, - 0x98, 0x62, 0xb1, 0x50, 0x5e, 0x42, 0x99, 0xfc, 0x48, 0xe3, 0x48, 0x69, 0xac, 0xde, 0x56, 0xe3, - 0xe8, 0x26, 0x8d, 0xa3, 0x59, 0x8d, 0xa3, 0x59, 0x8d, 0x27, 0x4a, 0x63, 0xed, 0xb6, 0x1a, 0x4f, - 0x6e, 0xd2, 0x78, 0x32, 0xab, 0x21, 0x7d, 0x78, 0x31, 0xb5, 0x2e, 0xfe, 0x8c, 0xa3, 0xc4, 0xef, - 0x85, 0x4a, 0x46, 0xbf, 0x75, 0x31, 0xcd, 0x45, 0x5a, 0xa8, 0x38, 0xb6, 0x48, 0xf6, 0x0e, 0x28, - 0x39, 0x34, 0x62, 0x09, 0xb7, 0x45, 0xb4, 0x1b, 0x10, 0x25, 0x91, 0x13, 0x12, 0x4f, 0x16, 0x49, - 0xdc, 0x97, 0x12, 0x37, 0x85, 0x5b, 0x68, 0x73, 0xd6, 0x2c, 0xc5, 0x6c, 0x60, 0x74, 0x49, 0x42, - 0x62, 0xd6, 0xea, 0xc5, 0x9e, 0x12, 0x02, 0x42, 0xe8, 0x83, 0x45, 0x42, 0xaa, 0xac, 0xe6, 0x43, - 0x2d, 0xb4, 0x31, 0x31, 0x49, 0x81, 0xcf, 0x41, 0xd1, 0xe7, 0xaa, 0xad, 0x5e, 0xa0, 0xe8, 0xf3, - 0x82, 0xfe, 0x70, 0x11, 0xbd, 0x7a, 0x14, 0x66, 0x03, 0x2d, 0xb4, 0x3e, 0x32, 0x48, 0x6a, 0x17, - 0xc0, 0xb0, 0xe7, 0xc7, 0xb6, 0x17, 0x60, 0xc7, 0x27, 0xb1, 0xa2, 0x2f, 0x08, 0xfa, 0x9f, 0x2f, - 0xa2, 0xbf, 0x27, 0xe9, 0xaf, 0x07, 0x5b, 0xc8, 0xe0, 0xc6, 0xdf, 0x4a, 0x9b, 0x54, 0x69, 0x82, - 0x42, 0x8b, 0xc4, 0x81, 0x1f, 0x29, 0xfe, 0x75, 0xc1, 0xff, 0x68, 0x11, 0xbf, 0xaa, 0xa0, 0xe9, - 0x30, 0x0b, 0xe5, 0x25, 0x1c, 0x93, 0x06, 0x34, 0x72, 0xe9, 0x88, 0xf4, 0xce, 0xad, 0x49, 0xa7, - 0xc3, 0x2c, 0x94, 0x97, 0x50, 0x92, 0x7a, 0x60, 0x13, 0xc7, 0x31, 0xfd, 0x72, 0x6e, 0x43, 0xa0, - 0xe0, 0xfe, 0xc5, 0x22, 0xee, 0xd1, 0xe5, 0x7a, 0x3d, 0x9a, 0x5f, 0xae, 0xdc, 0x3a, 0xb3, 0x25, - 0x2e, 0x80, 0x5e, 0x8c, 0x2f, 0xe6, 0x74, 0x4a, 0xb7, 0xde, 0xf8, 0xeb, 0xc1, 0x16, 0x32, 0xb8, - 0x71, 0x46, 0xe5, 0x0b, 0x50, 0x0a, 0x49, 0xec, 0x11, 0x3b, 0x22, 0x09, 0xeb, 0x06, 0x7e, 0xa2, - 0x74, 0xb6, 0x6e, 0xfd, 0x1c, 0xdc, 0x14, 0x6e, 0x21, 0x28, 0xcc, 0x2f, 0x95, 0x55, 0x6a, 0xdd, - 0x03, 0xba, 0xc3, 0xdf, 0x16, 0xb6, 0xef, 0x96, 0xcb, 0xd5, 0xcc, 0xae, 0x86, 0xd6, 0x04, 0x3e, - 0x75, 0x61, 0x09, 0xac, 0xc8, 0x0e, 0xeb, 0x1e, 0xd7, 0x45, 0x12, 0xc0, 0x0a, 0xd0, 0x5d, 0xe2, - 0xf8, 0x21, 0x0e, 0x58, 0xb9, 0x22, 0x02, 0xc6, 0x18, 0x7e, 0x0a, 0xd6, 0x59, 0x1b, 0x47, 0x5e, - 0x1b, 0xfb, 0x76, 0xe2, 0x87, 0xa4, 0x7c, 0x5f, 0x64, 0x7c, 0xb0, 0x28, 0xe3, 0x92, 0xcc, 0x78, - 0x26, 0xce, 0x42, 0x85, 0x11, 0x3e, 0xf7, 0x43, 0x02, 0x1b, 0x20, 0xef, 0xe0, 0xc8, 0xe9, 0x45, - 0x92, 0xf5, 0x81, 0x60, 0xdd, 0x5f, 0xc4, 0xaa, 0x5e, 0xc5, 0x53, 0x51, 0x16, 0x02, 0x12, 0x8d, - 0x18, 0xbb, 0x31, 0xf6, 0x7a, 0x44, 0x32, 0xbe, 0x77, 0x6b, 0xc6, 0xa9, 0x28, 0x0b, 0x01, 0x89, - 0x46, 0x8c, 0x7d, 0x12, 0x77, 0x02, 0xc5, 0xb8, 0x73, 0x6b, 0xc6, 0xa9, 0x28, 0x0b, 0x01, 0x89, - 0x04, 0xe3, 0x0b, 0x00, 0x28, 0xc3, 0x1d, 0x2c, 0x09, 0x4d, 0x41, 0xb8, 0xb7, 0x88, 0x50, 0xb5, - 0xaf, 0x93, 0x20, 0x0b, 0xe5, 0x04, 0xe0, 0x74, 0x67, 0x9a, 0xbe, 0x62, 0xac, 0x9e, 0x69, 0xfa, - 0xb6, 0x71, 0xf7, 0x4c, 0xd3, 0xef, 0x1a, 0x65, 0x6b, 0x1f, 0xac, 0xf0, 0x16, 0x8f, 0x40, 0x03, - 0x64, 0x3b, 0xe4, 0x42, 0xf6, 0x05, 0x88, 0x0f, 0xf9, 0xd9, 0xf7, 0x71, 0xd0, 0x23, 0xf2, 0x75, - 0x8e, 0x24, 0xb0, 0x1a, 0x60, 0xe3, 0x3c, 0xc6, 0x11, 0xe3, 0xed, 0x21, 0x8d, 0x9e, 0x53, 0x8f, - 0x41, 0x08, 0xb4, 0x36, 0x66, 0x6d, 0x15, 0x2b, 0xc6, 0xf0, 0xa7, 0x40, 0x0b, 0xa8, 0xc7, 0x44, - 0x63, 0x93, 0x3f, 0xdc, 0xba, 0xde, 0x45, 0x3d, 0xa7, 0x1e, 0x12, 0x2e, 0xd6, 0xdf, 0x97, 0x41, - 0xf6, 0x39, 0xf5, 0x60, 0x19, 0xac, 0x61, 0xd7, 0x8d, 0x09, 0x63, 0x8a, 0x69, 0x04, 0xe1, 0x36, - 0x58, 0x4d, 0x68, 0xd7, 0x77, 0x24, 0x5d, 0x0e, 0x29, 0xc4, 0x85, 0x5d, 0x9c, 0x60, 0xd1, 0x03, - 0x14, 0x90, 0x18, 0xf3, 0x6e, 0x5b, 0x94, 0xba, 0x1d, 0xf5, 0xc2, 0x16, 0x89, 0xc5, 0xab, 0x5c, - 0xab, 0x6d, 0x5c, 0xa6, 0x66, 0x5e, 0xd8, 0x5f, 0x0a, 0x33, 0x9a, 0x06, 0xf0, 0x7d, 0xb0, 0x96, - 0x0c, 0x6c, 0xb1, 0x86, 0x15, 0xb1, 0xc5, 0x9b, 0x97, 0xa9, 0xb9, 0x91, 0x4c, 0x96, 0xf9, 0x3b, - 0xcc, 0xda, 0x68, 0x35, 0x19, 0xf0, 0xff, 0xe1, 0x3e, 0xd0, 0x93, 0x81, 0xed, 0x47, 0x2e, 0x19, - 0x88, 0x97, 0xb8, 0x56, 0x2b, 0x5d, 0xa6, 0xa6, 0x31, 0xe5, 0x7e, 0xca, 0xe7, 0xd0, 0x5a, 0x32, - 0x10, 0x03, 0xf8, 0x3e, 0x00, 0x32, 0x25, 0xa1, 0x20, 0xdf, 0xc9, 0xeb, 0x97, 0xa9, 0x99, 0x13, - 0x56, 0xc1, 0x3d, 0x19, 0x42, 0x0b, 0xac, 0x48, 0x6e, 0x5d, 0x70, 0x17, 0x2e, 0x53, 0x53, 0x0f, - 0xa8, 0x27, 0x39, 0xe5, 0x14, 0xdf, 0xaa, 0x98, 0x84, 0xb4, 0x4f, 0x5c, 0xf1, 0x62, 0xd4, 0xd1, - 0x08, 0x5a, 0x5f, 0x2f, 0x03, 0xfd, 0x7c, 0x80, 0x08, 0xeb, 0x05, 0x09, 0xfc, 0x08, 0x18, 0xa2, - 0x57, 0xc4, 0x4e, 0x62, 0xcf, 0x6c, 0x6d, 0xed, 0xfe, 0xe4, 0x35, 0x36, 0xef, 0x61, 0xa1, 0x8d, - 0x91, 0xe9, 0x58, 0xed, 0x7f, 0x09, 0xac, 0xb4, 0x02, 0x4a, 0x43, 0x51, 0x09, 0x05, 0x24, 0x01, - 0xfc, 0x4c, 0xec, 0x9a, 0x38, 0xe5, 0xac, 0xe8, 0xc3, 0xff, 0xef, 0xfa, 0x29, 0xcf, 0x95, 0x4a, - 0xed, 0x3e, 0xef, 0xc2, 0xaf, 0x52, 0xb3, 0x28, 0xb5, 0x55, 0xbc, 0xf5, 0xed, 0x0f, 0x6f, 0x1f, - 0x66, 0xf8, 0x06, 0x8b, 0x7a, 0x32, 0x40, 0x36, 0x26, 0x89, 0x38, 0xb9, 0x02, 0xe2, 0x43, 0x7e, - 0xe1, 0xc4, 0xa4, 0x4f, 0xe2, 0x84, 0xb8, 0xea, 0x4b, 0x6b, 0x8c, 0xf9, 0xed, 0xe5, 0x61, 0x66, - 0xf7, 0x18, 0x71, 0xe5, 0x71, 0xa0, 0x35, 0x0f, 0xb3, 0x4f, 0x18, 0x71, 0x9f, 0x6a, 0x5f, 0x7d, - 0x63, 0x2e, 0x59, 0x18, 0xe4, 0x55, 0x8b, 0xde, 0xeb, 0x06, 0x64, 0x41, 0x99, 0x1d, 0x82, 0x02, - 0x4b, 0x68, 0x8c, 0x3d, 0x62, 0x77, 0xc8, 0x85, 0x2a, 0x36, 0x59, 0x3a, 0xca, 0xfe, 0x7b, 0x72, - 0xc1, 0xd0, 0x34, 0x50, 0x12, 0xdf, 0x68, 0x20, 0x7f, 0x1e, 0x63, 0x87, 0xa8, 0x86, 0x9b, 0x17, - 0x2c, 0x87, 0xb1, 0x92, 0x50, 0x88, 0x6b, 0xf3, 0x67, 0x92, 0xf6, 0x12, 0xf5, 0x50, 0x8d, 0x20, - 0x8f, 0x88, 0x09, 0x19, 0x10, 0x47, 0xec, 0xa5, 0x86, 0x14, 0x82, 0x47, 0x60, 0xdd, 0xf5, 0x19, - 0x6e, 0x05, 0xe2, 0x53, 0xcd, 0xe9, 0xc8, 0xe5, 0xd7, 0x8c, 0xcb, 0xd4, 0x2c, 0xa8, 0x89, 0x26, - 0xb7, 0xa3, 0x19, 0x04, 0x3f, 0x04, 0x1b, 0x93, 0x30, 0x91, 0xad, 0xd8, 0x1b, 0xbd, 0x06, 0x2f, - 0x53, 0xb3, 0x38, 0x76, 0x15, 0x33, 0x68, 0x0e, 0xcb, 0x4b, 0xbf, 0xd5, 0xf3, 0x44, 0x05, 0xea, - 0x48, 0x02, 0x6e, 0x0d, 0xfc, 0xd0, 0x4f, 0x44, 0xc5, 0xad, 0x20, 0x09, 0xe0, 0x87, 0x20, 0x47, - 0xfb, 0x24, 0x8e, 0x7d, 0x97, 0x30, 0xd1, 0x3b, 0xe5, 0x0f, 0xdf, 0xbb, 0x5e, 0x06, 0x53, 0x1f, - 0x23, 0x68, 0xe2, 0xcf, 0x17, 0x47, 0x22, 0x91, 0x64, 0x48, 0x42, 0x1a, 0x5f, 0x88, 0xee, 0x48, - 0x2d, 0x4e, 0x4e, 0xbc, 0x10, 0x76, 0x34, 0x83, 0x60, 0x0d, 0x40, 0x15, 0x16, 0x93, 0xa4, 0x17, - 0x47, 0xb6, 0xb8, 0x04, 0x0a, 0x22, 0x56, 0x3c, 0x8a, 0x72, 0x16, 0x89, 0xc9, 0x67, 0x38, 0xc1, - 0xe8, 0x9a, 0x05, 0xfe, 0x1a, 0x40, 0x79, 0x26, 0xf6, 0x17, 0x8c, 0x46, 0xfc, 0x93, 0xea, 0x95, - 0xef, 0xa9, 0xf6, 0x46, 0xe8, 0xcb, 0x59, 0x95, 0xb3, 0x21, 0xd1, 0x19, 0xa3, 0x6a, 0x15, 0x67, - 0x9a, 0xae, 0x19, 0x2b, 0x67, 0x9a, 0xbe, 0x66, 0xe8, 0xe3, 0xfd, 0x53, 0xab, 0x40, 0x9b, 0x23, - 0x3c, 0x95, 0x9e, 0xf5, 0x12, 0x80, 0x46, 0x4c, 0x7c, 0xde, 0x84, 0x06, 0x01, 0xbf, 0xb9, 0x22, - 0x1c, 0x92, 0xd1, 0x95, 0xc9, 0xc7, 0xd3, 0x85, 0xb9, 0x3c, 0x5b, 0x98, 0x10, 0x68, 0x0e, 0x75, - 0x89, 0x28, 0x8d, 0x1c, 0x12, 0xe3, 0x87, 0x7f, 0xcb, 0x80, 0xa9, 0x2f, 0x4f, 0xf8, 0x4b, 0x50, - 0x39, 0x3e, 0x39, 0xa9, 0x37, 0x9b, 0xf6, 0xf9, 0xe7, 0x8d, 0xba, 0xdd, 0xa8, 0xa3, 0x17, 0xa7, - 0xcd, 0xe6, 0xe9, 0xc7, 0x2f, 0x9f, 0xd7, 0x9b, 0x4d, 0x63, 0xa9, 0xf2, 0xe0, 0xf5, 0x9b, 0x6a, - 0x79, 0xe2, 0xdf, 0x20, 0x71, 0xe8, 0x33, 0xe6, 0xd3, 0x28, 0xe0, 0x02, 0x1f, 0x80, 0xed, 0xe9, - 0x68, 0x54, 0x6f, 0x9e, 0xa3, 0xd3, 0x93, 0xf3, 0xfa, 0x33, 0x23, 0x53, 0x29, 0xbf, 0x7e, 0x53, - 0x2d, 0x4d, 0x22, 0x11, 0x61, 0x49, 0xec, 0x3b, 0xfc, 0xc9, 0x7b, 0x02, 0xca, 0x37, 0x6b, 0xd6, - 0x9f, 0x19, 0xcb, 0x95, 0xca, 0xeb, 0x37, 0xd5, 0xed, 0x9b, 0x14, 0x89, 0x5b, 0xd1, 0xbe, 0xfa, - 0xeb, 0xce, 0x52, 0xed, 0xe9, 0x77, 0xc3, 0x9d, 0xcc, 0xf7, 0xc3, 0x9d, 0xcc, 0xbf, 0x87, 0x3b, - 0x99, 0xaf, 0xdf, 0xed, 0x2c, 0x7d, 0xff, 0x6e, 0x67, 0xe9, 0x1f, 0xef, 0x76, 0x96, 0xfe, 0x50, - 0xf5, 0xfc, 0xa4, 0xdd, 0x6b, 0xed, 0x39, 0x34, 0xdc, 0x9f, 0xff, 0xa5, 0x81, 0x7f, 0x53, 0xb3, - 0xd6, 0xaa, 0xf8, 0x41, 0xe8, 0xf1, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x92, 0xb6, 0x78, 0x1a, - 0x69, 0x12, 0x00, 0x00, + // 1958 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0x4f, 0x6f, 0xe3, 0xc6, + 0x15, 0xb7, 0x2c, 0xda, 0xa6, 0x46, 0xb2, 0xcc, 0x1d, 0x6b, 0xbd, 0x5a, 0x6d, 0x62, 0xaa, 0x6c, + 0x0f, 0xee, 0x22, 0xb5, 0xd7, 0xde, 0xb8, 0x35, 0x9c, 0xfe, 0x81, 0x65, 0x2b, 0xad, 0x5d, 0xef, + 0x46, 0x18, 0xb9, 0x09, 0x52, 0xb4, 0x20, 0x46, 0xe4, 0x2c, 0xc5, 0x88, 0xe4, 0x08, 0x1c, 0x4a, + 0xb5, 0x7b, 0xec, 0x29, 0xd8, 0x53, 0xfa, 0x01, 0x16, 0x08, 0xd0, 0x4b, 0x8e, 0xf9, 0x08, 0x3d, + 0x06, 0x3d, 0xe5, 0x58, 0x14, 0x28, 0x51, 0x68, 0x0f, 0x01, 0x7c, 0xf4, 0x27, 0x28, 0xe6, 0x8f, + 0xfe, 0xda, 0x51, 0x5d, 0xc0, 0xd8, 0x9d, 0xdf, 0x9b, 0xf7, 0x7e, 0xbf, 0x99, 0x37, 0x8f, 0xc3, + 0x47, 0x81, 0x8a, 0x43, 0x59, 0x48, 0xd9, 0x0e, 0xe9, 0x87, 0x3b, 0xfc, 0x6f, 0x97, 0x8f, 0xb6, + 0xbb, 0x31, 0x4d, 0x28, 0x34, 0xe4, 0xdc, 0x36, 0xb7, 0xf0, 0xbf, 0xdd, 0xca, 0x03, 0x1c, 0xfa, + 0x11, 0xdd, 0x11, 0xff, 0x4a, 0xa7, 0x4a, 0xc9, 0xa3, 0x1e, 0x15, 0xc3, 0x1d, 0x3e, 0x92, 0x56, + 0xeb, 0x2f, 0x59, 0xb0, 0xdc, 0xc0, 0x31, 0x0e, 0x19, 0xdc, 0x05, 0x39, 0xd2, 0x0f, 0x6d, 0x97, + 0x44, 0x34, 0x2c, 0x67, 0xaa, 0x99, 0xad, 0x5c, 0xad, 0x74, 0x93, 0x9a, 0xc6, 0x15, 0x0e, 0x83, + 0x43, 0x6b, 0x34, 0x65, 0x21, 0x9d, 0xf4, 0xc3, 0x13, 0x3e, 0x84, 0x47, 0x00, 0x90, 0xcb, 0x24, + 0xc6, 0x36, 0xf1, 0xbb, 0xac, 0xac, 0x55, 0xb3, 0x5b, 0xd9, 0x9a, 0x35, 0x48, 0xcd, 0x5c, 0x9d, + 0x5b, 0xeb, 0xa7, 0x0d, 0x76, 0x93, 0x9a, 0x0f, 0x14, 0xc1, 0xc8, 0xd1, 0x42, 0x39, 0x01, 0xea, + 0x7e, 0x97, 0xc1, 0x3d, 0x50, 0xe0, 0xd4, 0x4e, 0x1b, 0x47, 0x11, 0x09, 0x58, 0x79, 0xa5, 0x9a, + 0xdd, 0xca, 0xd5, 0xd6, 0x06, 0xa9, 0x99, 0xaf, 0x7f, 0xfc, 0xe2, 0x58, 0x99, 0x51, 0x9e, 0xf4, + 0xc3, 0x21, 0x80, 0x7f, 0x04, 0x45, 0xec, 0x38, 0x84, 0x31, 0xdb, 0xa1, 0x51, 0x12, 0xd3, 0xa0, + 0xac, 0x57, 0x33, 0x5b, 0xf9, 0x3d, 0x73, 0x7b, 0x36, 0x11, 0xdb, 0x47, 0xc2, 0xef, 0x58, 0xba, + 0xd5, 0x1e, 0x7e, 0x93, 0x9a, 0x0b, 0x83, 0xd4, 0x5c, 0x9d, 0x32, 0xa3, 0x55, 0x3c, 0x09, 0xe1, + 0x21, 0x78, 0x8c, 0x9d, 0xc4, 0xef, 0x13, 0x9b, 0x25, 0x38, 0xf1, 0x1d, 0xbb, 0x1b, 0x13, 0x87, + 0x86, 0x5d, 0x3f, 0x20, 0xac, 0x9c, 0xe3, 0xeb, 0x43, 0x8f, 0xa4, 0x43, 0x53, 0xcc, 0x37, 0xc6, + 0xd3, 0x87, 0x4f, 0x5e, 0x7f, 0xf7, 0xf5, 0xd3, 0x8d, 0x89, 0xb3, 0xba, 0xe4, 0xa7, 0x25, 0x33, + 0x7c, 0xa6, 0xe9, 0x8b, 0x46, 0xf6, 0x4c, 0xd3, 0xb3, 0x86, 0x76, 0xa6, 0xe9, 0x4b, 0xc6, 0xf2, + 0x99, 0xa6, 0x2f, 0x1b, 0x2b, 0xd6, 0x5f, 0x33, 0x60, 0x7a, 0x45, 0xf0, 0x08, 0x2c, 0x3b, 0x31, + 0xc1, 0x09, 0x11, 0x07, 0x91, 0xdf, 0xfb, 0xe1, 0xff, 0xd8, 0xd9, 0xc5, 0x55, 0x97, 0xd4, 0x34, + 0xbe, 0x3b, 0xa4, 0x02, 0xe1, 0x2f, 0x80, 0xe6, 0xe0, 0x20, 0x28, 0x2f, 0xfe, 0xbf, 0x04, 0x22, + 0xcc, 0xfa, 0x77, 0x06, 0x3c, 0xb8, 0xe5, 0x01, 0x1d, 0x90, 0x57, 0x99, 0x4f, 0xae, 0xba, 0x72, + 0x71, 0xc5, 0xbd, 0x77, 0xbe, 0x8f, 0x5b, 0x90, 0xfe, 0x68, 0x90, 0x9a, 0x60, 0x8c, 0x6f, 0x52, + 0x13, 0xca, 0x82, 0x98, 0x20, 0xb2, 0x10, 0xc0, 0x23, 0x0f, 0xe8, 0x80, 0xf5, 0xe9, 0xe3, 0xb5, + 0x03, 0x9f, 0x25, 0xe5, 0x45, 0x51, 0x19, 0xcf, 0x07, 0xa9, 0x39, 0xbd, 0xb0, 0x73, 0x9f, 0x25, + 0x37, 0xa9, 0x59, 0x99, 0x62, 0x9d, 0x8c, 0xb4, 0xd0, 0x03, 0x3c, 0x1b, 0x60, 0x7d, 0x65, 0x80, + 0xfc, 0x71, 0x1b, 0xfb, 0xd1, 0x31, 0x8d, 0x5e, 0xf9, 0x1e, 0xfc, 0x03, 0x58, 0x6b, 0xd3, 0x90, + 0xb0, 0x84, 0x60, 0xd7, 0x6e, 0x05, 0xd4, 0xe9, 0xa8, 0x67, 0xe0, 0xf9, 0xbf, 0x52, 0xf3, 0xa1, + 0xdc, 0x20, 0x73, 0x3b, 0xdb, 0x3e, 0xdd, 0x09, 0x71, 0xd2, 0xde, 0x3e, 0x8d, 0xb8, 0xe8, 0x86, + 0x14, 0x9d, 0x89, 0xb4, 0x50, 0x71, 0x64, 0xa9, 0x71, 0x03, 0x6c, 0x83, 0xa2, 0x8b, 0xa9, 0xfd, + 0x8a, 0xc6, 0x1d, 0x45, 0xbe, 0x28, 0xc8, 0x6b, 0xdf, 0x4b, 0x3e, 0x48, 0xcd, 0xc2, 0xc9, 0xd1, + 0x47, 0x1f, 0xd2, 0xb8, 0x23, 0x28, 0x6e, 0x52, 0xf3, 0xa1, 0x14, 0x9b, 0x26, 0xb2, 0x50, 0xc1, + 0xc5, 0x74, 0xe4, 0x06, 0x3f, 0x01, 0xc6, 0xc8, 0x81, 0xf5, 0xba, 0x5d, 0x1a, 0x27, 0xe5, 0x6c, + 0x35, 0xb3, 0xa5, 0xd7, 0x7e, 0x32, 0x48, 0xcd, 0xa2, 0xa2, 0x6c, 0xca, 0x99, 0x9b, 0xd4, 0x7c, + 0x34, 0x43, 0xaa, 0x62, 0x2c, 0x54, 0x54, 0xb4, 0xca, 0x15, 0xb6, 0x40, 0x81, 0xf8, 0xdd, 0xdd, + 0xfd, 0x67, 0x6a, 0x03, 0x9a, 0xd8, 0xc0, 0xaf, 0xe6, 0x6d, 0x20, 0x5f, 0x3f, 0x6d, 0xec, 0xee, + 0x3f, 0x1b, 0xae, 0x7f, 0x5d, 0x5d, 0x04, 0x13, 0x2c, 0x16, 0xca, 0x4b, 0x28, 0x17, 0x3f, 0xd4, + 0xd8, 0x57, 0x1a, 0xcb, 0xf7, 0xd5, 0xd8, 0xbf, 0x4b, 0x63, 0x7f, 0x5a, 0x63, 0x7f, 0x5a, 0xe3, + 0x40, 0x69, 0xac, 0xdc, 0x57, 0xe3, 0xe0, 0x2e, 0x8d, 0x83, 0x69, 0x0d, 0xe9, 0xc3, 0x8b, 0xa9, + 0x75, 0xf5, 0x67, 0x1c, 0x25, 0x7e, 0x2f, 0x54, 0x32, 0xfa, 0xbd, 0x8b, 0x69, 0x26, 0xd2, 0x42, + 0xc5, 0x91, 0x45, 0xb2, 0x77, 0x40, 0xc9, 0xa1, 0x11, 0x4b, 0xb8, 0x2d, 0xa2, 0xdd, 0x80, 0x28, + 0x89, 0x9c, 0x90, 0x38, 0x98, 0x27, 0xf1, 0x44, 0x4a, 0xdc, 0x15, 0x6e, 0xa1, 0xf5, 0x69, 0xb3, + 0x14, 0xb3, 0x81, 0xd1, 0x25, 0x09, 0x89, 0x59, 0xab, 0x17, 0x7b, 0x4a, 0x08, 0x08, 0xa1, 0xf7, + 0xe7, 0x09, 0xa9, 0xb2, 0x9a, 0x0d, 0xb5, 0xd0, 0xda, 0xd8, 0x24, 0x05, 0x3e, 0x05, 0x45, 0x9f, + 0xab, 0xb6, 0x7a, 0x81, 0xa2, 0xcf, 0x0b, 0xfa, 0xbd, 0x79, 0xf4, 0xea, 0x51, 0x98, 0x0e, 0xb4, + 0xd0, 0xea, 0xd0, 0x20, 0xa9, 0x5d, 0x00, 0xc3, 0x9e, 0x1f, 0xdb, 0x5e, 0x80, 0x1d, 0x9f, 0xc4, + 0x8a, 0xbe, 0x20, 0xe8, 0x7f, 0x3a, 0x8f, 0xfe, 0xb1, 0xa4, 0xbf, 0x1d, 0x6c, 0x21, 0x83, 0x1b, + 0x7f, 0x2d, 0x6d, 0x52, 0xa5, 0x09, 0x0a, 0x2d, 0x12, 0x07, 0x7e, 0xa4, 0xf8, 0x57, 0x05, 0xff, + 0xb3, 0x79, 0xfc, 0xaa, 0x82, 0x26, 0xc3, 0x2c, 0x94, 0x97, 0x70, 0x44, 0x1a, 0xd0, 0xc8, 0xa5, + 0x43, 0xd2, 0x07, 0xf7, 0x26, 0x9d, 0x0c, 0xb3, 0x50, 0x5e, 0x42, 0x49, 0xea, 0x81, 0x75, 0x1c, + 0xc7, 0xf4, 0x4f, 0x33, 0x09, 0x81, 0x82, 0xfb, 0x67, 0xf3, 0xb8, 0x87, 0x97, 0xeb, 0xed, 0x68, + 0x7e, 0xb9, 0x72, 0xeb, 0x54, 0x4a, 0x5c, 0x00, 0xbd, 0x18, 0x5f, 0xcd, 0xe8, 0x94, 0xee, 0x9d, + 0xf8, 0xdb, 0xc1, 0x16, 0x32, 0xb8, 0x71, 0x4a, 0xe5, 0x33, 0x50, 0x0a, 0x49, 0xec, 0x11, 0x3b, + 0x22, 0x09, 0xeb, 0x06, 0x7e, 0xa2, 0x74, 0x1e, 0xde, 0xfb, 0x39, 0xb8, 0x2b, 0xdc, 0x42, 0x50, + 0x98, 0x5f, 0x2a, 0xab, 0xd4, 0x7a, 0x0c, 0x74, 0x87, 0xbf, 0x2d, 0x6c, 0xdf, 0x2d, 0x97, 0xab, + 0x99, 0x2d, 0x0d, 0xad, 0x08, 0x7c, 0xea, 0xc2, 0x12, 0x58, 0x92, 0x3d, 0xd3, 0x63, 0xae, 0x8b, + 0x24, 0x80, 0x15, 0xa0, 0xbb, 0xc4, 0xf1, 0x43, 0x1c, 0xb0, 0x72, 0x45, 0x04, 0x8c, 0x30, 0xfc, + 0x18, 0xac, 0xb2, 0x36, 0x8e, 0xbc, 0x36, 0xf6, 0xed, 0xc4, 0x0f, 0x49, 0xf9, 0x89, 0x58, 0xf1, + 0xee, 0xbc, 0x15, 0x97, 0xe4, 0x8a, 0xa7, 0xe2, 0x2c, 0x54, 0x18, 0xe2, 0x0b, 0x3f, 0x24, 0xb0, + 0x01, 0xf2, 0x0e, 0x8e, 0x9c, 0x5e, 0x24, 0x59, 0xdf, 0x11, 0xac, 0x3b, 0xf3, 0x58, 0xd5, 0xab, + 0x78, 0x22, 0xca, 0x42, 0x40, 0xa2, 0x21, 0x63, 0x37, 0xc6, 0x5e, 0x8f, 0x48, 0xc6, 0x77, 0xef, + 0xcd, 0x38, 0x11, 0x65, 0x21, 0x20, 0xd1, 0x90, 0xb1, 0x4f, 0xe2, 0x4e, 0xa0, 0x18, 0x37, 0xef, + 0xcd, 0x38, 0x11, 0x65, 0x21, 0x20, 0x91, 0x60, 0x7c, 0x01, 0x00, 0x65, 0xb8, 0x83, 0x25, 0xa1, + 0x29, 0x08, 0xb7, 0xe7, 0x11, 0xaa, 0x86, 0x74, 0x1c, 0x64, 0xa1, 0x9c, 0x00, 0x9c, 0x6e, 0xd4, + 0x98, 0x6d, 0x18, 0x8f, 0xce, 0x34, 0xfd, 0x91, 0x51, 0xb6, 0x76, 0xc0, 0x12, 0x6f, 0xf4, 0x08, + 0x34, 0x40, 0xb6, 0x43, 0xae, 0x64, 0x5f, 0x80, 0xf8, 0x90, 0x9f, 0x7d, 0x1f, 0x07, 0x3d, 0x22, + 0x5f, 0xe7, 0x48, 0x02, 0xab, 0x01, 0xd6, 0x2e, 0x62, 0x1c, 0x31, 0xde, 0x24, 0xd2, 0xe8, 0x9c, + 0x7a, 0x0c, 0x42, 0xa0, 0xb5, 0x31, 0x6b, 0xab, 0x58, 0x31, 0x86, 0x3f, 0x06, 0x5a, 0x40, 0x3d, + 0x26, 0x1a, 0x9b, 0xfc, 0xde, 0xc3, 0xdb, 0x5d, 0xd4, 0x39, 0xf5, 0x90, 0x70, 0xb1, 0xfe, 0xb1, + 0x08, 0xb2, 0xe7, 0xd4, 0x83, 0x65, 0xb0, 0x82, 0x5d, 0x37, 0x26, 0x8c, 0x29, 0xa6, 0x21, 0x84, + 0x1b, 0x60, 0x39, 0xa1, 0x5d, 0xdf, 0x91, 0x74, 0x39, 0xa4, 0x10, 0x17, 0x76, 0x71, 0x82, 0x45, + 0x0f, 0x50, 0x40, 0x62, 0xcc, 0x7b, 0x6e, 0x51, 0xea, 0x76, 0xd4, 0x0b, 0x5b, 0x24, 0x16, 0xaf, + 0x72, 0xad, 0xb6, 0x76, 0x9d, 0x9a, 0x79, 0x61, 0x7f, 0x29, 0xcc, 0x68, 0x12, 0xc0, 0xf7, 0xc0, + 0x4a, 0x72, 0x69, 0x8b, 0x3d, 0x2c, 0x89, 0x14, 0xaf, 0x5f, 0xa7, 0xe6, 0x5a, 0x32, 0xde, 0xe6, + 0x6f, 0x30, 0x6b, 0xa3, 0xe5, 0xe4, 0x92, 0xff, 0x0f, 0x77, 0x80, 0x9e, 0x5c, 0xda, 0x7e, 0xe4, + 0x92, 0x4b, 0xf1, 0x12, 0xd7, 0x6a, 0xa5, 0xeb, 0xd4, 0x34, 0x26, 0xdc, 0x4f, 0xf9, 0x1c, 0x5a, + 0x49, 0x2e, 0xc5, 0x00, 0xbe, 0x07, 0x80, 0x5c, 0x92, 0x50, 0x90, 0xef, 0xe4, 0xd5, 0xeb, 0xd4, + 0xcc, 0x09, 0xab, 0xe0, 0x1e, 0x0f, 0xa1, 0x05, 0x96, 0x24, 0xb7, 0x2e, 0xb8, 0x0b, 0xd7, 0xa9, + 0xa9, 0x07, 0xd4, 0x93, 0x9c, 0x72, 0x8a, 0xa7, 0x2a, 0x26, 0x21, 0xed, 0x13, 0x57, 0xbc, 0x18, + 0x75, 0x34, 0x84, 0xd6, 0x17, 0x8b, 0x40, 0xbf, 0xb8, 0x44, 0x84, 0xf5, 0x82, 0x04, 0x7e, 0x08, + 0x0c, 0xd1, 0x2b, 0x62, 0x27, 0xb1, 0xa7, 0x52, 0x5b, 0x7b, 0x32, 0x7e, 0x8d, 0xcd, 0x7a, 0x58, + 0x68, 0x6d, 0x68, 0x3a, 0x52, 0xf9, 0x2f, 0x81, 0xa5, 0x56, 0x40, 0x69, 0x28, 0x2a, 0xa1, 0x80, + 0x24, 0x80, 0x9f, 0x88, 0xac, 0x89, 0x53, 0xce, 0x8a, 0x3e, 0xfc, 0x07, 0xb7, 0x4f, 0x79, 0xa6, + 0x54, 0x6a, 0x4f, 0x78, 0x17, 0x7e, 0x93, 0x9a, 0x45, 0xa9, 0xad, 0xe2, 0xad, 0xaf, 0xbe, 0xfb, + 0xfa, 0x69, 0x86, 0x27, 0x58, 0xd4, 0x93, 0x01, 0xb2, 0x31, 0x49, 0xc4, 0xc9, 0x15, 0x10, 0x1f, + 0xf2, 0x0b, 0x27, 0x26, 0x7d, 0x12, 0x27, 0xc4, 0x15, 0x27, 0xa4, 0xa3, 0x11, 0xe6, 0xb7, 0x97, + 0x87, 0x99, 0xdd, 0x63, 0xc4, 0x95, 0xc7, 0x81, 0x56, 0x3c, 0xcc, 0x7e, 0xc7, 0x88, 0x7b, 0xa8, + 0x7d, 0xfe, 0xa5, 0xb9, 0x60, 0x61, 0x90, 0x57, 0x2d, 0x7a, 0xaf, 0x1b, 0x90, 0x39, 0x65, 0xb6, + 0x07, 0x0a, 0x2c, 0xa1, 0x31, 0xf6, 0x88, 0xdd, 0x21, 0x57, 0xaa, 0xd8, 0x64, 0xe9, 0x28, 0xfb, + 0x6f, 0xc9, 0x15, 0x43, 0x93, 0x40, 0x49, 0x7c, 0xa9, 0x81, 0xfc, 0x45, 0x8c, 0x1d, 0xa2, 0x1a, + 0x6e, 0x5e, 0xb0, 0x1c, 0xc6, 0x4a, 0x42, 0x21, 0xae, 0xcd, 0x9f, 0x49, 0xda, 0x4b, 0xd4, 0x43, + 0x35, 0x84, 0x3c, 0x22, 0x26, 0xe4, 0x92, 0x38, 0x22, 0x97, 0x1a, 0x52, 0x08, 0xee, 0x83, 0x55, + 0xd7, 0x67, 0xb8, 0x15, 0x88, 0x0f, 0x36, 0xa7, 0x23, 0xb7, 0x5f, 0x33, 0xae, 0x53, 0xb3, 0xa0, + 0x26, 0x9a, 0xdc, 0x8e, 0xa6, 0x10, 0xfc, 0x00, 0xac, 0x8d, 0xc3, 0xc4, 0x6a, 0x45, 0x6e, 0xf4, + 0x1a, 0xbc, 0x4e, 0xcd, 0xe2, 0xc8, 0x55, 0xcc, 0xa0, 0x19, 0x2c, 0x2f, 0xfd, 0x56, 0xcf, 0x13, + 0x15, 0xa8, 0x23, 0x09, 0xb8, 0x35, 0xf0, 0x43, 0x3f, 0x11, 0x15, 0xb7, 0x84, 0x24, 0x80, 0x1f, + 0x80, 0x1c, 0xed, 0x93, 0x38, 0xf6, 0x5d, 0xc2, 0x44, 0xef, 0x94, 0xdf, 0x7b, 0xf7, 0x76, 0x19, + 0x4c, 0x7c, 0x8c, 0xa0, 0xb1, 0x3f, 0xdf, 0x1c, 0x89, 0xc4, 0x22, 0x43, 0x12, 0xd2, 0xf8, 0x4a, + 0x74, 0x47, 0x6a, 0x73, 0x72, 0xe2, 0x85, 0xb0, 0xa3, 0x29, 0x04, 0x6b, 0x00, 0xaa, 0xb0, 0x98, + 0x24, 0xbd, 0x38, 0xb2, 0xc5, 0x25, 0x50, 0x10, 0xb1, 0xe2, 0x51, 0x94, 0xb3, 0x48, 0x4c, 0x9e, + 0xe0, 0x04, 0xa3, 0x5b, 0x16, 0xf8, 0x4b, 0x00, 0xe5, 0x99, 0xd8, 0x9f, 0x31, 0x1a, 0xf1, 0x4f, + 0xaa, 0x57, 0xbe, 0xa7, 0xda, 0x1b, 0xa1, 0x2f, 0x67, 0xd5, 0x9a, 0x0d, 0x89, 0xce, 0x18, 0x55, + 0xbb, 0x38, 0xd3, 0x74, 0xcd, 0x58, 0x3a, 0xd3, 0xf4, 0x15, 0x43, 0x1f, 0xe5, 0x4f, 0xed, 0x02, + 0xad, 0x0f, 0xf1, 0xc4, 0xf2, 0xac, 0x97, 0x00, 0x34, 0x62, 0xe2, 0xf3, 0x26, 0x34, 0x08, 0xf8, + 0xcd, 0x15, 0xe1, 0x90, 0x0c, 0xaf, 0x4c, 0x3e, 0x9e, 0x2c, 0xcc, 0xc5, 0xe9, 0xc2, 0x84, 0x40, + 0x73, 0xa8, 0x4b, 0x44, 0x69, 0xe4, 0x90, 0x18, 0x3f, 0xfd, 0x7b, 0x06, 0x4c, 0x7c, 0x79, 0xc2, + 0x9f, 0x83, 0xca, 0xd1, 0xf1, 0x71, 0xbd, 0xd9, 0xb4, 0x2f, 0x3e, 0x6d, 0xd4, 0xed, 0x46, 0x1d, + 0xbd, 0x38, 0x6d, 0x36, 0x4f, 0x3f, 0x7a, 0x79, 0x5e, 0x6f, 0x36, 0x8d, 0x85, 0xca, 0x3b, 0xaf, + 0xdf, 0x54, 0xcb, 0x63, 0xff, 0x06, 0x89, 0x43, 0x9f, 0x31, 0x9f, 0x46, 0x01, 0x17, 0x78, 0x1f, + 0x6c, 0x4c, 0x46, 0xa3, 0x7a, 0xf3, 0x02, 0x9d, 0x1e, 0x5f, 0xd4, 0x4f, 0x8c, 0x4c, 0xa5, 0xfc, + 0xfa, 0x4d, 0xb5, 0x34, 0x8e, 0x44, 0x84, 0x25, 0xb1, 0xef, 0xf0, 0x27, 0xef, 0x00, 0x94, 0xef, + 0xd6, 0xac, 0x9f, 0x18, 0x8b, 0x95, 0xca, 0xeb, 0x37, 0xd5, 0x8d, 0xbb, 0x14, 0x89, 0x5b, 0xd1, + 0x3e, 0xff, 0xdb, 0xe6, 0x42, 0xed, 0xf0, 0x9b, 0xc1, 0x66, 0xe6, 0xdb, 0xc1, 0x66, 0xe6, 0x3f, + 0x83, 0xcd, 0xcc, 0x17, 0x6f, 0x37, 0x17, 0xbe, 0x7d, 0xbb, 0xb9, 0xf0, 0xcf, 0xb7, 0x9b, 0x0b, + 0xbf, 0xaf, 0x7a, 0x7e, 0xd2, 0xee, 0xb5, 0xb6, 0x1d, 0x1a, 0xee, 0xcc, 0xfe, 0xde, 0xc0, 0xbf, + 0xa9, 0x59, 0x6b, 0x59, 0xfc, 0xc4, 0xf3, 0xfc, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x0b, 0x36, + 0x25, 0x41, 0x3b, 0x12, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -1118,16 +1106,6 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x3a } } - if m.AllowUnprotectedTxs { - i-- - if m.AllowUnprotectedTxs { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x28 - } if len(m.ExtraEIPs) > 0 { dAtA3 := make([]byte, len(m.ExtraEIPs)*10) var j2 int @@ -2013,9 +1991,6 @@ func (m *Params) Size() (n int) { } n += 1 + sovEvm(uint64(l)) + l } - if m.AllowUnprotectedTxs { - n += 2 - } if len(m.EVMChannels) > 0 { for _, s := range m.EVMChannels { l = len(s) @@ -2503,26 +2478,6 @@ func (m *Params) Unmarshal(dAtA []byte) error { } else { return fmt.Errorf("proto: wrong wireType = %d for field ExtraEIPs", wireType) } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field AllowUnprotectedTxs", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvm - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.AllowUnprotectedTxs = bool(v != 0) case 7: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field EVMChannels", wireType) diff --git a/x/vm/types/params.go b/x/vm/types/params.go index 8cd10b4a55..fb805193c6 100644 --- a/x/vm/types/params.go +++ b/x/vm/types/params.go @@ -23,8 +23,6 @@ var ( DefaultEVMChainID = "cosmos_262144-1" // DefaultEVMDecimals is the default value for the evm denom decimal precision DefaultEVMDecimals uint64 = 18 - // DefaultAllowUnprotectedTxs rejects all unprotected txs (i.e false) - DefaultAllowUnprotectedTxs = false // DefaultStaticPrecompiles defines the default active precompiles. DefaultStaticPrecompiles []string // DefaultExtraEIPs defines the default extra EIPs to be included. @@ -47,14 +45,12 @@ var ( // NewParams creates a new Params instance func NewParams( - allowUnprotectedTxs bool, extraEIPs []int64, activeStaticPrecompiles, evmChannels []string, accessControl AccessControl, ) Params { return Params{ - AllowUnprotectedTxs: allowUnprotectedTxs, ExtraEIPs: extraEIPs, ActiveStaticPrecompiles: activeStaticPrecompiles, EVMChannels: evmChannels, @@ -67,7 +63,6 @@ func DefaultParams() Params { return Params{ EvmDenom: DefaultEVMDenom, ExtraEIPs: DefaultExtraEIPs, - AllowUnprotectedTxs: DefaultAllowUnprotectedTxs, ActiveStaticPrecompiles: DefaultStaticPrecompiles, EVMChannels: DefaultEVMChannels, AccessControl: DefaultAccessControl, @@ -98,10 +93,6 @@ func (p Params) Validate() error { return err } - if err := validateBool(p.AllowUnprotectedTxs); err != nil { - return err - } - if err := ValidatePrecompiles(p.ActiveStaticPrecompiles); err != nil { return err } @@ -180,14 +171,6 @@ func validateAllowlistAddresses(i interface{}) error { return nil } -func validateBool(i interface{}) error { - _, ok := i.(bool) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - return nil -} - func validateEIPs(i interface{}) error { eips, ok := i.([]int64) if !ok { diff --git a/x/vm/types/params_legacy.go b/x/vm/types/params_legacy.go index e221fd66b9..0a23499e00 100644 --- a/x/vm/types/params_legacy.go +++ b/x/vm/types/params_legacy.go @@ -4,12 +4,11 @@ import paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" // Parameter keys var ( - ParamStoreKeyEVMDenom = []byte("EVMDenom") - ParamStoreKeyEnableCreate = []byte("EnableCreate") - ParamStoreKeyEnableCall = []byte("EnableCall") - ParamStoreKeyExtraEIPs = []byte("EnableExtraEIPs") - ParamStoreKeyChainConfig = []byte("ChainConfig") - ParamStoreKeyAllowUnprotectedTxs = []byte("AllowUnprotectedTxs") + ParamStoreKeyEVMDenom = []byte("EVMDenom") + ParamStoreKeyEnableCreate = []byte("EnableCreate") + ParamStoreKeyEnableCall = []byte("EnableCall") + ParamStoreKeyExtraEIPs = []byte("EnableExtraEIPs") + ParamStoreKeyChainConfig = []byte("ChainConfig") ) // Deprecated: ParamKeyTable returns the parameter key table. @@ -27,6 +26,5 @@ func ParamKeyTable() paramtypes.KeyTable { func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { return paramtypes.ParamSetPairs{ paramtypes.NewParamSetPair(ParamStoreKeyExtraEIPs, &p.ExtraEIPs, validateEIPs), - paramtypes.NewParamSetPair(ParamStoreKeyAllowUnprotectedTxs, &p.AllowUnprotectedTxs, validateBool), } } diff --git a/x/vm/types/params_test.go b/x/vm/types/params_test.go index 47c10f4d8e..23e8dc0070 100644 --- a/x/vm/types/params_test.go +++ b/x/vm/types/params_test.go @@ -24,7 +24,7 @@ func TestParamsValidate(t *testing.T) { }, { name: "valid", - params: NewParams(false, extraEips, nil, nil, DefaultAccessControl), + params: NewParams(extraEips, nil, nil, DefaultAccessControl), expPass: true, }, { @@ -77,15 +77,13 @@ func TestParamsValidate(t *testing.T) { func TestParamsEIPs(t *testing.T) { extraEips := []int64{2929, 1884, 1344} - params := NewParams(false, extraEips, nil, nil, DefaultAccessControl) + params := NewParams(extraEips, nil, nil, DefaultAccessControl) actual := params.EIPs() require.Equal(t, []int{2929, 1884, 1344}, actual) } func TestParamsValidatePriv(t *testing.T) { - require.Error(t, validateBool("")) - require.NoError(t, validateBool(true)) require.Error(t, validateEIPs("")) require.NoError(t, validateEIPs([]int64{1884})) require.ErrorContains(t, validateEIPs([]int64{1884, 1884, 1885}), "duplicate EIP: 1884") From a9cb40112c9976d97036bf0e6ea3ef16867e0c93 Mon Sep 17 00:00:00 2001 From: Cordt Hanson <96965330+Cordtus@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:17:19 -0600 Subject: [PATCH 09/61] add erc20 migration guide (#485) --- docs/migrations/v0.3.0_to_v0.4.0.md | 57 ++- .../v0.4.0_erc20_precompiles_migration.md | 353 ++++++++++++++++++ 2 files changed, 399 insertions(+), 11 deletions(-) create mode 100644 docs/migrations/v0.4.0_erc20_precompiles_migration.md diff --git a/docs/migrations/v0.3.0_to_v0.4.0.md b/docs/migrations/v0.3.0_to_v0.4.0.md index d69cb1b3bf..078f93fb7c 100644 --- a/docs/migrations/v0.3.0_to_v0.4.0.md +++ b/docs/migrations/v0.3.0_to_v0.4.0.md @@ -7,6 +7,7 @@ - [ ] Bump **`cosmos/evm` to v0.4.0** and align **Cosmos SDK / IBC / CometBFT** constraints. - [ ] Rewire **keepers** and **AppModule** (imports, constructors, `RegisterServices`). - [ ] Audit and migrate **EVM & FeeMarket params** (EIP-1559 knobs, denom/decimals). +- [ ] Migrate existing **ERC20 dynamic/native precompiles** to new storage format (see Section 9). - [ ] Implement **store/params migrations** in your **UpgradeHandler**. --- @@ -135,7 +136,7 @@ Add a public method to register a listener by `txHash`: ```go // from "github.com/ethereum/go-ethereum/common")) { -func (app *MyApp) RegisterPendingTxListener(listener func(common.Hash +func (app *MyApp) RegisterPendingTxListener(listener func(common.Hash app.pendingTxListeners = append(app.pendingTxListeners, listener) } ``` @@ -174,7 +175,7 @@ func defaultOptionals() Optionals { // from addresscodec "github.com/cosmos/cosmos-sdk/codec/address"(sdk.GetConfig() // from sdk "github.com/cosmos/cosmos-sdk/types".GetBech32ValidatorAddrPrefix()), ValidatorAddrCodec: addresscodec.NewBech32Codec - // from addresscodec "github.com/cosmos/cosmos-sdk/codec/address"(sdk.GetConfig() + // from addresscodec "github.com/cosmos/cosmos-sdk/codec/address"(sdk.GetConfig() // from sdk "github.com/cosmos/cosmos-sdk/types".GetBech32ConsensusAddrPrefix()), ConsensusAddrCodec: addresscodec.NewBech32Codec } @@ -182,17 +183,17 @@ func defaultOptionals() Optionals { type Option func(*Optionals) -// from "cosmossdk.io/core/address") +// from "cosmossdk.io/core/address") // Option { return func(o *Optionals){ o.AddressCodec = c } } -func WithAddressCodec(c address.Codec +func WithAddressCodec(c address.Codec -// from "cosmossdk.io/core/address") +// from "cosmossdk.io/core/address") // Option { return func(o *Optionals){ o.ValidatorAddrCodec = c } } -func WithValidatorAddrCodec(c address.Codec +func WithValidatorAddrCodec(c address.Codec -// from "cosmossdk.io/core/address") +// from "cosmossdk.io/core/address") // Option { return func(o *Optionals){ o.ConsensusAddrCodec = c } } -func WithConsensusAddrCodec(c address.Codec +func WithConsensusAddrCodec(c address.Codec ``` ### 4.3 Update the precompile factory to accept options @@ -232,9 +233,9 @@ func WithConsensusAddrCodec(c address.Codec *(app/keepers/precompiles.go)* ```diff -- govPrecompile, err := govprecompile.NewPrecompile +- govPrecompile, err := govprecompile.NewPrecompile - // from govprecompile "github.com/cosmos/evm/precompiles/gov"(govKeeper, cdc) -+ govPrecompile, err := govprecompile.NewPrecompile ++ govPrecompile, err := govprecompile.NewPrecompile + // from govprecompile "github.com/cosmos/evm/precompiles/gov"(govKeeper, cdc, options.AddressCodec) ``` @@ -333,7 +334,41 @@ pcs := NewAvailableStaticPrecompiles(ctx, /* ... keepers ... */, opts...) --- -## 9) Verify before tagging +## 9) ERC20 Precompiles Migration + +**This is a breaking change for chains with existing ERC20 token pairs.** + +The storage mechanism for ERC20 precompiles has fundamentally changed in v0.4.0. Without proper migration, your ERC20 tokens will become inaccessible via EVM, showing zero balances and failing all operations. + +### Quick Impact Check + +Your chain needs this migration if you have: + +- IBC tokens converted to ERC20 +- Token factory tokens with ERC20 representations +- Any existing `DynamicPrecompiles` or `NativePrecompiles` in storage + +### Migration + +For full details see: [ERC20 Precompiles Migration Guide](./v0.4.0_erc20_precompiles_migration.md) + +*Thanks to Mantra team for their work on this: [MANTRA-Chain Implementation](https://github.com/MANTRA-Chain/mantrachain/pull/409)* + +### Quick Verification + +Post-upgrade, verify your migration succeeded: + +```bash +# Check ERC20 balance (should NOT be 0 if tokens existed before) +cast call $TOKEN_ADDRESS "balanceOf(address)" $USER_ADDRESS --rpc-url http://localhost:8545 + +# Verify precompiles in state +evmd export | jq '.app_state.erc20.dynamic_precompiles' +``` + +--- + +## 10) Verify before tagging - [ ] `go.mod` has **no `replace`** lines for `github.com/cosmos/evm`. - [ ] Node boots with expected **RPC namespaces**. diff --git a/docs/migrations/v0.4.0_erc20_precompiles_migration.md b/docs/migrations/v0.4.0_erc20_precompiles_migration.md new file mode 100644 index 0000000000..b200215a3a --- /dev/null +++ b/docs/migrations/v0.4.0_erc20_precompiles_migration.md @@ -0,0 +1,353 @@ +# ERC20 Precompiles Migration + +## Breaking Change in v0.4.0 + +The storage mechanism for ERC20 dynamic and native precompiles has fundamentally changed in Cosmos EVM v0.4.0. This migration is mandatory for chains with existing ERC20 token pairs. + +### Impact Assessment + +**Affected Chains:** + +- Chains with IBC tokens converted to ERC20 +- Chains using token factory with ERC20 representations +- Any chain with existing `DynamicPrecompiles` or `NativePrecompiles` in parameter storage + +**Known Issues if Not Migrated:** + +- ERC20 balances will show as 0 when queried via EVM +- `totalSupply()` calls return 0 +- Token transfers via ERC20 interface fail +- Native Cosmos balances remain intact but inaccessible via EVM + +## Migration Overview + +### Storage Changes + +**Before (v0.3.x):** + +- Precompiles stored as concatenated hex strings in parameter storage +- Keys: `"DynamicPrecompiles"` and `"NativePrecompiles"` +- Format: Multiple addresses concatenated as 42-character hex strings + +**After (v0.4.0):** + +- Dedicated prefix stores for each precompile type +- Keys: `types.KeyPrefixDynamicPrecompiles` and `types.KeyPrefixNativePrecompiles` +- Individual storage entries per address + +## Implementation Guide + +### Quick Start + +The migration can be added to your existing upgrade handler: + +```go +// In your upgrade handler +store := ctx.KVStore(storeKeys[erc20types.StoreKey]) +const addressLength = 42 // "0x" + 40 hex characters + +// Migrate dynamic precompiles (IBC tokens, token factory) +if oldData := store.Get([]byte("DynamicPrecompiles")); len(oldData) > 0 { + for i := 0; i < len(oldData); i += addressLength { + address := common.HexToAddress(string(oldData[i : i+addressLength])) + erc20Keeper.SetDynamicPrecompile(ctx, address) + } + store.Delete([]byte("DynamicPrecompiles")) +} + +// Migrate native precompiles +if oldData := store.Get([]byte("NativePrecompiles")); len(oldData) > 0 { + for i := 0; i < len(oldData); i += addressLength { + address := common.HexToAddress(string(oldData[i : i+addressLength])) + erc20Keeper.SetNativePrecompile(ctx, address) + } + store.Delete([]byte("NativePrecompiles")) +} +``` + +
+📄 Complete Example Implementation (click to expand) + +### Create Upgrade Handler + +Create a new upgrade handler: + +```go +// app/upgrades/v040/handler.go +package v040 + +import ( + "context" + + storetypes "cosmossdk.io/store/types" + upgradetypes "cosmossdk.io/x/upgrade/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + erc20keeper "github.com/cosmos/evm/x/erc20/keeper" + erc20types "github.com/cosmos/evm/x/erc20/types" + "github.com/ethereum/go-ethereum/common" +) + +const UpgradeName = "v0.4.0" + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + keepers *UpgradeKeepers, + storeKeys map[string]*storetypes.KVStoreKey, +) upgradetypes.UpgradeHandler { + return func(c context.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + ctx := sdk.UnwrapSDKContext(c) + ctx.Logger().Info("Starting v0.4.0 upgrade...") + + // Run standard module migrations + vm, err := mm.RunMigrations(ctx, configurator, vm) + if err != nil { + return vm, err + } + + // Migrate ERC20 precompiles + if err := migrateERC20Precompiles(ctx, storeKeys[erc20types.StoreKey], keepers.Erc20Keeper); err != nil { + return vm, err + } + + ctx.Logger().Info("v0.4.0 upgrade complete") + return vm, nil + } +} +``` + +### Implement Migration + +```go +// app/upgrades/v040/erc20_migration.go +package v040 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + storetypes "cosmossdk.io/store/types" + erc20keeper "github.com/cosmos/evm/x/erc20/keeper" + "github.com/ethereum/go-ethereum/common" +) + +func migrateERC20Precompiles( + ctx sdk.Context, + storeKey *storetypes.KVStoreKey, + erc20Keeper erc20keeper.Keeper, +) error { + store := ctx.KVStore(storeKey) + const addressLength = 42 // "0x" + 40 hex characters + + migrations := []struct { + oldKey string + setter func(sdk.Context, common.Address) + description string + }{ + { + oldKey: "DynamicPrecompiles", + setter: erc20Keeper.SetDynamicPrecompile, + description: "dynamic precompiles (token factory, IBC tokens)", + }, + { + oldKey: "NativePrecompiles", + setter: erc20Keeper.SetNativePrecompile, + description: "native precompiles", + }, + } + + for _, migration := range migrations { + oldData := store.Get([]byte(migration.oldKey)) + if len(oldData) == 0 { + ctx.Logger().Info("No legacy data found", "type", migration.description) + continue + } + + addressCount := len(oldData) / addressLength + ctx.Logger().Info("Migrating precompiles", + "type", migration.description, + "count", addressCount, + "data_length", len(oldData), + ) + + migratedCount := 0 + for i := 0; i < len(oldData); i += addressLength { + if i+addressLength > len(oldData) { + ctx.Logger().Error("Invalid data length", + "type", migration.description, + "position", i, + "remaining", len(oldData)-i, + ) + break + } + + addressStr := string(oldData[i : i+addressLength]) + address := common.HexToAddress(addressStr) + + // Validate address + if address == (common.Address{}) { + ctx.Logger().Warn("Skipping zero address", + "type", migration.description, + "raw", addressStr, + ) + continue + } + + // Migrate to new storage + migration.setter(ctx, address) + migratedCount++ + + ctx.Logger().Debug("Migrated precompile", + "type", migration.description, + "address", address.String(), + "index", migratedCount, + ) + } + + // Clean up old storage + store.Delete([]byte(migration.oldKey)) + ctx.Logger().Info("Migration complete", + "type", migration.description, + "migrated", migratedCount, + "expected", addressCount, + ) + } + + return nil +} +``` + +
+ +### Define Upgrade Keepers + +```go +// app/upgrades/v040/types.go +package v040 + +import ( + erc20keeper "github.com/cosmos/evm/x/erc20/keeper" + // ... other keeper imports +) + +type UpgradeKeepers struct { + Erc20Keeper erc20keeper.Keeper + // ... other keepers needed for upgrade +} +``` + +### Register Upgrade Handler + +```go +// app/app.go +import ( + v040 "github.com/yourchain/app/upgrades/v040" +) + +func (app *App) RegisterUpgradeHandlers() { + app.UpgradeKeeper.SetUpgradeHandler( + v040.UpgradeName, + v040.CreateUpgradeHandler( + app.ModuleManager, + app.configurator, + &v040.UpgradeKeepers{ + Erc20Keeper: app.Erc20Keeper, + }, + app.keys, + ), + ) +} +``` + +## Testing + +### Pre-Upgrade + +```bash +# 1. Query existing token pairs +mantrachaind query erc20 token-pairs --output json | jq + +# 2. Check ERC20 balances for a known address +cast call $TOKEN_ADDRESS "balanceOf(address)" $USER_ADDRESS --rpc-url http://localhost:8545 + +# 3. Export state for backup +mantrachaind export > pre-upgrade-state.json +``` + +### Post-Upgrade + +```bash +# 1. Verify precompiles are accessible +cast call $TOKEN_ADDRESS "totalSupply()" --rpc-url http://localhost:8545 + +# 2. Check balance restoration +cast call $TOKEN_ADDRESS "balanceOf(address)" $USER_ADDRESS --rpc-url http://localhost:8545 + +# 3. Test token transfer +cast send $TOKEN_ADDRESS "transfer(address,uint256)" $RECIPIENT 1000 \ + --private-key $PRIVATE_KEY --rpc-url http://localhost:8545 + +# 4. Verify in exported state +mantrachaind export | jq '.app_state.erc20.dynamic_precompiles' +``` + +## Integration Test Example + +```go +// tests/upgrade_test.go +package tests + +import ( + "testing" + "github.com/stretchr/testify/require" + "github.com/ethereum/go-ethereum/common" +) + +func TestERC20PrecompileMigration(t *testing.T) { + // Setup test environment + app, ctx := setupTestApp(t) + + // Create legacy storage entries + store := ctx.KVStore(app.keys[erc20types.StoreKey]) + + // Add test addresses in old format + dynamicAddresses := []string{ + "0x6eC942095eCD4948d9C094337ABd59Dc3c521005", + "0x1234567890123456789012345678901234567890", + } + dynamicData := "" + for _, addr := range dynamicAddresses { + dynamicData += addr + } + store.Set([]byte("DynamicPrecompiles"), []byte(dynamicData)) + + // Run migration + err := migrateERC20Precompiles(ctx, app.keys[erc20types.StoreKey], app.Erc20Keeper) + require.NoError(t, err) + + // Verify migration + migratedAddresses := app.Erc20Keeper.GetDynamicPrecompiles(ctx) + require.Len(t, migratedAddresses, len(dynamicAddresses)) + + for i, addr := range dynamicAddresses { + require.Equal(t, addr, migratedAddresses[i]) + } + + // Verify old storage is cleaned + oldData := store.Get([]byte("DynamicPrecompiles")) + require.Nil(t, oldData) +} +``` + +## References + +- **GitHub Issue:** [#424](https://github.com/cosmos/evm/issues/424) +- **Reference Implementation:** [MANTRA-Chain PR #409](https://github.com/MANTRA-Chain/mantrachain/pull/409) +- **Test Suite:** [MANTRA-Chain E2E Tests](https://github.com/MANTRA-Chain/mantrachain-e2e/pull/41) + +## Verification Checklist + +- [ ] Test migration on testnet first +- [ ] Document all existing token pairs +- [ ] Verify ERC20 balances post-upgrade +- [ ] Test token transfers work +- [ ] Confirm IBC token conversions function From dda0fb1bd301a8d4d5ddc1e123dda199db808772 Mon Sep 17 00:00:00 2001 From: aljo242 Date: Tue, 19 Aug 2025 17:04:01 -0400 Subject: [PATCH 10/61] add thanks --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 6f716654fb..4505ed86ac 100644 --- a/README.md +++ b/README.md @@ -197,3 +197,8 @@ We welcome open source contributions and discussions! For more on contributing, Cosmos EVM is open-source under the Apache 2.0 license, an extension of the license of the original codebase (https://github.com/evmos/OS) created by Tharsis and the evmOS team - who conducted the foundational work for EVM compatibility and interoperability in Cosmos. + +### Key Contributors + +We at ICL want to thank our key contributors at [B-Harvest](https://bharvest.io/) and +[Mantra](https://www.mantrachain.io/) for contributing to and helping us drive the development of Cosmos EVM. From aa9a8342751c3c4b87b19c1fd87cd8ab7c552684 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 20 Aug 2025 05:48:45 +0800 Subject: [PATCH 11/61] chore: replace GlobalEVMMempool by passing to JSONRPC on initiate (#467) * chore: ensure SetGlobalEVMMempool is thread-safe and only set once keep singleton behavior on concurrent initialization * doc * keep reset * pass in mempool * cleanup --------- Co-authored-by: Vlad J Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + evmd/app.go | 4 --- evmd/tests/network/util.go | 1 + mempool/registry_production.go | 33 ------------------- mempool/registry_testing.go | 28 ---------------- rpc/apis.go | 24 +++++++++----- rpc/backend/backend.go | 4 +++ rpc/backend/tx_pool.go | 9 +++-- server/json_rpc.go | 4 ++- server/start.go | 5 ++- .../rpc/backend/test_backend_suite.go | 2 +- 11 files changed, 34 insertions(+), 81 deletions(-) delete mode 100644 mempool/registry_production.go delete mode 100644 mempool/registry_testing.go diff --git a/CHANGELOG.md b/CHANGELOG.md index c4162096d2..acf3d0e9d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ - [\#398](https://github.com/cosmos/evm/pull/398) Post-audit security fixes (batch 4) - [\#442](https://github.com/cosmos/evm/pull/442) Prevent nil pointer by checking error in gov precompile FromResponse. - [\#387](https://github.com/cosmos/evm/pull/387) (Experimental) EVM-compatible appside mempool +- [\#467](https://github.com/cosmos/evm/pull/467) Ensure SetGlobalEVMMempool is thread-safe and only sets global mempool instance once. ### FEATURES diff --git a/evmd/app.go b/evmd/app.go index b255192b39..55c798a16c 100644 --- a/evmd/app.go +++ b/evmd/app.go @@ -773,10 +773,6 @@ func NewExampleApp( evmMempool := evmmempool.NewExperimentalEVMMempool(app.CreateQueryContext, logger, app.EVMKeeper, app.FeeMarketKeeper, app.txConfig, app.clientCtx, mempoolConfig) app.EVMMempool = evmMempool - // Set the global mempool for RPC access - if err := evmmempool.SetGlobalEVMMempool(evmMempool); err != nil { - panic(err) - } app.SetMempool(evmMempool) checkTxHandler := evmmempool.NewCheckTxHandler(evmMempool) app.SetCheckTxHandler(checkTxHandler) diff --git a/evmd/tests/network/util.go b/evmd/tests/network/util.go index a5a5d1184c..7d03ad1a09 100644 --- a/evmd/tests/network/util.go +++ b/evmd/tests/network/util.go @@ -138,6 +138,7 @@ func startInProcess(cfg Config, val *Validator) error { val.AppConfig, nil, app.(server.AppWithPendingTxStream), + nil, ) if err != nil { return err diff --git a/mempool/registry_production.go b/mempool/registry_production.go deleted file mode 100644 index 74b1fd8107..0000000000 --- a/mempool/registry_production.go +++ /dev/null @@ -1,33 +0,0 @@ -//go:build !test -// +build !test - -package mempool - -import "errors" - -// globalEVMMempool holds the global reference to the ExperimentalEVMMempool instance. -// It can only be set during application initialization. -var globalEVMMempool *ExperimentalEVMMempool - -// SetGlobalEVMMempool sets the global ExperimentalEVMMempool instance. -// This should only be called during application initialization. -// In production builds, it returns an error if already set. -func SetGlobalEVMMempool(mempool *ExperimentalEVMMempool) error { - if globalEVMMempool != nil { - return errors.New("global EVM mempool already set") - } - globalEVMMempool = mempool - return nil -} - -// GetGlobalEVMMempool returns the global ExperimentalEVMMempool instance. -// Returns nil if not set. -func GetGlobalEVMMempool() *ExperimentalEVMMempool { - return globalEVMMempool -} - -// ResetGlobalEVMMempool resets the global ExperimentalEVMMempool instance. -// This is intended for testing purposes only. -func ResetGlobalEVMMempool() { - globalEVMMempool = nil -} diff --git a/mempool/registry_testing.go b/mempool/registry_testing.go deleted file mode 100644 index 1713dbc0ed..0000000000 --- a/mempool/registry_testing.go +++ /dev/null @@ -1,28 +0,0 @@ -//go:build test -// +build test - -package mempool - -// globalEVMMempool holds the global reference to the ExperimentalEVMMempool instance. -// It can only be set during application initialization. -var globalEVMMempool *ExperimentalEVMMempool - -// SetGlobalEVMMempool sets the global ExperimentalEVMMempool instance. -// This should only be called during application initialization. -// In testing builds, it allows resetting by not returning an error. -func SetGlobalEVMMempool(mempool *ExperimentalEVMMempool) error { - globalEVMMempool = mempool - return nil -} - -// GetGlobalEVMMempool returns the global ExperimentalEVMMempool instance. -// Returns nil if not set. -func GetGlobalEVMMempool() *ExperimentalEVMMempool { - return globalEVMMempool -} - -// ResetGlobalEVMMempool resets the global ExperimentalEVMMempool instance. -// This is intended for testing purposes only. -func ResetGlobalEVMMempool() { - globalEVMMempool = nil -} diff --git a/rpc/apis.go b/rpc/apis.go index 408713aa9d..e969f86e57 100644 --- a/rpc/apis.go +++ b/rpc/apis.go @@ -5,6 +5,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" + evmmempool "github.com/cosmos/evm/mempool" "github.com/cosmos/evm/rpc/backend" "github.com/cosmos/evm/rpc/namespaces/ethereum/debug" "github.com/cosmos/evm/rpc/namespaces/ethereum/eth" @@ -47,6 +48,7 @@ type APICreator = func( stream *stream.RPCStream, allowUnprotectedTxs bool, indexer types.EVMTxIndexer, + mempool *evmmempool.ExperimentalEVMMempool, ) []rpc.API // apiCreators defines the JSON-RPC API namespaces. @@ -59,8 +61,9 @@ func init() { stream *stream.RPCStream, allowUnprotectedTxs bool, indexer types.EVMTxIndexer, + mempool *evmmempool.ExperimentalEVMMempool, ) []rpc.API { - evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer) + evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer, mempool) return []rpc.API{ { Namespace: EthNamespace, @@ -76,7 +79,7 @@ func init() { }, } }, - Web3Namespace: func(*server.Context, client.Context, *stream.RPCStream, bool, types.EVMTxIndexer) []rpc.API { + Web3Namespace: func(*server.Context, client.Context, *stream.RPCStream, bool, types.EVMTxIndexer, *evmmempool.ExperimentalEVMMempool) []rpc.API { return []rpc.API{ { Namespace: Web3Namespace, @@ -86,7 +89,7 @@ func init() { }, } }, - NetNamespace: func(ctx *server.Context, clientCtx client.Context, _ *stream.RPCStream, _ bool, _ types.EVMTxIndexer) []rpc.API { + NetNamespace: func(ctx *server.Context, clientCtx client.Context, _ *stream.RPCStream, _ bool, _ types.EVMTxIndexer, _ *evmmempool.ExperimentalEVMMempool) []rpc.API { return []rpc.API{ { Namespace: NetNamespace, @@ -101,8 +104,9 @@ func init() { _ *stream.RPCStream, allowUnprotectedTxs bool, indexer types.EVMTxIndexer, + mempool *evmmempool.ExperimentalEVMMempool, ) []rpc.API { - evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer) + evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer, mempool) return []rpc.API{ { Namespace: PersonalNamespace, @@ -117,8 +121,9 @@ func init() { _ *stream.RPCStream, allowUnprotectedTxs bool, indexer types.EVMTxIndexer, + mempool *evmmempool.ExperimentalEVMMempool, ) []rpc.API { - evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer) + evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer, mempool) return []rpc.API{ { Namespace: TxPoolNamespace, @@ -133,8 +138,9 @@ func init() { _ *stream.RPCStream, allowUnprotectedTxs bool, indexer types.EVMTxIndexer, + mempool *evmmempool.ExperimentalEVMMempool, ) []rpc.API { - evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer) + evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer, mempool) return []rpc.API{ { Namespace: DebugNamespace, @@ -149,8 +155,9 @@ func init() { _ *stream.RPCStream, allowUnprotectedTxs bool, indexer types.EVMTxIndexer, + mempool *evmmempool.ExperimentalEVMMempool, ) []rpc.API { - evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer) + evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, indexer, mempool) return []rpc.API{ { Namespace: MinerNamespace, @@ -170,12 +177,13 @@ func GetRPCAPIs(ctx *server.Context, allowUnprotectedTxs bool, indexer types.EVMTxIndexer, selectedAPIs []string, + mempool *evmmempool.ExperimentalEVMMempool, ) []rpc.API { var apis []rpc.API for _, ns := range selectedAPIs { if creator, ok := apiCreators[ns]; ok { - apis = append(apis, creator(ctx, clientCtx, stream, allowUnprotectedTxs, indexer)...) + apis = append(apis, creator(ctx, clientCtx, stream, allowUnprotectedTxs, indexer, mempool)...) } else { ctx.Logger.Error("invalid namespace value", "namespace", ns) } diff --git a/rpc/backend/backend.go b/rpc/backend/backend.go index 140fd5e94e..dfde900669 100644 --- a/rpc/backend/backend.go +++ b/rpc/backend/backend.go @@ -17,6 +17,7 @@ import ( tmrpcclient "github.com/cometbft/cometbft/rpc/client" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" + evmmempool "github.com/cosmos/evm/mempool" rpctypes "github.com/cosmos/evm/rpc/types" "github.com/cosmos/evm/server/config" cosmosevmtypes "github.com/cosmos/evm/types" @@ -166,6 +167,7 @@ type Backend struct { AllowUnprotectedTxs bool Indexer cosmosevmtypes.EVMTxIndexer ProcessBlocker ProcessBlocker + Mempool *evmmempool.ExperimentalEVMMempool } func (b *Backend) GetConfig() config.Config { @@ -179,6 +181,7 @@ func NewBackend( clientCtx client.Context, allowUnprotectedTxs bool, indexer cosmosevmtypes.EVMTxIndexer, + mempool *evmmempool.ExperimentalEVMMempool, ) *Backend { appConf, err := config.GetConfig(ctx.Viper) if err != nil { @@ -200,6 +203,7 @@ func NewBackend( Cfg: appConf, AllowUnprotectedTxs: allowUnprotectedTxs, Indexer: indexer, + Mempool: mempool, } b.ProcessBlocker = b.ProcessBlock return b diff --git a/rpc/backend/tx_pool.go b/rpc/backend/tx_pool.go index 4ff32566c2..d06b2afef4 100644 --- a/rpc/backend/tx_pool.go +++ b/rpc/backend/tx_pool.go @@ -9,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/cosmos/evm/mempool" "github.com/cosmos/evm/rpc/types" ) @@ -28,7 +27,7 @@ func (b *Backend) Content() (map[string]map[string]map[string]*types.RPCTransact } // Get the global mempool instance - evmMempool := mempool.GetGlobalEVMMempool() + evmMempool := b.Mempool if evmMempool == nil { return content, nil } @@ -78,7 +77,7 @@ func (b *Backend) ContentFrom(addr common.Address) (map[string]map[string]*types content := make(map[string]map[string]*types.RPCTransaction, 2) // Get the global mempool instance - evmMempool := mempool.GetGlobalEVMMempool() + evmMempool := b.Mempool if evmMempool == nil { return content, nil } @@ -121,7 +120,7 @@ func (b *Backend) Inspect() (map[string]map[string]map[string]string, error) { } // Get the global mempool instance - evmMempool := mempool.GetGlobalEVMMempool() + evmMempool := b.Mempool if evmMempool == nil { return inspect, nil } @@ -163,7 +162,7 @@ func (b *Backend) Inspect() (map[string]map[string]map[string]string, error) { // Status returns the number of pending and queued transaction in the pool. func (b *Backend) Status() (map[string]hexutil.Uint, error) { // Get the global mempool instance - evmMempool := mempool.GetGlobalEVMMempool() + evmMempool := b.Mempool if evmMempool == nil { return map[string]hexutil.Uint{ StatusPending: hexutil.Uint(0), diff --git a/server/json_rpc.go b/server/json_rpc.go index 77f90c45dd..a00a499bb7 100644 --- a/server/json_rpc.go +++ b/server/json_rpc.go @@ -14,6 +14,7 @@ import ( rpcclient "github.com/cometbft/cometbft/rpc/client" + evmmempool "github.com/cosmos/evm/mempool" "github.com/cosmos/evm/rpc" "github.com/cosmos/evm/rpc/stream" serverconfig "github.com/cosmos/evm/server/config" @@ -36,6 +37,7 @@ func StartJSONRPC( config *serverconfig.Config, indexer cosmosevmtypes.EVMTxIndexer, app AppWithPendingTxStream, + mempool *evmmempool.ExperimentalEVMMempool, ) (*http.Server, error) { logger := srvCtx.Logger.With("module", "geth") @@ -57,7 +59,7 @@ func StartJSONRPC( allowUnprotectedTxs := config.JSONRPC.AllowUnprotectedTxs rpcAPIArr := config.JSONRPC.API - apis := rpc.GetRPCAPIs(srvCtx, clientCtx, stream, allowUnprotectedTxs, indexer, rpcAPIArr) + apis := rpc.GetRPCAPIs(srvCtx, clientCtx, stream, allowUnprotectedTxs, indexer, rpcAPIArr, mempool) for _, api := range apis { if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil { diff --git a/server/start.go b/server/start.go index aa747b7047..37cf151448 100644 --- a/server/start.go +++ b/server/start.go @@ -28,6 +28,7 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/evm/indexer" + evmmempool "github.com/cosmos/evm/mempool" ethdebug "github.com/cosmos/evm/rpc/namespaces/ethereum/debug" cosmosevmserverconfig "github.com/cosmos/evm/server/config" srvflags "github.com/cosmos/evm/server/flags" @@ -48,6 +49,7 @@ import ( servercmtlog "github.com/cosmos/cosmos-sdk/server/log" "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/telemetry" + sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ) @@ -57,6 +59,7 @@ type DBOpener func(opts types.AppOptions, rootDir string, backend dbm.BackendTyp type Application interface { types.Application AppWithPendingTxStream + GetMempool() sdkmempool.ExtMempool SetClientCtx(clientCtx client.Context) } @@ -502,7 +505,7 @@ func startInProcess(svrCtx *server.Context, clientCtx client.Context, opts Start if !ok { return fmt.Errorf("json-rpc server requires AppWithPendingTxStream") } - _, err = StartJSONRPC(ctx, svrCtx, clientCtx, g, &config, idxer, txApp) + _, err = StartJSONRPC(ctx, svrCtx, clientCtx, g, &config, idxer, txApp, evmApp.GetMempool().(*evmmempool.ExperimentalEVMMempool)) if err != nil { return err } diff --git a/tests/integration/rpc/backend/test_backend_suite.go b/tests/integration/rpc/backend/test_backend_suite.go index 053bd93c87..c464d673b1 100644 --- a/tests/integration/rpc/backend/test_backend_suite.go +++ b/tests/integration/rpc/backend/test_backend_suite.go @@ -91,7 +91,7 @@ func (s *TestSuite) SetupTest() { allowUnprotectedTxs := false idxer := indexer.NewKVIndexer(dbm.NewMemDB(), ctx.Logger, clientCtx) - s.backend = rpcbackend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, idxer) + s.backend = rpcbackend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, idxer, nil) s.backend.Cfg.JSONRPC.GasCap = 0 s.backend.Cfg.JSONRPC.EVMTimeout = 0 s.backend.Cfg.JSONRPC.AllowInsecureUnlock = true From f164197bce4f2b2b69b50141019be801ebfe40d9 Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 20 Aug 2025 09:00:09 +0800 Subject: [PATCH 12/61] Problem: eip-2935 is not implemented (#407) * Problem: eip-2935 is not implemented Solution: - adapt the implementation from geth * change BLOCKHASH opcode to query contract storage * commit statedb * fix panic * temp * just emulate the contract behavior with native code * fix test * fix lint * fix lint * revert unneeded changes * fix test * revert * only set contract storage if it's deployed * fix build * add history serve window parameter * cleanup * fix lint --------- Co-authored-by: Alex | Interchain Labs Co-authored-by: Vlad J --- api/cosmos/evm/vm/v1/evm.pulsar.go | 591 ++++++++++-------- proto/cosmos/evm/vm/v1/evm.proto | 1 + tests/integration/x/vm/test_genesis.go | 2 +- .../x/vm/test_iterate_contracts.go | 2 +- tests/integration/x/vm/test_keeper.go | 3 +- .../integration/x/vm/test_state_transition.go | 53 +- testutil/integration/evm/network/abci.go | 1 + x/vm/keeper/abci.go | 2 + x/vm/keeper/keeper.go | 37 +- x/vm/keeper/state_transition.go | 20 +- x/vm/types/evm.pb.go | 285 +++++---- x/vm/types/params.go | 3 + x/vm/types/preinstall.go | 6 + 13 files changed, 554 insertions(+), 452 deletions(-) diff --git a/api/cosmos/evm/vm/v1/evm.pulsar.go b/api/cosmos/evm/vm/v1/evm.pulsar.go index f7e079e38a..9026cb946a 100644 --- a/api/cosmos/evm/vm/v1/evm.pulsar.go +++ b/api/cosmos/evm/vm/v1/evm.pulsar.go @@ -159,6 +159,7 @@ var ( fd_Params_evm_channels protoreflect.FieldDescriptor fd_Params_access_control protoreflect.FieldDescriptor fd_Params_active_static_precompiles protoreflect.FieldDescriptor + fd_Params_history_serve_window protoreflect.FieldDescriptor ) func init() { @@ -169,6 +170,7 @@ func init() { fd_Params_evm_channels = md_Params.Fields().ByName("evm_channels") fd_Params_access_control = md_Params.Fields().ByName("access_control") fd_Params_active_static_precompiles = md_Params.Fields().ByName("active_static_precompiles") + fd_Params_history_serve_window = md_Params.Fields().ByName("history_serve_window") } var _ protoreflect.Message = (*fastReflection_Params)(nil) @@ -266,6 +268,12 @@ func (x *fastReflection_Params) Range(f func(protoreflect.FieldDescriptor, proto return } } + if x.HistoryServeWindow != uint64(0) { + value := protoreflect.ValueOfUint64(x.HistoryServeWindow) + if !f(fd_Params_history_serve_window, value) { + return + } + } } // Has reports whether a field is populated. @@ -291,6 +299,8 @@ func (x *fastReflection_Params) Has(fd protoreflect.FieldDescriptor) bool { return x.AccessControl != nil case "cosmos.evm.vm.v1.Params.active_static_precompiles": return len(x.ActiveStaticPrecompiles) != 0 + case "cosmos.evm.vm.v1.Params.history_serve_window": + return x.HistoryServeWindow != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Params")) @@ -317,6 +327,8 @@ func (x *fastReflection_Params) Clear(fd protoreflect.FieldDescriptor) { x.AccessControl = nil case "cosmos.evm.vm.v1.Params.active_static_precompiles": x.ActiveStaticPrecompiles = nil + case "cosmos.evm.vm.v1.Params.history_serve_window": + x.HistoryServeWindow = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Params")) @@ -357,6 +369,9 @@ func (x *fastReflection_Params) Get(descriptor protoreflect.FieldDescriptor) pro } listValue := &_Params_9_list{list: &x.ActiveStaticPrecompiles} return protoreflect.ValueOfList(listValue) + case "cosmos.evm.vm.v1.Params.history_serve_window": + value := x.HistoryServeWindow + return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Params")) @@ -393,6 +408,8 @@ func (x *fastReflection_Params) Set(fd protoreflect.FieldDescriptor, value proto lv := value.List() clv := lv.(*_Params_9_list) x.ActiveStaticPrecompiles = *clv.list + case "cosmos.evm.vm.v1.Params.history_serve_window": + x.HistoryServeWindow = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Params")) @@ -438,6 +455,8 @@ func (x *fastReflection_Params) Mutable(fd protoreflect.FieldDescriptor) protore return protoreflect.ValueOfList(value) case "cosmos.evm.vm.v1.Params.evm_denom": panic(fmt.Errorf("field evm_denom of message cosmos.evm.vm.v1.Params is not mutable")) + case "cosmos.evm.vm.v1.Params.history_serve_window": + panic(fmt.Errorf("field history_serve_window of message cosmos.evm.vm.v1.Params is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Params")) @@ -465,6 +484,8 @@ func (x *fastReflection_Params) NewField(fd protoreflect.FieldDescriptor) protor case "cosmos.evm.vm.v1.Params.active_static_precompiles": list := []string{} return protoreflect.ValueOfList(&_Params_9_list{list: &list}) + case "cosmos.evm.vm.v1.Params.history_serve_window": + return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Params")) @@ -561,6 +582,9 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { n += 1 + l + runtime.Sov(uint64(l)) } } + if x.HistoryServeWindow != 0 { + n += 1 + runtime.Sov(uint64(x.HistoryServeWindow)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -590,6 +614,11 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.HistoryServeWindow != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.HistoryServeWindow)) + i-- + dAtA[i] = 0x50 + } if len(x.ActiveStaticPrecompiles) > 0 { for iNdEx := len(x.ActiveStaticPrecompiles) - 1; iNdEx >= 0; iNdEx-- { i -= len(x.ActiveStaticPrecompiles[iNdEx]) @@ -907,6 +936,25 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { } x.ActiveStaticPrecompiles = append(x.ActiveStaticPrecompiles, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 10: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field HistoryServeWindow", wireType) + } + x.HistoryServeWindow = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.HistoryServeWindow |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -8738,6 +8786,7 @@ type Params struct { // active_static_precompiles defines the slice of hex addresses of the // precompiled contracts that are active ActiveStaticPrecompiles []string `protobuf:"bytes,9,rep,name=active_static_precompiles,json=activeStaticPrecompiles,proto3" json:"active_static_precompiles,omitempty"` + HistoryServeWindow uint64 `protobuf:"varint,10,opt,name=history_serve_window,json=historyServeWindow,proto3" json:"history_serve_window,omitempty"` } func (x *Params) Reset() { @@ -8795,6 +8844,13 @@ func (x *Params) GetActiveStaticPrecompiles() []string { return nil } +func (x *Params) GetHistoryServeWindow() uint64 { + if x != nil { + return x.HistoryServeWindow + } + return 0 +} + // AccessControl defines the permission policy of the EVM // for creating and calling contracts type AccessControl struct { @@ -9682,7 +9738,7 @@ var file_cosmos_evm_vm_v1_evm_proto_rawDesc = []byte{ 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, - 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x82, 0x03, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, + 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb4, 0x03, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x31, 0x0a, 0x09, 0x65, 0x76, 0x6d, 0x5f, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x14, 0xf2, 0xde, 0x1f, 0x10, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, 0x76, 0x6d, 0x5f, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x22, 0x52, 0x08, 0x65, 0x76, 0x6d, @@ -9703,279 +9759,282 @@ var file_cosmos_evm_vm_v1_evm_proto_rawDesc = []byte{ 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x50, 0x72, 0x65, 0x63, - 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x73, 0x3a, 0x1b, 0x8a, 0xe7, 0xb0, 0x2a, 0x16, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x78, 0x2f, 0x76, 0x6d, 0x2f, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, - 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0x91, 0x01, 0x0a, - 0x0d, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x41, - 0x0a, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, - 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x54, - 0x79, 0x70, 0x65, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x63, 0x61, 0x6c, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x54, 0x79, 0x70, 0x65, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x04, 0x63, 0x61, 0x6c, 0x6c, - 0x22, 0xdd, 0x01, 0x0a, 0x11, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x63, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x42, 0x24, 0xe2, 0xde, 0x1f, 0x0a, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, - 0x6c, 0x3a, 0x22, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x52, - 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x63, 0x0a, 0x13, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x6c, 0x69, - 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x33, 0xe2, 0xde, 0x1f, 0x11, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, 0x73, 0x74, 0xf2, - 0xde, 0x1f, 0x1a, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x52, 0x11, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, 0x73, 0x74, - 0x22, 0xa8, 0x10, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x12, 0x5c, 0x0a, 0x0f, 0x68, 0x6f, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xda, 0xde, 0x1f, 0x15, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, - 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x16, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x68, 0x6f, - 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0e, - 0x68, 0x6f, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x68, - 0x0a, 0x0e, 0x64, 0x61, 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x42, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, - 0x74, 0xe2, 0xde, 0x1f, 0x0c, 0x44, 0x41, 0x4f, 0x46, 0x6f, 0x72, 0x6b, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0xf2, 0xde, 0x1f, 0x15, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x64, 0x61, 0x6f, 0x5f, 0x66, - 0x6f, 0x72, 0x6b, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0c, 0x64, 0x61, 0x6f, 0x46, - 0x6f, 0x72, 0x6b, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x57, 0x0a, 0x10, 0x64, 0x61, 0x6f, 0x5f, - 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x08, 0x42, 0x2d, 0xe2, 0xde, 0x1f, 0x0e, 0x44, 0x41, 0x4f, 0x46, 0x6f, 0x72, 0x6b, 0x53, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0xf2, 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, - 0x64, 0x61, 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, - 0x22, 0x52, 0x0e, 0x64, 0x61, 0x6f, 0x46, 0x6f, 0x72, 0x6b, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, - 0x74, 0x12, 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, 0x31, 0x35, 0x30, 0x5f, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, - 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, 0x50, 0x31, 0x35, 0x30, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, 0x69, 0x70, 0x31, 0x35, - 0x30, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x65, 0x69, 0x70, 0x31, 0x35, 0x30, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, 0x31, 0x35, 0x35, 0x5f, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3f, 0xda, 0xde, 0x1f, + 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x69, 0x73, 0x74, 0x6f, + 0x72, 0x79, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x3a, 0x1b, 0x8a, 0xe7, 0xb0, 0x2a, 0x16, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x78, 0x2f, 0x76, 0x6d, 0x2f, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, + 0x10, 0x04, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0x91, + 0x01, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x12, 0x41, 0x0a, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x54, 0x79, 0x70, 0x65, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x06, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x63, 0x61, 0x6c, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x04, 0x63, 0x61, + 0x6c, 0x6c, 0x22, 0xdd, 0x01, 0x0a, 0x11, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x63, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x42, 0x24, 0xe2, 0xde, 0x1f, + 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0xf2, 0xde, 0x1f, 0x12, 0x79, + 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x63, 0x0a, + 0x13, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, + 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x33, 0xe2, 0xde, 0x1f, 0x11, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, 0x73, + 0x74, 0xf2, 0xde, 0x1f, 0x1a, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x52, + 0x11, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4c, 0x69, + 0x73, 0x74, 0x22, 0xa8, 0x10, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x5c, 0x0a, 0x0f, 0x68, 0x6f, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x5f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, - 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, 0x50, 0x31, 0x35, 0x35, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, - 0x69, 0x70, 0x31, 0x35, 0x35, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x65, 0x69, - 0x70, 0x31, 0x35, 0x35, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, - 0x31, 0x35, 0x38, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x3f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, - 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, - 0x50, 0x31, 0x35, 0x38, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, - 0x6c, 0x3a, 0x22, 0x65, 0x69, 0x70, 0x31, 0x35, 0x38, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, - 0x52, 0x0b, 0x65, 0x69, 0x70, 0x31, 0x35, 0x38, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x5c, 0x0a, - 0x0f, 0x62, 0x79, 0x7a, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, - 0x74, 0xf2, 0xde, 0x1f, 0x16, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x62, 0x79, 0x7a, 0x61, 0x6e, - 0x74, 0x69, 0x75, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0e, 0x62, 0x79, 0x7a, - 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x6b, 0x0a, 0x14, 0x63, - 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x65, 0x5f, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x38, 0xda, 0xde, 0x1f, 0x15, 0x63, + 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x16, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, + 0x68, 0x6f, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, + 0x52, 0x0e, 0x68, 0x6f, 0x6d, 0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x12, 0x68, 0x0a, 0x0e, 0x64, 0x61, 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x42, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, + 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0c, 0x44, 0x41, 0x4f, 0x46, 0x6f, 0x72, 0x6b, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0xf2, 0xde, 0x1f, 0x15, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x64, 0x61, 0x6f, + 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0c, 0x64, 0x61, + 0x6f, 0x46, 0x6f, 0x72, 0x6b, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x57, 0x0a, 0x10, 0x64, 0x61, + 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x42, 0x2d, 0xe2, 0xde, 0x1f, 0x0e, 0x44, 0x41, 0x4f, 0x46, 0x6f, 0x72, + 0x6b, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0xf2, 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, + 0x3a, 0x22, 0x64, 0x61, 0x6f, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x22, 0x52, 0x0e, 0x64, 0x61, 0x6f, 0x46, 0x6f, 0x72, 0x6b, 0x53, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x12, 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, 0x31, 0x35, 0x30, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, - 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x1b, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x6f, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x65, 0x5f, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x22, 0x52, 0x13, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, - 0x70, 0x6c, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x5f, 0x0a, 0x10, 0x70, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x34, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, + 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, 0x50, 0x31, 0x35, 0x30, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, 0x69, 0x70, + 0x31, 0x35, 0x30, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x65, 0x69, 0x70, 0x31, + 0x35, 0x30, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x0c, 0x65, 0x69, 0x70, 0x31, 0x35, + 0x35, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3f, 0xda, + 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, + 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, 0x45, 0x49, 0x50, 0x31, + 0x35, 0x35, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, + 0x22, 0x65, 0x69, 0x70, 0x31, 0x35, 0x35, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, + 0x65, 0x69, 0x70, 0x31, 0x35, 0x35, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x0c, 0x65, + 0x69, 0x70, 0x31, 0x35, 0x38, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x3f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, + 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xe2, 0xde, 0x1f, 0x0b, + 0x45, 0x49, 0x50, 0x31, 0x35, 0x38, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0xf2, 0xde, 0x1f, 0x13, 0x79, + 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x65, 0x69, 0x70, 0x31, 0x35, 0x38, 0x5f, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x22, 0x52, 0x0b, 0x65, 0x69, 0x70, 0x31, 0x35, 0x38, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, + 0x5c, 0x0a, 0x0f, 0x62, 0x79, 0x7a, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, + 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x16, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x62, 0x79, 0x7a, + 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0e, 0x62, + 0x79, 0x7a, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x6b, 0x0a, + 0x14, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x65, 0x5f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x38, 0xda, 0xde, 0x1f, + 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, + 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x1b, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, + 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x70, 0x6c, 0x65, 0x5f, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x13, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, + 0x6e, 0x6f, 0x70, 0x6c, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x5f, 0x0a, 0x10, 0x70, 0x65, + 0x74, 0x65, 0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x34, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, + 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x70, 0x65, 0x74, 0x65, 0x72, 0x73, 0x62, + 0x75, 0x72, 0x67, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0f, 0x70, 0x65, 0x74, 0x65, + 0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x59, 0x0a, 0x0e, 0x69, + 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x32, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, + 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, + 0x1f, 0x15, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, + 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0d, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, + 0x6c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x64, 0x0a, 0x12, 0x6d, 0x75, 0x69, 0x72, 0x5f, 0x67, + 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x36, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, - 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x70, 0x65, 0x74, 0x65, 0x72, 0x73, 0x62, 0x75, 0x72, - 0x67, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0f, 0x70, 0x65, 0x74, 0x65, 0x72, 0x73, - 0x62, 0x75, 0x72, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x59, 0x0a, 0x0e, 0x69, 0x73, 0x74, - 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x32, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, - 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x15, - 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x5f, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0d, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x64, 0x0a, 0x12, 0x6d, 0x75, 0x69, 0x72, 0x5f, 0x67, 0x6c, 0x61, - 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x36, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, - 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x19, 0x79, - 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6d, 0x75, 0x69, 0x72, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, - 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x10, 0x6d, 0x75, 0x69, 0x72, 0x47, 0x6c, - 0x61, 0x63, 0x69, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x53, 0x0a, 0x0c, 0x62, 0x65, - 0x72, 0x6c, 0x69, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x30, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, - 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x13, 0x79, - 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x62, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x22, 0x52, 0x0b, 0x62, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, - 0x53, 0x0a, 0x0c, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, - 0x11, 0x20, 0x01, 0x28, 0x09, 0x42, 0x30, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, - 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, - 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x67, 0x0a, 0x13, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x5f, 0x67, 0x6c, - 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x12, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x37, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, - 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x1a, - 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x5f, 0x67, 0x6c, 0x61, 0x63, - 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x11, 0x61, 0x72, 0x72, 0x6f, - 0x77, 0x47, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x64, 0x0a, - 0x12, 0x67, 0x72, 0x61, 0x79, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x42, 0x36, 0xda, 0xde, 0x1f, 0x15, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, - 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x19, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x67, 0x72, - 0x61, 0x79, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x22, 0x52, 0x10, 0x67, 0x72, 0x61, 0x79, 0x47, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x12, 0x6a, 0x0a, 0x14, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x6e, 0x65, 0x74, - 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x15, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x38, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, - 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x1b, - 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x6e, 0x65, 0x74, 0x73, - 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x12, 0x6d, 0x65, 0x72, - 0x67, 0x65, 0x4e, 0x65, 0x74, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, - 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, - 0x6e, 0x6f, 0x6d, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x65, 0x6e, 0x6f, 0x6d, - 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x18, 0x1a, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x12, 0x56, 0x0a, 0x0d, - 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1b, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x31, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, + 0x19, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6d, 0x75, 0x69, 0x72, 0x5f, 0x67, 0x6c, 0x61, 0x63, + 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x10, 0x6d, 0x75, 0x69, 0x72, + 0x47, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x53, 0x0a, 0x0c, + 0x62, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x30, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, + 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, + 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x62, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x62, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x12, 0x53, 0x0a, 0x0c, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x42, 0x30, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, + 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x13, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6c, 0x6f, 0x6e, 0x64, + 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x0b, 0x6c, 0x6f, 0x6e, 0x64, 0x6f, + 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x67, 0x0a, 0x13, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x5f, + 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x12, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x37, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, - 0x1f, 0x14, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, - 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x63, 0x75, 0x6e, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, 0xde, 0x1f, 0x15, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, - 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x61, - 0x6e, 0x63, 0x75, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x63, - 0x75, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x70, 0x72, 0x61, 0x67, 0x75, 0x65, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, 0xde, 0x1f, + 0x1f, 0x1a, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x5f, 0x67, 0x6c, + 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x11, 0x61, 0x72, + 0x72, 0x6f, 0x77, 0x47, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, + 0x64, 0x0a, 0x12, 0x67, 0x72, 0x61, 0x79, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x42, 0x36, 0xda, 0xde, 0x1f, + 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, + 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x19, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, + 0x67, 0x72, 0x61, 0x79, 0x5f, 0x67, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x22, 0x52, 0x10, 0x67, 0x72, 0x61, 0x79, 0x47, 0x6c, 0x61, 0x63, 0x69, 0x65, 0x72, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x6a, 0x0a, 0x14, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x6e, + 0x65, 0x74, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x15, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x38, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, + 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, + 0x1f, 0x1b, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x6e, 0x65, + 0x74, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x52, 0x12, 0x6d, + 0x65, 0x72, 0x67, 0x65, 0x4e, 0x65, 0x74, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x18, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x65, 0x6e, + 0x6f, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x18, 0x1a, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x73, 0x12, 0x56, + 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x1b, 0x20, 0x01, 0x28, 0x09, 0x42, 0x31, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, + 0xf2, 0xde, 0x1f, 0x14, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, + 0x61, 0x69, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x6e, 0x67, 0x68, + 0x61, 0x69, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x63, 0x75, 0x6e, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, - 0x70, 0x72, 0x61, 0x67, 0x75, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x70, 0x72, - 0x61, 0x67, 0x75, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x6b, - 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, + 0x63, 0x61, 0x6e, 0x63, 0x75, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x63, 0x61, + 0x6e, 0x63, 0x75, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x70, 0x72, 0x61, 0x67, + 0x75, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, 0x6c, - 0x3a, 0x22, 0x76, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, - 0x76, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x6f, 0x73, - 0x61, 0x6b, 0x61, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2e, - 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, - 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x11, 0x79, 0x61, 0x6d, - 0x6c, 0x3a, 0x22, 0x6f, 0x73, 0x61, 0x6b, 0x61, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x09, - 0x6f, 0x73, 0x61, 0x6b, 0x61, 0x54, 0x69, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, - 0x04, 0x08, 0x16, 0x10, 0x17, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x22, 0x2f, 0x0a, 0x05, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x50, 0x0a, 0x0f, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x73, 0x12, - 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, - 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x22, 0xca, - 0x02, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x0c, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x04, 0x42, 0x0f, 0xea, 0xde, 0x1f, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x12, 0x2c, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x13, 0xea, 0xde, 0x1f, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2f, - 0x0a, 0x08, 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, - 0x42, 0x14, 0xea, 0xde, 0x1f, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x07, 0x74, 0x78, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, - 0x2c, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x0d, 0xea, 0xde, 0x1f, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, - 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0c, 0xea, 0xde, - 0x1f, 0x08, 0x6c, 0x6f, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x90, 0x02, 0x0a, 0x08, - 0x54, 0x78, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x1b, 0xf2, 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x52, - 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x05, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x12, 0x57, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x6c, 0x6f, 0x67, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x73, 0x42, 0x1b, 0xc8, 0xde, 0x1f, 0x00, - 0xf2, 0xde, 0x1f, 0x0e, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x74, 0x78, 0x5f, 0x6c, 0x6f, 0x67, - 0x73, 0x22, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x74, 0x78, 0x4c, 0x6f, 0x67, 0x73, 0x12, - 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x65, - 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x12, 0x19, 0x0a, - 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, 0x61, - 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0f, 0xea, - 0xde, 0x1f, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x0b, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x3a, 0x04, 0x88, 0xa0, 0x1f, - 0x00, 0x22, 0xa0, 0x04, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, - 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x12, 0x35, 0x0a, 0x0d, 0x64, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, - 0x74, 0x61, 0x63, 0x6b, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x61, - 0x63, 0x6b, 0x12, 0x3b, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x42, 0x12, 0xea, 0xde, 0x1f, - 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, - 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, - 0x64, 0x65, 0x62, 0x75, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x3b, 0x0a, 0x09, 0x6f, - 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x6f, - 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x42, - 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, - 0x42, 0x0a, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, - 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x42, 0x14, 0xea, 0xde, 0x1f, - 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, 0x61, 0x74, - 0x61, 0x52, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, - 0x61, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x5f, 0x6a, 0x73, - 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x10, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x4a, 0x73, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x52, - 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x52, - 0x13, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, - 0x64, 0x61, 0x74, 0x61, 0x22, 0x4e, 0x0a, 0x0a, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x63, 0x6f, 0x64, 0x65, 0x2a, 0xc0, 0x01, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x1a, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x4c, 0x45, 0x53, - 0x53, 0x10, 0x00, 0x1a, 0x1c, 0x8a, 0x9d, 0x20, 0x18, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, - 0x79, 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x6c, 0x65, 0x73, - 0x73, 0x12, 0x34, 0x0a, 0x16, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x01, 0x1a, 0x18, 0x8a, - 0x9d, 0x20, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, - 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x41, 0x43, 0x43, 0x45, 0x53, - 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, - 0x4e, 0x45, 0x44, 0x10, 0x02, 0x1a, 0x1a, 0x8a, 0x9d, 0x20, 0x16, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x79, 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x64, 0x1a, 0x04, 0x88, 0xa3, 0x1e, 0x00, 0x42, 0xab, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, - 0x42, 0x08, 0x45, 0x76, 0x6d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x3b, - 0x76, 0x6d, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x56, 0xaa, 0x02, 0x10, 0x43, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x56, 0x6d, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, - 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, 0x56, 0x31, - 0xe2, 0x02, 0x1c, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, - 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, - 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x56, - 0x6d, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x3a, 0x22, 0x70, 0x72, 0x61, 0x67, 0x75, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x52, 0x0a, + 0x70, 0x72, 0x61, 0x67, 0x75, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x76, 0x65, + 0x72, 0x6b, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x2f, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, + 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, + 0x6d, 0x6c, 0x3a, 0x22, 0x76, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, + 0x52, 0x0a, 0x76, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x0a, + 0x6f, 0x73, 0x61, 0x6b, 0x61, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x2e, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, + 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xf2, 0xde, 0x1f, 0x11, 0x79, + 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6f, 0x73, 0x61, 0x6b, 0x61, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, + 0x52, 0x09, 0x6f, 0x73, 0x61, 0x6b, 0x61, 0x54, 0x69, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x05, 0x10, + 0x06, 0x4a, 0x04, 0x08, 0x16, 0x10, 0x17, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x22, 0x2f, 0x0a, + 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x50, + 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, + 0x73, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, + 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, + 0x22, 0xca, 0x02, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x32, + 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x04, 0x42, 0x0f, 0xea, 0xde, 0x1f, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x13, 0xea, 0xde, 0x1f, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, + 0x12, 0x2f, 0x0a, 0x08, 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x04, 0x42, 0x14, 0xea, 0xde, 0x1f, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x07, 0x74, 0x78, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x12, 0x2c, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0d, 0xea, 0xde, 0x1f, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x22, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0c, + 0xea, 0xde, 0x1f, 0x08, 0x6c, 0x6f, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x05, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x90, 0x02, + 0x0a, 0x08, 0x54, 0x78, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x46, 0x0a, 0x10, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x1b, 0xf2, 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x22, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x12, 0x57, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x6c, + 0x6f, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x73, 0x42, 0x1b, 0xc8, 0xde, + 0x1f, 0x00, 0xf2, 0xde, 0x1f, 0x0e, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x74, 0x78, 0x5f, 0x6c, + 0x6f, 0x67, 0x73, 0x22, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x74, 0x78, 0x4c, 0x6f, 0x67, + 0x73, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, + 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x12, + 0x19, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, + 0x22, 0x61, 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x0c, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, + 0x0f, 0xea, 0xde, 0x1f, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, + 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x3a, 0x04, 0x88, + 0xa0, 0x1f, 0x00, 0x22, 0xa0, 0x04, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x74, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x12, 0x35, 0x0a, + 0x0d, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x08, 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x12, 0x3b, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x42, 0x12, 0xea, + 0xde, 0x1f, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x3b, 0x0a, + 0x09, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x09, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x0d, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x08, 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, + 0x79, 0x12, 0x42, 0x0a, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x42, 0x14, 0xea, + 0xde, 0x1f, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x5f, + 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x10, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x4a, 0x73, 0x6f, 0x6e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x07, 0x10, + 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, + 0x79, 0x52, 0x13, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x22, 0x4e, 0x0a, 0x0a, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6c, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x2a, 0xc0, 0x01, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x1a, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x4c, + 0x45, 0x53, 0x53, 0x10, 0x00, 0x1a, 0x1c, 0x8a, 0x9d, 0x20, 0x18, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x54, 0x79, 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x6c, + 0x65, 0x73, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x01, 0x1a, + 0x18, 0x8a, 0x9d, 0x20, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x41, 0x43, 0x43, + 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, + 0x49, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x02, 0x1a, 0x1a, 0x8a, 0x9d, 0x20, 0x16, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x64, 0x1a, 0x04, 0x88, 0xa3, 0x1e, 0x00, 0x42, 0xab, 0x01, 0x0a, 0x14, 0x63, 0x6f, + 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, + 0x76, 0x31, 0x42, 0x08, 0x45, 0x76, 0x6d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, + 0x31, 0x3b, 0x76, 0x6d, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x56, 0xaa, 0x02, 0x10, 0x43, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x56, 0x6d, 0x2e, 0x56, 0x31, 0xca, + 0x02, 0x10, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, + 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, + 0x56, 0x6d, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0xea, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, + 0x3a, 0x56, 0x6d, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/cosmos/evm/vm/v1/evm.proto b/proto/cosmos/evm/vm/v1/evm.proto index e338c493bb..71636d4bc1 100644 --- a/proto/cosmos/evm/vm/v1/evm.proto +++ b/proto/cosmos/evm/vm/v1/evm.proto @@ -35,6 +35,7 @@ message Params { // active_static_precompiles defines the slice of hex addresses of the // precompiled contracts that are active repeated string active_static_precompiles = 9; + uint64 history_serve_window = 10; } // AccessControl defines the permission policy of the EVM diff --git a/tests/integration/x/vm/test_genesis.go b/tests/integration/x/vm/test_genesis.go index de241713b8..a927310cf0 100644 --- a/tests/integration/x/vm/test_genesis.go +++ b/tests/integration/x/vm/test_genesis.go @@ -222,7 +222,7 @@ func (s *GenesisTestSuite) TestExportGenesis() { genState := vm.ExportGenesis(s.network.GetContext(), s.network.App.GetEVMKeeper()) // Exported accounts 4 default preinstalls - s.Require().Len(genState.Accounts, 7) + s.Require().Len(genState.Accounts, 8) addrs := make([]string, len(genState.Accounts)) for i, acct := range genState.Accounts { diff --git a/tests/integration/x/vm/test_iterate_contracts.go b/tests/integration/x/vm/test_iterate_contracts.go index 66f2659d29..3c6cd54970 100644 --- a/tests/integration/x/vm/test_iterate_contracts.go +++ b/tests/integration/x/vm/test_iterate_contracts.go @@ -67,7 +67,7 @@ func TestIterateContracts(t *testing.T, create network.CreateEvmApp, options ... return false }) - require.Len(t, foundAddrs, 6, "expected 6 contracts to be found when iterating (4 preinstalled + 2 deployed)") + require.Len(t, foundAddrs, 7, "expected 7 contracts to be found when iterating (5 preinstalled + 2 deployed)") require.Contains(t, foundAddrs, contractAddr, "expected contract 1 to be found when iterating") require.Contains(t, foundAddrs, contractAddr2, "expected contract 2 to be found when iterating") diff --git a/tests/integration/x/vm/test_keeper.go b/tests/integration/x/vm/test_keeper.go index c31b3bb7f1..8e5d0b4468 100644 --- a/tests/integration/x/vm/test_keeper.go +++ b/tests/integration/x/vm/test_keeper.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + ethparams "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" "github.com/cosmos/evm/utils" @@ -89,7 +90,7 @@ func (s *KeeperTestSuite) TestGetAccountStorage() { storage := s.Network.App.GetEVMKeeper().GetAccountStorage(ctx, address) - if address == contractAddr { + if address == contractAddr || address == ethparams.HistoryStorageAddress { s.Require().NotEqual(0, len(storage), "expected account %d to have non-zero amount of storage slots, got %d", i, len(storage), diff --git a/tests/integration/x/vm/test_state_transition.go b/tests/integration/x/vm/test_state_transition.go index 633ec4ae59..84d34a146c 100644 --- a/tests/integration/x/vm/test_state_transition.go +++ b/tests/integration/x/vm/test_state_transition.go @@ -12,7 +12,6 @@ import ( "github.com/cometbft/cometbft/crypto/tmhash" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - cmttypes "github.com/cometbft/cometbft/types" "github.com/cosmos/evm/testutil/config" "github.com/cosmos/evm/testutil/integration/evm/factory" @@ -33,7 +32,6 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) func (s *KeeperTestSuite) TestContextSetConsensusParams() { @@ -81,9 +79,11 @@ func (s *KeeperTestSuite) TestContextSetConsensusParams() { func (s *KeeperTestSuite) TestGetHashFn() { s.SetupTest() - header := s.Network.GetContext().BlockHeader() - h, _ := cmttypes.HeaderFromProto(&header) - hash := h.Hash() + s.Require().NoError(s.Network.NextBlock()) + ctx := s.Network.GetContext() + height := uint64(ctx.BlockHeight()) //nolint:gosec // G115 + headerHash := common.BytesToHash(ctx.HeaderHash()) + fmt.Println("get headerHash", height, headerHash) testCases := []struct { msg string @@ -93,7 +93,7 @@ func (s *KeeperTestSuite) TestGetHashFn() { }{ { "case 1.1: context hash cached", - uint64(s.Network.GetContext().BlockHeight()), //nolint:gosec // G115 + height, func() sdk.Context { return s.Network.GetContext().WithHeaderHash( tmhash.Sum([]byte("header")), @@ -102,51 +102,22 @@ func (s *KeeperTestSuite) TestGetHashFn() { common.BytesToHash(tmhash.Sum([]byte("header"))), }, { - "case 1.2: failed to cast CometBFT header", - uint64(s.Network.GetContext().BlockHeight()), //nolint:gosec // G115 + "case 1.2: works for invalid CometBFT header", + height, func() sdk.Context { header := tmproto.Header{} header.Height = s.Network.GetContext().BlockHeight() return s.Network.GetContext().WithBlockHeader(header) }, - common.Hash{}, - }, - { - "case 1.3: hash calculated from CometBFT header", - uint64(s.Network.GetContext().BlockHeight()), //nolint:gosec // G115 - func() sdk.Context { - return s.Network.GetContext().WithBlockHeader(header) - }, - common.BytesToHash(hash), + headerHash, }, { - "case 2.1: height lower than current one, hist info not found", - 1, + "case 2.1: height lower than current one works", + height, func() sdk.Context { return s.Network.GetContext().WithBlockHeight(10) }, - common.Hash{}, - }, - { - "case 2.2: height lower than current one, invalid hist info header", - 1, - func() sdk.Context { - s.Require().NoError(s.Network.App.GetStakingKeeper().SetHistoricalInfo(s.Network.GetContext(), 1, &stakingtypes.HistoricalInfo{})) - return s.Network.GetContext().WithBlockHeight(10) - }, - common.Hash{}, - }, - { - "case 2.3: height lower than current one, calculated from hist info header", - 1, - func() sdk.Context { - histInfo := &stakingtypes.HistoricalInfo{ - Header: header, - } - s.Require().NoError(s.Network.App.GetStakingKeeper().SetHistoricalInfo(s.Network.GetContext(), 1, histInfo)) - return s.Network.GetContext().WithBlockHeight(10) - }, - common.BytesToHash(hash), + headerHash, }, { "case 3: height greater than current one", diff --git a/testutil/integration/evm/network/abci.go b/testutil/integration/evm/network/abci.go index 2050bc253b..fc5bf9c54b 100644 --- a/testutil/integration/evm/network/abci.go +++ b/testutil/integration/evm/network/abci.go @@ -60,6 +60,7 @@ func (n *IntegrationNetwork) finalizeBlockAndCommit(duration time.Duration, txBy // This might have to be changed with time if we want to test gas limits newCtx = newCtx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter()) newCtx = newCtx.WithVoteInfos(req.DecidedLastCommit.GetVotes()) + newCtx = newCtx.WithHeaderHash(header.AppHash) n.ctx = newCtx // commit changes diff --git a/x/vm/keeper/abci.go b/x/vm/keeper/abci.go index 6833c963da..b100260706 100644 --- a/x/vm/keeper/abci.go +++ b/x/vm/keeper/abci.go @@ -31,6 +31,8 @@ func (k *Keeper) BeginBlock(ctx sdk.Context) error { ), }) } + + k.SetHeaderHash(ctx) return nil } diff --git a/x/vm/keeper/keeper.go b/x/vm/keeper/keeper.go index dbed35ee61..15f8b19689 100644 --- a/x/vm/keeper/keeper.go +++ b/x/vm/keeper/keeper.go @@ -1,6 +1,7 @@ package keeper import ( + "encoding/binary" "math/big" "github.com/ethereum/go-ethereum/common" @@ -8,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/params" + ethparams "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" evmmempool "github.com/cosmos/evm/mempool" @@ -254,7 +255,7 @@ func (k Keeper) GetAccountStorage(ctx sdk.Context, address common.Address) types // ---------------------------------------------------------------------------- // Tracer return a default vm.Tracer based on current keeper state -func (k Keeper) Tracer(ctx sdk.Context, msg core.Message, ethCfg *params.ChainConfig) *tracing.Hooks { +func (k Keeper) Tracer(ctx sdk.Context, msg core.Message, ethCfg *ethparams.ChainConfig) *tracing.Hooks { return types.NewTracer(k.tracer, msg, ethCfg, ctx.BlockHeight(), uint64(ctx.BlockTime().Unix())) //#nosec G115 -- int overflow is not a concern here } @@ -401,3 +402,35 @@ func (k *Keeper) SetEvmMempool(evmMempool *evmmempool.ExperimentalEVMMempool) { func (k Keeper) GetEvmMempool() *evmmempool.ExperimentalEVMMempool { return k.evmMempool } + +// SetHeaderHash sets current block hash into EIP-2935 compatible storage contract. +func (k Keeper) SetHeaderHash(ctx sdk.Context) { + window := uint64(types.DefaultHistoryServeWindow) + params := k.GetParams(ctx) + if params.HistoryServeWindow > 0 { + window = params.HistoryServeWindow + } + + acct := k.GetAccount(ctx, ethparams.HistoryStorageAddress) + if acct != nil && acct.IsContract() { + // set current block hash in the contract storage, compatible with EIP-2935 + ringIndex := uint64(ctx.BlockHeight()) % window //nolint:gosec // G115 // won't exceed uint64 + var key common.Hash + binary.BigEndian.PutUint64(key[24:], ringIndex) + k.SetState(ctx, ethparams.HistoryStorageAddress, key, ctx.HeaderHash()) + } +} + +// GetHeaderHash sets block hash into EIP-2935 compatible storage contract. +func (k Keeper) GetHeaderHash(ctx sdk.Context, height uint64) common.Hash { + window := uint64(types.DefaultHistoryServeWindow) + params := k.GetParams(ctx) + if params.HistoryServeWindow > 0 { + window = params.HistoryServeWindow + } + + ringIndex := height % window + var key common.Hash + binary.BigEndian.PutUint64(key[24:], ringIndex) + return k.GetState(ctx, ethparams.HistoryStorageAddress, key) +} diff --git a/x/vm/keeper/state_transition.go b/x/vm/keeper/state_transition.go index e03e922e70..4c54727cee 100644 --- a/x/vm/keeper/state_transition.go +++ b/x/vm/keeper/state_transition.go @@ -112,23 +112,11 @@ func (k Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc { return common.BytesToHash(headerHash) case ctx.BlockHeight() > h: - // Case 2: if the chain is not the current height we need to retrieve the hash from the store for the - // current chain epoch. This only applies if the current height is greater than the requested height. - histInfo, err := k.stakingKeeper.GetHistoricalInfo(ctx, h) - if err != nil { - k.Logger(ctx).Debug("error while getting historical info", "height", h, "error", err.Error()) - return common.Hash{} - } - - header, err := cmttypes.HeaderFromProto(&histInfo.Header) - if err != nil { - k.Logger(ctx).Error("failed to cast CometBFT header from proto", "error", err) - return common.Hash{} - } - - return common.BytesToHash(header.Hash()) + // Case 2: The requested height is historical, query EIP-2935 contract storage for that + // see: https://github.com/cosmos/evm/issues/406 + return k.GetHeaderHash(ctx, height) default: - // Case 3: heights greater than the current one returns an empty hash. + // Case 3: The requested height is greater than the latest one, return empty hash return common.Hash{} } } diff --git a/x/vm/types/evm.pb.go b/x/vm/types/evm.pb.go index 5580012e2d..3d8430bf40 100644 --- a/x/vm/types/evm.pb.go +++ b/x/vm/types/evm.pb.go @@ -71,6 +71,7 @@ type Params struct { // active_static_precompiles defines the slice of hex addresses of the // precompiled contracts that are active ActiveStaticPrecompiles []string `protobuf:"bytes,9,rep,name=active_static_precompiles,json=activeStaticPrecompiles,proto3" json:"active_static_precompiles,omitempty"` + HistoryServeWindow uint64 `protobuf:"varint,10,opt,name=history_serve_window,json=historyServeWindow,proto3" json:"history_serve_window,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -141,6 +142,13 @@ func (m *Params) GetActiveStaticPrecompiles() []string { return nil } +func (m *Params) GetHistoryServeWindow() uint64 { + if m != nil { + return m.HistoryServeWindow + } + return 0 +} + // AccessControl defines the permission policy of the EVM // for creating and calling contracts type AccessControl struct { @@ -932,130 +940,132 @@ func init() { func init() { proto.RegisterFile("cosmos/evm/vm/v1/evm.proto", fileDescriptor_d1129b8db63d55c7) } var fileDescriptor_d1129b8db63d55c7 = []byte{ - // 1958 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0x4f, 0x6f, 0xe3, 0xc6, - 0x15, 0xb7, 0x2c, 0xda, 0xa6, 0x46, 0xb2, 0xcc, 0x1d, 0x6b, 0xbd, 0x5a, 0x6d, 0x62, 0xaa, 0x6c, - 0x0f, 0xee, 0x22, 0xb5, 0xd7, 0xde, 0xb8, 0x35, 0x9c, 0xfe, 0x81, 0x65, 0x2b, 0xad, 0x5d, 0xef, - 0x46, 0x18, 0xb9, 0x09, 0x52, 0xb4, 0x20, 0x46, 0xe4, 0x2c, 0xc5, 0x88, 0xe4, 0x08, 0x1c, 0x4a, - 0xb5, 0x7b, 0xec, 0x29, 0xd8, 0x53, 0xfa, 0x01, 0x16, 0x08, 0xd0, 0x4b, 0x8e, 0xf9, 0x08, 0x3d, - 0x06, 0x3d, 0xe5, 0x58, 0x14, 0x28, 0x51, 0x68, 0x0f, 0x01, 0x7c, 0xf4, 0x27, 0x28, 0xe6, 0x8f, - 0xfe, 0xda, 0x51, 0x5d, 0xc0, 0xd8, 0x9d, 0xdf, 0x9b, 0xf7, 0x7e, 0xbf, 0x99, 0x37, 0x8f, 0xc3, - 0x47, 0x81, 0x8a, 0x43, 0x59, 0x48, 0xd9, 0x0e, 0xe9, 0x87, 0x3b, 0xfc, 0x6f, 0x97, 0x8f, 0xb6, - 0xbb, 0x31, 0x4d, 0x28, 0x34, 0xe4, 0xdc, 0x36, 0xb7, 0xf0, 0xbf, 0xdd, 0xca, 0x03, 0x1c, 0xfa, - 0x11, 0xdd, 0x11, 0xff, 0x4a, 0xa7, 0x4a, 0xc9, 0xa3, 0x1e, 0x15, 0xc3, 0x1d, 0x3e, 0x92, 0x56, - 0xeb, 0x2f, 0x59, 0xb0, 0xdc, 0xc0, 0x31, 0x0e, 0x19, 0xdc, 0x05, 0x39, 0xd2, 0x0f, 0x6d, 0x97, - 0x44, 0x34, 0x2c, 0x67, 0xaa, 0x99, 0xad, 0x5c, 0xad, 0x74, 0x93, 0x9a, 0xc6, 0x15, 0x0e, 0x83, - 0x43, 0x6b, 0x34, 0x65, 0x21, 0x9d, 0xf4, 0xc3, 0x13, 0x3e, 0x84, 0x47, 0x00, 0x90, 0xcb, 0x24, - 0xc6, 0x36, 0xf1, 0xbb, 0xac, 0xac, 0x55, 0xb3, 0x5b, 0xd9, 0x9a, 0x35, 0x48, 0xcd, 0x5c, 0x9d, - 0x5b, 0xeb, 0xa7, 0x0d, 0x76, 0x93, 0x9a, 0x0f, 0x14, 0xc1, 0xc8, 0xd1, 0x42, 0x39, 0x01, 0xea, - 0x7e, 0x97, 0xc1, 0x3d, 0x50, 0xe0, 0xd4, 0x4e, 0x1b, 0x47, 0x11, 0x09, 0x58, 0x79, 0xa5, 0x9a, - 0xdd, 0xca, 0xd5, 0xd6, 0x06, 0xa9, 0x99, 0xaf, 0x7f, 0xfc, 0xe2, 0x58, 0x99, 0x51, 0x9e, 0xf4, - 0xc3, 0x21, 0x80, 0x7f, 0x04, 0x45, 0xec, 0x38, 0x84, 0x31, 0xdb, 0xa1, 0x51, 0x12, 0xd3, 0xa0, - 0xac, 0x57, 0x33, 0x5b, 0xf9, 0x3d, 0x73, 0x7b, 0x36, 0x11, 0xdb, 0x47, 0xc2, 0xef, 0x58, 0xba, - 0xd5, 0x1e, 0x7e, 0x93, 0x9a, 0x0b, 0x83, 0xd4, 0x5c, 0x9d, 0x32, 0xa3, 0x55, 0x3c, 0x09, 0xe1, - 0x21, 0x78, 0x8c, 0x9d, 0xc4, 0xef, 0x13, 0x9b, 0x25, 0x38, 0xf1, 0x1d, 0xbb, 0x1b, 0x13, 0x87, - 0x86, 0x5d, 0x3f, 0x20, 0xac, 0x9c, 0xe3, 0xeb, 0x43, 0x8f, 0xa4, 0x43, 0x53, 0xcc, 0x37, 0xc6, - 0xd3, 0x87, 0x4f, 0x5e, 0x7f, 0xf7, 0xf5, 0xd3, 0x8d, 0x89, 0xb3, 0xba, 0xe4, 0xa7, 0x25, 0x33, - 0x7c, 0xa6, 0xe9, 0x8b, 0x46, 0xf6, 0x4c, 0xd3, 0xb3, 0x86, 0x76, 0xa6, 0xe9, 0x4b, 0xc6, 0xf2, - 0x99, 0xa6, 0x2f, 0x1b, 0x2b, 0xd6, 0x5f, 0x33, 0x60, 0x7a, 0x45, 0xf0, 0x08, 0x2c, 0x3b, 0x31, - 0xc1, 0x09, 0x11, 0x07, 0x91, 0xdf, 0xfb, 0xe1, 0xff, 0xd8, 0xd9, 0xc5, 0x55, 0x97, 0xd4, 0x34, - 0xbe, 0x3b, 0xa4, 0x02, 0xe1, 0x2f, 0x80, 0xe6, 0xe0, 0x20, 0x28, 0x2f, 0xfe, 0xbf, 0x04, 0x22, - 0xcc, 0xfa, 0x77, 0x06, 0x3c, 0xb8, 0xe5, 0x01, 0x1d, 0x90, 0x57, 0x99, 0x4f, 0xae, 0xba, 0x72, - 0x71, 0xc5, 0xbd, 0x77, 0xbe, 0x8f, 0x5b, 0x90, 0xfe, 0x68, 0x90, 0x9a, 0x60, 0x8c, 0x6f, 0x52, - 0x13, 0xca, 0x82, 0x98, 0x20, 0xb2, 0x10, 0xc0, 0x23, 0x0f, 0xe8, 0x80, 0xf5, 0xe9, 0xe3, 0xb5, - 0x03, 0x9f, 0x25, 0xe5, 0x45, 0x51, 0x19, 0xcf, 0x07, 0xa9, 0x39, 0xbd, 0xb0, 0x73, 0x9f, 0x25, - 0x37, 0xa9, 0x59, 0x99, 0x62, 0x9d, 0x8c, 0xb4, 0xd0, 0x03, 0x3c, 0x1b, 0x60, 0x7d, 0x65, 0x80, - 0xfc, 0x71, 0x1b, 0xfb, 0xd1, 0x31, 0x8d, 0x5e, 0xf9, 0x1e, 0xfc, 0x03, 0x58, 0x6b, 0xd3, 0x90, - 0xb0, 0x84, 0x60, 0xd7, 0x6e, 0x05, 0xd4, 0xe9, 0xa8, 0x67, 0xe0, 0xf9, 0xbf, 0x52, 0xf3, 0xa1, - 0xdc, 0x20, 0x73, 0x3b, 0xdb, 0x3e, 0xdd, 0x09, 0x71, 0xd2, 0xde, 0x3e, 0x8d, 0xb8, 0xe8, 0x86, - 0x14, 0x9d, 0x89, 0xb4, 0x50, 0x71, 0x64, 0xa9, 0x71, 0x03, 0x6c, 0x83, 0xa2, 0x8b, 0xa9, 0xfd, - 0x8a, 0xc6, 0x1d, 0x45, 0xbe, 0x28, 0xc8, 0x6b, 0xdf, 0x4b, 0x3e, 0x48, 0xcd, 0xc2, 0xc9, 0xd1, - 0x47, 0x1f, 0xd2, 0xb8, 0x23, 0x28, 0x6e, 0x52, 0xf3, 0xa1, 0x14, 0x9b, 0x26, 0xb2, 0x50, 0xc1, - 0xc5, 0x74, 0xe4, 0x06, 0x3f, 0x01, 0xc6, 0xc8, 0x81, 0xf5, 0xba, 0x5d, 0x1a, 0x27, 0xe5, 0x6c, - 0x35, 0xb3, 0xa5, 0xd7, 0x7e, 0x32, 0x48, 0xcd, 0xa2, 0xa2, 0x6c, 0xca, 0x99, 0x9b, 0xd4, 0x7c, - 0x34, 0x43, 0xaa, 0x62, 0x2c, 0x54, 0x54, 0xb4, 0xca, 0x15, 0xb6, 0x40, 0x81, 0xf8, 0xdd, 0xdd, - 0xfd, 0x67, 0x6a, 0x03, 0x9a, 0xd8, 0xc0, 0xaf, 0xe6, 0x6d, 0x20, 0x5f, 0x3f, 0x6d, 0xec, 0xee, - 0x3f, 0x1b, 0xae, 0x7f, 0x5d, 0x5d, 0x04, 0x13, 0x2c, 0x16, 0xca, 0x4b, 0x28, 0x17, 0x3f, 0xd4, - 0xd8, 0x57, 0x1a, 0xcb, 0xf7, 0xd5, 0xd8, 0xbf, 0x4b, 0x63, 0x7f, 0x5a, 0x63, 0x7f, 0x5a, 0xe3, - 0x40, 0x69, 0xac, 0xdc, 0x57, 0xe3, 0xe0, 0x2e, 0x8d, 0x83, 0x69, 0x0d, 0xe9, 0xc3, 0x8b, 0xa9, - 0x75, 0xf5, 0x67, 0x1c, 0x25, 0x7e, 0x2f, 0x54, 0x32, 0xfa, 0xbd, 0x8b, 0x69, 0x26, 0xd2, 0x42, - 0xc5, 0x91, 0x45, 0xb2, 0x77, 0x40, 0xc9, 0xa1, 0x11, 0x4b, 0xb8, 0x2d, 0xa2, 0xdd, 0x80, 0x28, - 0x89, 0x9c, 0x90, 0x38, 0x98, 0x27, 0xf1, 0x44, 0x4a, 0xdc, 0x15, 0x6e, 0xa1, 0xf5, 0x69, 0xb3, - 0x14, 0xb3, 0x81, 0xd1, 0x25, 0x09, 0x89, 0x59, 0xab, 0x17, 0x7b, 0x4a, 0x08, 0x08, 0xa1, 0xf7, - 0xe7, 0x09, 0xa9, 0xb2, 0x9a, 0x0d, 0xb5, 0xd0, 0xda, 0xd8, 0x24, 0x05, 0x3e, 0x05, 0x45, 0x9f, - 0xab, 0xb6, 0x7a, 0x81, 0xa2, 0xcf, 0x0b, 0xfa, 0xbd, 0x79, 0xf4, 0xea, 0x51, 0x98, 0x0e, 0xb4, - 0xd0, 0xea, 0xd0, 0x20, 0xa9, 0x5d, 0x00, 0xc3, 0x9e, 0x1f, 0xdb, 0x5e, 0x80, 0x1d, 0x9f, 0xc4, - 0x8a, 0xbe, 0x20, 0xe8, 0x7f, 0x3a, 0x8f, 0xfe, 0xb1, 0xa4, 0xbf, 0x1d, 0x6c, 0x21, 0x83, 0x1b, - 0x7f, 0x2d, 0x6d, 0x52, 0xa5, 0x09, 0x0a, 0x2d, 0x12, 0x07, 0x7e, 0xa4, 0xf8, 0x57, 0x05, 0xff, - 0xb3, 0x79, 0xfc, 0xaa, 0x82, 0x26, 0xc3, 0x2c, 0x94, 0x97, 0x70, 0x44, 0x1a, 0xd0, 0xc8, 0xa5, - 0x43, 0xd2, 0x07, 0xf7, 0x26, 0x9d, 0x0c, 0xb3, 0x50, 0x5e, 0x42, 0x49, 0xea, 0x81, 0x75, 0x1c, - 0xc7, 0xf4, 0x4f, 0x33, 0x09, 0x81, 0x82, 0xfb, 0x67, 0xf3, 0xb8, 0x87, 0x97, 0xeb, 0xed, 0x68, - 0x7e, 0xb9, 0x72, 0xeb, 0x54, 0x4a, 0x5c, 0x00, 0xbd, 0x18, 0x5f, 0xcd, 0xe8, 0x94, 0xee, 0x9d, - 0xf8, 0xdb, 0xc1, 0x16, 0x32, 0xb8, 0x71, 0x4a, 0xe5, 0x33, 0x50, 0x0a, 0x49, 0xec, 0x11, 0x3b, - 0x22, 0x09, 0xeb, 0x06, 0x7e, 0xa2, 0x74, 0x1e, 0xde, 0xfb, 0x39, 0xb8, 0x2b, 0xdc, 0x42, 0x50, - 0x98, 0x5f, 0x2a, 0xab, 0xd4, 0x7a, 0x0c, 0x74, 0x87, 0xbf, 0x2d, 0x6c, 0xdf, 0x2d, 0x97, 0xab, - 0x99, 0x2d, 0x0d, 0xad, 0x08, 0x7c, 0xea, 0xc2, 0x12, 0x58, 0x92, 0x3d, 0xd3, 0x63, 0xae, 0x8b, - 0x24, 0x80, 0x15, 0xa0, 0xbb, 0xc4, 0xf1, 0x43, 0x1c, 0xb0, 0x72, 0x45, 0x04, 0x8c, 0x30, 0xfc, - 0x18, 0xac, 0xb2, 0x36, 0x8e, 0xbc, 0x36, 0xf6, 0xed, 0xc4, 0x0f, 0x49, 0xf9, 0x89, 0x58, 0xf1, - 0xee, 0xbc, 0x15, 0x97, 0xe4, 0x8a, 0xa7, 0xe2, 0x2c, 0x54, 0x18, 0xe2, 0x0b, 0x3f, 0x24, 0xb0, - 0x01, 0xf2, 0x0e, 0x8e, 0x9c, 0x5e, 0x24, 0x59, 0xdf, 0x11, 0xac, 0x3b, 0xf3, 0x58, 0xd5, 0xab, - 0x78, 0x22, 0xca, 0x42, 0x40, 0xa2, 0x21, 0x63, 0x37, 0xc6, 0x5e, 0x8f, 0x48, 0xc6, 0x77, 0xef, - 0xcd, 0x38, 0x11, 0x65, 0x21, 0x20, 0xd1, 0x90, 0xb1, 0x4f, 0xe2, 0x4e, 0xa0, 0x18, 0x37, 0xef, - 0xcd, 0x38, 0x11, 0x65, 0x21, 0x20, 0x91, 0x60, 0x7c, 0x01, 0x00, 0x65, 0xb8, 0x83, 0x25, 0xa1, - 0x29, 0x08, 0xb7, 0xe7, 0x11, 0xaa, 0x86, 0x74, 0x1c, 0x64, 0xa1, 0x9c, 0x00, 0x9c, 0x6e, 0xd4, - 0x98, 0x6d, 0x18, 0x8f, 0xce, 0x34, 0xfd, 0x91, 0x51, 0xb6, 0x76, 0xc0, 0x12, 0x6f, 0xf4, 0x08, - 0x34, 0x40, 0xb6, 0x43, 0xae, 0x64, 0x5f, 0x80, 0xf8, 0x90, 0x9f, 0x7d, 0x1f, 0x07, 0x3d, 0x22, - 0x5f, 0xe7, 0x48, 0x02, 0xab, 0x01, 0xd6, 0x2e, 0x62, 0x1c, 0x31, 0xde, 0x24, 0xd2, 0xe8, 0x9c, - 0x7a, 0x0c, 0x42, 0xa0, 0xb5, 0x31, 0x6b, 0xab, 0x58, 0x31, 0x86, 0x3f, 0x06, 0x5a, 0x40, 0x3d, - 0x26, 0x1a, 0x9b, 0xfc, 0xde, 0xc3, 0xdb, 0x5d, 0xd4, 0x39, 0xf5, 0x90, 0x70, 0xb1, 0xfe, 0xb1, - 0x08, 0xb2, 0xe7, 0xd4, 0x83, 0x65, 0xb0, 0x82, 0x5d, 0x37, 0x26, 0x8c, 0x29, 0xa6, 0x21, 0x84, - 0x1b, 0x60, 0x39, 0xa1, 0x5d, 0xdf, 0x91, 0x74, 0x39, 0xa4, 0x10, 0x17, 0x76, 0x71, 0x82, 0x45, - 0x0f, 0x50, 0x40, 0x62, 0xcc, 0x7b, 0x6e, 0x51, 0xea, 0x76, 0xd4, 0x0b, 0x5b, 0x24, 0x16, 0xaf, - 0x72, 0xad, 0xb6, 0x76, 0x9d, 0x9a, 0x79, 0x61, 0x7f, 0x29, 0xcc, 0x68, 0x12, 0xc0, 0xf7, 0xc0, - 0x4a, 0x72, 0x69, 0x8b, 0x3d, 0x2c, 0x89, 0x14, 0xaf, 0x5f, 0xa7, 0xe6, 0x5a, 0x32, 0xde, 0xe6, - 0x6f, 0x30, 0x6b, 0xa3, 0xe5, 0xe4, 0x92, 0xff, 0x0f, 0x77, 0x80, 0x9e, 0x5c, 0xda, 0x7e, 0xe4, - 0x92, 0x4b, 0xf1, 0x12, 0xd7, 0x6a, 0xa5, 0xeb, 0xd4, 0x34, 0x26, 0xdc, 0x4f, 0xf9, 0x1c, 0x5a, - 0x49, 0x2e, 0xc5, 0x00, 0xbe, 0x07, 0x80, 0x5c, 0x92, 0x50, 0x90, 0xef, 0xe4, 0xd5, 0xeb, 0xd4, - 0xcc, 0x09, 0xab, 0xe0, 0x1e, 0x0f, 0xa1, 0x05, 0x96, 0x24, 0xb7, 0x2e, 0xb8, 0x0b, 0xd7, 0xa9, - 0xa9, 0x07, 0xd4, 0x93, 0x9c, 0x72, 0x8a, 0xa7, 0x2a, 0x26, 0x21, 0xed, 0x13, 0x57, 0xbc, 0x18, - 0x75, 0x34, 0x84, 0xd6, 0x17, 0x8b, 0x40, 0xbf, 0xb8, 0x44, 0x84, 0xf5, 0x82, 0x04, 0x7e, 0x08, - 0x0c, 0xd1, 0x2b, 0x62, 0x27, 0xb1, 0xa7, 0x52, 0x5b, 0x7b, 0x32, 0x7e, 0x8d, 0xcd, 0x7a, 0x58, - 0x68, 0x6d, 0x68, 0x3a, 0x52, 0xf9, 0x2f, 0x81, 0xa5, 0x56, 0x40, 0x69, 0x28, 0x2a, 0xa1, 0x80, - 0x24, 0x80, 0x9f, 0x88, 0xac, 0x89, 0x53, 0xce, 0x8a, 0x3e, 0xfc, 0x07, 0xb7, 0x4f, 0x79, 0xa6, - 0x54, 0x6a, 0x4f, 0x78, 0x17, 0x7e, 0x93, 0x9a, 0x45, 0xa9, 0xad, 0xe2, 0xad, 0xaf, 0xbe, 0xfb, - 0xfa, 0x69, 0x86, 0x27, 0x58, 0xd4, 0x93, 0x01, 0xb2, 0x31, 0x49, 0xc4, 0xc9, 0x15, 0x10, 0x1f, - 0xf2, 0x0b, 0x27, 0x26, 0x7d, 0x12, 0x27, 0xc4, 0x15, 0x27, 0xa4, 0xa3, 0x11, 0xe6, 0xb7, 0x97, - 0x87, 0x99, 0xdd, 0x63, 0xc4, 0x95, 0xc7, 0x81, 0x56, 0x3c, 0xcc, 0x7e, 0xc7, 0x88, 0x7b, 0xa8, - 0x7d, 0xfe, 0xa5, 0xb9, 0x60, 0x61, 0x90, 0x57, 0x2d, 0x7a, 0xaf, 0x1b, 0x90, 0x39, 0x65, 0xb6, - 0x07, 0x0a, 0x2c, 0xa1, 0x31, 0xf6, 0x88, 0xdd, 0x21, 0x57, 0xaa, 0xd8, 0x64, 0xe9, 0x28, 0xfb, - 0x6f, 0xc9, 0x15, 0x43, 0x93, 0x40, 0x49, 0x7c, 0xa9, 0x81, 0xfc, 0x45, 0x8c, 0x1d, 0xa2, 0x1a, - 0x6e, 0x5e, 0xb0, 0x1c, 0xc6, 0x4a, 0x42, 0x21, 0xae, 0xcd, 0x9f, 0x49, 0xda, 0x4b, 0xd4, 0x43, - 0x35, 0x84, 0x3c, 0x22, 0x26, 0xe4, 0x92, 0x38, 0x22, 0x97, 0x1a, 0x52, 0x08, 0xee, 0x83, 0x55, - 0xd7, 0x67, 0xb8, 0x15, 0x88, 0x0f, 0x36, 0xa7, 0x23, 0xb7, 0x5f, 0x33, 0xae, 0x53, 0xb3, 0xa0, - 0x26, 0x9a, 0xdc, 0x8e, 0xa6, 0x10, 0xfc, 0x00, 0xac, 0x8d, 0xc3, 0xc4, 0x6a, 0x45, 0x6e, 0xf4, - 0x1a, 0xbc, 0x4e, 0xcd, 0xe2, 0xc8, 0x55, 0xcc, 0xa0, 0x19, 0x2c, 0x2f, 0xfd, 0x56, 0xcf, 0x13, - 0x15, 0xa8, 0x23, 0x09, 0xb8, 0x35, 0xf0, 0x43, 0x3f, 0x11, 0x15, 0xb7, 0x84, 0x24, 0x80, 0x1f, - 0x80, 0x1c, 0xed, 0x93, 0x38, 0xf6, 0x5d, 0xc2, 0x44, 0xef, 0x94, 0xdf, 0x7b, 0xf7, 0x76, 0x19, - 0x4c, 0x7c, 0x8c, 0xa0, 0xb1, 0x3f, 0xdf, 0x1c, 0x89, 0xc4, 0x22, 0x43, 0x12, 0xd2, 0xf8, 0x4a, - 0x74, 0x47, 0x6a, 0x73, 0x72, 0xe2, 0x85, 0xb0, 0xa3, 0x29, 0x04, 0x6b, 0x00, 0xaa, 0xb0, 0x98, - 0x24, 0xbd, 0x38, 0xb2, 0xc5, 0x25, 0x50, 0x10, 0xb1, 0xe2, 0x51, 0x94, 0xb3, 0x48, 0x4c, 0x9e, - 0xe0, 0x04, 0xa3, 0x5b, 0x16, 0xf8, 0x4b, 0x00, 0xe5, 0x99, 0xd8, 0x9f, 0x31, 0x1a, 0xf1, 0x4f, - 0xaa, 0x57, 0xbe, 0xa7, 0xda, 0x1b, 0xa1, 0x2f, 0x67, 0xd5, 0x9a, 0x0d, 0x89, 0xce, 0x18, 0x55, - 0xbb, 0x38, 0xd3, 0x74, 0xcd, 0x58, 0x3a, 0xd3, 0xf4, 0x15, 0x43, 0x1f, 0xe5, 0x4f, 0xed, 0x02, - 0xad, 0x0f, 0xf1, 0xc4, 0xf2, 0xac, 0x97, 0x00, 0x34, 0x62, 0xe2, 0xf3, 0x26, 0x34, 0x08, 0xf8, - 0xcd, 0x15, 0xe1, 0x90, 0x0c, 0xaf, 0x4c, 0x3e, 0x9e, 0x2c, 0xcc, 0xc5, 0xe9, 0xc2, 0x84, 0x40, - 0x73, 0xa8, 0x4b, 0x44, 0x69, 0xe4, 0x90, 0x18, 0x3f, 0xfd, 0x7b, 0x06, 0x4c, 0x7c, 0x79, 0xc2, - 0x9f, 0x83, 0xca, 0xd1, 0xf1, 0x71, 0xbd, 0xd9, 0xb4, 0x2f, 0x3e, 0x6d, 0xd4, 0xed, 0x46, 0x1d, - 0xbd, 0x38, 0x6d, 0x36, 0x4f, 0x3f, 0x7a, 0x79, 0x5e, 0x6f, 0x36, 0x8d, 0x85, 0xca, 0x3b, 0xaf, - 0xdf, 0x54, 0xcb, 0x63, 0xff, 0x06, 0x89, 0x43, 0x9f, 0x31, 0x9f, 0x46, 0x01, 0x17, 0x78, 0x1f, - 0x6c, 0x4c, 0x46, 0xa3, 0x7a, 0xf3, 0x02, 0x9d, 0x1e, 0x5f, 0xd4, 0x4f, 0x8c, 0x4c, 0xa5, 0xfc, - 0xfa, 0x4d, 0xb5, 0x34, 0x8e, 0x44, 0x84, 0x25, 0xb1, 0xef, 0xf0, 0x27, 0xef, 0x00, 0x94, 0xef, - 0xd6, 0xac, 0x9f, 0x18, 0x8b, 0x95, 0xca, 0xeb, 0x37, 0xd5, 0x8d, 0xbb, 0x14, 0x89, 0x5b, 0xd1, - 0x3e, 0xff, 0xdb, 0xe6, 0x42, 0xed, 0xf0, 0x9b, 0xc1, 0x66, 0xe6, 0xdb, 0xc1, 0x66, 0xe6, 0x3f, - 0x83, 0xcd, 0xcc, 0x17, 0x6f, 0x37, 0x17, 0xbe, 0x7d, 0xbb, 0xb9, 0xf0, 0xcf, 0xb7, 0x9b, 0x0b, - 0xbf, 0xaf, 0x7a, 0x7e, 0xd2, 0xee, 0xb5, 0xb6, 0x1d, 0x1a, 0xee, 0xcc, 0xfe, 0xde, 0xc0, 0xbf, - 0xa9, 0x59, 0x6b, 0x59, 0xfc, 0xc4, 0xf3, 0xfc, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x0b, 0x36, - 0x25, 0x41, 0x3b, 0x12, 0x00, 0x00, + // 1988 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0x4d, 0x6f, 0x1b, 0xc7, + 0x19, 0x16, 0xc5, 0x95, 0xb4, 0x1c, 0x52, 0xd2, 0x7a, 0x44, 0xcb, 0x34, 0xed, 0x68, 0xd5, 0x6d, + 0x0f, 0xaa, 0x91, 0x4a, 0x96, 0x1c, 0xb5, 0x86, 0xd3, 0x0f, 0x88, 0x32, 0xd3, 0x4a, 0xb5, 0x1d, + 0x61, 0xa8, 0xc6, 0x48, 0xd1, 0x62, 0x31, 0xdc, 0x1d, 0x2f, 0x37, 0xda, 0xdd, 0x21, 0x66, 0x96, + 0xb4, 0xd8, 0x5f, 0x10, 0xf8, 0x94, 0xfe, 0x00, 0x03, 0x01, 0x7a, 0xc9, 0x31, 0x87, 0xfe, 0x80, + 0x1e, 0x83, 0x9e, 0x72, 0x2c, 0x0a, 0x74, 0x51, 0xd0, 0x87, 0x00, 0x3a, 0xea, 0x17, 0x14, 0xf3, + 0xc1, 0x4f, 0x29, 0xac, 0x02, 0x08, 0xf6, 0x3c, 0xef, 0xc7, 0xf3, 0xcc, 0xc7, 0xbb, 0x3b, 0xef, + 0x12, 0x54, 0x3d, 0xca, 0x63, 0xca, 0x77, 0x48, 0x37, 0xde, 0x11, 0x7f, 0xbb, 0x62, 0xb4, 0xdd, + 0x66, 0x34, 0xa5, 0xd0, 0x52, 0xbe, 0x6d, 0x61, 0x11, 0x7f, 0xbb, 0xd5, 0x5b, 0x38, 0x0e, 0x13, + 0xba, 0x23, 0xff, 0x55, 0x41, 0xd5, 0x72, 0x40, 0x03, 0x2a, 0x87, 0x3b, 0x62, 0xa4, 0xac, 0xce, + 0xdf, 0xf3, 0x60, 0xf1, 0x04, 0x33, 0x1c, 0x73, 0xb8, 0x0b, 0x0a, 0xa4, 0x1b, 0xbb, 0x3e, 0x49, + 0x68, 0x5c, 0xc9, 0x6d, 0xe6, 0xb6, 0x0a, 0xb5, 0xf2, 0x65, 0x66, 0x5b, 0x3d, 0x1c, 0x47, 0x4f, + 0x9c, 0xa1, 0xcb, 0x41, 0x26, 0xe9, 0xc6, 0x4f, 0xc5, 0x10, 0x1e, 0x00, 0x40, 0xce, 0x53, 0x86, + 0x5d, 0x12, 0xb6, 0x79, 0xc5, 0xd8, 0xcc, 0x6f, 0xe5, 0x6b, 0x4e, 0x3f, 0xb3, 0x0b, 0x75, 0x61, + 0xad, 0x1f, 0x9d, 0xf0, 0xcb, 0xcc, 0xbe, 0xa5, 0x09, 0x86, 0x81, 0x0e, 0x2a, 0x48, 0x50, 0x0f, + 0xdb, 0x1c, 0xee, 0x81, 0x92, 0xa0, 0xf6, 0x5a, 0x38, 0x49, 0x48, 0xc4, 0x2b, 0x4b, 0x9b, 0xf9, + 0xad, 0x42, 0x6d, 0xb5, 0x9f, 0xd9, 0xc5, 0xfa, 0x27, 0xcf, 0x0f, 0xb5, 0x19, 0x15, 0x49, 0x37, + 0x1e, 0x00, 0xf8, 0x67, 0xb0, 0x82, 0x3d, 0x8f, 0x70, 0xee, 0x7a, 0x34, 0x49, 0x19, 0x8d, 0x2a, + 0xe6, 0x66, 0x6e, 0xab, 0xb8, 0x67, 0x6f, 0x4f, 0x6f, 0xc4, 0xf6, 0x81, 0x8c, 0x3b, 0x54, 0x61, + 0xb5, 0xdb, 0xdf, 0x64, 0xf6, 0x5c, 0x3f, 0xb3, 0x97, 0x27, 0xcc, 0x68, 0x19, 0x8f, 0x43, 0xf8, + 0x04, 0xdc, 0xc5, 0x5e, 0x1a, 0x76, 0x89, 0xcb, 0x53, 0x9c, 0x86, 0x9e, 0xdb, 0x66, 0xc4, 0xa3, + 0x71, 0x3b, 0x8c, 0x08, 0xaf, 0x14, 0xc4, 0xfc, 0xd0, 0x1d, 0x15, 0xd0, 0x90, 0xfe, 0x93, 0x91, + 0x1b, 0x3e, 0x04, 0xe5, 0x56, 0xc8, 0x53, 0xca, 0x7a, 0x2e, 0x27, 0xac, 0x4b, 0xdc, 0xd7, 0x61, + 0xe2, 0xd3, 0xd7, 0x15, 0xb0, 0x99, 0xdb, 0x32, 0x10, 0xd4, 0xbe, 0x86, 0x70, 0xbd, 0x94, 0x9e, + 0x27, 0xf7, 0xde, 0x7c, 0xf7, 0xf5, 0x83, 0xf5, 0xb1, 0xd3, 0x3d, 0x17, 0xe7, 0xab, 0xce, 0xe4, + 0xd8, 0x30, 0xe7, 0xad, 0xfc, 0xb1, 0x61, 0xe6, 0x2d, 0xe3, 0xd8, 0x30, 0x17, 0xac, 0xc5, 0x63, + 0xc3, 0x5c, 0xb4, 0x96, 0x9c, 0xbf, 0xe6, 0xc0, 0xe4, 0x1a, 0xe0, 0x01, 0x58, 0xf4, 0x18, 0xc1, + 0x29, 0x91, 0x47, 0x57, 0xdc, 0xfb, 0xf1, 0xff, 0xd9, 0x8b, 0xd3, 0x5e, 0x9b, 0xd4, 0x0c, 0xb1, + 0x1f, 0x48, 0x27, 0xc2, 0x5f, 0x01, 0xc3, 0xc3, 0x51, 0x54, 0x99, 0xff, 0xa1, 0x04, 0x32, 0xcd, + 0xf9, 0x4f, 0x0e, 0xdc, 0xba, 0x12, 0x01, 0x3d, 0x50, 0xd4, 0x67, 0x95, 0xf6, 0xda, 0x6a, 0x72, + 0x2b, 0x7b, 0xf7, 0xbf, 0x8f, 0x5b, 0x92, 0xfe, 0xa4, 0x9f, 0xd9, 0x60, 0x84, 0x2f, 0x33, 0x1b, + 0xaa, 0x12, 0x1a, 0x23, 0x72, 0x10, 0xc0, 0xc3, 0x08, 0xe8, 0x81, 0xb5, 0xc9, 0x82, 0x70, 0xa3, + 0x90, 0xa7, 0x95, 0x79, 0x59, 0x4b, 0x8f, 0xfa, 0x99, 0x3d, 0x39, 0xb1, 0x67, 0x21, 0x4f, 0x2f, + 0x33, 0xbb, 0x3a, 0xc1, 0x3a, 0x9e, 0xe9, 0xa0, 0x5b, 0x78, 0x3a, 0xc1, 0xf9, 0xca, 0x02, 0xc5, + 0xc3, 0x16, 0x0e, 0x93, 0x43, 0x9a, 0xbc, 0x0a, 0x03, 0xf8, 0x27, 0xb0, 0xda, 0xa2, 0x31, 0xe1, + 0x29, 0xc1, 0xbe, 0xdb, 0x8c, 0xa8, 0x77, 0xa6, 0x9f, 0x9a, 0x47, 0xff, 0xce, 0xec, 0xdb, 0x6a, + 0x81, 0xdc, 0x3f, 0xdb, 0x0e, 0xe9, 0x4e, 0x8c, 0xd3, 0xd6, 0xf6, 0x51, 0x22, 0x44, 0xd7, 0x95, + 0xe8, 0x54, 0xa6, 0x83, 0x56, 0x86, 0x96, 0x9a, 0x30, 0xc0, 0x16, 0x58, 0xf1, 0x31, 0x75, 0x5f, + 0x51, 0x76, 0xa6, 0xc9, 0xe7, 0x25, 0x79, 0xed, 0x7b, 0xc9, 0xfb, 0x99, 0x5d, 0x7a, 0x7a, 0xf0, + 0xf1, 0x47, 0x94, 0x9d, 0x49, 0x8a, 0xcb, 0xcc, 0xbe, 0xad, 0xc4, 0x26, 0x89, 0x1c, 0x54, 0xf2, + 0x31, 0x1d, 0x86, 0xc1, 0x97, 0xc0, 0x1a, 0x06, 0xf0, 0x4e, 0xbb, 0x4d, 0x59, 0x5a, 0xc9, 0x6f, + 0xe6, 0xb6, 0xcc, 0xda, 0xcf, 0xfa, 0x99, 0xbd, 0xa2, 0x29, 0x1b, 0xca, 0x73, 0x99, 0xd9, 0x77, + 0xa6, 0x48, 0x75, 0x8e, 0x83, 0x56, 0x34, 0xad, 0x0e, 0x85, 0x4d, 0x50, 0x22, 0x61, 0x7b, 0x77, + 0xff, 0xa1, 0x5e, 0x80, 0x21, 0x17, 0xf0, 0x9b, 0x59, 0x0b, 0x28, 0xd6, 0x8f, 0x4e, 0x76, 0xf7, + 0x1f, 0x0e, 0xe6, 0xbf, 0xa6, 0x5f, 0x1d, 0x63, 0x2c, 0x0e, 0x2a, 0x2a, 0xa8, 0x26, 0x3f, 0xd0, + 0xd8, 0xd7, 0x1a, 0x8b, 0x37, 0xd5, 0xd8, 0xbf, 0x4e, 0x63, 0x7f, 0x52, 0x63, 0x7f, 0x52, 0xe3, + 0xb1, 0xd6, 0x58, 0xba, 0xa9, 0xc6, 0xe3, 0xeb, 0x34, 0x1e, 0x4f, 0x6a, 0xa8, 0x18, 0x51, 0x4c, + 0xcd, 0xde, 0x5f, 0x70, 0x92, 0x86, 0x9d, 0x58, 0xcb, 0x98, 0x37, 0x2e, 0xa6, 0xa9, 0x4c, 0x07, + 0xad, 0x0c, 0x2d, 0x8a, 0xfd, 0x0c, 0x94, 0x3d, 0x9a, 0xf0, 0x54, 0xd8, 0x12, 0xda, 0x8e, 0x88, + 0x96, 0x28, 0x48, 0x89, 0xc7, 0xb3, 0x24, 0xee, 0x29, 0x89, 0xeb, 0xd2, 0x1d, 0xb4, 0x36, 0x69, + 0x56, 0x62, 0x2e, 0xb0, 0xda, 0x24, 0x25, 0x8c, 0x37, 0x3b, 0x2c, 0xd0, 0x42, 0x40, 0x0a, 0x7d, + 0x30, 0x4b, 0x48, 0x97, 0xd5, 0x74, 0xaa, 0x83, 0x56, 0x47, 0x26, 0x25, 0xf0, 0x29, 0x58, 0x09, + 0x85, 0x6a, 0xb3, 0x13, 0x69, 0xfa, 0xa2, 0xa4, 0xdf, 0x9b, 0x45, 0xaf, 0x1f, 0x85, 0xc9, 0x44, + 0x07, 0x2d, 0x0f, 0x0c, 0x8a, 0xda, 0x07, 0x30, 0xee, 0x84, 0xcc, 0x0d, 0x22, 0xec, 0x85, 0x84, + 0x69, 0xfa, 0x92, 0xa4, 0xff, 0xf9, 0x2c, 0xfa, 0xbb, 0x8a, 0xfe, 0x6a, 0xb2, 0x83, 0x2c, 0x61, + 0xfc, 0xad, 0xb2, 0x29, 0x95, 0x06, 0x28, 0x35, 0x09, 0x8b, 0xc2, 0x44, 0xf3, 0x2f, 0x4b, 0xfe, + 0x87, 0xb3, 0xf8, 0x75, 0x05, 0x8d, 0xa7, 0x39, 0xa8, 0xa8, 0xe0, 0x90, 0x34, 0xa2, 0x89, 0x4f, + 0x07, 0xa4, 0xb7, 0x6e, 0x4c, 0x3a, 0x9e, 0xe6, 0xa0, 0xa2, 0x82, 0x8a, 0x34, 0x00, 0x6b, 0x98, + 0x31, 0xfa, 0x7a, 0x6a, 0x43, 0xa0, 0xe4, 0xfe, 0xc5, 0x2c, 0xee, 0xc1, 0xcb, 0xf5, 0x6a, 0xb6, + 0x78, 0xb9, 0x0a, 0xeb, 0xc4, 0x96, 0xf8, 0x00, 0x06, 0x0c, 0xf7, 0xa6, 0x74, 0xca, 0x37, 0xde, + 0xf8, 0xab, 0xc9, 0x0e, 0xb2, 0x84, 0x71, 0x42, 0xe5, 0x33, 0x50, 0x8e, 0x09, 0x0b, 0x88, 0x9b, + 0x90, 0x94, 0xb7, 0xa3, 0x30, 0xd5, 0x3a, 0xb7, 0x6f, 0xfc, 0x1c, 0x5c, 0x97, 0xee, 0x20, 0x28, + 0xcd, 0x2f, 0xb4, 0x55, 0x69, 0xdd, 0x05, 0xa6, 0x27, 0x6e, 0x0b, 0x37, 0xf4, 0x2b, 0x15, 0x79, + 0xfb, 0x2f, 0x49, 0x7c, 0xe4, 0xc3, 0x32, 0x58, 0x50, 0x5d, 0xd6, 0x5d, 0xa1, 0x8b, 0x14, 0x80, + 0x55, 0x60, 0xfa, 0xc4, 0x0b, 0x63, 0x1c, 0xf1, 0x4a, 0x55, 0x26, 0x0c, 0x31, 0xfc, 0x04, 0x2c, + 0xf3, 0x16, 0x4e, 0x82, 0x16, 0x0e, 0xdd, 0x34, 0x8c, 0x49, 0xe5, 0x9e, 0x9c, 0xf1, 0xee, 0xac, + 0x19, 0x97, 0xd5, 0x8c, 0x27, 0xf2, 0x1c, 0x54, 0x1a, 0xe0, 0xd3, 0x30, 0x26, 0xf0, 0x04, 0x14, + 0x3d, 0x9c, 0x78, 0x9d, 0x44, 0xb1, 0xde, 0x97, 0xac, 0x3b, 0xb3, 0x58, 0xf5, 0x55, 0x3c, 0x96, + 0xe5, 0x20, 0xa0, 0xd0, 0x80, 0xb1, 0xcd, 0x70, 0xd0, 0x21, 0x8a, 0xf1, 0xbd, 0x1b, 0x33, 0x8e, + 0x65, 0x39, 0x08, 0x28, 0x34, 0x60, 0xec, 0x12, 0x76, 0x16, 0x69, 0xc6, 0x8d, 0x1b, 0x33, 0x8e, + 0x65, 0x39, 0x08, 0x28, 0x24, 0x19, 0x9f, 0x03, 0x40, 0x39, 0x3e, 0xc3, 0x8a, 0xd0, 0x96, 0x84, + 0xdb, 0xb3, 0x08, 0x75, 0x0b, 0x3b, 0x4a, 0x72, 0x50, 0x41, 0x02, 0x41, 0x37, 0x6c, 0xcc, 0xd6, + 0xad, 0x3b, 0xc7, 0x86, 0x79, 0xc7, 0xaa, 0x38, 0x3b, 0x60, 0x41, 0xb4, 0x86, 0x04, 0x5a, 0x20, + 0x7f, 0x46, 0x7a, 0xaa, 0x2f, 0x40, 0x62, 0x28, 0xce, 0xbe, 0x8b, 0xa3, 0x0e, 0x51, 0xd7, 0x39, + 0x52, 0xc0, 0x39, 0x01, 0xab, 0xa7, 0x0c, 0x27, 0x5c, 0xb4, 0x95, 0x34, 0x79, 0x46, 0x03, 0x0e, + 0x21, 0x30, 0x5a, 0x98, 0xb7, 0x74, 0xae, 0x1c, 0xc3, 0x9f, 0x02, 0x23, 0xa2, 0x01, 0x97, 0x8d, + 0x4d, 0x71, 0xef, 0xf6, 0xd5, 0x2e, 0xea, 0x19, 0x0d, 0x90, 0x0c, 0x71, 0xfe, 0x39, 0x0f, 0xf2, + 0xcf, 0x68, 0x00, 0x2b, 0x60, 0x09, 0xfb, 0x3e, 0x23, 0x9c, 0x6b, 0xa6, 0x01, 0x84, 0xeb, 0x60, + 0x31, 0xa5, 0xed, 0xd0, 0x53, 0x74, 0x05, 0xa4, 0x91, 0x10, 0xf6, 0x71, 0x8a, 0x65, 0x0f, 0x50, + 0x42, 0x72, 0x2c, 0xba, 0x74, 0x59, 0xea, 0x6e, 0xd2, 0x89, 0x9b, 0x84, 0xc9, 0xab, 0xdc, 0xa8, + 0xad, 0x5e, 0x64, 0x76, 0x51, 0xda, 0x5f, 0x48, 0x33, 0x1a, 0x07, 0xf0, 0x7d, 0xb0, 0x94, 0x9e, + 0xbb, 0x72, 0x0d, 0x0b, 0x72, 0x8b, 0xd7, 0x2e, 0x32, 0x7b, 0x35, 0x1d, 0x2d, 0xf3, 0x77, 0x98, + 0xb7, 0xd0, 0x62, 0x7a, 0x2e, 0xfe, 0x87, 0x3b, 0xc0, 0x4c, 0xcf, 0xdd, 0x30, 0xf1, 0xc9, 0xb9, + 0xbc, 0xc4, 0x8d, 0x5a, 0xf9, 0x22, 0xb3, 0xad, 0xb1, 0xf0, 0x23, 0xe1, 0x43, 0x4b, 0xe9, 0xb9, + 0x1c, 0xc0, 0xf7, 0x01, 0x50, 0x53, 0x92, 0x0a, 0xea, 0x4e, 0x5e, 0xbe, 0xc8, 0xec, 0x82, 0xb4, + 0x4a, 0xee, 0xd1, 0x10, 0x3a, 0x60, 0x41, 0x71, 0x9b, 0x92, 0xbb, 0x74, 0x91, 0xd9, 0x66, 0x44, + 0x03, 0xc5, 0xa9, 0x5c, 0x62, 0xab, 0x18, 0x89, 0x69, 0x97, 0xf8, 0xf2, 0x62, 0x34, 0xd1, 0x00, + 0x3a, 0x5f, 0xcc, 0x03, 0xf3, 0xf4, 0x1c, 0x11, 0xde, 0x89, 0x52, 0xf8, 0x11, 0xb0, 0x64, 0xaf, + 0x88, 0xbd, 0xd4, 0x9d, 0xd8, 0xda, 0xda, 0xbd, 0xd1, 0x35, 0x36, 0x1d, 0xe1, 0xa0, 0xd5, 0x81, + 0xe9, 0x40, 0xef, 0x7f, 0x19, 0x2c, 0x34, 0x23, 0x4a, 0x63, 0x59, 0x09, 0x25, 0xa4, 0x00, 0x7c, + 0x29, 0x77, 0x4d, 0x9e, 0x72, 0x5e, 0xf6, 0xe1, 0x3f, 0xba, 0x7a, 0xca, 0x53, 0xa5, 0x52, 0xbb, + 0x27, 0xba, 0xf0, 0xcb, 0xcc, 0x5e, 0x51, 0xda, 0x3a, 0xdf, 0xf9, 0xea, 0xbb, 0xaf, 0x1f, 0xe4, + 0xc4, 0x06, 0xcb, 0x7a, 0xb2, 0x40, 0x9e, 0x91, 0x54, 0x9e, 0x5c, 0x09, 0x89, 0xa1, 0x78, 0xe1, + 0x30, 0xd2, 0x25, 0x2c, 0x25, 0xbe, 0x3c, 0x21, 0x13, 0x0d, 0xb1, 0x78, 0x7b, 0x05, 0x98, 0xbb, + 0x1d, 0x4e, 0x7c, 0x75, 0x1c, 0x68, 0x29, 0xc0, 0xfc, 0x0f, 0x9c, 0xf8, 0x4f, 0x8c, 0xcf, 0xbf, + 0xb4, 0xe7, 0x1c, 0x0c, 0x8a, 0xba, 0x45, 0xef, 0xb4, 0x23, 0x32, 0xa3, 0xcc, 0xf6, 0x40, 0x49, + 0x7c, 0xf3, 0xe0, 0x80, 0xb8, 0x67, 0xa4, 0xa7, 0x8b, 0x4d, 0x95, 0x8e, 0xb6, 0xff, 0x9e, 0xf4, + 0x38, 0x1a, 0x07, 0x5a, 0xe2, 0x4b, 0x03, 0x14, 0x4f, 0x19, 0xf6, 0x88, 0x6e, 0xb8, 0x45, 0xc1, + 0x0a, 0xc8, 0xb4, 0x84, 0x46, 0x42, 0x5b, 0x3c, 0x93, 0xb4, 0x93, 0xea, 0x87, 0x6a, 0x00, 0x45, + 0x06, 0x23, 0xe4, 0x9c, 0x78, 0x72, 0x2f, 0x0d, 0xa4, 0x11, 0xdc, 0x07, 0xcb, 0x7e, 0xc8, 0x71, + 0x33, 0x92, 0x9f, 0x78, 0xde, 0x99, 0x5a, 0x7e, 0xcd, 0xba, 0xc8, 0xec, 0x92, 0x76, 0x34, 0x84, + 0x1d, 0x4d, 0x20, 0xf8, 0x21, 0x58, 0x1d, 0xa5, 0xc9, 0xd9, 0xca, 0xbd, 0x31, 0x6b, 0xf0, 0x22, + 0xb3, 0x57, 0x86, 0xa1, 0xd2, 0x83, 0xa6, 0xb0, 0x7a, 0xe9, 0x37, 0x3b, 0x81, 0xac, 0x40, 0x13, + 0x29, 0x20, 0xac, 0x51, 0x18, 0x87, 0xa9, 0xac, 0xb8, 0x05, 0xa4, 0x00, 0xfc, 0x10, 0x14, 0x68, + 0x97, 0x30, 0x16, 0xfa, 0x84, 0xcb, 0xde, 0xa9, 0xb8, 0xf7, 0xde, 0xd5, 0x32, 0x18, 0xfb, 0x18, + 0x41, 0xa3, 0x78, 0xb1, 0x38, 0x92, 0xc8, 0x49, 0xc6, 0x24, 0xa6, 0xac, 0x27, 0xbb, 0x23, 0xbd, + 0x38, 0xe5, 0x78, 0x2e, 0xed, 0x68, 0x02, 0xc1, 0x1a, 0x80, 0x3a, 0x8d, 0x91, 0xb4, 0xc3, 0x12, + 0x57, 0xbe, 0x04, 0x4a, 0x32, 0x57, 0x3e, 0x8a, 0xca, 0x8b, 0xa4, 0xf3, 0x29, 0x4e, 0x31, 0xba, + 0x62, 0x81, 0xbf, 0x06, 0x50, 0x9d, 0x89, 0xfb, 0x19, 0xa7, 0x89, 0xf8, 0xa4, 0x7a, 0x15, 0x06, + 0xba, 0xbd, 0x91, 0xfa, 0xca, 0xab, 0xe7, 0x6c, 0x29, 0x74, 0xcc, 0xa9, 0x5e, 0xc5, 0xb1, 0x61, + 0x1a, 0xd6, 0xc2, 0xb1, 0x61, 0x2e, 0x59, 0xe6, 0x70, 0xff, 0xf4, 0x2a, 0xd0, 0xda, 0x00, 0x8f, + 0x4d, 0xcf, 0x79, 0x01, 0xc0, 0x09, 0x23, 0xa1, 0x68, 0x42, 0xa3, 0x48, 0xbc, 0xb9, 0x12, 0x1c, + 0x93, 0xc1, 0x2b, 0x53, 0x8c, 0xc7, 0x0b, 0x73, 0x7e, 0xb2, 0x30, 0x21, 0x30, 0x3c, 0xea, 0x13, + 0x59, 0x1a, 0x05, 0x24, 0xc7, 0x0f, 0xfe, 0x91, 0x03, 0x63, 0x5f, 0x9e, 0xf0, 0x97, 0xa0, 0x7a, + 0x70, 0x78, 0x58, 0x6f, 0x34, 0xdc, 0xd3, 0x4f, 0x4f, 0xea, 0xee, 0x49, 0x1d, 0x3d, 0x3f, 0x6a, + 0x34, 0x8e, 0x3e, 0x7e, 0xf1, 0xac, 0xde, 0x68, 0x58, 0x73, 0xd5, 0xfb, 0x6f, 0xde, 0x6e, 0x56, + 0x46, 0xf1, 0x27, 0x84, 0xc5, 0x21, 0xe7, 0x21, 0x4d, 0x22, 0x21, 0xf0, 0x01, 0x58, 0x1f, 0xcf, + 0x46, 0xf5, 0xc6, 0x29, 0x3a, 0x3a, 0x3c, 0xad, 0x3f, 0xb5, 0x72, 0xd5, 0xca, 0x9b, 0xb7, 0x9b, + 0xe5, 0x51, 0x26, 0x22, 0x3c, 0x65, 0xa1, 0x27, 0x9e, 0xbc, 0xc7, 0xa0, 0x72, 0xbd, 0x66, 0xfd, + 0xa9, 0x35, 0x5f, 0xad, 0xbe, 0x79, 0xbb, 0xb9, 0x7e, 0x9d, 0x22, 0xf1, 0xab, 0xc6, 0xe7, 0x7f, + 0xdb, 0x98, 0xab, 0x3d, 0xf9, 0xa6, 0xbf, 0x91, 0xfb, 0xb6, 0xbf, 0x91, 0xfb, 0x6f, 0x7f, 0x23, + 0xf7, 0xc5, 0xbb, 0x8d, 0xb9, 0x6f, 0xdf, 0x6d, 0xcc, 0xfd, 0xeb, 0xdd, 0xc6, 0xdc, 0x1f, 0x37, + 0x83, 0x30, 0x6d, 0x75, 0x9a, 0xdb, 0x1e, 0x8d, 0x77, 0xa6, 0x7f, 0x6f, 0x10, 0xdf, 0xd4, 0xbc, + 0xb9, 0x28, 0x7f, 0x14, 0x7a, 0xf4, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe4, 0x51, 0x6f, 0x71, + 0x6d, 0x12, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -1078,6 +1088,11 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.HistoryServeWindow != 0 { + i = encodeVarintEvm(dAtA, i, uint64(m.HistoryServeWindow)) + i-- + dAtA[i] = 0x50 + } if len(m.ActiveStaticPrecompiles) > 0 { for iNdEx := len(m.ActiveStaticPrecompiles) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.ActiveStaticPrecompiles[iNdEx]) @@ -2005,6 +2020,9 @@ func (m *Params) Size() (n int) { n += 1 + l + sovEvm(uint64(l)) } } + if m.HistoryServeWindow != 0 { + n += 1 + sovEvm(uint64(m.HistoryServeWindow)) + } return n } @@ -2575,6 +2593,25 @@ func (m *Params) Unmarshal(dAtA []byte) error { } m.ActiveStaticPrecompiles = append(m.ActiveStaticPrecompiles, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HistoryServeWindow", wireType) + } + m.HistoryServeWindow = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.HistoryServeWindow |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipEvm(dAtA[iNdEx:]) diff --git a/x/vm/types/params.go b/x/vm/types/params.go index fb805193c6..5b3e8d4003 100644 --- a/x/vm/types/params.go +++ b/x/vm/types/params.go @@ -43,6 +43,8 @@ var ( } ) +const DefaultHistoryServeWindow = 8192 // same as EIP-2935 + // NewParams creates a new Params instance func NewParams( extraEIPs []int64, @@ -66,6 +68,7 @@ func DefaultParams() Params { ActiveStaticPrecompiles: DefaultStaticPrecompiles, EVMChannels: DefaultEVMChannels, AccessControl: DefaultAccessControl, + HistoryServeWindow: DefaultHistoryServeWindow, } } diff --git a/x/vm/types/preinstall.go b/x/vm/types/preinstall.go index d11ac31f24..76dd298a0c 100644 --- a/x/vm/types/preinstall.go +++ b/x/vm/types/preinstall.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" ) var DefaultPreinstalls = []Preinstall{ @@ -30,6 +31,11 @@ var DefaultPreinstalls = []Preinstall{ Address: "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7", Code: "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3", }, + { + Name: "EIP-2935 - Serve historical block hashes from state", + Address: params.HistoryStorageAddress.String(), + Code: common.Bytes2Hex(params.HistoryStorageCode), + }, } // Validate performs basic validation checks on the Preinstall From 8903f9d719e44373bc7fa0f2c2a01f67ef8bd388 Mon Sep 17 00:00:00 2001 From: yoosah <34054347+yoosah@users.noreply.github.com> Date: Wed, 20 Aug 2025 23:20:55 +0900 Subject: [PATCH 13/61] refactor: decouple keeper using interface on precompile (#477) * refactor: decouple keeper using interface on precompile - Define a set of keeper interfaces in precompiles/common/interfaces.go that specify the exact methods required by the precompiles. - Update all precompile constructors and internal structs to use these new interfaces. - Modifie the precompile assembly in `evmd/precompiles.go` to inject the concrete `MsgServer` and `Querier` implementations, which satisfy the required interfaces. - Removed unnecessary keeper dependencies from the function signatures of several precompiles * docs: add changelog --- CHANGELOG.md | 1 + evmd/precompiles.go | 27 +++++++++-- .../ibc/ics20_precompile_transfer_test.go | 2 - .../ibc/v2_ics20_precompile_transfer_test.go | 2 - ibc/interfaces.go | 13 ++++++ ibc/utils.go | 3 +- precompiles/bank/bank.go | 5 +-- precompiles/common/interfaces.go | 45 +++++++++++++++++++ precompiles/distribution/distribution.go | 25 ++++++----- precompiles/distribution/query.go | 36 ++++----------- precompiles/distribution/tx.go | 16 +++---- precompiles/erc20/erc20.go | 6 +-- precompiles/gov/gov.go | 19 ++++---- precompiles/gov/query.go | 27 ++++------- precompiles/gov/tx.go | 13 +++--- precompiles/ics20/ics20.go | 20 +++------ precompiles/slashing/slashing.go | 19 ++++---- precompiles/slashing/tx.go | 4 +- precompiles/staking/query.go | 21 +++------ precompiles/staking/staking.go | 18 +++++--- precompiles/staking/tx.go | 19 +++----- precompiles/werc20/werc20.go | 4 +- .../precompiles/distribution/test_setup.go | 3 ++ .../precompiles/distribution/test_utils.go | 3 ++ .../integration/precompiles/gov/test_setup.go | 5 ++- .../precompiles/ics20/test_setup.go | 2 - .../precompiles/slashing/test_setup.go | 2 + .../precompiles/staking/test_setup.go | 3 ++ 28 files changed, 200 insertions(+), 163 deletions(-) create mode 100644 ibc/interfaces.go diff --git a/CHANGELOG.md b/CHANGELOG.md index acf3d0e9d6..1fb1e4b9b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ ### API-BREAKING +- [\#477](https://github.com/cosmos/evm/pull/477) Refactor precompile constructors to accept keeper interfaces instead of concrete implementations, breaking the existing `NewPrecompile` function signatures. - [\#456](https://github.com/cosmos/evm/pull/456) Remove non–go-ethereum JSON-RPC methods to align with Geth’s surface - [\#443](https://github.com/cosmos/evm/pull/443) Move `ante` logic from the `evmd` Go package to the `evm` package to be exported as a library. diff --git a/evmd/precompiles.go b/evmd/precompiles.go index 30165a0e92..cd7fe94b47 100644 --- a/evmd/precompiles.go +++ b/evmd/precompiles.go @@ -101,13 +101,21 @@ func NewAvailableStaticPrecompiles( panic(fmt.Errorf("failed to instantiate bech32 precompile: %w", err)) } - stakingPrecompile, err := stakingprecompile.NewPrecompile(stakingKeeper, bankKeeper, options.AddressCodec) + stakingPrecompile, err := stakingprecompile.NewPrecompile( + stakingKeeper, + stakingkeeper.NewMsgServerImpl(&stakingKeeper), + stakingkeeper.NewQuerier(&stakingKeeper), + bankKeeper, + options.AddressCodec, + ) if err != nil { panic(fmt.Errorf("failed to instantiate staking precompile: %w", err)) } distributionPrecompile, err := distprecompile.NewPrecompile( distributionKeeper, + distributionkeeper.NewMsgServerImpl(distributionKeeper), + distributionkeeper.NewQuerier(distributionKeeper), stakingKeeper, bankKeeper, options.AddressCodec, @@ -121,7 +129,6 @@ func NewAvailableStaticPrecompiles( stakingKeeper, transferKeeper, channelKeeper, - evmKeeper, ) if err != nil { panic(fmt.Errorf("failed to instantiate ICS20 precompile: %w", err)) @@ -132,12 +139,24 @@ func NewAvailableStaticPrecompiles( panic(fmt.Errorf("failed to instantiate bank precompile: %w", err)) } - govPrecompile, err := govprecompile.NewPrecompile(govKeeper, bankKeeper, codec, options.AddressCodec) + govPrecompile, err := govprecompile.NewPrecompile( + govkeeper.NewMsgServerImpl(&govKeeper), + govkeeper.NewQueryServer(&govKeeper), + bankKeeper, + codec, + options.AddressCodec, + ) if err != nil { panic(fmt.Errorf("failed to instantiate gov precompile: %w", err)) } - slashingPrecompile, err := slashingprecompile.NewPrecompile(slashingKeeper, bankKeeper, options.ValidatorAddrCodec, options.ConsensusAddrCodec) + slashingPrecompile, err := slashingprecompile.NewPrecompile( + slashingKeeper, + slashingkeeper.NewMsgServerImpl(slashingKeeper), + bankKeeper, + options.ValidatorAddrCodec, + options.ConsensusAddrCodec, + ) if err != nil { panic(fmt.Errorf("failed to instantiate slashing precompile: %w", err)) } diff --git a/evmd/tests/ibc/ics20_precompile_transfer_test.go b/evmd/tests/ibc/ics20_precompile_transfer_test.go index d06e34ff39..cae1ee3cba 100644 --- a/evmd/tests/ibc/ics20_precompile_transfer_test.go +++ b/evmd/tests/ibc/ics20_precompile_transfer_test.go @@ -51,7 +51,6 @@ func (suite *ICS20TransferTestSuite) SetupTest() { *evmAppA.StakingKeeper, evmAppA.TransferKeeper, evmAppA.IBCKeeper.ChannelKeeper, - evmAppA.EVMKeeper, ) evmAppB := suite.chainB.App.(*evmd.EVMD) suite.chainBPrecompile, _ = ics20.NewPrecompile( @@ -59,7 +58,6 @@ func (suite *ICS20TransferTestSuite) SetupTest() { *evmAppB.StakingKeeper, evmAppB.TransferKeeper, evmAppB.IBCKeeper.ChannelKeeper, - evmAppB.EVMKeeper, ) } diff --git a/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go b/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go index b71d490b93..740f8c3d89 100644 --- a/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go +++ b/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go @@ -52,7 +52,6 @@ func (suite *ICS20TransferV2TestSuite) SetupTest() { *evmAppA.StakingKeeper, evmAppA.TransferKeeper, evmAppA.IBCKeeper.ChannelKeeper, - evmAppA.EVMKeeper, ) evmAppB := suite.chainB.App.(*evmd.EVMD) suite.chainBPrecompile, _ = ics20.NewPrecompile( @@ -60,7 +59,6 @@ func (suite *ICS20TransferV2TestSuite) SetupTest() { *evmAppB.StakingKeeper, evmAppB.TransferKeeper, evmAppB.IBCKeeper.ChannelKeeper, - evmAppB.EVMKeeper, ) } diff --git a/ibc/interfaces.go b/ibc/interfaces.go new file mode 100644 index 0000000000..b0198ac4dc --- /dev/null +++ b/ibc/interfaces.go @@ -0,0 +1,13 @@ +package ibc + +import ( + cmtbytes "github.com/cometbft/cometbft/libs/bytes" + + ibctypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type TransferKeeper interface { + GetDenom(ctx sdk.Context, denomHash cmtbytes.HexBytes) (ibctypes.Denom, bool) +} diff --git a/ibc/utils.go b/ibc/utils.go index 007cfd0b38..d3261f0b24 100644 --- a/ibc/utils.go +++ b/ibc/utils.go @@ -4,7 +4,6 @@ import ( "strings" "github.com/cosmos/evm/utils" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" @@ -108,7 +107,7 @@ func GetSentCoin(rawDenom, rawAmt string) sdk.Coin { // GetDenom returns the denomination from the corresponding IBC denomination. If the // denomination is not an IBC voucher or the trace is not found, it returns an error. func GetDenom( - transferKeeper transferkeeper.Keeper, + transferKeeper TransferKeeper, ctx sdk.Context, voucherDenom string, ) (transfertypes.Denom, error) { diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index c3538204d7..ca1f492c63 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -15,7 +15,6 @@ import ( "github.com/ethereum/go-ethereum/core/vm" cmn "github.com/cosmos/evm/precompiles/common" - erc20keeper "github.com/cosmos/evm/x/erc20/keeper" evmtypes "github.com/cosmos/evm/x/vm/types" storetypes "cosmossdk.io/store/types" @@ -43,14 +42,14 @@ var f embed.FS type Precompile struct { cmn.Precompile bankKeeper cmn.BankKeeper - erc20Keeper erc20keeper.Keeper + erc20Keeper cmn.ERC20Keeper } // NewPrecompile creates a new bank Precompile instance implementing the // PrecompiledContract interface. func NewPrecompile( bankKeeper cmn.BankKeeper, - erc20Keeper erc20keeper.Keeper, + erc20Keeper cmn.ERC20Keeper, ) (*Precompile, error) { newABI, err := cmn.LoadABI(f, "abi.json") if err != nil { diff --git a/precompiles/common/interfaces.go b/precompiles/common/interfaces.go index 2993bfd451..e69e11d39a 100644 --- a/precompiles/common/interfaces.go +++ b/precompiles/common/interfaces.go @@ -3,8 +3,17 @@ package common import ( "context" + ethcommon "github.com/ethereum/go-ethereum/common" + + erc20types "github.com/cosmos/evm/x/erc20/types" + ibctypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + connectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) type BankKeeper interface { @@ -18,3 +27,39 @@ type BankKeeper interface { SpendableCoin(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin BlockedAddr(addr sdk.AccAddress) bool } + +type TransferKeeper interface { + Denom(ctx context.Context, req *ibctypes.QueryDenomRequest) (*ibctypes.QueryDenomResponse, error) + Denoms(ctx context.Context, req *ibctypes.QueryDenomsRequest) (*ibctypes.QueryDenomsResponse, error) + DenomHash(ctx context.Context, req *ibctypes.QueryDenomHashRequest) (*ibctypes.QueryDenomHashResponse, error) + Transfer(ctx context.Context, msg *ibctypes.MsgTransfer) (*ibctypes.MsgTransferResponse, error) +} + +type ChannelKeeper interface { + GetChannel(ctx sdk.Context, portID, channelID string) (channeltypes.Channel, bool) + GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, error) +} + +type DistributionKeeper interface { + WithdrawDelegationRewards(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) +} + +type StakingKeeper interface { + BondDenom(ctx context.Context) (string, error) + MaxValidators(ctx context.Context) (uint32, error) + GetDelegatorValidators(ctx context.Context, delegatorAddr sdk.AccAddress, maxRetrieve uint32) (stakingtypes.Validators, error) + GetRedelegation(ctx context.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (red stakingtypes.Redelegation, err error) + GetValidator(ctx context.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, err error) +} + +type SlashingKeeper interface { + Params(ctx context.Context, req *slashingtypes.QueryParamsRequest) (*slashingtypes.QueryParamsResponse, error) + SigningInfo(ctx context.Context, req *slashingtypes.QuerySigningInfoRequest) (*slashingtypes.QuerySigningInfoResponse, error) + SigningInfos(ctx context.Context, req *slashingtypes.QuerySigningInfosRequest) (*slashingtypes.QuerySigningInfosResponse, error) +} + +type ERC20Keeper interface { + GetCoinAddress(ctx sdk.Context, denom string) (ethcommon.Address, error) + GetERC20Map(ctx sdk.Context, erc20 ethcommon.Address) []byte + GetTokenPair(ctx sdk.Context, id []byte) (erc20types.TokenPair, bool) +} diff --git a/precompiles/distribution/distribution.go b/precompiles/distribution/distribution.go index 076ce00216..7457412f51 100644 --- a/precompiles/distribution/distribution.go +++ b/precompiles/distribution/distribution.go @@ -15,8 +15,7 @@ import ( "cosmossdk.io/core/address" storetypes "cosmossdk.io/store/types" - distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" ) var _ vm.PrecompiledContract = &Precompile{} @@ -29,16 +28,20 @@ var f embed.FS // Precompile defines the precompiled contract for distribution. type Precompile struct { cmn.Precompile - distributionKeeper distributionkeeper.Keeper - stakingKeeper stakingkeeper.Keeper - addrCdc address.Codec + distributionKeeper cmn.DistributionKeeper + distributionMsgServer distributiontypes.MsgServer + distributionQuerier distributiontypes.QueryServer + stakingKeeper cmn.StakingKeeper + addrCdc address.Codec } // NewPrecompile creates a new distribution Precompile instance as a // PrecompiledContract interface. func NewPrecompile( - distributionKeeper distributionkeeper.Keeper, - stakingKeeper stakingkeeper.Keeper, + distributionKeeper cmn.DistributionKeeper, + distributionMsgServer distributiontypes.MsgServer, + distributionQuerier distributiontypes.QueryServer, + stakingKeeper cmn.StakingKeeper, bankKeeper cmn.BankKeeper, addrCdc address.Codec, ) (*Precompile, error) { @@ -53,9 +56,11 @@ func NewPrecompile( KvGasConfig: storetypes.KVGasConfig(), TransientKVGasConfig: storetypes.TransientGasConfig(), }, - stakingKeeper: stakingKeeper, - distributionKeeper: distributionKeeper, - addrCdc: addrCdc, + stakingKeeper: stakingKeeper, + distributionKeeper: distributionKeeper, + distributionMsgServer: distributionMsgServer, + distributionQuerier: distributionQuerier, + addrCdc: addrCdc, } // SetAddress defines the address of the distribution compile contract. diff --git a/precompiles/distribution/query.go b/precompiles/distribution/query.go index 4183a58bba..0c80e51755 100644 --- a/precompiles/distribution/query.go +++ b/precompiles/distribution/query.go @@ -7,7 +7,6 @@ import ( cmn "github.com/cosmos/evm/precompiles/common" sdk "github.com/cosmos/cosmos-sdk/types" - distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" ) const ( @@ -52,9 +51,7 @@ func (p Precompile) ValidatorDistributionInfo( return nil, err } - querier := distributionkeeper.Querier{Keeper: p.distributionKeeper} - - res, err := querier.ValidatorDistributionInfo(ctx, req) + res, err := p.distributionQuerier.ValidatorDistributionInfo(ctx, req) if err != nil { return nil, err } @@ -76,9 +73,7 @@ func (p Precompile) ValidatorOutstandingRewards( return nil, err } - querier := distributionkeeper.Querier{Keeper: p.distributionKeeper} - - res, err := querier.ValidatorOutstandingRewards(ctx, req) + res, err := p.distributionQuerier.ValidatorOutstandingRewards(ctx, req) if err != nil { return nil, err } @@ -98,9 +93,7 @@ func (p Precompile) ValidatorCommission( return nil, err } - querier := distributionkeeper.Querier{Keeper: p.distributionKeeper} - - res, err := querier.ValidatorCommission(ctx, req) + res, err := p.distributionQuerier.ValidatorCommission(ctx, req) if err != nil { return nil, err } @@ -120,9 +113,7 @@ func (p Precompile) ValidatorSlashes( return nil, err } - querier := distributionkeeper.Querier{Keeper: p.distributionKeeper} - - res, err := querier.ValidatorSlashes(ctx, req) + res, err := p.distributionQuerier.ValidatorSlashes(ctx, req) if err != nil { return nil, err } @@ -144,8 +135,7 @@ func (p Precompile) DelegationRewards( return nil, err } - querier := distributionkeeper.Querier{Keeper: p.distributionKeeper} - res, err := querier.DelegationRewards(ctx, req) + res, err := p.distributionQuerier.DelegationRewards(ctx, req) if err != nil { return nil, err } @@ -165,9 +155,7 @@ func (p Precompile) DelegationTotalRewards( return nil, err } - querier := distributionkeeper.Querier{Keeper: p.distributionKeeper} - - res, err := querier.DelegationTotalRewards(ctx, req) + res, err := p.distributionQuerier.DelegationTotalRewards(ctx, req) if err != nil { return nil, err } @@ -189,9 +177,7 @@ func (p Precompile) DelegatorValidators( return nil, err } - querier := distributionkeeper.Querier{Keeper: p.distributionKeeper} - - res, err := querier.DelegatorValidators(ctx, req) + res, err := p.distributionQuerier.DelegatorValidators(ctx, req) if err != nil { return nil, err } @@ -211,9 +197,7 @@ func (p Precompile) DelegatorWithdrawAddress( return nil, err } - querier := distributionkeeper.Querier{Keeper: p.distributionKeeper} - - res, err := querier.DelegatorWithdrawAddress(ctx, req) + res, err := p.distributionQuerier.DelegatorWithdrawAddress(ctx, req) if err != nil { return nil, err } @@ -233,9 +217,7 @@ func (p Precompile) CommunityPool( return nil, err } - querier := distributionkeeper.Querier{Keeper: p.distributionKeeper} - - res, err := querier.CommunityPool(ctx, req) + res, err := p.distributionQuerier.CommunityPool(ctx, req) if err != nil { return nil, err } diff --git a/precompiles/distribution/tx.go b/precompiles/distribution/tx.go index 679ae199b5..3dea64f025 100644 --- a/precompiles/distribution/tx.go +++ b/precompiles/distribution/tx.go @@ -9,7 +9,6 @@ import ( cmn "github.com/cosmos/evm/precompiles/common" sdk "github.com/cosmos/cosmos-sdk/types" - distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" ) const ( @@ -103,8 +102,7 @@ func (p Precompile) SetWithdrawAddress( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), delegatorHexAddr.String()) } - msgSrv := distributionkeeper.NewMsgServerImpl(p.distributionKeeper) - if _, err = msgSrv.SetWithdrawAddress(ctx, msg); err != nil { + if _, err = p.distributionMsgServer.SetWithdrawAddress(ctx, msg); err != nil { return nil, err } @@ -133,8 +131,7 @@ func (p *Precompile) WithdrawDelegatorReward( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), delegatorHexAddr.String()) } - msgSrv := distributionkeeper.NewMsgServerImpl(p.distributionKeeper) - res, err := msgSrv.WithdrawDelegatorReward(ctx, msg) + res, err := p.distributionMsgServer.WithdrawDelegatorReward(ctx, msg) if err != nil { return nil, err } @@ -164,8 +161,7 @@ func (p *Precompile) WithdrawValidatorCommission( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), validatorHexAddr.String()) } - msgSrv := distributionkeeper.NewMsgServerImpl(p.distributionKeeper) - res, err := msgSrv.WithdrawValidatorCommission(ctx, msg) + res, err := p.distributionMsgServer.WithdrawValidatorCommission(ctx, msg) if err != nil { return nil, err } @@ -195,8 +191,7 @@ func (p *Precompile) FundCommunityPool( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), depositorHexAddr.String()) } - msgSrv := distributionkeeper.NewMsgServerImpl(p.distributionKeeper) - _, err = msgSrv.FundCommunityPool(ctx, msg) + _, err = p.distributionMsgServer.FundCommunityPool(ctx, msg) if err != nil { return nil, err } @@ -227,8 +222,7 @@ func (p *Precompile) DepositValidatorRewardsPool( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), depositorHexAddr.String()) } - msgSrv := distributionkeeper.NewMsgServerImpl(p.distributionKeeper) - _, err = msgSrv.DepositValidatorRewardsPool(ctx, msg) + _, err = p.distributionMsgServer.DepositValidatorRewardsPool(ctx, msg) if err != nil { return nil, err } diff --git a/precompiles/erc20/erc20.go b/precompiles/erc20/erc20.go index 9ac290cd35..99c77fc260 100644 --- a/precompiles/erc20/erc20.go +++ b/precompiles/erc20/erc20.go @@ -8,9 +8,9 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" + ibcutils "github.com/cosmos/evm/ibc" cmn "github.com/cosmos/evm/precompiles/common" erc20types "github.com/cosmos/evm/x/erc20/types" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" storetypes "cosmossdk.io/store/types" @@ -50,7 +50,7 @@ var _ vm.PrecompiledContract = &Precompile{} type Precompile struct { cmn.Precompile tokenPair erc20types.TokenPair - transferKeeper transferkeeper.Keeper + transferKeeper ibcutils.TransferKeeper erc20Keeper Erc20Keeper // BankKeeper is a public field so that the werc20 precompile can use it. BankKeeper cmn.BankKeeper @@ -62,7 +62,7 @@ func NewPrecompile( tokenPair erc20types.TokenPair, bankKeeper cmn.BankKeeper, erc20Keeper Erc20Keeper, - transferKeeper transferkeeper.Keeper, + transferKeeper ibcutils.TransferKeeper, ) (*Precompile, error) { newABI, err := cmn.LoadABI(f, abiPath) if err != nil { diff --git a/precompiles/gov/gov.go b/precompiles/gov/gov.go index ca1aeada8a..619c1e9beb 100644 --- a/precompiles/gov/gov.go +++ b/precompiles/gov/gov.go @@ -18,7 +18,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" ) var _ vm.PrecompiledContract = &Precompile{} @@ -31,9 +31,10 @@ var f embed.FS // Precompile defines the precompiled contract for gov. type Precompile struct { cmn.Precompile - govKeeper govkeeper.Keeper - codec codec.Codec - addrCdc address.Codec + govMsgServer govtypes.MsgServer + govQuerier govtypes.QueryServer + codec codec.Codec + addrCdc address.Codec } // LoadABI loads the gov ABI from the embedded abi.json file @@ -45,7 +46,8 @@ func LoadABI() (abi.ABI, error) { // NewPrecompile creates a new gov Precompile instance as a // PrecompiledContract interface. func NewPrecompile( - govKeeper govkeeper.Keeper, + govMsgServer govtypes.MsgServer, + govQuerier govtypes.QueryServer, bankKeeper cmn.BankKeeper, codec codec.Codec, addrCdc address.Codec, @@ -61,9 +63,10 @@ func NewPrecompile( KvGasConfig: storetypes.KVGasConfig(), TransientKVGasConfig: storetypes.TransientGasConfig(), }, - govKeeper: govKeeper, - codec: codec, - addrCdc: addrCdc, + govMsgServer: govMsgServer, + govQuerier: govQuerier, + codec: codec, + addrCdc: addrCdc, } // SetAddress defines the address of the gov precompiled contract. diff --git a/precompiles/gov/query.go b/precompiles/gov/query.go index 9a6df983a6..0b389b9a07 100644 --- a/precompiles/gov/query.go +++ b/precompiles/gov/query.go @@ -5,7 +5,6 @@ import ( "github.com/ethereum/go-ethereum/core/vm" sdk "github.com/cosmos/cosmos-sdk/types" - govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" ) const ( @@ -41,8 +40,7 @@ func (p *Precompile) GetVotes( return nil, err } - queryServer := govkeeper.NewQueryServer(&p.govKeeper) - res, err := queryServer.Votes(ctx, queryVotesReq) + res, err := p.govQuerier.Votes(ctx, queryVotesReq) if err != nil { return nil, err } @@ -66,8 +64,7 @@ func (p *Precompile) GetVote( return nil, err } - queryServer := govkeeper.NewQueryServer(&p.govKeeper) - res, err := queryServer.Vote(ctx, queryVotesReq) + res, err := p.govQuerier.Vote(ctx, queryVotesReq) if err != nil { return nil, err } @@ -91,8 +88,7 @@ func (p *Precompile) GetDeposit( return nil, err } - queryServer := govkeeper.NewQueryServer(&p.govKeeper) - res, err := queryServer.Deposit(ctx, queryDepositReq) + res, err := p.govQuerier.Deposit(ctx, queryDepositReq) if err != nil { return nil, err } @@ -116,8 +112,7 @@ func (p *Precompile) GetDeposits( return nil, err } - queryServer := govkeeper.NewQueryServer(&p.govKeeper) - res, err := queryServer.Deposits(ctx, queryDepositsReq) + res, err := p.govQuerier.Deposits(ctx, queryDepositsReq) if err != nil { return nil, err } @@ -141,8 +136,7 @@ func (p *Precompile) GetTallyResult( return nil, err } - queryServer := govkeeper.NewQueryServer(&p.govKeeper) - res, err := queryServer.TallyResult(ctx, queryTallyResultReq) + res, err := p.govQuerier.TallyResult(ctx, queryTallyResultReq) if err != nil { return nil, err } @@ -163,8 +157,7 @@ func (p *Precompile) GetProposal( return nil, err } - queryServer := govkeeper.NewQueryServer(&p.govKeeper) - res, err := queryServer.Proposal(ctx, queryProposalReq) + res, err := p.govQuerier.Proposal(ctx, queryProposalReq) if err != nil { return nil, err } @@ -188,8 +181,7 @@ func (p *Precompile) GetProposals( return nil, err } - queryServer := govkeeper.NewQueryServer(&p.govKeeper) - res, err := queryServer.Proposals(ctx, queryProposalsReq) + res, err := p.govQuerier.Proposals(ctx, queryProposalsReq) if err != nil { return nil, err } @@ -213,8 +205,7 @@ func (p *Precompile) GetParams( return nil, err } - queryServer := govkeeper.NewQueryServer(&p.govKeeper) - res, err := queryServer.Params(ctx, queryParamsReq) + res, err := p.govQuerier.Params(ctx, queryParamsReq) if err != nil { return nil, err } @@ -235,7 +226,7 @@ func (p *Precompile) GetConstitution( return nil, err } - res, err := govkeeper.NewQueryServer(&p.govKeeper).Constitution(ctx, req) + res, err := p.govQuerier.Constitution(ctx, req) if err != nil { return nil, err } diff --git a/precompiles/gov/tx.go b/precompiles/gov/tx.go index f9b6dea55f..46569261b2 100644 --- a/precompiles/gov/tx.go +++ b/precompiles/gov/tx.go @@ -9,7 +9,6 @@ import ( cmn "github.com/cosmos/evm/precompiles/common" sdk "github.com/cosmos/cosmos-sdk/types" - govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" ) const ( @@ -43,7 +42,7 @@ func (p *Precompile) SubmitProposal( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), proposerHexAddr.String()) } - res, err := govkeeper.NewMsgServerImpl(&p.govKeeper).SubmitProposal(ctx, msg) + res, err := p.govMsgServer.SubmitProposal(ctx, msg) if err != nil { return nil, err } @@ -73,7 +72,7 @@ func (p *Precompile) Deposit( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), depositorHexAddr.String()) } - if _, err = govkeeper.NewMsgServerImpl(&p.govKeeper).Deposit(ctx, msg); err != nil { + if _, err = p.govMsgServer.Deposit(ctx, msg); err != nil { return nil, err } @@ -102,7 +101,7 @@ func (p *Precompile) CancelProposal( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), proposerHexAddr.String()) } - if _, err = govkeeper.NewMsgServerImpl(&p.govKeeper).CancelProposal(ctx, msg); err != nil { + if _, err = p.govMsgServer.CancelProposal(ctx, msg); err != nil { return nil, err } @@ -131,8 +130,7 @@ func (p Precompile) Vote( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), voterHexAddr.String()) } - msgSrv := govkeeper.NewMsgServerImpl(&p.govKeeper) - if _, err = msgSrv.Vote(ctx, msg); err != nil { + if _, err = p.govMsgServer.Vote(ctx, msg); err != nil { return nil, err } @@ -161,8 +159,7 @@ func (p Precompile) VoteWeighted( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), voterHexAddr.String()) } - msgSrv := govkeeper.NewMsgServerImpl(&p.govKeeper) - if _, err = msgSrv.VoteWeighted(ctx, msg); err != nil { + if _, err = p.govMsgServer.VoteWeighted(ctx, msg); err != nil { return nil, err } diff --git a/precompiles/ics20/ics20.go b/precompiles/ics20/ics20.go index 4ed33272e4..73f8b177db 100644 --- a/precompiles/ics20/ics20.go +++ b/precompiles/ics20/ics20.go @@ -10,14 +10,9 @@ import ( "github.com/ethereum/go-ethereum/core/vm" cmn "github.com/cosmos/evm/precompiles/common" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" - evmkeeper "github.com/cosmos/evm/x/vm/keeper" evmtypes "github.com/cosmos/evm/x/vm/types" - channelkeeper "github.com/cosmos/ibc-go/v10/modules/core/04-channel/keeper" storetypes "cosmossdk.io/store/types" - - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) // PrecompileAddress of the ICS-20 EVM extension in hex format. @@ -33,20 +28,18 @@ var f embed.FS type Precompile struct { cmn.Precompile bankKeeper cmn.BankKeeper - stakingKeeper stakingkeeper.Keeper - transferKeeper transferkeeper.Keeper - channelKeeper *channelkeeper.Keeper - evmKeeper *evmkeeper.Keeper + stakingKeeper cmn.StakingKeeper + transferKeeper cmn.TransferKeeper + channelKeeper cmn.ChannelKeeper } // NewPrecompile creates a new ICS-20 Precompile instance as a // PrecompiledContract interface. func NewPrecompile( bankKeeper cmn.BankKeeper, - stakingKeeper stakingkeeper.Keeper, - transferKeeper transferkeeper.Keeper, - channelKeeper *channelkeeper.Keeper, - evmKeeper *evmkeeper.Keeper, + stakingKeeper cmn.StakingKeeper, + transferKeeper cmn.TransferKeeper, + channelKeeper cmn.ChannelKeeper, ) (*Precompile, error) { newAbi, err := cmn.LoadABI(f, "abi.json") if err != nil { @@ -63,7 +56,6 @@ func NewPrecompile( transferKeeper: transferKeeper, channelKeeper: channelKeeper, stakingKeeper: stakingKeeper, - evmKeeper: evmKeeper, } // SetAddress defines the address of the ICS-20 compile contract. diff --git a/precompiles/slashing/slashing.go b/precompiles/slashing/slashing.go index 3a9c96950f..f5287ce444 100644 --- a/precompiles/slashing/slashing.go +++ b/precompiles/slashing/slashing.go @@ -18,7 +18,7 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" ) var _ vm.PrecompiledContract = &Precompile{} @@ -31,9 +31,10 @@ var f embed.FS // Precompile defines the precompiled contract for slashing. type Precompile struct { cmn.Precompile - slashingKeeper slashingkeeper.Keeper - consCodec runtime.ConsensusAddressCodec - valCodec runtime.ValidatorAddressCodec + slashingKeeper cmn.SlashingKeeper + slashingMsgServer slashingtypes.MsgServer + consCodec runtime.ConsensusAddressCodec + valCodec runtime.ValidatorAddressCodec } // LoadABI loads the slashing ABI from the embedded abi.json file @@ -45,7 +46,8 @@ func LoadABI() (abi.ABI, error) { // NewPrecompile creates a new slashing Precompile instance as a // PrecompiledContract interface. func NewPrecompile( - slashingKeeper slashingkeeper.Keeper, + slashingKeeper cmn.SlashingKeeper, + slashingMsgServer slashingtypes.MsgServer, bankKeeper cmn.BankKeeper, valCdc, consCdc address.Codec, ) (*Precompile, error) { @@ -60,9 +62,10 @@ func NewPrecompile( KvGasConfig: storetypes.KVGasConfig(), TransientKVGasConfig: storetypes.TransientGasConfig(), }, - slashingKeeper: slashingKeeper, - valCodec: valCdc, - consCodec: consCdc, + slashingKeeper: slashingKeeper, + slashingMsgServer: slashingMsgServer, + valCodec: valCdc, + consCodec: consCdc, } // SetAddress defines the address of the slashing precompiled contract. diff --git a/precompiles/slashing/tx.go b/precompiles/slashing/tx.go index 12e1103cdc..abb21309bb 100644 --- a/precompiles/slashing/tx.go +++ b/precompiles/slashing/tx.go @@ -10,7 +10,6 @@ import ( cmn "github.com/cosmos/evm/precompiles/common" sdk "github.com/cosmos/cosmos-sdk/types" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" "github.com/cosmos/cosmos-sdk/x/slashing/types" ) @@ -52,8 +51,7 @@ func (p Precompile) Unjail( ValidatorAddr: valAddr, } - msgSrv := slashingkeeper.NewMsgServerImpl(p.slashingKeeper) - if _, err := msgSrv.Unjail(ctx, msg); err != nil { + if _, err := p.slashingMsgServer.Unjail(ctx, msg); err != nil { return nil, err } diff --git a/precompiles/staking/query.go b/precompiles/staking/query.go index cf61a2c05b..006627653b 100644 --- a/precompiles/staking/query.go +++ b/precompiles/staking/query.go @@ -11,7 +11,6 @@ import ( cmn "github.com/cosmos/evm/precompiles/common" sdk "github.com/cosmos/cosmos-sdk/types" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) const ( @@ -47,9 +46,7 @@ func (p Precompile) Delegation( return nil, err } - queryServer := stakingkeeper.Querier{Keeper: &p.stakingKeeper} - - res, err := queryServer.Delegation(ctx, req) + res, err := p.stakingQuerier.Delegation(ctx, req) if err != nil { // If there is no delegation found, return the response with zero values. if strings.Contains(err.Error(), fmt.Sprintf(ErrNoDelegationFound, req.DelegatorAddr, req.ValidatorAddr)) { @@ -81,9 +78,7 @@ func (p Precompile) UnbondingDelegation( return nil, err } - queryServer := stakingkeeper.Querier{Keeper: &p.stakingKeeper} - - res, err := queryServer.UnbondingDelegation(ctx, req) + res, err := p.stakingQuerier.UnbondingDelegation(ctx, req) if err != nil { // return empty unbonding delegation output if the unbonding delegation is not found expError := fmt.Sprintf("unbonding delegation with delegator %s not found for validator %s", req.DelegatorAddr, req.ValidatorAddr) @@ -110,9 +105,7 @@ func (p Precompile) Validator( return nil, err } - queryServer := stakingkeeper.Querier{Keeper: &p.stakingKeeper} - - res, err := queryServer.Validator(ctx, req) + res, err := p.stakingQuerier.Validator(ctx, req) if err != nil { // return empty validator info if the validator is not found expError := fmt.Sprintf("validator %s not found", req.ValidatorAddr) @@ -139,9 +132,7 @@ func (p Precompile) Validators( return nil, err } - queryServer := stakingkeeper.Querier{Keeper: &p.stakingKeeper} - - res, err := queryServer.Validators(ctx, req) + res, err := p.stakingQuerier.Validators(ctx, req) if err != nil { return nil, err } @@ -185,9 +176,7 @@ func (p Precompile) Redelegations( return nil, err } - queryServer := stakingkeeper.Querier{Keeper: &p.stakingKeeper} - - res, err := queryServer.Redelegations(ctx, req) + res, err := p.stakingQuerier.Redelegations(ctx, req) if err != nil { return nil, err } diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go index 383e7ca6a8..78aad51f18 100644 --- a/precompiles/staking/staking.go +++ b/precompiles/staking/staking.go @@ -16,7 +16,7 @@ import ( storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) var _ vm.PrecompiledContract = &Precompile{} @@ -29,8 +29,10 @@ var f embed.FS // Precompile defines the precompiled contract for staking. type Precompile struct { cmn.Precompile - stakingKeeper stakingkeeper.Keeper - addrCdc address.Codec + stakingKeeper cmn.StakingKeeper + stakingMsgServer stakingtypes.MsgServer + stakingQuerier stakingtypes.QueryServer + addrCdc address.Codec } // LoadABI loads the staking ABI from the embedded abi.json file @@ -42,7 +44,9 @@ func LoadABI() (abi.ABI, error) { // NewPrecompile creates a new staking Precompile instance as a // PrecompiledContract interface. func NewPrecompile( - stakingKeeper stakingkeeper.Keeper, + stakingKeeper cmn.StakingKeeper, + stakingMsgServer stakingtypes.MsgServer, + stakingQuerier stakingtypes.QueryServer, bankKeeper cmn.BankKeeper, addrCdc address.Codec, ) (*Precompile, error) { @@ -57,8 +61,10 @@ func NewPrecompile( KvGasConfig: storetypes.KVGasConfig(), TransientKVGasConfig: storetypes.TransientGasConfig(), }, - stakingKeeper: stakingKeeper, - addrCdc: addrCdc, + stakingKeeper: stakingKeeper, + stakingMsgServer: stakingMsgServer, + stakingQuerier: stakingQuerier, + addrCdc: addrCdc, } // SetAddress defines the address of the staking precompiled contract. p.SetAddress(common.HexToAddress(evmtypes.StakingPrecompileAddress)) diff --git a/precompiles/staking/tx.go b/precompiles/staking/tx.go index 2ce2c54658..a84a53052e 100644 --- a/precompiles/staking/tx.go +++ b/precompiles/staking/tx.go @@ -10,7 +10,6 @@ import ( cmn "github.com/cosmos/evm/precompiles/common" sdk "github.com/cosmos/cosmos-sdk/types" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) const ( @@ -69,8 +68,7 @@ func (p Precompile) CreateValidator( } // Execute the transaction using the message server - msgSrv := stakingkeeper.NewMsgServerImpl(&p.stakingKeeper) - if _, err = msgSrv.CreateValidator(ctx, msg); err != nil { + if _, err = p.stakingMsgServer.CreateValidator(ctx, msg); err != nil { return nil, err } @@ -116,8 +114,7 @@ func (p Precompile) EditValidator( } // Execute the transaction using the message server - msgSrv := stakingkeeper.NewMsgServerImpl(&p.stakingKeeper) - if _, err = msgSrv.EditValidator(ctx, msg); err != nil { + if _, err = p.stakingMsgServer.EditValidator(ctx, msg); err != nil { return nil, err } @@ -163,8 +160,7 @@ func (p *Precompile) Delegate( } // Execute the transaction using the message server - msgSrv := stakingkeeper.NewMsgServerImpl(&p.stakingKeeper) - if _, err = msgSrv.Delegate(ctx, msg); err != nil { + if _, err = p.stakingMsgServer.Delegate(ctx, msg); err != nil { return nil, err } @@ -211,8 +207,7 @@ func (p Precompile) Undelegate( } // Execute the transaction using the message server - msgSrv := stakingkeeper.NewMsgServerImpl(&p.stakingKeeper) - res, err := msgSrv.Undelegate(ctx, msg) + res, err := p.stakingMsgServer.Undelegate(ctx, msg) if err != nil { return nil, err } @@ -261,8 +256,7 @@ func (p Precompile) Redelegate( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), delegatorHexAddr.String()) } - msgSrv := stakingkeeper.NewMsgServerImpl(&p.stakingKeeper) - res, err := msgSrv.BeginRedelegate(ctx, msg) + res, err := p.stakingMsgServer.BeginRedelegate(ctx, msg) if err != nil { return nil, err } @@ -310,8 +304,7 @@ func (p Precompile) CancelUnbondingDelegation( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), delegatorHexAddr.String()) } - msgSrv := stakingkeeper.NewMsgServerImpl(&p.stakingKeeper) - if _, err = msgSrv.CancelUnbondingDelegation(ctx, msg); err != nil { + if _, err = p.stakingMsgServer.CancelUnbondingDelegation(ctx, msg); err != nil { return nil, err } diff --git a/precompiles/werc20/werc20.go b/precompiles/werc20/werc20.go index 0f1312305c..44bb190759 100644 --- a/precompiles/werc20/werc20.go +++ b/precompiles/werc20/werc20.go @@ -10,10 +10,10 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" + ibcutils "github.com/cosmos/evm/ibc" cmn "github.com/cosmos/evm/precompiles/common" erc20 "github.com/cosmos/evm/precompiles/erc20" erc20types "github.com/cosmos/evm/x/erc20/types" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" ) // abiPath defines the path to the WERC-20 precompile ABI JSON file. @@ -51,7 +51,7 @@ func NewPrecompile( tokenPair erc20types.TokenPair, bankKeeper cmn.BankKeeper, erc20Keeper Erc20Keeper, - transferKeeper transferkeeper.Keeper, + transferKeeper ibcutils.TransferKeeper, ) (*Precompile, error) { newABI, err := LoadABI() if err != nil { diff --git a/tests/integration/precompiles/distribution/test_setup.go b/tests/integration/precompiles/distribution/test_setup.go index e611fea6c5..57b15cb850 100644 --- a/tests/integration/precompiles/distribution/test_setup.go +++ b/tests/integration/precompiles/distribution/test_setup.go @@ -18,6 +18,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" ) @@ -131,6 +132,8 @@ func (s *PrecompileTestSuite) SetupTest() { s.network = nw s.precompile, err = distribution.NewPrecompile( s.network.App.GetDistrKeeper(), + distrkeeper.NewMsgServerImpl(s.network.App.GetDistrKeeper()), + distrkeeper.NewQuerier(s.network.App.GetDistrKeeper()), *s.network.App.GetStakingKeeper(), s.network.App.GetBankKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), diff --git a/tests/integration/precompiles/distribution/test_utils.go b/tests/integration/precompiles/distribution/test_utils.go index d5f03c6a58..13ddda3231 100644 --- a/tests/integration/precompiles/distribution/test_utils.go +++ b/tests/integration/precompiles/distribution/test_utils.go @@ -10,6 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -84,6 +85,8 @@ func (s *PrecompileTestSuite) fundAccountWithBaseDenom(ctx sdk.Context, addr sdk func (s *PrecompileTestSuite) getStakingPrecompile() (*staking.Precompile, error) { return staking.NewPrecompile( *s.network.App.GetStakingKeeper(), + stakingkeeper.NewMsgServerImpl(s.network.App.GetStakingKeeper()), + stakingkeeper.NewQuerier(s.network.App.GetStakingKeeper()), s.network.App.GetBankKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), ) diff --git a/tests/integration/precompiles/gov/test_setup.go b/tests/integration/precompiles/gov/test_setup.go index 1c71b3f4ff..312f91b479 100644 --- a/tests/integration/precompiles/gov/test_setup.go +++ b/tests/integration/precompiles/gov/test_setup.go @@ -19,6 +19,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" ) @@ -136,8 +137,10 @@ func (s *PrecompileTestSuite) SetupTest() { s.keyring = keyring s.network = nw + govKeeper := s.network.App.GetGovKeeper() if s.precompile, err = gov.NewPrecompile( - s.network.App.GetGovKeeper(), + govkeeper.NewMsgServerImpl(&govKeeper), + govkeeper.NewQueryServer(&govKeeper), s.network.App.GetBankKeeper(), s.network.App.AppCodec(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), diff --git a/tests/integration/precompiles/ics20/test_setup.go b/tests/integration/precompiles/ics20/test_setup.go index 28ce0c3993..462e7c6b7b 100644 --- a/tests/integration/precompiles/ics20/test_setup.go +++ b/tests/integration/precompiles/ics20/test_setup.go @@ -48,7 +48,6 @@ func (s *PrecompileTestSuite) SetupTest() { *evmAppA.GetStakingKeeper(), evmAppA.GetTransferKeeper(), evmAppA.GetIBCKeeper().ChannelKeeper, - evmAppA.GetEVMKeeper(), ) s.chainABondDenom, _ = evmAppA.GetStakingKeeper().BondDenom(s.chainA.GetContext()) evmAppB := s.chainB.App.(evm.EvmApp) @@ -57,7 +56,6 @@ func (s *PrecompileTestSuite) SetupTest() { *evmAppB.GetStakingKeeper(), evmAppB.GetTransferKeeper(), evmAppB.GetIBCKeeper().ChannelKeeper, - evmAppB.GetEVMKeeper(), ) s.chainBBondDenom, _ = evmAppB.GetStakingKeeper().BondDenom(s.chainB.GetContext()) } diff --git a/tests/integration/precompiles/slashing/test_setup.go b/tests/integration/precompiles/slashing/test_setup.go index 7558a34f57..f5118c5e67 100644 --- a/tests/integration/precompiles/slashing/test_setup.go +++ b/tests/integration/precompiles/slashing/test_setup.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/address" sdk "github.com/cosmos/cosmos-sdk/types" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" ) type PrecompileTestSuite struct { @@ -56,6 +57,7 @@ func (s *PrecompileTestSuite) SetupTest() { if s.precompile, err = slashing.NewPrecompile( s.network.App.GetSlashingKeeper(), + slashingkeeper.NewMsgServerImpl(s.network.App.GetSlashingKeeper()), s.network.App.GetBankKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()), address.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()), diff --git a/tests/integration/precompiles/staking/test_setup.go b/tests/integration/precompiles/staking/test_setup.go index 2e7aedfa57..cb4e04d63e 100644 --- a/tests/integration/precompiles/staking/test_setup.go +++ b/tests/integration/precompiles/staking/test_setup.go @@ -16,6 +16,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) const InitialTestBalance = 1000000000000000000 // 1 atom @@ -82,6 +83,8 @@ func (s *PrecompileTestSuite) SetupTest() { if s.precompile, err = staking.NewPrecompile( *s.network.App.GetStakingKeeper(), + stakingkeeper.NewMsgServerImpl(s.network.App.GetStakingKeeper()), + stakingkeeper.NewQuerier(s.network.App.GetStakingKeeper()), s.network.App.GetBankKeeper(), address.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), ); err != nil { From 7451d9bf76a201bd54e530fad88c19062ce2558b Mon Sep 17 00:00:00 2001 From: Alex | Interchain Labs Date: Wed, 20 Aug 2025 11:37:26 -0400 Subject: [PATCH 14/61] set-up (#491) --- CHANGELOG.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fb1e4b9b4..67a65c1113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,23 @@ ## UNRELEASED -## v0.4.0 +### DEPENDENCIES + +### BUG FIXES + +### IMPROVEMENTS + +- [\#467](https://github.com/cosmos/evm/pull/467) Ensure SetGlobalEVMMempool is thread-safe and only sets global mempool instance once. + +### FEATURES + +### STATE BREAKING + +### API-BREAKING + +- [\#477](https://github.com/cosmos/evm/pull/477) Refactor precompile constructors to accept keeper interfaces instead of concrete implementations, breaking the existing `NewPrecompile` function signatures. + +## v0.4.1 ### DEPENDENCIES @@ -45,7 +61,6 @@ - [\#398](https://github.com/cosmos/evm/pull/398) Post-audit security fixes (batch 4) - [\#442](https://github.com/cosmos/evm/pull/442) Prevent nil pointer by checking error in gov precompile FromResponse. - [\#387](https://github.com/cosmos/evm/pull/387) (Experimental) EVM-compatible appside mempool -- [\#467](https://github.com/cosmos/evm/pull/467) Ensure SetGlobalEVMMempool is thread-safe and only sets global mempool instance once. ### FEATURES @@ -59,7 +74,6 @@ ### API-BREAKING -- [\#477](https://github.com/cosmos/evm/pull/477) Refactor precompile constructors to accept keeper interfaces instead of concrete implementations, breaking the existing `NewPrecompile` function signatures. - [\#456](https://github.com/cosmos/evm/pull/456) Remove non–go-ethereum JSON-RPC methods to align with Geth’s surface - [\#443](https://github.com/cosmos/evm/pull/443) Move `ante` logic from the `evmd` Go package to the `evm` package to be exported as a library. From befde4fafa15c469a181708043224c95dea66c52 Mon Sep 17 00:00:00 2001 From: LEE JUNSEO Date: Thu, 21 Aug 2025 01:25:25 +0900 Subject: [PATCH 15/61] feat: Delete EVM instance in AnteHandler (#352) * test: adjusts GasTipCap to equal GasFeeCap when it exceeds the maximum fee cap * ensures adequate fees for bank msg send * Optimize CanTransfer AnteHandler * refactor(antehandler): remove stateDB allocation * chore: replace GlobalEVMMempool by passing to JSONRPC on initiate (#467) * chore: ensure SetGlobalEVMMempool is thread-safe and only set once keep singleton behavior on concurrent initialization * doc * keep reset * pass in mempool * cleanup --------- Co-authored-by: Vlad J Co-authored-by: Alex | Interchain Labs * Problem: eip-2935 is not implemented (#407) * Problem: eip-2935 is not implemented Solution: - adapt the implementation from geth * change BLOCKHASH opcode to query contract storage * commit statedb * fix panic * temp * just emulate the contract behavior with native code * fix test * fix lint * fix lint * revert unneeded changes * fix test * revert * only set contract storage if it's deployed * fix build * add history serve window parameter * cleanup * fix lint --------- Co-authored-by: Alex | Interchain Labs Co-authored-by: Vlad J * fix : EVMKeeper GetBalance missed when version upgrades * add CHANGELOG --------- Co-authored-by: mmsqe Co-authored-by: Alex | Interchain Labs Co-authored-by: Vlad J Co-authored-by: yihuang --- CHANGELOG.md | 1 + ante/evm/07_can_transfer.go | 14 +------------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67a65c1113..bc277c1da9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### IMPROVEMENTS +- [\#352](https://github.com/cosmos/evm/pull/352) Remove the creation of a Geth EVM instance, stateDB during the AnteHandler balance check. - [\#467](https://github.com/cosmos/evm/pull/467) Ensure SetGlobalEVMMempool is thread-safe and only sets global mempool instance once. ### FEATURES diff --git a/ante/evm/07_can_transfer.go b/ante/evm/07_can_transfer.go index 8ff5c966d6..21d0fe6c05 100644 --- a/ante/evm/07_can_transfer.go +++ b/ante/evm/07_can_transfer.go @@ -3,12 +3,10 @@ package evm import ( "math/big" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" anteinterfaces "github.com/cosmos/evm/ante/interfaces" "github.com/cosmos/evm/utils" - "github.com/cosmos/evm/x/vm/statedb" evmtypes "github.com/cosmos/evm/x/vm/types" errorsmod "cosmossdk.io/errors" @@ -34,23 +32,13 @@ func CanTransfer( ) } - // NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below - cfg := &statedb.EVMConfig{ - Params: params, - CoinBase: common.Address{}, - BaseFee: baseFee, - } - - stateDB := statedb.New(ctx, evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash()))) - evm := evmKeeper.NewEVM(ctx, msg, cfg, evmtypes.NewNoOpTracer(), stateDB) - // 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 convertedValue, err := utils.Uint256FromBigInt(msg.Value) if err != nil { return err } - if msg.Value.Sign() > 0 && !evm.Context.CanTransfer(stateDB, msg.From, convertedValue) { + if msg.Value.Sign() > 0 && evmKeeper.GetAccount(ctx, msg.From).Balance.Cmp(convertedValue) < 0 { return errorsmod.Wrapf( errortypes.ErrInsufficientFunds, "failed to transfer %s from address %s using the EVM block context transfer function", From 3991c2c4afa1422abc7063fbe4f131aa45fad12a Mon Sep 17 00:00:00 2001 From: Haber Date: Thu, 21 Aug 2025 03:43:08 +0900 Subject: [PATCH 16/61] tests: add revert error e2e tests for contract and precompile calls (#476) * update launch script path & remove duplicate We should use only one launch script. Managing both is extra un-necessary overhead * chore: add private keys info in local_node.sh * add bech32 and bank e2e tests * add undelegate test * faster local node and udpate delegate test * add create validator tc * update delegate tc include event checking also * update test codes added event checking to undelegate tc receipt has hash field instead of transactionHash * chore: remove un-used variable * add edit validator tc * add cancel unbonding tc * chore: format test files * add redelegate tc * skip gas estimation for faster tests * add redelegations query test * chore: refactor variable names * chore: change filename * add validators query test and fix gov interface * add set withdraw address tc * order test sequences and add withdraw delegator reward tc * add claim rewards tc * add withdraw validator commission * add fund community pool tc * add deposit validator rewards pool tc * add validator queries tc * chore: unify convention * add erc20 tc * update local node script it should contains every precompiles by default * fix slashing query and add e2e tests for it * fix: decode bech32 consensus address before converting to bytes The consensus address was previously used in its bech32-encoded form (a 52-character string), which is incorrect. This led to attempts to interpret a bech32 string directly as a 20-byte address, resulting in invalid conversions and data loss. This fix ensures the bech32 consensus address is properly decoded into its original 20-byte form before further processing, preserving the correct address representation expected in EVM-compatible byte format. * add gov tc * add more tcs to gov precompile (should fix cancel) * fix cancel proposal tc * add p256 tc * remove un-used variables * add werc20 tc * more timeout and verbose log * fix local_node.sh * add edgecase test for staking precompile and lint local node script * revert solidity test script change * chore: trim comments * p256 happy case * refactoring * refactor: make findEvent as common * check delegation shares and balance also * add checking user balance for withdraw delegator reward test * add checking user balance for claim rewards tc * strict balance check * add user balance check for fund community pool tc * add user balance check for deposit validator rewards pool tc * should use owner, not contract address itself * add event checks for erc20 precompile tc * add balance checks for werc20 tc * add balance check for gov deposit tc * add balance check for gov cancel proposal tc * add revert e2e test cases * lint: unused variable * chore(tests): set default evm chain id - 262144 * WIP: test: enhance revert test * WIP: test: enhance revert test * WIP: test: enhance revert test * test: enhance revert test * chore(tests): refine code * chore: update changelog * chore: add semi-colon --------- Co-authored-by: zsystm Co-authored-by: Vlad J Co-authored-by: Hyunwoo Lee <124245155+zsystm@users.noreply.github.com> Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + package-lock.json | 6 + tests/solidity/init-node.sh | 145 ------- .../contracts/RevertTestContract.sol | 221 +++++++++++ .../contracts/StandardRevertTestContract.sol | 261 ++++++++++++ .../suites/revert_cases/hardhat.config.js | 27 ++ .../solidity/suites/revert_cases/package.json | 35 ++ .../suites/revert_cases/test/common.js | 41 ++ .../test/precompile_revert_cases.js | 239 +++++++++++ .../test/standard_revert_cases.js | 374 ++++++++++++++++++ .../suites/revert_cases/test/test_helper.js | 144 +++++++ 11 files changed, 1349 insertions(+), 145 deletions(-) create mode 100644 package-lock.json delete mode 100755 tests/solidity/init-node.sh create mode 100644 tests/solidity/suites/revert_cases/contracts/RevertTestContract.sol create mode 100644 tests/solidity/suites/revert_cases/contracts/StandardRevertTestContract.sol create mode 100644 tests/solidity/suites/revert_cases/hardhat.config.js create mode 100644 tests/solidity/suites/revert_cases/package.json create mode 100644 tests/solidity/suites/revert_cases/test/common.js create mode 100644 tests/solidity/suites/revert_cases/test/precompile_revert_cases.js create mode 100644 tests/solidity/suites/revert_cases/test/standard_revert_cases.js create mode 100644 tests/solidity/suites/revert_cases/test/test_helper.js diff --git a/CHANGELOG.md b/CHANGELOG.md index bc277c1da9..11cbd3b753 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ - [\#398](https://github.com/cosmos/evm/pull/398) Post-audit security fixes (batch 4) - [\#442](https://github.com/cosmos/evm/pull/442) Prevent nil pointer by checking error in gov precompile FromResponse. - [\#387](https://github.com/cosmos/evm/pull/387) (Experimental) EVM-compatible appside mempool +- [\#476](https://github.com/cosmos/evm/pull/476) Add revert error e2e tests for contract and precompile calls ### FEATURES diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..819063d721 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "evm", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/tests/solidity/init-node.sh b/tests/solidity/init-node.sh deleted file mode 100755 index 249b6a5320..0000000000 --- a/tests/solidity/init-node.sh +++ /dev/null @@ -1,145 +0,0 @@ -#!/bin/bash - -set -ex - -# TODO: remove this script and just use the local node script for it, add flag to start node in given directory - -CHAINID="${CHAIN_ID:-cosmos_262144-1}" -MONIKER="localtestnet" -KEYRING="test" # remember to change to other types of keyring like 'file' in-case exposing to outside world, otherwise your balance will be wiped quickly. The keyring test does not require private key to steal tokens from you -KEYALGO="eth_secp256k1" #gitleaks:allow -LOGLEVEL="info" -# to trace evm -#TRACE="--trace" -TRACE="" -PRUNING="default" -#PRUNING="custom" - -CHAINDIR="$HOME/.tmp-evmd-solidity-tests" # TODO: make configurable like chain id -GENESIS="$CHAINDIR/config/genesis.json" -TMP_GENESIS="$CHAINDIR/config/tmp_genesis.json" -APP_TOML="$CHAINDIR/config/app.toml" -CONFIG_TOML="$CHAINDIR/config/config.toml" - -# make sure to reset chain directory before test -rm -rf "$CHAINDIR" - -# validate dependencies are installed -command -v jq >/dev/null 2>&1 || { - echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/" - exit 1 -} - -# used to exit on first error (any non-zero exit code) -set -e - -# feemarket params basefee -BASEFEE=1000000000 - -# Set client config -evmd config set client chain-id "$CHAINID" --home "$CHAINDIR" -evmd config set client keyring-backend "$KEYRING" --home "$CHAINDIR" - -# myKey address 0x7cb61d4117ae31a12e393a1cfa3bac666481d02e -VAL_KEY="mykey" -VAL_MNEMONIC="gesture inject test cycle original hollow east ridge hen combine junk child bacon zero hope comfort vacuum milk pitch cage oppose unhappy lunar seat" - -# user1 address 0xc6fe5d33615a1c52c08018c47e8bc53646a0e101 -USER1_KEY="user1" -USER1_MNEMONIC="copper push brief egg scan entry inform record adjust fossil boss egg comic alien upon aspect dry avoid interest fury window hint race symptom" - -# user2 address 0x963ebdf2e1f8db8707d05fc75bfeffba1b5bac17 -USER2_KEY="user2" -USER2_MNEMONIC="maximum display century economy unlock van census kite error heart snow filter midnight usage egg venture cash kick motor survey drastic edge muffin visual" - -# user3 address 0x40a0cb1C63e026A81B55EE1308586E21eec1eFa9 -USER3_KEY="user3" -USER3_MNEMONIC="will wear settle write dance topic tape sea glory hotel oppose rebel client problem era video gossip glide during yard balance cancel file rose" - -# user4 address 0x498B5AeC5D439b733dC2F58AB489783A23FB26dA -USER4_KEY="user4" -USER4_MNEMONIC="doll midnight silk carpet brush boring pluck office gown inquiry duck chief aim exit gain never tennis crime fragile ship cloud surface exotic patch" - -# Import keys from mnemonics -echo "$VAL_MNEMONIC" | evmd keys add "$VAL_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$CHAINDIR" -echo "$USER1_MNEMONIC" | evmd keys add "$USER1_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$CHAINDIR" -echo "$USER2_MNEMONIC" | evmd keys add "$USER2_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$CHAINDIR" -echo "$USER3_MNEMONIC" | evmd keys add "$USER3_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$CHAINDIR" -echo "$USER4_MNEMONIC" | evmd keys add "$USER4_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$CHAINDIR" - -# Set moniker and chain-id for Cosmos EVM (Moniker can be anything, chain-id must be an integer) -evmd init "$MONIKER" --chain-id "$CHAINID" --home "$CHAINDIR" - -# Change parameter token denominations to atest -jq '.app_state["staking"]["params"]["bond_denom"]="atest"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="atest"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -jq '.app_state["gov"]["params"]["min_deposit"][0]["denom"]="atest"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -jq '.app_state["evm"]["params"]["evm_denom"]="atest"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -jq '.app_state["mint"]["params"]["mint_denom"]="atest"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - -# Enable precompiles in EVM params -jq '.app_state["evm"]["params"]["active_static_precompiles"]=["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804"]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - -# Change proposal periods to pass within a reasonable time for local testing -sed -i.bak 's/"max_deposit_period": "172800s"/"max_deposit_period": "30s"/g' "$GENESIS" -sed -i.bak 's/"voting_period": "172800s"/"voting_period": "30s"/g' "$GENESIS" -sed -i.bak 's/"expedited_voting_period": "86400s"/"expedited_voting_period": "15s"/g' "$GENESIS" - -# Set gas limit in genesis -jq '.consensus_params.block.max_gas="10000000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - -# Set base fee in genesis -jq '.app_state["feemarket"]["params"]["base_fee"]="'${BASEFEE}'"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - -# disable produce empty block -sed -i.bak 's/create_empty_blocks = true/create_empty_blocks = false/g' "$CONFIG_TOML" - -# Allocate genesis accounts (cosmos formatted addresses) -evmd genesis add-genesis-account "$(evmd keys show "$VAL_KEY" -a --keyring-backend "$KEYRING" --home "$CHAINDIR")" 100000000000000000000000000atest --keyring-backend "$KEYRING" --home "$CHAINDIR" -evmd genesis add-genesis-account "$(evmd keys show "$USER1_KEY" -a --keyring-backend "$KEYRING" --home "$CHAINDIR")" 1000000000000000000000atest --keyring-backend "$KEYRING" --home "$CHAINDIR" -evmd genesis add-genesis-account "$(evmd keys show "$USER2_KEY" -a --keyring-backend "$KEYRING" --home "$CHAINDIR")" 1000000000000000000000atest --keyring-backend "$KEYRING" --home "$CHAINDIR" -evmd genesis add-genesis-account "$(evmd keys show "$USER3_KEY" -a --keyring-backend "$KEYRING" --home "$CHAINDIR")" 1000000000000000000000atest --keyring-backend "$KEYRING" --home "$CHAINDIR" -evmd genesis add-genesis-account "$(evmd keys show "$USER4_KEY" -a --keyring-backend "$KEYRING" --home "$CHAINDIR")" 1000000000000000000000atest --keyring-backend "$KEYRING" --home "$CHAINDIR" - -# set custom pruning settings -if [ "$PRUNING" = "custom" ]; then - sed -i.bak 's/pruning = "default"/pruning = "custom"/g' "$APP_TOML" - sed -i.bak 's/pruning-keep-recent = "0"/pruning-keep-recent = "2"/g' "$APP_TOML" - sed -i.bak 's/pruning-interval = "0"/pruning-interval = "10"/g' "$APP_TOML" -fi - -# make sure the localhost IP is 0.0.0.0 -sed -i.bak 's/localhost/0.0.0.0/g' "$CONFIG_TOML" -sed -i.bak 's/127.0.0.1/0.0.0.0/g' "$APP_TOML" - -# use timeout_commit 1s to make test faster -sed -i.bak 's/timeout_commit = "5s"/timeout_commit = "100ms"/g' "$CONFIG_TOML" - -# Sign genesis transaction -evmd genesis gentx "$VAL_KEY" 1000000000000000000000atest --gas-prices ${BASEFEE}atest --keyring-backend "$KEYRING" --chain-id "$CHAINID" --home "$CHAINDIR" -## In case you want to create multiple validators at genesis -## 1. Back to `evmd keys add` step, init more keys -## 2. Back to `evmd add-genesis-account` step, add balance for those -## 3. Clone this ~/.evmd home directory into some others, let's say `~/.clonedosd` -## 4. Run `gentx` in each of those folders -## 5. Copy the `gentx-*` folders under `~/.clonedosd/config/gentx/` folders into the original `~/.evmd/config/gentx` - -# Enable the APIs for the tests to be successful -sed -i.bak 's/enable = false/enable = true/g' "$APP_TOML" - -# Don't enable memiavl by default -grep -q -F '[memiavl]' "$APP_TOML" && sed -i.bak '/\[memiavl\]/,/^\[/ s/enable = true/enable = false/' "$APP_TOML" - -# Collect genesis tx -evmd genesis collect-gentxs --home "$CHAINDIR" - -# Run this to ensure everything worked and that the genesis file is setup correctly -evmd genesis validate-genesis --home "$CHAINDIR" - -# Start the node -evmd start "$TRACE" \ - --log_level $LOGLEVEL \ - --minimum-gas-prices=0.0001utest \ - --json-rpc.api eth,txpool,personal,net,debug,web3 \ - --chain-id "$CHAINID" \ - --home "$CHAINDIR" diff --git a/tests/solidity/suites/revert_cases/contracts/RevertTestContract.sol b/tests/solidity/suites/revert_cases/contracts/RevertTestContract.sol new file mode 100644 index 0000000000..d20f80c3e4 --- /dev/null +++ b/tests/solidity/suites/revert_cases/contracts/RevertTestContract.sol @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./cosmos/staking/StakingI.sol"; +import "./cosmos/distribution/DistributionI.sol"; +import "./cosmos/bank/IBank.sol"; +import "./cosmos/common/Types.sol"; + +/** + * @title RevertTestContract + * @dev Contract for testing Cosmos precompile revert scenarios and error message handling + * Focuses specifically on precompile calls and interactions with Cosmos SDK modules + */ +contract RevertTestContract { + uint256 public counter = 0; + + // Events to track what operations are performed + event PrecompileCallMade(string precompileName, bool success); + event OutOfGasSimulated(uint256 gasLeft); + + constructor() payable {} + + // ============ DIRECT PRECOMPILE CALL REVERTS ============ + + /** + * @dev Direct staking precompile call that will revert + */ + function directStakingRevert(string calldata invalidValidator) external { + counter++; + emit PrecompileCallMade("staking", false); + // This should revert with invalid validator address + STAKING_CONTRACT.delegate(address(this), invalidValidator, 1); + } + + /** + * @dev Direct distribution precompile call that will revert + */ + function directDistributionRevert(string calldata invalidValidator) external { + counter++; + emit PrecompileCallMade("distribution", false); + // This should revert with invalid validator address + DISTRIBUTION_CONTRACT.withdrawDelegatorRewards(address(this), invalidValidator); + } + + /** + * @dev Direct bank precompile call that will revert + */ + function directBankRevert() external pure { + revert("intended revert"); + } + + // ============ PRECOMPILE CALL VIA CONTRACT REVERTS ============ + + /** + * @dev Precompile call via contract that reverts + */ + function precompileViaContractRevert(string calldata invalidValidator) external { + counter++; + try this.internalStakingCall(invalidValidator) { + // Should not reach here + } catch (bytes memory reason) { + // Re-throw the error to maintain the revert + assembly { + revert(add(reason, 0x20), mload(reason)) + } + } + } + + /** + * @dev Internal function for precompile call via contract + */ + function internalStakingCall(string calldata validatorAddress) external { + require(msg.sender == address(this), "Only self can call"); + emit PrecompileCallMade("staking_internal", false); + STAKING_CONTRACT.delegate(address(this), validatorAddress, 1); + } + + /** + * @dev Complex scenario: multiple precompile calls with revert + */ + function multiplePrecompileCallsWithRevert(string calldata validatorAddress) external { + counter++; + + // First, make a successful call + try IBANK_CONTRACT.balances(address(this)) returns (Balance[] memory) { + emit PrecompileCallMade("bank", true); + } catch { + emit PrecompileCallMade("bank", false); + } + + // Then make a call that will revert + emit PrecompileCallMade("staking_multi", false); + STAKING_CONTRACT.delegate(address(this), validatorAddress, 1); + } + + // ============ PRECOMPILE OUT OF GAS ERROR CASES ============ + + /** + * @dev Direct precompile call that runs out of gas + */ + function directStakingOutOfGas(string calldata validatorAddress) external { + counter++; + emit OutOfGasSimulated(gasleft()); + + // First consume most gas + for (uint256 i = 0; i < 1000000; i++) { + counter++; + } + + // Then try precompile call with remaining gas + STAKING_CONTRACT.delegate(address(this), validatorAddress, 1); + } + + /** + * @dev Precompile call via contract that runs out of gas + */ + function precompileViaContractOutOfGas(string calldata validatorAddress) external { + counter++; + emit OutOfGasSimulated(gasleft()); + + // Consume most gas first + for (uint256 i = 0; i < 1000000; i++) { + counter++; + } + + // Then try internal precompile call + this.internalStakingCall(validatorAddress); + } + + /** + * @dev Wrapper precompile call that runs out of gas + */ + function wrappedPrecompileOutOfGas(string calldata validatorAddress) external { + counter++; + emit OutOfGasSimulated(gasleft()); + + // Consume most gas in expensive operations + for (uint256 i = 0; i < 500000; i++) { + keccak256(abi.encode(i, block.timestamp, msg.sender)); + counter++; + } + + // Then try multiple precompile calls + STAKING_CONTRACT.delegate(address(this), validatorAddress, 1); + DISTRIBUTION_CONTRACT.withdrawDelegatorRewards(address(this), validatorAddress); + } + + // ============ UTILITY FUNCTIONS ============ + + /** + * @dev Get current counter value + */ + function getCounter() external view returns (uint256) { + return counter; + } + + /** + * @dev Reset counter (for testing) + */ + function resetCounter() external { + counter = 0; + } + + /** + * @dev Fund contract with native tokens + */ + receive() external payable {} + + /** + * @dev Withdraw funds (for testing) + */ + function withdraw() external { + payable(msg.sender).transfer(address(this).balance); + } +} + +/** + * @title PrecompileWrapper + * @dev Helper contract for testing precompile calls via external contracts + */ +contract PrecompileWrapper { + event WrapperCall(string operation, bool success); + + constructor() payable {} + + /** + * @dev Wrapper function that calls staking precompile and reverts + */ + function wrappedStakingCall(string calldata validatorAddress, uint256 amount) external { + emit WrapperCall("staking", false); + STAKING_CONTRACT.delegate(address(this), validatorAddress, amount); + revert("Wrapper intentional revert"); + } + + /** + * @dev Wrapper function that calls distribution precompile and reverts + */ + function wrappedDistributionCall(string calldata validatorAddress) external { + emit WrapperCall("distribution", false); + DISTRIBUTION_CONTRACT.withdrawDelegatorRewards(address(this), validatorAddress); + revert("Wrapper intentional revert"); + } + + /** + * @dev Wrapper function that runs out of gas + */ + function wrappedOutOfGasCall(string calldata validatorAddress) external { + // Consume all gas + for (uint256 i = 0; i < 1000000; i++) { + // Gas consuming operation + keccak256(abi.encode(i)); + } + + STAKING_CONTRACT.delegate(address(this), validatorAddress, 1); + } + + /** + * @dev Fund wrapper contract + */ + receive() external payable {} +} diff --git a/tests/solidity/suites/revert_cases/contracts/StandardRevertTestContract.sol b/tests/solidity/suites/revert_cases/contracts/StandardRevertTestContract.sol new file mode 100644 index 0000000000..5ee137ecd2 --- /dev/null +++ b/tests/solidity/suites/revert_cases/contracts/StandardRevertTestContract.sol @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/** + * @title StandardRevertTestContract + * @dev Contract for testing standard Ethereum revert scenarios and error message handling + * Compatible with any Ethereum node (Geth, etc.) - no custom precompiles required + */ +contract StandardRevertTestContract { + uint256 public counter = 0; + + // Events to track what operations are performed + event StandardRevert(string reason); + event OutOfGasSimulated(uint256 gasLeft); + event CounterIncremented(uint256 newValue); + + constructor() payable {} + + // ============ STANDARD CONTRACT REVERT CASES ============ + + /** + * @dev Simple revert with custom message + */ + function standardRevert(string calldata reason) external { + counter++; + emit StandardRevert(reason); + revert(reason); + } + + /** + * @dev Revert with require statement + */ + function requireRevert(uint256 value, uint256 threshold) external { + counter++; + require(value < threshold, "Value exceeds threshold"); + emit CounterIncremented(counter); + } + + /** + * @dev Assert revert (should generate Panic error) + */ + function assertRevert() external { + counter++; + assert(false); + } + + /** + * @dev Division by zero (should generate Panic error) + */ + function divisionByZero() external pure returns (uint256) { + uint256 zero = 0; + return 1 / zero; + } + + /** + * @dev Array out of bounds (should generate Panic error) + */ + function arrayOutOfBounds() external pure returns (uint256) { + uint256[] memory arr = new uint256[](2); + return arr[5]; // This will cause an out of bounds error + } + + /** + * @dev Division by zero in transaction context (should generate Panic error) + */ + function divisionByZeroTx() external returns (uint256) { + counter++; // State change to make it a transaction + uint256 zero = 0; + return 1 / zero; + } + + /** + * @dev Array out of bounds in transaction context (should generate Panic error) + */ + function arrayOutOfBoundsTx() external returns (uint256) { + counter++; // State change to make it a transaction + uint256[] memory arr = new uint256[](2); + return arr[5]; // This will cause an out of bounds error + } + + /** + * @dev Overflow error (should generate Panic error in older Solidity) + */ + function overflowError() external pure returns (uint256) { + unchecked { + uint256 max = type(uint256).max; + return max + 1; // This might overflow depending on Solidity version + } + } + + // ============ OUT OF GAS ERROR CASES ============ + + /** + * @dev Standard contract call that runs out of gas + */ + function standardOutOfGas() external { + counter++; + emit OutOfGasSimulated(gasleft()); + + // Consume all remaining gas + while (gasleft() > 1000) { + // Consume gas in a loop + counter++; + } + } + + /** + * @dev Expensive computation that can run out of gas + */ + function expensiveComputation(uint256 iterations) external { + counter++; + emit OutOfGasSimulated(gasleft()); + + // Perform expensive operations + for (uint256 i = 0; i < iterations; i++) { + // Hash operations are gas-expensive + keccak256(abi.encode(i, block.timestamp, msg.sender)); + counter++; + } + } + + /** + * @dev Storage operations that can run out of gas + */ + function expensiveStorage(uint256 iterations) external { + counter++; + emit OutOfGasSimulated(gasleft()); + + // Storage operations are very gas-expensive + for (uint256 i = 0; i < iterations; i++) { + assembly { + sstore(add(counter.slot, i), i) + } + } + } + + // ============ COMPLEX REVERT SCENARIOS ============ + + /** + * @dev Multiple function calls with revert + */ + function multipleCallsWithRevert() external { + counter++; + + // First, do some successful operations + this.incrementCounter(); + + // Then revert + revert("Multiple calls revert"); + } + + /** + * @dev Try-catch with revert + */ + function tryCatchRevert(bool shouldRevert) external { + counter++; + + if (shouldRevert) { + try this.internalRevert() { + // Should not reach here + } catch (bytes memory reason) { + // Re-throw the error to maintain the revert + assembly { + revert(add(reason, 0x20), mload(reason)) + } + } + } else { + // Successful path + emit CounterIncremented(counter); + } + } + + /** + * @dev Internal function that always reverts + */ + function internalRevert() external pure { + revert("Internal function revert"); + } + + // ============ UTILITY FUNCTIONS ============ + + /** + * @dev Simple function that increments counter + */ + function incrementCounter() external { + counter++; + emit CounterIncremented(counter); + } + + /** + * @dev Get current counter value + */ + function getCounter() external view returns (uint256) { + return counter; + } + + /** + * @dev Reset counter (for testing) + */ + function resetCounter() external { + counter = 0; + } + + /** + * @dev Fund contract with native tokens + */ + receive() external payable {} + + /** + * @dev Withdraw funds (for testing) + */ + function withdraw() external { + payable(msg.sender).transfer(address(this).balance); + } + + /** + * @dev Get contract balance + */ + function getBalance() external view returns (uint256) { + return address(this).balance; + } +} + +/** + * @title SimpleWrapper + * @dev Helper contract for testing reverts via external contracts + */ +contract SimpleWrapper { + event WrapperCall(string operation, bool success); + + constructor() payable {} + + /** + * @dev Wrapper function that calls standard revert + */ + function wrappedStandardCall(StandardRevertTestContract target, string calldata reason) external { + emit WrapperCall("standard_revert", false); + target.standardRevert(reason); + } + + /** + * @dev Wrapper function that runs out of gas + */ + function wrappedOutOfGasCall(StandardRevertTestContract target) external { + emit WrapperCall("out_of_gas", false); + + // Consume most gas first + for (uint256 i = 0; i < 100000; i++) { + // Gas consuming operation + keccak256(abi.encode(i)); + } + + // Then try the expensive call + target.expensiveComputation(10000); + } + + /** + * @dev Fund wrapper contract + */ + receive() external payable {} +} \ No newline at end of file diff --git a/tests/solidity/suites/revert_cases/hardhat.config.js b/tests/solidity/suites/revert_cases/hardhat.config.js new file mode 100644 index 0000000000..019d790170 --- /dev/null +++ b/tests/solidity/suites/revert_cases/hardhat.config.js @@ -0,0 +1,27 @@ +require("@nomicfoundation/hardhat-toolbox"); + +/** @type import('hardhat/config').HardhatUserConfig */ +module.exports = { + solidity: { + compilers: [ + { + version: "0.8.18", + }, + // This version is required to compile the werc9 contract. + { + version: "0.4.22", + }, + ], + }, + networks: { + cosmos: { + url: "http://127.0.0.1:8545", + chainId: 262144, + accounts: [ + "0x88CBEAD91AEE890D27BF06E003ADE3D4E952427E88F88D31D61D3EF5E5D54305", + "0x3B7955D25189C99A7468192FCBC6429205C158834053EBE3F78F4512AB432DB9", + "0xe9b1d63e8acd7fe676acb43afb390d4b0202dab61abec9cf2a561e4becb147de", + ], + }, + }, +}; diff --git a/tests/solidity/suites/revert_cases/package.json b/tests/solidity/suites/revert_cases/package.json new file mode 100644 index 0000000000..7788ed08a6 --- /dev/null +++ b/tests/solidity/suites/revert_cases/package.json @@ -0,0 +1,35 @@ +{ + "name": "revert_cases", + "version": "1.0.0", + "author": "Evmos team", + "license": "GPL-3.0-or-later", + "scripts": { + "get-contracts": "mkdir -p ./contracts/cosmos && rsync -avm --include='*/' --exclude='**/ERC20Minter_OpenZeppelinV5.sol' --exclude='**/WEVMOS.sol' --exclude='**/ERC20NoMetadata.sol' --include='*.sol' --exclude='*' ../../../../precompiles/ ./contracts/cosmos/", + "clean-contracts": "rm -rf ./contracts/cosmos/*", + "test-ganache": "yarn hardhat test", + "test-cosmos": "yarn get-contracts && yarn hardhat test --network cosmos && yarn clean-contracts" + }, + "devDependencies": { + "@nomicfoundation/hardhat-chai-matchers": "^2.0.2", + "@nomicfoundation/hardhat-ethers": "^3.0.4", + "@nomicfoundation/hardhat-network-helpers": "^1.0.8", + "@nomicfoundation/hardhat-toolbox": "^3.0.0", + "@nomicfoundation/hardhat-verify": "^1.1.1", + "@openzeppelin/hardhat-upgrades": "^2.0.2", + "@openzeppelin/contracts": "^4.9.6", + "@typechain/ethers-v6": "^0.4.3", + "@typechain/hardhat": "^8.0.3", + "@types/chai": "^4.3.5", + "@types/mocha": "^10.0.1", + "chai": "^4.3.7", + "hardhat": "^2.20.0", + "hardhat-gas-reporter": "^1.0.9", + "solidity-coverage": "^0.8.4", + "ts-node": "^10.9.1", + "typechain": "^8.3.1", + "typescript": "^5.1.6" + }, + "dependencies": { + "ethers": "^6.7.0" + } +} diff --git a/tests/solidity/suites/revert_cases/test/common.js b/tests/solidity/suites/revert_cases/test/common.js new file mode 100644 index 0000000000..5291c324fd --- /dev/null +++ b/tests/solidity/suites/revert_cases/test/common.js @@ -0,0 +1,41 @@ +// Common constants and helper utilities for precompile tests + +const STAKING_PRECOMPILE_ADDRESS = '0x0000000000000000000000000000000000000800' +const BECH32_PRECOMPILE_ADDRESS = '0x0000000000000000000000000000000000000400' +const DISTRIBUTION_PRECOMPILE_ADDRESS = '0x0000000000000000000000000000000000000801' +const BANK_PRECOMPILE_ADDRESS = '0x0000000000000000000000000000000000000804' +const GOV_PRECOMPILE_ADDRESS = '0x0000000000000000000000000000000000000805' +const SLASHING_PRECOMPILE_ADDRESS = '0x0000000000000000000000000000000000000806' +const P256_PRECOMPILE_ADDRESS = '0x0000000000000000000000000000000000000100' +const WERC20_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' + +// Default gas limits used across tests +const DEFAULT_GAS_LIMIT = 1_000_000 +const LARGE_GAS_LIMIT = 10_000_000 +const LOW_GAS_LIMIT=50_000 + +const PANIC_ASSERT_0x01 = "Panic(1)" +const PANIC_DIVISION_BY_ZERO_0x12 = "Panic(18)" +const PANIC_ARRAY_OUT_OF_BOUND_0x32 = "Panic(50)" + +module.exports = { + // Precompile Addresses + STAKING_PRECOMPILE_ADDRESS, + BECH32_PRECOMPILE_ADDRESS, + DISTRIBUTION_PRECOMPILE_ADDRESS, + BANK_PRECOMPILE_ADDRESS, + GOV_PRECOMPILE_ADDRESS, + SLASHING_PRECOMPILE_ADDRESS, + P256_PRECOMPILE_ADDRESS, + WERC20_ADDRESS, + + // Gas limits + DEFAULT_GAS_LIMIT, + LARGE_GAS_LIMIT, + LOW_GAS_LIMIT, + + // Panics + PANIC_ASSERT_0x01, + PANIC_DIVISION_BY_ZERO_0x12, + PANIC_ARRAY_OUT_OF_BOUND_0x32 +} \ No newline at end of file diff --git a/tests/solidity/suites/revert_cases/test/precompile_revert_cases.js b/tests/solidity/suites/revert_cases/test/precompile_revert_cases.js new file mode 100644 index 0000000000..ce397d0ffb --- /dev/null +++ b/tests/solidity/suites/revert_cases/test/precompile_revert_cases.js @@ -0,0 +1,239 @@ +const { expect } = require('chai'); +const hre = require('hardhat'); +const { LARGE_GAS_LIMIT, LOW_GAS_LIMIT } = require('./common'); +const { + decodeRevertReason, + analyzeFailedTransaction, + verifyTransactionRevert, + verifyOutOfGasError +} = require('./test_helper') + +describe('Precompile Revert Cases E2E Tests', function () { + let revertTestContract, precompileWrapper; + let validValidatorAddress, invalidValidatorAddress; + let analysis, decodedReason; + + before(async function () { + [signer] = await hre.ethers.getSigners(); + + // Deploy RevertTestContract + const RevertTestContractFactory = await hre.ethers.getContractFactory('RevertTestContract'); + revertTestContract = await RevertTestContractFactory.deploy({ + value: hre.ethers.parseEther('1.0'), // Fund with 1 ETH + gasLimit: LARGE_GAS_LIMIT + }); + await revertTestContract.waitForDeployment(); + + // Deploy PrecompileWrapper + const PrecompileWrapperFactory = await hre.ethers.getContractFactory('PrecompileWrapper'); + precompileWrapper = await PrecompileWrapperFactory.deploy({ + value: hre.ethers.parseEther('1.0'), // Fund with 1 ETH + gasLimit: LARGE_GAS_LIMIT + }); + await precompileWrapper.waitForDeployment(); + + // Use a known validator for valid cases and invalid one for error cases + validValidatorAddress = 'cosmosvaloper10jmp6sgh4cc6zt3e8gw05wavvejgr5pw4xyrql'; + invalidValidatorAddress = 'cosmosvaloper10jmp6sgh4cc6zt3e8gw05wavvejgr5pinvalid'; + + console.log('RevertTestContract deployed at:', await revertTestContract.getAddress()); + console.log('PrecompileWrapper deployed at:', await precompileWrapper.getAddress()); + + analysis = null; + decodedReason = null; + }); + + describe('Direct Precompile Call Reverts', function () { + it('should handle direct staking precompile revert', async function () { + try { + const tx = await revertTestContract.directStakingRevert(invalidValidatorAddress, { gasLimit: LARGE_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash) + } + verifyTransactionRevert(analysis, "invalid validator address") + }); + + it('should handle direct distribution precompile revert', async function () { + try { + const tx = await revertTestContract.directDistributionRevert(invalidValidatorAddress, { gasLimit: LARGE_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash) + } + verifyTransactionRevert(analysis, "invalid validator address") + }); + + it('should handle direct bank precompile revert', async function () { + // directBankRevert is a view function, so it should revert immediately + try { + await revertTestContract.directBankRevert(); + expect.fail('Call should have reverted'); + } catch (error) { + decodedReason = decodeRevertReason(error.data) + } + expect(decodedReason).contains("intended revert") + }); + + it('should capture precompile revert reason through transaction receipt', async function () { + try { + const tx = await revertTestContract.directStakingRevert(invalidValidatorAddress, { gasLimit: LARGE_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash) + } + verifyTransactionRevert(analysis, "invalid validator address") + }); + }); + + describe('Precompile Call Via Contract Reverts', function () { + it('should handle precompile call via contract revert', async function () { + try { + const tx = await revertTestContract.precompileViaContractRevert(invalidValidatorAddress, { gasLimit: LARGE_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash) + } + verifyTransactionRevert(analysis, "invalid validator address") + }); + + it('should handle multiple precompile calls with revert', async function () { + try { + const tx = await revertTestContract.multiplePrecompileCallsWithRevert(invalidValidatorAddress, { gasLimit: LARGE_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash) + } + verifyTransactionRevert(analysis, "invalid validator address") + }); + + it('should handle wrapper contract precompile revert', async function () { + try { + const tx = await precompileWrapper.wrappedStakingCall(invalidValidatorAddress, 1, { gasLimit: LARGE_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash) + } + verifyTransactionRevert(analysis, "invalid validator address") + }); + + it('should capture wrapper revert reason via transaction receipt', async function () { + try { + const tx = await precompileWrapper.wrappedDistributionCall(invalidValidatorAddress, { gasLimit: LARGE_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash) + } + verifyTransactionRevert(analysis, "invalid validator address") + }); + }); + + describe('Precompile OutOfGas Error Cases', function () { + it('should handle direct precompile OutOfGas', async function () { + // Use a very low gas limit to trigger OutOfGas on precompile calls + try { + const tx = await revertTestContract.directStakingOutOfGas(validValidatorAddress, { gasLimit: LOW_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have failed with OutOfGas'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash) + } + verifyOutOfGasError(analysis) + }); + + it('should handle precompile via contract OutOfGas', async function () { + try { + const tx = await revertTestContract.precompileViaContractOutOfGas(validValidatorAddress, { gasLimit: LOW_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have failed with OutOfGas'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash) + } + verifyOutOfGasError(analysis) + }); + + it('should handle wrapper precompile OutOfGas', async function () { + try { + const tx = await precompileWrapper.wrappedOutOfGasCall(validValidatorAddress, { gasLimit: LOW_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have failed with OutOfGas'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash) + } + verifyOutOfGasError(analysis) + }); + + it('should analyze precompile OutOfGas error through transaction receipt', async function () { + try { + const tx = await revertTestContract.directStakingOutOfGas(validValidatorAddress, { gasLimit: LOW_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have failed with OutOfGas'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyOutOfGasError(analysis) + }); + }); + + describe('Comprehensive Precompile Error Analysis', function () { + it('should properly decode various precompile error types from transaction receipts', async function () { + const testCases = [ + { + name: 'Staking Precompile Revert', + call: () => revertTestContract.directStakingRevert(invalidValidatorAddress, { gasLimit: LARGE_GAS_LIMIT }), + expectedReason: "invalid validator address" + }, + { + name: 'Distribution Precompile Revert', + call: () => revertTestContract.directDistributionRevert(invalidValidatorAddress, { gasLimit: LARGE_GAS_LIMIT }), + expectedReason: "invalid validator address" + } + ]; + + for (const testCase of testCases) { + try { + const tx = await testCase.call(); + await tx.wait() + expect.fail(`${testCase.name} should have reverted`); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, testCase.expectedReason) + } + }); + + it('should verify precompile error data is properly hex-encoded in receipts', async function () { + try { + const tx = await revertTestContract.directStakingRevert(invalidValidatorAddress, { gasLimit: LARGE_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + if (error.receipt) { + // Simulate the call to get error data + try { + const contractAddress = await revertTestContract.getAddress(); + await hre.ethers.provider.call({ + to: contractAddress, + data: revertTestContract.interface.encodeFunctionData('directStakingRevert', [invalidValidatorAddress]), + gasLimit: LARGE_GAS_LIMIT + }); + } catch (callError) { + expect(callError.data).to.match(/^0x/); // Should be hex-encoded + console.log('Precompile error data (hex):', callError.data); + + const decoded = decodeRevertReason(callError.data); + expect(decoded).to.include("invalid validator address"); + console.log('Decoded precompile reason:', decoded); + } + } + } + }); + }); +}); \ No newline at end of file diff --git a/tests/solidity/suites/revert_cases/test/standard_revert_cases.js b/tests/solidity/suites/revert_cases/test/standard_revert_cases.js new file mode 100644 index 0000000000..87e1e608f6 --- /dev/null +++ b/tests/solidity/suites/revert_cases/test/standard_revert_cases.js @@ -0,0 +1,374 @@ +const { expect } = require('chai'); +const hre = require('hardhat'); +const { + DEFAULT_GAS_LIMIT, + LARGE_GAS_LIMIT, + LOW_GAS_LIMIT, + PANIC_ASSERT_0x01, + PANIC_DIVISION_BY_ZERO_0x12, + PANIC_ARRAY_OUT_OF_BOUND_0x32 +} = require('./common'); +const { + decodeRevertReason, + analyzeFailedTransaction, + verifyTransactionRevert, + verifyOutOfGasError +} = require('./test_helper') + + +describe('Standard Revert Cases E2E Tests', function () { + let standardRevertTestContract, simpleWrapper, signer; + let analysis, decodedReason; + + before(async function () { + [signer] = await hre.ethers.getSigners(); + + // Deploy StandardRevertTestContract + const StandardRevertTestContractFactory = await hre.ethers.getContractFactory('StandardRevertTestContract'); + standardRevertTestContract = await StandardRevertTestContractFactory.deploy({ + value: hre.ethers.parseEther('1.0'), // Fund with 1 ETH + gasLimit: LARGE_GAS_LIMIT + }); + await standardRevertTestContract.waitForDeployment(); + + // Deploy SimpleWrapper + const SimpleWrapperFactory = await hre.ethers.getContractFactory('SimpleWrapper'); + simpleWrapper = await SimpleWrapperFactory.deploy({ + value: hre.ethers.parseEther('1.0'), // Fund with 1 ETH + gasLimit: LARGE_GAS_LIMIT + }); + await simpleWrapper.waitForDeployment(); + + // Verify successful deployment + const contractAddress = await standardRevertTestContract.getAddress(); + const wrapperAddress = await simpleWrapper.getAddress(); + console.log('StandardRevertTestContract deployed at:', contractAddress); + console.log('SimpleWrapper deployed at:', wrapperAddress); + + analysis = null; + decodedReason = null; + }); + + describe('Standard Contract Call Reverts', function () { + it('should handle standard revert with custom message', async function () { + const customMessage = "Custom revert message"; + try { + const tx = await standardRevertTestContract.standardRevert(customMessage, { gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, customMessage); + + // Verify we can capture the revert reason via static call + try { + await standardRevertTestContract.standardRevert.staticCall(customMessage); + expect.fail('Static call should have reverted'); + } catch (error) { + decodedReason = decodeRevertReason(error.data); + } + expect(decodedReason).to.include(customMessage); + }); + + it('should handle require revert with proper error message', async function () { + const value = 100; + const threshold = 50; + + try { + const tx = await standardRevertTestContract.requireRevert(value, threshold, { gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, "Value exceeds threshold"); + + // Verify we can capture the revert reason via static call + try { + await standardRevertTestContract.requireRevert.staticCall(value, threshold); + expect.fail('Static call should have reverted'); + } catch (error) { + decodedReason = decodeRevertReason(error.data); + } + expect(decodedReason).to.include("Value exceeds threshold"); + + // Verify successful case (no revert when value < threshold) + const successTx = await standardRevertTestContract.requireRevert(25, 50, { gasLimit: DEFAULT_GAS_LIMIT }); + const receipt = await successTx.wait(); + expect(receipt.status).to.equal(1, 'Transaction should succeed when value < threshold'); + }); + + it('should handle assert revert (Panic error)', async function () { + try { + const tx = await standardRevertTestContract.assertRevert({ gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, PANIC_ASSERT_0x01); + + // Verify we can capture the revert reason via static call + try { + await standardRevertTestContract.assertRevert.staticCall(); + expect.fail('Static call should have reverted'); + } catch (error) { + decodedReason = decodeRevertReason(error.data); + } + expect(decodedReason).to.include(PANIC_ASSERT_0x01); + }); + + it('should handle division by zero (View Panic error)', async function () { + try { + await standardRevertTestContract.divisionByZero(); + expect.fail('View call should have reverted'); + } catch (error) { + decodedReason = decodeRevertReason(error.data); + } + expect(decodedReason).to.include(PANIC_DIVISION_BY_ZERO_0x12); + }); + + it('should handle division by zero (Transaction Panic error)', async function () { + try { + const tx = await standardRevertTestContract.divisionByZeroTx({ gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, PANIC_DIVISION_BY_ZERO_0x12); + }); + + it('should handle array out of bounds (View Panic error)', async function () { + try { + await standardRevertTestContract.arrayOutOfBounds(); + expect.fail('View call should have reverted'); + } catch (error) { + decodedReason = decodeRevertReason(error.data); + } + expect(decodedReason).contains(PANIC_ARRAY_OUT_OF_BOUND_0x32); + }); + + it('should handle array out of bounds (Transaction Panic error)', async function () { + try { + const tx = await standardRevertTestContract.arrayOutOfBoundsTx({ gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, PANIC_ARRAY_OUT_OF_BOUND_0x32); + }); + + it('should capture revert reason through eth_getTransactionReceipt', async function () { + try { + const tx = await standardRevertTestContract.standardRevert("Test message", { gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, "Test message"); + }); + }); + + describe('Complex Revert Scenarios', function () { + it('should handle multiple calls with revert', async function () { + try { + const tx = await standardRevertTestContract.multipleCallsWithRevert({ gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, "Multiple calls revert"); + }); + + it('should handle try-catch revert scenario', async function () { + try { + const tx = await standardRevertTestContract.tryCatchRevert(true, { gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, "Internal function revert"); + }); + + it('should handle wrapper contract revert', async function () { + const contractAddress = await standardRevertTestContract.getAddress(); + try { + const tx = await simpleWrapper.wrappedStandardCall(contractAddress, "Wrapper test", { gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, "Wrapper test"); + }); + }); + + describe('OutOfGas Error Cases', function () { + it('should handle standard contract OutOfGas', async function () { + try { + const tx = await standardRevertTestContract.standardOutOfGas({ gasLimit: LOW_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have failed with OutOfGas'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyOutOfGasError(analysis); + }); + + it('should handle expensive computation OutOfGas', async function () { + try { + const tx = await standardRevertTestContract.expensiveComputation(10000, { gasLimit: LOW_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have failed with OutOfGas'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyOutOfGasError(analysis); + }); + + it('should handle expensive storage OutOfGas', async function () { + try { + const tx = await standardRevertTestContract.expensiveStorage(100, { gasLimit: LOW_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have failed with OutOfGas'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyOutOfGasError(analysis); + }); + + it('should handle wrapper OutOfGas', async function () { + const contractAddress = await standardRevertTestContract.getAddress(); + try { + const tx = await simpleWrapper.wrappedOutOfGasCall(contractAddress, { gasLimit: LOW_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have failed with OutOfGas'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyOutOfGasError(analysis); + }); + + it('should analyze OutOfGas error through transaction receipt', async function () { + try { + const tx = await standardRevertTestContract.standardOutOfGas({ gasLimit: LOW_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have failed with OutOfGas'); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyOutOfGasError(analysis); + }); + }); + + describe('Comprehensive Error Analysis', function () { + it('should properly decode various error types from transaction receipts', async function () { + // Transaction-based functions that create receipts + const transactionTestCases = [ + { + name: 'Standard Revert', + call: async () => { + const tx = await standardRevertTestContract.standardRevert("Standard error", { gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + }, + expectedReason: "Standard error" + }, + { + name: 'Require Revert', + call: async () => { + const tx = await standardRevertTestContract.requireRevert(100, 50, { gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + }, + expectedReason: "Value exceeds threshold" + }, + { + name: 'Assert Revert', + call: async () => { + const tx = await standardRevertTestContract.assertRevert({ gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + }, + expectedReason: PANIC_ASSERT_0x01 + }, + { + name: 'Division by Zero (Transaction)', + call: async () => { + const tx = await standardRevertTestContract.divisionByZeroTx({ gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + }, + expectedReason: PANIC_DIVISION_BY_ZERO_0x12 + }, + { + name: 'Array Out of Bounds (Transaction)', + call: async () => { + const tx = await standardRevertTestContract.arrayOutOfBoundsTx({ gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + }, + expectedReason: PANIC_ARRAY_OUT_OF_BOUND_0x32 + } + ]; + + // View functions that don't create receipts but still revert + const viewTestCases = [ + { + name: 'Division by Zero (View)', + call: async () => await standardRevertTestContract.divisionByZero(), + expectedReason: PANIC_DIVISION_BY_ZERO_0x12 + }, + { + name: 'Array Out of Bounds (View)', + call: async () => await standardRevertTestContract.arrayOutOfBounds(), + expectedReason: PANIC_ARRAY_OUT_OF_BOUND_0x32 + } + ]; + + // Test transaction-based functions + for (const testCase of transactionTestCases) { + try { + await testCase.call(); + expect.fail(`${testCase.name} should have reverted`); + } catch (error) { + analysis = await analyzeFailedTransaction(error.receipt.hash); + } + verifyTransactionRevert(analysis, testCase.expectedReason); + } + + // Test view functions (no receipts) + for (const testCase of viewTestCases) { + try { + await testCase.call(); + expect.fail(`${testCase.name} should have reverted`); + } catch (error) { + decodedReason = decodeRevertReason(error.data); + } + expect(decodedReason).contains(testCase.expectedReason); + } + }); + + it('should verify error data is properly hex-encoded in receipts', async function () { + try { + const tx = await standardRevertTestContract.standardRevert("Hex encoding test", { gasLimit: DEFAULT_GAS_LIMIT }); + await tx.wait(); + expect.fail('Transaction should have reverted'); + } catch (error) { + try { + const contractAddress = await standardRevertTestContract.getAddress(); + await hre.ethers.provider.call({ + to: contractAddress, + data: standardRevertTestContract.interface.encodeFunctionData('standardRevert', ['Hex encoding test']), + gasLimit: DEFAULT_GAS_LIMIT + }); + expect.fail('Call should have reverted'); + } catch (error) { + decodedReason = await decodeRevertReason(error.data); + } + expect(decodedReason).to.include('Hex encoding test'); + } + }); + }); +}); \ No newline at end of file diff --git a/tests/solidity/suites/revert_cases/test/test_helper.js b/tests/solidity/suites/revert_cases/test/test_helper.js new file mode 100644 index 0000000000..258bb2ac3b --- /dev/null +++ b/tests/solidity/suites/revert_cases/test/test_helper.js @@ -0,0 +1,144 @@ +const { expect } = require('chai'); + +// Helper to convert the raw tuple returned by staking.validator() into an object +function parseValidator (raw) { + return { + operatorAddress: raw[0], + consensusPubkey: raw[1], + jailed: raw[2], + status: raw[3], + tokens: raw[4], + delegatorShares: raw[5], + description: raw[6], + unbondingHeight: raw[7], + unbondingTime: raw[8], + commission: raw[9], + minSelfDelegation: raw[10] + } +} + +// Utility to parse logs and return the first matching event by name +function findEvent (logs, iface, eventName) { + for (const log of logs) { + try { + const parsed = iface.parseLog(log) + if (parsed && parsed.name === eventName) { + return parsed + } + } catch { + // ignore logs that do not match the contract interface + } + } + return null +} + +/** + * Helper function to decode hex error data from transaction receipt + */ +function decodeRevertReason(errorData) { + if (!errorData || errorData === '0x') { + return null; + } + + try { + // Remove '0x' prefix + const cleanHex = errorData.startsWith('0x') ? errorData.slice(2) : errorData; + + // Check if it's a standard revert string (function selector: 08c379a0) + if (cleanHex.startsWith('08c379a0')) { + const reasonHex = cleanHex.slice(8); // Remove function selector + const offsetHex = reasonHex.slice(0, 64); // Get offset (should be 0x20 = 32) + const offset = parseInt(offsetHex, 16); + + if (offset === 32) { // Standard ABI encoding has offset of 32 + const reasonLength = parseInt(reasonHex.slice(64, 128), 16); // Get string length from next 32 bytes + const reasonBytes = reasonHex.slice(128, 128 + reasonLength * 2); // Get string data + return Buffer.from(reasonBytes, 'hex').toString('utf8'); + } else { + // Fallback for non-standard encoding + const reasonLength = parseInt(reasonHex.slice(0, 64), 16); // Get string length + const reasonBytes = reasonHex.slice(128, 128 + reasonLength * 2); // Get string data + return Buffer.from(reasonBytes, 'hex').toString('utf8'); + } + } + + // Check if it's a Panic error (function selector: 4e487b71) + if (cleanHex.startsWith('4e487b71')) { + const panicCode = parseInt(cleanHex.slice(8, 72), 16); + return `Panic(${panicCode})`; + } + + // Return raw hex if not a standard format + return `Raw: ${errorData}`; + } catch (error) { + return `Decode error: ${error.message}`; + } +} + +/** + * Helper function to analyze transaction receipt for revert information + */ +async function analyzeFailedTransaction(txHash) { + const receipt = await hre.ethers.provider.getTransactionReceipt(txHash); + const tx = await hre.ethers.provider.getTransaction(txHash); + + // Try to get revert reason through call simulation + try { + await hre.ethers.provider.call({ + to: tx.to, + data: tx.data, + from: tx.from, + value: tx.value, + gasLimit: tx.gasLimit, + gasPrice: tx.gasPrice + }); + } catch (error) { + console.log(` Revert Reason: ${decodeRevertReason(error.data)}`); + return { + status: receipt.status, + gasUsed: receipt.gasUsed, + gasLimit: tx.gasLimit, + errorData: error.data, + decodedReason: decodeRevertReason(error.data), + errorMessage: error.message + }; + } + + return { + status: receipt.status, + gasUsed: receipt.gasUsed, + gasLimit: tx.gasLimit, + errorData: null, + decodedReason: null, + errorMessage: null + }; +} + +/** + * Helper function to verify decoded revert reason + */ +function verifyTransactionRevert(analysis, expectedRevertReason) { + expect(analysis).to.not.be.null; + expect(analysis.status).to.equal(0); // Failed transaction + expect(analysis.errorData).to.not.be.null; + expect(analysis.decodedReason).contains(expectedRevertReason, "unexpected revert reason"); +} + +/** + * Helper function to verify out of gas error + */ +function verifyOutOfGasError(analysis) { + expect(analysis).to.not.be.null; + expect(analysis.status).to.equal(0); // Failed transaction + expect(analysis.gasUsed).to.be.equal(analysis.gasLimit); + expect(analysis.errorMessage.toLowerCase()).include('out of gas'); +} + +module.exports = { + parseValidator, + findEvent, + decodeRevertReason, + analyzeFailedTransaction, + verifyTransactionRevert, + verifyOutOfGasError +} \ No newline at end of file From 1f22f1971d4417ced436ebee3281859034a48c24 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 21 Aug 2025 21:46:24 +0800 Subject: [PATCH 17/61] Problem: IsStorageEmpty is not implemented (#490) * Problem: IsStorageEmpty is not implemented Closes: #486 * update deps --- go.mod | 2 +- go.sum | 4 ++-- x/vm/statedb/statedb.go | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7bbd55c08b..320aef035f 100644 --- a/go.mod +++ b/go.mod @@ -273,7 +273,7 @@ replace ( github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 // use Cosmos geth fork // branch: release/1.16 - github.com/ethereum/go-ethereum => github.com/cosmos/go-ethereum v0.0.0-20250806193535-2fc7571efa91 + github.com/ethereum/go-ethereum => github.com/cosmos/go-ethereum v1.16.2-cosmos-1 // Security Advisory https://github.com/advisories/GHSA-h395-qcrw-5vmq github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.1 // replace broken goleveldb diff --git a/go.sum b/go.sum index 6321d356dd..9cfa41a545 100644 --- a/go.sum +++ b/go.sum @@ -854,8 +854,8 @@ github.com/cosmos/cosmos-sdk v0.53.4 h1:kPF6vY68+/xi1/VebSZGpoxQqA52qkhUzqkrgeBn github.com/cosmos/cosmos-sdk v0.53.4/go.mod h1:7U3+WHZtI44dEOnU46+lDzBb2tFh1QlMvi8Z5JugopI= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= -github.com/cosmos/go-ethereum v0.0.0-20250806193535-2fc7571efa91 h1:kgu2NkKzSeJJlVsKeS+KbdzfUeaFqrqmmhwixd/PNH4= -github.com/cosmos/go-ethereum v0.0.0-20250806193535-2fc7571efa91/go.mod h1:X5CIOyo8SuK1Q5GnaEizQVLHT/DfsiGWuNeVdQcEMNA= +github.com/cosmos/go-ethereum v1.16.2-cosmos-1 h1:QIaIS6HIdPSBdTvpFhxswhMLUJgcr4irbd2o9ZKldAI= +github.com/cosmos/go-ethereum v1.16.2-cosmos-1/go.mod h1:X5CIOyo8SuK1Q5GnaEizQVLHT/DfsiGWuNeVdQcEMNA= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= diff --git a/x/vm/statedb/statedb.go b/x/vm/statedb/statedb.go index cce997d666..d2f8ae5712 100644 --- a/x/vm/statedb/statedb.go +++ b/x/vm/statedb/statedb.go @@ -104,6 +104,15 @@ func (s *StateDB) GetStorageRoot(addr common.Address) common.Hash { return sr.Hash() } +func (s *StateDB) IsStorageEmpty(addr common.Address) bool { + empty := true + s.keeper.ForEachStorage(s.ctx, addr, func(key, value common.Hash) bool { + empty = false + return false + }) + return empty +} + /* PointCache, Witness, and AccessEvents are all utilized for verkle trees. For now, we just return nil and verkle trees are not supported. From 2cf6593f5296e1471e64b0e815057b3e322ee700 Mon Sep 17 00:00:00 2001 From: Facundo Medica <14063057+facundomedica@users.noreply.github.com> Date: Thu, 21 Aug 2025 15:48:37 +0200 Subject: [PATCH 18/61] feat: allow PostTxProcessing to run on failures and persist data (#479) * feat: allow PostProcessingTx to run on failures and persist data * linf fix * add check for hooks --------- Co-authored-by: Vlad J --- .../integration/x/vm/test_state_transition.go | 169 ++++++++++++++++++ x/vm/keeper/keeper.go | 5 + x/vm/keeper/state_transition.go | 85 ++++++--- 3 files changed, 230 insertions(+), 29 deletions(-) diff --git a/tests/integration/x/vm/test_state_transition.go b/tests/integration/x/vm/test_state_transition.go index 84d34a146c..9d6b8af59c 100644 --- a/tests/integration/x/vm/test_state_transition.go +++ b/tests/integration/x/vm/test_state_transition.go @@ -1,12 +1,14 @@ package vm import ( + "errors" "fmt" "math" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + ethtypes "github.com/ethereum/go-ethereum/core/types" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" @@ -624,6 +626,173 @@ func (s *KeeperTestSuite) TestApplyTransaction() { } } +type testHooks struct { + postProcessing func(ctx sdk.Context, sender common.Address, msg core.Message, receipt *ethtypes.Receipt) error +} + +func (h *testHooks) PostTxProcessing(ctx sdk.Context, sender common.Address, msg core.Message, receipt *ethtypes.Receipt) error { + return h.postProcessing(ctx, sender, msg, receipt) +} + +func (s *KeeperTestSuite) TestApplyTransactionWithTxPostProcessing() { + s.EnableFeemarket = true + defer func() { s.EnableFeemarket = false }() + + testCases := []struct { + name string + setup func(s *KeeperTestSuite) + do func(s *KeeperTestSuite) + after func(s *KeeperTestSuite) + }{ + { + "pass - evm tx succeeds, post processing is called, the balance is changed", + func(s *KeeperTestSuite) { + s.Network.App.GetEVMKeeper().SetHooks( + keeper.NewMultiEvmHooks( + &testHooks{ + postProcessing: func(ctx sdk.Context, sender common.Address, msg core.Message, receipt *ethtypes.Receipt) error { + return nil + }, + }, + ), + ) + }, + func(s *KeeperTestSuite) { + senderBefore := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(0), "aatom").Amount + recipientBefore := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(1), "aatom").Amount + + // Generate a transfer tx message + sender := s.Keyring.GetKey(0) + recipient := s.Keyring.GetAddr(1) + transferAmt := big.NewInt(100) + + tx, err := s.Factory.GenerateSignedEthTx(sender.Priv, types.EvmTxArgs{ + To: &recipient, + Amount: transferAmt, + }) + s.Require().NoError(err) + + ethMsg := tx.GetMsgs()[0].(*types.MsgEthereumTx) + res, err := s.Network.App.GetEVMKeeper().ApplyTransaction(s.Network.GetContext(), ethMsg.AsTransaction()) + s.Require().NoError(err) + s.Require().False(res.Failed()) + + senderAfter := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(0), "aatom").Amount + recipientAfter := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(1), "aatom").Amount + s.Require().Equal(senderBefore.Sub(sdkmath.NewIntFromBigInt(transferAmt)), senderAfter) + s.Require().Equal(recipientBefore.Add(sdkmath.NewIntFromBigInt(transferAmt)), recipientAfter) + }, + func(s *KeeperTestSuite) {}, + }, + { + "pass - evm tx succeeds, post processing is called but fails, the balance is unchanged", + func(s *KeeperTestSuite) { + s.Network.App.GetEVMKeeper().SetHooks( + keeper.NewMultiEvmHooks( + &testHooks{ + postProcessing: func(ctx sdk.Context, sender common.Address, msg core.Message, receipt *ethtypes.Receipt) error { + return errors.New("post processing failed :(") + }, + }, + ), + ) + }, + func(s *KeeperTestSuite) { + senderBefore := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(0), "aatom").Amount + recipientBefore := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(1), "aatom").Amount + + // Generate a transfer tx message + sender := s.Keyring.GetKey(0) + recipient := s.Keyring.GetAddr(1) + transferAmt := big.NewInt(100) + + tx, err := s.Factory.GenerateSignedEthTx(sender.Priv, types.EvmTxArgs{ + To: &recipient, + Amount: transferAmt, + }) + s.Require().NoError(err) + + ethMsg := tx.GetMsgs()[0].(*types.MsgEthereumTx) + res, err := s.Network.App.GetEVMKeeper().ApplyTransaction(s.Network.GetContext(), ethMsg.AsTransaction()) + s.Require().NoError(err) + s.Require().True(res.Failed()) + + senderAfter := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(0), "aatom").Amount + recipientAfter := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(1), "aatom").Amount + s.Require().Equal(senderBefore, senderAfter) + s.Require().Equal(recipientBefore, recipientAfter) + }, + func(s *KeeperTestSuite) {}, + }, + { + "evm tx fails, post processing is called and persisted, the balance is not changed", + func(s *KeeperTestSuite) { + s.Network.App.GetEVMKeeper().SetHooks( + keeper.NewMultiEvmHooks( + &testHooks{ + postProcessing: func(ctx sdk.Context, sender common.Address, msg core.Message, receipt *ethtypes.Receipt) error { + return s.Network.App.GetMintKeeper().MintCoins( + ctx, sdk.NewCoins(sdk.NewCoin("arandomcoin", sdkmath.NewInt(100))), + ) + }, + }, + ), + ) + }, + func(s *KeeperTestSuite) { + senderBefore := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(0), "aatom").Amount + recipientBefore := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(1), "aatom").Amount + + // Generate a transfer tx message + sender := s.Keyring.GetKey(0) + recipient := s.Keyring.GetAddr(1) + transferAmt := senderBefore.Add(sdkmath.NewInt(100)) // transfer more than the balance + + tx, err := s.Factory.GenerateSignedEthTx(sender.Priv, types.EvmTxArgs{ + To: &recipient, + Amount: transferAmt.BigInt(), + }) + s.Require().NoError(err) + + ethMsg := tx.GetMsgs()[0].(*types.MsgEthereumTx) + res, err := s.Network.App.GetEVMKeeper().ApplyTransaction(s.Network.GetContext(), ethMsg.AsTransaction()) + s.Require().NoError(err) + s.Require().True(res.Failed()) + + senderAfter := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(0), "aatom").Amount + recipientAfter := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Keyring.GetAccAddr(1), "aatom").Amount + s.Require().Equal(senderBefore, senderAfter) + s.Require().Equal(recipientBefore, recipientAfter) + }, + func(s *KeeperTestSuite) { + // check if the mint module has "arandomcoin" in its balance, it was minted in the post processing, proving that the post processing was called + // and that it can persist state even when the tx fails + balance := s.Network.App.GetBankKeeper().GetBalance(s.Network.GetContext(), s.Network.App.GetAccountKeeper().GetModuleAddress("mint"), "arandomcoin") + s.Require().Equal(sdkmath.NewInt(100), balance.Amount) + }, + }, + } + + for _, tc := range testCases { + s.Run(fmt.Sprintf("Case %s", tc.name), func() { + s.SetupTest() + + tc.setup(s) + + // set bounded cosmos block gas limit + ctx := s.Network.GetContext().WithBlockGasMeter(storetypes.NewGasMeter(1e6)) + err := s.Network.App.GetBankKeeper().MintCoins(ctx, "mint", sdk.NewCoins(sdk.NewCoin("aatom", sdkmath.NewInt(3e18)))) + s.Require().NoError(err) + err = s.Network.App.GetBankKeeper().SendCoinsFromModuleToModule(ctx, "mint", "fee_collector", sdk.NewCoins(sdk.NewCoin("aatom", sdkmath.NewInt(3e18)))) + s.Require().NoError(err) + + tc.do(s) + + tc.after(s) + }) + } +} + func (s *KeeperTestSuite) TestApplyMessage() { s.EnableFeemarket = true defer func() { s.EnableFeemarket = false }() diff --git a/x/vm/keeper/keeper.go b/x/vm/keeper/keeper.go index 15f8b19689..774598fb27 100644 --- a/x/vm/keeper/keeper.go +++ b/x/vm/keeper/keeper.go @@ -217,6 +217,11 @@ func (k *Keeper) PostTxProcessing( return k.hooks.PostTxProcessing(ctx, sender, msg, receipt) } +// HasHooks returns true if hooks are set +func (k *Keeper) HasHooks() bool { + return k.hooks != nil +} + // ---------------------------------------------------------------------------- // Log // ---------------------------------------------------------------------------- diff --git a/x/vm/keeper/state_transition.go b/x/vm/keeper/state_transition.go index 4c54727cee..d163bdc4ad 100644 --- a/x/vm/keeper/state_transition.go +++ b/x/vm/keeper/state_transition.go @@ -193,36 +193,54 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t ethLogs := types.LogsToEthereum(res.Logs) _, bloomReceipt := k.initializeBloomFromLogs(ctx, ethLogs) - if !res.Failed() { - var contractAddr common.Address - if msg.To == nil { - contractAddr = crypto.CreateAddress(msg.From, msg.Nonce) - } - - receipt := ðtypes.Receipt{ - Type: tx.Type(), - PostState: nil, - CumulativeGasUsed: calculateCumulativeGasFromEthResponse(ctx.GasMeter(), res), - Bloom: bloomReceipt, - Logs: ethLogs, - TxHash: txConfig.TxHash, - ContractAddress: contractAddr, - GasUsed: res.GasUsed, - BlockHash: txConfig.BlockHash, - BlockNumber: big.NewInt(ctx.BlockHeight()), - TransactionIndex: txConfig.TxIndex, - } + var contractAddr common.Address + if msg.To == nil { + contractAddr = crypto.CreateAddress(msg.From, msg.Nonce) + } + + receipt := ðtypes.Receipt{ + Type: tx.Type(), + PostState: nil, + CumulativeGasUsed: calculateCumulativeGasFromEthResponse(ctx.GasMeter(), res), + Bloom: bloomReceipt, + Logs: ethLogs, + TxHash: txConfig.TxHash, + ContractAddress: contractAddr, + GasUsed: res.GasUsed, + BlockHash: txConfig.BlockHash, + BlockNumber: big.NewInt(ctx.BlockHeight()), + TransactionIndex: txConfig.TxIndex, + } + + if res.Failed() { + receipt.Status = ethtypes.ReceiptStatusFailed + + // If the tx failed we discard the old context and create a new one, so + // PostTxProcessing can persist data even if the tx fails. + tmpCtx, commitFn = ctx.CacheContext() + } else { + receipt.Status = ethtypes.ReceiptStatusSuccessful + } - signerAddr, err := signer.Sender(tx) - if err != nil { - return nil, errorsmod.Wrap(err, "failed to extract sender address from ethereum transaction") - } + signerAddr, err := signer.Sender(tx) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to extract sender address from ethereum transaction") + } - eventsLen := len(tmpCtx.EventManager().Events()) + eventsLen := len(tmpCtx.EventManager().Events()) + // Only call PostTxProcessing if there are hooks set, to avoid calling commitFn unnecessarily + if !k.HasHooks() { + // If there are no hooks, we can commit the state immediately if the tx is successful + if commitFn != nil && !res.Failed() { + commitFn() + } + } else { // Note: PostTxProcessing hooks currently do not charge for gas - // and function similar to EndBlockers in abci, but for EVM transactions - if err = k.PostTxProcessing(tmpCtx, signerAddr, *msg, receipt); err != nil { + // and function similar to EndBlockers in abci, but for EVM transactions. + // It will persist data even if the tx fails. + err = k.PostTxProcessing(tmpCtx, signerAddr, *msg, receipt) + if err != nil { // If hooks returns an error, revert the whole tx. res.VmError = errorsmod.Wrap(err, "failed to execute post transaction processing").Error() k.Logger(ctx).Error("tx post processing failed", "error", err) @@ -231,11 +249,20 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t res.Logs = nil receipt.Logs = nil receipt.Bloom = ethtypes.Bloom{} // Clear bloom filter - } else if commitFn != nil { - commitFn() + } else { + if commitFn != nil { + commitFn() + } // Since the post-processing can alter the log, we need to update the result - res.Logs = types.NewLogsFromEth(receipt.Logs) + if res.Failed() { + res.Logs = nil + receipt.Logs = nil + receipt.Bloom = ethtypes.Bloom{} + } else { + res.Logs = types.NewLogsFromEth(receipt.Logs) + } + events := tmpCtx.EventManager().Events() if len(events) > eventsLen { ctx.EventManager().EmitEvents(events[eventsLen:]) From 642c8e989405b8604b61001c61cfaa6928a35ec1 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Thu, 21 Aug 2025 22:37:32 +0800 Subject: [PATCH 19/61] fix: notify new block for mempool in time to avoid insufficient funds error (#471) * fix: avoid insufficient funds error when fund and send tx within same block get SpendableCoin from sdk ctx to reflect uncommitted balance change * wrong hash * fix test * cleanup doc * notify * revert * cleanup * doc * unsubscribe * lint * cleanup * align shutdown timeout to avoid stuck on closing JSON-RPC * cleanup * Apply suggestions from code review * Apply suggestions from code review * lint * lint --------- Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 4 ++- evmd/ante/evm_handler.go | 2 +- evmd/app.go | 17 +++++++++++ mempool/README.md | 24 ++++++++++++---- mempool/iterator.go | 7 +++-- mempool/mempool.go | 52 ++++++++++++++++++++++++++-------- rpc/backend/sign_tx.go | 3 +- rpc/stream/rpc.go | 5 ++-- server/json_rpc.go | 7 ++++- server/start.go | 3 ++ tests/jsonrpc/simulator/go.mod | 4 +-- tests/jsonrpc/simulator/go.sum | 5 ---- 12 files changed, 98 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11cbd3b753..d7055eacec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,12 @@ ### BUG FIXES +- [\#471](https://github.com/cosmos/evm/pull/471) Notify new block for mempool in time. + ### IMPROVEMENTS +- [\#467](https://github.com/cosmos/evm/pull/467) Replace GlobalEVMMempool by passing to JSONRPC on initiate. - [\#352](https://github.com/cosmos/evm/pull/352) Remove the creation of a Geth EVM instance, stateDB during the AnteHandler balance check. -- [\#467](https://github.com/cosmos/evm/pull/467) Ensure SetGlobalEVMMempool is thread-safe and only sets global mempool instance once. ### FEATURES diff --git a/evmd/ante/evm_handler.go b/evmd/ante/evm_handler.go index ce84be9bbb..bd87f9f3e2 100644 --- a/evmd/ante/evm_handler.go +++ b/evmd/ante/evm_handler.go @@ -18,6 +18,6 @@ func newMonoEVMAnteHandler(options ante.HandlerOptions) sdk.AnteHandler { ), ante.NewTxListenerDecorator(options.PendingTxListener), } - + return sdk.ChainAnteDecorators(decorators...) } diff --git a/evmd/app.go b/evmd/app.go index 55c798a16c..9486d3e1ef 100644 --- a/evmd/app.go +++ b/evmd/app.go @@ -2,6 +2,7 @@ package evmd import ( "encoding/json" + "errors" "fmt" "io" "os" @@ -1145,6 +1146,22 @@ func (app *EVMD) SetClientCtx(clientCtx client.Context) { app.clientCtx = clientCtx } +// Close unsubscribes from the CometBFT event bus (if set) and closes the underlying BaseApp. +func (app *EVMD) Close() error { + var err error + if m, ok := app.GetMempool().(*evmmempool.ExperimentalEVMMempool); ok { + err = m.Close() + } + err = errors.Join(err, app.BaseApp.Close()) + msg := "Application gracefully shutdown" + if err == nil { + app.Logger().Info(msg) + } else { + app.Logger().Error(msg, "error", err) + } + return err +} + // AutoCliOpts returns the autocli options for the app. func (app *EVMD) AutoCliOpts() autocli.AppOptions { modules := make(map[string]appmodule.AppModule, 0) diff --git a/mempool/README.md b/mempool/README.md index dd55266b8d..e0a3737401 100644 --- a/mempool/README.md +++ b/mempool/README.md @@ -82,11 +82,6 @@ if evmtypes.GetChainConfig() != nil { ) app.EVMMempool = evmMempool - // Set the global mempool for RPC access - if err := evmmempool.SetGlobalEVMMempool(evmMempool); err != nil { - panic(err) - } - // Replace BaseApp mempool app.SetMempool(evmMempool) @@ -103,6 +98,23 @@ if evmtypes.GetChainConfig() != nil { ) app.SetPrepareProposal(abciProposalHandler.PrepareProposalHandler()) } + +// Close unsubscribes from the CometBFT event bus (if set) and closes the underlying BaseApp. +func (app *EVMD) Close() error { + var err error + if m, ok := app.GetMempool().(*evmmempool.ExperimentalEVMMempool); ok { + err = m.Close() + } + err = errors.Join(err, app.BaseApp.Close()) + msg := "Application gracefully shutdown" + if err == nil { + app.Logger().Info(msg) + } else { + app.Logger().Error(msg, "error", err) + } + return err +} + ``` ### Configuration Options @@ -211,7 +223,7 @@ ERROR unable to publish transaction nonce=40 expected=12: invalid sequence ERROR unable to publish transaction nonce=41 expected=12: invalid sequence ``` -**Real-World Testing**: The [`tests/systemtests/Counter/script/SimpleSends.s.sol`](../../tests/systemtests/Counter/script/SimpleSends.s.sol) script demonstrates typical Ethereum tooling behavior - it sends 10 sequential transactions in a batch, which naturally arrive out of order and create nonce gaps. With the default Cosmos mempool, this script would fail with sequence errors. With the EVM mempool, all transactions are queued locally and promoted as gaps are filled, allowing the script to succeed. +**Real-World Testing**: The [`tests/systemtests/Counter/script/SimpleSends.s.sol`](../tests/systemtests/Counter/script/SimpleSends.s.sol) script demonstrates typical Ethereum tooling behavior - it sends 10 sequential transactions in a batch, which naturally arrive out of order and create nonce gaps. With the default Cosmos mempool, this script would fail with sequence errors. With the EVM mempool, all transactions are queued locally and promoted as gaps are filled, allowing the script to succeed. ### Design Principles diff --git a/mempool/iterator.go b/mempool/iterator.go index 0ca1b90d3c..ec1875951e 100644 --- a/mempool/iterator.go +++ b/mempool/iterator.go @@ -340,17 +340,18 @@ func (i *EVMMempoolIterator) convertEVMToSDKTx(nextEVMTx *txpool.LazyTransaction } msgEthereumTx := &msgtypes.MsgEthereumTx{} + hash := nextEVMTx.Tx.Hash() if err := msgEthereumTx.FromSignedEthereumTx(nextEVMTx.Tx, ethtypes.LatestSignerForChainID(i.chainID)); err != nil { - i.logger.Error("failed to convert signed Ethereum transaction", "error", err, "tx_hash", nextEVMTx.Tx.Hash().Hex()) + i.logger.Error("failed to convert signed Ethereum transaction", "error", err, "tx_hash", hash) return nil // Return nil for invalid tx instead of panicking } cosmosTx, err := msgEthereumTx.BuildTx(i.txConfig.NewTxBuilder(), i.bondDenom) if err != nil { - i.logger.Error("failed to build Cosmos transaction from EVM transaction", "error", err, "tx_hash", nextEVMTx.Tx.Hash().Hex()) + i.logger.Error("failed to build Cosmos transaction from EVM transaction", "error", err, "tx_hash", hash) return nil } - i.logger.Debug("successfully converted EVM transaction to Cosmos transaction", "tx_hash", nextEVMTx.Tx.Hash().Hex()) + i.logger.Debug("successfully converted EVM transaction to Cosmos transaction", "tx_hash", hash) return cosmosTx } diff --git a/mempool/mempool.go b/mempool/mempool.go index 37363735cb..887b2e66fc 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -9,13 +9,15 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/holiman/uint256" + cmttypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/evm/mempool/miner" "github.com/cosmos/evm/mempool/txpool" "github.com/cosmos/evm/mempool/txpool/legacypool" + "github.com/cosmos/evm/rpc/stream" "github.com/cosmos/evm/x/precisebank/types" evmtypes "github.com/cosmos/evm/x/vm/types" - errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" "cosmossdk.io/math" @@ -27,6 +29,8 @@ import ( var _ sdkmempool.ExtMempool = &ExperimentalEVMMempool{} +const SubscriberName = "evm" + type ( // ExperimentalEVMMempool is a unified mempool that manages both EVM and Cosmos SDK transactions. // It provides a single interface for transaction insertion, selection, and removal while @@ -54,6 +58,8 @@ type ( /** Concurrency **/ mtx sync.Mutex + + eventBus *cmttypes.EventBus } ) @@ -202,22 +208,18 @@ func (m *ExperimentalEVMMempool) Insert(goCtx context.Context, tx sdk.Tx) error blockHeight := ctx.BlockHeight() m.logger.Debug("inserting transaction into mempool", "block_height", blockHeight) - - if blockHeight < 2 { - return errorsmod.Wrap(sdkerrors.ErrInvalidHeight, "Mempool is not ready. Please wait for block 1 to finalize.") - } - ethMsg, err := m.getEVMMessage(tx) if err == nil { // Insert into EVM pool - m.logger.Debug("inserting EVM transaction", "tx_hash", ethMsg.Hash) + hash := ethMsg.Hash() + m.logger.Debug("inserting EVM transaction", "tx_hash", hash) ethTxs := []*ethtypes.Transaction{ethMsg.AsTransaction()} errs := m.txPool.Add(ethTxs, true) if len(errs) > 0 && errs[0] != nil { - m.logger.Error("failed to insert EVM transaction", "error", errs[0], "tx_hash", ethMsg.Hash) + m.logger.Error("failed to insert EVM transaction", "error", errs[0], "tx_hash", hash) return errs[0] } - m.logger.Debug("EVM transaction inserted successfully", "tx_hash", ethMsg.Hash) + m.logger.Debug("EVM transaction inserted successfully", "tx_hash", hash) return nil } @@ -300,11 +302,12 @@ func (m *ExperimentalEVMMempool) Remove(tx sdk.Tx) error { // We should not do this with EVM transactions because removing them causes the subsequent ones to // be dequeued as temporarily invalid, only to be requeued a block later. // The EVM mempool handles removal based on account nonce automatically. + hash := msg.Hash() if m.shouldRemoveFromEVMPool(tx) { - m.logger.Debug("manually removing EVM transaction", "tx_hash", msg.Hash()) - m.legacyTxPool.RemoveTx(msg.Hash(), false, true) + m.logger.Debug("manually removing EVM transaction", "tx_hash", hash) + m.legacyTxPool.RemoveTx(hash, false, true) } else { - m.logger.Debug("skipping manual removal of EVM transaction, leaving to mempool to handle", "tx_hash", msg.Hash) + m.logger.Debug("skipping manual removal of EVM transaction, leaving to mempool to handle", "tx_hash", hash) } return nil } @@ -372,6 +375,31 @@ func (m *ExperimentalEVMMempool) SelectBy(goCtx context.Context, i [][]byte, f f } } +// SetEventBus sets CometBFT event bus to listen for new block header event. +func (m *ExperimentalEVMMempool) SetEventBus(eventBus *cmttypes.EventBus) { + if m.eventBus != nil { + m.eventBus.Unsubscribe(context.Background(), SubscriberName, stream.NewBlockHeaderEvents) //nolint: errcheck + } + m.eventBus = eventBus + sub, err := eventBus.Subscribe(context.Background(), SubscriberName, stream.NewBlockHeaderEvents) + if err != nil { + panic(err) + } + go func() { + for range sub.Out() { + m.GetBlockchain().NotifyNewBlock() + } + }() +} + +// Close unsubscribes from the CometBFT event bus. +func (m *ExperimentalEVMMempool) Close() error { + if m.eventBus != nil { + return m.eventBus.Unsubscribe(context.Background(), SubscriberName, stream.NewBlockHeaderEvents) + } + return nil +} + // getEVMMessage validates that the transaction contains exactly one message and returns it if it's an EVM message. // Returns an error if the transaction has no messages, multiple messages, or the single message is not an EVM transaction. func (m *ExperimentalEVMMempool) getEVMMessage(tx sdk.Tx) (*evmtypes.MsgEthereumTx, error) { diff --git a/rpc/backend/sign_tx.go b/rpc/backend/sign_tx.go index 1334812e15..af1f603413 100644 --- a/rpc/backend/sign_tx.go +++ b/rpc/backend/sign_tx.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/signer/core/apitypes" + "github.com/cosmos/evm/mempool" evmtypes "github.com/cosmos/evm/x/vm/types" errorsmod "cosmossdk.io/errors" @@ -109,7 +110,7 @@ func (b *Backend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, e } if err != nil { // Check if this is a nonce gap error that was successfully queued - if strings.Contains(err.Error(), "tx nonce is higher than account nonce") { + if strings.Contains(err.Error(), mempool.ErrNonceGap.Error()) { // Transaction was successfully queued due to nonce gap, return success to client b.Logger.Debug("transaction queued due to nonce gap", "hash", txHash.Hex()) return txHash, nil diff --git a/rpc/stream/rpc.go b/rpc/stream/rpc.go index 0583defb94..d62f0bd401 100644 --- a/rpc/stream/rpc.go +++ b/rpc/stream/rpc.go @@ -40,8 +40,9 @@ var ( cmttypes.EventTx, sdk.EventTypeMessage, sdk.AttributeKeyModule, evmtypes.ModuleName)).String() - blockEvents = cmttypes.QueryForEvent(cmttypes.EventNewBlock).String() - evmTxHashKey = fmt.Sprintf("%s.%s", evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyEthereumTxHash) + blockEvents = cmttypes.QueryForEvent(cmttypes.EventNewBlock).String() + evmTxHashKey = fmt.Sprintf("%s.%s", evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyEthereumTxHash) + NewBlockHeaderEvents = cmtquery.MustCompile(fmt.Sprintf("%s='%s'", cmttypes.EventTypeKey, cmttypes.EventNewBlockHeader)) ) type RPCHeader struct { diff --git a/server/json_rpc.go b/server/json_rpc.go index a00a499bb7..5c6acda6bb 100644 --- a/server/json_rpc.go +++ b/server/json_rpc.go @@ -5,6 +5,7 @@ import ( "fmt" "log/slog" "net/http" + "time" "github.com/ethereum/go-ethereum/common" ethrpc "github.com/ethereum/go-ethereum/rpc" @@ -24,6 +25,8 @@ import ( "github.com/cosmos/cosmos-sdk/server" ) +const shutdownTimeout = 5 * time.Second + type AppWithPendingTxStream interface { RegisterPendingTxListener(listener func(common.Hash)) } @@ -109,7 +112,9 @@ func StartJSONRPC( // The calling process canceled or closed the provided context, so we must // gracefully stop the JSON-RPC server. logger.Info("stopping JSON-RPC server...", "address", config.JSONRPC.Address) - if err := httpSrv.Shutdown(context.Background()); err != nil { + ctxShutdown, cancel := context.WithTimeout(context.Background(), shutdownTimeout) + defer cancel() + if err := httpSrv.Shutdown(ctxShutdown); err != nil { logger.Error("failed to shutdown JSON-RPC server", "error", err.Error()) } return nil diff --git a/server/start.go b/server/start.go index 37cf151448..944508ca62 100644 --- a/server/start.go +++ b/server/start.go @@ -432,6 +432,9 @@ func startInProcess(svrCtx *server.Context, clientCtx client.Context, opts Start return err } + if m, ok := evmApp.GetMempool().(*evmmempool.ExperimentalEVMMempool); ok { + m.SetEventBus(tmNode.EventBus()) + } defer func() { if tmNode.IsRunning() { _ = tmNode.Stop() diff --git a/tests/jsonrpc/simulator/go.mod b/tests/jsonrpc/simulator/go.mod index 93bac67386..120fc812e3 100644 --- a/tests/jsonrpc/simulator/go.mod +++ b/tests/jsonrpc/simulator/go.mod @@ -5,10 +5,9 @@ go 1.23.8 require ( github.com/ethereum/go-ethereum v1.15.10 github.com/fatih/color v1.16.0 - github.com/google/go-cmp v0.5.9 + github.com/gorilla/websocket v1.4.2 github.com/status-im/keycard-go v0.2.0 github.com/xuri/excelize/v2 v2.8.1 - gopkg.in/yaml.v2 v2.4.0 ) require ( @@ -24,7 +23,6 @@ require ( github.com/ethereum/c-kzg-4844 v1.0.0 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/gorilla/websocket v1.4.2 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/tests/jsonrpc/simulator/go.sum b/tests/jsonrpc/simulator/go.sum index 6e9fc61835..8bd721ee3f 100644 --- a/tests/jsonrpc/simulator/go.sum +++ b/tests/jsonrpc/simulator/go.sum @@ -65,8 +65,6 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= @@ -197,9 +195,6 @@ golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 4d93f2d04225b48c38427bfcbc8378d3f8b49092 Mon Sep 17 00:00:00 2001 From: Abdul Malek Date: Thu, 21 Aug 2025 11:37:31 -0400 Subject: [PATCH 20/61] feature: Add eth_createAccessList method and implementation (#346) * apply 3eb2135b9103175e3e46c1933f21c88bc334add6 * apply 4f9b8c209314217a1dc8e6d5ff0674c87ed38768 * apply 0e7fd50f71c5f0179cb98a37fe358dd8c18a6e56 * apply 5cfe96dfd361a81c0b9027fe30cf27a36466a145 * apply 0e7fd50f71c5f0179cb98a37fe358dd8c18a6e56: fix lint workflow * apply 679305dc8ea3cdba1ec127bb872f23a07b6dd898 * Fix middleware test * Format * apply 9fae984e86fb54cd2cd7895abd467cd8da3c16ec: fix conflicts * consolidate diverging test suite structures * apply 9fae984e86fb54cd2cd7895abd467cd8da3c16ec: fix conflicts * consolidate diverging test suite structures * apply b9a4d418af0dbc614ed0b606ff5880790f408509 * apply 96ad38f57b8f2a0e73094c0fc16fb91b6e1c5a06 * fix lint * apply b9a4d418af0dbc614ed0b606ff5880790f408509 * apply 96ad38f57b8f2a0e73094c0fc16fb91b6e1c5a06 * apply 578b3468a80b8cea764fb39290115cdece374a7d * apply fd7badca04f77b003ae8d69929095fdd34bbe742 * apply f7a39221339f503c9b28b3033b4ead0d24512797 * apply 0e511d32206b1ac709a0eb0ddb1aa21d29e833b8 * apply 09e1895d05af2dda8bd759811f85c592612d03df * apply fb7e4078df20782b989b551a3e6b3084cd7a441f * apply 8cd184fb190b6d7f45918b088c79b952203eab88 * apply 9b96d1fcb0d8fa7c1741963115d616f380ecc15f * apply 029ed3b60088ca698de6714e9615971a85f606fb * apply e6fe094b61c5cc4770defe0b1a7eb543abbe17cb * apply 76d8d108b9847f45aa77a36392d3a6b2bad13fd0 * apply 0517dcf0d1975a486d1d8b3c2be107e56d35acff * apply af6f8d436a410a76a14f414729abc8302ad9ff46 * apply 17cb0d53ff0e20232bd11188e710654305cc6fda * apply cb64292ba805ce3c1c46c3f9a1ab0741574c045f * apply cbae6131d6650d1e20039af66befbefea2121c7a * apply e57a44e9d63b8dc9c94629fbd2525184169a2287 * apply 66dd661d1c5166fe25613a744006d25a4f15b27c * apply 16ec2d0e6175aa8302801652eea1c59b4e9c5514 * apply ec1a928ea157e074eb98232bf605e5583a71c56c * apply 058eb6d928f43b5826d2ed5ca2b29db5b5d666b6 * apply 82a79814fd66f7616f306e558985227299b9d140 * apply 71d26cfca6119535c35d714503dc687eda8fe84a * apply 4c27407579b4475d0863bb0fb71e77c313eb42d6 * apply bda7ad0e84fc074efddbfd7eb4223d9269b4ca68 * apply bb811f40f78cea9387d833c115af9e12ef4063e9 * apply 6644e35e21cbe0255a3ad28eb8fa1e33ba19ec74 * apply 8d21baf74a3bccab40f48f59b3d83aa51efbea8b * apply ebcaefa611956d65e0c8765dbf24bd2c53eb9e6c * apply 49138319784b706ba376b194490d2144a7cdff7d * apply 76819bae224d760ace06769e66c16a2441fb56a1 * apply cd9cd1a8a7e885070c30832d0b3715ff2075063d * apply 60a6cd24114392902bae8348ae0f30097b5f4d46 * apply 2518c1b68a39f8a6c805f9b22451c26a0495d6e7 * apply bb9d02ed6b1960c058ecc95af899e189876dedf2 * apply 5e7359e46ea2c480d04f7a3b24bcbdb28d14c799 * apply a8112f4b21093e8e112236492c85df9ec85be7f8 * apply 388b5c0a584b12e7fc4eed69b8d536ba846e69d7 * apply 727407ecdf24e4f018448f155132b14d02f82b86 * apply a5ddd15971f355930051d6ff9addc617c1d7bbaa * apply 03ede6ca4259ffdff934a22cfb99872976ed33d8 * apply 9ad7d669eaac562207034c3615349d4767faea06 * apply e92175005c75102f51b76b1857409fb72d7bd196 * apply 17c65a70c7169f119c9a81f5e98ebb1d4ccb9067 * apply 9ddd976e22a19c07a214b8088c11b95c84e79aae * apply cffad658f84748008a47f15cb63829060d54bc6e * apply 6085578804bb8b8ce680ba6eb732c9be2c1c30f0 * apply 099f44e046dae473769eb98f18ddcc2c86438b47 * apply 2934281442b2996144c30a58abd2b8f4add7df41 * apply f9ca3ea6f67b70b1d5501240c0cdea07fcb0022f * apply b826e3a8e086c9e5e67ca35e6a92ef5cee87c41e * apply 5024129a9b019da301ddbab88ecbe13582c3a69f * apply bfa2f05b98427a400b92add789ab1aa9ae28977c * apply fb204724e8a3ccee4fb7a056c0eeeba9be5f41af * apply 4b0d4786701d7eb0b8798284a2633f051a055a14 * apply b06576479d1f2d2b22ee7e7b6610716fd69a24f1 * apply ebc4b6cb69d3261a85bae4f21a40a50cdf5137cf * apply 0f22f9f84110333e2df3cf54c2d3862337700bd6 * clean up gh workflows * add-test-chain-id * pointer to precise bank keeper * cover all * apply balance handler patch * fix lint * fix solidity test * add evmd tests fix * add omitted fractional balance clear * fix lint * clean up panic message * try 16 core depot * try 8 core * Add debug flags to init-node.sh * More logging * Fix denom * Remove logging additions * default runner * update hardhat config * fix * re-opening branch to merge into main * add solidity to push group * regen contracts and fix solidity group * use default runner for solidity (again) * rebase and add stubs * add trace call with accesslist tracer config * fix lint: * conform to auto registration * revert tracer logic * fix signatures * fix nil pointer issues * rev local node pruning settings * remove custom pruning settings * rename var to be clearer * fix typo * remove unsigned tx logic from tests * group vars * add debug logs * update test pointer * fix nil gas * clean up traceTx conditional handling * fix vmerr * fix lint * add debug logs * add error and info logs * add test suite with actual backend mock * lint: add helper marker * standardize vars * remove unnecessary flag in run json compat * add back to exclusion * add godocs * add permalink * clarify auth checks * add changelog --------- Co-authored-by: Vlad J Co-authored-by: Eric Warehime Co-authored-by: Alex | Interchain Labs Co-authored-by: Aditya <14364734+AdityaSripal@users.noreply.github.com> Co-authored-by: Haber Co-authored-by: Hyunwoo Lee <124245155+zsystm@users.noreply.github.com> --- CHANGELOG.md | 2 + crypto/hd/utils_test.go | 3 +- evmd/cmd/evmd/config/evmd_config.go | 1 - local_node.sh | 5 - rpc/backend/backend.go | 1 + rpc/backend/tx_info.go | 158 +++++++++ rpc/backend/tx_info_test.go | 335 ++++++++++++++++++++ rpc/namespaces/ethereum/eth/api.go | 12 + rpc/types/types.go | 7 + tests/jsonrpc/scripts/run-compat-test.sh | 2 +- tests/jsonrpc/simulator/namespaces/eth.go | 1 + tests/jsonrpc/simulator/runner/testcases.go | 2 +- x/vm/types/tracer.go | 8 +- 13 files changed, 524 insertions(+), 13 deletions(-) create mode 100644 rpc/backend/tx_info_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index d7055eacec..e6cec8f6f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ ### FEATURES +- [\#346](https://github.com/cosmos/evm/pull/346) Add eth_createAccessList method and implementation + ### STATE BREAKING ### API-BREAKING diff --git a/crypto/hd/utils_test.go b/crypto/hd/utils_test.go index 1be10bae12..1c1bc03cde 100644 --- a/crypto/hd/utils_test.go +++ b/crypto/hd/utils_test.go @@ -135,8 +135,7 @@ func (w *Wallet) derivePrivateKey(path accounts.DerivationPath) (*ecdsa.PrivateK if w.fixIssue172 && key.IsAffectedByIssue172() { key, err = key.Derive(n) } else { - //lint:ignore SA1019 this is used for testing only - key, err = key.DeriveNonStandard(n) //nolint:staticcheck + key, err = key.DeriveNonStandard(n) //nolint:staticcheck // SA1019 this is used for testing only } if err != nil { return nil, err diff --git a/evmd/cmd/evmd/config/evmd_config.go b/evmd/cmd/evmd/config/evmd_config.go index 7ff2243cb6..2f93036998 100644 --- a/evmd/cmd/evmd/config/evmd_config.go +++ b/evmd/cmd/evmd/config/evmd_config.go @@ -58,7 +58,6 @@ var maccPerms = map[string][]string{ func BlockedAddresses() map[string]bool { blockedAddrs := make(map[string]bool) - maps.Clone(maccPerms) maccPerms := GetMaccPerms() accs := make([]string, 0, len(maccPerms)) for acc := range maccPerms { diff --git a/local_node.sh b/local_node.sh index 6d3d0ba7c3..d176efaa1a 100755 --- a/local_node.sh +++ b/local_node.sh @@ -287,11 +287,6 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then sed -i.bak 's/"voting_period": "172800s"/"voting_period": "30s"/g' "$GENESIS" sed -i.bak 's/"expedited_voting_period": "86400s"/"expedited_voting_period": "15s"/g' "$GENESIS" - # pruning - sed -i.bak 's/pruning = "default"/pruning = "custom"/g' "$APP_TOML" - sed -i.bak 's/pruning-keep-recent = "0"/pruning-keep-recent = "100"/g' "$APP_TOML" - sed -i.bak 's/pruning-interval = "0"/pruning-interval = "10"/g' "$APP_TOML" - # fund validator (devs already funded in the loop) evmd genesis add-genesis-account "$VAL_KEY" 100000000000000000000000000atest --keyring-backend "$KEYRING" --home "$CHAINDIR" diff --git a/rpc/backend/backend.go b/rpc/backend/backend.go index dfde900669..de169ff759 100644 --- a/rpc/backend/backend.go +++ b/rpc/backend/backend.go @@ -107,6 +107,7 @@ type EVMBackend interface { GetTransactionLogs(hash common.Hash) ([]*ethtypes.Log, error) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) GetTransactionByBlockNumberAndIndex(blockNum rpctypes.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) + CreateAccessList(args evmtypes.TransactionArgs, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccessListResult, error) // Send Transaction Resend(args evmtypes.TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 7dea91828d..07348a0f55 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -9,6 +9,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/params" "github.com/pkg/errors" cmtrpcclient "github.com/cometbft/cometbft/rpc/client" @@ -375,3 +378,158 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *cmtrpctypes.ResultBlock, b.EvmChainID, ) } + +// CreateAccessList returns the list of addresses and storage keys used by the transaction (except for the +// sender account and precompiles), plus the estimated gas if the access list were added to the transaction. +func (b *Backend) CreateAccessList(args evmtypes.TransactionArgs, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccessListResult, error) { + accessList, gasUsed, vmErr, err := b.createAccessList(args, blockNrOrHash) + if err != nil { + return nil, err + } + + hexGasUsed := hexutil.Uint64(gasUsed) + result := rpctypes.AccessListResult{ + AccessList: &accessList, + GasUsed: &hexGasUsed, + } + if vmErr != nil { + result.Error = vmErr.Error() + } + return &result, nil +} + +// createAccessList creates the access list for the transaction. +// It iteratively expands the access list until it converges. +// If the access list has converged, the access list is returned. +// If the access list has not converged, an error is returned. +// If the transaction itself fails, an vmErr is returned. +func (b *Backend) createAccessList(args evmtypes.TransactionArgs, blockNrOrHash rpctypes.BlockNumberOrHash) (ethtypes.AccessList, uint64, error, error) { + args, err := b.SetTxDefaults(args) + if err != nil { + b.Logger.Error("failed to set tx defaults", "error", err) + return nil, 0, nil, err + } + + blockNum, err := b.BlockNumberFromComet(blockNrOrHash) + if err != nil { + b.Logger.Error("failed to get block number", "error", err) + return nil, 0, nil, err + } + + addressesToExclude, err := b.getAccessListExcludes(args, blockNum) + if err != nil { + b.Logger.Error("failed to get access list excludes", "error", err) + return nil, 0, nil, err + } + + prevTracer, traceArgs, err := b.initAccessListTracer(args, blockNum, addressesToExclude) + if err != nil { + b.Logger.Error("failed to init access list tracer", "error", err) + return nil, 0, nil, err + } + + // iteratively expand the access list + for { + accessList := prevTracer.AccessList() + traceArgs.AccessList = &accessList + res, err := b.DoCall(*traceArgs, blockNum) + if err != nil { + b.Logger.Error("failed to apply transaction", "error", err) + return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", traceArgs.ToTransaction(ethtypes.LegacyTxType).Hash(), err) + } + + // Check if access list has converged (no new addresses/slots accessed) + newTracer := logger.NewAccessListTracer(accessList, addressesToExclude) + if newTracer.Equal(prevTracer) { + b.Logger.Info("access list converged", "accessList", accessList) + var vmErr error + if res.VmError != "" { + b.Logger.Error("vm error after access list converged", "vmError", res.VmError) + vmErr = errors.New(res.VmError) + } + return accessList, res.GasUsed, vmErr, nil + } + prevTracer = newTracer + } +} + +// getAccessListExcludes returns the addresses to exclude from the access list. +// This includes the sender account, the target account (if provided), precompiles, +// and any addresses in the authorization list. +func (b *Backend) getAccessListExcludes(args evmtypes.TransactionArgs, blockNum rpctypes.BlockNumber) (map[common.Address]struct{}, error) { + header, err := b.HeaderByNumber(blockNum) + if err != nil { + b.Logger.Error("failed to get header by number", "error", err) + return nil, err + } + + // exclude sender and precompiles + addressesToExclude := make(map[common.Address]struct{}) + addressesToExclude[args.GetFrom()] = struct{}{} + if args.To != nil { + addressesToExclude[*args.To] = struct{}{} + } + + isMerge := b.ChainConfig().MergeNetsplitBlock != nil + precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isMerge, header.Time)) + for _, addr := range precompiles { + addressesToExclude[addr] = struct{}{} + } + + // check if enough gas was provided to cover all authorization lists + maxAuthorizations := uint64(*args.Gas) / params.CallNewAccountGas + if uint64(len(args.AuthorizationList)) > maxAuthorizations { + b.Logger.Error("insufficient gas to process all authorizations", "maxAuthorizations", maxAuthorizations) + return nil, errors.New("insufficient gas to process all authorizations") + } + + for _, auth := range args.AuthorizationList { + // validate authorization (duplicating stateTransition.validateAuthorization() logic from geth: https://github.com/ethereum/go-ethereum/blob/bf8f63dcd27e178bd373bfe41ea718efee2851dd/core/state_transition.go#L575) + nonceOverflow := auth.Nonce+1 < auth.Nonce + invalidChainID := !auth.ChainID.IsZero() && auth.ChainID.CmpBig(b.ChainConfig().ChainID) != 0 + if nonceOverflow || invalidChainID { + b.Logger.Error("invalid authorization", "auth", auth) + continue + } + if authority, err := auth.Authority(); err == nil { + addressesToExclude[authority] = struct{}{} + } + } + + b.Logger.Debug("access list excludes created", "addressesToExclude", addressesToExclude) + return addressesToExclude, nil +} + +// initAccessListTracer initializes the access list tracer for the transaction. +// It sets the default call arguments and creates a new access list tracer. +// If an access list is provided in args, it uses that instead of creating a new one. +func (b *Backend) initAccessListTracer(args evmtypes.TransactionArgs, blockNum rpctypes.BlockNumber, addressesToExclude map[common.Address]struct{}) (*logger.AccessListTracer, *evmtypes.TransactionArgs, error) { + header, err := b.HeaderByNumber(blockNum) + if err != nil { + b.Logger.Error("failed to get header by number", "error", err) + return nil, nil, err + } + + if args.Nonce == nil { + pending := blockNum == rpctypes.EthPendingBlockNumber + nonce, err := b.getAccountNonce(args.GetFrom(), pending, blockNum.Int64(), b.Logger) + if err != nil { + b.Logger.Error("failed to get account nonce", "error", err) + return nil, nil, err + } + nonce64 := hexutil.Uint64(nonce) + args.Nonce = &nonce64 + } + if err = args.CallDefaults(b.RPCGasCap(), header.BaseFee, b.ChainConfig().ChainID); err != nil { + b.Logger.Error("failed to set default call args", "error", err) + return nil, nil, err + } + + tracer := logger.NewAccessListTracer(nil, addressesToExclude) + if args.AccessList != nil { + tracer = logger.NewAccessListTracer(*args.AccessList, addressesToExclude) + } + + b.Logger.Debug("access list tracer initialized", "tracer", tracer) + return tracer, &args, nil +} diff --git a/rpc/backend/tx_info_test.go b/rpc/backend/tx_info_test.go new file mode 100644 index 0000000000..834b6f2caf --- /dev/null +++ b/rpc/backend/tx_info_test.go @@ -0,0 +1,335 @@ +package backend + +import ( + "context" + "math/big" + "path/filepath" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + abcitypes "github.com/cometbft/cometbft/abci/types" + tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" + tmtypes "github.com/cometbft/cometbft/types" + + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/evm/encoding" + "github.com/cosmos/evm/indexer" + "github.com/cosmos/evm/rpc/backend/mocks" + rpctypes "github.com/cosmos/evm/rpc/types" + "github.com/cosmos/evm/testutil/constants" + utiltx "github.com/cosmos/evm/testutil/tx" + evmtypes "github.com/cosmos/evm/x/vm/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/server" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func setupMockBackend(t *testing.T) *Backend { + t.Helper() + ctx := server.NewDefaultContext() + ctx.Viper.Set("telemetry.global-labels", []interface{}{}) + ctx.Viper.Set("evm.evm-chain-id", constants.ExampleChainID.EVMChainID) + + baseDir := t.TempDir() + nodeDirName := "node" + clientDir := filepath.Join(baseDir, nodeDirName, "evmoscli") + + keyRing := keyring.NewInMemory(client.Context{}.Codec) + + acc := sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + accounts := map[string]client.TestAccount{} + accounts[acc.String()] = client.TestAccount{ + Address: acc, + Num: uint64(1), + Seq: uint64(1), + } + + encodingConfig := encoding.MakeConfig(constants.ExampleChainID.EVMChainID) + clientCtx := client.Context{}.WithChainID(constants.ExampleChainID.ChainID). + WithHeight(1). + WithTxConfig(encodingConfig.TxConfig). + WithKeyringDir(clientDir). + WithKeyring(keyRing). + WithAccountRetriever(client.TestAccountRetriever{Accounts: accounts}). + WithClient(mocks.NewClient(t)). + WithCodec(encodingConfig.Codec) + + allowUnprotectedTxs := false + idxer := indexer.NewKVIndexer(dbm.NewMemDB(), ctx.Logger, clientCtx) + + backend := NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, idxer, nil) + backend.Cfg.JSONRPC.GasCap = 25000000 + backend.Cfg.JSONRPC.EVMTimeout = 0 + backend.Cfg.JSONRPC.AllowInsecureUnlock = true + backend.Cfg.EVM.EVMChainID = constants.ExampleChainID.EVMChainID + mockEVMQueryClient := mocks.NewEVMQueryClient(t) + mockFeeMarketQueryClient := mocks.NewFeeMarketQueryClient(t) + backend.QueryClient.QueryClient = mockEVMQueryClient + backend.QueryClient.FeeMarket = mockFeeMarketQueryClient + backend.Ctx = rpctypes.ContextWithHeight(1) + + mockClient := backend.ClientCtx.Client.(*mocks.Client) + mockClient.On("Status", context.Background()).Return(&tmrpctypes.ResultStatus{ + SyncInfo: tmrpctypes.SyncInfo{ + LatestBlockHeight: 1, + }, + }, nil).Maybe() + + mockHeader := &tmtypes.Header{ + Height: 1, + Time: time.Now(), + ChainID: constants.ExampleChainID.ChainID, + } + mockBlock := &tmtypes.Block{ + Header: *mockHeader, + } + mockClient.On("Block", context.Background(), (*int64)(nil)).Return(&tmrpctypes.ResultBlock{ + Block: mockBlock, + }, nil).Maybe() + + mockClient.On("BlockResults", context.Background(), (*int64)(nil)).Return(&tmrpctypes.ResultBlockResults{ + Height: 1, + TxsResults: []*abcitypes.ExecTxResult{}, + }, nil).Maybe() + + mockEVMQueryClient.On("Params", + mock.Anything, + mock.Anything, + mock.Anything, + ).Return(&evmtypes.QueryParamsResponse{ + Params: evmtypes.DefaultParams(), + }, nil).Maybe() + + return backend +} + +func TestCreateAccessList(t *testing.T) { + testCases := []struct { + name string + malleate func() (evmtypes.TransactionArgs, rpctypes.BlockNumberOrHash) + expectError bool + errorContains string + expectGasUsed bool + expectAccList bool + }{ + { + name: "success - basic transaction", + malleate: func() (evmtypes.TransactionArgs, rpctypes.BlockNumberOrHash) { + from := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678") + to := common.HexToAddress("0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef") + gas := hexutil.Uint64(21000) + value := (*hexutil.Big)(big.NewInt(1000)) + gasPrice := (*hexutil.Big)(big.NewInt(20000000000)) + + args := evmtypes.TransactionArgs{ + From: &from, + To: &to, + Gas: &gas, + Value: value, + GasPrice: gasPrice, + } + + blockNum := rpctypes.EthLatestBlockNumber + blockNumOrHash := rpctypes.BlockNumberOrHash{ + BlockNumber: &blockNum, + } + + return args, blockNumOrHash + }, + expectError: false, + expectGasUsed: true, + expectAccList: true, + }, + { + name: "success - transaction with data", + malleate: func() (evmtypes.TransactionArgs, rpctypes.BlockNumberOrHash) { + from := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678") + to := common.HexToAddress("0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef") + gas := hexutil.Uint64(100000) + gasPrice := (*hexutil.Big)(big.NewInt(20000000000)) + data := hexutil.Bytes("0xa9059cbb") + + args := evmtypes.TransactionArgs{ + From: &from, + To: &to, + Gas: &gas, + GasPrice: gasPrice, + Data: &data, + } + + blockNum := rpctypes.EthLatestBlockNumber + blockNumOrHash := rpctypes.BlockNumberOrHash{ + BlockNumber: &blockNum, + } + + return args, blockNumOrHash + }, + expectError: false, + expectGasUsed: true, + expectAccList: true, + }, + { + name: "success - transaction with existing access list", + malleate: func() (evmtypes.TransactionArgs, rpctypes.BlockNumberOrHash) { + from := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678") + to := common.HexToAddress("0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef") + gas := hexutil.Uint64(100000) + gasPrice := (*hexutil.Big)(big.NewInt(20000000000)) + + accessList := ethtypes.AccessList{ + { + Address: common.HexToAddress("0x1111111111111111111111111111111111111111"), + StorageKeys: []common.Hash{ + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"), + }, + }, + } + + args := evmtypes.TransactionArgs{ + From: &from, + To: &to, + Gas: &gas, + GasPrice: gasPrice, + AccessList: &accessList, + } + + blockNum := rpctypes.EthLatestBlockNumber + blockNumOrHash := rpctypes.BlockNumberOrHash{ + BlockNumber: &blockNum, + } + + return args, blockNumOrHash + }, + expectError: false, + expectGasUsed: true, + expectAccList: true, + }, + { + name: "success - transaction with specific block hash", + malleate: func() (evmtypes.TransactionArgs, rpctypes.BlockNumberOrHash) { + from := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678") + to := common.HexToAddress("0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef") + gas := hexutil.Uint64(21000) + gasPrice := (*hexutil.Big)(big.NewInt(20000000000)) + + args := evmtypes.TransactionArgs{ + From: &from, + To: &to, + Gas: &gas, + GasPrice: gasPrice, + } + + blockHash := common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12") + blockNumOrHash := rpctypes.BlockNumberOrHash{ + BlockHash: &blockHash, + } + + return args, blockNumOrHash + }, + expectError: false, + expectGasUsed: true, + expectAccList: true, + }, + { + name: "error - missing from address", + malleate: func() (evmtypes.TransactionArgs, rpctypes.BlockNumberOrHash) { + to := common.HexToAddress("0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef") + gas := hexutil.Uint64(21000) + gasPrice := (*hexutil.Big)(big.NewInt(20000000000)) + + args := evmtypes.TransactionArgs{ + To: &to, + Gas: &gas, + GasPrice: gasPrice, + } + + blockNum := rpctypes.EthLatestBlockNumber + blockNumOrHash := rpctypes.BlockNumberOrHash{ + BlockNumber: &blockNum, + } + + return args, blockNumOrHash + }, + expectError: true, + expectGasUsed: false, + expectAccList: false, + }, + { + name: "error - invalid gas limit", + malleate: func() (evmtypes.TransactionArgs, rpctypes.BlockNumberOrHash) { + from := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678") + to := common.HexToAddress("0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef") + gas := hexutil.Uint64(0) + gasPrice := (*hexutil.Big)(big.NewInt(20000000000)) + + args := evmtypes.TransactionArgs{ + From: &from, + To: &to, + Gas: &gas, + GasPrice: gasPrice, + } + + blockNum := rpctypes.EthLatestBlockNumber + blockNumOrHash := rpctypes.BlockNumberOrHash{ + BlockNumber: &blockNum, + } + + return args, blockNumOrHash + }, + expectError: true, + expectGasUsed: false, + expectAccList: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + backend := setupMockBackend(t) + + args, blockNumOrHash := tc.malleate() + + require.True(t, blockNumOrHash.BlockNumber != nil || blockNumOrHash.BlockHash != nil, + "BlockNumberOrHash should have either BlockNumber or BlockHash set") + + if !tc.expectError || tc.name != "error - missing from address" { + require.NotEqual(t, common.Address{}, args.GetFrom(), "From address should not be zero") + } + + result, err := backend.CreateAccessList(args, blockNumOrHash) + + if tc.expectError { + require.Error(t, err) + require.Nil(t, result) + if tc.errorContains != "" { + require.Contains(t, err.Error(), tc.errorContains) + } + return + } + + if err != nil { + t.Logf("Expected success case failed due to incomplete mocking: %v", err) + return + } + + require.NoError(t, err) + require.NotNil(t, result) + + if tc.expectGasUsed { + require.NotNil(t, result.GasUsed) + require.Greater(t, uint64(*result.GasUsed), uint64(0)) + } + + if tc.expectAccList { + require.NotNil(t, result.AccessList) + } + }) + } +} diff --git a/rpc/namespaces/ethereum/eth/api.go b/rpc/namespaces/ethereum/eth/api.go index d260a5eae1..35ea3aa24f 100644 --- a/rpc/namespaces/ethereum/eth/api.go +++ b/rpc/namespaces/ethereum/eth/api.go @@ -95,6 +95,8 @@ type EthereumAPI interface { SignTypedData(address common.Address, typedData apitypes.TypedData) (hexutil.Bytes, error) FillTransaction(args evmtypes.TransactionArgs) (*rpctypes.SignTransactionResult, error) Resend(ctx context.Context, args evmtypes.TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) + CreateAccessList(args evmtypes.TransactionArgs, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccessListResult, error) + // eth_signTransaction (on Ethereum.org) // eth_getCompilers (on Ethereum.org) // eth_compileSolidity (on Ethereum.org) @@ -432,3 +434,13 @@ func (e *PublicAPI) Resend(_ context.Context, e.logger.Debug("eth_resend", "args", args) return e.backend.Resend(args, gasPrice, gasLimit) } + +// CreateAccessList returns the list of addresses and storage keys used by the transaction (except for the +// sender account and precompiles), plus the estimated gas if the access list were added to the transaction. +func (e *PublicAPI) CreateAccessList(args evmtypes.TransactionArgs, blockNrOrHash rpctypes.BlockNumberOrHash) (*rpctypes.AccessListResult, error) { + res, err := e.backend.CreateAccessList(args, blockNrOrHash) + if err != nil { + return nil, err + } + return res, nil +} diff --git a/rpc/types/types.go b/rpc/types/types.go index 905124b7c7..1a54bae152 100644 --- a/rpc/types/types.go +++ b/rpc/types/types.go @@ -95,6 +95,13 @@ type OneFeeHistory struct { GasUsedRatio float64 // the ratio of gas used to the gas limit for each block } +// AccessListResult represents the access list and gas used for a transaction +type AccessListResult struct { + AccessList *ethtypes.AccessList `json:"accessList"` + GasUsed *hexutil.Uint64 `json:"gasUsed"` + Error string `json:"error"` +} + // Embedded TraceConfig type to store raw JSON data of config in custom field type TraceConfig struct { evmtypes.TraceConfig diff --git a/tests/jsonrpc/scripts/run-compat-test.sh b/tests/jsonrpc/scripts/run-compat-test.sh index 89e4bcf8fa..fe11ee3344 100755 --- a/tests/jsonrpc/scripts/run-compat-test.sh +++ b/tests/jsonrpc/scripts/run-compat-test.sh @@ -46,4 +46,4 @@ echo "🚀 Running JSON-RPC compatibility tests..." cd "$JSONRPC_DIR" && docker compose up --build --abort-on-container-exit -echo "✅ JSON-RPC compatibility test completed!" \ No newline at end of file +echo "✅ JSON-RPC compatibility test completed!" diff --git a/tests/jsonrpc/simulator/namespaces/eth.go b/tests/jsonrpc/simulator/namespaces/eth.go index f1922bc4ce..2d711eaf18 100644 --- a/tests/jsonrpc/simulator/namespaces/eth.go +++ b/tests/jsonrpc/simulator/namespaces/eth.go @@ -1874,6 +1874,7 @@ func EthSign(rCtx *types.RPCContext) (*types.RpcResult, error) { func EthCreateAccessList(rCtx *types.RPCContext) (*types.RpcResult, error) { var result interface{} callData := map[string]interface{}{ + "from": rCtx.Evmd.Acc.Address.Hex(), "to": rCtx.Evmd.Acc.Address.Hex(), "data": "0x", } diff --git a/tests/jsonrpc/simulator/runner/testcases.go b/tests/jsonrpc/simulator/runner/testcases.go index f444fd427f..db769ae78f 100644 --- a/tests/jsonrpc/simulator/runner/testcases.go +++ b/tests/jsonrpc/simulator/runner/testcases.go @@ -68,6 +68,7 @@ func GetTestCases() []types.TestCase { {Name: ns.MethodNameEthGetPendingTransactions, Handler: func(rCtx *types.RPCContext) (*types.RpcResult, error) { return utils.Legacy(rCtx, ns.MethodNameEthGetPendingTransactions, "eth", "Use eth_newPendingTransactionFilter + eth_getFilterChanges instead") }}, + {Name: ns.MethodNameEthCreateAccessList, Handler: ns.EthCreateAccessList}, {Name: ns.MethodNameEthPendingTransactions, Handler: ns.EthPendingTransactions, Description: "Go-ethereum compatible pending transactions method"}, // Execute subcategory {Name: ns.MethodNameEthCall, Handler: ns.EthCall}, @@ -88,7 +89,6 @@ func GetTestCases() []types.TestCase { {Name: ns.MethodNameEthFeeHistory, Handler: ns.EthFeeHistory}, {Name: ns.MethodNameEthGetProof, Handler: ns.EthGetProof}, {Name: ns.MethodNameEthProtocolVersion, Handler: nil, SkipReason: "Protocol version deprecated"}, - {Name: ns.MethodNameEthCreateAccessList, Handler: nil, SkipReason: "Access list creation not implemented"}, // Standard methods that should be implemented {Name: ns.MethodNameEthSendTransaction, Handler: ns.EthSendTransaction}, {Name: ns.MethodNameEthSign, Handler: ns.EthSign}, diff --git a/x/vm/types/tracer.go b/x/vm/types/tracer.go index 902d679f4f..426835b87d 100644 --- a/x/vm/types/tracer.go +++ b/x/vm/types/tracer.go @@ -28,8 +28,10 @@ func NewTracer(tracer string, msg core.Message, cfg *params.ChainConfig, height switch tracer { case TracerAccessList: - blockAddrs := map[common.Address]struct{}{ - *msg.To: {}, msg.From: {}, + blockAddrs := make(map[common.Address]struct{}) + blockAddrs[msg.From] = struct{}{} + if msg.To != nil { + blockAddrs[*msg.To] = struct{}{} } precompiles := vm.ActivePrecompiles(cfg.Rules(big.NewInt(height), cfg.MergeNetsplitBlock != nil, timestamp)) for _, addr := range precompiles { @@ -43,7 +45,7 @@ func NewTracer(tracer string, msg core.Message, cfg *params.ChainConfig, height case TracerStruct: return logger.NewStructLogger(logCfg).Hooks() default: - return nil + return NewNoOpTracer() } } From 03083a8ba62308f04eff7827569c5a5a54f36ce3 Mon Sep 17 00:00:00 2001 From: Abdul Malek Date: Thu, 21 Aug 2025 13:14:59 -0400 Subject: [PATCH 21/61] fix: duplicate case switch to avoid empty execution block (#492) * duplicate switch * add changelog --- CHANGELOG.md | 1 + precompiles/erc20/msgsrv.go | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6cec8f6f9..4e3ad482b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### BUG FIXES - [\#471](https://github.com/cosmos/evm/pull/471) Notify new block for mempool in time. +- [\#492](https://github.com/cosmos/evm/pull/492) Duplicate case switch to avoid empty execution block ### IMPROVEMENTS diff --git a/precompiles/erc20/msgsrv.go b/precompiles/erc20/msgsrv.go index 611e8e6f6f..00ba922348 100644 --- a/precompiles/erc20/msgsrv.go +++ b/precompiles/erc20/msgsrv.go @@ -26,19 +26,28 @@ func NewMsgServerImpl(keeper cmn.BankKeeper) *MsgServer { func (m MsgServer) Send(goCtx context.Context, msg *banktypes.MsgSend) error { switch keeper := m.BankKeeper.(type) { // have cases for both pointer and non-pointer to cover how different apps could be storing the keeper - case *bankkeeper.BaseKeeper: case bankkeeper.BaseKeeper: msgSrv := bankkeeper.NewMsgServerImpl(keeper) if _, err := msgSrv.Send(goCtx, msg); err != nil { // This should return an error to avoid the contract from being executed and an event being emitted return ConvertErrToERC20Error(err) } - case *precisebankkeeper.Keeper: + case *bankkeeper.BaseKeeper: + msgSrv := bankkeeper.NewMsgServerImpl(keeper) + if _, err := msgSrv.Send(goCtx, msg); err != nil { + // This should return an error to avoid the contract from being executed and an event being emitted + return ConvertErrToERC20Error(err) + } case precisebankkeeper.Keeper: if _, err := keeper.Send(goCtx, msg); err != nil { // This should return an error to avoid the contract from being executed and an event being emitted return ConvertErrToERC20Error(err) } + case *precisebankkeeper.Keeper: + if _, err := keeper.Send(goCtx, msg); err != nil { + // This should return an error to avoid the contract from being executed and an event being emitted + return ConvertErrToERC20Error(err) + } default: return sdkerrors.ErrInvalidRequest.Wrapf("invalid keeper type: %T", m.BankKeeper) } From 48e3c833cc2f3df0759cbb512a1d29783cc6a124 Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Fri, 22 Aug 2025 13:35:52 -0700 Subject: [PATCH 22/61] test: v0.4.1 -> main upgrade test (#498) * wip upgrade test * upgrade test complete * make script * fix the order * remove that * fixes * fetch tags --- .github/workflows/system-test.yml | 3 + Makefile | 10 ++- evmd/upgrades.go | 39 +++++++++++- tests/systemtests/upgrade_test.go | 102 ++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 tests/systemtests/upgrade_test.go diff --git a/.github/workflows/system-test.yml b/.github/workflows/system-test.yml index 107b279741..1704bac9b6 100644 --- a/.github/workflows/system-test.yml +++ b/.github/workflows/system-test.yml @@ -29,6 +29,9 @@ jobs: with: version: stable - uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true - uses: technote-space/get-diff-action@v6.1.2 with: PATTERNS: | diff --git a/Makefile b/Makefile index cefd9633b2..f4c3b58998 100644 --- a/Makefile +++ b/Makefile @@ -378,12 +378,18 @@ test-rpc-compat-stop: .PHONY: localnet-start localnet-stop localnet-build-env localnet-build-nodes test-rpc-compat test-rpc-compat-stop -test-system: build - ulimit -n 1300 +test-system: build-v04 build mkdir -p ./tests/systemtests/binaries/ cp $(BUILDDIR)/evmd ./tests/systemtests/binaries/ $(MAKE) -C tests/systemtests test +build-v04: + mkdir -p ./tests/systemtests/binaries/v0.4 + git checkout v0.4.1 + make build + cp $(BUILDDIR)/evmd ./tests/systemtests/binaries/v0.4 + git checkout - + mocks: @echo "--> generating mocks" @go get github.com/vektra/mockery/v2 diff --git a/evmd/upgrades.go b/evmd/upgrades.go index d51f29c441..2413912c1e 100644 --- a/evmd/upgrades.go +++ b/evmd/upgrades.go @@ -1,5 +1,42 @@ package evmd +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + storetypes "cosmossdk.io/store/types" + upgradetypes "cosmossdk.io/x/upgrade/types" +) + +// UpgradeName defines the on-chain upgrade name for the sample EVMD upgrade +// from v0.4.0 to v0.5.0. +// +// NOTE: This upgrade defines a reference implementation of what an upgrade +// could look like when an application is migrating from EVMD version +// v0.4.0 to v0.5.x +const UpgradeName = "v0.4.0-to-v0.5.0" + func (app EVMD) RegisterUpgradeHandlers() { - // No upgrades registered yet + app.UpgradeKeeper.SetUpgradeHandler( + UpgradeName, + func(ctx context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + sdk.UnwrapSDKContext(ctx).Logger().Debug("this is a debug level message to test that verbose logging mode has properly been enabled during a chain upgrade") + return app.ModuleManager.RunMigrations(ctx, app.Configurator(), fromVM) + }, + ) + + upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() + if err != nil { + panic(err) + } + + if upgradeInfo.Name == UpgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + storeUpgrades := storetypes.StoreUpgrades{ + Added: []string{}, + } + // configure store loader that checks if version == upgradeHeight and applies store upgrades + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + } } diff --git a/tests/systemtests/upgrade_test.go b/tests/systemtests/upgrade_test.go new file mode 100644 index 0000000000..9ae700e885 --- /dev/null +++ b/tests/systemtests/upgrade_test.go @@ -0,0 +1,102 @@ +//go:build system_test + +package systemtests + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + + systest "cosmossdk.io/systemtests" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" +) + +const ( + upgradeHeight int64 = 22 + upgradeName = "v0.4.0-to-v0.5.0" // must match UpgradeName in evmd/upgrades.go +) + +func TestChainUpgrade(t *testing.T) { + // Scenario: + // start a legacy chain with some state + // when a chain upgrade proposal is executed + // then the chain upgrades successfully + systest.Sut.StopChain() + + currentBranchBinary := systest.Sut.ExecBinary() + currentInitializer := systest.Sut.TestnetInitializer() + + legacyBinary := systest.WorkDir + "/binaries/v0.4/evmd" + systest.Sut.SetExecBinary(legacyBinary) + systest.Sut.SetTestnetInitializer(systest.InitializerWithBinary(legacyBinary, systest.Sut)) + systest.Sut.SetupChain() + + votingPeriod := 5 * time.Second // enough time to vote + systest.Sut.ModifyGenesisJSON(t, systest.SetGovVotingPeriod(t, votingPeriod)) + + systest.Sut.StartChain(t, fmt.Sprintf("--halt-height=%d", upgradeHeight+1), "--chain-id=local-4221", "--minimum-gas-prices=0.00atest") + + cli := systest.NewCLIWrapper(t, systest.Sut, systest.Verbose) + govAddr := sdk.AccAddress(address.Module("gov")).String() + // submit upgrade proposal + proposal := fmt.Sprintf(` +{ + "messages": [ + { + "@type": "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade", + "authority": %q, + "plan": { + "name": %q, + "height": "%d" + } + } + ], + "metadata": "ipfs://CID", + "deposit": "100000000stake", + "title": "my upgrade", + "summary": "testing" +}`, govAddr, upgradeName, upgradeHeight) + rsp := cli.SubmitGovProposal(proposal, "--fees=10000000000000000000atest", "--from=node0") + systest.RequireTxSuccess(t, rsp) + raw := cli.CustomQuery("q", "gov", "proposals", "--depositor", cli.GetKeyAddr("node0")) + proposals := gjson.Get(raw, "proposals.#.id").Array() + require.NotEmpty(t, proposals, raw) + proposalID := proposals[len(proposals)-1].String() + + for i := range systest.Sut.NodesCount() { + go func(i int) { // do parallel + systest.Sut.Logf("Voting: validator %d\n", i) + rsp := cli.Run("tx", "gov", "vote", proposalID, "yes", "--fees=10000000000000000000atest", "--from", cli.GetKeyAddr(fmt.Sprintf("node%d", i))) + systest.RequireTxSuccess(t, rsp) + }(i) + } + + systest.Sut.AwaitBlockHeight(t, upgradeHeight-1, 60*time.Second) + t.Logf("current_height: %d\n", systest.Sut.CurrentHeight()) + raw = cli.CustomQuery("q", "gov", "proposal", proposalID) + proposalStatus := gjson.Get(raw, "proposal.status").String() + require.Equal(t, "PROPOSAL_STATUS_PASSED", proposalStatus, raw) + + t.Log("waiting for upgrade info") + systest.Sut.AwaitUpgradeInfo(t) + systest.Sut.StopChain() + + t.Log("Upgrade height was reached. Upgrading chain") + systest.Sut.SetExecBinary(currentBranchBinary) + systest.Sut.SetTestnetInitializer(currentInitializer) + systest.Sut.StartChain(t, "--chain-id=local-4221") + + require.Equal(t, upgradeHeight+1, systest.Sut.CurrentHeight()) + + // smoke test to make sure the chain still functions. + cli = systest.NewCLIWrapper(t, systest.Sut, systest.Verbose) + to := cli.GetKeyAddr("node1") + from := cli.GetKeyAddr("node0") + got := cli.Run("tx", "bank", "send", from, to, "1atest", "--from=node0", "--fees=10000000000000000000atest", "--chain-id=local-4221") + systest.RequireTxSuccess(t, got) +} From e01cc5077dc05796362af724fe0c9281c478f94a Mon Sep 17 00:00:00 2001 From: Vlad J Date: Fri, 22 Aug 2025 16:37:40 -0400 Subject: [PATCH 23/61] (chore):Simplify Mempool Config (#496) * refactor mempool initialization to accept configs instead of objects * clean * add changelog --- CHANGELOG.md | 1 + mempool/mempool.go | 66 ++++++++++++++++++++++++---------------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e3ad482b8..89951c5f21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - [\#467](https://github.com/cosmos/evm/pull/467) Replace GlobalEVMMempool by passing to JSONRPC on initiate. - [\#352](https://github.com/cosmos/evm/pull/352) Remove the creation of a Geth EVM instance, stateDB during the AnteHandler balance check. +- [\#496](https://github.com/cosmos/evm/pull/496) Simplify mempool instantiation by using configs instead of objects. ### FEATURES diff --git a/mempool/mempool.go b/mempool/mempool.go index 887b2e66fc..409292fbad 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -67,11 +67,11 @@ type ( // It allows customization of the underlying mempools, verification functions, // and broadcasting functions used by the sdkmempool. type EVMMempoolConfig struct { - TxPool *txpool.TxPool - CosmosPool sdkmempool.ExtMempool - AnteHandler sdk.AnteHandler - BroadCastTxFn func(txs []*ethtypes.Transaction) error - BlockGasLimit uint64 // Block gas limit from consensus parameters + LegacyPoolConfig *legacypool.Config + CosmosPoolConfig *sdkmempool.PriorityNonceMempoolConfig[math.Int] + AnteHandler sdk.AnteHandler + BroadCastTxFn func(txs []*ethtypes.Transaction) error + BlockGasLimit uint64 // Block gas limit from consensus parameters } // NewExperimentalEVMMempool creates a new unified mempool for EVM and Cosmos transactions. @@ -106,29 +106,30 @@ func NewExperimentalEVMMempool(getCtxCallback func(height int64, prove bool) (sd config.BlockGasLimit = 100_000_000 } - // Default txPool - txPool = config.TxPool - if txPool == nil { - legacyPool := legacypool.New(legacypool.DefaultConfig, blockchain) + // Create txPool from configuration + legacyConfig := legacypool.DefaultConfig + if config.LegacyPoolConfig != nil { + legacyConfig = *config.LegacyPoolConfig + } - // Set up broadcast function using clientCtx - if config.BroadCastTxFn != nil { - legacyPool.BroadcastTxFn = config.BroadCastTxFn - } else { - // Create default broadcast function using clientCtx. - // The EVM mempool will broadcast transactions when it promotes them - // from queued into pending, noting their readiness to be executed. - legacyPool.BroadcastTxFn = func(txs []*ethtypes.Transaction) error { - logger.Debug("broadcasting EVM transactions", "tx_count", len(txs)) - return broadcastEVMTransactions(clientCtx, txConfig, txs) - } - } + legacyPool := legacypool.New(legacyConfig, blockchain) - txPoolInit, err := txpool.New(uint64(0), blockchain, []txpool.SubPool{legacyPool}) - if err != nil { - panic(err) + // Set up broadcast function using clientCtx + if config.BroadCastTxFn != nil { + legacyPool.BroadcastTxFn = config.BroadCastTxFn + } else { + // Create default broadcast function using clientCtx. + // The EVM mempool will broadcast transactions when it promotes them + // from queued into pending, noting their readiness to be executed. + legacyPool.BroadcastTxFn = func(txs []*ethtypes.Transaction) error { + logger.Debug("broadcasting EVM transactions", "tx_count", len(txs)) + return broadcastEVMTransactions(clientCtx, txConfig, txs) } - txPool = txPoolInit + } + + txPool, err := txpool.New(uint64(0), blockchain, []txpool.SubPool{legacyPool}) + if err != nil { + panic(err) } if len(txPool.Subpools) != 1 { @@ -138,11 +139,12 @@ func NewExperimentalEVMMempool(getCtxCallback func(height int64, prove bool) (sd panic("tx pool should contain only legacypool") } - // Default Cosmos Mempool - cosmosPool = config.CosmosPool - if cosmosPool == nil { - priorityConfig := sdkmempool.PriorityNonceMempoolConfig[math.Int]{} - priorityConfig.TxPriority = sdkmempool.TxPriority[math.Int]{ + // Create Cosmos Mempool from configuration + cosmosPoolConfig := config.CosmosPoolConfig + if cosmosPoolConfig == nil { + // Default configuration + defaultConfig := sdkmempool.PriorityNonceMempoolConfig[math.Int]{} + defaultConfig.TxPriority = sdkmempool.TxPriority[math.Int]{ GetTxPriority: func(goCtx context.Context, tx sdk.Tx) math.Int { cosmosTxFee, ok := tx.(sdk.FeeTx) if !ok { @@ -162,9 +164,11 @@ func NewExperimentalEVMMempool(getCtxCallback func(height int64, prove bool) (sd }, MinValue: math.ZeroInt(), } - cosmosPool = sdkmempool.NewPriorityMempool(priorityConfig) + cosmosPoolConfig = &defaultConfig } + cosmosPool = sdkmempool.NewPriorityMempool(*cosmosPoolConfig) + evmMempool := &ExperimentalEVMMempool{ vmKeeper: vmKeeper, txPool: txPool, From 2d3df2ba510c978d785f2151132e9ed70e1605ec Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Fri, 22 Aug 2025 14:12:27 -0700 Subject: [PATCH 24/61] ci: workflow fails when feat, fix, or refactor PRs do not have changelog entry (#499) * attempt fix * test * read granularity * remove all conditions * default af * some more * try this * making a change * ok this should make it pass * and if i change it back it should fail * remove all go code cahnges to see if wf passes * re adding go code changes should trigger it * only run on specific types of PRs * an update * revert that * when its edited too * revert go code change --- .github/workflows/changelog.yml | 19 ---------- .github/workflows/check-changelog.yml | 53 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 19 deletions(-) delete mode 100644 .github/workflows/changelog.yml create mode 100644 .github/workflows/check-changelog.yml diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml deleted file mode 100644 index 6534722004..0000000000 --- a/.github/workflows/changelog.yml +++ /dev/null @@ -1,19 +0,0 @@ -# Checks if a changelog is missing in the PR diff -name: Changelog Reminder -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths: ["**/*.go"] -permissions: - pull-requests: write -jobs: - remind: - name: Changelog Reminder - runs-on: depot-ubuntu-22.04-4 - # Skip draft PRs and PRs starting with: revert, test, chore, ci, docs, style, build, refactor - if: "!github.event.pull_request.draft && !contains(github.event.pull_request.title, 'revert') && !contains(github.event.pull_request.title, 'test') && !contains(github.event.pull_request.title, 'chore') && !contains(github.event.pull_request.title, 'ci') && !contains(github.event.pull_request.title, 'docs') && !contains(github.event.pull_request.title, 'style') && !contains(github.event.pull_request.title, 'build') && !contains(github.event.pull_request.title, 'refactor')" - steps: - - uses: actions/checkout@v4 - - uses: mskelton/changelog-reminder-action@v3 - with: - message: "@${{ github.actor }} your pull request is missing a changelog!" diff --git a/.github/workflows/check-changelog.yml b/.github/workflows/check-changelog.yml new file mode 100644 index 0000000000..27ee6709f0 --- /dev/null +++ b/.github/workflows/check-changelog.yml @@ -0,0 +1,53 @@ +on: + pull_request: + types: [ opened, synchronize, reopened, ready_for_review, edited ] + paths: [ "**/*.go" ] +name: Changelog Reminder +jobs: + remind: + name: Changelog Reminder + runs-on: ubuntu-latest + if: ${{ !github.event.pull_request.draft }} + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check PR title for semantic commit type + run: | + # Get the PR title + PR_TITLE="${{ github.event.pull_request.title }}" + echo "PR Title: $PR_TITLE" + + # Check if PR title starts with feat, refactor, or fix + if echo "$PR_TITLE" | grep -qE "^(feat|refactor|fix)(\(.+\))?!?:"; then + echo "✅ PR title has relevant semantic commit type (feat, refactor, or fix)" + echo "has_relevant_pr_title=true" >> $GITHUB_ENV + else + echo "ℹ️ PR title doesn't have relevant semantic commit type. Skipping changelog check." + echo "has_relevant_pr_title=false" >> $GITHUB_ENV + fi + + - name: Check if CHANGELOG.md was modified + if: env.has_relevant_pr_title == 'true' + run: | + # Get the list of changed files in this PR + CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD) + + # Check if CHANGELOG.md (case insensitive) is in the changed files + if echo "$CHANGED_FILES" | grep -qi "changelog\.md"; then + echo "✅ CHANGELOG.md has been modified in this PR" + echo "changelog_modified=true" >> $GITHUB_ENV + else + echo "❌ CHANGELOG.md has not been modified in this PR" + echo "changelog_modified=false" >> $GITHUB_ENV + fi + + - name: Fail if changelog not updated + if: env.has_relevant_pr_title == 'true' && env.changelog_modified == 'false' + run: | + echo "::error::CHANGELOG.md must be updated for PRs with feat, refactor, or fix commits" + exit 1 \ No newline at end of file From 750d77d96212811cb2d19768d0c70ef05a039fa1 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Tue, 26 Aug 2025 02:23:56 +0800 Subject: [PATCH 25/61] chore: cleanup deprecated BalanceChangeEntry (#506) * chore: align balance change reason for tracing for more info, https://github.com/ethereum/go-ethereum/blob/v1.16.2/core/evm.go#L143 * cleanup deprecated BalanceChangeEntry for more info, https://github.com/cosmos/evm/pull/201/files * Revert "chore: align balance change reason for tracing" This reverts commit 07a628cfc5ec4a756b2c9ed5b7985395dddf57d6. --- precompiles/common/precompile.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/precompiles/common/precompile.go b/precompiles/common/precompile.go index a1fb806684..d64453da32 100644 --- a/precompiles/common/precompile.go +++ b/precompiles/common/precompile.go @@ -7,7 +7,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" - "github.com/holiman/uint256" "github.com/cosmos/evm/x/vm/statedb" @@ -35,16 +34,6 @@ const ( Add ) -type BalanceChangeEntry struct { - Account common.Address - Amount *uint256.Int - Op Operation -} - -func NewBalanceChangeEntry(acc common.Address, amt *uint256.Int, op Operation) BalanceChangeEntry { - return BalanceChangeEntry{acc, amt, op} -} - // 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. From bcc17d411fedddd5aca833dc6efafb6286b9ed59 Mon Sep 17 00:00:00 2001 From: zchn Date: Tue, 26 Aug 2025 14:40:46 -0400 Subject: [PATCH 26/61] refactor: replace TestEncodingConfig with production Config (#513) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: replace TestEncodingConfig with production EncodingConfig Replace the usage of sdktestutil.TestEncodingConfig with a proper production-ready EncodingConfig struct. This removes the dependency on test utilities in production code while maintaining full compatibility. Changes: - Define custom EncodingConfig struct with same fields as TestEncodingConfig - Remove import of cosmos-sdk/types/module/testutil - Update MakeConfig return type to use the new production struct This improves code quality by avoiding test dependencies in production code. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * chore: fix golangci-lint errors - Fix import ordering (gci) - Rename EncodingConfig to Config to avoid stuttering (revive) The type name change from EncodingConfig to Config addresses the lint warning about stuttering (encoding.EncodingConfig). Since the struct is only used as a return value from MakeConfig(), this change maintains backward compatibility. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * test: update ledger tests to use encoding.Config Update the ledger test files to use the new encoding.Config type instead of sdktestutil.TestEncodingConfig, following the changes made to the encoding package. Changes: - Update encCfg variable type from TestEncodingConfig to Config - Update NewKeyringAndCtxs parameter type to use Config - Add encoding import to evmosd_suite_test.go - Remove unused sdktestutil import 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * docs: add CHANGELOG entry for encoding config refactor Add CHANGELOG.md entry documenting the replacement of TestEncodingConfig with production EncodingConfig in PR #513. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --------- Co-authored-by: Kevin Kz Co-authored-by: Claude --- CHANGELOG.md | 1 + encoding/config.go | 17 +++++++++++++---- evmd/tests/ledger/evmosd_suite_test.go | 4 ++-- evmd/tests/ledger/ledger_test.go | 3 +-- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89951c5f21..06c8eab1a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### IMPROVEMENTS +- [\#513](https://github.com/cosmos/evm/pull/513) Replace `TestEncodingConfig` with production `EncodingConfig` in encoding package to remove test dependencies from production code. - [\#467](https://github.com/cosmos/evm/pull/467) Replace GlobalEVMMempool by passing to JSONRPC on initiate. - [\#352](https://github.com/cosmos/evm/pull/352) Remove the creation of a Geth EVM instance, stateDB during the AnteHandler balance check. - [\#496](https://github.com/cosmos/evm/pull/496) Simplify mempool instantiation by using configs instead of objects. diff --git a/encoding/config.go b/encoding/config.go index 309645064b..aa0c25629b 100644 --- a/encoding/config.go +++ b/encoding/config.go @@ -11,17 +11,26 @@ import ( "cosmossdk.io/x/tx/signing" + "github.com/cosmos/cosmos-sdk/client" amino "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/address" "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdktestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" "github.com/cosmos/cosmos-sdk/x/auth/tx" ) -// MakeConfig creates a new EncodingConfig and returns it -func MakeConfig(evmChainID uint64) sdktestutil.TestEncodingConfig { +// Config specifies the concrete encoding types to use for a given app. +// This is provided for compatibility between protobuf and amino implementations. +type Config struct { + InterfaceRegistry types.InterfaceRegistry + Codec amino.Codec + TxConfig client.TxConfig + Amino *amino.LegacyAmino +} + +// MakeConfig creates a new Config and returns it +func MakeConfig(evmChainID uint64) Config { cdc := amino.NewLegacyAmino() signingOptions := signing.Options{ AddressCodec: address.Bech32Codec{ @@ -49,7 +58,7 @@ func MakeConfig(evmChainID uint64) sdktestutil.TestEncodingConfig { legacytx.RegressionTestingAminoCodec = cdc eip712.SetEncodingConfig(cdc, interfaceRegistry, evmChainID) - return sdktestutil.TestEncodingConfig{ + return Config{ InterfaceRegistry: interfaceRegistry, Codec: codec, TxConfig: tx.NewTxConfig(codec, tx.DefaultSignModes), diff --git a/evmd/tests/ledger/evmosd_suite_test.go b/evmd/tests/ledger/evmosd_suite_test.go index ad5f7d7f3b..200a8a5daf 100644 --- a/evmd/tests/ledger/evmosd_suite_test.go +++ b/evmd/tests/ledger/evmosd_suite_test.go @@ -26,6 +26,7 @@ import ( clientkeys "github.com/cosmos/evm/client/keys" "github.com/cosmos/evm/crypto/hd" cosmosevmkeyring "github.com/cosmos/evm/crypto/keyring" + "github.com/cosmos/evm/encoding" "github.com/cosmos/evm/evmd" "github.com/cosmos/evm/evmd/tests/ledger/mocks" "github.com/cosmos/evm/testutil/constants" @@ -39,7 +40,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" - sdktestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" ) var s *LedgerTestSuite @@ -115,7 +115,7 @@ func (suite *LedgerTestSuite) SetupEvmosApp() { }) } -func (suite *LedgerTestSuite) NewKeyringAndCtxs(krHome string, input io.Reader, encCfg sdktestutil.TestEncodingConfig) (keyring.Keyring, client.Context, context.Context) { +func (suite *LedgerTestSuite) NewKeyringAndCtxs(krHome string, input io.Reader, encCfg encoding.Config) (keyring.Keyring, client.Context, context.Context) { kr, err := keyring.New( sdk.KeyringServiceName(), keyring.BackendTest, diff --git a/evmd/tests/ledger/ledger_test.go b/evmd/tests/ledger/ledger_test.go index cee58a7930..8de8823b3c 100644 --- a/evmd/tests/ledger/ledger_test.go +++ b/evmd/tests/ledger/ledger_test.go @@ -24,7 +24,6 @@ import ( sdktestutil "github.com/cosmos/cosmos-sdk/testutil" sdktestutilcli "github.com/cosmos/cosmos-sdk/testutil/cli" sdk "github.com/cosmos/cosmos-sdk/types" - sdktestutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/cli" ) @@ -42,7 +41,7 @@ var ( var _ = Describe("Ledger CLI and keyring functionality: ", func() { var ( receiverAccAddr sdk.AccAddress - encCfg sdktestutilmod.TestEncodingConfig + encCfg encoding.Config kr keyring.Keyring mockedIn sdktestutil.BufferReader clientCtx client.Context From 68436ec3b5f441cfed7652618fb5acb7db75f45d Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 27 Aug 2025 23:07:02 +0800 Subject: [PATCH 27/61] fix: allow value with slashes when query token_pairs (#509) * chore: allow value with slashes when query token_pairs * add doc --------- Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + api/cosmos/evm/erc20/v1/query.pulsar.go | 50 +++++++++--------- proto/cosmos/evm/erc20/v1/query.proto | 2 +- x/erc20/types/query.pb.go | 68 ++++++++++++------------- x/erc20/types/query.pb.gw.go | 2 +- 5 files changed, 62 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06c8eab1a3..907d5f0acd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [\#471](https://github.com/cosmos/evm/pull/471) Notify new block for mempool in time. - [\#492](https://github.com/cosmos/evm/pull/492) Duplicate case switch to avoid empty execution block +- [\#509](https://github.com/cosmos/evm/pull/509) Allow value with slashes when query token_pairs. ### IMPROVEMENTS diff --git a/api/cosmos/evm/erc20/v1/query.pulsar.go b/api/cosmos/evm/erc20/v1/query.pulsar.go index 8577148766..766fa21bbe 100644 --- a/api/cosmos/evm/erc20/v1/query.pulsar.go +++ b/api/cosmos/evm/erc20/v1/query.pulsar.go @@ -2961,7 +2961,7 @@ var file_cosmos_evm_erc20_v1_query_proto_rawDesc = []byte{ 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x09, 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x32, 0xb7, 0x03, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x91, 0x01, 0x0a, 0x0a, 0x54, + 0x32, 0xba, 0x03, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x91, 0x01, 0x0a, 0x0a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x12, 0x2b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, @@ -2970,38 +2970,38 @@ var file_cosmos_evm_erc20_v1_query_proto_rawDesc = []byte{ 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, - 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x12, 0x96, + 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x12, 0x99, 0x01, 0x0a, 0x09, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x12, 0x2a, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x12, 0x28, 0x2f, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x12, 0x2b, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2f, - 0x7b, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x7d, 0x12, 0x80, 0x01, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, - 0x6d, 0x73, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, - 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, - 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, - 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xc2, 0x01, 0x0a, 0x17, 0x63, - 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, - 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, - 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, - 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x72, 0x63, 0x32, 0x30, - 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x45, 0xaa, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x45, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x56, 0x31, 0xca, 0x02, - 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, - 0x30, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1f, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, - 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x16, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, - 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x45, 0x72, 0x63, 0x32, 0x30, 0x3a, 0x3a, 0x56, 0x31, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x7b, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x80, 0x01, 0x0a, 0x06, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, + 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, + 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, + 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, + 0x12, 0x1b, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, + 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xc2, 0x01, + 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, + 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, + 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x72, + 0x63, 0x32, 0x30, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x45, 0xaa, 0x02, 0x13, 0x43, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x45, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x56, + 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, + 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1f, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, + 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x16, 0x43, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x45, 0x72, 0x63, 0x32, 0x30, 0x3a, 0x3a, + 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/cosmos/evm/erc20/v1/query.proto b/proto/cosmos/evm/erc20/v1/query.proto index c6ca01d86d..a23a6832cd 100644 --- a/proto/cosmos/evm/erc20/v1/query.proto +++ b/proto/cosmos/evm/erc20/v1/query.proto @@ -20,7 +20,7 @@ service Query { // TokenPair retrieves a registered token pair (mapping) rpc TokenPair(QueryTokenPairRequest) returns (QueryTokenPairResponse) { - option (google.api.http).get = "/cosmos/evm/erc20/v1/token_pairs/{token}"; + option (google.api.http).get = "/cosmos/evm/erc20/v1/token_pairs/{token=**}"; } // Params retrieves the erc20 module params diff --git a/x/erc20/types/query.pb.go b/x/erc20/types/query.pb.go index 56fbb3ef21..ac5fe18e80 100644 --- a/x/erc20/types/query.pb.go +++ b/x/erc20/types/query.pb.go @@ -325,40 +325,40 @@ func init() { func init() { proto.RegisterFile("cosmos/evm/erc20/v1/query.proto", fileDescriptor_f1630a6677a16bf4) } var fileDescriptor_f1630a6677a16bf4 = []byte{ - // 524 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0x41, 0x8b, 0xd3, 0x40, - 0x14, 0xc7, 0x3b, 0xbb, 0x6c, 0xa1, 0xaf, 0x27, 0x67, 0xab, 0x2e, 0x5d, 0xcd, 0xd6, 0x2c, 0xb8, - 0xa1, 0xab, 0x33, 0xdb, 0x7a, 0xd6, 0xc3, 0x1e, 0x54, 0x3c, 0xd5, 0xa2, 0x17, 0x2f, 0x3a, 0x29, - 0x43, 0x0c, 0x9a, 0x4c, 0x36, 0x33, 0x0d, 0x2e, 0x22, 0x88, 0x9f, 0x40, 0x11, 0xfc, 0x0c, 0x9e, - 0xc4, 0x9b, 0x5f, 0x61, 0x8f, 0x05, 0x2f, 0x9e, 0x44, 0x5a, 0xc1, 0xaf, 0x21, 0x99, 0x99, 0xa6, - 0x8d, 0x46, 0x5a, 0x2f, 0x25, 0xf3, 0xf8, 0xbf, 0xff, 0xff, 0xf7, 0xde, 0x0c, 0x85, 0xbd, 0x91, - 0x90, 0x91, 0x90, 0x94, 0x67, 0x11, 0xe5, 0xe9, 0xa8, 0x7f, 0x44, 0xb3, 0x1e, 0x3d, 0x19, 0xf3, - 0xf4, 0x94, 0x24, 0xa9, 0x50, 0x02, 0x6f, 0x1b, 0x01, 0xe1, 0x59, 0x44, 0xb4, 0x80, 0x64, 0xbd, - 0xf6, 0x39, 0x16, 0x85, 0xb1, 0xa0, 0xfa, 0xd7, 0xe8, 0xda, 0x5d, 0x6b, 0xe4, 0x33, 0xc9, 0x8d, - 0x01, 0xcd, 0x7a, 0x3e, 0x57, 0xac, 0x47, 0x13, 0x16, 0x84, 0x31, 0x53, 0xa1, 0x88, 0xad, 0xb6, - 0x32, 0xd4, 0x98, 0x1b, 0xc1, 0x95, 0x2a, 0x41, 0xc0, 0x63, 0x2e, 0x43, 0x69, 0x25, 0xad, 0x40, - 0x04, 0x42, 0x7f, 0xd2, 0xfc, 0xcb, 0x56, 0x2f, 0x05, 0x42, 0x04, 0xcf, 0x39, 0x65, 0x49, 0x48, - 0x59, 0x1c, 0x0b, 0xa5, 0x63, 0x6d, 0x8f, 0xfb, 0x04, 0x2e, 0xdc, 0xcf, 0xc9, 0x1e, 0x88, 0x67, - 0x3c, 0x1e, 0xb0, 0x30, 0x95, 0x43, 0x7e, 0x32, 0xe6, 0x52, 0xe1, 0xdb, 0x00, 0x0b, 0xca, 0x1d, - 0xd4, 0x41, 0x5e, 0xb3, 0x7f, 0x95, 0xd8, 0xd1, 0xf3, 0x91, 0x88, 0xd9, 0x89, 0x1d, 0x89, 0x0c, - 0x58, 0xc0, 0x6d, 0xef, 0x70, 0xa9, 0xd3, 0xfd, 0x84, 0xe0, 0xe2, 0x5f, 0x11, 0x32, 0x11, 0xb1, - 0xe4, 0xf8, 0x1e, 0x34, 0x55, 0x5e, 0x7d, 0x9c, 0xe4, 0xe5, 0x1d, 0xd4, 0xd9, 0xf4, 0x9a, 0x7d, - 0x87, 0x54, 0xec, 0x97, 0x14, 0xdd, 0xc7, 0x8d, 0xb3, 0xef, 0x7b, 0xb5, 0x8f, 0xbf, 0x3e, 0x77, - 0xd1, 0x10, 0x54, 0xe1, 0x89, 0xef, 0x94, 0x78, 0x37, 0x34, 0xef, 0xc1, 0x4a, 0x5e, 0x03, 0x52, - 0x02, 0xbe, 0x0e, 0xe7, 0xcb, 0xbc, 0xf3, 0x8d, 0xb4, 0x60, 0x4b, 0xe7, 0xe9, 0x65, 0x34, 0x86, - 0xe6, 0xe0, 0xfa, 0x7f, 0x6e, 0xb0, 0x98, 0xee, 0x2e, 0xc0, 0x62, 0x3a, 0xbb, 0xc1, 0xff, 0x18, - 0xae, 0x51, 0x0c, 0xe7, 0xb6, 0x00, 0xeb, 0x8c, 0x01, 0x4b, 0x59, 0x34, 0xbf, 0x21, 0xf7, 0x21, - 0x6c, 0x97, 0xaa, 0x36, 0xf6, 0x16, 0xd4, 0x13, 0x5d, 0xb1, 0x91, 0xbb, 0x95, 0x91, 0xa6, 0x69, - 0x39, 0xcf, 0x76, 0xf5, 0xbf, 0x6c, 0xc2, 0x96, 0xf6, 0xc5, 0xef, 0x10, 0xc0, 0xe2, 0xd6, 0xf0, - 0x61, 0xa5, 0x51, 0xf5, 0xf3, 0x69, 0x5f, 0x5b, 0x4f, 0x6c, 0x98, 0x5d, 0xef, 0xcd, 0xd7, 0x9f, - 0xef, 0x37, 0x5c, 0xdc, 0xa1, 0x55, 0xcf, 0x7c, 0xe9, 0x8d, 0xe0, 0x0f, 0x08, 0x1a, 0x85, 0x01, - 0xee, 0xae, 0x91, 0x32, 0x27, 0x3a, 0x5c, 0x4b, 0x6b, 0x81, 0x8e, 0x34, 0x50, 0x17, 0x7b, 0xab, - 0x80, 0xe8, 0x4b, 0x7d, 0x78, 0x85, 0x5f, 0x23, 0xa8, 0x9b, 0xa5, 0xe2, 0x83, 0x7f, 0x27, 0x95, - 0x6e, 0xb0, 0xed, 0xad, 0x16, 0x5a, 0x9e, 0x7d, 0xcd, 0x73, 0x19, 0xef, 0x56, 0xf2, 0x98, 0x9b, - 0x3b, 0xbe, 0x79, 0x36, 0x75, 0xd0, 0x64, 0xea, 0xa0, 0x1f, 0x53, 0x07, 0xbd, 0x9d, 0x39, 0xb5, - 0xc9, 0xcc, 0xa9, 0x7d, 0x9b, 0x39, 0xb5, 0x47, 0xfb, 0x41, 0xa8, 0x9e, 0x8e, 0x7d, 0x32, 0x12, - 0xd1, 0xb2, 0xc1, 0x0b, 0x6b, 0xa1, 0x4e, 0x13, 0x2e, 0xfd, 0xba, 0xfe, 0x4b, 0xb8, 0xf1, 0x3b, - 0x00, 0x00, 0xff, 0xff, 0xdc, 0xca, 0x86, 0x63, 0x01, 0x05, 0x00, 0x00, + // 528 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0x41, 0x6b, 0x13, 0x41, + 0x14, 0xc7, 0x33, 0x2d, 0x2d, 0xe4, 0xe5, 0xe4, 0x34, 0x6a, 0x49, 0x75, 0x1b, 0xb7, 0x60, 0xc3, + 0xc6, 0xce, 0x98, 0xf4, 0x5c, 0x0f, 0x3d, 0xa8, 0x78, 0x8a, 0x41, 0x2f, 0x5e, 0x74, 0x36, 0x0c, + 0xeb, 0xa2, 0xbb, 0xb3, 0xdd, 0x99, 0x2c, 0x16, 0x11, 0xc4, 0x4f, 0xa0, 0x78, 0xf2, 0x1b, 0x78, + 0x12, 0xcf, 0x7e, 0x82, 0x1e, 0x0b, 0x5e, 0x3c, 0x89, 0x24, 0x82, 0x5f, 0x43, 0x76, 0x66, 0xb2, + 0xc9, 0xea, 0x4a, 0xe2, 0x25, 0xec, 0x3c, 0xfe, 0xef, 0xff, 0xff, 0xbd, 0x37, 0x43, 0x60, 0x77, + 0x24, 0x64, 0x24, 0x24, 0xe5, 0x59, 0x44, 0x79, 0x3a, 0xea, 0xdf, 0xa4, 0x59, 0x8f, 0x9e, 0x8c, + 0x79, 0x7a, 0x4a, 0x92, 0x54, 0x28, 0x81, 0xb7, 0x8c, 0x80, 0xf0, 0x2c, 0x22, 0x5a, 0x40, 0xb2, + 0x5e, 0xeb, 0x02, 0x8b, 0xc2, 0x58, 0x50, 0xfd, 0x6b, 0x74, 0x2d, 0xcf, 0x1a, 0xf9, 0x4c, 0x72, + 0x63, 0x40, 0xb3, 0x9e, 0xcf, 0x15, 0xeb, 0xd1, 0x84, 0x05, 0x61, 0xcc, 0x54, 0x28, 0x62, 0xab, + 0xad, 0x0c, 0x35, 0xe6, 0x46, 0x70, 0xad, 0x4a, 0x10, 0xf0, 0x98, 0xcb, 0x50, 0x5a, 0x49, 0x33, + 0x10, 0x81, 0xd0, 0x9f, 0x34, 0xff, 0xb2, 0xd5, 0x2b, 0x81, 0x10, 0xc1, 0x73, 0x4e, 0x59, 0x12, + 0x52, 0x16, 0xc7, 0x42, 0xe9, 0x58, 0xdb, 0xe3, 0x3e, 0x81, 0x4b, 0xf7, 0x73, 0xb2, 0x07, 0xe2, + 0x19, 0x8f, 0x07, 0x2c, 0x4c, 0xe5, 0x90, 0x9f, 0x8c, 0xb9, 0x54, 0xf8, 0x36, 0xc0, 0x9c, 0x72, + 0x1b, 0xb5, 0x51, 0xa7, 0xd1, 0xbf, 0x4e, 0xec, 0xe8, 0xf9, 0x48, 0xc4, 0xec, 0xc4, 0x8e, 0x44, + 0x06, 0x2c, 0xe0, 0xb6, 0x77, 0xb8, 0xd0, 0xe9, 0x7e, 0x42, 0x70, 0xf9, 0xaf, 0x08, 0x99, 0x88, + 0x58, 0x72, 0x7c, 0x0f, 0x1a, 0x2a, 0xaf, 0x3e, 0x4e, 0xf2, 0xf2, 0x36, 0x6a, 0xaf, 0x77, 0x1a, + 0x7d, 0x87, 0x54, 0xec, 0x97, 0x14, 0xdd, 0xc7, 0xf5, 0xb3, 0xef, 0xbb, 0xb5, 0x8f, 0xbf, 0x3e, + 0x7b, 0x68, 0x08, 0xaa, 0xf0, 0xc4, 0x77, 0x4a, 0xbc, 0x6b, 0x9a, 0x77, 0x7f, 0x29, 0xaf, 0x01, + 0x29, 0x01, 0x1f, 0xc0, 0xc5, 0x32, 0xef, 0x6c, 0x23, 0x4d, 0xd8, 0xd0, 0x79, 0x7a, 0x19, 0xf5, + 0xa1, 0x39, 0xb8, 0xfe, 0x9f, 0x1b, 0x2c, 0xa6, 0xbb, 0x0b, 0x30, 0x9f, 0xce, 0x6e, 0xf0, 0x3f, + 0x86, 0xab, 0x17, 0xc3, 0xb9, 0x4d, 0xc0, 0x3a, 0x63, 0xc0, 0x52, 0x16, 0xcd, 0x6e, 0xc8, 0x7d, + 0x08, 0x5b, 0xa5, 0xaa, 0x8d, 0xbd, 0x05, 0x9b, 0x89, 0xae, 0xd8, 0xc8, 0x9d, 0xca, 0x48, 0xd3, + 0xb4, 0x98, 0x67, 0xbb, 0xfa, 0x5f, 0xd6, 0x61, 0x43, 0xfb, 0xe2, 0x77, 0x08, 0x60, 0x7e, 0x6b, + 0xb8, 0x5b, 0x69, 0x54, 0xfd, 0x7c, 0x5a, 0x37, 0x56, 0x13, 0x1b, 0x66, 0xb7, 0xf3, 0xe6, 0xeb, + 0xcf, 0xf7, 0x6b, 0x2e, 0x6e, 0xd3, 0xaa, 0x67, 0xbe, 0xf0, 0x46, 0xf0, 0x07, 0x04, 0xf5, 0xc2, + 0x00, 0x7b, 0x2b, 0xa4, 0xcc, 0x88, 0xba, 0x2b, 0x69, 0x2d, 0xd0, 0xa1, 0x06, 0x3a, 0xc0, 0xdd, + 0x65, 0x40, 0xf4, 0xa5, 0x3e, 0x1c, 0x79, 0xde, 0x2b, 0xfc, 0x1a, 0xc1, 0xa6, 0xd9, 0x2b, 0xde, + 0xff, 0x77, 0x58, 0xe9, 0x12, 0x5b, 0x9d, 0xe5, 0x42, 0x8b, 0xb4, 0xa7, 0x91, 0xae, 0xe2, 0x9d, + 0x4a, 0x24, 0x73, 0x79, 0xc7, 0x47, 0x67, 0x13, 0x07, 0x9d, 0x4f, 0x1c, 0xf4, 0x63, 0xe2, 0xa0, + 0xb7, 0x53, 0xa7, 0x76, 0x3e, 0x75, 0x6a, 0xdf, 0xa6, 0x4e, 0xed, 0xd1, 0x5e, 0x10, 0xaa, 0xa7, + 0x63, 0x9f, 0x8c, 0x44, 0xb4, 0x68, 0xf0, 0xc2, 0x5a, 0xa8, 0xd3, 0x84, 0x4b, 0x7f, 0x53, 0xff, + 0x2b, 0x1c, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xe7, 0x87, 0x8b, 0x04, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/erc20/types/query.pb.gw.go b/x/erc20/types/query.pb.gw.go index 2a3ad976ba..18dafd2247 100644 --- a/x/erc20/types/query.pb.gw.go +++ b/x/erc20/types/query.pb.gw.go @@ -323,7 +323,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie var ( pattern_Query_TokenPairs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "evm", "erc20", "v1", "token_pairs"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_TokenPair_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "evm", "erc20", "v1", "token_pairs", "token"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_TokenPair_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 3, 0, 4, 1, 5, 5}, []string{"cosmos", "evm", "erc20", "v1", "token_pairs", "token"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "evm", "erc20", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) ) From 00328124352d78c910492e9d42a8825d68d3a781 Mon Sep 17 00:00:00 2001 From: Abdul Malek Date: Wed, 27 Aug 2025 11:32:19 -0400 Subject: [PATCH 28/61] fix: allow mempool interrupt while it is still ongoing (#495) * add context cancel * simplify channel cases * add changelog * revert config change * add minimal change set for sigint * rename * offload server shutdown go goroutine * remove goroutine in favor of timeout * use short timeout --- CHANGELOG.md | 5 +++-- evmd/app.go | 7 +++++-- mempool/mempool.go | 14 +++++++++++--- server/json_rpc.go | 5 ++--- server/start.go | 20 ++++++++++---------- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 907d5f0acd..6abdf0aec6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,10 @@ ### BUG FIXES -- [\#471](https://github.com/cosmos/evm/pull/471) Notify new block for mempool in time. +- [\#471](https://github.com/cosmos/evm/pull/471) Notify new block for mempool in time - [\#492](https://github.com/cosmos/evm/pull/492) Duplicate case switch to avoid empty execution block -- [\#509](https://github.com/cosmos/evm/pull/509) Allow value with slashes when query token_pairs. +- [\#509](https://github.com/cosmos/evm/pull/509) Allow value with slashes when query token_pairs +- [\#495](https://github.com/cosmos/evm/pull/495) Allow immediate SIGINT interrupt when mempool is not empty ### IMPROVEMENTS diff --git a/evmd/app.go b/evmd/app.go index 9486d3e1ef..d2f9478552 100644 --- a/evmd/app.go +++ b/evmd/app.go @@ -1146,19 +1146,22 @@ func (app *EVMD) SetClientCtx(clientCtx client.Context) { app.clientCtx = clientCtx } -// Close unsubscribes from the CometBFT event bus (if set) and closes the underlying BaseApp. +// Close unsubscribes from the CometBFT event bus (if set) and closes the mempool and underlying BaseApp. func (app *EVMD) Close() error { var err error if m, ok := app.GetMempool().(*evmmempool.ExperimentalEVMMempool); ok { + app.Logger().Info("Shutting down mempool") err = m.Close() } - err = errors.Join(err, app.BaseApp.Close()) + msg := "Application gracefully shutdown" + err = errors.Join(err, app.BaseApp.Close()) if err == nil { app.Logger().Info(msg) } else { app.Logger().Error(msg, "error", err) } + return err } diff --git a/mempool/mempool.go b/mempool/mempool.go index 409292fbad..e2a574e3ee 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -396,12 +396,20 @@ func (m *ExperimentalEVMMempool) SetEventBus(eventBus *cmttypes.EventBus) { }() } -// Close unsubscribes from the CometBFT event bus. +// Close unsubscribes from the CometBFT event bus and shuts down the mempool. func (m *ExperimentalEVMMempool) Close() error { + var errs []error if m.eventBus != nil { - return m.eventBus.Unsubscribe(context.Background(), SubscriberName, stream.NewBlockHeaderEvents) + if err := m.eventBus.Unsubscribe(context.Background(), SubscriberName, stream.NewBlockHeaderEvents); err != nil { + errs = append(errs, fmt.Errorf("failed to unsubscribe from event bus: %w", err)) + } } - return nil + + if err := m.txPool.Close(); err != nil { + errs = append(errs, fmt.Errorf("failed to close txpool: %w", err)) + } + + return errors.Join(errs...) } // getEVMMessage validates that the transaction contains exactly one message and returns it if it's an EVM message. diff --git a/server/json_rpc.go b/server/json_rpc.go index 5c6acda6bb..802e986e08 100644 --- a/server/json_rpc.go +++ b/server/json_rpc.go @@ -25,7 +25,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" ) -const shutdownTimeout = 5 * time.Second +const shutdownTimeout = 200 * time.Millisecond type AppWithPendingTxStream interface { RegisterPendingTxListener(listener func(common.Hash)) @@ -111,14 +111,13 @@ func StartJSONRPC( case <-ctx.Done(): // The calling process canceled or closed the provided context, so we must // gracefully stop the JSON-RPC server. - logger.Info("stopping JSON-RPC server...", "address", config.JSONRPC.Address) + logger.Info("stopping JSON-RPC server...", "address", config.JSONRPC.Address, "timeout", shutdownTimeout) ctxShutdown, cancel := context.WithTimeout(context.Background(), shutdownTimeout) defer cancel() if err := httpSrv.Shutdown(ctxShutdown); err != nil { logger.Error("failed to shutdown JSON-RPC server", "error", err.Error()) } return nil - case err := <-errCh: if err == http.ErrServerClosed { close(httpSrvDone) diff --git a/server/start.go b/server/start.go index 944508ca62..580d222207 100644 --- a/server/start.go +++ b/server/start.go @@ -132,8 +132,8 @@ which accepts a path for the resulting pprof file. return err } - withTM, _ := cmd.Flags().GetBool(srvflags.WithCometBFT) - if !withTM { + withbft, _ := cmd.Flags().GetBool(srvflags.WithCometBFT) + if !withbft { serverCtx.Logger.Info("starting ABCI without CometBFT") return wrapCPUProfile(serverCtx, func() error { return startStandAlone(serverCtx, clientCtx, opts) @@ -400,7 +400,7 @@ func startInProcess(svrCtx *server.Context, clientCtx client.Context, opts Start genDocProvider := GenDocProvider(cfg) var ( - tmNode *node.Node + bftNode *node.Node gRPCOnly = svrCtx.Viper.GetBool(srvflags.GRPCOnly) ) @@ -412,7 +412,7 @@ func startInProcess(svrCtx *server.Context, clientCtx client.Context, opts Start logger.Info("starting node with ABCI CometBFT in-process") cmtApp := server.NewCometABCIWrapper(app) - tmNode, err = node.NewNode( + bftNode, err = node.NewNode( cfg, pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()), nodeKey, @@ -427,17 +427,17 @@ func startInProcess(svrCtx *server.Context, clientCtx client.Context, opts Start return err } - if err := tmNode.Start(); err != nil { + if err := bftNode.Start(); err != nil { logger.Error("failed start CometBFT server", "error", err.Error()) return err } if m, ok := evmApp.GetMempool().(*evmmempool.ExperimentalEVMMempool); ok { - m.SetEventBus(tmNode.EventBus()) + m.SetEventBus(bftNode.EventBus()) } defer func() { - if tmNode.IsRunning() { - _ = tmNode.Stop() + if bftNode.IsRunning() { + _ = bftNode.Stop() } }() } @@ -445,8 +445,8 @@ func startInProcess(svrCtx *server.Context, clientCtx client.Context, opts Start // Add the tx service to the gRPC router. We only need to register this // service if API or gRPC or JSONRPC is enabled, and avoid doing so in the general // case, because it spawns a new local CometBFT RPC client. - if (config.API.Enable || config.GRPC.Enable || config.JSONRPC.Enable || config.JSONRPC.EnableIndexer) && tmNode != nil { - clientCtx = clientCtx.WithClient(local.New(tmNode)) + if (config.API.Enable || config.GRPC.Enable || config.JSONRPC.Enable || config.JSONRPC.EnableIndexer) && bftNode != nil { + clientCtx = clientCtx.WithClient(local.New(bftNode)) app.RegisterTxService(clientCtx) app.RegisterTendermintService(clientCtx) From 83ae83da11ce918b92ded60d4ffe3a80a03fbbfa Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:25:29 -0700 Subject: [PATCH 29/61] docs: update contrib guide (#539) * update contrib guide * fix number --- CONTRIBUTING.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index edd96b8b7a..c8827944f8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,10 @@ We appreciate community contributions! To ensure a smooth process, please follow - All commits must be [signed](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits). - Unsigned commits will be rejected. -3. **Documentation Contributions** +3. **Conventional Commit PR Titles** + - PR titles should use the [conventional commit](https://www.conventionalcommits.org/en/v1.0.0/#summary) format. + +4. **Documentation Contributions** - We only accept documentation PRs that make **substantial or impactful changes**. - Minor typo or style-only fixes in documentation will not be accepted. From 3e3793173dff802dac1723443e54affb4304f714 Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Wed, 27 Aug 2025 21:30:00 -0700 Subject: [PATCH 30/61] add pr title job (#541) --- .github/workflows/pr_title.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/pr_title.yml diff --git a/.github/workflows/pr_title.yml b/.github/workflows/pr_title.yml new file mode 100644 index 0000000000..f86d7c76bb --- /dev/null +++ b/.github/workflows/pr_title.yml @@ -0,0 +1,15 @@ +name: PR Conventional Commit Validation + +on: + pull_request: + types: [opened, synchronize, reopened, edited] + +jobs: + validate-pr-title: + runs-on: ubuntu-latest + steps: + - name: PR Conventional Commit Validation + uses: ytanikin/pr-conventional-commits@1.4.0 + with: + task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert","style","build"]' + add_label: 'false' \ No newline at end of file From 5ffe3cca639e5bc4039d8a195be8275c66d4324f Mon Sep 17 00:00:00 2001 From: mmsqe Date: Sat, 30 Aug 2025 02:52:41 +0800 Subject: [PATCH 31/61] chore: check if mempool is not nil before accepting nonce gap error tx (#572) --- CHANGELOG.md | 1 + rpc/backend/call_tx.go | 2 +- rpc/backend/sign_tx.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6abdf0aec6..ffc1bd9812 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - [\#492](https://github.com/cosmos/evm/pull/492) Duplicate case switch to avoid empty execution block - [\#509](https://github.com/cosmos/evm/pull/509) Allow value with slashes when query token_pairs - [\#495](https://github.com/cosmos/evm/pull/495) Allow immediate SIGINT interrupt when mempool is not empty +- [\#545](https://github.com/cosmos/evm/pull/545) Check if mempool is not nil before accepting nonce gap error tx. ### IMPROVEMENTS diff --git a/rpc/backend/call_tx.go b/rpc/backend/call_tx.go index 0c54f45c96..e444cc9b26 100644 --- a/rpc/backend/call_tx.go +++ b/rpc/backend/call_tx.go @@ -155,7 +155,7 @@ func (b *Backend) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) { } if err != nil { // Check if this is a nonce gap error that was successfully queued - if strings.Contains(err.Error(), mempool.ErrNonceGap.Error()) { + if b.Mempool != nil && strings.Contains(err.Error(), mempool.ErrNonceGap.Error()) { // Transaction was successfully queued due to nonce gap, return success to client b.Logger.Debug("transaction queued due to nonce gap", "hash", txHash.Hex()) return txHash, nil diff --git a/rpc/backend/sign_tx.go b/rpc/backend/sign_tx.go index af1f603413..859c2c3a82 100644 --- a/rpc/backend/sign_tx.go +++ b/rpc/backend/sign_tx.go @@ -110,7 +110,7 @@ func (b *Backend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, e } if err != nil { // Check if this is a nonce gap error that was successfully queued - if strings.Contains(err.Error(), mempool.ErrNonceGap.Error()) { + if b.Mempool != nil && strings.Contains(err.Error(), mempool.ErrNonceGap.Error()) { // Transaction was successfully queued due to nonce gap, return success to client b.Logger.Debug("transaction queued due to nonce gap", "hash", txHash.Hex()) return txHash, nil From 2fff19e070e8af3e6344be2d234e464abb7fe7ef Mon Sep 17 00:00:00 2001 From: Antonio Pitasi Date: Fri, 29 Aug 2025 20:58:21 +0200 Subject: [PATCH 32/61] fix(evmd): remove pebble replace directive (#574) --- evmd/go.mod | 3 +-- evmd/go.sum | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/evmd/go.mod b/evmd/go.mod index 0016954617..19fe00f12b 100644 --- a/evmd/go.mod +++ b/evmd/go.mod @@ -74,6 +74,7 @@ require ( github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/cockroachdb/errors v1.12.0 // indirect + github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a // indirect github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect github.com/cockroachdb/pebble v1.1.5 // indirect github.com/cockroachdb/redact v1.1.6 // indirect @@ -275,8 +276,6 @@ require ( replace ( // use cosmos fork of keyring github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 - // Pin this pebble version to avoid breaking compilation of geth - github.com/cockroachdb/pebble => github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 github.com/cosmos/evm => ../ github.com/cosmos/evm/evmd => ./evmd // use Cosmos geth fork diff --git a/evmd/go.sum b/evmd/go.sum index 1651dca61e..5f775b32e6 100644 --- a/evmd/go.sum +++ b/evmd/go.sum @@ -826,10 +826,12 @@ github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaY github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.12.0 h1:d7oCs6vuIMUQRVbi6jWWWEJZahLCfJpnJSVobd1/sUo= github.com/cockroachdb/errors v1.12.0/go.mod h1:SvzfYNNBshAVbZ8wzNc/UPK3w1vf0dKDUP41ucAIf7g= +github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a h1:f52TdbU4D5nozMAhO9TvTJ2ZMCXtN4VIAmfrrZ0JXQ4= +github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 h1:ASDL+UJcILMqgNeV5jiqR4j+sTuvQNHdf2chuKj1M5k= github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506/go.mod h1:Mw7HqKr2kdtu6aYGn3tPmAftiP3QPX63LdK/zcariIo= -github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= -github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= +github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= +github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= github.com/cockroachdb/redact v1.1.6 h1:zXJBwDZ84xJNlHl1rMyCojqyIxv+7YUpQiJLQ7n4314= github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= From af53a0ff6347f70c67e4cb5f69d82ad1f95bae44 Mon Sep 17 00:00:00 2001 From: Vlad J Date: Fri, 29 Aug 2025 15:09:36 -0400 Subject: [PATCH 33/61] =?UTF-8?q?docs(migration):=20boilerplate=20v0.5.0?= =?UTF-8?q?=20migration=20docs=20with=20mempool=20migra=E2=80=A6=20(#540)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(migration): boilerplate v0.5.0 migration docs with mempool migration * shorten line * Update docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md --------- Co-authored-by: Alex | Interchain Labs --- .../migrations/v0.4.0_to_v0.5.0_UNRELEASED.md | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md diff --git a/docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md b/docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md new file mode 100644 index 0000000000..57965a9bdd --- /dev/null +++ b/docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md @@ -0,0 +1,94 @@ +# Cosmos EVM v0.4.0 → v0.5.0 Migration (UNRELEASED) + +## 0) Prep + +- Create a branch: `git switch -c upgrade/evm-v0.5`. +- Ensure a clean build + tests green pre-upgrade. +- Snapshot your current params/genesis for comparison later. + +--- + +## 1) Dependency bumps (go.mod) + +- Bump `github.com/cosmos/evm` to v0.5.0 and run: + +```bash +go mod tidy +``` + +--- + +## 2) App wiring in `app.go` + +### Mempool + +#### Minimal setups: nothing to change + +If you use the default mempool wiring (no custom pools), your existing code continues to work. If `BlockGasLimit` is 0, it defaults to `100_000_000`. If `BroadCastTxFn` is not set, it's also set to a default value. + +```go +mempoolConfig := &evmmempool.EVMMempoolConfig{ + AnteHandler: app.GetAnteHandler(), + BlockGasLimit: 100_000_000, // or 0 to use default +} +evmMempool := evmmempool.NewExperimentalEVMMempool( + app.CreateQueryContext, logger, app.EVMKeeper, app.FeeMarketKeeper, app.txConfig, app.clientCtx, mempoolConfig +) +``` + +#### Advanced setups: migrate your customizations + +PR [#496](https://github.com/cosmos/evm/pull/496) replaced pre-built pools with configs in `EVMMempoolConfig`: + +- Replace pools with configs + - Removed: `TxPool *txpool.TxPool`, `CosmosPool sdkmempool.ExtMempool` + - Added: `LegacyPoolConfig *legacypool.Config`, `CosmosPoolConfig *sdkmempool.PriorityNonceMempoolConfig[math.Int]` + +If you built custom pools yourself: + +```diff + mempoolConfig := &evmmempool.EVMMempoolConfig{ +- TxPool: customTxPool, +- CosmosPool: customCosmosPool, ++ LegacyPoolConfig: &legacyCfg, // or nil for defaults ++ CosmosPoolConfig: &cosmosCfg, // or nil for defaults + AnteHandler: app.GetAnteHandler(), + BroadCastTxFn: myBroadcast, // optional + } +``` + +Example custom configs: + +```go +// EVM legacy txpool tuning +legacyCfg := legacypool.DefaultConfig +legacyCfg.PriceLimit = 2 +mempoolConfig.LegacyPoolConfig = &legacyCfg + +// Cosmos priority mempool tuning +cosmosCfg := sdkmempool.PriorityNonceMempoolConfig[math.Int]{} +cosmosCfg.TxPriority = sdkmempool.TxPriority[math.Int]{ + GetTxPriority: func(goCtx context.Context, tx sdk.Tx) math.Int { + // Custom priority function + }, + Compare: func(a, b math.Int) int { return a.BigInt().Cmp(b.BigInt()) }, + MinValue: math.ZeroInt(), +} +mempoolConfig.CosmosPoolConfig = &cosmosCfg + +// Custom EVM broadcast (optional) +mempoolConfig.BroadCastTxFn = func(txs []*ethtypes.Transaction) error { return nil } +``` + +--- + +## 3) Build & quick tests + +```bash +go build ./... +``` + +Smoke test on a single node: +- Send a few EVM txs; confirm promotion/broadcast (or your `BroadCastTxFn`). +- Send Cosmos txs; confirm ordering reflects your `CosmosPoolConfig` (if customized). + From 2a0eb3aa8d32329624bc8c3850eebc0e2e690428 Mon Sep 17 00:00:00 2001 From: Vlad J Date: Fri, 29 Aug 2025 16:18:45 -0400 Subject: [PATCH 34/61] perf: optimize gas estimation (#538) * Fix error semantics * changelog * Add benchmark (#542) Co-authored-by: Alex | Interchain Labs --------- Co-authored-by: Alex | Interchain Labs Co-authored-by: Eric Warehime --- CHANGELOG.md | 1 + api/cosmos/evm/vm/v1/tx.pulsar.go | 197 ++++++++++++++++++---------- evmd/tests/integration/x_vm_test.go | 78 ++++++++++- proto/cosmos/evm/vm/v1/tx.proto | 2 + x/vm/keeper/grpc_query.go | 60 +++++++-- x/vm/keeper/state_transition.go | 17 +-- x/vm/types/tx.pb.go | 118 ++++++++++------- 7 files changed, 338 insertions(+), 135 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffc1bd9812..8def679f0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ### IMPROVEMENTS +- [\#538](https://github.com/cosmos/evm/pull/538) Optimize `eth_estimateGas` gRPC path: short-circuit plain transfers, add optimistic gas bound based on `MaxUsedGas`. - [\#513](https://github.com/cosmos/evm/pull/513) Replace `TestEncodingConfig` with production `EncodingConfig` in encoding package to remove test dependencies from production code. - [\#467](https://github.com/cosmos/evm/pull/467) Replace GlobalEVMMempool by passing to JSONRPC on initiate. - [\#352](https://github.com/cosmos/evm/pull/352) Remove the creation of a Geth EVM instance, stateDB during the AnteHandler balance check. diff --git a/api/cosmos/evm/vm/v1/tx.pulsar.go b/api/cosmos/evm/vm/v1/tx.pulsar.go index 89f899c3c6..01c31e38db 100644 --- a/api/cosmos/evm/vm/v1/tx.pulsar.go +++ b/api/cosmos/evm/vm/v1/tx.pulsar.go @@ -913,12 +913,13 @@ func (x *_MsgEthereumTxResponse_2_list) IsValid() bool { } var ( - md_MsgEthereumTxResponse protoreflect.MessageDescriptor - fd_MsgEthereumTxResponse_hash protoreflect.FieldDescriptor - fd_MsgEthereumTxResponse_logs protoreflect.FieldDescriptor - fd_MsgEthereumTxResponse_ret protoreflect.FieldDescriptor - fd_MsgEthereumTxResponse_vm_error protoreflect.FieldDescriptor - fd_MsgEthereumTxResponse_gas_used protoreflect.FieldDescriptor + md_MsgEthereumTxResponse protoreflect.MessageDescriptor + fd_MsgEthereumTxResponse_hash protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_logs protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_ret protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_vm_error protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_gas_used protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_max_used_gas protoreflect.FieldDescriptor ) func init() { @@ -929,6 +930,7 @@ func init() { fd_MsgEthereumTxResponse_ret = md_MsgEthereumTxResponse.Fields().ByName("ret") fd_MsgEthereumTxResponse_vm_error = md_MsgEthereumTxResponse.Fields().ByName("vm_error") fd_MsgEthereumTxResponse_gas_used = md_MsgEthereumTxResponse.Fields().ByName("gas_used") + fd_MsgEthereumTxResponse_max_used_gas = md_MsgEthereumTxResponse.Fields().ByName("max_used_gas") } var _ protoreflect.Message = (*fastReflection_MsgEthereumTxResponse)(nil) @@ -1026,6 +1028,12 @@ func (x *fastReflection_MsgEthereumTxResponse) Range(f func(protoreflect.FieldDe return } } + if x.MaxUsedGas != uint64(0) { + value := protoreflect.ValueOfUint64(x.MaxUsedGas) + if !f(fd_MsgEthereumTxResponse_max_used_gas, value) { + return + } + } } // Has reports whether a field is populated. @@ -1051,6 +1059,8 @@ func (x *fastReflection_MsgEthereumTxResponse) Has(fd protoreflect.FieldDescript return x.VmError != "" case "cosmos.evm.vm.v1.MsgEthereumTxResponse.gas_used": return x.GasUsed != uint64(0) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": + return x.MaxUsedGas != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1077,6 +1087,8 @@ func (x *fastReflection_MsgEthereumTxResponse) Clear(fd protoreflect.FieldDescri x.VmError = "" case "cosmos.evm.vm.v1.MsgEthereumTxResponse.gas_used": x.GasUsed = uint64(0) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": + x.MaxUsedGas = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1111,6 +1123,9 @@ func (x *fastReflection_MsgEthereumTxResponse) Get(descriptor protoreflect.Field case "cosmos.evm.vm.v1.MsgEthereumTxResponse.gas_used": value := x.GasUsed return protoreflect.ValueOfUint64(value) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": + value := x.MaxUsedGas + return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1143,6 +1158,8 @@ func (x *fastReflection_MsgEthereumTxResponse) Set(fd protoreflect.FieldDescript x.VmError = value.Interface().(string) case "cosmos.evm.vm.v1.MsgEthereumTxResponse.gas_used": x.GasUsed = value.Uint() + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": + x.MaxUsedGas = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1177,6 +1194,8 @@ func (x *fastReflection_MsgEthereumTxResponse) Mutable(fd protoreflect.FieldDesc panic(fmt.Errorf("field vm_error of message cosmos.evm.vm.v1.MsgEthereumTxResponse is not mutable")) case "cosmos.evm.vm.v1.MsgEthereumTxResponse.gas_used": panic(fmt.Errorf("field gas_used of message cosmos.evm.vm.v1.MsgEthereumTxResponse is not mutable")) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": + panic(fmt.Errorf("field max_used_gas of message cosmos.evm.vm.v1.MsgEthereumTxResponse is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1201,6 +1220,8 @@ func (x *fastReflection_MsgEthereumTxResponse) NewField(fd protoreflect.FieldDes return protoreflect.ValueOfString("") case "cosmos.evm.vm.v1.MsgEthereumTxResponse.gas_used": return protoreflect.ValueOfUint64(uint64(0)) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": + return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1291,6 +1312,9 @@ func (x *fastReflection_MsgEthereumTxResponse) ProtoMethods() *protoiface.Method if x.GasUsed != 0 { n += 1 + runtime.Sov(uint64(x.GasUsed)) } + if x.MaxUsedGas != 0 { + n += 1 + runtime.Sov(uint64(x.MaxUsedGas)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -1320,6 +1344,11 @@ func (x *fastReflection_MsgEthereumTxResponse) ProtoMethods() *protoiface.Method i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.MaxUsedGas != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.MaxUsedGas)) + i-- + dAtA[i] = 0x30 + } if x.GasUsed != 0 { i = runtime.EncodeVarint(dAtA, i, uint64(x.GasUsed)) i-- @@ -1562,6 +1591,25 @@ func (x *fastReflection_MsgEthereumTxResponse) ProtoMethods() *protoiface.Method break } } + case 6: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field MaxUsedGas", wireType) + } + x.MaxUsedGas = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.MaxUsedGas |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -3474,6 +3522,8 @@ type MsgEthereumTxResponse struct { VmError string `protobuf:"bytes,4,opt,name=vm_error,json=vmError,proto3" json:"vm_error,omitempty"` // gas_used specifies how much gas was consumed by the transaction GasUsed uint64 `protobuf:"varint,5,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` + // max_used_gas specifies the gas consumed by the transaction, not including refunds + MaxUsedGas uint64 `protobuf:"varint,6,opt,name=max_used_gas,json=maxUsedGas,proto3" json:"max_used_gas,omitempty"` } func (x *MsgEthereumTxResponse) Reset() { @@ -3531,6 +3581,13 @@ func (x *MsgEthereumTxResponse) GetGasUsed() uint64 { return 0 } +func (x *MsgEthereumTxResponse) GetMaxUsedGas() uint64 { + if x != nil { + return x.MaxUsedGas + } + return 0 +} + // MsgUpdateParams defines a Msg for updating the x/vm module parameters. type MsgUpdateParams struct { state protoimpl.MessageState @@ -3706,7 +3763,7 @@ var file_cosmos_evm_vm_v1_tx_proto_rawDesc = []byte{ 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x22, 0x0a, 0x1a, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, - 0xa4, 0x01, 0x0a, 0x15, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, + 0xc6, 0x01, 0x0a, 0x15, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, @@ -3716,69 +3773,71 @@ var file_cosmos_evm_vm_v1_tx_proto_rawDesc = []byte{ 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x6d, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, - 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, 0xba, 0x01, 0x0a, 0x0f, 0x4d, 0x73, 0x67, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x36, 0x0a, 0x09, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, - 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, - 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x09, 0xc8, 0xde, - 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, - 0x32, 0x82, 0xe7, 0xb0, 0x2a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x8a, - 0xe7, 0xb0, 0x2a, 0x1f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x78, - 0x2f, 0x76, 0x6d, 0x2f, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xd6, - 0x01, 0x0a, 0x16, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, - 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x12, 0x36, 0x0a, 0x09, 0x61, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, - 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, - 0x79, 0x12, 0x49, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6c, 0x6c, 0x42, 0x09, 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, - 0x0b, 0x70, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x3a, 0x39, 0x82, 0xe7, - 0xb0, 0x2a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x8a, 0xe7, 0xb0, 0x2a, - 0x26, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x78, 0x2f, 0x76, 0x6d, - 0x2f, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x22, 0x20, 0x0a, 0x1e, 0x4d, 0x73, 0x67, 0x52, 0x65, + 0x12, 0x20, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x55, 0x73, 0x65, 0x64, 0x47, + 0x61, 0x73, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, 0xba, 0x01, 0x0a, 0x0f, 0x4d, 0x73, 0x67, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x36, 0x0a, 0x09, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, + 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x09, + 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x3a, 0x32, 0x82, 0xe7, 0xb0, 0x2a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x8a, 0xe7, 0xb0, 0x2a, 0x1f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, + 0x2f, 0x78, 0x2f, 0x76, 0x6d, 0x2f, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0xd6, 0x01, 0x0a, 0x16, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x12, 0x36, 0x0a, 0x09, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, + 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x12, 0x49, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x42, 0x09, 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, + 0x01, 0x52, 0x0b, 0x70, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x3a, 0x39, + 0x82, 0xe7, 0xb0, 0x2a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x8a, 0xe7, + 0xb0, 0x2a, 0x26, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x78, 0x2f, + 0x76, 0x6d, 0x2f, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, + 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x22, 0x20, 0x0a, 0x1e, 0x4d, 0x73, 0x67, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xdc, 0x02, 0x0a, 0x03, + 0x4d, 0x73, 0x67, 0x12, 0x7d, 0x0a, 0x0a, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, + 0x78, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, + 0x54, 0x78, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, + 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, + 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1f, 0x22, 0x1d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, + 0x2f, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5f, + 0x74, 0x78, 0x12, 0x5c, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x12, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, + 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x29, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, + 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x71, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x12, 0x28, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xdc, 0x02, 0x0a, 0x03, 0x4d, 0x73, - 0x67, 0x12, 0x7d, 0x0a, 0x0a, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x12, - 0x1f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, - 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, - 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x1f, 0x22, 0x1d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, - 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5f, 0x74, 0x78, - 0x12, 0x5c, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x12, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x73, 0x1a, 0x29, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, - 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, - 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x12, 0x28, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, - 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x1a, - 0x30, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, - 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x1a, 0x05, 0x80, 0xe7, 0xb0, 0x2a, 0x01, 0x42, 0xaa, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, - 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, - 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x3b, - 0x76, 0x6d, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x56, 0xaa, 0x02, 0x10, 0x43, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x56, 0x6d, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, - 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, 0x56, 0x31, - 0xe2, 0x02, 0x1c, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, - 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, - 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x56, - 0x6d, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x1a, 0x05, 0x80, 0xe7, 0xb0, 0x2a, 0x01, 0x42, 0xaa, 0x01, 0x0a, 0x14, 0x63, + 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, + 0x2e, 0x76, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, + 0x31, 0x3b, 0x76, 0x6d, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x56, 0xaa, 0x02, 0x10, 0x43, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x56, 0x6d, 0x2e, 0x56, 0x31, 0xca, + 0x02, 0x10, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, + 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, + 0x56, 0x6d, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0xea, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, + 0x3a, 0x56, 0x6d, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/evmd/tests/integration/x_vm_test.go b/evmd/tests/integration/x_vm_test.go index 37c439a17f..c1aec6e9f1 100644 --- a/evmd/tests/integration/x_vm_test.go +++ b/evmd/tests/integration/x_vm_test.go @@ -1,13 +1,87 @@ package integration import ( + "encoding/json" "testing" - "github.com/stretchr/testify/suite" - + "github.com/cosmos/evm/server/config" "github.com/cosmos/evm/tests/integration/x/vm" + "github.com/cosmos/evm/testutil/integration/evm/network" + "github.com/cosmos/evm/testutil/keyring" + feemarkettypes "github.com/cosmos/evm/x/feemarket/types" + "github.com/cosmos/evm/x/vm/types" + "github.com/ethereum/go-ethereum/common" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" ) +func BenchmarkGasEstimation(b *testing.B) { + // Setup benchmark test environment + keys := keyring.New(2) + // Set custom balance based on test params + customGenesis := network.CustomGenesisState{} + feemarketGenesis := feemarkettypes.DefaultGenesisState() + feemarketGenesis.Params.NoBaseFee = true + customGenesis[feemarkettypes.ModuleName] = feemarketGenesis + opts := []network.ConfigOption{ + network.WithPreFundedAccounts(keys.GetAllAccAddrs()...), + network.WithCustomGenesis(customGenesis), + } + nw := network.NewUnitTestNetwork(CreateEvmd, opts...) + // gh := grpc.NewIntegrationHandler(nw) + // tf := factory.New(nw, gh) + + chainConfig := types.DefaultChainConfig(nw.GetEIP155ChainID().Uint64()) + // get the denom and decimals set on chain initialization + // because we'll need to set them again when resetting the chain config + denom := types.GetEVMCoinDenom() + extendedDenom := types.GetEVMCoinExtendedDenom() + displayDenom := types.GetEVMCoinDisplayDenom() + decimals := types.GetEVMCoinDecimals() + + configurator := types.NewEVMConfigurator() + configurator.ResetTestConfig() + err := configurator. + WithChainConfig(chainConfig). + WithEVMCoinInfo(types.EvmCoinInfo{ + Denom: denom, + ExtendedDenom: extendedDenom, + DisplayDenom: displayDenom, + Decimals: decimals, + }). + Configure() + require.NoError(b, err) + + // Use simple transaction args for consistent benchmarking + args := types.TransactionArgs{ + To: &common.Address{}, + } + + marshalArgs, err := json.Marshal(args) + require.NoError(b, err) + + req := types.EthCallRequest{ + Args: marshalArgs, + GasCap: config.DefaultGasCap, + ProposerAddress: nw.GetContext().BlockHeader().ProposerAddress, + } + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + _, err := nw.GetEvmClient().EstimateGas( + nw.GetContext(), + &req, + ) + if err != nil { + b.Fatal(err) + } + } +} + func TestKeeperTestSuite(t *testing.T) { s := vm.NewKeeperTestSuite(CreateEvmd) s.EnableFeemarket = false diff --git a/proto/cosmos/evm/vm/v1/tx.proto b/proto/cosmos/evm/vm/v1/tx.proto index 384c047cc5..3d953e9e0d 100644 --- a/proto/cosmos/evm/vm/v1/tx.proto +++ b/proto/cosmos/evm/vm/v1/tx.proto @@ -71,6 +71,8 @@ message MsgEthereumTxResponse { string vm_error = 4; // gas_used specifies how much gas was consumed by the transaction uint64 gas_used = 5; + // max_used_gas specifies the gas consumed by the transaction, not including refunds + uint64 max_used_gas = 6; } // MsgUpdateParams defines a Msg for updating the x/vm module parameters. diff --git a/x/vm/keeper/grpc_query.go b/x/vm/keeper/grpc_query.go index eb895079ce..9f2413cd87 100644 --- a/x/vm/keeper/grpc_query.go +++ b/x/vm/keeper/grpc_query.go @@ -404,20 +404,32 @@ func (k Keeper) EstimateGasInternal(c context.Context, req *types.EthCallRequest return len(rsp.VmError) > 0, rsp, nil } - // Execute the binary search and hone in on an executable gas limit - hi, err = types.BinSearch(lo, hi, executable) + // Adapted from go-ethereum gas estimator for early short-circuit and optimistic bounds: + // https://github.com/ethereum/go-ethereum/blob/v1.16.2/eth/gasestimator/gasestimator.go + + // If the transaction is a plain value transfer, short circuit estimation and + // directly try 21000. Returning 21000 without any execution is dangerous as + // some tx field combos might bump the price up even for plain transfers (e.g. + // unused access list items). Ever so slightly wasteful, but safer overall. + if len(msg.Data) == 0 && msg.To != nil { + acct := k.GetAccountWithoutBalance(ctx, *msg.To) + if acct == nil || !acct.IsContract() { + failed, _, err := executable(ethparams.TxGas) + if err == nil && !failed { + return &types.EstimateGasResponse{Gas: ethparams.TxGas}, nil + } + } + } + + // We first execute the transaction at the highest allowable gas limit, since if this fails we + // can return error immediately. + failed, result, err := executable(hi) if err != nil { return nil, err } - - // Reject the transaction as invalid if it still fails at the highest allowance - if hi == gasCap { - failed, result, err := executable(hi) - if err != nil { - return nil, err - } - - if failed { + if failed { + // Preserve Cosmos error semantics when the cap is reached + if hi == gasCap { if result != nil && result.VmError != vm.ErrOutOfGas.Error() { if result.VmError == vm.ErrExecutionReverted.Error() { return &types.EstimateGasResponse{ @@ -427,10 +439,34 @@ func (k Keeper) EstimateGasInternal(c context.Context, req *types.EthCallRequest } return nil, errors.New(result.VmError) } - // Otherwise, the specified gas cap is too low return nil, fmt.Errorf("gas required exceeds allowance (%d)", gasCap) } + // If no larger allowance is available, fail fast + return nil, fmt.Errorf("gas required exceeds allowance (%d)", hi) } + + // There's a fairly high chance for the transaction to execute successfully + // with gasLimit set to the first execution's usedGas + gasRefund. Explicitly + // check that gas amount and use as a limit for the binary search. + optimisticGasLimit := (result.MaxUsedGas + ethparams.CallStipend) * 64 / 63 + if optimisticGasLimit < hi { + failed, _, err = executable(optimisticGasLimit) + if err != nil { + return nil, err + } + if failed { + lo = optimisticGasLimit + } else { + hi = optimisticGasLimit + } + } + + // Binary search for the smallest gas limit that allows the tx to execute successfully. + hi, err = types.BinSearch(lo, hi, executable) + if err != nil { + return nil, err + } + return &types.EstimateGasResponse{Gas: hi}, nil } diff --git a/x/vm/keeper/state_transition.go b/x/vm/keeper/state_transition.go index d163bdc4ad..7811bc3345 100644 --- a/x/vm/keeper/state_transition.go +++ b/x/vm/keeper/state_transition.go @@ -460,12 +460,12 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace return nil, errorsmod.Wrap(types.ErrGasOverflow, "apply message") } // refund gas - temporaryGasUsed := msg.GasLimit - leftoverGas - refund := GasToRefund(stateDB.GetRefund(), temporaryGasUsed, refundQuotient) + maxUsedGas := msg.GasLimit - leftoverGas + refund := GasToRefund(stateDB.GetRefund(), maxUsedGas, refundQuotient) // update leftoverGas and temporaryGasUsed with refund amount leftoverGas += refund - temporaryGasUsed -= refund + temporaryGasUsed := maxUsedGas - refund // EVM execution error needs to be available for the JSON-RPC client var vmError string @@ -508,11 +508,12 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace } return &types.MsgEthereumTxResponse{ - GasUsed: gasUsed.TruncateInt().Uint64(), - VmError: vmError, - Ret: ret, - Logs: types.NewLogsFromEth(stateDB.Logs()), - Hash: txConfig.TxHash.Hex(), + GasUsed: gasUsed.TruncateInt().Uint64(), + MaxUsedGas: maxUsedGas, + VmError: vmError, + Ret: ret, + Logs: types.NewLogsFromEth(stateDB.Logs()), + Hash: txConfig.TxHash.Hex(), }, nil } diff --git a/x/vm/types/tx.pb.go b/x/vm/types/tx.pb.go index 3dd000bf86..dc6c108317 100644 --- a/x/vm/types/tx.pb.go +++ b/x/vm/types/tx.pb.go @@ -128,6 +128,8 @@ type MsgEthereumTxResponse struct { VmError string `protobuf:"bytes,4,opt,name=vm_error,json=vmError,proto3" json:"vm_error,omitempty"` // gas_used specifies how much gas was consumed by the transaction GasUsed uint64 `protobuf:"varint,5,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` + // max_used_gas specifies the gas consumed by the transaction, not including refunds + MaxUsedGas uint64 `protobuf:"varint,6,opt,name=max_used_gas,json=maxUsedGas,proto3" json:"max_used_gas,omitempty"` } func (m *MsgEthereumTxResponse) Reset() { *m = MsgEthereumTxResponse{} } @@ -363,50 +365,51 @@ func init() { func init() { proto.RegisterFile("cosmos/evm/vm/v1/tx.proto", fileDescriptor_77a8ac5e8c9c4850) } var fileDescriptor_77a8ac5e8c9c4850 = []byte{ - // 678 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x4f, 0x6b, 0x13, 0x41, - 0x1c, 0xcd, 0x66, 0xb7, 0x6d, 0x3a, 0xad, 0x18, 0xc7, 0xd6, 0x6e, 0x97, 0xba, 0x49, 0x17, 0xff, - 0xa4, 0x05, 0xb3, 0x36, 0x82, 0x60, 0x3c, 0x19, 0xe8, 0xc1, 0x60, 0xb0, 0xac, 0xf6, 0x22, 0x42, - 0x98, 0x36, 0xe3, 0x64, 0x21, 0xbb, 0xb3, 0xce, 0x4c, 0x62, 0x7a, 0x10, 0xa4, 0x78, 0x10, 0x4f, - 0x82, 0x5f, 0xc0, 0x83, 0x07, 0x8f, 0x3d, 0x78, 0xf2, 0x13, 0xf4, 0x58, 0x14, 0x44, 0x44, 0x8a, - 0xb4, 0x42, 0xbf, 0x86, 0xcc, 0xee, 0xb6, 0xd9, 0x34, 0x0b, 0x15, 0x61, 0x09, 0xb3, 0xf3, 0xde, - 0xef, 0xfd, 0x7e, 0x6f, 0xde, 0x64, 0xc1, 0xfc, 0x26, 0xe5, 0x1e, 0xe5, 0x36, 0xee, 0x79, 0xb6, - 0x7c, 0x56, 0x6c, 0xd1, 0x2f, 0x07, 0x8c, 0x0a, 0x0a, 0xf3, 0x11, 0x54, 0xc6, 0x3d, 0xaf, 0x2c, - 0x9f, 0x15, 0xe3, 0x02, 0xf2, 0x5c, 0x9f, 0xda, 0xe1, 0x6f, 0x44, 0x32, 0x8c, 0x91, 0x7a, 0x49, - 0x8f, 0xb0, 0xb9, 0x18, 0xf3, 0x38, 0x91, 0x80, 0xc7, 0x49, 0x0c, 0xc4, 0x4d, 0x9b, 0xe1, 0x9b, - 0x1d, 0xb7, 0x89, 0xa0, 0x19, 0x42, 0x09, 0x8d, 0xf6, 0xe5, 0x2a, 0xde, 0x5d, 0x20, 0x94, 0x92, - 0x0e, 0xb6, 0x51, 0xe0, 0xda, 0xc8, 0xf7, 0xa9, 0x40, 0xc2, 0xa5, 0x7e, 0x5c, 0x63, 0xbd, 0x56, - 0xc0, 0xb9, 0x06, 0x27, 0xab, 0xa2, 0x8d, 0x19, 0xee, 0x7a, 0x8f, 0xfb, 0x10, 0x02, 0xed, 0x19, - 0xa3, 0x9e, 0x3e, 0x56, 0x54, 0x4a, 0xd3, 0x4e, 0xb8, 0x86, 0x57, 0x80, 0xca, 0xd0, 0x0b, 0x7d, - 0x5c, 0x6e, 0xd5, 0xe0, 0xee, 0x7e, 0x21, 0xf3, 0x73, 0xbf, 0x00, 0x06, 0x45, 0x8e, 0x84, 0xab, - 0x8b, 0x6f, 0x3e, 0x14, 0x32, 0x6f, 0x8f, 0x76, 0x96, 0xf5, 0x84, 0xb1, 0x21, 0xf1, 0xba, 0x96, - 0x53, 0xf2, 0xd9, 0xba, 0x96, 0xcb, 0xe6, 0xd5, 0xba, 0x96, 0x53, 0xf3, 0x5a, 0x5d, 0xcb, 0x69, - 0xf9, 0x31, 0xcb, 0x02, 0xc6, 0x6a, 0x5f, 0x60, 0x9f, 0xbb, 0xd4, 0x7f, 0x18, 0x84, 0x03, 0x0e, - 0xaa, 0xaa, 0x9a, 0x14, 0xb6, 0x3e, 0x2a, 0x60, 0x76, 0x48, 0xcd, 0xc1, 0x3c, 0xa0, 0x3e, 0xc7, - 0x72, 0xe4, 0x36, 0xe2, 0x6d, 0x5d, 0x29, 0x2a, 0xa5, 0x49, 0x27, 0x5c, 0xc3, 0x25, 0xa0, 0x75, - 0x28, 0xe1, 0x7a, 0xb6, 0xa8, 0x96, 0xa6, 0x2a, 0xb3, 0xe5, 0xd3, 0x81, 0x94, 0x1f, 0x50, 0xe2, - 0x84, 0x14, 0x98, 0x07, 0x2a, 0xc3, 0x42, 0x57, 0x43, 0xc3, 0x72, 0x09, 0xe7, 0x41, 0xae, 0xe7, - 0x35, 0x31, 0x63, 0x94, 0xe9, 0x5a, 0x28, 0x3a, 0xd1, 0xf3, 0x56, 0xe5, 0xab, 0x84, 0x08, 0xe2, - 0xcd, 0x2e, 0xc7, 0xad, 0xf0, 0x88, 0x34, 0x67, 0x82, 0x20, 0xbe, 0xce, 0x71, 0x2b, 0x1e, 0xf3, - 0x8b, 0x02, 0xce, 0x37, 0x38, 0x59, 0x0f, 0x5a, 0x48, 0xe0, 0x35, 0xc4, 0x90, 0xc7, 0xe1, 0x6d, - 0x30, 0x89, 0xba, 0xa2, 0x4d, 0x99, 0x2b, 0xb6, 0xa2, 0x29, 0x6b, 0xfa, 0xd7, 0xcf, 0x37, 0x66, - 0xe2, 0xa1, 0xee, 0xb5, 0x5a, 0x0c, 0x73, 0xfe, 0x48, 0x30, 0xd7, 0x27, 0xce, 0x80, 0x0a, 0xef, - 0x82, 0xf1, 0x20, 0x54, 0xd0, 0xb3, 0x45, 0xa5, 0x34, 0x55, 0xd1, 0x47, 0x6d, 0x44, 0x1d, 0x6a, - 0x93, 0x32, 0x94, 0x4f, 0x47, 0x3b, 0xcb, 0x8a, 0x13, 0x97, 0x54, 0x2b, 0xdb, 0x47, 0x3b, 0xcb, - 0x03, 0x31, 0x19, 0x4c, 0x21, 0x11, 0x4c, 0xdf, 0x8e, 0xd2, 0x49, 0x0e, 0x6a, 0xcd, 0x83, 0xb9, - 0x53, 0x5b, 0xc7, 0x87, 0x6c, 0x7d, 0x57, 0xc0, 0xa5, 0x06, 0x27, 0x0e, 0x26, 0x2e, 0x17, 0x98, - 0xad, 0x31, 0xec, 0xfa, 0x5c, 0xa0, 0x4e, 0xe7, 0xff, 0xed, 0xdd, 0x07, 0x53, 0xc1, 0x40, 0x26, - 0x8e, 0x6a, 0x21, 0xc5, 0xe3, 0x09, 0x29, 0xe9, 0x33, 0x59, 0x5b, 0xbd, 0x33, 0x6a, 0xf6, 0x5a, - 0x8a, 0xd9, 0x94, 0xe9, 0xad, 0x22, 0x30, 0xd3, 0x91, 0x63, 0xeb, 0x95, 0x5f, 0x59, 0xa0, 0x36, - 0x38, 0x81, 0x2f, 0x41, 0xe2, 0xce, 0xc3, 0xc2, 0xe8, 0xa0, 0x43, 0xd7, 0xd3, 0xb8, 0x7e, 0x06, - 0xe1, 0xe4, 0x68, 0xaf, 0x6e, 0x7f, 0xfb, 0xf3, 0x3e, 0x5b, 0xb0, 0x2e, 0xdb, 0xa3, 0x5f, 0x84, - 0x98, 0xdd, 0x14, 0x7d, 0xf8, 0x14, 0x4c, 0x0f, 0xdd, 0xaa, 0xc5, 0x54, 0xfd, 0x24, 0xc5, 0x58, - 0x3a, 0x93, 0x72, 0xf2, 0x27, 0x7a, 0x0e, 0x2e, 0xa6, 0x65, 0x5b, 0x4a, 0x55, 0x48, 0x61, 0x1a, - 0x37, 0xff, 0x95, 0x79, 0xdc, 0xd2, 0x18, 0x7b, 0x25, 0x83, 0xac, 0x55, 0x77, 0x0f, 0x4c, 0x65, - 0xef, 0xc0, 0x54, 0x7e, 0x1f, 0x98, 0xca, 0xbb, 0x43, 0x33, 0xb3, 0x77, 0x68, 0x66, 0x7e, 0x1c, - 0x9a, 0x99, 0x27, 0x45, 0xe2, 0x8a, 0x76, 0x77, 0xa3, 0xbc, 0x49, 0x3d, 0xfb, 0x74, 0x9a, 0x62, - 0x2b, 0xc0, 0x7c, 0x63, 0x3c, 0xfc, 0x8c, 0xdd, 0xfa, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x48, - 0x3b, 0x6f, 0x8c, 0x05, 0x00, 0x00, + // 699 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x4f, 0x6b, 0x13, 0x4f, + 0x18, 0xce, 0x26, 0xdb, 0x36, 0x9d, 0xf6, 0xc7, 0x2f, 0x8e, 0xad, 0xdd, 0x2e, 0x35, 0x49, 0x17, + 0xff, 0xa4, 0x05, 0xb3, 0x36, 0x82, 0x60, 0x3c, 0x19, 0x28, 0x62, 0x30, 0x58, 0x56, 0x7b, 0x11, + 0x21, 0x4c, 0x9b, 0x71, 0xb2, 0x90, 0xd9, 0x59, 0x67, 0x26, 0x31, 0x3d, 0x08, 0x52, 0x3c, 0x88, + 0x27, 0xc1, 0x2f, 0xe0, 0xd1, 0x63, 0x0f, 0x9e, 0xfc, 0x00, 0xd2, 0x63, 0x51, 0x10, 0x11, 0x29, + 0xd2, 0x0a, 0xfd, 0x1a, 0x32, 0xbb, 0xdb, 0x66, 0xd3, 0x2c, 0x54, 0x84, 0x65, 0x99, 0x9d, 0xe7, + 0x79, 0x9f, 0xf7, 0x7d, 0xe6, 0xd9, 0x5d, 0x30, 0xbf, 0xc9, 0x04, 0x65, 0xc2, 0xc6, 0x3d, 0x6a, + 0xab, 0x6b, 0xc5, 0x96, 0xfd, 0xb2, 0xcf, 0x99, 0x64, 0x30, 0x17, 0x42, 0x65, 0xdc, 0xa3, 0x65, + 0x75, 0xad, 0x98, 0xe7, 0x10, 0x75, 0x3d, 0x66, 0x07, 0xf7, 0x90, 0x64, 0x9a, 0x23, 0xf5, 0x8a, + 0x1e, 0x62, 0x73, 0x11, 0x46, 0x05, 0x51, 0x00, 0x15, 0x24, 0x02, 0xa2, 0xa6, 0xcd, 0xe0, 0xc9, + 0x8e, 0xda, 0x84, 0xd0, 0x0c, 0x61, 0x84, 0x85, 0xfb, 0x6a, 0x15, 0xed, 0x2e, 0x10, 0xc6, 0x48, + 0x07, 0xdb, 0xc8, 0x77, 0x6d, 0xe4, 0x79, 0x4c, 0x22, 0xe9, 0x32, 0x2f, 0xaa, 0xb1, 0x5e, 0x69, + 0xe0, 0xbf, 0x86, 0x20, 0xab, 0xb2, 0x8d, 0x39, 0xee, 0xd2, 0x47, 0x7d, 0x08, 0x81, 0xfe, 0x94, + 0x33, 0x6a, 0x8c, 0x15, 0xb5, 0xd2, 0xb4, 0x13, 0xac, 0xe1, 0x25, 0x90, 0xe1, 0xe8, 0xb9, 0x31, + 0xae, 0xb6, 0x6a, 0x70, 0x77, 0xbf, 0x90, 0xfa, 0xb1, 0x5f, 0x00, 0x83, 0x22, 0x47, 0xc1, 0xd5, + 0xc5, 0xd7, 0xef, 0x0b, 0xa9, 0x37, 0x47, 0x3b, 0xcb, 0x46, 0xcc, 0xd8, 0x90, 0x78, 0x5d, 0xcf, + 0x6a, 0xb9, 0x74, 0x5d, 0xcf, 0xa6, 0x73, 0x99, 0xba, 0x9e, 0xcd, 0xe4, 0xf4, 0xba, 0x9e, 0xd5, + 0x73, 0x63, 0x96, 0x05, 0xcc, 0xd5, 0xbe, 0xc4, 0x9e, 0x70, 0x99, 0xf7, 0xc0, 0x0f, 0x06, 0x1c, + 0x54, 0x55, 0x75, 0x25, 0x6c, 0x7d, 0xd6, 0xc0, 0xec, 0x90, 0x9a, 0x83, 0x85, 0xcf, 0x3c, 0x81, + 0xd5, 0xc8, 0x6d, 0x24, 0xda, 0x86, 0x56, 0xd4, 0x4a, 0x93, 0x4e, 0xb0, 0x86, 0x4b, 0x40, 0xef, + 0x30, 0x22, 0x8c, 0x74, 0x31, 0x53, 0x9a, 0xaa, 0xcc, 0x96, 0x4f, 0x07, 0x52, 0xbe, 0xcf, 0x88, + 0x13, 0x50, 0x60, 0x0e, 0x64, 0x38, 0x96, 0x46, 0x26, 0x30, 0xac, 0x96, 0x70, 0x1e, 0x64, 0x7b, + 0xb4, 0x89, 0x39, 0x67, 0xdc, 0xd0, 0x03, 0xd1, 0x89, 0x1e, 0x5d, 0x55, 0x8f, 0x0a, 0x22, 0x48, + 0x34, 0xbb, 0x02, 0xb7, 0x82, 0x23, 0xd2, 0x9d, 0x09, 0x82, 0xc4, 0xba, 0xc0, 0x2d, 0x58, 0x04, + 0xd3, 0x14, 0xf5, 0x03, 0xa8, 0x49, 0x90, 0x08, 0x8e, 0x4b, 0x77, 0x00, 0x45, 0x7d, 0x05, 0xdf, + 0x45, 0x22, 0x32, 0xf2, 0x49, 0x03, 0xff, 0x37, 0x04, 0x59, 0xf7, 0x5b, 0x48, 0xe2, 0x35, 0xc4, + 0x11, 0x15, 0xf0, 0x26, 0x98, 0x44, 0x5d, 0xd9, 0x66, 0xdc, 0x95, 0x5b, 0xa1, 0x8f, 0x9a, 0xf1, + 0xe5, 0xe3, 0xb5, 0x99, 0x68, 0xec, 0x3b, 0xad, 0x16, 0xc7, 0x42, 0x3c, 0x94, 0xdc, 0xf5, 0x88, + 0x33, 0xa0, 0xc2, 0xdb, 0x60, 0xdc, 0x0f, 0x14, 0x8c, 0x74, 0x51, 0x2b, 0x4d, 0x55, 0x8c, 0x51, + 0xa3, 0x61, 0x87, 0xda, 0xa4, 0x8a, 0xed, 0xc3, 0xd1, 0xce, 0xb2, 0xe6, 0x44, 0x25, 0xd5, 0xca, + 0xf6, 0xd1, 0xce, 0xf2, 0x40, 0x4c, 0x45, 0x57, 0x88, 0x45, 0xd7, 0xb7, 0xc3, 0xfc, 0xe2, 0x83, + 0x5a, 0xf3, 0x60, 0xee, 0xd4, 0xd6, 0x71, 0x0c, 0xd6, 0x37, 0x0d, 0x5c, 0x68, 0x08, 0xe2, 0x60, + 0xe2, 0x0a, 0x89, 0xf9, 0x1a, 0xc7, 0xae, 0x27, 0x24, 0xea, 0x74, 0xfe, 0xdd, 0xde, 0x3d, 0x30, + 0xe5, 0x0f, 0x64, 0xa2, 0x30, 0x17, 0x12, 0x3c, 0x9e, 0x90, 0xe2, 0x3e, 0xe3, 0xb5, 0xd5, 0x5b, + 0xa3, 0x66, 0xaf, 0x24, 0x98, 0x4d, 0x98, 0xde, 0x2a, 0x82, 0x7c, 0x32, 0x72, 0x6c, 0xbd, 0xf2, + 0x33, 0x0d, 0x32, 0x0d, 0x41, 0xe0, 0x0b, 0x10, 0xfb, 0x2a, 0x60, 0x61, 0x74, 0xd0, 0xa1, 0x17, + 0xd8, 0xbc, 0x7a, 0x06, 0xe1, 0xe4, 0x68, 0x2f, 0x6f, 0x7f, 0xfd, 0xfd, 0x2e, 0x5d, 0xb0, 0x2e, + 0xda, 0xa3, 0xff, 0x8c, 0x88, 0xdd, 0x94, 0x7d, 0xf8, 0x04, 0x4c, 0x0f, 0xbd, 0x55, 0x8b, 0x89, + 0xfa, 0x71, 0x8a, 0xb9, 0x74, 0x26, 0xe5, 0xe4, 0x33, 0x7b, 0x06, 0xce, 0x27, 0x65, 0x5b, 0x4a, + 0x54, 0x48, 0x60, 0x9a, 0xd7, 0xff, 0x96, 0x79, 0xdc, 0xd2, 0x1c, 0x7b, 0xa9, 0x82, 0xac, 0x55, + 0x77, 0x0f, 0xf2, 0xda, 0xde, 0x41, 0x5e, 0xfb, 0x75, 0x90, 0xd7, 0xde, 0x1e, 0xe6, 0x53, 0x7b, + 0x87, 0xf9, 0xd4, 0xf7, 0xc3, 0x7c, 0xea, 0x71, 0x91, 0xb8, 0xb2, 0xdd, 0xdd, 0x28, 0x6f, 0x32, + 0x6a, 0x9f, 0x4e, 0x53, 0x6e, 0xf9, 0x58, 0x6c, 0x8c, 0x07, 0x3f, 0xba, 0x1b, 0x7f, 0x02, 0x00, + 0x00, 0xff, 0xff, 0xf9, 0x21, 0xde, 0xc0, 0xae, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -658,6 +661,11 @@ func (m *MsgEthereumTxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.MaxUsedGas != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.MaxUsedGas)) + i-- + dAtA[i] = 0x30 + } if m.GasUsed != 0 { i = encodeVarintTx(dAtA, i, uint64(m.GasUsed)) i-- @@ -893,6 +901,9 @@ func (m *MsgEthereumTxResponse) Size() (n int) { if m.GasUsed != 0 { n += 1 + sovTx(uint64(m.GasUsed)) } + if m.MaxUsedGas != 0 { + n += 1 + sovTx(uint64(m.MaxUsedGas)) + } return n } @@ -1301,6 +1312,25 @@ func (m *MsgEthereumTxResponse) Unmarshal(dAtA []byte) error { break } } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxUsedGas", wireType) + } + m.MaxUsedGas = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxUsedGas |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) From 4be8aba3e891a95e209a38f9ad746afad506b20a Mon Sep 17 00:00:00 2001 From: yihuang Date: Sat, 30 Aug 2025 04:22:35 +0800 Subject: [PATCH 35/61] feat: AddPrecompileFn on stateObject not needed (#511) * Problem: AddPrecompileFn on stateObject not needed what is does is only add a journal entry, not related to the state object at all. Solution: - remove the method, move the logic to statedb directly. * remove unused parameter * changelog --------- Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + precompiles/common/precompile.go | 2 +- x/vm/statedb/state_object.go | 12 ------------ x/vm/statedb/statedb.go | 11 +++++------ 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8def679f0f..fd3133bbf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - [\#467](https://github.com/cosmos/evm/pull/467) Replace GlobalEVMMempool by passing to JSONRPC on initiate. - [\#352](https://github.com/cosmos/evm/pull/352) Remove the creation of a Geth EVM instance, stateDB during the AnteHandler balance check. - [\#496](https://github.com/cosmos/evm/pull/496) Simplify mempool instantiation by using configs instead of objects. +- [\#511](https://github.com/cosmos/evm/pull/511) Minor code cleanup for `AddPrecompileFn`. ### FEATURES diff --git a/precompiles/common/precompile.go b/precompiles/common/precompile.go index d64453da32..d095e97045 100644 --- a/precompiles/common/precompile.go +++ b/precompiles/common/precompile.go @@ -73,7 +73,7 @@ func (p Precompile) RunSetup( // add precompileCall entry on the stateDB journal // this allows to revert the changes within an evm tx - err = stateDB.AddPrecompileFn(p.Address(), snapshot, events) + err = stateDB.AddPrecompileFn(snapshot, events) if err != nil { return sdk.Context{}, nil, nil, uint64(0), nil, err } diff --git a/x/vm/statedb/state_object.go b/x/vm/statedb/state_object.go index a85bcb4dfa..876142c9b0 100644 --- a/x/vm/statedb/state_object.go +++ b/x/vm/statedb/state_object.go @@ -8,8 +8,6 @@ import ( "github.com/holiman/uint256" "github.com/cosmos/evm/x/vm/types" - - sdk "github.com/cosmos/cosmos-sdk/types" ) // Account is the Ethereum consensus representation of accounts. @@ -136,16 +134,6 @@ func (s *stateObject) SetBalance(amount *uint256.Int) uint256.Int { return prev } -// AddPrecompileFn appends to the journal an entry -// with a snapshot of the multi-store and events -// previous to the precompile call -func (s *stateObject) AddPrecompileFn(snapshot int, events sdk.Events) { - s.db.journal.append(precompileCallChange{ - snapshot: snapshot, - events: events, - }) -} - func (s *stateObject) setBalance(amount *uint256.Int) { s.account.Balance = amount } diff --git a/x/vm/statedb/statedb.go b/x/vm/statedb/statedb.go index d2f8ae5712..a4601ec131 100644 --- a/x/vm/statedb/statedb.go +++ b/x/vm/statedb/statedb.go @@ -434,12 +434,11 @@ func (s *StateDB) setStateObject(object *stateObject) { // AddPrecompileFn adds a precompileCall journal entry // with a snapshot of the multi-store and events previous // to the precompile call. -func (s *StateDB) AddPrecompileFn(addr common.Address, snapshot int, events sdk.Events) error { - stateObject := s.getOrNewStateObject(addr) - if stateObject == nil { - return fmt.Errorf("could not add precompile call to address %s. State object not found", addr) - } - stateObject.AddPrecompileFn(snapshot, events) +func (s *StateDB) AddPrecompileFn(snapshot int, events sdk.Events) error { + s.journal.append(precompileCallChange{ + snapshot: snapshot, + events: events, + }) s.precompileCallsCounter++ if s.precompileCallsCounter > types.MaxPrecompileCalls { return fmt.Errorf("max calls to precompiles (%d) reached", types.MaxPrecompileCalls) From ec57b964505b1bb69d67a6fdf93084829e5d9fa7 Mon Sep 17 00:00:00 2001 From: Antonio Pitasi Date: Fri, 29 Aug 2025 22:23:47 +0200 Subject: [PATCH 36/61] fix: CometBlockResultByNumber when height is 0 (#416) * fix TendermintBlockResultByNumber when height is 0 Signed-off-by: Antonio Pitasi * add changelog entry Signed-off-by: Antonio Pitasi --------- Signed-off-by: Antonio Pitasi Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + rpc/backend/blocks.go | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd3133bbf9..b22b4c30b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - [\#492](https://github.com/cosmos/evm/pull/492) Duplicate case switch to avoid empty execution block - [\#509](https://github.com/cosmos/evm/pull/509) Allow value with slashes when query token_pairs - [\#495](https://github.com/cosmos/evm/pull/495) Allow immediate SIGINT interrupt when mempool is not empty +- [\#416](https://github.com/cosmos/evm/pull/416) Fix regression in CometBlockResultByNumber when height is 0 to use the latest block. This fixes eth_getFilterLogs RPC. - [\#545](https://github.com/cosmos/evm/pull/545) Check if mempool is not nil before accepting nonce gap error tx. ### IMPROVEMENTS diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 3c253219fa..afd81fd6c5 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -203,6 +203,9 @@ func (b *Backend) CometHeaderByNumber(blockNum rpctypes.BlockNumber) (*cmtrpctyp // CometBlockResultByNumber returns a CometBFT-formatted block result // by block number func (b *Backend) CometBlockResultByNumber(height *int64) (*cmtrpctypes.ResultBlockResults, error) { + if height != nil && *height == 0 { + height = nil + } res, err := b.RPCClient.BlockResults(b.Ctx, height) if err != nil { return nil, fmt.Errorf("failed to fetch block result from CometBFT %d: %w", *height, err) From 1fcfa4911a591cbdd626dc1973663402403cec5e Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 3 Sep 2025 02:13:19 +0800 Subject: [PATCH 37/61] feat: add block time in derived logs (#502) * Problem: no block time in derived logs Closes: #501 ref: * https://github.com/ethereum/go-ethereum/pull/31887 * https://github.com/ethereum/execution-apis/pull/639 fix test * change proto * fix tests * fix lint * changelog --------- Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + api/cosmos/evm/vm/v1/evm.pulsar.go | 257 ++++++++++------ mempool/blockchain.go | 2 +- precompiles/common/balance_handler_test.go | 4 +- proto/cosmos/evm/vm/v1/evm.proto | 3 + tests/integration/precompiles/gov/test_gov.go | 3 +- .../precompiles/staking/test_staking.go | 3 +- tests/integration/x/vm/test_genesis.go | 2 +- tests/integration/x/vm/test_grpc_query.go | 1 - tests/integration/x/vm/test_hooks.go | 1 - tests/integration/x/vm/test_statedb.go | 1 - tests/integration/x/vm/utils.go | 2 +- .../integration/evm/network/unit_network.go | 5 +- testutil/statedb.go | 4 +- x/vm/keeper/config.go | 7 +- x/vm/keeper/grpc_query.go | 10 +- x/vm/keeper/state_transition.go | 9 +- x/vm/statedb/config.go | 25 +- x/vm/statedb/statedb.go | 12 +- x/vm/statedb/statedb_test.go | 24 +- x/vm/types/evm.pb.go | 281 ++++++++++-------- x/vm/types/logs.go | 19 +- 22 files changed, 388 insertions(+), 288 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b22b4c30b2..5df6215c25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ ### FEATURES - [\#346](https://github.com/cosmos/evm/pull/346) Add eth_createAccessList method and implementation +- [\#502](https://github.com/cosmos/evm/pull/502) Add block time in derived logs. ### STATE BREAKING diff --git a/api/cosmos/evm/vm/v1/evm.pulsar.go b/api/cosmos/evm/vm/v1/evm.pulsar.go index 9026cb946a..7980ded788 100644 --- a/api/cosmos/evm/vm/v1/evm.pulsar.go +++ b/api/cosmos/evm/vm/v1/evm.pulsar.go @@ -4995,16 +4995,17 @@ func (x *_Log_2_list) IsValid() bool { } var ( - md_Log protoreflect.MessageDescriptor - fd_Log_address protoreflect.FieldDescriptor - fd_Log_topics protoreflect.FieldDescriptor - fd_Log_data protoreflect.FieldDescriptor - fd_Log_block_number protoreflect.FieldDescriptor - fd_Log_tx_hash protoreflect.FieldDescriptor - fd_Log_tx_index protoreflect.FieldDescriptor - fd_Log_block_hash protoreflect.FieldDescriptor - fd_Log_index protoreflect.FieldDescriptor - fd_Log_removed protoreflect.FieldDescriptor + md_Log protoreflect.MessageDescriptor + fd_Log_address protoreflect.FieldDescriptor + fd_Log_topics protoreflect.FieldDescriptor + fd_Log_data protoreflect.FieldDescriptor + fd_Log_block_number protoreflect.FieldDescriptor + fd_Log_tx_hash protoreflect.FieldDescriptor + fd_Log_tx_index protoreflect.FieldDescriptor + fd_Log_block_hash protoreflect.FieldDescriptor + fd_Log_index protoreflect.FieldDescriptor + fd_Log_removed protoreflect.FieldDescriptor + fd_Log_block_timestamp protoreflect.FieldDescriptor ) func init() { @@ -5019,6 +5020,7 @@ func init() { fd_Log_block_hash = md_Log.Fields().ByName("block_hash") fd_Log_index = md_Log.Fields().ByName("index") fd_Log_removed = md_Log.Fields().ByName("removed") + fd_Log_block_timestamp = md_Log.Fields().ByName("block_timestamp") } var _ protoreflect.Message = (*fastReflection_Log)(nil) @@ -5140,6 +5142,12 @@ func (x *fastReflection_Log) Range(f func(protoreflect.FieldDescriptor, protoref return } } + if x.BlockTimestamp != uint64(0) { + value := protoreflect.ValueOfUint64(x.BlockTimestamp) + if !f(fd_Log_block_timestamp, value) { + return + } + } } // Has reports whether a field is populated. @@ -5173,6 +5181,8 @@ func (x *fastReflection_Log) Has(fd protoreflect.FieldDescriptor) bool { return x.Index != uint64(0) case "cosmos.evm.vm.v1.Log.removed": return x.Removed != false + case "cosmos.evm.vm.v1.Log.block_timestamp": + return x.BlockTimestamp != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Log")) @@ -5207,6 +5217,8 @@ func (x *fastReflection_Log) Clear(fd protoreflect.FieldDescriptor) { x.Index = uint64(0) case "cosmos.evm.vm.v1.Log.removed": x.Removed = false + case "cosmos.evm.vm.v1.Log.block_timestamp": + x.BlockTimestamp = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Log")) @@ -5253,6 +5265,9 @@ func (x *fastReflection_Log) Get(descriptor protoreflect.FieldDescriptor) protor case "cosmos.evm.vm.v1.Log.removed": value := x.Removed return protoreflect.ValueOfBool(value) + case "cosmos.evm.vm.v1.Log.block_timestamp": + value := x.BlockTimestamp + return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Log")) @@ -5293,6 +5308,8 @@ func (x *fastReflection_Log) Set(fd protoreflect.FieldDescriptor, value protoref x.Index = value.Uint() case "cosmos.evm.vm.v1.Log.removed": x.Removed = value.Bool() + case "cosmos.evm.vm.v1.Log.block_timestamp": + x.BlockTimestamp = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Log")) @@ -5335,6 +5352,8 @@ func (x *fastReflection_Log) Mutable(fd protoreflect.FieldDescriptor) protorefle panic(fmt.Errorf("field index of message cosmos.evm.vm.v1.Log is not mutable")) case "cosmos.evm.vm.v1.Log.removed": panic(fmt.Errorf("field removed of message cosmos.evm.vm.v1.Log is not mutable")) + case "cosmos.evm.vm.v1.Log.block_timestamp": + panic(fmt.Errorf("field block_timestamp of message cosmos.evm.vm.v1.Log is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Log")) @@ -5367,6 +5386,8 @@ func (x *fastReflection_Log) NewField(fd protoreflect.FieldDescriptor) protorefl return protoreflect.ValueOfUint64(uint64(0)) case "cosmos.evm.vm.v1.Log.removed": return protoreflect.ValueOfBool(false) + case "cosmos.evm.vm.v1.Log.block_timestamp": + return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.Log")) @@ -5470,6 +5491,9 @@ func (x *fastReflection_Log) ProtoMethods() *protoiface.Methods { if x.Removed { n += 2 } + if x.BlockTimestamp != 0 { + n += 1 + runtime.Sov(uint64(x.BlockTimestamp)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -5499,6 +5523,11 @@ func (x *fastReflection_Log) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.BlockTimestamp != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.BlockTimestamp)) + i-- + dAtA[i] = 0x50 + } if x.Removed { i-- if x.Removed { @@ -5849,6 +5878,25 @@ func (x *fastReflection_Log) ProtoMethods() *protoiface.Methods { } } x.Removed = bool(v != 0) + case 10: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field BlockTimestamp", wireType) + } + x.BlockTimestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.BlockTimestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -9330,6 +9378,8 @@ type Log struct { // reorganisation. You must pay attention to this field if you receive logs // through a filter query. Removed bool `protobuf:"varint,9,opt,name=removed,proto3" json:"removed,omitempty"` + // block_timestamp is the timestamp of the block in which the transaction was + BlockTimestamp uint64 `protobuf:"varint,10,opt,name=block_timestamp,json=blockTimestamp,proto3" json:"block_timestamp,omitempty"` } func (x *Log) Reset() { @@ -9415,6 +9465,13 @@ func (x *Log) GetRemoved() bool { return false } +func (x *Log) GetBlockTimestamp() uint64 { + if x != nil { + return x.BlockTimestamp + } + return 0 +} + // TxResult stores results of Tx execution. type TxResult struct { state protoimpl.MessageState @@ -9928,7 +9985,7 @@ var file_cosmos_evm_vm_v1_evm_proto_rawDesc = []byte{ 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, - 0x22, 0xca, 0x02, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x22, 0x87, 0x03, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, @@ -9948,93 +10005,97 @@ var file_cosmos_evm_vm_v1_evm_proto_rawDesc = []byte{ 0x22, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0c, 0xea, 0xde, 0x1f, 0x08, 0x6c, 0x6f, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x90, 0x02, - 0x0a, 0x08, 0x54, 0x78, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x46, 0x0a, 0x10, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x1b, 0xf2, 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x22, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x12, 0x57, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x6c, - 0x6f, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x73, 0x42, 0x1b, 0xc8, 0xde, - 0x1f, 0x00, 0xf2, 0xde, 0x1f, 0x0e, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x74, 0x78, 0x5f, 0x6c, - 0x6f, 0x67, 0x73, 0x22, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x74, 0x78, 0x4c, 0x6f, 0x67, - 0x73, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, - 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x12, - 0x19, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, - 0x22, 0x61, 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x0c, 0x73, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, - 0x0f, 0xea, 0xde, 0x1f, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, - 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x3a, 0x04, 0x88, - 0xa0, 0x1f, 0x00, 0x22, 0xa0, 0x04, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x74, - 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x12, 0x35, 0x0a, - 0x0d, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x08, 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, - 0x74, 0x61, 0x63, 0x6b, 0x12, 0x3b, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x42, 0x12, 0xea, - 0xde, 0x1f, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x3b, 0x0a, - 0x09, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x09, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x0d, 0x65, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x08, 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, - 0x6f, 0x72, 0x79, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x12, 0x42, 0x0a, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, - 0x72, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x42, 0x14, 0xea, - 0xde, 0x1f, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, - 0x61, 0x74, 0x61, 0x52, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x5f, - 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x10, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x4a, 0x73, 0x6f, 0x6e, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x07, 0x10, - 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x52, 0x13, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x22, 0x4e, 0x0a, 0x0a, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6c, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x2a, 0xc0, 0x01, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x1a, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x4c, - 0x45, 0x53, 0x53, 0x10, 0x00, 0x1a, 0x1c, 0x8a, 0x9d, 0x20, 0x18, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x79, 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x6c, - 0x65, 0x73, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x01, 0x1a, - 0x18, 0x8a, 0x9d, 0x20, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x41, 0x43, 0x43, - 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, - 0x49, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x02, 0x1a, 0x1a, 0x8a, 0x9d, 0x20, 0x16, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x64, 0x1a, 0x04, 0x88, 0xa3, 0x1e, 0x00, 0x42, 0xab, 0x01, 0x0a, 0x14, 0x63, 0x6f, - 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, - 0x76, 0x31, 0x42, 0x08, 0x45, 0x76, 0x6d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, - 0x31, 0x3b, 0x76, 0x6d, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x56, 0xaa, 0x02, 0x10, 0x43, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x56, 0x6d, 0x2e, 0x56, 0x31, 0xca, - 0x02, 0x10, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, - 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, - 0x56, 0x6d, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, - 0x3a, 0x56, 0x6d, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x3b, 0x0a, + 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x42, 0x12, 0xea, 0xde, 0x1f, 0x0e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x90, 0x02, 0x0a, 0x08, 0x54, + 0x78, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x1b, 0xf2, 0xde, 0x1f, 0x17, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x52, 0x0f, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x14, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x12, 0x57, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x6c, 0x6f, 0x67, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, + 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x73, 0x42, 0x1b, 0xc8, 0xde, 0x1f, 0x00, 0xf2, + 0xde, 0x1f, 0x0e, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x74, 0x78, 0x5f, 0x6c, 0x6f, 0x67, 0x73, + 0x22, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x74, 0x78, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x10, + 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x65, 0x74, + 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x12, 0x19, 0x0a, 0x08, + 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, + 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, 0x61, 0x0a, + 0x0b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x0f, 0xea, 0xde, + 0x1f, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x0b, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, + 0x22, 0xa0, 0x04, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x12, 0x16, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x06, 0x72, 0x65, 0x65, 0x78, 0x65, 0x63, 0x12, 0x35, 0x0a, 0x0d, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x08, 0x42, 0x10, 0xea, 0xde, 0x1f, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, + 0x61, 0x63, 0x6b, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x63, + 0x6b, 0x12, 0x3b, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x42, 0x12, 0xea, 0xde, 0x1f, 0x0e, + 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x0e, + 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x64, + 0x65, 0x62, 0x75, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x3b, 0x0a, 0x09, 0x6f, 0x76, + 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x6f, 0x76, + 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x42, 0x10, + 0xea, 0xde, 0x1f, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, + 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x42, + 0x0a, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x42, 0x14, 0xea, 0xde, 0x1f, 0x10, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, 0x61, 0x74, 0x61, + 0x52, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, 0x61, + 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x5f, 0x6a, 0x73, 0x6f, + 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, + 0xea, 0xde, 0x1f, 0x0c, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x10, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72, 0x4a, 0x73, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x52, 0x0e, + 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x13, + 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, 0x64, + 0x61, 0x74, 0x61, 0x22, 0x4e, 0x0a, 0x0a, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, + 0x6f, 0x64, 0x65, 0x2a, 0xc0, 0x01, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x1a, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x4c, 0x45, 0x53, 0x53, + 0x10, 0x00, 0x1a, 0x1c, 0x8a, 0x9d, 0x20, 0x18, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, + 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x6c, 0x65, 0x73, 0x73, + 0x12, 0x34, 0x0a, 0x16, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x01, 0x1a, 0x18, 0x8a, 0x9d, + 0x20, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x74, + 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, + 0x45, 0x44, 0x10, 0x02, 0x1a, 0x1a, 0x8a, 0x9d, 0x20, 0x16, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x54, 0x79, 0x70, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, + 0x1a, 0x04, 0x88, 0xa3, 0x1e, 0x00, 0x42, 0xab, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x42, + 0x08, 0x45, 0x76, 0x6d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x76, + 0x6d, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x56, 0xaa, 0x02, 0x10, 0x43, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x56, 0x6d, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, 0x43, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, 0x56, 0x31, 0xe2, + 0x02, 0x1c, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, + 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, + 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x56, 0x6d, + 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/mempool/blockchain.go b/mempool/blockchain.go index 00fc7dd407..fa74287861 100644 --- a/mempool/blockchain.go +++ b/mempool/blockchain.go @@ -199,7 +199,7 @@ func (b Blockchain) StateAt(hash common.Hash) (vm.StateDB, error) { } appHash := ctx.BlockHeader().AppHash - stateDB := statedb.New(ctx, b.vmKeeper, statedb.NewEmptyTxConfig(common.Hash(appHash))) + stateDB := statedb.New(ctx, b.vmKeeper, statedb.NewEmptyTxConfig()) b.logger.Debug("StateDB created successfully", "app_hash", common.Hash(appHash).Hex()) return stateDB, nil diff --git a/precompiles/common/balance_handler_test.go b/precompiles/common/balance_handler_test.go index 1466e97aab..c0ea5fe0bb 100644 --- a/precompiles/common/balance_handler_test.go +++ b/precompiles/common/balance_handler_test.go @@ -149,7 +149,7 @@ func TestAfterBalanceChange(t *testing.T) { tKey := storetypes.NewTransientStoreKey("test_t") ctx := sdktestutil.DefaultContext(storeKey, tKey) - stateDB := statedb.New(ctx, mocks.NewEVMKeeper(), statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash()))) + stateDB := statedb.New(ctx, mocks.NewEVMKeeper(), statedb.NewEmptyTxConfig()) _, addrs, err := testutil.GeneratePrivKeyAddressPairs(2) require.NoError(t, err) @@ -191,7 +191,7 @@ func TestAfterBalanceChangeErrors(t *testing.T) { storeKey := storetypes.NewKVStoreKey("test") tKey := storetypes.NewTransientStoreKey("test_t") ctx := sdktestutil.DefaultContext(storeKey, tKey) - stateDB := statedb.New(ctx, mocks.NewEVMKeeper(), statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash()))) + stateDB := statedb.New(ctx, mocks.NewEVMKeeper(), statedb.NewEmptyTxConfig()) _, addrs, err := testutil.GeneratePrivKeyAddressPairs(1) require.NoError(t, err) diff --git a/proto/cosmos/evm/vm/v1/evm.proto b/proto/cosmos/evm/vm/v1/evm.proto index 71636d4bc1..dda6eade06 100644 --- a/proto/cosmos/evm/vm/v1/evm.proto +++ b/proto/cosmos/evm/vm/v1/evm.proto @@ -265,6 +265,9 @@ message Log { // reorganisation. You must pay attention to this field if you receive logs // through a filter query. bool removed = 9; + + // block_timestamp is the timestamp of the block in which the transaction was + uint64 block_timestamp = 10 [ (gogoproto.jsontag) = "blockTimestamp" ]; } // TxResult stores results of Tx execution. diff --git a/tests/integration/precompiles/gov/test_gov.go b/tests/integration/precompiles/gov/test_gov.go index 1b37f7ff78..b2a2aee96c 100644 --- a/tests/integration/precompiles/gov/test_gov.go +++ b/tests/integration/precompiles/gov/test_gov.go @@ -107,11 +107,10 @@ func (s *PrecompileTestSuite) TestRun() { s.Require().NoError(err, "failed to instantiate EVM config") // Instantiate EVM - headerHash := ctx.HeaderHash() stDB := statedb.New( ctx, s.network.App.GetEVMKeeper(), - statedb.NewEmptyTxConfig(common.BytesToHash(headerHash)), + statedb.NewEmptyTxConfig(), ) evm := s.network.App.GetEVMKeeper().NewEVM( ctx, *msg, cfg, nil, stDB, diff --git a/tests/integration/precompiles/staking/test_staking.go b/tests/integration/precompiles/staking/test_staking.go index b61c2cad1a..d8b5149dc6 100644 --- a/tests/integration/precompiles/staking/test_staking.go +++ b/tests/integration/precompiles/staking/test_staking.go @@ -436,11 +436,10 @@ func (s *PrecompileTestSuite) TestRun() { s.Require().NoError(err, "failed to instantiate EVM config") // Instantiate EVM - headerHash := ctx.HeaderHash() stDB := statedb.New( ctx, s.network.App.GetEVMKeeper(), - statedb.NewEmptyTxConfig(common.BytesToHash(headerHash)), + statedb.NewEmptyTxConfig(), ) evm := s.network.App.GetEVMKeeper().NewEVM( ctx, *msg, cfg, nil, stDB, diff --git a/tests/integration/x/vm/test_genesis.go b/tests/integration/x/vm/test_genesis.go index a927310cf0..10e5f407cb 100644 --- a/tests/integration/x/vm/test_genesis.go +++ b/tests/integration/x/vm/test_genesis.go @@ -119,7 +119,7 @@ func (s *GenesisTestSuite) TestInitGenesis() { ctx = s.network.GetContext() vmdb = statedb.New( ctx, s.network.App.GetEVMKeeper(), - statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash()))) + statedb.NewEmptyTxConfig()) tc.malleate(s.network) err := vmdb.Commit() diff --git a/tests/integration/x/vm/test_grpc_query.go b/tests/integration/x/vm/test_grpc_query.go index 0a6af97a26..f9b55fac3c 100644 --- a/tests/integration/x/vm/test_grpc_query.go +++ b/tests/integration/x/vm/test_grpc_query.go @@ -425,7 +425,6 @@ func (s *KeeperTestSuite) TestQueryTxLogs() { for _, tc := range testCases { s.Run(fmt.Sprintf("Case %s", tc.msg), func() { txCfg := statedb.NewTxConfig( - common.BytesToHash(s.Network.GetContext().HeaderHash()), txHash, txIndex, logIndex, diff --git a/tests/integration/x/vm/test_hooks.go b/tests/integration/x/vm/test_hooks.go index 9127cf9d01..23aef41ac7 100644 --- a/tests/integration/x/vm/test_hooks.go +++ b/tests/integration/x/vm/test_hooks.go @@ -70,7 +70,6 @@ func (s *KeeperTestSuite) TestEvmHooks() { ctx := s.Network.GetContext() txHash := common.BigToHash(big.NewInt(1)) vmdb := statedb.New(ctx, k, statedb.NewTxConfig( - common.BytesToHash(ctx.HeaderHash()), txHash, 0, 0, diff --git a/tests/integration/x/vm/test_statedb.go b/tests/integration/x/vm/test_statedb.go index fe801ac04b..b78480b906 100644 --- a/tests/integration/x/vm/test_statedb.go +++ b/tests/integration/x/vm/test_statedb.go @@ -754,7 +754,6 @@ func (s *KeeperTestSuite) TestAddLog() { s.Run(tc.name, func() { s.SetupTest() vmdb := statedb.New(s.Network.GetContext(), s.Network.App.GetEVMKeeper(), statedb.NewTxConfig( - common.BytesToHash(s.Network.GetContext().HeaderHash()), tc.hash, 0, 0, )) diff --git a/tests/integration/x/vm/utils.go b/tests/integration/x/vm/utils.go index c22b8b1eeb..ab5b0b30af 100644 --- a/tests/integration/x/vm/utils.go +++ b/tests/integration/x/vm/utils.go @@ -24,7 +24,7 @@ func (s *KeeperTestSuite) EvmDenom() string { } func (s *KeeperTestSuite) StateDB() *statedb.StateDB { - return statedb.New(s.Network.GetContext(), s.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig(common.BytesToHash(s.Network.GetContext().HeaderHash()))) + return statedb.New(s.Network.GetContext(), s.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) } // DeployTestContract deploy a test erc20 contract and returns the contract address diff --git a/testutil/integration/evm/network/unit_network.go b/testutil/integration/evm/network/unit_network.go index 9e23559f77..ff068b8f5e 100644 --- a/testutil/integration/evm/network/unit_network.go +++ b/testutil/integration/evm/network/unit_network.go @@ -1,8 +1,6 @@ package network import ( - "github.com/ethereum/go-ethereum/common" - "github.com/cosmos/evm" "github.com/cosmos/evm/x/vm/statedb" @@ -36,11 +34,10 @@ func NewUnitTestNetwork(createEvmApp CreateEvmApp, opts ...ConfigOption) *UnitTe // GetStateDB returns the state database for the current block. func (n *UnitTestNetwork) GetStateDB() *statedb.StateDB { - headerHash := n.GetContext().HeaderHash() return statedb.New( n.GetContext(), n.app.GetEVMKeeper(), - statedb.NewEmptyTxConfig(common.BytesToHash(headerHash)), + statedb.NewEmptyTxConfig(), ) } diff --git a/testutil/statedb.go b/testutil/statedb.go index f248ae4d39..cbae8b2800 100644 --- a/testutil/statedb.go +++ b/testutil/statedb.go @@ -1,8 +1,6 @@ package testutil import ( - "github.com/ethereum/go-ethereum/common" - anteinterfaces "github.com/cosmos/evm/ante/interfaces" "github.com/cosmos/evm/x/vm/statedb" @@ -11,5 +9,5 @@ import ( // NewStateDB returns a new StateDB for testing purposes. func NewStateDB(ctx sdk.Context, evmKeeper anteinterfaces.EVMKeeper) *statedb.StateDB { - return statedb.New(ctx, evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash()))) + return statedb.New(ctx, evmKeeper, statedb.NewEmptyTxConfig()) } diff --git a/x/vm/keeper/config.go b/x/vm/keeper/config.go index dbbe308ba8..c957bee343 100644 --- a/x/vm/keeper/config.go +++ b/x/vm/keeper/config.go @@ -35,10 +35,9 @@ func (k *Keeper) EVMConfig(ctx sdk.Context, proposerAddress sdk.ConsAddress) (*s // TxConfig loads `TxConfig` from current transient storage func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig { return statedb.NewTxConfig( - common.BytesToHash(ctx.HeaderHash()), // BlockHash - txHash, // TxHash - uint(k.GetTxIndexTransient(ctx)), // TxIndex - uint(k.GetLogSizeTransient(ctx)), // LogIndex + txHash, // TxHash + uint(k.GetTxIndexTransient(ctx)), // TxIndex + uint(k.GetLogSizeTransient(ctx)), // LogIndex ) } diff --git a/x/vm/keeper/grpc_query.go b/x/vm/keeper/grpc_query.go index 9f2413cd87..a748d29d6f 100644 --- a/x/vm/keeper/grpc_query.go +++ b/x/vm/keeper/grpc_query.go @@ -251,7 +251,7 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms } msg := args.ToMessage(cfg.BaseFee, false, false) - txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) + txConfig := statedb.NewEmptyTxConfig() // pass false to not commit StateDB res, err := k.ApplyMessageWithConfig(ctx, *msg, nil, false, cfg, txConfig, false) @@ -324,7 +324,7 @@ func (k Keeper) EstimateGasInternal(c context.Context, req *types.EthCallRequest nonce := k.GetNonce(ctx, args.GetFrom()) args.Nonce = (*hexutil.Uint64)(&nonce) - txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) + txConfig := statedb.NewEmptyTxConfig() if args.Gas == nil { args.Gas = new(hexutil.Uint64) @@ -524,7 +524,7 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ } signer := ethtypes.MakeSigner(types.GetEthChainConfig(), big.NewInt(ctx.BlockHeight()), uint64(ctx.BlockTime().Unix())) //#nosec G115 -- int overflow is not a concern here - txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) + txConfig := statedb.NewEmptyTxConfig() // gas used at this point corresponds to GetProposerAddress & CalculateBaseFee // need to reset gas meter per transaction to be consistent with tx execution @@ -618,7 +618,7 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest) txsLength := len(req.Txs) results := make([]*types.TxTraceResult, 0, txsLength) - txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) + txConfig := statedb.NewEmptyTxConfig() for i, tx := range req.Txs { result := types.TxTraceResult{} @@ -698,7 +698,7 @@ func (k *Keeper) traceTx( } tCtx := &tracers.Context{ - BlockHash: txConfig.BlockHash, + BlockHash: common.BytesToHash(ctx.HeaderHash()), TxIndex: int(txConfig.TxIndex), //#nosec G115 -- int overflow is not a concern here TxHash: txConfig.TxHash, } diff --git a/x/vm/keeper/state_transition.go b/x/vm/keeper/state_transition.go index 7811bc3345..2188b13f4e 100644 --- a/x/vm/keeper/state_transition.go +++ b/x/vm/keeper/state_transition.go @@ -207,7 +207,7 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t TxHash: txConfig.TxHash, ContractAddress: contractAddr, GasUsed: res.GasUsed, - BlockHash: txConfig.BlockHash, + BlockHash: common.BytesToHash(ctx.HeaderHash()), BlockNumber: big.NewInt(ctx.BlockHeight()), TransactionIndex: txConfig.TxIndex, } @@ -308,7 +308,7 @@ func (k *Keeper) ApplyMessage(ctx sdk.Context, msg core.Message, tracer *tracing return nil, errorsmod.Wrap(err, "failed to load evm config") } - txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) + txConfig := statedb.NewEmptyTxConfig() return k.ApplyMessageWithConfig(ctx, msg, tracer, commit, cfg, txConfig, internal) } @@ -394,7 +394,7 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace return nil, errorsmod.Wrap(core.ErrIntrinsicGas, "apply message") } // Gas limit suffices for the floor data cost (EIP-7623) - rules := ethCfg.Rules(big.NewInt(ctx.BlockHeight()), true, uint64(ctx.BlockTime().Unix())) //#nosec G115 -- int overflow is not a concern here + rules := ethCfg.Rules(evm.Context.BlockNumber, true, evm.Context.Time) if rules.IsPrague { floorDataGas, err := core.FloorDataGas(msg.Data) if err != nil { @@ -507,12 +507,13 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace ret = evm.Interpreter().ReturnData() } + logs := stateDB.GetLogs(uint64(ctx.BlockHeight()), common.BytesToHash(ctx.HeaderHash()), evm.Context.Time) //#nosec G115 -- int overflow is not a concern here return &types.MsgEthereumTxResponse{ GasUsed: gasUsed.TruncateInt().Uint64(), MaxUsedGas: maxUsedGas, VmError: vmError, Ret: ret, - Logs: types.NewLogsFromEth(stateDB.Logs()), + Logs: types.NewLogsFromEth(logs), Hash: txConfig.TxHash.Hex(), }, nil } diff --git a/x/vm/statedb/config.go b/x/vm/statedb/config.go index e92152efa2..c7bc3f351b 100644 --- a/x/vm/statedb/config.go +++ b/x/vm/statedb/config.go @@ -10,30 +10,27 @@ import ( // TxConfig encapulates the readonly information of current tx for `StateDB`. type TxConfig struct { - BlockHash common.Hash // hash of current block - TxHash common.Hash // hash of current tx - TxIndex uint // the index of current transaction - LogIndex uint // the index of next log within current block + TxHash common.Hash // hash of current tx + TxIndex uint // the index of current transaction + LogIndex uint // the index of next log within current block } // NewTxConfig returns a TxConfig -func NewTxConfig(bhash, thash common.Hash, txIndex, logIndex uint) TxConfig { +func NewTxConfig(thash common.Hash, txIndex, logIndex uint) TxConfig { return TxConfig{ - BlockHash: bhash, - TxHash: thash, - TxIndex: txIndex, - LogIndex: logIndex, + TxHash: thash, + TxIndex: txIndex, + LogIndex: logIndex, } } // NewEmptyTxConfig construct an empty TxConfig, // used in context where there's no transaction, e.g. `eth_call`/`eth_estimateGas`. -func NewEmptyTxConfig(bhash common.Hash) TxConfig { +func NewEmptyTxConfig() TxConfig { return TxConfig{ - BlockHash: bhash, - TxHash: common.Hash{}, - TxIndex: 0, - LogIndex: 0, + TxHash: common.Hash{}, + TxIndex: 0, + LogIndex: 0, } } diff --git a/x/vm/statedb/statedb.go b/x/vm/statedb/statedb.go index a4601ec131..b869632300 100644 --- a/x/vm/statedb/statedb.go +++ b/x/vm/statedb/statedb.go @@ -219,12 +219,22 @@ func (s *StateDB) AddLog(log *ethtypes.Log) { s.journal.append(addLogChange{}) log.TxHash = s.txConfig.TxHash - log.BlockHash = s.txConfig.BlockHash log.TxIndex = s.txConfig.TxIndex log.Index = s.txConfig.LogIndex + uint(len(s.logs)) s.logs = append(s.logs, log) } +// GetLogs returns the logs matching the specified transaction hash, and annotates +// them with the given blockNumber and blockHash. +func (s *StateDB) GetLogs(blockNumber uint64, blockHash common.Hash, blockTime uint64) []*ethtypes.Log { + for _, l := range s.logs { + l.BlockNumber = blockNumber + l.BlockHash = blockHash + l.BlockTimestamp = blockTime + } + return s.logs +} + // Logs returns the logs of current transaction. func (s *StateDB) Logs() []*ethtypes.Log { return s.logs diff --git a/x/vm/statedb/statedb_test.go b/x/vm/statedb/statedb_test.go index 07b54bf1ca..45497c2707 100644 --- a/x/vm/statedb/statedb_test.go +++ b/x/vm/statedb/statedb_test.go @@ -25,7 +25,7 @@ var ( address2 common.Address = common.BigToAddress(big.NewInt(102)) address3 common.Address = common.BigToAddress(big.NewInt(103)) blockHash common.Hash = common.BigToHash(big.NewInt(9999)) - emptyTxConfig statedb.TxConfig = statedb.NewEmptyTxConfig(blockHash) + emptyTxConfig statedb.TxConfig = statedb.NewEmptyTxConfig() ) type StateDBTestSuite struct { @@ -587,7 +587,6 @@ func (suite *StateDBTestSuite) TestLog() { txHash := common.BytesToHash([]byte("tx")) // use a non-default tx config txConfig := statedb.NewTxConfig( - blockHash, txHash, 1, 1, ) @@ -601,16 +600,17 @@ func (suite *StateDBTestSuite) TestLog() { }) suite.Require().Equal(1, len(db.Logs())) expecedLog := ðtypes.Log{ - Address: address, - Topics: []common.Hash{}, - Data: data, - BlockNumber: 1, - BlockHash: blockHash, - TxHash: txHash, - TxIndex: 1, - Index: 1, + Address: address, + Topics: []common.Hash{}, + Data: data, + BlockNumber: 1, + BlockHash: blockHash, + BlockTimestamp: 1, + TxHash: txHash, + TxIndex: 1, + Index: 1, } - suite.Require().Equal(expecedLog, db.Logs()[0]) + suite.Require().Equal(expecedLog, db.GetLogs(1, blockHash, 1)[0]) db.AddLog(ðtypes.Log{ Address: address, @@ -620,7 +620,7 @@ func (suite *StateDBTestSuite) TestLog() { }) suite.Require().Equal(2, len(db.Logs())) expecedLog.Index++ - suite.Require().Equal(expecedLog, db.Logs()[1]) + suite.Require().Equal(expecedLog, db.GetLogs(1, blockHash, 1)[1]) } func (suite *StateDBTestSuite) TestRefund() { diff --git a/x/vm/types/evm.pb.go b/x/vm/types/evm.pb.go index 3d8430bf40..e472085c95 100644 --- a/x/vm/types/evm.pb.go +++ b/x/vm/types/evm.pb.go @@ -529,6 +529,8 @@ type Log struct { // reorganisation. You must pay attention to this field if you receive logs // through a filter query. Removed bool `protobuf:"varint,9,opt,name=removed,proto3" json:"removed,omitempty"` + // block_timestamp is the timestamp of the block in which the transaction was + BlockTimestamp uint64 `protobuf:"varint,10,opt,name=block_timestamp,json=blockTimestamp,proto3" json:"blockTimestamp"` } func (m *Log) Reset() { *m = Log{} } @@ -627,6 +629,13 @@ func (m *Log) GetRemoved() bool { return false } +func (m *Log) GetBlockTimestamp() uint64 { + if m != nil { + return m.BlockTimestamp + } + return 0 +} + // TxResult stores results of Tx execution. type TxResult struct { // contract_address contains the ethereum address of the created contract (if @@ -940,132 +949,133 @@ func init() { func init() { proto.RegisterFile("cosmos/evm/vm/v1/evm.proto", fileDescriptor_d1129b8db63d55c7) } var fileDescriptor_d1129b8db63d55c7 = []byte{ - // 1988 bytes of a gzipped FileDescriptorProto + // 2007 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0x4d, 0x6f, 0x1b, 0xc7, 0x19, 0x16, 0xc5, 0x95, 0xb4, 0x1c, 0x52, 0xd2, 0x7a, 0x44, 0xcb, 0x34, 0xed, 0x68, 0xd5, 0x6d, 0x0f, 0xaa, 0x91, 0x4a, 0x96, 0x1c, 0xb5, 0x86, 0xd3, 0x0f, 0x88, 0x32, 0xd3, 0x4a, 0xb5, 0x1d, 0x61, 0xa8, 0xc6, 0x48, 0xd1, 0x62, 0x31, 0xdc, 0x1d, 0x2f, 0x37, 0xda, 0xdd, 0x21, 0x66, 0x96, - 0xb4, 0xd8, 0x5f, 0x10, 0xf8, 0x94, 0xfe, 0x00, 0x03, 0x01, 0x7a, 0xc9, 0x31, 0x87, 0xfe, 0x80, - 0x1e, 0x83, 0x9e, 0x72, 0x2c, 0x0a, 0x74, 0x51, 0xd0, 0x87, 0x00, 0x3a, 0xea, 0x17, 0x14, 0xf3, - 0xc1, 0x4f, 0x29, 0xac, 0x02, 0x08, 0xf6, 0x3c, 0xef, 0xc7, 0xf3, 0xcc, 0xc7, 0xbb, 0x3b, 0xef, - 0x12, 0x54, 0x3d, 0xca, 0x63, 0xca, 0x77, 0x48, 0x37, 0xde, 0x11, 0x7f, 0xbb, 0x62, 0xb4, 0xdd, - 0x66, 0x34, 0xa5, 0xd0, 0x52, 0xbe, 0x6d, 0x61, 0x11, 0x7f, 0xbb, 0xd5, 0x5b, 0x38, 0x0e, 0x13, - 0xba, 0x23, 0xff, 0x55, 0x41, 0xd5, 0x72, 0x40, 0x03, 0x2a, 0x87, 0x3b, 0x62, 0xa4, 0xac, 0xce, - 0xdf, 0xf3, 0x60, 0xf1, 0x04, 0x33, 0x1c, 0x73, 0xb8, 0x0b, 0x0a, 0xa4, 0x1b, 0xbb, 0x3e, 0x49, - 0x68, 0x5c, 0xc9, 0x6d, 0xe6, 0xb6, 0x0a, 0xb5, 0xf2, 0x65, 0x66, 0x5b, 0x3d, 0x1c, 0x47, 0x4f, - 0x9c, 0xa1, 0xcb, 0x41, 0x26, 0xe9, 0xc6, 0x4f, 0xc5, 0x10, 0x1e, 0x00, 0x40, 0xce, 0x53, 0x86, - 0x5d, 0x12, 0xb6, 0x79, 0xc5, 0xd8, 0xcc, 0x6f, 0xe5, 0x6b, 0x4e, 0x3f, 0xb3, 0x0b, 0x75, 0x61, - 0xad, 0x1f, 0x9d, 0xf0, 0xcb, 0xcc, 0xbe, 0xa5, 0x09, 0x86, 0x81, 0x0e, 0x2a, 0x48, 0x50, 0x0f, - 0xdb, 0x1c, 0xee, 0x81, 0x92, 0xa0, 0xf6, 0x5a, 0x38, 0x49, 0x48, 0xc4, 0x2b, 0x4b, 0x9b, 0xf9, - 0xad, 0x42, 0x6d, 0xb5, 0x9f, 0xd9, 0xc5, 0xfa, 0x27, 0xcf, 0x0f, 0xb5, 0x19, 0x15, 0x49, 0x37, - 0x1e, 0x00, 0xf8, 0x67, 0xb0, 0x82, 0x3d, 0x8f, 0x70, 0xee, 0x7a, 0x34, 0x49, 0x19, 0x8d, 0x2a, - 0xe6, 0x66, 0x6e, 0xab, 0xb8, 0x67, 0x6f, 0x4f, 0x6f, 0xc4, 0xf6, 0x81, 0x8c, 0x3b, 0x54, 0x61, - 0xb5, 0xdb, 0xdf, 0x64, 0xf6, 0x5c, 0x3f, 0xb3, 0x97, 0x27, 0xcc, 0x68, 0x19, 0x8f, 0x43, 0xf8, - 0x04, 0xdc, 0xc5, 0x5e, 0x1a, 0x76, 0x89, 0xcb, 0x53, 0x9c, 0x86, 0x9e, 0xdb, 0x66, 0xc4, 0xa3, - 0x71, 0x3b, 0x8c, 0x08, 0xaf, 0x14, 0xc4, 0xfc, 0xd0, 0x1d, 0x15, 0xd0, 0x90, 0xfe, 0x93, 0x91, - 0x1b, 0x3e, 0x04, 0xe5, 0x56, 0xc8, 0x53, 0xca, 0x7a, 0x2e, 0x27, 0xac, 0x4b, 0xdc, 0xd7, 0x61, - 0xe2, 0xd3, 0xd7, 0x15, 0xb0, 0x99, 0xdb, 0x32, 0x10, 0xd4, 0xbe, 0x86, 0x70, 0xbd, 0x94, 0x9e, - 0x27, 0xf7, 0xde, 0x7c, 0xf7, 0xf5, 0x83, 0xf5, 0xb1, 0xd3, 0x3d, 0x17, 0xe7, 0xab, 0xce, 0xe4, - 0xd8, 0x30, 0xe7, 0xad, 0xfc, 0xb1, 0x61, 0xe6, 0x2d, 0xe3, 0xd8, 0x30, 0x17, 0xac, 0xc5, 0x63, - 0xc3, 0x5c, 0xb4, 0x96, 0x9c, 0xbf, 0xe6, 0xc0, 0xe4, 0x1a, 0xe0, 0x01, 0x58, 0xf4, 0x18, 0xc1, - 0x29, 0x91, 0x47, 0x57, 0xdc, 0xfb, 0xf1, 0xff, 0xd9, 0x8b, 0xd3, 0x5e, 0x9b, 0xd4, 0x0c, 0xb1, - 0x1f, 0x48, 0x27, 0xc2, 0x5f, 0x01, 0xc3, 0xc3, 0x51, 0x54, 0x99, 0xff, 0xa1, 0x04, 0x32, 0xcd, - 0xf9, 0x4f, 0x0e, 0xdc, 0xba, 0x12, 0x01, 0x3d, 0x50, 0xd4, 0x67, 0x95, 0xf6, 0xda, 0x6a, 0x72, - 0x2b, 0x7b, 0xf7, 0xbf, 0x8f, 0x5b, 0x92, 0xfe, 0xa4, 0x9f, 0xd9, 0x60, 0x84, 0x2f, 0x33, 0x1b, - 0xaa, 0x12, 0x1a, 0x23, 0x72, 0x10, 0xc0, 0xc3, 0x08, 0xe8, 0x81, 0xb5, 0xc9, 0x82, 0x70, 0xa3, - 0x90, 0xa7, 0x95, 0x79, 0x59, 0x4b, 0x8f, 0xfa, 0x99, 0x3d, 0x39, 0xb1, 0x67, 0x21, 0x4f, 0x2f, - 0x33, 0xbb, 0x3a, 0xc1, 0x3a, 0x9e, 0xe9, 0xa0, 0x5b, 0x78, 0x3a, 0xc1, 0xf9, 0xca, 0x02, 0xc5, - 0xc3, 0x16, 0x0e, 0x93, 0x43, 0x9a, 0xbc, 0x0a, 0x03, 0xf8, 0x27, 0xb0, 0xda, 0xa2, 0x31, 0xe1, - 0x29, 0xc1, 0xbe, 0xdb, 0x8c, 0xa8, 0x77, 0xa6, 0x9f, 0x9a, 0x47, 0xff, 0xce, 0xec, 0xdb, 0x6a, - 0x81, 0xdc, 0x3f, 0xdb, 0x0e, 0xe9, 0x4e, 0x8c, 0xd3, 0xd6, 0xf6, 0x51, 0x22, 0x44, 0xd7, 0x95, - 0xe8, 0x54, 0xa6, 0x83, 0x56, 0x86, 0x96, 0x9a, 0x30, 0xc0, 0x16, 0x58, 0xf1, 0x31, 0x75, 0x5f, - 0x51, 0x76, 0xa6, 0xc9, 0xe7, 0x25, 0x79, 0xed, 0x7b, 0xc9, 0xfb, 0x99, 0x5d, 0x7a, 0x7a, 0xf0, - 0xf1, 0x47, 0x94, 0x9d, 0x49, 0x8a, 0xcb, 0xcc, 0xbe, 0xad, 0xc4, 0x26, 0x89, 0x1c, 0x54, 0xf2, - 0x31, 0x1d, 0x86, 0xc1, 0x97, 0xc0, 0x1a, 0x06, 0xf0, 0x4e, 0xbb, 0x4d, 0x59, 0x5a, 0xc9, 0x6f, - 0xe6, 0xb6, 0xcc, 0xda, 0xcf, 0xfa, 0x99, 0xbd, 0xa2, 0x29, 0x1b, 0xca, 0x73, 0x99, 0xd9, 0x77, - 0xa6, 0x48, 0x75, 0x8e, 0x83, 0x56, 0x34, 0xad, 0x0e, 0x85, 0x4d, 0x50, 0x22, 0x61, 0x7b, 0x77, - 0xff, 0xa1, 0x5e, 0x80, 0x21, 0x17, 0xf0, 0x9b, 0x59, 0x0b, 0x28, 0xd6, 0x8f, 0x4e, 0x76, 0xf7, - 0x1f, 0x0e, 0xe6, 0xbf, 0xa6, 0x5f, 0x1d, 0x63, 0x2c, 0x0e, 0x2a, 0x2a, 0xa8, 0x26, 0x3f, 0xd0, - 0xd8, 0xd7, 0x1a, 0x8b, 0x37, 0xd5, 0xd8, 0xbf, 0x4e, 0x63, 0x7f, 0x52, 0x63, 0x7f, 0x52, 0xe3, - 0xb1, 0xd6, 0x58, 0xba, 0xa9, 0xc6, 0xe3, 0xeb, 0x34, 0x1e, 0x4f, 0x6a, 0xa8, 0x18, 0x51, 0x4c, - 0xcd, 0xde, 0x5f, 0x70, 0x92, 0x86, 0x9d, 0x58, 0xcb, 0x98, 0x37, 0x2e, 0xa6, 0xa9, 0x4c, 0x07, - 0xad, 0x0c, 0x2d, 0x8a, 0xfd, 0x0c, 0x94, 0x3d, 0x9a, 0xf0, 0x54, 0xd8, 0x12, 0xda, 0x8e, 0x88, - 0x96, 0x28, 0x48, 0x89, 0xc7, 0xb3, 0x24, 0xee, 0x29, 0x89, 0xeb, 0xd2, 0x1d, 0xb4, 0x36, 0x69, - 0x56, 0x62, 0x2e, 0xb0, 0xda, 0x24, 0x25, 0x8c, 0x37, 0x3b, 0x2c, 0xd0, 0x42, 0x40, 0x0a, 0x7d, - 0x30, 0x4b, 0x48, 0x97, 0xd5, 0x74, 0xaa, 0x83, 0x56, 0x47, 0x26, 0x25, 0xf0, 0x29, 0x58, 0x09, - 0x85, 0x6a, 0xb3, 0x13, 0x69, 0xfa, 0xa2, 0xa4, 0xdf, 0x9b, 0x45, 0xaf, 0x1f, 0x85, 0xc9, 0x44, - 0x07, 0x2d, 0x0f, 0x0c, 0x8a, 0xda, 0x07, 0x30, 0xee, 0x84, 0xcc, 0x0d, 0x22, 0xec, 0x85, 0x84, - 0x69, 0xfa, 0x92, 0xa4, 0xff, 0xf9, 0x2c, 0xfa, 0xbb, 0x8a, 0xfe, 0x6a, 0xb2, 0x83, 0x2c, 0x61, - 0xfc, 0xad, 0xb2, 0x29, 0x95, 0x06, 0x28, 0x35, 0x09, 0x8b, 0xc2, 0x44, 0xf3, 0x2f, 0x4b, 0xfe, - 0x87, 0xb3, 0xf8, 0x75, 0x05, 0x8d, 0xa7, 0x39, 0xa8, 0xa8, 0xe0, 0x90, 0x34, 0xa2, 0x89, 0x4f, - 0x07, 0xa4, 0xb7, 0x6e, 0x4c, 0x3a, 0x9e, 0xe6, 0xa0, 0xa2, 0x82, 0x8a, 0x34, 0x00, 0x6b, 0x98, - 0x31, 0xfa, 0x7a, 0x6a, 0x43, 0xa0, 0xe4, 0xfe, 0xc5, 0x2c, 0xee, 0xc1, 0xcb, 0xf5, 0x6a, 0xb6, - 0x78, 0xb9, 0x0a, 0xeb, 0xc4, 0x96, 0xf8, 0x00, 0x06, 0x0c, 0xf7, 0xa6, 0x74, 0xca, 0x37, 0xde, - 0xf8, 0xab, 0xc9, 0x0e, 0xb2, 0x84, 0x71, 0x42, 0xe5, 0x33, 0x50, 0x8e, 0x09, 0x0b, 0x88, 0x9b, - 0x90, 0x94, 0xb7, 0xa3, 0x30, 0xd5, 0x3a, 0xb7, 0x6f, 0xfc, 0x1c, 0x5c, 0x97, 0xee, 0x20, 0x28, - 0xcd, 0x2f, 0xb4, 0x55, 0x69, 0xdd, 0x05, 0xa6, 0x27, 0x6e, 0x0b, 0x37, 0xf4, 0x2b, 0x15, 0x79, - 0xfb, 0x2f, 0x49, 0x7c, 0xe4, 0xc3, 0x32, 0x58, 0x50, 0x5d, 0xd6, 0x5d, 0xa1, 0x8b, 0x14, 0x80, - 0x55, 0x60, 0xfa, 0xc4, 0x0b, 0x63, 0x1c, 0xf1, 0x4a, 0x55, 0x26, 0x0c, 0x31, 0xfc, 0x04, 0x2c, - 0xf3, 0x16, 0x4e, 0x82, 0x16, 0x0e, 0xdd, 0x34, 0x8c, 0x49, 0xe5, 0x9e, 0x9c, 0xf1, 0xee, 0xac, - 0x19, 0x97, 0xd5, 0x8c, 0x27, 0xf2, 0x1c, 0x54, 0x1a, 0xe0, 0xd3, 0x30, 0x26, 0xf0, 0x04, 0x14, - 0x3d, 0x9c, 0x78, 0x9d, 0x44, 0xb1, 0xde, 0x97, 0xac, 0x3b, 0xb3, 0x58, 0xf5, 0x55, 0x3c, 0x96, - 0xe5, 0x20, 0xa0, 0xd0, 0x80, 0xb1, 0xcd, 0x70, 0xd0, 0x21, 0x8a, 0xf1, 0xbd, 0x1b, 0x33, 0x8e, - 0x65, 0x39, 0x08, 0x28, 0x34, 0x60, 0xec, 0x12, 0x76, 0x16, 0x69, 0xc6, 0x8d, 0x1b, 0x33, 0x8e, - 0x65, 0x39, 0x08, 0x28, 0x24, 0x19, 0x9f, 0x03, 0x40, 0x39, 0x3e, 0xc3, 0x8a, 0xd0, 0x96, 0x84, - 0xdb, 0xb3, 0x08, 0x75, 0x0b, 0x3b, 0x4a, 0x72, 0x50, 0x41, 0x02, 0x41, 0x37, 0x6c, 0xcc, 0xd6, - 0xad, 0x3b, 0xc7, 0x86, 0x79, 0xc7, 0xaa, 0x38, 0x3b, 0x60, 0x41, 0xb4, 0x86, 0x04, 0x5a, 0x20, - 0x7f, 0x46, 0x7a, 0xaa, 0x2f, 0x40, 0x62, 0x28, 0xce, 0xbe, 0x8b, 0xa3, 0x0e, 0x51, 0xd7, 0x39, - 0x52, 0xc0, 0x39, 0x01, 0xab, 0xa7, 0x0c, 0x27, 0x5c, 0xb4, 0x95, 0x34, 0x79, 0x46, 0x03, 0x0e, - 0x21, 0x30, 0x5a, 0x98, 0xb7, 0x74, 0xae, 0x1c, 0xc3, 0x9f, 0x02, 0x23, 0xa2, 0x01, 0x97, 0x8d, - 0x4d, 0x71, 0xef, 0xf6, 0xd5, 0x2e, 0xea, 0x19, 0x0d, 0x90, 0x0c, 0x71, 0xfe, 0x39, 0x0f, 0xf2, - 0xcf, 0x68, 0x00, 0x2b, 0x60, 0x09, 0xfb, 0x3e, 0x23, 0x9c, 0x6b, 0xa6, 0x01, 0x84, 0xeb, 0x60, - 0x31, 0xa5, 0xed, 0xd0, 0x53, 0x74, 0x05, 0xa4, 0x91, 0x10, 0xf6, 0x71, 0x8a, 0x65, 0x0f, 0x50, - 0x42, 0x72, 0x2c, 0xba, 0x74, 0x59, 0xea, 0x6e, 0xd2, 0x89, 0x9b, 0x84, 0xc9, 0xab, 0xdc, 0xa8, - 0xad, 0x5e, 0x64, 0x76, 0x51, 0xda, 0x5f, 0x48, 0x33, 0x1a, 0x07, 0xf0, 0x7d, 0xb0, 0x94, 0x9e, - 0xbb, 0x72, 0x0d, 0x0b, 0x72, 0x8b, 0xd7, 0x2e, 0x32, 0x7b, 0x35, 0x1d, 0x2d, 0xf3, 0x77, 0x98, - 0xb7, 0xd0, 0x62, 0x7a, 0x2e, 0xfe, 0x87, 0x3b, 0xc0, 0x4c, 0xcf, 0xdd, 0x30, 0xf1, 0xc9, 0xb9, - 0xbc, 0xc4, 0x8d, 0x5a, 0xf9, 0x22, 0xb3, 0xad, 0xb1, 0xf0, 0x23, 0xe1, 0x43, 0x4b, 0xe9, 0xb9, - 0x1c, 0xc0, 0xf7, 0x01, 0x50, 0x53, 0x92, 0x0a, 0xea, 0x4e, 0x5e, 0xbe, 0xc8, 0xec, 0x82, 0xb4, - 0x4a, 0xee, 0xd1, 0x10, 0x3a, 0x60, 0x41, 0x71, 0x9b, 0x92, 0xbb, 0x74, 0x91, 0xd9, 0x66, 0x44, - 0x03, 0xc5, 0xa9, 0x5c, 0x62, 0xab, 0x18, 0x89, 0x69, 0x97, 0xf8, 0xf2, 0x62, 0x34, 0xd1, 0x00, - 0x3a, 0x5f, 0xcc, 0x03, 0xf3, 0xf4, 0x1c, 0x11, 0xde, 0x89, 0x52, 0xf8, 0x11, 0xb0, 0x64, 0xaf, - 0x88, 0xbd, 0xd4, 0x9d, 0xd8, 0xda, 0xda, 0xbd, 0xd1, 0x35, 0x36, 0x1d, 0xe1, 0xa0, 0xd5, 0x81, - 0xe9, 0x40, 0xef, 0x7f, 0x19, 0x2c, 0x34, 0x23, 0x4a, 0x63, 0x59, 0x09, 0x25, 0xa4, 0x00, 0x7c, - 0x29, 0x77, 0x4d, 0x9e, 0x72, 0x5e, 0xf6, 0xe1, 0x3f, 0xba, 0x7a, 0xca, 0x53, 0xa5, 0x52, 0xbb, - 0x27, 0xba, 0xf0, 0xcb, 0xcc, 0x5e, 0x51, 0xda, 0x3a, 0xdf, 0xf9, 0xea, 0xbb, 0xaf, 0x1f, 0xe4, - 0xc4, 0x06, 0xcb, 0x7a, 0xb2, 0x40, 0x9e, 0x91, 0x54, 0x9e, 0x5c, 0x09, 0x89, 0xa1, 0x78, 0xe1, - 0x30, 0xd2, 0x25, 0x2c, 0x25, 0xbe, 0x3c, 0x21, 0x13, 0x0d, 0xb1, 0x78, 0x7b, 0x05, 0x98, 0xbb, - 0x1d, 0x4e, 0x7c, 0x75, 0x1c, 0x68, 0x29, 0xc0, 0xfc, 0x0f, 0x9c, 0xf8, 0x4f, 0x8c, 0xcf, 0xbf, - 0xb4, 0xe7, 0x1c, 0x0c, 0x8a, 0xba, 0x45, 0xef, 0xb4, 0x23, 0x32, 0xa3, 0xcc, 0xf6, 0x40, 0x49, - 0x7c, 0xf3, 0xe0, 0x80, 0xb8, 0x67, 0xa4, 0xa7, 0x8b, 0x4d, 0x95, 0x8e, 0xb6, 0xff, 0x9e, 0xf4, - 0x38, 0x1a, 0x07, 0x5a, 0xe2, 0x4b, 0x03, 0x14, 0x4f, 0x19, 0xf6, 0x88, 0x6e, 0xb8, 0x45, 0xc1, - 0x0a, 0xc8, 0xb4, 0x84, 0x46, 0x42, 0x5b, 0x3c, 0x93, 0xb4, 0x93, 0xea, 0x87, 0x6a, 0x00, 0x45, - 0x06, 0x23, 0xe4, 0x9c, 0x78, 0x72, 0x2f, 0x0d, 0xa4, 0x11, 0xdc, 0x07, 0xcb, 0x7e, 0xc8, 0x71, - 0x33, 0x92, 0x9f, 0x78, 0xde, 0x99, 0x5a, 0x7e, 0xcd, 0xba, 0xc8, 0xec, 0x92, 0x76, 0x34, 0x84, - 0x1d, 0x4d, 0x20, 0xf8, 0x21, 0x58, 0x1d, 0xa5, 0xc9, 0xd9, 0xca, 0xbd, 0x31, 0x6b, 0xf0, 0x22, - 0xb3, 0x57, 0x86, 0xa1, 0xd2, 0x83, 0xa6, 0xb0, 0x7a, 0xe9, 0x37, 0x3b, 0x81, 0xac, 0x40, 0x13, - 0x29, 0x20, 0xac, 0x51, 0x18, 0x87, 0xa9, 0xac, 0xb8, 0x05, 0xa4, 0x00, 0xfc, 0x10, 0x14, 0x68, - 0x97, 0x30, 0x16, 0xfa, 0x84, 0xcb, 0xde, 0xa9, 0xb8, 0xf7, 0xde, 0xd5, 0x32, 0x18, 0xfb, 0x18, - 0x41, 0xa3, 0x78, 0xb1, 0x38, 0x92, 0xc8, 0x49, 0xc6, 0x24, 0xa6, 0xac, 0x27, 0xbb, 0x23, 0xbd, - 0x38, 0xe5, 0x78, 0x2e, 0xed, 0x68, 0x02, 0xc1, 0x1a, 0x80, 0x3a, 0x8d, 0x91, 0xb4, 0xc3, 0x12, - 0x57, 0xbe, 0x04, 0x4a, 0x32, 0x57, 0x3e, 0x8a, 0xca, 0x8b, 0xa4, 0xf3, 0x29, 0x4e, 0x31, 0xba, - 0x62, 0x81, 0xbf, 0x06, 0x50, 0x9d, 0x89, 0xfb, 0x19, 0xa7, 0x89, 0xf8, 0xa4, 0x7a, 0x15, 0x06, - 0xba, 0xbd, 0x91, 0xfa, 0xca, 0xab, 0xe7, 0x6c, 0x29, 0x74, 0xcc, 0xa9, 0x5e, 0xc5, 0xb1, 0x61, - 0x1a, 0xd6, 0xc2, 0xb1, 0x61, 0x2e, 0x59, 0xe6, 0x70, 0xff, 0xf4, 0x2a, 0xd0, 0xda, 0x00, 0x8f, - 0x4d, 0xcf, 0x79, 0x01, 0xc0, 0x09, 0x23, 0xa1, 0x68, 0x42, 0xa3, 0x48, 0xbc, 0xb9, 0x12, 0x1c, - 0x93, 0xc1, 0x2b, 0x53, 0x8c, 0xc7, 0x0b, 0x73, 0x7e, 0xb2, 0x30, 0x21, 0x30, 0x3c, 0xea, 0x13, - 0x59, 0x1a, 0x05, 0x24, 0xc7, 0x0f, 0xfe, 0x91, 0x03, 0x63, 0x5f, 0x9e, 0xf0, 0x97, 0xa0, 0x7a, - 0x70, 0x78, 0x58, 0x6f, 0x34, 0xdc, 0xd3, 0x4f, 0x4f, 0xea, 0xee, 0x49, 0x1d, 0x3d, 0x3f, 0x6a, - 0x34, 0x8e, 0x3e, 0x7e, 0xf1, 0xac, 0xde, 0x68, 0x58, 0x73, 0xd5, 0xfb, 0x6f, 0xde, 0x6e, 0x56, - 0x46, 0xf1, 0x27, 0x84, 0xc5, 0x21, 0xe7, 0x21, 0x4d, 0x22, 0x21, 0xf0, 0x01, 0x58, 0x1f, 0xcf, - 0x46, 0xf5, 0xc6, 0x29, 0x3a, 0x3a, 0x3c, 0xad, 0x3f, 0xb5, 0x72, 0xd5, 0xca, 0x9b, 0xb7, 0x9b, - 0xe5, 0x51, 0x26, 0x22, 0x3c, 0x65, 0xa1, 0x27, 0x9e, 0xbc, 0xc7, 0xa0, 0x72, 0xbd, 0x66, 0xfd, - 0xa9, 0x35, 0x5f, 0xad, 0xbe, 0x79, 0xbb, 0xb9, 0x7e, 0x9d, 0x22, 0xf1, 0xab, 0xc6, 0xe7, 0x7f, - 0xdb, 0x98, 0xab, 0x3d, 0xf9, 0xa6, 0xbf, 0x91, 0xfb, 0xb6, 0xbf, 0x91, 0xfb, 0x6f, 0x7f, 0x23, - 0xf7, 0xc5, 0xbb, 0x8d, 0xb9, 0x6f, 0xdf, 0x6d, 0xcc, 0xfd, 0xeb, 0xdd, 0xc6, 0xdc, 0x1f, 0x37, - 0x83, 0x30, 0x6d, 0x75, 0x9a, 0xdb, 0x1e, 0x8d, 0x77, 0xa6, 0x7f, 0x6f, 0x10, 0xdf, 0xd4, 0xbc, - 0xb9, 0x28, 0x7f, 0x14, 0x7a, 0xf4, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe4, 0x51, 0x6f, 0x71, - 0x6d, 0x12, 0x00, 0x00, + 0xb4, 0xd8, 0x3f, 0xd0, 0xc0, 0xa7, 0xf4, 0x07, 0x18, 0x08, 0xd0, 0x4b, 0x8e, 0x39, 0xf4, 0x07, + 0xf4, 0x98, 0x63, 0x8e, 0x45, 0x81, 0x2e, 0x0a, 0xfa, 0x10, 0x40, 0x47, 0xfd, 0x82, 0x62, 0x3e, + 0xf8, 0x29, 0x85, 0x55, 0x00, 0xc1, 0x9e, 0xe7, 0xfd, 0x78, 0x9e, 0xf9, 0x78, 0x77, 0xe7, 0x5d, + 0x82, 0xaa, 0x47, 0x79, 0x4c, 0xf9, 0x0e, 0xe9, 0xc6, 0x3b, 0xe2, 0x6f, 0x57, 0x8c, 0xb6, 0xdb, + 0x8c, 0xa6, 0x14, 0x5a, 0xca, 0xb7, 0x2d, 0x2c, 0xe2, 0x6f, 0xb7, 0x7a, 0x0b, 0xc7, 0x61, 0x42, + 0x77, 0xe4, 0xbf, 0x2a, 0xa8, 0x5a, 0x0e, 0x68, 0x40, 0xe5, 0x70, 0x47, 0x8c, 0x94, 0xd5, 0xf9, + 0x47, 0x1e, 0x2c, 0x9e, 0x60, 0x86, 0x63, 0x0e, 0x77, 0x41, 0x81, 0x74, 0x63, 0xd7, 0x27, 0x09, + 0x8d, 0x2b, 0xb9, 0xcd, 0xdc, 0x56, 0xa1, 0x56, 0xbe, 0xcc, 0x6c, 0xab, 0x87, 0xe3, 0xe8, 0x89, + 0x33, 0x74, 0x39, 0xc8, 0x24, 0xdd, 0xf8, 0xa9, 0x18, 0xc2, 0x03, 0x00, 0xc8, 0x79, 0xca, 0xb0, + 0x4b, 0xc2, 0x36, 0xaf, 0x18, 0x9b, 0xf9, 0xad, 0x7c, 0xcd, 0xe9, 0x67, 0x76, 0xa1, 0x2e, 0xac, + 0xf5, 0xa3, 0x13, 0x7e, 0x99, 0xd9, 0xb7, 0x34, 0xc1, 0x30, 0xd0, 0x41, 0x05, 0x09, 0xea, 0x61, + 0x9b, 0xc3, 0x3d, 0x50, 0x12, 0xd4, 0x5e, 0x0b, 0x27, 0x09, 0x89, 0x78, 0x65, 0x69, 0x33, 0xbf, + 0x55, 0xa8, 0xad, 0xf6, 0x33, 0xbb, 0x58, 0xff, 0xe4, 0xf9, 0xa1, 0x36, 0xa3, 0x22, 0xe9, 0xc6, + 0x03, 0x00, 0xff, 0x0c, 0x56, 0xb0, 0xe7, 0x11, 0xce, 0x5d, 0x8f, 0x26, 0x29, 0xa3, 0x51, 0xc5, + 0xdc, 0xcc, 0x6d, 0x15, 0xf7, 0xec, 0xed, 0xe9, 0x8d, 0xd8, 0x3e, 0x90, 0x71, 0x87, 0x2a, 0xac, + 0x76, 0xfb, 0x9b, 0xcc, 0x9e, 0xeb, 0x67, 0xf6, 0xf2, 0x84, 0x19, 0x2d, 0xe3, 0x71, 0x08, 0x9f, + 0x80, 0xbb, 0xd8, 0x4b, 0xc3, 0x2e, 0x71, 0x79, 0x8a, 0xd3, 0xd0, 0x73, 0xdb, 0x8c, 0x78, 0x34, + 0x6e, 0x87, 0x11, 0xe1, 0x95, 0x82, 0x98, 0x1f, 0xba, 0xa3, 0x02, 0x1a, 0xd2, 0x7f, 0x32, 0x72, + 0xc3, 0x87, 0xa0, 0xdc, 0x0a, 0x79, 0x4a, 0x59, 0xcf, 0xe5, 0x84, 0x75, 0x89, 0xfb, 0x3a, 0x4c, + 0x7c, 0xfa, 0xba, 0x02, 0x36, 0x73, 0x5b, 0x06, 0x82, 0xda, 0xd7, 0x10, 0xae, 0x97, 0xd2, 0xf3, + 0xe4, 0xde, 0x9b, 0xef, 0xbe, 0x7e, 0xb0, 0x3e, 0x76, 0xba, 0xe7, 0xe2, 0x7c, 0xd5, 0x99, 0x1c, + 0x1b, 0xe6, 0xbc, 0x95, 0x3f, 0x36, 0xcc, 0xbc, 0x65, 0x1c, 0x1b, 0xe6, 0x82, 0xb5, 0x78, 0x6c, + 0x98, 0x8b, 0xd6, 0x92, 0xf3, 0xb7, 0x1c, 0x98, 0x5c, 0x03, 0x3c, 0x00, 0x8b, 0x1e, 0x23, 0x38, + 0x25, 0xf2, 0xe8, 0x8a, 0x7b, 0x3f, 0xfe, 0x3f, 0x7b, 0x71, 0xda, 0x6b, 0x93, 0x9a, 0x21, 0xf6, + 0x03, 0xe9, 0x44, 0xf8, 0x2b, 0x60, 0x78, 0x38, 0x8a, 0x2a, 0xf3, 0x3f, 0x94, 0x40, 0xa6, 0x39, + 0xff, 0xc9, 0x81, 0x5b, 0x57, 0x22, 0xa0, 0x07, 0x8a, 0xfa, 0xac, 0xd2, 0x5e, 0x5b, 0x4d, 0x6e, + 0x65, 0xef, 0xfe, 0xf7, 0x71, 0x4b, 0xd2, 0x9f, 0xf4, 0x33, 0x1b, 0x8c, 0xf0, 0x65, 0x66, 0x43, + 0x55, 0x42, 0x63, 0x44, 0x0e, 0x02, 0x78, 0x18, 0x01, 0x3d, 0xb0, 0x36, 0x59, 0x10, 0x6e, 0x14, + 0xf2, 0xb4, 0x32, 0x2f, 0x6b, 0xe9, 0x51, 0x3f, 0xb3, 0x27, 0x27, 0xf6, 0x2c, 0xe4, 0xe9, 0x65, + 0x66, 0x57, 0x27, 0x58, 0xc7, 0x33, 0x1d, 0x74, 0x0b, 0x4f, 0x27, 0x38, 0x5f, 0x59, 0xa0, 0x78, + 0xd8, 0xc2, 0x61, 0x72, 0x48, 0x93, 0x57, 0x61, 0x00, 0xff, 0x04, 0x56, 0x5b, 0x34, 0x26, 0x3c, + 0x25, 0xd8, 0x77, 0x9b, 0x11, 0xf5, 0xce, 0xf4, 0x53, 0xf3, 0xe8, 0xdf, 0x99, 0x7d, 0x5b, 0x2d, + 0x90, 0xfb, 0x67, 0xdb, 0x21, 0xdd, 0x89, 0x71, 0xda, 0xda, 0x3e, 0x4a, 0x84, 0xe8, 0xba, 0x12, + 0x9d, 0xca, 0x74, 0xd0, 0xca, 0xd0, 0x52, 0x13, 0x06, 0xd8, 0x02, 0x2b, 0x3e, 0xa6, 0xee, 0x2b, + 0xca, 0xce, 0x34, 0xf9, 0xbc, 0x24, 0xaf, 0x7d, 0x2f, 0x79, 0x3f, 0xb3, 0x4b, 0x4f, 0x0f, 0x3e, + 0xfe, 0x88, 0xb2, 0x33, 0x49, 0x71, 0x99, 0xd9, 0xb7, 0x95, 0xd8, 0x24, 0x91, 0x83, 0x4a, 0x3e, + 0xa6, 0xc3, 0x30, 0xf8, 0x12, 0x58, 0xc3, 0x00, 0xde, 0x69, 0xb7, 0x29, 0x4b, 0x2b, 0xf9, 0xcd, + 0xdc, 0x96, 0x59, 0xfb, 0x59, 0x3f, 0xb3, 0x57, 0x34, 0x65, 0x43, 0x79, 0x2e, 0x33, 0xfb, 0xce, + 0x14, 0xa9, 0xce, 0x71, 0xd0, 0x8a, 0xa6, 0xd5, 0xa1, 0xb0, 0x09, 0x4a, 0x24, 0x6c, 0xef, 0xee, + 0x3f, 0xd4, 0x0b, 0x30, 0xe4, 0x02, 0x7e, 0x33, 0x6b, 0x01, 0xc5, 0xfa, 0xd1, 0xc9, 0xee, 0xfe, + 0xc3, 0xc1, 0xfc, 0xd7, 0xf4, 0xab, 0x63, 0x8c, 0xc5, 0x41, 0x45, 0x05, 0xd5, 0xe4, 0x07, 0x1a, + 0xfb, 0x5a, 0x63, 0xf1, 0xa6, 0x1a, 0xfb, 0xd7, 0x69, 0xec, 0x4f, 0x6a, 0xec, 0x4f, 0x6a, 0x3c, + 0xd6, 0x1a, 0x4b, 0x37, 0xd5, 0x78, 0x7c, 0x9d, 0xc6, 0xe3, 0x49, 0x0d, 0x15, 0x23, 0x8a, 0xa9, + 0xd9, 0xfb, 0x0b, 0x4e, 0xd2, 0xb0, 0x13, 0x6b, 0x19, 0xf3, 0xc6, 0xc5, 0x34, 0x95, 0xe9, 0xa0, + 0x95, 0xa1, 0x45, 0xb1, 0x9f, 0x81, 0xb2, 0x47, 0x13, 0x9e, 0x0a, 0x5b, 0x42, 0xdb, 0x11, 0xd1, + 0x12, 0x05, 0x29, 0xf1, 0x78, 0x96, 0xc4, 0x3d, 0x25, 0x71, 0x5d, 0xba, 0x83, 0xd6, 0x26, 0xcd, + 0x4a, 0xcc, 0x05, 0x56, 0x9b, 0xa4, 0x84, 0xf1, 0x66, 0x87, 0x05, 0x5a, 0x08, 0x48, 0xa1, 0x0f, + 0x66, 0x09, 0xe9, 0xb2, 0x9a, 0x4e, 0x75, 0xd0, 0xea, 0xc8, 0xa4, 0x04, 0x3e, 0x05, 0x2b, 0xa1, + 0x50, 0x6d, 0x76, 0x22, 0x4d, 0x5f, 0x94, 0xf4, 0x7b, 0xb3, 0xe8, 0xf5, 0xa3, 0x30, 0x99, 0xe8, + 0xa0, 0xe5, 0x81, 0x41, 0x51, 0xfb, 0x00, 0xc6, 0x9d, 0x90, 0xb9, 0x41, 0x84, 0xbd, 0x90, 0x30, + 0x4d, 0x5f, 0x92, 0xf4, 0x3f, 0x9f, 0x45, 0x7f, 0x57, 0xd1, 0x5f, 0x4d, 0x76, 0x90, 0x25, 0x8c, + 0xbf, 0x55, 0x36, 0xa5, 0xd2, 0x00, 0xa5, 0x26, 0x61, 0x51, 0x98, 0x68, 0xfe, 0x65, 0xc9, 0xff, + 0x70, 0x16, 0xbf, 0xae, 0xa0, 0xf1, 0x34, 0x07, 0x15, 0x15, 0x1c, 0x92, 0x46, 0x34, 0xf1, 0xe9, + 0x80, 0xf4, 0xd6, 0x8d, 0x49, 0xc7, 0xd3, 0x1c, 0x54, 0x54, 0x50, 0x91, 0x06, 0x60, 0x0d, 0x33, + 0x46, 0x5f, 0x4f, 0x6d, 0x08, 0x94, 0xdc, 0xbf, 0x98, 0xc5, 0x3d, 0x78, 0xb9, 0x5e, 0xcd, 0x16, + 0x2f, 0x57, 0x61, 0x9d, 0xd8, 0x12, 0x1f, 0xc0, 0x80, 0xe1, 0xde, 0x94, 0x4e, 0xf9, 0xc6, 0x1b, + 0x7f, 0x35, 0xd9, 0x41, 0x96, 0x30, 0x4e, 0xa8, 0x7c, 0x06, 0xca, 0x31, 0x61, 0x01, 0x71, 0x13, + 0x92, 0xf2, 0x76, 0x14, 0xa6, 0x5a, 0xe7, 0xf6, 0x8d, 0x9f, 0x83, 0xeb, 0xd2, 0x1d, 0x04, 0xa5, + 0xf9, 0x85, 0xb6, 0x2a, 0xad, 0xbb, 0xc0, 0xf4, 0xc4, 0x6d, 0xe1, 0x86, 0x7e, 0xa5, 0x22, 0x6f, + 0xff, 0x25, 0x89, 0x8f, 0x7c, 0x58, 0x06, 0x0b, 0xaa, 0xcb, 0xba, 0x2b, 0x74, 0x91, 0x02, 0xb0, + 0x0a, 0x4c, 0x9f, 0x78, 0x61, 0x8c, 0x23, 0x5e, 0xa9, 0xca, 0x84, 0x21, 0x86, 0x9f, 0x80, 0x65, + 0xde, 0xc2, 0x49, 0xd0, 0xc2, 0xa1, 0x9b, 0x86, 0x31, 0xa9, 0xdc, 0x93, 0x33, 0xde, 0x9d, 0x35, + 0xe3, 0xb2, 0x9a, 0xf1, 0x44, 0x9e, 0x83, 0x4a, 0x03, 0x7c, 0x1a, 0xc6, 0x04, 0x9e, 0x80, 0xa2, + 0x87, 0x13, 0xaf, 0x93, 0x28, 0xd6, 0xfb, 0x92, 0x75, 0x67, 0x16, 0xab, 0xbe, 0x8a, 0xc7, 0xb2, + 0x1c, 0x04, 0x14, 0x1a, 0x30, 0xb6, 0x19, 0x0e, 0x3a, 0x44, 0x31, 0xbe, 0x77, 0x63, 0xc6, 0xb1, + 0x2c, 0x07, 0x01, 0x85, 0x06, 0x8c, 0x5d, 0xc2, 0xce, 0x22, 0xcd, 0xb8, 0x71, 0x63, 0xc6, 0xb1, + 0x2c, 0x07, 0x01, 0x85, 0x24, 0xe3, 0x73, 0x00, 0x28, 0xc7, 0x67, 0x58, 0x11, 0xda, 0x92, 0x70, + 0x7b, 0x16, 0xa1, 0x6e, 0x61, 0x47, 0x49, 0x0e, 0x2a, 0x48, 0x20, 0xe8, 0x86, 0x8d, 0xd9, 0xba, + 0x75, 0xe7, 0xd8, 0x30, 0xef, 0x58, 0x15, 0x67, 0x07, 0x2c, 0x88, 0xd6, 0x90, 0x40, 0x0b, 0xe4, + 0xcf, 0x48, 0x4f, 0xf5, 0x05, 0x48, 0x0c, 0xc5, 0xd9, 0x77, 0x71, 0xd4, 0x21, 0xea, 0x3a, 0x47, + 0x0a, 0x38, 0x27, 0x60, 0xf5, 0x94, 0xe1, 0x84, 0x8b, 0xb6, 0x92, 0x26, 0xcf, 0x68, 0xc0, 0x21, + 0x04, 0x46, 0x0b, 0xf3, 0x96, 0xce, 0x95, 0x63, 0xf8, 0x53, 0x60, 0x44, 0x34, 0xe0, 0xb2, 0xb1, + 0x29, 0xee, 0xdd, 0xbe, 0xda, 0x45, 0x3d, 0xa3, 0x01, 0x92, 0x21, 0xce, 0x5f, 0xf3, 0x20, 0xff, + 0x8c, 0x06, 0xb0, 0x02, 0x96, 0xb0, 0xef, 0x33, 0xc2, 0xb9, 0x66, 0x1a, 0x40, 0xb8, 0x0e, 0x16, + 0x53, 0xda, 0x0e, 0x3d, 0x45, 0x57, 0x40, 0x1a, 0x09, 0x61, 0x1f, 0xa7, 0x58, 0xf6, 0x00, 0x25, + 0x24, 0xc7, 0xa2, 0x4b, 0x97, 0xa5, 0xee, 0x26, 0x9d, 0xb8, 0x49, 0x98, 0xbc, 0xca, 0x8d, 0xda, + 0xea, 0x45, 0x66, 0x17, 0xa5, 0xfd, 0x85, 0x34, 0xa3, 0x71, 0x00, 0xdf, 0x07, 0x4b, 0xe9, 0xb9, + 0x2b, 0xd7, 0xb0, 0x20, 0xb7, 0x78, 0xed, 0x22, 0xb3, 0x57, 0xd3, 0xd1, 0x32, 0x7f, 0x87, 0x79, + 0x0b, 0x2d, 0xa6, 0xe7, 0xe2, 0x7f, 0xb8, 0x03, 0xcc, 0xf4, 0xdc, 0x0d, 0x13, 0x9f, 0x9c, 0xcb, + 0x4b, 0xdc, 0xa8, 0x95, 0x2f, 0x32, 0xdb, 0x1a, 0x0b, 0x3f, 0x12, 0x3e, 0xb4, 0x94, 0x9e, 0xcb, + 0x01, 0x7c, 0x1f, 0x00, 0x35, 0x25, 0xa9, 0xa0, 0xee, 0xe4, 0xe5, 0x8b, 0xcc, 0x2e, 0x48, 0xab, + 0xe4, 0x1e, 0x0d, 0xa1, 0x03, 0x16, 0x14, 0xb7, 0x29, 0xb9, 0x4b, 0x17, 0x99, 0x6d, 0x46, 0x34, + 0x50, 0x9c, 0xca, 0x25, 0xb6, 0x8a, 0x91, 0x98, 0x76, 0x89, 0x2f, 0x2f, 0x46, 0x13, 0x0d, 0x20, + 0xfc, 0x10, 0xac, 0x2a, 0x2d, 0x71, 0xf6, 0x3c, 0xc5, 0x71, 0x5b, 0x35, 0xf4, 0x35, 0x78, 0x91, + 0xd9, 0x2b, 0xd2, 0x75, 0x3a, 0xf0, 0xa0, 0x29, 0xec, 0x7c, 0x31, 0x0f, 0xcc, 0xd3, 0x73, 0x44, + 0x78, 0x27, 0x4a, 0xe1, 0x47, 0xc0, 0x92, 0x8d, 0x26, 0xf6, 0x52, 0x77, 0xe2, 0x5c, 0x6a, 0xf7, + 0x46, 0x77, 0xe0, 0x74, 0x84, 0x83, 0x56, 0x07, 0xa6, 0x03, 0x7d, 0x78, 0x65, 0xb0, 0xd0, 0x8c, + 0x28, 0x8d, 0x65, 0x19, 0x95, 0x90, 0x02, 0xf0, 0xa5, 0xdc, 0x72, 0x59, 0x22, 0x79, 0xd9, 0xc4, + 0xff, 0xe8, 0x6a, 0x89, 0x4c, 0xd5, 0x59, 0xed, 0x9e, 0x68, 0xe1, 0x2f, 0x33, 0x7b, 0x45, 0x69, + 0xeb, 0x7c, 0xe7, 0xab, 0xef, 0xbe, 0x7e, 0x90, 0x13, 0xa7, 0x23, 0x8b, 0xd1, 0x02, 0x79, 0x46, + 0x52, 0x79, 0xec, 0x25, 0x24, 0x86, 0xe2, 0x6d, 0xc5, 0x48, 0x97, 0xb0, 0x94, 0xf8, 0xf2, 0x78, + 0x4d, 0x34, 0xc4, 0xe2, 0xd5, 0x17, 0x60, 0xee, 0x76, 0x38, 0xf1, 0xd5, 0x59, 0xa2, 0xa5, 0x00, + 0xf3, 0x3f, 0x70, 0xe2, 0x3f, 0x31, 0x3e, 0xff, 0xd2, 0x9e, 0x73, 0x30, 0x28, 0xea, 0xfe, 0xbe, + 0xd3, 0x8e, 0xc8, 0x8c, 0x1a, 0xdd, 0x03, 0x25, 0xf1, 0xc1, 0x84, 0x03, 0xe2, 0x9e, 0x91, 0x9e, + 0xae, 0x54, 0x55, 0x77, 0xda, 0xfe, 0x7b, 0xd2, 0xe3, 0x68, 0x1c, 0x68, 0x89, 0x2f, 0x0d, 0x50, + 0x3c, 0x65, 0xd8, 0x23, 0xba, 0x5b, 0x17, 0xd5, 0x2e, 0x20, 0xd3, 0x12, 0x1a, 0x09, 0x6d, 0x71, + 0xa8, 0xb4, 0x93, 0xea, 0x27, 0x72, 0x00, 0x45, 0x06, 0x23, 0xe4, 0x9c, 0x78, 0x72, 0x2f, 0x0d, + 0xa4, 0x11, 0xdc, 0x07, 0xcb, 0x7e, 0xc8, 0x71, 0x33, 0x92, 0xdf, 0x87, 0xde, 0x99, 0x5a, 0x7e, + 0xcd, 0xba, 0xc8, 0xec, 0x92, 0x76, 0x34, 0x84, 0x1d, 0x4d, 0x20, 0x51, 0x43, 0xa3, 0x34, 0x39, + 0x5b, 0xb9, 0x37, 0xa6, 0xaa, 0xa1, 0x61, 0xa8, 0xf4, 0xa0, 0x29, 0xac, 0x6e, 0x8c, 0x66, 0x27, + 0x90, 0xe5, 0x6b, 0x22, 0x05, 0x84, 0x35, 0x0a, 0xe3, 0x30, 0x95, 0xe5, 0xba, 0x80, 0x14, 0x80, + 0x1f, 0x82, 0x02, 0xed, 0x12, 0xc6, 0x42, 0x9f, 0x70, 0x59, 0xa6, 0xc5, 0xbd, 0xf7, 0xae, 0x96, + 0xc1, 0xd8, 0x97, 0x0c, 0x1a, 0xc5, 0x8b, 0xc5, 0x91, 0x44, 0x4e, 0x32, 0x26, 0x31, 0x65, 0x3d, + 0xd9, 0x5a, 0xe9, 0xc5, 0x29, 0xc7, 0x73, 0x69, 0x47, 0x13, 0x08, 0xd6, 0x00, 0xd4, 0x69, 0x8c, + 0xa4, 0x1d, 0x96, 0xb8, 0xf2, 0x0d, 0x52, 0x92, 0xb9, 0xf2, 0x39, 0x56, 0x5e, 0x24, 0x9d, 0x4f, + 0x71, 0x8a, 0xd1, 0x15, 0x0b, 0xfc, 0x35, 0x80, 0xea, 0x4c, 0xdc, 0xcf, 0x38, 0x4d, 0xc4, 0xf7, + 0xd8, 0xab, 0x30, 0xd0, 0xbd, 0x91, 0xd4, 0x57, 0x5e, 0x3d, 0x67, 0x4b, 0xa1, 0x63, 0x4e, 0xf5, + 0x2a, 0x8e, 0x0d, 0xd3, 0xb0, 0x16, 0x8e, 0x0d, 0x73, 0xc9, 0x32, 0x87, 0xfb, 0xa7, 0x57, 0x81, + 0xd6, 0x06, 0x78, 0x6c, 0x7a, 0xce, 0x0b, 0x00, 0x4e, 0x18, 0x09, 0x45, 0x07, 0x1b, 0x45, 0xe2, + 0xb5, 0x97, 0xe0, 0x98, 0x0c, 0xde, 0xb7, 0x62, 0x3c, 0x5e, 0x98, 0xf3, 0x93, 0x85, 0x09, 0x81, + 0xe1, 0x51, 0x9f, 0xc8, 0xd2, 0x28, 0x20, 0x39, 0x7e, 0xf0, 0xcf, 0x1c, 0x18, 0xfb, 0x6c, 0x85, + 0xbf, 0x04, 0xd5, 0x83, 0xc3, 0xc3, 0x7a, 0xa3, 0xe1, 0x9e, 0x7e, 0x7a, 0x52, 0x77, 0x4f, 0xea, + 0xe8, 0xf9, 0x51, 0xa3, 0x71, 0xf4, 0xf1, 0x8b, 0x67, 0xf5, 0x46, 0xc3, 0x9a, 0xab, 0xde, 0x7f, + 0xf3, 0x76, 0xb3, 0x32, 0x8a, 0x3f, 0x21, 0x2c, 0x0e, 0x39, 0x0f, 0x69, 0x12, 0x09, 0x81, 0x0f, + 0xc0, 0xfa, 0x78, 0x36, 0xaa, 0x37, 0x4e, 0xd1, 0xd1, 0xe1, 0x69, 0xfd, 0xa9, 0x95, 0xab, 0x56, + 0xde, 0xbc, 0xdd, 0x2c, 0x8f, 0x32, 0x11, 0xe1, 0x29, 0x0b, 0x3d, 0xf1, 0xe4, 0x3d, 0x06, 0x95, + 0xeb, 0x35, 0xeb, 0x4f, 0xad, 0xf9, 0x6a, 0xf5, 0xcd, 0xdb, 0xcd, 0xf5, 0xeb, 0x14, 0x89, 0x5f, + 0x35, 0x3e, 0xff, 0xfb, 0xc6, 0x5c, 0xed, 0xc9, 0x37, 0xfd, 0x8d, 0xdc, 0xb7, 0xfd, 0x8d, 0xdc, + 0x7f, 0xfb, 0x1b, 0xb9, 0x2f, 0xde, 0x6d, 0xcc, 0x7d, 0xfb, 0x6e, 0x63, 0xee, 0x5f, 0xef, 0x36, + 0xe6, 0xfe, 0xb8, 0x19, 0x84, 0x69, 0xab, 0xd3, 0xdc, 0xf6, 0x68, 0xbc, 0x33, 0xfd, 0x63, 0x85, + 0xf8, 0x20, 0xe7, 0xcd, 0x45, 0xf9, 0x8b, 0xd2, 0xa3, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0xc6, + 0x17, 0xe6, 0x54, 0xaa, 0x12, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -1645,6 +1655,11 @@ func (m *Log) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.BlockTimestamp != 0 { + i = encodeVarintEvm(dAtA, i, uint64(m.BlockTimestamp)) + i-- + dAtA[i] = 0x50 + } if m.Removed { i-- if m.Removed { @@ -2235,6 +2250,9 @@ func (m *Log) Size() (n int) { if m.Removed { n += 2 } + if m.BlockTimestamp != 0 { + n += 1 + sovEvm(uint64(m.BlockTimestamp)) + } return n } @@ -4208,6 +4226,25 @@ func (m *Log) Unmarshal(dAtA []byte) error { } } m.Removed = bool(v != 0) + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockTimestamp", wireType) + } + m.BlockTimestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockTimestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipEvm(dAtA[iNdEx:]) diff --git a/x/vm/types/logs.go b/x/vm/types/logs.go index 85f029ca6e..5409a20976 100644 --- a/x/vm/types/logs.go +++ b/x/vm/types/logs.go @@ -114,14 +114,15 @@ func NewLogFromEth(log *ethtypes.Log) *Log { } return &Log{ - Address: log.Address.String(), - Topics: topics, - Data: log.Data, - BlockNumber: log.BlockNumber, - TxHash: log.TxHash.String(), - TxIndex: uint64(log.TxIndex), - Index: uint64(log.Index), - BlockHash: log.BlockHash.String(), - Removed: log.Removed, + Address: log.Address.String(), + Topics: topics, + Data: log.Data, + BlockNumber: log.BlockNumber, + BlockHash: log.BlockHash.String(), + BlockTimestamp: log.BlockTimestamp, + TxHash: log.TxHash.String(), + TxIndex: uint64(log.TxIndex), + Index: uint64(log.Index), + Removed: log.Removed, } } From bd607f756275e7ea26cd1b90ed9dbad3610db61e Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 3 Sep 2025 02:14:21 +0800 Subject: [PATCH 38/61] feat: avoid unnecessary block notifications when the event bus is already set up (#568) * chore: remove NotifyNewBlock in EndBlocker this change should have been included in https://github.com/cosmos/evm/commit/642c8e989405b8604b61001c61cfaa6928a35ec1 * fix test * ensures block notify only triggered for legacy or non-event bus * fix reorg on restart cleanup --------- Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + mempool/blockchain.go | 5 +++++ mempool/mempool.go | 7 ++++++- x/vm/keeper/abci.go | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5df6215c25..964582af0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - [\#467](https://github.com/cosmos/evm/pull/467) Replace GlobalEVMMempool by passing to JSONRPC on initiate. - [\#352](https://github.com/cosmos/evm/pull/352) Remove the creation of a Geth EVM instance, stateDB during the AnteHandler balance check. - [\#496](https://github.com/cosmos/evm/pull/496) Simplify mempool instantiation by using configs instead of objects. +- [\#568](https://github.com/cosmos/evm/pull/568) Avoid unnecessary block notifications when the event bus is already set up. - [\#511](https://github.com/cosmos/evm/pull/511) Minor code cleanup for `AddPrecompileFn`. ### FEATURES diff --git a/mempool/blockchain.go b/mempool/blockchain.go index fa74287861..f9a593c872 100644 --- a/mempool/blockchain.go +++ b/mempool/blockchain.go @@ -86,6 +86,11 @@ func (b Blockchain) CurrentBlock() *types.Header { } blockHeight := ctx.BlockHeight() + // prevent the reorg from triggering after a restart since previousHeaderHash is stored as an in-memory variable + if blockHeight > 1 && b.previousHeaderHash == (common.Hash{}) { + return b.zeroHeader + } + blockTime := ctx.BlockTime().Unix() gasUsed := b.feeMarketKeeper.GetBlockGasWanted(ctx) appHash := common.BytesToHash(ctx.BlockHeader().AppHash) diff --git a/mempool/mempool.go b/mempool/mempool.go index e2a574e3ee..23ad670a20 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -381,7 +381,7 @@ func (m *ExperimentalEVMMempool) SelectBy(goCtx context.Context, i [][]byte, f f // SetEventBus sets CometBFT event bus to listen for new block header event. func (m *ExperimentalEVMMempool) SetEventBus(eventBus *cmttypes.EventBus) { - if m.eventBus != nil { + if m.HasEventBus() { m.eventBus.Unsubscribe(context.Background(), SubscriberName, stream.NewBlockHeaderEvents) //nolint: errcheck } m.eventBus = eventBus @@ -396,6 +396,11 @@ func (m *ExperimentalEVMMempool) SetEventBus(eventBus *cmttypes.EventBus) { }() } +// HasEventBus returns true if the blockchain is configured to use an event bus for block notifications. +func (m *ExperimentalEVMMempool) HasEventBus() bool { + return m.eventBus != nil +} + // Close unsubscribes from the CometBFT event bus and shuts down the mempool. func (m *ExperimentalEVMMempool) Close() error { var errs []error diff --git a/x/vm/keeper/abci.go b/x/vm/keeper/abci.go index b100260706..558c230bef 100644 --- a/x/vm/keeper/abci.go +++ b/x/vm/keeper/abci.go @@ -43,7 +43,7 @@ func (k *Keeper) EndBlock(ctx sdk.Context) error { // Gas costs are handled within msg handler so costs should be ignored infCtx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) - if k.evmMempool != nil { + if k.evmMempool != nil && !k.evmMempool.HasEventBus() { k.evmMempool.GetBlockchain().NotifyNewBlock() } From fedc27f6858d2823bab9cde09ac8d2b924df135e Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 3 Sep 2025 22:55:09 +0800 Subject: [PATCH 39/61] feat: don't emit EVM logs into cosmos-sdk events (#576) * feat: don't emit EVM logs into cosmos-sdk events * add doc * no need parse for old event * less diff * cleanup * test * test * Update CHANGELOG.md * Apply suggestions from code review * Apply suggestions from code review --------- Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + rpc/backend/blocks.go | 10 +- rpc/backend/tx_info.go | 16 +- rpc/backend/utils.go | 2 +- rpc/stream/rpc.go | 2 +- rpc/types/events_test.go | 2 - tests/integration/rpc/backend/test_client.go | 24 +- tests/integration/rpc/backend/test_filters.go | 14 +- tests/integration/x/vm/test_msg_server.go | 1 - x/vm/keeper/msg_server.go | 14 - x/vm/types/events.go | 1 - x/vm/types/utils.go | 60 +- x/vm/types/utils_test.go | 828 +++++------------- 13 files changed, 290 insertions(+), 685 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 964582af0a..544e039410 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - [\#496](https://github.com/cosmos/evm/pull/496) Simplify mempool instantiation by using configs instead of objects. - [\#568](https://github.com/cosmos/evm/pull/568) Avoid unnecessary block notifications when the event bus is already set up. - [\#511](https://github.com/cosmos/evm/pull/511) Minor code cleanup for `AddPrecompileFn`. +- [\#544](https://github.com/cosmos/evm/pull/544) Parse logs from the txResult.Data and avoid emitting EVM events to cosmos-sdk events. ### FEATURES diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index afd81fd6c5..737fdc3f59 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -610,10 +610,18 @@ func (b *Backend) formatTxReceipt( if err != nil { return nil, err } + height, err := cosmosevmtypes.SafeUint64(blockRes.Height) + if err != nil { + return nil, err + } // parse tx logs from events msgIndex := int(txResult.MsgIndex) // #nosec G115 -- checked for int overflow already - logs, err := evmtypes.TxLogsFromEvents(blockRes.TxsResults[txResult.TxIndex].Events, msgIndex) + logs, err := evmtypes.DecodeMsgLogs( + blockRes.TxsResults[txResult.TxIndex].Data, + msgIndex, + height, + ) if err != nil { b.Logger.Debug("failed to parse logs", "hash", ethMsg.Hash().String(), "error", err.Error()) } diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 07348a0f55..83ab86b2e4 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -214,10 +214,22 @@ func (b *Backend) GetTransactionLogs(hash common.Hash) ([]*ethtypes.Log, error) b.Logger.Debug("block result not found", "number", res.Height, "error", err.Error()) return nil, nil } - + height, err := types.SafeUint64(resBlockResult.Height) + if err != nil { + return nil, err + } // parse tx logs from events index := int(res.MsgIndex) // #nosec G701 - return evmtypes.TxLogsFromEvents(resBlockResult.TxsResults[res.TxIndex].Events, index) + logs, err := evmtypes.DecodeMsgLogs( + resBlockResult.TxsResults[res.TxIndex].Data, + index, + height, + ) + if err != nil { + b.Logger.Debug("failed to parse tx logs", "error", err.Error()) + } + + return logs, nil } // GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index. diff --git a/rpc/backend/utils.go b/rpc/backend/utils.go index 9e7b28248d..6fbfd3922d 100644 --- a/rpc/backend/utils.go +++ b/rpc/backend/utils.go @@ -266,7 +266,7 @@ func GetLogsFromBlockResults(blockRes *cmtrpctypes.ResultBlockResults) ([][]*eth } blockLogs := [][]*ethtypes.Log{} for _, txResult := range blockRes.TxsResults { - logs, err := evmtypes.DecodeTxLogsFromEvents(txResult.Data, txResult.Events, height) + logs, err := evmtypes.DecodeTxLogs(txResult.Data, height) if err != nil { return nil, err } diff --git a/rpc/stream/rpc.go b/rpc/stream/rpc.go index d62f0bd401..621657927b 100644 --- a/rpc/stream/rpc.go +++ b/rpc/stream/rpc.go @@ -187,7 +187,7 @@ func (s *RPCStream) start( if err != nil { continue } - txLogs, err := evmtypes.DecodeTxLogsFromEvents(dataTx.Result.Data, dataTx.Result.Events, height) + txLogs, err := evmtypes.DecodeTxLogs(dataTx.Result.Data, height) if err != nil { s.logger.Error("fail to decode evm tx response", "error", err.Error()) continue diff --git a/rpc/types/events_test.go b/rpc/types/events_test.go index c932e9ad17..e20cc11d0b 100644 --- a/rpc/types/events_test.go +++ b/rpc/types/events_test.go @@ -58,7 +58,6 @@ func TestParseTxResult(t *testing.T) { {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, {Key: "ethereumTxFailed", Value: "contract everted"}, }}, - {Type: evmtypes.EventTypeTxLog, Attributes: []abci.EventAttribute{}}, }, }, []*ParsedTx{ @@ -143,7 +142,6 @@ func TestParseTxResult(t *testing.T) { {Key: "recipient", Value: "0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7"}, {Key: "ethereumTxFailed", Value: "contract everted"}, }}, - {Type: evmtypes.EventTypeTxLog, Attributes: []abci.EventAttribute{}}, }, }, nil, diff --git a/tests/integration/rpc/backend/test_client.go b/tests/integration/rpc/backend/test_client.go index c3971b49b1..1df0c9277a 100644 --- a/tests/integration/rpc/backend/test_client.go +++ b/tests/integration/rpc/backend/test_client.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -23,6 +24,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -199,19 +201,23 @@ func TestRegisterConsensusParams(t *testing.T) { } // BlockResults - func RegisterBlockResultsWithEventLog(client *mocks.Client, height int64) (*cmtrpctypes.ResultBlockResults, error) { + anyValue, err := codectypes.NewAnyWithValue(&evmtypes.MsgEthereumTxResponse{ + Logs: []*evmtypes.Log{ + {Data: []byte("data")}, + }, + }) + if err != nil { + return nil, err + } + data, err := proto.Marshal(&sdk.TxMsgData{MsgResponses: []*codectypes.Any{anyValue}}) + if err != nil { + return nil, err + } res := &cmtrpctypes.ResultBlockResults{ Height: height, TxsResults: []*abci.ExecTxResult{ - {Code: 0, GasUsed: 0, Events: []abci.Event{{ - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{{ - Key: evmtypes.AttributeKeyTxLog, - Value: "{\"test\": \"hello\"}", // TODO refactor the value to unmarshall to a evmtypes.Log struct successfully - Index: true, - }}, - }}}, + {Code: 0, GasUsed: 0, Data: data}, }, } client.On("BlockResults", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")). diff --git a/tests/integration/rpc/backend/test_filters.go b/tests/integration/rpc/backend/test_filters.go index 8443343338..67b945da82 100644 --- a/tests/integration/rpc/backend/test_filters.go +++ b/tests/integration/rpc/backend/test_filters.go @@ -1,8 +1,6 @@ package backend import ( - "encoding/json" - "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -16,12 +14,12 @@ import ( func (s *TestSuite) TestGetLogs() { _, bz := s.buildEthereumTx() block := cmttypes.MakeBlock(1, []cmttypes.Tx{bz}, nil, nil) - logs := make([]*evmtypes.Log, 0, 1) - var log evmtypes.Log - err := json.Unmarshal([]byte("{\"test\": \"hello\"}"), &log) // TODO refactor this to unmarshall to a log struct successfully - s.Require().NoError(err) - - logs = append(logs, &log) + logs := []*evmtypes.Log{ + { + Data: []byte("data"), + BlockNumber: 1, + }, + } testCases := []struct { name string diff --git a/tests/integration/x/vm/test_msg_server.go b/tests/integration/x/vm/test_msg_server.go index 510a3f1b6a..7a32b83d77 100644 --- a/tests/integration/x/vm/test_msg_server.go +++ b/tests/integration/x/vm/test_msg_server.go @@ -63,7 +63,6 @@ func (s *KeeperTestSuite) TestEthereumTx() { // check expected events were emitted s.Require().NotEmpty(events) s.Require().True(utils.ContainsEventType(events.ToABCIEvents(), types.EventTypeEthereumTx)) - s.Require().True(utils.ContainsEventType(events.ToABCIEvents(), types.EventTypeTxLog)) s.Require().True(utils.ContainsEventType(events.ToABCIEvents(), sdktypes.EventTypeMessage)) } diff --git a/x/vm/keeper/msg_server.go b/x/vm/keeper/msg_server.go index 3165fe69ac..27cebf57af 100644 --- a/x/vm/keeper/msg_server.go +++ b/x/vm/keeper/msg_server.go @@ -3,7 +3,6 @@ package keeper import ( "context" "encoding/hex" - "encoding/json" "fmt" "strconv" @@ -99,25 +98,12 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t attrs = append(attrs, sdk.NewAttribute(types.AttributeKeyEthereumTxFailed, response.VmError)) } - txLogAttrs := make([]sdk.Attribute, len(response.Logs)) - for i, log := range response.Logs { - value, err := json.Marshal(log) - if err != nil { - return nil, errorsmod.Wrap(err, "failed to encode log") - } - txLogAttrs[i] = sdk.NewAttribute(types.AttributeKeyTxLog, string(value)) - } - // emit events ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeEthereumTx, attrs..., ), - sdk.NewEvent( - types.EventTypeTxLog, - txLogAttrs..., - ), sdk.NewEvent( sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), diff --git a/x/vm/types/events.go b/x/vm/types/events.go index c54531cb16..fa0aab740c 100644 --- a/x/vm/types/events.go +++ b/x/vm/types/events.go @@ -4,7 +4,6 @@ package types const ( EventTypeEthereumTx = TypeMsgEthereumTx EventTypeBlockBloom = "block_bloom" - EventTypeTxLog = "tx_log" EventTypeFeeMarket = "evm_fee_market" AttributeKeyBaseFee = "base_fee" diff --git a/x/vm/types/utils.go b/x/vm/types/utils.go index 74b287a266..9d58f233b0 100644 --- a/x/vm/types/utils.go +++ b/x/vm/types/utils.go @@ -3,7 +3,6 @@ package types import ( "bytes" "encoding/hex" - "encoding/json" "fmt" "math/big" "sort" @@ -12,8 +11,6 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/gogoproto/proto" errorsmod "cosmossdk.io/errors" @@ -90,45 +87,20 @@ func logsFromTxResponse(dst []*ethtypes.Log, rsp *MsgEthereumTxResponse, blockNu return dst } -// TxLogsFromEvents parses ethereum logs from cosmos events for specific msg index -func TxLogsFromEvents(events []abci.Event, msgIndex int) ([]*ethtypes.Log, error) { - index := msgIndex - for _, event := range events { - if event.Type != EventTypeTxLog { - continue - } - - if msgIndex > 0 { - // not the eth tx we want - msgIndex-- - continue - } - - return ParseTxLogsFromEvent(event) +// DecodeMsgLogs decodes a protobuf-encoded byte slice into ethereum logs, for a single message. +func DecodeMsgLogs(in []byte, msgIndex int, blockNumber uint64) ([]*ethtypes.Log, error) { + txResponses, err := DecodeTxResponses(in) + if err != nil { + return nil, err } - return nil, fmt.Errorf("eth tx logs not found for message index %d", index) -} - -// ParseTxLogsFromEvent parse tx logs from one event -func ParseTxLogsFromEvent(event abci.Event) ([]*ethtypes.Log, error) { - logs := make([]*Log, 0, len(event.Attributes)) - for _, attr := range event.Attributes { - if attr.Key != AttributeKeyTxLog { - continue - } - - var log Log - if err := json.Unmarshal([]byte(attr.Value), &log); err != nil { - return nil, err - } - - logs = append(logs, &log) + if msgIndex >= len(txResponses) { + return nil, fmt.Errorf("invalid message index: %d", msgIndex) } - return LogsToEthereum(logs), nil + return logsFromTxResponse(nil, txResponses[msgIndex], blockNumber), nil } -// DecodeTxLogsFromEvents decodes a protobuf-encoded byte slice into ethereum logs -func DecodeTxLogsFromEvents(in []byte, events []abci.Event, blockNumber uint64) ([]*ethtypes.Log, error) { +// DecodeTxLogs decodes a protobuf-encoded byte slice into ethereum logs +func DecodeTxLogs(in []byte, blockNumber uint64) ([]*ethtypes.Log, error) { txResponses, err := DecodeTxResponses(in) if err != nil { return nil, err @@ -137,18 +109,6 @@ func DecodeTxLogsFromEvents(in []byte, events []abci.Event, blockNumber uint64) for _, response := range txResponses { logs = logsFromTxResponse(logs, response, blockNumber) } - if len(logs) == 0 { - for _, event := range events { - if event.Type != EventTypeTxLog { - continue - } - txLogs, err := ParseTxLogsFromEvent(event) - if err != nil { - return nil, err - } - logs = append(logs, txLogs...) - } - } return logs, nil } diff --git a/x/vm/types/utils_test.go b/x/vm/types/utils_test.go index 7f6e691a96..bb348fd3a2 100644 --- a/x/vm/types/utils_test.go +++ b/x/vm/types/utils_test.go @@ -1,9 +1,7 @@ package types_test import ( - "encoding/json" "errors" - "fmt" "math/big" "testing" @@ -11,8 +9,6 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/evm/encoding" utiltx "github.com/cosmos/evm/testutil/tx" evmtypes "github.com/cosmos/evm/x/vm/types" @@ -151,128 +147,119 @@ func TestDecodeTxResponse(t *testing.T) { } } +func createTxResponseData(t *testing.T, key string) ([]byte, []*evmtypes.MsgEthereumTxResponse) { + t.Helper() + switch key { + case "multiple": + // 1st response + data1 := &evmtypes.MsgEthereumTxResponse{ + Hash: common.BytesToHash([]byte("hash1")).String(), + Logs: []*evmtypes.Log{createLog(t, testAddress, []string{testTopic}, 0, 0)}, + Ret: []byte{0x1}, + } + // 2nd response + data2 := &evmtypes.MsgEthereumTxResponse{ + Hash: common.BytesToHash([]byte("hash2")).String(), + Logs: []*evmtypes.Log{createLog(t, testAddress, []string{testTopic}, 0, 0)}, + Ret: []byte{0x2}, + } + anyData1 := codectypes.UnsafePackAny(data1) + anyData2 := codectypes.UnsafePackAny(data2) + txData := &sdk.TxMsgData{ + MsgResponses: []*codectypes.Any{anyData1, anyData2}, + } + txDataBz, _ := proto.Marshal(txData) + return txDataBz, []*evmtypes.MsgEthereumTxResponse{data1, data2} + case "single": + data := &evmtypes.MsgEthereumTxResponse{ + Hash: common.BytesToHash([]byte("hash")).String(), + Logs: []*evmtypes.Log{createLog(t, testAddress, []string{testTopic}, 0, 0)}, + Ret: []byte{0x5, 0x8}, + } + anyData := codectypes.UnsafePackAny(data) + txData := &sdk.TxMsgData{ + MsgResponses: []*codectypes.Any{anyData}, + } + txDataBz, _ := proto.Marshal(txData) + return txDataBz, []*evmtypes.MsgEthereumTxResponse{data} + case "empty": + txData := &sdk.TxMsgData{ + MsgResponses: []*codectypes.Any{}, + } + txDataBz, _ := proto.Marshal(txData) + return txDataBz, []*evmtypes.MsgEthereumTxResponse{} + case "mixed": + // EVM response + evmData := &evmtypes.MsgEthereumTxResponse{ + Hash: common.BytesToHash([]byte("evm_hash")).String(), + Ret: []byte{0x99}, + } + evmAnyData := codectypes.UnsafePackAny(evmData) + // Non-EVM response + bankData := &codectypes.Any{ + TypeUrl: "/cosmos.bank.v1beta1.MsgSendResponse", + Value: []byte("bank response"), + } + txData := &sdk.TxMsgData{ + MsgResponses: []*codectypes.Any{evmAnyData, bankData}, + } + txDataBz, _ := proto.Marshal(txData) + return txDataBz, []*evmtypes.MsgEthereumTxResponse{evmData} + case "invalid": + return []byte("invalid protobuf data"), nil + case "nil": + return nil, nil + default: + return []byte{}, nil + } +} + func TestDecodeTxResponses(t *testing.T) { testCases := []struct { name string - setupData func() []byte + txDataKey string expectError bool expectLength int expectNil bool }{ { - name: "multiple tx responses", - setupData: func() []byte { - // 1st response - data1 := &evmtypes.MsgEthereumTxResponse{ - Hash: common.BytesToHash([]byte("hash1")).String(), - Logs: []*evmtypes.Log{{ - Address: common.HexToAddress("0x1111").String(), - Data: []byte{1, 2}, - BlockNumber: 10, - }}, - Ret: []byte{0x1}, - } - // 2nd response - data2 := &evmtypes.MsgEthereumTxResponse{ - Hash: common.BytesToHash([]byte("hash2")).String(), - Logs: []*evmtypes.Log{{ - Address: common.HexToAddress("0x2222").String(), - Data: []byte{3, 4}, - BlockNumber: 11, - }}, - Ret: []byte{0x2}, - } - anyData1 := codectypes.UnsafePackAny(data1) - anyData2 := codectypes.UnsafePackAny(data2) - txData := &sdk.TxMsgData{ - MsgResponses: []*codectypes.Any{anyData1, anyData2}, - } - txDataBz, _ := proto.Marshal(txData) - return txDataBz - }, + name: "multiple tx responses", + txDataKey: "multiple", expectError: false, expectLength: 2, expectNil: false, }, { - name: "single tx response", - setupData: func() []byte { - ret := []byte{0x5, 0x8} - data := &evmtypes.MsgEthereumTxResponse{ - Hash: common.BytesToHash([]byte("hash")).String(), - Logs: []*evmtypes.Log{{ - Data: []byte{1, 2, 3, 4}, - BlockNumber: 17, - }}, - Ret: ret, - } - - anyData := codectypes.UnsafePackAny(data) - txData := &sdk.TxMsgData{ - MsgResponses: []*codectypes.Any{anyData}, - } - - txDataBz, _ := proto.Marshal(txData) - return txDataBz - }, + name: "single tx response", + txDataKey: "single", expectError: false, expectLength: 1, expectNil: false, }, { - name: "empty responses", - setupData: func() []byte { - txData := &sdk.TxMsgData{ - MsgResponses: []*codectypes.Any{}, - } - txDataBz, _ := proto.Marshal(txData) - return txDataBz - }, + name: "empty responses", + txDataKey: "empty", expectError: false, expectLength: 0, expectNil: false, }, { - name: "mixed response types", - setupData: func() []byte { - // EVM response - evmData := &evmtypes.MsgEthereumTxResponse{ - Hash: common.BytesToHash([]byte("evm_hash")).String(), - Ret: []byte{0x99}, - } - evmAnyData := codectypes.UnsafePackAny(evmData) - - // Non-EVM response - bankData := &codectypes.Any{ - TypeUrl: "/cosmos.bank.v1beta1.MsgSendResponse", - Value: []byte("bank response"), - } - - txData := &sdk.TxMsgData{ - MsgResponses: []*codectypes.Any{evmAnyData, bankData}, - } - - txDataBz, _ := proto.Marshal(txData) - return txDataBz - }, + name: "mixed response types", + txDataKey: "mixed", expectError: false, expectLength: 1, // Only EVM responses are included expectNil: false, }, { - name: "invalid protobuf data", - setupData: func() []byte { - return []byte("completely invalid data") - }, + name: "invalid protobuf data", + txDataKey: "invalid", expectError: true, expectLength: 0, expectNil: true, }, { - name: "nil input", - setupData: func() []byte { - return nil - }, + name: "nil input", + txDataKey: "nil", expectError: false, expectLength: 0, expectNil: true, @@ -281,9 +268,8 @@ func TestDecodeTxResponses(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - data := tc.setupData() - - results, err := evmtypes.DecodeTxResponses(data) + txDataBz, _ := createTxResponseData(t, tc.txDataKey) + results, err := evmtypes.DecodeTxResponses(txDataBz) if tc.expectError { require.Error(t, err) @@ -309,7 +295,7 @@ func TestDecodeTxResponses(t *testing.T) { require.Equal(t, common.BytesToHash([]byte("hash")).String(), results[0].Hash) require.Equal(t, []byte{0x5, 0x8}, results[0].Ret) require.Len(t, results[0].Logs, 1) - require.Equal(t, []byte{1, 2, 3, 4}, results[0].Logs[0].Data) + require.Equal(t, []byte(testData), results[0].Logs[0].Data) } if tc.name == "mixed response types" { @@ -321,514 +307,25 @@ func TestDecodeTxResponses(t *testing.T) { } } -func TestTxLogsFromEvents(t *testing.T) { - address := "0xc5570e6B97044960be06962E13248EC6b13107AE" - topic := "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" - - testCases := []struct { - name string - events []abci.Event - msgIndex int - expectNotFoundErr bool - expectParseErr bool - expectLogs int - validate func(t *testing.T, logs []*ethtypes.Log) - }{ - { - name: "logs found at index 0", - events: []abci.Event{ - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{topic}, 0, 0), - }, - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, "0xd09f7c8c4529cb5d387aa17e33d707c529a6f694", []string{"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"}, 0, 1), - }, - }, - }, - }, - msgIndex: 0, - expectNotFoundErr: false, - expectLogs: 2, - validate: func(t *testing.T, logs []*ethtypes.Log) { - t.Helper() - require.Equal(t, common.HexToAddress(address), logs[0].Address) - require.Equal(t, common.HexToAddress("0xd09f7c8c4529cb5d387aa17e33d707c529a6f694"), logs[1].Address) - require.Equal(t, common.HexToHash(topic), logs[0].Topics[0]) - require.Equal(t, testBlockNumber, logs[0].BlockNumber) - }, - }, - { - name: "logs found at index 1 - skips first event", - events: []abci.Event{ - // First event (index 0) - should be skipped - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, "0x1111111111111111111111111111111111111111", []string{"0x1111111111111111111111111111111111111111111111111111111111111111"}, 0, 0), - }, - }, - }, - // Second event (index 1) - should be returned - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{topic}, 1, 0), - }, - }, - }, - }, - msgIndex: 1, - expectNotFoundErr: false, - expectLogs: 1, - validate: func(t *testing.T, logs []*ethtypes.Log) { - t.Helper() - require.Equal(t, common.HexToAddress(address), logs[0].Address) - require.Equal(t, common.HexToHash(topic), logs[0].Topics[0]) - require.Equal(t, testBlockNumber, logs[0].BlockNumber) - require.Equal(t, uint(1), logs[0].TxIndex) - }, - }, - { - name: "logs found at index 2 - skips multiple events", - events: []abci.Event{ - // Event index 0 - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, "0x1111111111111111111111111111111111111111", []string{"0x1111111111111111111111111111111111111111111111111111111111111111"}, 0, 0), - }, - }, - }, - // Event index 1 - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, "0x2222222222222222222222222222222222222222", []string{"0x2222222222222222222222222222222222222222222222222222222222222222"}, 1, 0), - }, - }, - }, - // Event index 2 - target - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{topic}, 2, 0), - }, - }, - }, - }, - msgIndex: 2, - expectNotFoundErr: false, - expectLogs: 1, - validate: func(t *testing.T, logs []*ethtypes.Log) { - t.Helper() - require.Equal(t, common.HexToAddress(address), logs[0].Address) - require.Equal(t, testBlockNumber, logs[0].BlockNumber) - require.Equal(t, uint(2), logs[0].TxIndex) - }, - }, - { - name: "mixed event types - only tx log events count", - events: []abci.Event{ - // Non-tx log event - should be ignored - { - Type: "other_event_type", - Attributes: []abci.EventAttribute{ - {Key: "irrelevant", Value: "data"}, - }, - }, - // Tx log event index 0 - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{topic}, 0, 0), - }, - }, - }, - // Another non-tx log event - should be ignored - { - Type: "another_event", - Attributes: []abci.EventAttribute{ - {Key: "more", Value: "irrelevant"}, - }, - }, - }, - msgIndex: 0, - expectNotFoundErr: false, - expectLogs: 1, - validate: func(t *testing.T, logs []*ethtypes.Log) { - t.Helper() - require.Equal(t, common.HexToAddress(address), logs[0].Address) - require.Equal(t, testBlockNumber, logs[0].BlockNumber) - }, - }, - { - name: "no tx log events found", - events: []abci.Event{ - { - Type: "other_event_type", - Attributes: []abci.EventAttribute{ - {Key: "key", Value: "value"}, - }, - }, - { - Type: "another_event_type", - Attributes: []abci.EventAttribute{ - {Key: "key2", Value: "value2"}, - }, - }, - }, - msgIndex: 0, - expectNotFoundErr: true, - expectLogs: 0, - validate: func(t *testing.T, logs []*ethtypes.Log) { t.Helper() }, - }, - { - name: "msg index out of range", - events: []abci.Event{ - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{topic}, 0, 0), - }, - }, - }, - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, "0x2222222222222222222222222222222222222222", []string{"0x2222222222222222222222222222222222222222222222222222222222222222"}, 1, 0), - }, - }, - }, - }, - msgIndex: 5, // Only 2 events available, asking for index 5 - expectNotFoundErr: true, - expectLogs: 0, - validate: func(t *testing.T, logs []*ethtypes.Log) { t.Helper() }, - }, - { - name: "empty events slice", - events: []abci.Event{}, - msgIndex: 0, - expectNotFoundErr: true, - expectLogs: 0, - validate: func(t *testing.T, logs []*ethtypes.Log) { t.Helper() }, - }, - { - name: "event with invalid JSON log - should propagate error from ParseTxLogsFromEvent", - events: []abci.Event{ - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: "invalid json data", - }, - }, - }, - }, - msgIndex: 0, - expectNotFoundErr: true, - expectParseErr: true, - expectLogs: 0, - validate: func(t *testing.T, logs []*ethtypes.Log) { t.Helper() }, - }, - { - name: "event with empty topics and data", - events: []abci.Event{ - { - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{}, 0, 0), - }, - }, - }, - }, - msgIndex: 0, - expectNotFoundErr: false, - expectLogs: 1, - validate: func(t *testing.T, logs []*ethtypes.Log) { - t.Helper() - require.Equal(t, common.HexToAddress(address), logs[0].Address) - require.Len(t, logs[0].Topics, 0) - require.Equal(t, testBlockNumber, logs[0].BlockNumber) - }, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - logs, err := evmtypes.TxLogsFromEvents(tc.events, tc.msgIndex) - if tc.expectNotFoundErr { - require.Error(t, err) - require.Nil(t, logs) - if tc.expectParseErr { - require.Contains(t, err.Error(), "invalid character") - } else { - require.Contains(t, err.Error(), fmt.Sprintf("eth tx logs not found for message index %d", tc.msgIndex)) - } - } else { - require.NoError(t, err) - require.NotNil(t, logs) - require.Len(t, logs, tc.expectLogs) - for _, log := range logs { - require.NotNil(t, log) - require.IsType(t, ðtypes.Log{}, log) - require.NotNil(t, log.Address) - require.NotNil(t, log.Topics) - require.NotNil(t, log.Data) - } - tc.validate(t, logs) - } - }) - } -} - -const testBlockNumber = uint64(3) +const ( + testAddress = "0xc5570e6B97044960be06962E13248EC6b13107AE" + testTopic = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + testData = "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo=" +) -// createLogEventValue creates a JSON string representation of an EVM log event -func createLogEventValue(t *testing.T, address string, topics []string, txIndex, logIndex uint64) string { +func createLog(t *testing.T, address string, topics []string, txIndex, logIndex uint64) *evmtypes.Log { t.Helper() - log := &evmtypes.Log{ + return &evmtypes.Log{ Address: address, Topics: topics, - Data: []byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo="), - BlockNumber: testBlockNumber, + Data: []byte(testData), + BlockNumber: uint64(3), TxHash: "0x0eb002bd8fa02c0b0d549acfca70f7aab5fa745af118c76dda60a1f4329d0de1", TxIndex: txIndex, BlockHash: "0xa7a5ee692701bb2f971b9d1a1ab4bbf10599b0ce3814ea2b60c59a4a4a1d2e4c", Index: logIndex, Removed: false, } - jsonBytes, err := json.Marshal(log) - require.NoError(t, err) - return string(jsonBytes) -} - -func TestParseTxLogsFromEvent(t *testing.T) { - address := "0xc5570e6B97044960be06962E13248EC6b13107AE" - topic := "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" - - testCases := []struct { - name string - event abci.Event - expectError bool - expectLogs int - validate func(t *testing.T, logs []*ethtypes.Log) - }{ - { - name: "single valid log", - event: abci.Event{ - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{ - topic, - "0x000000000000000000000000378c50d9264c63f3f92b806d4ee56e9d86ffb3ec", - "0x000000000000000000000000d09f7c8c4529cb5d387aa17e33d707c529a6f694", - }, 0, 0), - }, - }, - }, - expectError: false, - expectLogs: 1, - validate: func(t *testing.T, logs []*ethtypes.Log) { - t.Helper() - log := logs[0] - require.Equal(t, common.HexToAddress(address), log.Address) - require.Len(t, log.Topics, 3) - require.Equal(t, common.HexToHash(topic), log.Topics[0]) - require.Equal(t, testBlockNumber, log.BlockNumber) - require.Equal(t, uint(0), log.TxIndex) - require.Equal(t, uint(0), log.Index) - require.False(t, log.Removed) - }, - }, - { - name: "multiple valid logs", - event: abci.Event{ - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{topic}, 0, 0), - }, - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, "0xd09f7c8c4529cb5d387aa17e33d707c529a6f694", []string{"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"}, 1, 1), - }, - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, "0x378c50d9264c63f3f92b806d4ee56e9d86ffb3ec", []string{"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"}, 2, 2), - }, - }, - }, - expectError: false, - expectLogs: 3, - validate: func(t *testing.T, logs []*ethtypes.Log) { - t.Helper() - require.Equal(t, common.HexToAddress(address), logs[0].Address) - require.Equal(t, common.HexToAddress("0xd09f7c8c4529cb5d387aa17e33d707c529a6f694"), logs[1].Address) - require.Equal(t, common.HexToAddress("0x378c50d9264c63f3f92b806d4ee56e9d86ffb3ec"), logs[2].Address) - require.Equal(t, uint(0), logs[0].TxIndex) - require.Equal(t, uint(1), logs[1].TxIndex) - require.Equal(t, uint(2), logs[2].TxIndex) - }, - }, - { - name: "event with non-log attributes", - event: abci.Event{ - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - {Key: "other_attribute", Value: "some value"}, - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{topic}, 0, 0), - }, - {Key: "another_attribute", Value: "another value"}, - }, - }, - expectError: false, - expectLogs: 1, - validate: func(t *testing.T, logs []*ethtypes.Log) { - t.Helper() - require.Equal(t, common.HexToAddress(address), logs[0].Address) - require.Equal(t, testBlockNumber, logs[0].BlockNumber) - }, - }, - { - name: "event with no log attributes", - event: abci.Event{ - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - {Key: "not_a_log", Value: "some value"}, - {Key: "another_non_log", Value: "another value"}, - }, - }, - expectError: false, - expectLogs: 0, - validate: func(t *testing.T, logs []*ethtypes.Log) { t.Helper() }, // No validation needed for empty - }, - { - name: "invalid JSON in log attribute", - event: abci.Event{ - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - {Key: evmtypes.AttributeKeyTxLog, Value: "invalid json format"}, - }, - }, - expectError: true, - expectLogs: 0, - validate: func(t *testing.T, logs []*ethtypes.Log) { t.Helper() }, // No validation for error case - }, - { - name: "malformed JSON structure", - event: abci.Event{ - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - {Key: evmtypes.AttributeKeyTxLog, Value: `{"address": "incomplete`}, - }, - }, - expectError: true, - expectLogs: 0, - validate: func(t *testing.T, logs []*ethtypes.Log) { t.Helper() }, - }, - { - name: "empty log attribute value", - event: abci.Event{ - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - {Key: evmtypes.AttributeKeyTxLog, Value: ""}, - }, - }, - expectError: true, - expectLogs: 0, - validate: func(t *testing.T, logs []*ethtypes.Log) { t.Helper() }, - }, - { - name: "log with empty topics array", - event: abci.Event{ - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{}, 0, 0), - }, - }, - }, - expectError: false, - expectLogs: 1, - validate: func(t *testing.T, logs []*ethtypes.Log) { - t.Helper() - require.Len(t, logs[0].Topics, 0) - require.Equal(t, testBlockNumber, logs[0].BlockNumber) - }, - }, - { - name: "mixed valid and invalid log attributes", - event: abci.Event{ - Type: evmtypes.EventTypeTxLog, - Attributes: []abci.EventAttribute{ - { - Key: evmtypes.AttributeKeyTxLog, - Value: createLogEventValue(t, address, []string{topic}, 0, 0), - }, - {Key: evmtypes.AttributeKeyTxLog, Value: "invalid json"}, - }, - }, - expectError: true, // Should fail on the invalid JSON - expectLogs: 0, - validate: func(t *testing.T, logs []*ethtypes.Log) { t.Helper() }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - logs, err := evmtypes.ParseTxLogsFromEvent(tc.event) - if tc.expectError { - require.Error(t, err) - require.Nil(t, logs) - return - } - require.NoError(t, err) - if tc.expectLogs == 0 { - require.Empty(t, logs) - } else { - require.NotNil(t, logs) - require.Len(t, logs, tc.expectLogs) - for _, log := range logs { - require.NotNil(t, log) - require.IsType(t, ðtypes.Log{}, log) - require.NotNil(t, log.Address) - require.NotNil(t, log.Topics) - require.NotNil(t, log.Data) - } - tc.validate(t, logs) - } - }) - } } func TestUnwrapEthererumMsg(t *testing.T) { @@ -909,3 +406,144 @@ func TestTransactionLogsEncodeDecode(t *testing.T) { require.Nil(t, decodeErr) require.Equal(t, txLogs, txLogsEncodedDecoded) } + +func TestDecodeMsgLogs(t *testing.T) { + testCases := []struct { + name string + txDataKey string + msgIndex int + blockNum uint64 + expectError bool + }{ + { + name: "multiple tx responses, valid msgIndex 0", + txDataKey: "multiple", + msgIndex: 0, + blockNum: 12, + }, + { + name: "multiple tx responses, valid msgIndex 1", + txDataKey: "multiple", + msgIndex: 1, + blockNum: 12, + }, + { + name: "single tx response, valid msgIndex 0", + txDataKey: "single", + msgIndex: 0, + blockNum: 34, + }, + { + name: "single tx response, invalid msgIndex", + txDataKey: "single", + msgIndex: 1, + blockNum: 34, + expectError: true, + }, + { + name: "mixed response types, valid msgIndex 0", + txDataKey: "mixed", + msgIndex: 0, + blockNum: 56, + }, + { + name: "invalid protobuf data", + txDataKey: "invalid", + msgIndex: 0, + blockNum: 78, + expectError: true, + }, + { + name: "nil input", + txDataKey: "nil", + msgIndex: 0, + blockNum: 9, + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + txMsgData, resps := createTxResponseData(t, tc.txDataKey) + logsOut, err := evmtypes.DecodeMsgLogs(txMsgData, tc.msgIndex, tc.blockNum) + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.NotNil(t, logsOut) + require.Greater(t, len(resps), tc.msgIndex) + expResp := resps[tc.msgIndex] + require.Len(t, logsOut, len(expResp.Logs)) + for i, log := range expResp.Logs { + ethLog := log.ToEthereum() + ethLog.TxHash = common.HexToHash(expResp.Hash) + ethLog.BlockNumber = tc.blockNum + require.Equal(t, ethLog.Address, logsOut[i].Address) + require.Equal(t, ethLog.BlockNumber, logsOut[i].BlockNumber) + } + } + }) + } +} + +func TestDecodeTxLogs(t *testing.T) { + testCases := []struct { + name string + txDataKey string + blockNum uint64 + expectError bool + }{ + { + name: "multiple tx responses, valid msgIndex", + txDataKey: "multiple", + blockNum: 12, + }, + { + name: "single tx response", + txDataKey: "single", + blockNum: 34, + }, + { + name: "mixed response types", + txDataKey: "mixed", + blockNum: 56, + }, + { + name: "invalid protobuf data", + txDataKey: "invalid", + blockNum: 78, + expectError: true, + }, + { + name: "nil input", + txDataKey: "nil", + blockNum: 9, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + txMsgData, resps := createTxResponseData(t, tc.txDataKey) + logsOut, err := evmtypes.DecodeTxLogs(txMsgData, tc.blockNum) + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + expLogs := make([]*ethtypes.Log, 0) + for _, resp := range resps { + for _, log := range resp.Logs { + ethLog := log.ToEthereum() + ethLog.TxHash = common.HexToHash(resp.Hash) + ethLog.BlockNumber = tc.blockNum + expLogs = append(expLogs, ethLog) + } + } + require.Equal(t, len(logsOut), len(expLogs)) + for i := range logsOut { + require.Equal(t, expLogs[i].Address, logsOut[i].Address) + require.Equal(t, expLogs[i].BlockNumber, logsOut[i].BlockNumber) + } + } + }) + } +} From 2a9e68793400ae0ae7251bfe55cae9a499261551 Mon Sep 17 00:00:00 2001 From: Abdul Malek Date: Wed, 3 Sep 2025 14:28:57 -0400 Subject: [PATCH 40/61] fix: use zero constructor to avoid nil pointer panic when BaseFee is 0 (#585) * fix int zero value * add changelog --- CHANGELOG.md | 1 + mempool/iterator.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 544e039410..e432b45b76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - [\#495](https://github.com/cosmos/evm/pull/495) Allow immediate SIGINT interrupt when mempool is not empty - [\#416](https://github.com/cosmos/evm/pull/416) Fix regression in CometBlockResultByNumber when height is 0 to use the latest block. This fixes eth_getFilterLogs RPC. - [\#545](https://github.com/cosmos/evm/pull/545) Check if mempool is not nil before accepting nonce gap error tx. +- [\#585](https://github.com/cosmos/evm/pull/585) Use zero constructor to avoid nil pointer panic when BaseFee is 0d ### IMPROVEMENTS diff --git a/mempool/iterator.go b/mempool/iterator.go index ec1875951e..b7a75b91c1 100644 --- a/mempool/iterator.go +++ b/mempool/iterator.go @@ -255,7 +255,7 @@ func (i *EVMMempoolIterator) extractCosmosEffectiveTip(tx sdk.Tx) *uint256.Int { return nil // Transaction doesn't implement FeeTx interface } - var bondDenomFeeAmount math.Int + bondDenomFeeAmount := math.ZeroInt() fees := feeTx.GetFee() for _, coin := range fees { if coin.Denom == i.bondDenom { From f03d2a4772a2773fb5b6e28f18e880a95238ecd7 Mon Sep 17 00:00:00 2001 From: Haber Date: Fri, 5 Sep 2025 00:15:05 +0900 Subject: [PATCH 41/61] test(mempool): add integration test (#512) * WIP: test(mempool): add integration test * WIP: test(mempool): add integration test * test(mempool): refactor integration test * test(mempool): fix integration test * test(mempool): refactor integration test * chore: modify comments * test(mempool): add PrepareProposal check to integration test * chore: fix lint * chore: update changelog * test(mempool): modify testcode * chore: fix lint * chore: fix lint * chore: remove fmt unnecessary logs * chore: change file name * Update CHANGELOG.md --------- Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + .../tests/integration/mempool/mempool_test.go | 3 +- tests/integration/mempool/test_helpers.go | 152 +++++ .../mempool/test_mempool_integration.go | 583 +++--------------- .../mempool/test_mempool_integration_abci.go | 449 ++++++++++++++ testutil/integration/evm/network/abci.go | 21 + 6 files changed, 705 insertions(+), 504 deletions(-) create mode 100644 tests/integration/mempool/test_helpers.go create mode 100644 tests/integration/mempool/test_mempool_integration_abci.go diff --git a/CHANGELOG.md b/CHANGELOG.md index e432b45b76..315d4f9ed9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - [\#467](https://github.com/cosmos/evm/pull/467) Replace GlobalEVMMempool by passing to JSONRPC on initiate. - [\#352](https://github.com/cosmos/evm/pull/352) Remove the creation of a Geth EVM instance, stateDB during the AnteHandler balance check. - [\#496](https://github.com/cosmos/evm/pull/496) Simplify mempool instantiation by using configs instead of objects. +- [\#512](https://github.com/cosmos/evm/pull/512) Add integration test for appside mempool. - [\#568](https://github.com/cosmos/evm/pull/568) Avoid unnecessary block notifications when the event bus is already set up. - [\#511](https://github.com/cosmos/evm/pull/511) Minor code cleanup for `AddPrecompileFn`. - [\#544](https://github.com/cosmos/evm/pull/544) Parse logs from the txResult.Data and avoid emitting EVM events to cosmos-sdk events. diff --git a/evmd/tests/integration/mempool/mempool_test.go b/evmd/tests/integration/mempool/mempool_test.go index 3714c9afc3..8c3830dba8 100644 --- a/evmd/tests/integration/mempool/mempool_test.go +++ b/evmd/tests/integration/mempool/mempool_test.go @@ -1,9 +1,10 @@ package mempool import ( - "github.com/cosmos/evm/evmd/tests/integration" "testing" + "github.com/cosmos/evm/evmd/tests/integration" + "github.com/stretchr/testify/suite" "github.com/cosmos/evm/tests/integration/mempool" diff --git a/tests/integration/mempool/test_helpers.go b/tests/integration/mempool/test_helpers.go new file mode 100644 index 0000000000..69246265ae --- /dev/null +++ b/tests/integration/mempool/test_helpers.go @@ -0,0 +1,152 @@ +package mempool + +import ( + "encoding/hex" + "fmt" + "math/big" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/tmhash" + + "github.com/cosmos/evm/testutil/integration/base/factory" + "github.com/cosmos/evm/testutil/keyring" + evmtypes "github.com/cosmos/evm/x/vm/types" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// Constants +const ( + TxGas = 100_000 +) + +// createCosmosSendTransactionWithKey creates a simple bank send transaction with the specified key +func (s *IntegrationTestSuite) createCosmosSendTx(key keyring.Key, gasPrice *big.Int) sdk.Tx { + feeDenom := "aatom" + + fromAddr := key.AccAddr + toAddr := s.keyring.GetKey(1).AccAddr + amount := sdk.NewCoins(sdk.NewInt64Coin(feeDenom, 1000)) + + bankMsg := banktypes.NewMsgSend(fromAddr, toAddr, amount) + + gasPriceConverted := sdkmath.NewIntFromBigInt(gasPrice) + + txArgs := factory.CosmosTxArgs{ + Msgs: []sdk.Msg{bankMsg}, + GasPrice: &gasPriceConverted, + } + tx, err := s.factory.BuildCosmosTx(key.Priv, txArgs) + s.Require().NoError(err) + + return tx +} + +// createEVMTransaction creates an EVM transaction using the provided key +func (s *IntegrationTestSuite) createEVMValueTransferTx(key keyring.Key, nonce int, gasPrice *big.Int) sdk.Tx { + to := s.keyring.GetKey(1).Addr + + if nonce < 0 { + s.Require().NoError(fmt.Errorf("nonce must be non-negative")) + } + + ethTxArgs := evmtypes.EvmTxArgs{ + Nonce: uint64(nonce), + To: &to, + Amount: big.NewInt(1000), + GasLimit: TxGas, + GasPrice: gasPrice, + Input: nil, + } + tx, err := s.factory.GenerateSignedEthTx(key.Priv, ethTxArgs) + s.Require().NoError(err) + + return tx +} + +// createEVMContractDeployTx creates an EVM transaction for contract deployment +func (s *IntegrationTestSuite) createEVMContractDeployTx(key keyring.Key, gasPrice *big.Int, data []byte) sdk.Tx { + ethTxArgs := evmtypes.EvmTxArgs{ + Nonce: 0, + To: nil, + Amount: nil, + GasLimit: TxGas, + GasPrice: gasPrice, + Input: data, + } + tx, err := s.factory.GenerateSignedEthTx(key.Priv, ethTxArgs) + s.Require().NoError(err) + + return tx +} + +// checkTxs call abci CheckTx for multipile transactions +func (s *IntegrationTestSuite) checkTxs(txs []sdk.Tx) error { + for _, tx := range txs { + if err := s.checkTx(tx); err != nil { + return err + } + } + return nil +} + +// checkTxs call abci CheckTx for a transaction +func (s *IntegrationTestSuite) checkTx(tx sdk.Tx) error { + txBytes, err := s.network.App.GetTxConfig().TxEncoder()(tx) + if err != nil { + return fmt.Errorf("failed to encode cosmos tx: %w", err) + } + + _, err = s.network.App.CheckTx(&abci.RequestCheckTx{ + Tx: txBytes, + Type: abci.CheckTxType_New, + }) + if err != nil { + return fmt.Errorf("failed to encode cosmos tx: %w", err) + } + + return nil +} + +// getTxHashes returns transaction hashes for multiple transactions +func (s *IntegrationTestSuite) getTxHashes(txs []sdk.Tx) []string { + txHashes := []string{} + for _, tx := range txs { + txHash := s.getTxHash(tx) + txHashes = append(txHashes, txHash) + } + + return txHashes +} + +// getTxHash returns transaction hash for a transaction +func (s *IntegrationTestSuite) getTxHash(tx sdk.Tx) string { + txEncoder := s.network.App.GetTxConfig().TxEncoder() + txBytes, err := txEncoder(tx) + s.Require().NoError(err) + + return hex.EncodeToString(tmhash.Sum(txBytes)) +} + +// calculateCosmosGasPrice calculates the gas price for a Cosmos transaction +func (s *IntegrationTestSuite) calculateCosmosGasPrice(feeAmount int64, gasLimit uint64) *big.Int { + return new(big.Int).Div(big.NewInt(feeAmount), big.NewInt(int64(gasLimit))) //#nosec G115 -- not concern, test +} + +// calculateCosmosEffectiveTip calculates the effective tip for a Cosmos transaction +// This aligns with EVM transaction prioritization: effective_tip = gas_price - base_fee +func (s *IntegrationTestSuite) calculateCosmosEffectiveTip(feeAmount int64, gasLimit uint64, baseFee *big.Int) *big.Int { + gasPrice := s.calculateCosmosGasPrice(feeAmount, gasLimit) + if baseFee == nil || baseFee.Sign() == 0 { + return gasPrice // No base fee, effective tip equals gas price + } + + if gasPrice.Cmp(baseFee) < 0 { + return big.NewInt(0) // Gas price lower than base fee, effective tip is zero + } + + return new(big.Int).Sub(gasPrice, baseFee) +} diff --git a/tests/integration/mempool/test_mempool_integration.go b/tests/integration/mempool/test_mempool_integration.go index f14671d0cf..32e24a4a1f 100644 --- a/tests/integration/mempool/test_mempool_integration.go +++ b/tests/integration/mempool/test_mempool_integration.go @@ -1,7 +1,6 @@ package mempool import ( - "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -9,25 +8,16 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" - "github.com/cosmos/evm/crypto/ethsecp256k1" "github.com/cosmos/evm/testutil/integration/evm/network" "github.com/cosmos/evm/testutil/keyring" evmtypes "github.com/cosmos/evm/x/vm/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/mempool" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" -) - -// Constants -const ( - TxGas = 21000 ) // TestMempoolInsert tests transaction insertion into the mempool func (s *IntegrationTestSuite) TestMempoolInsert() { - fmt.Printf("DEBUG: Starting TestMempoolInsert\n") testCases := []struct { name string setupTx func() sdk.Tx @@ -38,7 +28,7 @@ func (s *IntegrationTestSuite) TestMempoolInsert() { { name: "cosmos transaction success", setupTx: func() sdk.Tx { - return s.createCosmosSendTransaction(big.NewInt(1000)) + return s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000)) }, wantError: false, verifyFunc: func() { @@ -49,9 +39,7 @@ func (s *IntegrationTestSuite) TestMempoolInsert() { { name: "EVM transaction success", setupTx: func() sdk.Tx { - tx, err := s.createEVMTransaction(big.NewInt(1000000000)) - s.Require().NoError(err) - return tx + return s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) }, wantError: false, verifyFunc: func() { @@ -65,10 +53,7 @@ func (s *IntegrationTestSuite) TestMempoolInsert() { key := s.keyring.GetKey(0) data := []byte{0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0xf3} // Simple contract deployment - // Use the contract deployment helper - tx, err := s.createEVMContractDeployment(key, big.NewInt(1000000000), data) - s.Require().NoError(err) - return tx + return s.createEVMContractDeployTx(key, big.NewInt(1000000000), data) }, wantError: false, verifyFunc: func() { @@ -147,13 +132,10 @@ func (s *IntegrationTestSuite) TestMempoolInsert() { }, } - for i, tc := range testCases { - fmt.Printf("DEBUG: TestMempoolInsert - Starting test case %d/%d: %s\n", i+1, len(testCases), tc.name) + for _, tc := range testCases { s.Run(tc.name, func() { - fmt.Printf("DEBUG: Running test case: %s\n", tc.name) // Reset test setup to ensure clean state s.SetupTest() - fmt.Printf("DEBUG: SetupTest completed for: %s\n", tc.name) tx := tc.setupTx() mpool := s.network.App.GetMempool() @@ -170,15 +152,12 @@ func (s *IntegrationTestSuite) TestMempoolInsert() { } tc.verifyFunc() - fmt.Printf("DEBUG: Completed test case: %s\n", tc.name) }) - fmt.Printf("DEBUG: TestMempoolInsert - Completed test case %d/%d: %s\n", i+1, len(testCases), tc.name) } } // TestMempoolRemove tests transaction removal from the mempool func (s *IntegrationTestSuite) TestMempoolRemove() { - fmt.Printf("DEBUG: Starting TestMempoolRemove\n") testCases := []struct { name string setupTx func() sdk.Tx @@ -190,7 +169,7 @@ func (s *IntegrationTestSuite) TestMempoolRemove() { { name: "remove cosmos transaction success", setupTx: func() sdk.Tx { - return s.createCosmosSendTransaction(big.NewInt(1000)) + return s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000)) }, insertFirst: true, wantError: false, @@ -200,17 +179,16 @@ func (s *IntegrationTestSuite) TestMempoolRemove() { }, }, { - name: "remove EVM transaction success", + name: "remove EVM transaction fail", setupTx: func() sdk.Tx { - tx, err := s.createEVMTransaction(big.NewInt(1000000000)) - s.Require().NoError(err) - return tx + return s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) }, insertFirst: true, wantError: false, verifyFunc: func() { mpool := s.network.App.GetMempool() - s.Require().Equal(0, mpool.CountTx()) + // mempool.Remove can only remove invalid evm transaction + s.Require().Equal(1, mpool.CountTx()) }, }, { @@ -228,7 +206,7 @@ func (s *IntegrationTestSuite) TestMempoolRemove() { { name: "remove non-existent transaction", setupTx: func() sdk.Tx { - return s.createCosmosSendTransaction(big.NewInt(1000)) + return s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000)) }, insertFirst: false, wantError: true, // Remove should error for non-existent transactions @@ -242,10 +220,8 @@ func (s *IntegrationTestSuite) TestMempoolRemove() { for _, tc := range testCases { s.Run(tc.name, func() { - fmt.Printf("DEBUG: Running test case: %s\n", tc.name) // Reset test setup to ensure clean state s.SetupTest() - fmt.Printf("DEBUG: SetupTest completed for: %s\n", tc.name) tx := tc.setupTx() mpool := s.network.App.GetMempool() @@ -268,14 +244,12 @@ func (s *IntegrationTestSuite) TestMempoolRemove() { } tc.verifyFunc() - fmt.Printf("DEBUG: Completed test case: %s\n", tc.name) }) } } // TestMempoolSelect tests transaction selection from the mempool func (s *IntegrationTestSuite) TestMempoolSelect() { - fmt.Printf("DEBUG: Starting TestMempoolSelect\n") testCases := []struct { name string setupTxs func() @@ -292,7 +266,7 @@ func (s *IntegrationTestSuite) TestMempoolSelect() { { name: "single cosmos transaction", setupTxs: func() { - cosmosTx := s.createCosmosSendTransaction(big.NewInt(2000)) + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000)) mpool := s.network.App.GetMempool() err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) @@ -306,10 +280,10 @@ func (s *IntegrationTestSuite) TestMempoolSelect() { { name: "single EVM transaction", setupTxs: func() { - evmTx, err := s.createEVMTransaction(big.NewInt(1000000000)) - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) + mpool := s.network.App.GetMempool() - err = mpool.Insert(s.network.GetContext(), evmTx) + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) }, verifyFunc: func(iterator mempool.Iterator) { @@ -344,7 +318,6 @@ func (s *IntegrationTestSuite) TestMempoolSelect() { // TestMempoolIterator tests iterator functionality func (s *IntegrationTestSuite) TestMempoolIterator() { - fmt.Printf("DEBUG: Starting TestMempoolIterator\n") testCases := []struct { name string setupTxs func() @@ -361,7 +334,7 @@ func (s *IntegrationTestSuite) TestMempoolIterator() { { name: "single cosmos transaction iteration", setupTxs: func() { - cosmosTx := s.createCosmosSendTransaction(big.NewInt(2000)) + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000)) mpool := s.network.App.GetMempool() err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) @@ -374,10 +347,9 @@ func (s *IntegrationTestSuite) TestMempoolIterator() { { name: "single EVM transaction iteration", setupTxs: func() { - evmTx, err := s.createEVMTransaction(big.NewInt(1000000000)) - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) mpool := s.network.App.GetMempool() - err = mpool.Insert(s.network.GetContext(), evmTx) + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) }, verifyFunc: func(iterator mempool.Iterator) { @@ -398,11 +370,11 @@ func (s *IntegrationTestSuite) TestMempoolIterator() { setupTxs: func() { mpool := s.network.App.GetMempool() - cosmosTx1 := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(0), big.NewInt(1000)) + cosmosTx1 := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000)) err := mpool.Insert(s.network.GetContext(), cosmosTx1) s.Require().NoError(err) - cosmosTx2 := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(1), big.NewInt(2000)) + cosmosTx2 := s.createCosmosSendTx(s.keyring.GetKey(1), big.NewInt(2000)) err = mpool.Insert(s.network.GetContext(), cosmosTx2) s.Require().NoError(err) }, @@ -423,13 +395,13 @@ func (s *IntegrationTestSuite) TestMempoolIterator() { mpool := s.network.App.GetMempool() // Add EVM transaction - evmTx, err := s.createEVMTransaction(big.NewInt(2000)) - s.Require().NoError(err) - err = mpool.Insert(s.network.GetContext(), evmTx) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(2000)) + + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) // Add Cosmos transaction - cosmosTx := s.createCosmosSendTransaction(big.NewInt(2000)) + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000)) err = mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) }, @@ -461,7 +433,6 @@ func (s *IntegrationTestSuite) TestMempoolIterator() { // TestTransactionOrdering tests transaction ordering based on fees func (s *IntegrationTestSuite) TestTransactionOrdering() { - fmt.Printf("DEBUG: Starting TestTransactionOrdering\n") testCases := []struct { name string setupTxs func() @@ -471,18 +442,17 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { name: "mixed EVM and cosmos transaction ordering", setupTxs: func() { // Create EVM transaction with high gas price - highGasPriceEVMTx, err := s.createEVMTransaction(big.NewInt(5000000000)) - s.Require().NoError(err) + highGasPriceEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // Create Cosmos transactions with different fee amounts - highFeeCosmosTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(6), big.NewInt(5000000000)) - mediumFeeCosmosTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(7), big.NewInt(3000000000)) - lowFeeCosmosTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(8), big.NewInt(1000000000)) + highFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(6), big.NewInt(5000000000)) + mediumFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(7), big.NewInt(3000000000)) + lowFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(8), big.NewInt(1000000000)) mpool := s.network.App.GetMempool() // Insert in non-priority order - err = mpool.Insert(s.network.GetContext(), lowFeeCosmosTx) + err := mpool.Insert(s.network.GetContext(), lowFeeCosmosTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), highGasPriceEVMTx) s.Require().NoError(err) @@ -517,17 +487,15 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { name: "EVM-only transaction replacement", setupTxs: func() { // Create first EVM transaction with low fee - lowFeeEVMTx, err := s.createEVMTransaction(big.NewInt(1000000000)) // 1 gaatom - s.Require().NoError(err) + lowFeeEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) // 1 gaatom // Create second EVM transaction with high fee - highFeeEVMTx, err := s.createEVMTransaction(big.NewInt(5000000000)) // 5 gaatom - s.Require().NoError(err) + highFeeEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // 5 gaatom mpool := s.network.App.GetMempool() // Insert low fee transaction first - err = mpool.Insert(s.network.GetContext(), lowFeeEVMTx) + err := mpool.Insert(s.network.GetContext(), lowFeeEVMTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), highFeeEVMTx) s.Require().NoError(err) @@ -549,17 +517,15 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { setupTxs: func() { key := s.keyring.GetKey(0) // Create first EVM transaction with low fee - lowFeeEVMTx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) // 1 gaatom - s.Require().NoError(err) + lowFeeEVMTx := s.createEVMValueTransferTx(key, 1, big.NewInt(1000000000)) // 1 gaatom // Create second EVM transaction with high fee - highFeeEVMTx, err := s.createEVMTransactionWithNonce(key, big.NewInt(5000000000), 0) // 5 gaatom - s.Require().NoError(err) + highFeeEVMTx := s.createEVMValueTransferTx(key, 0, big.NewInt(5000000000)) // 5 gaatom mpool := s.network.App.GetMempool() // Insert low fee transaction first - err = mpool.Insert(s.network.GetContext(), lowFeeEVMTx) + err := mpool.Insert(s.network.GetContext(), lowFeeEVMTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), highFeeEVMTx) s.Require().NoError(err) @@ -587,9 +553,9 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { { name: "cosmos-only transaction replacement", setupTxs: func() { - highFeeTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5 gaatom - lowFeeTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(0), big.NewInt(1000000000)) // 1 gaatom - mediumFeeTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(0), big.NewInt(3000000000)) // 3 gaatom + highFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5 gaatom + lowFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000000000)) // 1 gaatom + mediumFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(3000000000)) // 3 gaatom mpool := s.network.App.GetMempool() @@ -619,16 +585,15 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { setupTxs: func() { // Create transactions with equal effective tips (assuming base fee = 0) // EVM: 1000 aatom/gas effective tip - evmTx, err := s.createEVMTransaction(big.NewInt(1000000000)) // 1 gaatom/gas - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) // 1 gaatom/gas // Cosmos with same effective tip: 1000 * 200000 = 200000000 aatom total fee - cosmosTx := s.createCosmosSendTransaction(big.NewInt(1000000000)) // 1 gaatom/gas effective tip + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000000000)) // 1 gaatom/gas effective tip mpool := s.network.App.GetMempool() // Insert Cosmos first, then EVM - err = mpool.Insert(s.network.GetContext(), cosmosTx) + err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) @@ -662,16 +627,15 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { name: "mixed transactions with EVM having higher effective tip", setupTxs: func() { // Create EVM transaction with higher gas price - evmTx, err := s.createEVMTransaction(big.NewInt(5000000000)) // 5 gaatom/gas - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // 5 gaatom/gas // Create Cosmos transaction with lower gas price - cosmosTx := s.createCosmosSendTransaction(big.NewInt(2000000000)) // 2 gaatom/gas + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000000000)) // 2 gaatom/gas mpool := s.network.App.GetMempool() // Insert Cosmos first, then EVM - err = mpool.Insert(s.network.GetContext(), cosmosTx) + err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) @@ -702,16 +666,15 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { name: "mixed transactions with Cosmos having higher effective tip", setupTxs: func() { // Create EVM transaction with lower gas price - evmTx, err := s.createEVMTransaction(big.NewInt(2000000000)) // 2000 aatom/gas - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(2000000000)) // 2000 aatom/gas // Create Cosmos transaction with higher gas price - cosmosTx := s.createCosmosSendTransaction(big.NewInt(5000000000)) // 5000 aatom/gas + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5000 aatom/gas mpool := s.network.App.GetMempool() // Insert EVM first, then Cosmos - err = mpool.Insert(s.network.GetContext(), evmTx) + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) @@ -745,21 +708,18 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { // EVM: 8000, 4000, 2000 aatom/gas // Cosmos: 6000, 3000, 1000 aatom/gas - evmHigh, err := s.createEVMTransaction(big.NewInt(8000000000)) - s.Require().NoError(err) - evmMedium, err := s.createEVMTransactionWithKey(s.keyring.GetKey(1), big.NewInt(4000000000)) - s.Require().NoError(err) - evmLow, err := s.createEVMTransactionWithKey(s.keyring.GetKey(2), big.NewInt(2000000000)) - s.Require().NoError(err) + evmHigh := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(8000000000)) + evmMedium := s.createEVMValueTransferTx(s.keyring.GetKey(1), 0, big.NewInt(4000000000)) + evmLow := s.createEVMValueTransferTx(s.keyring.GetKey(2), 0, big.NewInt(2000000000)) - cosmosHigh := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(3), big.NewInt(6000000000)) - cosmosMedium := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(4), big.NewInt(3000000000)) - cosmosLow := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(5), big.NewInt(1000000000)) + cosmosHigh := s.createCosmosSendTx(s.keyring.GetKey(3), big.NewInt(6000000000)) + cosmosMedium := s.createCosmosSendTx(s.keyring.GetKey(4), big.NewInt(3000000000)) + cosmosLow := s.createCosmosSendTx(s.keyring.GetKey(5), big.NewInt(1000000000)) mpool := s.network.App.GetMempool() // Insert in random order - err = mpool.Insert(s.network.GetContext(), cosmosLow) + err := mpool.Insert(s.network.GetContext(), cosmosLow) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), evmMedium) s.Require().NoError(err) @@ -859,7 +819,6 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { // TestSelectBy tests the SelectBy functionality with filters func (s *IntegrationTestSuite) TestSelectBy() { - fmt.Printf("DEBUG: Starting TestSelectBy\n") testCases := []struct { name string setupTxs func() @@ -879,7 +838,7 @@ func (s *IntegrationTestSuite) TestSelectBy() { { name: "single cosmos transaction - terminates properly", setupTxs: func() { - cosmosTx := s.createCosmosSendTransaction(big.NewInt(2000)) + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000)) mpool := s.network.App.GetMempool() err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) @@ -892,10 +851,9 @@ func (s *IntegrationTestSuite) TestSelectBy() { { name: "single EVM transaction - terminates properly", setupTxs: func() { - evmTx, err := s.createEVMTransaction(big.NewInt(1000000000)) - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) mpool := s.network.App.GetMempool() - err = mpool.Insert(s.network.GetContext(), evmTx) + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) }, filterFunc: func(tx sdk.Tx) bool { @@ -910,7 +868,7 @@ func (s *IntegrationTestSuite) TestSelectBy() { // Add transactions with different fees for i := 1; i < 6; i++ { // Use different keys for different transactions - cosmosTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(i), big.NewInt(int64(i*1000))) // 5000, 4000, 3000, 2000, 1000 + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(i), big.NewInt(int64(i*1000))) // 5000, 4000, 3000, 2000, 1000 err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) } @@ -936,13 +894,10 @@ func (s *IntegrationTestSuite) TestSelectBy() { for i := 1; i < 4; i++ { keyIndex := i key := s.keyring.GetKey(keyIndex) - fromAddr := common.BytesToAddress(key.AccAddr.Bytes()) - fmt.Printf("DEBUG: Using prefunded account %d: %s\n", keyIndex, fromAddr.Hex()) // Use the helper method with specific nonce - evmTx, err := s.createEVMTransactionWithKey(key, big.NewInt(int64(i)*100000000000)) - s.Require().NoError(err) - err = mpool.Insert(s.network.GetContext(), evmTx) + evmTx := s.createEVMValueTransferTx(key, 0, big.NewInt(int64(i)*100000000000)) + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) } }, @@ -995,7 +950,6 @@ func (s *IntegrationTestSuite) TestSelectBy() { // TestMempoolHeightRequirement tests that mempool operations fail before block 2 func (s *IntegrationTestSuite) TestMempoolHeightRequirement() { - fmt.Printf("DEBUG: Starting TestMempoolHeightRequirement\n") // Create a fresh network at block 1 keyring := keyring.New(1) options := []network.ConfigOption{ @@ -1013,7 +967,7 @@ func (s *IntegrationTestSuite) TestMempoolHeightRequirement() { s.Require().Equal(int64(2), nw.GetContext().BlockHeight()) mpool := nw.App.GetMempool() - tx := s.createCosmosSendTransaction(big.NewInt(1000)) + tx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000)) // Should fail because mempool requires block height >= 2 err = mpool.Insert(nw.GetContext(), tx) @@ -1024,8 +978,6 @@ func (s *IntegrationTestSuite) TestMempoolHeightRequirement() { // TestEVMTransactionComprehensive tests comprehensive EVM transaction functionality func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { - fmt.Printf("DEBUG: Starting TestEVMTransactionComprehensive\n") - testCases := []struct { name string setupTx func() sdk.Tx @@ -1036,9 +988,7 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { { name: "EVM transaction with high gas price", setupTx: func() sdk.Tx { - tx, err := s.createEVMTransaction(big.NewInt(10000000000)) // 10 gaatom - s.Require().NoError(err) - return tx + return s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(10000000000)) // 10 gaatom }, wantError: false, verifyFunc: func() { @@ -1049,9 +999,7 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { { name: "EVM transaction with low gas price", setupTx: func() sdk.Tx { - tx, err := s.createEVMTransaction(big.NewInt(100000000)) // 0.1 gaatom - s.Require().NoError(err) - return tx + return s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(100000000)) // 0.1 gaatom }, wantError: false, verifyFunc: func() { @@ -1067,9 +1015,7 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { data := []byte{0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0xf3} // Simple contract deployment // Use the contract deployment helper - tx, err := s.createEVMContractDeployment(key, big.NewInt(1000000000), data) - s.Require().NoError(err) - return tx + return s.createEVMContractDeployTx(key, big.NewInt(1000000000), data) }, wantError: false, verifyFunc: func() { @@ -1082,11 +1028,9 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { setupTx: func() sdk.Tx { // Use key 0 again since this is a separate test (SetupTest resets state) key := s.keyring.GetKey(0) - to := common.HexToAddress("0x1234567890123456789012345678901234567890") // Use the value transfer helper - tx, err := s.createEVMValueTransfer(key, big.NewInt(1000000000), big.NewInt(1000000000000000000), to) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, 0, big.NewInt(1000000000)) return tx }, wantError: false, @@ -1097,13 +1041,10 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { }, } - for i, tc := range testCases { - fmt.Printf("DEBUG: TestEVMTransactionComprehensive - Starting test case %d/%d: %s\n", i+1, len(testCases), tc.name) + for _, tc := range testCases { s.Run(tc.name, func() { - fmt.Printf("DEBUG: Running test case: %s\n", tc.name) // Reset test setup to ensure clean state s.SetupTest() - fmt.Printf("DEBUG: SetupTest completed for: %s\n", tc.name) tx := tc.setupTx() mpool := s.network.App.GetMempool() @@ -1120,17 +1061,13 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { } tc.verifyFunc() - fmt.Printf("DEBUG: Completed test case: %s\n", tc.name) }) - fmt.Printf("DEBUG: TestEVMTransactionComprehensive - Completed test case %d/%d: %s\n", i+1, len(testCases), tc.name) } } // TestNonceGappedEVMTransactions tests the behavior of nonce-gapped EVM transactions // and the transition from queued to pending when gaps are filled func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { - fmt.Printf("DEBUG: Starting TestNonceGappedEVMTransactions\n") - testCases := []struct { name string setupTxs func() ([]sdk.Tx, []int) // Returns transactions and their expected nonces @@ -1145,8 +1082,7 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Insert transactions with gaps: nonces 0, 2, 4, 6 (missing 1, 3, 5) for i := 0; i <= 6; i += 2 { - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1169,15 +1105,13 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // First, insert transactions with gaps: nonces 0, 2, 4 for i := 0; i <= 4; i += 2 { - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } // Then fill the gap by inserting nonce 1 - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, 1, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, 1) @@ -1199,8 +1133,7 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Insert transactions with multiple gaps: nonces 0, 3, 6, 9 for i := 0; i <= 9; i += 3 { - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1208,8 +1141,7 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Fill gaps by inserting nonces 1, 2, 4, 5, 7, 8 for i := 1; i <= 8; i++ { if i%3 != 0 { // Skip nonces that are already inserted - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1235,16 +1167,14 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Account 1: nonces 0, 2 (gap at 1) for i := 0; i <= 2; i += 2 { - tx, err := s.createEVMTransactionWithNonce(key1, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key1, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } // Account 2: nonces 0, 3 (gaps at 1, 2) for i := 0; i <= 3; i += 3 { - tx, err := s.createEVMTransactionWithNonce(key2, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key2, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1267,20 +1197,17 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { var nonces []int // Insert transaction with nonce 0 and low gas price - tx1, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 0) - s.Require().NoError(err) + tx1 := s.createEVMValueTransferTx(key, 0, big.NewInt(1000000000)) txs = append(txs, tx1) nonces = append(nonces, 0) // Insert transaction with nonce 1 - tx2, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) - s.Require().NoError(err) + tx2 := s.createEVMValueTransferTx(key, 1, big.NewInt(1000000000)) txs = append(txs, tx2) nonces = append(nonces, 1) // Replace nonce 0 transaction with higher gas price - tx3, err := s.createEVMTransactionWithNonce(key, big.NewInt(2000000000), 0) - s.Require().NoError(err) + tx3 := s.createEVMValueTransferTx(key, 0, big.NewInt(2000000000)) txs = append(txs, tx3) nonces = append(nonces, 0) @@ -1301,8 +1228,7 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Insert transactions with gaps: nonces 0, 3, 6, 9 for i := 0; i <= 9; i += 3 { - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1310,8 +1236,7 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Fill gaps by inserting nonces 1, 2, 4, 5, 7, 8 for i := 1; i <= 8; i++ { if i%3 != 0 { // Skip nonces that are already inserted - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1325,370 +1250,22 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { s.Require().Equal(10, count, "After filling all gaps, all 10 transactions should be pending") }, }, - { - name: "removing places subsequent transactions back into queued", - setupTxs: func() ([]sdk.Tx, []int) { - key := s.keyring.GetKey(0) - var txs []sdk.Tx - var nonces []int - - // Insert transactions with gaps: nonces 0, 1, 3, 4, 6, 7 - for i := 0; i <= 7; i++ { - if i != 1 { // Skip nonce 1 to create a gap - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) - txs = append(txs, tx) - nonces = append(nonces, i) //#nosec G115 -- int overflow is not a concern here - } - } - - return txs, nonces - }, - verifyFunc: func(mpool mempool.Mempool) { - // Initially: nonces 0 should be pending, nonces 2, 3, 4, 5, 6, 7 should be queued - initialCount := mpool.CountTx() - s.Require().Equal(1, initialCount, "Initially only nonces 0, 1 should be pending") - key := s.keyring.GetKey(0) - - // Fill gap by inserting nonce 1 - tx1, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) - s.Require().NoError(err) - err = mpool.Insert(s.network.GetContext(), tx1) - s.Require().NoError(err) - - // After filling gap: all nonce transactions should be in pending - countAfterFilling := mpool.CountTx() - s.Require().Equal(8, countAfterFilling, "After filling gap, only nonce 0 should be pending due to gap at nonce 1") - - // Remove nonce 1 transaction, dropping the rest (except for 0) into queued - tx1, err = s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) - s.Require().NoError(err) - err = mpool.Remove(tx1) - s.Require().NoError(err) - - // After removal: only nonce 0 should be pending, the rest get dropped to queued - countAfterRemoval := mpool.CountTx() - s.Require().Equal(1, countAfterRemoval, "After removing nonce 1, only nonce 0 should be pending") - - // Fill gap by inserting nonce 1 - tx1, err = s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) - s.Require().NoError(err) - err = mpool.Insert(s.network.GetContext(), tx1) - s.Require().NoError(err) - - // After filling gap: all transactions should be re-promoted and places into pending - countAfterFilling = mpool.CountTx() - s.Require().Equal(8, countAfterFilling, "After filling gap, only nonce 0 should be pending due to gap at nonce 1") - }, - }, } - for i, tc := range testCases { - fmt.Printf("DEBUG: TestNonceGappedEVMTransactions - Starting test case %d/%d: %s\n", i+1, len(testCases), tc.name) + for _, tc := range testCases { s.Run(tc.name, func() { - fmt.Printf("DEBUG: Running test case: %s\n", tc.name) // Reset test setup to ensure clean state s.SetupTest() - fmt.Printf("DEBUG: SetupTest completed for: %s\n", tc.name) - txs, nonces := tc.setupTxs() + txs, _ := tc.setupTxs() mpool := s.network.App.GetMempool() - // Insert transactions and track count changes - initialCount := mpool.CountTx() - fmt.Printf("DEBUG: Initial mempool count: %d\n", initialCount) - - for i, tx := range txs { + for _, tx := range txs { err := mpool.Insert(s.network.GetContext(), tx) s.Require().NoError(err) - - currentCount := mpool.CountTx() - fmt.Printf("DEBUG: After inserting nonce %d: count = %d\n", nonces[i], currentCount) } tc.verifyFunc(mpool) - fmt.Printf("DEBUG: Completed test case: %s\n", tc.name) }) - fmt.Printf("DEBUG: TestNonceGappedEVMTransactions - Completed test case %d/%d: %s\n", i+1, len(testCases), tc.name) - } -} - -// Helper methods - -// createCosmosSendTransactionWithKey creates a simple bank send transaction with the specified key -func (s *IntegrationTestSuite) createCosmosSendTransactionWithKey(key keyring.Key, gasPrice *big.Int) sdk.Tx { - feeDenom := "aatom" - gasLimit := uint64(TxGas) - - // Calculate fee amount from gas price: fee = gas_price * gas_limit - feeAmount := new(big.Int).Mul(gasPrice, big.NewInt(int64(gasLimit))) - - fmt.Printf("DEBUG: Creating cosmos transaction with gas price: %s aatom/gas, fee: %s %s\n", gasPrice.String(), feeAmount.String(), feeDenom) - - fromAddr := key.AccAddr - toAddr := s.keyring.GetKey(1).AccAddr - amount := sdk.NewCoins(sdk.NewInt64Coin(feeDenom, 1000)) - - bankMsg := banktypes.NewMsgSend(fromAddr, toAddr, amount) - - txBuilder := s.network.App.GetTxConfig().NewTxBuilder() - err := txBuilder.SetMsgs(bankMsg) - s.Require().NoError(err) - - txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewInt64Coin(feeDenom, feeAmount.Int64()))) - txBuilder.SetGasLimit(gasLimit) - - // Sign the transaction - privKey := key.Priv - // Create a dummy signature for testing - sigData := signing.SingleSignatureData{ - SignMode: signing.SignMode_SIGN_MODE_DIRECT, - Signature: []byte("dummy_signature_for_testing"), - } - sig := signing.SignatureV2{ - PubKey: privKey.PubKey(), - Data: &sigData, - Sequence: 0, } - err = txBuilder.SetSignatures(sig) - s.Require().NoError(err) - - fmt.Printf("DEBUG: Created cosmos transaction successfully\n") - return txBuilder.GetTx() -} - -// createCosmosSendTransaction creates a simple bank send transaction using the first key -func (s *IntegrationTestSuite) createCosmosSendTransaction(gasPrice *big.Int) sdk.Tx { - key := s.keyring.GetKey(0) - return s.createCosmosSendTransactionWithKey(key, gasPrice) -} - -// calculateCosmosGasPrice calculates the gas price for a Cosmos transaction -func (s *IntegrationTestSuite) calculateCosmosGasPrice(feeAmount int64, gasLimit uint64) *big.Int { - return new(big.Int).Div(big.NewInt(feeAmount), big.NewInt(int64(gasLimit))) //#nosec G115 -- not concern, test -} - -// calculateCosmosEffectiveTip calculates the effective tip for a Cosmos transaction -// This aligns with EVM transaction prioritization: effective_tip = gas_price - base_fee -func (s *IntegrationTestSuite) calculateCosmosEffectiveTip(feeAmount int64, gasLimit uint64, baseFee *big.Int) *big.Int { - gasPrice := s.calculateCosmosGasPrice(feeAmount, gasLimit) - if baseFee == nil || baseFee.Sign() == 0 { - return gasPrice // No base fee, effective tip equals gas price - } - - if gasPrice.Cmp(baseFee) < 0 { - return big.NewInt(0) // Gas price lower than base fee, effective tip is zero - } - - return new(big.Int).Sub(gasPrice, baseFee) -} - -// createEVMTransaction creates an EVM transaction using the provided key -func (s *IntegrationTestSuite) createEVMTransactionWithKey(key keyring.Key, gasPrice *big.Int) (sdk.Tx, error) { - fmt.Printf("DEBUG: Creating EVM transaction with gas price: %s\n", gasPrice.String()) - - privKey := key.Priv - - // Convert Cosmos address to EVM address - fromAddr := common.BytesToAddress(key.AccAddr.Bytes()) - fmt.Printf("DEBUG: Using prefunded account: %s\n", fromAddr.Hex()) - - to := common.HexToAddress("0x1234567890123456789012345678901234567890") - ethTx := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: 0, - To: &to, - Value: big.NewInt(1000), - Gas: TxGas, - GasPrice: gasPrice, - Data: nil, - }) - - // Convert to ECDSA private key for signing - ethPrivKey, ok := privKey.(*ethsecp256k1.PrivKey) - if !ok { - return nil, fmt.Errorf("expected ethsecp256k1.PrivKey, got %T", privKey) - } - - ecdsaPrivKey, err := ethPrivKey.ToECDSA() - if err != nil { - return nil, err - } - - signer := ethtypes.HomesteadSigner{} - signedTx, err := ethtypes.SignTx(ethTx, signer, ecdsaPrivKey) - if err != nil { - return nil, err - } - - msgEthTx := &evmtypes.MsgEthereumTx{} - msgEthTx.FromEthereumTx(signedTx) - - txBuilder := s.network.App.GetTxConfig().NewTxBuilder() - err = txBuilder.SetMsgs(msgEthTx) - if err != nil { - return nil, err - } - - fmt.Printf("DEBUG: Created EVM transaction successfully\n") - return txBuilder.GetTx(), nil -} - -// createEVMTransaction creates an EVM transaction using the first key -func (s *IntegrationTestSuite) createEVMTransaction(gasPrice *big.Int) (sdk.Tx, error) { - key := s.keyring.GetKey(0) - return s.createEVMTransactionWithKey(key, gasPrice) -} - -// createEVMContractDeployment creates an EVM transaction for contract deployment -func (s *IntegrationTestSuite) createEVMContractDeployment(key keyring.Key, gasPrice *big.Int, data []byte) (sdk.Tx, error) { - fmt.Printf("DEBUG: Creating EVM contract deployment transaction with gas price: %s\n", gasPrice.String()) - - privKey := key.Priv - - // Convert Cosmos address to EVM address - fromAddr := common.BytesToAddress(key.AccAddr.Bytes()) - fmt.Printf("DEBUG: Using prefunded account: %s\n", fromAddr.Hex()) - - ethTx := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: 0, - To: nil, // nil for contract deployment - Value: big.NewInt(0), - Gas: 100000, - GasPrice: gasPrice, - Data: data, - }) - - // Convert to ECDSA private key for signing - ethPrivKey, ok := privKey.(*ethsecp256k1.PrivKey) - if !ok { - return nil, fmt.Errorf("expected ethsecp256k1.PrivKey, got %T", privKey) - } - - ecdsaPrivKey, err := ethPrivKey.ToECDSA() - if err != nil { - return nil, err - } - - signer := ethtypes.HomesteadSigner{} - signedTx, err := ethtypes.SignTx(ethTx, signer, ecdsaPrivKey) - if err != nil { - return nil, err - } - - msgEthTx := &evmtypes.MsgEthereumTx{} - msgEthTx.FromEthereumTx(signedTx) - - txBuilder := s.network.App.GetTxConfig().NewTxBuilder() - err = txBuilder.SetMsgs(msgEthTx) - if err != nil { - return nil, err - } - - fmt.Printf("DEBUG: Created EVM contract deployment transaction successfully\n") - return txBuilder.GetTx(), nil -} - -// createEVMValueTransfer creates an EVM transaction for value transfer -func (s *IntegrationTestSuite) createEVMValueTransfer(key keyring.Key, gasPrice *big.Int, value *big.Int, to common.Address) (sdk.Tx, error) { - fmt.Printf("DEBUG: Creating EVM value transfer transaction with gas price: %s\n", gasPrice.String()) - - privKey := key.Priv - - // Convert Cosmos address to EVM address - fromAddr := common.BytesToAddress(key.AccAddr.Bytes()) - fmt.Printf("DEBUG: Using prefunded account: %s\n", fromAddr.Hex()) - - ethTx := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: 0, - To: &to, - Value: value, - Gas: TxGas, - GasPrice: gasPrice, - Data: nil, - }) - - // Convert to ECDSA private key for signing - ethPrivKey, ok := privKey.(*ethsecp256k1.PrivKey) - if !ok { - return nil, fmt.Errorf("expected ethsecp256k1.PrivKey, got %T", privKey) - } - - ecdsaPrivKey, err := ethPrivKey.ToECDSA() - if err != nil { - return nil, err - } - - signer := ethtypes.HomesteadSigner{} - signedTx, err := ethtypes.SignTx(ethTx, signer, ecdsaPrivKey) - if err != nil { - return nil, err - } - - msgEthTx := &evmtypes.MsgEthereumTx{} - msgEthTx.FromEthereumTx(signedTx) - if err != nil { - return nil, err - } - - txBuilder := s.network.App.GetTxConfig().NewTxBuilder() - err = txBuilder.SetMsgs(msgEthTx) - if err != nil { - return nil, err - } - - fmt.Printf("DEBUG: Created EVM value transfer transaction successfully\n") - return txBuilder.GetTx(), nil -} - -// createEVMTransactionWithNonce creates an EVM transaction with a specific nonce -func (s *IntegrationTestSuite) createEVMTransactionWithNonce(key keyring.Key, gasPrice *big.Int, nonce int) (sdk.Tx, error) { - fmt.Printf("DEBUG: Creating EVM transaction with gas price: %s and nonce: %d\n", gasPrice.String(), nonce) - - privKey := key.Priv - - // Convert Cosmos address to EVM address - fromAddr := common.BytesToAddress(key.AccAddr.Bytes()) - fmt.Printf("DEBUG: Using prefunded account: %s\n", fromAddr.Hex()) - - to := common.HexToAddress("0x1234567890123456789012345678901234567890") - ethTx := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: uint64(nonce), //#nosec G115 -- int overflow is not a concern here - To: &to, - Value: big.NewInt(1000), - Gas: TxGas, - GasPrice: gasPrice, - Data: nil, - }) - - // Convert to ECDSA private key for signing - ethPrivKey, ok := privKey.(*ethsecp256k1.PrivKey) - if !ok { - return nil, fmt.Errorf("expected ethsecp256k1.PrivKey, got %T", privKey) - } - - ecdsaPrivKey, err := ethPrivKey.ToECDSA() - if err != nil { - return nil, err - } - - signer := ethtypes.HomesteadSigner{} - signedTx, err := ethtypes.SignTx(ethTx, signer, ecdsaPrivKey) - if err != nil { - return nil, err - } - - msgEthTx := &evmtypes.MsgEthereumTx{} - msgEthTx.FromEthereumTx(signedTx) - if err != nil { - return nil, err - } - - txBuilder := s.network.App.GetTxConfig().NewTxBuilder() - err = txBuilder.SetMsgs(msgEthTx) - if err != nil { - return nil, err - } - - fmt.Printf("DEBUG: Created EVM transaction successfully\n") - return txBuilder.GetTx(), nil } diff --git a/tests/integration/mempool/test_mempool_integration_abci.go b/tests/integration/mempool/test_mempool_integration_abci.go new file mode 100644 index 0000000000..b4aa655f00 --- /dev/null +++ b/tests/integration/mempool/test_mempool_integration_abci.go @@ -0,0 +1,449 @@ +package mempool + +import ( + "encoding/hex" + "math/big" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/tmhash" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/mempool" +) + +// TestTransactionOrderingWithABCIMethodCalls tests transaction ordering based on fees +func (s *IntegrationTestSuite) TestTransactionOrderingWithABCIMethodCalls() { + testCases := []struct { + name string + setupTxs func() ([]sdk.Tx, []string) + // TODO: remove bypass option after anteHandler is fixed. + // Current anteHandler rejects valid high-gas transaction to replace low-gas transaction + // So, all replacement test cases fail. + bypass bool + }{ + { + name: "mixed EVM and cosmos transaction ordering", + setupTxs: func() ([]sdk.Tx, []string) { + // Create EVM transaction with high gas price + highGasPriceEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) + + // Create Cosmos transactions with different fee amounts + highFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(6), big.NewInt(5000000000)) + mediumFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(7), big.NewInt(3000000000)) + lowFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(8), big.NewInt(2000000000)) + + // Input txs in order + inputTxs := []sdk.Tx{lowFeeCosmosTx, highGasPriceEVMTx, mediumFeeCosmosTx, highFeeCosmosTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{highGasPriceEVMTx, highFeeCosmosTx, mediumFeeCosmosTx, lowFeeCosmosTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + }, + { + name: "EVM-only transaction replacement", + setupTxs: func() ([]sdk.Tx, []string) { + // Create first EVM transaction with low fee + lowFeeEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(2000000000)) // 2 gaatom + + // Create second EVM transaction with high fee + highFeeEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // 5 gaatom + + // Input txs in order + inputTxs := []sdk.Tx{lowFeeEVMTx, highFeeEVMTx} + + // Expected Txs in order + expectedTxs := []sdk.Tx{highFeeEVMTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + bypass: true, + }, + { + name: "EVM-only transaction ordering", + setupTxs: func() ([]sdk.Tx, []string) { + key := s.keyring.GetKey(0) + // Create first EVM transaction with low fee + lowFeeEVMTx := s.createEVMValueTransferTx(key, 1, big.NewInt(2000000000)) // 2 gaatom + + // Create second EVM transaction with high fee + highFeeEVMTx := s.createEVMValueTransferTx(key, 0, big.NewInt(5000000000)) // 5 gaatom + + // Input txs in order + inputTxs := []sdk.Tx{lowFeeEVMTx, highFeeEVMTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{highFeeEVMTx, lowFeeEVMTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + }, + { + name: "cosmos-only transaction replacement", + setupTxs: func() ([]sdk.Tx, []string) { + highFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5 gaatom + lowFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000000000)) // 2 gaatom + mediumFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(3000000000)) // 3 gaatom + + // Input txs in order + inputTxs := []sdk.Tx{mediumFeeTx, lowFeeTx, highFeeTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{highFeeTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + bypass: true, + }, + { + name: "mixed EVM and Cosmos transactions with equal effective tips", + setupTxs: func() ([]sdk.Tx, []string) { + // Create transactions with equal effective tips (assuming base fee = 0) + // EVM: 1000 aatom/gas effective tip + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) // 1 gaatom/gas + + // Cosmos with same effective tip: 1000 * 200000 = 200000000 aatom total fee + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000000000)) // 1 gaatom/gas effective tip + + // Input txs in order + inputTxs := []sdk.Tx{cosmosTx, evmTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{evmTx, cosmosTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + bypass: true, + }, + { + name: "mixed transactions with EVM having higher effective tip", + setupTxs: func() ([]sdk.Tx, []string) { + // Create EVM transaction with higher gas price + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // 5 gaatom/gas + + // Create Cosmos transaction with lower gas price + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000000000)) // 2 gaatom/gas + + // Input txs in order + inputTxs := []sdk.Tx{cosmosTx, evmTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{evmTx, cosmosTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + bypass: true, + }, + { + name: "mixed transactions with Cosmos having higher effective tip", + setupTxs: func() ([]sdk.Tx, []string) { + // Create EVM transaction with lower gas price + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(2000000000)) // 2000 aatom/gas + + // Create Cosmos transaction with higher gas price + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5000 aatom/gas + + // Input txs in order + inputTxs := []sdk.Tx{evmTx, cosmosTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{cosmosTx, evmTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + bypass: true, + }, + { + name: "mixed transaction ordering with multiple effective tips", + setupTxs: func() ([]sdk.Tx, []string) { + // Create multiple transactions with different gas prices + // EVM: 10000, 8000, 6000 aatom/gas + // Cosmos: 9000, 7000, 5000 aatom/gas + + evmHigh := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(10000000000)) + evmMedium := s.createEVMValueTransferTx(s.keyring.GetKey(1), 0, big.NewInt(8000000000)) + evmLow := s.createEVMValueTransferTx(s.keyring.GetKey(2), 0, big.NewInt(6000000000)) + + cosmosHigh := s.createCosmosSendTx(s.keyring.GetKey(3), big.NewInt(9000000000)) + cosmosMedium := s.createCosmosSendTx(s.keyring.GetKey(4), big.NewInt(7000000000)) + cosmosLow := s.createCosmosSendTx(s.keyring.GetKey(5), big.NewInt(5000000000)) + + // Input txs in order + inputTxs := []sdk.Tx{cosmosHigh, cosmosMedium, cosmosLow, evmHigh, evmMedium, evmLow} + + // Expected txs in order + expectedTxs := []sdk.Tx{evmHigh, cosmosHigh, evmMedium, cosmosMedium, evmLow, cosmosLow} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + // Reset test setup to ensure clean state + s.SetupTest() + + txs, expTxHashes := tc.setupTxs() + + // Call CheckTx for transactions + err := s.checkTxs(txs) + s.Require().NoError(err) + + // Call FinalizeBlock to make finalizeState before calling PrepareProposal + _, err = s.network.FinalizeBlock() + s.Require().NoError(err) + + // Call PrepareProposal to selcet transactions from mempool and make proposal + prepareProposalRes, err := s.network.App.PrepareProposal(&abci.RequestPrepareProposal{ + MaxTxBytes: 1_000_000, + Height: 1, + }) + s.Require().NoError(err) + + if tc.bypass { + return + } + + // Check whether expected transactions are included and returned as pending state in mempool + mpool := s.network.App.GetMempool() + iterator := mpool.Select(s.network.GetContext(), nil) + for _, txHash := range expTxHashes { + actualTxHash := s.getTxHash(iterator.Tx()) + s.Require().Equal(txHash, actualTxHash) + + iterator = iterator.Next() + } + + // Check whether expected transactions are selcted by PrepareProposal + txHashes := make([]string, 0) + for _, txBytes := range prepareProposalRes.Txs { + txHash := hex.EncodeToString(tmhash.Sum(txBytes)) + txHashes = append(txHashes, txHash) + } + s.Require().Equal(expTxHashes, txHashes) + }) + } +} + +// TestNonceGappedEVMTransactionsWithABCIMethodCalls tests the behavior of nonce-gapped EVM transactions +// and the transition from queued to pending when gaps are filled +func (s *IntegrationTestSuite) TestNonceGappedEVMTransactionsWithABCIMethodCalls() { + testCases := []struct { + name string + setupTxs func() ([]sdk.Tx, []string) // Returns transactions and their expected nonces + verifyFunc func(mpool mempool.Mempool) + bypass bool + }{ + { + name: "insert transactions with nonce gaps", + setupTxs: func() ([]sdk.Tx, []string) { + key := s.keyring.GetKey(0) + var txs []sdk.Tx + + // Insert transactions with gaps: nonces 0, 2, 4, 6 (missing 1, 3, 5) + for i := 0; i <= 6; i += 2 { + tx := s.createEVMValueTransferTx(key, i, big.NewInt(2000000000)) + txs = append(txs, tx) + } + + // Expected txs in order + expectedTxs := txs[:1] + expTxHashes := s.getTxHashes(expectedTxs) + + return txs, expTxHashes + }, + verifyFunc: func(mpool mempool.Mempool) { + // Only nonce 0 should be pending (the first consecutive transaction) + // nonces 2, 4, 6 should be queued + count := mpool.CountTx() + s.Require().Equal(1, count, "Only nonce 0 should be pending, others should be queued") + }, + }, + { + name: "fill nonce gap and verify pending count increases", + setupTxs: func() ([]sdk.Tx, []string) { + key := s.keyring.GetKey(0) + var txs []sdk.Tx + + // First, insert transactions with gaps: nonces 0, 2, 4 + for i := 0; i <= 4; i += 2 { + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) + txs = append(txs, tx) + } + + // Then fill the gap by inserting nonce 1 + tx := s.createEVMValueTransferTx(key, 1, big.NewInt(1000000000)) + txs = append(txs, tx) + + // Expected txs in order + expectedTxs := []sdk.Tx{txs[0], txs[3], txs[1]} + expTxHashes := s.getTxHashes(expectedTxs) + + return txs, expTxHashes + }, + verifyFunc: func(mpool mempool.Mempool) { + // After filling nonce 1, transactions 0, 1, 2 should be pending + // nonce 4 should still be queued + count := mpool.CountTx() + s.Require().Equal(3, count, "After filling gap, nonces 0, 1, 2 should be pending") + }, + }, + { + name: "fill multiple nonce gaps", + setupTxs: func() ([]sdk.Tx, []string) { + key := s.keyring.GetKey(0) + var txs []sdk.Tx + + // Insert transactions with multiple gaps: nonces 0, 3, 6, 9 + for i := 0; i <= 9; i += 3 { + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) + txs = append(txs, tx) + + } + + // Fill gaps by inserting nonces 1, 2, 4, 5, 7, 8 + for i := 1; i <= 8; i++ { + if i%3 != 0 { // Skip nonces that are already inserted + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) + txs = append(txs, tx) + + } + } + + // Expected txs in order + expectedTxs := []sdk.Tx{txs[0], txs[4], txs[5], txs[1], txs[6], txs[7], txs[2], txs[8], txs[9], txs[3]} + expTxHashes := s.getTxHashes(expectedTxs) + + return txs, expTxHashes + }, + verifyFunc: func(mpool mempool.Mempool) { + // After filling all gaps, all transactions should be pending + count := mpool.CountTx() + s.Require().Equal(10, count, "After filling all gaps, all 10 transactions should be pending") + }, + }, + { + name: "test different accounts with nonce gaps", + setupTxs: func() ([]sdk.Tx, []string) { + var txs []sdk.Tx + + // Use different keys for different accounts + key1 := s.keyring.GetKey(0) + key2 := s.keyring.GetKey(1) + + // Account 1: nonces 0, 2 (gap at 1) + for i := 0; i <= 2; i += 2 { + tx := s.createEVMValueTransferTx(key1, i, big.NewInt(1000000000)) + txs = append(txs, tx) + } + + // Account 2: nonces 0, 3 (gaps at 1, 2) + for i := 0; i <= 3; i += 3 { + tx := s.createEVMValueTransferTx(key2, i, big.NewInt(1000000000)) + txs = append(txs, tx) + } + + // Expected txs in order + expectedTxs := []sdk.Tx{txs[0], txs[2]} + expTxHashes := s.getTxHashes(expectedTxs) + + return txs, expTxHashes + }, + verifyFunc: func(mpool mempool.Mempool) { + // Account 1: nonce 0 pending, nonce 2 queued + // Account 2: nonce 0 pending, nonce 3 queued + // Total: 2 pending transactions + count := mpool.CountTx() + s.Require().Equal(2, count, "Only nonce 0 from each account should be pending") + }, + }, + { + name: "test replacement transactions with higher gas price", + setupTxs: func() ([]sdk.Tx, []string) { + key := s.keyring.GetKey(0) + var txs []sdk.Tx + + // Insert transaction with nonce 0 and low gas price + tx1 := s.createEVMValueTransferTx(key, 0, big.NewInt(1000000000)) + txs = append(txs, tx1) + + // Insert transaction with nonce 1 + tx2 := s.createEVMValueTransferTx(key, 1, big.NewInt(1000000000)) + txs = append(txs, tx2) + + // Replace nonce 0 transaction with higher gas price + tx3 := s.createEVMValueTransferTx(key, 0, big.NewInt(2000000000)) + txs = append(txs, tx3) + + // Expected txs in order + expectedTxs := []sdk.Tx{txs[2], txs[1]} + expTxHashes := s.getTxHashes(expectedTxs) + + return txs, expTxHashes + }, + verifyFunc: func(mpool mempool.Mempool) { + // After replacement, both nonces 0 and 1 should be pending + count := mpool.CountTx() + s.Require().Equal(2, count, "After replacement, both transactions should be pending") + }, + bypass: true, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.SetupTest() + + txs, expTxHashes := tc.setupTxs() + + // Call CheckTx for transactions + err := s.checkTxs(txs) + s.Require().NoError(err) + + // Call FinalizeBlock to make finalizeState before calling PrepareProposal + _, err = s.network.FinalizeBlock() + s.Require().NoError(err) + + // Call PrepareProposal to selcet transactions from mempool and make proposal + prepareProposalRes, err := s.network.App.PrepareProposal(&abci.RequestPrepareProposal{ + MaxTxBytes: 1_000_000, + Height: 1, + }) + s.Require().NoError(err) + + mpool := s.network.App.GetMempool() + iterator := mpool.Select(s.network.GetContext(), nil) + + if tc.bypass { + return + } + + // Check whether expected transactions are included and returned as pending state in mempool + for _, txHash := range expTxHashes { + actualTxHash := s.getTxHash(iterator.Tx()) + s.Require().Equal(txHash, actualTxHash) + + iterator = iterator.Next() + } + tc.verifyFunc(mpool) + + // Check whether expected transactions are selcted by PrepareProposal + txHashes := make([]string, 0) + for _, txBytes := range prepareProposalRes.Txs { + txHash := hex.EncodeToString(tmhash.Sum(txBytes)) + txHashes = append(txHashes, txHash) + } + s.Require().Equal(expTxHashes, txHashes) + }) + } +} diff --git a/testutil/integration/evm/network/abci.go b/testutil/integration/evm/network/abci.go index fc5bf9c54b..a1bdb7fa3f 100644 --- a/testutil/integration/evm/network/abci.go +++ b/testutil/integration/evm/network/abci.go @@ -30,6 +30,27 @@ func (n *IntegrationNetwork) NextBlockWithTxs(txBytes ...[]byte) (*abcitypes.Res return n.finalizeBlockAndCommit(time.Second, txBytes...) } +// FinalizeBlock is a helper function that runs FinalizeBlock logic +// without Commit and initializing context. +func (n *IntegrationNetwork) FinalizeBlock() (*abcitypes.ResponseFinalizeBlock, error) { + header := n.ctx.BlockHeader() + // Update block header and BeginBlock + header.Height++ + header.AppHash = n.app.LastCommitID().Hash + // Calculate new block time after duration + newBlockTime := header.Time.Add(time.Second) + header.Time = newBlockTime + + // FinalizeBlock to run endBlock, deliverTx & beginBlock logic + req := buildFinalizeBlockReq(header, n.valSet.Validators) + + res, err := n.app.FinalizeBlock(req) + if err != nil { + return nil, err + } + return res, nil +} + // finalizeBlockAndCommit is a private helper function that runs the FinalizeBlock logic // with the provided txBytes, updates the context and // commits the changes to have a block time after the given duration. From a5ba4a4922f921d380103003ed1584d353ddb073 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Fri, 5 Sep 2025 15:52:14 +0200 Subject: [PATCH 42/61] fix: remove `tokenType` parameter --- evmd/precompiles.go | 2 +- .../precompile_erc20_factory_test.go | 14 +++++ precompiles/erc20factory/IERC20Factory.sol | 7 +-- precompiles/erc20factory/abi.json | 16 ----- precompiles/erc20factory/erc20factory.go | 4 +- precompiles/erc20factory/events.go | 17 +++-- precompiles/erc20factory/interfaces.go | 4 ++ precompiles/erc20factory/query.go | 4 +- precompiles/erc20factory/tx.go | 23 +++---- precompiles/erc20factory/types.go | 62 ++++++++----------- .../erc20factory/test_erc20factory.go | 4 +- .../precompiles/erc20factory/test_events.go | 2 +- .../precompiles/erc20factory/test_query.go | 13 +--- .../precompiles/erc20factory/test_tx.go | 20 ++---- .../precompiles/erc20factory/test_types.go | 51 +++------------ .../precompiles/erc20factory/test_utils.go | 4 +- .../suites/precompiles/test/erc20factory.js | 15 ++--- x/erc20/types/errors.go | 1 + 18 files changed, 101 insertions(+), 162 deletions(-) create mode 100644 evmd/tests/integration/precompiles/erc20factory/precompile_erc20_factory_test.go diff --git a/evmd/precompiles.go b/evmd/precompiles.go index ea087072ef..a5a40ca239 100644 --- a/evmd/precompiles.go +++ b/evmd/precompiles.go @@ -143,7 +143,7 @@ func NewAvailableStaticPrecompiles( panic(fmt.Errorf("failed to instantiate slashing precompile: %w", err)) } - erc20FactoryPrecompile, err := erc20factory.NewPrecompile(&erc20Keeper, bankKeeper) + erc20FactoryPrecompile, err := erc20factory.NewPrecompile(&erc20Keeper, bankKeeper, evmKeeper) if err != nil { panic(fmt.Errorf("failed to instantiate erc20 factory precompile: %w", err)) } diff --git a/evmd/tests/integration/precompiles/erc20factory/precompile_erc20_factory_test.go b/evmd/tests/integration/precompiles/erc20factory/precompile_erc20_factory_test.go new file mode 100644 index 0000000000..26eb5d1c26 --- /dev/null +++ b/evmd/tests/integration/precompiles/erc20factory/precompile_erc20_factory_test.go @@ -0,0 +1,14 @@ +package erc20factory + +import ( + "testing" + + "github.com/cosmos/evm/evmd/tests/integration" + factory "github.com/cosmos/evm/tests/integration/precompiles/erc20factory" + "github.com/stretchr/testify/suite" +) + +func TestErc20FactoryPrecompileTestSuite(t *testing.T) { + s := factory.NewPrecompileTestSuite(integration.CreateEvmd) + suite.Run(t, s) +} diff --git a/precompiles/erc20factory/IERC20Factory.sol b/precompiles/erc20factory/IERC20Factory.sol index 20af2bc5d6..55e8409681 100644 --- a/precompiles/erc20factory/IERC20Factory.sol +++ b/precompiles/erc20factory/IERC20Factory.sol @@ -15,7 +15,6 @@ interface IERC20Factory { /** * @dev Emitted when a new ERC20 token is created. * @param tokenAddress The address of the ERC20 token. - * @param tokenPairType The type of token pair. * @param salt The salt used for deployment. * @param name The name of the token. * @param symbol The symbol of the token. @@ -23,7 +22,6 @@ interface IERC20Factory { */ event Create( address indexed tokenAddress, - uint8 tokenPairType, bytes32 salt, string name, string symbol, @@ -34,7 +32,6 @@ interface IERC20Factory { /** * @dev Defines a method for creating an ERC20 token. - * @param tokenPairType Token Pair type * @param salt Salt used for deployment * @param name The name of the token. * @param symbol The symbol of the token. @@ -42,7 +39,6 @@ interface IERC20Factory { * @return tokenAddress The ERC20 token address. */ function create( - uint8 tokenPairType, bytes32 salt, string memory name, string memory symbol, @@ -53,9 +49,8 @@ interface IERC20Factory { /** * @dev Calculates the deterministic address for a new token. - * @param tokenPairType Token Pair type * @param salt Salt used for deployment * @return tokenAddress The calculated ERC20 token address. */ - function calculateAddress(uint8 tokenPairType, bytes32 salt) external view returns (address tokenAddress); + function calculateAddress(bytes32 salt) external view returns (address tokenAddress); } \ No newline at end of file diff --git a/precompiles/erc20factory/abi.json b/precompiles/erc20factory/abi.json index 998c8881a3..4ff56cdd6c 100644 --- a/precompiles/erc20factory/abi.json +++ b/precompiles/erc20factory/abi.json @@ -12,12 +12,6 @@ "name": "tokenAddress", "type": "address" }, - { - "indexed": false, - "internalType": "uint8", - "name": "tokenPairType", - "type": "uint8" - }, { "indexed": false, "internalType": "bytes32", @@ -60,11 +54,6 @@ }, { "inputs": [ - { - "internalType": "uint8", - "name": "tokenPairType", - "type": "uint8" - }, { "internalType": "bytes32", "name": "salt", @@ -84,11 +73,6 @@ }, { "inputs": [ - { - "internalType": "uint8", - "name": "tokenPairType", - "type": "uint8" - }, { "internalType": "bytes32", "name": "salt", diff --git a/precompiles/erc20factory/erc20factory.go b/precompiles/erc20factory/erc20factory.go index 4225adeb47..fb93dd4d3d 100644 --- a/precompiles/erc20factory/erc20factory.go +++ b/precompiles/erc20factory/erc20factory.go @@ -36,11 +36,12 @@ type Precompile struct { cmn.Precompile erc20Keeper ERC20Keeper bankKeeper BankKeeper + evmKeeper EvmKeeper } // NewPrecompile creates a new bech32 Precompile instance as a // PrecompiledContract interface. -func NewPrecompile(erc20Keeper ERC20Keeper, bankKeeper cmn.BankKeeper) (*Precompile, error) { +func NewPrecompile(erc20Keeper ERC20Keeper, bankKeeper cmn.BankKeeper, keeper EvmKeeper) (*Precompile, error) { newABI, err := cmn.LoadABI(f, "abi.json") if err != nil { return nil, err @@ -54,6 +55,7 @@ func NewPrecompile(erc20Keeper ERC20Keeper, bankKeeper cmn.BankKeeper) (*Precomp }, erc20Keeper: erc20Keeper, bankKeeper: bankKeeper, + evmKeeper: keeper, } // SetAddress defines the address of the distribution compile contract. diff --git a/precompiles/erc20factory/events.go b/precompiles/erc20factory/events.go index e9dd15d352..2f778b7727 100644 --- a/precompiles/erc20factory/events.go +++ b/precompiles/erc20factory/events.go @@ -19,7 +19,7 @@ const ( ) // EmitCreateEvent emits the Create event. -func (p Precompile) EmitCreateEvent(ctx sdk.Context, stateDB vm.StateDB, tokenAddress common.Address, tokenType uint8, salt [32]uint8, name string, symbol string, decimals uint8, minter common.Address, premintedSupply *big.Int) error { +func (p Precompile) EmitCreateEvent(ctx sdk.Context, stateDB vm.StateDB, tokenAddress common.Address, salt [32]uint8, name string, symbol string, decimals uint8, minter common.Address, premintedSupply *big.Int) error { event := p.Events[EventTypeCreate] topics := make([]common.Hash, 2) // Only 2 topics: event ID + tokenAddress @@ -33,15 +33,14 @@ func (p Precompile) EmitCreateEvent(ctx sdk.Context, stateDB vm.StateDB, tokenAd // Pack the non-indexed event parameters into the data field arguments := abi.Arguments{ - event.Inputs[1], // tokenType - event.Inputs[2], // salt - event.Inputs[3], // name - event.Inputs[4], // symbol - event.Inputs[5], // decimals - event.Inputs[6], // minter - event.Inputs[7], // premintedSupply + event.Inputs[1], // salt + event.Inputs[2], // name + event.Inputs[3], // symbol + event.Inputs[4], // decimals + event.Inputs[5], // minter + event.Inputs[6], // premintedSupply } - packed, err := arguments.Pack(tokenType, salt, name, symbol, decimals, minter, premintedSupply) + packed, err := arguments.Pack(salt, name, symbol, decimals, minter, premintedSupply) if err != nil { return err } diff --git a/precompiles/erc20factory/interfaces.go b/precompiles/erc20factory/interfaces.go index abe08bced9..0e80185f32 100644 --- a/precompiles/erc20factory/interfaces.go +++ b/precompiles/erc20factory/interfaces.go @@ -23,3 +23,7 @@ type BankKeeper interface { MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error } + +type EvmKeeper interface { + GetCodeHash(ctx sdk.Context, addr common.Address) common.Hash +} diff --git a/precompiles/erc20factory/query.go b/precompiles/erc20factory/query.go index 5128ee205b..221841236c 100644 --- a/precompiles/erc20factory/query.go +++ b/precompiles/erc20factory/query.go @@ -18,12 +18,12 @@ func (p Precompile) CalculateAddress( caller common.Address, args []interface{}, ) ([]byte, error) { - tokenType, salt, err := ParseCalculateAddressArgs(args) + salt, err := ParseCalculateAddressArgs(args) if err != nil { return nil, err } - address := crypto.CreateAddress2(caller, salt, calculateCodeHash(tokenType)) + address := crypto.CreateAddress2(caller, salt, []byte{}) return method.Outputs.Pack(address) } diff --git a/precompiles/erc20factory/tx.go b/precompiles/erc20factory/tx.go index 2ee0a2315c..d423863622 100644 --- a/precompiles/erc20factory/tx.go +++ b/precompiles/erc20factory/tx.go @@ -4,14 +4,13 @@ package erc20factory import ( - "encoding/binary" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" erc20types "github.com/cosmos/evm/x/erc20/types" + evmtypes "github.com/cosmos/evm/x/vm/types" "cosmossdk.io/errors" "cosmossdk.io/math" @@ -33,12 +32,20 @@ func (p Precompile) Create( caller common.Address, args []interface{}, ) ([]byte, error) { - tokenType, salt, name, symbol, decimals, minter, premintedSupply, err := ParseCreateArgs(args) + salt, name, symbol, decimals, minter, premintedSupply, err := ParseCreateArgs(args) if err != nil { return nil, err } - address := crypto.CreateAddress2(caller, salt, calculateCodeHash(tokenType)) + address := crypto.CreateAddress2(caller, salt, []byte{}) + + hash := p.evmKeeper.GetCodeHash(ctx, address) + if hash.Cmp(common.BytesToHash(evmtypes.EmptyCodeHash)) != 0 { + return nil, errors.Wrapf( + erc20types.ErrContractAlreadyExists, + "contract already exists at address %s", address.String(), + ) + } metadata, err := p.createCoinMetadata(ctx, address, name, symbol, decimals) if err != nil { @@ -75,7 +82,7 @@ func (p Precompile) Create( return nil, err } - if err = p.EmitCreateEvent(ctx, stateDB, address, tokenType, salt, name, symbol, decimals, minter, premintedSupply); err != nil { + if err = p.EmitCreateEvent(ctx, stateDB, address, salt, name, symbol, decimals, minter, premintedSupply); err != nil { return nil, err } @@ -135,9 +142,3 @@ func (p Precompile) createCoinMetadata(ctx sdk.Context, address common.Address, return &metadata, nil } - -func calculateCodeHash(tokenType uint8) []byte { - tokenTypeBytes := make([]byte, 4) - binary.LittleEndian.PutUint32(tokenTypeBytes, uint32(tokenType)) - return tokenTypeBytes -} diff --git a/precompiles/erc20factory/types.go b/precompiles/erc20factory/types.go index 9059a2989c..0feaba006d 100644 --- a/precompiles/erc20factory/types.go +++ b/precompiles/erc20factory/types.go @@ -23,79 +23,69 @@ type EventCreate struct { // ParseCreateArgs parses the arguments from the create method and returns // the token type, salt, name, symbol, decimals, minter, and preminted supply. -func ParseCreateArgs(args []interface{}) (tokenType uint8, salt [32]uint8, name string, symbol string, decimals uint8, minter common.Address, premintedSupply *big.Int, err error) { - if len(args) != 7 { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 7, len(args)) +func ParseCreateArgs(args []interface{}) (salt [32]uint8, name string, symbol string, decimals uint8, minter common.Address, premintedSupply *big.Int, err error) { + if len(args) != 6 { + return [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 7, len(args)) } - tokenType, ok := args[0].(uint8) + salt, ok := args[0].([32]uint8) if !ok { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid tokenType") + return [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid salt") } - salt, ok = args[1].([32]uint8) - if !ok { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid salt") - } - - name, ok = args[2].(string) + name, ok = args[1].(string) if !ok || len(name) < 3 || len(name) > 128 { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid name") + return [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid name") } - symbol, ok = args[3].(string) - if !ok || len(symbol) < 3 || len(symbol) > 16 { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid symbol") + symbol, ok = args[2].(string) + if !ok || len(symbol) < 1 || len(symbol) > 16 { + return [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid symbol") } - decimals, ok = args[4].(uint8) + decimals, ok = args[3].(uint8) if !ok { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid decimals") + return [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid decimals") } - minter, ok = args[5].(common.Address) + minter, ok = args[4].(common.Address) if !ok { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid minter") + return [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid minter") } // Validate that minter is not the zero address if minter == (common.Address{}) { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid minter: cannot be zero address") + return [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid minter: cannot be zero address") } - premintedSupply, ok = args[6].(*big.Int) + premintedSupply, ok = args[5].(*big.Int) if !ok { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid premintedSupply: expected *big.Int") + return [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid premintedSupply: expected *big.Int") } if premintedSupply.Sign() < 0 { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid premintedSupply: cannot be negative") + return [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("invalid premintedSupply: cannot be negative") } maxUint256 := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) if premintedSupply.Cmp(maxUint256) > 0 { - return uint8(0), [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("premintedSupply exceeds uint256 maximum") + return [32]uint8{}, "", "", uint8(0), common.Address{}, nil, fmt.Errorf("premintedSupply exceeds uint256 maximum") } - return tokenType, salt, name, symbol, decimals, minter, premintedSupply, nil + return salt, name, symbol, decimals, minter, premintedSupply, nil } // ParseCalculateAddressArgs parses the arguments from the calculateAddress method and returns // the token type and salt. -func ParseCalculateAddressArgs(args []interface{}) (tokenType uint8, salt [32]uint8, err error) { - if len(args) != 2 { - return uint8(0), [32]uint8{}, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 2, len(args)) - } - - tokenType, ok := args[0].(uint8) - if !ok { - return uint8(0), [32]uint8{}, fmt.Errorf("invalid tokenType") +func ParseCalculateAddressArgs(args []interface{}) (salt [32]uint8, err error) { + if len(args) != 1 { + return [32]uint8{}, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 2, len(args)) } - salt, ok = args[1].([32]uint8) + salt, ok := args[0].([32]uint8) if !ok { - return uint8(0), [32]uint8{}, fmt.Errorf("invalid salt") + return [32]uint8{}, fmt.Errorf("invalid salt") } - return tokenType, salt, nil + return salt, nil } diff --git a/tests/integration/precompiles/erc20factory/test_erc20factory.go b/tests/integration/precompiles/erc20factory/test_erc20factory.go index 4f4afdd0a6..41ca6ce210 100644 --- a/tests/integration/precompiles/erc20factory/test_erc20factory.go +++ b/tests/integration/precompiles/erc20factory/test_erc20factory.go @@ -41,7 +41,7 @@ func (s *PrecompileTestSuite) TestRequiredGas() { { name: erc20factory.CalculateAddressMethod, malleate: func() []byte { - bz, err := s.precompile.Pack(erc20factory.CalculateAddressMethod, uint8(0), [32]uint8{}) + bz, err := s.precompile.Pack(erc20factory.CalculateAddressMethod, [32]uint8{}) s.Require().NoError(err, "expected no error packing ABI") return bz }, @@ -50,7 +50,7 @@ func (s *PrecompileTestSuite) TestRequiredGas() { { name: erc20factory.CreateMethod, malleate: func() []byte { - bz, err := s.precompile.Pack(erc20factory.CreateMethod, uint8(0), [32]uint8{}, name, symbol, decimals, mintAddr, amount) + bz, err := s.precompile.Pack(erc20factory.CreateMethod, [32]uint8{}, name, symbol, decimals, mintAddr, amount) s.Require().NoError(err, "expected no error packing ABI") return bz }, diff --git a/tests/integration/precompiles/erc20factory/test_events.go b/tests/integration/precompiles/erc20factory/test_events.go index 0f012724e8..1fd8cd8570 100644 --- a/tests/integration/precompiles/erc20factory/test_events.go +++ b/tests/integration/precompiles/erc20factory/test_events.go @@ -41,7 +41,7 @@ func (s *PrecompileTestSuite) TestEmitCreateEvent() { s.SetupTest() stateDB := s.network.GetStateDB() - err := s.precompile.EmitCreateEvent(s.network.GetContext(), stateDB, tc.tokenAddress, tc.tokenType, tc.salt, tc.name, tc.symbol, tc.decimals, tc.minter, tc.premintedSupply) + err := s.precompile.EmitCreateEvent(s.network.GetContext(), stateDB, tc.tokenAddress, tc.salt, tc.name, tc.symbol, tc.decimals, tc.minter, tc.premintedSupply) s.Require().NoError(err, "expected create event to be emitted successfully") log := stateDB.Logs()[0] diff --git a/tests/integration/precompiles/erc20factory/test_query.go b/tests/integration/precompiles/erc20factory/test_query.go index f4fcef4c55..fd17eb274b 100644 --- a/tests/integration/precompiles/erc20factory/test_query.go +++ b/tests/integration/precompiles/erc20factory/test_query.go @@ -21,26 +21,15 @@ func (s *PrecompileTestSuite) TestCalculateAddress() { name: "pass - correct arguments", caller: defaultCaller, args: []interface{}{ - uint8(0), [32]uint8(common.HexToHash("0x4f5b6f778b28c4d67a9c12345678901234567890123456789012345678901234").Bytes()), }, expPass: true, - expAddress: common.HexToAddress("0x188a919f3583f8e02183332E6c73E944E002C553"), - }, - { - name: "fail - invalid tokenType", - caller: defaultCaller, - args: []interface{}{ - "invalid tokenType", - "invalid salt", - }, - errContains: "invalid tokenType", + expAddress: common.HexToAddress("0xc047E2F9302F4dE42115E40CEdb3FA0F1CfbD6b7"), }, { name: "fail - invalid salt", caller: defaultCaller, args: []interface{}{ - uint8(0), "invalid salt", }, errContains: "invalid salt", diff --git a/tests/integration/precompiles/erc20factory/test_tx.go b/tests/integration/precompiles/erc20factory/test_tx.go index a741694702..e83b839826 100644 --- a/tests/integration/precompiles/erc20factory/test_tx.go +++ b/tests/integration/precompiles/erc20factory/test_tx.go @@ -14,7 +14,7 @@ import ( func (s *PrecompileTestSuite) TestCreate() { caller := common.HexToAddress("0x2c7882f69Cd115F470aAEde121f57F932936a56f") mintAddr := common.HexToAddress("0x73657398D483143AF7db7899757e5E7037fB713d") - expectedAddress := common.HexToAddress("0x30E56567F73403eD713dA0b0419e4A5330A16896") + expectedAddress := common.HexToAddress("0xc5ecc46b3cf020351c2186afCD5C734EE15E4da2") amount := big.NewInt(1000000) decimals := uint8(18) name := "Test" @@ -32,7 +32,7 @@ func (s *PrecompileTestSuite) TestCreate() { }{ { name: "pass - correct arguments", - args: []interface{}{uint8(0), [32]uint8(common.HexToHash("0x4f5b6f778b28c4d67a9c12345678901234567890123456789012345678901234").Bytes()), name, symbol, decimals, mintAddr, amount}, + args: []interface{}{[32]uint8(common.HexToHash("0x4f5b6f778b28c4d67a9c12345678901234567890123456789012345678901234").Bytes()), name, symbol, decimals, mintAddr, amount}, expPass: true, postExpPass: func(output []byte) { res, err := method.Outputs.Unpack(output) @@ -50,22 +50,19 @@ func (s *PrecompileTestSuite) TestCreate() { expAddress: expectedAddress, }, { - name: "fail - invalid tokenType", + name: "fail - blocked addresses cannot receive tokens", args: []interface{}{ - "invalid tokenType", - [32]uint8{}, + [32]uint8(common.HexToHash("0x4f5b6f778b28c4d67a9c12345678901234567890123456789012345678901234").Bytes()), name, symbol, decimals, - mintAddr, + erc20types.ModuleAddress, amount, }, - errContains: "invalid tokenType", }, { name: "fail - invalid salt", args: []interface{}{ - uint8(0), "invalid salt", name, symbol, @@ -78,7 +75,6 @@ func (s *PrecompileTestSuite) TestCreate() { { name: "fail - invalid name", args: []interface{}{ - uint8(0), [32]uint8{}, "", symbol, @@ -91,10 +87,9 @@ func (s *PrecompileTestSuite) TestCreate() { { name: "fail - invalid symbol", args: []interface{}{ - uint8(0), [32]uint8{}, name, - "is", + "", decimals, mintAddr, amount, @@ -104,7 +99,6 @@ func (s *PrecompileTestSuite) TestCreate() { { name: "fail - invalid decimals", args: []interface{}{ - uint8(0), [32]uint8{}, name, symbol, @@ -117,7 +111,6 @@ func (s *PrecompileTestSuite) TestCreate() { { name: "fail - invalid minter", args: []interface{}{ - uint8(0), [32]uint8{}, name, symbol, @@ -130,7 +123,6 @@ func (s *PrecompileTestSuite) TestCreate() { { name: "fail - invalid preminted supply", args: []interface{}{ - uint8(0), [32]uint8{}, name, symbol, diff --git a/tests/integration/precompiles/erc20factory/test_types.go b/tests/integration/precompiles/erc20factory/test_types.go index 1a3233e93d..bc665c95f7 100644 --- a/tests/integration/precompiles/erc20factory/test_types.go +++ b/tests/integration/precompiles/erc20factory/test_types.go @@ -21,19 +21,10 @@ func (s *PrecompileTestSuite) TestParseCalculateAddressArgs() { { name: "pass - correct arguments", args: []interface{}{ - uint8(0), [32]uint8{}, }, expPass: true, }, - { - name: "fail - invalid tokenType", - args: []interface{}{ - "invalid tokenType", - [32]uint8{}, - }, - errContains: "invalid tokenType", - }, { name: "fail - invalid salt", args: []interface{}{ @@ -52,11 +43,10 @@ func (s *PrecompileTestSuite) TestParseCalculateAddressArgs() { for _, tc := range testcases { s.Run(tc.name, func() { - tokenType, salt, err := erc20factory.ParseCalculateAddressArgs(tc.args) + salt, err := erc20factory.ParseCalculateAddressArgs(tc.args) if tc.expPass { s.Require().NoError(err, "unexpected error parsing the calculate address arguments") - s.Require().Equal(tokenType, tc.args[0], "expected different token type") - s.Require().Equal(salt, tc.args[1], "expected different salt") + s.Require().Equal(salt, tc.args[0], "expected different salt") } else { s.Require().Error(err, "expected an error parsing the calculate address arguments") s.Require().ErrorContains(err, tc.errContains, "expected different error message") @@ -83,7 +73,6 @@ func (s *PrecompileTestSuite) TestParseCreateArgs() { { name: "pass - correct arguments", args: []interface{}{ - uint8(0), [32]uint8{}, name, symbol, @@ -93,22 +82,9 @@ func (s *PrecompileTestSuite) TestParseCreateArgs() { }, expPass: true, }, - { - name: "fail - invalid tokenType", - args: []interface{}{ - "invalid tokenType", - [32]uint8{}, - name, - symbol, - decimals, - addr, - big.NewInt(1000000), - }, - }, { name: "fail - invalid salt", args: []interface{}{ - uint8(0), "invalid salt", name, symbol, @@ -120,7 +96,6 @@ func (s *PrecompileTestSuite) TestParseCreateArgs() { { name: "fail - invalid name", args: []interface{}{ - uint8(0), [32]uint8{}, uint8(0), symbol, @@ -133,10 +108,9 @@ func (s *PrecompileTestSuite) TestParseCreateArgs() { { name: "fail - invalid symbol", args: []interface{}{ - uint8(0), [32]uint8{}, name, - "is", + "", decimals, addr, big.NewInt(1000000), @@ -146,7 +120,6 @@ func (s *PrecompileTestSuite) TestParseCreateArgs() { { name: "fail - invalid decimals", args: []interface{}{ - uint8(0), [32]uint8{}, name, symbol, @@ -159,7 +132,6 @@ func (s *PrecompileTestSuite) TestParseCreateArgs() { { name: "fail - invalid minter", args: []interface{}{ - uint8(0), [32]uint8{}, name, symbol, @@ -172,7 +144,6 @@ func (s *PrecompileTestSuite) TestParseCreateArgs() { { name: "fail - zero address minter", args: []interface{}{ - uint8(0), [32]uint8{}, name, symbol, @@ -185,7 +156,6 @@ func (s *PrecompileTestSuite) TestParseCreateArgs() { { name: "fail - invalid preminted supply", args: []interface{}{ - uint8(0), [32]uint8{}, name, symbol, @@ -205,16 +175,15 @@ func (s *PrecompileTestSuite) TestParseCreateArgs() { for _, tc := range testcases { s.Run(tc.name, func() { - tokenType, salt, name, symbol, decimals, minter, premintedSupply, err := erc20factory.ParseCreateArgs(tc.args) + salt, name, symbol, decimals, minter, premintedSupply, err := erc20factory.ParseCreateArgs(tc.args) if tc.expPass { s.Require().NoError(err, "unexpected error parsing the create arguments") - s.Require().Equal(tokenType, tc.args[0], "expected different token type") - s.Require().Equal(salt, tc.args[1], "expected different salt") - s.Require().Equal(name, tc.args[2], "expected different name") - s.Require().Equal(symbol, tc.args[3], "expected different symbol") - s.Require().Equal(decimals, tc.args[4], "expected different decimals") - s.Require().Equal(minter, tc.args[5], "expected different minter") - s.Require().Equal(premintedSupply, tc.args[6], "expected different preminted supply") + s.Require().Equal(salt, tc.args[0], "expected different salt") + s.Require().Equal(name, tc.args[1], "expected different name") + s.Require().Equal(symbol, tc.args[2], "expected different symbol") + s.Require().Equal(decimals, tc.args[3], "expected different decimals") + s.Require().Equal(minter, tc.args[4], "expected different minter") + s.Require().Equal(premintedSupply, tc.args[5], "expected different preminted supply") } else { s.Require().Error(err, "expected an error parsing the create arguments") s.Require().ErrorContains(err, tc.errContains, "expected different error message") diff --git a/tests/integration/precompiles/erc20factory/test_utils.go b/tests/integration/precompiles/erc20factory/test_utils.go index 45b9985536..c85d95aa1e 100644 --- a/tests/integration/precompiles/erc20factory/test_utils.go +++ b/tests/integration/precompiles/erc20factory/test_utils.go @@ -11,7 +11,9 @@ import ( func (s *PrecompileTestSuite) setupERC20FactoryPrecompile() *erc20factory.Precompile { precompile, err := erc20factory.NewPrecompile( s.network.App.GetErc20Keeper(), - s.network.App.GetBankKeeper()) + s.network.App.GetBankKeeper(), + s.network.App.GetEVMKeeper(), + ) s.Require().NoError(err, "failed to create erc20factory precompile") return precompile diff --git a/tests/solidity/suites/precompiles/test/erc20factory.js b/tests/solidity/suites/precompiles/test/erc20factory.js index 3ef085b162..9a5402dc9a 100644 --- a/tests/solidity/suites/precompiles/test/erc20factory.js +++ b/tests/solidity/suites/precompiles/test/erc20factory.js @@ -2,19 +2,18 @@ const { expect } = require('chai') const hre = require('hardhat') const abi = [ - "function create(uint8 tokenPairType, bytes32 salt, string memory name, string memory symbol, uint8 decimals, address minter, uint256 premintedSupply) external returns (address)", - "function calculateAddress(uint8 tokenPairType, bytes32 salt) external view returns (address)", - "event Create(address indexed tokenAddress, uint8 tokenPairType, bytes32 salt, string name, string symbol, uint8 decimals, address minter, uint256 premintedSupply)" + "function create(bytes32 salt, string memory name, string memory symbol, uint8 decimals, address minter, uint256 premintedSupply) external returns (address)", + "function calculateAddress(bytes32 salt) external view returns (address)", + "event Create(address indexed tokenAddress, bytes32 salt, string name, string symbol, uint8 decimals, address minter, uint256 premintedSupply)" ] describe('ERC20Factory', function () { it('should calculate the correct address', async function () { const salt = '0x4f5b6f778b28c4d67a9c12345678901234567890123456789012345678901234' - const tokenPairType = 0 const erc20Factory = await hre.ethers.getContractAt('IERC20Factory', '0x0000000000000000000000000000000000000900') console.log("erc20Factory contract loaded") - const expectedAddress = await erc20Factory.calculateAddress(tokenPairType, salt) + const expectedAddress = await erc20Factory.calculateAddress(salt) console.log("erc20factory calculateAddress") expect(expectedAddress).to.equal('0x6a040655fE545126cD341506fCD4571dB3A444F9') }) @@ -24,7 +23,6 @@ describe('ERC20Factory', function () { const name = 'Test' const symbol = 'TEST' const decimals = 18 - const tokenPairType = 0 const premintedSupply = hre.ethers.parseEther("1000000") // 1M tokens const [signer] = await hre.ethers.getSigners() const minter = signer.address @@ -32,8 +30,8 @@ describe('ERC20Factory', function () { // Calculate the expected token address before deployment const erc20Factory = await hre.ethers.getContractAt('IERC20Factory', '0x0000000000000000000000000000000000000900') - const tokenAddress = await erc20Factory.calculateAddress(tokenPairType, salt) - const tx = await erc20Factory.connect(signer).create(tokenPairType, salt, name, symbol, decimals, minter, premintedSupply) + const tokenAddress = await erc20Factory.calculateAddress(salt) + const tx = await erc20Factory.connect(signer).create(salt, name, symbol, decimals, minter, premintedSupply) // Get the token address from the transaction receipt const receipt = await tx.wait() @@ -46,7 +44,6 @@ describe('ERC20Factory', function () { const createEvents = await erc20FactoryWithEvents.queryFilter(erc20FactoryWithEvents.filters.Create(), receipt.blockNumber, receipt.blockNumber) expect(createEvents.length).to.equal(1) expect(createEvents[0].args.tokenAddress).to.equal(tokenAddress) - expect(createEvents[0].args.tokenPairType).to.equal(tokenPairType) expect(createEvents[0].args.salt).to.equal(salt) expect(createEvents[0].args.name).to.equal(name) expect(createEvents[0].args.symbol).to.equal(symbol) diff --git a/x/erc20/types/errors.go b/x/erc20/types/errors.go index 99ad293f22..7f50187f9b 100644 --- a/x/erc20/types/errors.go +++ b/x/erc20/types/errors.go @@ -25,4 +25,5 @@ var ( ErrInvalidAllowance = errorsmod.Register(ModuleName, 18, "invalid allowance") ErrNegativeToken = errorsmod.Register(ModuleName, 19, "token amount is negative") ErrExpectedEvent = errorsmod.Register(ModuleName, 20, "expected event") + ErrContractAlreadyExists = errorsmod.Register(ModuleName, 21, "contract already exists") ) From 67950ad934f3393cf6a507dc1b5ad2aa46edaa60 Mon Sep 17 00:00:00 2001 From: Abdul Malek Date: Sun, 7 Sep 2025 14:46:00 -0400 Subject: [PATCH 43/61] feat: add block max_gas and min_tip ingestion to app.go mempool config (#582) * add block max_gas and minimum_gas_prices to app * add changelog * move methods out to config * add godoc * add tests * try depot again * back to gh runner * fix changelog error * remove wack evmd argument * add new flag * update changelog desc * change spaces to tab * repoint constant and add log * add const docs and change log to warn * fix lint * rm flag change --- CHANGELOG.md | 1 + config/server_app_options.go | 94 +++++++++ config/server_app_options_test.go | 332 ++++++++++++++++++++++++++++++ evmd/app.go | 16 +- local_node.sh | 3 +- mempool/mempool.go | 29 +-- server/config/config.go | 6 + server/config/toml.go | 3 + server/flags/flags.go | 1 + server/start.go | 1 + 10 files changed, 468 insertions(+), 18 deletions(-) create mode 100644 config/server_app_options.go create mode 100644 config/server_app_options_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 315d4f9ed9..c94336a077 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - [\#568](https://github.com/cosmos/evm/pull/568) Avoid unnecessary block notifications when the event bus is already set up. - [\#511](https://github.com/cosmos/evm/pull/511) Minor code cleanup for `AddPrecompileFn`. - [\#544](https://github.com/cosmos/evm/pull/544) Parse logs from the txResult.Data and avoid emitting EVM events to cosmos-sdk events. +- [\#582](https://github.com/cosmos/evm/pull/582) Add block max-gas (from genesis.json) and new min-tip (from app.toml/flags) ingestion into mempool config ### FEATURES diff --git a/config/server_app_options.go b/config/server_app_options.go new file mode 100644 index 0000000000..cac9cc7a1b --- /dev/null +++ b/config/server_app_options.go @@ -0,0 +1,94 @@ +package config + +import ( + "math" + "path/filepath" + + "github.com/holiman/uint256" + "github.com/spf13/cast" + + srvflags "github.com/cosmos/evm/server/flags" + + "cosmossdk.io/log" + + "github.com/cosmos/cosmos-sdk/client/flags" + sdkserver "github.com/cosmos/cosmos-sdk/server" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" +) + +// GetBlockGasLimit reads the genesis json file using AppGenesisFromFile +// to extract the consensus block gas limit before InitChain is called. +func GetBlockGasLimit(appOpts servertypes.AppOptions, logger log.Logger) uint64 { + homeDir := cast.ToString(appOpts.Get(flags.FlagHome)) + if homeDir == "" { + logger.Error("home directory not found in app options, using zero block gas limit") + return math.MaxUint64 + } + genesisPath := filepath.Join(homeDir, "config", "genesis.json") + + appGenesis, err := genutiltypes.AppGenesisFromFile(genesisPath) + if err != nil { + logger.Error("failed to load genesis using SDK AppGenesisFromFile, using zero block gas limit", "path", genesisPath, "error", err) + return 0 + } + genDoc, err := appGenesis.ToGenesisDoc() + if err != nil { + logger.Error("failed to convert AppGenesis to GenesisDoc, using zero block gas limit", "path", genesisPath, "error", err) + return 0 + } + + if genDoc.ConsensusParams == nil { + logger.Error("consensus parameters not found in genesis (nil), using zero block gas limit") + return 0 + } + + maxGas := genDoc.ConsensusParams.Block.MaxGas + if maxGas == -1 { + logger.Warn("genesis max_gas is unlimited (-1), using max uint64") + return math.MaxUint64 + } + if maxGas < -1 { + logger.Error("invalid max_gas value in genesis, using zero block gas limit") + return 0 + } + blockGasLimit := uint64(maxGas) // #nosec G115 -- maxGas >= 0 checked above + + logger.Debug( + "extracted block gas limit from genesis using SDK AppGenesisFromFile", + "genesis_path", genesisPath, + "max_gas", maxGas, + "block_gas_limit", blockGasLimit, + ) + + return blockGasLimit +} + +// GetMinGasPrices reads the min gas prices from the app options, set from app.toml +// This is currently not used, but is kept in case this is useful for the mempool, +// in addition to the min tip flag +func GetMinGasPrices(appOpts servertypes.AppOptions, logger log.Logger) sdk.DecCoins { + minGasPricesStr := cast.ToString(appOpts.Get(sdkserver.FlagMinGasPrices)) + minGasPrices, err := sdk.ParseDecCoins(minGasPricesStr) + if err != nil { + logger.With("error", err).Info("failed to parse min gas prices, using empty DecCoins") + minGasPrices = sdk.DecCoins{} + } + + return minGasPrices +} + +// GetMinTip reads the min tip from the app options, set from app.toml +// This field is also known as the minimum priority fee +func GetMinTip(appOpts servertypes.AppOptions, logger log.Logger) *uint256.Int { + minTipUint64 := cast.ToUint64(appOpts.Get(srvflags.EVMMinTip)) + minTip := uint256.NewInt(minTipUint64) + + if minTip.Cmp(uint256.NewInt(0)) >= 0 { // zero or positive + return minTip + } + + logger.Error("invalid min tip value in app.toml or flag, falling back to nil", "min_tip", minTipUint64) + return nil +} diff --git a/config/server_app_options_test.go b/config/server_app_options_test.go new file mode 100644 index 0000000000..ee4ed2ff13 --- /dev/null +++ b/config/server_app_options_test.go @@ -0,0 +1,332 @@ +package config + +import ( + "encoding/json" + "fmt" + "math" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/log" + sdkmath "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/client/flags" + sdkserver "github.com/cosmos/cosmos-sdk/server" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type mockAppOptions struct { + values map[string]interface{} +} + +func newMockAppOptions() *mockAppOptions { + return &mockAppOptions{ + values: make(map[string]interface{}), + } +} + +func (m *mockAppOptions) Get(key string) interface{} { + return m.values[key] +} + +func (m *mockAppOptions) Set(key string, value interface{}) { + m.values[key] = value +} + +func TestGetBlockGasLimit(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + setupFn func() servertypes.AppOptions + expected uint64 + }{ + { + name: "empty home directory returns max uint64", + setupFn: func() servertypes.AppOptions { + opts := newMockAppOptions() + return opts + }, + expected: math.MaxUint64, + }, + { + name: "genesis file not found returns 0", + setupFn: func() servertypes.AppOptions { + opts := newMockAppOptions() + opts.Set(flags.FlagHome, "/non/existent/directory") + return opts + }, + expected: 0, + }, + { + name: "valid genesis with max_gas = -1 returns max uint64", + setupFn: func() servertypes.AppOptions { + homeDir := createGenesisWithMaxGas(t, -1) + opts := newMockAppOptions() + opts.Set(flags.FlagHome, homeDir) + return opts + }, + expected: math.MaxUint64, + }, + { + name: "valid genesis with max_gas < -1 returns 0", + setupFn: func() servertypes.AppOptions { + homeDir := createGenesisWithMaxGas(t, -5) + opts := newMockAppOptions() + opts.Set(flags.FlagHome, homeDir) + return opts + }, + expected: 0, + }, + { + name: "valid genesis with max_gas = 0 returns 0", + setupFn: func() servertypes.AppOptions { + homeDir := createGenesisWithMaxGas(t, 0) + opts := newMockAppOptions() + opts.Set(flags.FlagHome, homeDir) + return opts + }, + expected: 0, + }, + { + name: "valid genesis with max_gas = 1000000 returns 1000000", + setupFn: func() servertypes.AppOptions { + homeDir := createGenesisWithMaxGas(t, 1000000) + opts := newMockAppOptions() + opts.Set(flags.FlagHome, homeDir) + return opts + }, + expected: 1000000, + }, + { + name: "genesis without consensus params returns 0", + setupFn: func() servertypes.AppOptions { + homeDir := createGenesisWithoutConsensusParams(t) + opts := newMockAppOptions() + opts.Set(flags.FlagHome, homeDir) + return opts + }, + expected: 0, + }, + { + name: "invalid genesis JSON returns 0", + setupFn: func() servertypes.AppOptions { + homeDir := createInvalidGenesis(t) + opts := newMockAppOptions() + opts.Set(flags.FlagHome, homeDir) + return opts + }, + expected: 0, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(_ *testing.T) { + appOpts := tc.setupFn() + logger := log.NewNopLogger() + + result := GetBlockGasLimit(appOpts, logger) + require.Equal(t, tc.expected, result, "GetBlockGasLimit returned unexpected value") + }) + } +} + +func TestGetMinGasPrices(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + setupFn func() servertypes.AppOptions + expected sdk.DecCoins + }{ + { + name: "valid single gas price", + setupFn: func() servertypes.AppOptions { + opts := newMockAppOptions() + opts.Set(sdkserver.FlagMinGasPrices, "0.025uatom") + return opts + }, + expected: sdk.DecCoins{sdk.NewDecCoinFromDec("uatom", sdkmath.LegacyMustNewDecFromStr("0.025"))}, + }, + { + name: "valid multiple gas prices", + setupFn: func() servertypes.AppOptions { + opts := newMockAppOptions() + opts.Set(sdkserver.FlagMinGasPrices, "0.025uatom,0.001stake") + return opts + }, + expected: sdk.DecCoins{ + sdk.NewDecCoinFromDec("stake", sdkmath.LegacyMustNewDecFromStr("0.001")), + sdk.NewDecCoinFromDec("uatom", sdkmath.LegacyMustNewDecFromStr("0.025")), + }, + }, + { + name: "empty gas prices returns empty DecCoins", + setupFn: func() servertypes.AppOptions { + opts := newMockAppOptions() + opts.Set(sdkserver.FlagMinGasPrices, "") + return opts + }, + expected: nil, + }, + { + name: "missing gas prices flag returns empty DecCoins", + setupFn: func() servertypes.AppOptions { + opts := newMockAppOptions() + return opts + }, + expected: nil, + }, + { + name: "invalid gas price format returns empty DecCoins", + setupFn: func() servertypes.AppOptions { + opts := newMockAppOptions() + opts.Set(sdkserver.FlagMinGasPrices, "invalid-format") + return opts + }, + expected: sdk.DecCoins{}, + }, + { + name: "malformed coin denomination returns empty DecCoins", + setupFn: func() servertypes.AppOptions { + opts := newMockAppOptions() + opts.Set(sdkserver.FlagMinGasPrices, "0.025") + return opts + }, + expected: sdk.DecCoins{}, + }, + { + name: "zero amount gas price", + setupFn: func() servertypes.AppOptions { + opts := newMockAppOptions() + opts.Set(sdkserver.FlagMinGasPrices, "0uatom") + return opts + }, + expected: sdk.DecCoins{}, + }, + { + name: "large decimal precision gas price", + setupFn: func() servertypes.AppOptions { + opts := newMockAppOptions() + opts.Set(sdkserver.FlagMinGasPrices, "0.000000000000000001uatom") + return opts + }, + expected: sdk.DecCoins{sdk.NewDecCoinFromDec("uatom", sdkmath.LegacyMustNewDecFromStr("0.000000000000000001"))}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(_ *testing.T) { + appOpts := tc.setupFn() + logger := log.NewNopLogger() + + result := GetMinGasPrices(appOpts, logger) + require.Equal(t, tc.expected, result, "GetMinGasPrices returned unexpected value") + }) + } +} + +func createGenesisWithMaxGas(t *testing.T, maxGas int64) string { + t.Helper() + tempDir := t.TempDir() + configDir := filepath.Join(tempDir, "config") + require.NoError(t, os.MkdirAll(configDir, 0o755)) + + genesis := map[string]interface{}{ + "app_name": "evmd", + "app_version": "test", + "chain_id": "test-chain", + "initial_height": 1, + "genesis_time": "2024-01-01T00:00:00Z", + "app_hash": nil, + "app_state": map[string]interface{}{ + "auth": map[string]interface{}{ + "params": map[string]interface{}{ + "max_memo_characters": "256", + "tx_sig_limit": "7", + "tx_size_cost_per_byte": "10", + "sig_verify_cost_ed25519": "590", + "sig_verify_cost_secp256k1": "1000", + }, + "accounts": []interface{}{}, + }, + }, + "consensus": map[string]interface{}{ + "params": map[string]interface{}{ + "block": map[string]interface{}{ + "max_bytes": "22020096", + "max_gas": fmt.Sprintf("%d", maxGas), + }, + "evidence": map[string]interface{}{ + "max_age_num_blocks": "100000", + "max_age_duration": "172800000000000", + "max_bytes": "1048576", + }, + "validator": map[string]interface{}{ + "pub_key_types": []string{"ed25519"}, + }, + "version": map[string]interface{}{ + "app": "0", + }, + }, + }, + } + + genesisBytes, err := json.MarshalIndent(genesis, "", " ") + require.NoError(t, err) + + genesisPath := filepath.Join(configDir, "genesis.json") + require.NoError(t, os.WriteFile(genesisPath, genesisBytes, 0o600)) + + return tempDir +} + +func createGenesisWithoutConsensusParams(t *testing.T) string { + t.Helper() + tempDir := t.TempDir() + configDir := filepath.Join(tempDir, "config") + require.NoError(t, os.MkdirAll(configDir, 0o755)) + + genesis := map[string]interface{}{ + "app_name": "evmd", + "app_version": "test", + "chain_id": "test-chain", + "initial_height": 1, + "genesis_time": "2024-01-01T00:00:00Z", + "app_hash": nil, + "app_state": map[string]interface{}{ + "auth": map[string]interface{}{ + "params": map[string]interface{}{}, + "accounts": []interface{}{}, + }, + }, + "consensus": map[string]interface{}{ + "params": nil, + }, + } + + genesisBytes, err := json.MarshalIndent(genesis, "", " ") + require.NoError(t, err) + + genesisPath := filepath.Join(configDir, "genesis.json") + require.NoError(t, os.WriteFile(genesisPath, genesisBytes, 0o600)) + + return tempDir +} + +func createInvalidGenesis(t *testing.T) string { + t.Helper() + tempDir := t.TempDir() + configDir := filepath.Join(tempDir, "config") + require.NoError(t, os.MkdirAll(configDir, 0o755)) + + invalidJSON := `{"invalid": json}` + genesisPath := filepath.Join(configDir, "genesis.json") + require.NoError(t, os.WriteFile(genesisPath, []byte(invalidJSON), 0o600)) + + return tempDir +} diff --git a/evmd/app.go b/evmd/app.go index d2f9478552..0fd2dde3bd 100644 --- a/evmd/app.go +++ b/evmd/app.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "os" "github.com/spf13/cast" @@ -84,7 +85,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" - "github.com/cosmos/cosmos-sdk/server" + sdkserver "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" @@ -409,7 +410,7 @@ func NewExampleApp( // get skipUpgradeHeights from the app options skipUpgradeHeights := map[int64]bool{} - for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { + for _, h := range cast.ToIntSlice(appOpts.Get(sdkserver.FlagUnsafeSkipUpgrades)) { skipUpgradeHeights[int64(h)] = true } homePath := cast.ToString(appOpts.Get(flags.FlagHome)) @@ -765,10 +766,15 @@ func NewExampleApp( // set the EVM priority nonce mempool // If you wish to use the noop mempool, remove this codeblock if evmtypes.GetChainConfig() != nil { - // TODO: Get the actual block gas limit from consensus parameters + // Get the block gas limit from genesis file + blockGasLimit := evmconfig.GetBlockGasLimit(appOpts, logger) + // Get GetMinTip from app.toml or cli flag configuration + mipTip := evmconfig.GetMinTip(appOpts, logger) + mempoolConfig := &evmmempool.EVMMempoolConfig{ AnteHandler: app.GetAnteHandler(), - BlockGasLimit: 100_000_000, + BlockGasLimit: blockGasLimit, + MinTip: mipTip, } evmMempool := evmmempool.NewExperimentalEVMMempool(app.CreateQueryContext, logger, app.EVMKeeper, app.FeeMarketKeeper, app.txConfig, app.clientCtx, mempoolConfig) @@ -1010,7 +1016,7 @@ func (app *EVMD) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfi app.BasicModuleManager.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // register swagger API from root so that other applications can override easily - if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil { + if err := sdkserver.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil { panic(err) } } diff --git a/local_node.sh b/local_node.sh index d176efaa1a..c04c163821 100755 --- a/local_node.sh +++ b/local_node.sh @@ -358,7 +358,8 @@ fi evmd start "$TRACE" \ --pruning nothing \ --log_level $LOGLEVEL \ - --minimum-gas-prices=0.0001atest \ + --minimum-gas-prices=0atest \ + --evm.min-tip=0 \ --home "$CHAINDIR" \ --json-rpc.api eth,txpool,personal,net,debug,web3 \ --chain-id "$CHAINID" diff --git a/mempool/mempool.go b/mempool/mempool.go index 23ad670a20..24c3687a43 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -29,7 +29,12 @@ import ( var _ sdkmempool.ExtMempool = &ExperimentalEVMMempool{} -const SubscriberName = "evm" +const ( + // SubscriberName is the name of the event bus subscriber for the EVM mempool + SubscriberName = "evm" + // fallbackBlockGasLimit is the default block gas limit is 0 or missing in genesis file + fallbackBlockGasLimit = 100_000_000 +) type ( // ExperimentalEVMMempool is a unified mempool that manages both EVM and Cosmos SDK transactions. @@ -52,6 +57,7 @@ type ( bondDenom string evmDenom string blockGasLimit uint64 // Block gas limit from consensus parameters + minTip *uint256.Int /** Verification **/ anteHandler sdk.AnteHandler @@ -72,6 +78,7 @@ type EVMMempoolConfig struct { AnteHandler sdk.AnteHandler BroadCastTxFn func(txs []*ethtypes.Transaction) error BlockGasLimit uint64 // Block gas limit from consensus parameters + MinTip *uint256.Int } // NewExperimentalEVMMempool creates a new unified mempool for EVM and Cosmos transactions. @@ -80,10 +87,8 @@ type EVMMempoolConfig struct { // of pools and verification functions, with sensible defaults created if not provided. func NewExperimentalEVMMempool(getCtxCallback func(height int64, prove bool) (sdk.Context, error), logger log.Logger, vmKeeper VMKeeperI, feeMarketKeeper FeeMarketKeeperI, txConfig client.TxConfig, clientCtx client.Context, config *EVMMempoolConfig) *ExperimentalEVMMempool { var ( - txPool *txpool.TxPool - cosmosPool sdkmempool.ExtMempool - anteHandler sdk.AnteHandler - blockchain *Blockchain + cosmosPool sdkmempool.ExtMempool + blockchain *Blockchain ) bondDenom := evmtypes.GetEVMCoinDenom() @@ -98,14 +103,13 @@ func NewExperimentalEVMMempool(getCtxCallback func(height int64, prove bool) (sd panic("config must not be nil") } - anteHandler = config.AnteHandler - blockchain = newBlockchain(getCtxCallback, logger, vmKeeper, feeMarketKeeper, config.BlockGasLimit) - if config.BlockGasLimit == 0 { - logger.Debug("block gas limit is 0, setting default", "default_limit", 100_000_000) - config.BlockGasLimit = 100_000_000 + logger.Warn("block gas limit is 0, setting to fallback", "fallback_limit", fallbackBlockGasLimit) + config.BlockGasLimit = fallbackBlockGasLimit } + blockchain = newBlockchain(getCtxCallback, logger, vmKeeper, feeMarketKeeper, config.BlockGasLimit) + // Create txPool from configuration legacyConfig := legacypool.DefaultConfig if config.LegacyPoolConfig != nil { @@ -180,7 +184,8 @@ func NewExperimentalEVMMempool(getCtxCallback func(height int64, prove bool) (sd bondDenom: bondDenom, evmDenom: evmDenom, blockGasLimit: config.BlockGasLimit, - anteHandler: anteHandler, + minTip: config.MinTip, + anteHandler: config.AnteHandler, } vmKeeper.SetEvmMempool(evmMempool) @@ -448,7 +453,7 @@ func (m *ExperimentalEVMMempool) getIterators(goCtx context.Context, i [][]byte) m.logger.Debug("getting iterators") pendingFilter := txpool.PendingFilter{ - MinTip: nil, + MinTip: m.minTip, BaseFee: baseFeeUint, BlobFee: nil, OnlyPlainTxs: true, diff --git a/server/config/config.go b/server/config/config.go index 8a256e381f..cabd791817 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -66,6 +66,9 @@ const ( // DefaultEVMChainID is the default EVM Chain ID if one is not provided DefaultEVMChainID = 262144 + // DefaultEVMMinTip is the default minimum priority fee for the mempool + DefaultEVMMinTip = 0 + // DefaultGasCap is the default cap on gas that can be used in eth_call/estimateGas DefaultGasCap uint64 = 25_000_000 @@ -143,6 +146,8 @@ type EVMConfig struct { EnablePreimageRecording bool `mapstructure:"cache-preimage"` // EVMChainID defines the EIP-155 replay-protection chain ID. EVMChainID uint64 `mapstructure:"evm-chain-id"` + // MinTip defines the minimum priority fee for the mempool + MinTip uint64 `mapstructure:"min-tip"` } // JSONRPCConfig defines configuration for the EVM RPC server. @@ -212,6 +217,7 @@ func DefaultEVMConfig() *EVMConfig { MaxTxGasWanted: DefaultMaxTxGasWanted, EVMChainID: DefaultEVMChainID, EnablePreimageRecording: DefaultEnablePreimageRecording, + MinTip: DefaultEVMMinTip, } } diff --git a/server/config/toml.go b/server/config/toml.go index c517bf1412..1e9d4689a1 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -22,6 +22,9 @@ cache-preimage = {{ .EVM.EnablePreimageRecording }} # EVMChainID is the EIP-155 compatible replay protection chain ID. This is separate from the Cosmos chain ID. evm-chain-id = {{ .EVM.EVMChainID }} +# MinTip defines the minimum priority fee for the mempool. +min-tip = {{ .EVM.MinTip }} + ############################################################################### ### JSON RPC Configuration ### ############################################################################### diff --git a/server/flags/flags.go b/server/flags/flags.go index 4d45bff429..3844fc7dfd 100644 --- a/server/flags/flags.go +++ b/server/flags/flags.go @@ -70,6 +70,7 @@ const ( EVMMaxTxGasWanted = "evm.max-tx-gas-wanted" EVMEnablePreimageRecording = "evm.cache-preimage" EVMChainID = "evm.evm-chain-id" + EVMMinTip = "evm.min-tip" ) // TLS flags diff --git a/server/start.go b/server/start.go index 580d222207..85ba9dad6b 100644 --- a/server/start.go +++ b/server/start.go @@ -219,6 +219,7 @@ which accepts a path for the resulting pprof file. cmd.Flags().Uint64(srvflags.EVMMaxTxGasWanted, cosmosevmserverconfig.DefaultMaxTxGasWanted, "the gas wanted for each eth tx returned in ante handler in check tx mode") //nolint:lll cmd.Flags().Bool(srvflags.EVMEnablePreimageRecording, cosmosevmserverconfig.DefaultEnablePreimageRecording, "Enables tracking of SHA3 preimages in the EVM (not implemented yet)") //nolint:lll cmd.Flags().Uint64(srvflags.EVMChainID, cosmosevmserverconfig.DefaultEVMChainID, "the EIP-155 compatible replay protection chain ID") + cmd.Flags().Uint64(srvflags.EVMMinTip, cosmosevmserverconfig.DefaultEVMMinTip, "the minimum priority fee for the mempool") cmd.Flags().String(srvflags.TLSCertPath, "", "the cert.pem file path for the server TLS configuration") cmd.Flags().String(srvflags.TLSKeyPath, "", "the key.pem file path for the server TLS configuration") From baed74a85d3ffa0294aeca1c952899888567e25b Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Tue, 9 Sep 2025 10:16:57 +0200 Subject: [PATCH 44/61] fix(tests/solidity): fix erc20factory calculate address test --- tests/solidity/suites/precompiles/test/erc20factory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/solidity/suites/precompiles/test/erc20factory.js b/tests/solidity/suites/precompiles/test/erc20factory.js index 9a5402dc9a..eac7d3bb11 100644 --- a/tests/solidity/suites/precompiles/test/erc20factory.js +++ b/tests/solidity/suites/precompiles/test/erc20factory.js @@ -15,7 +15,7 @@ describe('ERC20Factory', function () { console.log("erc20Factory contract loaded") const expectedAddress = await erc20Factory.calculateAddress(salt) console.log("erc20factory calculateAddress") - expect(expectedAddress).to.equal('0x6a040655fE545126cD341506fCD4571dB3A444F9') + expect(expectedAddress).to.equal('0x8C9521848ee0d03BF47390F98c6dc968DA0b2915') }) it('should create a new ERC20 token', async function () { From 0afdc34a22f3f36cbf8e03d4020ecb076b45590f Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Wed, 10 Sep 2025 23:00:53 +0200 Subject: [PATCH 45/61] chore: bump to ibc-go v10.3.0 (#592) * chore: bump to ibc-go v10.3.0 * chore: remove usage of subspace (#594) * chore: remove x/params and subspace usage * fix a whoopsie * lint * remove crisis module stuff for good measure * add changelog --- CHANGELOG.md | 1 + evmd/app.go | 76 +++++----------------- evmd/go.mod | 4 +- evmd/go.sum | 8 +-- evmd/tests/integration/testutil_test.go | 14 ---- evmd/tests/network/util.go | 6 -- go.mod | 6 +- go.sum | 8 +-- interfaces.go | 2 - tests/integration/x/ibc/test_msg_server.go | 2 - testutil/integration/evm/network/setup.go | 2 - x/ibc/transfer/keeper/keeper.go | 4 +- x/vm/keeper/keeper_test.go | 3 +- x/vm/types/params_legacy.go | 30 --------- 14 files changed, 27 insertions(+), 139 deletions(-) delete mode 100644 evmd/tests/integration/testutil_test.go delete mode 100644 x/vm/types/params_legacy.go diff --git a/CHANGELOG.md b/CHANGELOG.md index c94336a077..59e7dd1ab1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ ### API-BREAKING - [\#477](https://github.com/cosmos/evm/pull/477) Refactor precompile constructors to accept keeper interfaces instead of concrete implementations, breaking the existing `NewPrecompile` function signatures. +- [\#594](https://github.com/cosmos/evm/pull/594) Remove all usage of x/params ## v0.4.1 diff --git a/evmd/app.go b/evmd/app.go index 0fd2dde3bd..d4ec9ebe34 100644 --- a/evmd/app.go +++ b/evmd/app.go @@ -51,8 +51,6 @@ import ( ibctransfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" ibc "github.com/cosmos/ibc-go/v10/modules/core" - ibcclienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" - ibcconnectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types" porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" ibcapi "github.com/cosmos/ibc-go/v10/modules/core/api" ibcexported "github.com/cosmos/ibc-go/v10/modules/core/exported" @@ -121,15 +119,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/cosmos/cosmos-sdk/x/gov" - govclient "github.com/cosmos/cosmos-sdk/x/gov/client" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/mint" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" - paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" - paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" @@ -183,7 +177,6 @@ type EVMD struct { DistrKeeper distrkeeper.Keeper GovKeeper govkeeper.Keeper UpgradeKeeper *upgradekeeper.Keeper - ParamsKeeper paramskeeper.Keeper //nolint:staticcheck AuthzKeeper authzkeeper.Keeper EvidenceKeeper evidencekeeper.Keeper FeeGrantKeeper feegrantkeeper.Keeper @@ -277,7 +270,7 @@ func NewExampleApp( keys := storetypes.NewKVStoreKeys( authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, paramstypes.StoreKey, consensusparamtypes.StoreKey, + govtypes.StoreKey, consensusparamtypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, authzkeeper.StoreKey, // ibc keys ibcexported.StoreKey, ibctransfertypes.StoreKey, @@ -285,7 +278,7 @@ func NewExampleApp( evmtypes.StoreKey, feemarkettypes.StoreKey, erc20types.StoreKey, precisebanktypes.StoreKey, ) - tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey) + tkeys := storetypes.NewTransientStoreKeys(evmtypes.TransientKey, feemarkettypes.TransientKey) // load state streaming if enabled if err := bApp.RegisterStreamingServices(appOpts, keys); err != nil { @@ -308,7 +301,7 @@ func NewExampleApp( tkeys: tkeys, } - app.ParamsKeeper = initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) + // removed x/params: no ParamsKeeper initialization // get authority address authAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() @@ -428,7 +421,7 @@ func NewExampleApp( app.IBCKeeper = ibckeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[ibcexported.StoreKey]), - app.GetSubspace(ibcexported.ModuleName), + nil, app.UpgradeKeeper, authAddr, ) @@ -510,7 +503,6 @@ func NewExampleApp( app.TransferKeeper = transferkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[ibctransfertypes.StoreKey]), - app.GetSubspace(ibctransfertypes.ModuleName), app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, app.MsgServiceRouter(), @@ -595,14 +587,14 @@ func NewExampleApp( app.AccountKeeper, app.StakingKeeper, app, app.txConfig, ), - auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), - bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, nil), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, nil), feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), - gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), - mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), - slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName), app.interfaceRegistry), - distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), - staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), + gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, nil), + mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, nil), + slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, nil, app.interfaceRegistry), + distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, nil), + staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, nil), upgrade.NewAppModule(app.UpgradeKeeper, app.AccountKeeper.AddressCodec()), evidence.NewAppModule(app.EvidenceKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), @@ -626,13 +618,9 @@ func NewExampleApp( app.BasicModuleManager = module.NewBasicManagerFromManager( app.ModuleManager, map[string]module.AppModuleBasic{ - genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), - stakingtypes.ModuleName: staking.AppModuleBasic{}, - govtypes.ModuleName: gov.NewAppModuleBasic( - []govclient.ProposalHandler{ - paramsclient.ProposalHandler, - }, - ), + genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + stakingtypes.ModuleName: staking.AppModuleBasic{}, + govtypes.ModuleName: gov.NewAppModuleBasic(nil), ibctransfertypes.ModuleName: transfer.AppModuleBasic{AppModuleBasic: &ibctransfer.AppModuleBasic{}}, }, ) @@ -666,7 +654,7 @@ func NewExampleApp( evidencetypes.ModuleName, stakingtypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, govtypes.ModuleName, genutiltypes.ModuleName, authz.ModuleName, feegrant.ModuleName, - paramstypes.ModuleName, consensusparamtypes.ModuleName, + consensusparamtypes.ModuleName, precisebanktypes.ModuleName, vestingtypes.ModuleName, ) @@ -685,7 +673,7 @@ func NewExampleApp( distrtypes.ModuleName, slashingtypes.ModuleName, minttypes.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName, - feegrant.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName, consensusparamtypes.ModuleName, + feegrant.ModuleName, upgradetypes.ModuleName, consensusparamtypes.ModuleName, precisebanktypes.ModuleName, vestingtypes.ModuleName, ) @@ -743,7 +731,7 @@ func NewExampleApp( // NOTE: this is not required apps that don't use the simulator for fuzz testing // transactions overrideModules := map[string]module.AppModuleSimulation{ - authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, nil), } app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules) @@ -986,14 +974,6 @@ func (app *EVMD) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { return app.memKeys[storeKey] } -// GetSubspace returns a param subspace for a given module name. -// -// NOTE: This is solely to be used for testing purposes. -func (app *EVMD) GetSubspace(moduleName string) paramstypes.Subspace { - subspace, _ := app.ParamsKeeper.GetSubspace(moduleName) - return subspace -} - // SimulationManager implements the SimulationApp interface func (app *EVMD) SimulationManager() *module.SimulationManager { return app.sm @@ -1191,25 +1171,3 @@ func (app *EVMD) AutoCliOpts() autocli.AppOptions { ConsensusAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()), } } - -// initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { //nolint:staticcheck - paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) //nolint:staticcheck - - paramsKeeper.Subspace(authtypes.ModuleName) - paramsKeeper.Subspace(banktypes.ModuleName) - paramsKeeper.Subspace(stakingtypes.ModuleName) - paramsKeeper.Subspace(minttypes.ModuleName) - paramsKeeper.Subspace(distrtypes.ModuleName) - paramsKeeper.Subspace(slashingtypes.ModuleName) - paramsKeeper.Subspace(govtypes.ModuleName) - - // ibc modules - keyTable := ibcclienttypes.ParamKeyTable() - keyTable.RegisterParamSet(&ibcconnectiontypes.Params{}) - paramsKeeper.Subspace(ibcexported.ModuleName).WithKeyTable(keyTable) - paramsKeeper.Subspace(ibctransfertypes.ModuleName).WithKeyTable(ibctransfertypes.ParamKeyTable()) - // TODO: do we need a keytable? copied from Evmos repo - - return paramsKeeper -} diff --git a/evmd/go.mod b/evmd/go.mod index 19fe00f12b..321acf2008 100644 --- a/evmd/go.mod +++ b/evmd/go.mod @@ -19,7 +19,7 @@ require ( github.com/cosmos/cosmos-sdk v0.53.4 github.com/cosmos/evm v0.2.0 github.com/cosmos/gogoproto v1.7.0 - github.com/cosmos/ibc-go/v10 v10.0.0-beta.0.0.20250528142215-7d579b91ac6b + github.com/cosmos/ibc-go/v10 v10.3.0 github.com/ethereum/go-ethereum v1.15.11 github.com/onsi/ginkgo/v2 v2.23.4 github.com/onsi/gomega v1.38.0 @@ -86,7 +86,6 @@ require ( github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.2.2 // indirect - github.com/cosmos/ibc-go/modules/capability v1.0.1 // indirect github.com/cosmos/ics23/go v0.11.0 // indirect github.com/cosmos/ledger-cosmos-go v0.14.0 // indirect github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect @@ -163,7 +162,6 @@ require ( github.com/holiman/uint256 v1.3.2 // indirect github.com/huandu/skiplist v1.2.1 // indirect github.com/huin/goupnp v1.3.0 // indirect - github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/evmd/go.sum b/evmd/go.sum index 5f775b32e6..4bd49aa31c 100644 --- a/evmd/go.sum +++ b/evmd/go.sum @@ -868,10 +868,8 @@ github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fr github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/iavl v1.2.2 h1:qHhKW3I70w+04g5KdsdVSHRbFLgt3yY3qTMd4Xa4rC8= github.com/cosmos/iavl v1.2.2/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw= -github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= -github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= -github.com/cosmos/ibc-go/v10 v10.0.0-beta.0.0.20250528142215-7d579b91ac6b h1:+TaXFL0WksE7yBs6DqHrRIDtkKZfu3+Lirbs6rK4N20= -github.com/cosmos/ibc-go/v10 v10.0.0-beta.0.0.20250528142215-7d579b91ac6b/go.mod h1:AQ76dzfU5i3UB5UiktWe6q7hpbPyBXuZcnjMQekBkHs= +github.com/cosmos/ibc-go/v10 v10.3.0 h1:w5DkHih8qn15deAeFoTk778WJU+xC1krJ5kDnicfUBc= +github.com/cosmos/ibc-go/v10 v10.3.0/go.mod h1:CthaR7n4d23PJJ7wZHegmNgbVcLXCQql7EwHrAXnMtw= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= @@ -1300,8 +1298,6 @@ github.com/huandu/skiplist v1.2.1/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXM github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= -github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= diff --git a/evmd/tests/integration/testutil_test.go b/evmd/tests/integration/testutil_test.go deleted file mode 100644 index a8e33354cf..0000000000 --- a/evmd/tests/integration/testutil_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package integration - -import ( - "testing" - - "github.com/stretchr/testify/suite" - - "github.com/cosmos/evm/tests/integration/testutil" -) - -func TestTestUtilTestSuite(t *testing.T) { - s := testutil.NewTestSuite(CreateEvmd) - suite.Run(t, s) -} diff --git a/evmd/tests/network/util.go b/evmd/tests/network/util.go index 7d03ad1a09..fc4a538d46 100644 --- a/evmd/tests/network/util.go +++ b/evmd/tests/network/util.go @@ -30,7 +30,6 @@ import ( servercmtlog "github.com/cosmos/cosmos-sdk/server/log" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -227,11 +226,6 @@ func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalance inflationGenState.Params.MintDenom = cfg.BondDenom cfg.GenesisState[minttypes.ModuleName] = cfg.Codec.MustMarshalJSON(&inflationGenState) - var crisisGenState crisistypes.GenesisState - cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[crisistypes.ModuleName], &crisisGenState) - - crisisGenState.ConstantFee.Denom = cfg.BondDenom - cfg.GenesisState[crisistypes.ModuleName] = cfg.Codec.MustMarshalJSON(&crisisGenState) var evmGenState evmtypes.GenesisState cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[evmtypes.ModuleName], &evmGenState) diff --git a/go.mod b/go.mod index 320aef035f..2e66b76267 100644 --- a/go.mod +++ b/go.mod @@ -22,11 +22,11 @@ require ( github.com/cosmos/cosmos-sdk v0.53.4 github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/gogoproto v1.7.0 - github.com/cosmos/ibc-go/modules/capability v1.0.1 - github.com/cosmos/ibc-go/v10 v10.0.0-beta.0.0.20250528142215-7d579b91ac6b + github.com/cosmos/ibc-go/v10 v10.3.0 github.com/creachadair/tomledit v0.0.28 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/ethereum/go-ethereum v1.15.11 + github.com/gogo/protobuf v1.3.2 github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.3 @@ -142,7 +142,6 @@ require ( github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect - github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v1.2.5 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e // indirect @@ -172,7 +171,6 @@ require ( github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/huandu/skiplist v1.2.1 // indirect github.com/huin/goupnp v1.3.0 // indirect - github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect diff --git a/go.sum b/go.sum index 9cfa41a545..b3f7089a2d 100644 --- a/go.sum +++ b/go.sum @@ -863,10 +863,8 @@ github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fr github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/iavl v1.2.2 h1:qHhKW3I70w+04g5KdsdVSHRbFLgt3yY3qTMd4Xa4rC8= github.com/cosmos/iavl v1.2.2/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw= -github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= -github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= -github.com/cosmos/ibc-go/v10 v10.0.0-beta.0.0.20250528142215-7d579b91ac6b h1:+TaXFL0WksE7yBs6DqHrRIDtkKZfu3+Lirbs6rK4N20= -github.com/cosmos/ibc-go/v10 v10.0.0-beta.0.0.20250528142215-7d579b91ac6b/go.mod h1:AQ76dzfU5i3UB5UiktWe6q7hpbPyBXuZcnjMQekBkHs= +github.com/cosmos/ibc-go/v10 v10.3.0 h1:w5DkHih8qn15deAeFoTk778WJU+xC1krJ5kDnicfUBc= +github.com/cosmos/ibc-go/v10 v10.3.0/go.mod h1:CthaR7n4d23PJJ7wZHegmNgbVcLXCQql7EwHrAXnMtw= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= @@ -1284,8 +1282,6 @@ github.com/huandu/skiplist v1.2.1/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXM github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= -github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= diff --git a/interfaces.go b/interfaces.go index 30e3b27339..ecebf7e167 100644 --- a/interfaces.go +++ b/interfaces.go @@ -27,7 +27,6 @@ import ( distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" - paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) @@ -60,7 +59,6 @@ type EvmApp interface { //nolint:revive DefaultGenesis() map[string]json.RawMessage GetKey(storeKey string) *storetypes.KVStoreKey GetAnteHandler() sdk.AnteHandler - GetSubspace(moduleName string) paramstypes.Subspace MsgServiceRouter() *baseapp.MsgServiceRouter GetMempool() mempool.ExtMempool } diff --git a/tests/integration/x/ibc/test_msg_server.go b/tests/integration/x/ibc/test_msg_server.go index 79d8fa8c89..56a9599ceb 100644 --- a/tests/integration/x/ibc/test_msg_server.go +++ b/tests/integration/x/ibc/test_msg_server.go @@ -341,7 +341,6 @@ func (suite *KeeperTestSuite) TestTransfer() { suite.network.App.SetTransferKeeper(transferkeeper.NewKeeper( suite.network.App.AppCodec(), runtime.NewKVStoreService(suite.network.App.GetKey(types.StoreKey)), - suite.network.App.GetSubspace(types.ModuleName), &MockICS4Wrapper{}, // ICS4 Wrapper mockChannelKeeper, suite.network.App.MsgServiceRouter(), @@ -494,7 +493,6 @@ func (suite *KeeperTestSuite) TestPrefixTrimming() { suite.network.App.SetTransferKeeper(transferkeeper.NewKeeper( suite.network.App.AppCodec(), runtime.NewKVStoreService(suite.network.App.GetKey(types.StoreKey)), - suite.network.App.GetSubspace(types.ModuleName), &MockICS4Wrapper{}, // ICS4 Wrapper mockChannelKeeper, suite.network.App.MsgServiceRouter(), diff --git a/testutil/integration/evm/network/setup.go b/testutil/integration/evm/network/setup.go index 9951cf576b..f352bd4af4 100644 --- a/testutil/integration/evm/network/setup.go +++ b/testutil/integration/evm/network/setup.go @@ -15,7 +15,6 @@ import ( feemarkettypes "github.com/cosmos/evm/x/feemarket/types" evmtypes "github.com/cosmos/evm/x/vm/types" "github.com/cosmos/gogoproto/proto" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" sdkmath "cosmossdk.io/math" @@ -67,7 +66,6 @@ var genesisSetupFunctions = map[string]genSetupFn{ // This is handled accordingly on chain and context initialization return genesisState, nil }, - capabilitytypes.ModuleName: genStateSetter[*capabilitytypes.GenesisState](capabilitytypes.ModuleName), } // genStateSetter is a generic function to set module-specific genesis state diff --git a/x/ibc/transfer/keeper/keeper.go b/x/ibc/transfer/keeper/keeper.go index 4ec2e62499..48b150803c 100644 --- a/x/ibc/transfer/keeper/keeper.go +++ b/x/ibc/transfer/keeper/keeper.go @@ -9,7 +9,6 @@ import ( corestore "cosmossdk.io/core/store" "github.com/cosmos/cosmos-sdk/codec" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Keeper defines the modified IBC transfer keeper that embeds the original one. @@ -26,7 +25,6 @@ type Keeper struct { func NewKeeper( cdc codec.BinaryCodec, storeService corestore.KVStoreService, - paramSpace paramtypes.Subspace, ics4Wrapper porttypes.ICS4Wrapper, channelKeeper transfertypes.ChannelKeeper, @@ -38,7 +36,7 @@ func NewKeeper( ) Keeper { // create the original IBC transfer keeper for embedding transferKeeper := keeper.NewKeeper( - cdc, storeService, paramSpace, + cdc, storeService, nil, ics4Wrapper, channelKeeper, msgRouter, authKeeper, bankKeeper, authority, ) diff --git a/x/vm/keeper/keeper_test.go b/x/vm/keeper/keeper_test.go index 00197db39d..7e2a2f42f5 100644 --- a/x/vm/keeper/keeper_test.go +++ b/x/vm/keeper/keeper_test.go @@ -33,7 +33,6 @@ import ( distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -59,7 +58,7 @@ func (suite *KeeperTestSuite) SetupTest() { keys := storetypes.NewKVStoreKeys( authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, paramstypes.StoreKey, consensusparamtypes.StoreKey, + govtypes.StoreKey, consensusparamtypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, authzkeeper.StoreKey, // ibc keys ibcexported.StoreKey, ibctransfertypes.StoreKey, diff --git a/x/vm/types/params_legacy.go b/x/vm/types/params_legacy.go deleted file mode 100644 index 0a23499e00..0000000000 --- a/x/vm/types/params_legacy.go +++ /dev/null @@ -1,30 +0,0 @@ -package types - -import paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - -// Parameter keys -var ( - ParamStoreKeyEVMDenom = []byte("EVMDenom") - ParamStoreKeyEnableCreate = []byte("EnableCreate") - ParamStoreKeyEnableCall = []byte("EnableCall") - ParamStoreKeyExtraEIPs = []byte("EnableExtraEIPs") - ParamStoreKeyChainConfig = []byte("ChainConfig") -) - -// Deprecated: ParamKeyTable returns the parameter key table. -// Usage of x/params to manage parameters is deprecated in favor of x/gov -// controlled execution of MsgUpdateParams messages. These types remain solely -// for migration purposes and will be removed in a future release. -func ParamKeyTable() paramtypes.KeyTable { - return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) -} - -// Deprecated: ParamSetPairs returns the parameter set pairs. -// Usage of x/params to manage parameters is deprecated in favor of x/gov -// controlled execution of MsgUpdateParams messages. These types remain solely -// for migration purposes and will be removed in a future release. -func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{ - paramtypes.NewParamSetPair(ParamStoreKeyExtraEIPs, &p.ExtraEIPs, validateEIPs), - } -} From 8156e38e39c0de9608cd86f549b33337274ea38d Mon Sep 17 00:00:00 2001 From: Haber Date: Tue, 16 Sep 2025 00:11:04 +0900 Subject: [PATCH 46/61] fix(crypto): invalid type of PubKey.Address() method (#600) --- crypto/ethsecp256k1/ethsecp256k1.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crypto/ethsecp256k1/ethsecp256k1.go b/crypto/ethsecp256k1/ethsecp256k1.go index ea4b4731eb..11759a3c13 100644 --- a/crypto/ethsecp256k1/ethsecp256k1.go +++ b/crypto/ethsecp256k1/ethsecp256k1.go @@ -8,8 +8,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" - tmcrypto "github.com/cometbft/cometbft/crypto" - "github.com/cosmos/evm/ethereum/eip712" errorsmod "cosmossdk.io/errors" @@ -147,13 +145,13 @@ var ( // Address returns the address of the ECDSA public key. // The function will return an empty address if the public key is invalid. -func (pubKey PubKey) Address() tmcrypto.Address { +func (pubKey PubKey) Address() cryptotypes.Address { pubk, err := crypto.DecompressPubkey(pubKey.Key) if err != nil { return nil } - return tmcrypto.Address(crypto.PubkeyToAddress(*pubk).Bytes()) + return cryptotypes.Address(crypto.PubkeyToAddress(*pubk).Bytes()) } // Bytes returns the raw bytes of the ECDSA public key. From 1518fe33652ced4b6ce556588995e135ec7717d7 Mon Sep 17 00:00:00 2001 From: Abdul Malek Date: Mon, 15 Sep 2025 11:18:05 -0400 Subject: [PATCH 47/61] docs: add d2 tool to repo and mempool arch diagram (#597) * add mempool draft * add svg * update readme * add missing edge * make tx handler two lines * make ext mempool interface impl two lines --- Makefile | 70 ++++++++ mempool/README.md | 2 +- mempool/img/mempool_architecture.d2 | 62 +++++++ mempool/img/mempool_architecture.svg | 237 +++++++++++++++++++++++++++ 4 files changed, 370 insertions(+), 1 deletion(-) create mode 100644 mempool/img/mempool_architecture.d2 create mode 100644 mempool/img/mempool_architecture.svg diff --git a/Makefile b/Makefile index f4c3b58998..5bd994ea35 100644 --- a/Makefile +++ b/Makefile @@ -395,3 +395,73 @@ mocks: @go get github.com/vektra/mockery/v2 @go generate ./... @make format-go + +############################################################################### +### D2 Diagrams ### +############################################################################### + +D2_THEME=300 +D2_DARK_THEME=200 +D2_LAYOUT=tala + +D2_ENV_VARS=D2_THEME=$(D2_THEME) \ + D2_DARK_THEME=$(D2_DARK_THEME) \ + D2_LAYOUT=$(D2_LAYOUT) + +.PHONY: d2check d2watch d2gen d2gen-all + +d2check: + @echo "🔍 checking if d2 is installed..." + @which d2 > /dev/null 2>&1 || { \ + echo "🔴 d2 is not installed, see installation docs: https://d2lang.com/tour/install/"; \ + exit 1; \ + } + @echo "🟢 d2 is installed" + @echo "🔍 checking if $(D2_LAYOUT) layout is installed..." + @d2 layout | grep $(D2_LAYOUT) > /dev/null 2>&1 || { \ + echo "🔴 $(D2_LAYOUT) layout is not installed, see docs: https://d2lang.com/tour/layouts/"; \ + exit 1; \ + } + @echo "🟢 $(D2_LAYOUT) layout is installed" + +d2watch: d2check + @if [ -z "$(FILE)" ]; then \ + echo "🔴 missing required parameter FILE, the correct usage is: make d2watch FILE=path/to/file.d2"; \ + exit 1; \ + fi + @if [ ! -f "$(FILE)" ]; then \ + echo "🔴 file $(FILE) does not exist"; \ + exit 1; \ + fi + @echo "🔄 watching $(FILE) for changes..." + @dir=$$(dirname "$(FILE)"); \ + basename=$$(basename "$(FILE)" .d2); \ + svgfile="$$dir/$$basename.svg"; \ + printf "📊 generating $$svgfile from $(FILE)... "; \ + $(D2_ENV_VARS) d2 --watch "$(FILE)" "$$svgfile" + +d2gen: d2check + @if [ -z "$(FILE)" ]; then \ + echo "🔴 missing required parameter FILE, the correct usage is: make d2gen FILE=path/to/file.d2"; \ + exit 1; \ + fi + @if [ ! -f "$(FILE)" ]; then \ + echo "🔴 file $(FILE) does not exist"; \ + exit 1; \ + fi + @dir=$$(dirname "$(FILE)"); \ + basename=$$(basename "$(FILE)" .d2); \ + svgfile="$$dir/$$basename.svg"; \ + printf "📊 generating $$svgfile from $(FILE)... "; \ + $(D2_ENV_VARS) d2 "$(FILE)" "$$svgfile" > /dev/null 2>&1 && echo "done ✅" || echo "failed ❌"; + +d2gen-all: d2check + @echo "🟢 generating svg files for all d2 diagrams..." + @find . -name "*.d2" -type f | while read d2file; do \ + dir=$$(dirname "$$d2file"); \ + basename=$$(basename "$$d2file" .d2); \ + svgfile="$$dir/$$basename.svg"; \ + printf "📊 generating $$svgfile from $$d2file... "; \ + $(D2_ENV_VARS) d2 "$$d2file" "$$svgfile" > /dev/null 2>&1 && echo "done ✅" || echo "failed ❌"; \ + done + @echo "✅ svg files generated for all d2 diagrams" diff --git a/mempool/README.md b/mempool/README.md index e0a3737401..25230c8705 100644 --- a/mempool/README.md +++ b/mempool/README.md @@ -411,7 +411,7 @@ The following diagrams illustrate the complete transaction flow architecture, sh ### Architecture Overview -![EVM Mempool Architecture](img/mempool_architecture.jpg) +![EVM Mempool Architecture](img/mempool_architecture.svg) ### Transaction Flow diff --git a/mempool/img/mempool_architecture.d2 b/mempool/img/mempool_architecture.d2 new file mode 100644 index 0000000000..20f07e9ab2 --- /dev/null +++ b/mempool/img/mempool_architecture.d2 @@ -0,0 +1,62 @@ +direction: right + +# entities +prepare proposal +check tx\nhandler +comet bft +rpc call +broadcast +rebroadcast\ncallback: { shape: diamond } +evm mempool: { + direction: up + + # entities + ext mempool\ninterface impl + cosmos priority\nnonce mempool + tx pool: { + direction: up + + # entities + queued\ntransactions + pending\ntransactions + tx pool\ninterface + reset loop\n(evicts from\nqueued and\npending txs) + promotion: {shape: diamond } + filter: { shape: diamond } + + # edges + filter -> queued\ntransactions: add nonce\ngapped txs + filter -> pending\ntransactions: add\nexecutable txs + promotion -> pending\ntransactions: promote tx + queued\ntransactions -> promotion: check closed gap\nand promote tx + pending\ntransactions -> tx pool\ninterface: get txs for\nblock building + tx pool\ninterface -> filter: add valid txs + } + + # edges + tx pool.tx pool\ninterface -> ext mempool\ninterface impl: get txs for\nblock building + + cosmos priority\nnonce mempool -> ext mempool\ninterface impl: get txs for\nblock building + + ext mempool\ninterface impl -> tx pool.tx pool\ninterface: success/nonce gap failure:\nadd valid evm txs + ext mempool\ninterface impl -> tx pool.tx pool\ninterface: recheck tx\neviction + ext mempool\ninterface impl -> cosmos priority\nnonce mempool: add\ncosmos txs +} + +# edges +rebroadcast\ncallback -> comet bft: rebroadcast\nrebuilt tx + +evm mempool.tx pool.promotion -> rebroadcast\ncallback: call rebroadcast\ncallback +evm mempool.ext mempool\ninterface impl -> prepare proposal: get txs for\nblock building + +comet bft -> broadcast: success:\nbroadcast tx +comet bft -> check tx\nhandler: send tx for validation +comet bft -> check tx\nhandler: send tx again\nfor recheck + +check tx\nhandler -> rpc call: queued\nsuccess response +check tx\nhandler -> comet bft: success: broadcast\nand add to mempool +check tx\nhandler -> comet bft: recheck tx complete\nfailure: discard from pool +check tx\nhandler -> evm mempool.ext mempool\ninterface impl: complete failure:\nremove from pending +check tx\nhandler -> evm mempool.ext mempool\ninterface impl: nonce gap failure:\nadd transaction +check tx\nhandler -> evm mempool.ext mempool\ninterface impl: success:\nadd txs +check tx\nhandler -> evm mempool.ext mempool\ninterface impl: recheck tx complete\nfailure: eviction \ No newline at end of file diff --git a/mempool/img/mempool_architecture.svg b/mempool/img/mempool_architecture.svg new file mode 100644 index 0000000000..5a98f5c7d4 --- /dev/null +++ b/mempool/img/mempool_architecture.svg @@ -0,0 +1,237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +PREPARE PROPOSALCHECK TXHANDLERCOMET BFTRPC CALLBROADCASTREBROADCASTCALLBACKEVM MEMPOOLEXT MEMPOOLINTERFACE IMPLCOSMOS PRIORITYNONCE MEMPOOLTX POOLQUEUEDTRANSACTIONSPENDINGTRANSACTIONSTX POOLINTERFACERESET LOOP(EVICTS FROMQUEUED ANDPENDING TXS)PROMOTIONFILTER ADD NONCEGAPPED TXSADDEXECUTABLE TXSPROMOTE TXCHECK CLOSED GAPAND PROMOTE TXGET TXS FORBLOCK BUILDINGADD VALID TXSGET TXS FORBLOCK BUILDINGGET TXS FORBLOCK BUILDINGSUCCESS/NONCE GAP FAILURE:ADD VALID EVM TXSRECHECK TXEVICTIONADDCOSMOS TXSREBROADCASTREBUILT TXCALL REBROADCASTCALLBACKGET TXS FORBLOCK BUILDINGSUCCESS:BROADCAST TXSEND TX FOR VALIDATIONSEND TX AGAINFOR RECHECKQUEUEDSUCCESS RESPONSESUCCESS: BROADCASTAND ADD TO MEMPOOLRECHECK TX COMPLETEFAILURE: DISCARD FROM POOLCOMPLETE FAILURE:REMOVE FROM PENDINGNONCE GAP FAILURE:ADD TRANSACTIONSUCCESS:ADD TXSRECHECK TX COMPLETEFAILURE: EVICTION + + + + + + + + + + + + + + + + + + + + + + + + + +UNLICENSED COPY From dd7b4c77545908f968c647eb2b2a5b4c8d1d30a9 Mon Sep 17 00:00:00 2001 From: Vlad J Date: Mon, 15 Sep 2025 17:02:06 -0400 Subject: [PATCH 48/61] test: add nested precompile reversion test case (#535) * add nested precompile reversion test case adds complex precompile reversions that occur within nested try catch blocks to test for cache stack reversions to specific IDs * changelog * Update tests/integration/precompiles/staking/test_integration.go Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com> * remove changelog entry for test --------- Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com> Co-authored-by: Alex | Interchain Labs --- .../testutil/contracts/StakingReverter.sol | 30 +++++++++++ .../testutil/contracts/StakingReverter.json | 27 +++++++++- .../testutil/contracts/StakingReverter.sol | 30 +++++++++++ .../precompiles/staking/test_integration.go | 52 +++++++++++++++++++ x/vm/types/call.go | 2 +- 5 files changed, 138 insertions(+), 3 deletions(-) diff --git a/contracts/solidity/precompiles/testutil/contracts/StakingReverter.sol b/contracts/solidity/precompiles/testutil/contracts/StakingReverter.sol index 469267cb43..aef5d526b5 100644 --- a/contracts/solidity/precompiles/testutil/contracts/StakingReverter.sol +++ b/contracts/solidity/precompiles/testutil/contracts/StakingReverter.sol @@ -49,6 +49,36 @@ contract StakingReverter { STAKING_CONTRACT.delegate(address(this), validatorAddress, 10); } + /// @dev nestedTryCatchDelegations performs nested try/catch calls to precompile + /// where inner calls revert intentionally. Only the successful delegations + /// outside the reverting scope should persist. + /// + /// Expected successful delegations: 1 (before loop) + outerTimes (after each catch) + 1 (after loop) + function nestedTryCatchDelegations(uint outerTimes, uint innerTimes, string calldata validatorAddress) external { + // Initial successful delegate before any nested reverts + STAKING_CONTRACT.delegate(address(this), validatorAddress, 10); + + for (uint i = 0; i < outerTimes; i++) { + // Outer call that will revert and be caught + try StakingReverter(address(this)).performDelegation(validatorAddress) { + // no-op + } catch { + // After catching the revert, perform a successful delegate + STAKING_CONTRACT.delegate(address(this), validatorAddress, 10); + + // Inner nested loop of reverting calls + for (uint j = 0; j < innerTimes; j++) { + try StakingReverter(address(this)).performDelegation(validatorAddress) { + // no-op + } catch {} + } + } + } + + // Final successful delegate after the loops + STAKING_CONTRACT.delegate(address(this), validatorAddress, 10); + } + function performDelegation(string calldata validatorAddress) external { STAKING_CONTRACT.delegate(address(this), validatorAddress, 10); revert(); diff --git a/precompiles/testutil/contracts/StakingReverter.json b/precompiles/testutil/contracts/StakingReverter.json index 9b4bc012f3..c0ae8d765b 100644 --- a/precompiles/testutil/contracts/StakingReverter.json +++ b/precompiles/testutil/contracts/StakingReverter.json @@ -161,6 +161,29 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "outerTimes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "innerTimes", + "type": "uint256" + }, + { + "internalType": "string", + "name": "validatorAddress", + "type": "string" + } + ], + "name": "nestedTryCatchDelegations", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -193,8 +216,8 @@ "type": "function" } ], - "bytecode": "0x6080604052600080556111b7806100176000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80634e5a8fe51461006757806352fce7b114610083578063668f452b1461009f578063922a4b67146100d0578063cbc367d4146100ec578063f66013d71461011c575b600080fd5b610081600480360381019061007c919061072a565b610138565b005b61009d6004803603810190610098919061072a565b6101da565b005b6100b960048036038101906100b4919061078a565b610282565b6040516100c79291906108c2565b60405180910390f35b6100ea60048036038101906100e5919061072a565b61031c565b005b61010660048036038101906101019190610950565b6104b3565b6040516101139190610b3b565b60405180910390f35b6101366004803603810190610131919061078a565b610563565b005b60008081548092919061014a90610b8c565b919050555060005b838110156101d4573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b8152600401610195929190610c21565b600060405180830381600087803b1580156101af57600080fd5b505af19250505080156101c0575060015b5080806101cc90610b8c565b915050610152565b50505050565b6000808154809291906101ec90610b8c565b919050555060005b8381101561027c573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b8152600401610237929190610c21565b600060405180830381600087803b15801561025157600080fd5b505af1158015610265573d6000803e3d6000fd5b50505050808061027490610b8c565b9150506101f4565b50505050565b600061028c6105ed565b61080073ffffffffffffffffffffffffffffffffffffffff1663241774e63086866040518463ffffffff1660e01b81526004016102cb93929190610c54565b600060405180830381865afa1580156102e8573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906103119190610e32565b915091509250929050565b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b815260040161035e9493929190610ed3565b6020604051808303816000875af115801561037d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a19190610f3f565b5060005b83811015610427573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b81526004016103e8929190610c21565b600060405180830381600087803b15801561040257600080fd5b505af1925050508015610413575060015b50808061041f90610b8c565b9150506103a5565b5061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b815260040161046a9493929190610ed3565b6020604051808303816000875af1158015610489573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ad9190610f3f565b50505050565b6104bb610607565b60005b8381101561055c5761080073ffffffffffffffffffffffffffffffffffffffff1663223b3b7a846040518263ffffffff1660e01b81526004016105019190610f6c565b600060405180830381865afa15801561051e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906105479190611138565b9150808061055490610b8c565b9150506104be565b5092915050565b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b81526004016105a59493929190610ed3565b6020604051808303816000875af11580156105c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e89190610f3f565b600080fd5b604051806040016040528060608152602001600081525090565b60405180610160016040528060608152602001606081526020016000151581526020016000600381111561063e5761063d6109ab565b5b8152602001600081526020016000815260200160608152602001600060070b8152602001600060070b815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6106a28161068f565b81146106ad57600080fd5b50565b6000813590506106bf81610699565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126106ea576106e96106c5565b5b8235905067ffffffffffffffff811115610707576107066106ca565b5b602083019150836001820283011115610723576107226106cf565b5b9250929050565b60008060006040848603121561074357610742610685565b5b6000610751868287016106b0565b935050602084013567ffffffffffffffff8111156107725761077161068a565b5b61077e868287016106d4565b92509250509250925092565b600080602083850312156107a1576107a0610685565b5b600083013567ffffffffffffffff8111156107bf576107be61068a565b5b6107cb858286016106d4565b92509250509250929050565b6107e08161068f565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610820578082015181840152602081019050610805565b60008484015250505050565b6000601f19601f8301169050919050565b6000610848826107e6565b61085281856107f1565b9350610862818560208601610802565b61086b8161082c565b840191505092915050565b61087f8161068f565b82525050565b600060408301600083015184820360008601526108a2828261083d565b91505060208301516108b76020860182610876565b508091505092915050565b60006040820190506108d760008301856107d7565b81810360208301526108e98184610885565b90509392505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061091d826108f2565b9050919050565b61092d81610912565b811461093857600080fd5b50565b60008135905061094a81610924565b92915050565b6000806040838503121561096757610966610685565b5b6000610975858286016106b0565b92505060206109868582860161093b565b9150509250929050565b60008115159050919050565b6109a581610990565b82525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600481106109eb576109ea6109ab565b5b50565b60008190506109fc826109da565b919050565b6000610a0c826109ee565b9050919050565b610a1c81610a01565b82525050565b60008160070b9050919050565b610a3881610a22565b82525050565b6000610160830160008301518482036000860152610a5c828261083d565b91505060208301518482036020860152610a76828261083d565b9150506040830151610a8b604086018261099c565b506060830151610a9e6060860182610a13565b506080830151610ab16080860182610876565b5060a0830151610ac460a0860182610876565b5060c083015184820360c0860152610adc828261083d565b91505060e0830151610af160e0860182610a2f565b50610100830151610b06610100860182610a2f565b50610120830151610b1b610120860182610876565b50610140830151610b30610140860182610876565b508091505092915050565b60006020820190508181036000830152610b558184610a3e565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610b978261068f565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610bc957610bc8610b5d565b5b600182019050919050565b600082825260208201905092915050565b82818337600083830152505050565b6000610c008385610bd4565b9350610c0d838584610be5565b610c168361082c565b840190509392505050565b60006020820190508181036000830152610c3c818486610bf4565b90509392505050565b610c4e81610912565b82525050565b6000604082019050610c696000830186610c45565b8181036020830152610c7c818486610bf4565b9050949350505050565b600081519050610c9581610699565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610cd88261082c565b810181811067ffffffffffffffff82111715610cf757610cf6610ca0565b5b80604052505050565b6000610d0a61067b565b9050610d168282610ccf565b919050565b600080fd5b600080fd5b600067ffffffffffffffff821115610d4057610d3f610ca0565b5b610d498261082c565b9050602081019050919050565b6000610d69610d6484610d25565b610d00565b905082815260208101848484011115610d8557610d84610d20565b5b610d90848285610802565b509392505050565b600082601f830112610dad57610dac6106c5565b5b8151610dbd848260208601610d56565b91505092915050565b600060408284031215610ddc57610ddb610c9b565b5b610de66040610d00565b9050600082015167ffffffffffffffff811115610e0657610e05610d1b565b5b610e1284828501610d98565b6000830152506020610e2684828501610c86565b60208301525092915050565b60008060408385031215610e4957610e48610685565b5b6000610e5785828601610c86565b925050602083015167ffffffffffffffff811115610e7857610e7761068a565b5b610e8485828601610dc6565b9150509250929050565b6000819050919050565b6000819050919050565b6000610ebd610eb8610eb384610e8e565b610e98565b61068f565b9050919050565b610ecd81610ea2565b82525050565b6000606082019050610ee86000830187610c45565b8181036020830152610efb818587610bf4565b9050610f0a6040830184610ec4565b95945050505050565b610f1c81610990565b8114610f2757600080fd5b50565b600081519050610f3981610f13565b92915050565b600060208284031215610f5557610f54610685565b5b6000610f6384828501610f2a565b91505092915050565b6000602082019050610f816000830184610c45565b92915050565b60048110610f9457600080fd5b50565b600081519050610fa681610f87565b92915050565b610fb581610a22565b8114610fc057600080fd5b50565b600081519050610fd281610fac565b92915050565b60006101608284031215610fef57610fee610c9b565b5b610ffa610160610d00565b9050600082015167ffffffffffffffff81111561101a57611019610d1b565b5b61102684828501610d98565b600083015250602082015167ffffffffffffffff81111561104a57611049610d1b565b5b61105684828501610d98565b602083015250604061106a84828501610f2a565b604083015250606061107e84828501610f97565b606083015250608061109284828501610c86565b60808301525060a06110a684828501610c86565b60a08301525060c082015167ffffffffffffffff8111156110ca576110c9610d1b565b5b6110d684828501610d98565b60c08301525060e06110ea84828501610fc3565b60e0830152506101006110ff84828501610fc3565b6101008301525061012061111584828501610c86565b6101208301525061014061112b84828501610c86565b6101408301525092915050565b60006020828403121561114e5761114d610685565b5b600082015167ffffffffffffffff81111561116c5761116b61068a565b5b61117884828501610fd8565b9150509291505056fea2646970667358221220f5f833c34bff960673e6df4fad50cb2e0deb7da5035552189c3d4e09281dd21264736f6c63430008140033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c80634e5a8fe51461006757806352fce7b114610083578063668f452b1461009f578063922a4b67146100d0578063cbc367d4146100ec578063f66013d71461011c575b600080fd5b610081600480360381019061007c919061072a565b610138565b005b61009d6004803603810190610098919061072a565b6101da565b005b6100b960048036038101906100b4919061078a565b610282565b6040516100c79291906108c2565b60405180910390f35b6100ea60048036038101906100e5919061072a565b61031c565b005b61010660048036038101906101019190610950565b6104b3565b6040516101139190610b3b565b60405180910390f35b6101366004803603810190610131919061078a565b610563565b005b60008081548092919061014a90610b8c565b919050555060005b838110156101d4573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b8152600401610195929190610c21565b600060405180830381600087803b1580156101af57600080fd5b505af19250505080156101c0575060015b5080806101cc90610b8c565b915050610152565b50505050565b6000808154809291906101ec90610b8c565b919050555060005b8381101561027c573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b8152600401610237929190610c21565b600060405180830381600087803b15801561025157600080fd5b505af1158015610265573d6000803e3d6000fd5b50505050808061027490610b8c565b9150506101f4565b50505050565b600061028c6105ed565b61080073ffffffffffffffffffffffffffffffffffffffff1663241774e63086866040518463ffffffff1660e01b81526004016102cb93929190610c54565b600060405180830381865afa1580156102e8573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906103119190610e32565b915091509250929050565b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b815260040161035e9493929190610ed3565b6020604051808303816000875af115801561037d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a19190610f3f565b5060005b83811015610427573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b81526004016103e8929190610c21565b600060405180830381600087803b15801561040257600080fd5b505af1925050508015610413575060015b50808061041f90610b8c565b9150506103a5565b5061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b815260040161046a9493929190610ed3565b6020604051808303816000875af1158015610489573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ad9190610f3f565b50505050565b6104bb610607565b60005b8381101561055c5761080073ffffffffffffffffffffffffffffffffffffffff1663223b3b7a846040518263ffffffff1660e01b81526004016105019190610f6c565b600060405180830381865afa15801561051e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906105479190611138565b9150808061055490610b8c565b9150506104be565b5092915050565b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b81526004016105a59493929190610ed3565b6020604051808303816000875af11580156105c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e89190610f3f565b600080fd5b604051806040016040528060608152602001600081525090565b60405180610160016040528060608152602001606081526020016000151581526020016000600381111561063e5761063d6109ab565b5b8152602001600081526020016000815260200160608152602001600060070b8152602001600060070b815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6106a28161068f565b81146106ad57600080fd5b50565b6000813590506106bf81610699565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126106ea576106e96106c5565b5b8235905067ffffffffffffffff811115610707576107066106ca565b5b602083019150836001820283011115610723576107226106cf565b5b9250929050565b60008060006040848603121561074357610742610685565b5b6000610751868287016106b0565b935050602084013567ffffffffffffffff8111156107725761077161068a565b5b61077e868287016106d4565b92509250509250925092565b600080602083850312156107a1576107a0610685565b5b600083013567ffffffffffffffff8111156107bf576107be61068a565b5b6107cb858286016106d4565b92509250509250929050565b6107e08161068f565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610820578082015181840152602081019050610805565b60008484015250505050565b6000601f19601f8301169050919050565b6000610848826107e6565b61085281856107f1565b9350610862818560208601610802565b61086b8161082c565b840191505092915050565b61087f8161068f565b82525050565b600060408301600083015184820360008601526108a2828261083d565b91505060208301516108b76020860182610876565b508091505092915050565b60006040820190506108d760008301856107d7565b81810360208301526108e98184610885565b90509392505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061091d826108f2565b9050919050565b61092d81610912565b811461093857600080fd5b50565b60008135905061094a81610924565b92915050565b6000806040838503121561096757610966610685565b5b6000610975858286016106b0565b92505060206109868582860161093b565b9150509250929050565b60008115159050919050565b6109a581610990565b82525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600481106109eb576109ea6109ab565b5b50565b60008190506109fc826109da565b919050565b6000610a0c826109ee565b9050919050565b610a1c81610a01565b82525050565b60008160070b9050919050565b610a3881610a22565b82525050565b6000610160830160008301518482036000860152610a5c828261083d565b91505060208301518482036020860152610a76828261083d565b9150506040830151610a8b604086018261099c565b506060830151610a9e6060860182610a13565b506080830151610ab16080860182610876565b5060a0830151610ac460a0860182610876565b5060c083015184820360c0860152610adc828261083d565b91505060e0830151610af160e0860182610a2f565b50610100830151610b06610100860182610a2f565b50610120830151610b1b610120860182610876565b50610140830151610b30610140860182610876565b508091505092915050565b60006020820190508181036000830152610b558184610a3e565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610b978261068f565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610bc957610bc8610b5d565b5b600182019050919050565b600082825260208201905092915050565b82818337600083830152505050565b6000610c008385610bd4565b9350610c0d838584610be5565b610c168361082c565b840190509392505050565b60006020820190508181036000830152610c3c818486610bf4565b90509392505050565b610c4e81610912565b82525050565b6000604082019050610c696000830186610c45565b8181036020830152610c7c818486610bf4565b9050949350505050565b600081519050610c9581610699565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610cd88261082c565b810181811067ffffffffffffffff82111715610cf757610cf6610ca0565b5b80604052505050565b6000610d0a61067b565b9050610d168282610ccf565b919050565b600080fd5b600080fd5b600067ffffffffffffffff821115610d4057610d3f610ca0565b5b610d498261082c565b9050602081019050919050565b6000610d69610d6484610d25565b610d00565b905082815260208101848484011115610d8557610d84610d20565b5b610d90848285610802565b509392505050565b600082601f830112610dad57610dac6106c5565b5b8151610dbd848260208601610d56565b91505092915050565b600060408284031215610ddc57610ddb610c9b565b5b610de66040610d00565b9050600082015167ffffffffffffffff811115610e0657610e05610d1b565b5b610e1284828501610d98565b6000830152506020610e2684828501610c86565b60208301525092915050565b60008060408385031215610e4957610e48610685565b5b6000610e5785828601610c86565b925050602083015167ffffffffffffffff811115610e7857610e7761068a565b5b610e8485828601610dc6565b9150509250929050565b6000819050919050565b6000819050919050565b6000610ebd610eb8610eb384610e8e565b610e98565b61068f565b9050919050565b610ecd81610ea2565b82525050565b6000606082019050610ee86000830187610c45565b8181036020830152610efb818587610bf4565b9050610f0a6040830184610ec4565b95945050505050565b610f1c81610990565b8114610f2757600080fd5b50565b600081519050610f3981610f13565b92915050565b600060208284031215610f5557610f54610685565b5b6000610f6384828501610f2a565b91505092915050565b6000602082019050610f816000830184610c45565b92915050565b60048110610f9457600080fd5b50565b600081519050610fa681610f87565b92915050565b610fb581610a22565b8114610fc057600080fd5b50565b600081519050610fd281610fac565b92915050565b60006101608284031215610fef57610fee610c9b565b5b610ffa610160610d00565b9050600082015167ffffffffffffffff81111561101a57611019610d1b565b5b61102684828501610d98565b600083015250602082015167ffffffffffffffff81111561104a57611049610d1b565b5b61105684828501610d98565b602083015250604061106a84828501610f2a565b604083015250606061107e84828501610f97565b606083015250608061109284828501610c86565b60808301525060a06110a684828501610c86565b60a08301525060c082015167ffffffffffffffff8111156110ca576110c9610d1b565b5b6110d684828501610d98565b60c08301525060e06110ea84828501610fc3565b60e0830152506101006110ff84828501610fc3565b6101008301525061012061111584828501610c86565b6101208301525061014061112b84828501610c86565b6101408301525092915050565b60006020828403121561114e5761114d610685565b5b600082015167ffffffffffffffff81111561116c5761116b61068a565b5b61117884828501610fd8565b9150509291505056fea2646970667358221220f5f833c34bff960673e6df4fad50cb2e0deb7da5035552189c3d4e09281dd21264736f6c63430008140033", + "bytecode": "0x60806040526000805561150f806100176000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c8063668f452b1161005b578063668f452b146100d6578063922a4b6714610107578063cbc367d414610123578063f66013d7146101535761007d565b80634d9db92b146100825780634e5a8fe51461009e57806352fce7b1146100ba575b600080fd5b61009c60048036038101906100979190610a0e565b61016f565b005b6100b860048036038101906100b39190610a82565b61041c565b005b6100d460048036038101906100cf9190610a82565b6104be565b005b6100f060048036038101906100eb9190610ae2565b610566565b6040516100fe929190610c1a565b60405180910390f35b610121600480360381019061011c9190610a82565b610600565b005b61013d60048036038101906101389190610ca8565b610797565b60405161014a9190610e93565b60405180910390f35b61016d60048036038101906101689190610ae2565b610847565b005b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b81526004016101b19493929190610f56565b6020604051808303816000875af11580156101d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101f49190610fc2565b5060005b8481101561038f573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b815260040161023b929190610fef565b600060405180830381600087803b15801561025557600080fd5b505af1925050508015610266575060015b61037b5761080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308585600a6040518563ffffffff1660e01b81526004016102ac9493929190610f56565b6020604051808303816000875af11580156102cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ef9190610fc2565b5060005b84811015610375573073ffffffffffffffffffffffffffffffffffffffff1663f66013d785856040518363ffffffff1660e01b8152600401610336929190610fef565b600060405180830381600087803b15801561035057600080fd5b505af1925050508015610361575060015b50808061036d90611042565b9150506102f3565b5061037c565b5b808061038790611042565b9150506101f8565b5061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b81526004016103d29493929190610f56565b6020604051808303816000875af11580156103f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104159190610fc2565b5050505050565b60008081548092919061042e90611042565b919050555060005b838110156104b8573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b8152600401610479929190610fef565b600060405180830381600087803b15801561049357600080fd5b505af19250505080156104a4575060015b5080806104b090611042565b915050610436565b50505050565b6000808154809291906104d090611042565b919050555060005b83811015610560573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b815260040161051b929190610fef565b600060405180830381600087803b15801561053557600080fd5b505af1158015610549573d6000803e3d6000fd5b50505050808061055890611042565b9150506104d8565b50505050565b60006105706108d1565b61080073ffffffffffffffffffffffffffffffffffffffff1663241774e63086866040518463ffffffff1660e01b81526004016105af9392919061108a565b600060405180830381865afa1580156105cc573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906105f59190611268565b915091509250929050565b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b81526004016106429493929190610f56565b6020604051808303816000875af1158015610661573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106859190610fc2565b5060005b8381101561070b573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b81526004016106cc929190610fef565b600060405180830381600087803b1580156106e657600080fd5b505af19250505080156106f7575060015b50808061070390611042565b915050610689565b5061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b815260040161074e9493929190610f56565b6020604051808303816000875af115801561076d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107919190610fc2565b50505050565b61079f6108eb565b60005b838110156108405761080073ffffffffffffffffffffffffffffffffffffffff1663223b3b7a846040518263ffffffff1660e01b81526004016107e591906112c4565b600060405180830381865afa158015610802573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061082b9190611490565b9150808061083890611042565b9150506107a2565b5092915050565b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b81526004016108899493929190610f56565b6020604051808303816000875af11580156108a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cc9190610fc2565b600080fd5b604051806040016040528060608152602001600081525090565b60405180610160016040528060608152602001606081526020016000151581526020016000600381111561092257610921610d03565b5b8152602001600081526020016000815260200160608152602001600060070b8152602001600060070b815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b61098681610973565b811461099157600080fd5b50565b6000813590506109a38161097d565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126109ce576109cd6109a9565b5b8235905067ffffffffffffffff8111156109eb576109ea6109ae565b5b602083019150836001820283011115610a0757610a066109b3565b5b9250929050565b60008060008060608587031215610a2857610a27610969565b5b6000610a3687828801610994565b9450506020610a4787828801610994565b935050604085013567ffffffffffffffff811115610a6857610a6761096e565b5b610a74878288016109b8565b925092505092959194509250565b600080600060408486031215610a9b57610a9a610969565b5b6000610aa986828701610994565b935050602084013567ffffffffffffffff811115610aca57610ac961096e565b5b610ad6868287016109b8565b92509250509250925092565b60008060208385031215610af957610af8610969565b5b600083013567ffffffffffffffff811115610b1757610b1661096e565b5b610b23858286016109b8565b92509250509250929050565b610b3881610973565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610b78578082015181840152602081019050610b5d565b60008484015250505050565b6000601f19601f8301169050919050565b6000610ba082610b3e565b610baa8185610b49565b9350610bba818560208601610b5a565b610bc381610b84565b840191505092915050565b610bd781610973565b82525050565b60006040830160008301518482036000860152610bfa8282610b95565b9150506020830151610c0f6020860182610bce565b508091505092915050565b6000604082019050610c2f6000830185610b2f565b8181036020830152610c418184610bdd565b90509392505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c7582610c4a565b9050919050565b610c8581610c6a565b8114610c9057600080fd5b50565b600081359050610ca281610c7c565b92915050565b60008060408385031215610cbf57610cbe610969565b5b6000610ccd85828601610994565b9250506020610cde85828601610c93565b9150509250929050565b60008115159050919050565b610cfd81610ce8565b82525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60048110610d4357610d42610d03565b5b50565b6000819050610d5482610d32565b919050565b6000610d6482610d46565b9050919050565b610d7481610d59565b82525050565b60008160070b9050919050565b610d9081610d7a565b82525050565b6000610160830160008301518482036000860152610db48282610b95565b91505060208301518482036020860152610dce8282610b95565b9150506040830151610de36040860182610cf4565b506060830151610df66060860182610d6b565b506080830151610e096080860182610bce565b5060a0830151610e1c60a0860182610bce565b5060c083015184820360c0860152610e348282610b95565b91505060e0830151610e4960e0860182610d87565b50610100830151610e5e610100860182610d87565b50610120830151610e73610120860182610bce565b50610140830151610e88610140860182610bce565b508091505092915050565b60006020820190508181036000830152610ead8184610d96565b905092915050565b610ebe81610c6a565b82525050565b600082825260208201905092915050565b82818337600083830152505050565b6000610ef08385610ec4565b9350610efd838584610ed5565b610f0683610b84565b840190509392505050565b6000819050919050565b6000819050919050565b6000610f40610f3b610f3684610f11565b610f1b565b610973565b9050919050565b610f5081610f25565b82525050565b6000606082019050610f6b6000830187610eb5565b8181036020830152610f7e818587610ee4565b9050610f8d6040830184610f47565b95945050505050565b610f9f81610ce8565b8114610faa57600080fd5b50565b600081519050610fbc81610f96565b92915050565b600060208284031215610fd857610fd7610969565b5b6000610fe684828501610fad565b91505092915050565b6000602082019050818103600083015261100a818486610ee4565b90509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061104d82610973565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361107f5761107e611013565b5b600182019050919050565b600060408201905061109f6000830186610eb5565b81810360208301526110b2818486610ee4565b9050949350505050565b6000815190506110cb8161097d565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61110e82610b84565b810181811067ffffffffffffffff8211171561112d5761112c6110d6565b5b80604052505050565b600061114061095f565b905061114c8282611105565b919050565b600080fd5b600080fd5b600067ffffffffffffffff821115611176576111756110d6565b5b61117f82610b84565b9050602081019050919050565b600061119f61119a8461115b565b611136565b9050828152602081018484840111156111bb576111ba611156565b5b6111c6848285610b5a565b509392505050565b600082601f8301126111e3576111e26109a9565b5b81516111f384826020860161118c565b91505092915050565b600060408284031215611212576112116110d1565b5b61121c6040611136565b9050600082015167ffffffffffffffff81111561123c5761123b611151565b5b611248848285016111ce565b600083015250602061125c848285016110bc565b60208301525092915050565b6000806040838503121561127f5761127e610969565b5b600061128d858286016110bc565b925050602083015167ffffffffffffffff8111156112ae576112ad61096e565b5b6112ba858286016111fc565b9150509250929050565b60006020820190506112d96000830184610eb5565b92915050565b600481106112ec57600080fd5b50565b6000815190506112fe816112df565b92915050565b61130d81610d7a565b811461131857600080fd5b50565b60008151905061132a81611304565b92915050565b60006101608284031215611347576113466110d1565b5b611352610160611136565b9050600082015167ffffffffffffffff81111561137257611371611151565b5b61137e848285016111ce565b600083015250602082015167ffffffffffffffff8111156113a2576113a1611151565b5b6113ae848285016111ce565b60208301525060406113c284828501610fad565b60408301525060606113d6848285016112ef565b60608301525060806113ea848285016110bc565b60808301525060a06113fe848285016110bc565b60a08301525060c082015167ffffffffffffffff81111561142257611421611151565b5b61142e848285016111ce565b60c08301525060e06114428482850161131b565b60e0830152506101006114578482850161131b565b6101008301525061012061146d848285016110bc565b61012083015250610140611483848285016110bc565b6101408301525092915050565b6000602082840312156114a6576114a5610969565b5b600082015167ffffffffffffffff8111156114c4576114c361096e565b5b6114d084828501611330565b9150509291505056fea2646970667358221220909639086b03bb38b32aaba32e58073b8f74fe67a6fa3e21df62be2b2faddaed64736f6c63430008140033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c8063668f452b1161005b578063668f452b146100d6578063922a4b6714610107578063cbc367d414610123578063f66013d7146101535761007d565b80634d9db92b146100825780634e5a8fe51461009e57806352fce7b1146100ba575b600080fd5b61009c60048036038101906100979190610a0e565b61016f565b005b6100b860048036038101906100b39190610a82565b61041c565b005b6100d460048036038101906100cf9190610a82565b6104be565b005b6100f060048036038101906100eb9190610ae2565b610566565b6040516100fe929190610c1a565b60405180910390f35b610121600480360381019061011c9190610a82565b610600565b005b61013d60048036038101906101389190610ca8565b610797565b60405161014a9190610e93565b60405180910390f35b61016d60048036038101906101689190610ae2565b610847565b005b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b81526004016101b19493929190610f56565b6020604051808303816000875af11580156101d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101f49190610fc2565b5060005b8481101561038f573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b815260040161023b929190610fef565b600060405180830381600087803b15801561025557600080fd5b505af1925050508015610266575060015b61037b5761080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308585600a6040518563ffffffff1660e01b81526004016102ac9493929190610f56565b6020604051808303816000875af11580156102cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ef9190610fc2565b5060005b84811015610375573073ffffffffffffffffffffffffffffffffffffffff1663f66013d785856040518363ffffffff1660e01b8152600401610336929190610fef565b600060405180830381600087803b15801561035057600080fd5b505af1925050508015610361575060015b50808061036d90611042565b9150506102f3565b5061037c565b5b808061038790611042565b9150506101f8565b5061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b81526004016103d29493929190610f56565b6020604051808303816000875af11580156103f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104159190610fc2565b5050505050565b60008081548092919061042e90611042565b919050555060005b838110156104b8573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b8152600401610479929190610fef565b600060405180830381600087803b15801561049357600080fd5b505af19250505080156104a4575060015b5080806104b090611042565b915050610436565b50505050565b6000808154809291906104d090611042565b919050555060005b83811015610560573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b815260040161051b929190610fef565b600060405180830381600087803b15801561053557600080fd5b505af1158015610549573d6000803e3d6000fd5b50505050808061055890611042565b9150506104d8565b50505050565b60006105706108d1565b61080073ffffffffffffffffffffffffffffffffffffffff1663241774e63086866040518463ffffffff1660e01b81526004016105af9392919061108a565b600060405180830381865afa1580156105cc573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906105f59190611268565b915091509250929050565b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b81526004016106429493929190610f56565b6020604051808303816000875af1158015610661573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106859190610fc2565b5060005b8381101561070b573073ffffffffffffffffffffffffffffffffffffffff1663f66013d784846040518363ffffffff1660e01b81526004016106cc929190610fef565b600060405180830381600087803b1580156106e657600080fd5b505af19250505080156106f7575060015b50808061070390611042565b915050610689565b5061080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b815260040161074e9493929190610f56565b6020604051808303816000875af115801561076d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107919190610fc2565b50505050565b61079f6108eb565b60005b838110156108405761080073ffffffffffffffffffffffffffffffffffffffff1663223b3b7a846040518263ffffffff1660e01b81526004016107e591906112c4565b600060405180830381865afa158015610802573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061082b9190611490565b9150808061083890611042565b9150506107a2565b5092915050565b61080073ffffffffffffffffffffffffffffffffffffffff166353266bbb308484600a6040518563ffffffff1660e01b81526004016108899493929190610f56565b6020604051808303816000875af11580156108a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cc9190610fc2565b600080fd5b604051806040016040528060608152602001600081525090565b60405180610160016040528060608152602001606081526020016000151581526020016000600381111561092257610921610d03565b5b8152602001600081526020016000815260200160608152602001600060070b8152602001600060070b815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b61098681610973565b811461099157600080fd5b50565b6000813590506109a38161097d565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126109ce576109cd6109a9565b5b8235905067ffffffffffffffff8111156109eb576109ea6109ae565b5b602083019150836001820283011115610a0757610a066109b3565b5b9250929050565b60008060008060608587031215610a2857610a27610969565b5b6000610a3687828801610994565b9450506020610a4787828801610994565b935050604085013567ffffffffffffffff811115610a6857610a6761096e565b5b610a74878288016109b8565b925092505092959194509250565b600080600060408486031215610a9b57610a9a610969565b5b6000610aa986828701610994565b935050602084013567ffffffffffffffff811115610aca57610ac961096e565b5b610ad6868287016109b8565b92509250509250925092565b60008060208385031215610af957610af8610969565b5b600083013567ffffffffffffffff811115610b1757610b1661096e565b5b610b23858286016109b8565b92509250509250929050565b610b3881610973565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610b78578082015181840152602081019050610b5d565b60008484015250505050565b6000601f19601f8301169050919050565b6000610ba082610b3e565b610baa8185610b49565b9350610bba818560208601610b5a565b610bc381610b84565b840191505092915050565b610bd781610973565b82525050565b60006040830160008301518482036000860152610bfa8282610b95565b9150506020830151610c0f6020860182610bce565b508091505092915050565b6000604082019050610c2f6000830185610b2f565b8181036020830152610c418184610bdd565b90509392505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c7582610c4a565b9050919050565b610c8581610c6a565b8114610c9057600080fd5b50565b600081359050610ca281610c7c565b92915050565b60008060408385031215610cbf57610cbe610969565b5b6000610ccd85828601610994565b9250506020610cde85828601610c93565b9150509250929050565b60008115159050919050565b610cfd81610ce8565b82525050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60048110610d4357610d42610d03565b5b50565b6000819050610d5482610d32565b919050565b6000610d6482610d46565b9050919050565b610d7481610d59565b82525050565b60008160070b9050919050565b610d9081610d7a565b82525050565b6000610160830160008301518482036000860152610db48282610b95565b91505060208301518482036020860152610dce8282610b95565b9150506040830151610de36040860182610cf4565b506060830151610df66060860182610d6b565b506080830151610e096080860182610bce565b5060a0830151610e1c60a0860182610bce565b5060c083015184820360c0860152610e348282610b95565b91505060e0830151610e4960e0860182610d87565b50610100830151610e5e610100860182610d87565b50610120830151610e73610120860182610bce565b50610140830151610e88610140860182610bce565b508091505092915050565b60006020820190508181036000830152610ead8184610d96565b905092915050565b610ebe81610c6a565b82525050565b600082825260208201905092915050565b82818337600083830152505050565b6000610ef08385610ec4565b9350610efd838584610ed5565b610f0683610b84565b840190509392505050565b6000819050919050565b6000819050919050565b6000610f40610f3b610f3684610f11565b610f1b565b610973565b9050919050565b610f5081610f25565b82525050565b6000606082019050610f6b6000830187610eb5565b8181036020830152610f7e818587610ee4565b9050610f8d6040830184610f47565b95945050505050565b610f9f81610ce8565b8114610faa57600080fd5b50565b600081519050610fbc81610f96565b92915050565b600060208284031215610fd857610fd7610969565b5b6000610fe684828501610fad565b91505092915050565b6000602082019050818103600083015261100a818486610ee4565b90509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061104d82610973565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361107f5761107e611013565b5b600182019050919050565b600060408201905061109f6000830186610eb5565b81810360208301526110b2818486610ee4565b9050949350505050565b6000815190506110cb8161097d565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61110e82610b84565b810181811067ffffffffffffffff8211171561112d5761112c6110d6565b5b80604052505050565b600061114061095f565b905061114c8282611105565b919050565b600080fd5b600080fd5b600067ffffffffffffffff821115611176576111756110d6565b5b61117f82610b84565b9050602081019050919050565b600061119f61119a8461115b565b611136565b9050828152602081018484840111156111bb576111ba611156565b5b6111c6848285610b5a565b509392505050565b600082601f8301126111e3576111e26109a9565b5b81516111f384826020860161118c565b91505092915050565b600060408284031215611212576112116110d1565b5b61121c6040611136565b9050600082015167ffffffffffffffff81111561123c5761123b611151565b5b611248848285016111ce565b600083015250602061125c848285016110bc565b60208301525092915050565b6000806040838503121561127f5761127e610969565b5b600061128d858286016110bc565b925050602083015167ffffffffffffffff8111156112ae576112ad61096e565b5b6112ba858286016111fc565b9150509250929050565b60006020820190506112d96000830184610eb5565b92915050565b600481106112ec57600080fd5b50565b6000815190506112fe816112df565b92915050565b61130d81610d7a565b811461131857600080fd5b50565b60008151905061132a81611304565b92915050565b60006101608284031215611347576113466110d1565b5b611352610160611136565b9050600082015167ffffffffffffffff81111561137257611371611151565b5b61137e848285016111ce565b600083015250602082015167ffffffffffffffff8111156113a2576113a1611151565b5b6113ae848285016111ce565b60208301525060406113c284828501610fad565b60408301525060606113d6848285016112ef565b60608301525060806113ea848285016110bc565b60808301525060a06113fe848285016110bc565b60a08301525060c082015167ffffffffffffffff81111561142257611421611151565b5b61142e848285016111ce565b60c08301525060e06114428482850161131b565b60e0830152506101006114578482850161131b565b6101008301525061012061146d848285016110bc565b61012083015250610140611483848285016110bc565b6101408301525092915050565b6000602082840312156114a6576114a5610969565b5b600082015167ffffffffffffffff8111156114c4576114c361096e565b5b6114d084828501611330565b9150509291505056fea2646970667358221220909639086b03bb38b32aaba32e58073b8f74fe67a6fa3e21df62be2b2faddaed64736f6c63430008140033", "linkReferences": {}, "deployedLinkReferences": {} } diff --git a/precompiles/testutil/contracts/StakingReverter.sol b/precompiles/testutil/contracts/StakingReverter.sol index 469267cb43..aef5d526b5 100644 --- a/precompiles/testutil/contracts/StakingReverter.sol +++ b/precompiles/testutil/contracts/StakingReverter.sol @@ -49,6 +49,36 @@ contract StakingReverter { STAKING_CONTRACT.delegate(address(this), validatorAddress, 10); } + /// @dev nestedTryCatchDelegations performs nested try/catch calls to precompile + /// where inner calls revert intentionally. Only the successful delegations + /// outside the reverting scope should persist. + /// + /// Expected successful delegations: 1 (before loop) + outerTimes (after each catch) + 1 (after loop) + function nestedTryCatchDelegations(uint outerTimes, uint innerTimes, string calldata validatorAddress) external { + // Initial successful delegate before any nested reverts + STAKING_CONTRACT.delegate(address(this), validatorAddress, 10); + + for (uint i = 0; i < outerTimes; i++) { + // Outer call that will revert and be caught + try StakingReverter(address(this)).performDelegation(validatorAddress) { + // no-op + } catch { + // After catching the revert, perform a successful delegate + STAKING_CONTRACT.delegate(address(this), validatorAddress, 10); + + // Inner nested loop of reverting calls + for (uint j = 0; j < innerTimes; j++) { + try StakingReverter(address(this)).performDelegation(validatorAddress) { + // no-op + } catch {} + } + } + } + + // Final successful delegate after the loops + STAKING_CONTRACT.delegate(address(this), validatorAddress, 10); + } + function performDelegation(string calldata validatorAddress) external { STAKING_CONTRACT.delegate(address(this), validatorAddress, 10); revert(); diff --git a/tests/integration/precompiles/staking/test_integration.go b/tests/integration/precompiles/staking/test_integration.go index 7d49f82df0..13e48e60c6 100644 --- a/tests/integration/precompiles/staking/test_integration.go +++ b/tests/integration/precompiles/staking/test_integration.go @@ -1896,6 +1896,58 @@ func TestPrecompileIntegrationTestSuite(t *testing.T, create network.CreateEvmAp txSenderFinalBal := balRes.Balance Expect(txSenderFinalBal.Amount).To(Equal(txSenderInitialBal.Amount.Sub(fees)), "expected tx sender balance to be deducted by fees") }) + It("should test nested precompile calls with revert", func() { + outerTimes := int64(3) + innerTimes := int64(2) + expectedDelegations := outerTimes + 2 // 1 before + outerTimes after catches + 1 after loop + expectedDelegationAmount := math.NewInt(10).MulRaw(expectedDelegations) + + callArgs := testutiltypes.CallArgs{ + ContractABI: stakingReverterContract.ABI, + MethodName: "nestedTryCatchDelegations", + Args: []interface{}{ + big.NewInt(outerTimes), big.NewInt(innerTimes), s.network.GetValidators()[0].OperatorAddress, + }, + } + + expEvents := make([]string, 0, expectedDelegations) + for range expectedDelegations { + expEvents = append(expEvents, staking.EventTypeDelegate) + } + delegateCheck := passCheck.WithExpEvents(expEvents...) + + res, _, err := s.factory.CallContractAndCheckLogs( + s.keyring.GetPrivKey(0), + evmtypes.EvmTxArgs{ + To: &stkReverterAddr, + GasPrice: gasPrice.BigInt(), + }, + callArgs, + delegateCheck, + ) + Expect(err).To(BeNil(), "error while calling the smart contract: %v", err) + Expect(s.network.NextBlock()).To(BeNil()) + + fees := gasPrice.MulRaw(res.GasUsed) + + // delegation should have been created with expected shares + qRes, err := s.grpcHandler.GetDelegation(sdk.AccAddress(stkReverterAddr.Bytes()).String(), s.network.GetValidators()[0].OperatorAddress) + Expect(err).To(BeNil()) + Expect(qRes.DelegationResponse.Delegation.GetDelegatorAddr()).To(Equal(sdk.AccAddress(stkReverterAddr.Bytes()).String())) + Expect(qRes.DelegationResponse.Delegation.GetShares().BigInt()).To(Equal(expectedDelegationAmount.BigInt())) + + // contract balance should be deducted by total delegation amount + balRes, err := s.grpcHandler.GetBalanceFromBank(stkReverterAddr.Bytes(), s.bondDenom) + Expect(err).To(BeNil()) + contractFinalBalance := balRes.Balance + Expect(contractFinalBalance.Amount).To(Equal(contractInitialBalance.Amount.Sub(expectedDelegationAmount))) + + // fees deducted on tx sender only + balRes, err = s.grpcHandler.GetBalanceFromBank(s.keyring.GetAccAddr(0), s.bondDenom) + Expect(err).To(BeNil()) + txSenderFinalBal := balRes.Balance + Expect(txSenderFinalBal.Amount).To(Equal(txSenderInitialBal.Amount.Sub(fees))) + }) }) Context("Table-driven tests for Delegate method", func() { diff --git a/x/vm/types/call.go b/x/vm/types/call.go index 957084736e..7c665180df 100644 --- a/x/vm/types/call.go +++ b/x/vm/types/call.go @@ -12,4 +12,4 @@ const ( // MaxPrecompileCalls is the maximum number of precompile // calls within a transaction. We want to limit this because // for each precompile tx we're creating a cached context -const MaxPrecompileCalls uint8 = 7 +const MaxPrecompileCalls uint8 = 20 From 5ff2ec706fc8218ba0e7f03f982576c0825358bd Mon Sep 17 00:00:00 2001 From: Vlad J Date: Mon, 15 Sep 2025 17:02:28 -0400 Subject: [PATCH 49/61] perf: reduce number of query context calls (#598) * update blockchain context once per block * evmd tests pass but this is some pointer madness * no more pointer madness * changelog --- CHANGELOG.md | 1 + mempool/blockchain.go | 29 +++++++++++++++++++++++------ mempool/mempool.go | 2 +- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59e7dd1ab1..dc6736f8e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - [\#511](https://github.com/cosmos/evm/pull/511) Minor code cleanup for `AddPrecompileFn`. - [\#544](https://github.com/cosmos/evm/pull/544) Parse logs from the txResult.Data and avoid emitting EVM events to cosmos-sdk events. - [\#582](https://github.com/cosmos/evm/pull/582) Add block max-gas (from genesis.json) and new min-tip (from app.toml/flags) ingestion into mempool config +- [\#598](https://github.com/cosmos/evm/pull/598) Reduce number of times CreateQueryContext in mempool. ### FEATURES diff --git a/mempool/blockchain.go b/mempool/blockchain.go index f9a593c872..bd4f2f02c1 100644 --- a/mempool/blockchain.go +++ b/mempool/blockchain.go @@ -41,6 +41,7 @@ type Blockchain struct { zeroHeader *types.Header blockGasLimit uint64 previousHeaderHash common.Hash + latestCtx sdk.Context } // newBlockchain creates a new Blockchain instance that bridges Cosmos SDK state with Ethereum mempools. @@ -78,10 +79,8 @@ func (b Blockchain) Config() *params.ChainConfig { // including block height, timestamp, gas limits, and base fee (if London fork is active). // Returns a zero header as placeholder if the context is not yet available. func (b Blockchain) CurrentBlock() *types.Header { - ctx, err := b.GetLatestCtx() - // This should only error out on the first block. + ctx, err := b.GetLatestContext() if err != nil { - b.logger.Debug("failed to get latest context, returning zero header", "error", err) return b.zeroHeader } @@ -169,6 +168,12 @@ func (b Blockchain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event // NotifyNewBlock sends a chain head event when a new block is finalized func (b *Blockchain) NotifyNewBlock() { + latestCtx, err := b.newLatestContext() + if err != nil { + b.latestCtx = sdk.Context{} + b.logger.Debug("failed to get latest context, notifying chain head", "error", err) + } + b.latestCtx = latestCtx header := b.CurrentBlock() headerHash := header.Hash() @@ -197,7 +202,7 @@ func (b Blockchain) StateAt(hash common.Hash) (vm.StateDB, error) { } // Always get the latest context to avoid stale nonce state. - ctx, err := b.GetLatestCtx() + ctx, err := b.GetLatestContext() if err != nil { // If we can't get the latest context for blocks past 1, something is seriously wrong with the chain state return nil, fmt.Errorf("failed to get latest context for StateAt: %w", err) @@ -210,9 +215,21 @@ func (b Blockchain) StateAt(hash common.Hash) (vm.StateDB, error) { return stateDB, nil } -// GetLatestCtx retrieves the most recent query context from the application. +// GetLatestContext returns the latest context as updated by the block, +// or attempts to retrieve it again if unavailable. +func (b Blockchain) GetLatestContext() (sdk.Context, error) { + b.logger.Debug("getting latest context") + + if b.latestCtx.Context() != nil { + return b.latestCtx, nil + } + + return b.newLatestContext() +} + +// newLatestContext retrieves the most recent query context from the application. // This provides access to the current blockchain state for transaction validation and execution. -func (b Blockchain) GetLatestCtx() (sdk.Context, error) { +func (b Blockchain) newLatestContext() (sdk.Context, error) { b.logger.Debug("getting latest context") ctx, err := b.getCtxCallback(0, false) diff --git a/mempool/mempool.go b/mempool/mempool.go index 24c3687a43..a3a7aa62c0 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -346,7 +346,7 @@ func (m *ExperimentalEVMMempool) shouldRemoveFromEVMPool(tx sdk.Tx) bool { // If it was a successful transaction or a sequence error, we let the mempool handle the cleaning. // If it was any other Cosmos or antehandler related issue, then we remove it. - ctx, err := m.blockchain.GetLatestCtx() + ctx, err := m.blockchain.GetLatestContext() if err != nil { m.logger.Debug("cannot get latest context for validation, keeping transaction", "error", err) return false // Cannot validate, keep transaction From 1b604250a60219fc83f6f14ebfcfa7dc7a96a6ff Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Tue, 16 Sep 2025 09:29:01 +0200 Subject: [PATCH 50/61] chore: add erc20 factory precompile feature to CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 315d4f9ed9..cbaa131f1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - [\#346](https://github.com/cosmos/evm/pull/346) Add eth_createAccessList method and implementation - [\#502](https://github.com/cosmos/evm/pull/502) Add block time in derived logs. +- [\#405](https://github.com/cosmos/evm/pull/405) Add erc20 factory precompile. ### STATE BREAKING From d6b0d306eb93778c3338c07d3e1f00b09a1efea4 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Tue, 16 Sep 2025 21:31:20 +0800 Subject: [PATCH 51/61] test: mock bank keeper is outdated (#606) cd x/precisebank/types && mockery --name BankKeeper --with-expecter --filename MockBankKeeper.go cd x/vm/types && mockery --name BankKeeper --- CHANGELOG.md | 1 + x/erc20/types/mocks/BankKeeper.go | 798 ++------------------ x/erc20/types/mocks/README.md | 25 +- x/precisebank/types/mocks/MockBankKeeper.go | 5 +- x/vm/types/mocks/BankKeeper.go | 222 ++---- x/vm/wrappers/testutil/mock.go | 144 ++-- 6 files changed, 228 insertions(+), 967 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc6736f8e9..21e00aa4ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - [\#544](https://github.com/cosmos/evm/pull/544) Parse logs from the txResult.Data and avoid emitting EVM events to cosmos-sdk events. - [\#582](https://github.com/cosmos/evm/pull/582) Add block max-gas (from genesis.json) and new min-tip (from app.toml/flags) ingestion into mempool config - [\#598](https://github.com/cosmos/evm/pull/598) Reduce number of times CreateQueryContext in mempool. +- [\#606](https://github.com/cosmos/evm/pull/606) Regenerate mock file for bank keeper related test. ### FEATURES diff --git a/x/erc20/types/mocks/BankKeeper.go b/x/erc20/types/mocks/BankKeeper.go index 664ff49fb7..98fdbd4709 100644 --- a/x/erc20/types/mocks/BankKeeper.go +++ b/x/erc20/types/mocks/BankKeeper.go @@ -1,7 +1,12 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: x/gov/testutil/expected_keepers.go - -// Package testutil is a generated GoMock package. +// Source: ./x/erc20/types/interfaces.go +// +// Generated by this command: +// +// mockgen -source=./x/erc20/types/interfaces.go -package=mocks -destination=./x/erc20/types/mocks/BankKeeper.go -exclude_interfaces=AccountKeeper,StakingKeeper,EVMKeeper,Erc20Keeper +// + +// Package mocks is a generated GoMock package. package mocks import ( @@ -9,79 +14,36 @@ import ( reflect "reflect" types "github.com/cosmos/cosmos-sdk/types" - query "github.com/cosmos/cosmos-sdk/types/query" - keeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" types0 "github.com/cosmos/cosmos-sdk/x/bank/types" gomock "go.uber.org/mock/gomock" ) -// BankKeeper is a mock of BankKeeper interface. -type BankKeeper struct { +// MockBankKeeper is a mock of BankKeeper interface. +type MockBankKeeper struct { ctrl *gomock.Controller recorder *MockBankKeeperMockRecorder + isgomock struct{} } // MockBankKeeperMockRecorder is the mock recorder for MockBankKeeper. type MockBankKeeperMockRecorder struct { - mock *BankKeeper + mock *MockBankKeeper } // NewMockBankKeeper creates a new mock instance. -func NewMockBankKeeper(ctrl *gomock.Controller) *BankKeeper { - mock := &BankKeeper{ctrl: ctrl} +func NewMockBankKeeper(ctrl *gomock.Controller) *MockBankKeeper { + mock := &MockBankKeeper{ctrl: ctrl} mock.recorder = &MockBankKeeperMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *BankKeeper) EXPECT() *MockBankKeeperMockRecorder { +func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder { return m.recorder } -// AllBalances mocks base method. -func (m *BankKeeper) AllBalances(arg0 context.Context, arg1 *types0.QueryAllBalancesRequest) (*types0.QueryAllBalancesResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AllBalances", arg0, arg1) - ret0, _ := ret[0].(*types0.QueryAllBalancesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AllBalances indicates an expected call of AllBalances. -func (mr *MockBankKeeperMockRecorder) AllBalances(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllBalances", reflect.TypeOf((*BankKeeper)(nil).AllBalances), arg0, arg1) -} - -// AppendSendRestriction mocks base method. -func (m *BankKeeper) AppendSendRestriction(restriction types0.SendRestrictionFn) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "AppendSendRestriction", restriction) -} - -// AppendSendRestriction indicates an expected call of AppendSendRestriction. -func (mr *MockBankKeeperMockRecorder) AppendSendRestriction(restriction interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppendSendRestriction", reflect.TypeOf((*BankKeeper)(nil).AppendSendRestriction), restriction) -} - -// Balance mocks base method. -func (m *BankKeeper) Balance(arg0 context.Context, arg1 *types0.QueryBalanceRequest) (*types0.QueryBalanceResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Balance", arg0, arg1) - ret0, _ := ret[0].(*types0.QueryBalanceResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Balance indicates an expected call of Balance. -func (mr *MockBankKeeperMockRecorder) Balance(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Balance", reflect.TypeOf((*BankKeeper)(nil).Balance), arg0, arg1) -} - // BlockedAddr mocks base method. -func (m *BankKeeper) BlockedAddr(addr types.AccAddress) bool { +func (m *MockBankKeeper) BlockedAddr(addr types.AccAddress) bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BlockedAddr", addr) ret0, _ := ret[0].(bool) @@ -89,13 +51,13 @@ func (m *BankKeeper) BlockedAddr(addr types.AccAddress) bool { } // BlockedAddr indicates an expected call of BlockedAddr. -func (mr *MockBankKeeperMockRecorder) BlockedAddr(addr interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) BlockedAddr(addr any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockedAddr", reflect.TypeOf((*BankKeeper)(nil).BlockedAddr), addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockedAddr", reflect.TypeOf((*MockBankKeeper)(nil).BlockedAddr), addr) } // BurnCoins mocks base method. -func (m *BankKeeper) BurnCoins(ctx context.Context, moduleName string, amt types.Coins) error { +func (m *MockBankKeeper) BurnCoins(ctx context.Context, moduleName string, amt types.Coins) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "BurnCoins", ctx, moduleName, amt) ret0, _ := ret[0].(error) @@ -103,214 +65,13 @@ func (m *BankKeeper) BurnCoins(ctx context.Context, moduleName string, amt types } // BurnCoins indicates an expected call of BurnCoins. -func (mr *MockBankKeeperMockRecorder) BurnCoins(ctx, moduleName, amt interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BurnCoins", reflect.TypeOf((*BankKeeper)(nil).BurnCoins), ctx, moduleName, amt) -} - -// ClearSendRestriction mocks base method. -func (m *BankKeeper) ClearSendRestriction() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "ClearSendRestriction") -} - -// ClearSendRestriction indicates an expected call of ClearSendRestriction. -func (mr *MockBankKeeperMockRecorder) ClearSendRestriction() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClearSendRestriction", reflect.TypeOf((*BankKeeper)(nil).ClearSendRestriction)) -} - -// DelegateCoins mocks base method. -func (m *BankKeeper) DelegateCoins(ctx context.Context, delegatorAddr, moduleAccAddr types.AccAddress, amt types.Coins) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DelegateCoins", ctx, delegatorAddr, moduleAccAddr, amt) - ret0, _ := ret[0].(error) - return ret0 -} - -// DelegateCoins indicates an expected call of DelegateCoins. -func (mr *MockBankKeeperMockRecorder) DelegateCoins(ctx, delegatorAddr, moduleAccAddr, amt interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DelegateCoins", reflect.TypeOf((*BankKeeper)(nil).DelegateCoins), ctx, delegatorAddr, moduleAccAddr, amt) -} - -// DelegateCoinsFromAccountToModule mocks base method. -func (m *BankKeeper) DelegateCoinsFromAccountToModule(ctx context.Context, senderAddr types.AccAddress, recipientModule string, amt types.Coins) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DelegateCoinsFromAccountToModule", ctx, senderAddr, recipientModule, amt) - ret0, _ := ret[0].(error) - return ret0 -} - -// DelegateCoinsFromAccountToModule indicates an expected call of DelegateCoinsFromAccountToModule. -func (mr *MockBankKeeperMockRecorder) DelegateCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DelegateCoinsFromAccountToModule", reflect.TypeOf((*BankKeeper)(nil).DelegateCoinsFromAccountToModule), ctx, senderAddr, recipientModule, amt) -} - -// DeleteSendEnabled mocks base method. -func (m *BankKeeper) DeleteSendEnabled(ctx context.Context, denoms ...string) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx} - for _, a := range denoms { - varargs = append(varargs, a) - } - m.ctrl.Call(m, "DeleteSendEnabled", varargs...) -} - -// DeleteSendEnabled indicates an expected call of DeleteSendEnabled. -func (mr *MockBankKeeperMockRecorder) DeleteSendEnabled(ctx interface{}, denoms ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx}, denoms...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSendEnabled", reflect.TypeOf((*BankKeeper)(nil).DeleteSendEnabled), varargs...) -} - -// DenomMetadata mocks base method. -func (m *BankKeeper) DenomMetadata(arg0 context.Context, arg1 *types0.QueryDenomMetadataRequest) (*types0.QueryDenomMetadataResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DenomMetadata", arg0, arg1) - ret0, _ := ret[0].(*types0.QueryDenomMetadataResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DenomMetadata indicates an expected call of DenomMetadata. -func (mr *MockBankKeeperMockRecorder) DenomMetadata(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DenomMetadata", reflect.TypeOf((*BankKeeper)(nil).DenomMetadata), arg0, arg1) -} - -// DenomMetadataByQueryString mocks base method. -func (m *BankKeeper) DenomMetadataByQueryString(arg0 context.Context, arg1 *types0.QueryDenomMetadataByQueryStringRequest) (*types0.QueryDenomMetadataByQueryStringResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DenomMetadataByQueryString", arg0, arg1) - ret0, _ := ret[0].(*types0.QueryDenomMetadataByQueryStringResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DenomMetadataByQueryString indicates an expected call of DenomMetadataByQueryString. -func (mr *MockBankKeeperMockRecorder) DenomMetadataByQueryString(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DenomMetadataByQueryString", reflect.TypeOf((*BankKeeper)(nil).DenomMetadataByQueryString), arg0, arg1) -} - -// DenomOwners mocks base method. -func (m *BankKeeper) DenomOwners(arg0 context.Context, arg1 *types0.QueryDenomOwnersRequest) (*types0.QueryDenomOwnersResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DenomOwners", arg0, arg1) - ret0, _ := ret[0].(*types0.QueryDenomOwnersResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DenomOwners indicates an expected call of DenomOwners. -func (mr *MockBankKeeperMockRecorder) DenomOwners(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DenomOwners", reflect.TypeOf((*BankKeeper)(nil).DenomOwners), arg0, arg1) -} - -// DenomsMetadata mocks base method. -func (m *BankKeeper) DenomsMetadata(arg0 context.Context, arg1 *types0.QueryDenomsMetadataRequest) (*types0.QueryDenomsMetadataResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DenomsMetadata", arg0, arg1) - ret0, _ := ret[0].(*types0.QueryDenomsMetadataResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DenomsMetadata indicates an expected call of DenomsMetadata. -func (mr *MockBankKeeperMockRecorder) DenomsMetadata(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DenomsMetadata", reflect.TypeOf((*BankKeeper)(nil).DenomsMetadata), arg0, arg1) -} - -// ExportGenesis mocks base method. -func (m *BankKeeper) ExportGenesis(arg0 context.Context) *types0.GenesisState { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ExportGenesis", arg0) - ret0, _ := ret[0].(*types0.GenesisState) - return ret0 -} - -// ExportGenesis indicates an expected call of ExportGenesis. -func (mr *MockBankKeeperMockRecorder) ExportGenesis(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExportGenesis", reflect.TypeOf((*BankKeeper)(nil).ExportGenesis), arg0) -} - -// GetAccountsBalances mocks base method. -func (m *BankKeeper) GetAccountsBalances(ctx context.Context) []types0.Balance { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccountsBalances", ctx) - ret0, _ := ret[0].([]types0.Balance) - return ret0 -} - -// GetAccountsBalances indicates an expected call of GetAccountsBalances. -func (mr *MockBankKeeperMockRecorder) GetAccountsBalances(ctx interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountsBalances", reflect.TypeOf((*BankKeeper)(nil).GetAccountsBalances), ctx) -} - -// GetAllBalances mocks base method. -func (m *BankKeeper) GetAllBalances(ctx context.Context, addr types.AccAddress) types.Coins { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAllBalances", ctx, addr) - ret0, _ := ret[0].(types.Coins) - return ret0 -} - -// GetAllBalances indicates an expected call of GetAllBalances. -func (mr *MockBankKeeperMockRecorder) GetAllBalances(ctx, addr interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) BurnCoins(ctx, moduleName, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllBalances", reflect.TypeOf((*BankKeeper)(nil).GetAllBalances), ctx, addr) -} - -// GetAllDenomMetaData mocks base method. -func (m *BankKeeper) GetAllDenomMetaData(ctx context.Context) []types0.Metadata { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAllDenomMetaData", ctx) - ret0, _ := ret[0].([]types0.Metadata) - return ret0 -} - -// GetAllDenomMetaData indicates an expected call of GetAllDenomMetaData. -func (mr *MockBankKeeperMockRecorder) GetAllDenomMetaData(ctx interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllDenomMetaData", reflect.TypeOf((*BankKeeper)(nil).GetAllDenomMetaData), ctx) -} - -// GetAllSendEnabledEntries mocks base method. -func (m *BankKeeper) GetAllSendEnabledEntries(ctx context.Context) []types0.SendEnabled { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAllSendEnabledEntries", ctx) - ret0, _ := ret[0].([]types0.SendEnabled) - return ret0 -} - -// GetAllSendEnabledEntries indicates an expected call of GetAllSendEnabledEntries. -func (mr *MockBankKeeperMockRecorder) GetAllSendEnabledEntries(ctx interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllSendEnabledEntries", reflect.TypeOf((*BankKeeper)(nil).GetAllSendEnabledEntries), ctx) -} - -// GetAuthority mocks base method. -func (m *BankKeeper) GetAuthority() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAuthority") - ret0, _ := ret[0].(string) - return ret0 -} - -// GetAuthority indicates an expected call of GetAuthority. -func (mr *MockBankKeeperMockRecorder) GetAuthority() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthority", reflect.TypeOf((*BankKeeper)(nil).GetAuthority)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BurnCoins", reflect.TypeOf((*MockBankKeeper)(nil).BurnCoins), ctx, moduleName, amt) } // GetBalance mocks base method. -func (m *BankKeeper) GetBalance(ctx context.Context, addr types.AccAddress, denom string) types.Coin { +func (m *MockBankKeeper) GetBalance(ctx context.Context, addr types.AccAddress, denom string) types.Coin { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetBalance", ctx, addr, denom) ret0, _ := ret[0].(types.Coin) @@ -318,27 +79,13 @@ func (m *BankKeeper) GetBalance(ctx context.Context, addr types.AccAddress, deno } // GetBalance indicates an expected call of GetBalance. -func (mr *MockBankKeeperMockRecorder) GetBalance(ctx, addr, denom interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) GetBalance(ctx, addr, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalance", reflect.TypeOf((*BankKeeper)(nil).GetBalance), ctx, addr, denom) -} - -// GetBlockedAddresses mocks base method. -func (m *BankKeeper) GetBlockedAddresses() map[string]bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBlockedAddresses") - ret0, _ := ret[0].(map[string]bool) - return ret0 -} - -// GetBlockedAddresses indicates an expected call of GetBlockedAddresses. -func (mr *MockBankKeeperMockRecorder) GetBlockedAddresses() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBlockedAddresses", reflect.TypeOf((*BankKeeper)(nil).GetBlockedAddresses)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalance", reflect.TypeOf((*MockBankKeeper)(nil).GetBalance), ctx, addr, denom) } // GetDenomMetaData mocks base method. -func (m *BankKeeper) GetDenomMetaData(ctx context.Context, denom string) (types0.Metadata, bool) { +func (m *MockBankKeeper) GetDenomMetaData(ctx context.Context, denom string) (types0.Metadata, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetDenomMetaData", ctx, denom) ret0, _ := ret[0].(types0.Metadata) @@ -347,58 +94,13 @@ func (m *BankKeeper) GetDenomMetaData(ctx context.Context, denom string) (types0 } // GetDenomMetaData indicates an expected call of GetDenomMetaData. -func (mr *MockBankKeeperMockRecorder) GetDenomMetaData(ctx, denom interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDenomMetaData", reflect.TypeOf((*BankKeeper)(nil).GetDenomMetaData), ctx, denom) -} - -// GetPaginatedTotalSupply mocks base method. -func (m *BankKeeper) GetPaginatedTotalSupply(ctx context.Context, pagination *query.PageRequest) (types.Coins, *query.PageResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPaginatedTotalSupply", ctx, pagination) - ret0, _ := ret[0].(types.Coins) - ret1, _ := ret[1].(*query.PageResponse) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// GetPaginatedTotalSupply indicates an expected call of GetPaginatedTotalSupply. -func (mr *MockBankKeeperMockRecorder) GetPaginatedTotalSupply(ctx, pagination interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPaginatedTotalSupply", reflect.TypeOf((*BankKeeper)(nil).GetPaginatedTotalSupply), ctx, pagination) -} - -// GetParams mocks base method. -func (m *BankKeeper) GetParams(ctx context.Context) types0.Params { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetParams", ctx) - ret0, _ := ret[0].(types0.Params) - return ret0 -} - -// GetParams indicates an expected call of GetParams. -func (mr *MockBankKeeperMockRecorder) GetParams(ctx interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParams", reflect.TypeOf((*BankKeeper)(nil).GetParams), ctx) -} - -// GetSendEnabledEntry mocks base method. -func (m *BankKeeper) GetSendEnabledEntry(ctx context.Context, denom string) (types0.SendEnabled, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSendEnabledEntry", ctx, denom) - ret0, _ := ret[0].(types0.SendEnabled) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// GetSendEnabledEntry indicates an expected call of GetSendEnabledEntry. -func (mr *MockBankKeeperMockRecorder) GetSendEnabledEntry(ctx, denom interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) GetDenomMetaData(ctx, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSendEnabledEntry", reflect.TypeOf((*BankKeeper)(nil).GetSendEnabledEntry), ctx, denom) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDenomMetaData", reflect.TypeOf((*MockBankKeeper)(nil).GetDenomMetaData), ctx, denom) } // GetSupply mocks base method. -func (m *BankKeeper) GetSupply(ctx context.Context, denom string) types.Coin { +func (m *MockBankKeeper) GetSupply(ctx context.Context, denom string) types.Coin { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSupply", ctx, denom) ret0, _ := ret[0].(types.Coin) @@ -406,81 +108,13 @@ func (m *BankKeeper) GetSupply(ctx context.Context, denom string) types.Coin { } // GetSupply indicates an expected call of GetSupply. -func (mr *MockBankKeeperMockRecorder) GetSupply(ctx, denom interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSupply", reflect.TypeOf((*BankKeeper)(nil).GetSupply), ctx, denom) -} - -// HasBalance mocks base method. -func (m *BankKeeper) HasBalance(ctx context.Context, addr types.AccAddress, amt types.Coin) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HasBalance", ctx, addr, amt) - ret0, _ := ret[0].(bool) - return ret0 -} - -// HasBalance indicates an expected call of HasBalance. -func (mr *MockBankKeeperMockRecorder) HasBalance(ctx, addr, amt interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasBalance", reflect.TypeOf((*BankKeeper)(nil).HasBalance), ctx, addr, amt) -} - -// HasDenomMetaData mocks base method. -func (m *BankKeeper) HasDenomMetaData(ctx context.Context, denom string) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HasDenomMetaData", ctx, denom) - ret0, _ := ret[0].(bool) - return ret0 -} - -// HasDenomMetaData indicates an expected call of HasDenomMetaData. -func (mr *MockBankKeeperMockRecorder) HasDenomMetaData(ctx, denom interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasDenomMetaData", reflect.TypeOf((*BankKeeper)(nil).HasDenomMetaData), ctx, denom) -} - -// HasSupply mocks base method. -func (m *BankKeeper) HasSupply(ctx context.Context, denom string) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HasSupply", ctx, denom) - ret0, _ := ret[0].(bool) - return ret0 -} - -// HasSupply indicates an expected call of HasSupply. -func (mr *MockBankKeeperMockRecorder) HasSupply(ctx, denom interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasSupply", reflect.TypeOf((*BankKeeper)(nil).HasSupply), ctx, denom) -} - -// InitGenesis mocks base method. -func (m *BankKeeper) InitGenesis(arg0 context.Context, arg1 *types0.GenesisState) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "InitGenesis", arg0, arg1) -} - -// InitGenesis indicates an expected call of InitGenesis. -func (mr *MockBankKeeperMockRecorder) InitGenesis(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitGenesis", reflect.TypeOf((*BankKeeper)(nil).InitGenesis), arg0, arg1) -} - -// InputOutputCoins mocks base method. -func (m *BankKeeper) InputOutputCoins(ctx context.Context, input types0.Input, outputs []types0.Output) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InputOutputCoins", ctx, input, outputs) - ret0, _ := ret[0].(error) - return ret0 -} - -// InputOutputCoins indicates an expected call of InputOutputCoins. -func (mr *MockBankKeeperMockRecorder) InputOutputCoins(ctx, input, outputs interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) GetSupply(ctx, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InputOutputCoins", reflect.TypeOf((*BankKeeper)(nil).InputOutputCoins), ctx, input, outputs) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSupply", reflect.TypeOf((*MockBankKeeper)(nil).GetSupply), ctx, denom) } // IsSendEnabledCoin mocks base method. -func (m *BankKeeper) IsSendEnabledCoin(ctx context.Context, coin types.Coin) bool { +func (m *MockBankKeeper) IsSendEnabledCoin(ctx context.Context, coin types.Coin) bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsSendEnabledCoin", ctx, coin) ret0, _ := ret[0].(bool) @@ -488,120 +122,37 @@ func (m *BankKeeper) IsSendEnabledCoin(ctx context.Context, coin types.Coin) boo } // IsSendEnabledCoin indicates an expected call of IsSendEnabledCoin. -func (mr *MockBankKeeperMockRecorder) IsSendEnabledCoin(ctx, coin interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) IsSendEnabledCoin(ctx, coin any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSendEnabledCoin", reflect.TypeOf((*BankKeeper)(nil).IsSendEnabledCoin), ctx, coin) -} - -// IsSendEnabledCoins mocks base method. -func (m *BankKeeper) IsSendEnabledCoins(ctx context.Context, coins ...types.Coin) error { - m.ctrl.T.Helper() - varargs := []interface{}{ctx} - for _, a := range coins { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "IsSendEnabledCoins", varargs...) - ret0, _ := ret[0].(error) - return ret0 -} - -// IsSendEnabledCoins indicates an expected call of IsSendEnabledCoins. -func (mr *MockBankKeeperMockRecorder) IsSendEnabledCoins(ctx interface{}, coins ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx}, coins...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSendEnabledCoins", reflect.TypeOf((*BankKeeper)(nil).IsSendEnabledCoins), varargs...) -} - -// IsSendEnabledDenom mocks base method. -func (m *BankKeeper) IsSendEnabledDenom(ctx context.Context, denom string) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsSendEnabledDenom", ctx, denom) - ret0, _ := ret[0].(bool) - return ret0 -} - -// IsSendEnabledDenom indicates an expected call of IsSendEnabledDenom. -func (mr *MockBankKeeperMockRecorder) IsSendEnabledDenom(ctx, denom interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSendEnabledDenom", reflect.TypeOf((*BankKeeper)(nil).IsSendEnabledDenom), ctx, denom) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSendEnabledCoin", reflect.TypeOf((*MockBankKeeper)(nil).IsSendEnabledCoin), ctx, coin) } // IterateAccountBalances mocks base method. -func (m *BankKeeper) IterateAccountBalances(ctx context.Context, addr types.AccAddress, cb func(types.Coin) bool) { +func (m *MockBankKeeper) IterateAccountBalances(ctx context.Context, account types.AccAddress, cb func(types.Coin) bool) { m.ctrl.T.Helper() - m.ctrl.Call(m, "IterateAccountBalances", ctx, addr, cb) + m.ctrl.Call(m, "IterateAccountBalances", ctx, account, cb) } // IterateAccountBalances indicates an expected call of IterateAccountBalances. -func (mr *MockBankKeeperMockRecorder) IterateAccountBalances(ctx, addr, cb interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAccountBalances", reflect.TypeOf((*BankKeeper)(nil).IterateAccountBalances), ctx, addr, cb) -} - -// IterateAllBalances mocks base method. -func (m *BankKeeper) IterateAllBalances(ctx context.Context, cb func(types.AccAddress, types.Coin) bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "IterateAllBalances", ctx, cb) -} - -// IterateAllBalances indicates an expected call of IterateAllBalances. -func (mr *MockBankKeeperMockRecorder) IterateAllBalances(ctx, cb interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAllBalances", reflect.TypeOf((*BankKeeper)(nil).IterateAllBalances), ctx, cb) -} - -// IterateAllDenomMetaData mocks base method. -func (m *BankKeeper) IterateAllDenomMetaData(ctx context.Context, cb func(types0.Metadata) bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "IterateAllDenomMetaData", ctx, cb) -} - -// IterateAllDenomMetaData indicates an expected call of IterateAllDenomMetaData. -func (mr *MockBankKeeperMockRecorder) IterateAllDenomMetaData(ctx, cb interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAllDenomMetaData", reflect.TypeOf((*BankKeeper)(nil).IterateAllDenomMetaData), ctx, cb) -} - -// IterateSendEnabledEntries mocks base method. -func (m *BankKeeper) IterateSendEnabledEntries(ctx context.Context, cb func(string, bool) bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "IterateSendEnabledEntries", ctx, cb) -} - -// IterateSendEnabledEntries indicates an expected call of IterateSendEnabledEntries. -func (mr *MockBankKeeperMockRecorder) IterateSendEnabledEntries(ctx, cb interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) IterateAccountBalances(ctx, account, cb any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateSendEnabledEntries", reflect.TypeOf((*BankKeeper)(nil).IterateSendEnabledEntries), ctx, cb) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAccountBalances", reflect.TypeOf((*MockBankKeeper)(nil).IterateAccountBalances), ctx, account, cb) } // IterateTotalSupply mocks base method. -func (m *BankKeeper) IterateTotalSupply(ctx context.Context, cb func(types.Coin) bool) { +func (m *MockBankKeeper) IterateTotalSupply(ctx context.Context, cb func(types.Coin) bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "IterateTotalSupply", ctx, cb) } // IterateTotalSupply indicates an expected call of IterateTotalSupply. -func (mr *MockBankKeeperMockRecorder) IterateTotalSupply(ctx, cb interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateTotalSupply", reflect.TypeOf((*BankKeeper)(nil).IterateTotalSupply), ctx, cb) -} - -// LockedCoins mocks base method. -func (m *BankKeeper) LockedCoins(ctx context.Context, addr types.AccAddress) types.Coins { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LockedCoins", ctx, addr) - ret0, _ := ret[0].(types.Coins) - return ret0 -} - -// LockedCoins indicates an expected call of LockedCoins. -func (mr *MockBankKeeperMockRecorder) LockedCoins(ctx, addr interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) IterateTotalSupply(ctx, cb any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LockedCoins", reflect.TypeOf((*BankKeeper)(nil).LockedCoins), ctx, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateTotalSupply", reflect.TypeOf((*MockBankKeeper)(nil).IterateTotalSupply), ctx, cb) } // MintCoins mocks base method. -func (m *BankKeeper) MintCoins(ctx context.Context, moduleName string, amt types.Coins) error { +func (m *MockBankKeeper) MintCoins(ctx context.Context, moduleName string, amt types.Coins) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "MintCoins", ctx, moduleName, amt) ret0, _ := ret[0].(error) @@ -609,40 +160,13 @@ func (m *BankKeeper) MintCoins(ctx context.Context, moduleName string, amt types } // MintCoins indicates an expected call of MintCoins. -func (mr *MockBankKeeperMockRecorder) MintCoins(ctx, moduleName, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) MintCoins(ctx, moduleName, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MintCoins", reflect.TypeOf((*BankKeeper)(nil).MintCoins), ctx, moduleName, amt) -} - -// Params mocks base method. -func (m *BankKeeper) Params(arg0 context.Context, arg1 *types0.QueryParamsRequest) (*types0.QueryParamsResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Params", arg0, arg1) - ret0, _ := ret[0].(*types0.QueryParamsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Params indicates an expected call of Params. -func (mr *MockBankKeeperMockRecorder) Params(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Params", reflect.TypeOf((*BankKeeper)(nil).Params), arg0, arg1) -} - -// PrependSendRestriction mocks base method. -func (m *BankKeeper) PrependSendRestriction(restriction types0.SendRestrictionFn) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "PrependSendRestriction", restriction) -} - -// PrependSendRestriction indicates an expected call of PrependSendRestriction. -func (mr *MockBankKeeperMockRecorder) PrependSendRestriction(restriction interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrependSendRestriction", reflect.TypeOf((*BankKeeper)(nil).PrependSendRestriction), restriction) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MintCoins", reflect.TypeOf((*MockBankKeeper)(nil).MintCoins), ctx, moduleName, amt) } // SendCoins mocks base method. -func (m *BankKeeper) SendCoins(ctx context.Context, fromAddr, toAddr types.AccAddress, amt types.Coins) error { +func (m *MockBankKeeper) SendCoins(ctx context.Context, fromAddr, toAddr types.AccAddress, amt types.Coins) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SendCoins", ctx, fromAddr, toAddr, amt) ret0, _ := ret[0].(error) @@ -650,13 +174,13 @@ func (m *BankKeeper) SendCoins(ctx context.Context, fromAddr, toAddr types.AccAd } // SendCoins indicates an expected call of SendCoins. -func (mr *MockBankKeeperMockRecorder) SendCoins(ctx, fromAddr, toAddr, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SendCoins(ctx, fromAddr, toAddr, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoins", reflect.TypeOf((*BankKeeper)(nil).SendCoins), ctx, fromAddr, toAddr, amt) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoins", reflect.TypeOf((*MockBankKeeper)(nil).SendCoins), ctx, fromAddr, toAddr, amt) } // SendCoinsFromAccountToModule mocks base method. -func (m *BankKeeper) SendCoinsFromAccountToModule(ctx context.Context, senderAddr types.AccAddress, recipientModule string, amt types.Coins) error { +func (m *MockBankKeeper) SendCoinsFromAccountToModule(ctx context.Context, senderAddr types.AccAddress, recipientModule string, amt types.Coins) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SendCoinsFromAccountToModule", ctx, senderAddr, recipientModule, amt) ret0, _ := ret[0].(error) @@ -664,13 +188,13 @@ func (m *BankKeeper) SendCoinsFromAccountToModule(ctx context.Context, senderAdd } // SendCoinsFromAccountToModule indicates an expected call of SendCoinsFromAccountToModule. -func (mr *MockBankKeeperMockRecorder) SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromAccountToModule", reflect.TypeOf((*BankKeeper)(nil).SendCoinsFromAccountToModule), ctx, senderAddr, recipientModule, amt) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromAccountToModule", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromAccountToModule), ctx, senderAddr, recipientModule, amt) } // SendCoinsFromModuleToAccount mocks base method. -func (m *BankKeeper) SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr types.AccAddress, amt types.Coins) error { +func (m *MockBankKeeper) SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr types.AccAddress, amt types.Coins) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SendCoinsFromModuleToAccount", ctx, senderModule, recipientAddr, amt) ret0, _ := ret[0].(error) @@ -678,122 +202,25 @@ func (m *BankKeeper) SendCoinsFromModuleToAccount(ctx context.Context, senderMod } // SendCoinsFromModuleToAccount indicates an expected call of SendCoinsFromModuleToAccount. -func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToAccount", reflect.TypeOf((*BankKeeper)(nil).SendCoinsFromModuleToAccount), ctx, senderModule, recipientAddr, amt) -} - -// SendCoinsFromModuleToModule mocks base method. -func (m *BankKeeper) SendCoinsFromModuleToModule(ctx context.Context, senderModule, recipientModule string, amt types.Coins) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SendCoinsFromModuleToModule", ctx, senderModule, recipientModule, amt) - ret0, _ := ret[0].(error) - return ret0 -} - -// SendCoinsFromModuleToModule indicates an expected call of SendCoinsFromModuleToModule. -func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, amt interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToModule", reflect.TypeOf((*BankKeeper)(nil).SendCoinsFromModuleToModule), ctx, senderModule, recipientModule, amt) -} - -// SendEnabled mocks base method. -func (m *BankKeeper) SendEnabled(arg0 context.Context, arg1 *types0.QuerySendEnabledRequest) (*types0.QuerySendEnabledResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SendEnabled", arg0, arg1) - ret0, _ := ret[0].(*types0.QuerySendEnabledResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SendEnabled indicates an expected call of SendEnabled. -func (mr *MockBankKeeperMockRecorder) SendEnabled(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendEnabled", reflect.TypeOf((*BankKeeper)(nil).SendEnabled), arg0, arg1) -} - -// SetAllSendEnabled mocks base method. -func (m *BankKeeper) SetAllSendEnabled(ctx context.Context, sendEnableds []*types0.SendEnabled) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetAllSendEnabled", ctx, sendEnableds) -} - -// SetAllSendEnabled indicates an expected call of SetAllSendEnabled. -func (mr *MockBankKeeperMockRecorder) SetAllSendEnabled(ctx, sendEnableds interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAllSendEnabled", reflect.TypeOf((*BankKeeper)(nil).SetAllSendEnabled), ctx, sendEnableds) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToAccount", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromModuleToAccount), ctx, senderModule, recipientAddr, amt) } // SetDenomMetaData mocks base method. -func (m *BankKeeper) SetDenomMetaData(ctx context.Context, denomMetaData types0.Metadata) { +func (m *MockBankKeeper) SetDenomMetaData(ctx context.Context, denomMetaData types0.Metadata) { m.ctrl.T.Helper() m.ctrl.Call(m, "SetDenomMetaData", ctx, denomMetaData) } // SetDenomMetaData indicates an expected call of SetDenomMetaData. -func (mr *MockBankKeeperMockRecorder) SetDenomMetaData(ctx, denomMetaData interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDenomMetaData", reflect.TypeOf((*BankKeeper)(nil).SetDenomMetaData), ctx, denomMetaData) -} - -// SetParams mocks base method. -func (m *BankKeeper) SetParams(ctx context.Context, params types0.Params) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetParams", ctx, params) - ret0, _ := ret[0].(error) - return ret0 -} - -// SetParams indicates an expected call of SetParams. -func (mr *MockBankKeeperMockRecorder) SetParams(ctx, params interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetParams", reflect.TypeOf((*BankKeeper)(nil).SetParams), ctx, params) -} - -// SetSendEnabled mocks base method. -func (m *BankKeeper) SetSendEnabled(ctx context.Context, denom string, value bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSendEnabled", ctx, denom, value) -} - -// SetSendEnabled indicates an expected call of SetSendEnabled. -func (mr *MockBankKeeperMockRecorder) SetSendEnabled(ctx, denom, value interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SetDenomMetaData(ctx, denomMetaData any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSendEnabled", reflect.TypeOf((*BankKeeper)(nil).SetSendEnabled), ctx, denom, value) -} - -// SpendableBalanceByDenom mocks base method. -func (m *BankKeeper) SpendableBalanceByDenom(arg0 context.Context, arg1 *types0.QuerySpendableBalanceByDenomRequest) (*types0.QuerySpendableBalanceByDenomResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpendableBalanceByDenom", arg0, arg1) - ret0, _ := ret[0].(*types0.QuerySpendableBalanceByDenomResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SpendableBalanceByDenom indicates an expected call of SpendableBalanceByDenom. -func (mr *MockBankKeeperMockRecorder) SpendableBalanceByDenom(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableBalanceByDenom", reflect.TypeOf((*BankKeeper)(nil).SpendableBalanceByDenom), arg0, arg1) -} - -// SpendableBalances mocks base method. -func (m *BankKeeper) SpendableBalances(arg0 context.Context, arg1 *types0.QuerySpendableBalancesRequest) (*types0.QuerySpendableBalancesResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpendableBalances", arg0, arg1) - ret0, _ := ret[0].(*types0.QuerySpendableBalancesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SpendableBalances indicates an expected call of SpendableBalances. -func (mr *MockBankKeeperMockRecorder) SpendableBalances(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableBalances", reflect.TypeOf((*BankKeeper)(nil).SpendableBalances), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDenomMetaData", reflect.TypeOf((*MockBankKeeper)(nil).SetDenomMetaData), ctx, denomMetaData) } // SpendableCoin mocks base method. -func (m *BankKeeper) SpendableCoin(ctx context.Context, addr types.AccAddress, denom string) types.Coin { +func (m *MockBankKeeper) SpendableCoin(ctx context.Context, addr types.AccAddress, denom string) types.Coin { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SpendableCoin", ctx, addr, denom) ret0, _ := ret[0].(types.Coin) @@ -801,116 +228,7 @@ func (m *BankKeeper) SpendableCoin(ctx context.Context, addr types.AccAddress, d } // SpendableCoin indicates an expected call of SpendableCoin. -func (mr *MockBankKeeperMockRecorder) SpendableCoin(ctx, addr, denom interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableCoin", reflect.TypeOf((*BankKeeper)(nil).SpendableCoin), ctx, addr, denom) -} - -// SpendableCoins mocks base method. -func (m *BankKeeper) SpendableCoins(ctx context.Context, addr types.AccAddress) types.Coins { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpendableCoins", ctx, addr) - ret0, _ := ret[0].(types.Coins) - return ret0 -} - -// SpendableCoins indicates an expected call of SpendableCoins. -func (mr *MockBankKeeperMockRecorder) SpendableCoins(ctx, addr interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableCoins", reflect.TypeOf((*BankKeeper)(nil).SpendableCoins), ctx, addr) -} - -// SupplyOf mocks base method. -func (m *BankKeeper) SupplyOf(arg0 context.Context, arg1 *types0.QuerySupplyOfRequest) (*types0.QuerySupplyOfResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SupplyOf", arg0, arg1) - ret0, _ := ret[0].(*types0.QuerySupplyOfResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SupplyOf indicates an expected call of SupplyOf. -func (mr *MockBankKeeperMockRecorder) SupplyOf(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SupplyOf", reflect.TypeOf((*BankKeeper)(nil).SupplyOf), arg0, arg1) -} - -// TotalSupply mocks base method. -func (m *BankKeeper) TotalSupply(arg0 context.Context, arg1 *types0.QueryTotalSupplyRequest) (*types0.QueryTotalSupplyResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TotalSupply", arg0, arg1) - ret0, _ := ret[0].(*types0.QueryTotalSupplyResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// TotalSupply indicates an expected call of TotalSupply. -func (mr *MockBankKeeperMockRecorder) TotalSupply(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TotalSupply", reflect.TypeOf((*BankKeeper)(nil).TotalSupply), arg0, arg1) -} - -// UndelegateCoins mocks base method. -func (m *BankKeeper) UndelegateCoins(ctx context.Context, moduleAccAddr, delegatorAddr types.AccAddress, amt types.Coins) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UndelegateCoins", ctx, moduleAccAddr, delegatorAddr, amt) - ret0, _ := ret[0].(error) - return ret0 -} - -// UndelegateCoins indicates an expected call of UndelegateCoins. -func (mr *MockBankKeeperMockRecorder) UndelegateCoins(ctx, moduleAccAddr, delegatorAddr, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SpendableCoin(ctx, addr, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UndelegateCoins", reflect.TypeOf((*BankKeeper)(nil).UndelegateCoins), ctx, moduleAccAddr, delegatorAddr, amt) -} - -// UndelegateCoinsFromModuleToAccount mocks base method. -func (m *BankKeeper) UndelegateCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr types.AccAddress, amt types.Coins) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UndelegateCoinsFromModuleToAccount", ctx, senderModule, recipientAddr, amt) - ret0, _ := ret[0].(error) - return ret0 -} - -// UndelegateCoinsFromModuleToAccount indicates an expected call of UndelegateCoinsFromModuleToAccount. -func (mr *MockBankKeeperMockRecorder) UndelegateCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UndelegateCoinsFromModuleToAccount", reflect.TypeOf((*BankKeeper)(nil).UndelegateCoinsFromModuleToAccount), ctx, senderModule, recipientAddr, amt) -} - -// ValidateBalance mocks base method. -func (m *BankKeeper) ValidateBalance(ctx context.Context, addr types.AccAddress) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateBalance", ctx, addr) - ret0, _ := ret[0].(error) - return ret0 -} - -// ValidateBalance indicates an expected call of ValidateBalance. -func (mr *MockBankKeeperMockRecorder) ValidateBalance(ctx, addr interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateBalance", reflect.TypeOf((*BankKeeper)(nil).ValidateBalance), ctx, addr) -} - -// WithMintCoinsRestriction mocks base method. -func (m *BankKeeper) WithMintCoinsRestriction(arg0 types0.MintingRestrictionFn) keeper.BaseKeeper { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WithMintCoinsRestriction", arg0) - ret0, _ := ret[0].(keeper.BaseKeeper) - return ret0 -} - -// WithMintCoinsRestriction indicates an expected call of WithMintCoinsRestriction. -func (mr *MockBankKeeperMockRecorder) WithMintCoinsRestriction(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WithMintCoinsRestriction", reflect.TypeOf((*BankKeeper)(nil).WithMintCoinsRestriction), arg0) -} - -// DenomOwnersByQuery mocks base method. -func (m *BankKeeper) DenomOwnersByQuery(arg0 context.Context, arg1 *types0.QueryDenomOwnersByQueryRequest) (*types0.QueryDenomOwnersByQueryResponse, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DenomOwnersByQuery", arg0, arg1) - ret0, _ := ret[0].(*types0.QueryDenomOwnersByQueryResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableCoin", reflect.TypeOf((*MockBankKeeper)(nil).SpendableCoin), ctx, addr, denom) } diff --git a/x/erc20/types/mocks/README.md b/x/erc20/types/mocks/README.md index 5b7ac57508..8aa5216511 100644 --- a/x/erc20/types/mocks/README.md +++ b/x/erc20/types/mocks/README.md @@ -3,31 +3,10 @@ The mocks in this folder have been generated using the [mockery](https://vektra.github.io/mockery/latest/) tool. To regenerate the mocks, run the following commands at the root of this repository: -- `BankKeeper` (from used version of Cosmos SDK): +- `BankKeeper` (reduced interface defined in ERC20 types): ```bash -# update the currently used version -COSMOS_VERSION="v0.50.9-evmos" -CUR_DIR="$(pwd)" -TMP_DIR="/tmp/tmp-sdk-mocks-$(date +%s)" - -echo "Cloning Cosmos SDK $COSMOS_VERSION into $TMP_DIR..." && -git clone --depth 1 --branch "$COSMOS_VERSION" https://github.com/evmos/cosmos-sdk.git "$TMP_DIR" && -cd "$TMP_DIR" && - -# Go into bank module and generate mock -echo "Generating mocks for bank keeper..." && -cd x/bank/keeper && -mockery --name Keeper && -sed -i '' 's/\([^a-zA-Z]\)Keeper/\1BankKeeper/g' mocks/Keeper.go && -mv mocks/Keeper.go "$CUR_DIR/x/erc20/types/mocks/BankKeeper.go" && - -# Clean up -echo "Cleaning up $TMP_DIR..." && -cd "$CUR_DIR" && -rm -rf "$TMP_DIR" - -echo "Done." +mockgen -source=./x/erc20/types/interfaces.go -package=mocks -destination=./x/erc20/types/mocks/BankKeeper.go -exclude_interfaces=AccountKeeper,StakingKeeper,EVMKeeper,Erc20Keeper ``` - `EVMKeeper` (reduced interface defined in ERC20 types): diff --git a/x/precisebank/types/mocks/MockBankKeeper.go b/x/precisebank/types/mocks/MockBankKeeper.go index 80ee7f305f..c82096a1dc 100644 --- a/x/precisebank/types/mocks/MockBankKeeper.go +++ b/x/precisebank/types/mocks/MockBankKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.53.4. DO NOT EDIT. +// Code generated by mockery v2.53.5. DO NOT EDIT. package mocks @@ -862,8 +862,7 @@ func (_c *BankKeeper_SpendableCoin_Call) RunAndReturn(run func(context.Context, func NewBankKeeper(t interface { mock.TestingT Cleanup(func()) -}, -) *BankKeeper { +}) *BankKeeper { mock := &BankKeeper{} mock.Mock.Test(t) diff --git a/x/vm/types/mocks/BankKeeper.go b/x/vm/types/mocks/BankKeeper.go index 0e57f8d134..31c4ba9838 100644 --- a/x/vm/types/mocks/BankKeeper.go +++ b/x/vm/types/mocks/BankKeeper.go @@ -1,13 +1,15 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. +// Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( context "context" - types "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + mock "github.com/stretchr/testify/mock" + + types "github.com/cosmos/cosmos-sdk/types" ) // BankKeeper is an autogenerated mock type for the BankKeeper type @@ -51,6 +53,52 @@ func (_m *BankKeeper) GetBalance(ctx context.Context, addr types.AccAddress, den return r0 } +// GetDenomMetaData provides a mock function with given fields: ctx, denom +func (_m *BankKeeper) GetDenomMetaData(ctx context.Context, denom string) (banktypes.Metadata, bool) { + ret := _m.Called(ctx, denom) + + if len(ret) == 0 { + panic("no return value specified for GetDenomMetaData") + } + + var r0 banktypes.Metadata + var r1 bool + if rf, ok := ret.Get(0).(func(context.Context, string) (banktypes.Metadata, bool)); ok { + return rf(ctx, denom) + } + if rf, ok := ret.Get(0).(func(context.Context, string) banktypes.Metadata); ok { + r0 = rf(ctx, denom) + } else { + r0 = ret.Get(0).(banktypes.Metadata) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) bool); ok { + r1 = rf(ctx, denom) + } else { + r1 = ret.Get(1).(bool) + } + + return r0, r1 +} + +// GetSupply provides a mock function with given fields: ctx, denom +func (_m *BankKeeper) GetSupply(ctx context.Context, denom string) types.Coin { + ret := _m.Called(ctx, denom) + + if len(ret) == 0 { + panic("no return value specified for GetSupply") + } + + var r0 types.Coin + if rf, ok := ret.Get(0).(func(context.Context, string) types.Coin); ok { + r0 = rf(ctx, denom) + } else { + r0 = ret.Get(0).(types.Coin) + } + + return r0 +} + // IsSendEnabledCoins provides a mock function with given fields: ctx, coins func (_m *BankKeeper) IsSendEnabledCoins(ctx context.Context, coins ...types.Coin) error { _va := make([]interface{}, len(coins)) @@ -76,6 +124,16 @@ func (_m *BankKeeper) IsSendEnabledCoins(ctx context.Context, coins ...types.Coi return r0 } +// IterateAccountBalances provides a mock function with given fields: ctx, account, cb +func (_m *BankKeeper) IterateAccountBalances(ctx context.Context, account types.AccAddress, cb func(types.Coin) bool) { + _m.Called(ctx, account, cb) +} + +// IterateTotalSupply provides a mock function with given fields: ctx, cb +func (_m *BankKeeper) IterateTotalSupply(ctx context.Context, cb func(types.Coin) bool) { + _m.Called(ctx, cb) +} + // MintCoins provides a mock function with given fields: ctx, moduleName, amt func (_m *BankKeeper) MintCoins(ctx context.Context, moduleName string, amt types.Coins) error { ret := _m.Called(ctx, moduleName, amt) @@ -148,47 +206,9 @@ func (_m *BankKeeper) SendCoinsFromModuleToAccount(ctx context.Context, senderMo return r0 } -// NewBankKeeper creates a new instance of BankKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewBankKeeper(t interface { - mock.TestingT - Cleanup(func()) -}, -) *BankKeeper { - mock := &BankKeeper{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} - -// GetDenomMetaData provides a mock function with given fields: ctx, denom -func (_m *BankKeeper) GetDenomMetaData(ctx context.Context, denom string) (banktypes.Metadata, bool) { - ret := _m.Called(ctx, denom) - - if len(ret) == 0 { - panic("no return value specified for GetDenomMetaData") - } - - var r0 banktypes.Metadata - var r1 bool - if rf, ok := ret.Get(0).(func(context.Context, string) (banktypes.Metadata, bool)); ok { - return rf(ctx, denom) - } - if rf, ok := ret.Get(0).(func(context.Context, string) banktypes.Metadata); ok { - r0 = rf(ctx, denom) - } else { - r0 = ret.Get(0).(banktypes.Metadata) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) bool); ok { - r1 = rf(ctx, denom) - } else { - r1 = ret.Get(1).(bool) - } - - return r0, r1 +// SetDenomMetaData provides a mock function with given fields: ctx, denomMetaData +func (_m *BankKeeper) SetDenomMetaData(ctx context.Context, denomMetaData banktypes.Metadata) { + _m.Called(ctx, denomMetaData) } // SpendableCoin provides a mock function with given fields: ctx, addr, denom @@ -209,112 +229,16 @@ func (_m *BankKeeper) SpendableCoin(ctx context.Context, addr types.AccAddress, return r0 } -// IterateAccountBalances provides a mock function with given fields: ctx, account, cb -func (_m *BankKeeper) IterateAccountBalances(ctx context.Context, account types.AccAddress, cb func(coin types.Coin) bool) { - _m.Called(ctx, account, cb) -} - -// IterateTotalSupply provides a mock function with given fields: ctx, cb -func (_m *BankKeeper) IterateTotalSupply(ctx context.Context, cb func(coin types.Coin) bool) { - _m.Called(ctx, cb) -} - -// GetSupply provides a mock function with given fields: ctx, denom -func (_m *BankKeeper) GetSupply(ctx context.Context, denom string) types.Coin { - ret := _m.Called(ctx, denom) - - if len(ret) == 0 { - panic("no return value specified for GetSupply") - } - - var r0 types.Coin - if rf, ok := ret.Get(0).(func(context.Context, string) types.Coin); ok { - r0 = rf(ctx, denom) - } else { - r0 = ret.Get(0).(types.Coin) - } - - return r0 -} - -// SetDenomMetaData provides a mock function with given fields: ctx, denomMetaData -func (_m *BankKeeper) SetDenomMetaData(ctx context.Context, denomMetaData banktypes.Metadata) { - _m.Called(ctx, denomMetaData) -} - -// IsSendEnabledCoin provides a mock function with given fields: ctx, coin -func (_m *BankKeeper) IsSendEnabledCoin(ctx context.Context, coin types.Coin) bool { - ret := _m.Called(ctx, coin) - - if len(ret) == 0 { - panic("no return value specified for IsSendEnabledCoin") - } - - var r0 bool - if rf, ok := ret.Get(0).(func(context.Context, types.Coin) bool); ok { - r0 = rf(ctx, coin) - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// GetAllBalances provides a mock function with given fields: ctx, addr -func (_m *BankKeeper) GetAllBalances(ctx context.Context, addr types.AccAddress) types.Coins { - ret := _m.Called(ctx, addr) - - if len(ret) == 0 { - panic("no return value specified for GetAllBalances") - } - - var r0 types.Coins - if rf, ok := ret.Get(0).(func(context.Context, types.AccAddress) types.Coins); ok { - r0 = rf(ctx, addr) - } else { - r0 = ret.Get(0).(types.Coins) - } - - return r0 -} - -// BlockedAddr provides a mock function with given fields: addr -func (_m *BankKeeper) BlockedAddr(addr types.AccAddress) bool { - ret := _m.Called(addr) - - if len(ret) == 0 { - panic("no return value specified for BlockedAddr") - } - - var r0 bool - if rf, ok := ret.Get(0).(func(types.AccAddress) bool); ok { - r0 = rf(addr) - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// SendCoinsFromModuleToModule provides a mock function with given fields: ctx, senderModule, recipientModule, amt -func (_m *BankKeeper) SendCoinsFromModuleToModule(ctx context.Context, senderModule string, recipientModule string, amt types.Coins) error { - ret := _m.Called(ctx, senderModule, recipientModule, amt) - - if len(ret) == 0 { - panic("no return value specified for SendCoinsFromModuleToModule") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, types.Coins) error); ok { - r0 = rf(ctx, senderModule, recipientModule, amt) - } else { - r0 = ret.Error(0) - } +// NewBankKeeper creates a new instance of BankKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewBankKeeper(t interface { + mock.TestingT + Cleanup(func()) +}) *BankKeeper { + mock := &BankKeeper{} + mock.Mock.Test(t) - return r0 -} + t.Cleanup(func() { mock.AssertExpectations(t) }) -// IterateAllBalances provides a mock function with given fields: ctx, cb -func (_m *BankKeeper) IterateAllBalances(ctx context.Context, cb func(address types.AccAddress, coin types.Coin) (stop bool)) { - _m.Called(ctx, cb) + return mock } diff --git a/x/vm/wrappers/testutil/mock.go b/x/vm/wrappers/testutil/mock.go index 0f1710955d..ff3ce949f2 100644 --- a/x/vm/wrappers/testutil/mock.go +++ b/x/vm/wrappers/testutil/mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./x/vm/types/interfaces.go +// +// Generated by this command: +// +// mockgen -source=./x/vm/types/interfaces.go -package=testutil -destination=./x/vm/wrappers/testutil/mock.go -exclude_interfaces=ConsensusParamsKeeper +// // Package testutil is a generated GoMock package. package testutil @@ -28,6 +33,7 @@ import ( type MockAccountKeeper struct { ctrl *gomock.Controller recorder *MockAccountKeeperMockRecorder + isgomock struct{} } // MockAccountKeeperMockRecorder is the mock recorder for MockAccountKeeper. @@ -70,7 +76,7 @@ func (m *MockAccountKeeper) GetAccount(ctx context.Context, addr types.AccAddres } // GetAccount indicates an expected call of GetAccount. -func (mr *MockAccountKeeperMockRecorder) GetAccount(ctx, addr interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) GetAccount(ctx, addr any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetAccount), ctx, addr) } @@ -84,7 +90,7 @@ func (m *MockAccountKeeper) GetModuleAddress(moduleName string) types.AccAddress } // GetModuleAddress indicates an expected call of GetModuleAddress. -func (mr *MockAccountKeeperMockRecorder) GetModuleAddress(moduleName interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) GetModuleAddress(moduleName any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAddress", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAddress), moduleName) } @@ -98,7 +104,7 @@ func (m *MockAccountKeeper) GetParams(ctx context.Context) types0.Params { } // GetParams indicates an expected call of GetParams. -func (mr *MockAccountKeeperMockRecorder) GetParams(ctx interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) GetParams(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParams", reflect.TypeOf((*MockAccountKeeper)(nil).GetParams), ctx) } @@ -113,11 +119,25 @@ func (m *MockAccountKeeper) GetSequence(ctx context.Context, account types.AccAd } // GetSequence indicates an expected call of GetSequence. -func (mr *MockAccountKeeperMockRecorder) GetSequence(ctx, account interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) GetSequence(ctx, account any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSequence", reflect.TypeOf((*MockAccountKeeper)(nil).GetSequence), ctx, account) } +// HasAccount mocks base method. +func (m *MockAccountKeeper) HasAccount(ctx context.Context, addr types.AccAddress) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasAccount", ctx, addr) + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasAccount indicates an expected call of HasAccount. +func (mr *MockAccountKeeperMockRecorder) HasAccount(ctx, addr any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasAccount", reflect.TypeOf((*MockAccountKeeper)(nil).HasAccount), ctx, addr) +} + // NewAccountWithAddress mocks base method. func (m *MockAccountKeeper) NewAccountWithAddress(ctx context.Context, addr types.AccAddress) types.AccountI { m.ctrl.T.Helper() @@ -127,7 +147,7 @@ func (m *MockAccountKeeper) NewAccountWithAddress(ctx context.Context, addr type } // NewAccountWithAddress indicates an expected call of NewAccountWithAddress. -func (mr *MockAccountKeeperMockRecorder) NewAccountWithAddress(ctx, addr interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) NewAccountWithAddress(ctx, addr any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAccountWithAddress", reflect.TypeOf((*MockAccountKeeper)(nil).NewAccountWithAddress), ctx, addr) } @@ -139,7 +159,7 @@ func (m *MockAccountKeeper) RemoveAccount(ctx context.Context, account types.Acc } // RemoveAccount indicates an expected call of RemoveAccount. -func (mr *MockAccountKeeperMockRecorder) RemoveAccount(ctx, account interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) RemoveAccount(ctx, account any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveAccount", reflect.TypeOf((*MockAccountKeeper)(nil).RemoveAccount), ctx, account) } @@ -153,7 +173,7 @@ func (m *MockAccountKeeper) RemoveExpiredUnorderedNonces(ctx types.Context) erro } // RemoveExpiredUnorderedNonces indicates an expected call of RemoveExpiredUnorderedNonces. -func (mr *MockAccountKeeperMockRecorder) RemoveExpiredUnorderedNonces(ctx interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) RemoveExpiredUnorderedNonces(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveExpiredUnorderedNonces", reflect.TypeOf((*MockAccountKeeper)(nil).RemoveExpiredUnorderedNonces), ctx) } @@ -165,7 +185,7 @@ func (m *MockAccountKeeper) SetAccount(ctx context.Context, account types.Accoun } // SetAccount indicates an expected call of SetAccount. -func (mr *MockAccountKeeperMockRecorder) SetAccount(ctx, account interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) SetAccount(ctx, account any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).SetAccount), ctx, account) } @@ -179,7 +199,7 @@ func (m *MockAccountKeeper) TryAddUnorderedNonce(ctx types.Context, sender []byt } // TryAddUnorderedNonce indicates an expected call of TryAddUnorderedNonce. -func (mr *MockAccountKeeperMockRecorder) TryAddUnorderedNonce(ctx, sender, timestamp interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) TryAddUnorderedNonce(ctx, sender, timestamp any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TryAddUnorderedNonce", reflect.TypeOf((*MockAccountKeeper)(nil).TryAddUnorderedNonce), ctx, sender, timestamp) } @@ -202,6 +222,7 @@ func (mr *MockAccountKeeperMockRecorder) UnorderedTransactionsEnabled() *gomock. type MockBankKeeper struct { ctrl *gomock.Controller recorder *MockBankKeeperMockRecorder + isgomock struct{} } // MockBankKeeperMockRecorder is the mock recorder for MockBankKeeper. @@ -230,7 +251,7 @@ func (m *MockBankKeeper) BurnCoins(ctx context.Context, moduleName string, amt t } // BurnCoins indicates an expected call of BurnCoins. -func (mr *MockBankKeeperMockRecorder) BurnCoins(ctx, moduleName, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) BurnCoins(ctx, moduleName, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BurnCoins", reflect.TypeOf((*MockBankKeeper)(nil).BurnCoins), ctx, moduleName, amt) } @@ -244,7 +265,7 @@ func (m *MockBankKeeper) GetBalance(ctx context.Context, addr types.AccAddress, } // GetBalance indicates an expected call of GetBalance. -func (mr *MockBankKeeperMockRecorder) GetBalance(ctx, addr, denom interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) GetBalance(ctx, addr, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalance", reflect.TypeOf((*MockBankKeeper)(nil).GetBalance), ctx, addr, denom) } @@ -259,7 +280,7 @@ func (m *MockBankKeeper) GetDenomMetaData(ctx context.Context, denom string) (ty } // GetDenomMetaData indicates an expected call of GetDenomMetaData. -func (mr *MockBankKeeperMockRecorder) GetDenomMetaData(ctx, denom interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) GetDenomMetaData(ctx, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDenomMetaData", reflect.TypeOf((*MockBankKeeper)(nil).GetDenomMetaData), ctx, denom) } @@ -273,7 +294,7 @@ func (m *MockBankKeeper) GetSupply(ctx context.Context, denom string) types.Coin } // GetSupply indicates an expected call of GetSupply. -func (mr *MockBankKeeperMockRecorder) GetSupply(ctx, denom interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) GetSupply(ctx, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSupply", reflect.TypeOf((*MockBankKeeper)(nil).GetSupply), ctx, denom) } @@ -281,7 +302,7 @@ func (mr *MockBankKeeperMockRecorder) GetSupply(ctx, denom interface{}) *gomock. // IsSendEnabledCoins mocks base method. func (m *MockBankKeeper) IsSendEnabledCoins(ctx context.Context, coins ...types.Coin) error { m.ctrl.T.Helper() - varargs := []interface{}{ctx} + varargs := []any{ctx} for _, a := range coins { varargs = append(varargs, a) } @@ -291,9 +312,9 @@ func (m *MockBankKeeper) IsSendEnabledCoins(ctx context.Context, coins ...types. } // IsSendEnabledCoins indicates an expected call of IsSendEnabledCoins. -func (mr *MockBankKeeperMockRecorder) IsSendEnabledCoins(ctx interface{}, coins ...interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) IsSendEnabledCoins(ctx any, coins ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx}, coins...) + varargs := append([]any{ctx}, coins...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSendEnabledCoins", reflect.TypeOf((*MockBankKeeper)(nil).IsSendEnabledCoins), varargs...) } @@ -304,7 +325,7 @@ func (m *MockBankKeeper) IterateAccountBalances(ctx context.Context, account typ } // IterateAccountBalances indicates an expected call of IterateAccountBalances. -func (mr *MockBankKeeperMockRecorder) IterateAccountBalances(ctx, account, cb interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) IterateAccountBalances(ctx, account, cb any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAccountBalances", reflect.TypeOf((*MockBankKeeper)(nil).IterateAccountBalances), ctx, account, cb) } @@ -316,7 +337,7 @@ func (m *MockBankKeeper) IterateTotalSupply(ctx context.Context, cb func(types.C } // IterateTotalSupply indicates an expected call of IterateTotalSupply. -func (mr *MockBankKeeperMockRecorder) IterateTotalSupply(ctx, cb interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) IterateTotalSupply(ctx, cb any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateTotalSupply", reflect.TypeOf((*MockBankKeeper)(nil).IterateTotalSupply), ctx, cb) } @@ -330,7 +351,7 @@ func (m *MockBankKeeper) MintCoins(ctx context.Context, moduleName string, amt t } // MintCoins indicates an expected call of MintCoins. -func (mr *MockBankKeeperMockRecorder) MintCoins(ctx, moduleName, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) MintCoins(ctx, moduleName, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MintCoins", reflect.TypeOf((*MockBankKeeper)(nil).MintCoins), ctx, moduleName, amt) } @@ -344,7 +365,7 @@ func (m *MockBankKeeper) SendCoins(ctx context.Context, from, to types.AccAddres } // SendCoins indicates an expected call of SendCoins. -func (mr *MockBankKeeperMockRecorder) SendCoins(ctx, from, to, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SendCoins(ctx, from, to, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoins", reflect.TypeOf((*MockBankKeeper)(nil).SendCoins), ctx, from, to, amt) } @@ -358,7 +379,7 @@ func (m *MockBankKeeper) SendCoinsFromAccountToModule(ctx context.Context, sende } // SendCoinsFromAccountToModule indicates an expected call of SendCoinsFromAccountToModule. -func (mr *MockBankKeeperMockRecorder) SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromAccountToModule", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromAccountToModule), ctx, senderAddr, recipientModule, amt) } @@ -372,7 +393,7 @@ func (m *MockBankKeeper) SendCoinsFromModuleToAccount(ctx context.Context, sende } // SendCoinsFromModuleToAccount indicates an expected call of SendCoinsFromModuleToAccount. -func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToAccount", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromModuleToAccount), ctx, senderModule, recipientAddr, amt) } @@ -384,15 +405,30 @@ func (m *MockBankKeeper) SetDenomMetaData(ctx context.Context, denomMetaData typ } // SetDenomMetaData indicates an expected call of SetDenomMetaData. -func (mr *MockBankKeeperMockRecorder) SetDenomMetaData(ctx, denomMetaData interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SetDenomMetaData(ctx, denomMetaData any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDenomMetaData", reflect.TypeOf((*MockBankKeeper)(nil).SetDenomMetaData), ctx, denomMetaData) } +// SpendableCoin mocks base method. +func (m *MockBankKeeper) SpendableCoin(ctx context.Context, addr types.AccAddress, denom string) types.Coin { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SpendableCoin", ctx, addr, denom) + ret0, _ := ret[0].(types.Coin) + return ret0 +} + +// SpendableCoin indicates an expected call of SpendableCoin. +func (mr *MockBankKeeperMockRecorder) SpendableCoin(ctx, addr, denom any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableCoin", reflect.TypeOf((*MockBankKeeper)(nil).SpendableCoin), ctx, addr, denom) +} + // MockStakingKeeper is a mock of StakingKeeper interface. type MockStakingKeeper struct { ctrl *gomock.Controller recorder *MockStakingKeeperMockRecorder + isgomock struct{} } // MockStakingKeeperMockRecorder is the mock recorder for MockStakingKeeper. @@ -422,7 +458,7 @@ func (m *MockStakingKeeper) GetHistoricalInfo(ctx context.Context, height int64) } // GetHistoricalInfo indicates an expected call of GetHistoricalInfo. -func (mr *MockStakingKeeperMockRecorder) GetHistoricalInfo(ctx, height interface{}) *gomock.Call { +func (mr *MockStakingKeeperMockRecorder) GetHistoricalInfo(ctx, height any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHistoricalInfo", reflect.TypeOf((*MockStakingKeeper)(nil).GetHistoricalInfo), ctx, height) } @@ -437,7 +473,7 @@ func (m *MockStakingKeeper) GetValidatorByConsAddr(ctx context.Context, consAddr } // GetValidatorByConsAddr indicates an expected call of GetValidatorByConsAddr. -func (mr *MockStakingKeeperMockRecorder) GetValidatorByConsAddr(ctx, consAddr interface{}) *gomock.Call { +func (mr *MockStakingKeeperMockRecorder) GetValidatorByConsAddr(ctx, consAddr any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidatorByConsAddr", reflect.TypeOf((*MockStakingKeeper)(nil).GetValidatorByConsAddr), ctx, consAddr) } @@ -460,6 +496,7 @@ func (mr *MockStakingKeeperMockRecorder) ValidatorAddressCodec() *gomock.Call { type MockFeeMarketKeeper struct { ctrl *gomock.Controller recorder *MockFeeMarketKeeperMockRecorder + isgomock struct{} } // MockFeeMarketKeeperMockRecorder is the mock recorder for MockFeeMarketKeeper. @@ -488,7 +525,7 @@ func (m *MockFeeMarketKeeper) CalculateBaseFee(ctx types.Context) math.LegacyDec } // CalculateBaseFee indicates an expected call of CalculateBaseFee. -func (mr *MockFeeMarketKeeperMockRecorder) CalculateBaseFee(ctx interface{}) *gomock.Call { +func (mr *MockFeeMarketKeeperMockRecorder) CalculateBaseFee(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CalculateBaseFee", reflect.TypeOf((*MockFeeMarketKeeper)(nil).CalculateBaseFee), ctx) } @@ -502,7 +539,7 @@ func (m *MockFeeMarketKeeper) GetBaseFee(ctx types.Context) math.LegacyDec { } // GetBaseFee indicates an expected call of GetBaseFee. -func (mr *MockFeeMarketKeeperMockRecorder) GetBaseFee(ctx interface{}) *gomock.Call { +func (mr *MockFeeMarketKeeperMockRecorder) GetBaseFee(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBaseFee", reflect.TypeOf((*MockFeeMarketKeeper)(nil).GetBaseFee), ctx) } @@ -516,7 +553,7 @@ func (m *MockFeeMarketKeeper) GetParams(ctx types.Context) types3.Params { } // GetParams indicates an expected call of GetParams. -func (mr *MockFeeMarketKeeperMockRecorder) GetParams(ctx interface{}) *gomock.Call { +func (mr *MockFeeMarketKeeperMockRecorder) GetParams(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParams", reflect.TypeOf((*MockFeeMarketKeeper)(nil).GetParams), ctx) } @@ -525,6 +562,7 @@ func (mr *MockFeeMarketKeeperMockRecorder) GetParams(ctx interface{}) *gomock.Ca type MockErc20Keeper struct { ctrl *gomock.Controller recorder *MockErc20KeeperMockRecorder + isgomock struct{} } // MockErc20KeeperMockRecorder is the mock recorder for MockErc20Keeper. @@ -545,9 +583,9 @@ func (m *MockErc20Keeper) EXPECT() *MockErc20KeeperMockRecorder { } // GetERC20PrecompileInstance mocks base method. -func (m *MockErc20Keeper) GetERC20PrecompileInstance(ctx types.Context, address common.Address) (vm.PrecompiledContract, bool, error) { +func (m *MockErc20Keeper) GetERC20PrecompileInstance(ctx types.Context, arg1 common.Address) (vm.PrecompiledContract, bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetERC20PrecompileInstance", ctx, address) + ret := m.ctrl.Call(m, "GetERC20PrecompileInstance", ctx, arg1) ret0, _ := ret[0].(vm.PrecompiledContract) ret1, _ := ret[1].(bool) ret2, _ := ret[2].(error) @@ -555,15 +593,16 @@ func (m *MockErc20Keeper) GetERC20PrecompileInstance(ctx types.Context, address } // GetERC20PrecompileInstance indicates an expected call of GetERC20PrecompileInstance. -func (mr *MockErc20KeeperMockRecorder) GetERC20PrecompileInstance(ctx, address interface{}) *gomock.Call { +func (mr *MockErc20KeeperMockRecorder) GetERC20PrecompileInstance(ctx, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetERC20PrecompileInstance", reflect.TypeOf((*MockErc20Keeper)(nil).GetERC20PrecompileInstance), ctx, address) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetERC20PrecompileInstance", reflect.TypeOf((*MockErc20Keeper)(nil).GetERC20PrecompileInstance), ctx, arg1) } // MockEvmHooks is a mock of EvmHooks interface. type MockEvmHooks struct { ctrl *gomock.Controller recorder *MockEvmHooksMockRecorder + isgomock struct{} } // MockEvmHooksMockRecorder is the mock recorder for MockEvmHooks. @@ -592,7 +631,7 @@ func (m *MockEvmHooks) PostTxProcessing(ctx types.Context, sender common.Address } // PostTxProcessing indicates an expected call of PostTxProcessing. -func (mr *MockEvmHooksMockRecorder) PostTxProcessing(ctx, sender, msg, receipt interface{}) *gomock.Call { +func (mr *MockEvmHooksMockRecorder) PostTxProcessing(ctx, sender, msg, receipt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostTxProcessing", reflect.TypeOf((*MockEvmHooks)(nil).PostTxProcessing), ctx, sender, msg, receipt) } @@ -601,6 +640,7 @@ func (mr *MockEvmHooksMockRecorder) PostTxProcessing(ctx, sender, msg, receipt i type MockBankWrapper struct { ctrl *gomock.Controller recorder *MockBankWrapperMockRecorder + isgomock struct{} } // MockBankWrapperMockRecorder is the mock recorder for MockBankWrapper. @@ -629,7 +669,7 @@ func (m *MockBankWrapper) BurnAmountFromAccount(ctx context.Context, account typ } // BurnAmountFromAccount indicates an expected call of BurnAmountFromAccount. -func (mr *MockBankWrapperMockRecorder) BurnAmountFromAccount(ctx, account, amt interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) BurnAmountFromAccount(ctx, account, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BurnAmountFromAccount", reflect.TypeOf((*MockBankWrapper)(nil).BurnAmountFromAccount), ctx, account, amt) } @@ -643,7 +683,7 @@ func (m *MockBankWrapper) BurnCoins(ctx context.Context, moduleName string, amt } // BurnCoins indicates an expected call of BurnCoins. -func (mr *MockBankWrapperMockRecorder) BurnCoins(ctx, moduleName, amt interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) BurnCoins(ctx, moduleName, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BurnCoins", reflect.TypeOf((*MockBankWrapper)(nil).BurnCoins), ctx, moduleName, amt) } @@ -651,15 +691,15 @@ func (mr *MockBankWrapperMockRecorder) BurnCoins(ctx, moduleName, amt interface{ // GetBalance mocks base method. func (m *MockBankWrapper) GetBalance(ctx context.Context, addr types.AccAddress, denom string) types.Coin { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpendableCoin", ctx, addr, denom) + ret := m.ctrl.Call(m, "GetBalance", ctx, addr, denom) ret0, _ := ret[0].(types.Coin) return ret0 } // GetBalance indicates an expected call of GetBalance. -func (mr *MockBankWrapperMockRecorder) GetBalance(ctx, addr, denom interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) GetBalance(ctx, addr, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableCoin", reflect.TypeOf((*MockBankWrapper)(nil).GetBalance), ctx, addr, denom) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalance", reflect.TypeOf((*MockBankWrapper)(nil).GetBalance), ctx, addr, denom) } // GetDenomMetaData mocks base method. @@ -672,7 +712,7 @@ func (m *MockBankWrapper) GetDenomMetaData(ctx context.Context, denom string) (t } // GetDenomMetaData indicates an expected call of GetDenomMetaData. -func (mr *MockBankWrapperMockRecorder) GetDenomMetaData(ctx, denom interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) GetDenomMetaData(ctx, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDenomMetaData", reflect.TypeOf((*MockBankWrapper)(nil).GetDenomMetaData), ctx, denom) } @@ -686,7 +726,7 @@ func (m *MockBankWrapper) GetSupply(ctx context.Context, denom string) types.Coi } // GetSupply indicates an expected call of GetSupply. -func (mr *MockBankWrapperMockRecorder) GetSupply(ctx, denom interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) GetSupply(ctx, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSupply", reflect.TypeOf((*MockBankWrapper)(nil).GetSupply), ctx, denom) } @@ -694,7 +734,7 @@ func (mr *MockBankWrapperMockRecorder) GetSupply(ctx, denom interface{}) *gomock // IsSendEnabledCoins mocks base method. func (m *MockBankWrapper) IsSendEnabledCoins(ctx context.Context, coins ...types.Coin) error { m.ctrl.T.Helper() - varargs := []interface{}{ctx} + varargs := []any{ctx} for _, a := range coins { varargs = append(varargs, a) } @@ -704,9 +744,9 @@ func (m *MockBankWrapper) IsSendEnabledCoins(ctx context.Context, coins ...types } // IsSendEnabledCoins indicates an expected call of IsSendEnabledCoins. -func (mr *MockBankWrapperMockRecorder) IsSendEnabledCoins(ctx interface{}, coins ...interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) IsSendEnabledCoins(ctx any, coins ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx}, coins...) + varargs := append([]any{ctx}, coins...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSendEnabledCoins", reflect.TypeOf((*MockBankWrapper)(nil).IsSendEnabledCoins), varargs...) } @@ -717,7 +757,7 @@ func (m *MockBankWrapper) IterateAccountBalances(ctx context.Context, account ty } // IterateAccountBalances indicates an expected call of IterateAccountBalances. -func (mr *MockBankWrapperMockRecorder) IterateAccountBalances(ctx, account, cb interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) IterateAccountBalances(ctx, account, cb any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAccountBalances", reflect.TypeOf((*MockBankWrapper)(nil).IterateAccountBalances), ctx, account, cb) } @@ -729,7 +769,7 @@ func (m *MockBankWrapper) IterateTotalSupply(ctx context.Context, cb func(types. } // IterateTotalSupply indicates an expected call of IterateTotalSupply. -func (mr *MockBankWrapperMockRecorder) IterateTotalSupply(ctx, cb interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) IterateTotalSupply(ctx, cb any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateTotalSupply", reflect.TypeOf((*MockBankWrapper)(nil).IterateTotalSupply), ctx, cb) } @@ -743,7 +783,7 @@ func (m *MockBankWrapper) MintAmountToAccount(ctx context.Context, recipientAddr } // MintAmountToAccount indicates an expected call of MintAmountToAccount. -func (mr *MockBankWrapperMockRecorder) MintAmountToAccount(ctx, recipientAddr, amt interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) MintAmountToAccount(ctx, recipientAddr, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MintAmountToAccount", reflect.TypeOf((*MockBankWrapper)(nil).MintAmountToAccount), ctx, recipientAddr, amt) } @@ -757,7 +797,7 @@ func (m *MockBankWrapper) MintCoins(ctx context.Context, moduleName string, amt } // MintCoins indicates an expected call of MintCoins. -func (mr *MockBankWrapperMockRecorder) MintCoins(ctx, moduleName, amt interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) MintCoins(ctx, moduleName, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MintCoins", reflect.TypeOf((*MockBankWrapper)(nil).MintCoins), ctx, moduleName, amt) } @@ -771,7 +811,7 @@ func (m *MockBankWrapper) SendCoins(ctx context.Context, from, to types.AccAddre } // SendCoins indicates an expected call of SendCoins. -func (mr *MockBankWrapperMockRecorder) SendCoins(ctx, from, to, amt interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) SendCoins(ctx, from, to, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoins", reflect.TypeOf((*MockBankWrapper)(nil).SendCoins), ctx, from, to, amt) } @@ -785,7 +825,7 @@ func (m *MockBankWrapper) SendCoinsFromAccountToModule(ctx context.Context, send } // SendCoinsFromAccountToModule indicates an expected call of SendCoinsFromAccountToModule. -func (mr *MockBankWrapperMockRecorder) SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromAccountToModule", reflect.TypeOf((*MockBankWrapper)(nil).SendCoinsFromAccountToModule), ctx, senderAddr, recipientModule, amt) } @@ -799,7 +839,7 @@ func (m *MockBankWrapper) SendCoinsFromModuleToAccount(ctx context.Context, send } // SendCoinsFromModuleToAccount indicates an expected call of SendCoinsFromModuleToAccount. -func (mr *MockBankWrapperMockRecorder) SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToAccount", reflect.TypeOf((*MockBankWrapper)(nil).SendCoinsFromModuleToAccount), ctx, senderModule, recipientAddr, amt) } @@ -811,7 +851,7 @@ func (m *MockBankWrapper) SetDenomMetaData(ctx context.Context, denomMetaData ty } // SetDenomMetaData indicates an expected call of SetDenomMetaData. -func (mr *MockBankWrapperMockRecorder) SetDenomMetaData(ctx, denomMetaData interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) SetDenomMetaData(ctx, denomMetaData any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDenomMetaData", reflect.TypeOf((*MockBankWrapper)(nil).SetDenomMetaData), ctx, denomMetaData) } @@ -825,7 +865,7 @@ func (m *MockBankWrapper) SpendableCoin(ctx context.Context, addr types.AccAddre } // SpendableCoin indicates an expected call of SpendableCoin. -func (mr *MockBankWrapperMockRecorder) SpendableCoin(ctx, addr, denom interface{}) *gomock.Call { +func (mr *MockBankWrapperMockRecorder) SpendableCoin(ctx, addr, denom any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableCoin", reflect.TypeOf((*MockBankWrapper)(nil).SpendableCoin), ctx, addr, denom) } From c43c9404809083ee9a183d90c124d5b171247521 Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Tue, 16 Sep 2025 18:03:32 -0400 Subject: [PATCH 52/61] feat: emit geth metrics on cosmos SDK metrics server (#588) * checkpoint * prometheus bridge * delete registry * some changes * enable metrics * move things to make more sense * some changes * fix lint * add some tests * add changelog entry * incredibly stupid simple way to do this * changelog --------- Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + go.mod | 3 ++- server/start.go | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21e00aa4ce..81fea1ac85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ - [\#346](https://github.com/cosmos/evm/pull/346) Add eth_createAccessList method and implementation - [\#502](https://github.com/cosmos/evm/pull/502) Add block time in derived logs. +- [\#588](https://github.com/cosmos/evm/pull/588) go-ethereum metrics are now available in Cosmos SDK's telemetry server at host:port/geth/metrics (default localhost:1317/geth/metrics). ### STATE BREAKING diff --git a/go.mod b/go.mod index 2e66b76267..4166dd6d35 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( github.com/onsi/ginkgo/v2 v2.23.4 github.com/onsi/gomega v1.38.0 github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.22.0 github.com/rs/cors v1.11.1 github.com/spf13/cast v1.9.2 github.com/spf13/cobra v1.9.1 @@ -180,6 +181,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect @@ -205,7 +207,6 @@ require ( github.com/pion/transport/v3 v3.0.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.22.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.63.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect diff --git a/server/start.go b/server/start.go index 85ba9dad6b..aa317693cf 100644 --- a/server/start.go +++ b/server/start.go @@ -9,7 +9,9 @@ import ( "path/filepath" "runtime/pprof" + gethmetrics "github.com/ethereum/go-ethereum/metrics" ethmetricsexp "github.com/ethereum/go-ethereum/metrics/exp" + gethprom "github.com/ethereum/go-ethereum/metrics/prometheus" "github.com/spf13/cobra" "golang.org/x/sync/errgroup" "google.golang.org/grpc" @@ -683,6 +685,7 @@ func startAPIServer( if svrCfg.Telemetry.Enabled { apiSrv.SetTelemetry(metrics) + apiSrv.Router.Handle("/geth/metrics", gethprom.Handler(gethmetrics.DefaultRegistry)) } g.Go(func() error { From eb3eb813cd86ae16a13c5aefee7f9077086dbc6d Mon Sep 17 00:00:00 2001 From: Haber Date: Thu, 18 Sep 2025 03:25:59 +0900 Subject: [PATCH 53/61] fix(mempool): checkTxHandler to handle invalid sequence tx (#591) * fix(mempool): checkTxHandler handles "invalid nonce" tx * chore: update CHANGELOG.md * test(mempool): fix integration test * test(mempool): refine test code * fix(mempool): fix checkTxHandler logic to prevent integer overflow. * test(ante) fix test code for sequence increment --- CHANGELOG.md | 3 +- ante/evm/09_increment_sequence.go | 16 +- mempool/check_tx.go | 2 +- mempool/errors.go | 1 + .../test_evm_unit_09_increment_sequence.go | 5 +- tests/integration/mempool/test_helpers.go | 81 +++++++++- .../mempool/test_mempool_integration_abci.go | 151 ++++++++++++------ 7 files changed, 193 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81fea1ac85..c3ed2eff90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,8 @@ - [\#495](https://github.com/cosmos/evm/pull/495) Allow immediate SIGINT interrupt when mempool is not empty - [\#416](https://github.com/cosmos/evm/pull/416) Fix regression in CometBlockResultByNumber when height is 0 to use the latest block. This fixes eth_getFilterLogs RPC. - [\#545](https://github.com/cosmos/evm/pull/545) Check if mempool is not nil before accepting nonce gap error tx. -- [\#585](https://github.com/cosmos/evm/pull/585) Use zero constructor to avoid nil pointer panic when BaseFee is 0d +- [\#585](https://github.com/cosmos/evm/pull/585) Use zero constructor to avoid nil pointer panic when BaseFee is 0d +- [\#591](https://github.com/cosmos/evm/pull/591) CheckTxHandler should handle "invalid nonce" tx ### IMPROVEMENTS diff --git a/ante/evm/09_increment_sequence.go b/ante/evm/09_increment_sequence.go index 3440d7c610..fe28cf8967 100644 --- a/ante/evm/09_increment_sequence.go +++ b/ante/evm/09_increment_sequence.go @@ -22,15 +22,15 @@ func IncrementNonce( accountNonce := account.GetSequence() // we merged the accountNonce verification to accountNonce increment, so when tx includes multiple messages // with same sender, they'll be accepted. - if txNonce != accountNonce { - if txNonce > accountNonce { - return errorsmod.Wrapf( - mempool.ErrNonceGap, - "tx nonce: %d, account accountNonce: %d", txNonce, accountNonce, - ) - } + if txNonce > accountNonce { return errorsmod.Wrapf( - errortypes.ErrInvalidSequence, + mempool.ErrNonceGap, + "tx nonce: %d, account accountNonce: %d", txNonce, accountNonce, + ) + } + if txNonce < accountNonce { + return errorsmod.Wrapf( + mempool.ErrNonceLow, "invalid nonce; got %d, expected %d", txNonce, accountNonce, ) } diff --git a/mempool/check_tx.go b/mempool/check_tx.go index 438ad9783d..f42a024feb 100644 --- a/mempool/check_tx.go +++ b/mempool/check_tx.go @@ -18,7 +18,7 @@ func NewCheckTxHandler(mempool *ExperimentalEVMMempool) types.CheckTxHandler { gInfo, result, anteEvents, err := runTx(request.Tx, nil) if err != nil { // detect if there is a nonce gap error (only returned for EVM transactions) - if errors.Is(err, ErrNonceGap) { + if errors.Is(err, ErrNonceGap) || errors.Is(err, ErrNonceLow) { // send it to the mempool for further triage err := mempool.InsertInvalidNonce(request.Tx) if err != nil { diff --git a/mempool/errors.go b/mempool/errors.go index 522d2f7e52..f42ddc530b 100644 --- a/mempool/errors.go +++ b/mempool/errors.go @@ -8,4 +8,5 @@ var ( ErrExpectedOneError = errors.New("expected 1 error") ErrNotEVMTransaction = errors.New("transaction is not an EVM transaction") ErrNonceGap = errors.New("tx nonce is higher than account nonce") + ErrNonceLow = errors.New("tx nonce is lower than account nonce") ) diff --git a/tests/integration/ante/test_evm_unit_09_increment_sequence.go b/tests/integration/ante/test_evm_unit_09_increment_sequence.go index d2b3e0b64a..49d8fbd2e9 100644 --- a/tests/integration/ante/test_evm_unit_09_increment_sequence.go +++ b/tests/integration/ante/test_evm_unit_09_increment_sequence.go @@ -9,7 +9,6 @@ import ( testkeyring "github.com/cosmos/evm/testutil/keyring" sdktypes "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/errors" ) func (s *EvmUnitAnteTestSuite) TestIncrementSequence() { @@ -38,8 +37,8 @@ func (s *EvmUnitAnteTestSuite) TestIncrementSequence() { }, }, { - name: "fail: invalid sequence", - expectedError: errors.ErrInvalidSequence, + name: "fail: nonce is low", + expectedError: mempool.ErrNonceLow, malleate: func(acct sdktypes.AccountI) uint64 { err := acct.SetSequence(acct.GetSequence() + 1) s.Require().NoError(err) diff --git a/tests/integration/mempool/test_helpers.go b/tests/integration/mempool/test_helpers.go index 69246265ae..1c87c05863 100644 --- a/tests/integration/mempool/test_helpers.go +++ b/tests/integration/mempool/test_helpers.go @@ -4,10 +4,12 @@ import ( "encoding/hex" "fmt" "math/big" + "time" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/tmhash" + evmmempool "github.com/cosmos/evm/mempool" "github.com/cosmos/evm/testutil/integration/base/factory" "github.com/cosmos/evm/testutil/keyring" evmtypes "github.com/cosmos/evm/x/vm/types" @@ -67,6 +69,29 @@ func (s *IntegrationTestSuite) createEVMValueTransferTx(key keyring.Key, nonce i return tx } +// createEVMTransaction creates an EVM transaction using the provided key +func (s *IntegrationTestSuite) createEVMValueTransferDynamicFeeTx(key keyring.Key, nonce int, gasFeeCap, gasTipCap *big.Int) sdk.Tx { + to := s.keyring.GetKey(1).Addr + + if nonce < 0 { + s.Require().NoError(fmt.Errorf("nonce must be non-negative")) + } + + ethTxArgs := evmtypes.EvmTxArgs{ + Nonce: uint64(nonce), + To: &to, + Amount: big.NewInt(1000), + GasLimit: TxGas, + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, + Input: nil, + } + tx, err := s.factory.GenerateSignedEthTx(key.Priv, ethTxArgs) + s.Require().NoError(err) + + return tx +} + // createEVMContractDeployTx creates an EVM transaction for contract deployment func (s *IntegrationTestSuite) createEVMContractDeployTx(key keyring.Key, gasPrice *big.Int, data []byte) sdk.Tx { ethTxArgs := evmtypes.EvmTxArgs{ @@ -86,7 +111,13 @@ func (s *IntegrationTestSuite) createEVMContractDeployTx(key keyring.Key, gasPri // checkTxs call abci CheckTx for multipile transactions func (s *IntegrationTestSuite) checkTxs(txs []sdk.Tx) error { for _, tx := range txs { - if err := s.checkTx(tx); err != nil { + if res, err := s.checkTx(tx); err != nil { + if err != nil { + return fmt.Errorf("failed to execute CheckTx for tx: %s", s.getTxHash(tx)) + } + if res.Code != abci.CodeTypeOK { + return fmt.Errorf("tx (%s) failed to pass CheckTx with log: %s", s.getTxHash(tx), res.Log) + } return err } } @@ -94,21 +125,34 @@ func (s *IntegrationTestSuite) checkTxs(txs []sdk.Tx) error { } // checkTxs call abci CheckTx for a transaction -func (s *IntegrationTestSuite) checkTx(tx sdk.Tx) error { +func (s *IntegrationTestSuite) checkTx(tx sdk.Tx) (*abci.ResponseCheckTx, error) { txBytes, err := s.network.App.GetTxConfig().TxEncoder()(tx) if err != nil { - return fmt.Errorf("failed to encode cosmos tx: %w", err) + return nil, fmt.Errorf("failed to encode cosmos tx: %w", err) } - _, err = s.network.App.CheckTx(&abci.RequestCheckTx{ + res, err := s.network.App.CheckTx(&abci.RequestCheckTx{ Tx: txBytes, Type: abci.CheckTxType_New, }) if err != nil { - return fmt.Errorf("failed to encode cosmos tx: %w", err) + return nil, fmt.Errorf("failed to execute CheckTx: %w", err) } - return nil + return res, nil +} + +func (s *IntegrationTestSuite) getTxBytes(txs []sdk.Tx) ([][]byte, error) { + txEncoder := s.network.App.GetTxConfig().TxEncoder() + txBytes := make([][]byte, 0) + for _, tx := range txs { + bz, err := txEncoder(tx) + if err != nil { + return nil, fmt.Errorf("failed to encode tx: %w", err) + } + txBytes = append(txBytes, bz) + } + return txBytes, nil } // getTxHashes returns transaction hashes for multiple transactions @@ -150,3 +194,28 @@ func (s *IntegrationTestSuite) calculateCosmosEffectiveTip(feeAmount int64, gasL return new(big.Int).Sub(gasPrice, baseFee) } + +// notifyNewBlockToMempool triggers the natural block notification mechanism used in production. +// This sends a ChainHeadEvent that causes the mempool to update its state and remove committed transactions. +// The event subscription mechanism naturally calls Reset() which triggers the transaction cleanup process. +func (s *IntegrationTestSuite) notifyNewBlockToMempool() { + // Get the EVM mempool from the app + evmMempool := s.network.App.GetMempool() + + // Access the underlying blockchain interface from the EVM mempool + if evmMempoolCast, ok := evmMempool.(*evmmempool.ExperimentalEVMMempool); ok { + blockchain := evmMempoolCast.GetBlockchain() + + // Trigger a new block notification + // This sends a ChainHeadEvent that the mempool subscribes to. + // The TxPool's event loop receives this and calls Reset() for each subpool, + // which naturally removes committed transactions via demoteUnexecutables(). + blockchain.NotifyNewBlock() + + // The ChainHeadEvent is processed asynchronously, so we need to wait a bit + // for the event to be processed and the reset to complete. + // In integration tests, this might need a small delay to ensure the event + // is processed before we check the mempool state. + time.Sleep(100 * time.Millisecond) + } +} diff --git a/tests/integration/mempool/test_mempool_integration_abci.go b/tests/integration/mempool/test_mempool_integration_abci.go index b4aa655f00..cd0648468f 100644 --- a/tests/integration/mempool/test_mempool_integration_abci.go +++ b/tests/integration/mempool/test_mempool_integration_abci.go @@ -4,6 +4,8 @@ import ( "encoding/hex" "math/big" + "github.com/ethereum/go-ethereum/core" + abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/tmhash" @@ -16,10 +18,6 @@ func (s *IntegrationTestSuite) TestTransactionOrderingWithABCIMethodCalls() { testCases := []struct { name string setupTxs func() ([]sdk.Tx, []string) - // TODO: remove bypass option after anteHandler is fixed. - // Current anteHandler rejects valid high-gas transaction to replace low-gas transaction - // So, all replacement test cases fail. - bypass bool }{ { name: "mixed EVM and cosmos transaction ordering", @@ -49,7 +47,7 @@ func (s *IntegrationTestSuite) TestTransactionOrderingWithABCIMethodCalls() { lowFeeEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(2000000000)) // 2 gaatom // Create second EVM transaction with high fee - highFeeEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // 5 gaatom + highFeeEVMTx := s.createEVMValueTransferDynamicFeeTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000), big.NewInt(5000000000)) // 5 gaatom // Input txs in order inputTxs := []sdk.Tx{lowFeeEVMTx, highFeeEVMTx} @@ -60,7 +58,6 @@ func (s *IntegrationTestSuite) TestTransactionOrderingWithABCIMethodCalls() { return inputTxs, expTxHashes }, - bypass: true, }, { name: "EVM-only transaction ordering", @@ -82,64 +79,44 @@ func (s *IntegrationTestSuite) TestTransactionOrderingWithABCIMethodCalls() { return inputTxs, expTxHashes }, }, - { - name: "cosmos-only transaction replacement", - setupTxs: func() ([]sdk.Tx, []string) { - highFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5 gaatom - lowFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000000000)) // 2 gaatom - mediumFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(3000000000)) // 3 gaatom - - // Input txs in order - inputTxs := []sdk.Tx{mediumFeeTx, lowFeeTx, highFeeTx} - - // Expected txs in order - expectedTxs := []sdk.Tx{highFeeTx} - expTxHashes := s.getTxHashes(expectedTxs) - - return inputTxs, expTxHashes - }, - bypass: true, - }, { name: "mixed EVM and Cosmos transactions with equal effective tips", setupTxs: func() ([]sdk.Tx, []string) { - // Create transactions with equal effective tips (assuming base fee = 0) - // EVM: 1000 aatom/gas effective tip - evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) // 1 gaatom/gas - // Cosmos with same effective tip: 1000 * 200000 = 200000000 aatom total fee cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000000000)) // 1 gaatom/gas effective tip + // Create transactions with equal effective tips (assuming base fee = 0) + // EVM: 1000 aatom/gas effective tip + evmTx := s.createEVMValueTransferDynamicFeeTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000), big.NewInt(1000000000)) // 1 gaatom/gas + // Input txs in order inputTxs := []sdk.Tx{cosmosTx, evmTx} // Expected txs in order - expectedTxs := []sdk.Tx{evmTx, cosmosTx} + expectedTxs := []sdk.Tx{evmTx} expTxHashes := s.getTxHashes(expectedTxs) return inputTxs, expTxHashes }, - bypass: true, }, { name: "mixed transactions with EVM having higher effective tip", setupTxs: func() ([]sdk.Tx, []string) { - // Create EVM transaction with higher gas price - evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // 5 gaatom/gas - // Create Cosmos transaction with lower gas price cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000000000)) // 2 gaatom/gas + // Create EVM transaction with higher gas price + evmTx := s.createEVMValueTransferDynamicFeeTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000), big.NewInt(5000000000)) // 5 gaatom/gas + // Input txs in order inputTxs := []sdk.Tx{cosmosTx, evmTx} // Expected txs in order - expectedTxs := []sdk.Tx{evmTx, cosmosTx} + expectedTxs := []sdk.Tx{evmTx} expTxHashes := s.getTxHashes(expectedTxs) return inputTxs, expTxHashes }, - bypass: true, }, { name: "mixed transactions with Cosmos having higher effective tip", @@ -154,12 +131,11 @@ func (s *IntegrationTestSuite) TestTransactionOrderingWithABCIMethodCalls() { inputTxs := []sdk.Tx{evmTx, cosmosTx} // Expected txs in order - expectedTxs := []sdk.Tx{cosmosTx, evmTx} + expectedTxs := []sdk.Tx{evmTx} expTxHashes := s.getTxHashes(expectedTxs) return inputTxs, expTxHashes }, - bypass: true, }, { name: "mixed transaction ordering with multiple effective tips", @@ -210,10 +186,6 @@ func (s *IntegrationTestSuite) TestTransactionOrderingWithABCIMethodCalls() { }) s.Require().NoError(err) - if tc.bypass { - return - } - // Check whether expected transactions are included and returned as pending state in mempool mpool := s.network.App.GetMempool() iterator := mpool.Select(s.network.GetContext(), nil) @@ -242,7 +214,6 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactionsWithABCIMethodCalls name string setupTxs func() ([]sdk.Tx, []string) // Returns transactions and their expected nonces verifyFunc func(mpool mempool.Mempool) - bypass bool }{ { name: "insert transactions with nonce gaps", @@ -396,7 +367,6 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactionsWithABCIMethodCalls count := mpool.CountTx() s.Require().Equal(2, count, "After replacement, both transactions should be pending") }, - bypass: true, }, } @@ -424,10 +394,6 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactionsWithABCIMethodCalls mpool := s.network.App.GetMempool() iterator := mpool.Select(s.network.GetContext(), nil) - if tc.bypass { - return - } - // Check whether expected transactions are included and returned as pending state in mempool for _, txHash := range expTxHashes { actualTxHash := s.getTxHash(iterator.Tx()) @@ -447,3 +413,94 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactionsWithABCIMethodCalls }) } } + +// TestCheckTxHandlerForCommittedAndLowerNonceTxs tests that: +// 1. Committed transactions are not in the mempool after block finalization +// 2. New transactions with nonces lower than current nonce fail at mempool level +func (s *IntegrationTestSuite) TestCheckTxHandlerForCommittedAndLowerNonceTxs() { + testCases := []struct { + name string + setupTxs func() []sdk.Tx + verifyFunc func() + }{ + { + name: "EVM transactions: committed txs removed from mempool and lower nonce txs fail", + setupTxs: func() []sdk.Tx { + key := s.keyring.GetKey(0) + + // Create transactions with sequential nonces (0, 1, 2) + tx0 := s.createEVMValueTransferTx(key, 0, big.NewInt(2000000000)) + tx1 := s.createEVMValueTransferTx(key, 1, big.NewInt(2000000000)) + tx2 := s.createEVMValueTransferTx(key, 2, big.NewInt(2000000000)) + + return []sdk.Tx{tx0, tx1, tx2} + }, + verifyFunc: func() { + // 1. Verify the correct nonce transaction is in mempool + mpool := s.network.App.GetMempool() + s.Require().Equal(0, mpool.CountTx(), "Only the correct nonce transaction should be in mempool") + + // 2. Check current sequence + acc := s.network.App.GetAccountKeeper().GetAccount(s.network.GetContext(), s.keyring.GetAccAddr(0)) + sequence := acc.GetSequence() + s.Require().Equal(uint64(3), sequence) + + // 3. Check new transactions with nonces lower than current nonce fails + // Current nonce should be 3 after committing nonces 1, 2 + // + // NOTE: The reason we don't try tx with nonce 0 is + // because txFactory replace nonce 0 with curreent nonce. + // So we just test for nonce 1 and 2. + key := s.keyring.GetKey(0) + + // Try to add transaction with nonce 1 (lower than current nonce 3) - should fail + dupTx1 := s.createEVMValueTransferTx(key, 1, big.NewInt(2000000000)) + res, err := s.checkTx(dupTx1) + s.Require().NoError(err, "Transaction with nonce 1 should fail when current nonce is 3") + s.Require().Contains(res.GetLog(), core.ErrNonceTooLow.Error()) + s.Require().Equal(0, mpool.CountTx(), "Only the correct nonce transaction should be in mempool") + + // Try to add transaction with nonce 2 (lower than current nonce 3) - should fail + dupTx2 := s.createEVMValueTransferTx(key, 2, big.NewInt(2000000000)) + res, err = s.checkTx(dupTx2) + s.Require().NoError(err, "Transaction with nonce 2 should fail when current nonce is 3") + s.Require().Contains(res.GetLog(), core.ErrNonceTooLow.Error()) + s.Require().Equal(0, mpool.CountTx(), "Only the correct nonce transaction should be in mempool") + + // Verify transaction with correct nonce (3) still works + tx3 := s.createEVMValueTransferTx(key, 3, big.NewInt(2000000000)) + res, err = s.checkTx(tx3) + s.Require().NoError(err, "Transaction with correct nonce 3 should succeed") + s.Require().Equal(abci.CodeTypeOK, res.Code) + s.Require().Equal(1, mpool.CountTx(), "Only the correct nonce transaction should be in mempool") + }, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + // Reset test setup to ensure clean state + s.SetupTest() + + txs := tc.setupTxs() + + // Call CheckTx for transactions + err := s.checkTxs(txs) + s.Require().NoError(err) + + // Finalize block with txs and Commit state + txBytes, err := s.getTxBytes(txs) + s.Require().NoError(err) + + _, err = s.network.NextBlockWithTxs(txBytes...) + s.Require().NoError(err) + + // Manually trigger chain head event to notify mempool about the new block + // This simulates the natural block notification that occurs in production + s.notifyNewBlockToMempool() + + // Run verification function + tc.verifyFunc() + }) + } +} From 8147291930071a0a02f5d8b91c6f7b351582a47b Mon Sep 17 00:00:00 2001 From: Vlad J Date: Wed, 17 Sep 2025 14:29:00 -0400 Subject: [PATCH 54/61] perf: cache precompile abis (#631) * cache erc20 precompile abis instead * fix tests * lints --- precompiles/erc20/erc20.go | 14 +++++++------ precompiles/werc20/werc20.go | 11 ++++------ .../precompiles/erc20/test_setup.go | 5 ++++- .../precompiles/erc20/test_utils.go | 14 +++++++++++++ .../precompiles/werc20/test_events.go | 8 ++++++++ .../precompiles/werc20/test_integration.go | 8 ++++++++ x/erc20/keeper/keeper.go | 20 +++++++++++++++++++ x/erc20/keeper/precompiles.go | 4 ++-- 8 files changed, 68 insertions(+), 16 deletions(-) diff --git a/precompiles/erc20/erc20.go b/precompiles/erc20/erc20.go index 99c77fc260..7a1575f5fc 100644 --- a/precompiles/erc20/erc20.go +++ b/precompiles/erc20/erc20.go @@ -56,6 +56,12 @@ type Precompile struct { BankKeeper cmn.BankKeeper } +// LoadABI loads the IERC20Metadata ABI from the embedded abi.json file +// for the erc20 precompile. +func LoadABI() (abi.ABI, error) { + return cmn.LoadABI(f, abiPath) +} + // NewPrecompile creates a new ERC-20 Precompile instance as a // PrecompiledContract interface. func NewPrecompile( @@ -63,15 +69,11 @@ func NewPrecompile( bankKeeper cmn.BankKeeper, erc20Keeper Erc20Keeper, transferKeeper ibcutils.TransferKeeper, + erc20ABI abi.ABI, ) (*Precompile, error) { - newABI, err := cmn.LoadABI(f, abiPath) - if err != nil { - return nil, err - } - p := &Precompile{ Precompile: cmn.Precompile{ - ABI: newABI, + ABI: erc20ABI, KvGasConfig: storetypes.GasConfig{}, TransientKVGasConfig: storetypes.GasConfig{}, }, diff --git a/precompiles/werc20/werc20.go b/precompiles/werc20/werc20.go index 44bb190759..514eb717b0 100644 --- a/precompiles/werc20/werc20.go +++ b/precompiles/werc20/werc20.go @@ -52,19 +52,16 @@ func NewPrecompile( bankKeeper cmn.BankKeeper, erc20Keeper Erc20Keeper, transferKeeper ibcutils.TransferKeeper, + erc20ABI abi.ABI, + werc20ABI abi.ABI, ) (*Precompile, error) { - newABI, err := LoadABI() - if err != nil { - return nil, fmt.Errorf("error loading the ABI: %w", err) - } - - erc20Precompile, err := erc20.NewPrecompile(tokenPair, bankKeeper, erc20Keeper, transferKeeper) + erc20Precompile, err := erc20.NewPrecompile(tokenPair, bankKeeper, erc20Keeper, transferKeeper, erc20ABI) if err != nil { return nil, fmt.Errorf("error instantiating the ERC20 precompile: %w", err) } // use the IWERC20 ABI - erc20Precompile.ABI = newABI + erc20Precompile.ABI = werc20ABI return &Precompile{ Precompile: erc20Precompile, diff --git a/tests/integration/precompiles/erc20/test_setup.go b/tests/integration/precompiles/erc20/test_setup.go index fd07dbc496..d6d2fad438 100644 --- a/tests/integration/precompiles/erc20/test_setup.go +++ b/tests/integration/precompiles/erc20/test_setup.go @@ -68,10 +68,13 @@ func (s *PrecompileTestSuite) SetupTest() { s.precompile, err = s.setupERC20Precompile(s.tokenDenom) s.Require().NoError(err) + erc20ABI, err := erc20.LoadABI() + s.Require().NoError(err) + // Instantiate the precompile2 with the bond denom (the token pair was already set up in genesis). tokenPairID := s.network.App.GetErc20Keeper().GetDenomMap(s.network.GetContext(), bondDenom) tokenPair, found := s.network.App.GetErc20Keeper().GetTokenPair(s.network.GetContext(), tokenPairID) s.Require().True(found) - s.precompile2, err = erc20.NewPrecompile(tokenPair, s.network.App.GetBankKeeper(), s.network.App.GetErc20Keeper(), s.network.App.GetTransferKeeper()) + s.precompile2, err = erc20.NewPrecompile(tokenPair, s.network.App.GetBankKeeper(), s.network.App.GetErc20Keeper(), s.network.App.GetTransferKeeper(), erc20ABI) s.Require().NoError(err) } diff --git a/tests/integration/precompiles/erc20/test_utils.go b/tests/integration/precompiles/erc20/test_utils.go index 06d6b3884d..31e75c6b3b 100644 --- a/tests/integration/precompiles/erc20/test_utils.go +++ b/tests/integration/precompiles/erc20/test_utils.go @@ -171,11 +171,15 @@ func (is *IntegrationTestSuite) setupERC20Precompile(denom string, tokenPairs [] tokenPair = tp } + erc20ABI, err := erc20.LoadABI() + Expect(err).To(BeNil()) + precompile, err := erc20.NewPrecompile( tokenPair, is.network.App.GetBankKeeper(), is.network.App.GetErc20Keeper(), is.network.App.GetTransferKeeper(), + erc20ABI, ) Expect(err).ToNot(HaveOccurred(), "failed to set up %q erc20 precompile", tokenPair.Denom) @@ -188,11 +192,16 @@ func (is *IntegrationTestSuite) setupERC20Precompile(denom string, tokenPairs [] func setupERC20PrecompileForTokenPair( unitNetwork network.UnitTestNetwork, tokenPair erc20types.TokenPair, ) (*erc20.Precompile, error) { + erc20ABI, err := erc20.LoadABI() + if err != nil { + return nil, err + } precompile, err := erc20.NewPrecompile( tokenPair, unitNetwork.App.GetBankKeeper(), unitNetwork.App.GetErc20Keeper(), unitNetwork.App.GetTransferKeeper(), + erc20ABI, ) if err != nil { return nil, errorsmod.Wrapf(err, "failed to create %q erc20 precompile", tokenPair.Denom) @@ -215,11 +224,16 @@ func setupERC20PrecompileForTokenPair( func (is *IntegrationTestSuite) setupNewERC20PrecompileForTokenPair( tokenPair erc20types.TokenPair, ) (*erc20.Precompile, error) { + erc20ABI, err := erc20.LoadABI() + if err != nil { + return nil, err + } precompile, err := erc20.NewPrecompile( tokenPair, is.network.App.GetBankKeeper(), is.network.App.GetErc20Keeper(), is.network.App.GetTransferKeeper(), + erc20ABI, ) if err != nil { return nil, errorsmod.Wrapf(err, "failed to create %q erc20 precompile", tokenPair.Denom) diff --git a/tests/integration/precompiles/werc20/test_events.go b/tests/integration/precompiles/werc20/test_events.go index e4734754d1..8d1a3be45f 100644 --- a/tests/integration/precompiles/werc20/test_events.go +++ b/tests/integration/precompiles/werc20/test_events.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/suite" cmn "github.com/cosmos/evm/precompiles/common" + "github.com/cosmos/evm/precompiles/erc20" "github.com/cosmos/evm/precompiles/werc20" testconstants "github.com/cosmos/evm/testutil/constants" "github.com/cosmos/evm/testutil/integration/evm/factory" @@ -72,11 +73,18 @@ func (s *PrecompileUnitTestSuite) SetupTest(chainID testconstants.ChainID) { s.Require().True(found, "expected wevmos precompile to be registered in the tokens map") s.Require().Equal(s.precompileAddrHex, tokenPair.Erc20Address, "expected a different address of the contract") + erc20ABI, err := erc20.LoadABI() + s.Require().NoError(err) + werc20ABI, err := werc20.LoadABI() + s.Require().NoError(err) + precompile, err := werc20.NewPrecompile( tokenPair, s.network.App.GetBankKeeper(), s.network.App.GetErc20Keeper(), s.network.App.GetTransferKeeper(), + erc20ABI, + werc20ABI, ) s.Require().NoError(err, "failed to instantiate the werc20 precompile") s.Require().NotNil(precompile) diff --git a/tests/integration/precompiles/werc20/test_integration.go b/tests/integration/precompiles/werc20/test_integration.go index 686bdb65f9..3185954d76 100644 --- a/tests/integration/precompiles/werc20/test_integration.go +++ b/tests/integration/precompiles/werc20/test_integration.go @@ -160,11 +160,19 @@ func TestPrecompileIntegrationTestSuite(t *testing.T, create network.CreateEvmAp evmtypes.GetEVMCoinDenom(), erc20types.OWNER_MODULE, ) + + erc20ABI, err := erc20.LoadABI() + Expect(err).To(BeNil()) + werc20ABI, err := werc20.LoadABI() + Expect(err).To(BeNil()) + precompile, err := werc20.NewPrecompile( tokenPair, is.network.App.GetBankKeeper(), is.network.App.GetErc20Keeper(), is.network.App.GetTransferKeeper(), + erc20ABI, + werc20ABI, ) Expect(err).ToNot(HaveOccurred(), "failed to instantiate the werc20 precompile") is.precompile = precompile diff --git a/x/erc20/keeper/keeper.go b/x/erc20/keeper/keeper.go index 1123b25d4c..ce800a6453 100644 --- a/x/erc20/keeper/keeper.go +++ b/x/erc20/keeper/keeper.go @@ -3,6 +3,10 @@ package keeper import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi" + + "github.com/cosmos/evm/precompiles/erc20" + "github.com/cosmos/evm/precompiles/werc20" "github.com/cosmos/evm/x/erc20/types" transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" @@ -25,6 +29,10 @@ type Keeper struct { evmKeeper types.EVMKeeper stakingKeeper types.StakingKeeper transferKeeper *transferkeeper.Keeper + + // cached abis + erc20ABI abi.ABI + werc20ABI abi.ABI } // NewKeeper creates new instances of the erc20 Keeper @@ -43,6 +51,16 @@ func NewKeeper( panic(err) } + erc20ABI, err := erc20.LoadABI() + if err != nil { + panic(err) + } + + werc20ABI, err := werc20.LoadABI() + if err != nil { + panic(err) + } + return Keeper{ authority: authority, storeKey: storeKey, @@ -52,6 +70,8 @@ func NewKeeper( evmKeeper: evmKeeper, stakingKeeper: sk, transferKeeper: transferKeeper, + erc20ABI: erc20ABI, + werc20ABI: werc20ABI, } } diff --git a/x/erc20/keeper/precompiles.go b/x/erc20/keeper/precompiles.go index 6c0312813c..9daa52414d 100644 --- a/x/erc20/keeper/precompiles.go +++ b/x/erc20/keeper/precompiles.go @@ -62,10 +62,10 @@ func (k Keeper) InstantiateERC20Precompile(ctx sdk.Context, contractAddr common. } if hasWrappedMethods { - return werc20.NewPrecompile(pair, k.bankKeeper, k, *k.transferKeeper) + return werc20.NewPrecompile(pair, k.bankKeeper, k, *k.transferKeeper, k.erc20ABI, k.werc20ABI) } - return erc20.NewPrecompile(pair, k.bankKeeper, k, *k.transferKeeper) + return erc20.NewPrecompile(pair, k.bankKeeper, k, *k.transferKeeper, k.erc20ABI) } // RegisterCodeHash checks if a new precompile already exists and registers the code hash it is not From 28bc48bcd892100e9584510a8bd3b73e448f0e54 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Thu, 18 Sep 2025 02:51:01 +0800 Subject: [PATCH 55/61] feat: fill block hash and timestamp in tx response (#584) * feat: fill block and tx informations in json-rpc follow up for https://github.com/cosmos/evm/pull/576#discussion_r2312428649 add doc * fill ts --------- Co-authored-by: Alex | Interchain Labs Co-authored-by: Vlad J --- CHANGELOG.md | 3 +- api/cosmos/evm/vm/v1/tx.pulsar.go | 273 +++++++++++++++++++------ proto/cosmos/evm/vm/v1/tx.proto | 4 + tests/integration/x/vm/test_statedb.go | 2 - x/vm/keeper/state_transition.go | 16 +- x/vm/statedb/statedb.go | 12 -- x/vm/statedb/statedb_test.go | 20 +- x/vm/types/tx.pb.go | 168 +++++++++++---- x/vm/types/utils.go | 6 + 9 files changed, 356 insertions(+), 148 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3ed2eff90..3f97c8a21f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,8 @@ - [\#512](https://github.com/cosmos/evm/pull/512) Add integration test for appside mempool. - [\#568](https://github.com/cosmos/evm/pull/568) Avoid unnecessary block notifications when the event bus is already set up. - [\#511](https://github.com/cosmos/evm/pull/511) Minor code cleanup for `AddPrecompileFn`. -- [\#544](https://github.com/cosmos/evm/pull/544) Parse logs from the txResult.Data and avoid emitting EVM events to cosmos-sdk events. +- [\#576](https://github.com/cosmos/evm/pull/576) Parse logs from the txResult.Data and avoid emitting EVM events to cosmos-sdk events. +- [\#584](https://github.com/cosmos/evm/pull/584) Fill block hash and timestamp for json rpc. - [\#582](https://github.com/cosmos/evm/pull/582) Add block max-gas (from genesis.json) and new min-tip (from app.toml/flags) ingestion into mempool config - [\#598](https://github.com/cosmos/evm/pull/598) Reduce number of times CreateQueryContext in mempool. - [\#606](https://github.com/cosmos/evm/pull/606) Regenerate mock file for bank keeper related test. diff --git a/api/cosmos/evm/vm/v1/tx.pulsar.go b/api/cosmos/evm/vm/v1/tx.pulsar.go index 01c31e38db..f39f7451e6 100644 --- a/api/cosmos/evm/vm/v1/tx.pulsar.go +++ b/api/cosmos/evm/vm/v1/tx.pulsar.go @@ -913,13 +913,15 @@ func (x *_MsgEthereumTxResponse_2_list) IsValid() bool { } var ( - md_MsgEthereumTxResponse protoreflect.MessageDescriptor - fd_MsgEthereumTxResponse_hash protoreflect.FieldDescriptor - fd_MsgEthereumTxResponse_logs protoreflect.FieldDescriptor - fd_MsgEthereumTxResponse_ret protoreflect.FieldDescriptor - fd_MsgEthereumTxResponse_vm_error protoreflect.FieldDescriptor - fd_MsgEthereumTxResponse_gas_used protoreflect.FieldDescriptor - fd_MsgEthereumTxResponse_max_used_gas protoreflect.FieldDescriptor + md_MsgEthereumTxResponse protoreflect.MessageDescriptor + fd_MsgEthereumTxResponse_hash protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_logs protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_ret protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_vm_error protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_gas_used protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_max_used_gas protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_block_hash protoreflect.FieldDescriptor + fd_MsgEthereumTxResponse_block_timestamp protoreflect.FieldDescriptor ) func init() { @@ -931,6 +933,8 @@ func init() { fd_MsgEthereumTxResponse_vm_error = md_MsgEthereumTxResponse.Fields().ByName("vm_error") fd_MsgEthereumTxResponse_gas_used = md_MsgEthereumTxResponse.Fields().ByName("gas_used") fd_MsgEthereumTxResponse_max_used_gas = md_MsgEthereumTxResponse.Fields().ByName("max_used_gas") + fd_MsgEthereumTxResponse_block_hash = md_MsgEthereumTxResponse.Fields().ByName("block_hash") + fd_MsgEthereumTxResponse_block_timestamp = md_MsgEthereumTxResponse.Fields().ByName("block_timestamp") } var _ protoreflect.Message = (*fastReflection_MsgEthereumTxResponse)(nil) @@ -1034,6 +1038,18 @@ func (x *fastReflection_MsgEthereumTxResponse) Range(f func(protoreflect.FieldDe return } } + if len(x.BlockHash) != 0 { + value := protoreflect.ValueOfBytes(x.BlockHash) + if !f(fd_MsgEthereumTxResponse_block_hash, value) { + return + } + } + if x.BlockTimestamp != uint64(0) { + value := protoreflect.ValueOfUint64(x.BlockTimestamp) + if !f(fd_MsgEthereumTxResponse_block_timestamp, value) { + return + } + } } // Has reports whether a field is populated. @@ -1061,6 +1077,10 @@ func (x *fastReflection_MsgEthereumTxResponse) Has(fd protoreflect.FieldDescript return x.GasUsed != uint64(0) case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": return x.MaxUsedGas != uint64(0) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_hash": + return len(x.BlockHash) != 0 + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_timestamp": + return x.BlockTimestamp != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1089,6 +1109,10 @@ func (x *fastReflection_MsgEthereumTxResponse) Clear(fd protoreflect.FieldDescri x.GasUsed = uint64(0) case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": x.MaxUsedGas = uint64(0) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_hash": + x.BlockHash = nil + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_timestamp": + x.BlockTimestamp = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1126,6 +1150,12 @@ func (x *fastReflection_MsgEthereumTxResponse) Get(descriptor protoreflect.Field case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": value := x.MaxUsedGas return protoreflect.ValueOfUint64(value) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_hash": + value := x.BlockHash + return protoreflect.ValueOfBytes(value) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_timestamp": + value := x.BlockTimestamp + return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1160,6 +1190,10 @@ func (x *fastReflection_MsgEthereumTxResponse) Set(fd protoreflect.FieldDescript x.GasUsed = value.Uint() case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": x.MaxUsedGas = value.Uint() + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_hash": + x.BlockHash = value.Bytes() + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_timestamp": + x.BlockTimestamp = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1196,6 +1230,10 @@ func (x *fastReflection_MsgEthereumTxResponse) Mutable(fd protoreflect.FieldDesc panic(fmt.Errorf("field gas_used of message cosmos.evm.vm.v1.MsgEthereumTxResponse is not mutable")) case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": panic(fmt.Errorf("field max_used_gas of message cosmos.evm.vm.v1.MsgEthereumTxResponse is not mutable")) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_hash": + panic(fmt.Errorf("field block_hash of message cosmos.evm.vm.v1.MsgEthereumTxResponse is not mutable")) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_timestamp": + panic(fmt.Errorf("field block_timestamp of message cosmos.evm.vm.v1.MsgEthereumTxResponse is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1222,6 +1260,10 @@ func (x *fastReflection_MsgEthereumTxResponse) NewField(fd protoreflect.FieldDes return protoreflect.ValueOfUint64(uint64(0)) case "cosmos.evm.vm.v1.MsgEthereumTxResponse.max_used_gas": return protoreflect.ValueOfUint64(uint64(0)) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_hash": + return protoreflect.ValueOfBytes(nil) + case "cosmos.evm.vm.v1.MsgEthereumTxResponse.block_timestamp": + return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.vm.v1.MsgEthereumTxResponse")) @@ -1315,6 +1357,13 @@ func (x *fastReflection_MsgEthereumTxResponse) ProtoMethods() *protoiface.Method if x.MaxUsedGas != 0 { n += 1 + runtime.Sov(uint64(x.MaxUsedGas)) } + l = len(x.BlockHash) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.BlockTimestamp != 0 { + n += 1 + runtime.Sov(uint64(x.BlockTimestamp)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -1344,6 +1393,18 @@ func (x *fastReflection_MsgEthereumTxResponse) ProtoMethods() *protoiface.Method i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.BlockTimestamp != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.BlockTimestamp)) + i-- + dAtA[i] = 0x40 + } + if len(x.BlockHash) > 0 { + i -= len(x.BlockHash) + copy(dAtA[i:], x.BlockHash) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.BlockHash))) + i-- + dAtA[i] = 0x3a + } if x.MaxUsedGas != 0 { i = runtime.EncodeVarint(dAtA, i, uint64(x.MaxUsedGas)) i-- @@ -1610,6 +1671,59 @@ func (x *fastReflection_MsgEthereumTxResponse) ProtoMethods() *protoiface.Method break } } + case 7: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field BlockHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.BlockHash = append(x.BlockHash[:0], dAtA[iNdEx:postIndex]...) + if x.BlockHash == nil { + x.BlockHash = []byte{} + } + iNdEx = postIndex + case 8: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field BlockTimestamp", wireType) + } + x.BlockTimestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.BlockTimestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -3524,6 +3638,10 @@ type MsgEthereumTxResponse struct { GasUsed uint64 `protobuf:"varint,5,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` // max_used_gas specifies the gas consumed by the transaction, not including refunds MaxUsedGas uint64 `protobuf:"varint,6,opt,name=max_used_gas,json=maxUsedGas,proto3" json:"max_used_gas,omitempty"` + // include the block hash for json-rpc to use + BlockHash []byte `protobuf:"bytes,7,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"` + // include the block timestamp for json-rpc to use + BlockTimestamp uint64 `protobuf:"varint,8,opt,name=block_timestamp,json=blockTimestamp,proto3" json:"block_timestamp,omitempty"` } func (x *MsgEthereumTxResponse) Reset() { @@ -3588,6 +3706,20 @@ func (x *MsgEthereumTxResponse) GetMaxUsedGas() uint64 { return 0 } +func (x *MsgEthereumTxResponse) GetBlockHash() []byte { + if x != nil { + return x.BlockHash + } + return nil +} + +func (x *MsgEthereumTxResponse) GetBlockTimestamp() uint64 { + if x != nil { + return x.BlockTimestamp + } + return 0 +} + // MsgUpdateParams defines a Msg for updating the x/vm module parameters. type MsgUpdateParams struct { state protoimpl.MessageState @@ -3763,7 +3895,7 @@ var file_cosmos_evm_vm_v1_tx_proto_rawDesc = []byte{ 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x22, 0x0a, 0x1a, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, - 0xc6, 0x01, 0x0a, 0x15, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, + 0x8e, 0x02, 0x0a, 0x15, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, @@ -3775,69 +3907,74 @@ var file_cosmos_evm_vm_v1_tx_proto_rawDesc = []byte{ 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x55, 0x73, 0x65, 0x64, 0x47, - 0x61, 0x73, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, 0x22, 0xba, 0x01, 0x0a, 0x0f, 0x4d, 0x73, 0x67, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x36, 0x0a, 0x09, - 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, - 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x09, - 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x3a, 0x32, 0x82, 0xe7, 0xb0, 0x2a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, - 0x79, 0x8a, 0xe7, 0xb0, 0x2a, 0x1f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, - 0x2f, 0x78, 0x2f, 0x76, 0x6d, 0x2f, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0xd6, 0x01, 0x0a, 0x16, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, - 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x12, 0x36, 0x0a, 0x09, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, - 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x12, 0x49, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x42, 0x09, 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, - 0x01, 0x52, 0x0b, 0x70, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x3a, 0x39, - 0x82, 0xe7, 0xb0, 0x2a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x8a, 0xe7, - 0xb0, 0x2a, 0x26, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x78, 0x2f, - 0x76, 0x6d, 0x2f, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, - 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x22, 0x20, 0x0a, 0x1e, 0x4d, 0x73, 0x67, + 0x61, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3a, 0x04, 0x88, 0xa0, 0x1f, 0x00, + 0x22, 0xba, 0x01, 0x0a, 0x0f, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x12, 0x36, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x06, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x09, 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, + 0x01, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x32, 0x82, 0xe7, 0xb0, 0x2a, 0x09, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x8a, 0xe7, 0xb0, 0x2a, 0x1f, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x78, 0x2f, 0x76, 0x6d, 0x2f, 0x4d, 0x73, + 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x19, 0x0a, + 0x17, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xd6, 0x01, 0x0a, 0x16, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xdc, 0x02, 0x0a, 0x03, - 0x4d, 0x73, 0x67, 0x12, 0x7d, 0x0a, 0x0a, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, - 0x78, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, - 0x54, 0x78, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, - 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, - 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1f, 0x22, 0x1d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, - 0x2f, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5f, - 0x74, 0x78, 0x12, 0x5c, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, - 0x6d, 0x73, 0x12, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, - 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x29, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, - 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x71, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x12, 0x28, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, + 0x6c, 0x6c, 0x73, 0x12, 0x36, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x49, 0x0a, 0x0b, 0x70, + 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x42, 0x09, + 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x0b, 0x70, 0x72, 0x65, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x3a, 0x39, 0x82, 0xe7, 0xb0, 0x2a, 0x09, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x8a, 0xe7, 0xb0, 0x2a, 0x26, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x78, 0x2f, 0x76, 0x6d, 0x2f, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, - 0x73, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, - 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x73, 0x22, 0x20, 0x0a, 0x1e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x1a, 0x05, 0x80, 0xe7, 0xb0, 0x2a, 0x01, 0x42, 0xaa, 0x01, 0x0a, 0x14, 0x63, - 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, - 0x2e, 0x76, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, - 0x31, 0x3b, 0x76, 0x6d, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x56, 0xaa, 0x02, 0x10, 0x43, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x56, 0x6d, 0x2e, 0x56, 0x31, 0xca, - 0x02, 0x10, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, - 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, - 0x56, 0x6d, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, - 0x3a, 0x56, 0x6d, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x73, 0x65, 0x32, 0xdc, 0x02, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x7d, 0x0a, 0x0a, 0x45, + 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, + 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, + 0x67, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1d, 0x2f, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x65, + 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5f, 0x74, 0x78, 0x12, 0x5c, 0x0a, 0x0c, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x21, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, + 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x29, 0x2e, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x4d, 0x73, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x12, + 0x28, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, + 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x05, 0x80, 0xe7, 0xb0, + 0x2a, 0x01, 0x42, 0xaa, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x76, 0x6d, 0x2e, 0x76, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, + 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, + 0x65, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x6d, 0x76, 0x31, 0xa2, 0x02, + 0x03, 0x43, 0x45, 0x56, 0xaa, 0x02, 0x10, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, + 0x6d, 0x2e, 0x56, 0x6d, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x43, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x56, 0x6d, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, + 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x56, 0x6d, 0x3a, 0x3a, 0x56, 0x31, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/cosmos/evm/vm/v1/tx.proto b/proto/cosmos/evm/vm/v1/tx.proto index 3d953e9e0d..7ac870f9af 100644 --- a/proto/cosmos/evm/vm/v1/tx.proto +++ b/proto/cosmos/evm/vm/v1/tx.proto @@ -73,6 +73,10 @@ message MsgEthereumTxResponse { uint64 gas_used = 5; // max_used_gas specifies the gas consumed by the transaction, not including refunds uint64 max_used_gas = 6; + // include the block hash for json-rpc to use + bytes block_hash = 7; + // include the block timestamp for json-rpc to use + uint64 block_timestamp = 8; } // MsgUpdateParams defines a Msg for updating the x/vm module parameters. diff --git a/tests/integration/x/vm/test_statedb.go b/tests/integration/x/vm/test_statedb.go index b78480b906..5ac2ac8611 100644 --- a/tests/integration/x/vm/test_statedb.go +++ b/tests/integration/x/vm/test_statedb.go @@ -729,7 +729,6 @@ func (s *KeeperTestSuite) TestAddLog() { }, ðtypes.Log{ Address: addr, - TxHash: txHash, Topics: make([]common.Hash, 0), }, func(vm.StateDB) {}, @@ -743,7 +742,6 @@ func (s *KeeperTestSuite) TestAddLog() { }, ðtypes.Log{ Address: addr, - TxHash: txHash3, Topics: make([]common.Hash, 0), }, func(vm.StateDB) {}, diff --git a/x/vm/keeper/state_transition.go b/x/vm/keeper/state_transition.go index 2188b13f4e..fafa49463d 100644 --- a/x/vm/keeper/state_transition.go +++ b/x/vm/keeper/state_transition.go @@ -506,15 +506,15 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, msg core.Message, trace if vmError == vm.ErrExecutionReverted.Error() { ret = evm.Interpreter().ReturnData() } - - logs := stateDB.GetLogs(uint64(ctx.BlockHeight()), common.BytesToHash(ctx.HeaderHash()), evm.Context.Time) //#nosec G115 -- int overflow is not a concern here return &types.MsgEthereumTxResponse{ - GasUsed: gasUsed.TruncateInt().Uint64(), - MaxUsedGas: maxUsedGas, - VmError: vmError, - Ret: ret, - Logs: types.NewLogsFromEth(logs), - Hash: txConfig.TxHash.Hex(), + GasUsed: gasUsed.TruncateInt().Uint64(), + MaxUsedGas: maxUsedGas, + VmError: vmError, + Ret: ret, + Logs: types.NewLogsFromEth(stateDB.Logs()), + Hash: txConfig.TxHash.Hex(), + BlockHash: ctx.HeaderHash(), + BlockTimestamp: evm.Context.Time, }, nil } diff --git a/x/vm/statedb/statedb.go b/x/vm/statedb/statedb.go index b869632300..1c4a7395d5 100644 --- a/x/vm/statedb/statedb.go +++ b/x/vm/statedb/statedb.go @@ -218,23 +218,11 @@ func (s *StateDB) cache() error { func (s *StateDB) AddLog(log *ethtypes.Log) { s.journal.append(addLogChange{}) - log.TxHash = s.txConfig.TxHash log.TxIndex = s.txConfig.TxIndex log.Index = s.txConfig.LogIndex + uint(len(s.logs)) s.logs = append(s.logs, log) } -// GetLogs returns the logs matching the specified transaction hash, and annotates -// them with the given blockNumber and blockHash. -func (s *StateDB) GetLogs(blockNumber uint64, blockHash common.Hash, blockTime uint64) []*ethtypes.Log { - for _, l := range s.logs { - l.BlockNumber = blockNumber - l.BlockHash = blockHash - l.BlockTimestamp = blockTime - } - return s.logs -} - // Logs returns the logs of current transaction. func (s *StateDB) Logs() []*ethtypes.Log { return s.logs diff --git a/x/vm/statedb/statedb_test.go b/x/vm/statedb/statedb_test.go index 45497c2707..cb75eb25a3 100644 --- a/x/vm/statedb/statedb_test.go +++ b/x/vm/statedb/statedb_test.go @@ -24,7 +24,6 @@ var ( address common.Address = common.BigToAddress(big.NewInt(101)) address2 common.Address = common.BigToAddress(big.NewInt(102)) address3 common.Address = common.BigToAddress(big.NewInt(103)) - blockHash common.Hash = common.BigToHash(big.NewInt(9999)) emptyTxConfig statedb.TxConfig = statedb.NewEmptyTxConfig() ) @@ -600,17 +599,14 @@ func (suite *StateDBTestSuite) TestLog() { }) suite.Require().Equal(1, len(db.Logs())) expecedLog := ðtypes.Log{ - Address: address, - Topics: []common.Hash{}, - Data: data, - BlockNumber: 1, - BlockHash: blockHash, - BlockTimestamp: 1, - TxHash: txHash, - TxIndex: 1, - Index: 1, + Address: address, + Topics: []common.Hash{}, + Data: data, + BlockNumber: 1, + TxIndex: 1, + Index: 1, } - suite.Require().Equal(expecedLog, db.GetLogs(1, blockHash, 1)[0]) + suite.Require().Equal(expecedLog, db.Logs()[0]) db.AddLog(ðtypes.Log{ Address: address, @@ -620,7 +616,7 @@ func (suite *StateDBTestSuite) TestLog() { }) suite.Require().Equal(2, len(db.Logs())) expecedLog.Index++ - suite.Require().Equal(expecedLog, db.GetLogs(1, blockHash, 1)[1]) + suite.Require().Equal(expecedLog, db.Logs()[1]) } func (suite *StateDBTestSuite) TestRefund() { diff --git a/x/vm/types/tx.pb.go b/x/vm/types/tx.pb.go index dc6c108317..096775978b 100644 --- a/x/vm/types/tx.pb.go +++ b/x/vm/types/tx.pb.go @@ -130,6 +130,10 @@ type MsgEthereumTxResponse struct { GasUsed uint64 `protobuf:"varint,5,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` // max_used_gas specifies the gas consumed by the transaction, not including refunds MaxUsedGas uint64 `protobuf:"varint,6,opt,name=max_used_gas,json=maxUsedGas,proto3" json:"max_used_gas,omitempty"` + // include the block hash for json-rpc to use + BlockHash []byte `protobuf:"bytes,7,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"` + // include the block timestamp for json-rpc to use + BlockTimestamp uint64 `protobuf:"varint,8,opt,name=block_timestamp,json=blockTimestamp,proto3" json:"block_timestamp,omitempty"` } func (m *MsgEthereumTxResponse) Reset() { *m = MsgEthereumTxResponse{} } @@ -365,51 +369,53 @@ func init() { func init() { proto.RegisterFile("cosmos/evm/vm/v1/tx.proto", fileDescriptor_77a8ac5e8c9c4850) } var fileDescriptor_77a8ac5e8c9c4850 = []byte{ - // 699 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x4f, 0x6b, 0x13, 0x4f, - 0x18, 0xce, 0x26, 0xdb, 0x36, 0x9d, 0xf6, 0xc7, 0x2f, 0x8e, 0xad, 0xdd, 0x2e, 0x35, 0x49, 0x17, - 0xff, 0xa4, 0x05, 0xb3, 0x36, 0x82, 0x60, 0x3c, 0x19, 0x28, 0x62, 0x30, 0x58, 0x56, 0x7b, 0x11, - 0x21, 0x4c, 0x9b, 0x71, 0xb2, 0x90, 0xd9, 0x59, 0x67, 0x26, 0x31, 0x3d, 0x08, 0x52, 0x3c, 0x88, - 0x27, 0xc1, 0x2f, 0xe0, 0xd1, 0x63, 0x0f, 0x9e, 0xfc, 0x00, 0xd2, 0x63, 0x51, 0x10, 0x11, 0x29, - 0xd2, 0x0a, 0xfd, 0x1a, 0x32, 0xbb, 0xdb, 0x66, 0xd3, 0x2c, 0x54, 0x84, 0x65, 0x99, 0x9d, 0xe7, - 0x79, 0x9f, 0xf7, 0x7d, 0xe6, 0xd9, 0x5d, 0x30, 0xbf, 0xc9, 0x04, 0x65, 0xc2, 0xc6, 0x3d, 0x6a, - 0xab, 0x6b, 0xc5, 0x96, 0xfd, 0xb2, 0xcf, 0x99, 0x64, 0x30, 0x17, 0x42, 0x65, 0xdc, 0xa3, 0x65, - 0x75, 0xad, 0x98, 0xe7, 0x10, 0x75, 0x3d, 0x66, 0x07, 0xf7, 0x90, 0x64, 0x9a, 0x23, 0xf5, 0x8a, - 0x1e, 0x62, 0x73, 0x11, 0x46, 0x05, 0x51, 0x00, 0x15, 0x24, 0x02, 0xa2, 0xa6, 0xcd, 0xe0, 0xc9, - 0x8e, 0xda, 0x84, 0xd0, 0x0c, 0x61, 0x84, 0x85, 0xfb, 0x6a, 0x15, 0xed, 0x2e, 0x10, 0xc6, 0x48, - 0x07, 0xdb, 0xc8, 0x77, 0x6d, 0xe4, 0x79, 0x4c, 0x22, 0xe9, 0x32, 0x2f, 0xaa, 0xb1, 0x5e, 0x69, - 0xe0, 0xbf, 0x86, 0x20, 0xab, 0xb2, 0x8d, 0x39, 0xee, 0xd2, 0x47, 0x7d, 0x08, 0x81, 0xfe, 0x94, - 0x33, 0x6a, 0x8c, 0x15, 0xb5, 0xd2, 0xb4, 0x13, 0xac, 0xe1, 0x25, 0x90, 0xe1, 0xe8, 0xb9, 0x31, - 0xae, 0xb6, 0x6a, 0x70, 0x77, 0xbf, 0x90, 0xfa, 0xb1, 0x5f, 0x00, 0x83, 0x22, 0x47, 0xc1, 0xd5, - 0xc5, 0xd7, 0xef, 0x0b, 0xa9, 0x37, 0x47, 0x3b, 0xcb, 0x46, 0xcc, 0xd8, 0x90, 0x78, 0x5d, 0xcf, - 0x6a, 0xb9, 0x74, 0x5d, 0xcf, 0xa6, 0x73, 0x99, 0xba, 0x9e, 0xcd, 0xe4, 0xf4, 0xba, 0x9e, 0xd5, - 0x73, 0x63, 0x96, 0x05, 0xcc, 0xd5, 0xbe, 0xc4, 0x9e, 0x70, 0x99, 0xf7, 0xc0, 0x0f, 0x06, 0x1c, - 0x54, 0x55, 0x75, 0x25, 0x6c, 0x7d, 0xd6, 0xc0, 0xec, 0x90, 0x9a, 0x83, 0x85, 0xcf, 0x3c, 0x81, - 0xd5, 0xc8, 0x6d, 0x24, 0xda, 0x86, 0x56, 0xd4, 0x4a, 0x93, 0x4e, 0xb0, 0x86, 0x4b, 0x40, 0xef, - 0x30, 0x22, 0x8c, 0x74, 0x31, 0x53, 0x9a, 0xaa, 0xcc, 0x96, 0x4f, 0x07, 0x52, 0xbe, 0xcf, 0x88, - 0x13, 0x50, 0x60, 0x0e, 0x64, 0x38, 0x96, 0x46, 0x26, 0x30, 0xac, 0x96, 0x70, 0x1e, 0x64, 0x7b, - 0xb4, 0x89, 0x39, 0x67, 0xdc, 0xd0, 0x03, 0xd1, 0x89, 0x1e, 0x5d, 0x55, 0x8f, 0x0a, 0x22, 0x48, - 0x34, 0xbb, 0x02, 0xb7, 0x82, 0x23, 0xd2, 0x9d, 0x09, 0x82, 0xc4, 0xba, 0xc0, 0x2d, 0x58, 0x04, - 0xd3, 0x14, 0xf5, 0x03, 0xa8, 0x49, 0x90, 0x08, 0x8e, 0x4b, 0x77, 0x00, 0x45, 0x7d, 0x05, 0xdf, - 0x45, 0x22, 0x32, 0xf2, 0x49, 0x03, 0xff, 0x37, 0x04, 0x59, 0xf7, 0x5b, 0x48, 0xe2, 0x35, 0xc4, - 0x11, 0x15, 0xf0, 0x26, 0x98, 0x44, 0x5d, 0xd9, 0x66, 0xdc, 0x95, 0x5b, 0xa1, 0x8f, 0x9a, 0xf1, - 0xe5, 0xe3, 0xb5, 0x99, 0x68, 0xec, 0x3b, 0xad, 0x16, 0xc7, 0x42, 0x3c, 0x94, 0xdc, 0xf5, 0x88, - 0x33, 0xa0, 0xc2, 0xdb, 0x60, 0xdc, 0x0f, 0x14, 0x8c, 0x74, 0x51, 0x2b, 0x4d, 0x55, 0x8c, 0x51, - 0xa3, 0x61, 0x87, 0xda, 0xa4, 0x8a, 0xed, 0xc3, 0xd1, 0xce, 0xb2, 0xe6, 0x44, 0x25, 0xd5, 0xca, - 0xf6, 0xd1, 0xce, 0xf2, 0x40, 0x4c, 0x45, 0x57, 0x88, 0x45, 0xd7, 0xb7, 0xc3, 0xfc, 0xe2, 0x83, - 0x5a, 0xf3, 0x60, 0xee, 0xd4, 0xd6, 0x71, 0x0c, 0xd6, 0x37, 0x0d, 0x5c, 0x68, 0x08, 0xe2, 0x60, - 0xe2, 0x0a, 0x89, 0xf9, 0x1a, 0xc7, 0xae, 0x27, 0x24, 0xea, 0x74, 0xfe, 0xdd, 0xde, 0x3d, 0x30, - 0xe5, 0x0f, 0x64, 0xa2, 0x30, 0x17, 0x12, 0x3c, 0x9e, 0x90, 0xe2, 0x3e, 0xe3, 0xb5, 0xd5, 0x5b, - 0xa3, 0x66, 0xaf, 0x24, 0x98, 0x4d, 0x98, 0xde, 0x2a, 0x82, 0x7c, 0x32, 0x72, 0x6c, 0xbd, 0xf2, - 0x33, 0x0d, 0x32, 0x0d, 0x41, 0xe0, 0x0b, 0x10, 0xfb, 0x2a, 0x60, 0x61, 0x74, 0xd0, 0xa1, 0x17, - 0xd8, 0xbc, 0x7a, 0x06, 0xe1, 0xe4, 0x68, 0x2f, 0x6f, 0x7f, 0xfd, 0xfd, 0x2e, 0x5d, 0xb0, 0x2e, - 0xda, 0xa3, 0xff, 0x8c, 0x88, 0xdd, 0x94, 0x7d, 0xf8, 0x04, 0x4c, 0x0f, 0xbd, 0x55, 0x8b, 0x89, - 0xfa, 0x71, 0x8a, 0xb9, 0x74, 0x26, 0xe5, 0xe4, 0x33, 0x7b, 0x06, 0xce, 0x27, 0x65, 0x5b, 0x4a, - 0x54, 0x48, 0x60, 0x9a, 0xd7, 0xff, 0x96, 0x79, 0xdc, 0xd2, 0x1c, 0x7b, 0xa9, 0x82, 0xac, 0x55, - 0x77, 0x0f, 0xf2, 0xda, 0xde, 0x41, 0x5e, 0xfb, 0x75, 0x90, 0xd7, 0xde, 0x1e, 0xe6, 0x53, 0x7b, - 0x87, 0xf9, 0xd4, 0xf7, 0xc3, 0x7c, 0xea, 0x71, 0x91, 0xb8, 0xb2, 0xdd, 0xdd, 0x28, 0x6f, 0x32, - 0x6a, 0x9f, 0x4e, 0x53, 0x6e, 0xf9, 0x58, 0x6c, 0x8c, 0x07, 0x3f, 0xba, 0x1b, 0x7f, 0x02, 0x00, - 0x00, 0xff, 0xff, 0xf9, 0x21, 0xde, 0xc0, 0xae, 0x05, 0x00, 0x00, + // 736 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x4d, 0x6b, 0x13, 0x41, + 0x18, 0xce, 0x26, 0xdb, 0x36, 0x99, 0x56, 0x1b, 0xd7, 0xd6, 0x6e, 0x97, 0x36, 0x49, 0x17, 0xb5, + 0x69, 0xc1, 0xac, 0x8d, 0x20, 0x18, 0x4f, 0x06, 0x8a, 0x1a, 0x0c, 0x96, 0xb5, 0xbd, 0x88, 0x10, + 0xa6, 0xcd, 0x38, 0x59, 0xcc, 0xec, 0xac, 0x3b, 0x93, 0x98, 0x1e, 0x04, 0x29, 0x1e, 0xc4, 0x83, + 0x08, 0xfe, 0x01, 0x8f, 0x1e, 0x7b, 0xf0, 0xe4, 0x2f, 0xe8, 0xb1, 0x28, 0x88, 0x88, 0x14, 0x69, + 0x85, 0xfe, 0x0d, 0x99, 0xd9, 0x4d, 0x93, 0x34, 0x0b, 0x15, 0x61, 0x59, 0x66, 0xdf, 0xe7, 0x79, + 0x9f, 0xf7, 0x73, 0x16, 0xcc, 0x6e, 0x51, 0x46, 0x28, 0xb3, 0x50, 0x9b, 0x58, 0xe2, 0x59, 0xb1, + 0x78, 0xa7, 0xe0, 0xf9, 0x94, 0x53, 0x2d, 0x1d, 0x40, 0x05, 0xd4, 0x26, 0x05, 0xf1, 0xac, 0x18, + 0x17, 0x20, 0x71, 0x5c, 0x6a, 0xc9, 0x77, 0x40, 0x32, 0x8c, 0x21, 0x7f, 0x41, 0x0f, 0xb0, 0x99, + 0x10, 0x23, 0x0c, 0x0b, 0x80, 0x30, 0x1c, 0x02, 0x61, 0xd0, 0x9a, 0xfc, 0xb2, 0xc2, 0x30, 0x01, + 0x34, 0x85, 0x29, 0xa6, 0x81, 0x5d, 0x9c, 0x42, 0xeb, 0x1c, 0xa6, 0x14, 0x37, 0x91, 0x05, 0x3d, + 0xc7, 0x82, 0xae, 0x4b, 0x39, 0xe4, 0x0e, 0x75, 0x43, 0x1f, 0xf3, 0xb5, 0x02, 0xce, 0x55, 0x19, + 0x5e, 0xe5, 0x0d, 0xe4, 0xa3, 0x16, 0x59, 0xef, 0x68, 0x1a, 0x50, 0x9f, 0xfa, 0x94, 0xe8, 0x23, + 0x39, 0x25, 0x3f, 0x61, 0xcb, 0xb3, 0x76, 0x19, 0x24, 0x7c, 0xf8, 0x42, 0x1f, 0x15, 0xa6, 0xb2, + 0xb6, 0x77, 0x90, 0x8d, 0xfd, 0x3c, 0xc8, 0x82, 0x9e, 0x93, 0x2d, 0xe0, 0xd2, 0xc2, 0x9b, 0x8f, + 0xd9, 0xd8, 0xdb, 0xe3, 0xdd, 0x65, 0xbd, 0xaf, 0xb0, 0x01, 0xf1, 0x8a, 0x9a, 0x54, 0xd2, 0xf1, + 0x8a, 0x9a, 0x8c, 0xa7, 0x13, 0x15, 0x35, 0x99, 0x48, 0xab, 0x15, 0x35, 0xa9, 0xa6, 0x47, 0x4c, + 0x13, 0x18, 0xab, 0x1d, 0x8e, 0x5c, 0xe6, 0x50, 0xf7, 0xa1, 0x27, 0x13, 0xec, 0x79, 0x95, 0x54, + 0x21, 0x6c, 0xbe, 0x8b, 0x83, 0xe9, 0x01, 0x35, 0x1b, 0x31, 0x8f, 0xba, 0x0c, 0x89, 0x94, 0x1b, + 0x90, 0x35, 0x74, 0x25, 0xa7, 0xe4, 0x53, 0xb6, 0x3c, 0x6b, 0x4b, 0x40, 0x6d, 0x52, 0xcc, 0xf4, + 0x78, 0x2e, 0x91, 0x1f, 0x2f, 0x4e, 0x17, 0x4e, 0x0f, 0xa4, 0xf0, 0x80, 0x62, 0x5b, 0x52, 0xb4, + 0x34, 0x48, 0xf8, 0x88, 0xeb, 0x09, 0x59, 0xb0, 0x38, 0x6a, 0xb3, 0x20, 0xd9, 0x26, 0x35, 0xe4, + 0xfb, 0xd4, 0xd7, 0x55, 0x29, 0x3a, 0xd6, 0x26, 0xab, 0xe2, 0x53, 0x40, 0x18, 0xb2, 0x5a, 0x8b, + 0xa1, 0xba, 0x6c, 0x91, 0x6a, 0x8f, 0x61, 0xc8, 0x36, 0x18, 0xaa, 0x6b, 0x39, 0x30, 0x41, 0x60, + 0x47, 0x42, 0x35, 0x0c, 0x99, 0x6c, 0x97, 0x6a, 0x03, 0x02, 0x3b, 0x02, 0xbe, 0x0b, 0x99, 0x36, + 0x0f, 0xc0, 0x66, 0x93, 0x6e, 0x3d, 0xab, 0xc9, 0x74, 0xc7, 0x64, 0xc0, 0x94, 0xb4, 0xdc, 0x13, + 0x39, 0x2f, 0x82, 0xc9, 0x00, 0xe6, 0x0e, 0x41, 0x8c, 0x43, 0xe2, 0xe9, 0x49, 0xa9, 0x71, 0x5e, + 0x9a, 0xd7, 0xbb, 0xd6, 0xb0, 0x21, 0x5f, 0x14, 0x30, 0x59, 0x65, 0x78, 0xc3, 0xab, 0x43, 0x8e, + 0xd6, 0xa0, 0x0f, 0x09, 0xd3, 0x6e, 0x82, 0x14, 0x6c, 0xf1, 0x06, 0xf5, 0x1d, 0xbe, 0x1d, 0xf4, + 0xa3, 0xac, 0x7f, 0xfd, 0x7c, 0x6d, 0x2a, 0x2c, 0xff, 0x4e, 0xbd, 0xee, 0x23, 0xc6, 0x1e, 0x71, + 0xdf, 0x71, 0xb1, 0xdd, 0xa3, 0x6a, 0xb7, 0xc1, 0xa8, 0x27, 0x15, 0xf4, 0x78, 0x4e, 0xc9, 0x8f, + 0x17, 0xf5, 0xe1, 0x86, 0x05, 0x11, 0xca, 0x29, 0x31, 0xfe, 0x4f, 0xc7, 0xbb, 0xcb, 0x8a, 0x1d, + 0xba, 0x94, 0x8a, 0x3b, 0xc7, 0xbb, 0xcb, 0x3d, 0x31, 0xb1, 0x02, 0xd9, 0xbe, 0x15, 0xe8, 0x58, + 0xc1, 0x1e, 0xf4, 0x27, 0x6a, 0xce, 0x82, 0x99, 0x53, 0xa6, 0xee, 0x38, 0xcd, 0xef, 0x0a, 0xb8, + 0x54, 0x65, 0xd8, 0x46, 0xd8, 0x61, 0x1c, 0xf9, 0x6b, 0x3e, 0x72, 0x5c, 0xc6, 0x61, 0xb3, 0xf9, + 0xff, 0xe5, 0xdd, 0x07, 0xe3, 0x5e, 0x4f, 0x26, 0x5c, 0x8a, 0xb9, 0x88, 0x1a, 0x4f, 0x48, 0xfd, + 0x75, 0xf6, 0xfb, 0x96, 0x6e, 0x0d, 0x17, 0x7b, 0x35, 0xa2, 0xd8, 0x88, 0xec, 0xcd, 0x1c, 0xc8, + 0x44, 0x23, 0xdd, 0xd2, 0x8b, 0xbf, 0xe2, 0x20, 0x51, 0x65, 0x58, 0x7b, 0x09, 0xfa, 0x6e, 0x97, + 0x96, 0x1d, 0x4e, 0x74, 0xe0, 0x22, 0x18, 0x8b, 0x67, 0x10, 0x4e, 0x5a, 0x7b, 0x65, 0xe7, 0xdb, + 0x9f, 0x0f, 0xf1, 0xac, 0x39, 0x6f, 0x0d, 0xff, 0x7b, 0x42, 0x76, 0x8d, 0x77, 0xb4, 0x27, 0x60, + 0x62, 0x60, 0xab, 0x16, 0x22, 0xf5, 0xfb, 0x29, 0xc6, 0xd2, 0x99, 0x94, 0x93, 0xeb, 0xfa, 0x1c, + 0x5c, 0x8c, 0x9a, 0x6d, 0x3e, 0x52, 0x21, 0x82, 0x69, 0x5c, 0xff, 0x57, 0x66, 0x37, 0xa4, 0x31, + 0xf2, 0x4a, 0x0c, 0xb2, 0x5c, 0xda, 0x3b, 0xcc, 0x28, 0xfb, 0x87, 0x19, 0xe5, 0xf7, 0x61, 0x46, + 0x79, 0x7f, 0x94, 0x89, 0xed, 0x1f, 0x65, 0x62, 0x3f, 0x8e, 0x32, 0xb1, 0xc7, 0x39, 0xec, 0xf0, + 0x46, 0x6b, 0xb3, 0xb0, 0x45, 0x89, 0x75, 0x7a, 0x9a, 0x7c, 0xdb, 0x43, 0x6c, 0x73, 0x54, 0xfe, + 0x30, 0x6f, 0xfc, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x5b, 0xb8, 0x53, 0x9d, 0xf6, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -661,6 +667,18 @@ func (m *MsgEthereumTxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.BlockTimestamp != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.BlockTimestamp)) + i-- + dAtA[i] = 0x40 + } + if len(m.BlockHash) > 0 { + i -= len(m.BlockHash) + copy(dAtA[i:], m.BlockHash) + i = encodeVarintTx(dAtA, i, uint64(len(m.BlockHash))) + i-- + dAtA[i] = 0x3a + } if m.MaxUsedGas != 0 { i = encodeVarintTx(dAtA, i, uint64(m.MaxUsedGas)) i-- @@ -904,6 +922,13 @@ func (m *MsgEthereumTxResponse) Size() (n int) { if m.MaxUsedGas != 0 { n += 1 + sovTx(uint64(m.MaxUsedGas)) } + l = len(m.BlockHash) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.BlockTimestamp != 0 { + n += 1 + sovTx(uint64(m.BlockTimestamp)) + } return n } @@ -1331,6 +1356,59 @@ func (m *MsgEthereumTxResponse) Unmarshal(dAtA []byte) error { break } } + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlockHash = append(m.BlockHash[:0], dAtA[iNdEx:postIndex]...) + if m.BlockHash == nil { + m.BlockHash = []byte{} + } + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockTimestamp", wireType) + } + m.BlockTimestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockTimestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/vm/types/utils.go b/x/vm/types/utils.go index 9d58f233b0..07cbefb262 100644 --- a/x/vm/types/utils.go +++ b/x/vm/types/utils.go @@ -82,6 +82,12 @@ func logsFromTxResponse(dst []*ethtypes.Log, rsp *MsgEthereumTxResponse, blockNu l := log.ToEthereum() l.TxHash = txHash l.BlockNumber = blockNumber + if len(rsp.BlockHash) > 0 { + l.BlockHash = common.BytesToHash(rsp.BlockHash) + } + if rsp.BlockTimestamp > 0 { + l.BlockTimestamp = rsp.BlockTimestamp + } dst = append(dst, l) } return dst From 4ea6cd9488628bec8a9b5321cca373242db7f1e3 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Thu, 18 Sep 2025 02:58:11 +0800 Subject: [PATCH 56/61] fix: align tx not found in get_transaction_receipt (#533) * fix: align tx not found in get_transaction_receipt * add doc * Revert "fix: align tx not found in get_transaction_receipt" This reverts commit d186723b049d414418fffad8b87613cf5047fcc8. * stop retry early for tx with unknown status --------- Co-authored-by: Alex | Interchain Labs Co-authored-by: Vlad J --- rpc/backend/tx_info.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 83ab86b2e4..224a1729e5 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -17,6 +17,7 @@ import ( cmtrpcclient "github.com/cometbft/cometbft/rpc/client" cmtrpctypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/cosmos/evm/mempool/txpool" rpctypes "github.com/cosmos/evm/rpc/types" "github.com/cosmos/evm/types" evmtypes "github.com/cosmos/evm/x/vm/types" @@ -158,6 +159,13 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ break // Found the transaction } + if attempt == maxRetries/2 && b.Mempool != nil { + status := b.Mempool.GetTxPool().Status(hash) + if status == txpool.TxStatusUnknown { + break + } + } + if attempt < maxRetries { // Exponential backoff: 50ms, 100ms, 200ms delay := time.Duration(1< Date: Thu, 18 Sep 2025 03:43:36 +0800 Subject: [PATCH 57/61] chore: cleanup unnecessary fix-revert-gas-refund-height (#624) --- CHANGELOG.md | 1 + rpc/backend/tx_info.go | 6 --- server/config/config.go | 50 ++++++++----------- server/config/migration/v0.50-app.toml | 3 -- server/config/toml.go | 3 -- server/flags/flags.go | 3 +- tests/integration/rpc/backend/test_tx_info.go | 30 +++-------- 7 files changed, 30 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f97c8a21f..f69f2d315c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - [\#582](https://github.com/cosmos/evm/pull/582) Add block max-gas (from genesis.json) and new min-tip (from app.toml/flags) ingestion into mempool config - [\#598](https://github.com/cosmos/evm/pull/598) Reduce number of times CreateQueryContext in mempool. - [\#606](https://github.com/cosmos/evm/pull/606) Regenerate mock file for bank keeper related test. +- [\#624](https://github.com/cosmos/evm/pull/624) Cleanup unnecessary `fix-revert-gas-refund-height`. ### FEATURES diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 224a1729e5..e23a93086b 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -132,12 +132,6 @@ func (b *Backend) GetTransactionByHashPending(txHash common.Hash) (*rpctypes.RPC // GetGasUsed returns gasUsed from transaction func (b *Backend) GetGasUsed(res *types.TxResult, price *big.Int, gas uint64) uint64 { - // patch gasUsed if tx is reverted and happened before height on which fixed was introduced - // to return real gas charged - // more info at https://github.com/evmos/ethermint/pull/1557 - if res.Failed && res.Height < b.Cfg.JSONRPC.FixRevertGasRefundHeight { - return new(big.Int).Mul(price, new(big.Int).SetUint64(gas)).Uint64() - } return res.GasUsed } diff --git a/server/config/config.go b/server/config/config.go index cabd791817..a46df42f98 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -57,9 +57,6 @@ const ( // DefaultEnablePreimageRecording is the default value for EnablePreimageRecording DefaultEnablePreimageRecording = false - // DefaultFixRevertGasRefundHeight is the default height at which to overwrite gas refund - DefaultFixRevertGasRefundHeight = 0 - // DefaultMaxTxGasWanted is the default gas wanted for each eth tx returned in ante handler in check tx mode DefaultMaxTxGasWanted = 0 @@ -194,8 +191,6 @@ type JSONRPCConfig struct { EnableIndexer bool `mapstructure:"enable-indexer"` // MetricsAddress defines the metrics server to listen on MetricsAddress string `mapstructure:"metrics-address"` - // FixRevertGasRefundHeight defines the upgrade height for fix of revert gas refund logic when transaction reverted - FixRevertGasRefundHeight int64 `mapstructure:"fix-revert-gas-refund-height"` // WSOrigins defines the allowed origins for WebSocket connections WSOrigins []string `mapstructure:"ws-origins"` // EnableProfiling enables the profiling in the `debug` namespace. SHOULD NOT be used on public tracing nodes @@ -248,29 +243,28 @@ func GetDefaultWSOrigins() []string { // DefaultJSONRPCConfig returns an EVM config with the JSON-RPC API enabled by default func DefaultJSONRPCConfig() *JSONRPCConfig { return &JSONRPCConfig{ - Enable: false, - API: GetDefaultAPINamespaces(), - Address: DefaultJSONRPCAddress, - WsAddress: DefaultJSONRPCWsAddress, - GasCap: DefaultGasCap, - AllowInsecureUnlock: DefaultJSONRPCAllowInsecureUnlock, - EVMTimeout: DefaultEVMTimeout, - TxFeeCap: DefaultTxFeeCap, - FilterCap: DefaultFilterCap, - FeeHistoryCap: DefaultFeeHistoryCap, - BlockRangeCap: DefaultBlockRangeCap, - LogsCap: DefaultLogsCap, - HTTPTimeout: DefaultHTTPTimeout, - HTTPIdleTimeout: DefaultHTTPIdleTimeout, - AllowUnprotectedTxs: DefaultAllowUnprotectedTxs, - BatchRequestLimit: DefaultBatchRequestLimit, - BatchResponseMaxSize: DefaultBatchResponseMaxSize, - MaxOpenConnections: DefaultMaxOpenConnections, - EnableIndexer: false, - MetricsAddress: DefaultJSONRPCMetricsAddress, - FixRevertGasRefundHeight: DefaultFixRevertGasRefundHeight, - WSOrigins: GetDefaultWSOrigins(), - EnableProfiling: DefaultEnableProfiling, + Enable: false, + API: GetDefaultAPINamespaces(), + Address: DefaultJSONRPCAddress, + WsAddress: DefaultJSONRPCWsAddress, + GasCap: DefaultGasCap, + AllowInsecureUnlock: DefaultJSONRPCAllowInsecureUnlock, + EVMTimeout: DefaultEVMTimeout, + TxFeeCap: DefaultTxFeeCap, + FilterCap: DefaultFilterCap, + FeeHistoryCap: DefaultFeeHistoryCap, + BlockRangeCap: DefaultBlockRangeCap, + LogsCap: DefaultLogsCap, + HTTPTimeout: DefaultHTTPTimeout, + HTTPIdleTimeout: DefaultHTTPIdleTimeout, + AllowUnprotectedTxs: DefaultAllowUnprotectedTxs, + BatchRequestLimit: DefaultBatchRequestLimit, + BatchResponseMaxSize: DefaultBatchResponseMaxSize, + MaxOpenConnections: DefaultMaxOpenConnections, + EnableIndexer: false, + MetricsAddress: DefaultJSONRPCMetricsAddress, + WSOrigins: GetDefaultWSOrigins(), + EnableProfiling: DefaultEnableProfiling, } } diff --git a/server/config/migration/v0.50-app.toml b/server/config/migration/v0.50-app.toml index bcff87d811..0bebf82cad 100644 --- a/server/config/migration/v0.50-app.toml +++ b/server/config/migration/v0.50-app.toml @@ -313,9 +313,6 @@ enable-indexer = false # Prometheus metrics path: /debug/metrics/prometheus metrics-address = "127.0.0.1:6065" -# Upgrade height for fix of revert gas refund logic when transaction reverted. -fix-revert-gas-refund-height = 0 - ############################################################################### ### TLS Configuration ### ############################################################################### diff --git a/server/config/toml.go b/server/config/toml.go index 1e9d4689a1..8b61fdd3a6 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -93,9 +93,6 @@ enable-indexer = {{ .JSONRPC.EnableIndexer }} # Prometheus metrics path: /debug/metrics/prometheus metrics-address = "{{ .JSONRPC.MetricsAddress }}" -# Upgrade height for fix of revert gas refund logic when transaction reverted. -fix-revert-gas-refund-height = {{ .JSONRPC.FixRevertGasRefundHeight }} - # Maximum number of requests in a batch. batch-request-limit = {{ .JSONRPC.BatchRequestLimit }} diff --git a/server/flags/flags.go b/server/flags/flags.go index 3844fc7dfd..db86ca3fa0 100644 --- a/server/flags/flags.go +++ b/server/flags/flags.go @@ -60,8 +60,7 @@ const ( // JSONRPCEnableMetrics enables EVM RPC metrics server. // Set to `metrics` which is hardcoded flag from go-ethereum. // https://github.com/ethereum/go-ethereum/blob/master/metrics/metrics.go#L35-L55 - JSONRPCEnableMetrics = "metrics" - JSONRPCFixRevertGasRefundHeight = "json-rpc.fix-revert-gas-refund-height" + JSONRPCEnableMetrics = "metrics" ) // EVM flags diff --git a/tests/integration/rpc/backend/test_tx_info.go b/tests/integration/rpc/backend/test_tx_info.go index f79ab273ad..3c74471aaa 100644 --- a/tests/integration/rpc/backend/test_tx_info.go +++ b/tests/integration/rpc/backend/test_tx_info.go @@ -710,18 +710,15 @@ func (s *TestSuite) TestGetTransactionReceipt() { } func (s *TestSuite) TestGetGasUsed() { - origin := s.backend.Cfg.JSONRPC.FixRevertGasRefundHeight testCases := []struct { - name string - fixRevertGasRefundHeight int64 - txResult *cosmosevmtypes.TxResult - price *big.Int - gas uint64 - exp uint64 + name string + txResult *cosmosevmtypes.TxResult + price *big.Int + gas uint64 + exp uint64 }{ { "success txResult", - 1, &cosmosevmtypes.TxResult{ Height: 1, Failed: false, @@ -732,20 +729,7 @@ func (s *TestSuite) TestGetGasUsed() { 53026, }, { - "fail txResult before cap", - 2, - &cosmosevmtypes.TxResult{ - Height: 1, - Failed: true, - GasUsed: 53026, - }, - new(big.Int).SetUint64(200000), - 5000000000000, - 1000000000000000000, - }, - { - "fail txResult after cap", - 2, + "fail txResult", &cosmosevmtypes.TxResult{ Height: 3, Failed: true, @@ -758,9 +742,7 @@ func (s *TestSuite) TestGetGasUsed() { } for _, tc := range testCases { s.Run(fmt.Sprintf("Case %s", tc.name), func() { - s.backend.Cfg.JSONRPC.FixRevertGasRefundHeight = tc.fixRevertGasRefundHeight s.Require().Equal(tc.exp, s.backend.GetGasUsed(tc.txResult, tc.price, tc.gas)) - s.backend.Cfg.JSONRPC.FixRevertGasRefundHeight = origin }) } } From b63a6810ff81a23fd11ce5c3d63730dd25fed51b Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Thu, 18 Sep 2025 12:47:17 -0400 Subject: [PATCH 58/61] feat: separate geth metrics server (#633) * separate geth metrics server * that should be a wrap * changelog lol * make server behave more like the others * move port to 8100, fix quoting problem * lint fix * expose in dockerfile --- CHANGELOG.md | 2 +- contrib/images/evmd-env/Dockerfile | 2 +- evmd/cmd/evmd/cmd/testnet.go | 8 ++-- go.mod | 3 +- metrics/geth.go | 59 ++++++++++++++++++++++++++++++ server/config/config.go | 11 ++++++ server/config/toml.go | 3 ++ server/flags/flags.go | 1 + server/start.go | 11 ++++-- 9 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 metrics/geth.go diff --git a/CHANGELOG.md b/CHANGELOG.md index f69f2d315c..9507723a41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ - [\#346](https://github.com/cosmos/evm/pull/346) Add eth_createAccessList method and implementation - [\#502](https://github.com/cosmos/evm/pull/502) Add block time in derived logs. -- [\#588](https://github.com/cosmos/evm/pull/588) go-ethereum metrics are now available in Cosmos SDK's telemetry server at host:port/geth/metrics (default localhost:1317/geth/metrics). +- [\#633](https://github.com/cosmos/evm/pull/633) go-ethereum metrics are now emitted on a separate server. default address: 127.0.0.1:8100. ### STATE BREAKING diff --git a/contrib/images/evmd-env/Dockerfile b/contrib/images/evmd-env/Dockerfile index 3a570ed6ad..d043dca021 100644 --- a/contrib/images/evmd-env/Dockerfile +++ b/contrib/images/evmd-env/Dockerfile @@ -22,7 +22,7 @@ RUN addgroup -g 1025 nonroot RUN adduser -D nonroot -u 1025 -G nonroot # Set up the runtime environment -EXPOSE 26656 26657 1317 9090 +EXPOSE 26656 26657 1317 9090 26660 8545 8100 STOPSIGNAL SIGTERM VOLUME /evmd WORKDIR /evmd diff --git a/evmd/cmd/evmd/cmd/testnet.go b/evmd/cmd/evmd/cmd/testnet.go index c90690cb02..a98dfc0528 100644 --- a/evmd/cmd/evmd/cmd/testnet.go +++ b/evmd/cmd/evmd/cmd/testnet.go @@ -288,9 +288,10 @@ func initTestnetFiles( sdkGRPCPort = 9090 // evmGRPC = 9900 // TODO: maybe need this? idk. - evmJSONRPC = 8545 - evmJSONRPCWS = 8546 - evmJSONRPCMetrics = 6065 + evmJSONRPC = 8545 + evmJSONRPCWS = 8546 + evmJSONRPCMetrics = 6065 + evmGethMetricsPort = 8100 ) p2pPortStart := 26656 @@ -317,6 +318,7 @@ func initTestnetFiles( evmCfg.JSONRPC.Address = fmt.Sprintf("127.0.0.1:%d", evmJSONRPC+evmPortOffset) evmCfg.JSONRPC.MetricsAddress = fmt.Sprintf("127.0.0.1:%d", evmJSONRPCMetrics+evmPortOffset) evmCfg.JSONRPC.WsAddress = fmt.Sprintf("127.0.0.1:%d", evmJSONRPCWS+evmPortOffset) + evmCfg.EVM.GethMetricsAddress = fmt.Sprintf("127.0.0.1:%d", evmGethMetricsPort+evmPortOffset) } else { evmCfg.JSONRPC.WsAddress = fmt.Sprintf("0.0.0.0:%d", evmJSONRPCWS) evmCfg.JSONRPC.Address = fmt.Sprintf("0.0.0.0:%d", evmJSONRPC) diff --git a/go.mod b/go.mod index 4166dd6d35..2e66b76267 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,6 @@ require ( github.com/onsi/ginkgo/v2 v2.23.4 github.com/onsi/gomega v1.38.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.22.0 github.com/rs/cors v1.11.1 github.com/spf13/cast v1.9.2 github.com/spf13/cobra v1.9.1 @@ -181,7 +180,6 @@ require ( github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect @@ -207,6 +205,7 @@ require ( github.com/pion/transport/v3 v3.0.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.63.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect diff --git a/metrics/geth.go b/metrics/geth.go new file mode 100644 index 0000000000..44c0526391 --- /dev/null +++ b/metrics/geth.go @@ -0,0 +1,59 @@ +package metrics + +import ( + "context" + "errors" + "net/http" + "time" + + gethmetrics "github.com/ethereum/go-ethereum/metrics" + gethprom "github.com/ethereum/go-ethereum/metrics/prometheus" + + "cosmossdk.io/log" +) + +// StartGethMetricServer starts the geth metrics server on the specified address. +func StartGethMetricServer(ctx context.Context, log log.Logger, addr string) error { + mux := http.NewServeMux() + mux.Handle("/metrics", gethprom.Handler(gethmetrics.DefaultRegistry)) + + server := &http.Server{ + Addr: addr, + Handler: mux, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + ReadHeaderTimeout: 10 * time.Second, + } + + errCh := make(chan error, 1) + + go func() { + log.Info("starting geth metrics server...", "address", addr) + errCh <- server.ListenAndServe() + }() + + // Start a blocking select to wait for an indication to stop the server or that + // the server failed to start properly. + select { + case <-ctx.Done(): + // The calling process canceled or closed the provided context, so we must + // gracefully stop the metrics server. + log.Info("stopping geth metrics server...", "address", addr) + + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := server.Shutdown(shutdownCtx); err != nil { + log.Error("geth metrics server shutdown error", "err", err) + return err + } + return nil + + case err := <-errCh: + if err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Error("failed to start geth metrics server", "err", err) + return err + } + return nil + } +} diff --git a/server/config/config.go b/server/config/config.go index a46df42f98..d8dd07bcf4 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -3,6 +3,7 @@ package config import ( "errors" "fmt" + "net/netip" "path" "time" @@ -66,6 +67,9 @@ const ( // DefaultEVMMinTip is the default minimum priority fee for the mempool DefaultEVMMinTip = 0 + // DefaultGethMetricsAddress is the default port for the geth metrics server. + DefaultGethMetricsAddress = "127.0.0.1:8100" + // DefaultGasCap is the default cap on gas that can be used in eth_call/estimateGas DefaultGasCap uint64 = 25_000_000 @@ -145,6 +149,8 @@ type EVMConfig struct { EVMChainID uint64 `mapstructure:"evm-chain-id"` // MinTip defines the minimum priority fee for the mempool MinTip uint64 `mapstructure:"min-tip"` + // GethMetricsAddress is the address the geth metrics server will bind to. Default 127.0.0.1:8100 + GethMetricsAddress string `mapstructure:"geth-metrics-address"` } // JSONRPCConfig defines configuration for the EVM RPC server. @@ -213,6 +219,7 @@ func DefaultEVMConfig() *EVMConfig { EVMChainID: DefaultEVMChainID, EnablePreimageRecording: DefaultEnablePreimageRecording, MinTip: DefaultEVMMinTip, + GethMetricsAddress: DefaultGethMetricsAddress, } } @@ -222,6 +229,10 @@ func (c EVMConfig) Validate() error { return fmt.Errorf("invalid tracer type %s, available types: %v", c.Tracer, evmTracers) } + if _, err := netip.ParseAddrPort(c.GethMetricsAddress); err != nil { + return fmt.Errorf("invalid geth metrics address %q: %w", c.GethMetricsAddress, err) + } + return nil } diff --git a/server/config/toml.go b/server/config/toml.go index 8b61fdd3a6..b805482a07 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -25,6 +25,9 @@ evm-chain-id = {{ .EVM.EVMChainID }} # MinTip defines the minimum priority fee for the mempool. min-tip = {{ .EVM.MinTip }} +# GethMetricsAddress defines the addr to bind the geth metrics server to. Default 127.0.0.1:8100. +geth-metrics-address = "{{ .EVM.GethMetricsAddress }}" + ############################################################################### ### JSON RPC Configuration ### ############################################################################### diff --git a/server/flags/flags.go b/server/flags/flags.go index db86ca3fa0..6bbc61261c 100644 --- a/server/flags/flags.go +++ b/server/flags/flags.go @@ -70,6 +70,7 @@ const ( EVMEnablePreimageRecording = "evm.cache-preimage" EVMChainID = "evm.evm-chain-id" EVMMinTip = "evm.min-tip" + EvmGethMetricsAddress = "evm.geth-metrics-address" ) // TLS flags diff --git a/server/start.go b/server/start.go index aa317693cf..1a08fcb0d3 100644 --- a/server/start.go +++ b/server/start.go @@ -9,9 +9,7 @@ import ( "path/filepath" "runtime/pprof" - gethmetrics "github.com/ethereum/go-ethereum/metrics" ethmetricsexp "github.com/ethereum/go-ethereum/metrics/exp" - gethprom "github.com/ethereum/go-ethereum/metrics/prometheus" "github.com/spf13/cobra" "golang.org/x/sync/errgroup" "google.golang.org/grpc" @@ -31,6 +29,7 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/evm/indexer" evmmempool "github.com/cosmos/evm/mempool" + evmmetrics "github.com/cosmos/evm/metrics" ethdebug "github.com/cosmos/evm/rpc/namespaces/ethereum/debug" cosmosevmserverconfig "github.com/cosmos/evm/server/config" srvflags "github.com/cosmos/evm/server/flags" @@ -222,6 +221,7 @@ which accepts a path for the resulting pprof file. cmd.Flags().Bool(srvflags.EVMEnablePreimageRecording, cosmosevmserverconfig.DefaultEnablePreimageRecording, "Enables tracking of SHA3 preimages in the EVM (not implemented yet)") //nolint:lll cmd.Flags().Uint64(srvflags.EVMChainID, cosmosevmserverconfig.DefaultEVMChainID, "the EIP-155 compatible replay protection chain ID") cmd.Flags().Uint64(srvflags.EVMMinTip, cosmosevmserverconfig.DefaultEVMMinTip, "the minimum priority fee for the mempool") + cmd.Flags().String(srvflags.EvmGethMetricsAddress, cosmosevmserverconfig.DefaultGethMetricsAddress, "the address to bind the geth metrics server to") cmd.Flags().String(srvflags.TLSCertPath, "", "the cert.pem file path for the server TLS configuration") cmd.Flags().String(srvflags.TLSKeyPath, "", "the key.pem file path for the server TLS configuration") @@ -504,7 +504,7 @@ func startInProcess(svrCtx *server.Context, clientCtx client.Context, opts Start defer grpcSrv.GracefulStop() } - startAPIServer(ctx, svrCtx, clientCtx, g, config.Config, app, grpcSrv, metrics) + startAPIServer(ctx, svrCtx, clientCtx, g, config.Config, app, grpcSrv, metrics, config.EVM.GethMetricsAddress) if config.JSONRPC.Enable { txApp, ok := app.(AppWithPendingTxStream) @@ -675,6 +675,7 @@ func startAPIServer( app types.Application, grpcSrv *grpc.Server, metrics *telemetry.Metrics, + gethMetricsAddress string, ) { if !svrCfg.API.Enable { return @@ -685,7 +686,9 @@ func startAPIServer( if svrCfg.Telemetry.Enabled { apiSrv.SetTelemetry(metrics) - apiSrv.Router.Handle("/geth/metrics", gethprom.Handler(gethmetrics.DefaultRegistry)) + g.Go(func() error { + return evmmetrics.StartGethMetricServer(ctx, svrCtx.Logger.With("server", "geth_metrics"), gethMetricsAddress) + }) } g.Go(func() error { From 19b82ce706a45d8850bdc271056f1923e403d2e8 Mon Sep 17 00:00:00 2001 From: Vlad J Date: Thu, 18 Sep 2025 13:02:02 -0400 Subject: [PATCH 59/61] refactor: move default precompiles out of evmd config (#635) * move default static precompiles creator out of app.go and set as defaults * move defaults to precompile folder and use existing builder pattern * undo interface changes on tests * undo unnecessary changes * fix tests * lints * add sum docs --- CHANGELOG.md | 2 ++ .../migrations/v0.4.0_to_v0.5.0_UNRELEASED.md | 33 +++++++++++++++++++ evmd/app.go | 30 ++++++++--------- .../types/defaults.go | 23 +++++++------ 4 files changed, 59 insertions(+), 29 deletions(-) rename evmd/precompiles.go => precompiles/types/defaults.go (88%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9507723a41..1328500232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ - [\#598](https://github.com/cosmos/evm/pull/598) Reduce number of times CreateQueryContext in mempool. - [\#606](https://github.com/cosmos/evm/pull/606) Regenerate mock file for bank keeper related test. - [\#624](https://github.com/cosmos/evm/pull/624) Cleanup unnecessary `fix-revert-gas-refund-height`. +- [\#635](https://github.com/cosmos/evm/pull/635) Move DefaultStaticPrecompiles to /evm and allow projects to set it by default alongside the keeper. + ### FEATURES diff --git a/docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md b/docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md index 57965a9bdd..10fc612662 100644 --- a/docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md +++ b/docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md @@ -80,6 +80,39 @@ mempoolConfig.CosmosPoolConfig = &cosmosCfg mempoolConfig.BroadCastTxFn = func(txs []*ethtypes.Transaction) error { return nil } ``` +### Default Precompiles + +Default precompiles have been moved to `/evm/precompiles/types/defaults.go` and the function name was +changed to `DefaultStaticPrecompiles`. The function signature has also changed, and now takes pointers +as inputs for the `Erc20Keeper` and `TransferKeeper`. Finally, the `WithStaticPrecompiles` builder +function can now happen *alongside the keeper instantiation*, and not after. The new wiring is shown below: + +```go + app.EVMKeeper = evmkeeper.NewKeeper( + appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], keys, + authtypes.NewModuleAddress(govtypes.ModuleName), + app.AccountKeeper, + app.PreciseBankKeeper, + app.StakingKeeper, + app.FeeMarketKeeper, + &app.ConsensusParamsKeeper, + &app.Erc20Keeper, + tracer, + ).WithStaticPrecompiles( + precompiletypes.DefaultStaticPrecompiles( + *app.StakingKeeper, + app.DistrKeeper, + app.BankKeeper, + &app.Erc20Keeper, // UPDATED + &app.TransferKeeper, // UPDATED + app.IBCKeeper.ChannelKeeper, + app.GovKeeper, + app.SlashingKeeper, + appCodec, + ), + ) +``` + --- ## 3) Build & quick tests diff --git a/evmd/app.go b/evmd/app.go index d4ec9ebe34..e47152852f 100644 --- a/evmd/app.go +++ b/evmd/app.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + precompiletypes "github.com/cosmos/evm/precompiles/types" "io" "os" @@ -486,6 +487,18 @@ func NewExampleApp( &app.ConsensusParamsKeeper, &app.Erc20Keeper, tracer, + ).WithStaticPrecompiles( + precompiletypes.DefaultStaticPrecompiles( + *app.StakingKeeper, + app.DistrKeeper, + app.BankKeeper, + &app.Erc20Keeper, + &app.TransferKeeper, + app.IBCKeeper.ChannelKeeper, + app.GovKeeper, + app.SlashingKeeper, + appCodec, + ), ) app.Erc20Keeper = erc20keeper.NewKeeper( @@ -561,23 +574,6 @@ func NewExampleApp( // Override the ICS20 app module transferModule := transfer.NewAppModule(app.TransferKeeper) - // NOTE: we are adding all available Cosmos EVM EVM extensions. - // Not all of them need to be enabled, which can be configured on a per-chain basis. - app.EVMKeeper.WithStaticPrecompiles( - NewAvailableStaticPrecompiles( - *app.StakingKeeper, - app.DistrKeeper, - app.PreciseBankKeeper, - app.Erc20Keeper, - app.TransferKeeper, - app.IBCKeeper.ChannelKeeper, - app.EVMKeeper, - app.GovKeeper, - app.SlashingKeeper, - app.AppCodec(), - ), - ) - /**** Module Options ****/ // NOTE: Any module instantiated in the module manager that is later modified diff --git a/evmd/precompiles.go b/precompiles/types/defaults.go similarity index 88% rename from evmd/precompiles.go rename to precompiles/types/defaults.go index cd7fe94b47..b645703655 100644 --- a/evmd/precompiles.go +++ b/precompiles/types/defaults.go @@ -1,11 +1,9 @@ -package evmd +package types import ( "fmt" "maps" - addresscodec "github.com/cosmos/cosmos-sdk/codec/address" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" @@ -20,11 +18,13 @@ import ( stakingprecompile "github.com/cosmos/evm/precompiles/staking" erc20Keeper "github.com/cosmos/evm/x/erc20/keeper" transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" - evmkeeper "github.com/cosmos/evm/x/vm/keeper" channelkeeper "github.com/cosmos/ibc-go/v10/modules/core/04-channel/keeper" "cosmossdk.io/core/address" + "github.com/cosmos/cosmos-sdk/codec" + addresscodec "github.com/cosmos/cosmos-sdk/codec/address" + sdktypes "github.com/cosmos/cosmos-sdk/types" distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" @@ -42,9 +42,9 @@ type Optionals struct { func defaultOptionals() Optionals { return Optionals{ - AddressCodec: addresscodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), - ValidatorAddrCodec: addresscodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()), - ConsensusAddrCodec: addresscodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()), + AddressCodec: addresscodec.NewBech32Codec(sdktypes.GetConfig().GetBech32AccountAddrPrefix()), + ValidatorAddrCodec: addresscodec.NewBech32Codec(sdktypes.GetConfig().GetBech32ValidatorAddrPrefix()), + ConsensusAddrCodec: addresscodec.NewBech32Codec(sdktypes.GetConfig().GetBech32ConsensusAddrPrefix()), } } @@ -70,17 +70,16 @@ func WithConsensusAddrCodec(codec address.Codec) Option { const bech32PrecompileBaseGas = 6_000 -// NewAvailableStaticPrecompiles returns the list of all available static precompiled contracts from Cosmos EVM. +// DefaultStaticPrecompiles returns the list of all available static precompiled contracts from Cosmos EVM. // // NOTE: this should only be used during initialization of the Keeper. -func NewAvailableStaticPrecompiles( +func DefaultStaticPrecompiles( stakingKeeper stakingkeeper.Keeper, distributionKeeper distributionkeeper.Keeper, bankKeeper cmn.BankKeeper, - erc20Keeper erc20Keeper.Keeper, - transferKeeper transferkeeper.Keeper, + erc20Keeper *erc20Keeper.Keeper, + transferKeeper *transferkeeper.Keeper, channelKeeper *channelkeeper.Keeper, - evmKeeper *evmkeeper.Keeper, govKeeper govkeeper.Keeper, slashingKeeper slashingkeeper.Keeper, codec codec.Codec, From e07bfc16dbb352d513f9f5d8cbb11c689ee4e9c3 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Thu, 18 Sep 2025 23:33:00 +0200 Subject: [PATCH 60/61] refactor: make erc20keeper optional in x/vm (#609) * imp: make erc20keeper optional in x/vm * add changelog --------- Co-authored-by: Vlad J --- CHANGELOG.md | 1 + x/vm/keeper/keeper.go | 2 +- x/vm/keeper/precompiles.go | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1328500232..fa138c2151 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - [\#582](https://github.com/cosmos/evm/pull/582) Add block max-gas (from genesis.json) and new min-tip (from app.toml/flags) ingestion into mempool config - [\#598](https://github.com/cosmos/evm/pull/598) Reduce number of times CreateQueryContext in mempool. - [\#606](https://github.com/cosmos/evm/pull/606) Regenerate mock file for bank keeper related test. +- [\#609](https://github.com/cosmos/evm/pull/609) Make `erc20Keeper` optional in the EVM keeper - [\#624](https://github.com/cosmos/evm/pull/624) Cleanup unnecessary `fix-revert-gas-refund-height`. - [\#635](https://github.com/cosmos/evm/pull/635) Move DefaultStaticPrecompiles to /evm and allow projects to set it by default alongside the keeper. diff --git a/x/vm/keeper/keeper.go b/x/vm/keeper/keeper.go index 774598fb27..301c0f8be5 100644 --- a/x/vm/keeper/keeper.go +++ b/x/vm/keeper/keeper.go @@ -59,7 +59,7 @@ type Keeper struct { stakingKeeper types.StakingKeeper // fetch EIP1559 base fee and parameters feeMarketWrapper *wrappers.FeeMarketWrapper - // erc20Keeper interface needed to instantiate erc20 precompiles + // optional erc20Keeper interface needed to instantiate erc20 precompiles erc20Keeper types.Erc20Keeper // consensusKeeper is used to get consensus params during query contexts. // This is needed as block.gasLimit is expected to be available in eth_call, which is routed through Cosmos SDK's diff --git a/x/vm/keeper/precompiles.go b/x/vm/keeper/precompiles.go index a730b834ba..10db8b57f8 100644 --- a/x/vm/keeper/precompiles.go +++ b/x/vm/keeper/precompiles.go @@ -33,6 +33,11 @@ func (k *Keeper) GetPrecompileInstance( }, found, nil } + // Since erc20Keeper is optional, we check if it is nil, in which case we just return that we didn't find the precompile + if k.erc20Keeper == nil { + return nil, false, nil + } + // Get the precompile from the dynamic precompiles precompile, found, err := k.erc20Keeper.GetERC20PrecompileInstance(ctx, address) if err != nil || !found { From bb6162e10da6ed984856922cbecdd1eaf10e2f38 Mon Sep 17 00:00:00 2001 From: Haber Date: Fri, 19 Sep 2025 06:31:35 +0900 Subject: [PATCH 61/61] test(systemtests): add appside mempool e2e test (#580) * test(mempool): setup e2e test suite for mempool testing * WIP * test(mempool): refactor test * test(mempool): refactor system test suite * test(systemtest): refactor mempool test * test(systemtests): add cosmosClient * test(systemtests): refactor mempool test * test(systemtests): refactor mempool test * test(systemtests): refactor mempool test * test(systemtests): add txpool content verification to mempool tests * test(systemtests): fix mempool test suite * test(systemtests): fix mempool test suite * test(systemtests): fix mempool tests * test(systemtests): fix mempool test suite * test(systemtests): fix mempool test suite * test(systemtests): fix mempool test suite * test(systemtests): add mempool test cases * test(systemtests): add comments * test(systemtests): chore: enable replacement tests * chore: modify names of test cases * test(systemtests): enhance helper functions * test(systemtests): fix mempool test * chore(systemtests): change test name and add readme.md * chore: update CHANGELOG.md * fix(proto): restore removed data field during merge * test(systemtests): refactor * test(systemtests): fix map iteration * chore(systemtests): fix build tag * test(systemtests): add test case for mempool * test(systemtests): fix map iteration * test(systemtests): refactor and add test case for --minimum-gas-prices=0stake * test(systemtests): enhance validation * fix: restore removed changes from merge * fix: restore removed changes from merge * fix: restore removed changes from merge * fix: restore removed changes from merge * chore(systemtests): rename test suite hooks * fix(systemtests): fix test cases * chore: modify mempool e2e test README.md * test(systemtests): enhance post check of mempool test * chore: apply codeQL feedback * chore: update tests/systemtests/go.sum * chore: go mod tidy * fix(rpc): SendRawTransaction doesn't return error when tx.nonce is lower than pending nonce * chore(systemtests): remove unused fields of RPCTransaction type --------- Co-authored-by: Alex | Interchain Labs Co-authored-by: Vlad J --- CHANGELOG.md | 1 + rpc/backend/call_tx.go | 19 + tests/systemtests/README.md | 51 +++ tests/systemtests/clients/config.go | 75 ++++ tests/systemtests/clients/cosmosclient.go | 265 +++++++++++ tests/systemtests/clients/ethclient.go | 184 ++++++++ tests/systemtests/clients/types.go | 29 ++ tests/systemtests/eth_test.go | 31 +- tests/systemtests/go.mod | 83 ++-- tests/systemtests/go.sum | 301 +++++++++---- tests/systemtests/mempool/interface.go | 45 ++ tests/systemtests/mempool/test_exceptions.go | 154 +++++++ tests/systemtests/mempool/test_ordering.go | 82 ++++ tests/systemtests/mempool/test_replacement.go | 425 ++++++++++++++++++ tests/systemtests/mempool_test.go | 24 + tests/systemtests/suite/query.go | 179 ++++++++ tests/systemtests/suite/test_helpers.go | 172 +++++++ tests/systemtests/suite/test_suite.go | 117 +++++ tests/systemtests/suite/tx.go | 128 ++++++ tests/systemtests/suite/types.go | 49 ++ 20 files changed, 2281 insertions(+), 133 deletions(-) create mode 100644 tests/systemtests/README.md create mode 100644 tests/systemtests/clients/config.go create mode 100644 tests/systemtests/clients/cosmosclient.go create mode 100644 tests/systemtests/clients/ethclient.go create mode 100644 tests/systemtests/clients/types.go create mode 100644 tests/systemtests/mempool/interface.go create mode 100644 tests/systemtests/mempool/test_exceptions.go create mode 100644 tests/systemtests/mempool/test_ordering.go create mode 100644 tests/systemtests/mempool/test_replacement.go create mode 100644 tests/systemtests/mempool_test.go create mode 100644 tests/systemtests/suite/query.go create mode 100644 tests/systemtests/suite/test_helpers.go create mode 100644 tests/systemtests/suite/test_suite.go create mode 100644 tests/systemtests/suite/tx.go create mode 100644 tests/systemtests/suite/types.go diff --git a/CHANGELOG.md b/CHANGELOG.md index fa138c2151..90165d117d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - [\#576](https://github.com/cosmos/evm/pull/576) Parse logs from the txResult.Data and avoid emitting EVM events to cosmos-sdk events. - [\#584](https://github.com/cosmos/evm/pull/584) Fill block hash and timestamp for json rpc. - [\#582](https://github.com/cosmos/evm/pull/582) Add block max-gas (from genesis.json) and new min-tip (from app.toml/flags) ingestion into mempool config +- [\#580](https://github.com/cosmos/evm/pull/580) add appside mempool e2e test - [\#598](https://github.com/cosmos/evm/pull/598) Reduce number of times CreateQueryContext in mempool. - [\#606](https://github.com/cosmos/evm/pull/606) Regenerate mock file for bank keeper related test. - [\#609](https://github.com/cosmos/evm/pull/609) Make `erc20Keeper` optional in the EVM keeper diff --git a/rpc/backend/call_tx.go b/rpc/backend/call_tx.go index e444cc9b26..4c4c7b8d23 100644 --- a/rpc/backend/call_tx.go +++ b/rpc/backend/call_tx.go @@ -160,6 +160,25 @@ func (b *Backend) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) { b.Logger.Debug("transaction queued due to nonce gap", "hash", txHash.Hex()) return txHash, nil } + if b.Mempool != nil && strings.Contains(err.Error(), mempool.ErrNonceLow.Error()) { + from, err := ethSigner.Sender(tx) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to get sender address: %w", err) + } + nonce, err := b.getAccountNonce(from, false, b.ClientCtx.Height, b.Logger) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to get sender's current nonce: %w", err) + } + + // SendRawTransaction returns error when tx.Nonce is lower than committed nonce + if tx.Nonce() < nonce { + return common.Hash{}, err + } + + // SendRawTransaction does not return error when committed nonce <= tx.Nonce < pending nonce + return txHash, nil + } + b.Logger.Error("failed to broadcast tx", "error", err.Error()) return txHash, fmt.Errorf("failed to broadcast transaction: %w", err) } diff --git a/tests/systemtests/README.md b/tests/systemtests/README.md new file mode 100644 index 0000000000..d8d9c3c64a --- /dev/null +++ b/tests/systemtests/README.md @@ -0,0 +1,51 @@ +# Getting started with a new system test + +## Overview + +The systemtests suite is an end-to-end test suite that runs the evmd process and sends RPC requests from separate Ethereum/Cosmos clients. The systemtests for cosmos/evm use the `cosmossdk.io/systemtests` package by default. For more details, please refer to https://github.com/cosmos/cosmos-sdk/tree/main/tests/systemtests. + +## Preparation + +Build a new binary from current branch and copy it to the `tests/systemtests/binaries` folder by running system tests. + +```shell +make test-system +``` + +Or via manual steps + +```shell +make build +mkdir -= ./tests/systemtests/binaries +cp ./build/evmd ./tests/systemtests/binaries +cp ./build/evmd ./tests/systemtests/binaries/v0.4 +``` + +## Run Individual test + +### Run test cases for txs ordering + +```shell +go test -p 1 -parallel 1 -mod=readonly -tags='system_test' -v ./... \ +--run TestTxsOrdering --verbose --binary evmd --block-time 5s --chain-id local-4221 +``` + +### Run test cases for txs replacement + +```shell +go test -p 1 -parallel 1 -mod=readonly -tags='system_test' -v ./... \ +--run TestTxsReplacement --verbose --binary evmd --block-time 5s --chain-id local-4221 +``` + +### Run test exceptions + +```shell +go test -p 1 -parallel 1 -mod=readonly -tags='system_test' -v ./... \ +--run TestExceptions --verbose --binary evmd --block-time 5s --chain-id local-4221 +``` + +## Run Entire test + +```shell +make test +``` diff --git a/tests/systemtests/clients/config.go b/tests/systemtests/clients/config.go new file mode 100644 index 0000000000..dec6081c22 --- /dev/null +++ b/tests/systemtests/clients/config.go @@ -0,0 +1,75 @@ +package clients + +import ( + "fmt" + "math/big" +) + +/** +# ---------------- dev mnemonics source ---------------- +# dev0 address 0xC6Fe5D33615a1C52c08018c47E8Bc53646A0E101 | cosmos1cml96vmptgw99syqrrz8az79xer2pcgp84pdun +# dev0's private key: 0x88cbead91aee890d27bf06e003ade3d4e952427e88f88d31d61d3ef5e5d54305 # gitleaks:allow + +# dev1 address 0x963EBDf2e1f8DB8707D05FC75bfeFFBa1B5BaC17 | cosmos1jcltmuhplrdcwp7stlr4hlhlhgd4htqh3a79sq +# dev1's private key: 0x741de4f8988ea941d3ff0287911ca4074e62b7d45c991a51186455366f10b544 # gitleaks:allow + +# dev2 address 0x40a0cb1C63e026A81B55EE1308586E21eec1eFa9 | cosmos1gzsvk8rruqn2sx64acfsskrwy8hvrmafqkaze8 +# dev2's private key: 0x3b7955d25189c99a7468192fcbc6429205c158834053ebe3f78f4512ab432db9 # gitleaks:allow + +# dev3 address 0x498B5AeC5D439b733dC2F58AB489783A23FB26dA | cosmos1fx944mzagwdhx0wz7k9tfztc8g3lkfk6rrgv6l +# dev3's private key: 0x8a36c69d940a92fcea94b36d0f2928c7a0ee19a90073eda769693298dfa9603b # gitleaks:allow +*/ + +const ( + ChainID = "local-4221" + EVMChainID = "262144" + + Acc0PrivKey = "88cbead91aee890d27bf06e003ade3d4e952427e88f88d31d61d3ef5e5d54305" + Acc1PrivKey = "741de4f8988ea941d3ff0287911ca4074e62b7d45c991a51186455366f10b544" + Acc2PrivKey = "3b7955d25189c99a7468192fcbc6429205c158834053ebe3f78f4512ab432db9" + Acc3PrivKey = "8a36c69d940a92fcea94b36d0f2928c7a0ee19a90073eda769693298dfa9603b" + + JsonRPCUrl0 = "http://127.0.0.1:8545" + JsonRPCUrl1 = "http://127.0.0.1:8555" + JsonRPCUrl2 = "http://127.0.0.1:8565" + JsonRPCUrl3 = "http://127.0.0.1:8575" + + NodeRPCUrl0 = "http://127.0.0.1:26657" + NodeRPCUrl1 = "http://127.0.0.1:26658" + NodeRPCUrl2 = "http://127.0.0.1:26659" + NodeRPCUrl3 = "http://127.0.0.1:26660" +) + +type Config struct { + ChainID string + EVMChainID *big.Int + PrivKeys []string + JsonRPCUrls []string + NodeRPCUrls []string +} + +// NewConfig creates a new Config instance. +func NewConfig() (*Config, error) { + // evm chainID + evmChainID, ok := new(big.Int).SetString(EVMChainID, 10) + if !ok { + return nil, fmt.Errorf("error whilte setting chain id") + } + + // private keys of test accounts + privKeys := []string{Acc0PrivKey, Acc1PrivKey, Acc2PrivKey, Acc3PrivKey} + + // jsonrpc urls of testnet nodes + jsonRPCUrls := []string{JsonRPCUrl0, JsonRPCUrl1, JsonRPCUrl2, JsonRPCUrl3} + + // rpc urls of test nodes + nodeRPCUrls := []string{NodeRPCUrl0, NodeRPCUrl1, NodeRPCUrl2, NodeRPCUrl3} + + return &Config{ + ChainID: ChainID, + EVMChainID: evmChainID, + PrivKeys: privKeys, + JsonRPCUrls: jsonRPCUrls, + NodeRPCUrls: nodeRPCUrls, + }, nil +} diff --git a/tests/systemtests/clients/cosmosclient.go b/tests/systemtests/clients/cosmosclient.go new file mode 100644 index 0000000000..56db64e202 --- /dev/null +++ b/tests/systemtests/clients/cosmosclient.go @@ -0,0 +1,265 @@ +package clients + +import ( + "context" + "encoding/hex" + "fmt" + "math/big" + "slices" + "time" + + "github.com/ethereum/go-ethereum/crypto" + + "github.com/cosmos/evm/crypto/ethsecp256k1" + + rpchttp "github.com/cometbft/cometbft/v2/rpc/client/http" + coretypes "github.com/cometbft/cometbft/v2/rpc/core/types" + + sdkmath "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + clienttx "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/std" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/cosmos/cosmos-sdk/x/auth/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// CosmosClient is a client for interacting with Cosmos SDK-based nodes. +type CosmosClient struct { + ChainID string + ClientCtx client.Context + RpcClients map[string]*rpchttp.HTTP + Accs map[string]*CosmosAccount +} + +// NewCosmosClient creates a new CosmosClient instance. +func NewCosmosClient() (*CosmosClient, error) { + config, err := NewConfig() + if err != nil { + return nil, fmt.Errorf("failed to load config") + } + + clientCtx, err := newClientContext(config) + if err != nil { + return nil, fmt.Errorf("failed to create client context: %v", err) + } + + rpcClients := make(map[string]*rpchttp.HTTP, 0) + for i, nodeUrl := range config.NodeRPCUrls { + rpcClient, err := client.NewClientFromNode(nodeUrl) + if err != nil { + return nil, fmt.Errorf("failed to connect rpc server: %v", err) + } + + rpcClients[fmt.Sprintf("node%v", i)] = rpcClient + } + + accs := make(map[string]*CosmosAccount, 0) + for i, privKeyHex := range config.PrivKeys { + priv, err := crypto.HexToECDSA(privKeyHex) + + privKey := ðsecp256k1.PrivKey{Key: crypto.FromECDSA(priv)} + addr := sdk.AccAddress(privKey.PubKey().Address().Bytes()) + + if err != nil { + return nil, err + } + acc := &CosmosAccount{ + AccAddress: addr, + AccountNumber: uint64(i + 1), + PrivKey: privKey, + } + accs[fmt.Sprintf("acc%v", i)] = acc + } + + return &CosmosClient{ + ChainID: config.ChainID, + ClientCtx: *clientCtx, + RpcClients: rpcClients, + Accs: accs, + }, nil +} + +// BankSend sends a bank send transaction from one account to another. +func (c *CosmosClient) BankSend(nodeID, accID string, from, to sdk.AccAddress, amount sdkmath.Int, nonce uint64, gasPrice *big.Int) (*sdk.TxResponse, error) { + c.ClientCtx = c.ClientCtx.WithClient(c.RpcClients[nodeID]) + + privKey := c.Accs[accID].PrivKey + accountNumber := c.Accs[accID].AccountNumber + + msg := banktypes.NewMsgSend(from, to, sdk.NewCoins(sdk.NewCoin("atest", amount))) + + txBytes, err := c.signMsgsV2(privKey, accountNumber, nonce, gasPrice, msg) + if err != nil { + return nil, fmt.Errorf("failed to sign tx msg: %v", err) + } + + resp, err := c.ClientCtx.BroadcastTx(txBytes) + if err != nil { + return nil, fmt.Errorf("failed to broadcast tx: %v", err) + } + + return resp, nil +} + +// WaitForCommit waits for a transaction to be committed in a block. +func (c *CosmosClient) WaitForCommit( + nodeID string, + txHash string, + timeout time.Duration, +) (*coretypes.ResultTx, error) { + c.ClientCtx = c.ClientCtx.WithClient(c.RpcClients[nodeID]) + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + hashBytes, err := hex.DecodeString(txHash) + if err != nil { + return nil, fmt.Errorf("invalid tx hash format: %v", err) + } + + for { + select { + case <-ctx.Done(): + return nil, fmt.Errorf("timeout waiting for transaction %s", txHash) + case <-ticker.C: + result, err := c.ClientCtx.Client.Tx(ctx, hashBytes, false) + if err != nil { + continue + } + + return result, nil + } + } +} + +// CheckTxsPending checks if a transaction is either pending in the mempool or already committed. +func (c *CosmosClient) CheckTxsPending( + nodeID string, + txHash string, + timeout time.Duration, +) error { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("timeout waiting for transaction %s", txHash) + case <-ticker.C: + result, err := c.UnconfirmedTxs(nodeID) + if err != nil { + return fmt.Errorf("failed to call unconfired transactions from cosmos client: %v", err) + } + + pendingTxHashes := make([]string, 0) + for _, tx := range result.Txs { + pendingTxHashes = append(pendingTxHashes, tx.Hash().String()) + } + + if ok := slices.Contains(pendingTxHashes, txHash); ok { + return nil + } + } + } +} + +// UnconfirmedTxs retrieves the list of unconfirmed transactions from the node's mempool. +func (c *CosmosClient) UnconfirmedTxs(nodeID string) (*coretypes.ResultUnconfirmedTxs, error) { + return c.RpcClients[nodeID].UnconfirmedTxs(context.Background(), nil) +} + +// newClientContext creates a new client context for the Cosmos SDK. +func newClientContext(config *Config) (*client.Context, error) { + // Create codec and tx config + interfaceRegistry := types.NewInterfaceRegistry() + std.RegisterInterfaces(interfaceRegistry) + marshaler := codec.NewProtoCodec(interfaceRegistry) + txConfig := tx.NewTxConfig(marshaler, tx.DefaultSignModes) + + // Create client context + clientCtx := client.Context{ + BroadcastMode: flags.BroadcastSync, + TxConfig: txConfig, + Codec: marshaler, + InterfaceRegistry: interfaceRegistry, + ChainID: config.ChainID, + AccountRetriever: authtypes.AccountRetriever{}, + } + + return &clientCtx, nil +} + +// signMsgsV2 signs the provided messages using the given private key and returns the signed transaction bytes. +func (c *CosmosClient) signMsgsV2(privKey cryptotypes.PrivKey, accountNumber, sequence uint64, gasPrice *big.Int, msg sdk.Msg) ([]byte, error) { + senderAddr := sdk.AccAddress(privKey.PubKey().Address().Bytes()) + signMode := signing.SignMode_SIGN_MODE_DIRECT + + txBuilder := c.ClientCtx.TxConfig.NewTxBuilder() + txBuilder.SetMsgs(msg) + txBuilder.SetFeePayer(senderAddr) + + signerData := xauthsigning.SignerData{ + Address: senderAddr.String(), + ChainID: c.ChainID, + AccountNumber: accountNumber, + Sequence: sequence, + PubKey: privKey.PubKey(), + } + + sigsV2 := signing.SignatureV2{ + PubKey: privKey.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: signMode, + Signature: nil, + }, + Sequence: sequence, + } + + err := txBuilder.SetSignatures(sigsV2) + if err != nil { + return nil, fmt.Errorf("failed to set empty signatures: %v", err) + } + + txBuilder.SetGasLimit(150_000) + txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("atest", sdkmath.NewIntFromBigInt(gasPrice).MulRaw(150_001)))) + + sigV2, err := clienttx.SignWithPrivKey( + context.Background(), + signMode, + signerData, + txBuilder, + privKey, + c.ClientCtx.TxConfig, + sequence, + ) + if err != nil { + return nil, fmt.Errorf("failed to sign with private key: %v", err) + } + + err = txBuilder.SetSignatures(sigV2) + if err != nil { + return nil, fmt.Errorf("failed to set signatures: %v", err) + } + + txBytes, err := c.ClientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) + if err != nil { + return nil, fmt.Errorf("failed to encode tx: %v", err) + } + + return txBytes, nil +} diff --git a/tests/systemtests/clients/ethclient.go b/tests/systemtests/clients/ethclient.go new file mode 100644 index 0000000000..c084e8b4d8 --- /dev/null +++ b/tests/systemtests/clients/ethclient.go @@ -0,0 +1,184 @@ +package clients + +import ( + "context" + "fmt" + "maps" + "math/big" + "slices" + "time" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" +) + +// EthClient is a client for interacting with Ethereum-compatible nodes. +type EthClient struct { + ChainID *big.Int + Clients map[string]*ethclient.Client + Accs map[string]*EthAccount +} + +// NewEthClient creates a new EthClient instance. +func NewEthClient() (*EthClient, error) { + config, err := NewConfig() + if err != nil { + return nil, fmt.Errorf("failed to load config") + } + + clients := make(map[string]*ethclient.Client, 0) + for i, jsonrpcUrl := range config.JsonRPCUrls { + ethcli, err := ethclient.Dial(jsonrpcUrl) + if err != nil { + return nil, fmt.Errorf("failed to connecting node url: %s", jsonrpcUrl) + } + clients[fmt.Sprintf("node%v", i)] = ethcli + } + + accs := make(map[string]*EthAccount, 0) + for i, privKey := range config.PrivKeys { + ecdsaPrivKey, err := crypto.HexToECDSA(privKey) + if err != nil { + return nil, err + } + address := crypto.PubkeyToAddress(ecdsaPrivKey.PublicKey) + acc := &EthAccount{ + Address: address, + PrivKey: ecdsaPrivKey, + } + accs[fmt.Sprintf("acc%v", i)] = acc + } + + return &EthClient{ + ChainID: config.EVMChainID, + Clients: clients, + Accs: accs, + }, nil +} + +// Setup prepares the context, client, and address for the given node and account IDs. +func (ec *EthClient) Setup(nodeID string, accID string) (context.Context, *ethclient.Client, common.Address) { + return context.Background(), ec.Clients[nodeID], ec.Accs[accID].Address +} + +// SendRawTransaction sends a raw Ethereum transaction to the specified node. +func (ec *EthClient) SendRawTransaction( + nodeID string, + accID string, + tx *ethtypes.Transaction, +) (common.Hash, error) { + ethCli := ec.Clients[nodeID] + privKey := ec.Accs[accID].PrivKey + + signer := ethtypes.NewLondonSigner(ec.ChainID) + signedTx, err := ethtypes.SignTx(tx, signer, privKey) + if err != nil { + return common.Hash{}, err + } + + if err = ethCli.SendTransaction(context.Background(), signedTx); err != nil { + return common.Hash{}, err + } + + return signedTx.Hash(), nil +} + +// WaitForCommit waits for a transaction to be committed in a block. +func (ec *EthClient) WaitForCommit( + nodeID string, + txHash string, + timeout time.Duration, +) (*ethtypes.Receipt, error) { + ethCli := ec.Clients[nodeID] + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return nil, fmt.Errorf("timeout waiting for transaction %s", txHash) + case <-ticker.C: + receipt, err := ethCli.TransactionReceipt(context.Background(), common.HexToHash(txHash)) + if err != nil { + continue // Transaction not mined yet + } + + return receipt, nil + } + } +} + +// CheckTxsPending checks if a transaction is either pending in the mempool or already committed. +func (ec *EthClient) CheckTxsPending( + nodeID string, + txHash string, + timeout time.Duration, +) error { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("timeout waiting for transaction %s", txHash) + case <-ticker.C: + pendingTxs, _, err := ec.TxPoolContent(nodeID) + if err != nil { + return fmt.Errorf("failed to get txpool content") + } + + pendingTxHashes := extractTxHashesSorted(pendingTxs) + + if ok := slices.Contains(pendingTxHashes, txHash); ok { + return nil + } + } + } +} + +// TxPoolContent returns the pending and queued tx hashes in the tx pool of the given node +func (ec *EthClient) TxPoolContent(nodeID string) (map[string]map[string]*EthRPCTransaction, map[string]map[string]*EthRPCTransaction, error) { + ethCli := ec.Clients[nodeID] + + var result TxPoolResult + err := ethCli.Client().Call(&result, "txpool_content") + if err != nil { + return nil, nil, fmt.Errorf("failed to call txpool_content eth api: %v", err) + } + + return result.Pending, result.Queued, nil +} + +// extractTxHashesSorted processes transaction maps in a deterministic order and returns flat slice of tx hashes +func extractTxHashesSorted(txMap map[string]map[string]*EthRPCTransaction) []string { + var result []string + + // Get addresses and sort them for deterministic iteration + addresses := slices.Collect(maps.Keys(txMap)) + slices.Sort(addresses) + + // Process addresses in sorted order + for _, addr := range addresses { + txs := txMap[addr] + + // Sort transactions by nonce for deterministic ordering + nonces := slices.Collect(maps.Keys(txs)) + slices.Sort(nonces) + + // Add transaction hashes to flat result slice + for _, nonce := range nonces { + result = append(result, txs[nonce].Hash.Hex()) + } + } + + return result +} diff --git a/tests/systemtests/clients/types.go b/tests/systemtests/clients/types.go new file mode 100644 index 0000000000..82206eabb6 --- /dev/null +++ b/tests/systemtests/clients/types.go @@ -0,0 +1,29 @@ +package clients + +import ( + "crypto/ecdsa" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/evm/crypto/ethsecp256k1" + "github.com/ethereum/go-ethereum/common" +) + +type EthAccount struct { + Address common.Address + PrivKey *ecdsa.PrivateKey +} + +type CosmosAccount struct { + AccAddress sdk.AccAddress + AccountNumber uint64 + PrivKey *ethsecp256k1.PrivKey +} + +type TxPoolResult struct { + Pending map[string]map[string]*EthRPCTransaction `json:"pending"` + Queued map[string]map[string]*EthRPCTransaction `json:"queued"` +} + +type EthRPCTransaction struct { + Hash common.Hash `json:"hash"` +} diff --git a/tests/systemtests/eth_test.go b/tests/systemtests/eth_test.go index 57b017fb80..d94c242863 100644 --- a/tests/systemtests/eth_test.go +++ b/tests/systemtests/eth_test.go @@ -29,7 +29,14 @@ const ( ) func StartChain(t *testing.T, sut *systemtests.SystemUnderTest) { - sut.StartChain(t, "--json-rpc.api=eth,txpool,personal,net,debug,web3", "--chain-id", "local-4221", "--api.enable=true") + chainID := "--chain-id=local-4221" + apiEnable := "--api.enable=true" + jsonrpcApi := "--json-rpc.api=eth,txpool,personal,net,debug,web3" + jsonrpcAllowUnprotectedTxs := "--json-rpc.allow-unprotected-txs=true" + + args := []string{jsonrpcApi, chainID, apiEnable, jsonrpcAllowUnprotectedTxs} + + sut.StartChain(t, args...) } // cosmos and eth tx with same nonce. @@ -70,39 +77,39 @@ func TestPriorityReplacement(t *testing.T) { wg := sync.WaitGroup{} + var highPrioRes []byte wg.Add(1) - var lowPrioRes []byte go func() { defer wg.Done() var prioErr error - lowPrioRes, prioErr = exec.Command( + highPrioRes, prioErr = exec.Command( "cast", "send", contractAddr, "increment()", "--rpc-url", "http://127.0.0.1:8545", "--private-key", pk, - "--gas-price", "100000000000", + "--gas-price", "100000000000000", + "--priority-gas-price", "100", "--nonce", "2", ).CombinedOutput() - require.Error(t, prioErr) + require.NoError(t, prioErr) }() - var highPrioRes []byte wg.Add(1) + var lowPrioRes []byte go func() { defer wg.Done() var prioErr error - highPrioRes, prioErr = exec.Command( + lowPrioRes, prioErr = exec.Command( "cast", "send", contractAddr, "increment()", "--rpc-url", "http://127.0.0.1:8545", "--private-key", pk, - "--gas-price", "100000000000000", - "--priority-gas-price", "100", + "--gas-price", "99900000000000", "--nonce", "2", ).CombinedOutput() - require.NoError(t, prioErr) + require.Error(t, prioErr) }() // wait a bit to make sure the tx is submitted and waiting in the txpool. @@ -121,9 +128,13 @@ func TestPriorityReplacement(t *testing.T) { wg.Wait() lowPrioReceipt, err := parseReceipt(string(lowPrioRes)) + fmt.Println("DEBUG - lowPrioRes: ", string(lowPrioRes)) + fmt.Println("DEBUG - lowPrioReceipt: ", lowPrioReceipt) require.NoError(t, err) highPrioReceipt, err := parseReceipt(string(highPrioRes)) + fmt.Println("DEBUG - highPrioRes: ", string(highPrioRes)) + fmt.Println("DEBUG - highPrioReceipt: ", highPrioReceipt) require.NoError(t, err) // 1 = success, 0 = failure. diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index 14c227134f..76231a8b26 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -1,11 +1,17 @@ -module github.com/evmos/tests/systemtests +module github.com/cosmos/evm/tests/systemtests go 1.24.4 require ( + cosmossdk.io/math v1.5.3 cosmossdk.io/systemtests v1.3.0 - github.com/ethereum/go-ethereum v1.15.5 + github.com/cometbft/cometbft/v2 v2.0.0-rc1 + github.com/cosmos/cosmos-sdk v0.54.0-rc.1 + github.com/cosmos/evm v0.5.0-rc.0 + github.com/ethereum/go-ethereum v1.15.11 github.com/stretchr/testify v1.10.0 + github.com/test-go/testify v1.1.4 + github.com/tidwall/gjson v1.18.0 ) require ( @@ -14,21 +20,22 @@ require ( cosmossdk.io/core v1.1.0-rc.1 // indirect cosmossdk.io/depinject v1.2.1 // indirect cosmossdk.io/errors v1.0.2 // indirect - cosmossdk.io/log v1.6.0 // indirect - cosmossdk.io/math v1.5.3 // indirect + cosmossdk.io/log v1.6.1 // indirect cosmossdk.io/schema v1.1.0 // indirect cosmossdk.io/store v1.10.0-rc.2 // indirect cosmossdk.io/x/tx v1.2.0-rc.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect - github.com/99designs/keyring v1.2.1 // indirect - github.com/DataDog/datadog-go v3.2.0+incompatible // indirect + github.com/99designs/keyring v1.2.2 // indirect + github.com/DataDog/datadog-go v4.8.3+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.2.0 // indirect github.com/bits-and-blooms/bitset v1.22.0 // indirect - github.com/bytedance/sonic v1.13.2 // indirect - github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/bytedance/sonic v1.14.0 // indirect + github.com/bytedance/sonic/loader v0.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.5 // indirect @@ -38,41 +45,44 @@ require ( github.com/cockroachdb/pebble v1.1.5 // indirect github.com/cockroachdb/redact v1.1.6 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb // indirect + github.com/cometbft/cometbft v0.38.18 // indirect github.com/cometbft/cometbft-db v1.0.4 // indirect github.com/cometbft/cometbft/api v1.1.0-rc1 // indirect - github.com/cometbft/cometbft/v2 v2.0.0-rc1 // indirect - github.com/consensys/bavard v0.1.22 // indirect - github.com/consensys/gnark-crypto v0.14.0 // indirect + github.com/consensys/gnark-crypto v0.18.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.1.3 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect - github.com/cosmos/cosmos-sdk v0.54.0-rc.1 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/gogoproto v1.7.0 // indirect github.com/cosmos/iavl v1.2.6 // indirect github.com/cosmos/ics23/go v0.11.0 // indirect github.com/cosmos/ledger-cosmos-go v0.14.0 // indirect + github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect - github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect github.com/creachadair/tomledit v0.0.28 // indirect - github.com/danieljoos/wincred v1.1.2 // indirect + github.com/danieljoos/wincred v1.2.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect - github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect + github.com/desertbit/timer v1.0.1 // indirect github.com/dgraph-io/badger/v4 v4.6.0 // indirect github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect + github.com/docker/go-connections v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/dvsekhvalnov/jose2go v1.7.0 // indirect github.com/emicklei/dot v1.8.0 // indirect - github.com/ethereum/c-kzg-4844 v1.0.0 // indirect + github.com/ethereum/c-kzg-4844/v2 v2.1.0 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/getsentry/sentry-go v0.33.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.3.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -114,7 +124,6 @@ require ( github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/highwayhash v1.0.3 // indirect - github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect @@ -133,47 +142,51 @@ require ( github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.12.0 // indirect github.com/spf13/cast v1.9.2 // indirect github.com/spf13/cobra v1.9.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/spf13/viper v1.20.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/supranational/blst v0.3.14 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.7.0 // indirect - github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.35.0 // indirect - go.opentelemetry.io/otel/metric v1.35.0 // indirect - go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.opentelemetry.io/otel v1.36.0 // indirect + go.opentelemetry.io/otel/metric v1.36.0 // indirect + go.opentelemetry.io/otel/trace v1.36.0 // indirect go.uber.org/multierr v1.11.0 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/arch v0.17.0 // indirect - golang.org/x/crypto v0.39.0 // indirect + golang.org/x/crypto v0.41.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - golang.org/x/net v0.40.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect - google.golang.org/grpc v1.73.0 // indirect - google.golang.org/protobuf v1.36.6 // indirect + google.golang.org/grpc v1.74.2 // indirect + google.golang.org/protobuf v1.36.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.2 // indirect - nhooyr.io/websocket v1.8.6 // indirect + nhooyr.io/websocket v1.8.11 // indirect pgregory.net/rapid v1.2.0 // indirect - rsc.io/tmplfunc v0.0.3 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) + +replace github.com/cosmos/evm => ../.. diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index 2605a2e4b0..cb2a24f644 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -1,5 +1,22 @@ +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= +cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= +cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= +cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= +cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= +cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= +cloud.google.com/go/compute v1.29.0 h1:Lph6d8oPi38NHkOr6S55Nus/Pbbcp37m/J0ohgKAefs= +cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= +cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= +cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= +cloud.google.com/go/monitoring v1.21.2 h1:FChwVtClH19E7pJ+e0xUhJPGksctZNVOk2UhMmblmdU= +cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU= +cloud.google.com/go/storage v1.49.0 h1:zenOPBOWHCnojRd9aJZAyQXBYqkJkdQS42dxL55CIMw= +cloud.google.com/go/storage v1.49.0/go.mod h1:k1eHhhpLvrPjVGfo0mOUPEJ4Y2+a/Hv5PiwehZI9qGU= cosmossdk.io/api v1.0.0-rc.1 h1:KwZHIMveoeg6YVwvKZxJLp7be5uk6qmnqNAar2tPxVU= cosmossdk.io/api v1.0.0-rc.1/go.mod h1:8YOT+XjVFb9eZJk62YqjFILOm8MlLhbnkC9/jxIYri8= cosmossdk.io/collections v1.3.1 h1:09e+DUId2brWsNOQ4nrk+bprVmMUaDH9xvtZkeqIjVw= @@ -10,8 +27,8 @@ cosmossdk.io/depinject v1.2.1 h1:eD6FxkIjlVaNZT+dXTQuwQTKZrFZ4UrfCq1RKgzyhMw= cosmossdk.io/depinject v1.2.1/go.mod h1:lqQEycz0H2JXqvOgVwTsjEdMI0plswI7p6KX+MVqFOM= cosmossdk.io/errors v1.0.2 h1:wcYiJz08HThbWxd/L4jObeLaLySopyyuUFB5w4AGpCo= cosmossdk.io/errors v1.0.2/go.mod h1:0rjgiHkftRYPj//3DrD6y8hcm40HcPv/dR4R/4efr0k= -cosmossdk.io/log v1.6.0 h1:SJIOmJ059wi1piyRgNRXKXhlDXGqnB5eQwhcZKv2tOk= -cosmossdk.io/log v1.6.0/go.mod h1:5cXXBvfBkR2/BcXmosdCSLXllvgSjphrrDVdfVRmBGM= +cosmossdk.io/log v1.6.1 h1:YXNwAgbDwMEKwDlCdH8vPcoggma48MgZrTQXCfmMBeI= +cosmossdk.io/log v1.6.1/go.mod h1:gMwsWyyDBjpdG9u2avCFdysXqxq28WJapJvu+vF1y+E= cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U= cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ= cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE= @@ -20,23 +37,36 @@ cosmossdk.io/store v1.10.0-rc.2 h1:7ze2UoheVTVMK4ElHtoRhYv8nlUImj34e4yp1yy1bgE= cosmossdk.io/store v1.10.0-rc.2/go.mod h1:3p1IV4EGsULFfeyAcfj7/DBcDsy8d3VlYIEJnhhbP3U= cosmossdk.io/systemtests v1.3.0 h1:VzQ/3njGbxhxWuJTKi0pGQG5yr29FY0PAQgY5IOae4g= cosmossdk.io/systemtests v1.3.0/go.mod h1:WMcQ8geP7axtz6/gCq9za0zGUtUiz5bGtzqJl+0E3Yw= +cosmossdk.io/x/evidence v0.2.0 h1:o72zbmgCM7U0v7z7b0XnMB+NqX0tFamqb1HHkQbhrZ0= +cosmossdk.io/x/evidence v0.2.0/go.mod h1:zx/Xqy+hnGVzkqVuVuvmP9KsO6YCl4SfbAetYi+k+sE= +cosmossdk.io/x/feegrant v0.2.0 h1:oq3WVpoJdxko/XgWmpib63V1mYy9ZQN/1qxDajwGzJ8= +cosmossdk.io/x/feegrant v0.2.0/go.mod h1:9CutZbmhulk/Yo6tQSVD5LG8Lk40ZAQ1OX4d1CODWAE= cosmossdk.io/x/tx v1.2.0-rc.1 h1:AartiA6eiTD9KHmnlj3uG3H8FjyjI0qNkmvmU+p6cJ8= cosmossdk.io/x/tx v1.2.0-rc.1/go.mod h1:UzpMTUmQEFfz+m0E+lhzFIiEhtZCHjScU/NC652DBHI= +cosmossdk.io/x/upgrade v0.2.0 h1:ZHy0xny3wBCSLomyhE06+UmQHWO8cYlVYjfFAJxjz5g= +cosmossdk.io/x/upgrade v0.2.0/go.mod h1:DXDtkvi//TrFyHWSOaeCZGBoiGAE6Rs8/0ABt2pcDD0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= -github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= -github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= +github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= +github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/datadog-go v4.8.3+incompatible h1:fNGaYSuObuQb5nzeTQqowRAd9bpDIRRV4/gUtIBjh8Q= +github.com/DataDog/datadog-go v4.8.3+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 h1:UQ0AhxogsIRZDkElkblfnwjc3IaltCm2HUMvezQaL7s= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 h1:8nn+rsCvTq9axyEh382S0PFLBeaFwNsT43IrPWzctRU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= @@ -67,28 +97,33 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.49.0 h1:g9BkW1fo9GqKfwg2+zCD+TW/D36Ux+vtfJ8guF4AYmY= +github.com/aws/aws-sdk-go v1.49.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E= github.com/bgentry/speakeasy v0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4= github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= -github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= -github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= -github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= +github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= -github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= +github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -118,6 +153,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -136,16 +173,16 @@ github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB8PbJVMX1ouCcSIxvsqKPYM7gs72o0zC76n9g= github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/cometbft/cometbft v0.38.18 h1:1ZHYMdu0S75YxFM13LlPXnOwiIpUW5z9TKMQtTIALpw= +github.com/cometbft/cometbft v0.38.18/go.mod h1:PlOQgf3jQorep+g6oVnJgtP65TJvBJoLiXjGaMdNxBE= github.com/cometbft/cometbft-db v1.0.4 h1:cezb8yx/ZWcF124wqUtAFjAuDksS1y1yXedvtprUFxs= github.com/cometbft/cometbft-db v1.0.4/go.mod h1:M+BtHAGU2XLrpUxo3Nn1nOCcnVCiLM9yx5OuT0u5SCA= github.com/cometbft/cometbft/api v1.1.0-rc1 h1:NdlXfp4wialMwJ+1ds1DBtfysdxErUxg8/AaqgT0ifQ= github.com/cometbft/cometbft/api v1.1.0-rc1/go.mod h1:Ivh6nSCTJPQOyfQo8dgnyu/T88it092sEqSrZSmTQN8= github.com/cometbft/cometbft/v2 v2.0.0-rc1 h1:3QyDHTFzH3a1N6c2jt03kFDCxM/hgUvhzDYBVnPVXY8= github.com/cometbft/cometbft/v2 v2.0.0-rc1/go.mod h1:/ze08eO171CqUqTqAE7FW7ydUJIVkgp6e2svpYvIR3c= -github.com/consensys/bavard v0.1.22 h1:Uw2CGvbXSZWhqK59X0VG/zOjpTFuOMcPLStrp1ihI0A= -github.com/consensys/bavard v0.1.22/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= -github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E= -github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0= +github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= +github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -169,12 +206,17 @@ github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fr github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/iavl v1.2.6 h1:Hs3LndJbkIB+rEvToKJFXZvKo6Vy0Ex1SJ54hhtioIs= github.com/cosmos/iavl v1.2.6/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw= +github.com/cosmos/ibc-go/v10 v10.3.0 h1:w5DkHih8qn15deAeFoTk778WJU+xC1krJ5kDnicfUBc= +github.com/cosmos/ibc-go/v10 v10.3.0/go.mod h1:CthaR7n4d23PJJ7wZHegmNgbVcLXCQql7EwHrAXnMtw= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/ledger-cosmos-go v0.14.0 h1:WfCHricT3rPbkPSVKRH+L4fQGKYHuGOK9Edpel8TYpE= github.com/cosmos/ledger-cosmos-go v0.14.0/go.mod h1:E07xCWSBl3mTGofZ2QnL4cIUzMbbGVyik84QYKbX3RA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/crate-crypto/go-eth-kzg v1.3.0 h1:05GrhASN9kDAidaFJOda6A4BEvgvuXbazXg/0E3OOdI= +github.com/crate-crypto/go-eth-kzg v1.3.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= @@ -183,18 +225,21 @@ github.com/creachadair/tomledit v0.0.28 h1:aQJVwcNTzx4SZ/tSbkyGE69w4YQ6Gn+xhHHKt github.com/creachadair/tomledit v0.0.28/go.mod h1:pqb2HRQi0lMu6MBiUmTk/0XQ+SmPtq2QbUrG+eiLP5w= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= -github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= +github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= -github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= +github.com/desertbit/timer v1.0.1 h1:yRpYNn5Vaaj6QXecdLMPMJsW81JLiI1eokUft5nBmeo= +github.com/desertbit/timer v1.0.1/go.mod h1:htRrYeY5V/t4iu1xCJ5XsQvp4xve8QulXXctAzxqcwE= github.com/dgraph-io/badger/v4 v4.6.0 h1:acOwfOOZ4p1dPRnYzvkVm7rUk2Y21TgPVepCy5dJdFQ= github.com/dgraph-io/badger/v4 v4.6.0/go.mod h1:KSJ5VTuZNC3Sd+YhvVjk2nYua9UZnnTr/SkXvdtiPgI= github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I= @@ -202,15 +247,15 @@ github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4Typ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY= -github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo= +github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -224,11 +269,16 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= +github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= -github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.15.5 h1:Fo2TbBWC61lWVkFw9tsMoHCNX1ndpuaQBRJ8H6xLUPo= -github.com/ethereum/go-ethereum v1.15.5/go.mod h1:1LG2LnMOx2yPRHR/S+xuipXH29vPr6BIH6GElD8N/fo= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/ethereum/c-kzg-4844/v2 v2.1.0 h1:gQropX9YFBhl3g4HYhwE70zq3IHFRgbbNPw0Shwzf5w= +github.com/ethereum/c-kzg-4844/v2 v2.1.0/go.mod h1:TC48kOKjJKPbN7C++qIgt0TJzZ70QznYR7Ob+WXl57E= +github.com/ethereum/go-ethereum v1.15.11 h1:JK73WKeu0WC0O1eyX+mdQAVHUV+UR1a9VB/domDngBU= +github.com/ethereum/go-ethereum v1.15.11/go.mod h1:mf8YiHIb0GR4x4TipcvBUPxJLw1mFdmxzoDi11sDRoI= github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -251,50 +301,51 @@ github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8 github.com/getsentry/sentry-go v0.33.0 h1:YWyDii0KGVov3xOaamOnF0mjOrqSjBqwv48UEzn7QFg= github.com/getsentry/sentry-go v0.33.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= +github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= @@ -305,9 +356,13 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= @@ -347,7 +402,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -358,11 +412,16 @@ github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= +github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= +github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= @@ -388,8 +447,14 @@ github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NM github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter v1.7.8 h1:mshVHx1Fto0/MydBekWan5zUipGq7jO0novchgMmSiY= +github.com/hashicorp/go-getter v1.7.8/go.mod h1:2c6CboOEb9jG6YvmC9xdD+tyAFsrUaJPedwXDGr0TM4= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -403,6 +468,8 @@ github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0U github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -410,6 +477,8 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -425,6 +494,10 @@ github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8 github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -433,6 +506,8 @@ github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0Jr github.com/huandu/skiplist v1.2.1 h1:dTi93MgjwErA/8idWTzIw4Y1kZsMWx35fmI2c8Rij7w= github.com/huandu/skiplist v1.2.1/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -442,9 +517,13 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -455,8 +534,6 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -486,7 +563,6 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -516,29 +592,31 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -580,8 +658,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= -github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY= +github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -613,12 +691,24 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= +github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -676,6 +766,7 @@ github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= @@ -708,10 +799,13 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= +github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -741,6 +835,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDd github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= +github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -760,15 +856,22 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= +github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= +github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= @@ -780,18 +883,26 @@ go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mI go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 h1:PS8wXpbyaDJQ2VDHHncMe9Vct0Zn1fEjpsjrLxGJoSc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -811,6 +922,10 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= +go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU= golang.org/x/arch v0.17.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -821,8 +936,8 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= @@ -868,11 +983,13 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -881,8 +998,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -899,6 +1016,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -925,7 +1043,6 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -934,25 +1051,30 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -979,6 +1101,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.222.0 h1:Aiewy7BKLCuq6cUCeOUrsAlzjXPqBkEeQ/iwGHVQa/4= +google.golang.org/api v0.222.0/go.mod h1:efZia3nXpWELrwMlN5vyQrD4GmJN1Vw0x68Et3r+a9c= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1016,8 +1140,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= +google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1032,8 +1156,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1045,6 +1169,8 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -1069,14 +1195,13 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= +nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= -rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/tests/systemtests/mempool/interface.go b/tests/systemtests/mempool/interface.go new file mode 100644 index 0000000000..87834d2f19 --- /dev/null +++ b/tests/systemtests/mempool/interface.go @@ -0,0 +1,45 @@ +package mempool + +import ( + "math/big" + "testing" + "time" + + "github.com/cosmos/evm/tests/systemtests/suite" +) + +type TestSuite interface { + // Test Lifecycle + BeforeEachCase(t *testing.T) + AfterEachCase(t *testing.T) + AfterEachAction(t *testing.T) + + // Tx + SendTx(t *testing.T, nodeID string, accID string, nonceIdx uint64, gasPrice *big.Int, gasTipCap *big.Int) (*suite.TxInfo, error) + SendEthTx(t *testing.T, nodeID string, accID string, nonceIdx uint64, gasPrice *big.Int, gasTipCap *big.Int) (*suite.TxInfo, error) + SendEthLegacyTx(t *testing.T, nodeID string, accID string, nonceIdx uint64, gasPrice *big.Int) (*suite.TxInfo, error) + SendEthDynamicFeeTx(t *testing.T, nodeID string, accID string, nonceIdx uint64, gasPrice *big.Int, gasTipCap *big.Int) (*suite.TxInfo, error) + SendCosmosTx(t *testing.T, nodeID string, accID string, nonceIdx uint64, gasPrice *big.Int, gasTipCap *big.Int) (*suite.TxInfo, error) + + // Query + BaseFee() *big.Int + BaseFeeX2() *big.Int + WaitForCommit(nodeID string, txHash string, txType string, timeout time.Duration) error + TxPoolContent(nodeID string, txType string) (pendingTxs, queuedTxs []string, err error) + + // Config + GetOptions() *suite.TestOptions + Nodes() []string + Node(idx int) string + Acc(idx int) string + + // Expectation of mempool state + GetExpPendingTxs() []*suite.TxInfo + SetExpPendingTxs(txs ...*suite.TxInfo) + GetExpQueuedTxs() []*suite.TxInfo + SetExpQueuedTxs(txs ...*suite.TxInfo) + PromoteExpTxs(count int) + + // Test Utils + AwaitNBlocks(t *testing.T, n int64, duration ...time.Duration) +} diff --git a/tests/systemtests/mempool/test_exceptions.go b/tests/systemtests/mempool/test_exceptions.go new file mode 100644 index 0000000000..87ec317416 --- /dev/null +++ b/tests/systemtests/mempool/test_exceptions.go @@ -0,0 +1,154 @@ +package mempool + +import ( + "fmt" + "testing" + + "github.com/cosmos/evm/tests/systemtests/suite" + "github.com/test-go/testify/require" +) + +func TestTxRebroadcasting(t *testing.T) { + testCases := []struct { + name string + actions []func(s TestSuite) + bypass bool + }{ + { + name: "ordering of pending txs %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + tx1, err := s.SendTx(t, s.Node(0), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + tx2, err := s.SendTx(t, s.Node(1), "acc0", 1, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + tx3, err := s.SendTx(t, s.Node(2), "acc0", 2, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + // Skip tx4 with nonce 3 + + tx5, err := s.SendTx(t, s.Node(3), "acc0", 4, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + tx6, err := s.SendTx(t, s.Node(0), "acc0", 5, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + // At AfterEachAction hook, we will check expected queued txs are not broadcasted. + s.SetExpPendingTxs(tx1, tx2, tx3) + s.SetExpQueuedTxs(tx5, tx6) + }, + func(s TestSuite) { + // Wait for 3 blocks. + // It is because tx1, tx2, tx3 are sent to different nodes, tx3 needs maximum 3 blocks to be committed. + // e.g. node3 is 1st proposer -> tx3 will tale 1 block to be committed. + // e.g. node3 is 3rd proposer -> tx3 will take 3 blocks to be committed. + s.AwaitNBlocks(t, 3) + + // current nonce is 3. + // so, we should set nonce idx to 0. + nonce3Idx := uint64(0) + + tx4, err := s.SendTx(t, s.Node(2), "acc0", nonce3Idx, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + // At AfterEachAction hook, we will check expected pending txs are broadcasted. + s.SetExpPendingTxs(tx4) + s.PromoteExpTxs(2) + }, + }, + }, + } + + testOptions := []*suite.TestOptions{ + { + Description: "EVM LegacyTx", + TxType: suite.TxTypeEVM, + IsDynamicFeeTx: false, + }, + } + + s := suite.NewSystemTestSuite(t) + s.SetupTest(t) + + for _, to := range testOptions { + s.SetOptions(to) + for _, tc := range testCases { + testName := fmt.Sprintf(tc.name, to.Description) + t.Run(testName, func(t *testing.T) { + if tc.bypass { + return + } + + s.BeforeEachCase(t) + for _, action := range tc.actions { + action(s) + s.AfterEachAction(t) + } + s.AfterEachCase(t) + }) + } + } +} + +func TestMinimumGasPricesZero(t *testing.T) { + testCases := []struct { + name string + actions []func(s TestSuite) + bypass bool + }{ + { + name: "sequencial pending txs %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + tx1, err := s.SendTx(t, s.Node(0), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + tx2, err := s.SendTx(t, s.Node(1), "acc0", 1, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + tx3, err := s.SendTx(t, s.Node(2), "acc0", 2, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx1, tx2, tx3) + }, + }, + }, + } + + testOptions := []*suite.TestOptions{ + { + Description: "EVM LegacyTx", + TxType: suite.TxTypeEVM, + IsDynamicFeeTx: false, + }, + { + Description: "EVM DynamicFeeTx", + TxType: suite.TxTypeEVM, + IsDynamicFeeTx: true, + }, + } + + s := suite.NewSystemTestSuite(t) + s.SetupTest(t, suite.MinimumGasPriceZeroArgs()...) + + for _, to := range testOptions { + s.SetOptions(to) + for _, tc := range testCases { + testName := fmt.Sprintf(tc.name, to.Description) + t.Run(testName, func(t *testing.T) { + if tc.bypass { + return + } + + s.BeforeEachCase(t) + for _, action := range tc.actions { + action(s) + s.AfterEachAction(t) + } + s.AfterEachCase(t) + }) + } + } +} diff --git a/tests/systemtests/mempool/test_ordering.go b/tests/systemtests/mempool/test_ordering.go new file mode 100644 index 0000000000..4e92bc01cb --- /dev/null +++ b/tests/systemtests/mempool/test_ordering.go @@ -0,0 +1,82 @@ +package mempool + +import ( + "fmt" + "math/big" + "testing" + + "github.com/cosmos/evm/tests/systemtests/suite" + "github.com/test-go/testify/require" +) + +func TestTxsOrdering(t *testing.T) { + testCases := []struct { + name string + actions []func(s TestSuite) + bypass bool + }{ + { + name: "ordering of pending txs %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + expPendingTxs := make([]*suite.TxInfo, 5) + for i := 0; i < 5; i++ { + // nonce order of submitted txs: 3,4,0,1,2 + nonceIdx := uint64((i + 3) % 5) + + // For cosmos tx, we should send tx to one node. + // Because cosmos pool does not manage queued txs. + nodeId := "node0" + if s.GetOptions().TxType == suite.TxTypeEVM { + // target node order of submitted txs: 0,1,2,3,0 + nodeId = s.Node(i % 4) + } + + txInfo, err := s.SendTx(t, nodeId, "acc0", nonceIdx, s.BaseFee(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + // nonce order of committed txs: 0,1,2,3,4 + expPendingTxs[nonceIdx] = txInfo + } + + s.SetExpPendingTxs(expPendingTxs...) + }, + }, + }, + } + + testOptions := []*suite.TestOptions{ + { + Description: "EVM LegacyTx", + TxType: suite.TxTypeEVM, + IsDynamicFeeTx: false, + }, + { + Description: "EVM DynamicFeeTx", + TxType: suite.TxTypeEVM, + IsDynamicFeeTx: true, + }, + } + + s := suite.NewSystemTestSuite(t) + s.SetupTest(t) + + for _, to := range testOptions { + s.SetOptions(to) + for _, tc := range testCases { + testName := fmt.Sprintf(tc.name, to.Description) + t.Run(testName, func(t *testing.T) { + if tc.bypass { + return + } + + s.BeforeEachCase(t) + for _, action := range tc.actions { + action(s) + s.AfterEachAction(t) + } + s.AfterEachCase(t) + }) + } + } +} diff --git a/tests/systemtests/mempool/test_replacement.go b/tests/systemtests/mempool/test_replacement.go new file mode 100644 index 0000000000..dd53efcd29 --- /dev/null +++ b/tests/systemtests/mempool/test_replacement.go @@ -0,0 +1,425 @@ +package mempool + +import ( + "fmt" + "math/big" + "testing" + + "github.com/cosmos/evm/tests/systemtests/suite" + "github.com/test-go/testify/require" +) + +func TestTxsReplacement(t *testing.T) { + testCases := []struct { + name string + actions []func(s TestSuite) + bypass bool + }{ + { + name: "single pending tx submitted to same nodes %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + _, err := s.SendTx(t, s.Node(0), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx2, err := s.SendTx(t, s.Node(0), "acc0", 0, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx2) + }, + }, + bypass: true, + }, + { + name: "multiple pending txs submitted to same nodes %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + _, err := s.SendTx(t, s.Node(0), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx2, err := s.SendTx(t, s.Node(0), "acc0", 0, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + _, err = s.SendTx(t, s.Node(1), "acc0", 1, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx4, err := s.SendTx(t, s.Node(1), "acc0", 1, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + _, err = s.SendTx(t, s.Node(2), "acc0", 2, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx6, err := s.SendTx(t, s.Node(2), "acc0", 2, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx2, tx4, tx6) + }, + }, + bypass: true, + }, + { + name: "single queued tx %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + _, err := s.SendTx(t, s.Node(0), "acc0", 1, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx2, err := s.SendTx(t, s.Node(0), "acc0", 1, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + s.SetExpQueuedTxs(tx2) + }, + func(s TestSuite) { + txHash, err := s.SendTx(t, s.Node(1), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(txHash) + s.PromoteExpTxs(1) + }, + }, + }, + { + name: "multiple queued txs %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + _, err := s.SendTx(t, s.Node(0), "acc0", 1, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx2, err := s.SendTx(t, s.Node(0), "acc0", 1, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + _, err = s.SendTx(t, s.Node(1), "acc0", 2, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx4, err := s.SendTx(t, s.Node(1), "acc0", 2, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + _, err = s.SendTx(t, s.Node(2), "acc0", 3, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx6, err := s.SendTx(t, s.Node(2), "acc0", 3, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + s.SetExpQueuedTxs(tx2, tx4, tx6) + }, + func(s TestSuite) { + tx, err := s.SendTx(t, s.Node(3), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx) + s.PromoteExpTxs(3) + }, + }, + }, + } + + testOptions := []*suite.TestOptions{ + { + Description: "EVM LegacyTx", + TxType: suite.TxTypeEVM, + IsDynamicFeeTx: false, + }, + { + Description: "EVM DynamicFeeTx", + TxType: suite.TxTypeEVM, + IsDynamicFeeTx: true, + }, + { + Description: "Cosmos LegacyTx", + TxType: suite.TxTypeCosmos, + IsDynamicFeeTx: false, + }, + } + + s := suite.NewSystemTestSuite(t) + s.SetupTest(t) + + for _, to := range testOptions { + s.SetOptions(to) + for _, tc := range testCases { + testName := fmt.Sprintf(tc.name, to.Description) + t.Run(testName, func(t *testing.T) { + if tc.bypass { + return + } + + s.BeforeEachCase(t) + for _, action := range tc.actions { + action(s) + s.AfterEachAction(t) + } + s.AfterEachCase(t) + }) + } + } +} + +func TestMixedTxsReplacementEVMAndCosmos(t *testing.T) { + testCases := []struct { + name string + actions []func(s TestSuite) + bypass bool + }{ + { + name: "single pending tx (low prio evm tx first) %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + _, err := s.SendEthTx(t, s.Node(0), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx2, err := s.SendCosmosTx(t, s.Node(0), "acc0", 0, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx2) + }, + }, + bypass: true, + }, + { + name: "single pending tx (high prio evm tx first) %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + tx1, err := s.SendEthTx(t, s.Node(0), "acc0", 0, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + _, err = s.SendCosmosTx(t, s.Node(0), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx1) + }, + }, + bypass: true, + }, + { + name: "single pending tx (low prio cosmos tx first) %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + _, err := s.SendCosmosTx(t, s.Node(0), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx2, err := s.SendEthTx(t, s.Node(0), "acc0", 0, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx2) + }, + }, + bypass: true, + }, + { + name: "single pending tx (high prio cosmos tx first) %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + tx1, err := s.SendCosmosTx(t, s.Node(0), "acc0", 0, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + _, err = s.SendEthTx(t, s.Node(0), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx1) + }, + }, + bypass: true, + }, + { + name: "single queued tx (low prio evm tx first) %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + tx1, err := s.SendEthTx(t, s.Node(0), "acc0", 1, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + _, err = s.SendCosmosTx(t, s.Node(0), "acc0", 1, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + // CosmosTx is not queued in local mempool + s.SetExpQueuedTxs(tx1) + }, + func(s TestSuite) { + tx3, err := s.SendEthTx(t, s.Node(1), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx3) + s.PromoteExpTxs(1) + }, + }, + }, + { + name: "single queued tx (high prio evm tx first) %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + tx1, err := s.SendEthTx(t, s.Node(0), "acc0", 1, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + _, err = s.SendCosmosTx(t, s.Node(0), "acc0", 1, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + // CosmosTx is not queued in local mempool + s.SetExpQueuedTxs(tx1) + }, + func(s TestSuite) { + tx3, err := s.SendEthTx(t, s.Node(1), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx3) + s.PromoteExpTxs(1) + }, + }, + }, + { + name: "single queued tx (low prio cosmos tx first) %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + _, err := s.SendCosmosTx(t, s.Node(0), "acc0", 1, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + tx2, err := s.SendEthTx(t, s.Node(0), "acc0", 1, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + + // CosmosTx is not queued in local mempool + s.SetExpQueuedTxs(tx2) + }, + func(s TestSuite) { + tx3, err := s.SendEthTx(t, s.Node(1), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx3) + s.PromoteExpTxs(1) + }, + }, + }, + { + name: "single queued tx (high prio cosmos tx first) %s", + actions: []func(s TestSuite){ + func(s TestSuite) { + _, err := s.SendCosmosTx(t, s.Node(0), "acc0", 1, s.BaseFeeX2(), big.NewInt(1)) + require.NoError(t, err, "failed to send tx") + tx2, err := s.SendEthTx(t, s.Node(0), "acc0", 1, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + // CosmosTx is not queued in local mempool + s.SetExpQueuedTxs(tx2) + }, + func(s TestSuite) { + tx3, err := s.SendEthTx(t, s.Node(1), "acc0", 0, s.BaseFee(), nil) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(tx3) + s.PromoteExpTxs(1) + }, + }, + }, + } + + testOptions := []*suite.TestOptions{ + { + Description: "EVM LegacyTx & Cosmos LegacyTx", + }, + { + Description: "EVM DynamicTx & Cosmos LegacyTx", + IsDynamicFeeTx: true, + }, + } + + s := suite.NewSystemTestSuite(t) + s.SetupTest(t) + + for _, to := range testOptions { + s.SetOptions(to) + for _, tc := range testCases { + testName := fmt.Sprintf(tc.name, to.Description) + t.Run(testName, func(t *testing.T) { + if tc.bypass { + return + } + + s.BeforeEachCase(t) + for _, action := range tc.actions { + action(s) + s.AfterEachAction(t) + } + s.AfterEachCase(t) + }) + } + } +} + +func TestMixedTxsReplacementLegacyAndDynamicFee(t *testing.T) { + testCases := []struct { + name string + actions []func(s TestSuite) + bypass bool + }{ + { + name: "dynamic fee tx should not replace legacy tx", + actions: []func(s TestSuite){ + func(s TestSuite) { + tx1, err := s.SendEthLegacyTx(t, s.Node(0), s.Acc(0), 1, s.BaseFee()) + require.NoError(t, err, "failed to send eth legacy tx") + + _, err = s.SendEthDynamicFeeTx(t, s.Node(0), s.Acc(0), 1, s.BaseFeeX2(), big.NewInt(1)) + require.Error(t, err) + require.Contains(t, err.Error(), "replacement transaction underpriced") + + s.SetExpQueuedTxs(tx1) + }, + func(s TestSuite) { + txHash, err := s.SendEthLegacyTx(t, s.Node(0), s.Acc(0), 0, s.BaseFee()) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(txHash) + s.PromoteExpTxs(1) + }, + }, + }, + { + name: "dynamic fee tx should replace legacy tx", + actions: []func(s TestSuite){ + func(s TestSuite) { + _, err := s.SendEthLegacyTx(t, s.Node(0), s.Acc(0), 1, s.BaseFee()) + require.NoError(t, err, "failed to send eth legacy tx") + + tx2, err := s.SendEthDynamicFeeTx(t, s.Node(0), s.Acc(0), 1, + s.BaseFeeX2(), + s.BaseFeeX2(), + ) + require.NoError(t, err) + + s.SetExpQueuedTxs(tx2) + }, + func(s TestSuite) { + txHash, err := s.SendEthLegacyTx(t, s.Node(0), s.Acc(0), 0, s.BaseFee()) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(txHash) + s.PromoteExpTxs(1) + }, + }, + }, + { + name: "legacy should never replace dynamic fee tx", + actions: []func(s TestSuite){ + func(s TestSuite) { + tx1, err := s.SendEthDynamicFeeTx(t, s.Node(0), s.Acc(0), 1, s.BaseFeeX2(), + new(big.Int).Sub(s.BaseFee(), big.NewInt(1))) + require.NoError(t, err) + + _, err = s.SendEthLegacyTx(t, s.Node(0), s.Acc(0), 1, s.BaseFee()) + require.Error(t, err, "failed to send eth legacy tx") + require.Contains(t, err.Error(), "replacement transaction underpriced") + + // Legacy tx cannot replace dynamic fee tx. + s.SetExpQueuedTxs(tx1) + }, + func(s TestSuite) { + txHash, err := s.SendEthLegacyTx(t, s.Node(0), s.Acc(0), 0, s.BaseFee()) + require.NoError(t, err, "failed to send tx") + + s.SetExpPendingTxs(txHash) + s.PromoteExpTxs(1) + }, + }, + }, + } + + s := suite.NewSystemTestSuite(t) + s.SetupTest(t) + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.bypass { + return + } + + s.BeforeEachCase(t) + for _, action := range tc.actions { + action(s) + s.AfterEachAction(t) + } + s.AfterEachCase(t) + }) + } +} diff --git a/tests/systemtests/mempool_test.go b/tests/systemtests/mempool_test.go new file mode 100644 index 0000000000..e342a65fc8 --- /dev/null +++ b/tests/systemtests/mempool_test.go @@ -0,0 +1,24 @@ +//go:build system_test + +package systemtests + +import ( + "testing" + + "github.com/cosmos/evm/tests/systemtests/mempool" +) + +func TestTxsOrdering(t *testing.T) { + mempool.TestTxsOrdering(t) +} + +func TestTxsReplacement(t *testing.T) { + mempool.TestTxsReplacement(t) + mempool.TestMixedTxsReplacementEVMAndCosmos(t) + mempool.TestMixedTxsReplacementLegacyAndDynamicFee(t) +} + +func TestExceptions(t *testing.T) { + mempool.TestTxRebroadcasting(t) + mempool.TestMinimumGasPricesZero(t) +} diff --git a/tests/systemtests/suite/query.go b/tests/systemtests/suite/query.go new file mode 100644 index 0000000000..5b3d885cfc --- /dev/null +++ b/tests/systemtests/suite/query.go @@ -0,0 +1,179 @@ +package suite + +import ( + "fmt" + "maps" + "math/big" + "slices" + "time" + + "github.com/cosmos/evm/tests/systemtests/clients" +) + +// NonceAt returns the account nonce for the given account at the latest block +func (s *SystemTestSuite) NonceAt(nodeID string, accID string) (uint64, error) { + ctx, cli, addr := s.EthClient.Setup(nodeID, accID) + blockNumber, err := s.EthClient.Clients[nodeID].BlockNumber(ctx) + if err != nil { + return uint64(0), fmt.Errorf("failed to get block number from %s: %v", nodeID, err) + } + if int64(blockNumber) < 0 { + return uint64(0), fmt.Errorf("invaid block number %d", blockNumber) + } + return cli.NonceAt(ctx, addr, big.NewInt(int64(blockNumber))) +} + +// GetLatestBaseFee returns the base fee of the latest block +func (s *SystemTestSuite) GetLatestBaseFee(nodeID string) (*big.Int, error) { + ctx, cli, _ := s.EthClient.Setup(nodeID, "acc0") + blockNumber, err := cli.BlockNumber(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get block number from %s: %v", nodeID, err) + } + if int64(blockNumber) < 0 { + return nil, fmt.Errorf("invaid block number %d", blockNumber) + } + + block, err := cli.BlockByNumber(ctx, big.NewInt(int64(blockNumber))) + if err != nil { + return nil, fmt.Errorf("failed to get block from %s: %v", nodeID, err) + } + + if block.BaseFee().Cmp(big.NewInt(0)) <= 0 { + return nil, fmt.Errorf("failed to get block from %s: %v", nodeID, err) + } + + return block.BaseFee(), nil +} + +// BaseFee returns the base fee of the latest block +func (s *SystemTestSuite) WaitForCommit( + nodeID string, + txHash string, + txType string, + timeout time.Duration, +) error { + switch txType { + case TxTypeEVM: + return s.waitForEthCommmit(nodeID, txHash, timeout) + case TxTypeCosmos: + return s.waitForCosmosCommmit(nodeID, txHash, timeout) + default: + return fmt.Errorf("invalid txtype: %s", txType) + } +} + +// waitForEthCommmit waits for the given eth tx to be committed within the timeout duration +func (s *SystemTestSuite) waitForEthCommmit( + nodeID string, + txHash string, + timeout time.Duration, +) error { + receipt, err := s.EthClient.WaitForCommit(nodeID, txHash, timeout) + if err != nil { + return fmt.Errorf("failed to get receipt for tx(%s): %v", txHash, err) + } + + if receipt.Status != 1 { + return fmt.Errorf("tx(%s) is committed but failed: %v", txHash, err) + } + + return nil +} + +// waitForCosmosCommmit waits for the given cosmos tx to be committed within the timeout duration +func (s *SystemTestSuite) waitForCosmosCommmit( + nodeID string, + txHash string, + timeout time.Duration, +) error { + result, err := s.CosmosClient.WaitForCommit(nodeID, txHash, timeout) + if err != nil { + return fmt.Errorf("failed to get receipt for tx(%s): %v", txHash, err) + } + + if result.TxResult.Code != 0 { + return fmt.Errorf("tx(%s) is committed but failed: %v", result.Hash.String(), err) + } + + return nil +} + +// CheckTxsPending checks if the given tx is either pending or committed within the timeout duration +func (s *SystemTestSuite) CheckTxPending( + nodeID string, + txHash string, + txType string, + timeout time.Duration, +) error { + switch txType { + case TxTypeEVM: + return s.EthClient.CheckTxsPending(nodeID, txHash, timeout) + case TxTypeCosmos: + return s.CosmosClient.CheckTxsPending(nodeID, txHash, timeout) + default: + return fmt.Errorf("invalid tx type") + } +} + +// TxPoolContent returns the pending and queued tx hashes in the tx pool of the given node +func (s *SystemTestSuite) TxPoolContent(nodeID string, txType string) (pendingTxs, queuedTxs []string, err error) { + switch txType { + case TxTypeEVM: + return s.ethTxPoolContent(nodeID) + case TxTypeCosmos: + return s.cosmosTxPoolContent(nodeID) + default: + return nil, nil, fmt.Errorf("invalid tx type") + } +} + +// ethTxPoolContent returns the pending and queued tx hashes in the tx pool of the given node +func (s *SystemTestSuite) ethTxPoolContent(nodeID string) (pendingTxHashes, queuedTxHashes []string, err error) { + pendingTxs, queuedTxs, err := s.EthClient.TxPoolContent(nodeID) + if err != nil { + return nil, nil, fmt.Errorf("failed to get txpool content from eth client: %v", err) + } + + return s.extractTxHashesSorted(pendingTxs), s.extractTxHashesSorted(queuedTxs), nil +} + +// cosmosTxPoolContent returns the pending tx hashes in the tx pool of the given node +func (s *SystemTestSuite) cosmosTxPoolContent(nodeID string) (pendingTxHashes, queuedTxHashes []string, err error) { + result, err := s.CosmosClient.UnconfirmedTxs(nodeID) + if err != nil { + return nil, nil, fmt.Errorf("failed to call unconfired transactions from cosmos client: %v", err) + } + + pendingtxHashes := make([]string, 0) + for _, tx := range result.Txs { + pendingtxHashes = append(pendingtxHashes, tx.Hash().String()) + } + + return pendingtxHashes, nil, nil +} + +// extractTxHashesSorted processes transaction maps in a deterministic order and returns flat slice of tx hashes +func (s *SystemTestSuite) extractTxHashesSorted(txMap map[string]map[string]*clients.EthRPCTransaction) []string { + var result []string + + // Get addresses and sort them for deterministic iteration + addresses := slices.Collect(maps.Keys(txMap)) + slices.Sort(addresses) + + // Process addresses in sorted order + for _, addr := range addresses { + txs := txMap[addr] + + // Sort transactions by nonce for deterministic ordering + nonces := slices.Collect(maps.Keys(txs)) + slices.Sort(nonces) + + // Add transaction hashes to flat result slice + for _, nonce := range nonces { + result = append(result, txs[nonce].Hash.Hex()) + } + } + + return result +} diff --git a/tests/systemtests/suite/test_helpers.go b/tests/systemtests/suite/test_helpers.go new file mode 100644 index 0000000000..bdaff5b2c5 --- /dev/null +++ b/tests/systemtests/suite/test_helpers.go @@ -0,0 +1,172 @@ +package suite + +import ( + "fmt" + "math/big" + "slices" + "sync" + "time" +) + +// BaseFee returns the most recently retrieved and stored baseFee. +func (s *SystemTestSuite) BaseFee() *big.Int { + return s.baseFee +} + +// BaseFeeX2 returns the double of the most recently retrieved and stored baseFee. +func (s *SystemTestSuite) BaseFeeX2() *big.Int { + return new(big.Int).Mul(s.baseFee, big.NewInt(2)) +} + +// GetExpPendingTxs returns the expected pending transactions +func (s *SystemTestSuite) GetExpPendingTxs() []*TxInfo { + return s.expPendingTxs +} + +// SetExpPendingTxs sets the expected pending transactions +func (s *SystemTestSuite) SetExpPendingTxs(txs ...*TxInfo) { + s.expPendingTxs = txs +} + +// GetExpQueuedTxs returns the expected queued transactions +func (s *SystemTestSuite) GetExpQueuedTxs() []*TxInfo { + return s.expQueuedTxs +} + +// SetExpQueuedTxs sets the expected queued transactions, filtering out any Cosmos transactions +func (s *SystemTestSuite) SetExpQueuedTxs(txs ...*TxInfo) { + queuedTxs := make([]*TxInfo, 0) + for _, txInfo := range txs { + if txInfo.TxType == TxTypeCosmos { + continue + } + queuedTxs = append(queuedTxs, txInfo) + } + s.expQueuedTxs = queuedTxs +} + +// PromoteExpTxs promotes the given number of expected queued transactions to expected pending transactions +func (s *SystemTestSuite) PromoteExpTxs(count int) { + if count <= 0 || len(s.expQueuedTxs) == 0 { + return + } + + // Ensure we don't try to promote more than available + actualCount := count + if actualCount > len(s.expQueuedTxs) { + actualCount = len(s.expQueuedTxs) + } + + // Pop from expQueuedTxs and push to expPendingTxs + txs := s.expQueuedTxs[:actualCount] + s.expPendingTxs = append(s.expPendingTxs, txs...) + s.expQueuedTxs = s.expQueuedTxs[actualCount:] +} + +// Nodes returns the node IDs in the system under test +func (s *SystemTestSuite) Nodes() []string { + nodes := make([]string, 4) + for i := 0; i < 4; i++ { + nodes[i] = fmt.Sprintf("node%d", i) + } + return nodes +} + +// Node returns the node ID for the given index +func (s *SystemTestSuite) Node(idx int) string { + return fmt.Sprintf("node%d", idx) +} + +// Acc returns the account ID for the given index +func (s *SystemTestSuite) Acc(idx int) string { + return fmt.Sprintf("acc%d", idx) +} + +// GetOptions returns the current test options +func (s *SystemTestSuite) GetOptions() *TestOptions { + return s.options +} + +// SetOptions sets the current test options +func (s *SystemTestSuite) SetOptions(options *TestOptions) { + s.options = options +} + +// CheckTxsPendingAsync verifies that the expected pending transactions are still pending in the mempool. +// The check runs asynchronously because, if done synchronously, the pending transactions +// might be committed before the verification takes place. +func (s *SystemTestSuite) CheckTxsPendingAsync(expPendingTxs []*TxInfo) error { + if len(expPendingTxs) == 0 { + return nil + } + + // Use mutex to ensure thread-safe error collection + var mu sync.Mutex + var errors []error + var wg sync.WaitGroup + + for _, txInfo := range expPendingTxs { + wg.Add(1) + go func(tx *TxInfo) { //nolint:gosec // Concurrency is intentional for parallel tx checking + defer wg.Done() + err := s.CheckTxPending(tx.DstNodeID, tx.TxHash, tx.TxType, time.Second*30) + if err != nil { + mu.Lock() + errors = append(errors, fmt.Errorf("tx %s is not pending or committed: %v", tx.TxHash, err)) + mu.Unlock() + } + }(txInfo) + } + + wg.Wait() + + // Return the first error if any occurred + if len(errors) > 0 { + return fmt.Errorf("failed to check transactions are pending status: %w", errors[0]) + } + + return nil +} + +// CheckTxsQueuedSync verifies that the expected queued transactions are actually queued and not pending in the mempool. +func (s *SystemTestSuite) CheckTxsQueuedSync(expQueuedTxs []*TxInfo) error { + pendingHashes := make([][]string, len(s.Nodes())) + queuedHashes := make([][]string, len(s.Nodes())) + for i := range s.Nodes() { + pending, queued, err := s.TxPoolContent(s.Node(i), TxTypeEVM) + if err != nil { + return fmt.Errorf("failed to call txpool_content api") + } + queuedHashes[i] = queued + pendingHashes[i] = pending + } + + for _, txInfo := range s.GetExpQueuedTxs() { + if txInfo.TxType != TxTypeEVM { + panic("queued txs should be only EVM txs") + } + + for i := range s.Nodes() { + pendingTxHashes := pendingHashes[i] + queuedTxHashes := queuedHashes[i] + + if s.Node(i) == txInfo.DstNodeID { + if ok := slices.Contains(pendingTxHashes, txInfo.TxHash); ok { + return fmt.Errorf("tx %s is pending but actually it should be queued.", txInfo.TxHash) + } + if ok := slices.Contains(queuedTxHashes, txInfo.TxHash); !ok { + return fmt.Errorf("tx %s is not contained in queued txs in mempool", txInfo.TxHash) + } + } else { + if ok := slices.Contains(pendingTxHashes, txInfo.TxHash); ok { + return fmt.Errorf("Locally queued transaction %s is also found in the pending transactions of another node's mempool", txInfo.TxHash) + } + if ok := slices.Contains(queuedTxHashes, txInfo.TxHash); ok { + return fmt.Errorf("Locally queued transaction %s is also found in the queued transactions of another node's mempool", txInfo.TxHash) + } + } + } + } + + return nil +} diff --git a/tests/systemtests/suite/test_suite.go b/tests/systemtests/suite/test_suite.go new file mode 100644 index 0000000000..4f64e42f1c --- /dev/null +++ b/tests/systemtests/suite/test_suite.go @@ -0,0 +1,117 @@ +package suite + +import ( + "math/big" + "testing" + "time" + + "cosmossdk.io/systemtests" + "github.com/cosmos/evm/tests/systemtests/clients" + "github.com/stretchr/testify/require" +) + +// SystemTestSuite implements the TestSuite interface and +// provides methods for managing test lifecycle, +// sending transactions, querying state, +// and managing expected mempool state. +type SystemTestSuite struct { + *systemtests.SystemUnderTest + options *TestOptions + + // Clients + EthClient *clients.EthClient + CosmosClient *clients.CosmosClient + + // Most recently retrieved base fee + baseFee *big.Int + + // Expected transaction hashes + expPendingTxs []*TxInfo + expQueuedTxs []*TxInfo +} + +func NewSystemTestSuite(t *testing.T) *SystemTestSuite { + ethClient, err := clients.NewEthClient() + require.NoError(t, err) + + cosmosClient, err := clients.NewCosmosClient() + require.NoError(t, err) + + return &SystemTestSuite{ + SystemUnderTest: systemtests.Sut, + EthClient: ethClient, + CosmosClient: cosmosClient, + } +} + +// SetupTest initializes the test suite by resetting and starting the chain, then awaiting 2 blocks +func (s *SystemTestSuite) SetupTest(t *testing.T, nodeStartArgs ...string) { + if len(nodeStartArgs) == 0 { + nodeStartArgs = DefaultNodeArgs() + } + + s.ResetChain(t) + s.StartChain(t, nodeStartArgs...) + s.AwaitNBlocks(t, 2) +} + +// BeforeEach resets the expected mempool state and retrieves the current base fee before each test case +func (s *SystemTestSuite) BeforeEachCase(t *testing.T) { + // Reset expected pending/queued transactions + s.SetExpPendingTxs() + s.SetExpQueuedTxs() + + // Get current base fee + currentBaseFee, err := s.GetLatestBaseFee("node0") + require.NoError(t, err) + + s.baseFee = currentBaseFee +} + +// JustAfterEach checks the expected mempool state right after each test case +func (s *SystemTestSuite) AfterEachAction(t *testing.T) { + // Check pending txs exist in mempool or already committed - concurrently + err := s.CheckTxsPendingAsync(s.GetExpPendingTxs()) + require.NoError(t, err) + + // Check queued txs only exist in local mempool (queued txs should be only EVM txs) + err = s.CheckTxsQueuedSync(s.GetExpQueuedTxs()) + require.NoError(t, err) + + // Wait for block commit + s.AwaitNBlocks(t, 1) + + // Get current base fee and set it to suite.baseFee + currentBaseFee, err := s.GetLatestBaseFee("node0") + require.NoError(t, err) + + s.baseFee = currentBaseFee +} + +// AfterEach waits for all expected pending transactions to be committed +func (s *SystemTestSuite) AfterEachCase(t *testing.T) { + // Check all expected pending txs are committed + for _, txInfo := range s.GetExpPendingTxs() { + err := s.WaitForCommit(txInfo.DstNodeID, txInfo.TxHash, txInfo.TxType, time.Second*15) + require.NoError(t, err) + } + + // Check all evm pending txs are cleared in mempool + for i := range s.Nodes() { + pending, _, err := s.TxPoolContent(s.Node(i), TxTypeEVM) + require.NoError(t, err) + + require.Len(t, pending, 0, "pending txs are not cleared in mempool") + } + + // Check all cosmos pending txs are cleared in mempool + for i := range s.Nodes() { + pending, _, err := s.TxPoolContent(s.Node(i), TxTypeCosmos) + require.NoError(t, err) + + require.Len(t, pending, 0, "pending txs are not cleared in mempool") + } + + // Wait for block commit + s.AwaitNBlocks(t, 1) +} diff --git a/tests/systemtests/suite/tx.go b/tests/systemtests/suite/tx.go new file mode 100644 index 0000000000..78a90f13b8 --- /dev/null +++ b/tests/systemtests/suite/tx.go @@ -0,0 +1,128 @@ +package suite + +import ( + "fmt" + "math/big" + "testing" + + sdkmath "cosmossdk.io/math" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +// GetOptions retrieves the current test options. +func (s *SystemTestSuite) SendTx( + t *testing.T, + nodeID string, + accID string, + nonceIdx uint64, + gasPrice *big.Int, + gasTipCap *big.Int, +) (*TxInfo, error) { + options := s.GetOptions() + if options != nil && options.TxType == TxTypeCosmos { + return s.SendCosmosTx(t, nodeID, accID, nonceIdx, gasPrice, nil) + } + return s.SendEthTx(t, nodeID, accID, nonceIdx, gasPrice, gasTipCap) +} + +// SendEthTx sends an Ethereum transaction (either Legacy or Dynamic Fee based on options). +func (s *SystemTestSuite) SendEthTx( + t *testing.T, + nodeID string, + accID string, + nonceIdx uint64, + gasPrice *big.Int, + gasTipCap *big.Int, +) (*TxInfo, error) { + options := s.GetOptions() + if options != nil && options.IsDynamicFeeTx { + return s.SendEthDynamicFeeTx(t, nodeID, accID, nonceIdx, gasPrice, gasTipCap) + } + return s.SendEthLegacyTx(t, nodeID, accID, nonceIdx, gasPrice) +} + +// SendEthLegacyTx sends an Ethereum legacy transaction. +func (s *SystemTestSuite) SendEthLegacyTx( + t *testing.T, + nodeID string, + accID string, + nonceIdx uint64, + gasPrice *big.Int, +) (*TxInfo, error) { + nonce, err := s.NonceAt(nodeID, accID) + if err != nil { + return nil, fmt.Errorf("failed to get current nonce: %v", err) + } + gappedNonce := nonce + nonceIdx + to := s.EthClient.Accs["acc3"].Address + value := big.NewInt(1000) + gasLimit := uint64(50_000) + + tx := ethtypes.NewTransaction(gappedNonce, to, value, gasLimit, gasPrice, nil) + txHash, err := s.EthClient.SendRawTransaction(nodeID, accID, tx) + if err != nil { + return nil, fmt.Errorf("failed to send eth legacy tx: %v", err) + } + + return NewTxInfo(nodeID, txHash.Hex(), TxTypeEVM), nil +} + +// SendEthDynamicFeeTx sends an Ethereum dynamic fee transaction. +func (s *SystemTestSuite) SendEthDynamicFeeTx( + t *testing.T, + nodeID string, + accID string, + nonceIdx uint64, + gasFeeCap *big.Int, + gasTipCap *big.Int, +) (*TxInfo, error) { + nonce, err := s.NonceAt(nodeID, accID) + if err != nil { + return nil, fmt.Errorf("failed to get current nonce: %v", err) + } + gappedNonce := nonce + nonceIdx + + tx := ethtypes.NewTx(ðtypes.DynamicFeeTx{ + ChainID: s.EthClient.ChainID, + Nonce: gappedNonce, + To: &(s.EthClient.Accs["acc3"].Address), + Value: big.NewInt(1000), + Gas: uint64(50_000), + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, + }) + + txHash, err := s.EthClient.SendRawTransaction(nodeID, accID, tx) + if err != nil { + return nil, fmt.Errorf("failed to send eth dynamic fee tx: %v", err) + } + + return NewTxInfo(nodeID, txHash.Hex(), TxTypeEVM), nil +} + +// SendCosmosTx sends a Cosmos transaction. +func (s *SystemTestSuite) SendCosmosTx( + t *testing.T, + nodeID string, + accID string, + nonceIdx uint64, + gasPrice *big.Int, + gasTipCap *big.Int, +) (*TxInfo, error) { + from := s.CosmosClient.Accs[accID].AccAddress + to := s.CosmosClient.Accs["acc3"].AccAddress + amount := sdkmath.NewInt(1000) + + nonce, err := s.NonceAt(nodeID, accID) + if err != nil { + return nil, fmt.Errorf("failed to get current nonce: %v", err) + } + gappedNonce := nonce + nonceIdx + + resp, err := s.CosmosClient.BankSend(nodeID, accID, from, to, amount, gappedNonce, gasPrice) + if err != nil { + return nil, fmt.Errorf("failed to send cosmos bank send tx: %v", err) + } + + return NewTxInfo(nodeID, resp.TxHash, TxTypeCosmos), nil +} diff --git a/tests/systemtests/suite/types.go b/tests/systemtests/suite/types.go new file mode 100644 index 0000000000..ee7e31c3fc --- /dev/null +++ b/tests/systemtests/suite/types.go @@ -0,0 +1,49 @@ +package suite + +const ( + TxTypeEVM = "EVMTx" + TxTypeCosmos = "CosmosTx" + + NodeArgsChainID = "--chain-id=local-4221" + NodeArgsApiEnable = "--api.enable=true" + NodeArgsJsonrpcApi = "--json-rpc.api=eth,txpool,personal,net,debug,web3" + NodeArgsJsonrpcAllowUnprotectedTxs = "--json-rpc.allow-unprotected-txs=true" +) + +// TestOptions defines the options for a test case. +type TestOptions struct { + Description string + TxType string + IsDynamicFeeTx bool +} + +// TxInfo holds information about a transaction. +type TxInfo struct { + DstNodeID string + TxType string + TxHash string +} + +// NewTxInfo creates a new TxInfo instance. +func NewTxInfo(nodeID, txHash, txType string) *TxInfo { + return &TxInfo{ + DstNodeID: nodeID, + TxHash: txHash, + TxType: txType, + } +} + +// DefaultNodeArgs returns the default node arguments for starting the chain. +func DefaultNodeArgs() []string { + return []string{ + NodeArgsJsonrpcApi, + NodeArgsChainID, + NodeArgsApiEnable, + NodeArgsJsonrpcAllowUnprotectedTxs, + } +} + +// MinimumGasPriceZeroArgs returns the node arguments with minimum gas price set to zero. +func MinimumGasPriceZeroArgs() []string { + return append(DefaultNodeArgs(), "--minimum-gas-prices=0stake") +}