From 7b7beb7b53a537a8ad1462cf8ca5520e21e4978c Mon Sep 17 00:00:00 2001 From: Matthias <97468149+matthiasmatt@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:09:25 +0100 Subject: [PATCH 1/2] feat: add validation for multi message execution wasm (#2092) * feat: add validation for multi message execution wasm * chore: changelog * merge conflicts + simplify --------- Co-authored-by: Unique-Divine --- CHANGELOG.md | 1 + x/evm/precompile/wasm.go | 12 ++- x/evm/precompile/wasm_test.go | 183 ++++++++++++++++++++++++++++++++++ x/evm/statedb/statedb.go | 3 - 4 files changed, 193 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61dc41b07..23dcb15d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,7 @@ reverts inside of a try-catch. for (1) ERC20 transfers with tokens that return false success values instead of throwing an error and (2) ERC20 transfers with other operations that don't bring about the expected resulting balance for the transfer recipient. +- [#2092](https://github.com/NibiruChain/nibiru/pull/2092) - feat(evm): add validation for wasm multi message execution #### Nibiru EVM | Before Audit 1 - 2024-10-18 diff --git a/x/evm/precompile/wasm.go b/x/evm/precompile/wasm.go index a7b21684c..f19511cb9 100644 --- a/x/evm/precompile/wasm.go +++ b/x/evm/precompile/wasm.go @@ -10,6 +10,7 @@ import ( "github.com/NibiruChain/nibiru/v2/x/evm/embeds" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasm "github.com/CosmWasm/wasmd/x/wasm/types" gethabi "github.com/ethereum/go-ethereum/accounts/abi" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" @@ -275,10 +276,15 @@ func (p precompileWasm) executeMulti( callerBech32 := eth.EthAddrToNibiruAddr(caller) var responses [][]byte - for _, m := range wasmExecMsgs { + for i, m := range wasmExecMsgs { wasmContract, e := sdk.AccAddressFromBech32(m.ContractAddr) if e != nil { - err = fmt.Errorf("Execute failed: %w", e) + err = fmt.Errorf("Execute failed at index %d: %w", i, e) + return + } + msgArgsCopy := wasm.RawContractMessage(m.MsgArgs) + if e := msgArgsCopy.ValidateBasic(); e != nil { + err = fmt.Errorf("Execute failed at index %d: error parsing msg args: %w", i, e) return } var funds sdk.Coins @@ -290,7 +296,7 @@ func (p precompileWasm) executeMulti( } respBz, e := p.Wasm.Execute(ctx, wasmContract, callerBech32, m.MsgArgs, funds) if e != nil { - err = e + err = fmt.Errorf("Execute failed at index %d: %w", i, e) return } responses = append(responses, respBz) diff --git a/x/evm/precompile/wasm_test.go b/x/evm/precompile/wasm_test.go index dbe35b839..72c45046c 100644 --- a/x/evm/precompile/wasm_test.go +++ b/x/evm/precompile/wasm_test.go @@ -8,6 +8,7 @@ import ( wasm "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/NibiruChain/nibiru/v2/x/common/testutil" + "github.com/NibiruChain/nibiru/v2/x/common/testutil/testapp" "github.com/NibiruChain/nibiru/v2/x/evm/embeds" "github.com/NibiruChain/nibiru/v2/x/evm/evmtest" "github.com/NibiruChain/nibiru/v2/x/evm/precompile" @@ -313,3 +314,185 @@ func (s *WasmSuite) TestSadArgsExecute() { }) } } + +type WasmExecuteMsg struct { + ContractAddr string `json:"contractAddr"` + MsgArgs []byte `json:"msgArgs"` + Funds []precompile.WasmBankCoin `json:"funds"` +} + +func (s *WasmSuite) TestExecuteMultiValidation() { + deps := evmtest.NewTestDeps() + + s.Require().NoError(testapp.FundAccount( + deps.App.BankKeeper, + deps.Ctx, + deps.Sender.NibiruAddr, + sdk.NewCoins(sdk.NewCoin("unibi", sdk.NewInt(100))), + )) + + wasmContracts := test.SetupWasmContracts(&deps, &s.Suite) + wasmContract := wasmContracts[1] // hello_world_counter.wasm + + invalidMsgArgsBz := []byte(`{"invalid": "json"}`) // Invalid message format + validMsgArgsBz := []byte(`{"increment": {}}`) // Valid increment message + + var emptyFunds []precompile.WasmBankCoin + validFunds := []precompile.WasmBankCoin{{ + Denom: "unibi", + Amount: big.NewInt(100), + }} + invalidFunds := []precompile.WasmBankCoin{{ + Denom: "invalid!denom", + Amount: big.NewInt(100), + }} + + testCases := []struct { + name string + executeMsgs []WasmExecuteMsg + wantError string + }{ + { + name: "valid - single message", + executeMsgs: []WasmExecuteMsg{ + { + ContractAddr: wasmContract.String(), + MsgArgs: validMsgArgsBz, + Funds: emptyFunds, + }, + }, + wantError: "", + }, + { + name: "valid - multiple messages", + executeMsgs: []WasmExecuteMsg{ + { + ContractAddr: wasmContract.String(), + MsgArgs: validMsgArgsBz, + Funds: validFunds, + }, + { + ContractAddr: wasmContract.String(), + MsgArgs: validMsgArgsBz, + Funds: emptyFunds, + }, + }, + wantError: "", + }, + { + name: "invalid - malformed contract address", + executeMsgs: []WasmExecuteMsg{ + { + ContractAddr: "invalid-address", + MsgArgs: validMsgArgsBz, + Funds: emptyFunds, + }, + }, + wantError: "decoding bech32 failed", + }, + { + name: "invalid - malformed message args", + executeMsgs: []WasmExecuteMsg{ + { + ContractAddr: wasmContract.String(), + MsgArgs: invalidMsgArgsBz, + Funds: emptyFunds, + }, + }, + wantError: "unknown variant", + }, + { + name: "invalid - malformed funds", + executeMsgs: []WasmExecuteMsg{ + { + ContractAddr: wasmContract.String(), + MsgArgs: validMsgArgsBz, + Funds: invalidFunds, + }, + }, + wantError: "invalid coins", + }, + { + name: "invalid - second message fails validation", + executeMsgs: []WasmExecuteMsg{ + { + ContractAddr: wasmContract.String(), + MsgArgs: validMsgArgsBz, + Funds: emptyFunds, + }, + { + ContractAddr: wasmContract.String(), + MsgArgs: invalidMsgArgsBz, + Funds: emptyFunds, + }, + }, + wantError: "unknown variant", + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + callArgs := []any{tc.executeMsgs} + input, err := embeds.SmartContract_Wasm.ABI.Pack( + string(precompile.WasmMethod_executeMulti), + callArgs..., + ) + s.Require().NoError(err) + + ethTxResp, _, err := deps.EvmKeeper.CallContractWithInput( + deps.Ctx, deps.Sender.EthAddr, &precompile.PrecompileAddr_Wasm, true, input, + ) + + if tc.wantError != "" { + s.Require().ErrorContains(err, tc.wantError) + return + } + s.Require().NoError(err) + s.NotNil(ethTxResp) + s.NotEmpty(ethTxResp.Ret) + }) + } +} + +// TestExecuteMultiPartialExecution ensures that no state changes occur if any message +// in the batch fails validation +func (s *WasmSuite) TestExecuteMultiPartialExecution() { + deps := evmtest.NewTestDeps() + wasmContracts := test.SetupWasmContracts(&deps, &s.Suite) + wasmContract := wasmContracts[1] // hello_world_counter.wasm + + // First verify initial state is 0 + test.AssertWasmCounterState(&s.Suite, deps, wasmContract, 0) + + // Create a batch where the second message will fail validation + executeMsgs := []WasmExecuteMsg{ + { + ContractAddr: wasmContract.String(), + MsgArgs: []byte(`{"increment": {}}`), + Funds: []precompile.WasmBankCoin{}, + }, + { + ContractAddr: wasmContract.String(), + MsgArgs: []byte(`{"invalid": "json"}`), // This will fail validation + Funds: []precompile.WasmBankCoin{}, + }, + } + + callArgs := []any{executeMsgs} + input, err := embeds.SmartContract_Wasm.ABI.Pack( + string(precompile.WasmMethod_executeMulti), + callArgs..., + ) + s.Require().NoError(err) + + ethTxResp, _, err := deps.EvmKeeper.CallContractWithInput( + deps.Ctx, deps.Sender.EthAddr, &precompile.PrecompileAddr_Wasm, true, input, + ) + + // Verify that the call failed + s.Require().Error(err, "ethTxResp: ", ethTxResp) + s.Require().Contains(err.Error(), "unknown variant") + + // Verify that no state changes occurred + test.AssertWasmCounterState(&s.Suite, deps, wasmContract, 0) +} diff --git a/x/evm/statedb/statedb.go b/x/evm/statedb/statedb.go index 4c79e61af..a411660f9 100644 --- a/x/evm/statedb/statedb.go +++ b/x/evm/statedb/statedb.go @@ -480,9 +480,6 @@ func (s *StateDB) Snapshot() int { // RevertToSnapshot reverts all state changes made since the given revision. func (s *StateDB) RevertToSnapshot(revid int) { - fmt.Printf("len(s.validRevisions): %d\n", len(s.validRevisions)) - fmt.Printf("s.validRevisions: %v\n", s.validRevisions) - // Find the snapshot in the stack of valid snapshots. idx := sort.Search(len(s.validRevisions), func(i int) bool { return s.validRevisions[i].id >= revid From 0afb08f403baffc6e61046f3ad0774f64e7d14c4 Mon Sep 17 00:00:00 2001 From: Kevin Yang <5478483+k-yang@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:48:29 -0700 Subject: [PATCH 2/2] refactor: general code style cleanups on precompile and statedb journal (#2100) * statedb: add cacheing for multistore before precompile runs * messy, working first version that allows for precompile reversion * wip!: Save checkpoint. 1. Created NibiruBankKeeper with safety around NIBI transfers inside of EthereumTx. 2. The "PrecompileCalled" JournalChange now has a propery implementation and a strong test case to show that reverting the precompile calls works as intended. 3. Remove unneeded functions created for testing with low-level struct fields. * chore: changelog * finalize bank keeper changes * revert to previous commit 7f904a07ac4d5555d8c088411024fc50ff65d085 * fix strange ignored file issue * remove new bank keeper * chore: comments from self-review * refactor: clean up test code * refactor: clean up parse fund args * refactor: clean up common precompile functions * refactor: clean up precompile onrunstart * refactor: clean up precompile onrunstart * refactor: clean up oracle precompile * fix: import * Delete .gitignore * Update CHANGELOG.md * refactor: replace interface{} with any * refactor: add ABI() precompile fn * refactor: replace assertNotReadonlyTx --------- Co-authored-by: Unique-Divine --- CHANGELOG.md | 7 +-- app/server/config/server_config.go | 2 +- cmd/nibid/cmd/base64.go | 2 +- cmd/nibid/cmd/decode_base64.go | 8 +-- eth/eip712/eip712_legacy.go | 10 ++-- eth/eip712/encoding_legacy.go | 4 +- eth/eip712/message.go | 4 +- eth/rpc/backend/blocks.go | 8 +-- eth/rpc/backend/node_info.go | 4 +- eth/rpc/backend/tracing.go | 8 +-- eth/rpc/backend/utils.go | 2 +- eth/rpc/rpc.go | 6 +-- eth/rpc/rpcapi/debugapi/api.go | 4 +- eth/rpc/rpcapi/eth_api.go | 20 ++++---- eth/rpc/rpcapi/eth_filters_api.go | 2 +- eth/rpc/rpcapi/websockets.go | 34 ++++++------- x/common/testutil/nullify.go | 2 +- x/common/testutil/testnetwork/logger.go | 4 +- x/devgas/v1/types/params.go | 6 +-- x/epochs/types/identifier.go | 2 +- x/evm/errors.go | 2 +- x/evm/keeper/grpc_query.go | 4 +- x/evm/params.go | 4 +- x/evm/precompile/.gitignore | 17 ------- x/evm/precompile/errors.go | 16 +++--- x/evm/precompile/funtoken.go | 28 ++++------- x/evm/precompile/oracle.go | 21 ++++---- x/evm/precompile/precompile.go | 43 ++++++++-------- x/evm/precompile/test/export.go | 63 +++++++++-------------- x/evm/precompile/wasm.go | 57 +++++++++++---------- x/evm/precompile/wasm_parse.go | 66 +++++++++++-------------- x/evm/statedb/journal_test.go | 27 +++++----- x/evm/statedb/statedb.go | 7 ++- x/evm/vmtracer.go | 4 +- x/inflation/types/params.go | 12 ++--- x/oracle/types/hash.go | 2 +- x/tokenfactory/types/codec.go | 2 +- 37 files changed, 230 insertions(+), 284 deletions(-) delete mode 100644 x/evm/precompile/.gitignore diff --git a/CHANGELOG.md b/CHANGELOG.md index 23dcb15d1..88fa93ee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,9 +63,9 @@ committed as expected, fixes the `StateDB.Commit` to follow its guidelines more closely, and solves for a critical state inconsistency producible from the FunToken.sol precompiled contract. It also aligns the precompiles to use consistent setup and dynamic gas calculations, addressing the following tickets. - - https://github.com/NibiruChain/nibiru/issues/2083 - - https://github.com/code-423n4/2024-10-nibiru-zenith/issues/43 - - https://github.com/code-423n4/2024-10-nibiru-zenith/issues/47 + - + - + - - [#2088](https://github.com/NibiruChain/nibiru/pull/2088) - refactor(evm): remove outdated comment and improper error message text - [#2089](https://github.com/NibiruChain/nibiru/pull/2089) - better handling of gas consumption within erc20 contract execution - [#2091](https://github.com/NibiruChain/nibiru/pull/2091) - feat(evm): add fun token creation fee validation @@ -163,6 +163,7 @@ about the expected resulting balance for the transfer recipient. - [#2060](https://github.com/NibiruChain/nibiru/pull/2060) - fix(evm-precompiles): add assertNumArgs validation - [#2056](https://github.com/NibiruChain/nibiru/pull/2056) - feat(evm): add oracle precompile - [#2065](https://github.com/NibiruChain/nibiru/pull/2065) - refactor(evm)!: Refactor out dead code from the evm.Params +- [#2100](https://github.com/NibiruChain/nibiru/pull/2100) - refactor: cleanup statedb and precompile sections ### State Machine Breaking (Other) diff --git a/app/server/config/server_config.go b/app/server/config/server_config.go index b72638ed2..f393983a9 100644 --- a/app/server/config/server_config.go +++ b/app/server/config/server_config.go @@ -174,7 +174,7 @@ type TLSConfig struct { // AppConfig helps to override default appConfig template and configs. // return "", nil if no custom configuration is required for the application. -func AppConfig(denom string) (string, interface{}) { +func AppConfig(denom string) (string, any) { // Optionally allow the chain developer to overwrite the SDK's default // server config. customAppConfig := DefaultConfig() diff --git a/cmd/nibid/cmd/base64.go b/cmd/nibid/cmd/base64.go index 5f235d3ea..ba5685aff 100644 --- a/cmd/nibid/cmd/base64.go +++ b/cmd/nibid/cmd/base64.go @@ -33,7 +33,7 @@ func GetBuildWasmMsg() *cobra.Command { Value string `json:"value,omitempty"` } - js, err := json.Marshal(map[string]interface{}{ + js, err := json.Marshal(map[string]any{ "stargate": stargateMessage{ TypeURL: anyMsg.TypeUrl, Value: base64.StdEncoding.EncodeToString(anyMsg.Value), diff --git a/cmd/nibid/cmd/decode_base64.go b/cmd/nibid/cmd/decode_base64.go index 3de3706f2..8625070c3 100644 --- a/cmd/nibid/cmd/decode_base64.go +++ b/cmd/nibid/cmd/decode_base64.go @@ -27,7 +27,7 @@ import ( // from the provided JSON data. // - err error: An error object, which is nil if the operation is successful. func YieldStargateMsgs(jsonBz []byte) (sgMsgs []wasmvm.StargateMsg, err error) { - var data interface{} + var data any if err := json.Unmarshal(jsonBz, &data); err != nil { return sgMsgs, err } @@ -50,7 +50,7 @@ func YieldStargateMsgs(jsonBz []byte) (sgMsgs []wasmvm.StargateMsg, err error) { // encoded base 64 string. func parseStargateMsgs(jsonData any, msgs *[]wasmvm.StargateMsg) { switch v := jsonData.(type) { - case map[string]interface{}: + case map[string]any: if typeURL, ok := v["type_url"].(string); ok { if value, ok := v["value"].(string); ok { *msgs = append(*msgs, wasmvm.StargateMsg{ @@ -62,7 +62,7 @@ func parseStargateMsgs(jsonData any, msgs *[]wasmvm.StargateMsg) { for _, value := range v { parseStargateMsgs(value, msgs) } - case []interface{}: + case []any: for _, value := range v { parseStargateMsgs(value, msgs) } @@ -93,7 +93,7 @@ func DecodeBase64StargateMsgs( ) (newSgMsgs []StargateMsgDecoded, err error) { codec := clientCtx.Codec - var data interface{} + var data any if err := json.Unmarshal(jsonBz, &data); err != nil { return newSgMsgs, fmt.Errorf( "failed to decode stargate msgs due to invalid JSON: %w", err) diff --git a/eth/eip712/eip712_legacy.go b/eth/eip712/eip712_legacy.go index c1d0b1b30..b50f10e5f 100644 --- a/eth/eip712/eip712_legacy.go +++ b/eth/eip712/eip712_legacy.go @@ -38,7 +38,7 @@ func LegacyWrapTxToTypedData( data []byte, feeDelegation *FeeDelegationOptions, ) (apitypes.TypedData, error) { - txData := make(map[string]interface{}) + txData := make(map[string]any) if err := json.Unmarshal(data, &txData); err != nil { return apitypes.TypedData{}, errorsmod.Wrap(errortypes.ErrJSONUnmarshal, "failed to JSON unmarshal data") @@ -58,7 +58,7 @@ func LegacyWrapTxToTypedData( } if feeDelegation != nil { - feeInfo, ok := txData["fee"].(map[string]interface{}) + feeInfo, ok := txData["fee"].(map[string]any) if !ok { return apitypes.TypedData{}, errorsmod.Wrap(errortypes.ErrInvalidType, "cannot parse fee from tx data") } @@ -139,7 +139,7 @@ func extractMsgTypes(cdc codectypes.AnyUnpacker, msgTypeName string, msg sdk.Msg return rootTypes, nil } -func walkFields(cdc codectypes.AnyUnpacker, typeMap apitypes.Types, rootType string, in interface{}) (err error) { +func walkFields(cdc codectypes.AnyUnpacker, typeMap apitypes.Types, rootType string, in any) (err error) { defer doRecover(&err) t := reflect.TypeOf(in) @@ -161,8 +161,8 @@ func walkFields(cdc codectypes.AnyUnpacker, typeMap apitypes.Types, rootType str } type CosmosAnyWrapper struct { - Type string `json:"type"` - Value interface{} `json:"value"` + Type string `json:"type"` + Value any `json:"value"` } // legacyTraverseFields: Recursively inspects the fields of a given diff --git a/eth/eip712/encoding_legacy.go b/eth/eip712/encoding_legacy.go index 805eb48dd..23f943eaf 100644 --- a/eth/eip712/encoding_legacy.go +++ b/eth/eip712/encoding_legacy.go @@ -17,8 +17,8 @@ import ( ) type aminoMessage struct { - Type string `json:"type"` - Value interface{} `json:"value"` + Type string `json:"type"` + Value any `json:"value"` } // LegacyGetEIP712BytesForMsg returns the EIP-712 object bytes for the given SignDoc bytes by decoding the bytes into diff --git a/eth/eip712/message.go b/eth/eip712/message.go index 6a8577c22..176d90b56 100644 --- a/eth/eip712/message.go +++ b/eth/eip712/message.go @@ -14,7 +14,7 @@ import ( type eip712MessagePayload struct { payload gjson.Result numPayloadMsgs int - message map[string]interface{} + message map[string]any } const ( @@ -34,7 +34,7 @@ func createEIP712MessagePayload(data []byte) (eip712MessagePayload, error) { return eip712MessagePayload{}, errorsmod.Wrap(err, "failed to flatten payload JSON messages") } - message, ok := payload.Value().(map[string]interface{}) + message, ok := payload.Value().(map[string]any) if !ok { return eip712MessagePayload{}, errorsmod.Wrap(errortypes.ErrInvalidType, "failed to parse JSON as map") } diff --git a/eth/rpc/backend/blocks.go b/eth/rpc/backend/blocks.go index a64e73e2a..7bc5f4b97 100644 --- a/eth/rpc/backend/blocks.go +++ b/eth/rpc/backend/blocks.go @@ -57,7 +57,7 @@ func (b *Backend) BlockNumber() (hexutil.Uint64, error) { // GetBlockByNumber returns the JSON-RPC compatible Ethereum block identified by // block number. Depending on fullTx it either returns the full transaction // objects or if false only the hashes of the transactions. -func (b *Backend) GetBlockByNumber(blockNum rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { +func (b *Backend) GetBlockByNumber(blockNum rpc.BlockNumber, fullTx bool) (map[string]any, error) { resBlock, err := b.TendermintBlockByNumber(blockNum) if err != nil { return nil, nil @@ -85,7 +85,7 @@ func (b *Backend) GetBlockByNumber(blockNum rpc.BlockNumber, fullTx bool) (map[s // GetBlockByHash returns the JSON-RPC compatible Ethereum block identified by // hash. -func (b *Backend) GetBlockByHash(hash gethcommon.Hash, fullTx bool) (map[string]interface{}, error) { +func (b *Backend) GetBlockByHash(hash gethcommon.Hash, fullTx bool) (map[string]any, error) { resBlock, err := b.TendermintBlockByHash(hash) if err != nil { return nil, err @@ -348,8 +348,8 @@ func (b *Backend) RPCBlockFromTendermintBlock( resBlock *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults, fullTx bool, -) (map[string]interface{}, error) { - ethRPCTxs := []interface{}{} +) (map[string]any, error) { + ethRPCTxs := []any{} block := resBlock.Block baseFeeWei, err := b.BaseFeeWei(blockRes) diff --git a/eth/rpc/backend/node_info.go b/eth/rpc/backend/node_info.go index 402578dd5..e95488b2a 100644 --- a/eth/rpc/backend/node_info.go +++ b/eth/rpc/backend/node_info.go @@ -39,7 +39,7 @@ func (b *Backend) Accounts() ([]gethcommon.Address, error) { // - highestBlock: block number of the highest block header this node has received from peers // - pulledStates: number of state entries processed until now // - knownStates: number of known state entries that still need to be pulled -func (b *Backend) Syncing() (interface{}, error) { +func (b *Backend) Syncing() (any, error) { status, err := b.clientCtx.Client.Status(b.ctx) if err != nil { return false, err @@ -49,7 +49,7 @@ func (b *Backend) Syncing() (interface{}, error) { return false, nil } - return map[string]interface{}{ + return map[string]any{ "startingBlock": hexutil.Uint64(status.SyncInfo.EarliestBlockHeight), "currentBlock": hexutil.Uint64(status.SyncInfo.LatestBlockHeight), // "highestBlock": nil, // NA diff --git a/eth/rpc/backend/tracing.go b/eth/rpc/backend/tracing.go index 4a20557cd..94bb8fbba 100644 --- a/eth/rpc/backend/tracing.go +++ b/eth/rpc/backend/tracing.go @@ -18,7 +18,7 @@ import ( // TraceTransaction returns the structured logs created during the execution of EVM // and returns them as a JSON object. -func (b *Backend) TraceTransaction(hash gethcommon.Hash, config *evm.TraceConfig) (interface{}, error) { +func (b *Backend) TraceTransaction(hash gethcommon.Hash, config *evm.TraceConfig) (any, error) { // Get transaction by hash transaction, err := b.GetTxByEthHash(hash) if err != nil { @@ -124,7 +124,7 @@ func (b *Backend) TraceTransaction(hash gethcommon.Hash, config *evm.TraceConfig // Response format is unknown due to custom tracer config param // More information can be found here https://geth.ethereum.org/docs/dapp/tracing-filtered - var decodedResult interface{} + var decodedResult any err = json.Unmarshal(traceResult.Data, &decodedResult) if err != nil { return nil, err @@ -219,7 +219,7 @@ func (b *Backend) TraceCall( txArgs evm.JsonTxArgs, contextBlock rpc.BlockNumber, config *evm.TraceConfig, -) (interface{}, error) { +) (any, error) { blk, err := b.TendermintBlockByNumber(contextBlock) if err != nil { b.logger.Debug("block not found", "contextBlock", contextBlock) @@ -253,7 +253,7 @@ func (b *Backend) TraceCall( if err != nil { return nil, err } - var decodedResult interface{} + var decodedResult any err = json.Unmarshal(traceResult.Data, &decodedResult) if err != nil { return nil, err diff --git a/eth/rpc/backend/utils.go b/eth/rpc/backend/utils.go index 23ce2f410..bb689bcce 100644 --- a/eth/rpc/backend/utils.go +++ b/eth/rpc/backend/utils.go @@ -109,7 +109,7 @@ func (b *Backend) getAccountNonce(accAddr common.Address, pending bool, height i // See eth_feeHistory method for more details of the return format. func (b *Backend) retrieveEVMTxFeesFromBlock( tendermintBlock *tmrpctypes.ResultBlock, - ethBlock *map[string]interface{}, + ethBlock *map[string]any, rewardPercentiles []float64, tendermintBlockResult *tmrpctypes.ResultBlockResults, targetOneFeeHistory *rpc.OneFeeHistory, diff --git a/eth/rpc/rpc.go b/eth/rpc/rpc.go index de5a97991..c6c0891de 100644 --- a/eth/rpc/rpc.go +++ b/eth/rpc/rpc.go @@ -114,9 +114,9 @@ func BlockMaxGasFromConsensusParams( // transactions. func FormatBlock( header tmtypes.Header, size int, gasLimit int64, - gasUsed *big.Int, transactions []interface{}, bloom gethcore.Bloom, + gasUsed *big.Int, transactions []any, bloom gethcore.Bloom, validatorAddr gethcommon.Address, baseFee *big.Int, -) map[string]interface{} { +) map[string]any { var transactionsRoot gethcommon.Hash if len(transactions) == 0 { transactionsRoot = gethcore.EmptyRootHash @@ -124,7 +124,7 @@ func FormatBlock( transactionsRoot = gethcommon.BytesToHash(header.DataHash) } - result := map[string]interface{}{ + result := map[string]any{ "number": hexutil.Uint64(header.Height), "hash": hexutil.Bytes(header.Hash()), "parentHash": gethcommon.BytesToHash(header.LastBlockID.Hash.Bytes()), diff --git a/eth/rpc/rpcapi/debugapi/api.go b/eth/rpc/rpcapi/debugapi/api.go index c70673273..7ce3fa345 100644 --- a/eth/rpc/rpcapi/debugapi/api.go +++ b/eth/rpc/rpcapi/debugapi/api.go @@ -65,7 +65,7 @@ func NewImplDebugAPI( // TraceTransaction returns the structured logs created during the execution of EVM // and returns them as a JSON object. -func (a *DebugAPI) TraceTransaction(hash common.Hash, config *evm.TraceConfig) (interface{}, error) { +func (a *DebugAPI) TraceTransaction(hash common.Hash, config *evm.TraceConfig) (any, error) { a.logger.Debug("debug_traceTransaction", "hash", hash) return a.backend.TraceTransaction(hash, config) } @@ -115,7 +115,7 @@ func (a *DebugAPI) TraceCall( args evm.JsonTxArgs, blockNrOrHash rpc.BlockNumberOrHash, config *evm.TraceConfig, -) (interface{}, error) { +) (any, error) { a.logger.Debug("debug_traceCall", args.String(), "block number or hash", blockNrOrHash) // Get Tendermint Block diff --git a/eth/rpc/rpcapi/eth_api.go b/eth/rpc/rpcapi/eth_api.go index 62590347f..3ada30358 100644 --- a/eth/rpc/rpcapi/eth_api.go +++ b/eth/rpc/rpcapi/eth_api.go @@ -30,8 +30,8 @@ type IEthAPI interface { // // Retrieves information from a particular block in the blockchain. BlockNumber() (hexutil.Uint64, error) - GetBlockByNumber(ethBlockNum rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) - GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) + GetBlockByNumber(ethBlockNum rpc.BlockNumber, fullTx bool) (map[string]any, error) + GetBlockByHash(hash common.Hash, fullTx bool) (map[string]any, error) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Uint GetBlockTransactionCountByNumber(blockNum rpc.BlockNumber) *hexutil.Uint @@ -97,15 +97,15 @@ type IEthAPI interface { // and replaced by a canonical block instead. GetUncleByBlockHashAndIndex( hash common.Hash, idx hexutil.Uint, - ) map[string]interface{} + ) map[string]any GetUncleByBlockNumberAndIndex( number, idx hexutil.Uint, - ) map[string]interface{} + ) map[string]any GetUncleCountByBlockHash(hash common.Hash) hexutil.Uint GetUncleCountByBlockNumber(blockNum rpc.BlockNumber) hexutil.Uint // Other - Syncing() (interface{}, error) + Syncing() (any, error) GetTransactionLogs(txHash common.Hash) ([]*gethcore.Log, error) FillTransaction( args evm.JsonTxArgs, @@ -144,13 +144,13 @@ func (e *EthAPI) BlockNumber() (hexutil.Uint64, error) { } // GetBlockByNumber returns the block identified by number. -func (e *EthAPI) GetBlockByNumber(ethBlockNum rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { +func (e *EthAPI) GetBlockByNumber(ethBlockNum rpc.BlockNumber, fullTx bool) (map[string]any, error) { e.logger.Debug("eth_getBlockByNumber", "number", ethBlockNum, "full", fullTx) return e.backend.GetBlockByNumber(ethBlockNum, fullTx) } // GetBlockByHash returns the block identified by hash. -func (e *EthAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) { +func (e *EthAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]any, error) { e.logger.Debug("eth_getBlockByHash", "hash", hash.Hex(), "full", fullTx) return e.backend.GetBlockByHash(hash, fullTx) } @@ -359,7 +359,7 @@ func (e *EthAPI) ChainId() (*hexutil.Big, error) { //nolint // Always returns nil. func (e *EthAPI) GetUncleByBlockHashAndIndex( _ common.Hash, _ hexutil.Uint, -) map[string]interface{} { +) map[string]any { return nil } @@ -367,7 +367,7 @@ func (e *EthAPI) GetUncleByBlockHashAndIndex( // index. Always returns nil. func (e *EthAPI) GetUncleByBlockNumberAndIndex( _, _ hexutil.Uint, -) map[string]interface{} { +) map[string]any { return nil } @@ -396,7 +396,7 @@ func (e *EthAPI) GetUncleCountByBlockNumber(_ rpc.BlockNumber) hexutil.Uint { // - highestBlock: block number of the highest block header this node has received from peers // - pulledStates: number of state entries processed until now // - knownStates: number of known state entries that still need to be pulled -func (e *EthAPI) Syncing() (interface{}, error) { +func (e *EthAPI) Syncing() (any, error) { e.logger.Debug("eth_syncing") return e.backend.Syncing() } diff --git a/eth/rpc/rpcapi/eth_filters_api.go b/eth/rpc/rpcapi/eth_filters_api.go index 782014bb5..eca8dd27c 100644 --- a/eth/rpc/rpcapi/eth_filters_api.go +++ b/eth/rpc/rpcapi/eth_filters_api.go @@ -621,7 +621,7 @@ func (api *FiltersAPI) GetFilterLogs(ctx context.Context, id gethrpc.ID) ([]*get // // This function implements the "eth_getFilterChanges" JSON-RPC service method. // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterchanges -func (api *FiltersAPI) GetFilterChanges(id gethrpc.ID) (interface{}, error) { +func (api *FiltersAPI) GetFilterChanges(id gethrpc.ID) (any, error) { api.logger.Debug("eth_getFilterChanges") api.filtersMu.Lock() defer api.filtersMu.Unlock() diff --git a/eth/rpc/rpcapi/websockets.go b/eth/rpc/rpcapi/websockets.go index 68fb7eb9e..530dd39d7 100644 --- a/eth/rpc/rpcapi/websockets.go +++ b/eth/rpc/rpcapi/websockets.go @@ -41,9 +41,9 @@ type WebsocketsServer interface { } type SubscriptionResponseJSON struct { - Jsonrpc string `json:"jsonrpc"` - Result interface{} `json:"result"` - ID float64 `json:"id"` + Jsonrpc string `json:"jsonrpc"` + Result any `json:"result"` + ID float64 `json:"id"` } type SubscriptionNotification struct { @@ -53,8 +53,8 @@ type SubscriptionNotification struct { } type SubscriptionResult struct { - Subscription gethrpc.ID `json:"subscription"` - Result interface{} `json:"result"` + Subscription gethrpc.ID `json:"subscription"` + Result any `json:"result"` } type ErrorResponseJSON struct { @@ -157,7 +157,7 @@ type wsConn struct { mux *sync.Mutex } -func (w *wsConn) WriteJSON(v interface{}) error { +func (w *wsConn) WriteJSON(v any) error { w.mux.Lock() defer w.mux.Unlock() @@ -203,7 +203,7 @@ func (s *websocketsServer) readLoop(wsConn *wsConn) { continue } - var msg map[string]interface{} + var msg map[string]any if err = json.Unmarshal(mb, &msg); err != nil { s.sendErrResponse(wsConn, err.Error()) continue @@ -299,8 +299,8 @@ func (s *websocketsServer) readLoop(wsConn *wsConn) { } // tcpGetAndSendResponse sends error response to client if params is invalid -func (s *websocketsServer) getParamsAndCheckValid(msg map[string]interface{}, wsConn *wsConn) ([]interface{}, bool) { - params, ok := msg["params"].([]interface{}) +func (s *websocketsServer) getParamsAndCheckValid(msg map[string]any, wsConn *wsConn) ([]any, bool) { + params, ok := msg["params"].([]any) if !ok { s.sendErrResponse(wsConn, "invalid parameters") return nil, false @@ -336,7 +336,7 @@ func (s *websocketsServer) tcpGetAndSendResponse(wsConn *wsConn, mb []byte) erro return errors.Wrap(err, "could not read body from response") } - var wsSend interface{} + var wsSend any err = json.Unmarshal(body, &wsSend) if err != nil { return errors.Wrap(err, "failed to unmarshal rest-server response") @@ -362,7 +362,7 @@ func newPubSubAPI(clientCtx client.Context, logger log.Logger, tmWSClient *rpccl } } -func (api *pubSubAPI) subscribe(wsConn *wsConn, subID gethrpc.ID, params []interface{}) (pubsub.UnsubscribeFunc, error) { +func (api *pubSubAPI) subscribe(wsConn *wsConn, subID gethrpc.ID, params []any) (pubsub.UnsubscribeFunc, error) { method, ok := params[0].(string) if !ok { return nil, errors.New("invalid parameters") @@ -462,11 +462,11 @@ func try(fn func(), l log.Logger, desc string) { fn() } -func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, subID gethrpc.ID, extra interface{}) (pubsub.UnsubscribeFunc, error) { +func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, subID gethrpc.ID, extra any) (pubsub.UnsubscribeFunc, error) { crit := filters.FilterCriteria{} if extra != nil { - params, ok := extra.(map[string]interface{}) + params, ok := extra.(map[string]any) if !ok { err := errors.New("invalid criteria") api.logger.Debug("invalid criteria", "type", fmt.Sprintf("%T", extra)) @@ -475,7 +475,7 @@ func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, subID gethrpc.ID, extra inte if params["address"] != nil { address, isString := params["address"].(string) - addresses, isSlice := params["address"].([]interface{}) + addresses, isSlice := params["address"].([]any) if !isString && !isSlice { err := errors.New("invalid addresses; must be address or array of addresses") api.logger.Debug("invalid addresses", "type", fmt.Sprintf("%T", params["address"])) @@ -502,7 +502,7 @@ func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, subID gethrpc.ID, extra inte } if params["topics"] != nil { - topics, ok := params["topics"].([]interface{}) + topics, ok := params["topics"].([]any) if !ok { err := errors.Errorf("invalid topics: %s", topics) api.logger.Error("invalid topics", "type", fmt.Sprintf("%T", topics)) @@ -511,7 +511,7 @@ func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, subID gethrpc.ID, extra inte crit.Topics = make([][]common.Hash, len(topics)) - addCritTopic := func(topicIdx int, topic interface{}) error { + addCritTopic := func(topicIdx int, topic any) error { tstr, ok := topic.(string) if !ok { err := errors.Errorf("invalid topic: %s", topic) @@ -538,7 +538,7 @@ func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, subID gethrpc.ID, extra inte } // in case we actually have a list of subtopics - subtopicsList, ok := subtopics.([]interface{}) + subtopicsList, ok := subtopics.([]any) if !ok { err := errors.New("invalid subtopics") api.logger.Error("invalid subtopic", "type", fmt.Sprintf("%T", subtopics)) diff --git a/x/common/testutil/nullify.go b/x/common/testutil/nullify.go index 202b59e6f..96fc340f6 100644 --- a/x/common/testutil/nullify.go +++ b/x/common/testutil/nullify.go @@ -16,7 +16,7 @@ var ( // Fill analyze all struct fields and slices with // reflection and initialize the nil and empty slices, // structs, and pointers. -func Fill(x interface{}) interface{} { +func Fill(x any) any { v := reflect.Indirect(reflect.ValueOf(x)) switch v.Kind() { case reflect.Slice: diff --git a/x/common/testutil/testnetwork/logger.go b/x/common/testutil/testnetwork/logger.go index dfdf56d97..7b1206a94 100644 --- a/x/common/testutil/testnetwork/logger.go +++ b/x/common/testutil/testnetwork/logger.go @@ -11,8 +11,8 @@ import ( // Typically, a `testing.T` struct is used as the logger for both the "Network" // and corresponding "Validators". type Logger interface { - Log(args ...interface{}) - Logf(format string, args ...interface{}) + Log(args ...any) + Logf(format string, args ...any) } var _ Logger = (*testing.T)(nil) diff --git a/x/devgas/v1/types/params.go b/x/devgas/v1/types/params.go index 433aa4d43..532436c73 100644 --- a/x/devgas/v1/types/params.go +++ b/x/devgas/v1/types/params.go @@ -28,7 +28,7 @@ func DefaultParams() ModuleParams { } } -func validateBool(i interface{}) error { +func validateBool(i any) error { _, ok := i.(bool) if !ok { return fmt.Errorf("invalid parameter type: %T", i) @@ -37,7 +37,7 @@ func validateBool(i interface{}) error { return nil } -func validateShares(i interface{}) error { +func validateShares(i any) error { v, ok := i.(sdk.Dec) if !ok { @@ -59,7 +59,7 @@ func validateShares(i interface{}) error { return nil } -func validateArray(i interface{}) error { +func validateArray(i any) error { _, ok := i.([]string) if !ok { return fmt.Errorf("invalid parameter type: %T", i) diff --git a/x/epochs/types/identifier.go b/x/epochs/types/identifier.go index 3dd3012cb..714b9dd66 100644 --- a/x/epochs/types/identifier.go +++ b/x/epochs/types/identifier.go @@ -20,7 +20,7 @@ const ( // ValidateEpochIdentifierInterface performs a stateless // validation of the epoch ID interface. -func ValidateEpochIdentifierInterface(i interface{}) error { +func ValidateEpochIdentifierInterface(i any) error { v, ok := i.(string) if !ok { return fmt.Errorf("invalid parameter type: %T", i) diff --git a/x/evm/errors.go b/x/evm/errors.go index 9fc6722ac..87d5c747b 100644 --- a/x/evm/errors.go +++ b/x/evm/errors.go @@ -106,6 +106,6 @@ func (e *RevertError) ErrorCode() int { } // ErrorData returns the hex encoded revert reason. -func (e *RevertError) ErrorData() interface{} { +func (e *RevertError) ErrorData() any { return e.reason } diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 9cc9290e9..4e13254a9 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -736,7 +736,7 @@ func (k *Keeper) TraceEthTxMsg( traceConfig *evm.TraceConfig, commitMessage bool, tracerJSONConfig json.RawMessage, -) (*interface{}, uint, error) { +) (*any, uint, error) { // Assemble the structured logger or the JavaScript tracer var ( tracer tracers.Tracer @@ -805,7 +805,7 @@ func (k *Keeper) TraceEthTxMsg( return nil, 0, grpcstatus.Error(grpccodes.Internal, err.Error()) } - var result interface{} + var result any result, err = tracer.GetResult() if err != nil { return nil, 0, grpcstatus.Error(grpccodes.Internal, err.Error()) diff --git a/x/evm/params.go b/x/evm/params.go index 66d31e035..e0211d0bb 100644 --- a/x/evm/params.go +++ b/x/evm/params.go @@ -35,7 +35,7 @@ func DefaultParams() Params { } // validateChannels checks if channels ids are valid -func validateChannels(i interface{}) error { +func validateChannels(i any) error { channels, ok := i.([]string) if !ok { return fmt.Errorf("invalid parameter type: %T", i) @@ -76,7 +76,7 @@ func (p Params) IsEVMChannel(channel string) bool { return slices.Contains(p.EVMChannels, channel) } -func validateEIPs(i interface{}) error { +func validateEIPs(i any) error { eips, ok := i.([]int64) if !ok { return fmt.Errorf("invalid EIP slice type: %T", i) diff --git a/x/evm/precompile/.gitignore b/x/evm/precompile/.gitignore deleted file mode 100644 index e8c12ff4f..000000000 --- a/x/evm/precompile/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -node_modules -.env - -# Hardhat files -/cache -/artifacts - -# TypeChain files -/typechain -/typechain-types - -# solidity-coverage files -/coverage -/coverage.json - -# Hardhat Ignition default folder for deployments against a local node -ignition/deployments/chain-31337 diff --git a/x/evm/precompile/errors.go b/x/evm/precompile/errors.go index a95989b71..438ffa750 100644 --- a/x/evm/precompile/errors.go +++ b/x/evm/precompile/errors.go @@ -1,7 +1,6 @@ package precompile import ( - "errors" "fmt" "reflect" @@ -9,6 +8,13 @@ import ( "github.com/ethereum/go-ethereum/core/vm" ) +func assertNotReadonlyTx(readOnly bool, method *gethabi.Method) error { + if readOnly { + return fmt.Errorf("method %s cannot be called in a read-only context (e.g. staticcall)", method.Name) + } + return nil +} + // ErrPrecompileRun is error function intended for use in a `defer` pattern, // which modifies the input error in the event that its value becomes non-nil. // This creates a concise way to prepend extra information to the original error. @@ -34,14 +40,6 @@ func ErrMethodCalled(method *gethabi.Method, wrapped error) error { return fmt.Errorf("%s method called: %w", method.Name, wrapped) } -// Check required for transactions but not needed for queries -func assertNotReadonlyTx(readOnly bool, isTx bool) error { - if readOnly && isTx { - return errors.New("cannot write state from staticcall (a read-only call)") - } - return nil -} - // assertContractQuery checks if a contract call is a valid query operation. This // function verifies that no funds (wei) are being sent with the query, as query // operations should be read-only and not involve any value transfer. diff --git a/x/evm/precompile/funtoken.go b/x/evm/precompile/funtoken.go index e9ccaee82..1d50d99ab 100644 --- a/x/evm/precompile/funtoken.go +++ b/x/evm/precompile/funtoken.go @@ -3,7 +3,6 @@ package precompile import ( "fmt" "math/big" - "sync" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" @@ -32,21 +31,19 @@ func (p precompileFunToken) Address() gethcommon.Address { return PrecompileAddr_FunToken } -func (p precompileFunToken) ABI() *gethabi.ABI { - return embeds.SmartContract_FunToken.ABI -} - // RequiredGas calculates the cost of calling the precompile in gas units. func (p precompileFunToken) RequiredGas(input []byte) (gasCost uint64) { - return RequiredGas(input, p.ABI()) + return requiredGas(input, p.ABI()) +} + +func (p precompileFunToken) ABI() *gethabi.ABI { + return embeds.SmartContract_FunToken.ABI } const ( FunTokenMethod_BankSend PrecompileMethod = "bankSend" ) -type PrecompileMethod string - // Run runs the precompiled contract func (p precompileFunToken) Run( evm *vm.EVM, contract *vm.Contract, readonly bool, @@ -54,7 +51,7 @@ func (p precompileFunToken) Run( defer func() { err = ErrPrecompileRun(err, p) }() - start, err := OnRunStart(evm, contract, p.ABI()) + start, err := OnRunStart(evm, contract.Input, p.ABI()) if err != nil { return nil, err } @@ -87,8 +84,6 @@ type precompileFunToken struct { evmKeeper evmkeeper.Keeper } -var executionGuard sync.Mutex - // bankSend: Implements "IFunToken.bankSend" // // The "args" populate the following function signature in Solidity: @@ -105,15 +100,10 @@ func (p precompileFunToken) bankSend( caller gethcommon.Address, readOnly bool, ) (bz []byte, err error) { - ctx, method, args := start.Ctx, start.Method, start.Args - if e := assertNotReadonlyTx(readOnly, true); e != nil { - err = e - return - } - if !executionGuard.TryLock() { - return nil, fmt.Errorf("bankSend is already in progress") + ctx, method, args := start.CacheCtx, start.Method, start.Args + if err := assertNotReadonlyTx(readOnly, method); err != nil { + return nil, err } - defer executionGuard.Unlock() erc20, amount, to, err := p.decomposeBankSendArgs(args) if err != nil { diff --git a/x/evm/precompile/oracle.go b/x/evm/precompile/oracle.go index fb0b2981b..f59b93822 100644 --- a/x/evm/precompile/oracle.go +++ b/x/evm/precompile/oracle.go @@ -24,7 +24,11 @@ func (p precompileOracle) Address() gethcommon.Address { } func (p precompileOracle) RequiredGas(input []byte) (gasPrice uint64) { - return RequiredGas(input, embeds.SmartContract_Oracle.ABI) + return requiredGas(input, p.ABI()) +} + +func (p precompileOracle) ABI() *gethabi.ABI { + return embeds.SmartContract_Oracle.ABI } const ( @@ -38,21 +42,19 @@ func (p precompileOracle) Run( defer func() { err = ErrPrecompileRun(err, p) }() - res, err := OnRunStart(evm, contract, embeds.SmartContract_Oracle.ABI) + startResult, err := OnRunStart(evm, contract.Input, p.ABI()) if err != nil { return nil, err } - method, args, ctx := res.Method, res.Args, res.Ctx + method, args, ctx := startResult.Method, startResult.Args, startResult.CacheCtx switch PrecompileMethod(method.Name) { case OracleMethod_queryExchangeRate: - bz, err = p.queryExchangeRate(ctx, method, args, readonly) + return p.queryExchangeRate(ctx, method, args) default: err = fmt.Errorf("invalid method called with name \"%s\"", method.Name) return } - - return } func PrecompileOracle(keepers keepers.PublicKeepers) vm.PrecompiledContract { @@ -68,10 +70,9 @@ type precompileOracle struct { func (p precompileOracle) queryExchangeRate( ctx sdk.Context, method *gethabi.Method, - args []interface{}, - readOnly bool, + args []any, ) (bz []byte, err error) { - pair, err := p.decomposeQueryExchangeRateArgs(args) + pair, err := p.parseQueryExchangeRateArgs(args) if err != nil { return nil, err } @@ -88,7 +89,7 @@ func (p precompileOracle) queryExchangeRate( return method.Outputs.Pack(price.String()) } -func (p precompileOracle) decomposeQueryExchangeRateArgs(args []any) ( +func (p precompileOracle) parseQueryExchangeRateArgs(args []any) ( pair string, err error, ) { diff --git a/x/evm/precompile/precompile.go b/x/evm/precompile/precompile.go index 40d0c74b4..234a27f4b 100644 --- a/x/evm/precompile/precompile.go +++ b/x/evm/precompile/precompile.go @@ -85,15 +85,15 @@ func methodById(abi *gethabi.ABI, sigdata []byte) (*gethabi.Method, error) { return nil, fmt.Errorf("no method with id: %#x", sigdata[:4]) } -func DecomposeInput( +func decomposeInput( abi *gethabi.ABI, input []byte, -) (method *gethabi.Method, args []interface{}, err error) { +) (method *gethabi.Method, args []any, err error) { // ABI method IDs are exactly 4 bytes according to "gethabi.ABI.MethodByID". if len(input) < 4 { - readableBz := collections.HumanizeBytes(input) - err = fmt.Errorf("input \"%s\" too short to extract method ID (less than 4 bytes)", readableBz) + err = fmt.Errorf("input \"%s\" too short to extract method ID (less than 4 bytes)", collections.HumanizeBytes(input)) return } + method, err = methodById(abi, input[:4]) if err != nil { err = fmt.Errorf("unable to parse ABI method by its 4-byte ID: %w", err) @@ -109,8 +109,8 @@ func DecomposeInput( return method, args, nil } -func RequiredGas(input []byte, abi *gethabi.ABI) uint64 { - method, _, err := DecomposeInput(abi, input) +func requiredGas(input []byte, abi *gethabi.ABI) uint64 { + method, err := methodById(abi, input[:4]) if err != nil { // It's appropriate to return a reasonable default here // because the error from DecomposeInput will be handled automatically by @@ -122,26 +122,27 @@ func RequiredGas(input []byte, abi *gethabi.ABI) uint64 { // Map access could panic. We know that it won't panic because all methods // are in the map, which is verified by unit tests. - methodIsTx := precompileMethodIsTxMap[PrecompileMethod(method.Name)] var costPerByte, costFlat uint64 - if methodIsTx { + if isMutation[PrecompileMethod(method.Name)] { costPerByte, costFlat = gasCfg.WriteCostPerByte, gasCfg.WriteCostFlat } else { costPerByte, costFlat = gasCfg.ReadCostPerByte, gasCfg.ReadCostFlat } - argsBzLen := uint64(len(input[4:])) - return (costPerByte * argsBzLen) + costFlat + // Calculate the total gas required based on the input size and flat cost + return (costPerByte * uint64(len(input[4:]))) + costFlat } +type PrecompileMethod string + type OnRunStartResult struct { // Args contains the decoded (ABI unpacked) arguments passed to the contract // as input. Args []any - // Ctx is a cached SDK context that allows isolated state + // CacheCtx is a cached SDK context that allows isolated state // operations to occur that can be reverted by the EVM's [statedb.StateDB]. - Ctx sdk.Context + CacheCtx sdk.Context // Method is the ABI method for the precompiled contract call. Method *gethabi.Method @@ -178,9 +179,9 @@ type OnRunStartResult struct { // } // ``` func OnRunStart( - evm *vm.EVM, contract *vm.Contract, abi *gethabi.ABI, + evm *vm.EVM, contractInput []byte, abi *gethabi.ABI, ) (res OnRunStartResult, err error) { - method, args, err := DecomposeInput(abi, contract.Input) + method, args, err := decomposeInput(abi, contractInput) if err != nil { return res, err } @@ -194,8 +195,8 @@ func OnRunStart( // journalEntry captures the state before precompile execution to enable // proper state reversal if the call fails or if [statedb.JournalChange] // is reverted in general. - cacheCtx, journalEntry := stateDB.CacheCtxForPrecompile(contract.Address()) - if err = stateDB.SavePrecompileCalledJournalChange(contract.Address(), journalEntry); err != nil { + cacheCtx, journalEntry := stateDB.CacheCtxForPrecompile() + if err = stateDB.SavePrecompileCalledJournalChange(journalEntry); err != nil { return res, err } if err = stateDB.CommitCacheCtx(); err != nil { @@ -203,14 +204,14 @@ func OnRunStart( } return OnRunStartResult{ - Args: args, - Ctx: cacheCtx, - Method: method, - StateDB: stateDB, + Args: args, + CacheCtx: cacheCtx, + Method: method, + StateDB: stateDB, }, nil } -var precompileMethodIsTxMap map[PrecompileMethod]bool = map[PrecompileMethod]bool{ +var isMutation map[PrecompileMethod]bool = map[PrecompileMethod]bool{ WasmMethod_execute: true, WasmMethod_instantiate: true, WasmMethod_executeMulti: true, diff --git a/x/evm/precompile/test/export.go b/x/evm/precompile/test/export.go index 28670e3e0..24700ce85 100644 --- a/x/evm/precompile/test/export.go +++ b/x/evm/precompile/test/export.go @@ -8,20 +8,17 @@ import ( "path" "strings" - serverconfig "github.com/NibiruChain/nibiru/v2/app/server/config" - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasm "github.com/CosmWasm/wasmd/x/wasm/types" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/stretchr/testify/suite" "github.com/NibiruChain/nibiru/v2/app" + serverconfig "github.com/NibiruChain/nibiru/v2/app/server/config" "github.com/NibiruChain/nibiru/v2/x/evm/embeds" "github.com/NibiruChain/nibiru/v2/x/evm/evmtest" "github.com/NibiruChain/nibiru/v2/x/evm/precompile" - "github.com/NibiruChain/nibiru/v2/x/evm/statedb" ) // SetupWasmContracts stores all Wasm bytecode and has the "deps.Sender" @@ -31,68 +28,52 @@ func SetupWasmContracts(deps *evmtest.TestDeps, s *suite.Suite) ( ) { wasmCodes := DeployWasmBytecode(s, deps.Ctx, deps.Sender.NibiruAddr, deps.App) - otherArgs := []struct { - InstMsg []byte - Label string + instantiateArgs := []struct { + InstantiateMsg []byte + Label string }{ { - InstMsg: []byte("{}"), - Label: "https://github.com/NibiruChain/nibiru-wasm/blob/main/contracts/nibi-stargate/src/contract.rs", + InstantiateMsg: []byte("{}"), + Label: "https://github.com/NibiruChain/nibiru-wasm/blob/main/contracts/nibi-stargate/src/contract.rs", }, { - InstMsg: []byte(`{"count": 0}`), - Label: "https://github.com/NibiruChain/nibiru-wasm/tree/ec3ab9f09587a11fbdfbd4021c7617eca3912044/contracts/00-hello-world-counter", + InstantiateMsg: []byte(`{"count": 0}`), + Label: "https://github.com/NibiruChain/nibiru-wasm/tree/ec3ab9f09587a11fbdfbd4021c7617eca3912044/contracts/00-hello-world-counter", }, } - for wasmCodeIdx, wasmCode := range wasmCodes { + for i, wasmCode := range wasmCodes { s.T().Logf("Instantiate using Wasm precompile: %s", wasmCode.binPath) codeId := wasmCode.codeId m := wasm.MsgInstantiateContract{ Admin: "", CodeID: codeId, - Label: otherArgs[wasmCodeIdx].Label, - Msg: otherArgs[wasmCodeIdx].InstMsg, - Funds: []sdk.Coin{}, + Label: instantiateArgs[i].Label, + Msg: instantiateArgs[i].InstantiateMsg, } msgArgsBz, err := json.Marshal(m.Msg) s.NoError(err) - var funds []precompile.WasmBankCoin - fundsJson, err := m.Funds.MarshalJSON() - s.NoErrorf(err, "fundsJson: %s", fundsJson) - err = json.Unmarshal(fundsJson, &funds) - s.Require().NoError(err) - - callArgs := []any{m.Admin, m.CodeID, msgArgsBz, m.Label, funds} + callArgs := []any{m.Admin, m.CodeID, msgArgsBz, m.Label, []precompile.WasmBankCoin{}} input, err := embeds.SmartContract_Wasm.ABI.Pack( string(precompile.WasmMethod_instantiate), callArgs..., ) s.Require().NoError(err) - ethTxResp, evmObj, err := deps.EvmKeeper.CallContractWithInput( + ethTxResp, _, err := deps.EvmKeeper.CallContractWithInput( deps.Ctx, deps.Sender.EthAddr, &precompile.PrecompileAddr_Wasm, true, input, ) s.Require().NoError(err) s.Require().NotEmpty(ethTxResp.Ret) - // Finalize transaction - err = evmObj.StateDB.(*statedb.StateDB).Commit() - s.Require().NoError(err) - s.T().Log("Parse the response contract addr and response bytes") - var contractAddrStr string - var data []byte - err = embeds.SmartContract_Wasm.ABI.UnpackIntoInterface( - &[]any{&contractAddrStr, &data}, - string(precompile.WasmMethod_instantiate), - ethTxResp.Ret, - ) + vals, err := embeds.SmartContract_Wasm.ABI.Unpack(string(precompile.WasmMethod_instantiate), ethTxResp.Ret) s.Require().NoError(err) - contractAddr, err := sdk.AccAddressFromBech32(contractAddrStr) + + contractAddr, err := sdk.AccAddressFromBech32(vals[0].(string)) s.NoError(err) contracts = append(contracts, contractAddr) } @@ -118,7 +99,7 @@ func DeployWasmBytecode( rootPathBz, err := exec.Command("go", "list", "-m", "-f", "{{.Dir}}").Output() s.Require().NoError(err) rootPath := strings.Trim(string(rootPathBz), "\n") - for _, pathToWasmBin := range []string{ + for _, wasmFile := range []string{ // nibi_stargate.wasm is a compiled version of: // https://github.com/NibiruChain/nibiru-wasm/blob/main/contracts/nibi-stargate/src/contract.rs "x/tokenfactory/fixture/nibi_stargate.wasm", @@ -129,11 +110,11 @@ func DeployWasmBytecode( // Add other wasm bytecode here if needed... } { - pathToWasmBin = path.Join(string(rootPath), pathToWasmBin) - wasmBytecode, err := os.ReadFile(pathToWasmBin) + binPath := path.Join(rootPath, wasmFile) + wasmBytecode, err := os.ReadFile(binPath) s.Require().NoErrorf( err, - "rootPath %s, pathToWasmBin %s", rootPath, pathToWasmBin, + "path %s, pathToWasmBin %s", binPath, ) // The "Create" fn is private on the nibiru.WasmKeeper. By placing it as the @@ -150,7 +131,7 @@ func DeployWasmBytecode( codeIds = append(codeIds, struct { codeId uint64 binPath string - }{codeId, pathToWasmBin}) + }{codeId, binPath}) } return codeIds diff --git a/x/evm/precompile/wasm.go b/x/evm/precompile/wasm.go index f19511cb9..cddfc488e 100644 --- a/x/evm/precompile/wasm.go +++ b/x/evm/precompile/wasm.go @@ -37,27 +37,26 @@ func (p precompileWasm) Run( defer func() { err = ErrPrecompileRun(err, p) }() - start, err := OnRunStart(evm, contract, p.ABI()) + startResult, err := OnRunStart(evm, contract.Input, p.ABI()) if err != nil { return nil, err } - method := start.Method - switch PrecompileMethod(method.Name) { + switch PrecompileMethod(startResult.Method.Name) { case WasmMethod_execute: - bz, err = p.execute(start, contract.CallerAddress, readonly) + bz, err = p.execute(startResult, contract.CallerAddress, readonly) case WasmMethod_query: - bz, err = p.query(start, contract) + bz, err = p.query(startResult, contract) case WasmMethod_instantiate: - bz, err = p.instantiate(start, contract.CallerAddress, readonly) + bz, err = p.instantiate(startResult, contract.CallerAddress, readonly) case WasmMethod_executeMulti: - bz, err = p.executeMulti(start, contract.CallerAddress, readonly) + bz, err = p.executeMulti(startResult, contract.CallerAddress, readonly) case WasmMethod_queryRaw: - bz, err = p.queryRaw(start, contract) + bz, err = p.queryRaw(startResult, contract) default: // Note that this code path should be impossible to reach since // "DecomposeInput" parses methods directly from the ABI. - err = fmt.Errorf("invalid method called with name \"%s\"", method.Name) + err = fmt.Errorf("invalid method called with name \"%s\"", startResult.Method.Name) return } if err != nil { @@ -74,13 +73,13 @@ func (p precompileWasm) Address() gethcommon.Address { return PrecompileAddr_Wasm } -func (p precompileWasm) ABI() *gethabi.ABI { - return embeds.SmartContract_Wasm.ABI -} - // RequiredGas calculates the cost of calling the precompile in gas units. func (p precompileWasm) RequiredGas(input []byte) (gasCost uint64) { - return RequiredGas(input, p.ABI()) + return requiredGas(input, p.ABI()) +} + +func (p precompileWasm) ABI() *gethabi.ABI { + return embeds.SmartContract_Wasm.ABI } // Wasm: A struct embedding keepers for read and write operations in Wasm, such @@ -123,23 +122,22 @@ func (p precompileWasm) execute( caller gethcommon.Address, readOnly bool, ) (bz []byte, err error) { - method, args, ctx := start.Method, start.Args, start.Ctx + method, args, ctx := start.Method, start.Args, start.CacheCtx defer func() { if err != nil { err = ErrMethodCalled(method, err) } }() - - if err := assertNotReadonlyTx(readOnly, true); err != nil { - return bz, err + if err := assertNotReadonlyTx(readOnly, method); err != nil { + return nil, err } - wasmContract, msgArgs, funds, err := p.parseExecuteArgs(args) + + wasmContract, msgArgsBz, funds, err := p.parseExecuteArgs(args) if err != nil { err = ErrInvalidArgs(err) return } - callerBech32 := eth.EthAddrToNibiruAddr(caller) - data, err := p.Wasm.Execute(ctx, wasmContract, callerBech32, msgArgs, funds) + data, err := p.Wasm.Execute(ctx, wasmContract, eth.EthAddrToNibiruAddr(caller), msgArgsBz, funds) if err != nil { return } @@ -162,7 +160,7 @@ func (p precompileWasm) query( start OnRunStartResult, contract *vm.Contract, ) (bz []byte, err error) { - method, args, ctx := start.Method, start.Args, start.Ctx + method, args, ctx := start.Method, start.Args, start.CacheCtx defer func() { if err != nil { err = ErrMethodCalled(method, err) @@ -171,6 +169,7 @@ func (p precompileWasm) query( if err := assertContractQuery(contract); err != nil { return bz, err } + wasmContract, req, err := p.parseQueryArgs(args) if err != nil { err = ErrInvalidArgs(err) @@ -207,14 +206,14 @@ func (p precompileWasm) instantiate( caller gethcommon.Address, readOnly bool, ) (bz []byte, err error) { - method, args, ctx := start.Method, start.Args, start.Ctx + method, args, ctx := start.Method, start.Args, start.CacheCtx defer func() { if err != nil { err = ErrMethodCalled(method, err) } }() - if err := assertNotReadonlyTx(readOnly, true); err != nil { - return bz, err + if err := assertNotReadonlyTx(readOnly, method); err != nil { + return nil, err } callerBech32 := eth.EthAddrToNibiruAddr(caller) @@ -258,14 +257,14 @@ func (p precompileWasm) executeMulti( caller gethcommon.Address, readOnly bool, ) (bz []byte, err error) { - method, args, ctx := start.Method, start.Args, start.Ctx + method, args, ctx := start.Method, start.Args, start.CacheCtx defer func() { if err != nil { err = ErrMethodCalled(method, err) } }() - if err := assertNotReadonlyTx(readOnly, true); err != nil { - return bz, err + if err := assertNotReadonlyTx(readOnly, method); err != nil { + return nil, err } wasmExecMsgs, err := p.parseExecuteMultiArgs(args) @@ -327,7 +326,7 @@ func (p precompileWasm) queryRaw( start OnRunStartResult, contract *vm.Contract, ) (bz []byte, err error) { - method, args, ctx := start.Method, start.Args, start.Ctx + method, args, ctx := start.Method, start.Args, start.CacheCtx defer func() { if err != nil { err = ErrMethodCalled(method, err) diff --git a/x/evm/precompile/wasm_parse.go b/x/evm/precompile/wasm_parse.go index 80d950622..97a532753 100644 --- a/x/evm/precompile/wasm_parse.go +++ b/x/evm/precompile/wasm_parse.go @@ -16,51 +16,38 @@ type WasmBankCoin struct { Amount *big.Int `json:"amount"` } -func parseSdkCoins(unparsed []struct { - Denom string `json:"denom"` - Amount *big.Int `json:"amount"` -}, -) sdk.Coins { - parsed := sdk.Coins{} - for _, coin := range unparsed { - parsed = append( - parsed, - // Favor the sdk.Coin constructor over sdk.NewCoin because sdk.NewCoin - // is not panic-safe. Validation will be handled when the coin is used - // as an argument during the execution of a transaction. - sdk.Coin{ - Denom: coin.Denom, - Amount: sdk.NewIntFromBigInt(coin.Amount), - }, - ) - } - return parsed -} - // Parses [sdk.Coins] from a "BankCoin[]" solidity argument: // // ```solidity // BankCoin[] memory funds // ``` func parseFundsArg(arg any) (funds sdk.Coins, err error) { - bankCoinsUnparsed, ok := arg.([]struct { + if arg == nil { + return funds, nil + } + + raw, ok := arg.([]struct { Denom string `json:"denom"` Amount *big.Int `json:"amount"` }) - switch { - case arg == nil: - bankCoinsUnparsed = []struct { - Denom string `json:"denom"` - Amount *big.Int `json:"amount"` - }{} - case !ok: - err = ErrArgTypeValidation("BankCoin[] funds", arg) - return - case ok: - // Type assertion succeeded + + if !ok { + return funds, ErrArgTypeValidation("BankCoin[] funds", arg) } - funds = parseSdkCoins(bankCoinsUnparsed) - return + + for _, coin := range raw { + funds = append( + funds, + // Favor the sdk.Coin constructor over sdk.NewCoin because sdk.NewCoin + // is not panic-safe. Validation will be handled when the coin is used + // as an argument during the execution of a transaction. + sdk.Coin{ + Denom: coin.Denom, + Amount: sdk.NewIntFromBigInt(coin.Amount), + }, + ) + } + return funds, nil } // Parses [sdk.AccAddress] from a "string" solidity argument: @@ -148,6 +135,7 @@ func (p precompileWasm) parseExecuteArgs(args []any) ( return } + // contract address argIdx := 0 contractAddrStr, ok := args[argIdx].(string) if !ok { @@ -162,6 +150,7 @@ func (p precompileWasm) parseExecuteArgs(args []any) ( return } + // msg args argIdx++ msgArgs, ok = args[argIdx].([]byte) if !ok { @@ -174,6 +163,7 @@ func (p precompileWasm) parseExecuteArgs(args []any) ( return } + // funds argIdx++ funds, e := parseFundsArg(args[argIdx]) if e != nil { @@ -202,7 +192,11 @@ func (p precompileWasm) parseQueryArgs(args []any) ( } argsIdx++ - reqBz := args[argsIdx].([]byte) + reqBz, ok := args[argsIdx].([]byte) + if !ok { + err = ErrArgTypeValidation("bytes req", args[argsIdx]) + return + } req = wasm.RawContractMessage(reqBz) if e := req.ValidateBasic(); e != nil { err = e diff --git a/x/evm/statedb/journal_test.go b/x/evm/statedb/journal_test.go index 6390b640f..c1c74110c 100644 --- a/x/evm/statedb/journal_test.go +++ b/x/evm/statedb/journal_test.go @@ -31,13 +31,12 @@ func (s *Suite) TestComplexJournalChanges() { )) s.T().Log("Set up helloworldcounter.wasm") - - wasmContract := test.SetupWasmContracts(&deps, &s.Suite)[1] - fmt.Printf("wasmContract: %s\n", wasmContract) + helloWorldCounterWasm := test.SetupWasmContracts(&deps, &s.Suite)[1] + fmt.Printf("wasmContract: %s\n", helloWorldCounterWasm) s.T().Log("Assert before transition") test.AssertWasmCounterState( - &s.Suite, deps, wasmContract, 0, + &s.Suite, deps, helloWorldCounterWasm, 0, ) deployArgs := []any{"name", "SYMBOL", uint8(18)} @@ -129,11 +128,11 @@ func (s *Suite) TestComplexJournalChanges() { s.T().Log("commitEvmTx=true, expect 0 dirty journal entries") commitEvmTx := true evmObj = test.IncrementWasmCounterWithExecuteMulti( - &s.Suite, &deps, wasmContract, 7, commitEvmTx, + &s.Suite, &deps, helloWorldCounterWasm, 7, commitEvmTx, ) // assertions after run test.AssertWasmCounterState( - &s.Suite, deps, wasmContract, 7, + &s.Suite, deps, helloWorldCounterWasm, 7, ) stateDB, ok := evmObj.StateDB.(*statedb.StateDB) s.Require().True(ok, "error retrieving StateDB from the EVM") @@ -145,7 +144,7 @@ func (s *Suite) TestComplexJournalChanges() { s.T().Log("commitEvmTx=false, expect dirty journal entries") commitEvmTx = false evmObj = test.IncrementWasmCounterWithExecuteMulti( - &s.Suite, &deps, wasmContract, 5, commitEvmTx, + &s.Suite, &deps, helloWorldCounterWasm, 5, commitEvmTx, ) stateDB, ok = evmObj.StateDB.(*statedb.StateDB) s.Require().True(ok, "error retrieving StateDB from the EVM") @@ -158,7 +157,7 @@ func (s *Suite) TestComplexJournalChanges() { s.T().Log("Expect no change since the StateDB has not been committed") test.AssertWasmCounterState( - &s.Suite, deps, wasmContract, 7, // 7 = 7 + 0 + &s.Suite, deps, helloWorldCounterWasm, 7, // 7 = 7 + 0 ) s.T().Log("Expect change to persist on the StateDB cacheCtx") @@ -166,14 +165,14 @@ func (s *Suite) TestComplexJournalChanges() { s.NotNil(cacheCtx) deps.Ctx = *cacheCtx test.AssertWasmCounterState( - &s.Suite, deps, wasmContract, 12, // 12 = 7 + 5 + &s.Suite, deps, helloWorldCounterWasm, 12, // 12 = 7 + 5 ) // NOTE: that the [StateDB.Commit] fn has not been called yet. We're still // mid-transaction. s.T().Log("EVM revert operation should bring about the old state") err = test.IncrementWasmCounterWithExecuteMultiViaVMCall( - &s.Suite, &deps, wasmContract, 50, commitEvmTx, evmObj, + &s.Suite, &deps, helloWorldCounterWasm, 50, commitEvmTx, evmObj, ) stateDBPtr := evmObj.StateDB.(*statedb.StateDB) s.Require().Equal(stateDB, stateDBPtr) @@ -185,7 +184,7 @@ snapshots and see the prior states.`)) cacheCtx = stateDB.GetCacheContext() deps.Ctx = *cacheCtx test.AssertWasmCounterState( - &s.Suite, deps, wasmContract, 7+5+50, + &s.Suite, deps, helloWorldCounterWasm, 7+5+50, ) errFn := common.TryCatch(func() { @@ -201,7 +200,7 @@ snapshots and see the prior states.`)) s.NotNil(cacheCtx) deps.Ctx = *cacheCtx test.AssertWasmCounterState( - &s.Suite, deps, wasmContract, 7+5, + &s.Suite, deps, helloWorldCounterWasm, 7+5, ) stateDB.RevertToSnapshot(0) @@ -209,13 +208,13 @@ snapshots and see the prior states.`)) s.NotNil(cacheCtx) deps.Ctx = *cacheCtx test.AssertWasmCounterState( - &s.Suite, deps, wasmContract, 7, // state before precompile called + &s.Suite, deps, helloWorldCounterWasm, 7, // state before precompile called ) err = stateDB.Commit() deps.Ctx = stateDB.GetEvmTxContext() test.AssertWasmCounterState( - &s.Suite, deps, wasmContract, 7, // state before precompile called + &s.Suite, deps, helloWorldCounterWasm, 7, // state before precompile called ) }) } diff --git a/x/evm/statedb/statedb.go b/x/evm/statedb/statedb.go index a411660f9..4e93b127a 100644 --- a/x/evm/statedb/statedb.go +++ b/x/evm/statedb/statedb.go @@ -569,7 +569,7 @@ func (s *StateDB) commitCtx(ctx sdk.Context) error { return nil } -func (s *StateDB) CacheCtxForPrecompile(precompileAddr common.Address) ( +func (s *StateDB) CacheCtxForPrecompile() ( sdk.Context, PrecompileCalled, ) { if s.writeToCommitCtxFromCacheCtx == nil { @@ -590,15 +590,14 @@ func (s *StateDB) CacheCtxForPrecompile(precompileAddr common.Address) ( // // See [PrecompileCalled] for more info. func (s *StateDB) SavePrecompileCalledJournalChange( - precompileAddr common.Address, journalChange PrecompileCalled, ) error { s.Journal.append(journalChange) s.multistoreCacheCount++ if s.multistoreCacheCount > maxMultistoreCacheCount { return fmt.Errorf( - "exceeded maximum number Nibiru-specific precompiled contract calls in one transaction (%d). Called address %s", - maxMultistoreCacheCount, precompileAddr.Hex(), + "exceeded maximum number Nibiru-specific precompiled contract calls in one transaction (%d).", + maxMultistoreCacheCount, ) } return nil diff --git a/x/evm/vmtracer.go b/x/evm/vmtracer.go index 2a20f2b01..2078bdfe7 100644 --- a/x/evm/vmtracer.go +++ b/x/evm/vmtracer.go @@ -51,8 +51,8 @@ func NewTracer(tracer string, msg core.Message, cfg *params.ChainConfig, height // TxTraceResult is the result of a single transaction trace during a block trace. type TxTraceResult struct { - Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer - Error string `json:"error,omitempty"` // Trace failure produced by the tracer + Result any `json:"result,omitempty"` // Trace results produced by the tracer + Error string `json:"error,omitempty"` // Trace failure produced by the tracer } var _ vm.EVMLogger = &NoOpTracer{} diff --git a/x/inflation/types/params.go b/x/inflation/types/params.go index 1ca46623b..6b95bbb7c 100644 --- a/x/inflation/types/params.go +++ b/x/inflation/types/params.go @@ -71,7 +71,7 @@ func DefaultParams() Params { } } -func validatePolynomialFactors(i interface{}) error { +func validatePolynomialFactors(i any) error { v, ok := i.([]sdk.Dec) if !ok { return fmt.Errorf("invalid parameter type: %T", i) @@ -83,7 +83,7 @@ func validatePolynomialFactors(i interface{}) error { return nil } -func validateInflationDistribution(i interface{}) error { +func validateInflationDistribution(i any) error { v, ok := i.(InflationDistribution) if !ok { return fmt.Errorf("invalid parameter type: %T", i) @@ -109,7 +109,7 @@ func validateInflationDistribution(i interface{}) error { return nil } -func validateBool(i interface{}) error { +func validateBool(i any) error { _, ok := i.(bool) if !ok { return fmt.Errorf("invalid parameter type: %T", i) @@ -118,7 +118,7 @@ func validateBool(i interface{}) error { return nil } -func validateUint64(i interface{}) error { +func validateUint64(i any) error { _, ok := i.(uint64) if !ok { return fmt.Errorf("invalid genesis state type: %T", i) @@ -126,7 +126,7 @@ func validateUint64(i interface{}) error { return nil } -func validateEpochsPerPeriod(i interface{}) error { +func validateEpochsPerPeriod(i any) error { val, ok := i.(uint64) if !ok { return fmt.Errorf("invalid parameter type: %T", i) @@ -139,7 +139,7 @@ func validateEpochsPerPeriod(i interface{}) error { return nil } -func validatePeriodsPerYear(i interface{}) error { +func validatePeriodsPerYear(i any) error { val, ok := i.(uint64) if !ok { return fmt.Errorf("invalid parameter type: %T", i) diff --git a/x/oracle/types/hash.go b/x/oracle/types/hash.go index b9d816ecc..a828a6414 100644 --- a/x/oracle/types/hash.go +++ b/x/oracle/types/hash.go @@ -99,7 +99,7 @@ func (h AggregateVoteHash) MarshalJSON() ([]byte, error) { } // MarshalYAML marshals to YAML using Bech32. -func (h AggregateVoteHash) MarshalYAML() (interface{}, error) { +func (h AggregateVoteHash) MarshalYAML() (any, error) { return h.String(), nil } diff --git a/x/tokenfactory/types/codec.go b/x/tokenfactory/types/codec.go index e0e639c0d..c20e55ad4 100644 --- a/x/tokenfactory/types/codec.go +++ b/x/tokenfactory/types/codec.go @@ -58,7 +58,7 @@ func TX_MSG_TYPE_URLS() []string { // Amino JSON serialization and EIP-712 compatibility. func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { for _, ele := range []struct { - MsgType interface{} + MsgType any Name string }{ {&MsgCreateDenom{}, "nibiru/tokenfactory/create-denom"},