From 657e6f32ed5f9bac3366747928b193dae9735929 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Sun, 13 Oct 2024 06:53:28 -0500 Subject: [PATCH] pkg/cosmos: add Context to ReaderWriter methods --- go.mod | 2 +- integration-tests/ocr2_test.go | 11 +- ops/test_helpers.go | 1 - .../cosmwasm/contract_config_tracker.go | 2 +- .../adapters/cosmwasm/contract_reader.go | 10 +- .../adapters/injective/config_tracker.go | 2 +- pkg/cosmos/chain.go | 10 +- pkg/cosmos/client/client.go | 74 +++--- pkg/cosmos/client/client_test.go | 75 +++--- pkg/cosmos/client/mocks/ReaderWriter.go | 225 +++++++++--------- pkg/cosmos/client/test_helpers.go | 17 +- pkg/cosmos/txm/helpers_test.go | 10 +- pkg/cosmos/txm/key_wrapper.go | 2 +- pkg/cosmos/txm/keystore_adapter.go | 14 +- pkg/cosmos/txm/txm.go | 12 +- pkg/cosmos/txm/txm_internal_test.go | 20 +- pkg/monitoring/chain_reader.go | 11 +- .../{testutils.go => helper_test.go} | 55 ++--- pkg/monitoring/proxy_monitoring_test.go | 23 +- pkg/monitoring/source_envelope_test.go | 65 ++++- pkg/monitoring/source_txresults_test.go | 7 +- 21 files changed, 344 insertions(+), 304 deletions(-) delete mode 100644 ops/test_helpers.go rename pkg/monitoring/{testutils.go => helper_test.go} (57%) diff --git a/go.mod b/go.mod index be52a63c2..7b805d1d9 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( cosmossdk.io/errors v1.0.1 github.com/CosmWasm/wasmd v0.40.1 github.com/cometbft/cometbft v0.37.5 + github.com/cosmos/btcutil v1.0.5 github.com/cosmos/cosmos-sdk v0.47.11 github.com/cosmos/go-bip39 v1.0.0 github.com/gogo/protobuf v1.3.3 @@ -72,7 +73,6 @@ require ( github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/containerd/containerd v1.7.18 // indirect - github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect github.com/cosmos/gogoproto v1.4.11 // indirect github.com/cosmos/iavl v0.20.1 // indirect diff --git a/integration-tests/ocr2_test.go b/integration-tests/ocr2_test.go index ad5b3c233..999a9c400 100644 --- a/integration-tests/ocr2_test.go +++ b/integration-tests/ocr2_test.go @@ -11,6 +11,7 @@ import ( "time" relaylogger "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-cosmos/integration-tests/common" "github.com/smartcontractkit/chainlink-cosmos/integration-tests/gauntlet" @@ -32,6 +33,7 @@ import ( ) func TestOCRBasic(t *testing.T) { + ctx := tests.Context(t) // Set up test environment logger := common.GetTestLogger(t) commonConfig := common.NewCommon(t) @@ -62,13 +64,13 @@ func TestOCRBasic(t *testing.T) { gasPrice := types.NewDecCoinFromDec("ucosm", types.MustNewDecFromStr("1")) amount := []types.Coin{types.NewCoin("ucosm", types.NewInt(int64(10000000)))} - accountNumber, sequenceNumber, err := cosmosClient.Account(testAccount) + accountNumber, sequenceNumber, err := cosmosClient.Account(ctx, testAccount) require.NoError(t, err, "Could not get account") for i, nodeAddr := range chainlinkClient.GetNodeAddresses() { to := types.MustAccAddressFromBech32(nodeAddr) msgSend := banktypes.NewMsgSend(testAccount, to, amount) - resp, err2 := cosmosClient.SignAndBroadcast([]types.Msg{msgSend}, accountNumber, sequenceNumber+uint64(i), gasPrice, privateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) + resp, err2 := cosmosClient.SignAndBroadcast(ctx, []types.Msg{msgSend}, accountNumber, sequenceNumber+uint64(i), gasPrice, privateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) require.NoError(t, err2, "Could not send tokens") logger.Info().Str("from", testAccount.String()). Str("to", nodeAddr). @@ -79,7 +81,7 @@ func TestOCRBasic(t *testing.T) { tx, success := client.AwaitTxCommitted(t, cosmosClient, resp.TxResponse.TxHash) require.True(t, success) require.Equal(t, cometbfttypes.CodeTypeOK, tx.TxResponse.Code) - balance, err2 := cosmosClient.Balance(to, "ucosm") + balance, err2 := cosmosClient.Balance(ctx, to, "ucosm") require.NoError(t, err2, "Could not fetch ucosm balance") require.Equal(t, balance.String(), "10000000ucosm") } @@ -218,6 +220,7 @@ func validateRounds(t *testing.T, cosmosClient *client.Client, ocrAddress types. stuckCount := 0 var positive bool resp, err := cosmosClient.ContractState( + ctx, ocrAddress, []byte(`{"link_available_for_payment":{}}`), ) @@ -332,7 +335,7 @@ func validateRounds(t *testing.T, cosmosClient *client.Client, ocrAddress types. // Test proxy reading // TODO: would be good to test proxy switching underlying feeds - resp, err = cosmosClient.ContractState(ocrProxyAddress, []byte(`{"latest_round_data":{}}`)) + resp, err = cosmosClient.ContractState(ctx, ocrProxyAddress, []byte(`{"latest_round_data":{}}`)) if !isSoak { require.NoError(t, err, "Reading round data from proxy should not fail") //assert.Equal(t, len(roundDataRaw), 5, "Round data from proxy should match expected size") diff --git a/ops/test_helpers.go b/ops/test_helpers.go deleted file mode 100644 index d79165ecd..000000000 --- a/ops/test_helpers.go +++ /dev/null @@ -1 +0,0 @@ -package ops diff --git a/pkg/cosmos/adapters/cosmwasm/contract_config_tracker.go b/pkg/cosmos/adapters/cosmwasm/contract_config_tracker.go index 14dc7b766..eae967715 100644 --- a/pkg/cosmos/adapters/cosmwasm/contract_config_tracker.go +++ b/pkg/cosmos/adapters/cosmwasm/contract_config_tracker.go @@ -30,7 +30,7 @@ func (ct *ContractTracker) Notify() <-chan struct{} { // TODO: seems heavy to fetch whole block rather than rpc.Status() -> SyncInfo.LatestBlockHeight // LatestBlockHeight returns the height of the most recent block in the chain. func (ct *ContractTracker) LatestBlockHeight(ctx context.Context) (blockHeight uint64, err error) { - b, err := ct.chainReader.LatestBlock() + b, err := ct.chainReader.LatestBlock(ctx) if err != nil { return 0, err } diff --git a/pkg/cosmos/adapters/cosmwasm/contract_reader.go b/pkg/cosmos/adapters/cosmwasm/contract_reader.go index a8e4b61a3..f835669c1 100644 --- a/pkg/cosmos/adapters/cosmwasm/contract_reader.go +++ b/pkg/cosmos/adapters/cosmwasm/contract_reader.go @@ -12,9 +12,10 @@ import ( cosmosSDK "github.com/cosmos/cosmos-sdk/types" - "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/libocr/offchainreporting2/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" ) @@ -34,6 +35,7 @@ func NewOCR2Reader(addess cosmosSDK.AccAddress, chainReader client.Reader, lggr func (r *OCR2Reader) LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest types.ConfigDigest, err error) { resp, err := r.chainReader.ContractState( + ctx, r.address, []byte(`{"latest_config_details":{}}`), ) @@ -54,7 +56,7 @@ func (r *OCR2Reader) LatestConfig(ctx context.Context, changedInBlock uint64) (t // work with wasmd 0.41.0, which is at cosmos-sdk v0.47.4, which contains the following regex for each event query string: // https://github.com/cosmos/cosmos-sdk/blob/3b509c187e1643757f5ef8a0b5ae3decca0c7719/x/auth/tx/service.go#L49 query := []string{fmt.Sprintf("tx.height=%d", changedInBlock), fmt.Sprintf("wasm._contract_address='%s'", r.address)} - res, err := r.chainReader.TxsEvents(query, nil) + res, err := r.chainReader.TxsEvents(ctx, query, nil) if err != nil { return types.ContractConfig{}, err } @@ -228,7 +230,7 @@ func (r *OCR2Reader) LatestTransmissionDetails(ctx context.Context) ( latestTimestamp time.Time, err error, ) { - resp, err := r.chainReader.ContractState(r.address, []byte(`{"latest_transmission_details":{}}`)) + resp, err := r.chainReader.ContractState(ctx, r.address, []byte(`{"latest_transmission_details":{}}`)) if err != nil { // Handle the 500 error that occurs when there has not been a submission // "rpc error: code = Unknown desc = ocr2::state::Transmission not found: contract query failed: unknown request" @@ -338,7 +340,7 @@ func (r *OCR2Reader) LatestConfigDigestAndEpoch(ctx context.Context) ( err error, ) { resp, err := r.chainReader.ContractState( - r.address, []byte(`{"latest_config_digest_and_epoch":{}}`), + ctx, r.address, []byte(`{"latest_config_digest_and_epoch":{}}`), ) if err != nil { return types.ConfigDigest{}, 0, err diff --git a/pkg/cosmos/adapters/injective/config_tracker.go b/pkg/cosmos/adapters/injective/config_tracker.go index 69c224a8c..f4f16755b 100644 --- a/pkg/cosmos/adapters/injective/config_tracker.go +++ b/pkg/cosmos/adapters/injective/config_tracker.go @@ -111,7 +111,7 @@ func (c *CosmosModuleConfigTracker) LatestBlockHeight( blockHeight uint64, err error, ) { - b, err := c.tendermintServiceClient.GetLatestBlock(context.Background(), &tmtypes.GetLatestBlockRequest{}) + b, err := c.tendermintServiceClient.GetLatestBlock(ctx, &tmtypes.GetLatestBlockRequest{}) if err != nil { return 0, err } diff --git a/pkg/cosmos/chain.go b/pkg/cosmos/chain.go index 4e4e65d0e..16a7ca97c 100644 --- a/pkg/cosmos/chain.go +++ b/pkg/cosmos/chain.go @@ -190,13 +190,13 @@ func (c *chain) HealthReport() map[string]error { return m } -func (c *chain) LatestHead(_ context.Context) (types.Head, error) { +func (c *chain) LatestHead(ctx context.Context) (types.Head, error) { reader, err := c.Reader("") if err != nil { return types.Head{}, fmt.Errorf("chain unreachable: %v", err) } - latestBlock, err := reader.LatestBlock() + latestBlock, err := reader.LatestBlock(ctx) if err != nil { return types.Head{}, err } @@ -249,7 +249,7 @@ func (c *chain) Transact(ctx context.Context, from, to string, amount *big.Int, return fmt.Errorf("gas price unavailable: %v", err2) } - err = validateBalance(reader, gasPrice, fromAcc, coin) + err = validateBalance(ctx, reader, gasPrice, fromAcc, coin) if err != nil { return fmt.Errorf("failed to validate balance: %v", err) } @@ -300,8 +300,8 @@ func nodeStatus(n *config.Node, id string) (types.NodeStatus, error) { const maxGasUsedTransfer = 100_000 // validateBalance validates that fromAddr's balance can cover coin, including fees at gasPrice. -func validateBalance(reader client.Reader, gasPrice sdk.DecCoin, fromAddr sdk.AccAddress, coin sdk.Coin) error { - balance, err := reader.Balance(fromAddr, coin.GetDenom()) +func validateBalance(ctx context.Context, reader client.Reader, gasPrice sdk.DecCoin, fromAddr sdk.AccAddress, coin sdk.Coin) error { + balance, err := reader.Balance(ctx, fromAddr, coin.GetDenom()) if err != nil { return err } diff --git a/pkg/cosmos/client/client.go b/pkg/cosmos/client/client.go index a69717f4f..e5a2ba2c4 100644 --- a/pkg/cosmos/client/client.go +++ b/pkg/cosmos/client/client.go @@ -38,13 +38,13 @@ type ReaderWriter interface { // Reader provides methods for reading from a cosmos chain. type Reader interface { - Account(address sdk.AccAddress) (uint64, uint64, error) - ContractState(contractAddress sdk.AccAddress, queryMsg []byte) ([]byte, error) - TxsEvents(events []string, paginationParams *query.PageRequest) (*txtypes.GetTxsEventResponse, error) - Tx(hash string) (*txtypes.GetTxResponse, error) - LatestBlock() (*tmtypes.GetLatestBlockResponse, error) - BlockByHeight(height int64) (*tmtypes.GetBlockByHeightResponse, error) - Balance(addr sdk.AccAddress, denom string) (*sdk.Coin, error) + Account(ctx context.Context, address sdk.AccAddress) (uint64, uint64, error) + ContractState(ctx context.Context, contractAddress sdk.AccAddress, queryMsg []byte) ([]byte, error) + TxsEvents(ctx context.Context, events []string, paginationParams *query.PageRequest) (*txtypes.GetTxsEventResponse, error) + Tx(ctx context.Context, hash string) (*txtypes.GetTxResponse, error) + LatestBlock(context.Context) (*tmtypes.GetLatestBlockResponse, error) + BlockByHeight(ctx context.Context, height int64) (*tmtypes.GetBlockByHeightResponse, error) + Balance(ctx context.Context, addr sdk.AccAddress, denom string) (*sdk.Coin, error) // TODO: escape hatch for injective client Context() *cosmosclient.Context } @@ -54,11 +54,11 @@ type Reader interface { // We may want to support multiple from addresses + signers if a use case arises. type Writer interface { // TODO: SignAndBroadcast is only used for testing, remove it - SignAndBroadcast(msgs []sdk.Msg, accountNum uint64, sequence uint64, gasPrice sdk.DecCoin, signer cryptotypes.PrivKey, mode txtypes.BroadcastMode) (*txtypes.BroadcastTxResponse, error) - Broadcast(txBytes []byte, mode txtypes.BroadcastMode) (*txtypes.BroadcastTxResponse, error) - Simulate(txBytes []byte) (*txtypes.SimulateResponse, error) - BatchSimulateUnsigned(msgs SimMsgs, sequence uint64) (*BatchSimResults, error) - SimulateUnsigned(msgs []sdk.Msg, sequence uint64) (*txtypes.SimulateResponse, error) + SignAndBroadcast(ctx context.Context, msgs []sdk.Msg, accountNum uint64, sequence uint64, gasPrice sdk.DecCoin, signer cryptotypes.PrivKey, mode txtypes.BroadcastMode) (*txtypes.BroadcastTxResponse, error) + Broadcast(ctx context.Context, txBytes []byte, mode txtypes.BroadcastMode) (*txtypes.BroadcastTxResponse, error) + Simulate(ctx context.Context, txBytes []byte) (*txtypes.SimulateResponse, error) + BatchSimulateUnsigned(ctx context.Context, msgs SimMsgs, sequence uint64) (*BatchSimResults, error) + SimulateUnsigned(ctx context.Context, msgs []sdk.Msg, sequence uint64) (*txtypes.SimulateResponse, error) CreateAndSign(msgs []sdk.Msg, account uint64, sequence uint64, gasLimit uint64, gasLimitMultiplier float64, gasPrice sdk.DecCoin, signer cryptotypes.PrivKey, timeoutHeight uint64) ([]byte, error) } @@ -146,8 +146,8 @@ func (c *Client) Context() *cosmosclient.Context { // Account read the account address for the account number and sequence number. // !!Note only one sequence number can be used per account per block!! -func (c *Client) Account(addr sdk.AccAddress) (uint64, uint64, error) { - r, err := c.authClient.Account(context.Background(), &authtypes.QueryAccountRequest{Address: addr.String()}) +func (c *Client) Account(ctx context.Context, addr sdk.AccAddress) (uint64, uint64, error) { + r, err := c.authClient.Account(ctx, &authtypes.QueryAccountRequest{Address: addr.String()}) if err != nil { return 0, 0, err } @@ -160,8 +160,8 @@ func (c *Client) Account(addr sdk.AccAddress) (uint64, uint64, error) { } // ContractState reads from a WASM contract store -func (c *Client) ContractState(contractAddress sdk.AccAddress, queryMsg []byte) ([]byte, error) { - s, err := c.wasmClient.SmartContractState(context.Background(), &wasmtypes.QuerySmartContractStateRequest{ +func (c *Client) ContractState(ctx context.Context, contractAddress sdk.AccAddress, queryMsg []byte) ([]byte, error) { + s, err := c.wasmClient.SmartContractState(ctx, &wasmtypes.QuerySmartContractStateRequest{ Address: contractAddress.String(), QueryData: queryMsg, }) @@ -176,8 +176,8 @@ func (c *Client) ContractState(contractAddress sdk.AccAddress, queryMsg []byte) // Each event is ANDed together and follows the query language defined // https://docs.cosmos.network/master/core/events.html // Note one current issue https://github.com/cosmos/cosmos-sdk/issues/10448 -func (c *Client) TxsEvents(events []string, paginationParams *query.PageRequest) (*txtypes.GetTxsEventResponse, error) { - e, err := c.cosmosServiceClient.GetTxsEvent(context.Background(), &txtypes.GetTxsEventRequest{ +func (c *Client) TxsEvents(ctx context.Context, events []string, paginationParams *query.PageRequest) (*txtypes.GetTxsEventResponse, error) { + e, err := c.cosmosServiceClient.GetTxsEvent(ctx, &txtypes.GetTxsEventRequest{ Events: events, Pagination: paginationParams, OrderBy: txtypes.OrderBy_ORDER_BY_DESC, @@ -186,21 +186,21 @@ func (c *Client) TxsEvents(events []string, paginationParams *query.PageRequest) } // Tx gets a tx by hash -func (c *Client) Tx(hash string) (*txtypes.GetTxResponse, error) { - e, err := c.cosmosServiceClient.GetTx(context.Background(), &txtypes.GetTxRequest{ +func (c *Client) Tx(ctx context.Context, hash string) (*txtypes.GetTxResponse, error) { + e, err := c.cosmosServiceClient.GetTx(ctx, &txtypes.GetTxRequest{ Hash: hash, }) return e, err } // LatestBlock returns the latest block -func (c *Client) LatestBlock() (*tmtypes.GetLatestBlockResponse, error) { - return c.tendermintServiceClient.GetLatestBlock(context.Background(), &tmtypes.GetLatestBlockRequest{}) +func (c *Client) LatestBlock(ctx context.Context) (*tmtypes.GetLatestBlockResponse, error) { + return c.tendermintServiceClient.GetLatestBlock(ctx, &tmtypes.GetLatestBlockRequest{}) } // BlockByHeight gets a block by height -func (c *Client) BlockByHeight(height int64) (*tmtypes.GetBlockByHeightResponse, error) { - return c.tendermintServiceClient.GetBlockByHeight(context.Background(), &tmtypes.GetBlockByHeightRequest{Height: height}) +func (c *Client) BlockByHeight(ctx context.Context, height int64) (*tmtypes.GetBlockByHeightResponse, error) { + return c.tendermintServiceClient.GetBlockByHeight(ctx, &tmtypes.GetBlockByHeightRequest{Height: height}) } // CreateAndSign creates and signs a transaction @@ -336,12 +336,12 @@ func (c *Client) failedMsgIndex(err error) (bool, int) { // Note that the error from simulating indicates the first // msg in the slice which failed (it simply loops over the msgs // and simulates them one by one, breaking at the first failure). -func (c *Client) BatchSimulateUnsigned(msgs SimMsgs, sequence uint64) (*BatchSimResults, error) { +func (c *Client) BatchSimulateUnsigned(ctx context.Context, msgs SimMsgs, sequence uint64) (*BatchSimResults, error) { var succeeded []SimMsg var failed []SimMsg toSim := msgs for { - _, err := c.SimulateUnsigned(toSim.GetMsgs(), sequence) + _, err := c.SimulateUnsigned(ctx, toSim.GetMsgs(), sequence) containsFailure, failureIndex := c.failedMsgIndex(err) if err != nil && !containsFailure { return nil, err @@ -370,7 +370,7 @@ func (c *Client) BatchSimulateUnsigned(msgs SimMsgs, sequence uint64) (*BatchSim } // SimulateUnsigned simulates an unsigned msg -func (c *Client) SimulateUnsigned(msgs []sdk.Msg, sequence uint64) (*txtypes.SimulateResponse, error) { +func (c *Client) SimulateUnsigned(ctx context.Context, msgs []sdk.Msg, sequence uint64) (*txtypes.SimulateResponse, error) { txConfig := params.ClientTxConfig() txBuilder := txConfig.NewTxBuilder() if err := txBuilder.SetMsgs(msgs...); err != nil { @@ -393,23 +393,23 @@ func (c *Client) SimulateUnsigned(msgs []sdk.Msg, sequence uint64) (*txtypes.Sim if err != nil { return nil, err } - s, err := c.cosmosServiceClient.Simulate(context.Background(), &txtypes.SimulateRequest{ + s, err := c.cosmosServiceClient.Simulate(ctx, &txtypes.SimulateRequest{ TxBytes: txBytes, }) return s, err } // Simulate simulates a signed transaction -func (c *Client) Simulate(txBytes []byte) (*txtypes.SimulateResponse, error) { - s, err := c.cosmosServiceClient.Simulate(context.Background(), &txtypes.SimulateRequest{ +func (c *Client) Simulate(ctx context.Context, txBytes []byte) (*txtypes.SimulateResponse, error) { + s, err := c.cosmosServiceClient.Simulate(ctx, &txtypes.SimulateRequest{ TxBytes: txBytes, }) return s, err } // Broadcast broadcasts a tx -func (c *Client) Broadcast(txBytes []byte, mode txtypes.BroadcastMode) (*txtypes.BroadcastTxResponse, error) { - res, err := c.cosmosServiceClient.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{ +func (c *Client) Broadcast(ctx context.Context, txBytes []byte, mode txtypes.BroadcastMode) (*txtypes.BroadcastTxResponse, error) { + res, err := c.cosmosServiceClient.BroadcastTx(ctx, &txtypes.BroadcastTxRequest{ Mode: mode, TxBytes: txBytes, }) @@ -426,8 +426,8 @@ func (c *Client) Broadcast(txBytes []byte, mode txtypes.BroadcastMode) (*txtypes } // SignAndBroadcast signs and broadcasts a group of msgs. -func (c *Client) SignAndBroadcast(msgs []sdk.Msg, account uint64, sequence uint64, gasPrice sdk.DecCoin, signer cryptotypes.PrivKey, mode txtypes.BroadcastMode) (*txtypes.BroadcastTxResponse, error) { - sim, err := c.SimulateUnsigned(msgs, sequence) +func (c *Client) SignAndBroadcast(ctx context.Context, msgs []sdk.Msg, account uint64, sequence uint64, gasPrice sdk.DecCoin, signer cryptotypes.PrivKey, mode txtypes.BroadcastMode) (*txtypes.BroadcastTxResponse, error) { + sim, err := c.SimulateUnsigned(ctx, msgs, sequence) if err != nil { return nil, err } @@ -436,12 +436,12 @@ func (c *Client) SignAndBroadcast(msgs []sdk.Msg, account uint64, sequence uint6 if err != nil { return nil, err } - return c.Broadcast(txBytes, mode) + return c.Broadcast(ctx, txBytes, mode) } // Balance returns the balance of an address -func (c *Client) Balance(addr sdk.AccAddress, denom string) (*sdk.Coin, error) { - b, err := c.bankClient.Balance(context.Background(), &banktypes.QueryBalanceRequest{Address: addr.String(), Denom: denom}) +func (c *Client) Balance(ctx context.Context, addr sdk.AccAddress, denom string) (*sdk.Coin, error) { + b, err := c.bankClient.Balance(ctx, &banktypes.QueryBalanceRequest{Address: addr.String(), Denom: denom}) if err != nil { return nil, err } diff --git a/pkg/cosmos/client/client_test.go b/pkg/cosmos/client/client_test.go index 01908bac7..1eeec7078 100644 --- a/pkg/cosmos/client/client_test.go +++ b/pkg/cosmos/client/client_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/params" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -66,10 +67,11 @@ func TestBatchSim(t *testing.T) { var fail sdk.Msg = &wasmtypes.MsgExecuteContract{Sender: accounts[0].Address.String(), Contract: contract.String(), Msg: []byte(`{"blah":{"count":5}}`)} t.Run("single success", func(t *testing.T) { - _, sn, err := tc.Account(accounts[0].Address) + ctx := tests.Context(t) + _, sn, err := tc.Account(ctx, accounts[0].Address) require.NoError(t, err) t.Cleanup(assertLogsLen(t, 0)) - res, err := tc.BatchSimulateUnsigned([]SimMsg{{ID: int64(1), Msg: succeed}}, sn) + res, err := tc.BatchSimulateUnsigned(ctx, []SimMsg{{ID: int64(1), Msg: succeed}}, sn) require.NoError(t, err) require.Equal(t, 1, len(res.Succeeded)) assert.Equal(t, int64(1), res.Succeeded[0].ID) @@ -77,10 +79,11 @@ func TestBatchSim(t *testing.T) { }) t.Run("single failure", func(t *testing.T) { - _, sn, err := tc.Account(accounts[0].Address) + ctx := tests.Context(t) + _, sn, err := tc.Account(ctx, accounts[0].Address) require.NoError(t, err) t.Cleanup(assertLogsLen(t, 1)) - res, err := tc.BatchSimulateUnsigned([]SimMsg{{ID: int64(1), Msg: fail}}, sn) + res, err := tc.BatchSimulateUnsigned(ctx, []SimMsg{{ID: int64(1), Msg: fail}}, sn) require.NoError(t, err) assert.Equal(t, 0, len(res.Succeeded)) require.Equal(t, 1, len(res.Failed)) @@ -88,10 +91,11 @@ func TestBatchSim(t *testing.T) { }) t.Run("multi failure", func(t *testing.T) { - _, sn, err := tc.Account(accounts[0].Address) + ctx := tests.Context(t) + _, sn, err := tc.Account(ctx, accounts[0].Address) require.NoError(t, err) t.Cleanup(assertLogsLen(t, 2)) - res, err := tc.BatchSimulateUnsigned([]SimMsg{{ID: int64(1), Msg: succeed}, {ID: int64(2), Msg: fail}, {ID: int64(3), Msg: fail}}, sn) + res, err := tc.BatchSimulateUnsigned(ctx, []SimMsg{{ID: int64(1), Msg: succeed}, {ID: int64(2), Msg: fail}, {ID: int64(3), Msg: fail}}, sn) require.NoError(t, err) require.Equal(t, 1, len(res.Succeeded)) assert.Equal(t, int64(1), res.Succeeded[0].ID) @@ -101,30 +105,33 @@ func TestBatchSim(t *testing.T) { }) t.Run("multi succeed", func(t *testing.T) { - _, sn, err := tc.Account(accounts[0].Address) + ctx := tests.Context(t) + _, sn, err := tc.Account(ctx, accounts[0].Address) require.NoError(t, err) t.Cleanup(assertLogsLen(t, 1)) - res, err := tc.BatchSimulateUnsigned([]SimMsg{{ID: int64(1), Msg: succeed}, {ID: int64(2), Msg: succeed}, {ID: int64(3), Msg: fail}}, sn) + res, err := tc.BatchSimulateUnsigned(ctx, []SimMsg{{ID: int64(1), Msg: succeed}, {ID: int64(2), Msg: succeed}, {ID: int64(3), Msg: fail}}, sn) require.NoError(t, err) assert.Equal(t, 2, len(res.Succeeded)) assert.Equal(t, 1, len(res.Failed)) }) t.Run("all succeed", func(t *testing.T) { - _, sn, err := tc.Account(accounts[0].Address) + ctx := tests.Context(t) + _, sn, err := tc.Account(ctx, accounts[0].Address) require.NoError(t, err) t.Cleanup(assertLogsLen(t, 0)) - res, err := tc.BatchSimulateUnsigned([]SimMsg{{ID: int64(1), Msg: succeed}, {ID: int64(2), Msg: succeed}, {ID: int64(3), Msg: succeed}}, sn) + res, err := tc.BatchSimulateUnsigned(ctx, []SimMsg{{ID: int64(1), Msg: succeed}, {ID: int64(2), Msg: succeed}, {ID: int64(3), Msg: succeed}}, sn) require.NoError(t, err) assert.Equal(t, 3, len(res.Succeeded)) assert.Equal(t, 0, len(res.Failed)) }) t.Run("all fail", func(t *testing.T) { - _, sn, err := tc.Account(accounts[0].Address) + ctx := tests.Context(t) + _, sn, err := tc.Account(ctx, accounts[0].Address) require.NoError(t, err) t.Cleanup(assertLogsLen(t, 3)) - res, err := tc.BatchSimulateUnsigned([]SimMsg{{ID: int64(1), Msg: fail}, {ID: int64(2), Msg: fail}, {ID: int64(3), Msg: fail}}, sn) + res, err := tc.BatchSimulateUnsigned(ctx, []SimMsg{{ID: int64(1), Msg: fail}, {ID: int64(2), Msg: fail}, {ID: int64(3), Msg: fail}}, sn) require.NoError(t, err) assert.Equal(t, 0, len(res.Succeeded)) assert.Equal(t, 3, len(res.Failed)) @@ -146,59 +153,62 @@ func TestCosmosClient(t *testing.T) { contract := DeployTestContract(t, tendermintURL, "42", "ucosm", accounts[0], accounts[0], tc, testdir, "../testdata/my_first_contract.wasm") t.Run("send tx between accounts", func(t *testing.T) { + ctx := tests.Context(t) // Assert balance before - b, err := tc.Balance(accounts[1].Address, "ucosm") + b, err := tc.Balance(ctx, accounts[1].Address, "ucosm") require.NoError(t, err) assert.Equal(t, "100000000", b.Amount.String()) // Send a ucosm from one account to another and ensure balances update - an, sn, err := tc.Account(accounts[0].Address) + an, sn, err := tc.Account(ctx, accounts[0].Address) require.NoError(t, err) fund := banktypes.NewMsgSend(accounts[0].Address, accounts[1].Address, sdk.NewCoins(sdk.NewInt64Coin("ucosm", 1))) - gasLimit, err := tc.SimulateUnsigned([]sdk.Msg{fund}, sn) + gasLimit, err := tc.SimulateUnsigned(ctx, []sdk.Msg{fund}, sn) require.NoError(t, err) gasPrices, err := gpe.GasPrices() require.NoError(t, err) txBytes, err := tc.CreateAndSign([]sdk.Msg{fund}, an, sn, gasLimit.GasInfo.GasUsed, DefaultGasLimitMultiplier, gasPrices["ucosm"], accounts[0].PrivateKey, 0) require.NoError(t, err) - _, err = tc.Simulate(txBytes) + _, err = tc.Simulate(ctx, txBytes) require.NoError(t, err) - resp, err := tc.Broadcast(txBytes, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) + resp, err := tc.Broadcast(ctx, txBytes, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) require.NoError(t, err) tx, success := AwaitTxCommitted(t, tc, resp.TxResponse.TxHash) require.True(t, success) require.Equal(t, types.CodeTypeOK, tx.TxResponse.Code) // Assert balance changed - b, err = tc.Balance(accounts[1].Address, "ucosm") + b, err = tc.Balance(ctx, accounts[1].Address, "ucosm") require.NoError(t, err) assert.Equal(t, "100000001", b.Amount.String()) // Invalid tx should error - _, err = tc.Tx("1234") + _, err = tc.Tx(ctx, "1234") require.Error(t, err) // Ensure we can read back the tx with Query - tr, err := tc.TxsEvents([]string{fmt.Sprintf("tx.height=%v", tx.TxResponse.Height)}, nil) + tr, err := tc.TxsEvents(ctx, []string{fmt.Sprintf("tx.height=%v", tx.TxResponse.Height)}, nil) require.NoError(t, err) assert.Equal(t, 1, len(tr.TxResponses)) assert.Equal(t, tx.TxResponse.TxHash, tr.TxResponses[0].TxHash) // And also Tx - getTx, err := tc.Tx(tx.TxResponse.TxHash) + getTx, err := tc.Tx(ctx, tx.TxResponse.TxHash) require.NoError(t, err) assert.Equal(t, getTx.TxResponse.TxHash, tx.TxResponse.TxHash) }) t.Run("can get height", func(t *testing.T) { // Check getting the height works - latestBlock, err := tc.LatestBlock() + latestBlock, err := tc.LatestBlock(tests.Context(t)) require.NoError(t, err) assert.True(t, latestBlock.SdkBlock.Header.Height > 1) }) t.Run("contract event querying", func(t *testing.T) { + ctx := tests.Context(t) // Query initial contract state count, err := tc.ContractState( + ctx, contract, []byte(`{"get_count":{}}`), ) @@ -206,6 +216,7 @@ func TestCosmosClient(t *testing.T) { assert.Equal(t, `{"count":0}`, string(count)) // Query invalid state should give an error count, err = tc.ContractState( + ctx, contract, []byte(`{"blah":{}}`), ) @@ -219,11 +230,11 @@ func TestCosmosClient(t *testing.T) { Msg: []byte(`{"reset":{"count":5}}`), Funds: sdk.Coins{}, } - an, sn, err := tc.Account(accounts[0].Address) + an, sn, err := tc.Account(ctx, accounts[0].Address) require.NoError(t, err) gasPrices, err := gpe.GasPrices() require.NoError(t, err) - resp1, err := tc.SignAndBroadcast([]sdk.Msg{rawMsg}, an, sn, gasPrices["ucosm"], accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) + resp1, err := tc.SignAndBroadcast(ctx, []sdk.Msg{rawMsg}, an, sn, gasPrices["ucosm"], accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) require.NoError(t, err) tx1, success := AwaitTxCommitted(t, tc, resp1.TxResponse.TxHash) require.True(t, success) @@ -236,9 +247,9 @@ func TestCosmosClient(t *testing.T) { Msg: []byte(`{"reset":{"count":4}}`), Funds: sdk.Coins{}, } - an, sn, err = tc.Account(accounts[0].Address) + an, sn, err = tc.Account(ctx, accounts[0].Address) require.NoError(t, err) - resp2, err := tc.SignAndBroadcast([]sdk.Msg{rawMsg}, an, sn, gasPrices["ucosm"], accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) + resp2, err := tc.SignAndBroadcast(ctx, []sdk.Msg{rawMsg}, an, sn, gasPrices["ucosm"], accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) require.NoError(t, err) tx2, success := AwaitTxCommitted(t, tc, resp2.TxResponse.TxHash) require.True(t, success) @@ -246,6 +257,7 @@ func TestCosmosClient(t *testing.T) { // Observe changed contract state count, err = tc.ContractState( + ctx, contract, []byte(`{"get_count":{}}`), ) @@ -254,7 +266,7 @@ func TestCosmosClient(t *testing.T) { // Check events querying works // TxEvents sorts in a descending manner, so latest txes are first - ev, err := tc.TxsEvents([]string{"wasm.action='reset'", fmt.Sprintf("wasm._contract_address='%s'", contract.String())}, nil) + ev, err := tc.TxsEvents(ctx, []string{"wasm.action='reset'", fmt.Sprintf("wasm._contract_address='%s'", contract.String())}, nil) require.NoError(t, err) require.Equal(t, 2, len(ev.TxResponses)) foundContract := false @@ -283,10 +295,10 @@ func TestCosmosClient(t *testing.T) { assert.True(t, foundContract) // Ensure the height filtering works - ev, err = tc.TxsEvents([]string{fmt.Sprintf("tx.height=%d", tx2.TxResponse.Height), "wasm.action='reset'", fmt.Sprintf("wasm._contract_address='%s'", contract.String())}, nil) + ev, err = tc.TxsEvents(ctx, []string{fmt.Sprintf("tx.height=%d", tx2.TxResponse.Height), "wasm.action='reset'", fmt.Sprintf("wasm._contract_address='%s'", contract.String())}, nil) require.NoError(t, err) require.Equal(t, 1, len(ev.TxResponses)) - ev, err = tc.TxsEvents([]string{fmt.Sprintf("tx.height=%d", tx1.TxResponse.Height), "wasm.action='reset'", fmt.Sprintf("wasm._contract_address='%s'", contract)}, nil) + ev, err = tc.TxsEvents(ctx, []string{fmt.Sprintf("tx.height=%d", tx1.TxResponse.Height), "wasm.action='reset'", fmt.Sprintf("wasm._contract_address='%s'", contract)}, nil) require.NoError(t, err) require.Equal(t, 1, len(ev.TxResponses)) for _, ev := range ev.TxResponses[0].Logs[0].Events { @@ -335,10 +347,11 @@ func TestCosmosClient(t *testing.T) { }, } { t.Run(tt.name, func(t *testing.T) { + ctx := tests.Context(t) t.Log("Gas price:", tt.gasPrice) - an, sn, err := tc.Account(accounts[0].Address) + an, sn, err := tc.Account(ctx, accounts[0].Address) require.NoError(t, err) - resp, err := tc.SignAndBroadcast([]sdk.Msg{rawMsg}, an, sn, tt.gasPrice, accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) + resp, err := tc.SignAndBroadcast(ctx, []sdk.Msg{rawMsg}, an, sn, tt.gasPrice, accounts[0].PrivateKey, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) require.NotNil(t, resp) if tt.expCode == 0 { diff --git a/pkg/cosmos/client/mocks/ReaderWriter.go b/pkg/cosmos/client/mocks/ReaderWriter.go index 3400ca964..af14743a5 100644 --- a/pkg/cosmos/client/mocks/ReaderWriter.go +++ b/pkg/cosmos/client/mocks/ReaderWriter.go @@ -3,9 +3,12 @@ package mocks import ( - cosmos_sdkclient "github.com/cosmos/cosmos-sdk/client" + context "context" + client "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" + cosmos_sdkclient "github.com/cosmos/cosmos-sdk/client" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" mock "github.com/stretchr/testify/mock" @@ -24,9 +27,9 @@ type ReaderWriter struct { mock.Mock } -// Account provides a mock function with given fields: address -func (_m *ReaderWriter) Account(address types.AccAddress) (uint64, uint64, error) { - ret := _m.Called(address) +// Account provides a mock function with given fields: ctx, address +func (_m *ReaderWriter) Account(ctx context.Context, address types.AccAddress) (uint64, uint64, error) { + ret := _m.Called(ctx, address) if len(ret) == 0 { panic("no return value specified for Account") @@ -35,23 +38,23 @@ func (_m *ReaderWriter) Account(address types.AccAddress) (uint64, uint64, error var r0 uint64 var r1 uint64 var r2 error - if rf, ok := ret.Get(0).(func(types.AccAddress) (uint64, uint64, error)); ok { - return rf(address) + if rf, ok := ret.Get(0).(func(context.Context, types.AccAddress) (uint64, uint64, error)); ok { + return rf(ctx, address) } - if rf, ok := ret.Get(0).(func(types.AccAddress) uint64); ok { - r0 = rf(address) + if rf, ok := ret.Get(0).(func(context.Context, types.AccAddress) uint64); ok { + r0 = rf(ctx, address) } else { r0 = ret.Get(0).(uint64) } - if rf, ok := ret.Get(1).(func(types.AccAddress) uint64); ok { - r1 = rf(address) + if rf, ok := ret.Get(1).(func(context.Context, types.AccAddress) uint64); ok { + r1 = rf(ctx, address) } else { r1 = ret.Get(1).(uint64) } - if rf, ok := ret.Get(2).(func(types.AccAddress) error); ok { - r2 = rf(address) + if rf, ok := ret.Get(2).(func(context.Context, types.AccAddress) error); ok { + r2 = rf(ctx, address) } else { r2 = ret.Error(2) } @@ -59,9 +62,9 @@ func (_m *ReaderWriter) Account(address types.AccAddress) (uint64, uint64, error return r0, r1, r2 } -// Balance provides a mock function with given fields: addr, denom -func (_m *ReaderWriter) Balance(addr types.AccAddress, denom string) (*types.Coin, error) { - ret := _m.Called(addr, denom) +// Balance provides a mock function with given fields: ctx, addr, denom +func (_m *ReaderWriter) Balance(ctx context.Context, addr types.AccAddress, denom string) (*types.Coin, error) { + ret := _m.Called(ctx, addr, denom) if len(ret) == 0 { panic("no return value specified for Balance") @@ -69,19 +72,19 @@ func (_m *ReaderWriter) Balance(addr types.AccAddress, denom string) (*types.Coi var r0 *types.Coin var r1 error - if rf, ok := ret.Get(0).(func(types.AccAddress, string) (*types.Coin, error)); ok { - return rf(addr, denom) + if rf, ok := ret.Get(0).(func(context.Context, types.AccAddress, string) (*types.Coin, error)); ok { + return rf(ctx, addr, denom) } - if rf, ok := ret.Get(0).(func(types.AccAddress, string) *types.Coin); ok { - r0 = rf(addr, denom) + if rf, ok := ret.Get(0).(func(context.Context, types.AccAddress, string) *types.Coin); ok { + r0 = rf(ctx, addr, denom) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.Coin) } } - if rf, ok := ret.Get(1).(func(types.AccAddress, string) error); ok { - r1 = rf(addr, denom) + if rf, ok := ret.Get(1).(func(context.Context, types.AccAddress, string) error); ok { + r1 = rf(ctx, addr, denom) } else { r1 = ret.Error(1) } @@ -89,9 +92,9 @@ func (_m *ReaderWriter) Balance(addr types.AccAddress, denom string) (*types.Coi return r0, r1 } -// BatchSimulateUnsigned provides a mock function with given fields: msgs, sequence -func (_m *ReaderWriter) BatchSimulateUnsigned(msgs client.SimMsgs, sequence uint64) (*client.BatchSimResults, error) { - ret := _m.Called(msgs, sequence) +// BatchSimulateUnsigned provides a mock function with given fields: ctx, msgs, sequence +func (_m *ReaderWriter) BatchSimulateUnsigned(ctx context.Context, msgs client.SimMsgs, sequence uint64) (*client.BatchSimResults, error) { + ret := _m.Called(ctx, msgs, sequence) if len(ret) == 0 { panic("no return value specified for BatchSimulateUnsigned") @@ -99,19 +102,19 @@ func (_m *ReaderWriter) BatchSimulateUnsigned(msgs client.SimMsgs, sequence uint var r0 *client.BatchSimResults var r1 error - if rf, ok := ret.Get(0).(func(client.SimMsgs, uint64) (*client.BatchSimResults, error)); ok { - return rf(msgs, sequence) + if rf, ok := ret.Get(0).(func(context.Context, client.SimMsgs, uint64) (*client.BatchSimResults, error)); ok { + return rf(ctx, msgs, sequence) } - if rf, ok := ret.Get(0).(func(client.SimMsgs, uint64) *client.BatchSimResults); ok { - r0 = rf(msgs, sequence) + if rf, ok := ret.Get(0).(func(context.Context, client.SimMsgs, uint64) *client.BatchSimResults); ok { + r0 = rf(ctx, msgs, sequence) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*client.BatchSimResults) } } - if rf, ok := ret.Get(1).(func(client.SimMsgs, uint64) error); ok { - r1 = rf(msgs, sequence) + if rf, ok := ret.Get(1).(func(context.Context, client.SimMsgs, uint64) error); ok { + r1 = rf(ctx, msgs, sequence) } else { r1 = ret.Error(1) } @@ -119,9 +122,9 @@ func (_m *ReaderWriter) BatchSimulateUnsigned(msgs client.SimMsgs, sequence uint return r0, r1 } -// BlockByHeight provides a mock function with given fields: height -func (_m *ReaderWriter) BlockByHeight(height int64) (*tmservice.GetBlockByHeightResponse, error) { - ret := _m.Called(height) +// BlockByHeight provides a mock function with given fields: ctx, height +func (_m *ReaderWriter) BlockByHeight(ctx context.Context, height int64) (*tmservice.GetBlockByHeightResponse, error) { + ret := _m.Called(ctx, height) if len(ret) == 0 { panic("no return value specified for BlockByHeight") @@ -129,19 +132,19 @@ func (_m *ReaderWriter) BlockByHeight(height int64) (*tmservice.GetBlockByHeight var r0 *tmservice.GetBlockByHeightResponse var r1 error - if rf, ok := ret.Get(0).(func(int64) (*tmservice.GetBlockByHeightResponse, error)); ok { - return rf(height) + if rf, ok := ret.Get(0).(func(context.Context, int64) (*tmservice.GetBlockByHeightResponse, error)); ok { + return rf(ctx, height) } - if rf, ok := ret.Get(0).(func(int64) *tmservice.GetBlockByHeightResponse); ok { - r0 = rf(height) + if rf, ok := ret.Get(0).(func(context.Context, int64) *tmservice.GetBlockByHeightResponse); ok { + r0 = rf(ctx, height) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*tmservice.GetBlockByHeightResponse) } } - if rf, ok := ret.Get(1).(func(int64) error); ok { - r1 = rf(height) + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, height) } else { r1 = ret.Error(1) } @@ -149,9 +152,9 @@ func (_m *ReaderWriter) BlockByHeight(height int64) (*tmservice.GetBlockByHeight return r0, r1 } -// Broadcast provides a mock function with given fields: txBytes, mode -func (_m *ReaderWriter) Broadcast(txBytes []byte, mode tx.BroadcastMode) (*tx.BroadcastTxResponse, error) { - ret := _m.Called(txBytes, mode) +// Broadcast provides a mock function with given fields: ctx, txBytes, mode +func (_m *ReaderWriter) Broadcast(ctx context.Context, txBytes []byte, mode tx.BroadcastMode) (*tx.BroadcastTxResponse, error) { + ret := _m.Called(ctx, txBytes, mode) if len(ret) == 0 { panic("no return value specified for Broadcast") @@ -159,19 +162,19 @@ func (_m *ReaderWriter) Broadcast(txBytes []byte, mode tx.BroadcastMode) (*tx.Br var r0 *tx.BroadcastTxResponse var r1 error - if rf, ok := ret.Get(0).(func([]byte, tx.BroadcastMode) (*tx.BroadcastTxResponse, error)); ok { - return rf(txBytes, mode) + if rf, ok := ret.Get(0).(func(context.Context, []byte, tx.BroadcastMode) (*tx.BroadcastTxResponse, error)); ok { + return rf(ctx, txBytes, mode) } - if rf, ok := ret.Get(0).(func([]byte, tx.BroadcastMode) *tx.BroadcastTxResponse); ok { - r0 = rf(txBytes, mode) + if rf, ok := ret.Get(0).(func(context.Context, []byte, tx.BroadcastMode) *tx.BroadcastTxResponse); ok { + r0 = rf(ctx, txBytes, mode) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*tx.BroadcastTxResponse) } } - if rf, ok := ret.Get(1).(func([]byte, tx.BroadcastMode) error); ok { - r1 = rf(txBytes, mode) + if rf, ok := ret.Get(1).(func(context.Context, []byte, tx.BroadcastMode) error); ok { + r1 = rf(ctx, txBytes, mode) } else { r1 = ret.Error(1) } @@ -199,9 +202,9 @@ func (_m *ReaderWriter) Context() *cosmos_sdkclient.Context { return r0 } -// ContractState provides a mock function with given fields: contractAddress, queryMsg -func (_m *ReaderWriter) ContractState(contractAddress types.AccAddress, queryMsg []byte) ([]byte, error) { - ret := _m.Called(contractAddress, queryMsg) +// ContractState provides a mock function with given fields: ctx, contractAddress, queryMsg +func (_m *ReaderWriter) ContractState(ctx context.Context, contractAddress types.AccAddress, queryMsg []byte) ([]byte, error) { + ret := _m.Called(ctx, contractAddress, queryMsg) if len(ret) == 0 { panic("no return value specified for ContractState") @@ -209,19 +212,19 @@ func (_m *ReaderWriter) ContractState(contractAddress types.AccAddress, queryMsg var r0 []byte var r1 error - if rf, ok := ret.Get(0).(func(types.AccAddress, []byte) ([]byte, error)); ok { - return rf(contractAddress, queryMsg) + if rf, ok := ret.Get(0).(func(context.Context, types.AccAddress, []byte) ([]byte, error)); ok { + return rf(ctx, contractAddress, queryMsg) } - if rf, ok := ret.Get(0).(func(types.AccAddress, []byte) []byte); ok { - r0 = rf(contractAddress, queryMsg) + if rf, ok := ret.Get(0).(func(context.Context, types.AccAddress, []byte) []byte); ok { + r0 = rf(ctx, contractAddress, queryMsg) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]byte) } } - if rf, ok := ret.Get(1).(func(types.AccAddress, []byte) error); ok { - r1 = rf(contractAddress, queryMsg) + if rf, ok := ret.Get(1).(func(context.Context, types.AccAddress, []byte) error); ok { + r1 = rf(ctx, contractAddress, queryMsg) } else { r1 = ret.Error(1) } @@ -259,9 +262,9 @@ func (_m *ReaderWriter) CreateAndSign(msgs []types.Msg, account uint64, sequence return r0, r1 } -// LatestBlock provides a mock function with given fields: -func (_m *ReaderWriter) LatestBlock() (*tmservice.GetLatestBlockResponse, error) { - ret := _m.Called() +// LatestBlock provides a mock function with given fields: _a0 +func (_m *ReaderWriter) LatestBlock(_a0 context.Context) (*tmservice.GetLatestBlockResponse, error) { + ret := _m.Called(_a0) if len(ret) == 0 { panic("no return value specified for LatestBlock") @@ -269,19 +272,19 @@ func (_m *ReaderWriter) LatestBlock() (*tmservice.GetLatestBlockResponse, error) var r0 *tmservice.GetLatestBlockResponse var r1 error - if rf, ok := ret.Get(0).(func() (*tmservice.GetLatestBlockResponse, error)); ok { - return rf() + if rf, ok := ret.Get(0).(func(context.Context) (*tmservice.GetLatestBlockResponse, error)); ok { + return rf(_a0) } - if rf, ok := ret.Get(0).(func() *tmservice.GetLatestBlockResponse); ok { - r0 = rf() + if rf, ok := ret.Get(0).(func(context.Context) *tmservice.GetLatestBlockResponse); ok { + r0 = rf(_a0) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*tmservice.GetLatestBlockResponse) } } - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) } else { r1 = ret.Error(1) } @@ -289,9 +292,9 @@ func (_m *ReaderWriter) LatestBlock() (*tmservice.GetLatestBlockResponse, error) return r0, r1 } -// SignAndBroadcast provides a mock function with given fields: msgs, accountNum, sequence, gasPrice, signer, mode -func (_m *ReaderWriter) SignAndBroadcast(msgs []types.Msg, accountNum uint64, sequence uint64, gasPrice types.DecCoin, signer cryptotypes.PrivKey, mode tx.BroadcastMode) (*tx.BroadcastTxResponse, error) { - ret := _m.Called(msgs, accountNum, sequence, gasPrice, signer, mode) +// SignAndBroadcast provides a mock function with given fields: ctx, msgs, accountNum, sequence, gasPrice, signer, mode +func (_m *ReaderWriter) SignAndBroadcast(ctx context.Context, msgs []types.Msg, accountNum uint64, sequence uint64, gasPrice types.DecCoin, signer cryptotypes.PrivKey, mode tx.BroadcastMode) (*tx.BroadcastTxResponse, error) { + ret := _m.Called(ctx, msgs, accountNum, sequence, gasPrice, signer, mode) if len(ret) == 0 { panic("no return value specified for SignAndBroadcast") @@ -299,19 +302,19 @@ func (_m *ReaderWriter) SignAndBroadcast(msgs []types.Msg, accountNum uint64, se var r0 *tx.BroadcastTxResponse var r1 error - if rf, ok := ret.Get(0).(func([]types.Msg, uint64, uint64, types.DecCoin, cryptotypes.PrivKey, tx.BroadcastMode) (*tx.BroadcastTxResponse, error)); ok { - return rf(msgs, accountNum, sequence, gasPrice, signer, mode) + if rf, ok := ret.Get(0).(func(context.Context, []types.Msg, uint64, uint64, types.DecCoin, cryptotypes.PrivKey, tx.BroadcastMode) (*tx.BroadcastTxResponse, error)); ok { + return rf(ctx, msgs, accountNum, sequence, gasPrice, signer, mode) } - if rf, ok := ret.Get(0).(func([]types.Msg, uint64, uint64, types.DecCoin, cryptotypes.PrivKey, tx.BroadcastMode) *tx.BroadcastTxResponse); ok { - r0 = rf(msgs, accountNum, sequence, gasPrice, signer, mode) + if rf, ok := ret.Get(0).(func(context.Context, []types.Msg, uint64, uint64, types.DecCoin, cryptotypes.PrivKey, tx.BroadcastMode) *tx.BroadcastTxResponse); ok { + r0 = rf(ctx, msgs, accountNum, sequence, gasPrice, signer, mode) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*tx.BroadcastTxResponse) } } - if rf, ok := ret.Get(1).(func([]types.Msg, uint64, uint64, types.DecCoin, cryptotypes.PrivKey, tx.BroadcastMode) error); ok { - r1 = rf(msgs, accountNum, sequence, gasPrice, signer, mode) + if rf, ok := ret.Get(1).(func(context.Context, []types.Msg, uint64, uint64, types.DecCoin, cryptotypes.PrivKey, tx.BroadcastMode) error); ok { + r1 = rf(ctx, msgs, accountNum, sequence, gasPrice, signer, mode) } else { r1 = ret.Error(1) } @@ -319,9 +322,9 @@ func (_m *ReaderWriter) SignAndBroadcast(msgs []types.Msg, accountNum uint64, se return r0, r1 } -// Simulate provides a mock function with given fields: txBytes -func (_m *ReaderWriter) Simulate(txBytes []byte) (*tx.SimulateResponse, error) { - ret := _m.Called(txBytes) +// Simulate provides a mock function with given fields: ctx, txBytes +func (_m *ReaderWriter) Simulate(ctx context.Context, txBytes []byte) (*tx.SimulateResponse, error) { + ret := _m.Called(ctx, txBytes) if len(ret) == 0 { panic("no return value specified for Simulate") @@ -329,19 +332,19 @@ func (_m *ReaderWriter) Simulate(txBytes []byte) (*tx.SimulateResponse, error) { var r0 *tx.SimulateResponse var r1 error - if rf, ok := ret.Get(0).(func([]byte) (*tx.SimulateResponse, error)); ok { - return rf(txBytes) + if rf, ok := ret.Get(0).(func(context.Context, []byte) (*tx.SimulateResponse, error)); ok { + return rf(ctx, txBytes) } - if rf, ok := ret.Get(0).(func([]byte) *tx.SimulateResponse); ok { - r0 = rf(txBytes) + if rf, ok := ret.Get(0).(func(context.Context, []byte) *tx.SimulateResponse); ok { + r0 = rf(ctx, txBytes) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*tx.SimulateResponse) } } - if rf, ok := ret.Get(1).(func([]byte) error); ok { - r1 = rf(txBytes) + if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok { + r1 = rf(ctx, txBytes) } else { r1 = ret.Error(1) } @@ -349,9 +352,9 @@ func (_m *ReaderWriter) Simulate(txBytes []byte) (*tx.SimulateResponse, error) { return r0, r1 } -// SimulateUnsigned provides a mock function with given fields: msgs, sequence -func (_m *ReaderWriter) SimulateUnsigned(msgs []types.Msg, sequence uint64) (*tx.SimulateResponse, error) { - ret := _m.Called(msgs, sequence) +// SimulateUnsigned provides a mock function with given fields: ctx, msgs, sequence +func (_m *ReaderWriter) SimulateUnsigned(ctx context.Context, msgs []types.Msg, sequence uint64) (*tx.SimulateResponse, error) { + ret := _m.Called(ctx, msgs, sequence) if len(ret) == 0 { panic("no return value specified for SimulateUnsigned") @@ -359,19 +362,19 @@ func (_m *ReaderWriter) SimulateUnsigned(msgs []types.Msg, sequence uint64) (*tx var r0 *tx.SimulateResponse var r1 error - if rf, ok := ret.Get(0).(func([]types.Msg, uint64) (*tx.SimulateResponse, error)); ok { - return rf(msgs, sequence) + if rf, ok := ret.Get(0).(func(context.Context, []types.Msg, uint64) (*tx.SimulateResponse, error)); ok { + return rf(ctx, msgs, sequence) } - if rf, ok := ret.Get(0).(func([]types.Msg, uint64) *tx.SimulateResponse); ok { - r0 = rf(msgs, sequence) + if rf, ok := ret.Get(0).(func(context.Context, []types.Msg, uint64) *tx.SimulateResponse); ok { + r0 = rf(ctx, msgs, sequence) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*tx.SimulateResponse) } } - if rf, ok := ret.Get(1).(func([]types.Msg, uint64) error); ok { - r1 = rf(msgs, sequence) + if rf, ok := ret.Get(1).(func(context.Context, []types.Msg, uint64) error); ok { + r1 = rf(ctx, msgs, sequence) } else { r1 = ret.Error(1) } @@ -379,9 +382,9 @@ func (_m *ReaderWriter) SimulateUnsigned(msgs []types.Msg, sequence uint64) (*tx return r0, r1 } -// Tx provides a mock function with given fields: hash -func (_m *ReaderWriter) Tx(hash string) (*tx.GetTxResponse, error) { - ret := _m.Called(hash) +// Tx provides a mock function with given fields: ctx, hash +func (_m *ReaderWriter) Tx(ctx context.Context, hash string) (*tx.GetTxResponse, error) { + ret := _m.Called(ctx, hash) if len(ret) == 0 { panic("no return value specified for Tx") @@ -389,19 +392,19 @@ func (_m *ReaderWriter) Tx(hash string) (*tx.GetTxResponse, error) { var r0 *tx.GetTxResponse var r1 error - if rf, ok := ret.Get(0).(func(string) (*tx.GetTxResponse, error)); ok { - return rf(hash) + if rf, ok := ret.Get(0).(func(context.Context, string) (*tx.GetTxResponse, error)); ok { + return rf(ctx, hash) } - if rf, ok := ret.Get(0).(func(string) *tx.GetTxResponse); ok { - r0 = rf(hash) + if rf, ok := ret.Get(0).(func(context.Context, string) *tx.GetTxResponse); ok { + r0 = rf(ctx, hash) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*tx.GetTxResponse) } } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(hash) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, hash) } else { r1 = ret.Error(1) } @@ -409,9 +412,9 @@ func (_m *ReaderWriter) Tx(hash string) (*tx.GetTxResponse, error) { return r0, r1 } -// TxsEvents provides a mock function with given fields: events, paginationParams -func (_m *ReaderWriter) TxsEvents(events []string, paginationParams *query.PageRequest) (*tx.GetTxsEventResponse, error) { - ret := _m.Called(events, paginationParams) +// TxsEvents provides a mock function with given fields: ctx, events, paginationParams +func (_m *ReaderWriter) TxsEvents(ctx context.Context, events []string, paginationParams *query.PageRequest) (*tx.GetTxsEventResponse, error) { + ret := _m.Called(ctx, events, paginationParams) if len(ret) == 0 { panic("no return value specified for TxsEvents") @@ -419,19 +422,19 @@ func (_m *ReaderWriter) TxsEvents(events []string, paginationParams *query.PageR var r0 *tx.GetTxsEventResponse var r1 error - if rf, ok := ret.Get(0).(func([]string, *query.PageRequest) (*tx.GetTxsEventResponse, error)); ok { - return rf(events, paginationParams) + if rf, ok := ret.Get(0).(func(context.Context, []string, *query.PageRequest) (*tx.GetTxsEventResponse, error)); ok { + return rf(ctx, events, paginationParams) } - if rf, ok := ret.Get(0).(func([]string, *query.PageRequest) *tx.GetTxsEventResponse); ok { - r0 = rf(events, paginationParams) + if rf, ok := ret.Get(0).(func(context.Context, []string, *query.PageRequest) *tx.GetTxsEventResponse); ok { + r0 = rf(ctx, events, paginationParams) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*tx.GetTxsEventResponse) } } - if rf, ok := ret.Get(1).(func([]string, *query.PageRequest) error); ok { - r1 = rf(events, paginationParams) + if rf, ok := ret.Get(1).(func(context.Context, []string, *query.PageRequest) error); ok { + r1 = rf(ctx, events, paginationParams) } else { r1 = ret.Error(1) } diff --git a/pkg/cosmos/client/test_helpers.go b/pkg/cosmos/client/test_helpers.go index fd6bdc2a1..899e6cfcd 100644 --- a/pkg/cosmos/client/test_helpers.go +++ b/pkg/cosmos/client/test_helpers.go @@ -14,10 +14,6 @@ import ( "testing" "time" - "github.com/tidwall/gjson" - - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/testutil" - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -25,6 +21,11 @@ import ( "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/testutil" ) type Account struct { @@ -156,6 +157,7 @@ func SetupLocalCosmosNode(t *testing.T, chainID string, token string) ([]Account // DeployTestContract deploys a test contract. func DeployTestContract(t *testing.T, tendermintURL, chainID string, token string, deployAccount, ownerAccount Account, tc *Client, testdir, wasmTestContractPath string) sdk.AccAddress { + ctx := tests.Context(t) minGasPrice := sdk.NewDecCoinFromDec(token, defaultCoin) //nolint:gosec submitResp, err2 := exec.Command("wasmd", "tx", "wasm", "store", wasmTestContractPath, "--node", tendermintURL, @@ -173,9 +175,9 @@ func DeployTestContract(t *testing.T, tendermintURL, chainID string, token strin codeID, err := strconv.ParseUint(storeCodeLog.GetEvents()[1].Attributes[1].Value, 10, 64) require.NoError(t, err, "failed to parse code id from tx receipt") - accountNumber, sequenceNumber, err := tc.Account(ownerAccount.Address) + accountNumber, sequenceNumber, err := tc.Account(ctx, ownerAccount.Address) require.NoError(t, err) - deployTx, err3 := tc.SignAndBroadcast([]sdk.Msg{ + deployTx, err3 := tc.SignAndBroadcast(ctx, []sdk.Msg{ &wasmtypes.MsgInstantiateContract{ Sender: ownerAccount.Address.String(), Admin: "", @@ -221,8 +223,9 @@ func mustRandomPort() int { // AwaitTxCommitted waits for a transaction to be committed on chain and returns the tx receipt func AwaitTxCommitted(t *testing.T, tc *Client, txHash string) (response *txtypes.GetTxResponse, success bool) { + ctx := tests.Context(t) for i := 0; i < 10; i++ { // max poll attempts to wait for tx commitment - txReceipt, err := tc.Tx(txHash) + txReceipt, err := tc.Tx(ctx, txHash) if err == nil { return txReceipt, true } diff --git a/pkg/cosmos/txm/helpers_test.go b/pkg/cosmos/txm/helpers_test.go index eac916d7f..2af8c0c4b 100644 --- a/pkg/cosmos/txm/helpers_test.go +++ b/pkg/cosmos/txm/helpers_test.go @@ -1,11 +1,15 @@ package txm -import "golang.org/x/exp/maps" +import ( + "context" -func (ka *keystoreAdapter) Accounts() ([]string, error) { + "golang.org/x/exp/maps" +) + +func (ka *keystoreAdapter) Accounts(ctx context.Context) ([]string, error) { ka.mutex.Lock() defer ka.mutex.Unlock() - err := ka.updateMappingLocked() + err := ka.updateMappingLocked(ctx) if err != nil { return nil, err } diff --git a/pkg/cosmos/txm/key_wrapper.go b/pkg/cosmos/txm/key_wrapper.go index fd8263974..c6325b53b 100644 --- a/pkg/cosmos/txm/key_wrapper.go +++ b/pkg/cosmos/txm/key_wrapper.go @@ -33,7 +33,7 @@ func (a *KeyWrapper) Sign(msg []byte) ([]byte, error) { } func (a *KeyWrapper) PubKey() cryptotypes.PubKey { - pubKey, err := a.adapter.PubKey(a.account) + pubKey, err := a.adapter.PubKey(context.Background(), a.account) if err != nil { // return an empty pubkey if it's not found. return &secp256k1.PubKey{Key: []byte{}} diff --git a/pkg/cosmos/txm/keystore_adapter.go b/pkg/cosmos/txm/keystore_adapter.go index eacd41373..c06c14aa0 100644 --- a/pkg/cosmos/txm/keystore_adapter.go +++ b/pkg/cosmos/txm/keystore_adapter.go @@ -37,8 +37,8 @@ func newKeystoreAdapter(keystore loop.Keystore, accountPrefix string) *keystoreA } } -func (ka *keystoreAdapter) updateMappingLocked() error { - accounts, err := ka.keystore.Accounts(context.Background()) +func (ka *keystoreAdapter) updateMappingLocked(ctx context.Context) error { + accounts, err := ka.keystore.Accounts(ctx) if err != nil { return err } @@ -90,14 +90,14 @@ func (ka *keystoreAdapter) updateMappingLocked() error { return nil } -func (ka *keystoreAdapter) lookup(id string) (*accountInfo, error) { +func (ka *keystoreAdapter) lookup(ctx context.Context, id string) (*accountInfo, error) { ka.mutex.RLock() ai, ok := ka.addressToPubKey[id] ka.mutex.RUnlock() if !ok { // try updating the mapping once, incase there was an update on the keystore. ka.mutex.Lock() - err := ka.updateMappingLocked() + err := ka.updateMappingLocked(ctx) if err != nil { ka.mutex.Unlock() return nil, err @@ -112,7 +112,7 @@ func (ka *keystoreAdapter) lookup(id string) (*accountInfo, error) { } func (ka *keystoreAdapter) Sign(ctx context.Context, id string, hash []byte) ([]byte, error) { - accountInfo, err := ka.lookup(id) + accountInfo, err := ka.lookup(ctx, id) if err != nil { return nil, err } @@ -120,8 +120,8 @@ func (ka *keystoreAdapter) Sign(ctx context.Context, id string, hash []byte) ([] } // Returns the cosmos PubKey associated with the prefixed address. -func (ka *keystoreAdapter) PubKey(address string) (cryptotypes.PubKey, error) { - accountInfo, err := ka.lookup(address) +func (ka *keystoreAdapter) PubKey(ctx context.Context, address string) (cryptotypes.PubKey, error) { + accountInfo, err := ka.lookup(ctx, address) if err != nil { return nil, err } diff --git a/pkg/cosmos/txm/txm.go b/pkg/cosmos/txm/txm.go index 9ffacea6f..efe0dc67f 100644 --- a/pkg/cosmos/txm/txm.go +++ b/pkg/cosmos/txm/txm.go @@ -273,7 +273,7 @@ func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoi txm.lggr.Criticalw("unable to get client", "err", err) return err } - an, sn, err := tc.Account(sender) + an, sn, err := tc.Account(ctx, sender) if err != nil { txm.lggr.Warnw("unable to read account", "err", err, "from", sender.String()) // If we can't read the account, assume transient api issues and leave msgs unstarted @@ -282,7 +282,7 @@ func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoi } txm.lggr.Debugw("simulating batch", "from", sender, "msgs", msgs, "seqnum", sn) - simResults, err := tc.BatchSimulateUnsigned(msgs.GetSimMsgs(), sn) + simResults, err := tc.BatchSimulateUnsigned(ctx, msgs.GetSimMsgs(), sn) if err != nil { txm.lggr.Warnw("unable to simulate", "err", err, "from", sender.String()) // If we can't simulate assume transient api issue and retry on next poll. @@ -305,7 +305,7 @@ func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoi return errors.New("all sim msgs errored") } // Get the gas limit for the successful batch - s, err := tc.SimulateUnsigned(simResults.Succeeded.GetMsgs(), sn) + s, err := tc.SimulateUnsigned(ctx, simResults.Succeeded.GetMsgs(), sn) if err != nil { // In the OCR context this should only happen upon stale report txm.lggr.Warnw("unexpected failure after successful simulation", "err", err) @@ -313,7 +313,7 @@ func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoi } gasLimit := s.GasInfo.GasUsed - lb, err := tc.LatestBlock() + lb, err := tc.LatestBlock(ctx) if err != nil { txm.lggr.Warnw("unable to get latest block", "err", err, "from", sender.String()) // Assume transient api issue and retry. @@ -347,7 +347,7 @@ func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoi } txm.lggr.Infow("broadcasting tx", "from", sender, "msgs", simResults.Succeeded, "gasLimit", gasLimit, "gasPrice", gasPrice.String(), "timeoutHeight", timeoutHeight, "hash", txHash) - resp, err = tc.Broadcast(signedTx, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) + resp, err = tc.Broadcast(ctx, signedTx, txtypes.BroadcastMode_BROADCAST_MODE_SYNC) if err != nil { // Rollback marking as broadcasted // Note can happen if the node's mempool is full, where we expect errCode 20. @@ -407,7 +407,7 @@ func (txm *Txm) confirmTx(ctx context.Context, tc client.Reader, txHash string, } // Confirm that this tx is onchain, ensuring the sequence number has incremented // so we can build a new batch - tx, err := tc.Tx(txHash) + tx, err := tc.Tx(ctx, txHash) if err != nil { if strings.Contains(err.Error(), "not found") { txm.lggr.Infow("txhash not found yet, still confirming", "hash", txHash) diff --git a/pkg/cosmos/txm/txm_internal_test.go b/pkg/cosmos/txm/txm_internal_test.go index 7939eea97..e829d2402 100644 --- a/pkg/cosmos/txm/txm_internal_test.go +++ b/pkg/cosmos/txm/txm_internal_test.go @@ -37,20 +37,14 @@ func generateExecuteMsg(msg []byte, from, to cosmostypes.AccAddress) cosmostypes } } -func newReaderWriterMock(t *testing.T) *mocks.ReaderWriter { - tc := new(mocks.ReaderWriter) - tc.Test(t) - t.Cleanup(func() { tc.AssertExpectations(t) }) - return tc -} - func TestTxm(t *testing.T) { + ctx := tests.Context(t) lggr := logger.Test(t) db := NewDB(t) ks := newKeystore(4) adapter := newKeystoreAdapter(ks, "wasm") - accounts, err := adapter.Accounts() + accounts, err := adapter.Accounts(ctx) require.NoError(t, err) require.Equal(t, len(accounts), 4) @@ -81,7 +75,7 @@ func TestTxm(t *testing.T) { t.Run("single msg", func(t *testing.T) { ctx := tests.Context(t) - tc := newReaderWriterMock(t) + tc := mocks.NewReaderWriter(t) tcFn := func() (client.ReaderWriter, error) { return tc, nil } loopKs := newKeystore(1) txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr) @@ -119,7 +113,7 @@ func TestTxm(t *testing.T) { t.Run("two msgs different accounts", func(t *testing.T) { ctx := tests.Context(t) - tc := newReaderWriterMock(t) + tc := mocks.NewReaderWriter(t) tcFn := func() (client.ReaderWriter, error) { return tc, nil } loopKs := newKeystore(1) txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr) @@ -176,7 +170,7 @@ func TestTxm(t *testing.T) { t.Run("two msgs different contracts", func(t *testing.T) { ctx := tests.Context(t) - tc := newReaderWriterMock(t) + tc := mocks.NewReaderWriter(t) tcFn := func() (client.ReaderWriter, error) { return tc, nil } loopKs := newKeystore(1) txm := NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr) @@ -237,7 +231,7 @@ func TestTxm(t *testing.T) { t.Run("failed to confirm", func(t *testing.T) { ctx := tests.Context(t) - tc := newReaderWriterMock(t) + tc := mocks.NewReaderWriter(t) tc.On("Tx", mock.Anything).Return(&txtypes.GetTxResponse{ Tx: &txtypes.Tx{}, TxResponse: &cosmostypes.TxResponse{TxHash: "0x123"}, @@ -264,7 +258,7 @@ func TestTxm(t *testing.T) { txHash1 := "0x1234" txHash2 := "0x1235" txHash3 := "0xabcd" - tc := newReaderWriterMock(t) + tc := mocks.NewReaderWriter(t) tc.On("Tx", txHash1).Return(&txtypes.GetTxResponse{ TxResponse: &cosmostypes.TxResponse{TxHash: txHash1}, }, nil).Once() diff --git a/pkg/monitoring/chain_reader.go b/pkg/monitoring/chain_reader.go index eedb48e35..0879f6e90 100644 --- a/pkg/monitoring/chain_reader.go +++ b/pkg/monitoring/chain_reader.go @@ -9,9 +9,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" txtypes "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/smartcontractkit/chainlink-common/pkg/logger" "go.uber.org/ratelimit" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + pkgClient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" ) @@ -45,7 +46,7 @@ type chainReader struct { rateLimiter ratelimit.Limiter } -func (c *chainReader) TxsEvents(_ context.Context, events []string, paginationParams *query.PageRequest) (*txtypes.GetTxsEventResponse, error) { +func (c *chainReader) TxsEvents(ctx context.Context, events []string, paginationParams *query.PageRequest) (*txtypes.GetTxsEventResponse, error) { c.globalSequencer.Lock() defer c.globalSequencer.Unlock() client, err := pkgClient.NewClient( @@ -58,10 +59,10 @@ func (c *chainReader) TxsEvents(_ context.Context, events []string, paginationPa return nil, fmt.Errorf("failed to create a cosmos client: %w", err) } _ = c.rateLimiter.Take() - return client.TxsEvents(events, paginationParams) + return client.TxsEvents(ctx, events, paginationParams) } -func (c *chainReader) ContractState(_ context.Context, contractAddress sdk.AccAddress, queryMsg []byte) ([]byte, error) { +func (c *chainReader) ContractState(ctx context.Context, contractAddress sdk.AccAddress, queryMsg []byte) ([]byte, error) { c.globalSequencer.Lock() defer c.globalSequencer.Unlock() client, err := pkgClient.NewClient( @@ -74,5 +75,5 @@ func (c *chainReader) ContractState(_ context.Context, contractAddress sdk.AccAd return nil, fmt.Errorf("failed to create a cosmos client: %w", err) } _ = c.rateLimiter.Take() - return client.ContractState(contractAddress, queryMsg) + return client.ContractState(ctx, contractAddress, queryMsg) } diff --git a/pkg/monitoring/testutils.go b/pkg/monitoring/helper_test.go similarity index 57% rename from pkg/monitoring/testutils.go rename to pkg/monitoring/helper_test.go index 6c79b1b85..e1a88591a 100644 --- a/pkg/monitoring/testutils.go +++ b/pkg/monitoring/helper_test.go @@ -1,22 +1,25 @@ package monitoring import ( - "context" cryptoRand "crypto/rand" "fmt" "math/big" "math/rand" + "testing" "time" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" - relayMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring" ) // Generators -func generateChainConfig() CosmosConfig { - address, _ := sdk.AccAddressFromBech32("wasm106x8mk9asfnptt5rqw5kx6hs8f75fseqa8rfz2") +func generateChainConfig(t *testing.T) CosmosConfig { + address, err := sdk.AccAddressFromBech32(randBech32()) + require.NoError(t, err) return CosmosConfig{ TendermintURL: "https://some-tendermint-url.com", FCDURL: "https://fcd.terra.dev", @@ -29,11 +32,13 @@ func generateChainConfig() CosmosConfig { } } -func generateFeedConfig() CosmosFeedConfig { +func generateFeedConfig(t *testing.T) CosmosFeedConfig { coins := []string{"btc", "eth", "matic", "link", "avax", "ftt", "srm", "usdc", "sol", "ray"} coin := coins[rand.Intn(len(coins))] - address, _ := sdk.AccAddressFromBech32("wasm106x8mk9asfnptt5rqw5kx6hs8f75fseqa8rfz2") - proxyAddress, _ := sdk.AccAddressFromBech32("wasm106x8mk9asfnptt5rqw5kx6hs8f75fseqa8rfz2") + address, err := sdk.AccAddressFromBech32(randBech32()) + require.NoError(t, err) + proxyAddress, err := sdk.AccAddressFromBech32(randBech32()) + require.NoError(t, err) return CosmosFeedConfig{ Name: fmt.Sprintf("%s / usd", coin), Path: fmt.Sprintf("%s-usd", coin), @@ -70,40 +75,10 @@ func generateProxyData() ProxyData { // Sources -// NewFakeProxySourceFactory makes a source that generates random proxy data. -func NewFakeProxySourceFactory(log relayMonitoring.Logger) relayMonitoring.SourceFactory { - return &fakeProxySourceFactory{log} -} - -type fakeProxySourceFactory struct { - log relayMonitoring.Logger -} - -func (f *fakeProxySourceFactory) NewSource( - _ relayMonitoring.ChainConfig, - _ relayMonitoring.FeedConfig, -) (relayMonitoring.Source, error) { - return &fakeProxySource{f.log}, nil -} - -func (f *fakeProxySourceFactory) GetType() string { - return "fake-proxy" -} - -type fakeProxySource struct { - log relayMonitoring.Logger -} - -func (f *fakeProxySource) Fetch(ctx context.Context) (interface{}, error) { - return generateProxyData(), nil -} - func newNullLogger() logger.Logger { return logger.Nop() } -var ( - _ = newNullLogger() - _ = generateChainConfig() - _ = generateFeedConfig() -) +func randBech32() string { + return sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address().Bytes()).String() +} diff --git a/pkg/monitoring/proxy_monitoring_test.go b/pkg/monitoring/proxy_monitoring_test.go index be9df4cd0..7b710c4a5 100644 --- a/pkg/monitoring/proxy_monitoring_test.go +++ b/pkg/monitoring/proxy_monitoring_test.go @@ -4,13 +4,14 @@ import ( "context" "math/big" "testing" - "time" sdk "github.com/cosmos/cosmos-sdk/types" - relayMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + relayMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-cosmos/pkg/monitoring/mocks" ) @@ -22,22 +23,22 @@ func TestProxyMonitoring(t *testing.T) { // It does so by using a mock ChainReader to return values that the real proxy would return. // Then it uses a mock Metrics object to record the data exported to prometheus. - ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) - defer cancel() + ctx := tests.Context(t) - chainConfig := generateChainConfig() - feedConfig := generateFeedConfig() + chainConfig := generateChainConfig(t) + feedConfig := generateFeedConfig(t) feedConfig.Multiply = big.NewInt(100) nodes := []relayMonitoring.NodeConfig{} chainReader := mocks.NewChainReader(t) metrics := mocks.NewMetrics(t) - sourceFactory := NewProxySourceFactory(chainReader, newNullLogger()) + lggr := logger.Test(t) + sourceFactory := NewProxySourceFactory(chainReader, lggr) source, err := sourceFactory.NewSource(chainConfig, feedConfig) require.NoError(t, err) - exporterFactory := NewPrometheusExporterFactory(newNullLogger(), metrics) + exporterFactory := NewPrometheusExporterFactory(lggr, metrics) exporter, err := exporterFactory.NewExporter(relayMonitoring.ExporterParams{ChainConfig: chainConfig, FeedConfig: feedConfig, Nodes: nodes}) require.NoError(t, err) @@ -94,14 +95,14 @@ func TestProxyMonitoring(t *testing.T) { }) t.Run("contract without a proxy are not monitored by the proxy source", func(t *testing.T) { - chainConfig := generateChainConfig() - feedConfig := generateFeedConfig() + chainConfig := generateChainConfig(t) + feedConfig := generateFeedConfig(t) feedConfig.ProxyAddressBech32 = "" feedConfig.ProxyAddress = sdk.AccAddress{} chainReader := mocks.NewChainReader(t) - sourceFactory := NewProxySourceFactory(chainReader, newNullLogger()) + sourceFactory := NewProxySourceFactory(chainReader, logger.Test(t)) source, err := sourceFactory.NewSource(chainConfig, feedConfig) require.NoError(t, err) diff --git a/pkg/monitoring/source_envelope_test.go b/pkg/monitoring/source_envelope_test.go index 175e2d45d..63ba1fbc7 100644 --- a/pkg/monitoring/source_envelope_test.go +++ b/pkg/monitoring/source_envelope_test.go @@ -1,29 +1,70 @@ package monitoring import ( - "context" "encoding/hex" "encoding/json" + "fmt" "math/big" "os" + "strings" "testing" "time" + "github.com/cosmos/btcutil/bech32" sdk "github.com/cosmos/cosmos-sdk/types" - ocr2types "github.com/smartcontractkit/libocr/offchainreporting2/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + ocr2types "github.com/smartcontractkit/libocr/offchainreporting2/types" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" relayMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/params" "github.com/smartcontractkit/chainlink-cosmos/pkg/monitoring/fcdclient" fcdclientmocks "github.com/smartcontractkit/chainlink-cosmos/pkg/monitoring/fcdclient/mocks" "github.com/smartcontractkit/chainlink-cosmos/pkg/monitoring/mocks" ) +const bech32Prefix = "wasm" + +func TestMain(m *testing.M) { + // these are hardcoded in test_helpers.go. + params.InitCosmosSdk( + bech32Prefix, + /* token= */ "cosm", + ) + os.Exit(m.Run()) +} + +// accAddressFromBech32 is like [sdk.AccAdressFromBech32], but does not validate the checksum. +// Deprecated: Don't use this. It was just required to patch a test. +func accAddressFromBech32(t *testing.T, addr string) sdk.AccAddress { + t.Helper() + if len(strings.TrimSpace(addr)) == 0 { + t.Fatal("empty address string is not allowed") + } + + _, err := bech32.Normalize(&addr) + if err != nil { + t.Fatal(err) + } + + _, b, _, err := bech32.DecodeUnsafe(addr) + if err != nil { + t.Fatal(err) + } + converted, err := bech32.ConvertBits(b, 5, 8, false) + if err != nil { + t.Fatalf("decoding bech32 failed: %s", err) + } + + return converted +} + func TestEnvelopeSource(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond) - defer cancel() + ctx := tests.Context(t) // Setup API responses balanceRes := []byte(`{"balance":"1234567890987654321"}`) @@ -39,14 +80,14 @@ func TestEnvelopeSource(t *testing.T) { require.NoError(t, json.Unmarshal(getTxsRaw, &getTxsRes)) // Configurations. - feedConfig := generateFeedConfig() + feedConfig := generateFeedConfig(t) feedConfig.ContractAddressBech32 = "wasm10kc4n52rk4xqny3hdew3ggjfk9r420pqxs9ylf" - feedConfig.ContractAddress, _ = sdk.AccAddressFromBech32("wasm10kc4n52rk4xqny3hdew3ggjfk9r420pqxs9ylf") - chainConfig := generateChainConfig() + feedConfig.ContractAddress = accAddressFromBech32(t, feedConfig.ContractAddressBech32) + chainConfig := generateChainConfig(t) // Setup mocks. rpcClient := mocks.NewChainReader(t) - fcdClient := new(fcdclientmocks.Client) + fcdClient := fcdclientmocks.NewClient(t) // Transmission fcdClient.On("GetTxList", mock.Anything, // context @@ -66,7 +107,7 @@ func TestEnvelopeSource(t *testing.T) { rpcClient.On("ContractState", mock.Anything, // context chainConfig.LinkTokenAddress, - []byte(`{"balance":{"address":"wasm10kc4n52rk4xqny3hdew3ggjfk9r420pqxs9ylf"}}`), + []byte(fmt.Sprintf(`{"balance":{"address":"%s"}}`, feedConfig.ContractAddressBech32)), ).Return(balanceRes, nil).Once() // LINK available for payment. rpcClient.On("ContractState", @@ -76,7 +117,7 @@ func TestEnvelopeSource(t *testing.T) { ).Return(linkAvailableForPaymentRes, nil).Once() // Execute Fetch() - factory := NewEnvelopeSourceFactory(rpcClient, fcdClient, newNullLogger()) + factory := NewEnvelopeSourceFactory(rpcClient, fcdClient, logger.Test(t)) source, err := factory.NewSource(chainConfig, feedConfig) require.NoError(t, err) rawEnvelope, err := source.Fetch(ctx) @@ -154,7 +195,7 @@ func TestEnvelopeSource(t *testing.T) { rpcClient.On("ContractState", mock.Anything, // context feedConfig.ContractAddress, - []byte(`"latest_config_details"`), + []byte(`{"latest_config_details":{}}`), ).Return(latestConfigDetailsRes, nil).Once() // Transmission fcdClient.On("GetTxList", @@ -165,7 +206,7 @@ func TestEnvelopeSource(t *testing.T) { rpcClient.On("ContractState", mock.Anything, // context chainConfig.LinkTokenAddress, - []byte(`{"balance":{"address":"wasm10kc4n52rk4xqny3hdew3ggjfk9r420pqxs9ylf"}}`), + []byte(fmt.Sprintf(`{"balance":{"address":"%s"}}`, feedConfig.ContractAddressBech32)), ).Return(balanceRes, nil).Once() // LINK available for payment. rpcClient.On("ContractState", diff --git a/pkg/monitoring/source_txresults_test.go b/pkg/monitoring/source_txresults_test.go index 4dfb061ac..644aae48e 100644 --- a/pkg/monitoring/source_txresults_test.go +++ b/pkg/monitoring/source_txresults_test.go @@ -7,10 +7,11 @@ import ( "testing" "time" - relayMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + relayMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring" + "github.com/smartcontractkit/chainlink-cosmos/pkg/monitoring/fcdclient" fcdclientmocks "github.com/smartcontractkit/chainlink-cosmos/pkg/monitoring/fcdclient/mocks" ) @@ -20,8 +21,8 @@ func TestTxResultsSource(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() - chainConfig := generateChainConfig() - feedConfig := generateFeedConfig() + chainConfig := generateChainConfig(t) + feedConfig := generateFeedConfig(t) fcdClient := new(fcdclientmocks.Client) factory := NewTxResultsSourceFactory(fcdClient)