From 4653b46c8e95eae7ea5c47d279bc1c36c34148df Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 18 Nov 2024 23:50:08 -0600 Subject: [PATCH 01/13] avoid endless rescan when the inbound vote message is invalid --- x/crosschain/types/message_vote_inbound.go | 2 +- zetaclient/chains/bitcoin/observer/event.go | 31 ++--- .../chains/bitcoin/observer/event_test.go | 15 ++- zetaclient/chains/bitcoin/observer/inbound.go | 17 ++- .../chains/bitcoin/observer/inbound_test.go | 4 +- zetaclient/chains/solana/observer/inbound.go | 61 +++++++-- .../chains/solana/observer/inbound_test.go | 82 +++++++++--- zetaclient/compliance/compliance.go | 24 ---- zetaclient/types/event.go | 68 ++++++++++ zetaclient/types/event_test.go | 124 ++++++++++++++++++ 10 files changed, 344 insertions(+), 84 deletions(-) create mode 100644 zetaclient/types/event_test.go diff --git a/x/crosschain/types/message_vote_inbound.go b/x/crosschain/types/message_vote_inbound.go index 3db9fdde0f..e612fe582a 100644 --- a/x/crosschain/types/message_vote_inbound.go +++ b/x/crosschain/types/message_vote_inbound.go @@ -22,7 +22,7 @@ const MaxMessageLength = 10240 // InboundVoteOption is a function that sets some option on the inbound vote message type InboundVoteOption func(*MsgVoteInbound) -// WithMemoRevertOptions sets the revert options for inbound vote message +// WithRevertOptions sets the revert options for inbound vote message func WithRevertOptions(revertOptions RevertOptions) InboundVoteOption { return func(msg *MsgVoteInbound) { msg.RevertOptions = revertOptions diff --git a/zetaclient/chains/bitcoin/observer/event.go b/zetaclient/chains/bitcoin/observer/event.go index 69657d29f1..ffc79916d7 100644 --- a/zetaclient/chains/bitcoin/observer/event.go +++ b/zetaclient/chains/bitcoin/observer/event.go @@ -19,20 +19,7 @@ import ( "github.com/zeta-chain/node/zetaclient/compliance" "github.com/zeta-chain/node/zetaclient/config" "github.com/zeta-chain/node/zetaclient/logs" -) - -// InboundProcessability is an enum representing the processability of an inbound -type InboundProcessability int - -const ( - // InboundProcessabilityGood represents a processable inbound - InboundProcessabilityGood InboundProcessability = iota - - // InboundProcessabilityDonation represents a donation inbound - InboundProcessabilityDonation - - // InboundProcessabilityComplianceViolation represents a compliance violation - InboundProcessabilityComplianceViolation + clienttypes "github.com/zeta-chain/node/zetaclient/types" ) // BTCInboundEvent represents an incoming transaction event @@ -63,10 +50,10 @@ type BTCInboundEvent struct { } // Processability returns the processability of the inbound event -func (event *BTCInboundEvent) Processability() InboundProcessability { +func (event *BTCInboundEvent) Processability() clienttypes.InboundProcessability { // compliance check on sender and receiver addresses if config.ContainRestrictedAddress(event.FromAddress, event.ToAddress) { - return InboundProcessabilityComplianceViolation + return clienttypes.InboundProcessabilityComplianceViolation } // compliance check on receiver, revert/abort addresses in standard memo @@ -76,16 +63,16 @@ func (event *BTCInboundEvent) Processability() InboundProcessability { event.MemoStd.RevertOptions.RevertAddress, event.MemoStd.RevertOptions.AbortAddress, ) { - return InboundProcessabilityComplianceViolation + return clienttypes.InboundProcessabilityComplianceViolation } } // donation check if bytes.Equal(event.MemoBytes, []byte(constant.DonationMessage)) { - return InboundProcessabilityDonation + return clienttypes.InboundProcessabilityDonation } - return InboundProcessabilityGood + return clienttypes.InboundProcessabilityGood } // DecodeMemoBytes decodes the contained memo bytes as either standard or legacy memo @@ -168,16 +155,16 @@ func ValidateStandardMemo(memoStd memo.InboundMemo, chainID int64) error { func (ob *Observer) CheckEventProcessability(event BTCInboundEvent) bool { // check if the event is processable switch result := event.Processability(); result { - case InboundProcessabilityGood: + case clienttypes.InboundProcessabilityGood: return true - case InboundProcessabilityDonation: + case clienttypes.InboundProcessabilityDonation: logFields := map[string]any{ logs.FieldChain: ob.Chain().ChainId, logs.FieldTx: event.TxHash, } ob.Logger().Inbound.Info().Fields(logFields).Msgf("thank you rich folk for your donation!") return false - case InboundProcessabilityComplianceViolation: + case clienttypes.InboundProcessabilityComplianceViolation: compliance.PrintComplianceLog(ob.logger.Inbound, ob.logger.Compliance, false, ob.Chain().ChainId, event.TxHash, event.FromAddress, event.ToAddress, "BTC") return false diff --git a/zetaclient/chains/bitcoin/observer/event_test.go b/zetaclient/chains/bitcoin/observer/event_test.go index 5ed8e9b103..fd870731f8 100644 --- a/zetaclient/chains/bitcoin/observer/event_test.go +++ b/zetaclient/chains/bitcoin/observer/event_test.go @@ -22,6 +22,7 @@ import ( "github.com/zeta-chain/node/zetaclient/keys" "github.com/zeta-chain/node/zetaclient/testutils" "github.com/zeta-chain/node/zetaclient/testutils/mocks" + clienttypes "github.com/zeta-chain/node/zetaclient/types" ) // createTestBtcEvent creates a test BTC inbound event @@ -41,7 +42,7 @@ func createTestBtcEvent( } } -func Test_CheckProcessability(t *testing.T) { +func Test_Processability(t *testing.T) { // setup compliance config cfg := config.Config{ ComplianceConfig: sample.ComplianceConfig(), @@ -52,7 +53,7 @@ func Test_CheckProcessability(t *testing.T) { tests := []struct { name string event *observer.BTCInboundEvent - expected observer.InboundProcessability + expected clienttypes.InboundProcessability }{ { name: "should return InboundProcessabilityGood for a processable inbound event", @@ -60,7 +61,7 @@ func Test_CheckProcessability(t *testing.T) { FromAddress: "tb1quhassyrlj43qar0mn0k5sufyp6mazmh2q85lr6ex8ehqfhxpzsksllwrsu", ToAddress: testutils.TSSAddressBTCAthens3, }, - expected: observer.InboundProcessabilityGood, + expected: clienttypes.InboundProcessabilityGood, }, { name: "should return InboundProcessabilityComplianceViolation for a restricted sender address", @@ -68,7 +69,7 @@ func Test_CheckProcessability(t *testing.T) { FromAddress: sample.RestrictedBtcAddressTest, ToAddress: testutils.TSSAddressBTCAthens3, }, - expected: observer.InboundProcessabilityComplianceViolation, + expected: clienttypes.InboundProcessabilityComplianceViolation, }, { name: "should return InboundProcessabilityComplianceViolation for a restricted receiver address in standard memo", @@ -81,7 +82,7 @@ func Test_CheckProcessability(t *testing.T) { }, }, }, - expected: observer.InboundProcessabilityComplianceViolation, + expected: clienttypes.InboundProcessabilityComplianceViolation, }, { name: "should return InboundProcessabilityComplianceViolation for a restricted revert address in standard memo", @@ -96,7 +97,7 @@ func Test_CheckProcessability(t *testing.T) { }, }, }, - expected: observer.InboundProcessabilityComplianceViolation, + expected: clienttypes.InboundProcessabilityComplianceViolation, }, { name: "should return InboundProcessabilityDonation for a donation inbound event", @@ -105,7 +106,7 @@ func Test_CheckProcessability(t *testing.T) { ToAddress: testutils.TSSAddressBTCAthens3, MemoBytes: []byte(constant.DonationMessage), }, - expected: observer.InboundProcessabilityDonation, + expected: clienttypes.InboundProcessabilityDonation, }, } diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index aa4f5667ad..65f7b852af 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -361,13 +361,22 @@ func (ob *Observer) GetInboundVoteFromBtcEvent(event *BTCInboundEvent) *crosscha } amountInt := big.NewInt(amountSats) - // create inbound vote message contract V1 for legacy memo + // create inbound vote message contract V1 for legacy memo or standard memo + var msg *crosschaintypes.MsgVoteInbound if event.MemoStd == nil { - return ob.NewInboundVoteFromLegacyMemo(event, amountInt) + msg = ob.NewInboundVoteFromLegacyMemo(event, amountInt) + } else { + msg = ob.NewInboundVoteFromStdMemo(event, amountInt) } - // create inbound vote message for standard memo - return ob.NewInboundVoteFromStdMemo(event, amountInt) + // make sure the message is valid before posting to zetacore + err = msg.ValidateBasic() + if err != nil { + ob.Logger().Inbound.Error().Err(err).Fields(lf).Msg("invalid inbound vote message") + return nil + } + + return msg } // GetBtcEvent returns a valid BTCInboundEvent or nil diff --git a/zetaclient/chains/bitcoin/observer/inbound_test.go b/zetaclient/chains/bitcoin/observer/inbound_test.go index 7ec938aab0..ba005a1303 100644 --- a/zetaclient/chains/bitcoin/observer/inbound_test.go +++ b/zetaclient/chains/bitcoin/observer/inbound_test.go @@ -157,7 +157,9 @@ func Test_GetInboundVoteFromBtcEvent(t *testing.T) { // create test observer ob := MockBTCObserver(t, chain, params, nil) - zetacoreClient := mocks.NewZetacoreClient(t).WithKeys(&keys.Keys{}).WithZetaChain() + zetacoreClient := mocks.NewZetacoreClient(t).WithKeys(&keys.Keys{ + OperatorAddress: sample.Bech32AccAddress(), + }).WithZetaChain() ob.WithZetacoreClient(zetacoreClient) // test cases diff --git a/zetaclient/chains/solana/observer/inbound.go b/zetaclient/chains/solana/observer/inbound.go index bd0e9a98b7..a560d6b9d0 100644 --- a/zetaclient/chains/solana/observer/inbound.go +++ b/zetaclient/chains/solana/observer/inbound.go @@ -1,7 +1,6 @@ package observer import ( - "bytes" "context" "encoding/hex" "fmt" @@ -13,12 +12,12 @@ import ( "github.com/rs/zerolog" "github.com/zeta-chain/node/pkg/coin" - "github.com/zeta-chain/node/pkg/constant" solanacontracts "github.com/zeta-chain/node/pkg/contracts/solana" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" solanarpc "github.com/zeta-chain/node/zetaclient/chains/solana/rpc" "github.com/zeta-chain/node/zetaclient/compliance" zctx "github.com/zeta-chain/node/zetaclient/context" + "github.com/zeta-chain/node/zetaclient/logs" clienttypes "github.com/zeta-chain/node/zetaclient/types" "github.com/zeta-chain/node/zetaclient/zetacore" ) @@ -256,19 +255,29 @@ func (ob *Observer) FilterInboundEvents(txResult *rpc.GetTransactionResult) ([]* // BuildInboundVoteMsgFromEvent builds a MsgVoteInbound from an inbound event func (ob *Observer) BuildInboundVoteMsgFromEvent(event *clienttypes.InboundEvent) *crosschaintypes.MsgVoteInbound { - // compliance check. Return nil if the inbound contains restricted addresses - if compliance.DoesInboundContainsRestrictedAddress(event, ob.Logger()) { + // prepare logger fields + lf := map[string]any{ + logs.FieldModule: logs.ModNameInbound, + logs.FieldMethod: "BuildInboundVoteMsgFromEvent", + logs.FieldChain: ob.Chain().ChainId, + logs.FieldTx: event.TxHash, + } + + // decode event memo bytes to get the receiver + err := event.DecodeMemo() + if err != nil { + ob.Logger().Inbound.Info().Fields(lf).Msgf("invalid memo bytes: %s", hex.EncodeToString(event.Memo)) return nil } - // donation check - if bytes.Equal(event.Memo, []byte(constant.DonationMessage)) { - ob.Logger().Inbound.Info(). - Msgf("thank you rich folk for your donation! tx %s chain %d", event.TxHash, event.SenderChainID) + // check if the event is processable + if !ob.CheckEventProcessability(*event) { return nil } - return zetacore.GetInboundVoteMessage( + // create inbound vote message + msg := crosschaintypes.NewMsgVoteInbound( + ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), event.Sender, event.SenderChainID, event.Sender, @@ -281,7 +290,39 @@ func (ob *Observer) BuildInboundVoteMsgFromEvent(event *clienttypes.InboundEvent 0, event.CoinType, event.Asset, - ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), 0, // not a smart contract call + crosschaintypes.ProtocolContractVersion_V1, + false, // not relevant for v1 ) + + // make sure the message is valid before posting to zetacore + err = msg.ValidateBasic() + if err != nil { + ob.Logger().Inbound.Error().Err(err).Fields(lf).Msg("invalid inbound vote message") + return nil + } + + return msg +} + +// CheckEventProcessability checks if the inbound event is processable +func (ob *Observer) CheckEventProcessability(event clienttypes.InboundEvent) bool { + switch result := event.Processability(); result { + case clienttypes.InboundProcessabilityGood: + return true + case clienttypes.InboundProcessabilityDonation: + logFields := map[string]any{ + logs.FieldChain: ob.Chain().ChainId, + logs.FieldTx: event.TxHash, + } + ob.Logger().Inbound.Info().Fields(logFields).Msgf("thank you rich folk for your donation!") + return false + case clienttypes.InboundProcessabilityComplianceViolation: + compliance.PrintComplianceLog(ob.Logger().Inbound, ob.Logger().Compliance, + false, ob.Chain().ChainId, event.TxHash, event.Sender, event.Receiver, event.CoinType.String()) + return false + default: + ob.Logger().Inbound.Error().Msgf("unreachable code got InboundProcessability: %v", result) + return false + } } diff --git a/zetaclient/chains/solana/observer/inbound_test.go b/zetaclient/chains/solana/observer/inbound_test.go index 28c31f04db..c8028dc5ce 100644 --- a/zetaclient/chains/solana/observer/inbound_test.go +++ b/zetaclient/chains/solana/observer/inbound_test.go @@ -2,6 +2,7 @@ package observer_test import ( "context" + "strings" "testing" "github.com/stretchr/testify/require" @@ -9,6 +10,7 @@ import ( "github.com/zeta-chain/node/pkg/coin" "github.com/zeta-chain/node/pkg/constant" "github.com/zeta-chain/node/testutil/sample" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" "github.com/zeta-chain/node/zetaclient/chains/base" "github.com/zeta-chain/node/zetaclient/chains/solana/observer" "github.com/zeta-chain/node/zetaclient/config" @@ -108,7 +110,9 @@ func Test_BuildInboundVoteMsgFromEvent(t *testing.T) { params := sample.ChainParams(chain.ChainId) params.GatewayAddress = sample.SolanaAddress(t) zetacoreClient := mocks.NewZetacoreClient(t) - zetacoreClient.WithKeys(&keys.Keys{}).WithZetaChain().WithPostVoteInbound("", "") + zetacoreClient.WithKeys(&keys.Keys{ + OperatorAddress: sample.Bech32AccAddress(), + }).WithZetaChain().WithPostVoteInbound("", "") database, err := db.NewFromSqliteInMemory(true) require.NoError(t, err) @@ -129,37 +133,85 @@ func Test_BuildInboundVoteMsgFromEvent(t *testing.T) { msg := ob.BuildInboundVoteMsgFromEvent(event) require.NotNil(t, msg) }) - t.Run("should return nil msg if sender is restricted", func(t *testing.T) { - sender := sample.SolanaAddress(t) - receiver := sample.SolanaAddress(t) - event := sample.InboundEvent(chain.ChainId, sender, receiver, 1280, nil) - // restrict sender - cfg.ComplianceConfig.RestrictedAddresses = []string{sender} - config.LoadComplianceConfig(cfg) + t.Run("should return nil if failed to decode memo", func(t *testing.T) { + sender := sample.SolanaAddress(t) + memo := []byte("a memo too short") + event := sample.InboundEvent(chain.ChainId, sender, sender, 1280, memo) msg := ob.BuildInboundVoteMsgFromEvent(event) require.Nil(t, msg) }) - t.Run("should return nil msg if receiver is restricted", func(t *testing.T) { + + t.Run("should return nil if event is not processable", func(t *testing.T) { sender := sample.SolanaAddress(t) receiver := sample.SolanaAddress(t) - memo := sample.EthAddress().Bytes() - event := sample.InboundEvent(chain.ChainId, sender, receiver, 1280, []byte(memo)) + event := sample.InboundEvent(chain.ChainId, sender, receiver, 1280, nil) - // restrict receiver - cfg.ComplianceConfig.RestrictedAddresses = []string{receiver} + // restrict sender + cfg.ComplianceConfig.RestrictedAddresses = []string{sender} config.LoadComplianceConfig(cfg) msg := ob.BuildInboundVoteMsgFromEvent(event) require.Nil(t, msg) }) - t.Run("should return nil msg on donation transaction", func(t *testing.T) { + + t.Run("should return nil if message basic validation fails", func(t *testing.T) { // create event with donation memo sender := sample.SolanaAddress(t) - event := sample.InboundEvent(chain.ChainId, sender, sender, 1280, []byte(constant.DonationMessage)) + maxMsgBytes := crosschaintypes.MaxMessageLength / 2 + event := sample.InboundEvent(chain.ChainId, sender, sender, 1280, []byte(strings.Repeat("a", maxMsgBytes+1))) msg := ob.BuildInboundVoteMsgFromEvent(event) require.Nil(t, msg) }) } + +func Test_CheckEventProcessability(t *testing.T) { + // parepare params + chain := chains.SolanaDevnet + params := sample.ChainParams(chain.ChainId) + params.GatewayAddress = sample.SolanaAddress(t) + + // create test observer + ob := MockSolanaObserver(t, chain, nil, *params, nil, nil) + + // setup compliance config + cfg := config.Config{ + ComplianceConfig: sample.ComplianceConfig(), + } + config.LoadComplianceConfig(cfg) + + // test cases + tests := []struct { + name string + event clienttypes.InboundEvent + result bool + }{ + { + name: "should return true for processable event", + event: clienttypes.InboundEvent{Sender: sample.SolanaAddress(t), Receiver: sample.SolanaAddress(t)}, + result: true, + }, + { + name: "should return false on donation message", + event: clienttypes.InboundEvent{Memo: []byte(constant.DonationMessage)}, + result: false, + }, + { + name: "should return false on compliance violation", + event: clienttypes.InboundEvent{ + Sender: sample.RestrictedSolAddressTest, + Receiver: sample.EthAddress().Hex(), + }, + result: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ob.CheckEventProcessability(tt.event) + require.Equal(t, tt.result, result) + }) + } +} diff --git a/zetaclient/compliance/compliance.go b/zetaclient/compliance/compliance.go index f0135c3ad9..2a16dee6b6 100644 --- a/zetaclient/compliance/compliance.go +++ b/zetaclient/compliance/compliance.go @@ -2,16 +2,10 @@ package compliance import ( - "encoding/hex" - - ethcommon "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" - "github.com/zeta-chain/node/pkg/memo" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" - "github.com/zeta-chain/node/zetaclient/chains/base" "github.com/zeta-chain/node/zetaclient/config" - clienttypes "github.com/zeta-chain/node/zetaclient/types" ) // IsCctxRestricted returns true if the cctx involves restricted addresses @@ -61,21 +55,3 @@ func PrintComplianceLog( inboundLoggerWithFields.Warn().Msg(logMsg) complianceLoggerWithFields.Warn().Msg(logMsg) } - -// DoesInboundContainsRestrictedAddress returns true if the inbound event contains restricted addresses -func DoesInboundContainsRestrictedAddress(event *clienttypes.InboundEvent, logger *base.ObserverLogger) bool { - // parse memo-specified receiver - receiver := "" - parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(event.Memo)) - if err == nil && parsedAddress != (ethcommon.Address{}) { - receiver = parsedAddress.Hex() - } - - // check restricted addresses - if config.ContainRestrictedAddress(event.Sender, event.Receiver, receiver) { - PrintComplianceLog(logger.Inbound, logger.Compliance, - false, event.SenderChainID, event.TxHash, event.Sender, receiver, event.CoinType.String()) - return true - } - return false -} diff --git a/zetaclient/types/event.go b/zetaclient/types/event.go index a0313236e6..90bdbbd5ea 100644 --- a/zetaclient/types/event.go +++ b/zetaclient/types/event.go @@ -1,7 +1,31 @@ package types import ( + "bytes" + "encoding/hex" + + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + "github.com/zeta-chain/node/pkg/coin" + "github.com/zeta-chain/node/pkg/constant" + "github.com/zeta-chain/node/pkg/crypto" + "github.com/zeta-chain/node/pkg/memo" + "github.com/zeta-chain/node/zetaclient/config" +) + +// InboundProcessability is an enum representing the processability of an inbound +type InboundProcessability int + +const ( + // InboundProcessabilityGood represents a processable inbound + InboundProcessabilityGood InboundProcessability = iota + + // InboundProcessabilityDonation represents a donation inbound + InboundProcessabilityDonation + + // InboundProcessabilityComplianceViolation represents a compliance violation + InboundProcessabilityComplianceViolation ) // InboundEvent represents an inbound event @@ -41,3 +65,47 @@ type InboundEvent struct { // Asset is the asset of the inbound Asset string } + +// DecodeMemo decodes the receiver from the memo bytes +func (event *InboundEvent) DecodeMemo() error { + // skip decoding donation tx as it won't go through zetacore + if bytes.Equal(event.Memo, []byte(constant.DonationMessage)) { + return nil + } + + // decode receiver address from memo + parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(event.Memo)) + if err != nil { // unreachable code + return errors.Wrap(err, "invalid memo hex") + } + + // ensure the receiver is valid + if crypto.IsEmptyAddress(parsedAddress) { + return errors.New("got empty receiver address from memo") + } + event.Receiver = parsedAddress.Hex() + + return nil +} + +// Processability returns the processability of the inbound event +func (event *InboundEvent) Processability() InboundProcessability { + // parse memo-specified receiver + receiver := "" + parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(event.Memo)) + if err == nil && parsedAddress != (ethcommon.Address{}) { + receiver = parsedAddress.Hex() + } + + // check restricted addresses + if config.ContainRestrictedAddress(event.Sender, event.Receiver, event.TxOrigin, receiver) { + return InboundProcessabilityComplianceViolation + } + + // donation check + if bytes.Equal(event.Memo, []byte(constant.DonationMessage)) { + return InboundProcessabilityDonation + } + + return InboundProcessabilityGood +} diff --git a/zetaclient/types/event_test.go b/zetaclient/types/event_test.go new file mode 100644 index 0000000000..f8e78b3424 --- /dev/null +++ b/zetaclient/types/event_test.go @@ -0,0 +1,124 @@ +package types_test + +import ( + "testing" + + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/constant" + "github.com/zeta-chain/node/testutil/sample" + "github.com/zeta-chain/node/zetaclient/config" + "github.com/zeta-chain/node/zetaclient/types" +) + +func Test_DecodeMemo(t *testing.T) { + testReceiver := sample.EthAddress() + + // test cases + tests := []struct { + name string + event *types.InboundEvent + expectedReceiver string + errMsg string + }{ + { + name: "should decode receiver address successfully", + event: &types.InboundEvent{ + Memo: testReceiver.Bytes(), + }, + expectedReceiver: testReceiver.Hex(), + }, + { + name: "should skip decoding donation message", + event: &types.InboundEvent{ + Memo: []byte(constant.DonationMessage), + }, + expectedReceiver: "", + }, + { + name: "should return error if got an empty receiver address", + event: &types.InboundEvent{ + Memo: []byte(""), + }, + errMsg: "got empty receiver address from memo", + expectedReceiver: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.event.DecodeMemo() + if tt.errMsg != "" { + require.Contains(t, err.Error(), tt.errMsg) + return + } + require.NoError(t, err) + require.Equal(t, tt.expectedReceiver, tt.event.Receiver) + }) + } +} + +func Test_Processability(t *testing.T) { + // setup compliance config + cfg := config.Config{ + ComplianceConfig: sample.ComplianceConfig(), + } + config.LoadComplianceConfig(cfg) + + // test cases + tests := []struct { + name string + event *types.InboundEvent + expected types.InboundProcessability + }{ + { + name: "should return InboundProcessabilityGood for a processable inbound event", + event: &types.InboundEvent{ + Sender: sample.SolanaAddress(t), + Receiver: sample.EthAddress().Hex(), + }, + expected: types.InboundProcessabilityGood, + }, + { + name: "should return InboundProcessabilityComplianceViolation for a restricted sender address", + event: &types.InboundEvent{ + Sender: sample.RestrictedSolAddressTest, + Receiver: sample.EthAddress().Hex(), + }, + expected: types.InboundProcessabilityComplianceViolation, + }, + { + name: "should return InboundProcessabilityComplianceViolation for a restricted receiver address", + event: &types.InboundEvent{ + Sender: sample.SolanaAddress(t), + Receiver: sample.RestrictedSolAddressTest, + }, + expected: types.InboundProcessabilityComplianceViolation, + }, + { + name: "should return InboundProcessabilityComplianceViolation for a restricted receiver address in memo", + event: &types.InboundEvent{ + Sender: sample.SolanaAddress(t), + Receiver: sample.EthAddress().Hex(), + Memo: ethcommon.HexToAddress(sample.RestrictedEVMAddressTest).Bytes(), + }, + expected: types.InboundProcessabilityComplianceViolation, + }, + { + name: "should return InboundProcessabilityDonation for a donation inbound event", + event: &types.InboundEvent{ + Sender: sample.SolanaAddress(t), + Receiver: sample.EthAddress().Hex(), + Memo: []byte(constant.DonationMessage), + }, + expected: types.InboundProcessabilityDonation, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.event.Processability() + require.Equal(t, tt.expected, result) + }) + } +} From 1e1e254f2c6215c754cb84b3b4b3a66916a6d58e Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Tue, 19 Nov 2024 00:07:01 -0600 Subject: [PATCH 02/13] add changelog entry --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index 184790d68f..38d4d92d3e 100644 --- a/changelog.md +++ b/changelog.md @@ -29,6 +29,7 @@ * [3149](https://github.com/zeta-chain/node/pull/3149) - abort the cctx if dust amount is detected in the revert outbound * [3155](https://github.com/zeta-chain/node/pull/3155) - fix potential panic in the Bitcoin inscription parsing * [3162](https://github.com/zeta-chain/node/pull/3162) - skip depositor fee calculation if transaction does not involve TSS address +* [3184](https://github.com/zeta-chain/node/pull/3184) - zetaclient should not retry if inbound vote message validation fails ## v21.0.0 From 5e4e6d7ef2ef2112c8d7bae7ddf1976eccd684aa Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Wed, 20 Nov 2024 15:58:55 -0600 Subject: [PATCH 03/13] rename CheckEventProcessability as IsEventProcessable --- zetaclient/chains/bitcoin/observer/event.go | 4 ++-- zetaclient/chains/bitcoin/observer/event_test.go | 4 ++-- zetaclient/chains/bitcoin/observer/inbound.go | 2 +- zetaclient/chains/bitcoin/signer/signer.go | 2 +- zetaclient/chains/evm/observer/v2_inbound.go | 10 +++++----- zetaclient/chains/solana/observer/inbound.go | 6 +++--- zetaclient/chains/solana/observer/inbound_test.go | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/zetaclient/chains/bitcoin/observer/event.go b/zetaclient/chains/bitcoin/observer/event.go index ffc79916d7..a30d2ac507 100644 --- a/zetaclient/chains/bitcoin/observer/event.go +++ b/zetaclient/chains/bitcoin/observer/event.go @@ -151,8 +151,8 @@ func ValidateStandardMemo(memoStd memo.InboundMemo, chainID int64) error { return nil } -// CheckEventProcessability checks if the inbound event is processable -func (ob *Observer) CheckEventProcessability(event BTCInboundEvent) bool { +// IsEventProcessable checks if the inbound event is processable +func (ob *Observer) IsEventProcessable(event BTCInboundEvent) bool { // check if the event is processable switch result := event.Processability(); result { case clienttypes.InboundProcessabilityGood: diff --git a/zetaclient/chains/bitcoin/observer/event_test.go b/zetaclient/chains/bitcoin/observer/event_test.go index fd870731f8..77c1cd84be 100644 --- a/zetaclient/chains/bitcoin/observer/event_test.go +++ b/zetaclient/chains/bitcoin/observer/event_test.go @@ -302,7 +302,7 @@ func Test_ValidateStandardMemo(t *testing.T) { } } -func Test_CheckEventProcessability(t *testing.T) { +func Test_IsEventProcessable(t *testing.T) { // can use any bitcoin chain for testing chain := chains.BitcoinMainnet params := mocks.MockChainParams(chain.ChainId, 10) @@ -345,7 +345,7 @@ func Test_CheckEventProcessability(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := ob.CheckEventProcessability(tt.event) + result := ob.IsEventProcessable(tt.event) require.Equal(t, tt.result, result) }) } diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index 65f7b852af..12d7d15f46 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -349,7 +349,7 @@ func (ob *Observer) GetInboundVoteFromBtcEvent(event *BTCInboundEvent) *crosscha } // check if the event is processable - if !ob.CheckEventProcessability(*event) { + if !ob.IsEventProcessable(*event) { return nil } diff --git a/zetaclient/chains/bitcoin/signer/signer.go b/zetaclient/chains/bitcoin/signer/signer.go index c239627f22..cb960183b6 100644 --- a/zetaclient/chains/bitcoin/signer/signer.go +++ b/zetaclient/chains/bitcoin/signer/signer.go @@ -450,7 +450,7 @@ func (signer *Signer) TryProcessOutbound( if err != nil { logger.Warn(). Err(err). - Msgf("SignConnectorOnReceive error: nonce %d chain %d", outboundTssNonce, params.ReceiverChainId) + Msgf("SignWithdrawTx error: nonce %d chain %d", outboundTssNonce, params.ReceiverChainId) return } logger.Info(). diff --git a/zetaclient/chains/evm/observer/v2_inbound.go b/zetaclient/chains/evm/observer/v2_inbound.go index 9688851af6..45eadaa4fe 100644 --- a/zetaclient/chains/evm/observer/v2_inbound.go +++ b/zetaclient/chains/evm/observer/v2_inbound.go @@ -23,8 +23,8 @@ import ( "github.com/zeta-chain/node/zetaclient/zetacore" ) -// checkEventProcessability checks if the event is processable -func (ob *Observer) checkEventProcessability( +// IsEventProcessable checks if the event is processable +func (ob *Observer) IsEventProcessable( sender, receiver ethcommon.Address, txHash ethcommon.Hash, payload []byte, @@ -99,7 +99,7 @@ func (ob *Observer) ObserveGatewayDeposit(ctx context.Context, startBlock, toBlo } // check if the event is processable - if !ob.checkEventProcessability(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { + if !ob.IsEventProcessable(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { continue } @@ -247,7 +247,7 @@ func (ob *Observer) ObserveGatewayCall(ctx context.Context, startBlock, toBlock } // check if the event is processable - if !ob.checkEventProcessability(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { + if !ob.IsEventProcessable(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { continue } @@ -378,7 +378,7 @@ func (ob *Observer) ObserveGatewayDepositAndCall(ctx context.Context, startBlock } // check if the event is processable - if !ob.checkEventProcessability(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { + if !ob.IsEventProcessable(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { continue } diff --git a/zetaclient/chains/solana/observer/inbound.go b/zetaclient/chains/solana/observer/inbound.go index a560d6b9d0..66e6a88055 100644 --- a/zetaclient/chains/solana/observer/inbound.go +++ b/zetaclient/chains/solana/observer/inbound.go @@ -271,7 +271,7 @@ func (ob *Observer) BuildInboundVoteMsgFromEvent(event *clienttypes.InboundEvent } // check if the event is processable - if !ob.CheckEventProcessability(*event) { + if !ob.IsEventProcessable(*event) { return nil } @@ -305,8 +305,8 @@ func (ob *Observer) BuildInboundVoteMsgFromEvent(event *clienttypes.InboundEvent return msg } -// CheckEventProcessability checks if the inbound event is processable -func (ob *Observer) CheckEventProcessability(event clienttypes.InboundEvent) bool { +// IsEventProcessable checks if the inbound event is processable +func (ob *Observer) IsEventProcessable(event clienttypes.InboundEvent) bool { switch result := event.Processability(); result { case clienttypes.InboundProcessabilityGood: return true diff --git a/zetaclient/chains/solana/observer/inbound_test.go b/zetaclient/chains/solana/observer/inbound_test.go index c8028dc5ce..02c4a95efd 100644 --- a/zetaclient/chains/solana/observer/inbound_test.go +++ b/zetaclient/chains/solana/observer/inbound_test.go @@ -167,7 +167,7 @@ func Test_BuildInboundVoteMsgFromEvent(t *testing.T) { }) } -func Test_CheckEventProcessability(t *testing.T) { +func Test_IsEventProcessable(t *testing.T) { // parepare params chain := chains.SolanaDevnet params := sample.ChainParams(chain.ChainId) @@ -210,7 +210,7 @@ func Test_CheckEventProcessability(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := ob.CheckEventProcessability(tt.event) + result := ob.IsEventProcessable(tt.event) require.Equal(t, tt.result, result) }) } From 426547ba897ab6180ec6add08d7370497b7e6972 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Wed, 20 Nov 2024 16:56:35 -0600 Subject: [PATCH 04/13] rename InboundProcessability as InboundCategory --- zetaclient/chains/bitcoin/observer/event.go | 23 ++++++++-------- .../chains/bitcoin/observer/event_test.go | 26 +++++++++---------- zetaclient/chains/solana/observer/inbound.go | 10 +++---- zetaclient/types/event.go | 26 +++++++++---------- zetaclient/types/event_test.go | 26 +++++++++---------- 5 files changed, 55 insertions(+), 56 deletions(-) diff --git a/zetaclient/chains/bitcoin/observer/event.go b/zetaclient/chains/bitcoin/observer/event.go index a30d2ac507..9ec2defdde 100644 --- a/zetaclient/chains/bitcoin/observer/event.go +++ b/zetaclient/chains/bitcoin/observer/event.go @@ -49,11 +49,11 @@ type BTCInboundEvent struct { TxHash string } -// Processability returns the processability of the inbound event -func (event *BTCInboundEvent) Processability() clienttypes.InboundProcessability { +// Category returns the category of the inbound event +func (event *BTCInboundEvent) Category() clienttypes.InboundCategory { // compliance check on sender and receiver addresses if config.ContainRestrictedAddress(event.FromAddress, event.ToAddress) { - return clienttypes.InboundProcessabilityComplianceViolation + return clienttypes.InboundCategoryRestricted } // compliance check on receiver, revert/abort addresses in standard memo @@ -63,16 +63,16 @@ func (event *BTCInboundEvent) Processability() clienttypes.InboundProcessability event.MemoStd.RevertOptions.RevertAddress, event.MemoStd.RevertOptions.AbortAddress, ) { - return clienttypes.InboundProcessabilityComplianceViolation + return clienttypes.InboundCategoryRestricted } } // donation check if bytes.Equal(event.MemoBytes, []byte(constant.DonationMessage)) { - return clienttypes.InboundProcessabilityDonation + return clienttypes.InboundCategoryDonation } - return clienttypes.InboundProcessabilityGood + return clienttypes.InboundCategoryGood } // DecodeMemoBytes decodes the contained memo bytes as either standard or legacy memo @@ -153,23 +153,22 @@ func ValidateStandardMemo(memoStd memo.InboundMemo, chainID int64) error { // IsEventProcessable checks if the inbound event is processable func (ob *Observer) IsEventProcessable(event BTCInboundEvent) bool { - // check if the event is processable - switch result := event.Processability(); result { - case clienttypes.InboundProcessabilityGood: + switch category := event.Category(); category { + case clienttypes.InboundCategoryGood: return true - case clienttypes.InboundProcessabilityDonation: + case clienttypes.InboundCategoryDonation: logFields := map[string]any{ logs.FieldChain: ob.Chain().ChainId, logs.FieldTx: event.TxHash, } ob.Logger().Inbound.Info().Fields(logFields).Msgf("thank you rich folk for your donation!") return false - case clienttypes.InboundProcessabilityComplianceViolation: + case clienttypes.InboundCategoryRestricted: compliance.PrintComplianceLog(ob.logger.Inbound, ob.logger.Compliance, false, ob.Chain().ChainId, event.TxHash, event.FromAddress, event.ToAddress, "BTC") return false default: - ob.Logger().Inbound.Error().Msgf("unreachable code got InboundProcessability: %v", result) + ob.Logger().Inbound.Error().Msgf("unreachable code got InboundProcessability: %v", category) return false } } diff --git a/zetaclient/chains/bitcoin/observer/event_test.go b/zetaclient/chains/bitcoin/observer/event_test.go index 77c1cd84be..ef9794f19d 100644 --- a/zetaclient/chains/bitcoin/observer/event_test.go +++ b/zetaclient/chains/bitcoin/observer/event_test.go @@ -42,7 +42,7 @@ func createTestBtcEvent( } } -func Test_Processability(t *testing.T) { +func Test_Category(t *testing.T) { // setup compliance config cfg := config.Config{ ComplianceConfig: sample.ComplianceConfig(), @@ -53,26 +53,26 @@ func Test_Processability(t *testing.T) { tests := []struct { name string event *observer.BTCInboundEvent - expected clienttypes.InboundProcessability + expected clienttypes.InboundCategory }{ { - name: "should return InboundProcessabilityGood for a processable inbound event", + name: "should return InboundCategoryGood for a processable inbound event", event: &observer.BTCInboundEvent{ FromAddress: "tb1quhassyrlj43qar0mn0k5sufyp6mazmh2q85lr6ex8ehqfhxpzsksllwrsu", ToAddress: testutils.TSSAddressBTCAthens3, }, - expected: clienttypes.InboundProcessabilityGood, + expected: clienttypes.InboundCategoryGood, }, { - name: "should return InboundProcessabilityComplianceViolation for a restricted sender address", + name: "should return InboundCategoryRestricted for a restricted sender address", event: &observer.BTCInboundEvent{ FromAddress: sample.RestrictedBtcAddressTest, ToAddress: testutils.TSSAddressBTCAthens3, }, - expected: clienttypes.InboundProcessabilityComplianceViolation, + expected: clienttypes.InboundCategoryRestricted, }, { - name: "should return InboundProcessabilityComplianceViolation for a restricted receiver address in standard memo", + name: "should return InboundCategoryRestricted for a restricted receiver address in standard memo", event: &observer.BTCInboundEvent{ FromAddress: "tb1quhassyrlj43qar0mn0k5sufyp6mazmh2q85lr6ex8ehqfhxpzsksllwrsu", ToAddress: testutils.TSSAddressBTCAthens3, @@ -82,10 +82,10 @@ func Test_Processability(t *testing.T) { }, }, }, - expected: clienttypes.InboundProcessabilityComplianceViolation, + expected: clienttypes.InboundCategoryRestricted, }, { - name: "should return InboundProcessabilityComplianceViolation for a restricted revert address in standard memo", + name: "should return InboundCategoryRestricted for a restricted revert address in standard memo", event: &observer.BTCInboundEvent{ FromAddress: "tb1quhassyrlj43qar0mn0k5sufyp6mazmh2q85lr6ex8ehqfhxpzsksllwrsu", ToAddress: testutils.TSSAddressBTCAthens3, @@ -97,22 +97,22 @@ func Test_Processability(t *testing.T) { }, }, }, - expected: clienttypes.InboundProcessabilityComplianceViolation, + expected: clienttypes.InboundCategoryRestricted, }, { - name: "should return InboundProcessabilityDonation for a donation inbound event", + name: "should return InboundCategoryDonation for a donation inbound event", event: &observer.BTCInboundEvent{ FromAddress: "tb1quhassyrlj43qar0mn0k5sufyp6mazmh2q85lr6ex8ehqfhxpzsksllwrsu", ToAddress: testutils.TSSAddressBTCAthens3, MemoBytes: []byte(constant.DonationMessage), }, - expected: clienttypes.InboundProcessabilityDonation, + expected: clienttypes.InboundCategoryDonation, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := tt.event.Processability() + result := tt.event.Category() require.Equal(t, tt.expected, result) }) } diff --git a/zetaclient/chains/solana/observer/inbound.go b/zetaclient/chains/solana/observer/inbound.go index 66e6a88055..432274bb62 100644 --- a/zetaclient/chains/solana/observer/inbound.go +++ b/zetaclient/chains/solana/observer/inbound.go @@ -307,22 +307,22 @@ func (ob *Observer) BuildInboundVoteMsgFromEvent(event *clienttypes.InboundEvent // IsEventProcessable checks if the inbound event is processable func (ob *Observer) IsEventProcessable(event clienttypes.InboundEvent) bool { - switch result := event.Processability(); result { - case clienttypes.InboundProcessabilityGood: + switch category := event.Category(); category { + case clienttypes.InboundCategoryGood: return true - case clienttypes.InboundProcessabilityDonation: + case clienttypes.InboundCategoryDonation: logFields := map[string]any{ logs.FieldChain: ob.Chain().ChainId, logs.FieldTx: event.TxHash, } ob.Logger().Inbound.Info().Fields(logFields).Msgf("thank you rich folk for your donation!") return false - case clienttypes.InboundProcessabilityComplianceViolation: + case clienttypes.InboundCategoryRestricted: compliance.PrintComplianceLog(ob.Logger().Inbound, ob.Logger().Compliance, false, ob.Chain().ChainId, event.TxHash, event.Sender, event.Receiver, event.CoinType.String()) return false default: - ob.Logger().Inbound.Error().Msgf("unreachable code got InboundProcessability: %v", result) + ob.Logger().Inbound.Error().Msgf("unreachable code got InboundProcessability: %v", category) return false } } diff --git a/zetaclient/types/event.go b/zetaclient/types/event.go index 90bdbbd5ea..65b045af7b 100644 --- a/zetaclient/types/event.go +++ b/zetaclient/types/event.go @@ -14,18 +14,18 @@ import ( "github.com/zeta-chain/node/zetaclient/config" ) -// InboundProcessability is an enum representing the processability of an inbound -type InboundProcessability int +// InboundCategory is an enum representing the category of an inbound event +type InboundCategory int const ( - // InboundProcessabilityGood represents a processable inbound - InboundProcessabilityGood InboundProcessability = iota + // InboundCategoryGood represents a processable inbound + InboundCategoryGood InboundCategory = iota - // InboundProcessabilityDonation represents a donation inbound - InboundProcessabilityDonation + // InboundCategoryDonation represents a donation inbound + InboundCategoryDonation - // InboundProcessabilityComplianceViolation represents a compliance violation - InboundProcessabilityComplianceViolation + // InboundCategoryRestricted represents a restricted inbound + InboundCategoryRestricted ) // InboundEvent represents an inbound event @@ -88,8 +88,8 @@ func (event *InboundEvent) DecodeMemo() error { return nil } -// Processability returns the processability of the inbound event -func (event *InboundEvent) Processability() InboundProcessability { +// Category returns the category of the inbound event +func (event *InboundEvent) Category() InboundCategory { // parse memo-specified receiver receiver := "" parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(event.Memo)) @@ -99,13 +99,13 @@ func (event *InboundEvent) Processability() InboundProcessability { // check restricted addresses if config.ContainRestrictedAddress(event.Sender, event.Receiver, event.TxOrigin, receiver) { - return InboundProcessabilityComplianceViolation + return InboundCategoryRestricted } // donation check if bytes.Equal(event.Memo, []byte(constant.DonationMessage)) { - return InboundProcessabilityDonation + return InboundCategoryDonation } - return InboundProcessabilityGood + return InboundCategoryGood } diff --git a/zetaclient/types/event_test.go b/zetaclient/types/event_test.go index f8e78b3424..3b6b1a50e3 100644 --- a/zetaclient/types/event_test.go +++ b/zetaclient/types/event_test.go @@ -58,7 +58,7 @@ func Test_DecodeMemo(t *testing.T) { } } -func Test_Processability(t *testing.T) { +func Test_Catetory(t *testing.T) { // setup compliance config cfg := config.Config{ ComplianceConfig: sample.ComplianceConfig(), @@ -69,55 +69,55 @@ func Test_Processability(t *testing.T) { tests := []struct { name string event *types.InboundEvent - expected types.InboundProcessability + expected types.InboundCategory }{ { - name: "should return InboundProcessabilityGood for a processable inbound event", + name: "should return InboundCategoryGood for a processable inbound event", event: &types.InboundEvent{ Sender: sample.SolanaAddress(t), Receiver: sample.EthAddress().Hex(), }, - expected: types.InboundProcessabilityGood, + expected: types.InboundCategoryGood, }, { - name: "should return InboundProcessabilityComplianceViolation for a restricted sender address", + name: "should return InboundCategoryRestricted for a restricted sender address", event: &types.InboundEvent{ Sender: sample.RestrictedSolAddressTest, Receiver: sample.EthAddress().Hex(), }, - expected: types.InboundProcessabilityComplianceViolation, + expected: types.InboundCategoryRestricted, }, { - name: "should return InboundProcessabilityComplianceViolation for a restricted receiver address", + name: "should return InboundCategoryRestricted for a restricted receiver address", event: &types.InboundEvent{ Sender: sample.SolanaAddress(t), Receiver: sample.RestrictedSolAddressTest, }, - expected: types.InboundProcessabilityComplianceViolation, + expected: types.InboundCategoryRestricted, }, { - name: "should return InboundProcessabilityComplianceViolation for a restricted receiver address in memo", + name: "should return InboundCategoryRestricted for a restricted receiver address in memo", event: &types.InboundEvent{ Sender: sample.SolanaAddress(t), Receiver: sample.EthAddress().Hex(), Memo: ethcommon.HexToAddress(sample.RestrictedEVMAddressTest).Bytes(), }, - expected: types.InboundProcessabilityComplianceViolation, + expected: types.InboundCategoryRestricted, }, { - name: "should return InboundProcessabilityDonation for a donation inbound event", + name: "should return InboundCategoryDonation for a donation inbound event", event: &types.InboundEvent{ Sender: sample.SolanaAddress(t), Receiver: sample.EthAddress().Hex(), Memo: []byte(constant.DonationMessage), }, - expected: types.InboundProcessabilityDonation, + expected: types.InboundCategoryDonation, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := tt.event.Processability() + result := tt.event.Category() require.Equal(t, tt.expected, result) }) } From a3a09c88a962f76c9e0d15f462ca64e1c134cb12 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Wed, 20 Nov 2024 17:01:38 -0600 Subject: [PATCH 05/13] remove btc inbound duplidate log fields --- zetaclient/chains/solana/observer/inbound.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/zetaclient/chains/solana/observer/inbound.go b/zetaclient/chains/solana/observer/inbound.go index 432274bb62..ea43788fd8 100644 --- a/zetaclient/chains/solana/observer/inbound.go +++ b/zetaclient/chains/solana/observer/inbound.go @@ -257,9 +257,7 @@ func (ob *Observer) FilterInboundEvents(txResult *rpc.GetTransactionResult) ([]* func (ob *Observer) BuildInboundVoteMsgFromEvent(event *clienttypes.InboundEvent) *crosschaintypes.MsgVoteInbound { // prepare logger fields lf := map[string]any{ - logs.FieldModule: logs.ModNameInbound, logs.FieldMethod: "BuildInboundVoteMsgFromEvent", - logs.FieldChain: ob.Chain().ChainId, logs.FieldTx: event.TxHash, } From b00341083ef4a443d844bac59a0b4c178797d25f Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Wed, 20 Nov 2024 17:16:31 -0600 Subject: [PATCH 06/13] remove duplicate log fields; add some function comments to improve readibality --- zetaclient/chains/bitcoin/observer/inbound.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index 12d7d15f46..dece5433a4 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -332,12 +332,15 @@ func FilterAndParseIncomingTx( } // GetInboundVoteFromBtcEvent converts a BTCInboundEvent to a MsgVoteInbound to enable voting on the inbound on zetacore +// +// Returns: +// - a valid MsgVoteInbound message, or +// - nil if no valid message can be created for whatever reasons: +// invalid data, not processable, invalid amount, etc. func (ob *Observer) GetInboundVoteFromBtcEvent(event *BTCInboundEvent) *crosschaintypes.MsgVoteInbound { // prepare logger fields lf := map[string]any{ - logs.FieldModule: logs.ModNameInbound, logs.FieldMethod: "GetInboundVoteFromBtcEvent", - logs.FieldChain: ob.Chain().ChainId, logs.FieldTx: event.TxHash, } From c8b50eb54d46e1d500f43bb1b4a94823073a4aa7 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Thu, 21 Nov 2024 23:31:35 -0600 Subject: [PATCH 07/13] move ValidateBasic checking right before posting the vote msg --- testutil/sample/crosschain.go | 2 +- zetaclient/chains/base/observer.go | 25 +++++++++----- zetaclient/chains/base/observer_test.go | 20 +++++++++++ zetaclient/chains/bitcoin/observer/event.go | 8 ++--- zetaclient/chains/bitcoin/observer/inbound.go | 33 +++---------------- .../chains/bitcoin/observer/inbound_test.go | 4 +-- zetaclient/chains/solana/observer/inbound.go | 19 +++-------- .../chains/solana/observer/inbound_test.go | 16 +-------- zetaclient/logs/fields.go | 3 ++ 9 files changed, 54 insertions(+), 76 deletions(-) diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 25733e1fef..759b620b2c 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -276,7 +276,7 @@ func ZetaAccounting(t *testing.T, index string) types.ZetaAccounting { func InboundVote(coinType coin.CoinType, from, to int64) types.MsgVoteInbound { return types.MsgVoteInbound{ - Creator: "", + Creator: Bech32AccAddress().String(), Sender: EthAddress().String(), SenderChainId: Chain(from).ChainId, Receiver: EthAddress().String(), diff --git a/zetaclient/chains/base/observer.go b/zetaclient/chains/base/observer.go index 9056e3aa1d..7bfd0c50de 100644 --- a/zetaclient/chains/base/observer.go +++ b/zetaclient/chains/base/observer.go @@ -466,7 +466,7 @@ func (ob *Observer) ReadLastTxScannedFromDB() (string, error) { return lastTx.Hash, nil } -// PostVoteInbound posts a vote for the given vote message +// PostVoteInbound posts a vote for the given vote message and returns the ballot. func (ob *Observer) PostVoteInbound( ctx context.Context, msg *crosschaintypes.MsgVoteInbound, @@ -477,19 +477,26 @@ func (ob *Observer) PostVoteInbound( var ( txHash = msg.InboundHash coinType = msg.CoinType - chainID = ob.Chain().ChainId ) - zetaHash, ballot, err := ob.ZetacoreClient().PostVoteInbound(ctx, gasLimit, retryGasLimit, msg) - + // prepare logger fields lf := map[string]any{ - "inbound.chain_id": chainID, - "inbound.coin_type": coinType.String(), - "inbound.external_tx_hash": txHash, - "inbound.ballot_index": ballot, - "inbound.zeta_tx_hash": zetaHash, + logs.FieldMethod: "PostVoteInbound", + logs.FieldTx: txHash, + logs.FieldCoinType: coinType.String(), + } + + // make sure the message is valid to avoid unnecessary retries + if err := msg.ValidateBasic(); err != nil { + ob.logger.Inbound.Warn().Err(err).Fields(lf).Msg("invalid inbound vote message") + return "", nil } + // post vote to zetacore + zetaHash, ballot, err := ob.ZetacoreClient().PostVoteInbound(ctx, gasLimit, retryGasLimit, msg) + lf[logs.FieldZetaTx] = zetaHash + lf[logs.FieldBallot] = ballot + switch { case err != nil: ob.logger.Inbound.Error().Err(err).Fields(lf).Msg("inbound detected: error posting vote") diff --git a/zetaclient/chains/base/observer_test.go b/zetaclient/chains/base/observer_test.go index 0c53bea35c..44dc296a8a 100644 --- a/zetaclient/chains/base/observer_test.go +++ b/zetaclient/chains/base/observer_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os" + "strings" "testing" "time" @@ -16,6 +17,7 @@ import ( "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" "github.com/zeta-chain/node/testutil/sample" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" observertypes "github.com/zeta-chain/node/x/observer/types" "github.com/zeta-chain/node/zetaclient/chains/base" "github.com/zeta-chain/node/zetaclient/chains/interfaces" @@ -626,6 +628,24 @@ func TestPostVoteInbound(t *testing.T) { require.NoError(t, err) require.Equal(t, "sampleBallotIndex", ballot) }) + + t.Run("should not post vote if message basic validation fails", func(t *testing.T) { + // create observer + ob := createObserver(t, chains.Ethereum, defaultAlertLatency) + + // create mock zetacore client + zetacoreClient := mocks.NewZetacoreClient(t) + ob = ob.WithZetacoreClient(zetacoreClient) + + // create sample message with long Message + msg := sample.InboundVote(coin.CoinType_Gas, chains.Ethereum.ChainId, chains.ZetaChainMainnet.ChainId) + msg.Message = strings.Repeat("1", crosschaintypes.MaxMessageLength+1) + + // post vote inbound + ballot, err := ob.PostVoteInbound(context.TODO(), &msg, 100000) + require.NoError(t, err) + require.Empty(t, ballot) + }) } func TestAlertOnRPCLatency(t *testing.T) { diff --git a/zetaclient/chains/bitcoin/observer/event.go b/zetaclient/chains/bitcoin/observer/event.go index 9ec2defdde..bff127dc25 100644 --- a/zetaclient/chains/bitcoin/observer/event.go +++ b/zetaclient/chains/bitcoin/observer/event.go @@ -153,14 +153,12 @@ func ValidateStandardMemo(memoStd memo.InboundMemo, chainID int64) error { // IsEventProcessable checks if the inbound event is processable func (ob *Observer) IsEventProcessable(event BTCInboundEvent) bool { + logFields := map[string]any{logs.FieldTx: event.TxHash} + switch category := event.Category(); category { case clienttypes.InboundCategoryGood: return true case clienttypes.InboundCategoryDonation: - logFields := map[string]any{ - logs.FieldChain: ob.Chain().ChainId, - logs.FieldTx: event.TxHash, - } ob.Logger().Inbound.Info().Fields(logFields).Msgf("thank you rich folk for your donation!") return false case clienttypes.InboundCategoryRestricted: @@ -168,7 +166,7 @@ func (ob *Observer) IsEventProcessable(event BTCInboundEvent) bool { false, ob.Chain().ChainId, event.TxHash, event.FromAddress, event.ToAddress, "BTC") return false default: - ob.Logger().Inbound.Error().Msgf("unreachable code got InboundProcessability: %v", category) + ob.Logger().Inbound.Error().Fields(logFields).Msgf("unreachable code got InboundCategory: %v", category) return false } } diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index dece5433a4..27f0839856 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -282,21 +282,7 @@ func (ob *Observer) CheckReceiptForBtcTxHash(ctx context.Context, txHash string, return msg.Digest(), nil } - zetaHash, ballot, err := ob.ZetacoreClient().PostVoteInbound( - ctx, - zetacore.PostVoteInboundGasLimit, - zetacore.PostVoteInboundExecutionGasLimit, - msg, - ) - if err != nil { - ob.logger.Inbound.Error().Err(err).Msg("error posting to zetacore") - return "", err - } else if zetaHash != "" { - ob.logger.Inbound.Info().Msgf("BTC deposit detected and reported: PostVoteInbound zeta tx hash: %s inbound %s ballot %s fee %v", - zetaHash, txHash, ballot, event.DepositorFee) - } - - return msg.Digest(), nil + return ob.PostVoteInbound(ctx, msg, zetacore.PostVoteInboundExecutionGasLimit) } // FilterAndParseIncomingTx given txs list returned by the "getblock 2" RPC command, return the txs that are relevant to us @@ -364,22 +350,13 @@ func (ob *Observer) GetInboundVoteFromBtcEvent(event *BTCInboundEvent) *crosscha } amountInt := big.NewInt(amountSats) - // create inbound vote message contract V1 for legacy memo or standard memo - var msg *crosschaintypes.MsgVoteInbound + // create inbound vote message contract V1 for legacy memo if event.MemoStd == nil { - msg = ob.NewInboundVoteFromLegacyMemo(event, amountInt) - } else { - msg = ob.NewInboundVoteFromStdMemo(event, amountInt) - } - - // make sure the message is valid before posting to zetacore - err = msg.ValidateBasic() - if err != nil { - ob.Logger().Inbound.Error().Err(err).Fields(lf).Msg("invalid inbound vote message") - return nil + return ob.NewInboundVoteFromLegacyMemo(event, amountInt) } - return msg + // create inbound vote message for standard memo + return ob.NewInboundVoteFromStdMemo(event, amountInt) } // GetBtcEvent returns a valid BTCInboundEvent or nil diff --git a/zetaclient/chains/bitcoin/observer/inbound_test.go b/zetaclient/chains/bitcoin/observer/inbound_test.go index ba005a1303..7ec938aab0 100644 --- a/zetaclient/chains/bitcoin/observer/inbound_test.go +++ b/zetaclient/chains/bitcoin/observer/inbound_test.go @@ -157,9 +157,7 @@ func Test_GetInboundVoteFromBtcEvent(t *testing.T) { // create test observer ob := MockBTCObserver(t, chain, params, nil) - zetacoreClient := mocks.NewZetacoreClient(t).WithKeys(&keys.Keys{ - OperatorAddress: sample.Bech32AccAddress(), - }).WithZetaChain() + zetacoreClient := mocks.NewZetacoreClient(t).WithKeys(&keys.Keys{}).WithZetaChain() ob.WithZetacoreClient(zetacoreClient) // test cases diff --git a/zetaclient/chains/solana/observer/inbound.go b/zetaclient/chains/solana/observer/inbound.go index ea43788fd8..8c1a270e80 100644 --- a/zetaclient/chains/solana/observer/inbound.go +++ b/zetaclient/chains/solana/observer/inbound.go @@ -274,7 +274,7 @@ func (ob *Observer) BuildInboundVoteMsgFromEvent(event *clienttypes.InboundEvent } // create inbound vote message - msg := crosschaintypes.NewMsgVoteInbound( + return crosschaintypes.NewMsgVoteInbound( ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), event.Sender, event.SenderChainID, @@ -292,27 +292,16 @@ func (ob *Observer) BuildInboundVoteMsgFromEvent(event *clienttypes.InboundEvent crosschaintypes.ProtocolContractVersion_V1, false, // not relevant for v1 ) - - // make sure the message is valid before posting to zetacore - err = msg.ValidateBasic() - if err != nil { - ob.Logger().Inbound.Error().Err(err).Fields(lf).Msg("invalid inbound vote message") - return nil - } - - return msg } // IsEventProcessable checks if the inbound event is processable func (ob *Observer) IsEventProcessable(event clienttypes.InboundEvent) bool { + logFields := map[string]any{logs.FieldTx: event.TxHash} + switch category := event.Category(); category { case clienttypes.InboundCategoryGood: return true case clienttypes.InboundCategoryDonation: - logFields := map[string]any{ - logs.FieldChain: ob.Chain().ChainId, - logs.FieldTx: event.TxHash, - } ob.Logger().Inbound.Info().Fields(logFields).Msgf("thank you rich folk for your donation!") return false case clienttypes.InboundCategoryRestricted: @@ -320,7 +309,7 @@ func (ob *Observer) IsEventProcessable(event clienttypes.InboundEvent) bool { false, ob.Chain().ChainId, event.TxHash, event.Sender, event.Receiver, event.CoinType.String()) return false default: - ob.Logger().Inbound.Error().Msgf("unreachable code got InboundProcessability: %v", category) + ob.Logger().Inbound.Error().Msgf("unreachable code got InboundCategory: %v", category) return false } } diff --git a/zetaclient/chains/solana/observer/inbound_test.go b/zetaclient/chains/solana/observer/inbound_test.go index 02c4a95efd..0b118ae55e 100644 --- a/zetaclient/chains/solana/observer/inbound_test.go +++ b/zetaclient/chains/solana/observer/inbound_test.go @@ -2,7 +2,6 @@ package observer_test import ( "context" - "strings" "testing" "github.com/stretchr/testify/require" @@ -10,7 +9,6 @@ import ( "github.com/zeta-chain/node/pkg/coin" "github.com/zeta-chain/node/pkg/constant" "github.com/zeta-chain/node/testutil/sample" - crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" "github.com/zeta-chain/node/zetaclient/chains/base" "github.com/zeta-chain/node/zetaclient/chains/solana/observer" "github.com/zeta-chain/node/zetaclient/config" @@ -110,9 +108,7 @@ func Test_BuildInboundVoteMsgFromEvent(t *testing.T) { params := sample.ChainParams(chain.ChainId) params.GatewayAddress = sample.SolanaAddress(t) zetacoreClient := mocks.NewZetacoreClient(t) - zetacoreClient.WithKeys(&keys.Keys{ - OperatorAddress: sample.Bech32AccAddress(), - }).WithZetaChain().WithPostVoteInbound("", "") + zetacoreClient.WithKeys(&keys.Keys{}).WithZetaChain().WithPostVoteInbound("", "") database, err := db.NewFromSqliteInMemory(true) require.NoError(t, err) @@ -155,16 +151,6 @@ func Test_BuildInboundVoteMsgFromEvent(t *testing.T) { msg := ob.BuildInboundVoteMsgFromEvent(event) require.Nil(t, msg) }) - - t.Run("should return nil if message basic validation fails", func(t *testing.T) { - // create event with donation memo - sender := sample.SolanaAddress(t) - maxMsgBytes := crosschaintypes.MaxMessageLength / 2 - event := sample.InboundEvent(chain.ChainId, sender, sender, 1280, []byte(strings.Repeat("a", maxMsgBytes+1))) - - msg := ob.BuildInboundVoteMsgFromEvent(event) - require.Nil(t, msg) - }) } func Test_IsEventProcessable(t *testing.T) { diff --git a/zetaclient/logs/fields.go b/zetaclient/logs/fields.go index 78b95fc7e0..58880543af 100644 --- a/zetaclient/logs/fields.go +++ b/zetaclient/logs/fields.go @@ -10,6 +10,9 @@ const ( FieldNonce = "nonce" FieldTx = "tx" FieldCctx = "cctx" + FieldZetaTx = "zeta_tx" + FieldBallot = "ballot" + FieldCoinType = "coin_type" // module names ModNameInbound = "inbound" From 2cbe254487cb276d3146b6270f53442fbda56ec7 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Fri, 22 Nov 2024 10:23:23 -0600 Subject: [PATCH 08/13] cleanup changelog --- changelog.md | 1 - 1 file changed, 1 deletion(-) diff --git a/changelog.md b/changelog.md index 8e9e9c0f12..7fd83857a5 100644 --- a/changelog.md +++ b/changelog.md @@ -90,7 +90,6 @@ ## Refactor * [3073](https://github.com/zeta-chain/node/pull/3073) - improve ZETA deposit check with max supply check ->>>>>>> cad1b36d6fdd96b8ecfd48f0be32246338db513e ## v21.0.0 From a7688f66dbe5942998bae2bd227855799b16f18b Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Fri, 22 Nov 2024 11:26:46 -0600 Subject: [PATCH 09/13] fix unit test --- zetaclient/chains/ton/observer/observer_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zetaclient/chains/ton/observer/observer_test.go b/zetaclient/chains/ton/observer/observer_test.go index 45a79f65ec..cc4b1dadc8 100644 --- a/zetaclient/chains/ton/observer/observer_test.go +++ b/zetaclient/chains/ton/observer/observer_test.go @@ -64,7 +64,9 @@ func newTestSuite(t *testing.T) *testSuite { liteClient = mocks.NewLiteClient(t) tss = mocks.NewGeneratedTSS(t, chain) - zetacore = mocks.NewZetacoreClient(t).WithKeys(&keys.Keys{}) + zetacore = mocks.NewZetacoreClient(t).WithKeys(&keys.Keys{ + OperatorAddress: sample.Bech32AccAddress(), + }) testLogger = zerolog.New(zerolog.NewTestWriter(t)) logger = base.Logger{Std: testLogger, Compliance: testLogger} From 97ce52a94a2553fccc9f93e5e7815c3745766281 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 25 Nov 2024 12:22:43 -0600 Subject: [PATCH 10/13] added InboundCategoryUnknown; logs fields cleaning; renaming --- zetaclient/chains/bitcoin/signer/signer.go | 37 ++++++++----------- zetaclient/chains/evm/observer/v2_inbound.go | 10 ++--- .../chains/evm/observer/v2_inbound_tracker.go | 6 +-- zetaclient/types/event.go | 5 ++- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/zetaclient/chains/bitcoin/signer/signer.go b/zetaclient/chains/bitcoin/signer/signer.go index cb960183b6..615c0dc8a3 100644 --- a/zetaclient/chains/bitcoin/signer/signer.go +++ b/zetaclient/chains/bitcoin/signer/signer.go @@ -30,6 +30,7 @@ import ( "github.com/zeta-chain/node/zetaclient/chains/interfaces" "github.com/zeta-chain/node/zetaclient/compliance" "github.com/zeta-chain/node/zetaclient/config" + "github.com/zeta-chain/node/zetaclient/logs" "github.com/zeta-chain/node/zetaclient/metrics" "github.com/zeta-chain/node/zetaclient/outboundprocessor" ) @@ -355,12 +356,13 @@ func (signer *Signer) TryProcessOutbound( // prepare logger params := cctx.GetCurrentOutboundParam() - logger := signer.Logger().Std.With(). - Str("method", "TryProcessOutbound"). - Int64("chain", signer.Chain().ChainId). - Uint64("nonce", params.TssNonce). - Str("cctx", cctx.Index). - Logger() + // prepare logger fields + lf := map[string]any{ + logs.FieldMethod: "TryProcessOutbound", + logs.FieldCctx: cctx.Index, + logs.FieldNonce: params.TssNonce, + } + logger := signer.Logger().Std.With().Fields(lf).Logger() // support gas token only for Bitcoin outbound coinType := cctx.InboundParams.CoinType @@ -431,7 +433,7 @@ func (signer *Signer) TryProcessOutbound( if cancelTx { amount = 0.0 } else { - logger.Info().Msgf("SignGasWithdraw: to %s, value %d sats", to.EncodeAddress(), params.Amount.Uint64()) + logger.Info().Msgf("withdraw BTC to %s, value %d sats", to.EncodeAddress(), params.Amount.Uint64()) } // sign withdraw tx @@ -448,25 +450,21 @@ func (signer *Signer) TryProcessOutbound( cancelTx, ) if err != nil { - logger.Warn(). - Err(err). - Msgf("SignWithdrawTx error: nonce %d chain %d", outboundTssNonce, params.ReceiverChainId) + logger.Warn().Err(err).Msg("SignWithdrawTx failed") return } - logger.Info(). - Msgf("Key-sign success: %d => %s, nonce %d", cctx.InboundParams.SenderChainId, chain.Name, outboundTssNonce) + logger.Info().Msg("Key-sign success") // FIXME: add prometheus metrics _, err = zetacoreClient.GetObserverList(ctx) if err != nil { logger.Warn(). Err(err). - Msgf("unable to get observer list: chain %d observation %s", outboundTssNonce, observertypes.ObservationType_OutboundTx.String()) + Msgf("unable to get observer list, observation %s", observertypes.ObservationType_OutboundTx.String()) } if tx != nil { outboundHash := tx.TxHash().String() - logger.Info(). - Msgf("on chain %s nonce %d, outboundHash %s signer %s", chain.Name, outboundTssNonce, outboundHash, signerAddress) + logger.Info().Msgf("signed outboundHash %s signer %s", outboundHash, signerAddress) // try broacasting tx with increasing backoff (1s, 2s, 4s, 8s, 16s) in case of RPC error backOff := broadcastBackoff @@ -474,14 +472,11 @@ func (signer *Signer) TryProcessOutbound( time.Sleep(backOff) err := signer.Broadcast(tx) if err != nil { - logger.Warn(). - Err(err). - Msgf("broadcasting tx %s to chain %s: nonce %d, retry %d", outboundHash, chain.Name, outboundTssNonce, i) + logger.Warn().Err(err).Msgf("broadcasting tx %s to chain %s, retry %d", outboundHash, chain.Name, i) backOff *= 2 continue } - logger.Info(). - Msgf("Broadcast success: nonce %d to chain %s outboundHash %s", outboundTssNonce, chain.String(), outboundHash) + logger.Info().Msgf("Broadcast success: chain %s outboundHash %s", chain.String(), outboundHash) zetaHash, err := zetacoreClient.PostOutboundTracker( ctx, chain.ChainId, @@ -490,7 +485,7 @@ func (signer *Signer) TryProcessOutbound( ) if err != nil { logger.Err(err). - Msgf("Unable to add to tracker on zetacore: nonce %d chain %s outboundHash %s", outboundTssNonce, chain.Name, outboundHash) + Msgf("Unable to add to tracker on zetacore: chain %s outboundHash %s", chain.Name, outboundHash) } logger.Info().Msgf("Broadcast to core successful %s", zetaHash) diff --git a/zetaclient/chains/evm/observer/v2_inbound.go b/zetaclient/chains/evm/observer/v2_inbound.go index 45eadaa4fe..6422034273 100644 --- a/zetaclient/chains/evm/observer/v2_inbound.go +++ b/zetaclient/chains/evm/observer/v2_inbound.go @@ -23,8 +23,8 @@ import ( "github.com/zeta-chain/node/zetaclient/zetacore" ) -// IsEventProcessable checks if the event is processable -func (ob *Observer) IsEventProcessable( +// isEventProcessable checks if the event is processable +func (ob *Observer) isEventProcessable( sender, receiver ethcommon.Address, txHash ethcommon.Hash, payload []byte, @@ -99,7 +99,7 @@ func (ob *Observer) ObserveGatewayDeposit(ctx context.Context, startBlock, toBlo } // check if the event is processable - if !ob.IsEventProcessable(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { + if !ob.isEventProcessable(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { continue } @@ -247,7 +247,7 @@ func (ob *Observer) ObserveGatewayCall(ctx context.Context, startBlock, toBlock } // check if the event is processable - if !ob.IsEventProcessable(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { + if !ob.isEventProcessable(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { continue } @@ -378,7 +378,7 @@ func (ob *Observer) ObserveGatewayDepositAndCall(ctx context.Context, startBlock } // check if the event is processable - if !ob.IsEventProcessable(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { + if !ob.isEventProcessable(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { continue } diff --git a/zetaclient/chains/evm/observer/v2_inbound_tracker.go b/zetaclient/chains/evm/observer/v2_inbound_tracker.go index fa1eded16a..d559e9e9d6 100644 --- a/zetaclient/chains/evm/observer/v2_inbound_tracker.go +++ b/zetaclient/chains/evm/observer/v2_inbound_tracker.go @@ -36,7 +36,7 @@ func (ob *Observer) ProcessInboundTrackerV2( eventDeposit, err := gateway.ParseDeposited(*log) if err == nil { // check if the event is processable - if !ob.IsEventProcessable( + if !ob.isEventProcessable( eventDeposit.Sender, eventDeposit.Receiver, eventDeposit.Raw.TxHash, @@ -53,7 +53,7 @@ func (ob *Observer) ProcessInboundTrackerV2( eventDepositAndCall, err := gateway.ParseDepositedAndCalled(*log) if err == nil { // check if the event is processable - if !ob.IsEventProcessable( + if !ob.isEventProcessable( eventDepositAndCall.Sender, eventDepositAndCall.Receiver, eventDepositAndCall.Raw.TxHash, @@ -70,7 +70,7 @@ func (ob *Observer) ProcessInboundTrackerV2( eventCall, err := gateway.ParseCalled(*log) if err == nil { // check if the event is processable - if !ob.IsEventProcessable( + if !ob.isEventProcessable( eventCall.Sender, eventCall.Receiver, eventCall.Raw.TxHash, diff --git a/zetaclient/types/event.go b/zetaclient/types/event.go index 65b045af7b..fefdc39681 100644 --- a/zetaclient/types/event.go +++ b/zetaclient/types/event.go @@ -18,8 +18,11 @@ import ( type InboundCategory int const ( + // InboundCategoryUnknown represents an unknown inbound + InboundCategoryUnknown InboundCategory = iota + // InboundCategoryGood represents a processable inbound - InboundCategoryGood InboundCategory = iota + InboundCategoryGood // InboundCategoryDonation represents a donation inbound InboundCategoryDonation From 82a08fadd3a2a03c73bedfba11a30fa7bd56bf0f Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 25 Nov 2024 13:46:43 -0600 Subject: [PATCH 11/13] remove uncessary log print --- zetaclient/chains/bitcoin/signer/signer.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/zetaclient/chains/bitcoin/signer/signer.go b/zetaclient/chains/bitcoin/signer/signer.go index f6b85c1191..4ad146cfb5 100644 --- a/zetaclient/chains/bitcoin/signer/signer.go +++ b/zetaclient/chains/bitcoin/signer/signer.go @@ -432,8 +432,6 @@ func (signer *Signer) TryProcessOutbound( cancelTx := restrictedCCTX || dustAmount if cancelTx { amount = 0.0 - } else { - logger.Info().Msgf("withdraw BTC to %s, value %d sats", to.EncodeAddress(), params.Amount.Uint64()) } // sign withdraw tx From 5644b3cb1c511f2d5ad34616946fc60bca6d86ef Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 25 Nov 2024 14:04:45 -0600 Subject: [PATCH 12/13] wrap a few log prints into fields --- zetaclient/chains/bitcoin/signer/signer.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/zetaclient/chains/bitcoin/signer/signer.go b/zetaclient/chains/bitcoin/signer/signer.go index 4ad146cfb5..4a68fb4807 100644 --- a/zetaclient/chains/bitcoin/signer/signer.go +++ b/zetaclient/chains/bitcoin/signer/signer.go @@ -385,6 +385,7 @@ func (signer *Signer) TryProcessOutbound( logger.Error().Err(err).Msg("cannot get signer address") return } + lf["signer"] = signerAddress.String() // get size limit and gas price sizelimit := params.CallOptions.GasLimit @@ -457,12 +458,12 @@ func (signer *Signer) TryProcessOutbound( _, err = zetacoreClient.GetObserverList(ctx) if err != nil { logger.Warn(). - Err(err). - Msgf("unable to get observer list, observation %s", observertypes.ObservationType_OutboundTx.String()) + Err(err).Stringer("observation_type", observertypes.ObservationType_OutboundTx). + Msg("unable to get observer list, observation") } if tx != nil { outboundHash := tx.TxHash().String() - logger.Info().Msgf("signed outboundHash %s signer %s", outboundHash, signerAddress) + lf[logs.FieldTx] = outboundHash // try broacasting tx with increasing backoff (1s, 2s, 4s, 8s, 16s) in case of RPC error backOff := broadcastBackoff @@ -470,11 +471,11 @@ func (signer *Signer) TryProcessOutbound( time.Sleep(backOff) err := signer.Broadcast(tx) if err != nil { - logger.Warn().Err(err).Msgf("broadcasting tx %s to chain %s, retry %d", outboundHash, chain.Name, i) + logger.Warn().Err(err).Fields(lf).Msgf("Broadcasting Bitcoin tx, retry %d", i) backOff *= 2 continue } - logger.Info().Msgf("Broadcast success: chain %s outboundHash %s", chain.String(), outboundHash) + logger.Info().Fields(lf).Msgf("Broadcast Bitcoin tx successfully") zetaHash, err := zetacoreClient.PostOutboundTracker( ctx, chain.ChainId, @@ -482,10 +483,9 @@ func (signer *Signer) TryProcessOutbound( outboundHash, ) if err != nil { - logger.Err(err). - Msgf("Unable to add to tracker on zetacore: chain %s outboundHash %s", chain.Name, outboundHash) + logger.Err(err).Fields(lf).Msgf("Unable to add Bitcoin outbound tracker") } - logger.Info().Msgf("Broadcast to core successful %s", zetaHash) + logger.Info().Msgf("Add Bitcoin outbound tracker successfully %s", zetaHash) // Save successfully broadcasted transaction to btc chain observer btcObserver.SaveBroadcastedTx(outboundHash, outboundTssNonce) From 5f46375c918c209d6c4655feca36a92f8d571421 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 25 Nov 2024 14:34:30 -0600 Subject: [PATCH 13/13] move zeta tx hash to log field --- zetaclient/chains/bitcoin/signer/signer.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zetaclient/chains/bitcoin/signer/signer.go b/zetaclient/chains/bitcoin/signer/signer.go index 4a68fb4807..1321b0c14f 100644 --- a/zetaclient/chains/bitcoin/signer/signer.go +++ b/zetaclient/chains/bitcoin/signer/signer.go @@ -485,7 +485,8 @@ func (signer *Signer) TryProcessOutbound( if err != nil { logger.Err(err).Fields(lf).Msgf("Unable to add Bitcoin outbound tracker") } - logger.Info().Msgf("Add Bitcoin outbound tracker successfully %s", zetaHash) + lf[logs.FieldZetaTx] = zetaHash + logger.Info().Fields(lf).Msgf("Add Bitcoin outbound tracker successfully") // Save successfully broadcasted transaction to btc chain observer btcObserver.SaveBroadcastedTx(outboundHash, outboundTssNonce)