From 53db2026defe7f34dc6745fdd74cde640b10220e Mon Sep 17 00:00:00 2001 From: dan13ram Date: Tue, 25 Jun 2024 18:48:54 +0530 Subject: [PATCH] more tests for cosmos signer --- cosmos/relayer.go | 11 +- cosmos/relayer_test.go | 1392 ++++++++++++++++++++++++++++++++++++---- cosmos/signer.go | 7 +- cosmos/signer_test.go | 558 +++++++++++++++- 4 files changed, 1838 insertions(+), 130 deletions(-) diff --git a/cosmos/relayer.go b/cosmos/relayer.go index 5dc05f8..e96187f 100644 --- a/cosmos/relayer.go +++ b/cosmos/relayer.go @@ -362,18 +362,15 @@ func NewMessageRelayer(config models.CosmosNetworkConfig, lastHealth *models.Run } multisigPk := multisig.NewLegacyAminoPubKey(int(config.MultisigThreshold), pks) - multisigAddress, err := common.Bech32FromBytes(config.Bech32Prefix, multisigPk.Address().Bytes()) - if err != nil { - logger.WithError(err).Fatalf("Error creating multisig address") - } + multisigAddress, _ := common.Bech32FromBytes(config.Bech32Prefix, multisigPk.Address().Bytes()) if !strings.EqualFold(multisigAddress, config.MultisigAddress) { logger.Fatalf("Multisig address does not match config") } - client, err := cosmos.NewClient(config) + client, err := cosmosNewClient(config) if err != nil { - logger.WithError(err).Errorf("Error creating cosmos client") + logger.WithError(err).Fatalf("Error creating cosmos client") } x := &CosmosMessageRelayerRunnable{ @@ -388,7 +385,7 @@ func NewMessageRelayer(config models.CosmosNetworkConfig, lastHealth *models.Run logger: logger, - db: db.NewDB(), + db: dbNewDB(), } x.UpdateCurrentHeight() diff --git a/cosmos/relayer_test.go b/cosmos/relayer_test.go index 43e41bd..115c187 100644 --- a/cosmos/relayer_test.go +++ b/cosmos/relayer_test.go @@ -1,6 +1,7 @@ package cosmos import ( + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -12,6 +13,9 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + cosmos "github.com/dan13ram/wpokt-oracle/cosmos/client" + "github.com/dan13ram/wpokt-oracle/cosmos/util" + "github.com/dan13ram/wpokt-oracle/db" "github.com/sirupsen/logrus" clientMocks "github.com/dan13ram/wpokt-oracle/cosmos/client/mocks" @@ -19,6 +23,8 @@ import ( "github.com/dan13ram/wpokt-oracle/models" ethcommon "github.com/ethereum/go-ethereum/common" + + log "github.com/sirupsen/logrus" ) func TestRelayerHeight(t *testing.T) { @@ -74,7 +80,7 @@ func TestRelayerUpdateCurrentHeight_Error(t *testing.T) { assert.Equal(t, uint64(0), relayer.currentBlockHeight) } -func TestUpdateRefund(t *testing.T) { +func TestRelayerUpdateRefund(t *testing.T) { mockDB := mocks.NewMockDB(t) logger := logrus.New().WithField("test", "relayer") @@ -94,6 +100,26 @@ func TestUpdateRefund(t *testing.T) { assert.True(t, result) } +func TestRelayerUpdateRefund_Error(t *testing.T) { + mockDB := mocks.NewMockDB(t) + logger := logrus.New().WithField("test", "relayer") + + refundID := &primitive.ObjectID{} + update := bson.M{"status": models.RefundStatusPending} + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + logger: logger, + } + + mockDB.EXPECT().UpdateRefund(refundID, update).Return(assert.AnError) + + result := relayer.UpdateRefund(refundID, update) + + mockDB.AssertExpectations(t) + assert.False(t, result) +} + func TestRelayerUpdateMessage(t *testing.T) { mockDB := mocks.NewMockDB(t) logger := logrus.New().WithField("test", "relayer") @@ -114,6 +140,26 @@ func TestRelayerUpdateMessage(t *testing.T) { assert.True(t, result) } +func TestRelayerUpdateMessage_Error(t *testing.T) { + mockDB := mocks.NewMockDB(t) + logger := logrus.New().WithField("test", "relayer") + + messageID := &primitive.ObjectID{} + update := bson.M{"status": models.MessageStatusPending} + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + logger: logger, + } + + mockDB.EXPECT().UpdateMessage(messageID, update).Return(assert.AnError) + + result := relayer.UpdateMessage(messageID, update) + + mockDB.AssertExpectations(t) + assert.False(t, result) +} + func TestCreateMessageTransaction(t *testing.T) { mockDB := mocks.NewMockDB(t) mockClient := clientMocks.NewMockCosmosClient(t) @@ -152,7 +198,7 @@ func TestCreateMessageTransaction(t *testing.T) { assert.True(t, result) } -func TestCreateRefundTransaction(t *testing.T) { +func TestCreateMessageTransaction_AddressError(t *testing.T) { mockDB := mocks.NewMockDB(t) mockClient := clientMocks.NewMockCosmosClient(t) logger := logrus.New().WithField("test", "relayer") @@ -160,12 +206,12 @@ func TestCreateRefundTransaction(t *testing.T) { signerKey := secp256k1.GenPrivKey() multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) - recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) - - refund := &models.Refund{ + message := &models.Message{ ID: &primitive.ObjectID{}, - TransactionHash: "txHash", - Recipient: recipientAddr.Hex(), + TransactionHash: "0x010203", + Content: models.MessageContent{MessageBody: models.MessageBody{RecipientAddress: "recipient", Amount: "100"}}, + Signatures: []models.Signature{}, + Sequence: new(uint64), } relayer := &CosmosMessageRelayerRunnable{ @@ -175,204 +221,1019 @@ func TestCreateRefundTransaction(t *testing.T) { multisigPk: multisigPk, } - tx := &sdk.TxResponse{} - mockClient.EXPECT().GetTx("txHash").Return(tx, nil) - mockDB.EXPECT().NewCosmosTransaction(tx, mock.Anything, mock.Anything, mock.Anything, models.TransactionStatusPending).Return(models.Transaction{}, nil) - mockDB.EXPECT().InsertTransaction(mock.Anything).Return(primitive.ObjectID{}, nil) - mockDB.EXPECT().UpdateRefund(refund.ID, mock.Anything).Return(nil) - - result := relayer.CreateRefundTransaction(refund) + result := relayer.CreateMessageTransaction(message) mockClient.AssertExpectations(t) mockDB.AssertExpectations(t) - assert.True(t, result) + assert.False(t, result) } -/* -func TestCreateTxForRefunds(t *testing.T) { +func TestCreateMessageTransaction_GetTxError(t *testing.T) { mockDB := mocks.NewMockDB(t) mockClient := clientMocks.NewMockCosmosClient(t) logger := logrus.New().WithField("test", "relayer") - refund := &models.Refund{ + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + message := &models.Message{ ID: &primitive.ObjectID{}, - TransactionHash: "txHash", - Recipient: "recipient", + TransactionHash: "0x010203", + Content: models.MessageContent{MessageBody: models.MessageBody{RecipientAddress: recipientAddr.Hex(), Amount: "100"}}, + Signatures: []models.Signature{}, + Sequence: new(uint64), } relayer := &CosmosMessageRelayerRunnable{ - db: mockDB, - client: mockClient, - logger: logger, + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, } - mockDB.EXPECT().GetBroadcastedRefunds().Return([]models.Refund{*refund}, nil) - mockClient.EXPECT().GetTx("txHash").Return(&sdk.TxResponse{}, nil) - mockDB.EXPECT().NewCosmosTransaction(mock.Anything, mock.Anything, mock.Anything, mock.Anything, models.TransactionStatusPending).Return(models.Transaction{}, nil) - mockDB.EXPECT().InsertTransaction(mock.Anything).Return(primitive.ObjectID{}, nil) - mockDB.EXPECT().UpdateRefund(refund.ID, mock.Anything).Return(nil) + mockClient.EXPECT().GetTx("0x010203").Return(nil, assert.AnError) - result := relayer.CreateTxForRefunds() + result := relayer.CreateMessageTransaction(message) + mockClient.AssertExpectations(t) mockDB.AssertExpectations(t) - assert.True(t, result) + assert.False(t, result) } -func TestCreateTxForMessages(t *testing.T) { +func TestCreateMessageTransaction_NewError(t *testing.T) { mockDB := mocks.NewMockDB(t) mockClient := clientMocks.NewMockCosmosClient(t) logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + message := &models.Message{ ID: &primitive.ObjectID{}, - TransactionHash: "txHash", - Content: models.MessageContent{MessageBody: models.MessageBody{RecipientAddress: "recipient"}}, + TransactionHash: "0x010203", + Content: models.MessageContent{MessageBody: models.MessageBody{RecipientAddress: recipientAddr.Hex(), Amount: "100"}}, + Signatures: []models.Signature{}, + Sequence: new(uint64), } relayer := &CosmosMessageRelayerRunnable{ - db: mockDB, - client: mockClient, - logger: logger, + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, } - mockDB.EXPECT().GetBroadcastedMessages(mock.Anything).Return([]models.Message{*message}, nil) - mockClient.EXPECT().GetTx("txHash").Return(&sdk.TxResponse{}, nil) - mockDB.EXPECT().NewCosmosTransaction(mock.Anything, mock.Anything, mock.Anything, mock.Anything, models.TransactionStatusPending).Return(models.Transaction{}, nil) - mockDB.EXPECT().InsertTransaction(mock.Anything).Return(primitive.ObjectID{}, nil) - mockDB.EXPECT().UpdateMessage(message.ID, mock.Anything).Return(nil) + tx := &sdk.TxResponse{} + mockClient.EXPECT().GetTx("0x010203").Return(tx, nil) + mockDB.EXPECT().NewCosmosTransaction(tx, mock.Anything, mock.Anything, mock.Anything, models.TransactionStatusPending).Return(models.Transaction{}, assert.AnError) - result := relayer.CreateTxForMessages() + result := relayer.CreateMessageTransaction(message) + mockClient.AssertExpectations(t) mockDB.AssertExpectations(t) - assert.True(t, result) + assert.False(t, result) } -func TestUpdateTransaction(t *testing.T) { +func TestCreateMessageTransaction_InsertError(t *testing.T) { mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) logger := logrus.New().WithField("test", "relayer") - transaction := &models.Transaction{ID: &primitive.ObjectID{}} - update := bson.M{"status": models.TransactionStatusConfirmed} + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + TransactionHash: "0x010203", + Content: models.MessageContent{MessageBody: models.MessageBody{RecipientAddress: recipientAddr.Hex(), Amount: "100"}}, + Signatures: []models.Signature{}, + Sequence: new(uint64), + } relayer := &CosmosMessageRelayerRunnable{ - db: mockDB, - logger: logger, + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, } - mockDB.EXPECT().UpdateTransaction(transaction.ID, update).Return(nil) + tx := &sdk.TxResponse{} + mockClient.EXPECT().GetTx("0x010203").Return(tx, nil) + mockDB.EXPECT().NewCosmosTransaction(tx, mock.Anything, mock.Anything, mock.Anything, models.TransactionStatusPending).Return(models.Transaction{}, nil) + mockDB.EXPECT().InsertTransaction(mock.Anything).Return(primitive.ObjectID{}, assert.AnError) - result := relayer.UpdateTransaction(transaction, update) + result := relayer.CreateMessageTransaction(message) + mockClient.AssertExpectations(t) mockDB.AssertExpectations(t) - assert.True(t, result) + assert.False(t, result) } -func TestResetRefund(t *testing.T) { +func TestCreateRefundTransaction(t *testing.T) { mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) logger := logrus.New().WithField("test", "relayer") - refundID := &primitive.ObjectID{} + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) - relayer := &CosmosMessageRelayerRunnable{ - db: mockDB, - logger: logger, + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + refund := &models.Refund{ + ID: &primitive.ObjectID{}, + TransactionHash: "txHash", + Recipient: recipientAddr.Hex(), } - update := bson.M{ - "status": models.RefundStatusPending, - "signatures": []models.Signature{}, - "transaction_body": "", - "transaction": nil, - "transaction_hash": "", + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, } - mockDB.EXPECT().UpdateRefund(refundID, update).Return(nil) + tx := &sdk.TxResponse{} + mockClient.EXPECT().GetTx("txHash").Return(tx, nil) + mockDB.EXPECT().NewCosmosTransaction(tx, mock.Anything, mock.Anything, mock.Anything, models.TransactionStatusPending).Return(models.Transaction{}, nil) + mockDB.EXPECT().InsertTransaction(mock.Anything).Return(primitive.ObjectID{}, nil) + mockDB.EXPECT().UpdateRefund(refund.ID, mock.Anything).Return(nil) - result := relayer.ResetRefund(refundID) + result := relayer.CreateRefundTransaction(refund) + mockClient.AssertExpectations(t) mockDB.AssertExpectations(t) assert.True(t, result) } -func TestResetMessage(t *testing.T) { +func TestCreateRefundTransaction_AddressError(t *testing.T) { mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) logger := logrus.New().WithField("test", "relayer") - messageID := &primitive.ObjectID{} + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) - relayer := &CosmosMessageRelayerRunnable{ - db: mockDB, - logger: logger, + refund := &models.Refund{ + ID: &primitive.ObjectID{}, + TransactionHash: "txHash", + Recipient: "recipientAddr", } - update := bson.M{ - "status": models.MessageStatusPending, - "signatures": []models.Signature{}, - "transaction_body": "", - "transaction": nil, - "transaction_hash": "", + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, } - mockDB.EXPECT().UpdateMessage(messageID, update).Return(nil) - - result := relayer.ResetMessage(messageID) + result := relayer.CreateRefundTransaction(refund) + mockClient.AssertExpectations(t) mockDB.AssertExpectations(t) - assert.True(t, result) + assert.False(t, result) } -func TestConfirmTransactions(t *testing.T) { +func TestCreateRefundTransaction_GetTxError(t *testing.T) { mockDB := mocks.NewMockDB(t) mockClient := clientMocks.NewMockCosmosClient(t) logger := logrus.New().WithField("test", "relayer") - transaction := models.Transaction{ - ID: &primitive.ObjectID{}, - Hash: "txHash", - Messages: []primitive.ObjectID{primitive.ObjectID{}}, - Refund: nil, - } + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) - relayer := &CosmosMessageRelayerRunnable{ - db: mockDB, - client: mockClient, - logger: logger, - currentBlockHeight: 100, + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + refund := &models.Refund{ + ID: &primitive.ObjectID{}, + TransactionHash: "txHash", + Recipient: recipientAddr.Hex(), } - txResponse := &sdk.TxResponse{ - Code: 0, - Height: 90, + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, } - mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) - mockClient.EXPECT().GetTx("txHash").Return(txResponse, nil) - mockDB.EXPECT().UpdateTransaction(transaction.ID, mock.Anything).Return(nil) - mockDB.EXPECT().UpdateMessage(mock.Anything, mock.Anything).Return(nil) + tx := &sdk.TxResponse{} + mockClient.EXPECT().GetTx("txHash").Return(tx, assert.AnError) - result := relayer.ConfirmTransactions() + result := relayer.CreateRefundTransaction(refund) - mockDB.AssertExpectations(t) mockClient.AssertExpectations(t) - assert.True(t, result) + mockDB.AssertExpectations(t) + assert.False(t, result) } -func TestRelayerInitStartBlockHeight(t *testing.T) { +func TestCreateRefundTransaction_NewError(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) logger := logrus.New().WithField("test", "relayer") - lastHealth := &models.RunnerServiceStatus{BlockHeight: 100} - relayer := &CosmosMessageRelayerRunnable{ - logger: logger, - startBlockHeight: 0, - currentBlockHeight: 200, - } + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) - relayer.InitStartBlockHeight(lastHealth) + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) - assert.Equal(t, uint64(100), relayer.startBlockHeight) + refund := &models.Refund{ + ID: &primitive.ObjectID{}, + TransactionHash: "txHash", + Recipient: recipientAddr.Hex(), + } - relayer = &CosmosMessageRelayerRunnable{ - logger: logger, + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, + } + + tx := &sdk.TxResponse{} + mockClient.EXPECT().GetTx("txHash").Return(tx, nil) + mockDB.EXPECT().NewCosmosTransaction(tx, mock.Anything, mock.Anything, mock.Anything, models.TransactionStatusPending).Return(models.Transaction{}, assert.AnError) + + result := relayer.CreateRefundTransaction(refund) + + mockClient.AssertExpectations(t) + mockDB.AssertExpectations(t) + assert.False(t, result) +} + +func TestCreateRefundTransaction_InsertError(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + refund := &models.Refund{ + ID: &primitive.ObjectID{}, + TransactionHash: "txHash", + Recipient: recipientAddr.Hex(), + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, + } + + tx := &sdk.TxResponse{} + mockClient.EXPECT().GetTx("txHash").Return(tx, nil) + mockDB.EXPECT().NewCosmosTransaction(tx, mock.Anything, mock.Anything, mock.Anything, models.TransactionStatusPending).Return(models.Transaction{}, nil) + mockDB.EXPECT().InsertTransaction(mock.Anything).Return(primitive.ObjectID{}, assert.AnError) + + result := relayer.CreateRefundTransaction(refund) + + mockClient.AssertExpectations(t) + mockDB.AssertExpectations(t) + assert.False(t, result) +} + +func TestCreateTxForRefunds_Error(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, + } + + mockDB.EXPECT().GetBroadcastedRefunds().Return(nil, assert.AnError) + + result := relayer.CreateTxForRefunds() + + mockDB.AssertExpectations(t) + assert.False(t, result) +} + +func TestCreateTxForRefunds(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + refund := &models.Refund{ + ID: &primitive.ObjectID{}, + TransactionHash: "txHash", + Recipient: recipientAddr.Hex(), + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, + } + + mockDB.EXPECT().GetBroadcastedRefunds().Return([]models.Refund{*refund}, nil) + tx := &sdk.TxResponse{} + mockClient.EXPECT().GetTx("txHash").Return(tx, nil) + mockDB.EXPECT().NewCosmosTransaction(tx, mock.Anything, mock.Anything, mock.Anything, models.TransactionStatusPending).Return(models.Transaction{}, nil) + mockDB.EXPECT().InsertTransaction(mock.Anything).Return(primitive.ObjectID{}, nil) + mockDB.EXPECT().UpdateRefund(refund.ID, mock.Anything).Return(nil) + + result := relayer.CreateTxForRefunds() + + mockDB.AssertExpectations(t) + assert.True(t, result) +} + +func TestCreateTxForMessages_Error(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, + } + + mockDB.EXPECT().GetBroadcastedMessages(mock.Anything).Return(nil, assert.AnError) + + result := relayer.CreateTxForMessages() + + mockDB.AssertExpectations(t) + assert.False(t, result) +} + +func TestCreateTxForMessages(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + TransactionHash: "0x010203", + Content: models.MessageContent{MessageBody: models.MessageBody{RecipientAddress: recipientAddr.Hex(), Amount: "100"}}, + Signatures: []models.Signature{}, + Sequence: new(uint64), + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, + } + + tx := &sdk.TxResponse{} + mockDB.EXPECT().GetBroadcastedMessages(mock.Anything).Return([]models.Message{*message}, nil) + mockClient.EXPECT().GetTx("0x010203").Return(tx, nil) + mockDB.EXPECT().NewCosmosTransaction(tx, mock.Anything, mock.Anything, mock.Anything, models.TransactionStatusPending).Return(models.Transaction{}, nil) + mockDB.EXPECT().InsertTransaction(mock.Anything).Return(primitive.ObjectID{}, nil) + mockDB.EXPECT().UpdateMessage(message.ID, mock.Anything).Return(nil) + + result := relayer.CreateTxForMessages() + + mockDB.AssertExpectations(t) + assert.True(t, result) +} + +func TestUpdateTransaction(t *testing.T) { + mockDB := mocks.NewMockDB(t) + logger := logrus.New().WithField("test", "relayer") + + transaction := &models.Transaction{ID: &primitive.ObjectID{}} + update := bson.M{"status": models.TransactionStatusConfirmed} + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + logger: logger, + } + + mockDB.EXPECT().UpdateTransaction(transaction.ID, update).Return(nil) + + result := relayer.UpdateTransaction(transaction, update) + + mockDB.AssertExpectations(t) + assert.True(t, result) +} + +func TestResetRefund_Nil(t *testing.T) { + mockDB := mocks.NewMockDB(t) + logger := logrus.New().WithField("test", "relayer") + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + logger: logger, + } + + result := relayer.ResetRefund(nil) + + mockDB.AssertExpectations(t) + assert.False(t, result) +} + +func TestResetRefund(t *testing.T) { + mockDB := mocks.NewMockDB(t) + logger := logrus.New().WithField("test", "relayer") + + refundID := &primitive.ObjectID{} + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + logger: logger, + } + + update := bson.M{ + "status": models.RefundStatusPending, + "signatures": []models.Signature{}, + "transaction_body": "", + "transaction": nil, + "transaction_hash": "", + } + + mockDB.EXPECT().UpdateRefund(refundID, update).Return(nil) + + result := relayer.ResetRefund(refundID) + + mockDB.AssertExpectations(t) + assert.True(t, result) +} + +func TestResetMessage_Nil(t *testing.T) { + mockDB := mocks.NewMockDB(t) + logger := logrus.New().WithField("test", "relayer") + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + logger: logger, + } + + result := relayer.ResetMessage(nil) + + mockDB.AssertExpectations(t) + assert.False(t, result) +} + +func TestResetMessage(t *testing.T) { + mockDB := mocks.NewMockDB(t) + logger := logrus.New().WithField("test", "relayer") + + messageID := &primitive.ObjectID{} + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + logger: logger, + } + + update := bson.M{ + "status": models.MessageStatusPending, + "signatures": []models.Signature{}, + "transaction_body": "", + "transaction": nil, + "transaction_hash": "", + } + + mockDB.EXPECT().UpdateMessage(messageID, update).Return(nil) + + result := relayer.ResetMessage(messageID) + + mockDB.AssertExpectations(t) + assert.True(t, result) +} + +func TestConfirmTransactions_ClientError(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return(nil, assert.AnError) + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.False(t, result) +} + +func TestConfirmTransactions_InvalidTx(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{}, + Refund: nil, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.False(t, result) +} + +func TestConfirmTransactions_GetTxError(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{{}}, + Refund: nil, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + mockClient.EXPECT().GetTx("txHash").Return(nil, assert.AnError) + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.False(t, result) +} + +func TestConfirmTransactions_FailedTx_Error(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{{}}, + Refund: nil, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + } + + txResponse := &sdk.TxResponse{ + Code: 1, + Height: 90, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + mockClient.EXPECT().GetTx("txHash").Return(txResponse, nil) + mockDB.EXPECT().UpdateTransaction(transaction.ID, bson.M{"status": models.TransactionStatusFailed}).Return(assert.AnError) + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.False(t, result) +} + +func TestConfirmTransactions_FailedTx_Message(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{{}}, + Refund: nil, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + } + + txResponse := &sdk.TxResponse{ + Code: 1, + Height: 90, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + mockClient.EXPECT().GetTx("txHash").Return(txResponse, nil) + mockDB.EXPECT().UpdateTransaction(transaction.ID, bson.M{"status": models.TransactionStatusFailed}).Return(nil) + update := bson.M{ + "status": models.MessageStatusPending, + "signatures": []models.Signature{}, + "transaction_body": "", + "transaction": nil, + "transaction_hash": "", + } + mockDB.EXPECT().UpdateMessage(mock.Anything, update).Return(nil).Once() + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.True(t, result) +} + +func TestConfirmTransactions_FailedTx_Refund(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{}, + Refund: &primitive.ObjectID{}, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + } + + txResponse := &sdk.TxResponse{ + Code: 1, + Height: 90, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + mockClient.EXPECT().GetTx("txHash").Return(txResponse, nil) + mockDB.EXPECT().UpdateTransaction(transaction.ID, bson.M{"status": models.TransactionStatusFailed}).Return(nil) + update := bson.M{ + "status": models.RefundStatusPending, + "signatures": []models.Signature{}, + "transaction_body": "", + "transaction": nil, + "transaction_hash": "", + } + mockDB.EXPECT().UpdateRefund(mock.Anything, update).Return(nil) + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.True(t, result) +} + +func TestConfirmTransactions_NotConfirmed(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{{}}, + Refund: nil, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + config: models.CosmosNetworkConfig{Confirmations: 10}, + } + + txResponse := &sdk.TxResponse{ + Code: 0, + Height: 100, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + mockClient.EXPECT().GetTx("txHash").Return(txResponse, nil) + update := bson.M{ + "status": models.TransactionStatusPending, + "confirmations": uint64(0), + } + mockDB.EXPECT().UpdateTransaction(transaction.ID, update).Return(nil) + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.True(t, result) +} + +func TestConfirmTransactions_NotConfirmed_Error(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{{}}, + Refund: nil, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + config: models.CosmosNetworkConfig{Confirmations: 10}, + } + + txResponse := &sdk.TxResponse{ + Code: 0, + Height: 100, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + mockClient.EXPECT().GetTx("txHash").Return(txResponse, nil) + update := bson.M{ + "status": models.TransactionStatusPending, + "confirmations": uint64(0), + } + mockDB.EXPECT().UpdateTransaction(transaction.ID, update).Return(assert.AnError) + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.False(t, result) +} + +func TestConfirmTransactions_Confirmed_Error(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{{}}, + Refund: nil, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + config: models.CosmosNetworkConfig{Confirmations: 10}, + } + + txResponse := &sdk.TxResponse{ + Code: 0, + Height: 90, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + mockClient.EXPECT().GetTx("txHash").Return(txResponse, nil) + update := bson.M{ + "status": models.TransactionStatusConfirmed, + "confirmations": uint64(10), + } + mockDB.EXPECT().UpdateTransaction(transaction.ID, update).Return(assert.AnError) + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.False(t, result) +} + +func TestConfirmTransactions_Message(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{{}, {}}, + Refund: nil, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + config: models.CosmosNetworkConfig{Confirmations: 10}, + } + + txResponse := &sdk.TxResponse{ + Code: 0, + Height: 90, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + mockClient.EXPECT().GetTx("txHash").Return(txResponse, nil) + txUpdate := bson.M{ + "status": models.TransactionStatusConfirmed, + "confirmations": uint64(10), + } + mockDB.EXPECT().UpdateTransaction(transaction.ID, txUpdate).Return(nil) + msgUpdate := bson.M{ + "status": models.MessageStatusSuccess, + "transaction": &primitive.ObjectID{}, + "transaction_hash": "txHash", + } + mockDB.EXPECT().UpdateMessage(mock.Anything, msgUpdate).Return(nil).Twice() + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.True(t, result) +} + +func TestConfirmTransactions_Refund(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{}, + Refund: &primitive.ObjectID{}, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + config: models.CosmosNetworkConfig{Confirmations: 10}, + } + + txResponse := &sdk.TxResponse{ + Code: 0, + Height: 90, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + mockClient.EXPECT().GetTx("txHash").Return(txResponse, nil) + txUpdate := bson.M{ + "status": models.TransactionStatusConfirmed, + "confirmations": uint64(10), + } + mockDB.EXPECT().UpdateTransaction(transaction.ID, txUpdate).Return(nil) + refundUpdate := bson.M{ + "status": models.MessageStatusSuccess, + "transaction": &primitive.ObjectID{}, + "transaction_hash": "txHash", + } + mockDB.EXPECT().UpdateRefund(mock.Anything, refundUpdate).Return(nil) + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.True(t, result) +} + +func TestConfirmTransactions_Refund_Error(t *testing.T) { + mockDB := mocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + transaction := models.Transaction{ + ID: &primitive.ObjectID{}, + Hash: "txHash", + Messages: []primitive.ObjectID{}, + Refund: &primitive.ObjectID{}, + } + + relayer := &CosmosMessageRelayerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + currentBlockHeight: 100, + multisigPk: multisigPk, + config: models.CosmosNetworkConfig{Confirmations: 10}, + } + + txResponse := &sdk.TxResponse{ + Code: 0, + Height: 90, + } + + mockDB.EXPECT().GetPendingTransactionsFrom(mock.Anything, mock.Anything).Return([]models.Transaction{transaction}, nil) + mockClient.EXPECT().GetTx("txHash").Return(txResponse, nil) + txUpdate := bson.M{ + "status": models.TransactionStatusConfirmed, + "confirmations": uint64(10), + } + mockDB.EXPECT().UpdateTransaction(transaction.ID, txUpdate).Return(nil) + refundUpdate := bson.M{ + "status": models.MessageStatusSuccess, + "transaction": &primitive.ObjectID{}, + "transaction_hash": "txHash", + } + mockDB.EXPECT().UpdateRefund(mock.Anything, refundUpdate).Return(assert.AnError) + + result := relayer.ConfirmTransactions() + + mockDB.AssertExpectations(t) + mockClient.AssertExpectations(t) + assert.False(t, result) +} + +func TestRelayerInitStartBlockHeight(t *testing.T) { + logger := logrus.New().WithField("test", "relayer") + lastHealth := &models.RunnerServiceStatus{BlockHeight: 100} + + relayer := &CosmosMessageRelayerRunnable{ + logger: logger, + startBlockHeight: 0, + currentBlockHeight: 200, + } + + relayer.InitStartBlockHeight(lastHealth) + + assert.Equal(t, uint64(100), relayer.startBlockHeight) + + relayer = &CosmosMessageRelayerRunnable{ + logger: logger, startBlockHeight: 0, currentBlockHeight: 200, } @@ -394,11 +1255,14 @@ func TestRelayerRun(t *testing.T) { mockDB := mocks.NewMockDB(t) mockClient := clientMocks.NewMockCosmosClient(t) logger := logrus.New().WithField("test", "relayer") + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) relayer := &CosmosMessageRelayerRunnable{ - db: mockDB, - client: mockClient, - logger: logger, + db: mockDB, + client: mockClient, + logger: logger, + multisigPk: multisigPk, } mockClient.EXPECT().GetLatestBlockHeight().Return(int64(100), nil) @@ -411,4 +1275,300 @@ func TestRelayerRun(t *testing.T) { mockClient.AssertExpectations(t) mockDB.AssertExpectations(t) } -*/ + +func TestNewMessageRelayer(t *testing.T) { + config := models.CosmosNetworkConfig{ + StartBlockHeight: 1, + Confirmations: 1, + RPCURL: "http://localhost:36657", + GRPCEnabled: true, + GRPCHost: "localhost", + GRPCPort: 9090, + TimeoutMS: 1000, + ChainID: "poktroll", + ChainName: "Poktroll", + TxFee: 1000, + Bech32Prefix: "pokt", + CoinDenom: "upokt", + MultisigAddress: "pokt13tsl3aglfyzf02n7x28x2ajzw94muu6y57k2ar", + MultisigPublicKeys: []string{"026892de2ec7fdf3125bc1bfd2ff2590d2c9ba756f98a05e9e843ac4d2a1acd4d9", "02faaaf0f385bb17381f36dcd86ab2486e8ff8d93440436496665ac007953076c2", "02cae233806460db75a941a269490ca5165a620b43241edb8bc72e169f4143a6df"}, + MultisigThreshold: 2, + MessageMonitor: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + MessageSigner: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + MessageRelayer: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + } + + lastHealth := &models.RunnerServiceStatus{BlockHeight: 100} + + mockClient := clientMocks.NewMockCosmosClient(t) + mockDB := mocks.NewMockDB(t) + + // Mocking client methods + mockClient.EXPECT().GetLatestBlockHeight().Return(int64(100), nil) + + originalNewDB := dbNewDB + defer func() { dbNewDB = originalNewDB }() + dbNewDB = func() db.DB { + return mockDB + } + + originalCosmosNewClient := cosmosNewClient + defer func() { cosmosNewClient = originalCosmosNewClient }() + cosmosNewClient = func(config models.CosmosNetworkConfig) (cosmos.CosmosClient, error) { + return mockClient, nil + } + + runnable := NewMessageRelayer(config, lastHealth) + + assert.NotNil(t, runnable) + relayer, ok := runnable.(*CosmosMessageRelayerRunnable) + assert.True(t, ok) + + assert.Equal(t, uint64(100), relayer.startBlockHeight) + assert.Equal(t, uint64(100), relayer.currentBlockHeight) + assert.Equal(t, config, relayer.config) + assert.Equal(t, util.ParseChain(config), relayer.chain) + assert.NotNil(t, relayer.client) + assert.NotNil(t, relayer.logger) + assert.NotNil(t, relayer.db) + + mockClient.AssertExpectations(t) + mockDB.AssertExpectations(t) +} + +func TestNewMessageRelayer_Disabled(t *testing.T) { + defer func() { log.StandardLogger().ExitFunc = nil }() + log.StandardLogger().ExitFunc = func(num int) { panic(fmt.Sprintf("exit %d", num)) } + + config := models.CosmosNetworkConfig{ + StartBlockHeight: 1, + Confirmations: 1, + RPCURL: "http://localhost:36657", + GRPCEnabled: true, + GRPCHost: "localhost", + GRPCPort: 9090, + TimeoutMS: 1000, + ChainID: "poktroll", + ChainName: "Poktroll", + TxFee: 1000, + Bech32Prefix: "pokt", + CoinDenom: "upokt", + MultisigAddress: "pokt13tsl3aglfyzf02n7x28x2ajzw94muu6y57k2ar", + MultisigPublicKeys: []string{"026892de2ec7fdf3125bc1bfd2ff2590d2c9ba756f98a05e9e843ac4d2a1acd4d9", "02faaaf0f385bb17381f36dcd86ab2486e8ff8d93440436496665ac007953076c2", "02cae233806460db75a941a269490ca5165a620b43241edb8bc72e169f4143a6df"}, + MultisigThreshold: 2, + MessageMonitor: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + MessageSigner: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + MessageRelayer: models.ServiceConfig{ + Enabled: false, + IntervalMS: 1000, + }, + } + + lastHealth := &models.RunnerServiceStatus{BlockHeight: 100} + + mockClient := clientMocks.NewMockCosmosClient(t) + mockDB := mocks.NewMockDB(t) + + originalNewDB := dbNewDB + defer func() { dbNewDB = originalNewDB }() + dbNewDB = func() db.DB { + return mockDB + } + + originalCosmosNewClient := cosmosNewClient + defer func() { cosmosNewClient = originalCosmosNewClient }() + cosmosNewClient = func(config models.CosmosNetworkConfig) (cosmos.CosmosClient, error) { + return mockClient, nil + } + + assert.Panics(t, func() { + NewMessageRelayer(config, lastHealth) + }) + +} + +func TestNewMessageRelayer_InvalidPublicKey(t *testing.T) { + defer func() { log.StandardLogger().ExitFunc = nil }() + log.StandardLogger().ExitFunc = func(num int) { panic(fmt.Sprintf("exit %d", num)) } + + config := models.CosmosNetworkConfig{ + StartBlockHeight: 1, + Confirmations: 1, + RPCURL: "http://localhost:36657", + GRPCEnabled: true, + GRPCHost: "localhost", + GRPCPort: 9090, + TimeoutMS: 1000, + ChainID: "poktroll", + ChainName: "Poktroll", + TxFee: 1000, + Bech32Prefix: "pokt", + CoinDenom: "upokt", + MultisigAddress: "pokt13tsl3aglfyzf02n7x28x2ajzw94muu6y57k2ar", + MultisigPublicKeys: []string{"026892de2ec7fdf3125bc1bfd2ff2590d2c9ba756f98a05e9e843ac4d2a1acd4d9", "02faaaf0f385bb17381f36dcd86ab2486e8ff8d93440436496665ac007953076c2", "02cae233806460db75a941a269490ca5165a620b43241edb8bc72e169f4143"}, + MultisigThreshold: 2, + MessageMonitor: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + MessageSigner: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + MessageRelayer: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + } + + lastHealth := &models.RunnerServiceStatus{BlockHeight: 100} + + mockClient := clientMocks.NewMockCosmosClient(t) + mockDB := mocks.NewMockDB(t) + + originalNewDB := dbNewDB + defer func() { dbNewDB = originalNewDB }() + dbNewDB = func() db.DB { + return mockDB + } + + originalCosmosNewClient := cosmosNewClient + defer func() { cosmosNewClient = originalCosmosNewClient }() + cosmosNewClient = func(config models.CosmosNetworkConfig) (cosmos.CosmosClient, error) { + return mockClient, nil + } + + assert.Panics(t, func() { + NewMessageRelayer(config, lastHealth) + }) + +} + +func TestNewMessageRelayer_InvalidMultisigAddress(t *testing.T) { + defer func() { log.StandardLogger().ExitFunc = nil }() + log.StandardLogger().ExitFunc = func(num int) { panic(fmt.Sprintf("exit %d", num)) } + + config := models.CosmosNetworkConfig{ + StartBlockHeight: 1, + Confirmations: 1, + RPCURL: "http://localhost:36657", + GRPCEnabled: true, + GRPCHost: "localhost", + GRPCPort: 9090, + TimeoutMS: 1000, + ChainID: "poktroll", + ChainName: "Poktroll", + TxFee: 1000, + Bech32Prefix: "pokt", + CoinDenom: "upokt", + MultisigAddress: "pokt1", + MultisigPublicKeys: []string{"026892de2ec7fdf3125bc1bfd2ff2590d2c9ba756f98a05e9e843ac4d2a1acd4d9", "02faaaf0f385bb17381f36dcd86ab2486e8ff8d93440436496665ac007953076c2", "02cae233806460db75a941a269490ca5165a620b43241edb8bc72e169f4143a6df"}, + MultisigThreshold: 2, + MessageMonitor: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + MessageSigner: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + MessageRelayer: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + } + + lastHealth := &models.RunnerServiceStatus{BlockHeight: 100} + + mockClient := clientMocks.NewMockCosmosClient(t) + mockDB := mocks.NewMockDB(t) + + originalNewDB := dbNewDB + defer func() { dbNewDB = originalNewDB }() + dbNewDB = func() db.DB { + return mockDB + } + + originalCosmosNewClient := cosmosNewClient + defer func() { cosmosNewClient = originalCosmosNewClient }() + cosmosNewClient = func(config models.CosmosNetworkConfig) (cosmos.CosmosClient, error) { + return mockClient, nil + } + + assert.Panics(t, func() { + NewMessageRelayer(config, lastHealth) + }) + +} + +func TestNewMessageRelayer_ClientError(t *testing.T) { + defer func() { log.StandardLogger().ExitFunc = nil }() + log.StandardLogger().ExitFunc = func(num int) { panic(fmt.Sprintf("exit %d", num)) } + + config := models.CosmosNetworkConfig{ + StartBlockHeight: 1, + Confirmations: 1, + RPCURL: "http://localhost:36657", + GRPCEnabled: true, + GRPCHost: "localhost", + GRPCPort: 9090, + TimeoutMS: 1000, + ChainID: "poktroll", + ChainName: "Poktroll", + TxFee: 1000, + Bech32Prefix: "pokt", + CoinDenom: "upokt", + MultisigAddress: "pokt13tsl3aglfyzf02n7x28x2ajzw94muu6y57k2ar", + MultisigPublicKeys: []string{"026892de2ec7fdf3125bc1bfd2ff2590d2c9ba756f98a05e9e843ac4d2a1acd4d9", "02faaaf0f385bb17381f36dcd86ab2486e8ff8d93440436496665ac007953076c2", "02cae233806460db75a941a269490ca5165a620b43241edb8bc72e169f4143a6df"}, + MultisigThreshold: 2, + MessageMonitor: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + MessageSigner: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + MessageRelayer: models.ServiceConfig{ + Enabled: true, + IntervalMS: 1000, + }, + } + + lastHealth := &models.RunnerServiceStatus{BlockHeight: 100} + + mockClient := clientMocks.NewMockCosmosClient(t) + mockDB := mocks.NewMockDB(t) + + originalNewDB := dbNewDB + defer func() { dbNewDB = originalNewDB }() + dbNewDB = func() db.DB { + return mockDB + } + + originalCosmosNewClient := cosmosNewClient + defer func() { cosmosNewClient = originalCosmosNewClient }() + cosmosNewClient = func(config models.CosmosNetworkConfig) (cosmos.CosmosClient, error) { + return mockClient, assert.AnError + } + + assert.Panics(t, func() { + NewMessageRelayer(config, lastHealth) + }) + +} diff --git a/cosmos/signer.go b/cosmos/signer.go index 4bc8172..e6b1d00 100644 --- a/cosmos/signer.go +++ b/cosmos/signer.go @@ -371,10 +371,7 @@ func (x *CosmosMessageSignerRunnable) ValidateEthereumTxAndSignMessage(messageDo func (x *CosmosMessageSignerRunnable) SignMessages() bool { x.logger.Infof("Signing messages") - addressHex, err := common.AddressHexFromBytes(x.signerKey.PubKey().Address().Bytes()) - if err != nil { - x.logger.WithError(err).Errorf("Error getting address hex") - } + addressHex, _ := common.AddressHexFromBytes(x.signerKey.PubKey().Address().Bytes()) messages, err := x.db.GetPendingMessages(addressHex, x.chain) if err != nil { @@ -1193,7 +1190,7 @@ func NewMessageSigner( client, err := cosmos.NewClient(config) if err != nil { - logger.WithError(err).Errorf("Error creating cosmos client") + logger.WithError(err).Fatalf("Error creating cosmos client") } privKey, err := common.CosmosPrivateKeyFromMnemonic(mnemonic) diff --git a/cosmos/signer_test.go b/cosmos/signer_test.go index 35398ed..c0c27ce 100644 --- a/cosmos/signer_test.go +++ b/cosmos/signer_test.go @@ -221,6 +221,318 @@ func TestSignMessage(t *testing.T) { assert.True(t, result) } +func TestValidateAndFindDispatchIdEvent_InvalidMessageID(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + ethClientMap := map[uint32]eth.EthereumClient{1: ethClient} + mailboxMap := map[uint32]eth.MailboxContract{1: mailbox} + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: "recipient"}}, + Signatures: []models.Signature{}, + MessageID: "invalid", + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + } + + result, err := signer.ValidateAndFindDispatchIdEvent(message) + + assert.Nil(t, result) + assert.Error(t, err) + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) +} + +func TestValidateAndFindDispatchIdEvent_EthClientError(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + ethClientMap := map[uint32]eth.EthereumClient{} + mailboxMap := map[uint32]eth.MailboxContract{1: mailbox} + + messageIDBytes := [32]byte{} + messageID := common.HexFromBytes(messageIDBytes[:]) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: "recipient"}}, + Signatures: []models.Signature{}, + MessageID: messageID, + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + } + + result, err := signer.ValidateAndFindDispatchIdEvent(message) + + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) + assert.Nil(t, result) + assert.Error(t, err) +} + +func TestValidateAndFindDispatchIdEvent_MailboxError(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + ethClientMap := map[uint32]eth.EthereumClient{1: ethClient} + mailboxMap := map[uint32]eth.MailboxContract{} + + messageIDBytes := [32]byte{} + messageID := common.HexFromBytes(messageIDBytes[:]) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: "recipient"}}, + Signatures: []models.Signature{}, + MessageID: messageID, + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + } + + result, err := signer.ValidateAndFindDispatchIdEvent(message) + + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) + assert.Nil(t, result) + assert.Error(t, err) +} + +func TestValidateAndFindDispatchIdEvent_ReceiptError(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + ethClientMap := map[uint32]eth.EthereumClient{1: ethClient} + mailboxMap := map[uint32]eth.MailboxContract{1: mailbox} + + messageIDBytes := [32]byte{} + messageID := common.HexFromBytes(messageIDBytes[:]) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: "recipient"}}, + Signatures: []models.Signature{}, + MessageID: messageID, + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + } + + ethClient.EXPECT().GetTransactionReceipt("hash1").Return(nil, assert.AnError) + + result, err := signer.ValidateAndFindDispatchIdEvent(message) + + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) + assert.Nil(t, result) + assert.Error(t, err) +} + +func TestValidateAndFindDispatchIdEvent_UnsuccessfulReceipt(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + ethClientMap := map[uint32]eth.EthereumClient{1: ethClient} + mailboxMap := map[uint32]eth.MailboxContract{1: mailbox} + + messageIDBytes := [32]byte{} + messageID := common.HexFromBytes(messageIDBytes[:]) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: "recipient"}}, + Signatures: []models.Signature{}, + MessageID: messageID, + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + } + + ethClient.EXPECT().GetTransactionReceipt("hash1").Return(&types.Receipt{ + BlockNumber: big.NewInt(90), + Status: types.ReceiptStatusFailed, + Logs: []*types.Log{}, + }, nil).Once() + + result, err := signer.ValidateAndFindDispatchIdEvent(message) + + assert.NotNil(t, result) + assert.Equal(t, models.TransactionStatusFailed, result.TxStatus) + assert.NoError(t, err) + + ethClient.EXPECT().GetTransactionReceipt("hash1").Return(nil, nil).Once() + + result, err = signer.ValidateAndFindDispatchIdEvent(message) + + assert.NotNil(t, result) + assert.Equal(t, models.TransactionStatusFailed, result.TxStatus) + assert.NoError(t, err) + + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) +} + +func TestValidateAndFindDispatchIdEvent_BlockHeightError(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + mailbox.EXPECT().Address().Return(ethcommon.BytesToAddress([]byte("mailbox"))) + + ethClientMap := map[uint32]eth.EthereumClient{1: ethClient} + mailboxMap := map[uint32]eth.MailboxContract{1: mailbox} + + messageIDBytes := [32]byte{} + messageID := common.HexFromBytes(messageIDBytes[:]) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: "recipient"}}, + Signatures: []models.Signature{}, + MessageID: messageID, + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + } + + ethClient.EXPECT().GetTransactionReceipt("hash1").Return(&types.Receipt{ + BlockNumber: big.NewInt(90), + Status: types.ReceiptStatusSuccessful, + Logs: []*types.Log{{Address: mailbox.Address()}}, + }, nil) + ethClient.EXPECT().GetBlockHeight().Return(uint64(100), assert.AnError) + mailbox.EXPECT().ParseDispatchId(mock.Anything).Return(&autogen.MailboxDispatchId{MessageId: [32]byte{}}, nil) + + result, err := signer.ValidateAndFindDispatchIdEvent(message) + + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) + assert.Nil(t, result) + assert.Error(t, err) +} + +func TestValidateAndFindDispatchIdEvent_NoEvent(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + mailbox.EXPECT().Address().Return(ethcommon.BytesToAddress([]byte("mailbox"))) + ethClient.EXPECT().Confirmations().Return(uint64(10)) + + ethClientMap := map[uint32]eth.EthereumClient{1: ethClient} + mailboxMap := map[uint32]eth.MailboxContract{1: mailbox} + + messageIDBytes := [32]byte{} + messageID := common.HexFromBytes(messageIDBytes[:]) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: "recipient"}}, + Signatures: []models.Signature{}, + MessageID: messageID, + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + } + + ethClient.EXPECT().GetTransactionReceipt("hash1").Return(&types.Receipt{ + BlockNumber: big.NewInt(90), + Status: types.ReceiptStatusSuccessful, + Logs: []*types.Log{{Address: mailbox.Address()}}, + }, nil) + ethClient.EXPECT().GetBlockHeight().Return(uint64(100), nil) + + mailbox.EXPECT().ParseDispatchId(mock.Anything).Return(nil, assert.AnError) + + result, err := signer.ValidateAndFindDispatchIdEvent(message) + + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) + assert.NotNil(t, result) + assert.NoError(t, err) + assert.Equal(t, uint64(10), result.Confirmations) + assert.Equal(t, models.TransactionStatusInvalid, result.TxStatus) +} + func TestValidateAndFindDispatchIdEvent(t *testing.T) { mockDB := dbMocks.NewMockDB(t) mockClient := clientMocks.NewMockCosmosClient(t) @@ -260,7 +572,6 @@ func TestValidateAndFindDispatchIdEvent(t *testing.T) { Logs: []*types.Log{{Address: mailbox.Address()}}, }, nil) ethClient.EXPECT().GetBlockHeight().Return(uint64(100), nil) - ethClient.EXPECT().Confirmations().Return(uint64(10)) mailbox.EXPECT().ParseDispatchId(mock.Anything).Return(&autogen.MailboxDispatchId{MessageId: [32]byte{}}, nil) @@ -276,6 +587,249 @@ func TestValidateAndFindDispatchIdEvent(t *testing.T) { assert.Equal(t, models.TransactionStatusConfirmed, result.TxStatus) } +func TestValidateEthereumTxAndSignMessage_ValidateError(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + ethClientMap := map[uint32]eth.EthereumClient{1: ethClient} + mailboxMap := map[uint32]eth.MailboxContract{1: mailbox} + + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: recipientAddr.Hex(), Amount: "100"}}, + Signatures: []models.Signature{}, + MessageID: "0xinvalid", + Sequence: new(uint64), + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + multisigPk: multisigPk, + signerKey: signerKey, + config: models.CosmosNetworkConfig{ + ChainID: "chain-id", + CoinDenom: "upokt", + Bech32Prefix: "pokt", + MultisigAddress: "multisigAddress", + }, + } + + result := signer.ValidateEthereumTxAndSignMessage(message) + + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) + assert.False(t, result) +} + +func TestValidateEthereumTxAndSignMessage_Pending(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + mailbox.EXPECT().Address().Return(ethcommon.BytesToAddress([]byte("mailbox"))) + ethClient.EXPECT().Confirmations().Return(uint64(10)) + + ethClientMap := map[uint32]eth.EthereumClient{1: ethClient} + mailboxMap := map[uint32]eth.MailboxContract{1: mailbox} + + messageIDBytes := [32]byte{} + messageID := common.HexFromBytes(messageIDBytes[:]) + + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: recipientAddr.Hex(), Amount: "100"}}, + Signatures: []models.Signature{}, + MessageID: messageID, + Sequence: new(uint64), + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + multisigPk: multisigPk, + signerKey: signerKey, + config: models.CosmosNetworkConfig{ + ChainID: "chain-id", + CoinDenom: "upokt", + Bech32Prefix: "pokt", + MultisigAddress: "multisigAddress", + }, + } + + ethClient.EXPECT().GetTransactionReceipt("hash1").Return(&types.Receipt{ + BlockNumber: big.NewInt(90), + Status: types.ReceiptStatusSuccessful, + Logs: []*types.Log{{Address: mailbox.Address()}}, + }, nil) + ethClient.EXPECT().GetBlockHeight().Return(uint64(91), nil) + ethClient.EXPECT().Confirmations().Return(uint64(10)) + + mailbox.EXPECT().ParseDispatchId(mock.Anything).Return(&autogen.MailboxDispatchId{MessageId: [32]byte{}}, nil) + + result := signer.ValidateEthereumTxAndSignMessage(message) + + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) + assert.False(t, result) +} + +func TestValidateEthereumTxAndSignMessage_FailedTx(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + mailbox.EXPECT().Address().Return(ethcommon.BytesToAddress([]byte("mailbox"))) + + ethClientMap := map[uint32]eth.EthereumClient{1: ethClient} + mailboxMap := map[uint32]eth.MailboxContract{1: mailbox} + + messageIDBytes := [32]byte{} + messageID := common.HexFromBytes(messageIDBytes[:]) + + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: recipientAddr.Hex(), Amount: "100"}}, + Signatures: []models.Signature{}, + MessageID: messageID, + Sequence: new(uint64), + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + multisigPk: multisigPk, + signerKey: signerKey, + config: models.CosmosNetworkConfig{ + ChainID: "chain-id", + CoinDenom: "upokt", + Bech32Prefix: "pokt", + MultisigAddress: "multisigAddress", + }, + } + + ethClient.EXPECT().GetTransactionReceipt("hash1").Return(&types.Receipt{ + BlockNumber: big.NewInt(90), + Status: types.ReceiptStatusFailed, + Logs: []*types.Log{{Address: mailbox.Address()}}, + }, nil) + + mockDB.EXPECT().UpdateMessage(message.ID, bson.M{"status": models.MessageStatusInvalid}).Return(nil) + + result := signer.ValidateEthereumTxAndSignMessage(message) + + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) + assert.True(t, result) +} + +func TestValidateEthereumTxAndSignMessage_LockError(t *testing.T) { + mockDB := dbMocks.NewMockDB(t) + mockClient := clientMocks.NewMockCosmosClient(t) + logger := log.New().WithField("test", "signer") + + signerKey := secp256k1.GenPrivKey() + multisigPk := multisig.NewLegacyAminoPubKey(1, []cryptotypes.PubKey{signerKey.PubKey()}) + + ethClient := ethMocks.NewMockEthereumClient(t) + mailbox := ethMocks.NewMockMailboxContract(t) + + mailbox.EXPECT().Address().Return(ethcommon.BytesToAddress([]byte("mailbox"))) + ethClient.EXPECT().Confirmations().Return(uint64(10)) + + ethClientMap := map[uint32]eth.EthereumClient{1: ethClient} + mailboxMap := map[uint32]eth.MailboxContract{1: mailbox} + + messageIDBytes := [32]byte{} + messageID := common.HexFromBytes(messageIDBytes[:]) + + recipientAddr := ethcommon.BytesToAddress([]byte("recipient")) + + message := &models.Message{ + ID: &primitive.ObjectID{}, + OriginTransactionHash: "hash1", + Content: models.MessageContent{OriginDomain: 1, MessageBody: models.MessageBody{RecipientAddress: recipientAddr.Hex(), Amount: "100"}}, + Signatures: []models.Signature{}, + MessageID: messageID, + Sequence: new(uint64), + } + + signer := &CosmosMessageSignerRunnable{ + db: mockDB, + client: mockClient, + logger: logger, + ethClientMap: ethClientMap, + mailboxMap: mailboxMap, + multisigPk: multisigPk, + signerKey: signerKey, + config: models.CosmosNetworkConfig{ + ChainID: "chain-id", + CoinDenom: "upokt", + Bech32Prefix: "pokt", + MultisigAddress: "multisigAddress", + }, + } + + ethClient.EXPECT().GetTransactionReceipt("hash1").Return(&types.Receipt{ + BlockNumber: big.NewInt(90), + Status: types.ReceiptStatusSuccessful, + Logs: []*types.Log{{Address: mailbox.Address()}}, + }, nil) + ethClient.EXPECT().GetBlockHeight().Return(uint64(100), nil) + ethClient.EXPECT().Confirmations().Return(uint64(10)) + + mailbox.EXPECT().ParseDispatchId(mock.Anything).Return(&autogen.MailboxDispatchId{MessageId: [32]byte{}}, nil) + + mockDB.EXPECT().LockWriteMessage(mock.Anything).Return("lock-id", assert.AnError) + + result := signer.ValidateEthereumTxAndSignMessage(message) + + mockDB.AssertExpectations(t) + ethClient.AssertExpectations(t) + mailbox.AssertExpectations(t) + assert.False(t, result) +} + func TestValidateEthereumTxAndSignMessage(t *testing.T) { mockDB := dbMocks.NewMockDB(t) mockClient := clientMocks.NewMockCosmosClient(t) @@ -506,7 +1060,7 @@ func TestSignMessages(t *testing.T) { assert.True(t, result) } -func TestSignMessages_Error(t *testing.T) { +func TestSignMessages_DBError(t *testing.T) { mockDB := dbMocks.NewMockDB(t) mockClient := clientMocks.NewMockCosmosClient(t) logger := log.New().WithField("test", "signer")