diff --git a/vald/evm/deposit_confirmation.go b/vald/evm/deposit_confirmation.go index da66ef7ba..3d71c8071 100644 --- a/vald/evm/deposit_confirmation.go +++ b/vald/evm/deposit_confirmation.go @@ -45,6 +45,10 @@ func (mgr Mgr) processDepositConfirmationLogs(event *types.ConfirmDepositStarted events := make([]types.Event, 0, len(logs)) for i, log := range logs { + if len(log.Topics) == 0 { + continue + } + if log.Topics[0] != ERC20TransferSig { continue } diff --git a/vald/evm/deposit_confirmation_test.go b/vald/evm/deposit_confirmation_test.go index c0179a193..a0df74b98 100644 --- a/vald/evm/deposit_confirmation_test.go +++ b/vald/evm/deposit_confirmation_test.go @@ -22,6 +22,7 @@ import ( "github.com/axelarnetwork/axelar-core/x/evm/types" "github.com/axelarnetwork/axelar-core/x/evm/types/testutils" nexus "github.com/axelarnetwork/axelar-core/x/nexus/exported" + "github.com/axelarnetwork/axelar-core/x/vote/exported" votetypes "github.com/axelarnetwork/axelar-core/x/vote/types" "github.com/axelarnetwork/utils/monads/results" "github.com/axelarnetwork/utils/slices" @@ -315,6 +316,35 @@ func TestMgr_ProccessDepositConfirmation(t *testing.T) { Run(t, 20) } +func TestMgr_ProccessDepositConfirmationNoTopicsNotPanics(t *testing.T) { + chain := nexus.ChainName(strings.ToLower(rand.NormalizedStr(5))) + receipt := geth.Receipt{ + Logs: []*geth.Log{{Topics: make([]common.Hash, 0)}}, + BlockNumber: big.NewInt(1), + Status: geth.ReceiptStatusSuccessful, + } + rpcClient := &mock.ClientMock{TransactionReceiptsFunc: func(_ context.Context, _ []common.Hash) ([]evmRpc.TxReceiptResult, error) { + return []evmRpc.TxReceiptResult{evmRpc.TxReceiptResult(results.FromOk(receipt))}, nil + }} + cache := &evmmock.LatestFinalizedBlockCacheMock{GetFunc: func(chain nexus.ChainName) *big.Int { + return big.NewInt(100) + }} + + broadcaster := &broadcastmock.BroadcasterMock{BroadcastFunc: func(_ context.Context, _ ...sdk.Msg) (*sdk.TxResponse, error) { + return nil, nil + }} + + valAddr := rand.ValAddr() + mgr := evm.NewMgr(map[string]evmRpc.Client{chain.String(): rpcClient}, broadcaster, valAddr, rand.AccAddr(), cache) + + assert.NotPanics(t, func() { + mgr.ProcessDepositConfirmation(&types.ConfirmDepositStarted{TxID: types.Hash{1}, + PollParticipants: exported.PollParticipants{PollID: 10, Participants: []sdk.ValAddress{valAddr}}, + Chain: chain, + }) + }) +} + type byter interface { Bytes() []byte } diff --git a/vald/evm/evm.go b/vald/evm/evm.go index 2383d1411..65b3b8bf7 100644 --- a/vald/evm/evm.go +++ b/vald/evm/evm.go @@ -10,6 +10,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/common" geth "github.com/ethereum/go-ethereum/core/types" + errors2 "github.com/pkg/errors" "github.com/axelarnetwork/axelar-core/sdk-utils/broadcast" "github.com/axelarnetwork/axelar-core/utils/errors" @@ -64,6 +65,10 @@ func (mgr Mgr) isFinalized(chain nexus.ChainName, txReceipt geth.Receipt, confHe return false, fmt.Errorf("rpc client not found for chain %s", chain.String()) } + if txReceipt.BlockNumber == nil { + return false, errors2.New("block number of tx receipt is nil") + } + if mgr.latestFinalizedBlockCache.Get(chain).Cmp(txReceipt.BlockNumber) >= 0 { return true, nil } diff --git a/vald/evm/gateway_tx_confirmation.go b/vald/evm/gateway_tx_confirmation.go index 9ae5e684c..434834167 100644 --- a/vald/evm/gateway_tx_confirmation.go +++ b/vald/evm/gateway_tx_confirmation.go @@ -50,6 +50,10 @@ func (mgr Mgr) processGatewayTxLogs(chain nexus.ChainName, gatewayAddress types. continue } + if len(txlog.Topics) == 0 { + continue + } + switch txlog.Topics[0] { case ContractCallSig: gatewayEvent, err := DecodeEventContractCall(txlog) diff --git a/vald/evm/gateway_tx_confirmation_test.go b/vald/evm/gateway_tx_confirmation_test.go new file mode 100644 index 000000000..7301ade2e --- /dev/null +++ b/vald/evm/gateway_tx_confirmation_test.go @@ -0,0 +1,78 @@ +package evm_test + +import ( + "context" + "math/big" + "strings" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + geth "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/assert" + + mock2 "github.com/axelarnetwork/axelar-core/sdk-utils/broadcast/mock" + "github.com/axelarnetwork/axelar-core/testutils/rand" + "github.com/axelarnetwork/axelar-core/vald/evm" + evmmock "github.com/axelarnetwork/axelar-core/vald/evm/mock" + evmRpc "github.com/axelarnetwork/axelar-core/vald/evm/rpc" + "github.com/axelarnetwork/axelar-core/vald/evm/rpc/mock" + "github.com/axelarnetwork/axelar-core/x/evm/types" + nexus "github.com/axelarnetwork/axelar-core/x/nexus/exported" + "github.com/axelarnetwork/axelar-core/x/vote/exported" + "github.com/axelarnetwork/utils/monads/results" +) + +func TestMgr_ProcessGatewayTxConfirmationMissingBlockNumberNotPanics(t *testing.T) { + chain := nexus.ChainName(strings.ToLower(rand.NormalizedStr(5))) + receipt := geth.Receipt{Logs: []*geth.Log{{Topics: make([]common.Hash, 0)}}} + rpcClient := &mock.ClientMock{TransactionReceiptsFunc: func(_ context.Context, _ []common.Hash) ([]evmRpc.TxReceiptResult, error) { + return []evmRpc.TxReceiptResult{evmRpc.TxReceiptResult(results.FromOk(receipt))}, nil + }} + cache := &evmmock.LatestFinalizedBlockCacheMock{GetFunc: func(chain nexus.ChainName) *big.Int { + return big.NewInt(100) + }} + + broadcaster := &mock2.BroadcasterMock{BroadcastFunc: func(_ context.Context, _ ...sdk.Msg) (*sdk.TxResponse, error) { + return nil, nil + }} + + valAddr := rand.ValAddr() + mgr := evm.NewMgr(map[string]evmRpc.Client{chain.String(): rpcClient}, broadcaster, valAddr, rand.AccAddr(), cache) + + assert.NotPanics(t, func() { + mgr.ProcessGatewayTxConfirmation(&types.ConfirmGatewayTxStarted{TxID: types.Hash{1}, + PollParticipants: exported.PollParticipants{PollID: 10, Participants: []sdk.ValAddress{valAddr}}, + Chain: chain, + }) + }) +} + +func TestMgr_ProcessGatewayTxConfirmationNoTopicsNotPanics(t *testing.T) { + chain := nexus.ChainName(strings.ToLower(rand.NormalizedStr(5))) + receipt := geth.Receipt{ + Logs: []*geth.Log{{Topics: make([]common.Hash, 0)}}, + BlockNumber: big.NewInt(1), + Status: geth.ReceiptStatusSuccessful, + } + rpcClient := &mock.ClientMock{TransactionReceiptsFunc: func(_ context.Context, _ []common.Hash) ([]evmRpc.TxReceiptResult, error) { + return []evmRpc.TxReceiptResult{evmRpc.TxReceiptResult(results.FromOk(receipt))}, nil + }} + cache := &evmmock.LatestFinalizedBlockCacheMock{GetFunc: func(chain nexus.ChainName) *big.Int { + return big.NewInt(100) + }} + + broadcaster := &mock2.BroadcasterMock{BroadcastFunc: func(_ context.Context, _ ...sdk.Msg) (*sdk.TxResponse, error) { + return nil, nil + }} + + valAddr := rand.ValAddr() + mgr := evm.NewMgr(map[string]evmRpc.Client{chain.String(): rpcClient}, broadcaster, valAddr, rand.AccAddr(), cache) + + assert.NotPanics(t, func() { + mgr.ProcessGatewayTxConfirmation(&types.ConfirmGatewayTxStarted{TxID: types.Hash{1}, + PollParticipants: exported.PollParticipants{PollID: 10, Participants: []sdk.ValAddress{valAddr}}, + Chain: chain, + }) + }) +} diff --git a/vald/evm/gateway_txs_confirmation_test.go b/vald/evm/gateway_txs_confirmation_test.go new file mode 100644 index 000000000..8c7d74dc2 --- /dev/null +++ b/vald/evm/gateway_txs_confirmation_test.go @@ -0,0 +1,79 @@ +package evm_test + +import ( + "context" + "math/big" + "strings" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + geth "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/assert" + + mock2 "github.com/axelarnetwork/axelar-core/sdk-utils/broadcast/mock" + "github.com/axelarnetwork/axelar-core/testutils/rand" + "github.com/axelarnetwork/axelar-core/vald/evm" + evmmock "github.com/axelarnetwork/axelar-core/vald/evm/mock" + evmRpc "github.com/axelarnetwork/axelar-core/vald/evm/rpc" + "github.com/axelarnetwork/axelar-core/vald/evm/rpc/mock" + "github.com/axelarnetwork/axelar-core/x/evm/types" + nexus "github.com/axelarnetwork/axelar-core/x/nexus/exported" + "github.com/axelarnetwork/utils/monads/results" +) + +func TestMgr_ProcessGatewayTxsConfirmationMissingBlockNumberNotPanics(t *testing.T) { + chain := nexus.ChainName(strings.ToLower(rand.NormalizedStr(5))) + receipt := geth.Receipt{Logs: []*geth.Log{{Topics: make([]common.Hash, 0)}}} + rpcClient := &mock.ClientMock{TransactionReceiptsFunc: func(_ context.Context, _ []common.Hash) ([]evmRpc.TxReceiptResult, error) { + return []evmRpc.TxReceiptResult{evmRpc.TxReceiptResult(results.FromOk(receipt))}, nil + }} + cache := &evmmock.LatestFinalizedBlockCacheMock{GetFunc: func(chain nexus.ChainName) *big.Int { + return big.NewInt(100) + }} + + broadcaster := &mock2.BroadcasterMock{BroadcastFunc: func(_ context.Context, _ ...sdk.Msg) (*sdk.TxResponse, error) { + return nil, nil + }} + + valAddr := rand.ValAddr() + mgr := evm.NewMgr(map[string]evmRpc.Client{chain.String(): rpcClient}, broadcaster, valAddr, rand.AccAddr(), cache) + + assert.NotPanics(t, func() { + mgr.ProcessGatewayTxsConfirmation(&types.ConfirmGatewayTxsStarted{ + PollMappings: []types.PollMapping{{PollID: 10, TxID: types.Hash{1}}}, + Participants: []sdk.ValAddress{valAddr}, + Chain: chain, + }) + }) +} + +func TestMgr_ProcessGatewayTxsConfirmationNoTopicsNotPanics(t *testing.T) { + chain := nexus.ChainName(strings.ToLower(rand.NormalizedStr(5))) + receipt := geth.Receipt{ + Logs: []*geth.Log{{Topics: make([]common.Hash, 0)}}, + BlockNumber: big.NewInt(1), + Status: geth.ReceiptStatusSuccessful, + } + rpcClient := &mock.ClientMock{TransactionReceiptsFunc: func(_ context.Context, _ []common.Hash) ([]evmRpc.TxReceiptResult, error) { + return []evmRpc.TxReceiptResult{evmRpc.TxReceiptResult(results.FromOk(receipt))}, nil + }} + cache := &evmmock.LatestFinalizedBlockCacheMock{GetFunc: func(chain nexus.ChainName) *big.Int { + return big.NewInt(100) + }} + + broadcaster := &mock2.BroadcasterMock{BroadcastFunc: func(_ context.Context, _ ...sdk.Msg) (*sdk.TxResponse, error) { + return nil, nil + }} + + valAddr := rand.ValAddr() + mgr := evm.NewMgr(map[string]evmRpc.Client{chain.String(): rpcClient}, broadcaster, valAddr, rand.AccAddr(), cache) + + assert.NotPanics(t, func() { + mgr.ProcessGatewayTxsConfirmation(&types.ConfirmGatewayTxsStarted{ + PollMappings: []types.PollMapping{{PollID: 10, TxID: types.Hash{1}}}, + Participants: []sdk.ValAddress{valAddr}, + Chain: chain, + }) + }) +} diff --git a/vald/evm/key_transfer_confirmation.go b/vald/evm/key_transfer_confirmation.go index a0bdf2bb2..c1142f4c4 100644 --- a/vald/evm/key_transfer_confirmation.go +++ b/vald/evm/key_transfer_confirmation.go @@ -44,6 +44,10 @@ func (mgr Mgr) processTransferKeyLogs(event *types.ConfirmKeyTransferStarted, lo for i := len(logs) - 1; i >= 0; i-- { txlog := logs[i] + if len(txlog.Topics) == 0 { + continue + } + if txlog.Topics[0] != MultisigTransferOperatorshipSig { continue } diff --git a/vald/evm/key_transfer_confirmation_test.go b/vald/evm/key_transfer_confirmation_test.go index 3c0e0471a..f759c8950 100644 --- a/vald/evm/key_transfer_confirmation_test.go +++ b/vald/evm/key_transfer_confirmation_test.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "math/big" + "strings" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -186,3 +187,32 @@ func TestMgr_ProcessTransferKeyConfirmation(t *testing.T) { ). Run(t, 5) } + +func TestMgr_ProcessTransferKeyConfirmationNoTopicsNotPanics(t *testing.T) { + chain := nexus.ChainName(strings.ToLower(rand.NormalizedStr(5))) + receipt := geth.Receipt{ + Logs: []*geth.Log{{Topics: make([]common.Hash, 0)}}, + BlockNumber: big.NewInt(1), + Status: geth.ReceiptStatusSuccessful, + } + rpcClient := &mock.ClientMock{TransactionReceiptsFunc: func(_ context.Context, _ []common.Hash) ([]evmrpc.TxReceiptResult, error) { + return []evmrpc.TxReceiptResult{evmrpc.TxReceiptResult(results.FromOk(receipt))}, nil + }} + cache := &evmmock.LatestFinalizedBlockCacheMock{GetFunc: func(chain nexus.ChainName) *big.Int { + return big.NewInt(100) + }} + + broadcaster := &broadcastmock.BroadcasterMock{BroadcastFunc: func(_ context.Context, _ ...sdk.Msg) (*sdk.TxResponse, error) { + return nil, nil + }} + + valAddr := rand.ValAddr() + mgr := evm.NewMgr(map[string]evmrpc.Client{chain.String(): rpcClient}, broadcaster, valAddr, rand.AccAddr(), cache) + + assert.NotPanics(t, func() { + mgr.ProcessTransferKeyConfirmation(&types.ConfirmKeyTransferStarted{TxID: types.Hash{1}, + PollParticipants: vote.PollParticipants{PollID: 10, Participants: []sdk.ValAddress{valAddr}}, + Chain: chain, + }) + }) +} diff --git a/vald/evm/token_confirmation.go b/vald/evm/token_confirmation.go index 6e8687b79..f2077cbfc 100644 --- a/vald/evm/token_confirmation.go +++ b/vald/evm/token_confirmation.go @@ -45,6 +45,10 @@ func (mgr Mgr) ProcessTokenConfirmation(event *types.ConfirmTokenStarted) error func (mgr Mgr) processTokenConfirmationLogs(event *types.ConfirmTokenStarted, logs []*geth.Log) []types.Event { for i, log := range logs { + if len(log.Topics) == 0 { + continue + } + if log.Topics[0] != ERC20TokenDeploymentSig { continue } diff --git a/vald/evm/token_confirmation_test.go b/vald/evm/token_confirmation_test.go index e1e47f76e..206d4422f 100644 --- a/vald/evm/token_confirmation_test.go +++ b/vald/evm/token_confirmation_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "math/big" + "strings" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -229,3 +230,32 @@ func createTokenLogs(denom string, gateway, tokenAddr common.Address, deploySig return logs } + +func TestMgr_ProcessTokenConfirmationNoTopicsNotPanics(t *testing.T) { + chain := nexus.ChainName(strings.ToLower(rand.NormalizedStr(5))) + receipt := geth.Receipt{ + Logs: []*geth.Log{{Topics: make([]common.Hash, 0)}}, + BlockNumber: big.NewInt(1), + Status: geth.ReceiptStatusSuccessful, + } + rpcClient := &mock.ClientMock{TransactionReceiptsFunc: func(_ context.Context, _ []common.Hash) ([]evmrpc.TxReceiptResult, error) { + return []evmrpc.TxReceiptResult{evmrpc.TxReceiptResult(results.FromOk(receipt))}, nil + }} + cache := &evmmock.LatestFinalizedBlockCacheMock{GetFunc: func(chain nexus.ChainName) *big.Int { + return big.NewInt(100) + }} + + broadcaster := &broadcastmock.BroadcasterMock{BroadcastFunc: func(_ context.Context, _ ...sdk.Msg) (*sdk.TxResponse, error) { + return nil, nil + }} + + valAddr := rand.ValAddr() + mgr := evm.NewMgr(map[string]evmrpc.Client{chain.String(): rpcClient}, broadcaster, valAddr, rand.AccAddr(), cache) + + assert.NotPanics(t, func() { + mgr.ProcessTokenConfirmation(&types.ConfirmTokenStarted{TxID: types.Hash{1}, + PollParticipants: vote.PollParticipants{PollID: 10, Participants: []sdk.ValAddress{valAddr}}, + Chain: chain, + }) + }) +}