Some checks are pending
Docs Deploy / build_and_deploy (push) Waiting to run
Generate Docs / cli (push) Waiting to run
Generate Config Doc / cli (push) Waiting to run
Go formatting / go-formatting (push) Waiting to run
Check links / markdown-link-check (push) Waiting to run
Integration / pre-test (push) Waiting to run
Integration / test on (push) Blocked by required conditions
Integration / status (push) Blocked by required conditions
Lint / Lint Go code (push) Waiting to run
Test / test (ubuntu-latest) (push) Waiting to run
309 lines
8.6 KiB
Go
309 lines
8.6 KiB
Go
package cosmosclient_test
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"testing"
|
|
|
|
"cosmossdk.io/math"
|
|
abci "github.com/cometbft/cometbft/abci/types"
|
|
ctypes "github.com/cometbft/cometbft/rpc/core/types"
|
|
sdktypes "github.com/cosmos/cosmos-sdk/types"
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/ignite/cli/v29/ignite/pkg/cosmosaccount"
|
|
"github.com/ignite/cli/v29/ignite/pkg/cosmosclient"
|
|
"github.com/ignite/cli/v29/ignite/pkg/errors"
|
|
)
|
|
|
|
func TestTxServiceBroadcast(t *testing.T) {
|
|
var (
|
|
accountName = "bob"
|
|
passphrase = "passphrase"
|
|
txHash = []byte{1, 2, 3}
|
|
txHashStr = hex.EncodeToString(txHash)
|
|
)
|
|
r, err := cosmosaccount.NewInMemory()
|
|
require.NoError(t, err)
|
|
a, _, err := r.Create(accountName)
|
|
require.NoError(t, err)
|
|
// Export created account to we can import it in the Client below.
|
|
key, err := r.Export(accountName, passphrase)
|
|
require.NoError(t, err)
|
|
sdkaddr, err := a.Record.GetAddress()
|
|
require.NoError(t, err)
|
|
msg := &banktypes.MsgSend{
|
|
FromAddress: sdkaddr.String(),
|
|
ToAddress: "cosmos1k8e50d2d8xkdfw9c4et3m45llh69e7xzw6uzga",
|
|
Amount: sdktypes.NewCoins(
|
|
sdktypes.NewCoin("token", math.NewIntFromUint64(1)),
|
|
),
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
msg sdktypes.Msg
|
|
opts []cosmosclient.Option
|
|
expectedResponse *sdktypes.TxResponse
|
|
expectedError string
|
|
setup func(suite)
|
|
}{
|
|
{
|
|
name: "fail: error not found",
|
|
msg: msg,
|
|
expectedError: "make sure that your account has enough balance",
|
|
|
|
setup: func(s suite) {
|
|
s.expectPrepareFactory(sdkaddr)
|
|
s.signer.EXPECT().
|
|
Sign(mock.Anything, mock.Anything, "bob", mock.Anything, true).
|
|
Return(nil)
|
|
s.rpcClient.EXPECT().
|
|
BroadcastTxSync(mock.Anything, mock.Anything).
|
|
Return(nil, sdkerrors.ErrNotFound)
|
|
},
|
|
},
|
|
{
|
|
name: "fail: response code > 0",
|
|
msg: msg,
|
|
expectedError: "error code: '42' msg: 'oups'",
|
|
|
|
setup: func(s suite) {
|
|
s.expectPrepareFactory(sdkaddr)
|
|
s.signer.EXPECT().
|
|
Sign(mock.Anything, mock.Anything, "bob", mock.Anything, true).
|
|
Return(nil)
|
|
s.rpcClient.EXPECT().
|
|
BroadcastTxSync(mock.Anything, mock.Anything).
|
|
Return(&ctypes.ResultBroadcastTx{
|
|
Code: 42,
|
|
Log: "oups",
|
|
}, nil)
|
|
},
|
|
},
|
|
{
|
|
name: "ok: tx confirmed immediately",
|
|
msg: msg,
|
|
expectedResponse: &sdktypes.TxResponse{
|
|
TxHash: txHashStr,
|
|
RawLog: "log",
|
|
},
|
|
|
|
setup: func(s suite) {
|
|
s.expectPrepareFactory(sdkaddr)
|
|
s.signer.EXPECT().
|
|
Sign(mock.Anything, mock.Anything, "bob", mock.Anything, true).
|
|
Return(nil)
|
|
s.rpcClient.EXPECT().
|
|
BroadcastTxSync(mock.Anything, mock.Anything).
|
|
Return(&ctypes.ResultBroadcastTx{
|
|
Hash: txHash,
|
|
}, nil)
|
|
|
|
// Tx is broadcasted, now check for confirmation
|
|
s.rpcClient.EXPECT().Tx(mock.Anything, txHash, false).
|
|
Return(&ctypes.ResultTx{
|
|
Hash: txHash,
|
|
TxResult: abci.ExecTxResult{
|
|
Log: "log",
|
|
},
|
|
}, nil)
|
|
},
|
|
},
|
|
{
|
|
name: "fail: tx confirmed with error code",
|
|
msg: msg,
|
|
expectedError: "error code: '42' msg: 'oups'",
|
|
|
|
setup: func(s suite) {
|
|
s.expectPrepareFactory(sdkaddr)
|
|
s.signer.EXPECT().
|
|
Sign(mock.Anything, mock.Anything, "bob", mock.Anything, true).
|
|
Return(nil)
|
|
s.rpcClient.EXPECT().
|
|
BroadcastTxSync(mock.Anything, mock.Anything).
|
|
Return(&ctypes.ResultBroadcastTx{
|
|
Hash: txHash,
|
|
}, nil)
|
|
|
|
// Tx is broadcasted, now check for confirmation
|
|
s.rpcClient.EXPECT().Tx(mock.Anything, txHash, false).
|
|
Return(&ctypes.ResultTx{
|
|
Hash: txHash,
|
|
TxResult: abci.ExecTxResult{
|
|
Code: 42,
|
|
Log: "oups",
|
|
},
|
|
}, nil)
|
|
},
|
|
},
|
|
{
|
|
name: "ok: tx confirmed after a while",
|
|
msg: msg,
|
|
expectedResponse: &sdktypes.TxResponse{
|
|
TxHash: txHashStr,
|
|
},
|
|
|
|
setup: func(s suite) {
|
|
s.expectPrepareFactory(sdkaddr)
|
|
s.signer.EXPECT().
|
|
Sign(mock.Anything, mock.Anything, "bob", mock.Anything, true).
|
|
Return(nil)
|
|
s.rpcClient.EXPECT().
|
|
BroadcastTxSync(mock.Anything, mock.Anything).
|
|
Return(&ctypes.ResultBroadcastTx{
|
|
Hash: txHash,
|
|
}, nil)
|
|
|
|
// Tx is broadcasted, now check for confirmation
|
|
// First time the tx is not found (not confirmed yet)
|
|
s.rpcClient.EXPECT().Tx(mock.Anything, txHash, false).
|
|
Return(nil, errors.New("not found")).Once()
|
|
// Wait for 1 block
|
|
s.rpcClient.EXPECT().Status(mock.Anything).
|
|
Return(&ctypes.ResultStatus{
|
|
SyncInfo: ctypes.SyncInfo{LatestBlockHeight: 1},
|
|
}, nil).Once()
|
|
s.rpcClient.EXPECT().Status(mock.Anything).
|
|
Return(&ctypes.ResultStatus{
|
|
SyncInfo: ctypes.SyncInfo{LatestBlockHeight: 2},
|
|
}, nil).Once()
|
|
// Then try gain to fetch the tx, this time it is confirmed
|
|
s.rpcClient.EXPECT().Tx(mock.Anything, txHash, false).
|
|
Return(&ctypes.ResultTx{
|
|
Hash: txHash,
|
|
}, nil)
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := newClient(t, tt.setup, tt.opts...)
|
|
account, err := c.AccountRegistry.Import(accountName, key, passphrase)
|
|
require.NoError(t, err)
|
|
ctx := c.Context().
|
|
WithFromName(accountName).
|
|
WithFromAddress(sdkaddr)
|
|
txService, err := c.CreateTx(ctx.CmdContext, account, tt.msg)
|
|
require.NoError(t, err)
|
|
|
|
res, err := txService.Broadcast(ctx.CmdContext)
|
|
if tt.expectedError != "" {
|
|
require.EqualError(t, err, tt.expectedError)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
require.Equal(t, ctx.Codec, res.Codec)
|
|
require.Equal(t, tt.expectedResponse, res.TxResponse)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTxServiceBroadcastAsync(t *testing.T) {
|
|
var (
|
|
accountName = "bob"
|
|
passphrase = "passphrase"
|
|
txHash = []byte{1, 2, 3}
|
|
txHashStr = hex.EncodeToString(txHash)
|
|
)
|
|
r, err := cosmosaccount.NewInMemory()
|
|
require.NoError(t, err)
|
|
a, _, err := r.Create(accountName)
|
|
require.NoError(t, err)
|
|
// Export created account to we can import it in the Client below.
|
|
key, err := r.Export(accountName, passphrase)
|
|
require.NoError(t, err)
|
|
sdkaddr, err := a.Record.GetAddress()
|
|
require.NoError(t, err)
|
|
msg := &banktypes.MsgSend{
|
|
FromAddress: sdkaddr.String(),
|
|
ToAddress: "cosmos1k8e50d2d8xkdfw9c4et3m45llh69e7xzw6uzga",
|
|
Amount: sdktypes.NewCoins(
|
|
sdktypes.NewCoin("token", math.NewIntFromUint64(1)),
|
|
),
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
msg sdktypes.Msg
|
|
opts []cosmosclient.Option
|
|
expectedResponse *sdktypes.TxResponse
|
|
expectedError string
|
|
setup func(suite)
|
|
}{
|
|
{
|
|
name: "fail: error not found",
|
|
msg: msg,
|
|
expectedError: "make sure that your account has enough balance",
|
|
|
|
setup: func(s suite) {
|
|
s.expectPrepareFactory(sdkaddr)
|
|
s.signer.EXPECT().
|
|
Sign(mock.Anything, mock.Anything, "bob", mock.Anything, true).
|
|
Return(nil)
|
|
s.rpcClient.EXPECT().
|
|
BroadcastTxSync(mock.Anything, mock.Anything).
|
|
Return(nil, sdkerrors.ErrNotFound)
|
|
},
|
|
},
|
|
{
|
|
name: "fail: response code > 0",
|
|
msg: msg,
|
|
expectedError: "error code: '42' msg: 'oups'",
|
|
|
|
setup: func(s suite) {
|
|
s.expectPrepareFactory(sdkaddr)
|
|
s.signer.EXPECT().
|
|
Sign(mock.Anything, mock.Anything, "bob", mock.Anything, true).
|
|
Return(nil)
|
|
s.rpcClient.EXPECT().
|
|
BroadcastTxSync(mock.Anything, mock.Anything).
|
|
Return(&ctypes.ResultBroadcastTx{
|
|
Code: 42,
|
|
Log: "oups",
|
|
}, nil)
|
|
},
|
|
},
|
|
{
|
|
name: "ok: tx broadcasted successfully",
|
|
msg: msg,
|
|
expectedResponse: &sdktypes.TxResponse{
|
|
TxHash: txHashStr,
|
|
RawLog: "",
|
|
},
|
|
|
|
setup: func(s suite) {
|
|
s.expectPrepareFactory(sdkaddr)
|
|
s.signer.EXPECT().
|
|
Sign(mock.Anything, mock.Anything, "bob", mock.Anything, true).
|
|
Return(nil)
|
|
s.rpcClient.EXPECT().
|
|
BroadcastTxSync(mock.Anything, mock.Anything).
|
|
Return(&ctypes.ResultBroadcastTx{
|
|
Hash: txHash,
|
|
}, nil)
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := newClient(t, tt.setup, tt.opts...)
|
|
account, err := c.AccountRegistry.Import(accountName, key, passphrase)
|
|
require.NoError(t, err)
|
|
ctx := c.Context().
|
|
WithFromName(accountName).
|
|
WithFromAddress(sdkaddr)
|
|
txService, err := c.CreateTx(ctx.CmdContext, account, tt.msg)
|
|
require.NoError(t, err)
|
|
|
|
res, err := txService.BroadcastAsync(ctx.CmdContext)
|
|
if tt.expectedError != "" {
|
|
require.EqualError(t, err, tt.expectedError)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
require.Equal(t, ctx.Codec, res.Codec)
|
|
require.Equal(t, tt.expectedResponse, res.TxResponse)
|
|
})
|
|
}
|
|
}
|