From 1f0d8d01383d617764996eb55cee90222d0c4368 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 30 Jul 2024 01:51:38 +0100 Subject: [PATCH 01/21] refactor: remove unused vars. improve error clarity for testnetwork/New --- app/appconst/appconst.go | 6 +++++ app/appconst/consensus_config.go | 29 ++++++++++++++++++++ cmd/ethclient/const.go | 3 --- cmd/nibid/cmd/init.go | 24 ++--------------- cmd/nibid/cmd/root.go | 2 +- eth/eip712/eip712_test.go | 6 ++--- x/common/testutil/testnetwork/network.go | 34 ++++++++++++++++-------- x/common/testutil/testnetwork/util.go | 4 +-- 8 files changed, 66 insertions(+), 42 deletions(-) create mode 100644 app/appconst/consensus_config.go delete mode 100644 cmd/ethclient/const.go diff --git a/app/appconst/appconst.go b/app/appconst/appconst.go index c2c1834c2..e1b3c47ea 100644 --- a/app/appconst/appconst.go +++ b/app/appconst/appconst.go @@ -5,6 +5,8 @@ import ( "fmt" "math/big" "runtime" + + db "github.com/cometbft/cometbft-db" ) const ( @@ -14,6 +16,10 @@ const ( AccountAddressPrefix = "nibi" ) +var ( + DefaultDBBackend db.BackendType = db.PebbleDBBackend +) + // Runtime version vars var ( AppVersion = "" diff --git a/app/appconst/consensus_config.go b/app/appconst/consensus_config.go new file mode 100644 index 000000000..4556112ae --- /dev/null +++ b/app/appconst/consensus_config.go @@ -0,0 +1,29 @@ +package appconst + +import ( + tmcfg "github.com/cometbft/cometbft/config" + "time" +) + +// NewDefaultTendermintConfig returns a consensus "Config" (CometBFT) with new +// default values for the "consensus" and "db_backend" fields to be enforced upon +// node initialization. See the "nibiru/cmd/nibid/cmd/InitCmd" function for more +// information. +func NewDefaultTendermintConfig() *tmcfg.Config { + cfg := tmcfg.DefaultConfig() + + // Overwrite consensus config + ms := func(n time.Duration) time.Duration { + return n * time.Millisecond + } + cfg.Consensus.TimeoutPropose = ms(3_000) + cfg.Consensus.TimeoutProposeDelta = ms(500) + cfg.Consensus.TimeoutPrevote = ms(1_000) + cfg.Consensus.TimeoutPrevoteDelta = ms(500) + cfg.Consensus.TimeoutPrecommit = ms(1_000) + cfg.Consensus.TimeoutPrecommitDelta = ms(500) + cfg.Consensus.TimeoutCommit = ms(1_000) + + cfg.DBBackend = string(DefaultDBBackend) + return cfg +} diff --git a/cmd/ethclient/const.go b/cmd/ethclient/const.go deleted file mode 100644 index b3d7a3038..000000000 --- a/cmd/ethclient/const.go +++ /dev/null @@ -1,3 +0,0 @@ -package ethclient - -const Bech32Prefix = "nibi" diff --git a/cmd/nibid/cmd/init.go b/cmd/nibid/cmd/init.go index cc8295bcf..744fd50f6 100644 --- a/cmd/nibid/cmd/init.go +++ b/cmd/nibid/cmd/init.go @@ -6,9 +6,8 @@ import ( "fmt" "os" "path/filepath" - "time" - db "github.com/cometbft/cometbft-db" + "github.com/NibiruChain/nibiru/app/appconst" tmcfg "github.com/cometbft/cometbft/config" tmcli "github.com/cometbft/cometbft/libs/cli" @@ -38,25 +37,6 @@ const ( FlagDefaultBondDenom = "default-denom" ) -func customTendermintConfig() *tmcfg.Config { - cfg := tmcfg.DefaultConfig() - - // Overwrite consensus config - ms := func(n time.Duration) time.Duration { - return n * time.Millisecond - } - cfg.Consensus.TimeoutPropose = ms(3_000) - cfg.Consensus.TimeoutProposeDelta = ms(500) - cfg.Consensus.TimeoutPrevote = ms(1_000) - cfg.Consensus.TimeoutPrevoteDelta = ms(500) - cfg.Consensus.TimeoutPrecommit = ms(1_000) - cfg.Consensus.TimeoutPrecommitDelta = ms(500) - cfg.Consensus.TimeoutCommit = ms(1_000) - - cfg.DBBackend = string(db.PebbleDBBackend) - return cfg -} - /* InitCmd is a stand-in replacement for genutilcli.InitCmd that overwrites the consensus configutation in the `config.toml` prior to writing it to the disk. @@ -176,7 +156,7 @@ func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command { toPrint := newPrintInfo(config.Moniker, chainID, nodeID, "", appState) - customCfg := customTendermintConfig() + customCfg := appconst.NewDefaultTendermintConfig() config.Consensus = customCfg.Consensus config.DBBackend = customCfg.DBBackend tmcfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config) diff --git a/cmd/nibid/cmd/root.go b/cmd/nibid/cmd/root.go index 5bc620516..f4ca78e60 100644 --- a/cmd/nibid/cmd/root.go +++ b/cmd/nibid/cmd/root.go @@ -76,7 +76,7 @@ func NewRootCmd() (*cobra.Command, app.EncodingConfig) { } customAppTemplate, customAppConfig := srvconfig.AppConfig("unibi") - tmCfg := customTendermintConfig() + tmCfg := appconst.NewDefaultTendermintConfig() return sdkserver.InterceptConfigsPreRunHandler( cmd, diff --git a/eth/eip712/eip712_test.go b/eth/eip712/eip712_test.go index 885f292a5..dd8a44595 100644 --- a/eth/eip712/eip712_test.go +++ b/eth/eip712/eip712_test.go @@ -17,6 +17,7 @@ import ( "github.com/tidwall/gjson" "github.com/tidwall/sjson" + "github.com/NibiruChain/nibiru/app/appconst" "github.com/NibiruChain/nibiru/eth/eip712" "github.com/NibiruChain/nibiru/x/common/testutil" "github.com/NibiruChain/nibiru/x/evm" @@ -27,7 +28,6 @@ import ( "github.com/NibiruChain/nibiru/eth/crypto/ethsecp256k1" "github.com/NibiruChain/nibiru/app" - "github.com/NibiruChain/nibiru/cmd/ethclient" sdktx "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx/signing" @@ -82,7 +82,7 @@ func (suite *EIP712TestSuite) SetupTest() { suite.clientCtx = client.Context{}.WithTxConfig(suite.config.TxConfig) suite.denom = evm.DefaultEVMDenom - sdk.GetConfig().SetBech32PrefixForAccount(ethclient.Bech32Prefix, "") + sdk.GetConfig().SetBech32PrefixForAccount(appconst.AccountAddressPrefix, "") eip712.SetEncodingConfig(suite.config) } @@ -369,7 +369,7 @@ func (suite *EIP712TestSuite) TestEIP712() { AccountNumber: params.accountNumber, Sequence: params.sequence, PubKey: pubKey, - Address: sdk.MustBech32ifyAddressBytes(ethclient.Bech32Prefix, pubKey.Bytes()), + Address: sdk.MustBech32ifyAddressBytes(appconst.AccountAddressPrefix, pubKey.Bytes()), } bz, err := suite.clientCtx.TxConfig.SignModeHandler().GetSignBytes( diff --git a/x/common/testutil/testnetwork/network.go b/x/common/testutil/testnetwork/network.go index 44c1f6ac2..679a95039 100644 --- a/x/common/testutil/testnetwork/network.go +++ b/x/common/testutil/testnetwork/network.go @@ -15,6 +15,7 @@ import ( srvconfig "github.com/cosmos/cosmos-sdk/server/config" "github.com/ethereum/go-ethereum/common" + "github.com/NibiruChain/nibiru/app/appconst" serverconfig "github.com/NibiruChain/nibiru/app/server/config" "github.com/cometbft/cometbft/libs/log" @@ -143,12 +144,20 @@ Example: network, err := testnetwork.New(s.T(), s.T().TempDir(), cfg) s.Require().NoError(err) */ -func New(logger Logger, baseDir string, cfg Config) (*Network, error) { +func New(logger Logger, baseDir string, cfg Config) (network *Network, err error) { // only one caller/test can create and use a network at a time logger.Log("acquiring test network lock") lock.Lock() - network := &Network{ + // This is a `defer` pattern to add behavior that runs in the case that the error is + // non-nil, creating a concise way to add extra information. + defer func() { + if err != nil { + err = fmt.Errorf("error starting test network: %w", err) + } + }() + + network = &Network{ Logger: logger, BaseDir: baseDir, Validators: make([]*Validator, cfg.NumValidators), @@ -180,7 +189,10 @@ func New(logger Logger, baseDir string, cfg Config) (*Network, error) { ctx := server.NewDefaultContext() tmCfg := ctx.Config + tmCfg.Consensus.TimeoutCommit = cfg.TimeoutCommit + defaultTmCfg := appconst.NewDefaultTendermintConfig() + tmCfg.DBBackend = defaultTmCfg.DBBackend // Only allow the first validator to expose an RPC, API and gRPC // server/client due to Tendermint in-process constraints. @@ -196,14 +208,14 @@ func New(logger Logger, baseDir string, cfg Config) (*Network, error) { var err error apiListenAddr, _, err = server.FreeTCPAddr() if err != nil { - return nil, err + return nil, fmt.Errorf("failed to get free TCP address for API: %w", err) } } appCfg.API.Address = apiListenAddr apiURL, err := url.Parse(apiListenAddr) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to parse API listen address: %w", err) } apiAddr = fmt.Sprintf("http://%s:%s", apiURL.Hostname(), apiURL.Port()) @@ -262,12 +274,12 @@ func New(logger Logger, baseDir string, cfg Config) (*Network, error) { err := os.MkdirAll(filepath.Join(nodeDir, "config"), 0o755) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to create node configuration directory: %w", err) } err = os.MkdirAll(clientDir, 0o755) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to create node client directory: %w", err) } tmCfg.SetRoot(nodeDir) @@ -291,7 +303,7 @@ func New(logger Logger, baseDir string, cfg Config) (*Network, error) { nodeID, pubKey, err := genutil.InitializeNodeValidatorFiles(tmCfg) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to initialize node validator files: %w", err) } nodeIDs[valIdx] = nodeID @@ -299,13 +311,13 @@ func New(logger Logger, baseDir string, cfg Config) (*Network, error) { kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, cfg.Codec, cfg.KeyringOptions...) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to create new keyring: %w", err) } keyringAlgos, _ := kb.SupportedAlgorithms() algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to parse signing algorithm: %w", err) } var mnemonic string @@ -429,7 +441,7 @@ func New(logger Logger, baseDir string, cfg Config) (*Network, error) { } } - err := initGenFiles(cfg, genAccounts, genBalances, genFiles) + err = initGenFiles(cfg, genAccounts, genBalances, genFiles) if err != nil { return nil, err } @@ -442,7 +454,7 @@ func New(logger Logger, baseDir string, cfg Config) (*Network, error) { for idx, v := range network.Validators { err := startInProcess(cfg, v) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to start node: %w", err) } logger.Log("started validator", idx) } diff --git a/x/common/testutil/testnetwork/util.go b/x/common/testutil/testnetwork/util.go index 150f623e8..0a092d918 100644 --- a/x/common/testutil/testnetwork/util.go +++ b/x/common/testutil/testnetwork/util.go @@ -69,11 +69,11 @@ func startInProcess(cfg Config, val *Validator) error { logger.With("module", val.Moniker), ) if err != nil { - return err + return fmt.Errorf("failed to construct Node: %w", err) } if err := tmNode.Start(); err != nil { - return err + return fmt.Errorf("failed Node.Start(): %w", err) } val.tmNode = tmNode From 3335463d30b3adb7417c4a42f53a0055067bcd64 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 30 Jul 2024 02:23:33 +0100 Subject: [PATCH 02/21] refactor: use pebbledb as the test db --- app/appconst/appconst.go | 3 ++- app/appconst/consensus_config.go | 3 ++- app/appconst/pebbledb.go | 8 ++++++++ cmd/nibid/cmd/init.go | 3 ++- contrib/make/test.mk | 5 +++-- x/common/testutil/testnetwork/network.go | 6 ++++-- 6 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 app/appconst/pebbledb.go diff --git a/app/appconst/appconst.go b/app/appconst/appconst.go index e1b3c47ea..39b8d0864 100644 --- a/app/appconst/appconst.go +++ b/app/appconst/appconst.go @@ -17,7 +17,8 @@ const ( ) var ( - DefaultDBBackend db.BackendType = db.PebbleDBBackend + DefaultDBBackend db.BackendType = db.PebbleDBBackend + HavePebbleDBBuildTag bool ) // Runtime version vars diff --git a/app/appconst/consensus_config.go b/app/appconst/consensus_config.go index 4556112ae..4291d2672 100644 --- a/app/appconst/consensus_config.go +++ b/app/appconst/consensus_config.go @@ -1,8 +1,9 @@ package appconst import ( - tmcfg "github.com/cometbft/cometbft/config" "time" + + tmcfg "github.com/cometbft/cometbft/config" ) // NewDefaultTendermintConfig returns a consensus "Config" (CometBFT) with new diff --git a/app/appconst/pebbledb.go b/app/appconst/pebbledb.go new file mode 100644 index 000000000..1a0bc1164 --- /dev/null +++ b/app/appconst/pebbledb.go @@ -0,0 +1,8 @@ +//go:build pebbledb +// +build pebbledb + +package appconst + +func init() { + HavePebbleDBBuildTag = true +} diff --git a/cmd/nibid/cmd/init.go b/cmd/nibid/cmd/init.go index 744fd50f6..0f84ec8a4 100644 --- a/cmd/nibid/cmd/init.go +++ b/cmd/nibid/cmd/init.go @@ -7,9 +7,10 @@ import ( "os" "path/filepath" - "github.com/NibiruChain/nibiru/app/appconst" tmcfg "github.com/cometbft/cometbft/config" + "github.com/NibiruChain/nibiru/app/appconst" + tmcli "github.com/cometbft/cometbft/libs/cli" tmrand "github.com/cometbft/cometbft/libs/rand" tmtypes "github.com/cometbft/cometbft/types" diff --git a/contrib/make/test.mk b/contrib/make/test.mk index 84e839a4e..529220445 100644 --- a/contrib/make/test.mk +++ b/contrib/make/test.mk @@ -9,6 +9,7 @@ test-unit: .PHONY: test-coverage-unit test-coverage-unit: go test ./... -short \ + -tags=pebbledb \ -coverprofile=coverage.txt \ -covermode=atomic \ -race @@ -18,10 +19,10 @@ test-coverage-unit: .PHONY: test-coverage-integration test-coverage-integration: go test ./... \ + -tags=pebbledb \ -coverprofile=coverage.txt \ -covermode=atomic \ - -race \ - -v + -race # Require Python3 .PHONY: test-create-test-cases diff --git a/x/common/testutil/testnetwork/network.go b/x/common/testutil/testnetwork/network.go index 679a95039..44a14cc59 100644 --- a/x/common/testutil/testnetwork/network.go +++ b/x/common/testutil/testnetwork/network.go @@ -191,8 +191,10 @@ func New(logger Logger, baseDir string, cfg Config) (network *Network, err error tmCfg := ctx.Config tmCfg.Consensus.TimeoutCommit = cfg.TimeoutCommit - defaultTmCfg := appconst.NewDefaultTendermintConfig() - tmCfg.DBBackend = defaultTmCfg.DBBackend + if appconst.HavePebbleDBBuildTag { + defaultTmCfg := appconst.NewDefaultTendermintConfig() + tmCfg.DBBackend = defaultTmCfg.DBBackend + } // Only allow the first validator to expose an RPC, API and gRPC // server/client due to Tendermint in-process constraints. From e106002fd6bcc4a7970f0027fb92738ee02c915d Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 30 Jul 2024 02:25:34 +0100 Subject: [PATCH 03/21] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cced5ac24..f6d2b78a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -92,6 +92,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#1971](https://github.com/NibiruChain/nibiru/pull/1971) - feat(evm): typed events for contract creation, contract execution and transfer - [#1973](https://github.com/NibiruChain/nibiru/pull/1973) - chore(appconst): Add chain IDs ending in "3" to the "knownEthChainIDMap". This makes it possible to use devnet 3 and testnet 3. - [#1977](https://github.com/NibiruChain/nibiru/pull/1977) - fix(localnet): rolled back change of evm validator address with cosmos derivation path +- [#1979](https://github.com/NibiruChain/nibiru/pull/1979) -refactor(db): use pebbledb as the default db in integration tests #### Dapp modules: perp, spot, oracle, etc From a1c57829ff4f32b51f21b3a917f4c45dca2b2131 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Sun, 4 Aug 2024 04:26:58 +0200 Subject: [PATCH 04/21] refactor(statedb): separate Account and AccountWei to have state objects manipulate in wei units --- x/evm/statedb/state_object.go | 65 ++++++++++++++++++++++++++++------- x/evm/statedb/statedb.go | 10 ++++-- x/evm/statedb/statedb_test.go | 18 ++++++---- 3 files changed, 70 insertions(+), 23 deletions(-) diff --git a/x/evm/statedb/state_object.go b/x/evm/statedb/state_object.go index 39592af7c..828af241d 100644 --- a/x/evm/statedb/state_object.go +++ b/x/evm/statedb/state_object.go @@ -6,25 +6,64 @@ import ( "math/big" "sort" + "github.com/NibiruChain/nibiru/x/evm" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) var emptyCodeHash = crypto.Keccak256(nil) -// Account is the Ethereum consensus representation of accounts. +// Account represents an Ethereum account as viewed by the Auth module state. The +// balance is stored in the smallest native unit (e.g., micronibi or unibi). // These objects are stored in the storage of auth module. type Account struct { - Nonce uint64 - Balance *big.Int + BalanceEvmDenom *big.Int + // Nonce is the number of transactions sent from this account or, for contract accounts, the number of contract-creations made by this account + Nonce uint64 + // CodeHash is the hash of the contract code for this account, or nil if it's not a contract account CodeHash []byte } +// AccountWei represents an Ethereum account as viewed by the EVM. This struct is +// derived from an `Account` but represents balances in wei, which is necessary +// for correct operation within the EVM. The EVM expects and operates on wei +// values, which are 10^12 times larger than the native unibi value due to the +// definition of NIBI as "ether". +type AccountWei struct { + BalanceWei *big.Int + Nonce uint64 + CodeHash []byte +} + +// ToWei converts an Account (native representation) to AccountWei (EVM +// representation). This conversion is necessary when moving from the Cosmos SDK +// context to the EVM context. It multiplies the balance by 10^12 to convert from +// unibi to wei. +func (acc Account) ToWei() AccountWei { + return AccountWei{ + BalanceWei: evm.NativeToWei(acc.BalanceEvmDenom), + Nonce: acc.Nonce, + CodeHash: acc.CodeHash, + } +} + +// ToNative converts an AccountWei (EVM representation) back to an Account +// (native representation). This conversion is necessary when moving from the EVM +// context back to the Cosmos SDK context. It divides the balance by 10^12 to +// convert from wei to unibi. +func (acc AccountWei) ToNative() Account { + return Account{ + BalanceEvmDenom: evm.WeiToNative(acc.BalanceWei), + Nonce: acc.Nonce, + CodeHash: acc.CodeHash, + } +} + // NewEmptyAccount returns an empty account. func NewEmptyAccount() *Account { return &Account{ - Balance: new(big.Int), - CodeHash: emptyCodeHash, + BalanceEvmDenom: new(big.Int), + CodeHash: emptyCodeHash, } } @@ -52,7 +91,7 @@ func (s Storage) SortedKeys() []common.Hash { type stateObject struct { db *StateDB - account Account + account AccountWei code []byte // state storage @@ -68,8 +107,8 @@ type stateObject struct { // newObject creates a state object. func newObject(db *StateDB, address common.Address, account Account) *stateObject { - if account.Balance == nil { - account.Balance = new(big.Int) + if account.BalanceEvmDenom == nil { + account.BalanceEvmDenom = new(big.Int) } if account.CodeHash == nil { account.CodeHash = emptyCodeHash @@ -77,7 +116,7 @@ func newObject(db *StateDB, address common.Address, account Account) *stateObjec return &stateObject{ db: db, address: address, - account: account, + account: account.ToWei(), originStorage: make(Storage), dirtyStorage: make(Storage), } @@ -85,7 +124,7 @@ func newObject(db *StateDB, address common.Address, account Account) *stateObjec // empty returns whether the account is considered empty. func (s *stateObject) empty() bool { - return s.account.Nonce == 0 && s.account.Balance.Sign() == 0 && bytes.Equal(s.account.CodeHash, emptyCodeHash) + return s.account.Nonce == 0 && s.account.BalanceWei.Sign() == 0 && bytes.Equal(s.account.CodeHash, emptyCodeHash) } func (s *stateObject) markSuicided() { @@ -114,13 +153,13 @@ func (s *stateObject) SubBalance(amount *big.Int) { func (s *stateObject) SetBalance(amount *big.Int) { s.db.journal.append(balanceChange{ account: &s.address, - prev: new(big.Int).Set(s.account.Balance), + prev: new(big.Int).Set(s.account.BalanceWei), }) s.setBalance(amount) } func (s *stateObject) setBalance(amount *big.Int) { - s.account.Balance = amount + s.account.BalanceWei = amount } // @@ -188,7 +227,7 @@ func (s *stateObject) CodeHash() []byte { // Balance returns the balance of account func (s *stateObject) Balance() *big.Int { - return s.account.Balance + return s.account.BalanceWei } // Nonce returns the nonce of account diff --git a/x/evm/statedb/statedb.go b/x/evm/statedb/statedb.go index d3a39790a..7be1aab2b 100644 --- a/x/evm/statedb/statedb.go +++ b/x/evm/statedb/statedb.go @@ -217,6 +217,10 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { if account == nil { return nil } + + // Reflect the micronibi (unibi) balance in wei + // weiBalance := account.BalanceWei() + // Insert into the live set obj := newObject(s, addr, *account) s.setStateObject(obj) @@ -263,7 +267,7 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) func (s *StateDB) CreateAccount(addr common.Address) { newObj, prev := s.createObject(addr) if prev != nil { - newObj.setBalance(prev.account.Balance) + newObj.setBalance(prev.account.BalanceWei) } } @@ -349,7 +353,7 @@ func (s *StateDB) Suicide(addr common.Address) bool { prevbalance: new(big.Int).Set(stateObject.Balance()), }) stateObject.markSuicided() - stateObject.account.Balance = new(big.Int) + stateObject.account.BalanceWei = new(big.Int) return true } @@ -457,7 +461,7 @@ func (s *StateDB) Commit() error { if obj.code != nil && obj.dirtyCode { s.keeper.SetCode(s.ctx, obj.CodeHash(), obj.code) } - if err := s.keeper.SetAccount(s.ctx, obj.Address(), obj.account); err != nil { + if err := s.keeper.SetAccount(s.ctx, obj.Address(), obj.account.ToNative()); err != nil { return errorsmod.Wrap(err, "failed to set account") } for _, key := range obj.dirtyStorage.SortedKeys() { diff --git a/x/evm/statedb/statedb_test.go b/x/evm/statedb/statedb_test.go index 21d4ac27e..37a4dd666 100644 --- a/x/evm/statedb/statedb_test.go +++ b/x/evm/statedb/statedb_test.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/suite" + "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" ) @@ -173,15 +174,16 @@ func (suite *StateDBTestSuite) TestBalance() { for _, tc := range testCases { suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() tc.malleate(db) // check dirty state suite.Require().Equal(tc.expBalance, db.GetBalance(address)) suite.Require().NoError(db.Commit()) + // check committed balance too - suite.Require().Equal(tc.expBalance, keeper.accounts[address].account.Balance) + suite.Require().Equal(tc.expBalance, db.GetBalance(address)) }) } } @@ -225,16 +227,18 @@ func (suite *StateDBTestSuite) TestState() { for _, tc := range testCases { suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() tc.malleate(db) suite.Require().NoError(db.Commit()) // check committed states in keeper - suite.Require().Equal(tc.expStates, keeper.accounts[address].states) + for k, v := range tc.expStates { + suite.Equal(v, db.GetState(address, k)) + } // check ForEachStorage - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db = deps.StateDB() collected := CollectContractStorage(db) if len(tc.expStates) > 0 { suite.Require().Equal(tc.expStates, collected) From cd9642b81fb37ef8e1a03941a28485933841fc13 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Sun, 4 Aug 2024 04:27:33 +0200 Subject: [PATCH 05/21] math functions for unibi and wei --- x/evm/const.go | 63 +++++++++++ x/evm/evm_test.go | 65 +++++++++++ x/evm/query.pb.go | 274 +++++++++++++++++++++++++++------------------- 3 files changed, 292 insertions(+), 110 deletions(-) diff --git a/x/evm/const.go b/x/evm/const.go index 360da5b49..1e41138d1 100644 --- a/x/evm/const.go +++ b/x/evm/const.go @@ -2,6 +2,9 @@ package evm import ( + "fmt" + "math/big" + "github.com/NibiruChain/collections" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" gethcommon "github.com/ethereum/go-ethereum/common" @@ -87,3 +90,63 @@ var ( zeroAddr gethcommon.Address evmModuleAddr gethcommon.Address ) + +// NativeToWei converts a "unibi" amount to "wei" units for the EVM. +// +// Micronibi, labeled "unibi", is the base denomination for NIBI. For NIBI to be +// considered "ether" by Ethereum clients, we need to follow the constraint +// equation: 1 NIBI = 10^18 wei. +// +// Since 1 NIBI = 10^6 micronibi = 10^6 unibi, the following is true: +// 10^0 unibi == 10^12 wei +func NativeToWei(evmDenomAmount *big.Int) (weiAmount *big.Int) { + pow10 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil) + return new(big.Int).Mul(evmDenomAmount, pow10) +} + +// WeiToNative converts a "wei" amount to "unibi" units. +// +// Micronibi, labeled "unibi", is the base denomination for NIBI. For NIBI to be +// considered "ether" by Ethereum clients, we need to follow the constraint +// equation: 1 NIBI = 10^18 wei. +// +// Since 1 NIBI = 10^6 micronibi = 10^6 unibi, the following is true: +// 10^0 unibi == 10^12 wei +func WeiToNative(weiAmount *big.Int) (evmDenomAmount *big.Int) { + pow10 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil) + return new(big.Int).Quo(weiAmount, pow10) +} + +// ParseWeiAsMultipleOfMicronibi truncates the given wei amount to the highest +// multiple of 1 micronibi (10^12 wei). It returns the truncated value and an +// error if the input value is too small. +// +// Args: +// - weiInt (*big.Int): The amount of wei to be parsed. +// +// Returns: +// - newWeiInt (*big.Int): The truncated amount of wei, which is a multiple of 1 micronibi. +// - err (error): An error indicating if the input value is within the range +// (1, 10^12) inclusive. +// +// Example: +// +// Input number: 123456789012345678901234567890 +// Parsed number: 123456789012 * 10^12 +func ParseWeiAsMultipleOfMicronibi(weiInt *big.Int) (newWeiInt *big.Int, err error) { + // if "weiValue" is nil, 0, or negative, early return + if weiInt == nil || !(weiInt.Cmp(big.NewInt(0)) > 0) { + return weiInt, nil + } + + // err if weiInt is too small + tenPow12 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil) + if weiInt.Cmp(tenPow12) < 0 { + return weiInt, fmt.Errorf( + "wei amount is too small (%s), cannot transfer less than 1 micronibi. 10^18 wei == 1 NIBI == 10^6 micronibi", weiInt) + } + + // truncate to highest micronibi amount + newWeiInt = NativeToWei(WeiToNative(weiInt)) + return newWeiInt, nil +} diff --git a/x/evm/evm_test.go b/x/evm/evm_test.go index 8da03c1c3..59ae0ba4b 100644 --- a/x/evm/evm_test.go +++ b/x/evm/evm_test.go @@ -2,7 +2,9 @@ package evm_test import ( + "math/big" "strconv" + "strings" "testing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -140,3 +142,66 @@ func (s *TestSuite) TestModuleAddressEVM() { s.Equal(nibiAddr.String(), resp.Address) } } + +func (s *TestSuite) TestWeiConversion() { + { + unibiAmt := big.NewInt(420) + s.Equal( + unibiAmt, + evm.WeiToNative(evm.NativeToWei(unibiAmt)), + "native -> wei -> native should be an identity operation", + ) + + weiAmt := evm.NativeToWei(unibiAmt) + want := "420" + strings.Repeat("0", 12) + s.Equal(weiAmt.String(), want) + } + + tenPow12 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil) + for _, tc := range []struct { + weiAmtIn string + want *big.Int + wantError string + }{ + { + // Input number: 123456789012345678901234567890 + // Parsed number: 123456789012345678 * 10^12 + weiAmtIn: "123456789012345678901234567890", + want: evm.NativeToWei(big.NewInt(123456789012345678)), + wantError: "", + }, + { + weiAmtIn: "123456789012345678901234567890", + want: evm.NativeToWei(big.NewInt(123456789012345678)), + wantError: "", + }, + { + weiAmtIn: "0", + want: big.NewInt(0), + wantError: "", + }, + { + weiAmtIn: "1", + wantError: "cannot transfer less than 1 micronibi.", + }, + { + weiAmtIn: new(big.Int).Sub( + tenPow12, big.NewInt(1), + ).String(), + wantError: "cannot transfer less than 1 micronibi.", + }, + { + weiAmtIn: "500", + wantError: "cannot transfer less than 1 micronibi.", + }, + } { + weiAmtIn, _ := new(big.Int).SetString(tc.weiAmtIn, 10) + got, err := evm.ParseWeiAsMultipleOfMicronibi(weiAmtIn) + if tc.wantError != "" { + s.Require().ErrorContains(err, tc.wantError) + return + } + s.NoError(err) + s.Require().Equal(tc.want.String(), got.String()) + } +} diff --git a/x/evm/query.pb.go b/x/evm/query.pb.go index 3463410a1..609bc55fe 100644 --- a/x/evm/query.pb.go +++ b/x/evm/query.pb.go @@ -77,8 +77,8 @@ var xxx_messageInfo_QueryEthAccountRequest proto.InternalMessageInfo // QueryEthAccountResponse is the response type for the Query/Account RPC method. type QueryEthAccountResponse struct { - // balance is the balance of the EVM denomination. - Balance string `protobuf:"bytes,1,opt,name=balance,proto3" json:"balance,omitempty"` + // balance_wei is the balance of wei (attoether, where NIBI is ether). + BalanceWei string `protobuf:"bytes,1,opt,name=balance_wei,json=balanceWei,proto3" json:"balance_wei,omitempty"` // code_hash is the hex-formatted code bytes from the EOA. CodeHash string `protobuf:"bytes,2,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"` // nonce is the account's sequence number. @@ -118,9 +118,9 @@ func (m *QueryEthAccountResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryEthAccountResponse proto.InternalMessageInfo -func (m *QueryEthAccountResponse) GetBalance() string { +func (m *QueryEthAccountResponse) GetBalanceWei() string { if m != nil { - return m.Balance + return m.BalanceWei } return "" } @@ -390,8 +390,10 @@ var xxx_messageInfo_QueryBalanceRequest proto.InternalMessageInfo // QueryBalanceResponse is the response type for the Query/Balance RPC method. type QueryBalanceResponse struct { - // balance is the balance of the EVM denomination. + // balance is the balance of the EVM denomination Balance string `protobuf:"bytes,1,opt,name=balance,proto3" json:"balance,omitempty"` + // balance is the balance of the EVM denomination in units of wei. + BalanceWei string `protobuf:"bytes,2,opt,name=balance_wei,json=balanceWei,proto3" json:"balance_wei,omitempty"` } func (m *QueryBalanceResponse) Reset() { *m = QueryBalanceResponse{} } @@ -434,6 +436,13 @@ func (m *QueryBalanceResponse) GetBalance() string { return "" } +func (m *QueryBalanceResponse) GetBalanceWei() string { + if m != nil { + return m.BalanceWei + } + return "" +} + // QueryStorageRequest is the request type for the Query/Storage RPC method. type QueryStorageRequest struct { // address is the ethereum hex address to query the storage state for. @@ -1411,104 +1420,106 @@ func init() { func init() { proto.RegisterFile("eth/evm/v1/query.proto", fileDescriptor_ffa36cdc5add14ed) } var fileDescriptor_ffa36cdc5add14ed = []byte{ - // 1550 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0xc6, 0x4e, 0xec, 0x3c, 0xa7, 0x4d, 0x98, 0xa6, 0x4d, 0xb2, 0x4d, 0xec, 0x64, 0x43, - 0x93, 0xb4, 0xb4, 0xbb, 0x4d, 0x40, 0x20, 0x2a, 0x2a, 0xd4, 0x44, 0x69, 0x28, 0xfd, 0xa3, 0x62, - 0x22, 0x0e, 0x20, 0x64, 0x8d, 0xed, 0xc9, 0x7a, 0x15, 0x7b, 0xc7, 0xdd, 0x19, 0x07, 0x87, 0x92, - 0x0b, 0xbd, 0x20, 0x21, 0x44, 0x25, 0xbe, 0x40, 0x4f, 0x7c, 0x05, 0xbe, 0x42, 0x8f, 0x95, 0x10, - 0x12, 0xe2, 0x50, 0x50, 0xcb, 0x81, 0x33, 0x47, 0x4e, 0x68, 0x66, 0x67, 0xbc, 0x6b, 0x7b, 0x9d, - 0x50, 0xfe, 0xdc, 0x38, 0xed, 0xce, 0xcc, 0x7b, 0xef, 0xf7, 0x9b, 0x99, 0x37, 0xef, 0xfd, 0xe0, - 0x0c, 0xe1, 0x35, 0x87, 0xec, 0x37, 0x9c, 0xfd, 0x35, 0xe7, 0x5e, 0x8b, 0x04, 0x07, 0x76, 0x33, - 0xa0, 0x9c, 0x22, 0x20, 0xbc, 0x66, 0x93, 0xfd, 0x86, 0xbd, 0xbf, 0x66, 0x5e, 0xa8, 0x50, 0xd6, - 0xa0, 0xcc, 0x29, 0x63, 0x46, 0x42, 0x23, 0x67, 0x7f, 0xad, 0x4c, 0x38, 0x5e, 0x73, 0x9a, 0xd8, - 0xf5, 0x7c, 0xcc, 0x3d, 0xea, 0x87, 0x7e, 0xe6, 0x54, 0x2c, 0x9e, 0x70, 0x0f, 0x67, 0x4f, 0xc5, - 0x66, 0x79, 0x5b, 0x9b, 0xba, 0xd4, 0xa5, 0xf2, 0xd7, 0x11, 0x7f, 0x6a, 0x76, 0xce, 0xa5, 0xd4, - 0xad, 0x13, 0x07, 0x37, 0x3d, 0x07, 0xfb, 0x3e, 0xe5, 0x32, 0x3a, 0x53, 0xab, 0x05, 0xb5, 0x2a, - 0x47, 0xe5, 0xd6, 0xae, 0xc3, 0xbd, 0x06, 0x61, 0x1c, 0x37, 0x9a, 0xa1, 0x81, 0xf5, 0x16, 0x9c, - 0x79, 0x4f, 0x30, 0xdc, 0xe2, 0xb5, 0x6b, 0x95, 0x0a, 0x6d, 0xf9, 0xbc, 0x48, 0xee, 0xb5, 0x08, - 0xe3, 0x68, 0x06, 0x32, 0xb8, 0x5a, 0x0d, 0x08, 0x63, 0x33, 0xc6, 0x82, 0xb1, 0x3a, 0x56, 0xd4, - 0xc3, 0x2b, 0xd9, 0x2f, 0x1e, 0x15, 0x86, 0x7e, 0x7b, 0x54, 0x18, 0xb2, 0x76, 0x61, 0xba, 0xcf, - 0x9b, 0x35, 0xa9, 0xcf, 0x88, 0x70, 0x2f, 0xe3, 0x3a, 0xf6, 0x2b, 0x44, 0xbb, 0xab, 0x21, 0x3a, - 0x0b, 0x63, 0x15, 0x5a, 0x25, 0xa5, 0x1a, 0x66, 0xb5, 0x99, 0x61, 0xb9, 0x96, 0x15, 0x13, 0xef, - 0x60, 0x56, 0x43, 0x53, 0x30, 0xe2, 0x53, 0xe1, 0x94, 0x5a, 0x30, 0x56, 0xd3, 0xc5, 0x70, 0x60, - 0xbd, 0x0d, 0xb3, 0x12, 0xe7, 0x8e, 0x57, 0xf6, 0x82, 0xd6, 0xdf, 0x20, 0x7a, 0x00, 0x66, 0x52, - 0x80, 0x88, 0x6b, 0x72, 0x04, 0x64, 0x42, 0x96, 0x09, 0x18, 0xc1, 0x68, 0x58, 0x32, 0xea, 0x8c, - 0xd1, 0x39, 0x38, 0x89, 0xc3, 0x40, 0x25, 0xbf, 0xd5, 0x28, 0x93, 0x40, 0x71, 0x3e, 0xa1, 0x66, - 0xef, 0xc8, 0x49, 0xeb, 0x26, 0xcc, 0x49, 0xe8, 0x0f, 0x70, 0xdd, 0xab, 0x62, 0x4e, 0x83, 0x1e, - 0xfa, 0x8b, 0x30, 0x5e, 0xa1, 0x3e, 0x2b, 0x75, 0x33, 0xc8, 0x89, 0xb9, 0x6b, 0x7d, 0xfb, 0xf8, - 0xd2, 0x80, 0xf9, 0x01, 0xd1, 0xd4, 0x5e, 0x56, 0x60, 0x42, 0xb3, 0xea, 0x8e, 0xa8, 0xc9, 0x5e, - 0xfb, 0xf7, 0xb6, 0xf6, 0x26, 0x9c, 0x92, 0x64, 0x36, 0xc2, 0x9b, 0x7d, 0x91, 0x0b, 0xb9, 0x0c, - 0x53, 0xdd, 0xae, 0xc7, 0xa5, 0x8d, 0x75, 0x53, 0x81, 0xbd, 0xcf, 0x69, 0x80, 0xdd, 0xe3, 0xc1, - 0xd0, 0x24, 0xa4, 0xf6, 0xc8, 0x81, 0xca, 0x30, 0xf1, 0x1b, 0x83, 0xbf, 0xa8, 0xe0, 0x3b, 0xc1, - 0x14, 0xfc, 0x14, 0x8c, 0xec, 0xe3, 0x7a, 0x4b, 0x83, 0x87, 0x03, 0xeb, 0x75, 0x98, 0x94, 0xd6, - 0x9b, 0xb4, 0xfa, 0x42, 0x9b, 0x5c, 0x81, 0x97, 0x62, 0x7e, 0x0a, 0x02, 0x41, 0x5a, 0x64, 0xbb, - 0xf4, 0x1a, 0x2f, 0xca, 0x7f, 0xeb, 0x53, 0x40, 0xd2, 0x70, 0xa7, 0x7d, 0x8b, 0xba, 0x4c, 0x43, - 0x20, 0x48, 0xcb, 0x37, 0x12, 0xc6, 0x97, 0xff, 0xe8, 0x3a, 0x40, 0x54, 0x43, 0xe4, 0xde, 0x72, - 0xeb, 0xcb, 0x76, 0x58, 0x70, 0x6c, 0x51, 0x70, 0xec, 0xb0, 0x2a, 0xa9, 0x82, 0x63, 0xdf, 0x8d, - 0x8e, 0xaa, 0x18, 0xf3, 0x8c, 0x91, 0x7c, 0x60, 0xa8, 0x83, 0xd5, 0xe0, 0x8a, 0xe7, 0x12, 0xa4, - 0xeb, 0xd4, 0x15, 0xbb, 0x4b, 0xad, 0xe6, 0xd6, 0x27, 0xec, 0xa8, 0xc0, 0xd9, 0xb7, 0xa8, 0x5b, - 0x94, 0x8b, 0x68, 0x3b, 0x81, 0xce, 0xca, 0xb1, 0x74, 0x42, 0x84, 0x38, 0x1f, 0x6b, 0x4a, 0x9d, - 0xc0, 0x5d, 0x1c, 0xe0, 0x86, 0x3e, 0x01, 0x6b, 0x5b, 0x51, 0xd3, 0xb3, 0x8a, 0xda, 0x65, 0x18, - 0x6d, 0xca, 0x19, 0x79, 0x34, 0xb9, 0x75, 0x14, 0x27, 0x17, 0xda, 0x6e, 0xa4, 0x1f, 0x3f, 0x2d, - 0x0c, 0x15, 0x95, 0x9d, 0xf5, 0x9d, 0x01, 0x27, 0xb7, 0x78, 0x6d, 0x13, 0xd7, 0xeb, 0xb1, 0xd3, - 0xc5, 0x81, 0xcb, 0xf4, 0x3d, 0x88, 0x7f, 0x34, 0x0d, 0x19, 0x17, 0xb3, 0x52, 0x05, 0x37, 0xd5, - 0x93, 0x18, 0x75, 0x31, 0xdb, 0xc4, 0x4d, 0xf4, 0x31, 0x4c, 0x36, 0x03, 0xda, 0xa4, 0x8c, 0x04, - 0x9d, 0x67, 0x25, 0x9e, 0xc4, 0xf8, 0xc6, 0xfa, 0x1f, 0x4f, 0x0b, 0xb6, 0xeb, 0xf1, 0x5a, 0xab, - 0x6c, 0x57, 0x68, 0xc3, 0x51, 0xb5, 0x3f, 0xfc, 0x5c, 0x62, 0xd5, 0x3d, 0x87, 0x1f, 0x34, 0x09, - 0xb3, 0x37, 0xa3, 0xf7, 0x5c, 0x9c, 0xd0, 0xb1, 0xf4, 0x5b, 0x9c, 0x85, 0x6c, 0xa5, 0x86, 0x3d, - 0xbf, 0xe4, 0x55, 0x67, 0xd2, 0x0b, 0xc6, 0x6a, 0xaa, 0x98, 0x91, 0xe3, 0x1b, 0x55, 0x6b, 0x05, - 0x4e, 0x6d, 0x31, 0xee, 0x35, 0x30, 0x27, 0xdb, 0x38, 0x3a, 0x82, 0x49, 0x48, 0xb9, 0x38, 0x24, - 0x9f, 0x2e, 0x8a, 0x5f, 0xeb, 0xf7, 0x94, 0xbe, 0xc7, 0x00, 0x57, 0xc8, 0x4e, 0x5b, 0xef, 0xf3, - 0x15, 0x48, 0x35, 0x98, 0xab, 0x4e, 0x6a, 0x36, 0x7e, 0x52, 0xb7, 0x99, 0xbb, 0xc5, 0x6b, 0x24, - 0x20, 0xad, 0xc6, 0x4e, 0xbb, 0x28, 0xac, 0xd0, 0x15, 0x18, 0xe7, 0xc2, 0xbd, 0x54, 0xa1, 0xfe, - 0xae, 0xe7, 0xca, 0x3d, 0xe6, 0xd6, 0xa7, 0xe3, 0x5e, 0x32, 0xfc, 0xa6, 0x5c, 0x2e, 0xe6, 0x78, - 0x34, 0x40, 0x57, 0x61, 0xbc, 0x19, 0x90, 0x2a, 0xa9, 0x10, 0xc6, 0x68, 0xc0, 0x66, 0xd2, 0x32, - 0x71, 0x8e, 0x40, 0xec, 0x32, 0x17, 0x75, 0xb0, 0x5c, 0xa7, 0x95, 0x3d, 0x5d, 0x71, 0x46, 0xe4, - 0x39, 0xe4, 0xe4, 0x5c, 0x58, 0x6f, 0xd0, 0x3c, 0x40, 0x68, 0x22, 0x9f, 0xc5, 0xa8, 0x7c, 0x16, - 0x63, 0x72, 0x46, 0xf6, 0x8e, 0x4d, 0xbd, 0x2c, 0x9a, 0xdc, 0x4c, 0x46, 0x52, 0x37, 0xed, 0xb0, - 0x03, 0xda, 0xba, 0x03, 0xda, 0x3b, 0xba, 0x03, 0x6e, 0x64, 0x45, 0x8a, 0x3c, 0xfc, 0xb9, 0x60, - 0xa8, 0x20, 0x62, 0x25, 0xf1, 0xa6, 0xb3, 0xff, 0xcd, 0x4d, 0x8f, 0x75, 0xdd, 0x34, 0xb2, 0xe0, - 0x44, 0x48, 0xbf, 0x81, 0xdb, 0x25, 0x71, 0xb9, 0x10, 0x3b, 0x81, 0xdb, 0xb8, 0xbd, 0x8d, 0xd9, - 0xbb, 0xe9, 0xec, 0xf0, 0x64, 0xaa, 0x98, 0xe5, 0xed, 0x92, 0xe7, 0x57, 0x49, 0xdb, 0xba, 0xa0, - 0xea, 0x58, 0xe7, 0xce, 0xa3, 0x22, 0x53, 0xc5, 0x1c, 0xeb, 0xe4, 0x16, 0xff, 0xd6, 0xb7, 0x29, - 0xd5, 0xeb, 0xa5, 0xf1, 0x86, 0x88, 0x1a, 0xcb, 0x11, 0xde, 0xd6, 0x4f, 0xfd, 0xa8, 0x1c, 0xe1, - 0x6d, 0xf6, 0x8f, 0x72, 0xe4, 0xff, 0x4b, 0x3e, 0xfe, 0x92, 0xad, 0x4b, 0x4a, 0x55, 0xc5, 0xef, - 0xe9, 0x88, 0x7b, 0x3d, 0xdd, 0xe9, 0xc2, 0x8c, 0x5c, 0x27, 0xba, 0xda, 0x5b, 0xb7, 0x3a, 0x1d, - 0x56, 0x4d, 0xab, 0x10, 0xaf, 0x41, 0x56, 0x14, 0xe6, 0xd2, 0x2e, 0x51, 0x5d, 0x6e, 0x63, 0xf6, - 0xa7, 0xa7, 0x85, 0xd3, 0xe1, 0x0e, 0x59, 0x75, 0xcf, 0xf6, 0xa8, 0xd3, 0xc0, 0xbc, 0x66, 0xdf, - 0xf0, 0xb9, 0xe8, 0xbe, 0xd2, 0xdb, 0xba, 0x0a, 0x67, 0x65, 0xb4, 0xeb, 0x2d, 0x7f, 0x87, 0xee, - 0x11, 0xff, 0x36, 0x6e, 0x36, 0x3d, 0xdf, 0xd5, 0x09, 0x34, 0x05, 0x23, 0x5c, 0x4c, 0xeb, 0xbe, - 0x29, 0x07, 0xb1, 0x26, 0xf3, 0x91, 0x12, 0x41, 0x7d, 0xee, 0x8a, 0xd4, 0x1a, 0x8c, 0xed, 0xb6, - 0xfc, 0x52, 0x14, 0x23, 0xb7, 0x3e, 0x15, 0x4f, 0x28, 0xed, 0x57, 0xcc, 0xee, 0xaa, 0xbf, 0x28, - 0xf8, 0xfa, 0x0f, 0xe3, 0x30, 0x22, 0xa3, 0xa3, 0x07, 0x06, 0x40, 0xa4, 0x45, 0x91, 0x15, 0x0f, - 0x91, 0x2c, 0x73, 0xcd, 0xa5, 0x23, 0x6d, 0x42, 0x7a, 0xd6, 0xc5, 0xcf, 0xbf, 0xff, 0xf5, 0x9b, - 0xe1, 0x65, 0xf4, 0xb2, 0xe3, 0x4b, 0x01, 0xd9, 0x51, 0xec, 0xbc, 0x56, 0x52, 0x92, 0xc8, 0xb9, - 0xaf, 0x12, 0xe9, 0x10, 0x7d, 0x6d, 0xc0, 0x89, 0x2e, 0xa1, 0x89, 0xce, 0xf5, 0x81, 0x24, 0x29, - 0x59, 0x73, 0xf9, 0x38, 0x33, 0x45, 0xc7, 0x91, 0x74, 0xce, 0xa3, 0x95, 0x1e, 0x3a, 0xe1, 0x28, - 0x81, 0xd1, 0x23, 0x03, 0x26, 0x7b, 0x15, 0x23, 0x5a, 0xed, 0x43, 0x1b, 0x20, 0x51, 0xcd, 0xf3, - 0x7f, 0xc1, 0x52, 0x51, 0x7b, 0x43, 0x52, 0x5b, 0x43, 0x4e, 0x0f, 0xb5, 0x7d, 0xed, 0x10, 0xb1, - 0x8b, 0xab, 0xde, 0x43, 0xf4, 0x09, 0x64, 0x94, 0x16, 0x44, 0x85, 0x3e, 0xb8, 0x6e, 0x81, 0x69, - 0x2e, 0x0c, 0x36, 0x50, 0x34, 0xce, 0x4b, 0x1a, 0x4b, 0x68, 0xb1, 0x87, 0x86, 0x12, 0x93, 0x2c, - 0x76, 0x36, 0x9f, 0x41, 0x46, 0xa9, 0xc0, 0x04, 0xe0, 0x6e, 0xb1, 0x99, 0x00, 0xdc, 0x23, 0x20, - 0x2d, 0x5b, 0x02, 0xaf, 0xa2, 0xe5, 0x1e, 0x60, 0x16, 0xda, 0x45, 0xb8, 0xce, 0xfd, 0x3d, 0x72, - 0x70, 0x88, 0xf6, 0x20, 0x2d, 0xd4, 0x21, 0x9a, 0xeb, 0x8b, 0x1c, 0x13, 0x9b, 0xe6, 0xfc, 0x80, - 0x55, 0x05, 0xba, 0x2c, 0x41, 0x17, 0x50, 0xbe, 0x07, 0x54, 0x68, 0xcb, 0xf8, 0x56, 0x6b, 0x30, - 0x1a, 0xaa, 0x23, 0x94, 0xef, 0x0b, 0xd8, 0x25, 0xbc, 0xcc, 0xc2, 0xc0, 0x75, 0x05, 0x39, 0x2f, - 0x21, 0xa7, 0xd1, 0xe9, 0x1e, 0xc8, 0x50, 0x6f, 0x21, 0x0f, 0x32, 0x4a, 0x6e, 0x21, 0x33, 0x1e, - 0xaa, 0x5b, 0x83, 0x99, 0x8b, 0x83, 0x5b, 0x8d, 0x06, 0x2a, 0x48, 0xa0, 0x59, 0x34, 0x9d, 0xf0, - 0xf4, 0x2a, 0x22, 0x3e, 0x85, 0x5c, 0x4c, 0x20, 0x1d, 0x09, 0xd7, 0xb5, 0xab, 0x04, 0x55, 0x65, - 0x2d, 0x49, 0xb0, 0x79, 0x74, 0xb6, 0x17, 0x4c, 0xd9, 0x8a, 0x8a, 0x8d, 0x1a, 0x90, 0x51, 0xed, - 0x36, 0x21, 0x61, 0xba, 0xc5, 0x57, 0x42, 0xc2, 0xf4, 0x74, 0xea, 0x81, 0xfb, 0x0b, 0x5b, 0x2c, - 0x6f, 0xa3, 0x03, 0x80, 0xa8, 0x11, 0x24, 0x94, 0xb4, 0xbe, 0x6e, 0x9e, 0x50, 0xd2, 0xfa, 0x3b, - 0x89, 0x65, 0x49, 0xdc, 0x39, 0x64, 0x26, 0xe2, 0xca, 0x76, 0x24, 0x76, 0xaa, 0xba, 0x47, 0xe2, - 0x9b, 0x8c, 0xb7, 0x9b, 0xc4, 0x37, 0xd9, 0xd5, 0x78, 0x06, 0xee, 0x54, 0x77, 0x23, 0xf4, 0x95, - 0x01, 0x13, 0x3d, 0x0d, 0x02, 0xad, 0xf4, 0x85, 0x4d, 0xee, 0x40, 0xe6, 0xea, 0xf1, 0x86, 0x8a, - 0xc7, 0x8a, 0xe4, 0xb1, 0x88, 0x0a, 0x3d, 0x3c, 0x76, 0x5b, 0xbe, 0xec, 0x3f, 0xce, 0x7d, 0xf9, - 0x39, 0xdc, 0xb8, 0xfa, 0xf8, 0x59, 0xde, 0x78, 0xf2, 0x2c, 0x6f, 0xfc, 0xf2, 0x2c, 0x6f, 0x3c, - 0x7c, 0x9e, 0x1f, 0x7a, 0xf2, 0x3c, 0x3f, 0xf4, 0xe3, 0xf3, 0xfc, 0xd0, 0x87, 0x4b, 0x31, 0x85, - 0x10, 0x96, 0xe8, 0x4d, 0xd1, 0xdf, 0x75, 0xc0, 0xb6, 0x08, 0x59, 0x1e, 0x95, 0x6a, 0xe4, 0xd5, - 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x68, 0x44, 0xe9, 0x8d, 0x33, 0x12, 0x00, 0x00, + // 1572 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0xcf, 0x6f, 0x1b, 0x45, + 0x1b, 0x8e, 0x63, 0x27, 0x76, 0x5e, 0xa7, 0x4d, 0xbe, 0x69, 0xda, 0x24, 0x6e, 0x62, 0x27, 0x9b, + 0xaf, 0x49, 0xda, 0xaf, 0xdd, 0xfd, 0x12, 0x10, 0x88, 0x8a, 0x0a, 0xd5, 0x51, 0x1a, 0x4a, 0x7f, + 0xa8, 0x35, 0x11, 0x48, 0x20, 0x64, 0x8d, 0xd7, 0x93, 0xf5, 0x2a, 0xde, 0x1d, 0x77, 0x67, 0x9c, + 0x3a, 0x94, 0x5c, 0xe8, 0x05, 0x09, 0x21, 0x2a, 0xf1, 0x0f, 0xf4, 0xc4, 0xbf, 0xc0, 0xbf, 0xd0, + 0x63, 0x25, 0x84, 0x84, 0x38, 0x14, 0xd4, 0x72, 0xe0, 0xcc, 0x91, 0x13, 0x9a, 0xd9, 0x99, 0x78, + 0xbd, 0x5e, 0x27, 0x94, 0x1f, 0x37, 0x4e, 0xbb, 0x33, 0xf3, 0xce, 0xfb, 0x3c, 0xf3, 0xeb, 0x7d, + 0x1e, 0x38, 0x43, 0x78, 0xc3, 0x22, 0x7b, 0x9e, 0xb5, 0xb7, 0x66, 0xdd, 0x6b, 0x93, 0x60, 0xdf, + 0x6c, 0x05, 0x94, 0x53, 0x04, 0x84, 0x37, 0x4c, 0xb2, 0xe7, 0x99, 0x7b, 0x6b, 0x85, 0x0b, 0x36, + 0x65, 0x1e, 0x65, 0x56, 0x0d, 0x33, 0x12, 0x06, 0x59, 0x7b, 0x6b, 0x35, 0xc2, 0xf1, 0x9a, 0xd5, + 0xc2, 0x8e, 0xeb, 0x63, 0xee, 0x52, 0x3f, 0x9c, 0x57, 0x98, 0x8a, 0xe4, 0x13, 0xd3, 0xc3, 0xde, + 0x53, 0x91, 0x5e, 0xde, 0xd1, 0xa1, 0x0e, 0x75, 0xa8, 0xfc, 0xb5, 0xc4, 0x9f, 0xea, 0x9d, 0x73, + 0x28, 0x75, 0x9a, 0xc4, 0xc2, 0x2d, 0xd7, 0xc2, 0xbe, 0x4f, 0xb9, 0xcc, 0xce, 0xd4, 0x68, 0x49, + 0x8d, 0xca, 0x56, 0xad, 0xbd, 0x63, 0x71, 0xd7, 0x23, 0x8c, 0x63, 0xaf, 0x15, 0x06, 0x18, 0x6f, + 0xc2, 0x99, 0xbb, 0x82, 0xe1, 0x26, 0x6f, 0x5c, 0xb5, 0x6d, 0xda, 0xf6, 0x79, 0x85, 0xdc, 0x6b, + 0x13, 0xc6, 0xd1, 0x0c, 0x64, 0x71, 0xbd, 0x1e, 0x10, 0xc6, 0x66, 0x52, 0x0b, 0xa9, 0xd5, 0xb1, + 0x8a, 0x6e, 0x5e, 0xce, 0x7d, 0xf6, 0xb8, 0x34, 0xf4, 0xcb, 0xe3, 0xd2, 0x90, 0xe1, 0xc1, 0x74, + 0xdf, 0x6c, 0xd6, 0xa2, 0x3e, 0x23, 0xa8, 0x04, 0xf9, 0x1a, 0x6e, 0x62, 0xdf, 0x26, 0xd5, 0xfb, + 0xc4, 0x55, 0x29, 0x40, 0x75, 0xbd, 0x4f, 0x5c, 0x74, 0x16, 0xc6, 0x6c, 0x5a, 0x27, 0xd5, 0x06, + 0x66, 0x8d, 0x99, 0x61, 0x39, 0x9c, 0x13, 0x1d, 0x6f, 0x63, 0xd6, 0x40, 0x53, 0x30, 0xe2, 0x53, + 0xdf, 0x26, 0x33, 0xe9, 0x85, 0xd4, 0x6a, 0xa6, 0x12, 0x36, 0x8c, 0xb7, 0x60, 0x56, 0xc2, 0xdd, + 0x76, 0x6b, 0x6e, 0xd0, 0xfe, 0x13, 0x7c, 0xf7, 0xa1, 0x90, 0x94, 0x40, 0x51, 0x1e, 0x98, 0x01, + 0x15, 0x20, 0xc7, 0x04, 0x8c, 0x60, 0x34, 0x2c, 0x19, 0x1d, 0xb6, 0xd1, 0x39, 0x38, 0x89, 0xc3, + 0x44, 0x55, 0xbf, 0xed, 0xd5, 0x48, 0xa0, 0x38, 0x9f, 0x50, 0xbd, 0xb7, 0x65, 0xa7, 0x71, 0x03, + 0xe6, 0x24, 0xf4, 0x7b, 0xb8, 0xe9, 0xd6, 0x31, 0xa7, 0x41, 0x8c, 0xfe, 0x22, 0x8c, 0xdb, 0xd4, + 0x67, 0xd5, 0x5e, 0x06, 0x79, 0xd1, 0x77, 0xb5, 0x6f, 0x1d, 0x9f, 0xa7, 0x60, 0x7e, 0x40, 0x36, + 0xb5, 0x96, 0x15, 0x98, 0xd0, 0xac, 0x7a, 0x33, 0x6a, 0xb2, 0x57, 0xff, 0xbe, 0xa5, 0xbd, 0x01, + 0xa7, 0x24, 0x99, 0x72, 0x78, 0xb8, 0x2f, 0x73, 0x20, 0x77, 0x61, 0xaa, 0x77, 0x6a, 0xf7, 0x28, + 0xd4, 0x55, 0xd1, 0x73, 0x55, 0x33, 0x7e, 0xaf, 0x86, 0xe3, 0xf7, 0xca, 0xb8, 0xa1, 0xd8, 0xbc, + 0xcb, 0x69, 0x80, 0x9d, 0xe3, 0xd9, 0xa0, 0x49, 0x48, 0xef, 0x92, 0x7d, 0x95, 0x49, 0xfc, 0x46, + 0xf8, 0x5d, 0x54, 0xfc, 0x0e, 0x93, 0x29, 0x7e, 0x53, 0x30, 0xb2, 0x87, 0x9b, 0x6d, 0xcd, 0x2e, + 0x6c, 0x18, 0xaf, 0xc1, 0xa4, 0x8c, 0xde, 0xa0, 0xf5, 0x97, 0xda, 0x85, 0x15, 0xf8, 0x4f, 0x64, + 0x9e, 0x82, 0x40, 0x90, 0x11, 0xcf, 0x41, 0xce, 0x1a, 0xaf, 0xc8, 0x7f, 0xe3, 0x63, 0x40, 0x32, + 0x70, 0xbb, 0x73, 0x93, 0x3a, 0x4c, 0x43, 0x20, 0xc8, 0xc8, 0x47, 0x14, 0xe6, 0x97, 0xff, 0xe8, + 0x1a, 0x40, 0xb7, 0xd6, 0xc8, 0xb5, 0xe5, 0xd7, 0x97, 0xcd, 0xb0, 0x30, 0x99, 0xa2, 0x30, 0x99, + 0x61, 0xf5, 0x52, 0x85, 0xc9, 0xbc, 0xd3, 0xdd, 0xaa, 0x4a, 0x64, 0x66, 0x84, 0xe4, 0xc3, 0x94, + 0xda, 0x58, 0x0d, 0xae, 0x78, 0x2e, 0x41, 0xa6, 0x49, 0x1d, 0xb1, 0xba, 0xf4, 0x6a, 0x7e, 0x7d, + 0xc2, 0xec, 0x16, 0x42, 0xf3, 0x26, 0x75, 0x2a, 0x72, 0x10, 0x6d, 0x25, 0xd0, 0x59, 0x39, 0x96, + 0x4e, 0x88, 0x10, 0xe5, 0x63, 0x4c, 0xa9, 0x1d, 0xb8, 0x83, 0x03, 0xec, 0xe9, 0x1d, 0x30, 0xb6, + 0x14, 0x35, 0xdd, 0xab, 0xa8, 0xfd, 0x1f, 0x46, 0x5b, 0xb2, 0x47, 0x6e, 0x4d, 0x7e, 0x1d, 0x45, + 0xc9, 0x85, 0xb1, 0xe5, 0xcc, 0x93, 0x67, 0xa5, 0xa1, 0x8a, 0x8a, 0x33, 0xbe, 0x49, 0xc1, 0xc9, + 0x4d, 0xde, 0xd8, 0xc0, 0xcd, 0x66, 0x64, 0x77, 0x71, 0xe0, 0x30, 0x7d, 0x0e, 0xe2, 0x1f, 0x4d, + 0x43, 0xd6, 0xc1, 0xac, 0x6a, 0xe3, 0x96, 0x7a, 0x33, 0xa3, 0x0e, 0x66, 0x1b, 0xb8, 0x85, 0x3e, + 0x82, 0xc9, 0x56, 0x40, 0x5b, 0x94, 0x91, 0xe0, 0xf0, 0xdd, 0x89, 0x37, 0x33, 0x5e, 0x5e, 0xff, + 0xed, 0x59, 0xc9, 0x74, 0x5c, 0xde, 0x68, 0xd7, 0x4c, 0x9b, 0x7a, 0x96, 0xd2, 0x88, 0xf0, 0x73, + 0x89, 0xd5, 0x77, 0x2d, 0xbe, 0xdf, 0x22, 0xcc, 0xdc, 0xe8, 0x3e, 0xf8, 0xca, 0x84, 0xce, 0xa5, + 0x1f, 0xeb, 0x2c, 0xe4, 0xec, 0x06, 0x76, 0xfd, 0xaa, 0x5b, 0x9f, 0xc9, 0x2c, 0xa4, 0x56, 0xd3, + 0x95, 0xac, 0x6c, 0x5f, 0xaf, 0x1b, 0x2b, 0x70, 0x6a, 0x93, 0x71, 0xd7, 0xc3, 0x9c, 0x6c, 0xe1, + 0xee, 0x16, 0x4c, 0x42, 0xda, 0xc1, 0x21, 0xf9, 0x4c, 0x45, 0xfc, 0x1a, 0xbf, 0xa6, 0xf5, 0x39, + 0x06, 0xd8, 0x26, 0xdb, 0x1d, 0xbd, 0xce, 0xff, 0x41, 0xda, 0x63, 0x8e, 0xda, 0xa9, 0xd9, 0xe8, + 0x4e, 0xdd, 0x62, 0xce, 0x26, 0x6f, 0x90, 0x80, 0xb4, 0xbd, 0xed, 0x4e, 0x45, 0x44, 0xa1, 0xcb, + 0x30, 0xce, 0xc5, 0xf4, 0xaa, 0x4d, 0xfd, 0x1d, 0xd7, 0x91, 0x6b, 0xcc, 0xaf, 0x4f, 0x47, 0x67, + 0xc9, 0xf4, 0x1b, 0x72, 0xb8, 0x92, 0xe7, 0xdd, 0x06, 0xba, 0x02, 0xe3, 0xad, 0x80, 0xd4, 0x89, + 0x4d, 0x18, 0xa3, 0x01, 0x9b, 0xc9, 0xc8, 0x8b, 0x73, 0x04, 0x62, 0x4f, 0xb8, 0x28, 0x94, 0xb5, + 0x26, 0xb5, 0x77, 0x75, 0x49, 0x1a, 0x91, 0xfb, 0x90, 0x97, 0x7d, 0x61, 0x41, 0x42, 0xf3, 0x00, + 0x61, 0x88, 0x7c, 0x16, 0xa3, 0xf2, 0x59, 0x8c, 0xc9, 0x1e, 0x29, 0x2e, 0x1b, 0x7a, 0x58, 0x88, + 0xe1, 0x4c, 0x56, 0x52, 0x2f, 0x98, 0xa1, 0x52, 0x9a, 0x5a, 0x29, 0xcd, 0x6d, 0xad, 0x94, 0xe5, + 0x9c, 0xb8, 0x22, 0x8f, 0x7e, 0x2c, 0xa5, 0x54, 0x12, 0x31, 0x92, 0x78, 0xd2, 0xb9, 0x7f, 0xe6, + 0xa4, 0xc7, 0x7a, 0x4e, 0x1a, 0x19, 0x70, 0x22, 0xa4, 0xef, 0xe1, 0x4e, 0x55, 0x1c, 0x2e, 0x44, + 0x76, 0xe0, 0x16, 0xee, 0x6c, 0x61, 0xf6, 0x4e, 0x26, 0x37, 0x3c, 0x99, 0xae, 0xe4, 0x78, 0xa7, + 0xea, 0xfa, 0x75, 0xd2, 0x31, 0x2e, 0xa8, 0x3a, 0x76, 0x78, 0xe6, 0xdd, 0x22, 0x53, 0xc7, 0x1c, + 0xeb, 0xcb, 0x2d, 0xfe, 0x8d, 0xaf, 0xd3, 0xca, 0x13, 0xc8, 0xe0, 0xb2, 0xc8, 0x1a, 0xb9, 0x23, + 0xbc, 0xa3, 0x9f, 0xfa, 0x51, 0x77, 0x84, 0x77, 0xd8, 0x5f, 0xba, 0x23, 0xff, 0x1e, 0xf2, 0xf1, + 0x87, 0x6c, 0x5c, 0x52, 0xee, 0x2b, 0x7a, 0x4e, 0x47, 0x9c, 0xeb, 0xe9, 0x43, 0x99, 0x66, 0xe4, + 0x1a, 0xd1, 0xd5, 0xde, 0xb8, 0x79, 0x28, 0xc1, 0xaa, 0x5b, 0xa5, 0x78, 0x15, 0x72, 0xa2, 0x30, + 0x57, 0x77, 0x88, 0x52, 0xb9, 0xf2, 0xec, 0x0f, 0xcf, 0x4a, 0xa7, 0xc3, 0x15, 0xb2, 0xfa, 0xae, + 0xe9, 0x52, 0xcb, 0xc3, 0xbc, 0x61, 0x5e, 0xf7, 0xb9, 0x90, 0x67, 0x39, 0xdb, 0xb8, 0x02, 0x67, + 0x65, 0xb6, 0x6b, 0x6d, 0x7f, 0x9b, 0xee, 0x12, 0xff, 0x16, 0x6e, 0xb5, 0x5c, 0xdf, 0xd1, 0x17, + 0x68, 0x0a, 0x46, 0xb8, 0xe8, 0xd6, 0xba, 0x29, 0x1b, 0x11, 0x91, 0xf9, 0x50, 0xb9, 0xa4, 0xbe, + 0xe9, 0x8a, 0xd4, 0x1a, 0x8c, 0xed, 0xb4, 0xfd, 0x6a, 0x37, 0x47, 0x7e, 0x7d, 0x2a, 0x7a, 0xa1, + 0xf4, 0xbc, 0x4a, 0x6e, 0x47, 0xfd, 0x75, 0x93, 0xaf, 0x7f, 0x37, 0x0e, 0x23, 0x32, 0x3b, 0x7a, + 0x98, 0x02, 0xe8, 0x7a, 0x56, 0x64, 0x44, 0x53, 0x24, 0xdb, 0xe1, 0xc2, 0xd2, 0x91, 0x31, 0x21, + 0x3d, 0xe3, 0xe2, 0xa7, 0xdf, 0xfe, 0xfc, 0xd5, 0xf0, 0x32, 0xfa, 0xaf, 0xe5, 0x4b, 0x87, 0x79, + 0xe8, 0xec, 0x79, 0xa3, 0xaa, 0x3c, 0x93, 0xf5, 0x40, 0x5d, 0xa4, 0x03, 0xf4, 0x65, 0x0a, 0x4e, + 0xf4, 0x38, 0x51, 0x74, 0xae, 0x0f, 0x24, 0xc9, 0xea, 0x16, 0x96, 0x8f, 0x0b, 0x53, 0x74, 0x2c, + 0x49, 0xe7, 0x3c, 0x5a, 0x89, 0xd1, 0x09, 0x5b, 0x09, 0x8c, 0x1e, 0xa7, 0x60, 0x32, 0x6e, 0x29, + 0xd1, 0x6a, 0x1f, 0xda, 0x00, 0x0f, 0x5b, 0x38, 0xff, 0x07, 0x22, 0x15, 0xb5, 0xd7, 0x25, 0xb5, + 0x35, 0x64, 0xc5, 0xa8, 0xed, 0xe9, 0x09, 0x5d, 0x76, 0x51, 0x5b, 0x7c, 0x80, 0xee, 0x43, 0xb6, + 0xac, 0xad, 0x60, 0x1f, 0x5c, 0xaf, 0x03, 0x2d, 0x2c, 0x0c, 0x0e, 0x50, 0x34, 0xce, 0x4b, 0x1a, + 0x4b, 0x68, 0x31, 0x46, 0x43, 0xf9, 0x49, 0x16, 0xd9, 0x9b, 0x4f, 0x20, 0xab, 0x5c, 0x60, 0x02, + 0x70, 0xaf, 0xd9, 0x4c, 0x00, 0x8e, 0x19, 0x48, 0xc3, 0x94, 0xc0, 0xab, 0x68, 0x39, 0x06, 0xcc, + 0xc2, 0xb8, 0x2e, 0xae, 0xf5, 0x60, 0x97, 0xec, 0x1f, 0xa0, 0x5d, 0xc8, 0x08, 0x77, 0x88, 0xe6, + 0xfa, 0x32, 0x47, 0xcc, 0x66, 0x61, 0x7e, 0xc0, 0xa8, 0x02, 0x5d, 0x96, 0xa0, 0x0b, 0xa8, 0x18, + 0x03, 0x15, 0xde, 0x32, 0xba, 0xd4, 0x06, 0x8c, 0x86, 0xee, 0x08, 0x15, 0xfb, 0x12, 0xf6, 0x18, + 0xaf, 0x42, 0x69, 0xe0, 0xb8, 0x82, 0x9c, 0x97, 0x90, 0xd3, 0xe8, 0x74, 0x0c, 0x32, 0xf4, 0x5b, + 0xc8, 0x85, 0xac, 0xb2, 0x5b, 0xa8, 0x10, 0x4d, 0xd5, 0xeb, 0xc1, 0x0a, 0x8b, 0x83, 0xa5, 0x46, + 0x03, 0x95, 0x24, 0xd0, 0x2c, 0x9a, 0x4e, 0x78, 0x7a, 0xb6, 0xc8, 0x4f, 0x21, 0x1f, 0x31, 0x48, + 0x47, 0xc2, 0xf5, 0xac, 0x2a, 0xc1, 0x55, 0x19, 0x4b, 0x12, 0x6c, 0x1e, 0x9d, 0x8d, 0x83, 0xa9, + 0x58, 0x51, 0xb1, 0x91, 0x07, 0x59, 0x25, 0xb7, 0x09, 0x17, 0xa6, 0xd7, 0x7c, 0x25, 0x5c, 0x98, + 0x98, 0x52, 0x0f, 0x5c, 0x5f, 0x28, 0xb1, 0xbc, 0x83, 0xf6, 0x01, 0xba, 0x42, 0x90, 0x50, 0xd2, + 0xfa, 0xd4, 0x3c, 0xa1, 0xa4, 0xf5, 0x2b, 0x89, 0x61, 0x48, 0xdc, 0x39, 0x54, 0x48, 0xc4, 0x95, + 0x72, 0x24, 0x56, 0xaa, 0xd4, 0x23, 0xf1, 0x4d, 0x46, 0xe5, 0x26, 0xf1, 0x4d, 0xf6, 0x08, 0xcf, + 0xc0, 0x95, 0x6a, 0x35, 0x42, 0x5f, 0xa4, 0x60, 0x22, 0x26, 0x10, 0x68, 0xa5, 0x2f, 0x6d, 0xb2, + 0x02, 0x15, 0x56, 0x8f, 0x0f, 0x54, 0x3c, 0x56, 0x24, 0x8f, 0x45, 0x54, 0x8a, 0xf1, 0xd8, 0x69, + 0xfb, 0x52, 0x7f, 0xac, 0x07, 0xf2, 0x73, 0x50, 0xbe, 0xf2, 0xe4, 0x79, 0x31, 0xf5, 0xf4, 0x79, + 0x31, 0xf5, 0xd3, 0xf3, 0x62, 0xea, 0xd1, 0x8b, 0xe2, 0xd0, 0xd3, 0x17, 0xc5, 0xa1, 0xef, 0x5f, + 0x14, 0x87, 0x3e, 0x58, 0x8a, 0x38, 0x84, 0xb0, 0x44, 0x6f, 0x08, 0x7d, 0xd7, 0x09, 0x3b, 0x22, + 0x65, 0x6d, 0x54, 0xba, 0x91, 0x57, 0x7e, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xdd, 0x5e, 0x28, + 0x5b, 0x12, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2115,10 +2126,10 @@ func (m *QueryEthAccountResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) i-- dAtA[i] = 0x12 } - if len(m.Balance) > 0 { - i -= len(m.Balance) - copy(dAtA[i:], m.Balance) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Balance))) + if len(m.BalanceWei) > 0 { + i -= len(m.BalanceWei) + copy(dAtA[i:], m.BalanceWei) + i = encodeVarintQuery(dAtA, i, uint64(len(m.BalanceWei))) i-- dAtA[i] = 0xa } @@ -2315,6 +2326,13 @@ func (m *QueryBalanceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.BalanceWei) > 0 { + i -= len(m.BalanceWei) + copy(dAtA[i:], m.BalanceWei) + i = encodeVarintQuery(dAtA, i, uint64(len(m.BalanceWei))) + i-- + dAtA[i] = 0x12 + } if len(m.Balance) > 0 { i -= len(m.Balance) copy(dAtA[i:], m.Balance) @@ -3071,7 +3089,7 @@ func (m *QueryEthAccountResponse) Size() (n int) { } var l int _ = l - l = len(m.Balance) + l = len(m.BalanceWei) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } @@ -3172,6 +3190,10 @@ func (m *QueryBalanceResponse) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } + l = len(m.BalanceWei) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -3595,7 +3617,7 @@ func (m *QueryEthAccountResponse) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Balance", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field BalanceWei", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -3623,7 +3645,7 @@ func (m *QueryEthAccountResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Balance = string(dAtA[iNdEx:postIndex]) + m.BalanceWei = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -4244,6 +4266,38 @@ func (m *QueryBalanceResponse) Unmarshal(dAtA []byte) error { } m.Balance = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BalanceWei", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BalanceWei = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) From 9cd1edf0a966563df7ae43a4a654b856d8c15f95 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Sun, 4 Aug 2024 04:32:31 +0200 Subject: [PATCH 06/21] chore: wei unit migration --- app/evmante/evmante_verify_eth_acc.go | 4 +- eth/rpc/backend/account_info.go | 11 +++-- eth/rpc/backend/evm_query_client_test.go | 12 ++--- proto/eth/evm/v1/query.proto | 8 ++-- x/evm/evmtest/tx.go | 29 ++++++++++++ x/evm/keeper/grpc_query.go | 21 ++++----- x/evm/keeper/grpc_query_test.go | 55 +++++++++++++++-------- x/evm/keeper/keeper.go | 7 ++- x/evm/keeper/keeper_test.go | 4 +- x/evm/keeper/msg_ethereum_tx_test.go | 8 ++-- x/evm/keeper/msg_server.go | 42 ++++++++++++++--- x/evm/keeper/statedb.go | 17 +++---- x/evm/keeper/statedb_test.go | 57 ++++++++++++++++++++++++ x/evm/statedb/state_object.go | 3 +- 14 files changed, 210 insertions(+), 68 deletions(-) create mode 100644 x/evm/keeper/statedb_test.go diff --git a/app/evmante/evmante_verify_eth_acc.go b/app/evmante/evmante_verify_eth_acc.go index d3bb8a4f0..164ec0669 100644 --- a/app/evmante/evmante_verify_eth_acc.go +++ b/app/evmante/evmante_verify_eth_acc.go @@ -73,7 +73,9 @@ func (anteDec AnteDecVerifyEthAcc) AnteHandle( "the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash) } - if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil { + if err := keeper.CheckSenderBalance( + sdkmath.NewIntFromBigInt(acct.BalanceEvmDenom), txData, + ); err != nil { return ctx, errors.Wrap(err, "failed to check sender balance") } } diff --git a/eth/rpc/backend/account_info.go b/eth/rpc/backend/account_info.go index a3340983d..f27e3c70d 100644 --- a/eth/rpc/backend/account_info.go +++ b/eth/rpc/backend/account_info.go @@ -111,7 +111,7 @@ func (b *Backend) GetProof( return nil, err } - balance, ok := sdkmath.NewIntFromString(res.Balance) + balance, ok := sdkmath.NewIntFromString(res.BalanceWei) if !ok { return nil, errors.New("invalid balance") } @@ -152,7 +152,10 @@ func (b *Backend) GetStorageAt(address common.Address, key string, blockNrOrHash } // GetBalance returns the provided account's balance up to the provided block number. -func (b *Backend) GetBalance(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { +func (b *Backend) GetBalance( + address common.Address, + blockNrOrHash rpc.BlockNumberOrHash, +) (*hexutil.Big, error) { blockNum, err := b.BlockNumberFromTendermint(blockNrOrHash) if err != nil { return nil, err @@ -172,9 +175,9 @@ func (b *Backend) GetBalance(address common.Address, blockNrOrHash rpc.BlockNumb return nil, err } - val, ok := sdkmath.NewIntFromString(res.Balance) + val, ok := sdkmath.NewIntFromString(res.BalanceWei) if !ok { - return nil, errors.New("invalid balance") + return nil, fmt.Errorf("invalid balance: %s", res.BalanceWei) } // balance can only be negative in case of pruned node diff --git a/eth/rpc/backend/evm_query_client_test.go b/eth/rpc/backend/evm_query_client_test.go index 974694dc9..3a5481a9e 100644 --- a/eth/rpc/backend/evm_query_client_test.go +++ b/eth/rpc/backend/evm_query_client_test.go @@ -289,9 +289,9 @@ func RegisterAccount( ) { queryClient.On("EthAccount", rpc.NewContextWithHeight(height), &evm.QueryEthAccountRequest{Address: addr.String()}). Return(&evm.QueryEthAccountResponse{ - Balance: "0", - CodeHash: "", - Nonce: 0, + BalanceWei: "0", + CodeHash: "", + Nonce: 0, }, nil, ) @@ -302,21 +302,21 @@ func RegisterBalance( queryClient *mocks.EVMQueryClient, addr common.Address, height int64, ) { queryClient.On("Balance", rpc.NewContextWithHeight(height), &evm.QueryBalanceRequest{Address: addr.String()}). - Return(&evm.QueryBalanceResponse{Balance: "1"}, nil) + Return(&evm.QueryBalanceResponse{BalanceWei: "1"}, nil) } func RegisterBalanceInvalid( queryClient *mocks.EVMQueryClient, addr common.Address, height int64, ) { queryClient.On("Balance", rpc.NewContextWithHeight(height), &evm.QueryBalanceRequest{Address: addr.String()}). - Return(&evm.QueryBalanceResponse{Balance: "invalid"}, nil) + Return(&evm.QueryBalanceResponse{BalanceWei: "invalid"}, nil) } func RegisterBalanceNegative( queryClient *mocks.EVMQueryClient, addr common.Address, height int64, ) { queryClient.On("Balance", rpc.NewContextWithHeight(height), &evm.QueryBalanceRequest{Address: addr.String()}). - Return(&evm.QueryBalanceResponse{Balance: "-1"}, nil) + Return(&evm.QueryBalanceResponse{BalanceWei: "-1"}, nil) } func RegisterBalanceError( diff --git a/proto/eth/evm/v1/query.proto b/proto/eth/evm/v1/query.proto index e1e7d0b4b..15cfbe125 100644 --- a/proto/eth/evm/v1/query.proto +++ b/proto/eth/evm/v1/query.proto @@ -92,8 +92,8 @@ message QueryEthAccountRequest { // QueryEthAccountResponse is the response type for the Query/Account RPC method. message QueryEthAccountResponse { - // balance is the balance of the EVM denomination. - string balance = 1; + // balance_wei is the balance of wei (attoether, where NIBI is ether). + string balance_wei = 1; // code_hash is the hex-formatted code bytes from the EOA. string code_hash = 2; // nonce is the account's sequence number. @@ -153,8 +153,10 @@ message QueryBalanceRequest { // QueryBalanceResponse is the response type for the Query/Balance RPC method. message QueryBalanceResponse { - // balance is the balance of the EVM denomination. + // balance is the balance of the EVM denomination string balance = 1; + // balance is the balance of the EVM denomination in units of wei. + string balance_wei = 2; } // QueryStorageRequest is the request type for the Query/Storage RPC method. diff --git a/x/evm/evmtest/tx.go b/x/evm/evmtest/tx.go index 5d09c4d5e..0256d17b3 100644 --- a/x/evm/evmtest/tx.go +++ b/x/evm/evmtest/tx.go @@ -241,3 +241,32 @@ func GenerateAndSignEthTxMsg( keyringSigner := deps.Sender.KeyringSigner return txMsg, txMsg.Sign(gethSigner, keyringSigner) } + +func TransferWei( + deps *TestDeps, + to gethcommon.Address, + amountWei *big.Int, +) error { + ethAcc := deps.Sender + var innerTxData []byte = nil + var accessList gethcore.AccessList = nil + ethTxMsg, err := NewEthTxMsgFromTxData( + deps, + gethcore.LegacyTxType, + innerTxData, + deps.StateDB().GetNonce(ethAcc.EthAddr), + &to, + amountWei, + gethparams.TxGas, + accessList, + ) + if err != nil { + return fmt.Errorf("error while transferring wei: %w", err) + } + + _, err = deps.Chain.EvmKeeper.EthereumTx(deps.GoCtx(), ethTxMsg) + if err != nil { + return fmt.Errorf("error while transferring wei: %w", err) + } + return err +} diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index e4dc7e78b..b06592142 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -58,9 +58,9 @@ func (k Keeper) EthAccount( acct := k.GetAccountOrEmpty(ctx, addr) return &evm.QueryEthAccountResponse{ - Balance: acct.Balance.String(), - CodeHash: gethcommon.BytesToHash(acct.CodeHash).Hex(), - Nonce: acct.Nonce, + BalanceWei: evm.NativeToWei(acct.BalanceEvmDenom).String(), + CodeHash: gethcommon.BytesToHash(acct.CodeHash).Hex(), + Nonce: acct.Nonce, }, nil } @@ -139,8 +139,8 @@ func (k Keeper) ValidatorAccount( } // Balance: Implements the gRPC query for "/eth.evm.v1.Query/Balance". -// Balance retrieves the balance of an Ethereum address in "Ether", which -// actually refers to NIBI tokens on Nibiru EVM. +// Balance retrieves the balance of an Ethereum address in "wei", the smallest +// unit of "Ether". Ether refers to NIBI tokens on Nibiru EVM. // // Parameters: // - goCtx: The context.Context object representing the request context. @@ -156,7 +156,8 @@ func (k Keeper) Balance(goCtx context.Context, req *evm.QueryBalanceRequest) (*e ctx := sdk.UnwrapSDKContext(goCtx) balanceInt := k.GetEvmGasBalance(ctx, gethcommon.HexToAddress(req.Address)) return &evm.QueryBalanceResponse{ - Balance: balanceInt.String(), + Balance: balanceInt.String(), + BalanceWei: evm.NativeToWei(balanceInt).String(), }, nil } @@ -444,7 +445,7 @@ func (k Keeper) EstimateGasForEvmCallType( if errors.Is(err, core.ErrIntrinsicGas) { return true, nil, nil // Special case, raise gas limit } - return true, nil, err // Bail out + return true, nil, fmt.Errorf("error applying EVM message to StateDB: %w", err) // Bail out } return len(rsp.VmError) > 0, rsp, nil } @@ -459,15 +460,15 @@ func (k Keeper) EstimateGasForEvmCallType( if hi == gasCap { failed, result, err := executable(hi) if err != nil { - return nil, err + return nil, fmt.Errorf("eth call exec error: %w", err) } if failed { if result != nil && result.VmError != vm.ErrOutOfGas.Error() { if result.VmError == vm.ErrExecutionReverted.Error() { - return nil, evm.NewExecErrorWithReason(result.Ret) + return nil, fmt.Errorf("VMError: %w", evm.NewExecErrorWithReason(result.Ret)) } - return nil, errors.New(result.VmError) + return nil, fmt.Errorf("VMError: %s", result.VmError) } // Otherwise, the specified gas cap is too low return nil, fmt.Errorf("gas required exceeds allowance (%d)", gasCap) diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index aeb6f1eb8..2cd865b54 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -29,7 +29,8 @@ type TestCase[In, Out any] struct { req In, wantResp Out, ) - wantErr string + onTestEnd func(deps *evmtest.TestDeps) + wantErr string } func InvalidEthAddr() string { return "0x0000" } @@ -149,9 +150,9 @@ func (s *Suite) TestQueryEthAccount() { Address: InvalidEthAddr(), } wantResp = &evm.QueryEthAccountResponse{ - Balance: "0", - CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), - Nonce: 0, + BalanceWei: "0", + CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), + Nonce: 0, } return req, wantResp }, @@ -176,9 +177,9 @@ func (s *Suite) TestQueryEthAccount() { Address: deps.Sender.EthAddr.Hex(), } wantResp = &evm.QueryEthAccountResponse{ - Balance: "420", - CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), - Nonce: 0, + BalanceWei: "420" + strings.Repeat("0", 12), + CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), + Nonce: 0, } return req, wantResp }, @@ -543,7 +544,7 @@ func (s *Suite) TestQueryBalance() { Address: InvalidEthAddr(), } wantResp = &evm.QueryBalanceResponse{ - Balance: "0", + BalanceWei: "0", } return req, wantResp }, @@ -556,7 +557,8 @@ func (s *Suite) TestQueryBalance() { Address: evmtest.NewEthAccInfo().EthAddr.String(), } wantResp = &evm.QueryBalanceResponse{ - Balance: "0", + Balance: "0", + BalanceWei: "0", } return req, wantResp }, @@ -581,7 +583,8 @@ func (s *Suite) TestQueryBalance() { Address: deps.Sender.EthAddr.Hex(), } wantResp = &evm.QueryBalanceResponse{ - Balance: "420", + Balance: "420", + BalanceWei: "420" + strings.Repeat("0", 12), } return req, wantResp }, @@ -681,7 +684,8 @@ func (s *Suite) TestEstimateGasForEvmCallType() { }, { name: "happy: estimate gas for transfer", - setup: func(deps *evmtest.TestDeps) { + scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { + // fund the account chain := deps.Chain ethAddr := deps.Sender.EthAddr coins := sdk.Coins{sdk.NewInt64Coin(evm.DefaultEVMDenom, 1000)} @@ -690,10 +694,17 @@ func (s *Suite) TestEstimateGasForEvmCallType() { err = chain.BankKeeper.SendCoinsFromModuleToAccount( deps.Ctx, evm.ModuleName, ethAddr.Bytes(), coins) s.Require().NoError(err) - }, - scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { + + // assert balance of 1000 * 10^12 wei + resp, _ := deps.Chain.EvmKeeper.Balance(deps.GoCtx(), &evm.QueryBalanceRequest{ + Address: deps.Sender.EthAddr.Hex(), + }) + s.Equal("1000", resp.Balance) + s.Require().Equal("1000"+strings.Repeat("0", 12), resp.BalanceWei) + + // Send Eth call to transfer from the account - 5 * 10^12 wei recipient := evmtest.NewEthAccInfo().EthAddr - amountToSend := hexutil.Big(*big.NewInt(10)) + amountToSend := hexutil.Big(*evm.NativeToWei(big.NewInt(5))) gasLimitArg := hexutil.Uint64(100000) jsonTxArgs, err := json.Marshal(&evm.JsonTxArgs{ @@ -713,12 +724,15 @@ func (s *Suite) TestEstimateGasForEvmCallType() { return req, wantResp }, wantErr: "", + onTestEnd: func(deps *evmtest.TestDeps) { + + }, }, { name: "sad: insufficient balance for transfer", scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { recipient := evmtest.NewEthAccInfo().EthAddr - amountToSend := hexutil.Big(*big.NewInt(10)) + amountToSend := hexutil.Big(*evm.NativeToWei(big.NewInt(10))) jsonTxArgs, err := json.Marshal(&evm.JsonTxArgs{ From: &deps.Sender.EthAddr, @@ -752,6 +766,10 @@ func (s *Suite) TestEstimateGasForEvmCallType() { } s.Assert().NoError(err) s.EqualValues(wantResp, gotResp) + + if tc.onTestEnd != nil { + tc.onTestEnd(&deps) + } }) } } @@ -781,9 +799,8 @@ func (s *Suite) TestTraceTx() { wantErr: "", }, { - "happy: trace erc-20 transfer tx", - nil, - func(deps *evmtest.TestDeps) (req In, wantResp Out) { + name: "happy: trace erc-20 transfer tx", + scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { txMsg, predecessors := evmtest.DeployAndExecuteERC20Transfer(deps, s.T()) req = &evm.QueryTraceTxRequest{ @@ -793,7 +810,7 @@ func (s *Suite) TestTraceTx() { wantResp = TraceERC20Transfer() return req, wantResp }, - "", + wantErr: "", }, } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 53f95861a..bbb5dc360 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -82,8 +82,8 @@ func NewKeeper( // GetEvmGasBalance: Implements `evm.EVMKeeper` from // "github.com/NibiruChain/nibiru/app/ante/evm": Load account's balance of gas -// tokens for EVM execution -func (k *Keeper) GetEvmGasBalance(ctx sdk.Context, addr gethcommon.Address) *big.Int { +// tokens for EVM execution in EVM denom units. +func (k *Keeper) GetEvmGasBalance(ctx sdk.Context, addr gethcommon.Address) (balance *big.Int) { nibiruAddr := sdk.AccAddress(addr.Bytes()) evmParams := k.GetParams(ctx) evmDenom := evmParams.GetEvmDenom() @@ -91,8 +91,7 @@ func (k *Keeper) GetEvmGasBalance(ctx sdk.Context, addr gethcommon.Address) *big if evmDenom == "" { return big.NewInt(-1) } - coin := k.bankKeeper.GetBalance(ctx, nibiruAddr, evmDenom) - return coin.Amount.BigInt() + return k.bankKeeper.GetBalance(ctx, nibiruAddr, evmDenom).Amount.BigInt() } func (k Keeper) EthChainID(ctx sdk.Context) *big.Int { diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index 1c81893b3..0ddc2de45 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -10,8 +10,8 @@ type Suite struct { suite.Suite } -// TestKeeperSuite: Runs all the tests in the suite. -func TestKeeperSuite(t *testing.T) { +// TestSuite: Runs all the tests in the suite. +func TestSuite(t *testing.T) { s := new(Suite) suite.Run(t, s) } diff --git a/x/evm/keeper/msg_ethereum_tx_test.go b/x/evm/keeper/msg_ethereum_tx_test.go index 2e7496fc9..c85fd7d7f 100644 --- a/x/evm/keeper/msg_ethereum_tx_test.go +++ b/x/evm/keeper/msg_ethereum_tx_test.go @@ -188,12 +188,12 @@ func (s *Suite) TestMsgEthereumTx_SimpleTransfer() { deps := evmtest.NewTestDeps() ethAcc := deps.Sender - amount := int64(123) + fundedAmount := evm.NativeToWei(big.NewInt(123)).Int64() err := testapp.FundAccount( deps.Chain.BankKeeper, deps.Ctx, deps.Sender.NibiruAddr, - sdk.NewCoins(sdk.NewInt64Coin("unibi", amount)), + sdk.NewCoins(sdk.NewInt64Coin("unibi", fundedAmount)), ) s.Require().NoError(err) @@ -208,7 +208,7 @@ func (s *Suite) TestMsgEthereumTx_SimpleTransfer() { innerTxData, deps.StateDB().GetNonce(ethAcc.EthAddr), &to, - big.NewInt(amount), + big.NewInt(fundedAmount), gethparams.TxGas, accessList, ) @@ -229,7 +229,7 @@ func (s *Suite) TestMsgEthereumTx_SimpleTransfer() { &evm.EventTransfer{ Sender: ethAcc.EthAddr.String(), Recipient: to.String(), - Amount: strconv.FormatInt(amount, 10), + Amount: strconv.FormatInt(fundedAmount, 10), }, ) } diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 2f5d4fcf1..55c2dc462 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -421,19 +421,31 @@ func (k *Keeper) ApplyEvmMsg(ctx sdk.Context, } leftoverGas -= intrinsicGas - // access list preparation is moved from ante handler to here, because it's needed when `ApplyMessage` is called - // under contexts where ante handlers are not run, for example `eth_call` and `eth_estimateGas`. - stateDB.PrepareAccessList(msg.From(), msg.To(), evmObj.ActivePrecompiles(params.Rules{}), msg.AccessList()) + // access list preparation is moved from ante handler to here, because it's + // needed when `ApplyMessage` is called under contexts where ante handlers + // are not run, for example `eth_call` and `eth_estimateGas`. + stateDB.PrepareAccessList( + msg.From(), + msg.To(), + evmObj.ActivePrecompiles(params.Rules{}), + msg.AccessList(), + ) + + msgWei, err := ParseWeiAsMultipleOfMicronibi(msg.Value()) + if err != nil { + return nil, err + // return nil, fmt.Errorf("cannot use \"value\" in wei that can't be converted to unibi. %s is not divisible by 10^12", msg.Value()) + } if contractCreation { // take over the nonce management from evm: // - reset sender's nonce to msg.Nonce() before calling evm. // - increase sender's nonce by one no matter the result. stateDB.SetNonce(sender.Address(), msg.Nonce()) - ret, _, leftoverGas, vmErr = evmObj.Create(sender, msg.Data(), leftoverGas, msg.Value()) + ret, _, leftoverGas, vmErr = evmObj.Create(sender, msg.Data(), leftoverGas, msgWei) stateDB.SetNonce(sender.Address(), msg.Nonce()+1) } else { - ret, leftoverGas, vmErr = evmObj.Call(sender, *msg.To(), msg.Data(), leftoverGas, msg.Value()) + ret, leftoverGas, vmErr = evmObj.Call(sender, *msg.To(), msg.Data(), leftoverGas, msgWei) } // After EIP-3529: refunds are capped to gasUsed / 5 @@ -460,7 +472,7 @@ func (k *Keeper) ApplyEvmMsg(ctx sdk.Context, // The dirty states in `StateDB` is either committed or discarded after return if commit { if err := stateDB.Commit(); err != nil { - return nil, errors.Wrap(err, "failed to commit stateDB") + return nil, fmt.Errorf("failed to commit stateDB: %w", err) } } @@ -489,6 +501,24 @@ func (k *Keeper) ApplyEvmMsg(ctx sdk.Context, }, nil } +func ParseWeiAsMultipleOfMicronibi(weiInt *big.Int) (newWeiInt *big.Int, err error) { + // if "weiValue" is nil, 0, or negative, early return + if weiInt == nil || !(weiInt.Cmp(big.NewInt(0)) > 0) { + return weiInt, nil + } + + // err if weiInt is too small + tenPow12 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil) + if weiInt.Cmp(tenPow12) < 0 { + return weiInt, fmt.Errorf( + "wei amount is too small (%s), cannot transfer less than 1 micronibi. 10^18 wei == 1 NIBI == 10^6 micronibi", weiInt) + } + + // truncate to highest micronibi amount + newWeiInt = evm.NativeToWei(evm.WeiToNative(weiInt)) + return newWeiInt, nil +} + // CreateFunToken is a gRPC transaction message for creating fungible token // ("FunToken") a mapping between a bank coin and ERC20 token. // diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index 3ce4ba434..d7897cbef 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -30,7 +30,7 @@ func (k *Keeper) GetAccount(ctx sdk.Context, addr gethcommon.Address) *statedb.A return nil } - acct.Balance = k.GetEvmGasBalance(ctx, addr) + acct.BalanceEvmDenom = k.GetEvmGasBalance(ctx, addr) return acct } @@ -67,13 +67,14 @@ func (k *Keeper) ForEachStorage( // SetAccBalance update account's balance, compare with current balance first, then decide to mint or burn. func (k *Keeper) SetAccBalance( - ctx sdk.Context, addr gethcommon.Address, amount *big.Int, + ctx sdk.Context, addr gethcommon.Address, amountEvmDenom *big.Int, ) error { nativeAddr := sdk.AccAddress(addr.Bytes()) params := k.GetParams(ctx) - coin := k.bankKeeper.GetBalance(ctx, nativeAddr, params.EvmDenom) - balance := coin.Amount.BigInt() - delta := new(big.Int).Sub(amount, balance) + balance := + k.bankKeeper.GetBalance(ctx, nativeAddr, params.EvmDenom).Amount.BigInt() + delta := new(big.Int).Sub(amountEvmDenom, balance) + switch delta.Sign() { case 1: // mint @@ -126,7 +127,7 @@ func (k *Keeper) SetAccount( k.accountKeeper.SetAccount(ctx, acct) - if err := k.SetAccBalance(ctx, addr, account.Balance); err != nil { + if err := k.SetAccBalance(ctx, addr, account.BalanceEvmDenom); err != nil { return err } @@ -213,7 +214,7 @@ func (k *Keeper) GetAccountOrEmpty( // empty account return statedb.Account{ - Balance: new(big.Int), - CodeHash: evm.EmptyCodeHash, + BalanceEvmDenom: new(big.Int), + CodeHash: evm.EmptyCodeHash, } } diff --git a/x/evm/keeper/statedb_test.go b/x/evm/keeper/statedb_test.go new file mode 100644 index 000000000..32ffebf2d --- /dev/null +++ b/x/evm/keeper/statedb_test.go @@ -0,0 +1,57 @@ +// Copyright (c) 2023-2024 Nibi, Inc. +package keeper_test + +import ( + "math/big" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/NibiruChain/nibiru/app/appconst" + "github.com/NibiruChain/nibiru/x/common/testutil/testapp" + "github.com/NibiruChain/nibiru/x/evm" + "github.com/NibiruChain/nibiru/x/evm/evmtest" + + gethcommon "github.com/ethereum/go-ethereum/common" +) + +// TestStateDBBalance tests the behavior of the StateDB with regards to account +// balances, ensuring correct conversion between native tokens (unibi) and EVM +// tokens (wei), as well as proper balance updates during transfers. +func (s *Suite) TestStateDBBalance() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() + s.Equal("0", db.GetBalance(deps.Sender.EthAddr).String()) + + s.T().Log("fund account in unibi. See expected wei amount.") + err := testapp.FundAccount( + deps.Chain.BankKeeper, + deps.Ctx, + deps.Sender.NibiruAddr, + sdk.NewCoins(sdk.NewInt64Coin(appconst.BondDenom, 42)), + ) + s.NoError(err) + s.Equal( + "42"+strings.Repeat("0", 12), + db.GetBalance(deps.Sender.EthAddr).String(), + ) + + s.T().Log("Send 12 unibi. See expected wei amounts.") + to := gethcommon.HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") + err = evmtest.TransferWei(&deps, to, evm.NativeToWei(big.NewInt(12))) + s.Require().NoError(err) + db = deps.StateDB() + + s.Equal( + "30"+strings.Repeat("0", 12), + db.GetBalance(deps.Sender.EthAddr).String(), + ) + s.Equal( + "12"+strings.Repeat("0", 12), + db.GetBalance(to).String(), + ) + + s.T().Log("Send 12 wei. Should error") + err = evmtest.TransferWei(&deps, to, big.NewInt(12)) + s.Require().ErrorContains(err, "wei amount is too small") +} diff --git a/x/evm/statedb/state_object.go b/x/evm/statedb/state_object.go index 828af241d..3f315afc9 100644 --- a/x/evm/statedb/state_object.go +++ b/x/evm/statedb/state_object.go @@ -6,9 +6,10 @@ import ( "math/big" "sort" - "github.com/NibiruChain/nibiru/x/evm" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + + "github.com/NibiruChain/nibiru/x/evm" ) var emptyCodeHash = crypto.Keccak256(nil) From 18995b60592a8f9da19caa17fc2956057ba4bcb4 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Mon, 5 Aug 2024 01:25:14 +0200 Subject: [PATCH 07/21] test(statedb): complete the wei-based account migration. Remove all mocks --- x/evm/evmtest/test_deps.go | 2 +- x/evm/keeper/grpc_query_test.go | 1 - x/evm/keeper/statedb.go | 3 +- x/evm/statedb/mock_test.go | 115 -------- x/evm/statedb/state_object.go | 26 +- x/evm/statedb/statedb.go | 3 - x/evm/statedb/statedb_test.go | 452 +++++++++++++++++--------------- 7 files changed, 267 insertions(+), 335 deletions(-) delete mode 100644 x/evm/statedb/mock_test.go diff --git a/x/evm/evmtest/test_deps.go b/x/evm/evmtest/test_deps.go index c02b8527f..e1c5076fb 100644 --- a/x/evm/evmtest/test_deps.go +++ b/x/evm/evmtest/test_deps.go @@ -49,7 +49,7 @@ func NewTestDeps() TestDeps { } } -func (deps *TestDeps) StateDB() *statedb.StateDB { +func (deps TestDeps) StateDB() *statedb.StateDB { return statedb.New(deps.Ctx, &deps.Chain.EvmKeeper, statedb.NewEmptyTxConfig( gethcommon.BytesToHash(deps.Ctx.HeaderHash().Bytes()), diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index 2cd865b54..f50fda474 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -725,7 +725,6 @@ func (s *Suite) TestEstimateGasForEvmCallType() { }, wantErr: "", onTestEnd: func(deps *evmtest.TestDeps) { - }, }, { diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index d7897cbef..7311dc63e 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -71,8 +71,7 @@ func (k *Keeper) SetAccBalance( ) error { nativeAddr := sdk.AccAddress(addr.Bytes()) params := k.GetParams(ctx) - balance := - k.bankKeeper.GetBalance(ctx, nativeAddr, params.EvmDenom).Amount.BigInt() + balance := k.bankKeeper.GetBalance(ctx, nativeAddr, params.EvmDenom).Amount.BigInt() delta := new(big.Int).Sub(amountEvmDenom, balance) switch delta.Sign() { diff --git a/x/evm/statedb/mock_test.go b/x/evm/statedb/mock_test.go deleted file mode 100644 index b4324abe9..000000000 --- a/x/evm/statedb/mock_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package statedb_test - -import ( - "bytes" - "errors" - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - - "github.com/NibiruChain/nibiru/x/evm/statedb" -) - -var ( - _ statedb.Keeper = &MockKeeper{} - errAddress common.Address = common.BigToAddress(big.NewInt(100)) - emptyCodeHash = crypto.Keccak256(nil) -) - -type MockAcount struct { - account statedb.Account - states statedb.Storage -} - -type MockKeeper struct { - accounts map[common.Address]MockAcount - codes map[common.Hash][]byte -} - -func NewMockKeeper() *MockKeeper { - return &MockKeeper{ - accounts: make(map[common.Address]MockAcount), - codes: make(map[common.Hash][]byte), - } -} - -func (k MockKeeper) GetAccount(_ sdk.Context, addr common.Address) *statedb.Account { - acct, ok := k.accounts[addr] - if !ok { - return nil - } - return &acct.account -} - -func (k MockKeeper) GetState(_ sdk.Context, addr common.Address, key common.Hash) common.Hash { - return k.accounts[addr].states[key] -} - -func (k MockKeeper) GetCode(_ sdk.Context, codeHash common.Hash) []byte { - return k.codes[codeHash] -} - -func (k MockKeeper) ForEachStorage(_ sdk.Context, addr common.Address, cb func(key, value common.Hash) bool) { - if acct, ok := k.accounts[addr]; ok { - for k, v := range acct.states { - if !cb(k, v) { - return - } - } - } -} - -func (k MockKeeper) SetAccount(_ sdk.Context, addr common.Address, account statedb.Account) error { - if addr == errAddress { - return errors.New("mock db error") - } - acct, exists := k.accounts[addr] - if exists { - // update - acct.account = account - k.accounts[addr] = acct - } else { - k.accounts[addr] = MockAcount{account: account, states: make(statedb.Storage)} - } - return nil -} - -func (k MockKeeper) SetState(_ sdk.Context, addr common.Address, key common.Hash, value []byte) { - if acct, ok := k.accounts[addr]; ok { - if len(value) == 0 { - delete(acct.states, key) - } else { - acct.states[key] = common.BytesToHash(value) - } - } -} - -func (k MockKeeper) SetCode(_ sdk.Context, codeHash []byte, code []byte) { - k.codes[common.BytesToHash(codeHash)] = code -} - -func (k MockKeeper) DeleteAccount(_ sdk.Context, addr common.Address) error { - if addr == errAddress { - return errors.New("mock db error") - } - old := k.accounts[addr] - delete(k.accounts, addr) - if !bytes.Equal(old.account.CodeHash, emptyCodeHash) { - delete(k.codes, common.BytesToHash(old.account.CodeHash)) - } - return nil -} - -func (k MockKeeper) Clone() *MockKeeper { - accounts := make(map[common.Address]MockAcount, len(k.accounts)) - for k, v := range k.accounts { - accounts[k] = v - } - codes := make(map[common.Hash][]byte, len(k.codes)) - for k, v := range k.codes { - codes[k] = v - } - return &MockKeeper{accounts, codes} -} diff --git a/x/evm/statedb/state_object.go b/x/evm/statedb/state_object.go index 3f315afc9..3425abc91 100644 --- a/x/evm/statedb/state_object.go +++ b/x/evm/statedb/state_object.go @@ -69,8 +69,8 @@ func NewEmptyAccount() *Account { } // IsContract returns if the account contains contract code. -func (acct Account) IsContract() bool { - return !bytes.Equal(acct.CodeHash, emptyCodeHash) +func (acct *Account) IsContract() bool { + return (acct != nil) && !bytes.Equal(acct.CodeHash, emptyCodeHash) } // Storage represents in-memory cache/buffer of contract storage. @@ -88,7 +88,22 @@ func (s Storage) SortedKeys() []common.Hash { return keys } -// stateObject is the state of an acount +// stateObject represents the state of a Nibiru EVM account. +// It encapsulates both the account data (balance, nonce, code) and the contract +// storage state. stateObject serves as an in-memory cache and staging area for +// changes before they are committed to the underlying storage. +// +// Key features: +// 1. It uses AccountWei, which represents balances in wei for EVM compatibility. +// 2. It maintains both the original (committed) storage and dirty (uncommitted) storage. +// 3. It tracks whether the account has been marked for deletion (suicided). +// 4. It caches the contract code for efficient access. +// +// stateObjects are used to: +// - Efficiently manage and track changes to account state during EVM execution. +// - Provide a layer of abstraction between the EVM and the underlying storage. +// - Enable features like state reverting and snapshotting. +// - Optimize performance by minimizing direct access to the underlying storage. type stateObject struct { db *StateDB @@ -115,8 +130,9 @@ func newObject(db *StateDB, address common.Address, account Account) *stateObjec account.CodeHash = emptyCodeHash } return &stateObject{ - db: db, - address: address, + db: db, + address: address, + // Reflect the micronibi (unibi) balance in wei account: account.ToWei(), originStorage: make(Storage), dirtyStorage: make(Storage), diff --git a/x/evm/statedb/statedb.go b/x/evm/statedb/statedb.go index 7be1aab2b..511060f15 100644 --- a/x/evm/statedb/statedb.go +++ b/x/evm/statedb/statedb.go @@ -218,9 +218,6 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { return nil } - // Reflect the micronibi (unibi) balance in wei - // weiBalance := account.BalanceWei() - // Insert into the live set obj := newObject(s, addr, *account) s.setStateObject(obj) diff --git a/x/evm/statedb/statedb_test.go b/x/evm/statedb/statedb_test.go index 37a4dd666..6368a1daf 100644 --- a/x/evm/statedb/statedb_test.go +++ b/x/evm/statedb/statedb_test.go @@ -4,68 +4,96 @@ import ( "math/big" "testing" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" gethcore "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/stretchr/testify/suite" + s "github.com/stretchr/testify/suite" + "github.com/NibiruChain/nibiru/x/common/set" "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" ) +// emptyCodeHash: The hash for empty contract bytecode, or a blank byte +// array. This is the code hash for a non-existent or empty account. +var emptyCodeHash []byte = crypto.Keccak256(nil) + +// dummy variables for tests 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(blockHash) + 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)) + errAddress common.Address = common.BigToAddress(big.NewInt(100)) ) -type StateDBTestSuite struct { - suite.Suite +// TestSuite runs the entire test suite. +func TestSuite(t *testing.T) { + s.Run(t, new(Suite)) +} + +type Suite struct { + s.Suite } -func (suite *StateDBTestSuite) TestAccount() { +// CollectContractStorage is a helper function that collects all storage key-value pairs +// for a given contract address using the ForEachStorage method of the StateDB. +// It returns a map of storage slots to their values. +func CollectContractStorage(db vm.StateDB) statedb.Storage { + storage := make(statedb.Storage) + err := db.ForEachStorage( + address, + func(k, v common.Hash) bool { + storage[k] = v + return true + }, + ) + if err != nil { + return nil + } + + return storage +} + +func (s *Suite) TestAccount() { key1 := common.BigToHash(big.NewInt(1)) value1 := common.BigToHash(big.NewInt(2)) key2 := common.BigToHash(big.NewInt(3)) value2 := common.BigToHash(big.NewInt(4)) testCases := []struct { name string - malleate func(*statedb.StateDB) + malleate func(deps *evmtest.TestDeps, db *statedb.StateDB) }{ - {"non-exist account", func(db *statedb.StateDB) { - suite.Require().Equal(false, db.Exist(address)) - suite.Require().Equal(true, db.Empty(address)) - suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) - suite.Require().Equal([]byte(nil), db.GetCode(address)) - suite.Require().Equal(common.Hash{}, db.GetCodeHash(address)) - suite.Require().Equal(uint64(0), db.GetNonce(address)) + {"non-exist account", func(deps *evmtest.TestDeps, db *statedb.StateDB) { + s.Require().Equal(false, db.Exist(address)) + s.Require().Equal(true, db.Empty(address)) + s.Require().Equal(big.NewInt(0), db.GetBalance(address)) + s.Require().Equal([]byte(nil), db.GetCode(address)) + s.Require().Equal(common.Hash{}, db.GetCodeHash(address)) + s.Require().Equal(uint64(0), db.GetNonce(address)) }}, - {"empty account", func(db *statedb.StateDB) { + {"empty account", func(deps *evmtest.TestDeps, db *statedb.StateDB) { db.CreateAccount(address) - suite.Require().NoError(db.Commit()) - - keeper := db.Keeper().(*MockKeeper) - acct := keeper.accounts[address] - suite.Require().Equal(statedb.NewEmptyAccount(), &acct.account) - suite.Require().Empty(acct.states) - suite.Require().False(acct.account.IsContract()) - - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) - suite.Require().Equal(true, db.Exist(address)) - suite.Require().Equal(true, db.Empty(address)) - suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) - suite.Require().Equal([]byte(nil), db.GetCode(address)) - suite.Require().Equal(common.BytesToHash(emptyCodeHash), db.GetCodeHash(address)) - suite.Require().Equal(uint64(0), db.GetNonce(address)) + s.Require().NoError(db.Commit()) + + k := db.Keeper() + acct := k.GetAccount(deps.Ctx, address) + s.Require().EqualValues(statedb.NewEmptyAccount(), acct) + s.Require().Empty(CollectContractStorage(db)) + + db = deps.StateDB() + s.Require().Equal(true, db.Exist(address)) + s.Require().Equal(true, db.Empty(address)) + s.Require().Equal(big.NewInt(0), db.GetBalance(address)) + s.Require().Equal([]byte(nil), db.GetCode(address)) + s.Require().Equal(common.BytesToHash(emptyCodeHash), db.GetCodeHash(address)) + s.Require().Equal(uint64(0), db.GetNonce(address)) }}, - {"suicide", func(db *statedb.StateDB) { + {"suicide", func(deps *evmtest.TestDeps, db *statedb.StateDB) { // non-exist account. - suite.Require().False(db.Suicide(address)) - suite.Require().False(db.HasSuicided(address)) + s.Require().False(db.Suicide(address)) + s.Require().False(db.HasSuicided(address)) // create a contract account db.CreateAccount(address) @@ -73,45 +101,41 @@ func (suite *StateDBTestSuite) TestAccount() { db.AddBalance(address, big.NewInt(100)) db.SetState(address, key1, value1) db.SetState(address, key2, value2) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) // suicide - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) - suite.Require().False(db.HasSuicided(address)) - suite.Require().True(db.Suicide(address)) + db = deps.StateDB() + s.Require().False(db.HasSuicided(address)) + s.Require().True(db.Suicide(address)) // check dirty state - suite.Require().True(db.HasSuicided(address)) + s.Require().True(db.HasSuicided(address)) // balance is cleared - suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) + s.Require().Equal(big.NewInt(0), db.GetBalance(address)) // but code and state are still accessible in dirty state - suite.Require().Equal(value1, db.GetState(address, key1)) - suite.Require().Equal([]byte("hello world"), db.GetCode(address)) + s.Require().Equal(value1, db.GetState(address, key1)) + s.Require().Equal([]byte("hello world"), db.GetCode(address)) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) // not accessible from StateDB anymore - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) - suite.Require().False(db.Exist(address)) - - // and cleared in keeper too - keeper := db.Keeper().(*MockKeeper) - suite.Require().Empty(keeper.accounts) - suite.Require().Empty(keeper.codes) + db = deps.StateDB() + s.Require().False(db.Exist(address)) + s.Require().Empty(CollectContractStorage(db)) }}, } for _, tc := range testCases { - suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) - tc.malleate(db) + s.Run(tc.name, func() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() + tc.malleate(&deps, db) }) } } -func (suite *StateDBTestSuite) TestAccountOverride() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) +func (s *Suite) TestAccountOverride() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() // test balance carry over when overwritten amount := big.NewInt(1) @@ -123,12 +147,12 @@ func (suite *StateDBTestSuite) TestAccountOverride() { db.CreateAccount(address) // check balance is not lost - suite.Require().Equal(amount, db.GetBalance(address)) + s.Require().Equal(amount, db.GetBalance(address)) // but nonce is reset - suite.Require().Equal(uint64(0), db.GetNonce(address)) + s.Require().Equal(uint64(0), db.GetNonce(address)) } -func (suite *StateDBTestSuite) TestDBError() { +func (s *Suite) TestDBError() { testCases := []struct { name string malleate func(vm.StateDB) @@ -138,17 +162,19 @@ func (suite *StateDBTestSuite) TestDBError() { }}, {"delete account", func(db vm.StateDB) { db.SetNonce(errAddress, 1) - suite.Require().True(db.Suicide(errAddress)) + s.Require().True(db.Suicide(errAddress)) + s.True(db.HasSuicided(errAddress)) }}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() tc.malleate(db) - suite.Require().Error(db.Commit()) + s.Require().NoError(db.Commit()) } } -func (suite *StateDBTestSuite) TestBalance() { +func (s *Suite) TestBalance() { // NOTE: no need to test overflow/underflow, that is guaranteed by evm implementation. testCases := []struct { name string @@ -161,7 +187,7 @@ func (suite *StateDBTestSuite) TestBalance() { {"sub balance", func(db *statedb.StateDB) { db.AddBalance(address, big.NewInt(10)) // get dirty balance - suite.Require().Equal(big.NewInt(10), db.GetBalance(address)) + s.Require().Equal(big.NewInt(10), db.GetBalance(address)) db.SubBalance(address, big.NewInt(2)) }, big.NewInt(8)}, {"add zero balance", func(db *statedb.StateDB) { @@ -173,22 +199,22 @@ func (suite *StateDBTestSuite) TestBalance() { } for _, tc := range testCases { - suite.Run(tc.name, func() { + s.Run(tc.name, func() { deps := evmtest.NewTestDeps() db := deps.StateDB() tc.malleate(db) // check dirty state - suite.Require().Equal(tc.expBalance, db.GetBalance(address)) - suite.Require().NoError(db.Commit()) + s.Require().Equal(tc.expBalance, db.GetBalance(address)) + s.Require().NoError(db.Commit()) // check committed balance too - suite.Require().Equal(tc.expBalance, db.GetBalance(address)) + s.Require().Equal(tc.expBalance, db.GetBalance(address)) }) } } -func (suite *StateDBTestSuite) TestState() { +func (s *Suite) TestState() { key1 := common.BigToHash(big.NewInt(1)) value1 := common.BigToHash(big.NewInt(1)) testCases := []struct { @@ -207,49 +233,49 @@ func (suite *StateDBTestSuite) TestState() { }, statedb.Storage{}}, {"set state", func(db *statedb.StateDB) { // check empty initial state - suite.Require().Equal(common.Hash{}, db.GetState(address, key1)) - suite.Require().Equal(common.Hash{}, db.GetCommittedState(address, key1)) + s.Require().Equal(common.Hash{}, db.GetState(address, key1)) + s.Require().Equal(common.Hash{}, db.GetCommittedState(address, key1)) // set state db.SetState(address, key1, value1) // query dirty state - suite.Require().Equal(value1, db.GetState(address, key1)) + s.Require().Equal(value1, db.GetState(address, key1)) // check committed state is still not exist - suite.Require().Equal(common.Hash{}, db.GetCommittedState(address, key1)) + s.Require().Equal(common.Hash{}, db.GetCommittedState(address, key1)) // set same value again, should be noop db.SetState(address, key1, value1) - suite.Require().Equal(value1, db.GetState(address, key1)) + s.Require().Equal(value1, db.GetState(address, key1)) }, statedb.Storage{ key1: value1, }}, } for _, tc := range testCases { - suite.Run(tc.name, func() { + s.Run(tc.name, func() { deps := evmtest.NewTestDeps() db := deps.StateDB() tc.malleate(db) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) // check committed states in keeper for k, v := range tc.expStates { - suite.Equal(v, db.GetState(address, k)) + s.Equal(v, db.GetState(address, k)) } // check ForEachStorage db = deps.StateDB() collected := CollectContractStorage(db) if len(tc.expStates) > 0 { - suite.Require().Equal(tc.expStates, collected) + s.Require().Equal(tc.expStates, collected) } else { - suite.Require().Empty(collected) + s.Require().Empty(collected) } }) } } -func (suite *StateDBTestSuite) TestCode() { +func (s *Suite) TestCode() { code := []byte("hello world") codeHash := crypto.Keccak256Hash(code) @@ -269,28 +295,28 @@ func (suite *StateDBTestSuite) TestCode() { } for _, tc := range testCases { - suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + s.Run(tc.name, func() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() tc.malleate(db) // check dirty state - suite.Require().Equal(tc.expCode, db.GetCode(address)) - suite.Require().Equal(len(tc.expCode), db.GetCodeSize(address)) - suite.Require().Equal(tc.expCodeHash, db.GetCodeHash(address)) + s.Require().Equal(tc.expCode, db.GetCode(address)) + s.Require().Equal(len(tc.expCode), db.GetCodeSize(address)) + s.Require().Equal(tc.expCodeHash, db.GetCodeHash(address)) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) // check again - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) - suite.Require().Equal(tc.expCode, db.GetCode(address)) - suite.Require().Equal(len(tc.expCode), db.GetCodeSize(address)) - suite.Require().Equal(tc.expCodeHash, db.GetCodeHash(address)) + db = deps.StateDB() + s.Require().Equal(tc.expCode, db.GetCode(address)) + s.Require().Equal(len(tc.expCode), db.GetCodeSize(address)) + s.Require().Equal(tc.expCodeHash, db.GetCodeHash(address)) }) } } -func (suite *StateDBTestSuite) TestRevertSnapshot() { +func (s *Suite) TestRevertSnapshot() { v1 := common.BigToHash(big.NewInt(1)) v2 := common.BigToHash(big.NewInt(2)) v3 := common.BigToHash(big.NewInt(3)) @@ -317,7 +343,7 @@ func (suite *StateDBTestSuite) TestRevertSnapshot() { {"suicide", func(db vm.StateDB) { db.SetState(address, v1, v2) db.SetCode(address, []byte("hello world")) - suite.Require().True(db.Suicide(address)) + s.Require().True(db.Suicide(address)) }}, {"add log", func(db vm.StateDB) { db.AddLog(&gethcore.Log{ @@ -334,70 +360,78 @@ func (suite *StateDBTestSuite) TestRevertSnapshot() { }}, } for _, tc := range testCases { - suite.Run(tc.name, func() { - ctx := sdk.Context{} - keeper := NewMockKeeper() - - { - // do some arbitrary changes to the storage - db := statedb.New(ctx, keeper, emptyTxConfig) - db.SetNonce(address, 1) - db.AddBalance(address, big.NewInt(100)) - db.SetCode(address, []byte("hello world")) - db.SetState(address, v1, v2) - db.SetNonce(address2, 1) - suite.Require().NoError(db.Commit()) - } + s.Run(tc.name, func() { + deps := evmtest.NewTestDeps() + + // do some arbitrary changes to the storage + db := deps.StateDB() + db.SetNonce(address, 1) + db.AddBalance(address, big.NewInt(100)) + db.SetCode(address, []byte("hello world")) + db.SetState(address, v1, v2) + db.SetNonce(address2, 1) + s.Require().NoError(db.Commit()) - originalKeeper := keeper.Clone() + // Store original state values + originalNonce := db.GetNonce(address) + originalBalance := db.GetBalance(address) + originalCode := db.GetCode(address) + originalState := db.GetState(address, v1) + originalNonce2 := db.GetNonce(address2) // run test - db := statedb.New(ctx, keeper, emptyTxConfig) rev := db.Snapshot() tc.malleate(db) db.RevertToSnapshot(rev) // check empty states after revert - suite.Require().Zero(db.GetRefund()) - suite.Require().Empty(db.Logs()) + s.Require().Zero(db.GetRefund()) + s.Require().Empty(db.Logs()) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) - // check keeper should stay the same - suite.Require().Equal(originalKeeper, keeper) + // Check again after commit to ensure persistence + s.Require().Equal(originalNonce, db.GetNonce(address)) + s.Require().Equal(originalBalance, db.GetBalance(address)) + s.Require().Equal(originalCode, db.GetCode(address)) + s.Require().Equal(originalState, db.GetState(address, v1)) + s.Require().Equal(originalNonce2, db.GetNonce(address2)) }) } } -func (suite *StateDBTestSuite) TestNestedSnapshot() { +func (s *Suite) TestNestedSnapshot() { key := common.BigToHash(big.NewInt(1)) value1 := common.BigToHash(big.NewInt(1)) value2 := common.BigToHash(big.NewInt(2)) - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() rev1 := db.Snapshot() db.SetState(address, key, value1) rev2 := db.Snapshot() db.SetState(address, key, value2) - suite.Require().Equal(value2, db.GetState(address, key)) + s.Require().Equal(value2, db.GetState(address, key)) db.RevertToSnapshot(rev2) - suite.Require().Equal(value1, db.GetState(address, key)) + s.Require().Equal(value1, db.GetState(address, key)) db.RevertToSnapshot(rev1) - suite.Require().Equal(common.Hash{}, db.GetState(address, key)) + s.Require().Equal(common.Hash{}, db.GetState(address, key)) } -func (suite *StateDBTestSuite) TestInvalidSnapshotId() { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) - suite.Require().Panics(func() { +func (s *Suite) TestInvalidSnapshotId() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() + + s.Require().Panics(func() { db.RevertToSnapshot(1) }) } -func (suite *StateDBTestSuite) TestAccessList() { +func (s *Suite) TestAccessList() { value1 := common.BigToHash(big.NewInt(1)) value2 := common.BigToHash(big.NewInt(2)) @@ -406,38 +440,38 @@ func (suite *StateDBTestSuite) TestAccessList() { malleate func(vm.StateDB) }{ {"add address", func(db vm.StateDB) { - suite.Require().False(db.AddressInAccessList(address)) + s.Require().False(db.AddressInAccessList(address)) db.AddAddressToAccessList(address) - suite.Require().True(db.AddressInAccessList(address)) + s.Require().True(db.AddressInAccessList(address)) addrPresent, slotPresent := db.SlotInAccessList(address, value1) - suite.Require().True(addrPresent) - suite.Require().False(slotPresent) + s.Require().True(addrPresent) + s.Require().False(slotPresent) // add again, should be no-op db.AddAddressToAccessList(address) - suite.Require().True(db.AddressInAccessList(address)) + s.Require().True(db.AddressInAccessList(address)) }}, {"add slot", func(db vm.StateDB) { addrPresent, slotPresent := db.SlotInAccessList(address, value1) - suite.Require().False(addrPresent) - suite.Require().False(slotPresent) + s.Require().False(addrPresent) + s.Require().False(slotPresent) db.AddSlotToAccessList(address, value1) addrPresent, slotPresent = db.SlotInAccessList(address, value1) - suite.Require().True(addrPresent) - suite.Require().True(slotPresent) + s.Require().True(addrPresent) + s.Require().True(slotPresent) // add another slot db.AddSlotToAccessList(address, value2) addrPresent, slotPresent = db.SlotInAccessList(address, value2) - suite.Require().True(addrPresent) - suite.Require().True(slotPresent) + s.Require().True(addrPresent) + s.Require().True(slotPresent) // add again, should be noop db.AddSlotToAccessList(address, value2) addrPresent, slotPresent = db.SlotInAccessList(address, value2) - suite.Require().True(addrPresent) - suite.Require().True(slotPresent) + s.Require().True(addrPresent) + s.Require().True(slotPresent) }}, {"prepare access list", func(db vm.StateDB) { al := gethcore.AccessList{{ @@ -448,68 +482,79 @@ func (suite *StateDBTestSuite) TestAccessList() { db.PrepareAccessList(address, &address2, vm.PrecompiledAddressesBerlin, al) // check sender and dst - suite.Require().True(db.AddressInAccessList(address)) - suite.Require().True(db.AddressInAccessList(address2)) + s.Require().True(db.AddressInAccessList(address)) + s.Require().True(db.AddressInAccessList(address2)) // check precompiles - suite.Require().True(db.AddressInAccessList(common.BytesToAddress([]byte{1}))) + s.Require().True(db.AddressInAccessList(common.BytesToAddress([]byte{1}))) // check AccessList - suite.Require().True(db.AddressInAccessList(address3)) + s.Require().True(db.AddressInAccessList(address3)) addrPresent, slotPresent := db.SlotInAccessList(address3, value1) - suite.Require().True(addrPresent) - suite.Require().True(slotPresent) + s.Require().True(addrPresent) + s.Require().True(slotPresent) addrPresent, slotPresent = db.SlotInAccessList(address3, value2) - suite.Require().True(addrPresent) - suite.Require().False(slotPresent) + s.Require().True(addrPresent) + s.Require().False(slotPresent) }}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() tc.malleate(db) } } -func (suite *StateDBTestSuite) TestLog() { +func (s *Suite) TestLog() { txHash := common.BytesToHash([]byte("tx")) + // use a non-default tx config + const ( + blockNumber = uint64(1) + txIdx = uint(1) + logIdx = uint(1) + ) txConfig := statedb.NewTxConfig( blockHash, txHash, - 1, 1, + txIdx, logIdx, ) - db := statedb.New(sdk.Context{}, NewMockKeeper(), txConfig) - data := []byte("hello world") - db.AddLog(&gethcore.Log{ - Address: address, - Topics: []common.Hash{}, - Data: data, - BlockNumber: 1, - }) - suite.Require().Equal(1, len(db.Logs())) - expecedLog := &gethcore.Log{ - Address: address, - Topics: []common.Hash{}, - Data: data, - BlockNumber: 1, - BlockHash: blockHash, - TxHash: txHash, - TxIndex: 1, - Index: 1, - } - suite.Require().Equal(expecedLog, db.Logs()[0]) - db.AddLog(&gethcore.Log{ + deps := evmtest.NewTestDeps() + db := statedb.New(deps.Ctx, &deps.Chain.EvmKeeper, txConfig) + + logData := []byte("hello world") + log := &gethcore.Log{ Address: address, Topics: []common.Hash{}, - Data: data, - BlockNumber: 1, - }) - suite.Require().Equal(2, len(db.Logs())) - expecedLog.Index++ - suite.Require().Equal(expecedLog, db.Logs()[1]) + Data: logData, + BlockNumber: blockNumber, + } + db.AddLog(log) + s.Require().Equal(1, len(db.Logs())) + + wantLog := &gethcore.Log{ + Address: log.Address, + Topics: log.Topics, + Data: log.Data, + BlockNumber: log.BlockNumber, + + // New fields + BlockHash: blockHash, + TxHash: txHash, + TxIndex: txIdx, + Index: logIdx, + } + s.Require().Equal(wantLog, db.Logs()[0]) + + // Add a second log and assert values + db.AddLog(log) + wantLog.Index++ + s.Require().Equal(2, len(db.Logs())) + gotLog := db.Logs()[1] + s.Require().Equal(wantLog, gotLog) } -func (suite *StateDBTestSuite) TestRefund() { +func (s *Suite) TestRefund() { testCases := []struct { name string malleate func(vm.StateDB) @@ -529,37 +574,45 @@ func (suite *StateDBTestSuite) TestRefund() { }, 0, true}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() if !tc.expPanic { tc.malleate(db) - suite.Require().Equal(tc.expRefund, db.GetRefund()) + s.Require().Equal(tc.expRefund, db.GetRefund()) } else { - suite.Require().Panics(func() { + s.Require().Panics(func() { tc.malleate(db) }) } } } -func (suite *StateDBTestSuite) TestIterateStorage() { +func (s *Suite) TestIterateStorage() { key1 := common.BigToHash(big.NewInt(1)) value1 := common.BigToHash(big.NewInt(2)) key2 := common.BigToHash(big.NewInt(3)) value2 := common.BigToHash(big.NewInt(4)) - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() db.SetState(address, key1, value1) db.SetState(address, key2, value2) // ForEachStorage only iterate committed state - suite.Require().Empty(CollectContractStorage(db)) + s.Require().Empty(CollectContractStorage(db)) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) storage := CollectContractStorage(db) - suite.Require().Equal(2, len(storage)) - suite.Require().Equal(keeper.accounts[address].states, storage) + s.Require().Equal(2, len(storage)) + + keySet := set.New[common.Hash](key1, key2) + valSet := set.New[common.Hash](value1, value2) + for _, stateKey := range storage.SortedKeys() { + stateValue := deps.K.GetState(deps.Ctx, address, stateKey) + s.True(keySet.Has(stateKey)) + s.True(valSet.Has(stateValue)) + } // break early iteration storage = make(statedb.Storage) @@ -568,23 +621,6 @@ func (suite *StateDBTestSuite) TestIterateStorage() { // return false to break early return false }) - suite.Require().NoError(err) - suite.Require().Equal(1, len(storage)) -} - -func CollectContractStorage(db vm.StateDB) statedb.Storage { - storage := make(statedb.Storage) - err := db.ForEachStorage(address, func(k, v common.Hash) bool { - storage[k] = v - return true - }) - if err != nil { - return nil - } - - return storage -} - -func TestStateDBTestSuite(t *testing.T) { - suite.Run(t, &StateDBTestSuite{}) + s.Require().NoError(err) + s.Require().Equal(1, len(storage)) } From 4419067f8ef0ebfc8836b8f4b24bacd2877c0e18 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Mon, 5 Aug 2024 03:04:46 +0200 Subject: [PATCH 08/21] test(statedb_test.go): more thorough test cases --- app/evmante/evmante_can_transfer.go | 4 +- app/evmante/evmante_can_transfer_test.go | 12 ++- app/evmante/evmante_gas_consume_test.go | 4 +- app/evmante/evmante_handler_test.go | 7 +- app/evmante/evmante_verify_eth_acc_test.go | 2 +- x/evm/keeper/statedb_test.go | 103 ++++++++++++++------- 6 files changed, 89 insertions(+), 43 deletions(-) diff --git a/app/evmante/evmante_can_transfer.go b/app/evmante/evmante_can_transfer.go index 2826aa742..62196c794 100644 --- a/app/evmante/evmante_can_transfer.go +++ b/app/evmante/evmante_can_transfer.go @@ -87,10 +87,12 @@ func (ctd CanTransferDecorator) AnteHandle( // NOTE: here the gas consumed is from the context with the infinite gas meter if coreMsg.Value().Sign() > 0 && !evmInstance.Context.CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) { + balanceWei := stateDB.GetBalance(coreMsg.From()) return ctx, errors.Wrapf( errortypes.ErrInsufficientFunds, - "failed to transfer %s from address %s using the EVM block context transfer function", + "failed to transfer %s wei (balance=%s) from address %s using the EVM block context transfer function", coreMsg.Value(), + balanceWei, coreMsg.From(), ) } diff --git a/app/evmante/evmante_can_transfer_test.go b/app/evmante/evmante_can_transfer_test.go index 9345b144a..31cfa3443 100644 --- a/app/evmante/evmante_can_transfer_test.go +++ b/app/evmante/evmante_can_transfer_test.go @@ -1,12 +1,11 @@ package evmante_test import ( - "math/big" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/NibiruChain/nibiru/app/evmante" "github.com/NibiruChain/nibiru/eth" + "github.com/NibiruChain/nibiru/x/common/testutil/testapp" "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" ) @@ -22,7 +21,14 @@ func (s *TestSuite) TestCanTransferDecorator() { { name: "happy: signed tx, sufficient funds", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { - sdb.AddBalance(deps.Sender.EthAddr, big.NewInt(100)) + s.NoError( + testapp.FundAccount( + deps.Chain.BankKeeper, + deps.Ctx, + deps.Sender.NibiruAddr, + sdk.NewCoins(sdk.NewInt64Coin(eth.EthBaseDenom, 100)), + ), + ) }, txSetup: func(deps *evmtest.TestDeps) sdk.FeeTx { txMsg := evmtest.HappyTransferTx(deps, 0) diff --git a/app/evmante/evmante_gas_consume_test.go b/app/evmante/evmante_gas_consume_test.go index a9b88e252..04f85c5e8 100644 --- a/app/evmante/evmante_gas_consume_test.go +++ b/app/evmante/evmante_gas_consume_test.go @@ -25,7 +25,7 @@ func (s *TestSuite) TestAnteDecEthGasConsume() { name: "happy: sender with funds", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { gasLimit := happyGasLimit() - balance := new(big.Int).Add(gasLimit, big.NewInt(100)) + balance := evm.NativeToWei(new(big.Int).Add(gasLimit, big.NewInt(100))) sdb.AddBalance(deps.Sender.EthAddr, balance) }, txSetup: evmtest.HappyCreateContractTx, @@ -46,7 +46,7 @@ func (s *TestSuite) TestAnteDecEthGasConsume() { name: "sad: out of gas", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { gasLimit := happyGasLimit() - balance := new(big.Int).Add(gasLimit, big.NewInt(100)) + balance := evm.NativeToWei(new(big.Int).Add(gasLimit, big.NewInt(100))) sdb.AddBalance(deps.Sender.EthAddr, balance) }, txSetup: evmtest.HappyCreateContractTx, diff --git a/app/evmante/evmante_handler_test.go b/app/evmante/evmante_handler_test.go index 8d63573ac..c1fa5c8d0 100644 --- a/app/evmante/evmante_handler_test.go +++ b/app/evmante/evmante_handler_test.go @@ -11,6 +11,7 @@ import ( "github.com/NibiruChain/nibiru/app/ante" "github.com/NibiruChain/nibiru/app/evmante" "github.com/NibiruChain/nibiru/eth" + "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" ) @@ -26,16 +27,18 @@ func (s *TestSuite) TestAnteHandlerEVM() { { name: "happy: signed tx, sufficient funds", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { + balanceMicronibi := new(big.Int).Add(evmtest.GasLimitCreateContract(), big.NewInt(100)) sdb.AddBalance( deps.Sender.EthAddr, - new(big.Int).Add(evmtest.GasLimitCreateContract(), big.NewInt(100)), + evm.NativeToWei(balanceMicronibi), ) }, ctxSetup: func(deps *evmtest.TestDeps) { gasPrice := sdk.NewInt64Coin("unibi", 1) + maxGasMicronibi := new(big.Int).Add(evmtest.GasLimitCreateContract(), big.NewInt(100)) cp := &tmproto.ConsensusParams{ Block: &tmproto.BlockParams{ - MaxGas: new(big.Int).Add(evmtest.GasLimitCreateContract(), big.NewInt(100)).Int64(), + MaxGas: evm.NativeToWei(maxGasMicronibi).Int64(), }, } deps.Ctx = deps.Ctx. diff --git a/app/evmante/evmante_verify_eth_acc_test.go b/app/evmante/evmante_verify_eth_acc_test.go index 06ba88604..f0fc05c08 100644 --- a/app/evmante/evmante_verify_eth_acc_test.go +++ b/app/evmante/evmante_verify_eth_acc_test.go @@ -21,7 +21,7 @@ func (s *TestSuite) TestAnteDecoratorVerifyEthAcc_CheckTx() { { name: "happy: sender with funds", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { - sdb.AddBalance(deps.Sender.EthAddr, happyGasLimit()) + sdb.AddBalance(deps.Sender.EthAddr, evm.NativeToWei(happyGasLimit())) }, txSetup: evmtest.HappyCreateContractTx, wantErr: "", diff --git a/x/evm/keeper/statedb_test.go b/x/evm/keeper/statedb_test.go index 32ffebf2d..2e81c81d9 100644 --- a/x/evm/keeper/statedb_test.go +++ b/x/evm/keeper/statedb_test.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/NibiruChain/nibiru/app/appconst" "github.com/NibiruChain/nibiru/x/common/testutil/testapp" "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" @@ -20,38 +19,74 @@ import ( // tokens (wei), as well as proper balance updates during transfers. func (s *Suite) TestStateDBBalance() { deps := evmtest.NewTestDeps() - db := deps.StateDB() - s.Equal("0", db.GetBalance(deps.Sender.EthAddr).String()) - - s.T().Log("fund account in unibi. See expected wei amount.") - err := testapp.FundAccount( - deps.Chain.BankKeeper, - deps.Ctx, - deps.Sender.NibiruAddr, - sdk.NewCoins(sdk.NewInt64Coin(appconst.BondDenom, 42)), - ) - s.NoError(err) - s.Equal( - "42"+strings.Repeat("0", 12), - db.GetBalance(deps.Sender.EthAddr).String(), - ) - - s.T().Log("Send 12 unibi. See expected wei amounts.") + { + db := deps.StateDB() + s.Equal("0", db.GetBalance(deps.Sender.EthAddr).String()) + + s.T().Log("fund account in unibi. See expected wei amount.") + err := testapp.FundAccount( + deps.Chain.BankKeeper, + deps.Ctx, + deps.Sender.NibiruAddr, + sdk.NewCoins(sdk.NewInt64Coin(evm.DefaultEVMDenom, 42)), + ) + s.NoError(err) + s.Equal( + "42"+strings.Repeat("0", 12), + db.GetBalance(deps.Sender.EthAddr).String(), + ) + s.Equal( + "42", + deps.Chain.BankKeeper.GetBalance(deps.Ctx, deps.Sender.NibiruAddr, evm.DefaultEVMDenom).Amount.String(), + ) + } + + s.T().Log("Send via EVM transfer. See expected wei amounts.") to := gethcommon.HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") - err = evmtest.TransferWei(&deps, to, evm.NativeToWei(big.NewInt(12))) - s.Require().NoError(err) - db = deps.StateDB() - - s.Equal( - "30"+strings.Repeat("0", 12), - db.GetBalance(deps.Sender.EthAddr).String(), - ) - s.Equal( - "12"+strings.Repeat("0", 12), - db.GetBalance(to).String(), - ) - - s.T().Log("Send 12 wei. Should error") - err = evmtest.TransferWei(&deps, to, big.NewInt(12)) - s.Require().ErrorContains(err, "wei amount is too small") + { + err := evmtest.TransferWei(&deps, to, evm.NativeToWei(big.NewInt(12))) + s.Require().NoError(err) + db := deps.StateDB() + s.Equal( + "30"+strings.Repeat("0", 12), + db.GetBalance(deps.Sender.EthAddr).String(), + ) + s.Equal( + "12"+strings.Repeat("0", 12), + db.GetBalance(to).String(), + ) + + s.T().Log("Send via EVM transfer with too little wei. Should error") + err = evmtest.TransferWei(&deps, to, big.NewInt(12)) + s.Require().ErrorContains(err, "wei amount is too small") + } + + s.T().Log("Send via bank transfer from account to account. See expected wei amounts.") + { + deps := evmtest.NewTestDeps() + toNibiAddr := evmtest.EthAddrToNibiruAddr(to) + err := testapp.FundAccount( + deps.Chain.BankKeeper, + deps.Ctx, + deps.Sender.NibiruAddr, + sdk.NewCoins(sdk.NewInt64Coin(evm.DefaultEVMDenom, 8)), + ) + s.NoError(err) + err = deps.Chain.BankKeeper.SendCoins( + deps.Ctx, deps.Sender.NibiruAddr, + toNibiAddr, + sdk.NewCoins(sdk.NewInt64Coin(evm.DefaultEVMDenom, 3)), + ) + s.NoError(err) + + db := deps.StateDB() + s.Equal( + "3"+strings.Repeat("0", 12), + db.GetBalance(to).String(), + ) + s.Equal( + "5"+strings.Repeat("0", 12), + db.GetBalance(deps.Sender.EthAddr).String(), + ) + } } From 37c09fff810e890e30cec41dec3976302d0386b1 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Mon, 5 Aug 2024 13:07:02 +0200 Subject: [PATCH 09/21] Squashed commit of the following: merge ud/attonibi commit e171a5edc75fec9d84149d11b1174c13dd3a1a06 Merge: 4419067f 3c73f036 Author: Unique-Divine Date: Mon Aug 5 06:01:44 2024 -0500 Merge branch 'main' into ud/attonibi commit 4419067f8ef0ebfc8836b8f4b24bacd2877c0e18 Author: Unique-Divine Date: Mon Aug 5 03:04:46 2024 +0200 test(statedb_test.go): more thorough test cases commit 18995b60592a8f9da19caa17fc2956057ba4bcb4 Author: Unique-Divine Date: Mon Aug 5 01:25:14 2024 +0200 test(statedb): complete the wei-based account migration. Remove all mocks commit 9cd1edf0a966563df7ae43a4a654b856d8c15f95 Author: Unique-Divine Date: Sun Aug 4 04:32:31 2024 +0200 chore: wei unit migration commit cd9642b81fb37ef8e1a03941a28485933841fc13 Author: Unique-Divine Date: Sun Aug 4 04:27:33 2024 +0200 math functions for unibi and wei commit a1c57829ff4f32b51f21b3a917f4c45dca2b2131 Author: Unique-Divine Date: Sun Aug 4 04:26:58 2024 +0200 refactor(statedb): separate Account and AccountWei to have state objects manipulate in wei units commit e106002fd6bcc4a7970f0027fb92738ee02c915d Author: Unique-Divine Date: Tue Jul 30 02:25:34 2024 +0100 changelog commit 3335463d30b3adb7417c4a42f53a0055067bcd64 Author: Unique-Divine Date: Tue Jul 30 02:23:33 2024 +0100 refactor: use pebbledb as the test db commit 1f0d8d01383d617764996eb55cee90222d0c4368 Author: Unique-Divine Date: Tue Jul 30 01:51:38 2024 +0100 refactor: remove unused vars. improve error clarity for testnetwork/New --- CHANGELOG.md | 3 +- app/evmante/evmante_can_transfer.go | 4 +- app/evmante/evmante_can_transfer_test.go | 12 +- app/evmante/evmante_gas_consume_test.go | 4 +- app/evmante/evmante_handler_test.go | 7 +- app/evmante/evmante_verify_eth_acc.go | 4 +- app/evmante/evmante_verify_eth_acc_test.go | 2 +- eth/rpc/backend/account_info.go | 11 +- eth/rpc/backend/evm_query_client_test.go | 12 +- proto/eth/evm/v1/query.proto | 8 +- x/evm/const.go | 63 +++ x/evm/evm_test.go | 65 +++ x/evm/evmtest/test_deps.go | 2 +- x/evm/evmtest/tx.go | 29 ++ x/evm/keeper/grpc_query.go | 21 +- x/evm/keeper/grpc_query_test.go | 54 ++- x/evm/keeper/keeper.go | 7 +- x/evm/keeper/keeper_test.go | 4 +- x/evm/keeper/msg_ethereum_tx_test.go | 8 +- x/evm/keeper/msg_server.go | 42 +- x/evm/keeper/statedb.go | 16 +- x/evm/keeper/statedb_test.go | 92 ++++ x/evm/query.pb.go | 274 +++++++----- x/evm/statedb/mock_test.go | 115 ----- x/evm/statedb/state_object.go | 92 +++- x/evm/statedb/statedb.go | 7 +- x/evm/statedb/statedb_test.go | 466 +++++++++++---------- 27 files changed, 887 insertions(+), 537 deletions(-) create mode 100644 x/evm/keeper/statedb_test.go delete mode 100644 x/evm/statedb/mock_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index a8a0185c9..0a4d4414b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,8 +93,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#1973](https://github.com/NibiruChain/nibiru/pull/1973) - chore(appconst): Add chain IDs ending in "3" to the "knownEthChainIDMap". This makes it possible to use devnet 3 and testnet 3. - [#1976](https://github.com/NibiruChain/nibiru/pull/1976) - refactor(evm): unique chain ids for all networks - [#1977](https://github.com/NibiruChain/nibiru/pull/1977) - fix(localnet): rolled back change of evm validator address with cosmos derivation path -- [#1981](https://github.com/NibiruChain/nibiru/pull/1981) - fix(evm): remove isCheckTx() short circuit on `AnteDecVerifyEthAcc` - [#1979](https://github.com/NibiruChain/nibiru/pull/1979) -refactor(db): use pebbledb as the default db in integration tests +- [#1981](https://github.com/NibiruChain/nibiru/pull/1981) - fix(evm): remove isCheckTx() short circuit on `AnteDecVerifyEthAcc` +- [#1985](https://github.com/NibiruChain/nibiru/pull/1985) - feat(evm)!: Use atto denomination for the wei units in the EVM so that NIBI is "ether" to clients. Only micronibi (unibi) amounts can be transferred. All clients follow the constraint equation, 1 ether == 1 NIBI == 10^6 unibi == 10^18 wei. #### Dapp modules: perp, spot, oracle, etc diff --git a/app/evmante/evmante_can_transfer.go b/app/evmante/evmante_can_transfer.go index 2826aa742..62196c794 100644 --- a/app/evmante/evmante_can_transfer.go +++ b/app/evmante/evmante_can_transfer.go @@ -87,10 +87,12 @@ func (ctd CanTransferDecorator) AnteHandle( // NOTE: here the gas consumed is from the context with the infinite gas meter if coreMsg.Value().Sign() > 0 && !evmInstance.Context.CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) { + balanceWei := stateDB.GetBalance(coreMsg.From()) return ctx, errors.Wrapf( errortypes.ErrInsufficientFunds, - "failed to transfer %s from address %s using the EVM block context transfer function", + "failed to transfer %s wei (balance=%s) from address %s using the EVM block context transfer function", coreMsg.Value(), + balanceWei, coreMsg.From(), ) } diff --git a/app/evmante/evmante_can_transfer_test.go b/app/evmante/evmante_can_transfer_test.go index 9345b144a..31cfa3443 100644 --- a/app/evmante/evmante_can_transfer_test.go +++ b/app/evmante/evmante_can_transfer_test.go @@ -1,12 +1,11 @@ package evmante_test import ( - "math/big" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/NibiruChain/nibiru/app/evmante" "github.com/NibiruChain/nibiru/eth" + "github.com/NibiruChain/nibiru/x/common/testutil/testapp" "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" ) @@ -22,7 +21,14 @@ func (s *TestSuite) TestCanTransferDecorator() { { name: "happy: signed tx, sufficient funds", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { - sdb.AddBalance(deps.Sender.EthAddr, big.NewInt(100)) + s.NoError( + testapp.FundAccount( + deps.Chain.BankKeeper, + deps.Ctx, + deps.Sender.NibiruAddr, + sdk.NewCoins(sdk.NewInt64Coin(eth.EthBaseDenom, 100)), + ), + ) }, txSetup: func(deps *evmtest.TestDeps) sdk.FeeTx { txMsg := evmtest.HappyTransferTx(deps, 0) diff --git a/app/evmante/evmante_gas_consume_test.go b/app/evmante/evmante_gas_consume_test.go index a9b88e252..04f85c5e8 100644 --- a/app/evmante/evmante_gas_consume_test.go +++ b/app/evmante/evmante_gas_consume_test.go @@ -25,7 +25,7 @@ func (s *TestSuite) TestAnteDecEthGasConsume() { name: "happy: sender with funds", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { gasLimit := happyGasLimit() - balance := new(big.Int).Add(gasLimit, big.NewInt(100)) + balance := evm.NativeToWei(new(big.Int).Add(gasLimit, big.NewInt(100))) sdb.AddBalance(deps.Sender.EthAddr, balance) }, txSetup: evmtest.HappyCreateContractTx, @@ -46,7 +46,7 @@ func (s *TestSuite) TestAnteDecEthGasConsume() { name: "sad: out of gas", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { gasLimit := happyGasLimit() - balance := new(big.Int).Add(gasLimit, big.NewInt(100)) + balance := evm.NativeToWei(new(big.Int).Add(gasLimit, big.NewInt(100))) sdb.AddBalance(deps.Sender.EthAddr, balance) }, txSetup: evmtest.HappyCreateContractTx, diff --git a/app/evmante/evmante_handler_test.go b/app/evmante/evmante_handler_test.go index 8d63573ac..c1fa5c8d0 100644 --- a/app/evmante/evmante_handler_test.go +++ b/app/evmante/evmante_handler_test.go @@ -11,6 +11,7 @@ import ( "github.com/NibiruChain/nibiru/app/ante" "github.com/NibiruChain/nibiru/app/evmante" "github.com/NibiruChain/nibiru/eth" + "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" ) @@ -26,16 +27,18 @@ func (s *TestSuite) TestAnteHandlerEVM() { { name: "happy: signed tx, sufficient funds", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { + balanceMicronibi := new(big.Int).Add(evmtest.GasLimitCreateContract(), big.NewInt(100)) sdb.AddBalance( deps.Sender.EthAddr, - new(big.Int).Add(evmtest.GasLimitCreateContract(), big.NewInt(100)), + evm.NativeToWei(balanceMicronibi), ) }, ctxSetup: func(deps *evmtest.TestDeps) { gasPrice := sdk.NewInt64Coin("unibi", 1) + maxGasMicronibi := new(big.Int).Add(evmtest.GasLimitCreateContract(), big.NewInt(100)) cp := &tmproto.ConsensusParams{ Block: &tmproto.BlockParams{ - MaxGas: new(big.Int).Add(evmtest.GasLimitCreateContract(), big.NewInt(100)).Int64(), + MaxGas: evm.NativeToWei(maxGasMicronibi).Int64(), }, } deps.Ctx = deps.Ctx. diff --git a/app/evmante/evmante_verify_eth_acc.go b/app/evmante/evmante_verify_eth_acc.go index 051f889b3..d40b39058 100644 --- a/app/evmante/evmante_verify_eth_acc.go +++ b/app/evmante/evmante_verify_eth_acc.go @@ -69,7 +69,9 @@ func (anteDec AnteDecVerifyEthAcc) AnteHandle( "the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash) } - if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil { + if err := keeper.CheckSenderBalance( + sdkmath.NewIntFromBigInt(acct.BalanceEvmDenom), txData, + ); err != nil { return ctx, errors.Wrap(err, "failed to check sender balance") } } diff --git a/app/evmante/evmante_verify_eth_acc_test.go b/app/evmante/evmante_verify_eth_acc_test.go index 06ba88604..f0fc05c08 100644 --- a/app/evmante/evmante_verify_eth_acc_test.go +++ b/app/evmante/evmante_verify_eth_acc_test.go @@ -21,7 +21,7 @@ func (s *TestSuite) TestAnteDecoratorVerifyEthAcc_CheckTx() { { name: "happy: sender with funds", beforeTxSetup: func(deps *evmtest.TestDeps, sdb *statedb.StateDB) { - sdb.AddBalance(deps.Sender.EthAddr, happyGasLimit()) + sdb.AddBalance(deps.Sender.EthAddr, evm.NativeToWei(happyGasLimit())) }, txSetup: evmtest.HappyCreateContractTx, wantErr: "", diff --git a/eth/rpc/backend/account_info.go b/eth/rpc/backend/account_info.go index a3340983d..f27e3c70d 100644 --- a/eth/rpc/backend/account_info.go +++ b/eth/rpc/backend/account_info.go @@ -111,7 +111,7 @@ func (b *Backend) GetProof( return nil, err } - balance, ok := sdkmath.NewIntFromString(res.Balance) + balance, ok := sdkmath.NewIntFromString(res.BalanceWei) if !ok { return nil, errors.New("invalid balance") } @@ -152,7 +152,10 @@ func (b *Backend) GetStorageAt(address common.Address, key string, blockNrOrHash } // GetBalance returns the provided account's balance up to the provided block number. -func (b *Backend) GetBalance(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { +func (b *Backend) GetBalance( + address common.Address, + blockNrOrHash rpc.BlockNumberOrHash, +) (*hexutil.Big, error) { blockNum, err := b.BlockNumberFromTendermint(blockNrOrHash) if err != nil { return nil, err @@ -172,9 +175,9 @@ func (b *Backend) GetBalance(address common.Address, blockNrOrHash rpc.BlockNumb return nil, err } - val, ok := sdkmath.NewIntFromString(res.Balance) + val, ok := sdkmath.NewIntFromString(res.BalanceWei) if !ok { - return nil, errors.New("invalid balance") + return nil, fmt.Errorf("invalid balance: %s", res.BalanceWei) } // balance can only be negative in case of pruned node diff --git a/eth/rpc/backend/evm_query_client_test.go b/eth/rpc/backend/evm_query_client_test.go index 974694dc9..3a5481a9e 100644 --- a/eth/rpc/backend/evm_query_client_test.go +++ b/eth/rpc/backend/evm_query_client_test.go @@ -289,9 +289,9 @@ func RegisterAccount( ) { queryClient.On("EthAccount", rpc.NewContextWithHeight(height), &evm.QueryEthAccountRequest{Address: addr.String()}). Return(&evm.QueryEthAccountResponse{ - Balance: "0", - CodeHash: "", - Nonce: 0, + BalanceWei: "0", + CodeHash: "", + Nonce: 0, }, nil, ) @@ -302,21 +302,21 @@ func RegisterBalance( queryClient *mocks.EVMQueryClient, addr common.Address, height int64, ) { queryClient.On("Balance", rpc.NewContextWithHeight(height), &evm.QueryBalanceRequest{Address: addr.String()}). - Return(&evm.QueryBalanceResponse{Balance: "1"}, nil) + Return(&evm.QueryBalanceResponse{BalanceWei: "1"}, nil) } func RegisterBalanceInvalid( queryClient *mocks.EVMQueryClient, addr common.Address, height int64, ) { queryClient.On("Balance", rpc.NewContextWithHeight(height), &evm.QueryBalanceRequest{Address: addr.String()}). - Return(&evm.QueryBalanceResponse{Balance: "invalid"}, nil) + Return(&evm.QueryBalanceResponse{BalanceWei: "invalid"}, nil) } func RegisterBalanceNegative( queryClient *mocks.EVMQueryClient, addr common.Address, height int64, ) { queryClient.On("Balance", rpc.NewContextWithHeight(height), &evm.QueryBalanceRequest{Address: addr.String()}). - Return(&evm.QueryBalanceResponse{Balance: "-1"}, nil) + Return(&evm.QueryBalanceResponse{BalanceWei: "-1"}, nil) } func RegisterBalanceError( diff --git a/proto/eth/evm/v1/query.proto b/proto/eth/evm/v1/query.proto index e1e7d0b4b..15cfbe125 100644 --- a/proto/eth/evm/v1/query.proto +++ b/proto/eth/evm/v1/query.proto @@ -92,8 +92,8 @@ message QueryEthAccountRequest { // QueryEthAccountResponse is the response type for the Query/Account RPC method. message QueryEthAccountResponse { - // balance is the balance of the EVM denomination. - string balance = 1; + // balance_wei is the balance of wei (attoether, where NIBI is ether). + string balance_wei = 1; // code_hash is the hex-formatted code bytes from the EOA. string code_hash = 2; // nonce is the account's sequence number. @@ -153,8 +153,10 @@ message QueryBalanceRequest { // QueryBalanceResponse is the response type for the Query/Balance RPC method. message QueryBalanceResponse { - // balance is the balance of the EVM denomination. + // balance is the balance of the EVM denomination string balance = 1; + // balance is the balance of the EVM denomination in units of wei. + string balance_wei = 2; } // QueryStorageRequest is the request type for the Query/Storage RPC method. diff --git a/x/evm/const.go b/x/evm/const.go index 360da5b49..1e41138d1 100644 --- a/x/evm/const.go +++ b/x/evm/const.go @@ -2,6 +2,9 @@ package evm import ( + "fmt" + "math/big" + "github.com/NibiruChain/collections" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" gethcommon "github.com/ethereum/go-ethereum/common" @@ -87,3 +90,63 @@ var ( zeroAddr gethcommon.Address evmModuleAddr gethcommon.Address ) + +// NativeToWei converts a "unibi" amount to "wei" units for the EVM. +// +// Micronibi, labeled "unibi", is the base denomination for NIBI. For NIBI to be +// considered "ether" by Ethereum clients, we need to follow the constraint +// equation: 1 NIBI = 10^18 wei. +// +// Since 1 NIBI = 10^6 micronibi = 10^6 unibi, the following is true: +// 10^0 unibi == 10^12 wei +func NativeToWei(evmDenomAmount *big.Int) (weiAmount *big.Int) { + pow10 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil) + return new(big.Int).Mul(evmDenomAmount, pow10) +} + +// WeiToNative converts a "wei" amount to "unibi" units. +// +// Micronibi, labeled "unibi", is the base denomination for NIBI. For NIBI to be +// considered "ether" by Ethereum clients, we need to follow the constraint +// equation: 1 NIBI = 10^18 wei. +// +// Since 1 NIBI = 10^6 micronibi = 10^6 unibi, the following is true: +// 10^0 unibi == 10^12 wei +func WeiToNative(weiAmount *big.Int) (evmDenomAmount *big.Int) { + pow10 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil) + return new(big.Int).Quo(weiAmount, pow10) +} + +// ParseWeiAsMultipleOfMicronibi truncates the given wei amount to the highest +// multiple of 1 micronibi (10^12 wei). It returns the truncated value and an +// error if the input value is too small. +// +// Args: +// - weiInt (*big.Int): The amount of wei to be parsed. +// +// Returns: +// - newWeiInt (*big.Int): The truncated amount of wei, which is a multiple of 1 micronibi. +// - err (error): An error indicating if the input value is within the range +// (1, 10^12) inclusive. +// +// Example: +// +// Input number: 123456789012345678901234567890 +// Parsed number: 123456789012 * 10^12 +func ParseWeiAsMultipleOfMicronibi(weiInt *big.Int) (newWeiInt *big.Int, err error) { + // if "weiValue" is nil, 0, or negative, early return + if weiInt == nil || !(weiInt.Cmp(big.NewInt(0)) > 0) { + return weiInt, nil + } + + // err if weiInt is too small + tenPow12 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil) + if weiInt.Cmp(tenPow12) < 0 { + return weiInt, fmt.Errorf( + "wei amount is too small (%s), cannot transfer less than 1 micronibi. 10^18 wei == 1 NIBI == 10^6 micronibi", weiInt) + } + + // truncate to highest micronibi amount + newWeiInt = NativeToWei(WeiToNative(weiInt)) + return newWeiInt, nil +} diff --git a/x/evm/evm_test.go b/x/evm/evm_test.go index 8da03c1c3..59ae0ba4b 100644 --- a/x/evm/evm_test.go +++ b/x/evm/evm_test.go @@ -2,7 +2,9 @@ package evm_test import ( + "math/big" "strconv" + "strings" "testing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -140,3 +142,66 @@ func (s *TestSuite) TestModuleAddressEVM() { s.Equal(nibiAddr.String(), resp.Address) } } + +func (s *TestSuite) TestWeiConversion() { + { + unibiAmt := big.NewInt(420) + s.Equal( + unibiAmt, + evm.WeiToNative(evm.NativeToWei(unibiAmt)), + "native -> wei -> native should be an identity operation", + ) + + weiAmt := evm.NativeToWei(unibiAmt) + want := "420" + strings.Repeat("0", 12) + s.Equal(weiAmt.String(), want) + } + + tenPow12 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil) + for _, tc := range []struct { + weiAmtIn string + want *big.Int + wantError string + }{ + { + // Input number: 123456789012345678901234567890 + // Parsed number: 123456789012345678 * 10^12 + weiAmtIn: "123456789012345678901234567890", + want: evm.NativeToWei(big.NewInt(123456789012345678)), + wantError: "", + }, + { + weiAmtIn: "123456789012345678901234567890", + want: evm.NativeToWei(big.NewInt(123456789012345678)), + wantError: "", + }, + { + weiAmtIn: "0", + want: big.NewInt(0), + wantError: "", + }, + { + weiAmtIn: "1", + wantError: "cannot transfer less than 1 micronibi.", + }, + { + weiAmtIn: new(big.Int).Sub( + tenPow12, big.NewInt(1), + ).String(), + wantError: "cannot transfer less than 1 micronibi.", + }, + { + weiAmtIn: "500", + wantError: "cannot transfer less than 1 micronibi.", + }, + } { + weiAmtIn, _ := new(big.Int).SetString(tc.weiAmtIn, 10) + got, err := evm.ParseWeiAsMultipleOfMicronibi(weiAmtIn) + if tc.wantError != "" { + s.Require().ErrorContains(err, tc.wantError) + return + } + s.NoError(err) + s.Require().Equal(tc.want.String(), got.String()) + } +} diff --git a/x/evm/evmtest/test_deps.go b/x/evm/evmtest/test_deps.go index c02b8527f..e1c5076fb 100644 --- a/x/evm/evmtest/test_deps.go +++ b/x/evm/evmtest/test_deps.go @@ -49,7 +49,7 @@ func NewTestDeps() TestDeps { } } -func (deps *TestDeps) StateDB() *statedb.StateDB { +func (deps TestDeps) StateDB() *statedb.StateDB { return statedb.New(deps.Ctx, &deps.Chain.EvmKeeper, statedb.NewEmptyTxConfig( gethcommon.BytesToHash(deps.Ctx.HeaderHash().Bytes()), diff --git a/x/evm/evmtest/tx.go b/x/evm/evmtest/tx.go index 5d09c4d5e..0256d17b3 100644 --- a/x/evm/evmtest/tx.go +++ b/x/evm/evmtest/tx.go @@ -241,3 +241,32 @@ func GenerateAndSignEthTxMsg( keyringSigner := deps.Sender.KeyringSigner return txMsg, txMsg.Sign(gethSigner, keyringSigner) } + +func TransferWei( + deps *TestDeps, + to gethcommon.Address, + amountWei *big.Int, +) error { + ethAcc := deps.Sender + var innerTxData []byte = nil + var accessList gethcore.AccessList = nil + ethTxMsg, err := NewEthTxMsgFromTxData( + deps, + gethcore.LegacyTxType, + innerTxData, + deps.StateDB().GetNonce(ethAcc.EthAddr), + &to, + amountWei, + gethparams.TxGas, + accessList, + ) + if err != nil { + return fmt.Errorf("error while transferring wei: %w", err) + } + + _, err = deps.Chain.EvmKeeper.EthereumTx(deps.GoCtx(), ethTxMsg) + if err != nil { + return fmt.Errorf("error while transferring wei: %w", err) + } + return err +} diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index e4dc7e78b..b06592142 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -58,9 +58,9 @@ func (k Keeper) EthAccount( acct := k.GetAccountOrEmpty(ctx, addr) return &evm.QueryEthAccountResponse{ - Balance: acct.Balance.String(), - CodeHash: gethcommon.BytesToHash(acct.CodeHash).Hex(), - Nonce: acct.Nonce, + BalanceWei: evm.NativeToWei(acct.BalanceEvmDenom).String(), + CodeHash: gethcommon.BytesToHash(acct.CodeHash).Hex(), + Nonce: acct.Nonce, }, nil } @@ -139,8 +139,8 @@ func (k Keeper) ValidatorAccount( } // Balance: Implements the gRPC query for "/eth.evm.v1.Query/Balance". -// Balance retrieves the balance of an Ethereum address in "Ether", which -// actually refers to NIBI tokens on Nibiru EVM. +// Balance retrieves the balance of an Ethereum address in "wei", the smallest +// unit of "Ether". Ether refers to NIBI tokens on Nibiru EVM. // // Parameters: // - goCtx: The context.Context object representing the request context. @@ -156,7 +156,8 @@ func (k Keeper) Balance(goCtx context.Context, req *evm.QueryBalanceRequest) (*e ctx := sdk.UnwrapSDKContext(goCtx) balanceInt := k.GetEvmGasBalance(ctx, gethcommon.HexToAddress(req.Address)) return &evm.QueryBalanceResponse{ - Balance: balanceInt.String(), + Balance: balanceInt.String(), + BalanceWei: evm.NativeToWei(balanceInt).String(), }, nil } @@ -444,7 +445,7 @@ func (k Keeper) EstimateGasForEvmCallType( if errors.Is(err, core.ErrIntrinsicGas) { return true, nil, nil // Special case, raise gas limit } - return true, nil, err // Bail out + return true, nil, fmt.Errorf("error applying EVM message to StateDB: %w", err) // Bail out } return len(rsp.VmError) > 0, rsp, nil } @@ -459,15 +460,15 @@ func (k Keeper) EstimateGasForEvmCallType( if hi == gasCap { failed, result, err := executable(hi) if err != nil { - return nil, err + return nil, fmt.Errorf("eth call exec error: %w", err) } if failed { if result != nil && result.VmError != vm.ErrOutOfGas.Error() { if result.VmError == vm.ErrExecutionReverted.Error() { - return nil, evm.NewExecErrorWithReason(result.Ret) + return nil, fmt.Errorf("VMError: %w", evm.NewExecErrorWithReason(result.Ret)) } - return nil, errors.New(result.VmError) + return nil, fmt.Errorf("VMError: %s", result.VmError) } // Otherwise, the specified gas cap is too low return nil, fmt.Errorf("gas required exceeds allowance (%d)", gasCap) diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index aeb6f1eb8..f50fda474 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -29,7 +29,8 @@ type TestCase[In, Out any] struct { req In, wantResp Out, ) - wantErr string + onTestEnd func(deps *evmtest.TestDeps) + wantErr string } func InvalidEthAddr() string { return "0x0000" } @@ -149,9 +150,9 @@ func (s *Suite) TestQueryEthAccount() { Address: InvalidEthAddr(), } wantResp = &evm.QueryEthAccountResponse{ - Balance: "0", - CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), - Nonce: 0, + BalanceWei: "0", + CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), + Nonce: 0, } return req, wantResp }, @@ -176,9 +177,9 @@ func (s *Suite) TestQueryEthAccount() { Address: deps.Sender.EthAddr.Hex(), } wantResp = &evm.QueryEthAccountResponse{ - Balance: "420", - CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), - Nonce: 0, + BalanceWei: "420" + strings.Repeat("0", 12), + CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), + Nonce: 0, } return req, wantResp }, @@ -543,7 +544,7 @@ func (s *Suite) TestQueryBalance() { Address: InvalidEthAddr(), } wantResp = &evm.QueryBalanceResponse{ - Balance: "0", + BalanceWei: "0", } return req, wantResp }, @@ -556,7 +557,8 @@ func (s *Suite) TestQueryBalance() { Address: evmtest.NewEthAccInfo().EthAddr.String(), } wantResp = &evm.QueryBalanceResponse{ - Balance: "0", + Balance: "0", + BalanceWei: "0", } return req, wantResp }, @@ -581,7 +583,8 @@ func (s *Suite) TestQueryBalance() { Address: deps.Sender.EthAddr.Hex(), } wantResp = &evm.QueryBalanceResponse{ - Balance: "420", + Balance: "420", + BalanceWei: "420" + strings.Repeat("0", 12), } return req, wantResp }, @@ -681,7 +684,8 @@ func (s *Suite) TestEstimateGasForEvmCallType() { }, { name: "happy: estimate gas for transfer", - setup: func(deps *evmtest.TestDeps) { + scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { + // fund the account chain := deps.Chain ethAddr := deps.Sender.EthAddr coins := sdk.Coins{sdk.NewInt64Coin(evm.DefaultEVMDenom, 1000)} @@ -690,10 +694,17 @@ func (s *Suite) TestEstimateGasForEvmCallType() { err = chain.BankKeeper.SendCoinsFromModuleToAccount( deps.Ctx, evm.ModuleName, ethAddr.Bytes(), coins) s.Require().NoError(err) - }, - scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { + + // assert balance of 1000 * 10^12 wei + resp, _ := deps.Chain.EvmKeeper.Balance(deps.GoCtx(), &evm.QueryBalanceRequest{ + Address: deps.Sender.EthAddr.Hex(), + }) + s.Equal("1000", resp.Balance) + s.Require().Equal("1000"+strings.Repeat("0", 12), resp.BalanceWei) + + // Send Eth call to transfer from the account - 5 * 10^12 wei recipient := evmtest.NewEthAccInfo().EthAddr - amountToSend := hexutil.Big(*big.NewInt(10)) + amountToSend := hexutil.Big(*evm.NativeToWei(big.NewInt(5))) gasLimitArg := hexutil.Uint64(100000) jsonTxArgs, err := json.Marshal(&evm.JsonTxArgs{ @@ -713,12 +724,14 @@ func (s *Suite) TestEstimateGasForEvmCallType() { return req, wantResp }, wantErr: "", + onTestEnd: func(deps *evmtest.TestDeps) { + }, }, { name: "sad: insufficient balance for transfer", scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { recipient := evmtest.NewEthAccInfo().EthAddr - amountToSend := hexutil.Big(*big.NewInt(10)) + amountToSend := hexutil.Big(*evm.NativeToWei(big.NewInt(10))) jsonTxArgs, err := json.Marshal(&evm.JsonTxArgs{ From: &deps.Sender.EthAddr, @@ -752,6 +765,10 @@ func (s *Suite) TestEstimateGasForEvmCallType() { } s.Assert().NoError(err) s.EqualValues(wantResp, gotResp) + + if tc.onTestEnd != nil { + tc.onTestEnd(&deps) + } }) } } @@ -781,9 +798,8 @@ func (s *Suite) TestTraceTx() { wantErr: "", }, { - "happy: trace erc-20 transfer tx", - nil, - func(deps *evmtest.TestDeps) (req In, wantResp Out) { + name: "happy: trace erc-20 transfer tx", + scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { txMsg, predecessors := evmtest.DeployAndExecuteERC20Transfer(deps, s.T()) req = &evm.QueryTraceTxRequest{ @@ -793,7 +809,7 @@ func (s *Suite) TestTraceTx() { wantResp = TraceERC20Transfer() return req, wantResp }, - "", + wantErr: "", }, } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 53f95861a..bbb5dc360 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -82,8 +82,8 @@ func NewKeeper( // GetEvmGasBalance: Implements `evm.EVMKeeper` from // "github.com/NibiruChain/nibiru/app/ante/evm": Load account's balance of gas -// tokens for EVM execution -func (k *Keeper) GetEvmGasBalance(ctx sdk.Context, addr gethcommon.Address) *big.Int { +// tokens for EVM execution in EVM denom units. +func (k *Keeper) GetEvmGasBalance(ctx sdk.Context, addr gethcommon.Address) (balance *big.Int) { nibiruAddr := sdk.AccAddress(addr.Bytes()) evmParams := k.GetParams(ctx) evmDenom := evmParams.GetEvmDenom() @@ -91,8 +91,7 @@ func (k *Keeper) GetEvmGasBalance(ctx sdk.Context, addr gethcommon.Address) *big if evmDenom == "" { return big.NewInt(-1) } - coin := k.bankKeeper.GetBalance(ctx, nibiruAddr, evmDenom) - return coin.Amount.BigInt() + return k.bankKeeper.GetBalance(ctx, nibiruAddr, evmDenom).Amount.BigInt() } func (k Keeper) EthChainID(ctx sdk.Context) *big.Int { diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index 1c81893b3..0ddc2de45 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -10,8 +10,8 @@ type Suite struct { suite.Suite } -// TestKeeperSuite: Runs all the tests in the suite. -func TestKeeperSuite(t *testing.T) { +// TestSuite: Runs all the tests in the suite. +func TestSuite(t *testing.T) { s := new(Suite) suite.Run(t, s) } diff --git a/x/evm/keeper/msg_ethereum_tx_test.go b/x/evm/keeper/msg_ethereum_tx_test.go index 2e7496fc9..c85fd7d7f 100644 --- a/x/evm/keeper/msg_ethereum_tx_test.go +++ b/x/evm/keeper/msg_ethereum_tx_test.go @@ -188,12 +188,12 @@ func (s *Suite) TestMsgEthereumTx_SimpleTransfer() { deps := evmtest.NewTestDeps() ethAcc := deps.Sender - amount := int64(123) + fundedAmount := evm.NativeToWei(big.NewInt(123)).Int64() err := testapp.FundAccount( deps.Chain.BankKeeper, deps.Ctx, deps.Sender.NibiruAddr, - sdk.NewCoins(sdk.NewInt64Coin("unibi", amount)), + sdk.NewCoins(sdk.NewInt64Coin("unibi", fundedAmount)), ) s.Require().NoError(err) @@ -208,7 +208,7 @@ func (s *Suite) TestMsgEthereumTx_SimpleTransfer() { innerTxData, deps.StateDB().GetNonce(ethAcc.EthAddr), &to, - big.NewInt(amount), + big.NewInt(fundedAmount), gethparams.TxGas, accessList, ) @@ -229,7 +229,7 @@ func (s *Suite) TestMsgEthereumTx_SimpleTransfer() { &evm.EventTransfer{ Sender: ethAcc.EthAddr.String(), Recipient: to.String(), - Amount: strconv.FormatInt(amount, 10), + Amount: strconv.FormatInt(fundedAmount, 10), }, ) } diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 2f5d4fcf1..55c2dc462 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -421,19 +421,31 @@ func (k *Keeper) ApplyEvmMsg(ctx sdk.Context, } leftoverGas -= intrinsicGas - // access list preparation is moved from ante handler to here, because it's needed when `ApplyMessage` is called - // under contexts where ante handlers are not run, for example `eth_call` and `eth_estimateGas`. - stateDB.PrepareAccessList(msg.From(), msg.To(), evmObj.ActivePrecompiles(params.Rules{}), msg.AccessList()) + // access list preparation is moved from ante handler to here, because it's + // needed when `ApplyMessage` is called under contexts where ante handlers + // are not run, for example `eth_call` and `eth_estimateGas`. + stateDB.PrepareAccessList( + msg.From(), + msg.To(), + evmObj.ActivePrecompiles(params.Rules{}), + msg.AccessList(), + ) + + msgWei, err := ParseWeiAsMultipleOfMicronibi(msg.Value()) + if err != nil { + return nil, err + // return nil, fmt.Errorf("cannot use \"value\" in wei that can't be converted to unibi. %s is not divisible by 10^12", msg.Value()) + } if contractCreation { // take over the nonce management from evm: // - reset sender's nonce to msg.Nonce() before calling evm. // - increase sender's nonce by one no matter the result. stateDB.SetNonce(sender.Address(), msg.Nonce()) - ret, _, leftoverGas, vmErr = evmObj.Create(sender, msg.Data(), leftoverGas, msg.Value()) + ret, _, leftoverGas, vmErr = evmObj.Create(sender, msg.Data(), leftoverGas, msgWei) stateDB.SetNonce(sender.Address(), msg.Nonce()+1) } else { - ret, leftoverGas, vmErr = evmObj.Call(sender, *msg.To(), msg.Data(), leftoverGas, msg.Value()) + ret, leftoverGas, vmErr = evmObj.Call(sender, *msg.To(), msg.Data(), leftoverGas, msgWei) } // After EIP-3529: refunds are capped to gasUsed / 5 @@ -460,7 +472,7 @@ func (k *Keeper) ApplyEvmMsg(ctx sdk.Context, // The dirty states in `StateDB` is either committed or discarded after return if commit { if err := stateDB.Commit(); err != nil { - return nil, errors.Wrap(err, "failed to commit stateDB") + return nil, fmt.Errorf("failed to commit stateDB: %w", err) } } @@ -489,6 +501,24 @@ func (k *Keeper) ApplyEvmMsg(ctx sdk.Context, }, nil } +func ParseWeiAsMultipleOfMicronibi(weiInt *big.Int) (newWeiInt *big.Int, err error) { + // if "weiValue" is nil, 0, or negative, early return + if weiInt == nil || !(weiInt.Cmp(big.NewInt(0)) > 0) { + return weiInt, nil + } + + // err if weiInt is too small + tenPow12 := new(big.Int).Exp(big.NewInt(10), big.NewInt(12), nil) + if weiInt.Cmp(tenPow12) < 0 { + return weiInt, fmt.Errorf( + "wei amount is too small (%s), cannot transfer less than 1 micronibi. 10^18 wei == 1 NIBI == 10^6 micronibi", weiInt) + } + + // truncate to highest micronibi amount + newWeiInt = evm.NativeToWei(evm.WeiToNative(weiInt)) + return newWeiInt, nil +} + // CreateFunToken is a gRPC transaction message for creating fungible token // ("FunToken") a mapping between a bank coin and ERC20 token. // diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index 3ce4ba434..7311dc63e 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -30,7 +30,7 @@ func (k *Keeper) GetAccount(ctx sdk.Context, addr gethcommon.Address) *statedb.A return nil } - acct.Balance = k.GetEvmGasBalance(ctx, addr) + acct.BalanceEvmDenom = k.GetEvmGasBalance(ctx, addr) return acct } @@ -67,13 +67,13 @@ func (k *Keeper) ForEachStorage( // SetAccBalance update account's balance, compare with current balance first, then decide to mint or burn. func (k *Keeper) SetAccBalance( - ctx sdk.Context, addr gethcommon.Address, amount *big.Int, + ctx sdk.Context, addr gethcommon.Address, amountEvmDenom *big.Int, ) error { nativeAddr := sdk.AccAddress(addr.Bytes()) params := k.GetParams(ctx) - coin := k.bankKeeper.GetBalance(ctx, nativeAddr, params.EvmDenom) - balance := coin.Amount.BigInt() - delta := new(big.Int).Sub(amount, balance) + balance := k.bankKeeper.GetBalance(ctx, nativeAddr, params.EvmDenom).Amount.BigInt() + delta := new(big.Int).Sub(amountEvmDenom, balance) + switch delta.Sign() { case 1: // mint @@ -126,7 +126,7 @@ func (k *Keeper) SetAccount( k.accountKeeper.SetAccount(ctx, acct) - if err := k.SetAccBalance(ctx, addr, account.Balance); err != nil { + if err := k.SetAccBalance(ctx, addr, account.BalanceEvmDenom); err != nil { return err } @@ -213,7 +213,7 @@ func (k *Keeper) GetAccountOrEmpty( // empty account return statedb.Account{ - Balance: new(big.Int), - CodeHash: evm.EmptyCodeHash, + BalanceEvmDenom: new(big.Int), + CodeHash: evm.EmptyCodeHash, } } diff --git a/x/evm/keeper/statedb_test.go b/x/evm/keeper/statedb_test.go new file mode 100644 index 000000000..2e81c81d9 --- /dev/null +++ b/x/evm/keeper/statedb_test.go @@ -0,0 +1,92 @@ +// Copyright (c) 2023-2024 Nibi, Inc. +package keeper_test + +import ( + "math/big" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/NibiruChain/nibiru/x/common/testutil/testapp" + "github.com/NibiruChain/nibiru/x/evm" + "github.com/NibiruChain/nibiru/x/evm/evmtest" + + gethcommon "github.com/ethereum/go-ethereum/common" +) + +// TestStateDBBalance tests the behavior of the StateDB with regards to account +// balances, ensuring correct conversion between native tokens (unibi) and EVM +// tokens (wei), as well as proper balance updates during transfers. +func (s *Suite) TestStateDBBalance() { + deps := evmtest.NewTestDeps() + { + db := deps.StateDB() + s.Equal("0", db.GetBalance(deps.Sender.EthAddr).String()) + + s.T().Log("fund account in unibi. See expected wei amount.") + err := testapp.FundAccount( + deps.Chain.BankKeeper, + deps.Ctx, + deps.Sender.NibiruAddr, + sdk.NewCoins(sdk.NewInt64Coin(evm.DefaultEVMDenom, 42)), + ) + s.NoError(err) + s.Equal( + "42"+strings.Repeat("0", 12), + db.GetBalance(deps.Sender.EthAddr).String(), + ) + s.Equal( + "42", + deps.Chain.BankKeeper.GetBalance(deps.Ctx, deps.Sender.NibiruAddr, evm.DefaultEVMDenom).Amount.String(), + ) + } + + s.T().Log("Send via EVM transfer. See expected wei amounts.") + to := gethcommon.HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") + { + err := evmtest.TransferWei(&deps, to, evm.NativeToWei(big.NewInt(12))) + s.Require().NoError(err) + db := deps.StateDB() + s.Equal( + "30"+strings.Repeat("0", 12), + db.GetBalance(deps.Sender.EthAddr).String(), + ) + s.Equal( + "12"+strings.Repeat("0", 12), + db.GetBalance(to).String(), + ) + + s.T().Log("Send via EVM transfer with too little wei. Should error") + err = evmtest.TransferWei(&deps, to, big.NewInt(12)) + s.Require().ErrorContains(err, "wei amount is too small") + } + + s.T().Log("Send via bank transfer from account to account. See expected wei amounts.") + { + deps := evmtest.NewTestDeps() + toNibiAddr := evmtest.EthAddrToNibiruAddr(to) + err := testapp.FundAccount( + deps.Chain.BankKeeper, + deps.Ctx, + deps.Sender.NibiruAddr, + sdk.NewCoins(sdk.NewInt64Coin(evm.DefaultEVMDenom, 8)), + ) + s.NoError(err) + err = deps.Chain.BankKeeper.SendCoins( + deps.Ctx, deps.Sender.NibiruAddr, + toNibiAddr, + sdk.NewCoins(sdk.NewInt64Coin(evm.DefaultEVMDenom, 3)), + ) + s.NoError(err) + + db := deps.StateDB() + s.Equal( + "3"+strings.Repeat("0", 12), + db.GetBalance(to).String(), + ) + s.Equal( + "5"+strings.Repeat("0", 12), + db.GetBalance(deps.Sender.EthAddr).String(), + ) + } +} diff --git a/x/evm/query.pb.go b/x/evm/query.pb.go index 3463410a1..609bc55fe 100644 --- a/x/evm/query.pb.go +++ b/x/evm/query.pb.go @@ -77,8 +77,8 @@ var xxx_messageInfo_QueryEthAccountRequest proto.InternalMessageInfo // QueryEthAccountResponse is the response type for the Query/Account RPC method. type QueryEthAccountResponse struct { - // balance is the balance of the EVM denomination. - Balance string `protobuf:"bytes,1,opt,name=balance,proto3" json:"balance,omitempty"` + // balance_wei is the balance of wei (attoether, where NIBI is ether). + BalanceWei string `protobuf:"bytes,1,opt,name=balance_wei,json=balanceWei,proto3" json:"balance_wei,omitempty"` // code_hash is the hex-formatted code bytes from the EOA. CodeHash string `protobuf:"bytes,2,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"` // nonce is the account's sequence number. @@ -118,9 +118,9 @@ func (m *QueryEthAccountResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryEthAccountResponse proto.InternalMessageInfo -func (m *QueryEthAccountResponse) GetBalance() string { +func (m *QueryEthAccountResponse) GetBalanceWei() string { if m != nil { - return m.Balance + return m.BalanceWei } return "" } @@ -390,8 +390,10 @@ var xxx_messageInfo_QueryBalanceRequest proto.InternalMessageInfo // QueryBalanceResponse is the response type for the Query/Balance RPC method. type QueryBalanceResponse struct { - // balance is the balance of the EVM denomination. + // balance is the balance of the EVM denomination Balance string `protobuf:"bytes,1,opt,name=balance,proto3" json:"balance,omitempty"` + // balance is the balance of the EVM denomination in units of wei. + BalanceWei string `protobuf:"bytes,2,opt,name=balance_wei,json=balanceWei,proto3" json:"balance_wei,omitempty"` } func (m *QueryBalanceResponse) Reset() { *m = QueryBalanceResponse{} } @@ -434,6 +436,13 @@ func (m *QueryBalanceResponse) GetBalance() string { return "" } +func (m *QueryBalanceResponse) GetBalanceWei() string { + if m != nil { + return m.BalanceWei + } + return "" +} + // QueryStorageRequest is the request type for the Query/Storage RPC method. type QueryStorageRequest struct { // address is the ethereum hex address to query the storage state for. @@ -1411,104 +1420,106 @@ func init() { func init() { proto.RegisterFile("eth/evm/v1/query.proto", fileDescriptor_ffa36cdc5add14ed) } var fileDescriptor_ffa36cdc5add14ed = []byte{ - // 1550 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0xc6, 0x4e, 0xec, 0x3c, 0xa7, 0x4d, 0x98, 0xa6, 0x4d, 0xb2, 0x4d, 0xec, 0x64, 0x43, - 0x93, 0xb4, 0xb4, 0xbb, 0x4d, 0x40, 0x20, 0x2a, 0x2a, 0xd4, 0x44, 0x69, 0x28, 0xfd, 0xa3, 0x62, - 0x22, 0x0e, 0x20, 0x64, 0x8d, 0xed, 0xc9, 0x7a, 0x15, 0x7b, 0xc7, 0xdd, 0x19, 0x07, 0x87, 0x92, - 0x0b, 0xbd, 0x20, 0x21, 0x44, 0x25, 0xbe, 0x40, 0x4f, 0x7c, 0x05, 0xbe, 0x42, 0x8f, 0x95, 0x10, - 0x12, 0xe2, 0x50, 0x50, 0xcb, 0x81, 0x33, 0x47, 0x4e, 0x68, 0x66, 0x67, 0xbc, 0x6b, 0x7b, 0x9d, - 0x50, 0xfe, 0xdc, 0x38, 0xed, 0xce, 0xcc, 0x7b, 0xef, 0xf7, 0x9b, 0x99, 0x37, 0xef, 0xfd, 0xe0, - 0x0c, 0xe1, 0x35, 0x87, 0xec, 0x37, 0x9c, 0xfd, 0x35, 0xe7, 0x5e, 0x8b, 0x04, 0x07, 0x76, 0x33, - 0xa0, 0x9c, 0x22, 0x20, 0xbc, 0x66, 0x93, 0xfd, 0x86, 0xbd, 0xbf, 0x66, 0x5e, 0xa8, 0x50, 0xd6, - 0xa0, 0xcc, 0x29, 0x63, 0x46, 0x42, 0x23, 0x67, 0x7f, 0xad, 0x4c, 0x38, 0x5e, 0x73, 0x9a, 0xd8, - 0xf5, 0x7c, 0xcc, 0x3d, 0xea, 0x87, 0x7e, 0xe6, 0x54, 0x2c, 0x9e, 0x70, 0x0f, 0x67, 0x4f, 0xc5, - 0x66, 0x79, 0x5b, 0x9b, 0xba, 0xd4, 0xa5, 0xf2, 0xd7, 0x11, 0x7f, 0x6a, 0x76, 0xce, 0xa5, 0xd4, - 0xad, 0x13, 0x07, 0x37, 0x3d, 0x07, 0xfb, 0x3e, 0xe5, 0x32, 0x3a, 0x53, 0xab, 0x05, 0xb5, 0x2a, - 0x47, 0xe5, 0xd6, 0xae, 0xc3, 0xbd, 0x06, 0x61, 0x1c, 0x37, 0x9a, 0xa1, 0x81, 0xf5, 0x16, 0x9c, - 0x79, 0x4f, 0x30, 0xdc, 0xe2, 0xb5, 0x6b, 0x95, 0x0a, 0x6d, 0xf9, 0xbc, 0x48, 0xee, 0xb5, 0x08, - 0xe3, 0x68, 0x06, 0x32, 0xb8, 0x5a, 0x0d, 0x08, 0x63, 0x33, 0xc6, 0x82, 0xb1, 0x3a, 0x56, 0xd4, - 0xc3, 0x2b, 0xd9, 0x2f, 0x1e, 0x15, 0x86, 0x7e, 0x7b, 0x54, 0x18, 0xb2, 0x76, 0x61, 0xba, 0xcf, - 0x9b, 0x35, 0xa9, 0xcf, 0x88, 0x70, 0x2f, 0xe3, 0x3a, 0xf6, 0x2b, 0x44, 0xbb, 0xab, 0x21, 0x3a, - 0x0b, 0x63, 0x15, 0x5a, 0x25, 0xa5, 0x1a, 0x66, 0xb5, 0x99, 0x61, 0xb9, 0x96, 0x15, 0x13, 0xef, - 0x60, 0x56, 0x43, 0x53, 0x30, 0xe2, 0x53, 0xe1, 0x94, 0x5a, 0x30, 0x56, 0xd3, 0xc5, 0x70, 0x60, - 0xbd, 0x0d, 0xb3, 0x12, 0xe7, 0x8e, 0x57, 0xf6, 0x82, 0xd6, 0xdf, 0x20, 0x7a, 0x00, 0x66, 0x52, - 0x80, 0x88, 0x6b, 0x72, 0x04, 0x64, 0x42, 0x96, 0x09, 0x18, 0xc1, 0x68, 0x58, 0x32, 0xea, 0x8c, - 0xd1, 0x39, 0x38, 0x89, 0xc3, 0x40, 0x25, 0xbf, 0xd5, 0x28, 0x93, 0x40, 0x71, 0x3e, 0xa1, 0x66, - 0xef, 0xc8, 0x49, 0xeb, 0x26, 0xcc, 0x49, 0xe8, 0x0f, 0x70, 0xdd, 0xab, 0x62, 0x4e, 0x83, 0x1e, - 0xfa, 0x8b, 0x30, 0x5e, 0xa1, 0x3e, 0x2b, 0x75, 0x33, 0xc8, 0x89, 0xb9, 0x6b, 0x7d, 0xfb, 0xf8, - 0xd2, 0x80, 0xf9, 0x01, 0xd1, 0xd4, 0x5e, 0x56, 0x60, 0x42, 0xb3, 0xea, 0x8e, 0xa8, 0xc9, 0x5e, - 0xfb, 0xf7, 0xb6, 0xf6, 0x26, 0x9c, 0x92, 0x64, 0x36, 0xc2, 0x9b, 0x7d, 0x91, 0x0b, 0xb9, 0x0c, - 0x53, 0xdd, 0xae, 0xc7, 0xa5, 0x8d, 0x75, 0x53, 0x81, 0xbd, 0xcf, 0x69, 0x80, 0xdd, 0xe3, 0xc1, - 0xd0, 0x24, 0xa4, 0xf6, 0xc8, 0x81, 0xca, 0x30, 0xf1, 0x1b, 0x83, 0xbf, 0xa8, 0xe0, 0x3b, 0xc1, - 0x14, 0xfc, 0x14, 0x8c, 0xec, 0xe3, 0x7a, 0x4b, 0x83, 0x87, 0x03, 0xeb, 0x75, 0x98, 0x94, 0xd6, - 0x9b, 0xb4, 0xfa, 0x42, 0x9b, 0x5c, 0x81, 0x97, 0x62, 0x7e, 0x0a, 0x02, 0x41, 0x5a, 0x64, 0xbb, - 0xf4, 0x1a, 0x2f, 0xca, 0x7f, 0xeb, 0x53, 0x40, 0xd2, 0x70, 0xa7, 0x7d, 0x8b, 0xba, 0x4c, 0x43, - 0x20, 0x48, 0xcb, 0x37, 0x12, 0xc6, 0x97, 0xff, 0xe8, 0x3a, 0x40, 0x54, 0x43, 0xe4, 0xde, 0x72, - 0xeb, 0xcb, 0x76, 0x58, 0x70, 0x6c, 0x51, 0x70, 0xec, 0xb0, 0x2a, 0xa9, 0x82, 0x63, 0xdf, 0x8d, - 0x8e, 0xaa, 0x18, 0xf3, 0x8c, 0x91, 0x7c, 0x60, 0xa8, 0x83, 0xd5, 0xe0, 0x8a, 0xe7, 0x12, 0xa4, - 0xeb, 0xd4, 0x15, 0xbb, 0x4b, 0xad, 0xe6, 0xd6, 0x27, 0xec, 0xa8, 0xc0, 0xd9, 0xb7, 0xa8, 0x5b, - 0x94, 0x8b, 0x68, 0x3b, 0x81, 0xce, 0xca, 0xb1, 0x74, 0x42, 0x84, 0x38, 0x1f, 0x6b, 0x4a, 0x9d, - 0xc0, 0x5d, 0x1c, 0xe0, 0x86, 0x3e, 0x01, 0x6b, 0x5b, 0x51, 0xd3, 0xb3, 0x8a, 0xda, 0x65, 0x18, - 0x6d, 0xca, 0x19, 0x79, 0x34, 0xb9, 0x75, 0x14, 0x27, 0x17, 0xda, 0x6e, 0xa4, 0x1f, 0x3f, 0x2d, - 0x0c, 0x15, 0x95, 0x9d, 0xf5, 0x9d, 0x01, 0x27, 0xb7, 0x78, 0x6d, 0x13, 0xd7, 0xeb, 0xb1, 0xd3, - 0xc5, 0x81, 0xcb, 0xf4, 0x3d, 0x88, 0x7f, 0x34, 0x0d, 0x19, 0x17, 0xb3, 0x52, 0x05, 0x37, 0xd5, - 0x93, 0x18, 0x75, 0x31, 0xdb, 0xc4, 0x4d, 0xf4, 0x31, 0x4c, 0x36, 0x03, 0xda, 0xa4, 0x8c, 0x04, - 0x9d, 0x67, 0x25, 0x9e, 0xc4, 0xf8, 0xc6, 0xfa, 0x1f, 0x4f, 0x0b, 0xb6, 0xeb, 0xf1, 0x5a, 0xab, - 0x6c, 0x57, 0x68, 0xc3, 0x51, 0xb5, 0x3f, 0xfc, 0x5c, 0x62, 0xd5, 0x3d, 0x87, 0x1f, 0x34, 0x09, - 0xb3, 0x37, 0xa3, 0xf7, 0x5c, 0x9c, 0xd0, 0xb1, 0xf4, 0x5b, 0x9c, 0x85, 0x6c, 0xa5, 0x86, 0x3d, - 0xbf, 0xe4, 0x55, 0x67, 0xd2, 0x0b, 0xc6, 0x6a, 0xaa, 0x98, 0x91, 0xe3, 0x1b, 0x55, 0x6b, 0x05, - 0x4e, 0x6d, 0x31, 0xee, 0x35, 0x30, 0x27, 0xdb, 0x38, 0x3a, 0x82, 0x49, 0x48, 0xb9, 0x38, 0x24, - 0x9f, 0x2e, 0x8a, 0x5f, 0xeb, 0xf7, 0x94, 0xbe, 0xc7, 0x00, 0x57, 0xc8, 0x4e, 0x5b, 0xef, 0xf3, - 0x15, 0x48, 0x35, 0x98, 0xab, 0x4e, 0x6a, 0x36, 0x7e, 0x52, 0xb7, 0x99, 0xbb, 0xc5, 0x6b, 0x24, - 0x20, 0xad, 0xc6, 0x4e, 0xbb, 0x28, 0xac, 0xd0, 0x15, 0x18, 0xe7, 0xc2, 0xbd, 0x54, 0xa1, 0xfe, - 0xae, 0xe7, 0xca, 0x3d, 0xe6, 0xd6, 0xa7, 0xe3, 0x5e, 0x32, 0xfc, 0xa6, 0x5c, 0x2e, 0xe6, 0x78, - 0x34, 0x40, 0x57, 0x61, 0xbc, 0x19, 0x90, 0x2a, 0xa9, 0x10, 0xc6, 0x68, 0xc0, 0x66, 0xd2, 0x32, - 0x71, 0x8e, 0x40, 0xec, 0x32, 0x17, 0x75, 0xb0, 0x5c, 0xa7, 0x95, 0x3d, 0x5d, 0x71, 0x46, 0xe4, - 0x39, 0xe4, 0xe4, 0x5c, 0x58, 0x6f, 0xd0, 0x3c, 0x40, 0x68, 0x22, 0x9f, 0xc5, 0xa8, 0x7c, 0x16, - 0x63, 0x72, 0x46, 0xf6, 0x8e, 0x4d, 0xbd, 0x2c, 0x9a, 0xdc, 0x4c, 0x46, 0x52, 0x37, 0xed, 0xb0, - 0x03, 0xda, 0xba, 0x03, 0xda, 0x3b, 0xba, 0x03, 0x6e, 0x64, 0x45, 0x8a, 0x3c, 0xfc, 0xb9, 0x60, - 0xa8, 0x20, 0x62, 0x25, 0xf1, 0xa6, 0xb3, 0xff, 0xcd, 0x4d, 0x8f, 0x75, 0xdd, 0x34, 0xb2, 0xe0, - 0x44, 0x48, 0xbf, 0x81, 0xdb, 0x25, 0x71, 0xb9, 0x10, 0x3b, 0x81, 0xdb, 0xb8, 0xbd, 0x8d, 0xd9, - 0xbb, 0xe9, 0xec, 0xf0, 0x64, 0xaa, 0x98, 0xe5, 0xed, 0x92, 0xe7, 0x57, 0x49, 0xdb, 0xba, 0xa0, - 0xea, 0x58, 0xe7, 0xce, 0xa3, 0x22, 0x53, 0xc5, 0x1c, 0xeb, 0xe4, 0x16, 0xff, 0xd6, 0xb7, 0x29, - 0xd5, 0xeb, 0xa5, 0xf1, 0x86, 0x88, 0x1a, 0xcb, 0x11, 0xde, 0xd6, 0x4f, 0xfd, 0xa8, 0x1c, 0xe1, - 0x6d, 0xf6, 0x8f, 0x72, 0xe4, 0xff, 0x4b, 0x3e, 0xfe, 0x92, 0xad, 0x4b, 0x4a, 0x55, 0xc5, 0xef, - 0xe9, 0x88, 0x7b, 0x3d, 0xdd, 0xe9, 0xc2, 0x8c, 0x5c, 0x27, 0xba, 0xda, 0x5b, 0xb7, 0x3a, 0x1d, - 0x56, 0x4d, 0xab, 0x10, 0xaf, 0x41, 0x56, 0x14, 0xe6, 0xd2, 0x2e, 0x51, 0x5d, 0x6e, 0x63, 0xf6, - 0xa7, 0xa7, 0x85, 0xd3, 0xe1, 0x0e, 0x59, 0x75, 0xcf, 0xf6, 0xa8, 0xd3, 0xc0, 0xbc, 0x66, 0xdf, - 0xf0, 0xb9, 0xe8, 0xbe, 0xd2, 0xdb, 0xba, 0x0a, 0x67, 0x65, 0xb4, 0xeb, 0x2d, 0x7f, 0x87, 0xee, - 0x11, 0xff, 0x36, 0x6e, 0x36, 0x3d, 0xdf, 0xd5, 0x09, 0x34, 0x05, 0x23, 0x5c, 0x4c, 0xeb, 0xbe, - 0x29, 0x07, 0xb1, 0x26, 0xf3, 0x91, 0x12, 0x41, 0x7d, 0xee, 0x8a, 0xd4, 0x1a, 0x8c, 0xed, 0xb6, - 0xfc, 0x52, 0x14, 0x23, 0xb7, 0x3e, 0x15, 0x4f, 0x28, 0xed, 0x57, 0xcc, 0xee, 0xaa, 0xbf, 0x28, - 0xf8, 0xfa, 0x0f, 0xe3, 0x30, 0x22, 0xa3, 0xa3, 0x07, 0x06, 0x40, 0xa4, 0x45, 0x91, 0x15, 0x0f, - 0x91, 0x2c, 0x73, 0xcd, 0xa5, 0x23, 0x6d, 0x42, 0x7a, 0xd6, 0xc5, 0xcf, 0xbf, 0xff, 0xf5, 0x9b, - 0xe1, 0x65, 0xf4, 0xb2, 0xe3, 0x4b, 0x01, 0xd9, 0x51, 0xec, 0xbc, 0x56, 0x52, 0x92, 0xc8, 0xb9, - 0xaf, 0x12, 0xe9, 0x10, 0x7d, 0x6d, 0xc0, 0x89, 0x2e, 0xa1, 0x89, 0xce, 0xf5, 0x81, 0x24, 0x29, - 0x59, 0x73, 0xf9, 0x38, 0x33, 0x45, 0xc7, 0x91, 0x74, 0xce, 0xa3, 0x95, 0x1e, 0x3a, 0xe1, 0x28, - 0x81, 0xd1, 0x23, 0x03, 0x26, 0x7b, 0x15, 0x23, 0x5a, 0xed, 0x43, 0x1b, 0x20, 0x51, 0xcd, 0xf3, - 0x7f, 0xc1, 0x52, 0x51, 0x7b, 0x43, 0x52, 0x5b, 0x43, 0x4e, 0x0f, 0xb5, 0x7d, 0xed, 0x10, 0xb1, - 0x8b, 0xab, 0xde, 0x43, 0xf4, 0x09, 0x64, 0x94, 0x16, 0x44, 0x85, 0x3e, 0xb8, 0x6e, 0x81, 0x69, - 0x2e, 0x0c, 0x36, 0x50, 0x34, 0xce, 0x4b, 0x1a, 0x4b, 0x68, 0xb1, 0x87, 0x86, 0x12, 0x93, 0x2c, - 0x76, 0x36, 0x9f, 0x41, 0x46, 0xa9, 0xc0, 0x04, 0xe0, 0x6e, 0xb1, 0x99, 0x00, 0xdc, 0x23, 0x20, - 0x2d, 0x5b, 0x02, 0xaf, 0xa2, 0xe5, 0x1e, 0x60, 0x16, 0xda, 0x45, 0xb8, 0xce, 0xfd, 0x3d, 0x72, - 0x70, 0x88, 0xf6, 0x20, 0x2d, 0xd4, 0x21, 0x9a, 0xeb, 0x8b, 0x1c, 0x13, 0x9b, 0xe6, 0xfc, 0x80, - 0x55, 0x05, 0xba, 0x2c, 0x41, 0x17, 0x50, 0xbe, 0x07, 0x54, 0x68, 0xcb, 0xf8, 0x56, 0x6b, 0x30, - 0x1a, 0xaa, 0x23, 0x94, 0xef, 0x0b, 0xd8, 0x25, 0xbc, 0xcc, 0xc2, 0xc0, 0x75, 0x05, 0x39, 0x2f, - 0x21, 0xa7, 0xd1, 0xe9, 0x1e, 0xc8, 0x50, 0x6f, 0x21, 0x0f, 0x32, 0x4a, 0x6e, 0x21, 0x33, 0x1e, - 0xaa, 0x5b, 0x83, 0x99, 0x8b, 0x83, 0x5b, 0x8d, 0x06, 0x2a, 0x48, 0xa0, 0x59, 0x34, 0x9d, 0xf0, - 0xf4, 0x2a, 0x22, 0x3e, 0x85, 0x5c, 0x4c, 0x20, 0x1d, 0x09, 0xd7, 0xb5, 0xab, 0x04, 0x55, 0x65, - 0x2d, 0x49, 0xb0, 0x79, 0x74, 0xb6, 0x17, 0x4c, 0xd9, 0x8a, 0x8a, 0x8d, 0x1a, 0x90, 0x51, 0xed, - 0x36, 0x21, 0x61, 0xba, 0xc5, 0x57, 0x42, 0xc2, 0xf4, 0x74, 0xea, 0x81, 0xfb, 0x0b, 0x5b, 0x2c, - 0x6f, 0xa3, 0x03, 0x80, 0xa8, 0x11, 0x24, 0x94, 0xb4, 0xbe, 0x6e, 0x9e, 0x50, 0xd2, 0xfa, 0x3b, - 0x89, 0x65, 0x49, 0xdc, 0x39, 0x64, 0x26, 0xe2, 0xca, 0x76, 0x24, 0x76, 0xaa, 0xba, 0x47, 0xe2, - 0x9b, 0x8c, 0xb7, 0x9b, 0xc4, 0x37, 0xd9, 0xd5, 0x78, 0x06, 0xee, 0x54, 0x77, 0x23, 0xf4, 0x95, - 0x01, 0x13, 0x3d, 0x0d, 0x02, 0xad, 0xf4, 0x85, 0x4d, 0xee, 0x40, 0xe6, 0xea, 0xf1, 0x86, 0x8a, - 0xc7, 0x8a, 0xe4, 0xb1, 0x88, 0x0a, 0x3d, 0x3c, 0x76, 0x5b, 0xbe, 0xec, 0x3f, 0xce, 0x7d, 0xf9, - 0x39, 0xdc, 0xb8, 0xfa, 0xf8, 0x59, 0xde, 0x78, 0xf2, 0x2c, 0x6f, 0xfc, 0xf2, 0x2c, 0x6f, 0x3c, - 0x7c, 0x9e, 0x1f, 0x7a, 0xf2, 0x3c, 0x3f, 0xf4, 0xe3, 0xf3, 0xfc, 0xd0, 0x87, 0x4b, 0x31, 0x85, - 0x10, 0x96, 0xe8, 0x4d, 0xd1, 0xdf, 0x75, 0xc0, 0xb6, 0x08, 0x59, 0x1e, 0x95, 0x6a, 0xe4, 0xd5, - 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x68, 0x44, 0xe9, 0x8d, 0x33, 0x12, 0x00, 0x00, + // 1572 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0xcf, 0x6f, 0x1b, 0x45, + 0x1b, 0x8e, 0x63, 0x27, 0x76, 0x5e, 0xa7, 0x4d, 0xbe, 0x69, 0xda, 0x24, 0x6e, 0x62, 0x27, 0x9b, + 0xaf, 0x49, 0xda, 0xaf, 0xdd, 0xfd, 0x12, 0x10, 0x88, 0x8a, 0x0a, 0xd5, 0x51, 0x1a, 0x4a, 0x7f, + 0xa8, 0x35, 0x11, 0x48, 0x20, 0x64, 0x8d, 0xd7, 0x93, 0xf5, 0x2a, 0xde, 0x1d, 0x77, 0x67, 0x9c, + 0x3a, 0x94, 0x5c, 0xe8, 0x05, 0x09, 0x21, 0x2a, 0xf1, 0x0f, 0xf4, 0xc4, 0xbf, 0xc0, 0xbf, 0xd0, + 0x63, 0x25, 0x84, 0x84, 0x38, 0x14, 0xd4, 0x72, 0xe0, 0xcc, 0x91, 0x13, 0x9a, 0xd9, 0x99, 0x78, + 0xbd, 0x5e, 0x27, 0x94, 0x1f, 0x37, 0x4e, 0xbb, 0x33, 0xf3, 0xce, 0xfb, 0x3c, 0xf3, 0xeb, 0x7d, + 0x1e, 0x38, 0x43, 0x78, 0xc3, 0x22, 0x7b, 0x9e, 0xb5, 0xb7, 0x66, 0xdd, 0x6b, 0x93, 0x60, 0xdf, + 0x6c, 0x05, 0x94, 0x53, 0x04, 0x84, 0x37, 0x4c, 0xb2, 0xe7, 0x99, 0x7b, 0x6b, 0x85, 0x0b, 0x36, + 0x65, 0x1e, 0x65, 0x56, 0x0d, 0x33, 0x12, 0x06, 0x59, 0x7b, 0x6b, 0x35, 0xc2, 0xf1, 0x9a, 0xd5, + 0xc2, 0x8e, 0xeb, 0x63, 0xee, 0x52, 0x3f, 0x9c, 0x57, 0x98, 0x8a, 0xe4, 0x13, 0xd3, 0xc3, 0xde, + 0x53, 0x91, 0x5e, 0xde, 0xd1, 0xa1, 0x0e, 0x75, 0xa8, 0xfc, 0xb5, 0xc4, 0x9f, 0xea, 0x9d, 0x73, + 0x28, 0x75, 0x9a, 0xc4, 0xc2, 0x2d, 0xd7, 0xc2, 0xbe, 0x4f, 0xb9, 0xcc, 0xce, 0xd4, 0x68, 0x49, + 0x8d, 0xca, 0x56, 0xad, 0xbd, 0x63, 0x71, 0xd7, 0x23, 0x8c, 0x63, 0xaf, 0x15, 0x06, 0x18, 0x6f, + 0xc2, 0x99, 0xbb, 0x82, 0xe1, 0x26, 0x6f, 0x5c, 0xb5, 0x6d, 0xda, 0xf6, 0x79, 0x85, 0xdc, 0x6b, + 0x13, 0xc6, 0xd1, 0x0c, 0x64, 0x71, 0xbd, 0x1e, 0x10, 0xc6, 0x66, 0x52, 0x0b, 0xa9, 0xd5, 0xb1, + 0x8a, 0x6e, 0x5e, 0xce, 0x7d, 0xf6, 0xb8, 0x34, 0xf4, 0xcb, 0xe3, 0xd2, 0x90, 0xe1, 0xc1, 0x74, + 0xdf, 0x6c, 0xd6, 0xa2, 0x3e, 0x23, 0xa8, 0x04, 0xf9, 0x1a, 0x6e, 0x62, 0xdf, 0x26, 0xd5, 0xfb, + 0xc4, 0x55, 0x29, 0x40, 0x75, 0xbd, 0x4f, 0x5c, 0x74, 0x16, 0xc6, 0x6c, 0x5a, 0x27, 0xd5, 0x06, + 0x66, 0x8d, 0x99, 0x61, 0x39, 0x9c, 0x13, 0x1d, 0x6f, 0x63, 0xd6, 0x40, 0x53, 0x30, 0xe2, 0x53, + 0xdf, 0x26, 0x33, 0xe9, 0x85, 0xd4, 0x6a, 0xa6, 0x12, 0x36, 0x8c, 0xb7, 0x60, 0x56, 0xc2, 0xdd, + 0x76, 0x6b, 0x6e, 0xd0, 0xfe, 0x13, 0x7c, 0xf7, 0xa1, 0x90, 0x94, 0x40, 0x51, 0x1e, 0x98, 0x01, + 0x15, 0x20, 0xc7, 0x04, 0x8c, 0x60, 0x34, 0x2c, 0x19, 0x1d, 0xb6, 0xd1, 0x39, 0x38, 0x89, 0xc3, + 0x44, 0x55, 0xbf, 0xed, 0xd5, 0x48, 0xa0, 0x38, 0x9f, 0x50, 0xbd, 0xb7, 0x65, 0xa7, 0x71, 0x03, + 0xe6, 0x24, 0xf4, 0x7b, 0xb8, 0xe9, 0xd6, 0x31, 0xa7, 0x41, 0x8c, 0xfe, 0x22, 0x8c, 0xdb, 0xd4, + 0x67, 0xd5, 0x5e, 0x06, 0x79, 0xd1, 0x77, 0xb5, 0x6f, 0x1d, 0x9f, 0xa7, 0x60, 0x7e, 0x40, 0x36, + 0xb5, 0x96, 0x15, 0x98, 0xd0, 0xac, 0x7a, 0x33, 0x6a, 0xb2, 0x57, 0xff, 0xbe, 0xa5, 0xbd, 0x01, + 0xa7, 0x24, 0x99, 0x72, 0x78, 0xb8, 0x2f, 0x73, 0x20, 0x77, 0x61, 0xaa, 0x77, 0x6a, 0xf7, 0x28, + 0xd4, 0x55, 0xd1, 0x73, 0x55, 0x33, 0x7e, 0xaf, 0x86, 0xe3, 0xf7, 0xca, 0xb8, 0xa1, 0xd8, 0xbc, + 0xcb, 0x69, 0x80, 0x9d, 0xe3, 0xd9, 0xa0, 0x49, 0x48, 0xef, 0x92, 0x7d, 0x95, 0x49, 0xfc, 0x46, + 0xf8, 0x5d, 0x54, 0xfc, 0x0e, 0x93, 0x29, 0x7e, 0x53, 0x30, 0xb2, 0x87, 0x9b, 0x6d, 0xcd, 0x2e, + 0x6c, 0x18, 0xaf, 0xc1, 0xa4, 0x8c, 0xde, 0xa0, 0xf5, 0x97, 0xda, 0x85, 0x15, 0xf8, 0x4f, 0x64, + 0x9e, 0x82, 0x40, 0x90, 0x11, 0xcf, 0x41, 0xce, 0x1a, 0xaf, 0xc8, 0x7f, 0xe3, 0x63, 0x40, 0x32, + 0x70, 0xbb, 0x73, 0x93, 0x3a, 0x4c, 0x43, 0x20, 0xc8, 0xc8, 0x47, 0x14, 0xe6, 0x97, 0xff, 0xe8, + 0x1a, 0x40, 0xb7, 0xd6, 0xc8, 0xb5, 0xe5, 0xd7, 0x97, 0xcd, 0xb0, 0x30, 0x99, 0xa2, 0x30, 0x99, + 0x61, 0xf5, 0x52, 0x85, 0xc9, 0xbc, 0xd3, 0xdd, 0xaa, 0x4a, 0x64, 0x66, 0x84, 0xe4, 0xc3, 0x94, + 0xda, 0x58, 0x0d, 0xae, 0x78, 0x2e, 0x41, 0xa6, 0x49, 0x1d, 0xb1, 0xba, 0xf4, 0x6a, 0x7e, 0x7d, + 0xc2, 0xec, 0x16, 0x42, 0xf3, 0x26, 0x75, 0x2a, 0x72, 0x10, 0x6d, 0x25, 0xd0, 0x59, 0x39, 0x96, + 0x4e, 0x88, 0x10, 0xe5, 0x63, 0x4c, 0xa9, 0x1d, 0xb8, 0x83, 0x03, 0xec, 0xe9, 0x1d, 0x30, 0xb6, + 0x14, 0x35, 0xdd, 0xab, 0xa8, 0xfd, 0x1f, 0x46, 0x5b, 0xb2, 0x47, 0x6e, 0x4d, 0x7e, 0x1d, 0x45, + 0xc9, 0x85, 0xb1, 0xe5, 0xcc, 0x93, 0x67, 0xa5, 0xa1, 0x8a, 0x8a, 0x33, 0xbe, 0x49, 0xc1, 0xc9, + 0x4d, 0xde, 0xd8, 0xc0, 0xcd, 0x66, 0x64, 0x77, 0x71, 0xe0, 0x30, 0x7d, 0x0e, 0xe2, 0x1f, 0x4d, + 0x43, 0xd6, 0xc1, 0xac, 0x6a, 0xe3, 0x96, 0x7a, 0x33, 0xa3, 0x0e, 0x66, 0x1b, 0xb8, 0x85, 0x3e, + 0x82, 0xc9, 0x56, 0x40, 0x5b, 0x94, 0x91, 0xe0, 0xf0, 0xdd, 0x89, 0x37, 0x33, 0x5e, 0x5e, 0xff, + 0xed, 0x59, 0xc9, 0x74, 0x5c, 0xde, 0x68, 0xd7, 0x4c, 0x9b, 0x7a, 0x96, 0xd2, 0x88, 0xf0, 0x73, + 0x89, 0xd5, 0x77, 0x2d, 0xbe, 0xdf, 0x22, 0xcc, 0xdc, 0xe8, 0x3e, 0xf8, 0xca, 0x84, 0xce, 0xa5, + 0x1f, 0xeb, 0x2c, 0xe4, 0xec, 0x06, 0x76, 0xfd, 0xaa, 0x5b, 0x9f, 0xc9, 0x2c, 0xa4, 0x56, 0xd3, + 0x95, 0xac, 0x6c, 0x5f, 0xaf, 0x1b, 0x2b, 0x70, 0x6a, 0x93, 0x71, 0xd7, 0xc3, 0x9c, 0x6c, 0xe1, + 0xee, 0x16, 0x4c, 0x42, 0xda, 0xc1, 0x21, 0xf9, 0x4c, 0x45, 0xfc, 0x1a, 0xbf, 0xa6, 0xf5, 0x39, + 0x06, 0xd8, 0x26, 0xdb, 0x1d, 0xbd, 0xce, 0xff, 0x41, 0xda, 0x63, 0x8e, 0xda, 0xa9, 0xd9, 0xe8, + 0x4e, 0xdd, 0x62, 0xce, 0x26, 0x6f, 0x90, 0x80, 0xb4, 0xbd, 0xed, 0x4e, 0x45, 0x44, 0xa1, 0xcb, + 0x30, 0xce, 0xc5, 0xf4, 0xaa, 0x4d, 0xfd, 0x1d, 0xd7, 0x91, 0x6b, 0xcc, 0xaf, 0x4f, 0x47, 0x67, + 0xc9, 0xf4, 0x1b, 0x72, 0xb8, 0x92, 0xe7, 0xdd, 0x06, 0xba, 0x02, 0xe3, 0xad, 0x80, 0xd4, 0x89, + 0x4d, 0x18, 0xa3, 0x01, 0x9b, 0xc9, 0xc8, 0x8b, 0x73, 0x04, 0x62, 0x4f, 0xb8, 0x28, 0x94, 0xb5, + 0x26, 0xb5, 0x77, 0x75, 0x49, 0x1a, 0x91, 0xfb, 0x90, 0x97, 0x7d, 0x61, 0x41, 0x42, 0xf3, 0x00, + 0x61, 0x88, 0x7c, 0x16, 0xa3, 0xf2, 0x59, 0x8c, 0xc9, 0x1e, 0x29, 0x2e, 0x1b, 0x7a, 0x58, 0x88, + 0xe1, 0x4c, 0x56, 0x52, 0x2f, 0x98, 0xa1, 0x52, 0x9a, 0x5a, 0x29, 0xcd, 0x6d, 0xad, 0x94, 0xe5, + 0x9c, 0xb8, 0x22, 0x8f, 0x7e, 0x2c, 0xa5, 0x54, 0x12, 0x31, 0x92, 0x78, 0xd2, 0xb9, 0x7f, 0xe6, + 0xa4, 0xc7, 0x7a, 0x4e, 0x1a, 0x19, 0x70, 0x22, 0xa4, 0xef, 0xe1, 0x4e, 0x55, 0x1c, 0x2e, 0x44, + 0x76, 0xe0, 0x16, 0xee, 0x6c, 0x61, 0xf6, 0x4e, 0x26, 0x37, 0x3c, 0x99, 0xae, 0xe4, 0x78, 0xa7, + 0xea, 0xfa, 0x75, 0xd2, 0x31, 0x2e, 0xa8, 0x3a, 0x76, 0x78, 0xe6, 0xdd, 0x22, 0x53, 0xc7, 0x1c, + 0xeb, 0xcb, 0x2d, 0xfe, 0x8d, 0xaf, 0xd3, 0xca, 0x13, 0xc8, 0xe0, 0xb2, 0xc8, 0x1a, 0xb9, 0x23, + 0xbc, 0xa3, 0x9f, 0xfa, 0x51, 0x77, 0x84, 0x77, 0xd8, 0x5f, 0xba, 0x23, 0xff, 0x1e, 0xf2, 0xf1, + 0x87, 0x6c, 0x5c, 0x52, 0xee, 0x2b, 0x7a, 0x4e, 0x47, 0x9c, 0xeb, 0xe9, 0x43, 0x99, 0x66, 0xe4, + 0x1a, 0xd1, 0xd5, 0xde, 0xb8, 0x79, 0x28, 0xc1, 0xaa, 0x5b, 0xa5, 0x78, 0x15, 0x72, 0xa2, 0x30, + 0x57, 0x77, 0x88, 0x52, 0xb9, 0xf2, 0xec, 0x0f, 0xcf, 0x4a, 0xa7, 0xc3, 0x15, 0xb2, 0xfa, 0xae, + 0xe9, 0x52, 0xcb, 0xc3, 0xbc, 0x61, 0x5e, 0xf7, 0xb9, 0x90, 0x67, 0x39, 0xdb, 0xb8, 0x02, 0x67, + 0x65, 0xb6, 0x6b, 0x6d, 0x7f, 0x9b, 0xee, 0x12, 0xff, 0x16, 0x6e, 0xb5, 0x5c, 0xdf, 0xd1, 0x17, + 0x68, 0x0a, 0x46, 0xb8, 0xe8, 0xd6, 0xba, 0x29, 0x1b, 0x11, 0x91, 0xf9, 0x50, 0xb9, 0xa4, 0xbe, + 0xe9, 0x8a, 0xd4, 0x1a, 0x8c, 0xed, 0xb4, 0xfd, 0x6a, 0x37, 0x47, 0x7e, 0x7d, 0x2a, 0x7a, 0xa1, + 0xf4, 0xbc, 0x4a, 0x6e, 0x47, 0xfd, 0x75, 0x93, 0xaf, 0x7f, 0x37, 0x0e, 0x23, 0x32, 0x3b, 0x7a, + 0x98, 0x02, 0xe8, 0x7a, 0x56, 0x64, 0x44, 0x53, 0x24, 0xdb, 0xe1, 0xc2, 0xd2, 0x91, 0x31, 0x21, + 0x3d, 0xe3, 0xe2, 0xa7, 0xdf, 0xfe, 0xfc, 0xd5, 0xf0, 0x32, 0xfa, 0xaf, 0xe5, 0x4b, 0x87, 0x79, + 0xe8, 0xec, 0x79, 0xa3, 0xaa, 0x3c, 0x93, 0xf5, 0x40, 0x5d, 0xa4, 0x03, 0xf4, 0x65, 0x0a, 0x4e, + 0xf4, 0x38, 0x51, 0x74, 0xae, 0x0f, 0x24, 0xc9, 0xea, 0x16, 0x96, 0x8f, 0x0b, 0x53, 0x74, 0x2c, + 0x49, 0xe7, 0x3c, 0x5a, 0x89, 0xd1, 0x09, 0x5b, 0x09, 0x8c, 0x1e, 0xa7, 0x60, 0x32, 0x6e, 0x29, + 0xd1, 0x6a, 0x1f, 0xda, 0x00, 0x0f, 0x5b, 0x38, 0xff, 0x07, 0x22, 0x15, 0xb5, 0xd7, 0x25, 0xb5, + 0x35, 0x64, 0xc5, 0xa8, 0xed, 0xe9, 0x09, 0x5d, 0x76, 0x51, 0x5b, 0x7c, 0x80, 0xee, 0x43, 0xb6, + 0xac, 0xad, 0x60, 0x1f, 0x5c, 0xaf, 0x03, 0x2d, 0x2c, 0x0c, 0x0e, 0x50, 0x34, 0xce, 0x4b, 0x1a, + 0x4b, 0x68, 0x31, 0x46, 0x43, 0xf9, 0x49, 0x16, 0xd9, 0x9b, 0x4f, 0x20, 0xab, 0x5c, 0x60, 0x02, + 0x70, 0xaf, 0xd9, 0x4c, 0x00, 0x8e, 0x19, 0x48, 0xc3, 0x94, 0xc0, 0xab, 0x68, 0x39, 0x06, 0xcc, + 0xc2, 0xb8, 0x2e, 0xae, 0xf5, 0x60, 0x97, 0xec, 0x1f, 0xa0, 0x5d, 0xc8, 0x08, 0x77, 0x88, 0xe6, + 0xfa, 0x32, 0x47, 0xcc, 0x66, 0x61, 0x7e, 0xc0, 0xa8, 0x02, 0x5d, 0x96, 0xa0, 0x0b, 0xa8, 0x18, + 0x03, 0x15, 0xde, 0x32, 0xba, 0xd4, 0x06, 0x8c, 0x86, 0xee, 0x08, 0x15, 0xfb, 0x12, 0xf6, 0x18, + 0xaf, 0x42, 0x69, 0xe0, 0xb8, 0x82, 0x9c, 0x97, 0x90, 0xd3, 0xe8, 0x74, 0x0c, 0x32, 0xf4, 0x5b, + 0xc8, 0x85, 0xac, 0xb2, 0x5b, 0xa8, 0x10, 0x4d, 0xd5, 0xeb, 0xc1, 0x0a, 0x8b, 0x83, 0xa5, 0x46, + 0x03, 0x95, 0x24, 0xd0, 0x2c, 0x9a, 0x4e, 0x78, 0x7a, 0xb6, 0xc8, 0x4f, 0x21, 0x1f, 0x31, 0x48, + 0x47, 0xc2, 0xf5, 0xac, 0x2a, 0xc1, 0x55, 0x19, 0x4b, 0x12, 0x6c, 0x1e, 0x9d, 0x8d, 0x83, 0xa9, + 0x58, 0x51, 0xb1, 0x91, 0x07, 0x59, 0x25, 0xb7, 0x09, 0x17, 0xa6, 0xd7, 0x7c, 0x25, 0x5c, 0x98, + 0x98, 0x52, 0x0f, 0x5c, 0x5f, 0x28, 0xb1, 0xbc, 0x83, 0xf6, 0x01, 0xba, 0x42, 0x90, 0x50, 0xd2, + 0xfa, 0xd4, 0x3c, 0xa1, 0xa4, 0xf5, 0x2b, 0x89, 0x61, 0x48, 0xdc, 0x39, 0x54, 0x48, 0xc4, 0x95, + 0x72, 0x24, 0x56, 0xaa, 0xd4, 0x23, 0xf1, 0x4d, 0x46, 0xe5, 0x26, 0xf1, 0x4d, 0xf6, 0x08, 0xcf, + 0xc0, 0x95, 0x6a, 0x35, 0x42, 0x5f, 0xa4, 0x60, 0x22, 0x26, 0x10, 0x68, 0xa5, 0x2f, 0x6d, 0xb2, + 0x02, 0x15, 0x56, 0x8f, 0x0f, 0x54, 0x3c, 0x56, 0x24, 0x8f, 0x45, 0x54, 0x8a, 0xf1, 0xd8, 0x69, + 0xfb, 0x52, 0x7f, 0xac, 0x07, 0xf2, 0x73, 0x50, 0xbe, 0xf2, 0xe4, 0x79, 0x31, 0xf5, 0xf4, 0x79, + 0x31, 0xf5, 0xd3, 0xf3, 0x62, 0xea, 0xd1, 0x8b, 0xe2, 0xd0, 0xd3, 0x17, 0xc5, 0xa1, 0xef, 0x5f, + 0x14, 0x87, 0x3e, 0x58, 0x8a, 0x38, 0x84, 0xb0, 0x44, 0x6f, 0x08, 0x7d, 0xd7, 0x09, 0x3b, 0x22, + 0x65, 0x6d, 0x54, 0xba, 0x91, 0x57, 0x7e, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xdd, 0x5e, 0x28, + 0x5b, 0x12, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2115,10 +2126,10 @@ func (m *QueryEthAccountResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) i-- dAtA[i] = 0x12 } - if len(m.Balance) > 0 { - i -= len(m.Balance) - copy(dAtA[i:], m.Balance) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Balance))) + if len(m.BalanceWei) > 0 { + i -= len(m.BalanceWei) + copy(dAtA[i:], m.BalanceWei) + i = encodeVarintQuery(dAtA, i, uint64(len(m.BalanceWei))) i-- dAtA[i] = 0xa } @@ -2315,6 +2326,13 @@ func (m *QueryBalanceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.BalanceWei) > 0 { + i -= len(m.BalanceWei) + copy(dAtA[i:], m.BalanceWei) + i = encodeVarintQuery(dAtA, i, uint64(len(m.BalanceWei))) + i-- + dAtA[i] = 0x12 + } if len(m.Balance) > 0 { i -= len(m.Balance) copy(dAtA[i:], m.Balance) @@ -3071,7 +3089,7 @@ func (m *QueryEthAccountResponse) Size() (n int) { } var l int _ = l - l = len(m.Balance) + l = len(m.BalanceWei) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } @@ -3172,6 +3190,10 @@ func (m *QueryBalanceResponse) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } + l = len(m.BalanceWei) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -3595,7 +3617,7 @@ func (m *QueryEthAccountResponse) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Balance", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field BalanceWei", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -3623,7 +3645,7 @@ func (m *QueryEthAccountResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Balance = string(dAtA[iNdEx:postIndex]) + m.BalanceWei = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -4244,6 +4266,38 @@ func (m *QueryBalanceResponse) Unmarshal(dAtA []byte) error { } m.Balance = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BalanceWei", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BalanceWei = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/x/evm/statedb/mock_test.go b/x/evm/statedb/mock_test.go deleted file mode 100644 index b4324abe9..000000000 --- a/x/evm/statedb/mock_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package statedb_test - -import ( - "bytes" - "errors" - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - - "github.com/NibiruChain/nibiru/x/evm/statedb" -) - -var ( - _ statedb.Keeper = &MockKeeper{} - errAddress common.Address = common.BigToAddress(big.NewInt(100)) - emptyCodeHash = crypto.Keccak256(nil) -) - -type MockAcount struct { - account statedb.Account - states statedb.Storage -} - -type MockKeeper struct { - accounts map[common.Address]MockAcount - codes map[common.Hash][]byte -} - -func NewMockKeeper() *MockKeeper { - return &MockKeeper{ - accounts: make(map[common.Address]MockAcount), - codes: make(map[common.Hash][]byte), - } -} - -func (k MockKeeper) GetAccount(_ sdk.Context, addr common.Address) *statedb.Account { - acct, ok := k.accounts[addr] - if !ok { - return nil - } - return &acct.account -} - -func (k MockKeeper) GetState(_ sdk.Context, addr common.Address, key common.Hash) common.Hash { - return k.accounts[addr].states[key] -} - -func (k MockKeeper) GetCode(_ sdk.Context, codeHash common.Hash) []byte { - return k.codes[codeHash] -} - -func (k MockKeeper) ForEachStorage(_ sdk.Context, addr common.Address, cb func(key, value common.Hash) bool) { - if acct, ok := k.accounts[addr]; ok { - for k, v := range acct.states { - if !cb(k, v) { - return - } - } - } -} - -func (k MockKeeper) SetAccount(_ sdk.Context, addr common.Address, account statedb.Account) error { - if addr == errAddress { - return errors.New("mock db error") - } - acct, exists := k.accounts[addr] - if exists { - // update - acct.account = account - k.accounts[addr] = acct - } else { - k.accounts[addr] = MockAcount{account: account, states: make(statedb.Storage)} - } - return nil -} - -func (k MockKeeper) SetState(_ sdk.Context, addr common.Address, key common.Hash, value []byte) { - if acct, ok := k.accounts[addr]; ok { - if len(value) == 0 { - delete(acct.states, key) - } else { - acct.states[key] = common.BytesToHash(value) - } - } -} - -func (k MockKeeper) SetCode(_ sdk.Context, codeHash []byte, code []byte) { - k.codes[common.BytesToHash(codeHash)] = code -} - -func (k MockKeeper) DeleteAccount(_ sdk.Context, addr common.Address) error { - if addr == errAddress { - return errors.New("mock db error") - } - old := k.accounts[addr] - delete(k.accounts, addr) - if !bytes.Equal(old.account.CodeHash, emptyCodeHash) { - delete(k.codes, common.BytesToHash(old.account.CodeHash)) - } - return nil -} - -func (k MockKeeper) Clone() *MockKeeper { - accounts := make(map[common.Address]MockAcount, len(k.accounts)) - for k, v := range k.accounts { - accounts[k] = v - } - codes := make(map[common.Hash][]byte, len(k.codes)) - for k, v := range k.codes { - codes[k] = v - } - return &MockKeeper{accounts, codes} -} diff --git a/x/evm/statedb/state_object.go b/x/evm/statedb/state_object.go index 39592af7c..3425abc91 100644 --- a/x/evm/statedb/state_object.go +++ b/x/evm/statedb/state_object.go @@ -8,29 +8,69 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + + "github.com/NibiruChain/nibiru/x/evm" ) var emptyCodeHash = crypto.Keccak256(nil) -// Account is the Ethereum consensus representation of accounts. +// Account represents an Ethereum account as viewed by the Auth module state. The +// balance is stored in the smallest native unit (e.g., micronibi or unibi). // These objects are stored in the storage of auth module. type Account struct { - Nonce uint64 - Balance *big.Int + BalanceEvmDenom *big.Int + // Nonce is the number of transactions sent from this account or, for contract accounts, the number of contract-creations made by this account + Nonce uint64 + // CodeHash is the hash of the contract code for this account, or nil if it's not a contract account CodeHash []byte } +// AccountWei represents an Ethereum account as viewed by the EVM. This struct is +// derived from an `Account` but represents balances in wei, which is necessary +// for correct operation within the EVM. The EVM expects and operates on wei +// values, which are 10^12 times larger than the native unibi value due to the +// definition of NIBI as "ether". +type AccountWei struct { + BalanceWei *big.Int + Nonce uint64 + CodeHash []byte +} + +// ToWei converts an Account (native representation) to AccountWei (EVM +// representation). This conversion is necessary when moving from the Cosmos SDK +// context to the EVM context. It multiplies the balance by 10^12 to convert from +// unibi to wei. +func (acc Account) ToWei() AccountWei { + return AccountWei{ + BalanceWei: evm.NativeToWei(acc.BalanceEvmDenom), + Nonce: acc.Nonce, + CodeHash: acc.CodeHash, + } +} + +// ToNative converts an AccountWei (EVM representation) back to an Account +// (native representation). This conversion is necessary when moving from the EVM +// context back to the Cosmos SDK context. It divides the balance by 10^12 to +// convert from wei to unibi. +func (acc AccountWei) ToNative() Account { + return Account{ + BalanceEvmDenom: evm.WeiToNative(acc.BalanceWei), + Nonce: acc.Nonce, + CodeHash: acc.CodeHash, + } +} + // NewEmptyAccount returns an empty account. func NewEmptyAccount() *Account { return &Account{ - Balance: new(big.Int), - CodeHash: emptyCodeHash, + BalanceEvmDenom: new(big.Int), + CodeHash: emptyCodeHash, } } // IsContract returns if the account contains contract code. -func (acct Account) IsContract() bool { - return !bytes.Equal(acct.CodeHash, emptyCodeHash) +func (acct *Account) IsContract() bool { + return (acct != nil) && !bytes.Equal(acct.CodeHash, emptyCodeHash) } // Storage represents in-memory cache/buffer of contract storage. @@ -48,11 +88,26 @@ func (s Storage) SortedKeys() []common.Hash { return keys } -// stateObject is the state of an acount +// stateObject represents the state of a Nibiru EVM account. +// It encapsulates both the account data (balance, nonce, code) and the contract +// storage state. stateObject serves as an in-memory cache and staging area for +// changes before they are committed to the underlying storage. +// +// Key features: +// 1. It uses AccountWei, which represents balances in wei for EVM compatibility. +// 2. It maintains both the original (committed) storage and dirty (uncommitted) storage. +// 3. It tracks whether the account has been marked for deletion (suicided). +// 4. It caches the contract code for efficient access. +// +// stateObjects are used to: +// - Efficiently manage and track changes to account state during EVM execution. +// - Provide a layer of abstraction between the EVM and the underlying storage. +// - Enable features like state reverting and snapshotting. +// - Optimize performance by minimizing direct access to the underlying storage. type stateObject struct { db *StateDB - account Account + account AccountWei code []byte // state storage @@ -68,16 +123,17 @@ type stateObject struct { // newObject creates a state object. func newObject(db *StateDB, address common.Address, account Account) *stateObject { - if account.Balance == nil { - account.Balance = new(big.Int) + if account.BalanceEvmDenom == nil { + account.BalanceEvmDenom = new(big.Int) } if account.CodeHash == nil { account.CodeHash = emptyCodeHash } return &stateObject{ - db: db, - address: address, - account: account, + db: db, + address: address, + // Reflect the micronibi (unibi) balance in wei + account: account.ToWei(), originStorage: make(Storage), dirtyStorage: make(Storage), } @@ -85,7 +141,7 @@ func newObject(db *StateDB, address common.Address, account Account) *stateObjec // empty returns whether the account is considered empty. func (s *stateObject) empty() bool { - return s.account.Nonce == 0 && s.account.Balance.Sign() == 0 && bytes.Equal(s.account.CodeHash, emptyCodeHash) + return s.account.Nonce == 0 && s.account.BalanceWei.Sign() == 0 && bytes.Equal(s.account.CodeHash, emptyCodeHash) } func (s *stateObject) markSuicided() { @@ -114,13 +170,13 @@ func (s *stateObject) SubBalance(amount *big.Int) { func (s *stateObject) SetBalance(amount *big.Int) { s.db.journal.append(balanceChange{ account: &s.address, - prev: new(big.Int).Set(s.account.Balance), + prev: new(big.Int).Set(s.account.BalanceWei), }) s.setBalance(amount) } func (s *stateObject) setBalance(amount *big.Int) { - s.account.Balance = amount + s.account.BalanceWei = amount } // @@ -188,7 +244,7 @@ func (s *stateObject) CodeHash() []byte { // Balance returns the balance of account func (s *stateObject) Balance() *big.Int { - return s.account.Balance + return s.account.BalanceWei } // Nonce returns the nonce of account diff --git a/x/evm/statedb/statedb.go b/x/evm/statedb/statedb.go index d3a39790a..511060f15 100644 --- a/x/evm/statedb/statedb.go +++ b/x/evm/statedb/statedb.go @@ -217,6 +217,7 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { if account == nil { return nil } + // Insert into the live set obj := newObject(s, addr, *account) s.setStateObject(obj) @@ -263,7 +264,7 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) func (s *StateDB) CreateAccount(addr common.Address) { newObj, prev := s.createObject(addr) if prev != nil { - newObj.setBalance(prev.account.Balance) + newObj.setBalance(prev.account.BalanceWei) } } @@ -349,7 +350,7 @@ func (s *StateDB) Suicide(addr common.Address) bool { prevbalance: new(big.Int).Set(stateObject.Balance()), }) stateObject.markSuicided() - stateObject.account.Balance = new(big.Int) + stateObject.account.BalanceWei = new(big.Int) return true } @@ -457,7 +458,7 @@ func (s *StateDB) Commit() error { if obj.code != nil && obj.dirtyCode { s.keeper.SetCode(s.ctx, obj.CodeHash(), obj.code) } - if err := s.keeper.SetAccount(s.ctx, obj.Address(), obj.account); err != nil { + if err := s.keeper.SetAccount(s.ctx, obj.Address(), obj.account.ToNative()); err != nil { return errorsmod.Wrap(err, "failed to set account") } for _, key := range obj.dirtyStorage.SortedKeys() { diff --git a/x/evm/statedb/statedb_test.go b/x/evm/statedb/statedb_test.go index 21d4ac27e..6368a1daf 100644 --- a/x/evm/statedb/statedb_test.go +++ b/x/evm/statedb/statedb_test.go @@ -4,67 +4,96 @@ import ( "math/big" "testing" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" gethcore "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/stretchr/testify/suite" + s "github.com/stretchr/testify/suite" + "github.com/NibiruChain/nibiru/x/common/set" + "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/NibiruChain/nibiru/x/evm/statedb" ) +// emptyCodeHash: The hash for empty contract bytecode, or a blank byte +// array. This is the code hash for a non-existent or empty account. +var emptyCodeHash []byte = crypto.Keccak256(nil) + +// dummy variables for tests 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(blockHash) + 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)) + errAddress common.Address = common.BigToAddress(big.NewInt(100)) ) -type StateDBTestSuite struct { - suite.Suite +// TestSuite runs the entire test suite. +func TestSuite(t *testing.T) { + s.Run(t, new(Suite)) +} + +type Suite struct { + s.Suite +} + +// CollectContractStorage is a helper function that collects all storage key-value pairs +// for a given contract address using the ForEachStorage method of the StateDB. +// It returns a map of storage slots to their values. +func CollectContractStorage(db vm.StateDB) statedb.Storage { + storage := make(statedb.Storage) + err := db.ForEachStorage( + address, + func(k, v common.Hash) bool { + storage[k] = v + return true + }, + ) + if err != nil { + return nil + } + + return storage } -func (suite *StateDBTestSuite) TestAccount() { +func (s *Suite) TestAccount() { key1 := common.BigToHash(big.NewInt(1)) value1 := common.BigToHash(big.NewInt(2)) key2 := common.BigToHash(big.NewInt(3)) value2 := common.BigToHash(big.NewInt(4)) testCases := []struct { name string - malleate func(*statedb.StateDB) + malleate func(deps *evmtest.TestDeps, db *statedb.StateDB) }{ - {"non-exist account", func(db *statedb.StateDB) { - suite.Require().Equal(false, db.Exist(address)) - suite.Require().Equal(true, db.Empty(address)) - suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) - suite.Require().Equal([]byte(nil), db.GetCode(address)) - suite.Require().Equal(common.Hash{}, db.GetCodeHash(address)) - suite.Require().Equal(uint64(0), db.GetNonce(address)) + {"non-exist account", func(deps *evmtest.TestDeps, db *statedb.StateDB) { + s.Require().Equal(false, db.Exist(address)) + s.Require().Equal(true, db.Empty(address)) + s.Require().Equal(big.NewInt(0), db.GetBalance(address)) + s.Require().Equal([]byte(nil), db.GetCode(address)) + s.Require().Equal(common.Hash{}, db.GetCodeHash(address)) + s.Require().Equal(uint64(0), db.GetNonce(address)) }}, - {"empty account", func(db *statedb.StateDB) { + {"empty account", func(deps *evmtest.TestDeps, db *statedb.StateDB) { db.CreateAccount(address) - suite.Require().NoError(db.Commit()) - - keeper := db.Keeper().(*MockKeeper) - acct := keeper.accounts[address] - suite.Require().Equal(statedb.NewEmptyAccount(), &acct.account) - suite.Require().Empty(acct.states) - suite.Require().False(acct.account.IsContract()) - - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) - suite.Require().Equal(true, db.Exist(address)) - suite.Require().Equal(true, db.Empty(address)) - suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) - suite.Require().Equal([]byte(nil), db.GetCode(address)) - suite.Require().Equal(common.BytesToHash(emptyCodeHash), db.GetCodeHash(address)) - suite.Require().Equal(uint64(0), db.GetNonce(address)) + s.Require().NoError(db.Commit()) + + k := db.Keeper() + acct := k.GetAccount(deps.Ctx, address) + s.Require().EqualValues(statedb.NewEmptyAccount(), acct) + s.Require().Empty(CollectContractStorage(db)) + + db = deps.StateDB() + s.Require().Equal(true, db.Exist(address)) + s.Require().Equal(true, db.Empty(address)) + s.Require().Equal(big.NewInt(0), db.GetBalance(address)) + s.Require().Equal([]byte(nil), db.GetCode(address)) + s.Require().Equal(common.BytesToHash(emptyCodeHash), db.GetCodeHash(address)) + s.Require().Equal(uint64(0), db.GetNonce(address)) }}, - {"suicide", func(db *statedb.StateDB) { + {"suicide", func(deps *evmtest.TestDeps, db *statedb.StateDB) { // non-exist account. - suite.Require().False(db.Suicide(address)) - suite.Require().False(db.HasSuicided(address)) + s.Require().False(db.Suicide(address)) + s.Require().False(db.HasSuicided(address)) // create a contract account db.CreateAccount(address) @@ -72,45 +101,41 @@ func (suite *StateDBTestSuite) TestAccount() { db.AddBalance(address, big.NewInt(100)) db.SetState(address, key1, value1) db.SetState(address, key2, value2) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) // suicide - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) - suite.Require().False(db.HasSuicided(address)) - suite.Require().True(db.Suicide(address)) + db = deps.StateDB() + s.Require().False(db.HasSuicided(address)) + s.Require().True(db.Suicide(address)) // check dirty state - suite.Require().True(db.HasSuicided(address)) + s.Require().True(db.HasSuicided(address)) // balance is cleared - suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) + s.Require().Equal(big.NewInt(0), db.GetBalance(address)) // but code and state are still accessible in dirty state - suite.Require().Equal(value1, db.GetState(address, key1)) - suite.Require().Equal([]byte("hello world"), db.GetCode(address)) + s.Require().Equal(value1, db.GetState(address, key1)) + s.Require().Equal([]byte("hello world"), db.GetCode(address)) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) // not accessible from StateDB anymore - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) - suite.Require().False(db.Exist(address)) - - // and cleared in keeper too - keeper := db.Keeper().(*MockKeeper) - suite.Require().Empty(keeper.accounts) - suite.Require().Empty(keeper.codes) + db = deps.StateDB() + s.Require().False(db.Exist(address)) + s.Require().Empty(CollectContractStorage(db)) }}, } for _, tc := range testCases { - suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) - tc.malleate(db) + s.Run(tc.name, func() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() + tc.malleate(&deps, db) }) } } -func (suite *StateDBTestSuite) TestAccountOverride() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) +func (s *Suite) TestAccountOverride() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() // test balance carry over when overwritten amount := big.NewInt(1) @@ -122,12 +147,12 @@ func (suite *StateDBTestSuite) TestAccountOverride() { db.CreateAccount(address) // check balance is not lost - suite.Require().Equal(amount, db.GetBalance(address)) + s.Require().Equal(amount, db.GetBalance(address)) // but nonce is reset - suite.Require().Equal(uint64(0), db.GetNonce(address)) + s.Require().Equal(uint64(0), db.GetNonce(address)) } -func (suite *StateDBTestSuite) TestDBError() { +func (s *Suite) TestDBError() { testCases := []struct { name string malleate func(vm.StateDB) @@ -137,17 +162,19 @@ func (suite *StateDBTestSuite) TestDBError() { }}, {"delete account", func(db vm.StateDB) { db.SetNonce(errAddress, 1) - suite.Require().True(db.Suicide(errAddress)) + s.Require().True(db.Suicide(errAddress)) + s.True(db.HasSuicided(errAddress)) }}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() tc.malleate(db) - suite.Require().Error(db.Commit()) + s.Require().NoError(db.Commit()) } } -func (suite *StateDBTestSuite) TestBalance() { +func (s *Suite) TestBalance() { // NOTE: no need to test overflow/underflow, that is guaranteed by evm implementation. testCases := []struct { name string @@ -160,7 +187,7 @@ func (suite *StateDBTestSuite) TestBalance() { {"sub balance", func(db *statedb.StateDB) { db.AddBalance(address, big.NewInt(10)) // get dirty balance - suite.Require().Equal(big.NewInt(10), db.GetBalance(address)) + s.Require().Equal(big.NewInt(10), db.GetBalance(address)) db.SubBalance(address, big.NewInt(2)) }, big.NewInt(8)}, {"add zero balance", func(db *statedb.StateDB) { @@ -172,21 +199,22 @@ func (suite *StateDBTestSuite) TestBalance() { } for _, tc := range testCases { - suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + s.Run(tc.name, func() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() tc.malleate(db) // check dirty state - suite.Require().Equal(tc.expBalance, db.GetBalance(address)) - suite.Require().NoError(db.Commit()) + s.Require().Equal(tc.expBalance, db.GetBalance(address)) + s.Require().NoError(db.Commit()) + // check committed balance too - suite.Require().Equal(tc.expBalance, keeper.accounts[address].account.Balance) + s.Require().Equal(tc.expBalance, db.GetBalance(address)) }) } } -func (suite *StateDBTestSuite) TestState() { +func (s *Suite) TestState() { key1 := common.BigToHash(big.NewInt(1)) value1 := common.BigToHash(big.NewInt(1)) testCases := []struct { @@ -205,47 +233,49 @@ func (suite *StateDBTestSuite) TestState() { }, statedb.Storage{}}, {"set state", func(db *statedb.StateDB) { // check empty initial state - suite.Require().Equal(common.Hash{}, db.GetState(address, key1)) - suite.Require().Equal(common.Hash{}, db.GetCommittedState(address, key1)) + s.Require().Equal(common.Hash{}, db.GetState(address, key1)) + s.Require().Equal(common.Hash{}, db.GetCommittedState(address, key1)) // set state db.SetState(address, key1, value1) // query dirty state - suite.Require().Equal(value1, db.GetState(address, key1)) + s.Require().Equal(value1, db.GetState(address, key1)) // check committed state is still not exist - suite.Require().Equal(common.Hash{}, db.GetCommittedState(address, key1)) + s.Require().Equal(common.Hash{}, db.GetCommittedState(address, key1)) // set same value again, should be noop db.SetState(address, key1, value1) - suite.Require().Equal(value1, db.GetState(address, key1)) + s.Require().Equal(value1, db.GetState(address, key1)) }, statedb.Storage{ key1: value1, }}, } for _, tc := range testCases { - suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + s.Run(tc.name, func() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() tc.malleate(db) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) // check committed states in keeper - suite.Require().Equal(tc.expStates, keeper.accounts[address].states) + for k, v := range tc.expStates { + s.Equal(v, db.GetState(address, k)) + } // check ForEachStorage - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db = deps.StateDB() collected := CollectContractStorage(db) if len(tc.expStates) > 0 { - suite.Require().Equal(tc.expStates, collected) + s.Require().Equal(tc.expStates, collected) } else { - suite.Require().Empty(collected) + s.Require().Empty(collected) } }) } } -func (suite *StateDBTestSuite) TestCode() { +func (s *Suite) TestCode() { code := []byte("hello world") codeHash := crypto.Keccak256Hash(code) @@ -265,28 +295,28 @@ func (suite *StateDBTestSuite) TestCode() { } for _, tc := range testCases { - suite.Run(tc.name, func() { - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + s.Run(tc.name, func() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() tc.malleate(db) // check dirty state - suite.Require().Equal(tc.expCode, db.GetCode(address)) - suite.Require().Equal(len(tc.expCode), db.GetCodeSize(address)) - suite.Require().Equal(tc.expCodeHash, db.GetCodeHash(address)) + s.Require().Equal(tc.expCode, db.GetCode(address)) + s.Require().Equal(len(tc.expCode), db.GetCodeSize(address)) + s.Require().Equal(tc.expCodeHash, db.GetCodeHash(address)) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) // check again - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) - suite.Require().Equal(tc.expCode, db.GetCode(address)) - suite.Require().Equal(len(tc.expCode), db.GetCodeSize(address)) - suite.Require().Equal(tc.expCodeHash, db.GetCodeHash(address)) + db = deps.StateDB() + s.Require().Equal(tc.expCode, db.GetCode(address)) + s.Require().Equal(len(tc.expCode), db.GetCodeSize(address)) + s.Require().Equal(tc.expCodeHash, db.GetCodeHash(address)) }) } } -func (suite *StateDBTestSuite) TestRevertSnapshot() { +func (s *Suite) TestRevertSnapshot() { v1 := common.BigToHash(big.NewInt(1)) v2 := common.BigToHash(big.NewInt(2)) v3 := common.BigToHash(big.NewInt(3)) @@ -313,7 +343,7 @@ func (suite *StateDBTestSuite) TestRevertSnapshot() { {"suicide", func(db vm.StateDB) { db.SetState(address, v1, v2) db.SetCode(address, []byte("hello world")) - suite.Require().True(db.Suicide(address)) + s.Require().True(db.Suicide(address)) }}, {"add log", func(db vm.StateDB) { db.AddLog(&gethcore.Log{ @@ -330,70 +360,78 @@ func (suite *StateDBTestSuite) TestRevertSnapshot() { }}, } for _, tc := range testCases { - suite.Run(tc.name, func() { - ctx := sdk.Context{} - keeper := NewMockKeeper() - - { - // do some arbitrary changes to the storage - db := statedb.New(ctx, keeper, emptyTxConfig) - db.SetNonce(address, 1) - db.AddBalance(address, big.NewInt(100)) - db.SetCode(address, []byte("hello world")) - db.SetState(address, v1, v2) - db.SetNonce(address2, 1) - suite.Require().NoError(db.Commit()) - } + s.Run(tc.name, func() { + deps := evmtest.NewTestDeps() + + // do some arbitrary changes to the storage + db := deps.StateDB() + db.SetNonce(address, 1) + db.AddBalance(address, big.NewInt(100)) + db.SetCode(address, []byte("hello world")) + db.SetState(address, v1, v2) + db.SetNonce(address2, 1) + s.Require().NoError(db.Commit()) - originalKeeper := keeper.Clone() + // Store original state values + originalNonce := db.GetNonce(address) + originalBalance := db.GetBalance(address) + originalCode := db.GetCode(address) + originalState := db.GetState(address, v1) + originalNonce2 := db.GetNonce(address2) // run test - db := statedb.New(ctx, keeper, emptyTxConfig) rev := db.Snapshot() tc.malleate(db) db.RevertToSnapshot(rev) // check empty states after revert - suite.Require().Zero(db.GetRefund()) - suite.Require().Empty(db.Logs()) + s.Require().Zero(db.GetRefund()) + s.Require().Empty(db.Logs()) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) - // check keeper should stay the same - suite.Require().Equal(originalKeeper, keeper) + // Check again after commit to ensure persistence + s.Require().Equal(originalNonce, db.GetNonce(address)) + s.Require().Equal(originalBalance, db.GetBalance(address)) + s.Require().Equal(originalCode, db.GetCode(address)) + s.Require().Equal(originalState, db.GetState(address, v1)) + s.Require().Equal(originalNonce2, db.GetNonce(address2)) }) } } -func (suite *StateDBTestSuite) TestNestedSnapshot() { +func (s *Suite) TestNestedSnapshot() { key := common.BigToHash(big.NewInt(1)) value1 := common.BigToHash(big.NewInt(1)) value2 := common.BigToHash(big.NewInt(2)) - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() rev1 := db.Snapshot() db.SetState(address, key, value1) rev2 := db.Snapshot() db.SetState(address, key, value2) - suite.Require().Equal(value2, db.GetState(address, key)) + s.Require().Equal(value2, db.GetState(address, key)) db.RevertToSnapshot(rev2) - suite.Require().Equal(value1, db.GetState(address, key)) + s.Require().Equal(value1, db.GetState(address, key)) db.RevertToSnapshot(rev1) - suite.Require().Equal(common.Hash{}, db.GetState(address, key)) + s.Require().Equal(common.Hash{}, db.GetState(address, key)) } -func (suite *StateDBTestSuite) TestInvalidSnapshotId() { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) - suite.Require().Panics(func() { +func (s *Suite) TestInvalidSnapshotId() { + deps := evmtest.NewTestDeps() + db := deps.StateDB() + + s.Require().Panics(func() { db.RevertToSnapshot(1) }) } -func (suite *StateDBTestSuite) TestAccessList() { +func (s *Suite) TestAccessList() { value1 := common.BigToHash(big.NewInt(1)) value2 := common.BigToHash(big.NewInt(2)) @@ -402,38 +440,38 @@ func (suite *StateDBTestSuite) TestAccessList() { malleate func(vm.StateDB) }{ {"add address", func(db vm.StateDB) { - suite.Require().False(db.AddressInAccessList(address)) + s.Require().False(db.AddressInAccessList(address)) db.AddAddressToAccessList(address) - suite.Require().True(db.AddressInAccessList(address)) + s.Require().True(db.AddressInAccessList(address)) addrPresent, slotPresent := db.SlotInAccessList(address, value1) - suite.Require().True(addrPresent) - suite.Require().False(slotPresent) + s.Require().True(addrPresent) + s.Require().False(slotPresent) // add again, should be no-op db.AddAddressToAccessList(address) - suite.Require().True(db.AddressInAccessList(address)) + s.Require().True(db.AddressInAccessList(address)) }}, {"add slot", func(db vm.StateDB) { addrPresent, slotPresent := db.SlotInAccessList(address, value1) - suite.Require().False(addrPresent) - suite.Require().False(slotPresent) + s.Require().False(addrPresent) + s.Require().False(slotPresent) db.AddSlotToAccessList(address, value1) addrPresent, slotPresent = db.SlotInAccessList(address, value1) - suite.Require().True(addrPresent) - suite.Require().True(slotPresent) + s.Require().True(addrPresent) + s.Require().True(slotPresent) // add another slot db.AddSlotToAccessList(address, value2) addrPresent, slotPresent = db.SlotInAccessList(address, value2) - suite.Require().True(addrPresent) - suite.Require().True(slotPresent) + s.Require().True(addrPresent) + s.Require().True(slotPresent) // add again, should be noop db.AddSlotToAccessList(address, value2) addrPresent, slotPresent = db.SlotInAccessList(address, value2) - suite.Require().True(addrPresent) - suite.Require().True(slotPresent) + s.Require().True(addrPresent) + s.Require().True(slotPresent) }}, {"prepare access list", func(db vm.StateDB) { al := gethcore.AccessList{{ @@ -444,68 +482,79 @@ func (suite *StateDBTestSuite) TestAccessList() { db.PrepareAccessList(address, &address2, vm.PrecompiledAddressesBerlin, al) // check sender and dst - suite.Require().True(db.AddressInAccessList(address)) - suite.Require().True(db.AddressInAccessList(address2)) + s.Require().True(db.AddressInAccessList(address)) + s.Require().True(db.AddressInAccessList(address2)) // check precompiles - suite.Require().True(db.AddressInAccessList(common.BytesToAddress([]byte{1}))) + s.Require().True(db.AddressInAccessList(common.BytesToAddress([]byte{1}))) // check AccessList - suite.Require().True(db.AddressInAccessList(address3)) + s.Require().True(db.AddressInAccessList(address3)) addrPresent, slotPresent := db.SlotInAccessList(address3, value1) - suite.Require().True(addrPresent) - suite.Require().True(slotPresent) + s.Require().True(addrPresent) + s.Require().True(slotPresent) addrPresent, slotPresent = db.SlotInAccessList(address3, value2) - suite.Require().True(addrPresent) - suite.Require().False(slotPresent) + s.Require().True(addrPresent) + s.Require().False(slotPresent) }}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() tc.malleate(db) } } -func (suite *StateDBTestSuite) TestLog() { +func (s *Suite) TestLog() { txHash := common.BytesToHash([]byte("tx")) + // use a non-default tx config + const ( + blockNumber = uint64(1) + txIdx = uint(1) + logIdx = uint(1) + ) txConfig := statedb.NewTxConfig( blockHash, txHash, - 1, 1, + txIdx, logIdx, ) - db := statedb.New(sdk.Context{}, NewMockKeeper(), txConfig) - data := []byte("hello world") - db.AddLog(&gethcore.Log{ - Address: address, - Topics: []common.Hash{}, - Data: data, - BlockNumber: 1, - }) - suite.Require().Equal(1, len(db.Logs())) - expecedLog := &gethcore.Log{ - Address: address, - Topics: []common.Hash{}, - Data: data, - BlockNumber: 1, - BlockHash: blockHash, - TxHash: txHash, - TxIndex: 1, - Index: 1, - } - suite.Require().Equal(expecedLog, db.Logs()[0]) - db.AddLog(&gethcore.Log{ + deps := evmtest.NewTestDeps() + db := statedb.New(deps.Ctx, &deps.Chain.EvmKeeper, txConfig) + + logData := []byte("hello world") + log := &gethcore.Log{ Address: address, Topics: []common.Hash{}, - Data: data, - BlockNumber: 1, - }) - suite.Require().Equal(2, len(db.Logs())) - expecedLog.Index++ - suite.Require().Equal(expecedLog, db.Logs()[1]) + Data: logData, + BlockNumber: blockNumber, + } + db.AddLog(log) + s.Require().Equal(1, len(db.Logs())) + + wantLog := &gethcore.Log{ + Address: log.Address, + Topics: log.Topics, + Data: log.Data, + BlockNumber: log.BlockNumber, + + // New fields + BlockHash: blockHash, + TxHash: txHash, + TxIndex: txIdx, + Index: logIdx, + } + s.Require().Equal(wantLog, db.Logs()[0]) + + // Add a second log and assert values + db.AddLog(log) + wantLog.Index++ + s.Require().Equal(2, len(db.Logs())) + gotLog := db.Logs()[1] + s.Require().Equal(wantLog, gotLog) } -func (suite *StateDBTestSuite) TestRefund() { +func (s *Suite) TestRefund() { testCases := []struct { name string malleate func(vm.StateDB) @@ -525,37 +574,45 @@ func (suite *StateDBTestSuite) TestRefund() { }, 0, true}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, NewMockKeeper(), emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() if !tc.expPanic { tc.malleate(db) - suite.Require().Equal(tc.expRefund, db.GetRefund()) + s.Require().Equal(tc.expRefund, db.GetRefund()) } else { - suite.Require().Panics(func() { + s.Require().Panics(func() { tc.malleate(db) }) } } } -func (suite *StateDBTestSuite) TestIterateStorage() { +func (s *Suite) TestIterateStorage() { key1 := common.BigToHash(big.NewInt(1)) value1 := common.BigToHash(big.NewInt(2)) key2 := common.BigToHash(big.NewInt(3)) value2 := common.BigToHash(big.NewInt(4)) - keeper := NewMockKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + deps := evmtest.NewTestDeps() + db := deps.StateDB() db.SetState(address, key1, value1) db.SetState(address, key2, value2) // ForEachStorage only iterate committed state - suite.Require().Empty(CollectContractStorage(db)) + s.Require().Empty(CollectContractStorage(db)) - suite.Require().NoError(db.Commit()) + s.Require().NoError(db.Commit()) storage := CollectContractStorage(db) - suite.Require().Equal(2, len(storage)) - suite.Require().Equal(keeper.accounts[address].states, storage) + s.Require().Equal(2, len(storage)) + + keySet := set.New[common.Hash](key1, key2) + valSet := set.New[common.Hash](value1, value2) + for _, stateKey := range storage.SortedKeys() { + stateValue := deps.K.GetState(deps.Ctx, address, stateKey) + s.True(keySet.Has(stateKey)) + s.True(valSet.Has(stateValue)) + } // break early iteration storage = make(statedb.Storage) @@ -564,23 +621,6 @@ func (suite *StateDBTestSuite) TestIterateStorage() { // return false to break early return false }) - suite.Require().NoError(err) - suite.Require().Equal(1, len(storage)) -} - -func CollectContractStorage(db vm.StateDB) statedb.Storage { - storage := make(statedb.Storage) - err := db.ForEachStorage(address, func(k, v common.Hash) bool { - storage[k] = v - return true - }) - if err != nil { - return nil - } - - return storage -} - -func TestStateDBTestSuite(t *testing.T) { - suite.Run(t, &StateDBTestSuite{}) + s.Require().NoError(err) + s.Require().Equal(1, len(storage)) } From 7b8addd68a02ef8d613326c13d3b55296395cbc4 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Mon, 5 Aug 2024 14:07:08 +0200 Subject: [PATCH 10/21] address conversion fns and tests --- eth/eth_account.go | 31 ++++++++++++++++--------- eth/eth_account_test.go | 42 ++++++++++++++++++++++++++++++++++ eth/rpc/rpcapi/eth_api_test.go | 4 ++-- eth/safe_math_test.go | 12 +++++----- eth/state_encoder_test.go | 12 +--------- 5 files changed, 71 insertions(+), 30 deletions(-) create mode 100644 eth/eth_account_test.go diff --git a/eth/eth_account.go b/eth/eth_account.go index 781f09f06..85a857b5a 100644 --- a/eth/eth_account.go +++ b/eth/eth_account.go @@ -7,10 +7,19 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/ethereum/go-ethereum/common" + sdk "github.com/cosmos/cosmos-sdk/types" + gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) +func EthAddrToNibiruAddr(ethAddr gethcommon.Address) sdk.AccAddress { + return ethAddr.Bytes() +} + +func NibiruAddrToEthAddr(nibiruAddr sdk.AccAddress) gethcommon.Address { + return gethcommon.BytesToAddress(nibiruAddr.Bytes()) +} + var ( _ authtypes.AccountI = (*EthAccount)(nil) _ EthAccountI = (*EthAccount)(nil) @@ -32,11 +41,11 @@ const ( type EthAccountI interface { //revive:disable-line:exported authtypes.AccountI // EthAddress returns the ethereum Address representation of the AccAddress - EthAddress() common.Address + EthAddress() gethcommon.Address // CodeHash is the keccak256 hash of the contract code (if any) - GetCodeHash() common.Hash + GetCodeHash() gethcommon.Hash // SetCodeHash sets the code hash to the account fields - SetCodeHash(code common.Hash) error + SetCodeHash(code gethcommon.Hash) error // Type returns the type of Ethereum Account (EOA or Contract) Type() EthAccType } @@ -46,15 +55,15 @@ func (acc EthAccount) GetBaseAccount() *authtypes.BaseAccount { } // EthAddress returns the account address ethereum format. -func (acc EthAccount) EthAddress() common.Address { - return common.BytesToAddress(acc.GetAddress().Bytes()) +func (acc EthAccount) EthAddress() gethcommon.Address { + return gethcommon.BytesToAddress(acc.GetAddress().Bytes()) } -func (acc EthAccount) GetCodeHash() common.Hash { - return common.HexToHash(acc.CodeHash) +func (acc EthAccount) GetCodeHash() gethcommon.Hash { + return gethcommon.HexToHash(acc.CodeHash) } -func (acc *EthAccount) SetCodeHash(codeHash common.Hash) error { +func (acc *EthAccount) SetCodeHash(codeHash gethcommon.Hash) error { acc.CodeHash = codeHash.Hex() return nil } @@ -62,7 +71,7 @@ func (acc *EthAccount) SetCodeHash(codeHash common.Hash) error { // Type returns the type of Ethereum Account (EOA or Contract) func (acc EthAccount) Type() EthAccType { if bytes.Equal( - emptyCodeHash, common.HexToHash(acc.CodeHash).Bytes(), + emptyCodeHash, gethcommon.HexToHash(acc.CodeHash).Bytes(), ) { return EthAccType_EOA } @@ -79,6 +88,6 @@ var emptyCodeHash = crypto.Keccak256(nil) func ProtoBaseAccount() authtypes.AccountI { return &EthAccount{ BaseAccount: &authtypes.BaseAccount{}, - CodeHash: common.BytesToHash(emptyCodeHash).String(), + CodeHash: gethcommon.BytesToHash(emptyCodeHash).String(), } } diff --git a/eth/eth_account_test.go b/eth/eth_account_test.go new file mode 100644 index 000000000..90e9b8e4b --- /dev/null +++ b/eth/eth_account_test.go @@ -0,0 +1,42 @@ +package eth_test + +import ( + "github.com/NibiruChain/nibiru/eth" + "github.com/NibiruChain/nibiru/x/evm/evmtest" +) + +func (s *Suite) TestEthAddrToNibiruAddr() { + + accInfo := evmtest.NewEthAccInfo() + s.Equal( + accInfo.EthAddr, + eth.NibiruAddrToEthAddr(accInfo.NibiruAddr), + ) + s.Equal( + accInfo.NibiruAddr, + eth.EthAddrToNibiruAddr(accInfo.EthAddr), + ) + + s.T().Log("unit operation - hex -> nibi -> hex") + { + + addr := evmtest.NewEthAccInfo().NibiruAddr + s.Equal( + addr, + eth.EthAddrToNibiruAddr( + eth.NibiruAddrToEthAddr(addr), + ), + ) + } + + s.T().Log("unit operation - nibi -> hex -> nibi") + { + addr := evmtest.NewEthAccInfo().EthAddr + s.Equal( + addr, + eth.NibiruAddrToEthAddr( + eth.EthAddrToNibiruAddr(addr), + ), + ) + } +} diff --git a/eth/rpc/rpcapi/eth_api_test.go b/eth/rpc/rpcapi/eth_api_test.go index 89398a373..da4dab9f1 100644 --- a/eth/rpc/rpcapi/eth_api_test.go +++ b/eth/rpc/rpcapi/eth_api_test.go @@ -15,11 +15,11 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/NibiruChain/nibiru/app/appconst" + "github.com/NibiruChain/nibiru/eth" nibirucommon "github.com/NibiruChain/nibiru/x/common" "github.com/NibiruChain/nibiru/x/common/denoms" "github.com/NibiruChain/nibiru/x/evm/embeds" - "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/stretchr/testify/suite" @@ -70,7 +70,7 @@ func (s *TestSuite) SetupSuite() { testAccPrivateKey, _ := crypto.GenerateKey() s.fundedAccPrivateKey = testAccPrivateKey s.fundedAccEthAddr = crypto.PubkeyToAddress(testAccPrivateKey.PublicKey) - s.fundedAccNibiAddr = evmtest.EthAddrToNibiruAddr(s.fundedAccEthAddr) + s.fundedAccNibiAddr = eth.EthAddrToNibiruAddr(s.fundedAccEthAddr) val := s.network.Validators[0] diff --git a/eth/safe_math_test.go b/eth/safe_math_test.go index a956251cf..655622ded 100644 --- a/eth/safe_math_test.go +++ b/eth/safe_math_test.go @@ -13,15 +13,15 @@ import ( const maxInt64 = 9223372036854775807 -type SuiteSafeMath struct { +type Suite struct { suite.Suite } -func TestTypesSuite(t *testing.T) { - suite.Run(t, new(SuiteSafeMath)) +func TestSuite_RunAll(t *testing.T) { + suite.Run(t, new(Suite)) } -func (s *SuiteSafeMath) TestSafeNewIntFromBigInt() { +func (s *Suite) TestSafeNewIntFromBigInt() { tests := []struct { name string input *big.Int @@ -57,7 +57,7 @@ func (s *SuiteSafeMath) TestSafeNewIntFromBigInt() { } } -func (s *SuiteSafeMath) TestIsValidInt256() { +func (s *Suite) TestIsValidInt256() { tests := []struct { name string input *big.Int @@ -88,7 +88,7 @@ func (s *SuiteSafeMath) TestIsValidInt256() { } } -func (s *SuiteSafeMath) TestSafeInt64() { +func (s *Suite) TestSafeInt64() { tests := []struct { name string input uint64 diff --git a/eth/state_encoder_test.go b/eth/state_encoder_test.go index 03eff2ac6..d75ffdd52 100644 --- a/eth/state_encoder_test.go +++ b/eth/state_encoder_test.go @@ -4,11 +4,9 @@ import ( "testing" "github.com/NibiruChain/collections" + "github.com/NibiruChain/nibiru/eth" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - - "github.com/NibiruChain/nibiru/eth" ) func assertBijectiveKey[T any](t *testing.T, encoder collections.KeyEncoder[T], key T) { @@ -34,14 +32,6 @@ func assertBijectiveValue[T any](t *testing.T, encoder collections.ValueEncoder[ require.NotEmpty(t, encoder.Name()) } -type Suite struct { - suite.Suite -} - -func TestSuite_RunAll(t *testing.T) { - suite.Run(t, new(Suite)) -} - func (s *Suite) TestEncoderBytes() { testCases := []struct { name string From 82a1d33b2cf03597609af93de8b2dfcb2cfae3fb Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Mon, 5 Aug 2024 14:42:58 +0200 Subject: [PATCH 11/21] feat(evm): Combine both account queries into "/eth.evm.v1.Query/EthAccount", accepting both nibi-prefixed Bech32 addresses and Ethereum-type hexadecimal addresses as input. --- CHANGELOG.md | 1 + eth/eth_account_test.go | 2 - eth/rpc/backend/mocks/evm_query_client.go | 29 - eth/state_encoder_test.go | 3 +- proto/eth/evm/v1/query.proto | 45 +- x/evm/evm_test.go | 11 +- x/evm/evmtest/eth.go | 6 +- x/evm/keeper/grpc_query.go | 68 +- x/evm/keeper/grpc_query_test.go | 119 ++-- x/evm/keeper/statedb_test.go | 3 +- x/evm/query.go | 36 +- x/evm/query.pb.go | 721 +++++++--------------- x/evm/query.pb.gw.go | 101 --- 13 files changed, 326 insertions(+), 819 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a4d4414b..da2b7b3ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#1979](https://github.com/NibiruChain/nibiru/pull/1979) -refactor(db): use pebbledb as the default db in integration tests - [#1981](https://github.com/NibiruChain/nibiru/pull/1981) - fix(evm): remove isCheckTx() short circuit on `AnteDecVerifyEthAcc` - [#1985](https://github.com/NibiruChain/nibiru/pull/1985) - feat(evm)!: Use atto denomination for the wei units in the EVM so that NIBI is "ether" to clients. Only micronibi (unibi) amounts can be transferred. All clients follow the constraint equation, 1 ether == 1 NIBI == 10^6 unibi == 10^18 wei. +- [#1986](https://github.com/NibiruChain/nibiru/pull/1986) - feat(evm): Combine both account queries into "/eth.evm.v1.Query/EthAccount", accepting both nibi-prefixed Bech32 addresses and Ethereum-type hexadecimal addresses as input. #### Dapp modules: perp, spot, oracle, etc diff --git a/eth/eth_account_test.go b/eth/eth_account_test.go index 90e9b8e4b..3777f086d 100644 --- a/eth/eth_account_test.go +++ b/eth/eth_account_test.go @@ -6,7 +6,6 @@ import ( ) func (s *Suite) TestEthAddrToNibiruAddr() { - accInfo := evmtest.NewEthAccInfo() s.Equal( accInfo.EthAddr, @@ -19,7 +18,6 @@ func (s *Suite) TestEthAddrToNibiruAddr() { s.T().Log("unit operation - hex -> nibi -> hex") { - addr := evmtest.NewEthAccInfo().NibiruAddr s.Equal( addr, diff --git a/eth/rpc/backend/mocks/evm_query_client.go b/eth/rpc/backend/mocks/evm_query_client.go index 252ee8b0f..0feeb470c 100644 --- a/eth/rpc/backend/mocks/evm_query_client.go +++ b/eth/rpc/backend/mocks/evm_query_client.go @@ -137,35 +137,6 @@ func (_m *EVMQueryClient) Code(ctx context.Context, in *evm.QueryCodeRequest, op return r0, r1 } -// NibiruAccount provides a mock function with given fields: ctx, in, opts -func (_m *EVMQueryClient) NibiruAccount(ctx context.Context, in *evm.QueryNibiruAccountRequest, opts ...grpc.CallOption) (*evm.QueryNibiruAccountResponse, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, in) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 *evm.QueryNibiruAccountResponse - if rf, ok := ret.Get(0).(func(context.Context, *evm.QueryNibiruAccountRequest, ...grpc.CallOption) *evm.QueryNibiruAccountResponse); ok { - r0 = rf(ctx, in, opts...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*evm.QueryNibiruAccountResponse) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, *evm.QueryNibiruAccountRequest, ...grpc.CallOption) error); ok { - r1 = rf(ctx, in, opts...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} // EstimateGas provides a mock function with given fields: ctx, in, opts func (_m *EVMQueryClient) EstimateGas(ctx context.Context, in *evm.EthCallRequest, opts ...grpc.CallOption) (*evm.EstimateGasResponse, error) { diff --git a/eth/state_encoder_test.go b/eth/state_encoder_test.go index d75ffdd52..be1bf36e4 100644 --- a/eth/state_encoder_test.go +++ b/eth/state_encoder_test.go @@ -4,9 +4,10 @@ import ( "testing" "github.com/NibiruChain/collections" - "github.com/NibiruChain/nibiru/eth" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + + "github.com/NibiruChain/nibiru/eth" ) func assertBijectiveKey[T any](t *testing.T, encoder collections.KeyEncoder[T], key T) { diff --git a/proto/eth/evm/v1/query.proto b/proto/eth/evm/v1/query.proto index 15cfbe125..2d6797a3b 100644 --- a/proto/eth/evm/v1/query.proto +++ b/proto/eth/evm/v1/query.proto @@ -13,16 +13,12 @@ option go_package = "github.com/NibiruChain/nibiru/x/evm"; // Query defines the gRPC querier service. service Query { - // EthAccount queries an Ethereum account. + // EthAccount queries a Nibiru account using its EVM address or Bech32 Nibiru + // address. rpc EthAccount(QueryEthAccountRequest) returns (QueryEthAccountResponse) { option (google.api.http).get = "/nibiru/evm/v1/eth_account/{address}"; } - // NibiruAccount queries the Bech32 Nibiru address corresponding to Nibiru EVM account. - rpc NibiruAccount(QueryNibiruAccountRequest) returns (QueryNibiruAccountResponse) { - option (google.api.http).get = "/nibiru/evm/v1/nibiru_account/{address}"; - } - // ValidatorAccount queries an Ethereum account's from a validator consensus // Address. rpc ValidatorAccount(QueryValidatorAccountRequest) returns (QueryValidatorAccountResponse) { @@ -86,39 +82,28 @@ message QueryEthAccountRequest { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; - // address is the ethereum hex address to query the account for. + // address is the Ethereum hex address or nibi Bech32 address to query the account for. string address = 1; } -// QueryEthAccountResponse is the response type for the Query/Account RPC method. +// QueryEthAccountResponse is the response type for the Query/EthAccount RPC method. message QueryEthAccountResponse { + // balance is the balance of unibi (micronibi). + string balance = 1; // balance_wei is the balance of wei (attoether, where NIBI is ether). - string balance_wei = 1; + string balance_wei = 2; // code_hash is the hex-formatted code bytes from the EOA. - string code_hash = 2; + string code_hash = 3; // nonce is the account's sequence number. - uint64 nonce = 3; -} - -// QueryNibiruAccountRequest is the request type for the Query/NibiruAccount RPC -// method. -message QueryNibiruAccountRequest { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; + uint64 nonce = 4; - // address is the ethereum hex address to query the account for. - string address = 1; -} + // eth_address: The hexadecimal-encoded string representing the 20 byte address + // of a Nibiru EVM account. + string eth_address = 5; -// QueryNibiruAccountResponse is the response type for the Query/NibiruAccount -// RPC method. -message QueryNibiruAccountResponse { - // Nibiru bech32 account "address" - string address = 1; - // sequence is the account's sequence number. - uint64 sequence = 2; - // account_number is the account number - uint64 account_number = 3; + // bech32_address is the nibi-prefixed address of the account that can receive + // bank transfers ("cosmos.bank.v1beta1.MsgSend"). + string bech32_address = 6; } // QueryValidatorAccountRequest is the request type for the diff --git a/x/evm/evm_test.go b/x/evm/evm_test.go index 59ae0ba4b..124fa5080 100644 --- a/x/evm/evm_test.go +++ b/x/evm/evm_test.go @@ -129,17 +129,12 @@ func (s *TestSuite) TestModuleAddressEVM() { // EVM module should have mint perms deps := evmtest.NewTestDeps() { - _, err := deps.K.EthAccount(deps.GoCtx(), &evm.QueryEthAccountRequest{ + resp, err := deps.K.EthAccount(deps.GoCtx(), &evm.QueryEthAccountRequest{ Address: evmModuleAddr.Hex(), }) s.NoError(err) - } - { - resp, err := deps.K.NibiruAccount(deps.GoCtx(), &evm.QueryNibiruAccountRequest{ - Address: evmModuleAddr.Hex(), - }) - s.NoError(err) - s.Equal(nibiAddr.String(), resp.Address) + s.Equal(nibiAddr.String(), resp.Bech32Address) + s.Equal(evmModuleAddr.String(), resp.EthAddress) } } diff --git a/x/evm/evmtest/eth.go b/x/evm/evmtest/eth.go index e9f9717c5..a90fd408f 100644 --- a/x/evm/evmtest/eth.go +++ b/x/evm/evmtest/eth.go @@ -32,17 +32,13 @@ func NewEthAccInfo() EthPrivKeyAcc { ethAddr := crypto.PubkeyToAddress(privKeyE.PublicKey) return EthPrivKeyAcc{ EthAddr: ethAddr, - NibiruAddr: EthAddrToNibiruAddr(ethAddr), + NibiruAddr: eth.EthAddrToNibiruAddr(ethAddr), PrivKey: privkey, PrivKeyE: privKeyE, KeyringSigner: NewSigner(privkey), } } -func EthAddrToNibiruAddr(ethAddr gethcommon.Address) sdk.AccAddress { - return ethAddr.Bytes() -} - type EthPrivKeyAcc struct { EthAddr gethcommon.Address NibiruAddr sdk.AccAddress diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index b06592142..542aaf4ed 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -37,65 +37,43 @@ import ( var _ evm.QueryServer = &Keeper{} // EthAccount: Implements the gRPC query for "/eth.evm.v1.Query/EthAccount". -// EthAccount retrieves the account details for a given Ethereum hex address. +// EthAccount retrieves the account and balance details for an account with the +// given address. // // Parameters: // - goCtx: The context.Context object representing the request context. -// - req: Request containing the Ethereum hexadecimal address. -// -// Returns: -// - A pointer to the QueryEthAccountResponse object containing the account details. -// - An error if the account retrieval process encounters any issues. +// - req: Request containing the address in either Ethereum hexadecimal or +// Bech32 format. func (k Keeper) EthAccount( goCtx context.Context, req *evm.QueryEthAccountRequest, ) (*evm.QueryEthAccountResponse, error) { - if err := req.Validate(); err != nil { + isBech32, err := req.Validate() + if err != nil { return nil, err } - addr := gethcommon.HexToAddress(req.Address) - ctx := sdk.UnwrapSDKContext(goCtx) - acct := k.GetAccountOrEmpty(ctx, addr) - - return &evm.QueryEthAccountResponse{ - BalanceWei: evm.NativeToWei(acct.BalanceEvmDenom).String(), - CodeHash: gethcommon.BytesToHash(acct.CodeHash).Hex(), - Nonce: acct.Nonce, - }, nil -} + var addrEth gethcommon.Address + var addrBech32 sdk.AccAddress -// NibiruAccount: Implements the gRPC query for "/eth.evm.v1.Query/NibiruAccount". -// NibiruAccount retrieves the Cosmos account details for a given Ethereum address. -// -// Parameters: -// - goCtx: The context.Context object representing the request context. -// - req: The QueryNibiruAccountRequest object containing the Ethereum address. -// -// Returns: -// - A pointer to the QueryNibiruAccountResponse object containing the Cosmos account details. -// - An error if the account retrieval process encounters any issues. -func (k Keeper) NibiruAccount( - goCtx context.Context, req *evm.QueryNibiruAccountRequest, -) (resp *evm.QueryNibiruAccountResponse, err error) { - if err := req.Validate(); err != nil { - return resp, err + if isBech32 { + addrBech32 = sdk.MustAccAddressFromBech32(req.Address) + addrEth = eth.NibiruAddrToEthAddr(addrBech32) + } else { + addrEth = gethcommon.HexToAddress(req.Address) + addrBech32 = eth.EthAddrToNibiruAddr(addrEth) } ctx := sdk.UnwrapSDKContext(goCtx) - ethAddr := gethcommon.HexToAddress(req.Address) - nibiruAddr := sdk.AccAddress(ethAddr.Bytes()) + acct := k.GetAccountOrEmpty(ctx, addrEth) - accountOrNil := k.accountKeeper.GetAccount(ctx, nibiruAddr) - resp = &evm.QueryNibiruAccountResponse{ - Address: nibiruAddr.String(), - } - - if accountOrNil != nil { - resp.Sequence = accountOrNil.GetSequence() - resp.AccountNumber = accountOrNil.GetAccountNumber() - } - - return resp, nil + return &evm.QueryEthAccountResponse{ + Balance: acct.BalanceEvmDenom.String(), + BalanceWei: evm.NativeToWei(acct.BalanceEvmDenom).String(), + CodeHash: gethcommon.BytesToHash(acct.CodeHash).Hex(), + Nonce: acct.Nonce, + EthAddress: addrEth.Hex(), + Bech32Address: addrBech32.String(), + }, nil } // ValidatorAccount: Implements the gRPC query for diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index f50fda474..e22cab129 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -68,81 +68,60 @@ func TraceERC20Transfer() string { }` } -func (s *Suite) TestQueryNibiruAccount() { - type In = *evm.QueryNibiruAccountRequest - type Out = *evm.QueryNibiruAccountResponse +func (s *Suite) TestQueryEvmAccount() { + type In = *evm.QueryEthAccountRequest + type Out = *evm.QueryEthAccountResponse testCases := []TestCase[In, Out]{ { - name: "sad: msg validation", - scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { - req = &evm.QueryNibiruAccountRequest{ - Address: InvalidEthAddr(), - } - wantResp = &evm.QueryNibiruAccountResponse{ - Address: sdk.AccAddress(gethcommon.Address{}.Bytes()).String(), - } - return req, wantResp + name: "happy: fund account + query eth addr", + setup: func(deps *evmtest.TestDeps) { + // fund account with 420 tokens + ethAddr := deps.Sender.EthAddr + coins := sdk.Coins{sdk.NewInt64Coin(evm.DefaultEVMDenom, 420)} + err := testapp.FundAccount(deps.Chain.BankKeeper, deps.Ctx, ethAddr.Bytes(), coins) + s.Require().NoError(err) }, - wantErr: "not a valid ethereum hex addr", - }, - { - name: "happy: not existing account", scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { - ethAcc := evmtest.NewEthAccInfo() - req = &evm.QueryNibiruAccountRequest{ - Address: ethAcc.EthAddr.String(), + req = &evm.QueryEthAccountRequest{ + Address: deps.Sender.EthAddr.Hex(), } - wantResp = &evm.QueryNibiruAccountResponse{ - Address: ethAcc.NibiruAddr.String(), - Sequence: 0, - AccountNumber: 0, + wantResp = &evm.QueryEthAccountResponse{ + Balance: "420", + BalanceWei: "420" + strings.Repeat("0", 12), + CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), + Nonce: 0, + EthAddress: deps.Sender.EthAddr.String(), + Bech32Address: deps.Sender.NibiruAddr.String(), } return req, wantResp }, wantErr: "", }, { - name: "happy: existing account", + name: "happy: fund account + query nibiru bech32 addr", + setup: func(deps *evmtest.TestDeps) { + // fund account with 420 tokens + ethAddr := deps.Sender.EthAddr + coins := sdk.Coins{sdk.NewInt64Coin(evm.DefaultEVMDenom, 420)} + err := testapp.FundAccount(deps.Chain.BankKeeper, deps.Ctx, ethAddr.Bytes(), coins) + s.Require().NoError(err) + }, scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { - ethAcc := evmtest.NewEthAccInfo() - accountKeeper := deps.Chain.AccountKeeper - account := accountKeeper.NewAccountWithAddress(deps.Ctx, ethAcc.NibiruAddr) - accountKeeper.SetAccount(deps.Ctx, account) - - req = &evm.QueryNibiruAccountRequest{ - Address: ethAcc.EthAddr.String(), + req = &evm.QueryEthAccountRequest{ + Address: deps.Sender.NibiruAddr.String(), } - wantResp = &evm.QueryNibiruAccountResponse{ - Address: ethAcc.NibiruAddr.String(), - Sequence: account.GetSequence(), - AccountNumber: account.GetAccountNumber(), + wantResp = &evm.QueryEthAccountResponse{ + Balance: "420", + BalanceWei: "420" + strings.Repeat("0", 12), + CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), + Nonce: 0, + EthAddress: deps.Sender.EthAddr.String(), + Bech32Address: deps.Sender.NibiruAddr.String(), } return req, wantResp }, wantErr: "", }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - deps := evmtest.NewTestDeps() - req, wantResp := tc.scenario(&deps) - goCtx := sdk.WrapSDKContext(deps.Ctx) - gotResp, err := deps.K.NibiruAccount(goCtx, req) - if tc.wantErr != "" { - s.Require().ErrorContains(err, tc.wantErr) - return - } - s.Assert().NoError(err) - s.EqualValues(wantResp, gotResp) - }) - } -} - -func (s *Suite) TestQueryEthAccount() { - type In = *evm.QueryEthAccountRequest - type Out = *evm.QueryEthAccountResponse - testCases := []TestCase[In, Out]{ { name: "sad: msg validation", scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { @@ -159,27 +138,19 @@ func (s *Suite) TestQueryEthAccount() { wantErr: "not a valid ethereum hex addr", }, { - name: "happy: fund account + query", - setup: func(deps *evmtest.TestDeps) { - chain := deps.Chain - ethAddr := deps.Sender.EthAddr - - // fund account with 420 tokens - coins := sdk.Coins{sdk.NewInt64Coin(evm.DefaultEVMDenom, 420)} - err := chain.BankKeeper.MintCoins(deps.Ctx, evm.ModuleName, coins) - s.NoError(err) - err = chain.BankKeeper.SendCoinsFromModuleToAccount( - deps.Ctx, evm.ModuleName, ethAddr.Bytes(), coins) - s.Require().NoError(err) - }, + name: "happy: not existing account", scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { + ethAcc := evmtest.NewEthAccInfo() req = &evm.QueryEthAccountRequest{ - Address: deps.Sender.EthAddr.Hex(), + Address: ethAcc.EthAddr.String(), } wantResp = &evm.QueryEthAccountResponse{ - BalanceWei: "420" + strings.Repeat("0", 12), - CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), - Nonce: 0, + Balance: "0", + BalanceWei: "0", + CodeHash: gethcommon.BytesToHash(evm.EmptyCodeHash).Hex(), + Nonce: 0, + EthAddress: ethAcc.EthAddr.String(), + Bech32Address: ethAcc.NibiruAddr.String(), } return req, wantResp }, diff --git a/x/evm/keeper/statedb_test.go b/x/evm/keeper/statedb_test.go index 2e81c81d9..903dee7d1 100644 --- a/x/evm/keeper/statedb_test.go +++ b/x/evm/keeper/statedb_test.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/NibiruChain/nibiru/eth" "github.com/NibiruChain/nibiru/x/common/testutil/testapp" "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" @@ -64,7 +65,7 @@ func (s *Suite) TestStateDBBalance() { s.T().Log("Send via bank transfer from account to account. See expected wei amounts.") { deps := evmtest.NewTestDeps() - toNibiAddr := evmtest.EthAddrToNibiruAddr(to) + toNibiAddr := eth.EthAddrToNibiruAddr(to) err := testapp.FundAccount( deps.Chain.BankKeeper, deps.Ctx, diff --git a/x/evm/query.go b/x/evm/query.go index f6d9cfde6..d024813eb 100644 --- a/x/evm/query.go +++ b/x/evm/query.go @@ -2,6 +2,8 @@ package evm import ( + "fmt" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "google.golang.org/grpc/codes" @@ -29,29 +31,29 @@ func (m QueryTraceBlockRequest) UnpackInterfaces(unpacker codectypes.AnyUnpacker return nil } -func (req *QueryEthAccountRequest) Validate() error { +func (req *QueryEthAccountRequest) Validate() (isBech32 bool, err error) { if req == nil { - return common.ErrNilGrpcMsg + return isBech32, common.ErrNilGrpcMsg } - if err := eth.ValidateAddress(req.Address); err != nil { - return status.Error( - codes.InvalidArgument, err.Error(), - ) - } - return nil -} -func (req *QueryNibiruAccountRequest) Validate() error { - if req == nil { - return common.ErrNilGrpcMsg - } + ethAddrErr := eth.ValidateAddress(req.Address) + _, bech32AddrErr := sdk.AccAddressFromBech32(req.Address) - if err := eth.ValidateAddress(req.Address); err != nil { - return status.Error( - codes.InvalidArgument, err.Error(), + switch { + case ethAddrErr == nil: + isBech32 = false + return isBech32, nil + case bech32AddrErr == nil: + isBech32 = true + return isBech32, nil + default: + return isBech32, status.Error( + codes.InvalidArgument, + fmt.Errorf( + "could not parse address as Nibiru Bech32 or Ethereum hexadecimal: {{ Ethereum error: %w, bech32 error: %w }}", ethAddrErr, bech32AddrErr, + ).Error(), ) } - return nil } func (req *QueryValidatorAccountRequest) Validate() ( diff --git a/x/evm/query.pb.go b/x/evm/query.pb.go index 609bc55fe..cf8347632 100644 --- a/x/evm/query.pb.go +++ b/x/evm/query.pb.go @@ -38,7 +38,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // QueryEthAccountRequest is the request type for the Query/Account RPC method. type QueryEthAccountRequest struct { - // address is the ethereum hex address to query the account for. + // address is the Ethereum hex address or nibi Bech32 address to query the account for. Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` } @@ -75,14 +75,22 @@ func (m *QueryEthAccountRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryEthAccountRequest proto.InternalMessageInfo -// QueryEthAccountResponse is the response type for the Query/Account RPC method. +// QueryEthAccountResponse is the response type for the Query/EthAccount RPC method. type QueryEthAccountResponse struct { + // balance is the balance of unibi (micronibi). + Balance string `protobuf:"bytes,1,opt,name=balance,proto3" json:"balance,omitempty"` // balance_wei is the balance of wei (attoether, where NIBI is ether). - BalanceWei string `protobuf:"bytes,1,opt,name=balance_wei,json=balanceWei,proto3" json:"balance_wei,omitempty"` + BalanceWei string `protobuf:"bytes,2,opt,name=balance_wei,json=balanceWei,proto3" json:"balance_wei,omitempty"` // code_hash is the hex-formatted code bytes from the EOA. - CodeHash string `protobuf:"bytes,2,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"` + CodeHash string `protobuf:"bytes,3,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"` // nonce is the account's sequence number. - Nonce uint64 `protobuf:"varint,3,opt,name=nonce,proto3" json:"nonce,omitempty"` + Nonce uint64 `protobuf:"varint,4,opt,name=nonce,proto3" json:"nonce,omitempty"` + // eth_address: The hexadecimal-encoded string representing the 20 byte address + // of a Nibiru EVM account. + EthAddress string `protobuf:"bytes,5,opt,name=eth_address,json=ethAddress,proto3" json:"eth_address,omitempty"` + // bech32_address is the nibi-prefixed address of the account that can receive + // bank transfers ("cosmos.bank.v1beta1.MsgSend"). + Bech32Address string `protobuf:"bytes,6,opt,name=bech32_address,json=bech32Address,proto3" json:"bech32_address,omitempty"` } func (m *QueryEthAccountResponse) Reset() { *m = QueryEthAccountResponse{} } @@ -118,6 +126,13 @@ func (m *QueryEthAccountResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryEthAccountResponse proto.InternalMessageInfo +func (m *QueryEthAccountResponse) GetBalance() string { + if m != nil { + return m.Balance + } + return "" +} + func (m *QueryEthAccountResponse) GetBalanceWei() string { if m != nil { return m.BalanceWei @@ -139,109 +154,18 @@ func (m *QueryEthAccountResponse) GetNonce() uint64 { return 0 } -// QueryNibiruAccountRequest is the request type for the Query/NibiruAccount RPC -// method. -type QueryNibiruAccountRequest struct { - // address is the ethereum hex address to query the account for. - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` -} - -func (m *QueryNibiruAccountRequest) Reset() { *m = QueryNibiruAccountRequest{} } -func (m *QueryNibiruAccountRequest) String() string { return proto.CompactTextString(m) } -func (*QueryNibiruAccountRequest) ProtoMessage() {} -func (*QueryNibiruAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{2} -} -func (m *QueryNibiruAccountRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryNibiruAccountRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryNibiruAccountRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryNibiruAccountRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryNibiruAccountRequest.Merge(m, src) -} -func (m *QueryNibiruAccountRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryNibiruAccountRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryNibiruAccountRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryNibiruAccountRequest proto.InternalMessageInfo - -// QueryNibiruAccountResponse is the response type for the Query/NibiruAccount -// RPC method. -type QueryNibiruAccountResponse struct { - // Nibiru bech32 account "address" - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - // sequence is the account's sequence number. - Sequence uint64 `protobuf:"varint,2,opt,name=sequence,proto3" json:"sequence,omitempty"` - // account_number is the account number - AccountNumber uint64 `protobuf:"varint,3,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty"` -} - -func (m *QueryNibiruAccountResponse) Reset() { *m = QueryNibiruAccountResponse{} } -func (m *QueryNibiruAccountResponse) String() string { return proto.CompactTextString(m) } -func (*QueryNibiruAccountResponse) ProtoMessage() {} -func (*QueryNibiruAccountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{3} -} -func (m *QueryNibiruAccountResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryNibiruAccountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryNibiruAccountResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryNibiruAccountResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryNibiruAccountResponse.Merge(m, src) -} -func (m *QueryNibiruAccountResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryNibiruAccountResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryNibiruAccountResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryNibiruAccountResponse proto.InternalMessageInfo - -func (m *QueryNibiruAccountResponse) GetAddress() string { +func (m *QueryEthAccountResponse) GetEthAddress() string { if m != nil { - return m.Address + return m.EthAddress } return "" } -func (m *QueryNibiruAccountResponse) GetSequence() uint64 { - if m != nil { - return m.Sequence - } - return 0 -} - -func (m *QueryNibiruAccountResponse) GetAccountNumber() uint64 { +func (m *QueryEthAccountResponse) GetBech32Address() string { if m != nil { - return m.AccountNumber + return m.Bech32Address } - return 0 + return "" } // QueryValidatorAccountRequest is the request type for the @@ -255,7 +179,7 @@ func (m *QueryValidatorAccountRequest) Reset() { *m = QueryValidatorAcco func (m *QueryValidatorAccountRequest) String() string { return proto.CompactTextString(m) } func (*QueryValidatorAccountRequest) ProtoMessage() {} func (*QueryValidatorAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{4} + return fileDescriptor_ffa36cdc5add14ed, []int{2} } func (m *QueryValidatorAccountRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -299,7 +223,7 @@ func (m *QueryValidatorAccountResponse) Reset() { *m = QueryValidatorAcc func (m *QueryValidatorAccountResponse) String() string { return proto.CompactTextString(m) } func (*QueryValidatorAccountResponse) ProtoMessage() {} func (*QueryValidatorAccountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{5} + return fileDescriptor_ffa36cdc5add14ed, []int{3} } func (m *QueryValidatorAccountResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -359,7 +283,7 @@ func (m *QueryBalanceRequest) Reset() { *m = QueryBalanceRequest{} } func (m *QueryBalanceRequest) String() string { return proto.CompactTextString(m) } func (*QueryBalanceRequest) ProtoMessage() {} func (*QueryBalanceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{6} + return fileDescriptor_ffa36cdc5add14ed, []int{4} } func (m *QueryBalanceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -400,7 +324,7 @@ func (m *QueryBalanceResponse) Reset() { *m = QueryBalanceResponse{} } func (m *QueryBalanceResponse) String() string { return proto.CompactTextString(m) } func (*QueryBalanceResponse) ProtoMessage() {} func (*QueryBalanceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{7} + return fileDescriptor_ffa36cdc5add14ed, []int{5} } func (m *QueryBalanceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -455,7 +379,7 @@ func (m *QueryStorageRequest) Reset() { *m = QueryStorageRequest{} } func (m *QueryStorageRequest) String() string { return proto.CompactTextString(m) } func (*QueryStorageRequest) ProtoMessage() {} func (*QueryStorageRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{8} + return fileDescriptor_ffa36cdc5add14ed, []int{6} } func (m *QueryStorageRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -495,7 +419,7 @@ func (m *QueryStorageResponse) Reset() { *m = QueryStorageResponse{} } func (m *QueryStorageResponse) String() string { return proto.CompactTextString(m) } func (*QueryStorageResponse) ProtoMessage() {} func (*QueryStorageResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{9} + return fileDescriptor_ffa36cdc5add14ed, []int{7} } func (m *QueryStorageResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -541,7 +465,7 @@ func (m *QueryCodeRequest) Reset() { *m = QueryCodeRequest{} } func (m *QueryCodeRequest) String() string { return proto.CompactTextString(m) } func (*QueryCodeRequest) ProtoMessage() {} func (*QueryCodeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{10} + return fileDescriptor_ffa36cdc5add14ed, []int{8} } func (m *QueryCodeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -581,7 +505,7 @@ func (m *QueryCodeResponse) Reset() { *m = QueryCodeResponse{} } func (m *QueryCodeResponse) String() string { return proto.CompactTextString(m) } func (*QueryCodeResponse) ProtoMessage() {} func (*QueryCodeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{11} + return fileDescriptor_ffa36cdc5add14ed, []int{9} } func (m *QueryCodeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -629,7 +553,7 @@ func (m *QueryTxLogsRequest) Reset() { *m = QueryTxLogsRequest{} } func (m *QueryTxLogsRequest) String() string { return proto.CompactTextString(m) } func (*QueryTxLogsRequest) ProtoMessage() {} func (*QueryTxLogsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{12} + return fileDescriptor_ffa36cdc5add14ed, []int{10} } func (m *QueryTxLogsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -670,7 +594,7 @@ func (m *QueryTxLogsResponse) Reset() { *m = QueryTxLogsResponse{} } func (m *QueryTxLogsResponse) String() string { return proto.CompactTextString(m) } func (*QueryTxLogsResponse) ProtoMessage() {} func (*QueryTxLogsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{13} + return fileDescriptor_ffa36cdc5add14ed, []int{11} } func (m *QueryTxLogsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -721,7 +645,7 @@ func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } func (*QueryParamsRequest) ProtoMessage() {} func (*QueryParamsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{14} + return fileDescriptor_ffa36cdc5add14ed, []int{12} } func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -760,7 +684,7 @@ func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } func (*QueryParamsResponse) ProtoMessage() {} func (*QueryParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{15} + return fileDescriptor_ffa36cdc5add14ed, []int{13} } func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -812,7 +736,7 @@ func (m *EthCallRequest) Reset() { *m = EthCallRequest{} } func (m *EthCallRequest) String() string { return proto.CompactTextString(m) } func (*EthCallRequest) ProtoMessage() {} func (*EthCallRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{16} + return fileDescriptor_ffa36cdc5add14ed, []int{14} } func (m *EthCallRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -879,7 +803,7 @@ func (m *EstimateGasResponse) Reset() { *m = EstimateGasResponse{} } func (m *EstimateGasResponse) String() string { return proto.CompactTextString(m) } func (*EstimateGasResponse) ProtoMessage() {} func (*EstimateGasResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{17} + return fileDescriptor_ffa36cdc5add14ed, []int{15} } func (m *EstimateGasResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -942,7 +866,7 @@ func (m *QueryTraceTxRequest) Reset() { *m = QueryTraceTxRequest{} } func (m *QueryTraceTxRequest) String() string { return proto.CompactTextString(m) } func (*QueryTraceTxRequest) ProtoMessage() {} func (*QueryTraceTxRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{18} + return fileDescriptor_ffa36cdc5add14ed, []int{16} } func (m *QueryTraceTxRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1044,7 +968,7 @@ func (m *QueryTraceTxResponse) Reset() { *m = QueryTraceTxResponse{} } func (m *QueryTraceTxResponse) String() string { return proto.CompactTextString(m) } func (*QueryTraceTxResponse) ProtoMessage() {} func (*QueryTraceTxResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{19} + return fileDescriptor_ffa36cdc5add14ed, []int{17} } func (m *QueryTraceTxResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1104,7 +1028,7 @@ func (m *QueryTraceBlockRequest) Reset() { *m = QueryTraceBlockRequest{} func (m *QueryTraceBlockRequest) String() string { return proto.CompactTextString(m) } func (*QueryTraceBlockRequest) ProtoMessage() {} func (*QueryTraceBlockRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{20} + return fileDescriptor_ffa36cdc5add14ed, []int{18} } func (m *QueryTraceBlockRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1199,7 +1123,7 @@ func (m *QueryTraceBlockResponse) Reset() { *m = QueryTraceBlockResponse func (m *QueryTraceBlockResponse) String() string { return proto.CompactTextString(m) } func (*QueryTraceBlockResponse) ProtoMessage() {} func (*QueryTraceBlockResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{21} + return fileDescriptor_ffa36cdc5add14ed, []int{19} } func (m *QueryTraceBlockResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1244,7 +1168,7 @@ func (m *QueryBaseFeeRequest) Reset() { *m = QueryBaseFeeRequest{} } func (m *QueryBaseFeeRequest) String() string { return proto.CompactTextString(m) } func (*QueryBaseFeeRequest) ProtoMessage() {} func (*QueryBaseFeeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{22} + return fileDescriptor_ffa36cdc5add14ed, []int{20} } func (m *QueryBaseFeeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1283,7 +1207,7 @@ func (m *QueryBaseFeeResponse) Reset() { *m = QueryBaseFeeResponse{} } func (m *QueryBaseFeeResponse) String() string { return proto.CompactTextString(m) } func (*QueryBaseFeeResponse) ProtoMessage() {} func (*QueryBaseFeeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{23} + return fileDescriptor_ffa36cdc5add14ed, []int{21} } func (m *QueryBaseFeeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1321,7 +1245,7 @@ func (m *QueryFunTokenMappingRequest) Reset() { *m = QueryFunTokenMappin func (m *QueryFunTokenMappingRequest) String() string { return proto.CompactTextString(m) } func (*QueryFunTokenMappingRequest) ProtoMessage() {} func (*QueryFunTokenMappingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{24} + return fileDescriptor_ffa36cdc5add14ed, []int{22} } func (m *QueryFunTokenMappingRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1359,7 +1283,7 @@ func (m *QueryFunTokenMappingResponse) Reset() { *m = QueryFunTokenMappi func (m *QueryFunTokenMappingResponse) String() string { return proto.CompactTextString(m) } func (*QueryFunTokenMappingResponse) ProtoMessage() {} func (*QueryFunTokenMappingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa36cdc5add14ed, []int{25} + return fileDescriptor_ffa36cdc5add14ed, []int{23} } func (m *QueryFunTokenMappingResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1391,8 +1315,6 @@ var xxx_messageInfo_QueryFunTokenMappingResponse proto.InternalMessageInfo func init() { proto.RegisterType((*QueryEthAccountRequest)(nil), "eth.evm.v1.QueryEthAccountRequest") proto.RegisterType((*QueryEthAccountResponse)(nil), "eth.evm.v1.QueryEthAccountResponse") - proto.RegisterType((*QueryNibiruAccountRequest)(nil), "eth.evm.v1.QueryNibiruAccountRequest") - proto.RegisterType((*QueryNibiruAccountResponse)(nil), "eth.evm.v1.QueryNibiruAccountResponse") proto.RegisterType((*QueryValidatorAccountRequest)(nil), "eth.evm.v1.QueryValidatorAccountRequest") proto.RegisterType((*QueryValidatorAccountResponse)(nil), "eth.evm.v1.QueryValidatorAccountResponse") proto.RegisterType((*QueryBalanceRequest)(nil), "eth.evm.v1.QueryBalanceRequest") @@ -1420,106 +1342,104 @@ func init() { func init() { proto.RegisterFile("eth/evm/v1/query.proto", fileDescriptor_ffa36cdc5add14ed) } var fileDescriptor_ffa36cdc5add14ed = []byte{ - // 1572 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0xcf, 0x6f, 0x1b, 0x45, - 0x1b, 0x8e, 0x63, 0x27, 0x76, 0x5e, 0xa7, 0x4d, 0xbe, 0x69, 0xda, 0x24, 0x6e, 0x62, 0x27, 0x9b, - 0xaf, 0x49, 0xda, 0xaf, 0xdd, 0xfd, 0x12, 0x10, 0x88, 0x8a, 0x0a, 0xd5, 0x51, 0x1a, 0x4a, 0x7f, - 0xa8, 0x35, 0x11, 0x48, 0x20, 0x64, 0x8d, 0xd7, 0x93, 0xf5, 0x2a, 0xde, 0x1d, 0x77, 0x67, 0x9c, - 0x3a, 0x94, 0x5c, 0xe8, 0x05, 0x09, 0x21, 0x2a, 0xf1, 0x0f, 0xf4, 0xc4, 0xbf, 0xc0, 0xbf, 0xd0, - 0x63, 0x25, 0x84, 0x84, 0x38, 0x14, 0xd4, 0x72, 0xe0, 0xcc, 0x91, 0x13, 0x9a, 0xd9, 0x99, 0x78, - 0xbd, 0x5e, 0x27, 0x94, 0x1f, 0x37, 0x4e, 0xbb, 0x33, 0xf3, 0xce, 0xfb, 0x3c, 0xf3, 0xeb, 0x7d, - 0x1e, 0x38, 0x43, 0x78, 0xc3, 0x22, 0x7b, 0x9e, 0xb5, 0xb7, 0x66, 0xdd, 0x6b, 0x93, 0x60, 0xdf, - 0x6c, 0x05, 0x94, 0x53, 0x04, 0x84, 0x37, 0x4c, 0xb2, 0xe7, 0x99, 0x7b, 0x6b, 0x85, 0x0b, 0x36, - 0x65, 0x1e, 0x65, 0x56, 0x0d, 0x33, 0x12, 0x06, 0x59, 0x7b, 0x6b, 0x35, 0xc2, 0xf1, 0x9a, 0xd5, - 0xc2, 0x8e, 0xeb, 0x63, 0xee, 0x52, 0x3f, 0x9c, 0x57, 0x98, 0x8a, 0xe4, 0x13, 0xd3, 0xc3, 0xde, - 0x53, 0x91, 0x5e, 0xde, 0xd1, 0xa1, 0x0e, 0x75, 0xa8, 0xfc, 0xb5, 0xc4, 0x9f, 0xea, 0x9d, 0x73, - 0x28, 0x75, 0x9a, 0xc4, 0xc2, 0x2d, 0xd7, 0xc2, 0xbe, 0x4f, 0xb9, 0xcc, 0xce, 0xd4, 0x68, 0x49, - 0x8d, 0xca, 0x56, 0xad, 0xbd, 0x63, 0x71, 0xd7, 0x23, 0x8c, 0x63, 0xaf, 0x15, 0x06, 0x18, 0x6f, - 0xc2, 0x99, 0xbb, 0x82, 0xe1, 0x26, 0x6f, 0x5c, 0xb5, 0x6d, 0xda, 0xf6, 0x79, 0x85, 0xdc, 0x6b, - 0x13, 0xc6, 0xd1, 0x0c, 0x64, 0x71, 0xbd, 0x1e, 0x10, 0xc6, 0x66, 0x52, 0x0b, 0xa9, 0xd5, 0xb1, - 0x8a, 0x6e, 0x5e, 0xce, 0x7d, 0xf6, 0xb8, 0x34, 0xf4, 0xcb, 0xe3, 0xd2, 0x90, 0xe1, 0xc1, 0x74, - 0xdf, 0x6c, 0xd6, 0xa2, 0x3e, 0x23, 0xa8, 0x04, 0xf9, 0x1a, 0x6e, 0x62, 0xdf, 0x26, 0xd5, 0xfb, - 0xc4, 0x55, 0x29, 0x40, 0x75, 0xbd, 0x4f, 0x5c, 0x74, 0x16, 0xc6, 0x6c, 0x5a, 0x27, 0xd5, 0x06, - 0x66, 0x8d, 0x99, 0x61, 0x39, 0x9c, 0x13, 0x1d, 0x6f, 0x63, 0xd6, 0x40, 0x53, 0x30, 0xe2, 0x53, - 0xdf, 0x26, 0x33, 0xe9, 0x85, 0xd4, 0x6a, 0xa6, 0x12, 0x36, 0x8c, 0xb7, 0x60, 0x56, 0xc2, 0xdd, - 0x76, 0x6b, 0x6e, 0xd0, 0xfe, 0x13, 0x7c, 0xf7, 0xa1, 0x90, 0x94, 0x40, 0x51, 0x1e, 0x98, 0x01, - 0x15, 0x20, 0xc7, 0x04, 0x8c, 0x60, 0x34, 0x2c, 0x19, 0x1d, 0xb6, 0xd1, 0x39, 0x38, 0x89, 0xc3, - 0x44, 0x55, 0xbf, 0xed, 0xd5, 0x48, 0xa0, 0x38, 0x9f, 0x50, 0xbd, 0xb7, 0x65, 0xa7, 0x71, 0x03, - 0xe6, 0x24, 0xf4, 0x7b, 0xb8, 0xe9, 0xd6, 0x31, 0xa7, 0x41, 0x8c, 0xfe, 0x22, 0x8c, 0xdb, 0xd4, - 0x67, 0xd5, 0x5e, 0x06, 0x79, 0xd1, 0x77, 0xb5, 0x6f, 0x1d, 0x9f, 0xa7, 0x60, 0x7e, 0x40, 0x36, - 0xb5, 0x96, 0x15, 0x98, 0xd0, 0xac, 0x7a, 0x33, 0x6a, 0xb2, 0x57, 0xff, 0xbe, 0xa5, 0xbd, 0x01, - 0xa7, 0x24, 0x99, 0x72, 0x78, 0xb8, 0x2f, 0x73, 0x20, 0x77, 0x61, 0xaa, 0x77, 0x6a, 0xf7, 0x28, - 0xd4, 0x55, 0xd1, 0x73, 0x55, 0x33, 0x7e, 0xaf, 0x86, 0xe3, 0xf7, 0xca, 0xb8, 0xa1, 0xd8, 0xbc, - 0xcb, 0x69, 0x80, 0x9d, 0xe3, 0xd9, 0xa0, 0x49, 0x48, 0xef, 0x92, 0x7d, 0x95, 0x49, 0xfc, 0x46, - 0xf8, 0x5d, 0x54, 0xfc, 0x0e, 0x93, 0x29, 0x7e, 0x53, 0x30, 0xb2, 0x87, 0x9b, 0x6d, 0xcd, 0x2e, - 0x6c, 0x18, 0xaf, 0xc1, 0xa4, 0x8c, 0xde, 0xa0, 0xf5, 0x97, 0xda, 0x85, 0x15, 0xf8, 0x4f, 0x64, - 0x9e, 0x82, 0x40, 0x90, 0x11, 0xcf, 0x41, 0xce, 0x1a, 0xaf, 0xc8, 0x7f, 0xe3, 0x63, 0x40, 0x32, - 0x70, 0xbb, 0x73, 0x93, 0x3a, 0x4c, 0x43, 0x20, 0xc8, 0xc8, 0x47, 0x14, 0xe6, 0x97, 0xff, 0xe8, - 0x1a, 0x40, 0xb7, 0xd6, 0xc8, 0xb5, 0xe5, 0xd7, 0x97, 0xcd, 0xb0, 0x30, 0x99, 0xa2, 0x30, 0x99, - 0x61, 0xf5, 0x52, 0x85, 0xc9, 0xbc, 0xd3, 0xdd, 0xaa, 0x4a, 0x64, 0x66, 0x84, 0xe4, 0xc3, 0x94, - 0xda, 0x58, 0x0d, 0xae, 0x78, 0x2e, 0x41, 0xa6, 0x49, 0x1d, 0xb1, 0xba, 0xf4, 0x6a, 0x7e, 0x7d, - 0xc2, 0xec, 0x16, 0x42, 0xf3, 0x26, 0x75, 0x2a, 0x72, 0x10, 0x6d, 0x25, 0xd0, 0x59, 0x39, 0x96, - 0x4e, 0x88, 0x10, 0xe5, 0x63, 0x4c, 0xa9, 0x1d, 0xb8, 0x83, 0x03, 0xec, 0xe9, 0x1d, 0x30, 0xb6, - 0x14, 0x35, 0xdd, 0xab, 0xa8, 0xfd, 0x1f, 0x46, 0x5b, 0xb2, 0x47, 0x6e, 0x4d, 0x7e, 0x1d, 0x45, - 0xc9, 0x85, 0xb1, 0xe5, 0xcc, 0x93, 0x67, 0xa5, 0xa1, 0x8a, 0x8a, 0x33, 0xbe, 0x49, 0xc1, 0xc9, - 0x4d, 0xde, 0xd8, 0xc0, 0xcd, 0x66, 0x64, 0x77, 0x71, 0xe0, 0x30, 0x7d, 0x0e, 0xe2, 0x1f, 0x4d, - 0x43, 0xd6, 0xc1, 0xac, 0x6a, 0xe3, 0x96, 0x7a, 0x33, 0xa3, 0x0e, 0x66, 0x1b, 0xb8, 0x85, 0x3e, - 0x82, 0xc9, 0x56, 0x40, 0x5b, 0x94, 0x91, 0xe0, 0xf0, 0xdd, 0x89, 0x37, 0x33, 0x5e, 0x5e, 0xff, - 0xed, 0x59, 0xc9, 0x74, 0x5c, 0xde, 0x68, 0xd7, 0x4c, 0x9b, 0x7a, 0x96, 0xd2, 0x88, 0xf0, 0x73, - 0x89, 0xd5, 0x77, 0x2d, 0xbe, 0xdf, 0x22, 0xcc, 0xdc, 0xe8, 0x3e, 0xf8, 0xca, 0x84, 0xce, 0xa5, - 0x1f, 0xeb, 0x2c, 0xe4, 0xec, 0x06, 0x76, 0xfd, 0xaa, 0x5b, 0x9f, 0xc9, 0x2c, 0xa4, 0x56, 0xd3, - 0x95, 0xac, 0x6c, 0x5f, 0xaf, 0x1b, 0x2b, 0x70, 0x6a, 0x93, 0x71, 0xd7, 0xc3, 0x9c, 0x6c, 0xe1, - 0xee, 0x16, 0x4c, 0x42, 0xda, 0xc1, 0x21, 0xf9, 0x4c, 0x45, 0xfc, 0x1a, 0xbf, 0xa6, 0xf5, 0x39, - 0x06, 0xd8, 0x26, 0xdb, 0x1d, 0xbd, 0xce, 0xff, 0x41, 0xda, 0x63, 0x8e, 0xda, 0xa9, 0xd9, 0xe8, - 0x4e, 0xdd, 0x62, 0xce, 0x26, 0x6f, 0x90, 0x80, 0xb4, 0xbd, 0xed, 0x4e, 0x45, 0x44, 0xa1, 0xcb, - 0x30, 0xce, 0xc5, 0xf4, 0xaa, 0x4d, 0xfd, 0x1d, 0xd7, 0x91, 0x6b, 0xcc, 0xaf, 0x4f, 0x47, 0x67, - 0xc9, 0xf4, 0x1b, 0x72, 0xb8, 0x92, 0xe7, 0xdd, 0x06, 0xba, 0x02, 0xe3, 0xad, 0x80, 0xd4, 0x89, - 0x4d, 0x18, 0xa3, 0x01, 0x9b, 0xc9, 0xc8, 0x8b, 0x73, 0x04, 0x62, 0x4f, 0xb8, 0x28, 0x94, 0xb5, - 0x26, 0xb5, 0x77, 0x75, 0x49, 0x1a, 0x91, 0xfb, 0x90, 0x97, 0x7d, 0x61, 0x41, 0x42, 0xf3, 0x00, - 0x61, 0x88, 0x7c, 0x16, 0xa3, 0xf2, 0x59, 0x8c, 0xc9, 0x1e, 0x29, 0x2e, 0x1b, 0x7a, 0x58, 0x88, - 0xe1, 0x4c, 0x56, 0x52, 0x2f, 0x98, 0xa1, 0x52, 0x9a, 0x5a, 0x29, 0xcd, 0x6d, 0xad, 0x94, 0xe5, - 0x9c, 0xb8, 0x22, 0x8f, 0x7e, 0x2c, 0xa5, 0x54, 0x12, 0x31, 0x92, 0x78, 0xd2, 0xb9, 0x7f, 0xe6, - 0xa4, 0xc7, 0x7a, 0x4e, 0x1a, 0x19, 0x70, 0x22, 0xa4, 0xef, 0xe1, 0x4e, 0x55, 0x1c, 0x2e, 0x44, - 0x76, 0xe0, 0x16, 0xee, 0x6c, 0x61, 0xf6, 0x4e, 0x26, 0x37, 0x3c, 0x99, 0xae, 0xe4, 0x78, 0xa7, - 0xea, 0xfa, 0x75, 0xd2, 0x31, 0x2e, 0xa8, 0x3a, 0x76, 0x78, 0xe6, 0xdd, 0x22, 0x53, 0xc7, 0x1c, - 0xeb, 0xcb, 0x2d, 0xfe, 0x8d, 0xaf, 0xd3, 0xca, 0x13, 0xc8, 0xe0, 0xb2, 0xc8, 0x1a, 0xb9, 0x23, - 0xbc, 0xa3, 0x9f, 0xfa, 0x51, 0x77, 0x84, 0x77, 0xd8, 0x5f, 0xba, 0x23, 0xff, 0x1e, 0xf2, 0xf1, - 0x87, 0x6c, 0x5c, 0x52, 0xee, 0x2b, 0x7a, 0x4e, 0x47, 0x9c, 0xeb, 0xe9, 0x43, 0x99, 0x66, 0xe4, - 0x1a, 0xd1, 0xd5, 0xde, 0xb8, 0x79, 0x28, 0xc1, 0xaa, 0x5b, 0xa5, 0x78, 0x15, 0x72, 0xa2, 0x30, - 0x57, 0x77, 0x88, 0x52, 0xb9, 0xf2, 0xec, 0x0f, 0xcf, 0x4a, 0xa7, 0xc3, 0x15, 0xb2, 0xfa, 0xae, - 0xe9, 0x52, 0xcb, 0xc3, 0xbc, 0x61, 0x5e, 0xf7, 0xb9, 0x90, 0x67, 0x39, 0xdb, 0xb8, 0x02, 0x67, - 0x65, 0xb6, 0x6b, 0x6d, 0x7f, 0x9b, 0xee, 0x12, 0xff, 0x16, 0x6e, 0xb5, 0x5c, 0xdf, 0xd1, 0x17, - 0x68, 0x0a, 0x46, 0xb8, 0xe8, 0xd6, 0xba, 0x29, 0x1b, 0x11, 0x91, 0xf9, 0x50, 0xb9, 0xa4, 0xbe, - 0xe9, 0x8a, 0xd4, 0x1a, 0x8c, 0xed, 0xb4, 0xfd, 0x6a, 0x37, 0x47, 0x7e, 0x7d, 0x2a, 0x7a, 0xa1, - 0xf4, 0xbc, 0x4a, 0x6e, 0x47, 0xfd, 0x75, 0x93, 0xaf, 0x7f, 0x37, 0x0e, 0x23, 0x32, 0x3b, 0x7a, - 0x98, 0x02, 0xe8, 0x7a, 0x56, 0x64, 0x44, 0x53, 0x24, 0xdb, 0xe1, 0xc2, 0xd2, 0x91, 0x31, 0x21, - 0x3d, 0xe3, 0xe2, 0xa7, 0xdf, 0xfe, 0xfc, 0xd5, 0xf0, 0x32, 0xfa, 0xaf, 0xe5, 0x4b, 0x87, 0x79, - 0xe8, 0xec, 0x79, 0xa3, 0xaa, 0x3c, 0x93, 0xf5, 0x40, 0x5d, 0xa4, 0x03, 0xf4, 0x65, 0x0a, 0x4e, - 0xf4, 0x38, 0x51, 0x74, 0xae, 0x0f, 0x24, 0xc9, 0xea, 0x16, 0x96, 0x8f, 0x0b, 0x53, 0x74, 0x2c, - 0x49, 0xe7, 0x3c, 0x5a, 0x89, 0xd1, 0x09, 0x5b, 0x09, 0x8c, 0x1e, 0xa7, 0x60, 0x32, 0x6e, 0x29, - 0xd1, 0x6a, 0x1f, 0xda, 0x00, 0x0f, 0x5b, 0x38, 0xff, 0x07, 0x22, 0x15, 0xb5, 0xd7, 0x25, 0xb5, - 0x35, 0x64, 0xc5, 0xa8, 0xed, 0xe9, 0x09, 0x5d, 0x76, 0x51, 0x5b, 0x7c, 0x80, 0xee, 0x43, 0xb6, - 0xac, 0xad, 0x60, 0x1f, 0x5c, 0xaf, 0x03, 0x2d, 0x2c, 0x0c, 0x0e, 0x50, 0x34, 0xce, 0x4b, 0x1a, - 0x4b, 0x68, 0x31, 0x46, 0x43, 0xf9, 0x49, 0x16, 0xd9, 0x9b, 0x4f, 0x20, 0xab, 0x5c, 0x60, 0x02, - 0x70, 0xaf, 0xd9, 0x4c, 0x00, 0x8e, 0x19, 0x48, 0xc3, 0x94, 0xc0, 0xab, 0x68, 0x39, 0x06, 0xcc, - 0xc2, 0xb8, 0x2e, 0xae, 0xf5, 0x60, 0x97, 0xec, 0x1f, 0xa0, 0x5d, 0xc8, 0x08, 0x77, 0x88, 0xe6, - 0xfa, 0x32, 0x47, 0xcc, 0x66, 0x61, 0x7e, 0xc0, 0xa8, 0x02, 0x5d, 0x96, 0xa0, 0x0b, 0xa8, 0x18, - 0x03, 0x15, 0xde, 0x32, 0xba, 0xd4, 0x06, 0x8c, 0x86, 0xee, 0x08, 0x15, 0xfb, 0x12, 0xf6, 0x18, - 0xaf, 0x42, 0x69, 0xe0, 0xb8, 0x82, 0x9c, 0x97, 0x90, 0xd3, 0xe8, 0x74, 0x0c, 0x32, 0xf4, 0x5b, - 0xc8, 0x85, 0xac, 0xb2, 0x5b, 0xa8, 0x10, 0x4d, 0xd5, 0xeb, 0xc1, 0x0a, 0x8b, 0x83, 0xa5, 0x46, - 0x03, 0x95, 0x24, 0xd0, 0x2c, 0x9a, 0x4e, 0x78, 0x7a, 0xb6, 0xc8, 0x4f, 0x21, 0x1f, 0x31, 0x48, - 0x47, 0xc2, 0xf5, 0xac, 0x2a, 0xc1, 0x55, 0x19, 0x4b, 0x12, 0x6c, 0x1e, 0x9d, 0x8d, 0x83, 0xa9, - 0x58, 0x51, 0xb1, 0x91, 0x07, 0x59, 0x25, 0xb7, 0x09, 0x17, 0xa6, 0xd7, 0x7c, 0x25, 0x5c, 0x98, - 0x98, 0x52, 0x0f, 0x5c, 0x5f, 0x28, 0xb1, 0xbc, 0x83, 0xf6, 0x01, 0xba, 0x42, 0x90, 0x50, 0xd2, - 0xfa, 0xd4, 0x3c, 0xa1, 0xa4, 0xf5, 0x2b, 0x89, 0x61, 0x48, 0xdc, 0x39, 0x54, 0x48, 0xc4, 0x95, - 0x72, 0x24, 0x56, 0xaa, 0xd4, 0x23, 0xf1, 0x4d, 0x46, 0xe5, 0x26, 0xf1, 0x4d, 0xf6, 0x08, 0xcf, - 0xc0, 0x95, 0x6a, 0x35, 0x42, 0x5f, 0xa4, 0x60, 0x22, 0x26, 0x10, 0x68, 0xa5, 0x2f, 0x6d, 0xb2, - 0x02, 0x15, 0x56, 0x8f, 0x0f, 0x54, 0x3c, 0x56, 0x24, 0x8f, 0x45, 0x54, 0x8a, 0xf1, 0xd8, 0x69, - 0xfb, 0x52, 0x7f, 0xac, 0x07, 0xf2, 0x73, 0x50, 0xbe, 0xf2, 0xe4, 0x79, 0x31, 0xf5, 0xf4, 0x79, - 0x31, 0xf5, 0xd3, 0xf3, 0x62, 0xea, 0xd1, 0x8b, 0xe2, 0xd0, 0xd3, 0x17, 0xc5, 0xa1, 0xef, 0x5f, - 0x14, 0x87, 0x3e, 0x58, 0x8a, 0x38, 0x84, 0xb0, 0x44, 0x6f, 0x08, 0x7d, 0xd7, 0x09, 0x3b, 0x22, - 0x65, 0x6d, 0x54, 0xba, 0x91, 0x57, 0x7e, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xdd, 0x5e, 0x28, - 0x5b, 0x12, 0x00, 0x00, + // 1544 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0x8f, 0x63, 0x27, 0x76, 0x9e, 0xd3, 0x26, 0x4c, 0xd3, 0x26, 0x71, 0x13, 0x3b, 0xd9, 0x40, + 0x92, 0x96, 0x76, 0x97, 0xb8, 0x08, 0x44, 0x45, 0x0f, 0x75, 0x94, 0x86, 0xd2, 0x3f, 0x6a, 0x4d, + 0x04, 0x12, 0x08, 0x59, 0x63, 0x7b, 0xb2, 0x5e, 0xc5, 0xde, 0x71, 0x77, 0xc6, 0xa9, 0x43, 0xc9, + 0x85, 0x5e, 0x90, 0x10, 0x52, 0x25, 0xbe, 0x40, 0x4f, 0x7c, 0x05, 0x3e, 0x00, 0x97, 0xde, 0xa8, + 0xc4, 0x05, 0x71, 0x28, 0xa8, 0xe5, 0xc0, 0x99, 0x23, 0x27, 0x34, 0xff, 0xec, 0xb5, 0xbd, 0x4e, + 0xa8, 0x2a, 0x6e, 0x9c, 0x76, 0xf6, 0xcd, 0x9b, 0xdf, 0xfb, 0xcd, 0x9b, 0x99, 0xdf, 0x7b, 0x70, + 0x86, 0xf0, 0x9a, 0x43, 0xf6, 0x1b, 0xce, 0xfe, 0x86, 0x73, 0xaf, 0x45, 0x82, 0x03, 0xbb, 0x19, + 0x50, 0x4e, 0x11, 0x10, 0x5e, 0xb3, 0xc9, 0x7e, 0xc3, 0xde, 0xdf, 0xc8, 0x9c, 0xaf, 0x50, 0xd6, + 0xa0, 0xcc, 0x29, 0x63, 0x46, 0x94, 0x93, 0xb3, 0xbf, 0x51, 0x26, 0x1c, 0x6f, 0x38, 0x4d, 0xec, + 0x7a, 0x3e, 0xe6, 0x1e, 0xf5, 0xd5, 0xba, 0xcc, 0x4c, 0x08, 0x4f, 0x2c, 0x57, 0xd6, 0x53, 0x21, + 0x2b, 0x6f, 0x1b, 0x57, 0x97, 0xba, 0x54, 0x0e, 0x1d, 0x31, 0xd2, 0xd6, 0x05, 0x97, 0x52, 0xb7, + 0x4e, 0x1c, 0xdc, 0xf4, 0x1c, 0xec, 0xfb, 0x94, 0x4b, 0x74, 0xa6, 0x67, 0x73, 0x7a, 0x56, 0xfe, + 0x95, 0x5b, 0xbb, 0x0e, 0xf7, 0x1a, 0x84, 0x71, 0xdc, 0x68, 0x2a, 0x07, 0xeb, 0x7d, 0x38, 0x73, + 0x57, 0x30, 0xdc, 0xe2, 0xb5, 0xab, 0x95, 0x0a, 0x6d, 0xf9, 0xbc, 0x48, 0xee, 0xb5, 0x08, 0xe3, + 0x68, 0x0e, 0x92, 0xb8, 0x5a, 0x0d, 0x08, 0x63, 0x73, 0xb1, 0xa5, 0xd8, 0xfa, 0x44, 0xd1, 0xfc, + 0x5e, 0x4e, 0x7d, 0xfd, 0x38, 0x37, 0xf2, 0xe7, 0xe3, 0xdc, 0x88, 0xf5, 0x53, 0x0c, 0x66, 0x07, + 0x96, 0xb3, 0x26, 0xf5, 0x19, 0x11, 0xeb, 0xcb, 0xb8, 0x8e, 0xfd, 0x0a, 0x31, 0xeb, 0xf5, 0x2f, + 0xca, 0x41, 0x5a, 0x0f, 0x4b, 0xf7, 0x89, 0x37, 0x37, 0x2a, 0x67, 0x41, 0x9b, 0x3e, 0x21, 0x1e, + 0x3a, 0x0b, 0x13, 0x15, 0x5a, 0x25, 0xa5, 0x1a, 0x66, 0xb5, 0xb9, 0xb8, 0x9c, 0x4e, 0x09, 0xc3, + 0x07, 0x98, 0xd5, 0xd0, 0x0c, 0x8c, 0xf9, 0x54, 0xa0, 0x26, 0x96, 0x62, 0xeb, 0x89, 0xa2, 0xfa, + 0x11, 0x98, 0x84, 0xd7, 0x4a, 0x86, 0xf1, 0x98, 0xc2, 0x24, 0xbc, 0x76, 0x55, 0x59, 0xd0, 0x1b, + 0x70, 0xb2, 0x4c, 0x2a, 0xb5, 0x4b, 0xf9, 0x8e, 0xcf, 0xb8, 0xf4, 0x39, 0xa1, 0xac, 0xda, 0xcd, + 0xba, 0x01, 0x0b, 0x72, 0x43, 0x1f, 0xe3, 0xba, 0x57, 0xc5, 0x9c, 0x06, 0x7d, 0x59, 0x59, 0x86, + 0xc9, 0x0a, 0xf5, 0x59, 0xa9, 0x37, 0x35, 0x69, 0x61, 0xbb, 0x3a, 0x90, 0x9e, 0x6f, 0x62, 0xb0, + 0x38, 0x04, 0x4d, 0x27, 0x69, 0x0d, 0xa6, 0xb0, 0x32, 0xf5, 0x21, 0x9e, 0xd4, 0x66, 0x43, 0x3f, + 0x03, 0x29, 0x26, 0x28, 0x88, 0x8d, 0x8f, 0xca, 0x8d, 0x77, 0xfe, 0xc5, 0xd6, 0x0c, 0x88, 0xdf, + 0x6a, 0x94, 0x49, 0x20, 0x73, 0x96, 0x28, 0x9e, 0xd0, 0xd6, 0xdb, 0xd2, 0x68, 0xbd, 0x07, 0xa7, + 0x24, 0x99, 0x82, 0x4a, 0xf4, 0xcb, 0x9c, 0xf3, 0x5d, 0x98, 0xe9, 0x5d, 0xfa, 0xca, 0x67, 0x6c, + 0xdd, 0xd0, 0x6c, 0x3e, 0xe2, 0x34, 0xc0, 0xee, 0xf1, 0x6c, 0xd0, 0x34, 0xc4, 0xf7, 0xc8, 0x81, + 0x46, 0x12, 0xc3, 0x10, 0xbf, 0x0b, 0x9a, 0x5f, 0x07, 0x4c, 0xf3, 0x9b, 0x81, 0xb1, 0x7d, 0x5c, + 0x6f, 0x19, 0x76, 0xea, 0xc7, 0x7a, 0x07, 0xa6, 0xa5, 0xf7, 0x26, 0xad, 0xbe, 0x54, 0x16, 0xd6, + 0xe0, 0xb5, 0xd0, 0x3a, 0x1d, 0x02, 0x41, 0x42, 0x5c, 0x4d, 0xb9, 0x6a, 0xb2, 0x28, 0xc7, 0xd6, + 0x17, 0x80, 0xa4, 0xe3, 0x4e, 0xfb, 0x26, 0x75, 0x99, 0x09, 0x81, 0x20, 0x21, 0x2f, 0xb4, 0xc2, + 0x97, 0x63, 0x74, 0x0d, 0xa0, 0x2b, 0x09, 0x72, 0x6f, 0xe9, 0xfc, 0xaa, 0xad, 0xf4, 0xc3, 0x16, + 0xfa, 0x61, 0x2b, 0x91, 0xd1, 0xfa, 0x61, 0xdf, 0xe9, 0xa6, 0xaa, 0x18, 0x5a, 0x19, 0x22, 0xf9, + 0x30, 0xa6, 0x13, 0x6b, 0x82, 0x6b, 0x9e, 0x2b, 0x90, 0xa8, 0x53, 0x57, 0xec, 0x2e, 0xbe, 0x9e, + 0xce, 0x4f, 0xd9, 0x5d, 0xbd, 0xb2, 0x6f, 0x52, 0xb7, 0x28, 0x27, 0xd1, 0x76, 0x04, 0x9d, 0xb5, + 0x63, 0xe9, 0xa8, 0x08, 0x61, 0x3e, 0xd6, 0x8c, 0xce, 0xc0, 0x1d, 0x1c, 0xe0, 0x86, 0xc9, 0x80, + 0xb5, 0xad, 0xa9, 0x19, 0xab, 0xa6, 0xf6, 0x16, 0x8c, 0x37, 0xa5, 0x45, 0xa6, 0x26, 0x9d, 0x47, + 0x61, 0x72, 0xca, 0xb7, 0x90, 0x78, 0xf2, 0x2c, 0x37, 0x52, 0xd4, 0x7e, 0xd6, 0x0f, 0x31, 0x38, + 0xb9, 0xc5, 0x6b, 0x9b, 0xb8, 0x5e, 0x0f, 0x65, 0x17, 0x07, 0x2e, 0x33, 0xe7, 0x20, 0xc6, 0x68, + 0x16, 0x92, 0x2e, 0x66, 0xa5, 0x0a, 0x6e, 0xea, 0x37, 0x33, 0xee, 0x62, 0xb6, 0x89, 0x9b, 0xe8, + 0x73, 0x98, 0x6e, 0x06, 0xb4, 0x49, 0x19, 0x09, 0x3a, 0xef, 0x4e, 0xbc, 0x99, 0xc9, 0x42, 0xfe, + 0xef, 0x67, 0x39, 0xdb, 0xf5, 0x78, 0xad, 0x55, 0xb6, 0x2b, 0xb4, 0xe1, 0x68, 0x29, 0x57, 0x9f, + 0x8b, 0xac, 0xba, 0xe7, 0xf0, 0x83, 0x26, 0x61, 0xf6, 0x66, 0xf7, 0xc1, 0x17, 0xa7, 0x0c, 0x96, + 0x79, 0xac, 0xf3, 0x90, 0xaa, 0xd4, 0xb0, 0xe7, 0x97, 0xbc, 0xaa, 0x54, 0xa9, 0x78, 0x31, 0x29, + 0xff, 0xaf, 0x57, 0xad, 0x35, 0x38, 0xb5, 0xc5, 0xb8, 0xd7, 0xc0, 0x9c, 0x6c, 0xe3, 0x6e, 0x0a, + 0xa6, 0x21, 0xee, 0x62, 0x45, 0x3e, 0x51, 0x14, 0x43, 0xeb, 0xaf, 0xb8, 0x39, 0xc7, 0x00, 0x57, + 0xc8, 0x4e, 0xdb, 0xec, 0xf3, 0x4d, 0x88, 0x37, 0x98, 0xab, 0x33, 0x35, 0x1f, 0xce, 0xd4, 0x2d, + 0xe6, 0x6e, 0xf1, 0x1a, 0x09, 0x48, 0xab, 0xb1, 0xd3, 0x2e, 0x0a, 0x2f, 0x74, 0x19, 0x26, 0xb9, + 0x58, 0x5e, 0xaa, 0x50, 0x7f, 0xd7, 0x73, 0xe5, 0x1e, 0xd3, 0xf9, 0xd9, 0xf0, 0x2a, 0x09, 0xbf, + 0x29, 0xa7, 0x8b, 0x69, 0xde, 0xfd, 0x41, 0x57, 0x60, 0xb2, 0x19, 0x90, 0x2a, 0xa9, 0x10, 0xc6, + 0x68, 0xc0, 0xe6, 0x12, 0xf2, 0xe2, 0x1c, 0x11, 0xb1, 0xc7, 0x5d, 0x08, 0x65, 0xb9, 0x4e, 0x2b, + 0x7b, 0x46, 0x92, 0xc6, 0x64, 0x1e, 0xd2, 0xd2, 0xa6, 0x04, 0x09, 0x2d, 0x02, 0x28, 0x17, 0xf9, + 0x2c, 0x94, 0x1c, 0x4f, 0x48, 0x8b, 0x14, 0xfa, 0x4d, 0x33, 0x2d, 0x6a, 0xd6, 0x5c, 0x52, 0x52, + 0xcf, 0xd8, 0xaa, 0xa0, 0xd9, 0xa6, 0xa0, 0xd9, 0x3b, 0xa6, 0xa0, 0x15, 0x52, 0xe2, 0x8a, 0x3c, + 0xfa, 0x2d, 0x17, 0xd3, 0x20, 0x62, 0x26, 0xf2, 0xa4, 0x53, 0xff, 0xcd, 0x49, 0x4f, 0xf4, 0x9c, + 0x34, 0xb2, 0xe0, 0x84, 0xa2, 0xdf, 0xc0, 0xed, 0x92, 0x38, 0x5c, 0x08, 0x65, 0xe0, 0x16, 0x6e, + 0x6f, 0x63, 0xf6, 0x61, 0x22, 0x35, 0x3a, 0x1d, 0x2f, 0xa6, 0x78, 0xbb, 0xe4, 0xf9, 0x55, 0xd2, + 0xb6, 0xce, 0x6b, 0x1d, 0xeb, 0x9c, 0x79, 0x57, 0x64, 0xaa, 0x98, 0x63, 0x73, 0xb9, 0xc5, 0xd8, + 0xfa, 0x3e, 0xae, 0x4b, 0xb7, 0x74, 0x2e, 0x08, 0xd4, 0xd0, 0x1d, 0xe1, 0x6d, 0xf3, 0xd4, 0x8f, + 0xba, 0x23, 0xbc, 0xcd, 0x5e, 0xe9, 0x8e, 0xfc, 0x7f, 0xc8, 0xc7, 0x1f, 0xb2, 0x75, 0x51, 0xf7, + 0x48, 0xe1, 0x73, 0x3a, 0xe2, 0x5c, 0x4f, 0x77, 0xca, 0x34, 0x23, 0xd7, 0x88, 0x51, 0x7b, 0xeb, + 0x66, 0xa7, 0x04, 0x6b, 0xb3, 0x86, 0x78, 0x1b, 0x52, 0x42, 0x98, 0x4b, 0xbb, 0x44, 0x57, 0xb9, + 0xc2, 0xfc, 0xaf, 0xcf, 0x72, 0xa7, 0xd5, 0x0e, 0x59, 0x75, 0xcf, 0xf6, 0xa8, 0xd3, 0xc0, 0xbc, + 0x66, 0x5f, 0xf7, 0xb9, 0x28, 0xcf, 0x72, 0xb5, 0x75, 0x05, 0xce, 0x4a, 0xb4, 0x6b, 0x2d, 0x7f, + 0x87, 0xee, 0x11, 0xff, 0x16, 0x6e, 0x36, 0x3d, 0xdf, 0x35, 0x17, 0x68, 0x06, 0xc6, 0xb8, 0x30, + 0x9b, 0xba, 0x29, 0x7f, 0x42, 0x45, 0xe6, 0x33, 0xdd, 0x25, 0x0d, 0x2c, 0xd7, 0xa4, 0x36, 0x60, + 0x62, 0xb7, 0xe5, 0x97, 0xba, 0x18, 0xe9, 0xfc, 0x4c, 0xf8, 0x42, 0x99, 0x75, 0xc5, 0xd4, 0xae, + 0x1e, 0x75, 0xc1, 0xf3, 0x3f, 0xa6, 0x61, 0x4c, 0xa2, 0xa3, 0x87, 0x31, 0x80, 0x6e, 0x67, 0x89, + 0xac, 0x30, 0x44, 0x74, 0xd7, 0x9a, 0x59, 0x39, 0xd2, 0x47, 0xd1, 0xb3, 0x2e, 0x7c, 0xf5, 0xf3, + 0x1f, 0xdf, 0x8d, 0xae, 0xa2, 0xd7, 0x1d, 0xdf, 0x2b, 0x7b, 0x41, 0xab, 0xd3, 0x80, 0x8b, 0x0e, + 0x52, 0xf9, 0x3a, 0x0f, 0xf4, 0x45, 0x3a, 0x44, 0x8f, 0x63, 0x30, 0xdd, 0xdf, 0xc0, 0xa1, 0xf5, + 0x81, 0x38, 0x43, 0x3a, 0xc6, 0xcc, 0xb9, 0x7f, 0xe1, 0xa9, 0x79, 0xbd, 0x2b, 0x79, 0x6d, 0x20, + 0xa7, 0x8f, 0xd7, 0xbe, 0x59, 0xd0, 0x65, 0x17, 0x6e, 0x42, 0x0f, 0xd1, 0x7d, 0x48, 0x16, 0x4c, + 0xe3, 0x35, 0x10, 0xae, 0xb7, 0xdf, 0xcb, 0x2c, 0x0d, 0x77, 0xd0, 0x34, 0xce, 0x49, 0x1a, 0x2b, + 0x68, 0xb9, 0x8f, 0x86, 0xee, 0xde, 0x58, 0x28, 0x37, 0x5f, 0x42, 0x52, 0xf7, 0x5c, 0x11, 0x81, + 0x7b, 0x5b, 0xbb, 0x88, 0xc0, 0x7d, 0xed, 0x9a, 0x65, 0xcb, 0xc0, 0xeb, 0x68, 0xb5, 0x2f, 0x30, + 0x53, 0x7e, 0xdd, 0xb8, 0xce, 0x83, 0x3d, 0x72, 0x70, 0x88, 0xf6, 0x20, 0x21, 0x7a, 0x31, 0xb4, + 0x30, 0x80, 0x1c, 0x6a, 0xed, 0x32, 0x8b, 0x43, 0x66, 0x75, 0xd0, 0x55, 0x19, 0x74, 0x09, 0x65, + 0xfb, 0x82, 0x8a, 0x4e, 0x2e, 0xbc, 0xd5, 0x1a, 0x8c, 0xab, 0x5e, 0x04, 0x65, 0x07, 0x00, 0x7b, + 0xda, 0x9c, 0x4c, 0x6e, 0xe8, 0xbc, 0x0e, 0xb9, 0x28, 0x43, 0xce, 0xa2, 0xd3, 0x7d, 0x21, 0x55, + 0x77, 0x83, 0x3c, 0x48, 0xea, 0xe6, 0x06, 0x65, 0xc2, 0x50, 0xbd, 0x1d, 0x4f, 0x66, 0x79, 0xb8, + 0xb0, 0x9b, 0x40, 0x39, 0x19, 0x68, 0x1e, 0xcd, 0x46, 0x5c, 0xf4, 0x8a, 0xc0, 0xa7, 0x90, 0x0e, + 0xb5, 0x23, 0x47, 0x86, 0xeb, 0xd9, 0x55, 0x44, 0x0f, 0x63, 0xad, 0xc8, 0x60, 0x8b, 0xe8, 0x6c, + 0x7f, 0x30, 0xed, 0x2b, 0xf4, 0x11, 0x35, 0x20, 0xa9, 0x8b, 0x5b, 0xc4, 0x85, 0xe9, 0x6d, 0x75, + 0x22, 0x2e, 0x4c, 0x5f, 0x5d, 0x1c, 0xba, 0x3f, 0x55, 0xd0, 0x78, 0x1b, 0x1d, 0x00, 0x74, 0x65, + 0x37, 0x42, 0x40, 0x06, 0x6a, 0x67, 0x84, 0x80, 0x0c, 0xea, 0xb6, 0x65, 0xc9, 0xb8, 0x0b, 0x28, + 0x13, 0x19, 0x57, 0x8a, 0xbf, 0xd8, 0xa9, 0xd6, 0xea, 0xc8, 0x37, 0x19, 0x16, 0xf7, 0xc8, 0x37, + 0xd9, 0x23, 0xf3, 0x43, 0x77, 0x6a, 0xb4, 0x1f, 0x7d, 0x1b, 0x83, 0xa9, 0x3e, 0x39, 0x46, 0x6b, + 0x03, 0xb0, 0xd1, 0x7a, 0x9f, 0x59, 0x3f, 0xde, 0x51, 0xf3, 0x58, 0x93, 0x3c, 0x96, 0x51, 0xae, + 0x8f, 0xc7, 0x6e, 0xcb, 0x97, 0x6a, 0xef, 0x3c, 0x90, 0x9f, 0xc3, 0xc2, 0x95, 0x27, 0xcf, 0xb3, + 0xb1, 0xa7, 0xcf, 0xb3, 0xb1, 0xdf, 0x9f, 0x67, 0x63, 0x8f, 0x5e, 0x64, 0x47, 0x9e, 0xbe, 0xc8, + 0x8e, 0xfc, 0xf2, 0x22, 0x3b, 0xf2, 0xe9, 0x4a, 0xa8, 0x1e, 0xdf, 0x96, 0x20, 0x9b, 0xa2, 0x9a, + 0x1a, 0xc0, 0xb6, 0x80, 0x2c, 0x8f, 0xcb, 0xda, 0x7f, 0xe9, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x01, 0x8f, 0x68, 0xfa, 0x70, 0x11, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1534,10 +1454,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 { - // EthAccount queries an Ethereum account. + // EthAccount queries a Nibiru account using its EVM address or Bech32 Nibiru + // address. EthAccount(ctx context.Context, in *QueryEthAccountRequest, opts ...grpc.CallOption) (*QueryEthAccountResponse, error) - // NibiruAccount queries the Bech32 Nibiru address corresponding to Nibiru EVM account. - NibiruAccount(ctx context.Context, in *QueryNibiruAccountRequest, opts ...grpc.CallOption) (*QueryNibiruAccountResponse, error) // ValidatorAccount queries an Ethereum account's from a validator consensus // Address. ValidatorAccount(ctx context.Context, in *QueryValidatorAccountRequest, opts ...grpc.CallOption) (*QueryValidatorAccountResponse, error) @@ -1581,15 +1500,6 @@ func (c *queryClient) EthAccount(ctx context.Context, in *QueryEthAccountRequest return out, nil } -func (c *queryClient) NibiruAccount(ctx context.Context, in *QueryNibiruAccountRequest, opts ...grpc.CallOption) (*QueryNibiruAccountResponse, error) { - out := new(QueryNibiruAccountResponse) - err := c.cc.Invoke(ctx, "/eth.evm.v1.Query/NibiruAccount", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *queryClient) ValidatorAccount(ctx context.Context, in *QueryValidatorAccountRequest, opts ...grpc.CallOption) (*QueryValidatorAccountResponse, error) { out := new(QueryValidatorAccountResponse) err := c.cc.Invoke(ctx, "/eth.evm.v1.Query/ValidatorAccount", in, out, opts...) @@ -1691,10 +1601,9 @@ func (c *queryClient) FunTokenMapping(ctx context.Context, in *QueryFunTokenMapp // QueryServer is the server API for Query service. type QueryServer interface { - // EthAccount queries an Ethereum account. + // EthAccount queries a Nibiru account using its EVM address or Bech32 Nibiru + // address. EthAccount(context.Context, *QueryEthAccountRequest) (*QueryEthAccountResponse, error) - // NibiruAccount queries the Bech32 Nibiru address corresponding to Nibiru EVM account. - NibiruAccount(context.Context, *QueryNibiruAccountRequest) (*QueryNibiruAccountResponse, error) // ValidatorAccount queries an Ethereum account's from a validator consensus // Address. ValidatorAccount(context.Context, *QueryValidatorAccountRequest) (*QueryValidatorAccountResponse, error) @@ -1728,9 +1637,6 @@ type UnimplementedQueryServer struct { func (*UnimplementedQueryServer) EthAccount(ctx context.Context, req *QueryEthAccountRequest) (*QueryEthAccountResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method EthAccount not implemented") } -func (*UnimplementedQueryServer) NibiruAccount(ctx context.Context, req *QueryNibiruAccountRequest) (*QueryNibiruAccountResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method NibiruAccount not implemented") -} func (*UnimplementedQueryServer) ValidatorAccount(ctx context.Context, req *QueryValidatorAccountRequest) (*QueryValidatorAccountResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ValidatorAccount not implemented") } @@ -1787,24 +1693,6 @@ func _Query_EthAccount_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } -func _Query_NibiruAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryNibiruAccountRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).NibiruAccount(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/eth.evm.v1.Query/NibiruAccount", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).NibiruAccount(ctx, req.(*QueryNibiruAccountRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _Query_ValidatorAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryValidatorAccountRequest) if err := dec(in); err != nil { @@ -2011,10 +1899,6 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "EthAccount", Handler: _Query_EthAccount_Handler, }, - { - MethodName: "NibiruAccount", - Handler: _Query_NibiruAccount_Handler, - }, { MethodName: "ValidatorAccount", Handler: _Query_ValidatorAccount_Handler, @@ -2114,92 +1998,43 @@ func (m *QueryEthAccountResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l + if len(m.Bech32Address) > 0 { + i -= len(m.Bech32Address) + copy(dAtA[i:], m.Bech32Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Bech32Address))) + i-- + dAtA[i] = 0x32 + } + if len(m.EthAddress) > 0 { + i -= len(m.EthAddress) + copy(dAtA[i:], m.EthAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.EthAddress))) + i-- + dAtA[i] = 0x2a + } if m.Nonce != 0 { i = encodeVarintQuery(dAtA, i, uint64(m.Nonce)) i-- - dAtA[i] = 0x18 + dAtA[i] = 0x20 } if len(m.CodeHash) > 0 { i -= len(m.CodeHash) copy(dAtA[i:], m.CodeHash) i = encodeVarintQuery(dAtA, i, uint64(len(m.CodeHash))) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a } if len(m.BalanceWei) > 0 { i -= len(m.BalanceWei) copy(dAtA[i:], m.BalanceWei) i = encodeVarintQuery(dAtA, i, uint64(len(m.BalanceWei))) i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryNibiruAccountRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryNibiruAccountRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryNibiruAccountRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryNibiruAccountResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryNibiruAccountResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryNibiruAccountResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.AccountNumber != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.AccountNumber)) - i-- - dAtA[i] = 0x18 - } - if m.Sequence != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.Sequence)) - i-- - dAtA[i] = 0x10 + dAtA[i] = 0x12 } - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + if len(m.Balance) > 0 { + i -= len(m.Balance) + copy(dAtA[i:], m.Balance) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Balance))) i-- dAtA[i] = 0xa } @@ -3089,6 +2924,10 @@ func (m *QueryEthAccountResponse) Size() (n int) { } var l int _ = l + l = len(m.Balance) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } l = len(m.BalanceWei) if l > 0 { n += 1 + l + sovQuery(uint64(l)) @@ -3100,38 +2939,14 @@ func (m *QueryEthAccountResponse) Size() (n int) { if m.Nonce != 0 { n += 1 + sovQuery(uint64(m.Nonce)) } - return n -} - -func (m *QueryNibiruAccountRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Address) + l = len(m.EthAddress) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } - return n -} - -func (m *QueryNibiruAccountResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Address) + l = len(m.Bech32Address) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } - if m.Sequence != 0 { - n += 1 + sovQuery(uint64(m.Sequence)) - } - if m.AccountNumber != 0 { - n += 1 + sovQuery(uint64(m.AccountNumber)) - } return n } @@ -3617,7 +3432,7 @@ func (m *QueryEthAccountResponse) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BalanceWei", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Balance", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -3645,11 +3460,11 @@ func (m *QueryEthAccountResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.BalanceWei = string(dAtA[iNdEx:postIndex]) + m.Balance = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CodeHash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field BalanceWei", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -3677,13 +3492,13 @@ func (m *QueryEthAccountResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CodeHash = string(dAtA[iNdEx:postIndex]) + m.BalanceWei = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeHash", wireType) } - m.Nonce = 0 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -3693,64 +3508,46 @@ func (m *QueryEthAccountResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Nonce |= uint64(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery } - if (skippy < 0) || (iNdEx+skippy) < 0 { + postIndex := iNdEx + intStringLen + if postIndex < 0 { return ErrInvalidLengthQuery } - if (iNdEx + skippy) > l { + if postIndex > l { return io.ErrUnexpectedEOF } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryNibiruAccountRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF + m.CodeHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryNibiruAccountRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryNibiruAccountRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field EthAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -3778,61 +3575,11 @@ func (m *QueryNibiruAccountRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Address = string(dAtA[iNdEx:postIndex]) + m.EthAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryNibiruAccountResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryNibiruAccountResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryNibiruAccountResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Bech32Address", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -3860,46 +3607,8 @@ func (m *QueryNibiruAccountResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Address = string(dAtA[iNdEx:postIndex]) + m.Bech32Address = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) - } - m.Sequence = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Sequence |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field AccountNumber", wireType) - } - m.AccountNumber = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.AccountNumber |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/x/evm/query.pb.gw.go b/x/evm/query.pb.gw.go index 6b1461fa7..f34b01e01 100644 --- a/x/evm/query.pb.gw.go +++ b/x/evm/query.pb.gw.go @@ -87,60 +87,6 @@ func local_request_Query_EthAccount_0(ctx context.Context, marshaler runtime.Mar } -func request_Query_NibiruAccount_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryNibiruAccountRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["address"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") - } - - protoReq.Address, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) - } - - msg, err := client.NibiruAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_NibiruAccount_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryNibiruAccountRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["address"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") - } - - protoReq.Address, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) - } - - msg, err := server.NibiruAccount(ctx, &protoReq) - return msg, metadata, err - -} - func request_Query_ValidatorAccount_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryValidatorAccountRequest var metadata runtime.ServerMetadata @@ -642,29 +588,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) - mux.Handle("GET", pattern_Query_NibiruAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_NibiruAccount_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_NibiruAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_Query_ValidatorAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -979,26 +902,6 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("GET", pattern_Query_NibiruAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_NibiruAccount_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_NibiruAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_Query_ValidatorAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1225,8 +1128,6 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie var ( pattern_Query_EthAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"nibiru", "evm", "v1", "eth_account", "address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_NibiruAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"nibiru", "evm", "v1", "nibiru_account", "address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ValidatorAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"nibiru", "evm", "v1", "validator_account", "cons_address"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_Balance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"nibiru", "evm", "v1", "balances", "address"}, "", runtime.AssumeColonVerbOpt(false))) @@ -1253,8 +1154,6 @@ var ( var ( forward_Query_EthAccount_0 = runtime.ForwardResponseMessage - forward_Query_NibiruAccount_0 = runtime.ForwardResponseMessage - forward_Query_ValidatorAccount_0 = runtime.ForwardResponseMessage forward_Query_Balance_0 = runtime.ForwardResponseMessage From 3f83bcf9ab56bd478f2e9101606f344680887f35 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 6 Aug 2024 01:10:02 +0200 Subject: [PATCH 12/21] fix(evmante): check balance in wei, deduct unibi gas --- app/evmante/evmante_verify_eth_acc.go | 3 +- eth/rpc/backend/mocks/evm_query_client.go | 1 - eth/rpc/rpcapi/eth_api_test.go | 82 +++++++++++++++++------ x/evm/keeper/gas_fees.go | 6 +- x/evm/tx_data.go | 1 + 5 files changed, 66 insertions(+), 27 deletions(-) diff --git a/app/evmante/evmante_verify_eth_acc.go b/app/evmante/evmante_verify_eth_acc.go index d40b39058..4c1ae1842 100644 --- a/app/evmante/evmante_verify_eth_acc.go +++ b/app/evmante/evmante_verify_eth_acc.go @@ -3,7 +3,6 @@ package evmante import ( "cosmossdk.io/errors" - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" gethcommon "github.com/ethereum/go-ethereum/common" @@ -70,7 +69,7 @@ func (anteDec AnteDecVerifyEthAcc) AnteHandle( } if err := keeper.CheckSenderBalance( - sdkmath.NewIntFromBigInt(acct.BalanceEvmDenom), txData, + evm.NativeToWei(acct.BalanceEvmDenom), txData, ); err != nil { return ctx, errors.Wrap(err, "failed to check sender balance") } diff --git a/eth/rpc/backend/mocks/evm_query_client.go b/eth/rpc/backend/mocks/evm_query_client.go index 0feeb470c..e7b536508 100644 --- a/eth/rpc/backend/mocks/evm_query_client.go +++ b/eth/rpc/backend/mocks/evm_query_client.go @@ -137,7 +137,6 @@ func (_m *EVMQueryClient) Code(ctx context.Context, in *evm.QueryCodeRequest, op return r0, r1 } - // EstimateGas provides a mock function with given fields: ctx, in, opts func (_m *EVMQueryClient) EstimateGas(ctx context.Context, in *evm.EthCallRequest, opts ...grpc.CallOption) (*evm.EstimateGasResponse, error) { _va := make([]interface{}, len(opts)) diff --git a/eth/rpc/rpcapi/eth_api_test.go b/eth/rpc/rpcapi/eth_api_test.go index da4dab9f1..7e4170216 100644 --- a/eth/rpc/rpcapi/eth_api_test.go +++ b/eth/rpc/rpcapi/eth_api_test.go @@ -3,10 +3,13 @@ package rpcapi_test import ( "context" "crypto/ecdsa" + "fmt" "math/big" + "strings" "testing" sdk "github.com/cosmos/cosmos-sdk/types" + bank "github.com/cosmos/cosmos-sdk/x/bank/types" geth "github.com/ethereum/go-ethereum" gethcommon "github.com/ethereum/go-ethereum/common" gethcore "github.com/ethereum/go-ethereum/core/types" @@ -16,9 +19,10 @@ import ( "github.com/NibiruChain/nibiru/app/appconst" "github.com/NibiruChain/nibiru/eth" + "github.com/NibiruChain/nibiru/gosdk" nibirucommon "github.com/NibiruChain/nibiru/x/common" - "github.com/NibiruChain/nibiru/x/common/denoms" + "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/embeds" "github.com/stretchr/testify/suite" @@ -30,7 +34,10 @@ import ( "github.com/NibiruChain/nibiru/x/common/testutil/testnetwork" ) -var _ suite.TearDownAllSuite = (*TestSuite)(nil) +var ( + _ suite.TearDownAllSuite = (*TestSuite)(nil) + _ suite.SetupAllSuite = (*TestSuite)(nil) +) type TestSuite struct { suite.Suite @@ -50,7 +57,8 @@ func TestSuite_RunAll(t *testing.T) { suite.Run(t, new(TestSuite)) } -// SetupSuite initialize network +// SetupSuite runs before every test in the suite. Implements the +// "suite.SetupAllSuite" interface. func (s *TestSuite) SetupSuite() { testutil.BeforeIntegrationSuite(s.T()) testapp.EnsureNibiruPrefix() @@ -74,8 +82,8 @@ func (s *TestSuite) SetupSuite() { val := s.network.Validators[0] - funds := sdk.NewCoins(sdk.NewInt64Coin(denoms.NIBI, 100_000_000)) // 10 NIBI - s.NoError(testnetwork.FillWalletFromValidator(s.fundedAccNibiAddr, funds, val, denoms.NIBI)) + funds := sdk.NewCoins(sdk.NewInt64Coin(eth.EthBaseDenom, 100_000_000)) // 10 NIBI + s.NoError(testnetwork.FillWalletFromValidator(s.fundedAccNibiAddr, funds, val, eth.EthBaseDenom)) s.NoError(s.network.WaitForNextBlock()) } @@ -172,11 +180,20 @@ func (s *TestSuite) Test_EstimateGas() { From: s.fundedAccEthAddr, To: &testAccEthAddr, Gas: gasLimit, - Value: big.NewInt(1), + Value: evm.NativeToWei(big.NewInt(1)), } gasEstimated, err := s.ethClient.EstimateGas(context.Background(), msg) s.NoError(err) - s.Equal(gasEstimated, gasLimit) + s.Equal(fmt.Sprintf("%d", gasLimit), fmt.Sprintf("%d", gasEstimated)) + + for _, msgValue := range []*big.Int{ + big.NewInt(1), + new(big.Int).Sub(evm.NativeToWei(big.NewInt(1)), big.NewInt(1)), // 10^12 - 1 + } { + msg.Value = msgValue + _, err = s.ethClient.EstimateGas(context.Background(), msg) + s.ErrorContains(err, "StateDB: wei amount is too small") + } } // Test_SuggestGasPrice EVM method: eth_gasPrice @@ -193,44 +210,67 @@ func (s *TestSuite) Test_SimpleTransferTransaction() { nonce, err := s.ethClient.PendingNonceAt(context.Background(), s.fundedAccEthAddr) s.NoError(err) - senderBalanceBefore, err := s.ethClient.BalanceAt( + recipientAddr := gethcommon.BytesToAddress(testnetwork.NewAccount(s.network, "recipient")) + recipientBalanceBefore, err := s.ethClient.BalanceAt(context.Background(), recipientAddr, nil) + s.Require().NoError(err) + s.Equal(int64(0), recipientBalanceBefore.Int64()) + + s.T().Log("make sure the sender has enough funds") + weiToSend := evm.NativeToWei(big.NewInt(1)) // 1 unibi + funds := sdk.NewCoins(sdk.NewInt64Coin(eth.EthBaseDenom, 5_000_000)) // 5 * 10^6 unibi + s.Require().NoError(testnetwork.FillWalletFromValidator( + s.fundedAccNibiAddr, funds, s.network.Validators[0], eth.EthBaseDenom), + ) + s.NoError(s.network.WaitForNextBlock()) + + senderBalanceBeforeWei, err := s.ethClient.BalanceAt( context.Background(), s.fundedAccEthAddr, nil, ) s.NoError(err) - recipientAddr := gethcommon.BytesToAddress(testnetwork.NewAccount(s.network, "recipient")) - recipientBalanceBefore, err := s.ethClient.BalanceAt(context.Background(), recipientAddr, nil) + + grpcUrl := s.network.Validators[0].AppConfig.GRPC.Address + grpcConn, err := gosdk.GetGRPCConnection(grpcUrl, true, 5) s.NoError(err) - s.Equal(int64(0), recipientBalanceBefore.Int64()) - amountToSend := big.NewInt(1000) + querier := bank.NewQueryClient(grpcConn) + resp, err := querier.Balance(context.Background(), &bank.QueryBalanceRequest{ + Address: s.fundedAccNibiAddr.String(), + Denom: eth.EthBaseDenom, + }) + s.Require().NoError(err) + s.Equal("105"+strings.Repeat("0", 6), resp.Balance.Amount.String()) + s.T().Logf("Sending %d wei to %s", weiToSend, recipientAddr.Hex()) signer := gethcore.LatestSignerForChainID(chainID) + gasPrice := big.NewInt(1) tx, err := gethcore.SignNewTx( s.fundedAccPrivateKey, signer, &gethcore.LegacyTx{ Nonce: nonce, To: &recipientAddr, - Value: amountToSend, + Value: weiToSend, Gas: params.TxGas, - GasPrice: big.NewInt(1), + GasPrice: gasPrice, }) s.NoError(err) err = s.ethClient.SendTransaction(context.Background(), tx) - s.NoError(err) + s.Require().NoError(err) s.NoError(s.network.WaitForNextBlock()) - senderAmountAfter, err := s.ethClient.BalanceAt(context.Background(), s.fundedAccEthAddr, nil) + senderAmountAfterWei, err := s.ethClient.BalanceAt(context.Background(), s.fundedAccEthAddr, nil) s.NoError(err) - expectedSenderBalance := senderBalanceBefore.Sub(senderBalanceBefore, amountToSend) - expectedSenderBalance = expectedSenderBalance.Sub(senderBalanceBefore, big.NewInt(int64(params.TxGas))) - - s.Equal(expectedSenderBalance.Int64(), senderAmountAfter.Int64()) + costOfTx := new(big.Int).Add( + weiToSend, + new(big.Int).Mul(evm.NativeToWei(new(big.Int).SetUint64(params.TxGas)), gasPrice), + ) + wantSenderBalWei := new(big.Int).Sub(senderBalanceBeforeWei, costOfTx) + s.Equal(wantSenderBalWei.String(), senderAmountAfterWei.String(), "surpising sender balance") recipientBalanceAfter, err := s.ethClient.BalanceAt(context.Background(), recipientAddr, nil) s.NoError(err) - s.Equal(amountToSend.Int64(), recipientBalanceAfter.Int64()) + s.Equal(weiToSend.String(), recipientBalanceAfter.String()) } // Test_SmartContract includes contract deployment, query, execution diff --git a/x/evm/keeper/gas_fees.go b/x/evm/keeper/gas_fees.go index 6d93e0f5e..2b78b2795 100644 --- a/x/evm/keeper/gas_fees.go +++ b/x/evm/keeper/gas_fees.go @@ -82,7 +82,7 @@ func GasToRefund(availableRefund, gasConsumed, refundQuotient uint64) uint64 { // CheckSenderBalance validates that the tx cost value is positive and that the // sender has enough funds to pay for the fees and value of the transaction. func CheckSenderBalance( - balance sdkmath.Int, + balanceWei *big.Int, txData evm.TxData, ) error { cost := txData.Cost() @@ -94,10 +94,10 @@ func CheckSenderBalance( ) } - if balance.IsNegative() || balance.BigInt().Cmp(cost) < 0 { + if balanceWei.Cmp(big.NewInt(0)) < 0 || balanceWei.Cmp(cost) < 0 { return errors.Wrapf( errortypes.ErrInsufficientFunds, - "sender balance < tx cost (%s < %s)", balance, txData.Cost(), + "sender balance < tx cost (%s < %s)", balanceWei, cost, ) } return nil diff --git a/x/evm/tx_data.go b/x/evm/tx_data.go index 24dde1e19..375eaf63d 100644 --- a/x/evm/tx_data.go +++ b/x/evm/tx_data.go @@ -40,6 +40,7 @@ type TxData interface { // static fee Fee() *big.Int + // Cost is the gas cost of the transaction in wei Cost() *big.Int // effective gasPrice/fee/cost according to current base fee From 811d6b556d2cdb7cf48807fb9b0497e753ebf51e Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Mon, 5 Aug 2024 19:20:20 -0500 Subject: [PATCH 13/21] fix(e2e): JavaScript BigInt is a joke --- e2e/evm/test/basic_queries.test.ts | 10 +++++----- e2e/evm/test/contract_send_nibi.test.ts | 19 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/e2e/evm/test/basic_queries.test.ts b/e2e/evm/test/basic_queries.test.ts index fe17340c0..1b3d7db66 100644 --- a/e2e/evm/test/basic_queries.test.ts +++ b/e2e/evm/test/basic_queries.test.ts @@ -1,11 +1,11 @@ -import { describe, expect, it } from "bun:test"; // eslint-disable-line import/no-unresolved -import { toBigInt, Wallet } from "ethers"; -import { account, provider } from "./setup"; +import { describe, expect, it } from "bun:test" // eslint-disable-line import/no-unresolved +import { toBigInt, Wallet } from "ethers" +import { account, provider } from "./setup" describe("Basic Queries", () => { it("Simple transfer, balance check", async () => { const alice = Wallet.createRandom() - const amountToSend = toBigInt(1e3) // unibi + const amountToSend = toBigInt(5e12) * toBigInt(1e6) // unibi const senderBalanceBefore = await provider.getBalance(account) const recipientBalanceBefore = await provider.getBalance(alice) @@ -19,7 +19,7 @@ describe("Basic Queries", () => { value: amountToSend, } const txResponse = await account.sendTransaction(transaction) - await txResponse.wait() + await txResponse.wait(1, 10e3) expect(txResponse).toHaveProperty("blockHash") const senderBalanceAfter = await provider.getBalance(account) diff --git a/e2e/evm/test/contract_send_nibi.test.ts b/e2e/evm/test/contract_send_nibi.test.ts index 02f7dc9b2..526b6c8b6 100644 --- a/e2e/evm/test/contract_send_nibi.test.ts +++ b/e2e/evm/test/contract_send_nibi.test.ts @@ -1,17 +1,17 @@ -import { describe, expect, it } from "bun:test"; // eslint-disable-line import/no-unresolved -import { ethers, toBigInt } from "ethers"; -import { SendNibiCompiled__factory } from "../types/ethers-contracts"; -import { account, provider } from "./setup"; +import { describe, expect, it } from "bun:test" // eslint-disable-line import/no-unresolved +import { ethers, toBigInt } from "ethers" +import { SendNibiCompiled__factory } from "../types/ethers-contracts" +import { account, provider } from "./setup" describe("Send NIBI via smart contract", async () => { - const factory = new SendNibiCompiled__factory(account); - const contract = await factory.deploy(); + const factory = new SendNibiCompiled__factory(account) + const contract = await factory.deploy() await contract.waitForDeployment() expect(contract.getAddress()).resolves.toBeDefined() it("should send via transfer method", async () => { const recipient = ethers.Wallet.createRandom() - const transferValue = toBigInt(100e6) // NIBI + const transferValue = toBigInt(5e12) * toBigInt(6) // 5 micro NIBI const ownerBalanceBefore = await provider.getBalance(account) // NIBI const recipientBalanceBefore = await provider.getBalance(recipient) // NIBI @@ -30,7 +30,7 @@ describe("Send NIBI via smart contract", async () => { it("should send via send method", async () => { const recipient = ethers.Wallet.createRandom() - const transferValue = toBigInt(100e6) // NIBI + const transferValue = toBigInt(100e12) * toBigInt(6) // 100 NIBi const ownerBalanceBefore = await provider.getBalance(account) // NIBI const recipientBalanceBefore = await provider.getBalance(recipient) // NIBI @@ -49,7 +49,7 @@ describe("Send NIBI via smart contract", async () => { it("should send via transfer method", async () => { const recipient = ethers.Wallet.createRandom() - const transferValue = toBigInt(100e6) // NIBI + const transferValue = toBigInt(100e12) * toBigInt(6) // 100 NIBI const ownerBalanceBefore = await provider.getBalance(account) // NIBI const recipientBalanceBefore = await provider.getBalance(recipient) // NIBI @@ -65,5 +65,4 @@ describe("Send NIBI via smart contract", async () => { ) expect(provider.getBalance(recipient)).resolves.toBe(transferValue) }, 20e3) - }) From ec8216f077aebca30859816377578fa2fc9bf76d Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 6 Aug 2024 11:56:49 +0200 Subject: [PATCH 14/21] fix(e2e): avoid BigInt overflow with 10^18 values --- e2e/evm/test/basic_queries.test.ts | 10 +++++----- e2e/evm/test/contract_send_nibi.test.ts | 19 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/e2e/evm/test/basic_queries.test.ts b/e2e/evm/test/basic_queries.test.ts index fe17340c0..1b3d7db66 100644 --- a/e2e/evm/test/basic_queries.test.ts +++ b/e2e/evm/test/basic_queries.test.ts @@ -1,11 +1,11 @@ -import { describe, expect, it } from "bun:test"; // eslint-disable-line import/no-unresolved -import { toBigInt, Wallet } from "ethers"; -import { account, provider } from "./setup"; +import { describe, expect, it } from "bun:test" // eslint-disable-line import/no-unresolved +import { toBigInt, Wallet } from "ethers" +import { account, provider } from "./setup" describe("Basic Queries", () => { it("Simple transfer, balance check", async () => { const alice = Wallet.createRandom() - const amountToSend = toBigInt(1e3) // unibi + const amountToSend = toBigInt(5e12) * toBigInt(1e6) // unibi const senderBalanceBefore = await provider.getBalance(account) const recipientBalanceBefore = await provider.getBalance(alice) @@ -19,7 +19,7 @@ describe("Basic Queries", () => { value: amountToSend, } const txResponse = await account.sendTransaction(transaction) - await txResponse.wait() + await txResponse.wait(1, 10e3) expect(txResponse).toHaveProperty("blockHash") const senderBalanceAfter = await provider.getBalance(account) diff --git a/e2e/evm/test/contract_send_nibi.test.ts b/e2e/evm/test/contract_send_nibi.test.ts index 02f7dc9b2..526b6c8b6 100644 --- a/e2e/evm/test/contract_send_nibi.test.ts +++ b/e2e/evm/test/contract_send_nibi.test.ts @@ -1,17 +1,17 @@ -import { describe, expect, it } from "bun:test"; // eslint-disable-line import/no-unresolved -import { ethers, toBigInt } from "ethers"; -import { SendNibiCompiled__factory } from "../types/ethers-contracts"; -import { account, provider } from "./setup"; +import { describe, expect, it } from "bun:test" // eslint-disable-line import/no-unresolved +import { ethers, toBigInt } from "ethers" +import { SendNibiCompiled__factory } from "../types/ethers-contracts" +import { account, provider } from "./setup" describe("Send NIBI via smart contract", async () => { - const factory = new SendNibiCompiled__factory(account); - const contract = await factory.deploy(); + const factory = new SendNibiCompiled__factory(account) + const contract = await factory.deploy() await contract.waitForDeployment() expect(contract.getAddress()).resolves.toBeDefined() it("should send via transfer method", async () => { const recipient = ethers.Wallet.createRandom() - const transferValue = toBigInt(100e6) // NIBI + const transferValue = toBigInt(5e12) * toBigInt(6) // 5 micro NIBI const ownerBalanceBefore = await provider.getBalance(account) // NIBI const recipientBalanceBefore = await provider.getBalance(recipient) // NIBI @@ -30,7 +30,7 @@ describe("Send NIBI via smart contract", async () => { it("should send via send method", async () => { const recipient = ethers.Wallet.createRandom() - const transferValue = toBigInt(100e6) // NIBI + const transferValue = toBigInt(100e12) * toBigInt(6) // 100 NIBi const ownerBalanceBefore = await provider.getBalance(account) // NIBI const recipientBalanceBefore = await provider.getBalance(recipient) // NIBI @@ -49,7 +49,7 @@ describe("Send NIBI via smart contract", async () => { it("should send via transfer method", async () => { const recipient = ethers.Wallet.createRandom() - const transferValue = toBigInt(100e6) // NIBI + const transferValue = toBigInt(100e12) * toBigInt(6) // 100 NIBI const ownerBalanceBefore = await provider.getBalance(account) // NIBI const recipientBalanceBefore = await provider.getBalance(recipient) // NIBI @@ -65,5 +65,4 @@ describe("Send NIBI via smart contract", async () => { ) expect(provider.getBalance(recipient)).resolves.toBe(transferValue) }, 20e3) - }) From d14ccf3c60192c2a0e11a7cd4dac89a190103016 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 6 Aug 2024 12:00:47 +0200 Subject: [PATCH 15/21] pull /eth from ud/account-query --- eth/eth_account.go | 31 +++++--- eth/eth_account_test.go | 40 +++++++++++ eth/rpc/backend/mocks/evm_query_client.go | 30 -------- eth/rpc/rpcapi/eth_api_test.go | 86 +++++++++++++++++------ eth/safe_math_test.go | 12 ++-- eth/state_encoder_test.go | 9 --- 6 files changed, 129 insertions(+), 79 deletions(-) create mode 100644 eth/eth_account_test.go diff --git a/eth/eth_account.go b/eth/eth_account.go index 781f09f06..85a857b5a 100644 --- a/eth/eth_account.go +++ b/eth/eth_account.go @@ -7,10 +7,19 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/ethereum/go-ethereum/common" + sdk "github.com/cosmos/cosmos-sdk/types" + gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) +func EthAddrToNibiruAddr(ethAddr gethcommon.Address) sdk.AccAddress { + return ethAddr.Bytes() +} + +func NibiruAddrToEthAddr(nibiruAddr sdk.AccAddress) gethcommon.Address { + return gethcommon.BytesToAddress(nibiruAddr.Bytes()) +} + var ( _ authtypes.AccountI = (*EthAccount)(nil) _ EthAccountI = (*EthAccount)(nil) @@ -32,11 +41,11 @@ const ( type EthAccountI interface { //revive:disable-line:exported authtypes.AccountI // EthAddress returns the ethereum Address representation of the AccAddress - EthAddress() common.Address + EthAddress() gethcommon.Address // CodeHash is the keccak256 hash of the contract code (if any) - GetCodeHash() common.Hash + GetCodeHash() gethcommon.Hash // SetCodeHash sets the code hash to the account fields - SetCodeHash(code common.Hash) error + SetCodeHash(code gethcommon.Hash) error // Type returns the type of Ethereum Account (EOA or Contract) Type() EthAccType } @@ -46,15 +55,15 @@ func (acc EthAccount) GetBaseAccount() *authtypes.BaseAccount { } // EthAddress returns the account address ethereum format. -func (acc EthAccount) EthAddress() common.Address { - return common.BytesToAddress(acc.GetAddress().Bytes()) +func (acc EthAccount) EthAddress() gethcommon.Address { + return gethcommon.BytesToAddress(acc.GetAddress().Bytes()) } -func (acc EthAccount) GetCodeHash() common.Hash { - return common.HexToHash(acc.CodeHash) +func (acc EthAccount) GetCodeHash() gethcommon.Hash { + return gethcommon.HexToHash(acc.CodeHash) } -func (acc *EthAccount) SetCodeHash(codeHash common.Hash) error { +func (acc *EthAccount) SetCodeHash(codeHash gethcommon.Hash) error { acc.CodeHash = codeHash.Hex() return nil } @@ -62,7 +71,7 @@ func (acc *EthAccount) SetCodeHash(codeHash common.Hash) error { // Type returns the type of Ethereum Account (EOA or Contract) func (acc EthAccount) Type() EthAccType { if bytes.Equal( - emptyCodeHash, common.HexToHash(acc.CodeHash).Bytes(), + emptyCodeHash, gethcommon.HexToHash(acc.CodeHash).Bytes(), ) { return EthAccType_EOA } @@ -79,6 +88,6 @@ var emptyCodeHash = crypto.Keccak256(nil) func ProtoBaseAccount() authtypes.AccountI { return &EthAccount{ BaseAccount: &authtypes.BaseAccount{}, - CodeHash: common.BytesToHash(emptyCodeHash).String(), + CodeHash: gethcommon.BytesToHash(emptyCodeHash).String(), } } diff --git a/eth/eth_account_test.go b/eth/eth_account_test.go new file mode 100644 index 000000000..3777f086d --- /dev/null +++ b/eth/eth_account_test.go @@ -0,0 +1,40 @@ +package eth_test + +import ( + "github.com/NibiruChain/nibiru/eth" + "github.com/NibiruChain/nibiru/x/evm/evmtest" +) + +func (s *Suite) TestEthAddrToNibiruAddr() { + accInfo := evmtest.NewEthAccInfo() + s.Equal( + accInfo.EthAddr, + eth.NibiruAddrToEthAddr(accInfo.NibiruAddr), + ) + s.Equal( + accInfo.NibiruAddr, + eth.EthAddrToNibiruAddr(accInfo.EthAddr), + ) + + s.T().Log("unit operation - hex -> nibi -> hex") + { + addr := evmtest.NewEthAccInfo().NibiruAddr + s.Equal( + addr, + eth.EthAddrToNibiruAddr( + eth.NibiruAddrToEthAddr(addr), + ), + ) + } + + s.T().Log("unit operation - nibi -> hex -> nibi") + { + addr := evmtest.NewEthAccInfo().EthAddr + s.Equal( + addr, + eth.NibiruAddrToEthAddr( + eth.EthAddrToNibiruAddr(addr), + ), + ) + } +} diff --git a/eth/rpc/backend/mocks/evm_query_client.go b/eth/rpc/backend/mocks/evm_query_client.go index 252ee8b0f..e7b536508 100644 --- a/eth/rpc/backend/mocks/evm_query_client.go +++ b/eth/rpc/backend/mocks/evm_query_client.go @@ -137,36 +137,6 @@ func (_m *EVMQueryClient) Code(ctx context.Context, in *evm.QueryCodeRequest, op return r0, r1 } -// NibiruAccount provides a mock function with given fields: ctx, in, opts -func (_m *EVMQueryClient) NibiruAccount(ctx context.Context, in *evm.QueryNibiruAccountRequest, opts ...grpc.CallOption) (*evm.QueryNibiruAccountResponse, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, in) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 *evm.QueryNibiruAccountResponse - if rf, ok := ret.Get(0).(func(context.Context, *evm.QueryNibiruAccountRequest, ...grpc.CallOption) *evm.QueryNibiruAccountResponse); ok { - r0 = rf(ctx, in, opts...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*evm.QueryNibiruAccountResponse) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, *evm.QueryNibiruAccountRequest, ...grpc.CallOption) error); ok { - r1 = rf(ctx, in, opts...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // EstimateGas provides a mock function with given fields: ctx, in, opts func (_m *EVMQueryClient) EstimateGas(ctx context.Context, in *evm.EthCallRequest, opts ...grpc.CallOption) (*evm.EstimateGasResponse, error) { _va := make([]interface{}, len(opts)) diff --git a/eth/rpc/rpcapi/eth_api_test.go b/eth/rpc/rpcapi/eth_api_test.go index 89398a373..7e4170216 100644 --- a/eth/rpc/rpcapi/eth_api_test.go +++ b/eth/rpc/rpcapi/eth_api_test.go @@ -3,10 +3,13 @@ package rpcapi_test import ( "context" "crypto/ecdsa" + "fmt" "math/big" + "strings" "testing" sdk "github.com/cosmos/cosmos-sdk/types" + bank "github.com/cosmos/cosmos-sdk/x/bank/types" geth "github.com/ethereum/go-ethereum" gethcommon "github.com/ethereum/go-ethereum/common" gethcore "github.com/ethereum/go-ethereum/core/types" @@ -15,11 +18,12 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/NibiruChain/nibiru/app/appconst" + "github.com/NibiruChain/nibiru/eth" + "github.com/NibiruChain/nibiru/gosdk" nibirucommon "github.com/NibiruChain/nibiru/x/common" - "github.com/NibiruChain/nibiru/x/common/denoms" + "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/embeds" - "github.com/NibiruChain/nibiru/x/evm/evmtest" "github.com/stretchr/testify/suite" @@ -30,7 +34,10 @@ import ( "github.com/NibiruChain/nibiru/x/common/testutil/testnetwork" ) -var _ suite.TearDownAllSuite = (*TestSuite)(nil) +var ( + _ suite.TearDownAllSuite = (*TestSuite)(nil) + _ suite.SetupAllSuite = (*TestSuite)(nil) +) type TestSuite struct { suite.Suite @@ -50,7 +57,8 @@ func TestSuite_RunAll(t *testing.T) { suite.Run(t, new(TestSuite)) } -// SetupSuite initialize network +// SetupSuite runs before every test in the suite. Implements the +// "suite.SetupAllSuite" interface. func (s *TestSuite) SetupSuite() { testutil.BeforeIntegrationSuite(s.T()) testapp.EnsureNibiruPrefix() @@ -70,12 +78,12 @@ func (s *TestSuite) SetupSuite() { testAccPrivateKey, _ := crypto.GenerateKey() s.fundedAccPrivateKey = testAccPrivateKey s.fundedAccEthAddr = crypto.PubkeyToAddress(testAccPrivateKey.PublicKey) - s.fundedAccNibiAddr = evmtest.EthAddrToNibiruAddr(s.fundedAccEthAddr) + s.fundedAccNibiAddr = eth.EthAddrToNibiruAddr(s.fundedAccEthAddr) val := s.network.Validators[0] - funds := sdk.NewCoins(sdk.NewInt64Coin(denoms.NIBI, 100_000_000)) // 10 NIBI - s.NoError(testnetwork.FillWalletFromValidator(s.fundedAccNibiAddr, funds, val, denoms.NIBI)) + funds := sdk.NewCoins(sdk.NewInt64Coin(eth.EthBaseDenom, 100_000_000)) // 10 NIBI + s.NoError(testnetwork.FillWalletFromValidator(s.fundedAccNibiAddr, funds, val, eth.EthBaseDenom)) s.NoError(s.network.WaitForNextBlock()) } @@ -172,11 +180,20 @@ func (s *TestSuite) Test_EstimateGas() { From: s.fundedAccEthAddr, To: &testAccEthAddr, Gas: gasLimit, - Value: big.NewInt(1), + Value: evm.NativeToWei(big.NewInt(1)), } gasEstimated, err := s.ethClient.EstimateGas(context.Background(), msg) s.NoError(err) - s.Equal(gasEstimated, gasLimit) + s.Equal(fmt.Sprintf("%d", gasLimit), fmt.Sprintf("%d", gasEstimated)) + + for _, msgValue := range []*big.Int{ + big.NewInt(1), + new(big.Int).Sub(evm.NativeToWei(big.NewInt(1)), big.NewInt(1)), // 10^12 - 1 + } { + msg.Value = msgValue + _, err = s.ethClient.EstimateGas(context.Background(), msg) + s.ErrorContains(err, "StateDB: wei amount is too small") + } } // Test_SuggestGasPrice EVM method: eth_gasPrice @@ -193,44 +210,67 @@ func (s *TestSuite) Test_SimpleTransferTransaction() { nonce, err := s.ethClient.PendingNonceAt(context.Background(), s.fundedAccEthAddr) s.NoError(err) - senderBalanceBefore, err := s.ethClient.BalanceAt( + recipientAddr := gethcommon.BytesToAddress(testnetwork.NewAccount(s.network, "recipient")) + recipientBalanceBefore, err := s.ethClient.BalanceAt(context.Background(), recipientAddr, nil) + s.Require().NoError(err) + s.Equal(int64(0), recipientBalanceBefore.Int64()) + + s.T().Log("make sure the sender has enough funds") + weiToSend := evm.NativeToWei(big.NewInt(1)) // 1 unibi + funds := sdk.NewCoins(sdk.NewInt64Coin(eth.EthBaseDenom, 5_000_000)) // 5 * 10^6 unibi + s.Require().NoError(testnetwork.FillWalletFromValidator( + s.fundedAccNibiAddr, funds, s.network.Validators[0], eth.EthBaseDenom), + ) + s.NoError(s.network.WaitForNextBlock()) + + senderBalanceBeforeWei, err := s.ethClient.BalanceAt( context.Background(), s.fundedAccEthAddr, nil, ) s.NoError(err) - recipientAddr := gethcommon.BytesToAddress(testnetwork.NewAccount(s.network, "recipient")) - recipientBalanceBefore, err := s.ethClient.BalanceAt(context.Background(), recipientAddr, nil) + + grpcUrl := s.network.Validators[0].AppConfig.GRPC.Address + grpcConn, err := gosdk.GetGRPCConnection(grpcUrl, true, 5) s.NoError(err) - s.Equal(int64(0), recipientBalanceBefore.Int64()) - amountToSend := big.NewInt(1000) + querier := bank.NewQueryClient(grpcConn) + resp, err := querier.Balance(context.Background(), &bank.QueryBalanceRequest{ + Address: s.fundedAccNibiAddr.String(), + Denom: eth.EthBaseDenom, + }) + s.Require().NoError(err) + s.Equal("105"+strings.Repeat("0", 6), resp.Balance.Amount.String()) + s.T().Logf("Sending %d wei to %s", weiToSend, recipientAddr.Hex()) signer := gethcore.LatestSignerForChainID(chainID) + gasPrice := big.NewInt(1) tx, err := gethcore.SignNewTx( s.fundedAccPrivateKey, signer, &gethcore.LegacyTx{ Nonce: nonce, To: &recipientAddr, - Value: amountToSend, + Value: weiToSend, Gas: params.TxGas, - GasPrice: big.NewInt(1), + GasPrice: gasPrice, }) s.NoError(err) err = s.ethClient.SendTransaction(context.Background(), tx) - s.NoError(err) + s.Require().NoError(err) s.NoError(s.network.WaitForNextBlock()) - senderAmountAfter, err := s.ethClient.BalanceAt(context.Background(), s.fundedAccEthAddr, nil) + senderAmountAfterWei, err := s.ethClient.BalanceAt(context.Background(), s.fundedAccEthAddr, nil) s.NoError(err) - expectedSenderBalance := senderBalanceBefore.Sub(senderBalanceBefore, amountToSend) - expectedSenderBalance = expectedSenderBalance.Sub(senderBalanceBefore, big.NewInt(int64(params.TxGas))) - - s.Equal(expectedSenderBalance.Int64(), senderAmountAfter.Int64()) + costOfTx := new(big.Int).Add( + weiToSend, + new(big.Int).Mul(evm.NativeToWei(new(big.Int).SetUint64(params.TxGas)), gasPrice), + ) + wantSenderBalWei := new(big.Int).Sub(senderBalanceBeforeWei, costOfTx) + s.Equal(wantSenderBalWei.String(), senderAmountAfterWei.String(), "surpising sender balance") recipientBalanceAfter, err := s.ethClient.BalanceAt(context.Background(), recipientAddr, nil) s.NoError(err) - s.Equal(amountToSend.Int64(), recipientBalanceAfter.Int64()) + s.Equal(weiToSend.String(), recipientBalanceAfter.String()) } // Test_SmartContract includes contract deployment, query, execution diff --git a/eth/safe_math_test.go b/eth/safe_math_test.go index a956251cf..655622ded 100644 --- a/eth/safe_math_test.go +++ b/eth/safe_math_test.go @@ -13,15 +13,15 @@ import ( const maxInt64 = 9223372036854775807 -type SuiteSafeMath struct { +type Suite struct { suite.Suite } -func TestTypesSuite(t *testing.T) { - suite.Run(t, new(SuiteSafeMath)) +func TestSuite_RunAll(t *testing.T) { + suite.Run(t, new(Suite)) } -func (s *SuiteSafeMath) TestSafeNewIntFromBigInt() { +func (s *Suite) TestSafeNewIntFromBigInt() { tests := []struct { name string input *big.Int @@ -57,7 +57,7 @@ func (s *SuiteSafeMath) TestSafeNewIntFromBigInt() { } } -func (s *SuiteSafeMath) TestIsValidInt256() { +func (s *Suite) TestIsValidInt256() { tests := []struct { name string input *big.Int @@ -88,7 +88,7 @@ func (s *SuiteSafeMath) TestIsValidInt256() { } } -func (s *SuiteSafeMath) TestSafeInt64() { +func (s *Suite) TestSafeInt64() { tests := []struct { name string input uint64 diff --git a/eth/state_encoder_test.go b/eth/state_encoder_test.go index 03eff2ac6..be1bf36e4 100644 --- a/eth/state_encoder_test.go +++ b/eth/state_encoder_test.go @@ -6,7 +6,6 @@ import ( "github.com/NibiruChain/collections" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" "github.com/NibiruChain/nibiru/eth" ) @@ -34,14 +33,6 @@ func assertBijectiveValue[T any](t *testing.T, encoder collections.ValueEncoder[ require.NotEmpty(t, encoder.Name()) } -type Suite struct { - suite.Suite -} - -func TestSuite_RunAll(t *testing.T) { - suite.Run(t, new(Suite)) -} - func (s *Suite) TestEncoderBytes() { testCases := []struct { name string From a90ef2f7ddfcb08bff41b5b9b925e50cda4d2a34 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 6 Aug 2024 12:09:36 +0200 Subject: [PATCH 16/21] fix(evmante): CheckSenderBalance needs to use wei --- app/evmante/evmante_verify_eth_acc.go | 3 +-- x/evm/evmtest/eth.go | 2 +- x/evm/keeper/gas_fees.go | 6 +++--- x/evm/keeper/statedb_test.go | 3 ++- x/evm/tx_data.go | 1 + 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/evmante/evmante_verify_eth_acc.go b/app/evmante/evmante_verify_eth_acc.go index d40b39058..4c1ae1842 100644 --- a/app/evmante/evmante_verify_eth_acc.go +++ b/app/evmante/evmante_verify_eth_acc.go @@ -3,7 +3,6 @@ package evmante import ( "cosmossdk.io/errors" - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" gethcommon "github.com/ethereum/go-ethereum/common" @@ -70,7 +69,7 @@ func (anteDec AnteDecVerifyEthAcc) AnteHandle( } if err := keeper.CheckSenderBalance( - sdkmath.NewIntFromBigInt(acct.BalanceEvmDenom), txData, + evm.NativeToWei(acct.BalanceEvmDenom), txData, ); err != nil { return ctx, errors.Wrap(err, "failed to check sender balance") } diff --git a/x/evm/evmtest/eth.go b/x/evm/evmtest/eth.go index e9f9717c5..6a069b429 100644 --- a/x/evm/evmtest/eth.go +++ b/x/evm/evmtest/eth.go @@ -32,7 +32,7 @@ func NewEthAccInfo() EthPrivKeyAcc { ethAddr := crypto.PubkeyToAddress(privKeyE.PublicKey) return EthPrivKeyAcc{ EthAddr: ethAddr, - NibiruAddr: EthAddrToNibiruAddr(ethAddr), + NibiruAddr: eth.EthAddrToNibiruAddr(ethAddr), PrivKey: privkey, PrivKeyE: privKeyE, KeyringSigner: NewSigner(privkey), diff --git a/x/evm/keeper/gas_fees.go b/x/evm/keeper/gas_fees.go index 6d93e0f5e..b4d723b42 100644 --- a/x/evm/keeper/gas_fees.go +++ b/x/evm/keeper/gas_fees.go @@ -82,7 +82,7 @@ func GasToRefund(availableRefund, gasConsumed, refundQuotient uint64) uint64 { // CheckSenderBalance validates that the tx cost value is positive and that the // sender has enough funds to pay for the fees and value of the transaction. func CheckSenderBalance( - balance sdkmath.Int, + balanceWei *big.Int, txData evm.TxData, ) error { cost := txData.Cost() @@ -94,10 +94,10 @@ func CheckSenderBalance( ) } - if balance.IsNegative() || balance.BigInt().Cmp(cost) < 0 { + if balanceWei.Cmp(big.NewInt(0)) < 0 || balanceWei.Cmp(cost) < 0 { return errors.Wrapf( errortypes.ErrInsufficientFunds, - "sender balance < tx cost (%s < %s)", balance, txData.Cost(), + "sender balance < tx cost (%s < %s)", balanceWei, txData.Cost(), ) } return nil diff --git a/x/evm/keeper/statedb_test.go b/x/evm/keeper/statedb_test.go index 2e81c81d9..903dee7d1 100644 --- a/x/evm/keeper/statedb_test.go +++ b/x/evm/keeper/statedb_test.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/NibiruChain/nibiru/eth" "github.com/NibiruChain/nibiru/x/common/testutil/testapp" "github.com/NibiruChain/nibiru/x/evm" "github.com/NibiruChain/nibiru/x/evm/evmtest" @@ -64,7 +65,7 @@ func (s *Suite) TestStateDBBalance() { s.T().Log("Send via bank transfer from account to account. See expected wei amounts.") { deps := evmtest.NewTestDeps() - toNibiAddr := evmtest.EthAddrToNibiruAddr(to) + toNibiAddr := eth.EthAddrToNibiruAddr(to) err := testapp.FundAccount( deps.Chain.BankKeeper, deps.Ctx, diff --git a/x/evm/tx_data.go b/x/evm/tx_data.go index 24dde1e19..375eaf63d 100644 --- a/x/evm/tx_data.go +++ b/x/evm/tx_data.go @@ -40,6 +40,7 @@ type TxData interface { // static fee Fee() *big.Int + // Cost is the gas cost of the transaction in wei Cost() *big.Int // effective gasPrice/fee/cost according to current base fee From 82bf5f08aacdf8cac3ea6c0ecaec7487e32270ee Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 6 Aug 2024 12:19:06 +0200 Subject: [PATCH 17/21] revert: add back NibiruAccount query to mock client --- eth/rpc/backend/mocks/evm_query_client.go | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/eth/rpc/backend/mocks/evm_query_client.go b/eth/rpc/backend/mocks/evm_query_client.go index e7b536508..4c4c5e557 100644 --- a/eth/rpc/backend/mocks/evm_query_client.go +++ b/eth/rpc/backend/mocks/evm_query_client.go @@ -47,6 +47,39 @@ func (_m *EVMQueryClient) EthAccount(ctx context.Context, in *evm.QueryEthAccoun return r0, r1 } +// NibiruAccount provides a mock function with given fields: ctx, in, opts +func (_m *EVMQueryClient) NibiruAccount( + ctx context.Context, in *evm.QueryNibiruAccountRequest, opts ...grpc.CallOption, +) (*evm.QueryNibiruAccountResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *evm.QueryNibiruAccountResponse + if rf, ok := ret.Get(0).(func(context.Context, *evm.QueryNibiruAccountRequest, ...grpc.CallOption) *evm.QueryNibiruAccountResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*evm.QueryNibiruAccountResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *evm.QueryNibiruAccountRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + + // Balance provides a mock function with given fields: ctx, in, opts func (_m *EVMQueryClient) Balance(ctx context.Context, in *evm.QueryBalanceRequest, opts ...grpc.CallOption) (*evm.QueryBalanceResponse, error) { _va := make([]interface{}, len(opts)) From 6ae937f1dafe4547563436e7904f3065c1d4446c Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 6 Aug 2024 12:56:01 +0200 Subject: [PATCH 18/21] fix(e2e-evm): add logging and fix tests --- e2e/evm/test/basic_queries.test.ts | 15 ++++++- e2e/evm/test/contract_send_nibi.test.ts | 54 +++++++++++++++++++------ 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/e2e/evm/test/basic_queries.test.ts b/e2e/evm/test/basic_queries.test.ts index b5452aa64..3ed1e2a8b 100644 --- a/e2e/evm/test/basic_queries.test.ts +++ b/e2e/evm/test/basic_queries.test.ts @@ -25,8 +25,19 @@ describe("Basic Queries", () => { const senderBalanceAfter = await provider.getBalance(account) const recipientBalanceAfter = await provider.getBalance(alice) - const expectedSenderBalance = senderBalanceBefore - amountToSend - 50000n // 50k gas for the transaction - expect(senderBalanceAfter).toEqual(expectedSenderBalance) + // Assert balances with logging + const tenPow12 = toBigInt(1e12) + const gasUsed = 50000n // 50k gas for the transaction + const txCostMicronibi = amountToSend / tenPow12 + gasUsed + const txCostWei = txCostMicronibi * tenPow12 + const expectedSenderWei = senderBalanceBefore - txCostWei + console.debug("DEBUG should send via transfer method %o:", { + senderBalanceBefore, + amountToSend, + expectedSenderWei, + senderBalanceAfter, + }) + expect(senderBalanceAfter).toEqual(expectedSenderWei) expect(recipientBalanceAfter).toEqual(amountToSend) }, 20e3) }) diff --git a/e2e/evm/test/contract_send_nibi.test.ts b/e2e/evm/test/contract_send_nibi.test.ts index e9bba487f..08c5e6422 100644 --- a/e2e/evm/test/contract_send_nibi.test.ts +++ b/e2e/evm/test/contract_send_nibi.test.ts @@ -11,7 +11,7 @@ describe("Send NIBI via smart contract", async () => { it("should send via transfer method", async () => { const recipient = Wallet.createRandom() - const transferValue = toBigInt(5e12) * toBigInt(6) // 5 micro NIBI + const transferValue = toBigInt(5e12) * toBigInt(1e6) // 5 micro NIBI const ownerBalanceBefore = await provider.getBalance(account) // NIBI const recipientBalanceBefore = await provider.getBalance(recipient) // NIBI @@ -22,15 +22,25 @@ describe("Send NIBI via smart contract", async () => { }) const receipt = await tx.wait(1, 5e3) - expect(provider.getBalance(account)).resolves.toBe( - ownerBalanceBefore - transferValue - receipt.gasUsed, - ) + // Assert balances with logging + const tenPow12 = toBigInt(1e12) + const txCostMicronibi = transferValue / tenPow12 + receipt.gasUsed + const txCostWei = txCostMicronibi * tenPow12 + const expectedOwnerWei = ownerBalanceBefore - txCostWei + console.debug("DEBUG should send via transfer method %o:", { + ownerBalanceBefore, + transferValue, + gasUsed: receipt.gasUsed, + gasPrice: `${receipt.gasPrice.toString()} micronibi`, + expectedOwnerWei, + }) + expect(provider.getBalance(account)).resolves.toBe(expectedOwnerWei) expect(provider.getBalance(recipient)).resolves.toBe(transferValue) }, 20e3) it("should send via send method", async () => { const recipient = Wallet.createRandom() - const transferValue = toBigInt(100e12) * toBigInt(6) // 100 NIBi + const transferValue = toBigInt(100e12) * toBigInt(1e6) // 100 NIBi const ownerBalanceBefore = await provider.getBalance(account) // NIBI const recipientBalanceBefore = await provider.getBalance(recipient) // NIBI @@ -41,15 +51,25 @@ describe("Send NIBI via smart contract", async () => { }) const receipt = await tx.wait(1, 5e3) - expect(provider.getBalance(account)).resolves.toBe( - ownerBalanceBefore - transferValue - receipt.gasUsed, - ) + // Assert balances with logging + const tenPow12 = toBigInt(1e12) + const txCostMicronibi = transferValue / tenPow12 + receipt.gasUsed + const txCostWei = txCostMicronibi * tenPow12 + const expectedOwnerWei = ownerBalanceBefore - txCostWei + console.debug("DEBUG send via send method %o:", { + ownerBalanceBefore, + transferValue, + gasUsed: receipt.gasUsed, + gasPrice: `${receipt.gasPrice.toString()} micronibi`, + expectedOwnerWei, + }) + expect(provider.getBalance(account)).resolves.toBe(expectedOwnerWei) expect(provider.getBalance(recipient)).resolves.toBe(transferValue) }, 20e3) it("should send via transfer method", async () => { const recipient = Wallet.createRandom() - const transferValue = toBigInt(100e12) * toBigInt(6) // 100 NIBI + const transferValue = toBigInt(100e12) * toBigInt(1e6) // 100 NIBI const ownerBalanceBefore = await provider.getBalance(account) // NIBI const recipientBalanceBefore = await provider.getBalance(recipient) // NIBI @@ -60,9 +80,19 @@ describe("Send NIBI via smart contract", async () => { }) const receipt = await tx.wait(1, 5e3) - expect(provider.getBalance(account)).resolves.toBe( - ownerBalanceBefore - transferValue - receipt.gasUsed, - ) + // Assert balances with logging + const tenPow12 = toBigInt(1e12) + const txCostMicronibi = transferValue / tenPow12 + receipt.gasUsed + const txCostWei = txCostMicronibi * tenPow12 + const expectedOwnerWei = ownerBalanceBefore - txCostWei + console.debug("DEBUG should send via transfer method %o:", { + ownerBalanceBefore, + transferValue, + gasUsed: receipt.gasUsed, + gasPrice: `${receipt.gasPrice.toString()} micronibi`, + expectedOwnerWei, + }) + expect(provider.getBalance(account)).resolves.toBe(expectedOwnerWei) expect(provider.getBalance(recipient)).resolves.toBe(transferValue) }, 20e3) }) From a6c17b59d62e4547d1912e308ffa69ab67a65cbf Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 6 Aug 2024 13:00:00 +0200 Subject: [PATCH 19/21] chore: resolve last few merge conflicts --- eth/rpc/backend/mocks/evm_query_client.go | 3 +-- x/evm/statedb/statedb_test.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/eth/rpc/backend/mocks/evm_query_client.go b/eth/rpc/backend/mocks/evm_query_client.go index 4c4c5e557..1f90610a4 100644 --- a/eth/rpc/backend/mocks/evm_query_client.go +++ b/eth/rpc/backend/mocks/evm_query_client.go @@ -49,7 +49,7 @@ func (_m *EVMQueryClient) EthAccount(ctx context.Context, in *evm.QueryEthAccoun // NibiruAccount provides a mock function with given fields: ctx, in, opts func (_m *EVMQueryClient) NibiruAccount( - ctx context.Context, in *evm.QueryNibiruAccountRequest, opts ...grpc.CallOption, + ctx context.Context, in *evm.QueryNibiruAccountRequest, opts ...grpc.CallOption, ) (*evm.QueryNibiruAccountResponse, error) { _va := make([]interface{}, len(opts)) for _i := range opts { @@ -79,7 +79,6 @@ func (_m *EVMQueryClient) NibiruAccount( return r0, r1 } - // Balance provides a mock function with given fields: ctx, in, opts func (_m *EVMQueryClient) Balance(ctx context.Context, in *evm.QueryBalanceRequest, opts ...grpc.CallOption) (*evm.QueryBalanceResponse, error) { _va := make([]interface{}, len(opts)) diff --git a/x/evm/statedb/statedb_test.go b/x/evm/statedb/statedb_test.go index 6368a1daf..56e3cddc4 100644 --- a/x/evm/statedb/statedb_test.go +++ b/x/evm/statedb/statedb_test.go @@ -609,7 +609,7 @@ func (s *Suite) TestIterateStorage() { keySet := set.New[common.Hash](key1, key2) valSet := set.New[common.Hash](value1, value2) for _, stateKey := range storage.SortedKeys() { - stateValue := deps.K.GetState(deps.Ctx, address, stateKey) + stateValue := deps.EvmKeeper.GetState(deps.Ctx, address, stateKey) s.True(keySet.Has(stateKey)) s.True(valSet.Has(stateValue)) } From 7126a8829e1e826726f7c010b4a67a108ff87ec9 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 6 Aug 2024 15:53:39 +0200 Subject: [PATCH 20/21] refactor: include variable name change suggestion for BalanceNative --- app/evmante/evmante_verify_eth_acc.go | 2 +- x/evm/keeper/statedb.go | 8 +++---- x/evm/statedb/state_object.go | 34 +++++++++++++-------------- x/evm/statedb/statedb.go | 14 +++++++---- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/app/evmante/evmante_verify_eth_acc.go b/app/evmante/evmante_verify_eth_acc.go index 4c1ae1842..80f591926 100644 --- a/app/evmante/evmante_verify_eth_acc.go +++ b/app/evmante/evmante_verify_eth_acc.go @@ -69,7 +69,7 @@ func (anteDec AnteDecVerifyEthAcc) AnteHandle( } if err := keeper.CheckSenderBalance( - evm.NativeToWei(acct.BalanceEvmDenom), txData, + evm.NativeToWei(acct.BalanceNative), txData, ); err != nil { return ctx, errors.Wrap(err, "failed to check sender balance") } diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index 7311dc63e..4f718be5f 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -30,7 +30,7 @@ func (k *Keeper) GetAccount(ctx sdk.Context, addr gethcommon.Address) *statedb.A return nil } - acct.BalanceEvmDenom = k.GetEvmGasBalance(ctx, addr) + acct.BalanceNative = k.GetEvmGasBalance(ctx, addr) return acct } @@ -126,7 +126,7 @@ func (k *Keeper) SetAccount( k.accountKeeper.SetAccount(ctx, acct) - if err := k.SetAccBalance(ctx, addr, account.BalanceEvmDenom); err != nil { + if err := k.SetAccBalance(ctx, addr, account.BalanceNative); err != nil { return err } @@ -213,7 +213,7 @@ func (k *Keeper) GetAccountOrEmpty( // empty account return statedb.Account{ - BalanceEvmDenom: new(big.Int), - CodeHash: evm.EmptyCodeHash, + BalanceNative: new(big.Int), + CodeHash: evm.EmptyCodeHash, } } diff --git a/x/evm/statedb/state_object.go b/x/evm/statedb/state_object.go index 3425abc91..e634a63b8 100644 --- a/x/evm/statedb/state_object.go +++ b/x/evm/statedb/state_object.go @@ -18,7 +18,9 @@ var emptyCodeHash = crypto.Keccak256(nil) // balance is stored in the smallest native unit (e.g., micronibi or unibi). // These objects are stored in the storage of auth module. type Account struct { - BalanceEvmDenom *big.Int + // BalanceNative is the micronibi (unibi) balance of the account, which is + // the official balance in the x/bank module state + BalanceNative *big.Int // Nonce is the number of transactions sent from this account or, for contract accounts, the number of contract-creations made by this account Nonce uint64 // CodeHash is the hash of the contract code for this account, or nil if it's not a contract account @@ -32,8 +34,10 @@ type Account struct { // definition of NIBI as "ether". type AccountWei struct { BalanceWei *big.Int - Nonce uint64 - CodeHash []byte + // Nonce is the number of transactions sent from this account or, for contract accounts, the number of contract-creations made by this account + Nonce uint64 + // CodeHash is the hash of the contract code for this account, or nil if it's not a contract account + CodeHash []byte } // ToWei converts an Account (native representation) to AccountWei (EVM @@ -42,7 +46,7 @@ type AccountWei struct { // unibi to wei. func (acc Account) ToWei() AccountWei { return AccountWei{ - BalanceWei: evm.NativeToWei(acc.BalanceEvmDenom), + BalanceWei: evm.NativeToWei(acc.BalanceNative), Nonce: acc.Nonce, CodeHash: acc.CodeHash, } @@ -54,17 +58,17 @@ func (acc Account) ToWei() AccountWei { // convert from wei to unibi. func (acc AccountWei) ToNative() Account { return Account{ - BalanceEvmDenom: evm.WeiToNative(acc.BalanceWei), - Nonce: acc.Nonce, - CodeHash: acc.CodeHash, + BalanceNative: evm.WeiToNative(acc.BalanceWei), + Nonce: acc.Nonce, + CodeHash: acc.CodeHash, } } // NewEmptyAccount returns an empty account. func NewEmptyAccount() *Account { return &Account{ - BalanceEvmDenom: new(big.Int), - CodeHash: emptyCodeHash, + BalanceNative: new(big.Int), + CodeHash: emptyCodeHash, } } @@ -123,8 +127,8 @@ type stateObject struct { // newObject creates a state object. func newObject(db *StateDB, address common.Address, account Account) *stateObject { - if account.BalanceEvmDenom == nil { - account.BalanceEvmDenom = new(big.Int) + if account.BalanceNative == nil { + account.BalanceNative = new(big.Int) } if account.CodeHash == nil { account.CodeHash = emptyCodeHash @@ -139,15 +143,11 @@ func newObject(db *StateDB, address common.Address, account Account) *stateObjec } } -// empty returns whether the account is considered empty. -func (s *stateObject) empty() bool { +// isEmpty returns whether the account is considered isEmpty. +func (s *stateObject) isEmpty() bool { return s.account.Nonce == 0 && s.account.BalanceWei.Sign() == 0 && bytes.Equal(s.account.CodeHash, emptyCodeHash) } -func (s *stateObject) markSuicided() { - s.suicided = true -} - // AddBalance adds amount to s's balance. // It is used to add funds to the destination account of a transfer. func (s *stateObject) AddBalance(amount *big.Int) { diff --git a/x/evm/statedb/statedb.go b/x/evm/statedb/statedb.go index 511060f15..27b81a3ce 100644 --- a/x/evm/statedb/statedb.go +++ b/x/evm/statedb/statedb.go @@ -6,7 +6,6 @@ import ( "math/big" "sort" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" gethcore "github.com/ethereum/go-ethereum/core/types" @@ -118,7 +117,7 @@ func (s *StateDB) Exist(addr common.Address) bool { // or empty according to the EIP161 specification (balance = nonce = code = 0) func (s *StateDB) Empty(addr common.Address) bool { so := s.getStateObject(addr) - return so == nil || so.empty() + return so == nil || so.isEmpty() } // GetBalance retrieves the balance from the given address or 0 if object not found @@ -349,7 +348,7 @@ func (s *StateDB) Suicide(addr common.Address) bool { prev: stateObject.suicided, prevbalance: new(big.Int).Set(stateObject.Balance()), }) - stateObject.markSuicided() + stateObject.suicided = true stateObject.account.BalanceWei = new(big.Int) return true @@ -445,6 +444,11 @@ func (s *StateDB) RevertToSnapshot(revid int) { s.validRevisions = s.validRevisions[:idx] } +// errorf: wrapper of "fmt.Errorf" specific to the current Go package. +func errorf(format string, args ...any) error { + return fmt.Errorf("StateDB error: "+format, args...) +} + // Commit writes the dirty states to keeper // the StateDB object should be discarded after committed. func (s *StateDB) Commit() error { @@ -452,14 +456,14 @@ func (s *StateDB) Commit() error { obj := s.stateObjects[addr] if obj.suicided { if err := s.keeper.DeleteAccount(s.ctx, obj.Address()); err != nil { - return errorsmod.Wrap(err, "failed to delete account") + return errorf("failed to delete account: %w") } } else { if obj.code != nil && obj.dirtyCode { s.keeper.SetCode(s.ctx, obj.CodeHash(), obj.code) } if err := s.keeper.SetAccount(s.ctx, obj.Address(), obj.account.ToNative()); err != nil { - return errorsmod.Wrap(err, "failed to set account") + return errorf("failed to set account: %w") } for _, key := range obj.dirtyStorage.SortedKeys() { value := obj.dirtyStorage[key] From 2c1d2b3655e30648f1839c2a0e5fada030fbbee6 Mon Sep 17 00:00:00 2001 From: Unique-Divine Date: Tue, 6 Aug 2024 15:53:39 +0200 Subject: [PATCH 21/21] refactor: include variable name change suggestion for BalanceNative --- app/evmante/evmante_verify_eth_acc.go | 2 +- x/evm/keeper/grpc_query.go | 2 +- x/evm/keeper/statedb.go | 8 +++---- x/evm/statedb/state_object.go | 34 +++++++++++++-------------- x/evm/statedb/statedb.go | 14 +++++++---- 5 files changed, 32 insertions(+), 28 deletions(-) diff --git a/app/evmante/evmante_verify_eth_acc.go b/app/evmante/evmante_verify_eth_acc.go index 4c1ae1842..80f591926 100644 --- a/app/evmante/evmante_verify_eth_acc.go +++ b/app/evmante/evmante_verify_eth_acc.go @@ -69,7 +69,7 @@ func (anteDec AnteDecVerifyEthAcc) AnteHandle( } if err := keeper.CheckSenderBalance( - evm.NativeToWei(acct.BalanceEvmDenom), txData, + evm.NativeToWei(acct.BalanceNative), txData, ); err != nil { return ctx, errors.Wrap(err, "failed to check sender balance") } diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index b06592142..cd6127e12 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -58,7 +58,7 @@ func (k Keeper) EthAccount( acct := k.GetAccountOrEmpty(ctx, addr) return &evm.QueryEthAccountResponse{ - BalanceWei: evm.NativeToWei(acct.BalanceEvmDenom).String(), + BalanceWei: evm.NativeToWei(acct.BalanceNative).String(), CodeHash: gethcommon.BytesToHash(acct.CodeHash).Hex(), Nonce: acct.Nonce, }, nil diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index 7311dc63e..4f718be5f 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -30,7 +30,7 @@ func (k *Keeper) GetAccount(ctx sdk.Context, addr gethcommon.Address) *statedb.A return nil } - acct.BalanceEvmDenom = k.GetEvmGasBalance(ctx, addr) + acct.BalanceNative = k.GetEvmGasBalance(ctx, addr) return acct } @@ -126,7 +126,7 @@ func (k *Keeper) SetAccount( k.accountKeeper.SetAccount(ctx, acct) - if err := k.SetAccBalance(ctx, addr, account.BalanceEvmDenom); err != nil { + if err := k.SetAccBalance(ctx, addr, account.BalanceNative); err != nil { return err } @@ -213,7 +213,7 @@ func (k *Keeper) GetAccountOrEmpty( // empty account return statedb.Account{ - BalanceEvmDenom: new(big.Int), - CodeHash: evm.EmptyCodeHash, + BalanceNative: new(big.Int), + CodeHash: evm.EmptyCodeHash, } } diff --git a/x/evm/statedb/state_object.go b/x/evm/statedb/state_object.go index 3425abc91..e634a63b8 100644 --- a/x/evm/statedb/state_object.go +++ b/x/evm/statedb/state_object.go @@ -18,7 +18,9 @@ var emptyCodeHash = crypto.Keccak256(nil) // balance is stored in the smallest native unit (e.g., micronibi or unibi). // These objects are stored in the storage of auth module. type Account struct { - BalanceEvmDenom *big.Int + // BalanceNative is the micronibi (unibi) balance of the account, which is + // the official balance in the x/bank module state + BalanceNative *big.Int // Nonce is the number of transactions sent from this account or, for contract accounts, the number of contract-creations made by this account Nonce uint64 // CodeHash is the hash of the contract code for this account, or nil if it's not a contract account @@ -32,8 +34,10 @@ type Account struct { // definition of NIBI as "ether". type AccountWei struct { BalanceWei *big.Int - Nonce uint64 - CodeHash []byte + // Nonce is the number of transactions sent from this account or, for contract accounts, the number of contract-creations made by this account + Nonce uint64 + // CodeHash is the hash of the contract code for this account, or nil if it's not a contract account + CodeHash []byte } // ToWei converts an Account (native representation) to AccountWei (EVM @@ -42,7 +46,7 @@ type AccountWei struct { // unibi to wei. func (acc Account) ToWei() AccountWei { return AccountWei{ - BalanceWei: evm.NativeToWei(acc.BalanceEvmDenom), + BalanceWei: evm.NativeToWei(acc.BalanceNative), Nonce: acc.Nonce, CodeHash: acc.CodeHash, } @@ -54,17 +58,17 @@ func (acc Account) ToWei() AccountWei { // convert from wei to unibi. func (acc AccountWei) ToNative() Account { return Account{ - BalanceEvmDenom: evm.WeiToNative(acc.BalanceWei), - Nonce: acc.Nonce, - CodeHash: acc.CodeHash, + BalanceNative: evm.WeiToNative(acc.BalanceWei), + Nonce: acc.Nonce, + CodeHash: acc.CodeHash, } } // NewEmptyAccount returns an empty account. func NewEmptyAccount() *Account { return &Account{ - BalanceEvmDenom: new(big.Int), - CodeHash: emptyCodeHash, + BalanceNative: new(big.Int), + CodeHash: emptyCodeHash, } } @@ -123,8 +127,8 @@ type stateObject struct { // newObject creates a state object. func newObject(db *StateDB, address common.Address, account Account) *stateObject { - if account.BalanceEvmDenom == nil { - account.BalanceEvmDenom = new(big.Int) + if account.BalanceNative == nil { + account.BalanceNative = new(big.Int) } if account.CodeHash == nil { account.CodeHash = emptyCodeHash @@ -139,15 +143,11 @@ func newObject(db *StateDB, address common.Address, account Account) *stateObjec } } -// empty returns whether the account is considered empty. -func (s *stateObject) empty() bool { +// isEmpty returns whether the account is considered isEmpty. +func (s *stateObject) isEmpty() bool { return s.account.Nonce == 0 && s.account.BalanceWei.Sign() == 0 && bytes.Equal(s.account.CodeHash, emptyCodeHash) } -func (s *stateObject) markSuicided() { - s.suicided = true -} - // AddBalance adds amount to s's balance. // It is used to add funds to the destination account of a transfer. func (s *stateObject) AddBalance(amount *big.Int) { diff --git a/x/evm/statedb/statedb.go b/x/evm/statedb/statedb.go index 511060f15..27b81a3ce 100644 --- a/x/evm/statedb/statedb.go +++ b/x/evm/statedb/statedb.go @@ -6,7 +6,6 @@ import ( "math/big" "sort" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" gethcore "github.com/ethereum/go-ethereum/core/types" @@ -118,7 +117,7 @@ func (s *StateDB) Exist(addr common.Address) bool { // or empty according to the EIP161 specification (balance = nonce = code = 0) func (s *StateDB) Empty(addr common.Address) bool { so := s.getStateObject(addr) - return so == nil || so.empty() + return so == nil || so.isEmpty() } // GetBalance retrieves the balance from the given address or 0 if object not found @@ -349,7 +348,7 @@ func (s *StateDB) Suicide(addr common.Address) bool { prev: stateObject.suicided, prevbalance: new(big.Int).Set(stateObject.Balance()), }) - stateObject.markSuicided() + stateObject.suicided = true stateObject.account.BalanceWei = new(big.Int) return true @@ -445,6 +444,11 @@ func (s *StateDB) RevertToSnapshot(revid int) { s.validRevisions = s.validRevisions[:idx] } +// errorf: wrapper of "fmt.Errorf" specific to the current Go package. +func errorf(format string, args ...any) error { + return fmt.Errorf("StateDB error: "+format, args...) +} + // Commit writes the dirty states to keeper // the StateDB object should be discarded after committed. func (s *StateDB) Commit() error { @@ -452,14 +456,14 @@ func (s *StateDB) Commit() error { obj := s.stateObjects[addr] if obj.suicided { if err := s.keeper.DeleteAccount(s.ctx, obj.Address()); err != nil { - return errorsmod.Wrap(err, "failed to delete account") + return errorf("failed to delete account: %w") } } else { if obj.code != nil && obj.dirtyCode { s.keeper.SetCode(s.ctx, obj.CodeHash(), obj.code) } if err := s.keeper.SetAccount(s.ctx, obj.Address(), obj.account.ToNative()); err != nil { - return errorsmod.Wrap(err, "failed to set account") + return errorf("failed to set account: %w") } for _, key := range obj.dirtyStorage.SortedKeys() { value := obj.dirtyStorage[key]