diff --git a/zetaclient/testutils/stub/sdk_client.go b/zetaclient/testutils/stub/sdk_client.go index b6dd48ed20..b7824252aa 100644 --- a/zetaclient/testutils/stub/sdk_client.go +++ b/zetaclient/testutils/stub/sdk_client.go @@ -13,7 +13,8 @@ import ( type MockSDKClient struct { mock.Client - err error + err error + code uint32 } func (c MockSDKClient) BroadcastTxCommit(_ context.Context, _ tmtypes.Tx) (*coretypes.ResultBroadcastTxCommit, error) { @@ -25,7 +26,17 @@ func (c MockSDKClient) BroadcastTxAsync(_ context.Context, _ tmtypes.Tx) (*coret } func (c MockSDKClient) BroadcastTxSync(_ context.Context, _ tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) { - return nil, c.err + log := "" + if c.err != nil { + log = c.err.Error() + } + return &coretypes.ResultBroadcastTx{ + Code: c.code, + Data: bytes.HexBytes{}, + Log: log, + Codespace: "", + Hash: bytes.HexBytes{}, + }, c.err } func (c MockSDKClient) Tx(_ context.Context, _ []byte, _ bool) (*coretypes.ResultTx, error) { @@ -49,9 +60,10 @@ func (c MockSDKClient) Block(_ context.Context, _ *int64) (*coretypes.ResultBloc }}, c.err } -func NewMockSDKClientWithErr(err error) *MockSDKClient { +func NewMockSDKClientWithErr(err error, code uint32) *MockSDKClient { return &MockSDKClient{ Client: mock.Client{}, err: err, + code: code, } } diff --git a/zetaclient/zetabridge/broadcast.go b/zetaclient/zetabridge/broadcast.go index 2a5e06282b..80f7e98bf7 100644 --- a/zetaclient/zetabridge/broadcast.go +++ b/zetaclient/zetabridge/broadcast.go @@ -214,6 +214,7 @@ func (b *ZetaCoreBridge) QueryTxResult(hash string) (*sdktypes.TxResponse, error } // HandleBroadcastError returns whether to retry in a few seconds, and whether to report via AddTxHashToOutTxTracker +// returns (bool retry, bool report) func HandleBroadcastError(err error, nonce, toChain, outTxHash string) (bool, bool) { if strings.Contains(err.Error(), "nonce too low") { log.Warn().Err(err).Msgf("nonce too low! this might be a unnecessary key-sign. increase re-try interval and awaits outTx confirmation") diff --git a/zetaclient/zetabridge/broadcast_test.go b/zetaclient/zetabridge/broadcast_test.go index a52ebb63eb..624c9e43f6 100644 --- a/zetaclient/zetabridge/broadcast_test.go +++ b/zetaclient/zetabridge/broadcast_test.go @@ -1,25 +1,86 @@ package zetabridge import ( - "fmt" - "regexp" + "encoding/hex" + "errors" + "net" + "testing" - . "gopkg.in/check.v1" + "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/pkg/chains" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + observerTypes "github.com/zeta-chain/zetacore/x/observer/types" + "github.com/zeta-chain/zetacore/zetaclient/keys" + "github.com/zeta-chain/zetacore/zetaclient/testutils/stub" + "go.nhat.io/grpcmock" + "go.nhat.io/grpcmock/planner" ) -type BcastSuite struct { +func TestHandleBroadcastError(t *testing.T) { + type response struct { + retry bool + report bool + } + testCases := map[error]response{ + errors.New("nonce too low"): {retry: false, report: false}, + errors.New("replacement transaction underpriced"): {retry: false, report: false}, + errors.New("already known"): {retry: false, report: true}, + errors.New(""): {retry: true, report: false}, + } + for input, output := range testCases { + retry, report := HandleBroadcastError(input, "", "", "") + require.Equal(t, output.report, report) + require.Equal(t, output.retry, retry) + } } -var _ = Suite(&BcastSuite{}) +func TestBroadcast(t *testing.T) { + address := types.AccAddress(stub.TestKeyringPair.PubKey().Address().Bytes()) -func (s *BcastSuite) SetUpTest(c *C) { - fmt.Println("hello") -} + //Setup server for multiple grpc calls + l, err := net.Listen("tcp", "127.0.0.1:9090") + require.NoError(t, err) + server := grpcmock.MockUnstartedServer( + grpcmock.RegisterService(crosschaintypes.RegisterQueryServer), + grpcmock.RegisterService(feemarkettypes.RegisterQueryServer), + grpcmock.RegisterService(authtypes.RegisterQueryServer), + grpcmock.WithPlanner(planner.FirstMatch()), + grpcmock.WithListener(l), + func(s *grpcmock.Server) { + method := "/zetachain.zetacore.crosschain.Query/LastZetaHeight" + s.ExpectUnary(method). + UnlimitedTimes(). + WithPayload(crosschaintypes.QueryLastZetaHeightRequest{}). + Return(crosschaintypes.QueryLastZetaHeightResponse{Height: 0}) + + method = "/ethermint.feemarket.v1.Query/Params" + s.ExpectUnary(method). + UnlimitedTimes(). + WithPayload(feemarkettypes.QueryParamsRequest{}). + Return(feemarkettypes.QueryParamsResponse{ + Params: feemarkettypes.Params{ + BaseFee: types.NewInt(23455), + }, + }) + }, + )(t) + + server.Serve() + defer closeMockServer(t, server) + + zetabridge, err := setupCorBridge() + require.NoError(t, err) + zetabridge.keys = keys.NewKeysWithKeybase(stub.NewMockKeyring(), address, "", "") + zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil, 0)) -func (s *BcastSuite) TestParsingSeqNumMismatch(c *C) { - err_msg := "fail to broadcast to zetabridge,code:32, log:account sequence mismatch, expected 386232, got 386230: incorrect account sequence" - re := regexp.MustCompile(`account sequence mismatch, expected ([0-9]*), got ([0-9]*)`) - fmt.Printf("%q\n", re.FindStringSubmatch(err_msg)) - err_msg2 := "hahah" - fmt.Printf("%q\n", re.FindStringSubmatch(err_msg2)) + blockHash, err := hex.DecodeString(ethBlockHash) + require.NoError(t, err) + msg := observerTypes.NewMsgAddBlockHeader(address.String(), chains.EthChain().ChainId, blockHash, 18495266, getHeaderData(t)) + authzMsg, authzSigner, err := zetabridge.WrapMessageWithAuthz(msg) + require.NoError(t, err) + _, err = zetabridge.Broadcast(10000, authzMsg, authzSigner) + require.NoError(t, err) } diff --git a/zetaclient/zetabridge/tx_test.go b/zetaclient/zetabridge/tx_test.go index d740e3ad3a..3dd7ec5558 100644 --- a/zetaclient/zetabridge/tx_test.go +++ b/zetaclient/zetabridge/tx_test.go @@ -9,6 +9,7 @@ import ( "os" "testing" + "cosmossdk.io/math" sdktypes "github.com/cosmos/cosmos-sdk/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -295,7 +296,7 @@ func TestZetaCoreBridge_UpdateZetaCoreContext(t *testing.T) { require.NoError(t, err) address := sdktypes.AccAddress(stub.TestKeyringPair.PubKey().Address().Bytes()) zetabridge.keys = keys.NewKeysWithKeybase(stub.NewMockKeyring(), address, "", "") - zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil)) + zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil, 0)) t.Run("core context update success", func(t *testing.T) { cfg := config.NewConfig() @@ -349,7 +350,6 @@ func TestZetaCoreBridge_PostAddBlockHeader(t *testing.T) { }) } -// TODO: Rest of tests Requires zetabridge refactoring func TestZetaCoreBridge_PostVoteInbound(t *testing.T) { address := sdktypes.AccAddress(stub.TestKeyringPair.PubKey().Address().Bytes()) @@ -366,7 +366,7 @@ func TestZetaCoreBridge_PostVoteInbound(t *testing.T) { zetabridge, err := setupCorBridge() require.NoError(t, err) zetabridge.keys = keys.NewKeysWithKeybase(stub.NewMockKeyring(), address, "", "") - zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil)) + zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil, 0)) t.Run("post inbound vote already voted", func(t *testing.T) { zetaBridgeBroadcast = ZetaBridgeBroadcastTest @@ -377,12 +377,35 @@ func TestZetaCoreBridge_PostVoteInbound(t *testing.T) { require.Equal(t, "", hash) }) } + +func TestZetaCoreBridge_GetInBoundVoteMessage(t *testing.T) { + address := sdktypes.AccAddress(stub.TestKeyringPair.PubKey().Address().Bytes()) + t.Run("get inbound vote message", func(t *testing.T) { + zetaBridgeBroadcast = ZetaBridgeBroadcastTest + msg := GetInBoundVoteMessage( + address.String(), + chains.EthChain().ChainId, + "", + address.String(), + chains.ZetaChainMainnet().ChainId, + math.NewUint(500), + "", + "", 12345, + 1000, + coin.CoinType_Gas, + "azeta", + address.String(), + 0) + require.Equal(t, address.String(), msg.Creator) + }) +} + func TestZetaCoreBridge_MonitorVoteInboundTxResult(t *testing.T) { address := sdktypes.AccAddress(stub.TestKeyringPair.PubKey().Address().Bytes()) zetabridge, err := setupCorBridge() require.NoError(t, err) zetabridge.keys = keys.NewKeysWithKeybase(stub.NewMockKeyring(), address, "", "") - zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil)) + zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil, 0)) t.Run("monitor inbound vote", func(t *testing.T) { zetaBridgeBroadcast = ZetaBridgeBroadcastTest @@ -410,7 +433,7 @@ func TestZetaCoreBridge_PostVoteOutbound(t *testing.T) { zetabridge, err := setupCorBridge() require.NoError(t, err) zetabridge.keys = keys.NewKeysWithKeybase(stub.NewMockKeyring(), address, "", "") - zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil)) + zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil, 0)) zetaBridgeBroadcast = ZetaBridgeBroadcastTest hash, ballot, err := zetabridge.PostVoteOutbound( @@ -435,7 +458,7 @@ func TestZetaCoreBridge_MonitorVoteOutboundTxResult(t *testing.T) { zetabridge, err := setupCorBridge() require.NoError(t, err) zetabridge.keys = keys.NewKeysWithKeybase(stub.NewMockKeyring(), address, "", "") - zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil)) + zetabridge.EnableMockSDKClient(stub.NewMockSDKClientWithErr(nil, 0)) t.Run("monitor outbound vote", func(t *testing.T) { zetaBridgeBroadcast = ZetaBridgeBroadcastTest