Skip to content

Commit

Permalink
move ValidateBasic checking right before posting the vote msg
Browse files Browse the repository at this point in the history
  • Loading branch information
ws4charlie committed Nov 22, 2024
1 parent 6c12632 commit c8b50eb
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 76 deletions.
2 changes: 1 addition & 1 deletion testutil/sample/crosschain.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
25 changes: 16 additions & 9 deletions zetaclient/chains/base/observer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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")
Expand Down
20 changes: 20 additions & 0 deletions zetaclient/chains/base/observer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"strings"
"testing"
"time"

Expand All @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down
8 changes: 3 additions & 5 deletions zetaclient/chains/bitcoin/observer/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,22 +153,20 @@ 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:
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", category)
ob.Logger().Inbound.Error().Fields(logFields).Msgf("unreachable code got InboundCategory: %v", category)
return false
}
}
Expand Down
33 changes: 5 additions & 28 deletions zetaclient/chains/bitcoin/observer/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions zetaclient/chains/bitcoin/observer/inbound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 4 additions & 15 deletions zetaclient/chains/solana/observer/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -292,35 +292,24 @@ 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:
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", category)
ob.Logger().Inbound.Error().Msgf("unreachable code got InboundCategory: %v", category)
return false
}
}
16 changes: 1 addition & 15 deletions zetaclient/chains/solana/observer/inbound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ package observer_test

import (
"context"
"strings"
"testing"

"github.com/stretchr/testify/require"
"github.com/zeta-chain/node/pkg/chains"
"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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions zetaclient/logs/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const (
FieldNonce = "nonce"
FieldTx = "tx"
FieldCctx = "cctx"
FieldZetaTx = "zeta_tx"
FieldBallot = "ballot"
FieldCoinType = "coin_type"

// module names
ModNameInbound = "inbound"
Expand Down

0 comments on commit c8b50eb

Please sign in to comment.