From 0ef4099439681bfd2b352075ec2f60b68e555208 Mon Sep 17 00:00:00 2001 From: Oleg Nikonychev Date: Mon, 20 Jan 2025 21:45:59 +0400 Subject: [PATCH] fix(evm): added tx logs events to the funtoken related txs (#2161) * fix: added tx logs emitting to the funtoken related txs * chore: changelog update * chore: lint * chore: debug failing integration test * fix: removed tx index updating for non eth txs * fix: tests --------- Co-authored-by: Unique Divine <51418232+Unique-Divine@users.noreply.github.com> Co-authored-by: Kevin Yang <5478483+k-yang@users.noreply.github.com> --- CHANGELOG.md | 1 + eth/rpc/backend/backend_suite_test.go | 2 +- eth/rpc/backend/gas_used_test.go | 18 +- eth/rpc/backend/tx_logs_test.go | 299 +++++++++++++++++++++++ eth/rpc/backend/utils_test.go | 18 +- x/common/testutil/testnetwork/tx.go | 15 +- x/common/testutil/testnetwork/tx_test.go | 2 +- x/evm/evmtest/tx.go | 4 +- x/evm/keeper/call_contract.go | 11 +- x/evm/keeper/grpc_query_test.go | 4 +- x/oracle/keeper/app_test.go | 4 +- 11 files changed, 345 insertions(+), 33 deletions(-) create mode 100644 eth/rpc/backend/tx_logs_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index b26df9fe1..7eaf068de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ needed to include double quotes around the hexadecimal string. - [#2156](https://github.com/NibiruChain/nibiru/pull/2156) - test(evm-e2e): add E2E test using the Nibiru Oracle's ChainLink impl - [#2157](https://github.com/NibiruChain/nibiru/pull/2157) - fix(evm): Fix unit inconsistency related to AuthInfo.Fee and txData.Fee using effective fee - [#2160](https://github.com/NibiruChain/nibiru/pull/2160) - fix(evm-precompile): use bank.MsgServer Send in precompile IFunToken.bankMsgSend +- [#2161](https://github.com/NibiruChain/nibiru/pull/2161) - fix(evm): added tx logs events to the funtoken related txs - [#2162](https://github.com/NibiruChain/nibiru/pull/2162) - test(testutil): try retrying for 'panic: pebbledb: closed' - [#2167](https://github.com/NibiruChain/nibiru/pull/2167) - refactor(evm): removed blockGasUsed transient variable - [#2168](https://github.com/NibiruChain/nibiru/pull/2168) - chore(evm-solidity): Move unrelated docs, gen-embeds, and add Solidity docs diff --git a/eth/rpc/backend/backend_suite_test.go b/eth/rpc/backend/backend_suite_test.go index dec06920f..16637a86c 100644 --- a/eth/rpc/backend/backend_suite_test.go +++ b/eth/rpc/backend/backend_suite_test.go @@ -252,7 +252,7 @@ func (s *BackendSuite) buildContractCallTx( nonce uint64, gasLimit uint64, ) gethcore.Transaction { - // recipient := crypto.CreateAddress(s.fundedAccEthAddr, 29381) + //recipient := crypto.CreateAddress(s.fundedAccEthAddr, 29381) transferAmount := big.NewInt(100) packedArgs, err := embeds.SmartContract_TestERC20.ABI.Pack( diff --git a/eth/rpc/backend/gas_used_test.go b/eth/rpc/backend/gas_used_test.go index 0ad3ed0c3..8362d599f 100644 --- a/eth/rpc/backend/gas_used_test.go +++ b/eth/rpc/backend/gas_used_test.go @@ -76,10 +76,10 @@ func (s *BackendSuite) TestGasUsedFunTokens() { erc20Addr, err := eth.NewEIP55AddrFromStr(testContractAddress.String()) s.Require().NoError(err) - _, err = s.backend.GetTransactionCount(s.fundedAccEthAddr, rpc.EthPendingBlockNumber) - s.Require().NoError(err) + nonce := s.getCurrentNonce(s.node.EthAddress) + balanceBefore := s.getUnibiBalance(s.fundedAccEthAddr) - txResp, err := s.network.BroadcastMsgs(s.node.Address, &evm.MsgCreateFunToken{ + txResp, err := s.network.BroadcastMsgs(s.node.Address, &nonce, &evm.MsgCreateFunToken{ Sender: s.node.Address.String(), FromErc20: &erc20Addr, }) @@ -96,15 +96,11 @@ func (s *BackendSuite) TestGasUsedFunTokens() { ) s.Require().NoError(err) - nonce, err := s.backend.GetTransactionCount(s.fundedAccEthAddr, rpc.EthPendingBlockNumber) - s.Require().NoError(err) - - balanceBefore := s.getUnibiBalance(s.fundedAccEthAddr) - + nonce = s.getCurrentNonce(s.fundedAccEthAddr) txHash1 := SendTransaction( s, &gethcore.LegacyTx{ - Nonce: uint64(*nonce), + Nonce: nonce, To: &precompile.PrecompileAddr_FunToken, Data: packedArgsPass, Gas: 1_500_000, @@ -123,7 +119,7 @@ func (s *BackendSuite) TestGasUsedFunTokens() { txHash2 := SendTransaction( // should fail due to invalid recipient address s, &gethcore.LegacyTx{ - Nonce: uint64(*nonce + 1), + Nonce: nonce + 1, To: &precompile.PrecompileAddr_FunToken, Data: packedArgsFail, Gas: 1_500_000, @@ -134,7 +130,7 @@ func (s *BackendSuite) TestGasUsedFunTokens() { txHash3 := SendTransaction( s, &gethcore.LegacyTx{ - Nonce: uint64(*nonce + 2), + Nonce: nonce + 2, To: &precompile.PrecompileAddr_FunToken, Data: packedArgsPass, Gas: 1_500_000, diff --git a/eth/rpc/backend/tx_logs_test.go b/eth/rpc/backend/tx_logs_test.go new file mode 100644 index 000000000..6bd1132cf --- /dev/null +++ b/eth/rpc/backend/tx_logs_test.go @@ -0,0 +1,299 @@ +package backend_test + +import ( + "fmt" + "math/big" + + tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" + sdk "github.com/cosmos/cosmos-sdk/types" + gethcommon "github.com/ethereum/go-ethereum/common" + gethcore "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/NibiruChain/nibiru/v2/eth" + "github.com/NibiruChain/nibiru/v2/eth/rpc/backend" + "github.com/NibiruChain/nibiru/v2/x/common/testutil" + "github.com/NibiruChain/nibiru/v2/x/evm" + "github.com/NibiruChain/nibiru/v2/x/evm/embeds" + "github.com/NibiruChain/nibiru/v2/x/evm/evmtest" + "github.com/NibiruChain/nibiru/v2/x/evm/precompile" +) + +// TestEthLogs checks that eth txs as well as funtoken txs produce tx_logs events and update tx index properly. +// To check that, we send a series of transactions: +// - 1: simple eth transfer +// - 2: deploying erc20 contract +// - 3. creating funtoken from erc20 +// - 4: creating funtoken from coin +// - 5. converting coin to erc20 +// - 6. converting erc20 born token to coin via precompile +// Each tx should emit some tx logs and emit proper tx index within ethereum tx event. +func (s *BackendSuite) TestLogs() { + // Test is broadcasting txs. Lock to avoid nonce conflicts. + testMutex.Lock() + defer testMutex.Unlock() + + // Start with fresh block + s.Require().NoError(s.network.WaitForNextBlock()) + + s.T().Log("TX1: Send simple nibi transfer") + randomEthAddr := evmtest.NewEthPrivAcc().EthAddr + txHashFirst := s.SendNibiViaEthTransfer(randomEthAddr, amountToSend, false) + + s.T().Log("TX2: Deploy ERC20 contract") + _, erc20ContractAddr := s.DeployTestContract(false) + erc20Addr, _ := eth.NewEIP55AddrFromStr(erc20ContractAddr.String()) + + s.T().Log("TX3: Create FunToken from ERC20") + nonce := s.getCurrentNonce(eth.NibiruAddrToEthAddr(s.node.Address)) + txResp, err := s.network.BroadcastMsgs(s.node.Address, &nonce, &evm.MsgCreateFunToken{ + Sender: s.node.Address.String(), + FromErc20: &erc20Addr, + }) + s.Require().NoError(err) + s.Require().NotNil(txResp) + s.Require().Equal( + uint32(0), + txResp.Code, + fmt.Sprintf("Failed to create FunToken from ERC20. RawLog: %s", txResp.RawLog), + ) + + s.T().Log("TX4: Create FunToken from unibi coin") + nonce++ + erc20FromCoinAddr := crypto.CreateAddress(evm.EVM_MODULE_ADDRESS, s.getCurrentNonce(evm.EVM_MODULE_ADDRESS)+1) + + txResp, err = s.network.BroadcastMsgs(s.node.Address, &nonce, &evm.MsgCreateFunToken{ + Sender: s.node.Address.String(), + FromBankDenom: evm.EVMBankDenom, + }) + s.Require().NoError(err) + s.Require().NotNil(txResp) + s.Require().Equal( + uint32(0), + txResp.Code, + fmt.Sprintf("Failed to create FunToken from unibi coin. RawLog: %s", txResp.RawLog), + ) + + s.T().Log("TX5: Convert coin to EVM") + nonce++ + txResp, err = s.network.BroadcastMsgs(s.node.Address, &nonce, &evm.MsgConvertCoinToEvm{ + Sender: s.node.Address.String(), + BankCoin: sdk.NewCoin(evm.EVMBankDenom, sdk.NewInt(1)), + ToEthAddr: eth.EIP55Addr{ + Address: s.fundedAccEthAddr, + }, + }) + s.Require().NoError(err) + s.Require().NotNil(txResp) + s.Require().Equal( + uint32(0), + txResp.Code, + fmt.Sprintf("Failed converting coin to evm. RawLog: %s", txResp.RawLog), + ) + + s.T().Log("TX6: Send erc20 token to coin using precompile") + randomNibiAddress := testutil.AccAddress() + packedArgsPass, err := embeds.SmartContract_FunToken.ABI.Pack( + "sendToBank", + erc20Addr.Address, + big.NewInt(1), + randomNibiAddress.String(), + ) + s.Require().NoError(err) + txHashLast := SendTransaction( + s, + &gethcore.LegacyTx{ + Nonce: s.getCurrentNonce(s.fundedAccEthAddr), + To: &precompile.PrecompileAddr_FunToken, + Data: packedArgsPass, + Gas: 1_500_000, + GasPrice: big.NewInt(1), + }, + false, + ) + + // Wait for all txs to be included in a block + blockNumFirstTx, _, _ := WaitForReceipt(s, txHashFirst) + blockNumLastTx, _, _ := WaitForReceipt(s, txHashLast) + s.Require().NotNil(blockNumFirstTx) + s.Require().NotNil(blockNumLastTx) + + // Check tx logs for each tx + type logsCheck struct { + txInfo string + logs []*gethcore.Log + expectEthTx bool + } + checks := []logsCheck{ + { + txInfo: "TX1 - simple eth transfer, should have empty logs", + logs: nil, + expectEthTx: true, + }, + { + txInfo: "TX2 - deploying erc20 contract, should have logs", + logs: []*gethcore.Log{ + // minting initial balance to the account + { + Address: erc20ContractAddr, + Topics: []gethcommon.Hash{ + crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")), + gethcommon.Address{}.Hash(), + s.fundedAccEthAddr.Hash(), + }, + }, + }, + expectEthTx: true, + }, + { + txInfo: "TX3 - create FunToken from ERC20, no eth tx, no logs", + logs: nil, + expectEthTx: false, + }, + { + txInfo: "TX4 - create FunToken from unibi coin, no eth tx, logs for contract deployment", + logs: []*gethcore.Log{ + // contract ownership to evm module + { + Address: erc20FromCoinAddr, + Topics: []gethcommon.Hash{ + crypto.Keccak256Hash([]byte("OwnershipTransferred(address,address)")), + gethcommon.Address{}.Hash(), + evm.EVM_MODULE_ADDRESS.Hash(), + }, + }, + }, + expectEthTx: false, + }, + { + txInfo: "TX5 - Convert coin to EVM, no eth tx, logs for minting tokens to the account", + logs: []*gethcore.Log{ + // minting to the account + { + Address: erc20FromCoinAddr, + Topics: []gethcommon.Hash{ + crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")), + gethcommon.Address{}.Hash(), + s.fundedAccEthAddr.Hash(), + }, + }, + }, + expectEthTx: false, + }, + { + txInfo: "TX6 - Send erc20 token to coin using precompile, eth tx, logs for transferring tokens to evm module", + logs: []*gethcore.Log{ + // transfer from account to evm module + { + Address: erc20ContractAddr, + Topics: []gethcommon.Hash{ + crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")), + s.fundedAccEthAddr.Hash(), + evm.EVM_MODULE_ADDRESS.Hash(), + }, + }, + }, + expectEthTx: true, + }, + } + + // Getting block results. Note: txs could be included in more than one block + blockNumber := blockNumFirstTx.Int64() + blockRes, err := s.backend.TendermintBlockResultByNumber(&blockNumber) + s.Require().NoError(err) + s.Require().NotNil(blockRes) + txIndex := 0 + ethTxIndex := 0 + for idx, check := range checks { + if txIndex+1 > len(blockRes.TxsResults) { + blockNumber++ + if blockNumber > blockNumLastTx.Int64() { + s.Fail("TX %d not found in block results", idx) + } + txIndex = 0 + ethTxIndex = 0 + blockRes, err = s.backend.TendermintBlockResultByNumber(&blockNumber) + s.Require().NoError(err) + s.Require().NotNil(blockRes) + } + s.assertTxLogsAndTxIndex(blockRes, txIndex, ethTxIndex, check.logs, check.expectEthTx, check.txInfo) + txIndex++ + if check.expectEthTx { + ethTxIndex++ + } + } +} + +// assertTxLogsAndTxIndex gets tx results from the block and checks tx logs and tx index. +func (s *BackendSuite) assertTxLogsAndTxIndex( + blockRes *tmrpctypes.ResultBlockResults, + txIndex int, + ethTxIndex int, + expectedTxLogs []*gethcore.Log, + expectedEthTx bool, + txInfo string, +) { + txResults := blockRes.TxsResults[txIndex] + s.Require().Equal(uint32(0x0), txResults.Code, "tx failed, %s. RawLog: %s", txInfo, txResults.Log) + + events := blockRes.TxsResults[txIndex].Events + + foundEthTx := false + for _, event := range events { + if event.Type == evm.TypeUrlEventTxLog { + logs, err := backend.ParseTxLogsFromEvent(event) + s.Require().NoError(err) + if len(expectedTxLogs) > 0 { + s.Require().GreaterOrEqual(len(logs), len(expectedTxLogs)) + s.assertTxLogsMatch(expectedTxLogs, logs, txInfo) + } else { + s.Require().Nil(logs) + } + } + if event.Type == evm.TypeUrlEventEthereumTx { + foundEthTx = true + if !expectedEthTx { + s.Fail("unexpected EventEthereumTx event for non-eth tx, %s", txInfo) + } + ethereumTx, err := evm.EventEthereumTxFromABCIEvent(event) + s.Require().NoError(err) + s.Require().Equal( + fmt.Sprintf("%d", ethTxIndex), + ethereumTx.Index, + "tx index mismatch, %s", txInfo, + ) + } + } + if expectedEthTx && !foundEthTx { + s.Fail("expected EventEthereumTx event not found, %s", txInfo) + } +} + +// assertTxLogsMatch checks that actual tx logs include the expected logs +func (s *BackendSuite) assertTxLogsMatch( + expectedLogs []*gethcore.Log, + actualLogs []*gethcore.Log, + txInfo string, +) { + for idx, expectedLog := range expectedLogs { + actualLog := actualLogs[idx] + s.Require().Equal( + expectedLog.Address, + actualLog.Address, fmt.Sprintf("log contract address mismatch, log index %d, %s", idx, txInfo), + ) + + s.Require().Equal( + len(expectedLog.Topics), + len(actualLog.Topics), + fmt.Sprintf("topics length mismatch, log index %d, %s", idx, txInfo), + ) + + for idx, topic := range expectedLog.Topics { + s.Require().Equal( + topic, + actualLog.Topics[idx], + fmt.Sprintf("topic mismatch, log index %d, %s", idx, txInfo), + ) + } + } +} diff --git a/eth/rpc/backend/utils_test.go b/eth/rpc/backend/utils_test.go index 94fc90fe4..083d24361 100644 --- a/eth/rpc/backend/utils_test.go +++ b/eth/rpc/backend/utils_test.go @@ -4,12 +4,16 @@ import ( "fmt" "github.com/cometbft/cometbft/proto/tendermint/crypto" + gethcommon "github.com/ethereum/go-ethereum/common" + gethcore "github.com/ethereum/go-ethereum/core/types" + + gethcrypto "github.com/ethereum/go-ethereum/crypto" "github.com/NibiruChain/nibiru/v2/eth/rpc/backend" ) func (s *BackendSuite) TestGetLogsFromBlockResults() { - blockWithTx := transferTxBlockNumber.Int64() + blockWithTx := deployContractBlockNumber.Int64() blockResults, err := s.backend.TendermintBlockResultByNumber(&blockWithTx) s.Require().NoError(err) s.Require().NotNil(blockResults) @@ -18,8 +22,16 @@ func (s *BackendSuite) TestGetLogsFromBlockResults() { s.Require().NoError(err) s.Require().NotNil(logs) - // TODO: ON: the structured event eth.evm.v1.EventTxLog is not emitted properly, so the logs are not retrieved - // Add proper checks after implementing + s.assertTxLogsMatch([]*gethcore.Log{ + { + Address: testContractAddress, + Topics: []gethcommon.Hash{ + gethcrypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")), + gethcommon.Address{}.Hash(), + s.fundedAccEthAddr.Hash(), + }, + }, + }, logs[0], "deploy contract tx") } func (s *BackendSuite) TestGetHexProofs() { diff --git a/x/common/testutil/testnetwork/tx.go b/x/common/testutil/testnetwork/tx.go index a368c8a86..279381a2a 100644 --- a/x/common/testutil/testnetwork/tx.go +++ b/x/common/testutil/testnetwork/tx.go @@ -126,7 +126,9 @@ func (network *Network) ExecTxCmd( } func (chain *Network) BroadcastMsgs( - from sdk.AccAddress, msgs ...sdk.Msg, + from sdk.AccAddress, + accountSequence *uint64, + msgs ...sdk.Msg, ) (*sdk.TxResponse, error) { cfg := chain.Config kb, info, err := chain.keyBaseAndInfoForAddr(from) @@ -142,13 +144,18 @@ func (chain *Network) BroadcastMsgs( } txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, math.NewInt(1000)))) - txBuilder.SetGasLimit(uint64(1 * common.TO_MICRO)) + txBuilder.SetGasLimit(uint64(10 * common.TO_MICRO)) acc, err := cfg.AccountRetriever.GetAccount(chain.Validators[0].ClientCtx, from) if err != nil { return nil, err } - + var sequence uint64 + if accountSequence != nil { + sequence = *accountSequence + } else { + sequence = acc.GetSequence() + } txFactory := tx.Factory{} txFactory = txFactory. WithChainID(cfg.ChainID). @@ -156,7 +163,7 @@ func (chain *Network) BroadcastMsgs( WithTxConfig(cfg.TxConfig). WithAccountRetriever(cfg.AccountRetriever). WithAccountNumber(acc.GetAccountNumber()). - WithSequence(acc.GetSequence()) + WithSequence(sequence) err = tx.Sign(txFactory, info.Name, txBuilder, true) if err != nil { diff --git a/x/common/testutil/testnetwork/tx_test.go b/x/common/testutil/testnetwork/tx_test.go index 7912b8cea..267140460 100644 --- a/x/common/testutil/testnetwork/tx_test.go +++ b/x/common/testutil/testnetwork/tx_test.go @@ -16,7 +16,7 @@ func (s *TestSuite) TestSendTx() { fromAddr := s.network.Validators[0].Address toAddr := testutil.AccAddress() sendCoin := sdk.NewCoin(denoms.NIBI, math.NewInt(42)) - txResp, err := s.network.BroadcastMsgs(fromAddr, &banktypes.MsgSend{ + txResp, err := s.network.BroadcastMsgs(fromAddr, nil, &banktypes.MsgSend{ FromAddress: fromAddr.String(), ToAddress: toAddr.String(), Amount: sdk.NewCoins(sendCoin), diff --git a/x/evm/evmtest/tx.go b/x/evm/evmtest/tx.go index 440e83556..a5803a3f7 100644 --- a/x/evm/evmtest/tx.go +++ b/x/evm/evmtest/tx.go @@ -26,7 +26,7 @@ import ( ) // ExecuteNibiTransfer executes nibi transfer -func ExecuteNibiTransfer(deps *TestDeps, t *testing.T) *evm.MsgEthereumTx { +func ExecuteNibiTransfer(deps *TestDeps, t *testing.T) (*evm.MsgEthereumTx, *evm.MsgEthereumTxResponse) { nonce := deps.NewStateDB().GetNonce(deps.Sender.EthAddr) recipient := NewEthPrivAcc().EthAddr @@ -43,7 +43,7 @@ func ExecuteNibiTransfer(deps *TestDeps, t *testing.T) *evm.MsgEthereumTx { resp, err := deps.App.EvmKeeper.EthereumTx(sdk.WrapSDKContext(deps.Ctx), ethTxMsg) require.NoError(t, err) require.Empty(t, resp.VmError) - return ethTxMsg + return ethTxMsg, resp } type DeployContractResult struct { diff --git a/x/evm/keeper/call_contract.go b/x/evm/keeper/call_contract.go index e38bbd4a2..f9fdc2c8b 100644 --- a/x/evm/keeper/call_contract.go +++ b/x/evm/keeper/call_contract.go @@ -84,14 +84,11 @@ func (k Keeper) CallContractWithInput( // Success, update block gas used and bloom filter if commit { k.updateBlockBloom(ctx, evmResp, uint64(txConfig.LogIndex)) - // TODO: remove after migrating logs - //err = k.EmitLogEvents(ctx, evmResp) - //if err != nil { - // return nil, nil, errors.Wrap(err, "error emitting tx logs") - //} - // blockTxIdx := uint64(txConfig.TxIndex) + 1 - // k.EvmState.BlockTxIndex.Set(ctx, blockTxIdx) + err = k.EmitLogEvents(ctx, evmResp) + if err != nil { + return nil, errors.Wrap(err, "error emitting tx logs") + } } return evmResp, nil } diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index 28da63173..2b75914b2 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -767,7 +767,7 @@ func (s *Suite) TestTraceTx() { { name: "happy: simple nibi transfer tx", scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { - txMsg := evmtest.ExecuteNibiTransfer(deps, s.T()) + txMsg, _ := evmtest.ExecuteNibiTransfer(deps, s.T()) req = &evm.QueryTraceTxRequest{ Msg: txMsg, } @@ -843,7 +843,7 @@ func (s *Suite) TestTraceBlock() { name: "happy: simple nibi transfer tx", setup: nil, scenario: func(deps *evmtest.TestDeps) (req In, wantResp Out) { - txMsg := evmtest.ExecuteNibiTransfer(deps, s.T()) + txMsg, _ := evmtest.ExecuteNibiTransfer(deps, s.T()) req = &evm.QueryTraceBlockRequest{ Txs: []*evm.MsgEthereumTx{ txMsg, diff --git a/x/oracle/keeper/app_test.go b/x/oracle/keeper/app_test.go index 197c73223..c8b5ebe33 100644 --- a/x/oracle/keeper/app_test.go +++ b/x/oracle/keeper/app_test.go @@ -117,7 +117,7 @@ func (s *TestSuite) sendPrevotes(prices []map[asset.Pair]sdk.Dec) []string { pricesStr, err := votes.ToString() s.Require().NoError(err) - _, err = s.network.BroadcastMsgs(val.Address, &types.MsgAggregateExchangeRatePrevote{ + _, err = s.network.BroadcastMsgs(val.Address, nil, &types.MsgAggregateExchangeRatePrevote{ Hash: types.GetAggregateVoteHash("1", pricesStr, val.ValAddress).String(), Feeder: val.Address.String(), Validator: val.ValAddress.String(), @@ -133,7 +133,7 @@ func (s *TestSuite) sendPrevotes(prices []map[asset.Pair]sdk.Dec) []string { func (s *TestSuite) sendVotes(rates []string) { for i, val := range s.network.Validators { - _, err := s.network.BroadcastMsgs(val.Address, &types.MsgAggregateExchangeRateVote{ + _, err := s.network.BroadcastMsgs(val.Address, nil, &types.MsgAggregateExchangeRateVote{ Salt: "1", ExchangeRates: rates[i], Feeder: val.Address.String(),