diff --git a/cmd/zetaclientd/inbound.go b/cmd/zetaclientd/inbound.go index 20a3422a37..ee602357fa 100644 --- a/cmd/zetaclientd/inbound.go +++ b/cmd/zetaclientd/inbound.go @@ -7,20 +7,19 @@ import ( "strings" "cosmossdk.io/errors" - "github.com/btcsuite/btcd/rpcclient" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/onrik/ethrpc" "github.com/rs/zerolog" "github.com/spf13/cobra" "github.com/zeta-chain/node/pkg/coin" "github.com/zeta-chain/node/testutil/sample" + "github.com/zeta-chain/node/zetaclient/chains/base" btcobserver "github.com/zeta-chain/node/zetaclient/chains/bitcoin/observer" evmobserver "github.com/zeta-chain/node/zetaclient/chains/evm/observer" "github.com/zeta-chain/node/zetaclient/config" zctx "github.com/zeta-chain/node/zetaclient/context" + "github.com/zeta-chain/node/zetaclient/db" "github.com/zeta-chain/node/zetaclient/keys" "github.com/zeta-chain/node/zetaclient/orchestrator" "github.com/zeta-chain/node/zetaclient/zetacore" @@ -87,27 +86,26 @@ func InboundGetBallot(_ *cobra.Command, args []string) error { return err } - chainProto := chain.RawChain() + baseLogger := base.Logger{Std: zerolog.Nop(), Compliance: zerolog.Nop()} + + observers, err := orchestrator.CreateChainObserverMap(ctx, client, nil, db.SqliteInMemory, baseLogger, nil) + if err != nil { + return errors.Wrap(err, "failed to create chain observer map") + } // get ballot identifier according to the chain type if chain.IsEVM() { - evmObserver := evmobserver.Observer{} - evmObserver.WithZetacoreClient(client) - var ethRPC *ethrpc.EthRPC - var client *ethclient.Client - coinType := coin.CoinType_Cmd - for chainIDFromConfig, evmConfig := range cfg.GetAllEVMConfigs() { - if chainIDFromConfig == chainID { - ethRPC = ethrpc.NewEthRPC(evmConfig.Endpoint) - client, err = ethclient.Dial(evmConfig.Endpoint) - if err != nil { - return err - } - evmObserver.WithEvmClient(client) - evmObserver.WithEvmJSONRPC(ethRPC) - evmObserver.WithChain(*chainProto) - } + observer, ok := observers[chainID] + if !ok { + return fmt.Errorf("observer not found for evm chain %d", chain.ID()) + } + + evmObserver, ok := observer.(*evmobserver.Observer) + if !ok { + return fmt.Errorf("observer is not evm observer for chain %d", chain.ID()) } + + coinType := coin.CoinType_Cmd hash := ethcommon.HexToHash(inboundHash) tx, isPending, err := evmObserver.TransactionByHash(inboundHash) if err != nil { @@ -118,7 +116,7 @@ func InboundGetBallot(_ *cobra.Command, args []string) error { return fmt.Errorf("tx is still pending") } - receipt, err := client.TransactionReceipt(context.Background(), hash) + receipt, err := evmObserver.TransactionReceipt(ctx, hash) if err != nil { return fmt.Errorf("tx receipt not found on chain %s, %d", err.Error(), chain.ID()) } @@ -158,33 +156,23 @@ func InboundGetBallot(_ *cobra.Command, args []string) error { } fmt.Println("CoinType : ", coinType) } else if chain.IsBitcoin() { - btcObserver := btcobserver.Observer{} - btcObserver.WithZetacoreClient(client) - btcObserver.WithChain(*chainProto) - btcConfig, found := cfg.GetBTCConfig(chainID) - if !found { - return fmt.Errorf("unable to find config for BTC chain %d", chainID) - } - connCfg := &rpcclient.ConnConfig{ - Host: btcConfig.RPCHost, - User: btcConfig.RPCUsername, - Pass: btcConfig.RPCPassword, - HTTPPostMode: true, - DisableTLS: true, - Params: btcConfig.RPCParams, + observer, ok := observers[chainID] + if !ok { + return fmt.Errorf("observer not found for btc chain %d", chainID) } - btcClient, err := rpcclient.New(connCfg, nil) - if err != nil { - return err + btcObserver, ok := observer.(*btcobserver.Observer) + if !ok { + return fmt.Errorf("observer is not btc observer for chain %d", chainID) } - btcObserver.WithBtcClient(btcClient) + ballotIdentifier, err = btcObserver.CheckReceiptForBtcTxHash(ctx, inboundHash, false) if err != nil { return err } } - fmt.Println("BallotIdentifier : ", ballotIdentifier) + + fmt.Println("BallotIdentifier: ", ballotIdentifier) // query ballot ballot, err := client.GetBallot(ctx, ballotIdentifier) @@ -193,9 +181,10 @@ func InboundGetBallot(_ *cobra.Command, args []string) error { } for _, vote := range ballot.Voters { - fmt.Printf("%s : %s \n", vote.VoterAddress, vote.VoteType) + fmt.Printf("%s: %s\n", vote.VoterAddress, vote.VoteType) } - fmt.Println("BallotStatus : ", ballot.BallotStatus) + + fmt.Println("BallotStatus: ", ballot.BallotStatus) return nil } diff --git a/cmd/zetaclientd/start.go b/cmd/zetaclientd/start.go index 76a3c0808c..9906d735fc 100644 --- a/cmd/zetaclientd/start.go +++ b/cmd/zetaclientd/start.go @@ -197,7 +197,7 @@ func Start(_ *cobra.Command, _ []string) error { // CreateSignerMap: This creates a map of all signers for each chain. // Each signer is responsible for signing transactions for a particular chain - signerMap, err := orchestrator.CreateSignerMap(ctx, tss, logger, telemetryServer) + signerMap, err := orchestrator.CreateSignerMap(ctx, tss, logger) if err != nil { log.Error().Err(err).Msg("Unable to create signer map") return err diff --git a/zetaclient/chains/base/observer.go b/zetaclient/chains/base/observer.go index af366faa5e..8cb3ab7cdb 100644 --- a/zetaclient/chains/base/observer.go +++ b/zetaclient/chains/base/observer.go @@ -31,10 +31,6 @@ const ( // DefaultBlockCacheSize is the default number of blocks that the observer will keep in cache for performance (without RPC calls) // Cached blocks can be used to get block information and verify transactions DefaultBlockCacheSize = 1000 - - // DefaultHeaderCacheSize is the default number of headers that the observer will keep in cache for performance (without RPC calls) - // Cached headers can be used to get header information - DefaultHeaderCacheSize = 1000 ) // Observer is the base structure for chain observers, grouping the common logic for each chain observer client. @@ -64,12 +60,8 @@ type Observer struct { // rpcAlertLatency is the threshold of RPC latency to trigger an alert rpcAlertLatency time.Duration - // blockCache is the cache for blocks blockCache *lru.Cache - // headerCache is the cache for headers - headerCache *lru.Cache - // db is the database to persist data db *db.DB @@ -95,13 +87,17 @@ func NewObserver( zetacoreClient interfaces.ZetacoreClient, tss interfaces.TSSSigner, blockCacheSize int, - headerCacheSize int, rpcAlertLatency int64, ts *metrics.TelemetryServer, database *db.DB, logger Logger, ) (*Observer, error) { - ob := Observer{ + blockCache, err := lru.New(blockCacheSize) + if err != nil { + return nil, errors.Wrap(err, "error creating block cache") + } + + return &Observer{ chain: chain, chainParams: chainParams, zetacoreClient: zetacoreClient, @@ -112,27 +108,11 @@ func NewObserver( rpcAlertLatency: time.Duration(rpcAlertLatency) * time.Second, ts: ts, db: database, + blockCache: blockCache, mu: &sync.Mutex{}, + logger: newObserverLogger(chain, logger), stop: make(chan struct{}), - } - - // setup loggers - ob.WithLogger(logger) - - // create block cache - var err error - ob.blockCache, err = lru.New(blockCacheSize) - if err != nil { - return nil, errors.Wrap(err, "error creating block cache") - } - - // create header cache - ob.headerCache, err = lru.New(headerCacheSize) - if err != nil { - return nil, errors.Wrap(err, "error creating header cache") - } - - return &ob, nil + }, nil } // Start starts the observer. Returns false if it's already started (noop). @@ -178,12 +158,6 @@ func (ob *Observer) Chain() chains.Chain { return ob.chain } -// WithChain attaches a new chain to the observer. -func (ob *Observer) WithChain(chain chains.Chain) *Observer { - ob.chain = chain - return ob -} - // ChainParams returns the chain params for the observer. func (ob *Observer) ChainParams() observertypes.ChainParams { ob.mu.Lock() @@ -205,23 +179,11 @@ func (ob *Observer) ZetacoreClient() interfaces.ZetacoreClient { return ob.zetacoreClient } -// WithZetacoreClient attaches a new zetacore client to the observer. -func (ob *Observer) WithZetacoreClient(client interfaces.ZetacoreClient) *Observer { - ob.zetacoreClient = client - return ob -} - // TSS returns the tss signer for the observer. func (ob *Observer) TSS() interfaces.TSSSigner { return ob.tss } -// WithTSS attaches a new tss signer to the observer. -func (ob *Observer) WithTSS(tss interfaces.TSSSigner) *Observer { - ob.tss = tss - return ob -} - // TSSAddressString returns the TSS address for the chain. // // Note: all chains uses TSS EVM address except Bitcoin chain. @@ -287,23 +249,6 @@ func (ob *Observer) BlockCache() *lru.Cache { return ob.blockCache } -// WithBlockCache attaches a new block cache to the observer. -func (ob *Observer) WithBlockCache(cache *lru.Cache) *Observer { - ob.blockCache = cache - return ob -} - -// HeaderCache returns the header cache for the observer. -func (ob *Observer) HeaderCache() *lru.Cache { - return ob.headerCache -} - -// WithHeaderCache attaches a new header cache to the observer. -func (ob *Observer) WithHeaderCache(cache *lru.Cache) *Observer { - ob.headerCache = cache - return ob -} - // OutboundID returns a unique identifier for the outbound transaction. // The identifier is now used as the key for maps that store outbound related data (e.g. transaction, receipt, etc). func (ob *Observer) OutboundID(nonce uint64) string { @@ -316,12 +261,6 @@ func (ob *Observer) DB() *db.DB { return ob.db } -// WithTelemetryServer attaches a new telemetry server to the observer. -func (ob *Observer) WithTelemetryServer(ts *metrics.TelemetryServer) *Observer { - ob.ts = ts - return ob -} - // TelemetryServer returns the telemetry server for the observer. func (ob *Observer) TelemetryServer() *metrics.TelemetryServer { return ob.ts @@ -332,26 +271,6 @@ func (ob *Observer) Logger() *ObserverLogger { return &ob.logger } -// WithLogger attaches a new logger to the observer. -func (ob *Observer) WithLogger(logger Logger) *Observer { - chainLogger := logger.Std. - With(). - Int64(logs.FieldChain, ob.chain.ChainId). - Str(logs.FieldChainNetwork, ob.chain.Network.String()). - Logger() - - ob.logger = ObserverLogger{ - Chain: chainLogger, - Inbound: chainLogger.With().Str(logs.FieldModule, logs.ModNameInbound).Logger(), - Outbound: chainLogger.With().Str(logs.FieldModule, logs.ModNameOutbound).Logger(), - GasPrice: chainLogger.With().Str(logs.FieldModule, logs.ModNameGasPrice).Logger(), - Headers: chainLogger.With().Str(logs.FieldModule, logs.ModNameHeaders).Logger(), - Compliance: logger.Compliance, - } - - return ob -} - // Mu returns the mutex for the observer. func (ob *Observer) Mu() *sync.Mutex { return ob.mu @@ -544,3 +463,24 @@ func EnvVarLatestBlockByChain(chain chains.Chain) string { func EnvVarLatestTxByChain(chain chains.Chain) string { return fmt.Sprintf("CHAIN_%d_SCAN_FROM_TX", chain.ChainId) } + +func newObserverLogger(chain chains.Chain, logger Logger) ObserverLogger { + withLogFields := func(l zerolog.Logger) zerolog.Logger { + return l.With(). + Int64(logs.FieldChain, chain.ChainId). + Str(logs.FieldChainNetwork, chain.Network.String()). + Logger() + } + + log := withLogFields(logger.Std) + complianceLog := withLogFields(logger.Compliance) + + return ObserverLogger{ + Chain: log, + Inbound: log.With().Str(logs.FieldModule, logs.ModNameInbound).Logger(), + Outbound: log.With().Str(logs.FieldModule, logs.ModNameOutbound).Logger(), + GasPrice: log.With().Str(logs.FieldModule, logs.ModNameGasPrice).Logger(), + Headers: log.With().Str(logs.FieldModule, logs.ModNameHeaders).Logger(), + Compliance: complianceLog, + } +} diff --git a/zetaclient/chains/base/observer_test.go b/zetaclient/chains/base/observer_test.go index 0ca1a6a147..5c08563b7b 100644 --- a/zetaclient/chains/base/observer_test.go +++ b/zetaclient/chains/base/observer_test.go @@ -8,7 +8,6 @@ import ( "testing" "time" - lru "github.com/hashicorp/golang-lru" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/stretchr/testify/require" @@ -22,7 +21,6 @@ import ( "github.com/zeta-chain/node/zetaclient/config" zctx "github.com/zeta-chain/node/zetaclient/context" "github.com/zeta-chain/node/zetaclient/db" - "github.com/zeta-chain/node/zetaclient/metrics" "github.com/zeta-chain/node/zetaclient/testutils/mocks" ) @@ -34,8 +32,15 @@ const ( defaultConfirmationCount = 2 ) -// createObserver creates a new observer for testing -func createObserver(t *testing.T, chain chains.Chain, alertLatency int64) *base.Observer { +type testSuite struct { + *base.Observer + db *db.DB + tss *mocks.TSS + zetacore *mocks.ZetacoreClient +} + +// newTestSuite creates a new observer for testing +func newTestSuite(t *testing.T, chain chains.Chain, alertLatency int64) *testSuite { // constructor parameters chainParams := *sample.ChainParams(chain.ChainId) chainParams.ConfirmationCount = defaultConfirmationCount @@ -52,7 +57,6 @@ func createObserver(t *testing.T, chain chains.Chain, alertLatency int64) *base. zetacoreClient, tss, base.DefaultBlockCacheSize, - base.DefaultHeaderCacheSize, alertLatency, nil, database, @@ -60,7 +64,12 @@ func createObserver(t *testing.T, chain chains.Chain, alertLatency int64) *base. ) require.NoError(t, err) - return ob + return &testSuite{ + Observer: ob, + db: database, + tss: tss, + zetacore: zetacoreClient, + } } func TestNewObserver(t *testing.T) { @@ -71,57 +80,41 @@ func TestNewObserver(t *testing.T) { zetacoreClient := mocks.NewZetacoreClient(t) tss := mocks.NewTSS(t) blockCacheSize := base.DefaultBlockCacheSize - headersCacheSize := base.DefaultHeaderCacheSize database := createDatabase(t) // test cases tests := []struct { - name string - chain chains.Chain - chainParams observertypes.ChainParams - appContext *zctx.AppContext - zetacoreClient interfaces.ZetacoreClient - tss interfaces.TSSSigner - blockCacheSize int - headerCacheSize int - fail bool - message string + name string + chain chains.Chain + chainParams observertypes.ChainParams + appContext *zctx.AppContext + zetacoreClient interfaces.ZetacoreClient + tss interfaces.TSSSigner + blockCacheSize int + fail bool + message string }{ { - name: "should be able to create new observer", - chain: chain, - chainParams: chainParams, - appContext: appContext, - zetacoreClient: zetacoreClient, - tss: tss, - blockCacheSize: blockCacheSize, - headerCacheSize: headersCacheSize, - fail: false, - }, - { - name: "should return error on invalid block cache size", - chain: chain, - chainParams: chainParams, - appContext: appContext, - zetacoreClient: zetacoreClient, - tss: tss, - blockCacheSize: 0, - headerCacheSize: headersCacheSize, - fail: true, - message: "error creating block cache", + name: "should be able to create new observer", + chain: chain, + chainParams: chainParams, + appContext: appContext, + zetacoreClient: zetacoreClient, + tss: tss, + blockCacheSize: blockCacheSize, + fail: false, }, { - name: "should return error on invalid header cache size", - chain: chain, - chainParams: chainParams, - appContext: appContext, - zetacoreClient: zetacoreClient, - tss: tss, - blockCacheSize: blockCacheSize, - headerCacheSize: 0, - fail: true, - message: "error creating header cache", + name: "should return error on invalid block cache size", + chain: chain, + chainParams: chainParams, + appContext: appContext, + zetacoreClient: zetacoreClient, + tss: tss, + blockCacheSize: 0, + fail: true, + message: "error creating block cache", }, } @@ -134,7 +127,6 @@ func TestNewObserver(t *testing.T) { tt.zetacoreClient, tt.tss, tt.blockCacheSize, - tt.headerCacheSize, 60, nil, database, @@ -155,7 +147,7 @@ func TestNewObserver(t *testing.T) { func TestStop(t *testing.T) { t.Run("should be able to stop observer", func(t *testing.T) { // create observer and initialize db - ob := createObserver(t, chains.Ethereum, defaultAlertLatency) + ob := newTestSuite(t, chains.Ethereum, defaultAlertLatency) // stop observer ob.Stop() @@ -165,93 +157,35 @@ func TestStop(t *testing.T) { func TestObserverGetterAndSetter(t *testing.T) { chain := chains.Ethereum - t.Run("should be able to update chain", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) - - // update chain - newChain := chains.BscMainnet - ob = ob.WithChain(chains.BscMainnet) - require.Equal(t, newChain, ob.Chain()) - }) - - t.Run("should be able to update zetacore client", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) - - // update zetacore client - newZetacoreClient := mocks.NewZetacoreClient(t) - ob = ob.WithZetacoreClient(newZetacoreClient) - require.Equal(t, newZetacoreClient, ob.ZetacoreClient()) - }) - - t.Run("should be able to update tss", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) - - // update tss - newTSS := mocks.NewTSS(t) - ob = ob.WithTSS(newTSS) - require.Equal(t, newTSS, ob.TSS()) - }) - t.Run("should be able to update last block", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // update last block newLastBlock := uint64(100) - ob = ob.WithLastBlock(newLastBlock) + ob.Observer.WithLastBlock(newLastBlock) require.Equal(t, newLastBlock, ob.LastBlock()) }) t.Run("should be able to update last block scanned", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // update last block scanned newLastBlockScanned := uint64(100) - ob = ob.WithLastBlockScanned(newLastBlockScanned) + ob.Observer.WithLastBlockScanned(newLastBlockScanned) require.Equal(t, newLastBlockScanned, ob.LastBlockScanned()) }) t.Run("should be able to update last tx scanned", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // update last tx scanned newLastTxScanned := sample.EthAddress().String() - ob = ob.WithLastTxScanned(newLastTxScanned) + ob.Observer.WithLastTxScanned(newLastTxScanned) require.Equal(t, newLastTxScanned, ob.LastTxScanned()) }) - t.Run("should be able to replace block cache", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) - - // update block cache - newBlockCache, err := lru.New(200) - require.NoError(t, err) - - ob = ob.WithBlockCache(newBlockCache) - require.Equal(t, newBlockCache, ob.BlockCache()) - }) - - t.Run("should be able to replace header cache", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) - - // update headers cache - newHeadersCache, err := lru.New(200) - require.NoError(t, err) - - ob = ob.WithHeaderCache(newHeadersCache) - require.Equal(t, newHeadersCache, ob.HeaderCache()) - }) - - t.Run("should be able to update telemetry server", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) - - // update telemetry server - newServer := metrics.NewTelemetryServer() - ob = ob.WithTelemetryServer(newServer) - require.Equal(t, newServer, ob.TelemetryServer()) - }) - t.Run("should be able to get logger", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) logger := ob.Logger() // should be able to print log @@ -265,10 +199,12 @@ func TestObserverGetterAndSetter(t *testing.T) { } func TestTSSAddressString(t *testing.T) { + btcSomething := chains.BitcoinMainnet + btcSomething.ChainId = 123123123 + tests := []struct { name string chain chains.Chain - forceError bool addrExpected string }{ { @@ -288,8 +224,7 @@ func TestTSSAddressString(t *testing.T) { }, { name: "should return empty address for unknown BTC chain", - chain: chains.BitcoinMainnet, - forceError: true, + chain: btcSomething, addrExpected: "", }, } @@ -298,18 +233,7 @@ func TestTSSAddressString(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // create observer - ob := createObserver(t, tt.chain, defaultAlertLatency) - - // force error if needed - if tt.forceError { - // pause TSS to cause error - tss := mocks.NewTSS(t) - tss.Pause() - ob = ob.WithTSS(tss) - c := chains.BitcoinRegtest - c.ChainId = 123123123 - ob.WithChain(c) - } + ob := newTestSuite(t, tt.chain, defaultAlertLatency) // get TSS address addr := ob.TSSAddressString() @@ -362,8 +286,8 @@ func TestIsBlockConfirmed(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // create observer - ob := createObserver(t, tt.chain, defaultAlertLatency) - ob = ob.WithLastBlock(tt.lastBlock) + ob := newTestSuite(t, tt.chain, defaultAlertLatency) + ob.Observer.WithLastBlock(tt.lastBlock) // check if block is confirmed confirmed := ob.IsBlockConfirmed(tt.block) @@ -376,19 +300,16 @@ func TestOutboundID(t *testing.T) { tests := []struct { name string chain chains.Chain - tss interfaces.TSSSigner nonce uint64 }{ { name: "should get correct outbound id for Ethereum chain", chain: chains.Ethereum, - tss: mocks.NewTSS(t), nonce: 100, }, { name: "should get correct outbound id for Bitcoin chain", chain: chains.BitcoinMainnet, - tss: mocks.NewTSS(t), nonce: 200, }, } @@ -397,8 +318,7 @@ func TestOutboundID(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // create observer - ob := createObserver(t, tt.chain, defaultAlertLatency) - ob = ob.WithTSS(tt.tss) + ob := newTestSuite(t, tt.chain, defaultAlertLatency) // get outbound id outboundID := ob.OutboundID(tt.nonce) @@ -416,7 +336,7 @@ func TestLoadLastBlockScanned(t *testing.T) { t.Run("should be able to load last block scanned", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // create db and write 100 as last block scanned err := ob.WriteLastBlockScannedToDB(100) @@ -430,7 +350,7 @@ func TestLoadLastBlockScanned(t *testing.T) { t.Run("latest block scanned should be 0 if not found in db", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // read last block scanned err := ob.LoadLastBlockScanned(log.Logger) @@ -440,7 +360,7 @@ func TestLoadLastBlockScanned(t *testing.T) { t.Run("should overwrite last block scanned if env var is set", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // create db and write 100 as last block scanned ob.WriteLastBlockScannedToDB(100) @@ -456,7 +376,7 @@ func TestLoadLastBlockScanned(t *testing.T) { t.Run("last block scanned should remain 0 if env var is set to latest", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // create db and write 100 as last block scanned ob.WriteLastBlockScannedToDB(100) @@ -472,7 +392,7 @@ func TestLoadLastBlockScanned(t *testing.T) { t.Run("should return error on invalid env var", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // set invalid env var os.Setenv(envvar, "invalid") @@ -486,7 +406,7 @@ func TestLoadLastBlockScanned(t *testing.T) { func TestSaveLastBlockScanned(t *testing.T) { t.Run("should be able to save last block scanned", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chains.Ethereum, defaultAlertLatency) + ob := newTestSuite(t, chains.Ethereum, defaultAlertLatency) // save 100 as last block scanned err := ob.SaveLastBlockScanned(100) @@ -506,7 +426,7 @@ func TestReadWriteDBLastBlockScanned(t *testing.T) { chain := chains.Ethereum t.Run("should be able to write and read last block scanned to db", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // write last block scanned err := ob.WriteLastBlockScannedToDB(100) @@ -519,7 +439,7 @@ func TestReadWriteDBLastBlockScanned(t *testing.T) { t.Run("should return error when last block scanned not found in db", func(t *testing.T) { // create empty db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) lastScannedBlock, err := ob.ReadLastBlockScannedFromDB() require.Error(t, err) @@ -533,7 +453,7 @@ func TestLoadLastTxScanned(t *testing.T) { t.Run("should be able to load last tx scanned", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // create db and write sample hash as last tx scanned ob.WriteLastTxScannedToDB(lastTx) @@ -545,7 +465,7 @@ func TestLoadLastTxScanned(t *testing.T) { t.Run("latest tx scanned should be empty if not found in db", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // read last tx scanned ob.LoadLastTxScanned() @@ -554,7 +474,7 @@ func TestLoadLastTxScanned(t *testing.T) { t.Run("should overwrite last tx scanned if env var is set", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // create db and write sample hash as last tx scanned ob.WriteLastTxScannedToDB(lastTx) @@ -573,7 +493,7 @@ func TestSaveLastTxScanned(t *testing.T) { chain := chains.SolanaDevnet t.Run("should be able to save last tx scanned", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // save random tx hash lastSlot := uint64(100) @@ -596,7 +516,7 @@ func TestReadWriteDBLastTxScanned(t *testing.T) { chain := chains.SolanaDevnet t.Run("should be able to write and read last tx scanned to db", func(t *testing.T) { // create observer and open db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) // write last tx scanned lastTx := "5LuQMorgd11p8GWEw6pmyHCDtA26NUyeNFhLWPNk2oBoM9pkag1LzhwGSRos3j4TJLhKjswFhZkGtvSGdLDkmqsk" @@ -610,7 +530,7 @@ func TestReadWriteDBLastTxScanned(t *testing.T) { t.Run("should return error when last tx scanned not found in db", func(t *testing.T) { // create empty db - ob := createObserver(t, chain, defaultAlertLatency) + ob := newTestSuite(t, chain, defaultAlertLatency) lastTxScanned, err := ob.ReadLastTxScannedFromDB() require.Error(t, err) @@ -621,12 +541,9 @@ func TestReadWriteDBLastTxScanned(t *testing.T) { func TestPostVoteInbound(t *testing.T) { t.Run("should be able to post vote inbound", func(t *testing.T) { // create observer - ob := createObserver(t, chains.Ethereum, defaultAlertLatency) + ob := newTestSuite(t, chains.Ethereum, defaultAlertLatency) - // create mock zetacore client - zetacoreClient := mocks.NewZetacoreClient(t) - zetacoreClient.WithPostVoteInbound("", "sampleBallotIndex") - ob = ob.WithZetacoreClient(zetacoreClient) + ob.zetacore.WithPostVoteInbound("", "sampleBallotIndex") // post vote inbound msg := sample.InboundVote(coin.CoinType_Gas, chains.Ethereum.ChainId, chains.ZetaChainMainnet.ChainId) @@ -637,11 +554,7 @@ func TestPostVoteInbound(t *testing.T) { 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) + ob := newTestSuite(t, chains.Ethereum, defaultAlertLatency) // create sample message with long Message msg := sample.InboundVote(coin.CoinType_Gas, chains.Ethereum.ChainId, chains.ZetaChainMainnet.ChainId) @@ -693,7 +606,7 @@ func TestAlertOnRPCLatency(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // create observer - ob := createObserver(t, chains.Ethereum, tt.alertLatency) + ob := newTestSuite(t, chains.Ethereum, tt.alertLatency) alerted := ob.AlertOnRPCLatency(tt.blockTime, time.Duration(defaultAlertLatency)*time.Second) require.Equal(t, tt.alerted, alerted) diff --git a/zetaclient/chains/base/signer.go b/zetaclient/chains/base/signer.go index 71cebaf47a..e2e6ae45a4 100644 --- a/zetaclient/chains/base/signer.go +++ b/zetaclient/chains/base/signer.go @@ -3,10 +3,11 @@ package base import ( "sync" + "github.com/rs/zerolog" + "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/zetaclient/chains/interfaces" "github.com/zeta-chain/node/zetaclient/logs" - "github.com/zeta-chain/node/zetaclient/metrics" ) // Signer is the base structure for grouping the common logic between chain signers. @@ -18,9 +19,6 @@ type Signer struct { // tss is the TSS signer tss interfaces.TSSSigner - // ts is the telemetry server for metrics - ts *metrics.TelemetryServer - // logger contains the loggers used by signer logger Logger @@ -33,19 +31,22 @@ type Signer struct { } // NewSigner creates a new base signer. -func NewSigner(chain chains.Chain, tss interfaces.TSSSigner, ts *metrics.TelemetryServer, logger Logger) *Signer { +func NewSigner(chain chains.Chain, tss interfaces.TSSSigner, logger Logger) *Signer { + withLogFields := func(log zerolog.Logger) zerolog.Logger { + return log.With(). + Int64(logs.FieldChain, chain.ChainId). + Str(logs.FieldModule, "signer"). + Logger() + } + return &Signer{ - chain: chain, - tss: tss, - ts: ts, + chain: chain, + tss: tss, + outboundBeingReported: make(map[string]bool), logger: Logger{ - Std: logger.Std.With(). - Int64(logs.FieldChain, chain.ChainId). - Str(logs.FieldModule, "signer"). - Logger(), - Compliance: logger.Compliance, + Std: withLogFields(logger.Std), + Compliance: withLogFields(logger.Compliance), }, - outboundBeingReported: make(map[string]bool), } } @@ -54,34 +55,11 @@ func (s *Signer) Chain() chains.Chain { return s.chain } -// WithChain attaches a new chain to the signer. -func (s *Signer) WithChain(chain chains.Chain) *Signer { - s.chain = chain - return s -} - -// Tss returns the tss signer for the signer. +// TSS returns the tss signer for the signer. func (s *Signer) TSS() interfaces.TSSSigner { return s.tss } -// WithTSS attaches a new tss signer to the signer. -func (s *Signer) WithTSS(tss interfaces.TSSSigner) *Signer { - s.tss = tss - return s -} - -// TelemetryServer returns the telemetry server for the signer. -func (s *Signer) TelemetryServer() *metrics.TelemetryServer { - return s.ts -} - -// WithTelemetryServer attaches a new telemetry server to the signer. -func (s *Signer) WithTelemetryServer(ts *metrics.TelemetryServer) *Signer { - s.ts = ts - return s -} - // Logger returns the logger for the signer. func (s *Signer) Logger() *Logger { return &s.logger diff --git a/zetaclient/chains/base/signer_test.go b/zetaclient/chains/base/signer_test.go index 6a7489741c..54883236bb 100644 --- a/zetaclient/chains/base/signer_test.go +++ b/zetaclient/chains/base/signer_test.go @@ -7,7 +7,6 @@ import ( "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/zetaclient/chains/base" - "github.com/zeta-chain/node/zetaclient/metrics" "github.com/zeta-chain/node/zetaclient/testutils/mocks" ) @@ -19,7 +18,7 @@ func createSigner(t *testing.T) *base.Signer { logger := base.DefaultLogger() // create signer - return base.NewSigner(chain, tss, nil, logger) + return base.NewSigner(chain, tss, logger) } func TestNewSigner(t *testing.T) { @@ -27,41 +26,6 @@ func TestNewSigner(t *testing.T) { require.NotNil(t, signer) } -func TestSignerGetterAndSetter(t *testing.T) { - t.Run("should be able to update chain", func(t *testing.T) { - signer := createSigner(t) - - // update chain - newChain := chains.BscMainnet - signer = signer.WithChain(chains.BscMainnet) - require.Equal(t, newChain, signer.Chain()) - }) - t.Run("should be able to update tss", func(t *testing.T) { - signer := createSigner(t) - - // update tss - newTSS := mocks.NewTSS(t) - signer = signer.WithTSS(newTSS) - require.Equal(t, newTSS, signer.TSS()) - }) - t.Run("should be able to update telemetry server", func(t *testing.T) { - signer := createSigner(t) - - // update telemetry server - newTs := metrics.NewTelemetryServer() - signer = signer.WithTelemetryServer(newTs) - require.Equal(t, newTs, signer.TelemetryServer()) - }) - t.Run("should be able to get logger", func(t *testing.T) { - ob := createSigner(t) - logger := ob.Logger() - - // should be able to print log - logger.Std.Info().Msg("print standard log") - logger.Compliance.Info().Msg("print compliance log") - }) -} - func Test_BeingReportedFlag(t *testing.T) { signer := createSigner(t) diff --git a/zetaclient/chains/bitcoin/observer/event_test.go b/zetaclient/chains/bitcoin/observer/event_test.go index 9a73d28069..ab78269527 100644 --- a/zetaclient/chains/bitcoin/observer/event_test.go +++ b/zetaclient/chains/bitcoin/observer/event_test.go @@ -21,7 +21,6 @@ import ( "github.com/zeta-chain/node/zetaclient/config" "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" ) @@ -305,10 +304,9 @@ func Test_ValidateStandardMemo(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) // create test observer - ob := MockBTCObserver(t, chain, params, nil) + ob := newTestSuite(t, chain) // setup compliance config cfg := config.Config{ @@ -354,12 +352,10 @@ func Test_IsEventProcessable(t *testing.T) { func Test_NewInboundVoteFromLegacyMemo(t *testing.T) { // can use any bitcoin chain for testing chain := chains.BitcoinMainnet - params := mocks.MockChainParams(chain.ChainId, 10) // create test observer - ob := MockBTCObserver(t, chain, params, nil) - zetacoreClient := mocks.NewZetacoreClient(t).WithKeys(&keys.Keys{}).WithZetaChain() - ob.WithZetacoreClient(zetacoreClient) + ob := newTestSuite(t, chain) + ob.zetacore.WithKeys(&keys.Keys{}).WithZetaChain() t.Run("should create new inbound vote msg V1", func(t *testing.T) { // create test event @@ -396,12 +392,10 @@ func Test_NewInboundVoteFromLegacyMemo(t *testing.T) { func Test_NewInboundVoteFromStdMemo(t *testing.T) { // can use any bitcoin chain for testing chain := chains.BitcoinMainnet - params := mocks.MockChainParams(chain.ChainId, 10) // create test observer - ob := MockBTCObserver(t, chain, params, nil) - zetacoreClient := mocks.NewZetacoreClient(t).WithKeys(&keys.Keys{}).WithZetaChain() - ob.WithZetacoreClient(zetacoreClient) + ob := newTestSuite(t, chain) + ob.zetacore.WithKeys(&keys.Keys{}).WithZetaChain() t.Run("should create new inbound vote msg with standard memo", func(t *testing.T) { // create revert options diff --git a/zetaclient/chains/bitcoin/observer/inbound_test.go b/zetaclient/chains/bitcoin/observer/inbound_test.go index 7ec938aab0..b1cfe8d369 100644 --- a/zetaclient/chains/bitcoin/observer/inbound_test.go +++ b/zetaclient/chains/bitcoin/observer/inbound_test.go @@ -153,12 +153,10 @@ func TestAvgFeeRateBlock828440Errors(t *testing.T) { func Test_GetInboundVoteFromBtcEvent(t *testing.T) { // can use any bitcoin chain for testing chain := chains.BitcoinMainnet - params := mocks.MockChainParams(chain.ChainId, 10) // create test observer - ob := MockBTCObserver(t, chain, params, nil) - zetacoreClient := mocks.NewZetacoreClient(t).WithKeys(&keys.Keys{}).WithZetaChain() - ob.WithZetacoreClient(zetacoreClient) + ob := newTestSuite(t, chain) + ob.zetacore.WithKeys(&keys.Keys{}).WithZetaChain() // test cases tests := []struct { diff --git a/zetaclient/chains/bitcoin/observer/observer.go b/zetaclient/chains/bitcoin/observer/observer.go index 8a3516f3d0..74bc263e3a 100644 --- a/zetaclient/chains/bitcoin/observer/observer.go +++ b/zetaclient/chains/bitcoin/observer/observer.go @@ -107,7 +107,6 @@ func NewObserver( zetacoreClient, tss, btcBlocksPerDay, - base.DefaultHeaderCacheSize, rpcAlertLatency, ts, database, @@ -157,11 +156,6 @@ func (ob *Observer) BtcClient() interfaces.BTCRPCClient { return ob.btcClient } -// WithBtcClient attaches a new btc client to the observer -func (ob *Observer) WithBtcClient(client interfaces.BTCRPCClient) { - ob.btcClient = client -} - // Start starts the Go routine processes to observe the Bitcoin chain func (ob *Observer) Start(ctx context.Context) { if ok := ob.Observer.Start(); !ok { diff --git a/zetaclient/chains/bitcoin/observer/observer_test.go b/zetaclient/chains/bitcoin/observer/observer_test.go index 7679b00bc9..18358703b5 100644 --- a/zetaclient/chains/bitcoin/observer/observer_test.go +++ b/zetaclient/chains/bitcoin/observer/observer_test.go @@ -8,8 +8,8 @@ import ( "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/wire" - lru "github.com/hashicorp/golang-lru" "github.com/pkg/errors" + "github.com/rs/zerolog" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/zeta-chain/node/zetaclient/db" @@ -63,40 +63,6 @@ func setupDBTxResults(t *testing.T) (*gorm.DB, map[string]btcjson.GetTransaction return database.Client(), submittedTx } -// MockBTCObserver creates a mock Bitcoin observer for testing -func MockBTCObserver( - t *testing.T, - chain chains.Chain, - params observertypes.ChainParams, - btcClient interfaces.BTCRPCClient, -) *observer.Observer { - // use default mock btc client if not provided - if btcClient == nil { - rpcClient := mocks.NewBTCRPCClient(t) - rpcClient.On("GetBlockCount").Return(int64(100), nil) - btcClient = rpcClient - } - - database, err := db.NewFromSqliteInMemory(true) - require.NoError(t, err) - - // create observer - ob, err := observer.NewObserver( - chain, - btcClient, - params, - nil, - nil, - 60, - database, - base.Logger{}, - nil, - ) - require.NoError(t, err) - - return ob -} - func Test_NewObserver(t *testing.T) { // use Bitcoin mainnet chain for testing chain := chains.BitcoinMainnet @@ -199,22 +165,15 @@ func Test_NewObserver(t *testing.T) { func Test_BlockCache(t *testing.T) { t.Run("should add and get block from cache", func(t *testing.T) { // create observer - ob := &observer.Observer{} - blockCache, err := lru.New(100) - require.NoError(t, err) - ob.WithBlockCache(blockCache) - - // create mock btc client - btcClient := mocks.NewBTCRPCClient(t) - ob.WithBtcClient(btcClient) + ob := newTestSuite(t, chains.BitcoinMainnet) // feed block hash, header and block to btc client hash := sample.BtcHash() header := &wire.BlockHeader{Version: 1} block := &btcjson.GetBlockVerboseTxResult{Version: 1} - btcClient.On("GetBlockHash", mock.Anything).Return(&hash, nil) - btcClient.On("GetBlockHeader", &hash).Return(header, nil) - btcClient.On("GetBlockVerboseTx", &hash).Return(block, nil) + ob.client.On("GetBlockHash", mock.Anything).Return(&hash, nil) + ob.client.On("GetBlockHeader", &hash).Return(header, nil) + ob.client.On("GetBlockVerboseTx", &hash).Return(block, nil) // get block and header from observer, fallback to btc client result, err := ob.GetBlockByNumberCached(100) @@ -230,14 +189,11 @@ func Test_BlockCache(t *testing.T) { }) t.Run("should fail if stored type is not BlockNHeader", func(t *testing.T) { // create observer - ob := &observer.Observer{} - blockCache, err := lru.New(100) - require.NoError(t, err) - ob.WithBlockCache(blockCache) + ob := newTestSuite(t, chains.BitcoinMainnet) // add a string to cache blockNumber := int64(100) - blockCache.Add(blockNumber, "a string value") + ob.BlockCache().Add(blockNumber, "a string value") // get result from cache result, err := ob.GetBlockByNumberCached(blockNumber) @@ -249,15 +205,10 @@ func Test_BlockCache(t *testing.T) { func Test_LoadLastBlockScanned(t *testing.T) { // use Bitcoin mainnet chain for testing chain := chains.BitcoinMainnet - params := mocks.MockChainParams(chain.ChainId, 10) - - // create mock btc client with block height 200 - btcClient := mocks.NewBTCRPCClient(t) - btcClient.On("GetBlockCount").Return(int64(200), nil) t.Run("should load last block scanned", func(t *testing.T) { // create observer and write 199 as last block scanned - ob := MockBTCObserver(t, chain, params, btcClient) + ob := newTestSuite(t, chain) ob.WriteLastBlockScannedToDB(199) // load last block scanned @@ -267,7 +218,7 @@ func Test_LoadLastBlockScanned(t *testing.T) { }) t.Run("should fail on invalid env var", func(t *testing.T) { // create observer - ob := MockBTCObserver(t, chain, params, btcClient) + ob := newTestSuite(t, chain) // set invalid environment variable envvar := base.EnvVarLatestBlockByChain(chain) @@ -280,15 +231,14 @@ func Test_LoadLastBlockScanned(t *testing.T) { }) t.Run("should fail on RPC error", func(t *testing.T) { // create observer on separate path, as we need to reset last block scanned - obOther := MockBTCObserver(t, chain, params, btcClient) + obOther := newTestSuite(t, chain) // reset last block scanned to 0 so that it will be loaded from RPC obOther.WithLastBlockScanned(0) // attach a mock btc client that returns rpc error - errClient := mocks.NewBTCRPCClient(t) - errClient.On("GetBlockCount").Return(int64(0), errors.New("rpc error")) - obOther.WithBtcClient(errClient) + obOther.client.ExpectedCalls = nil + obOther.client.On("GetBlockCount").Return(int64(0), errors.New("rpc error")) // load last block scanned err := obOther.LoadLastBlockScanned() @@ -296,8 +246,7 @@ func Test_LoadLastBlockScanned(t *testing.T) { }) t.Run("should use hardcode block 100 for regtest", func(t *testing.T) { // use regtest chain - regtest := chains.BitcoinRegtest - obRegnet := MockBTCObserver(t, regtest, params, btcClient) + obRegnet := newTestSuite(t, chains.BitcoinRegtest) // load last block scanned err := obRegnet.LoadLastBlockScanned() @@ -308,8 +257,7 @@ func Test_LoadLastBlockScanned(t *testing.T) { func TestConfirmationThreshold(t *testing.T) { chain := chains.BitcoinMainnet - params := mocks.MockChainParams(chain.ChainId, 10) - ob := MockBTCObserver(t, chain, params, nil) + ob := newTestSuite(t, chain) t.Run("should return confirmations in chain param", func(t *testing.T) { ob.SetChainParams(observertypes.ChainParams{ConfirmationCount: 3}) @@ -348,3 +296,47 @@ func TestSubmittedTx(t *testing.T) { require.Equal(t, want, have) } } + +type testSuite struct { + *observer.Observer + + client *mocks.BTCRPCClient + zetacore *mocks.ZetacoreClient + db *db.DB +} + +func newTestSuite(t *testing.T, chain chains.Chain) *testSuite { + require.True(t, chain.IsBitcoinChain()) + + chainParams := mocks.MockChainParams(chain.ChainId, 10) + + client := mocks.NewBTCRPCClient(t) + client.On("GetBlockCount").Return(int64(100), nil).Maybe() + + zetacore := mocks.NewZetacoreClient(t) + + database, err := db.NewFromSqliteInMemory(true) + require.NoError(t, err) + + log := zerolog.New(zerolog.NewTestWriter(t)) + + ob, err := observer.NewObserver( + chain, + client, + chainParams, + zetacore, + nil, + 60, + database, + base.Logger{Std: log, Compliance: log}, + nil, + ) + require.NoError(t, err) + + return &testSuite{ + Observer: ob, + client: client, + zetacore: zetacore, + db: database, + } +} diff --git a/zetaclient/chains/bitcoin/observer/outbound_test.go b/zetaclient/chains/bitcoin/observer/outbound_test.go index fd477e64bd..98b34ea435 100644 --- a/zetaclient/chains/bitcoin/observer/outbound_test.go +++ b/zetaclient/chains/bitcoin/observer/outbound_test.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/rs/zerolog" "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/zetaclient/chains/interfaces" "github.com/zeta-chain/node/zetaclient/db" "github.com/zeta-chain/node/pkg/chains" @@ -22,11 +23,14 @@ import ( var TestDataDir = "../../../" // MockBTCObserverMainnet creates a mock Bitcoin mainnet observer for testing -func MockBTCObserverMainnet(t *testing.T) *Observer { +func MockBTCObserverMainnet(t *testing.T, tss interfaces.TSSSigner) *Observer { // setup mock arguments chain := chains.BitcoinMainnet params := mocks.MockChainParams(chain.ChainId, 10) - tss := mocks.NewTSS(t).FakePubKey(testutils.TSSPubKeyMainnet) + + if tss == nil { + tss = mocks.NewTSS(t).FakePubKey(testutils.TSSPubKeyMainnet) + } // create mock rpc client btcClient := mocks.NewBTCRPCClient(t) @@ -53,8 +57,7 @@ func createObserverWithPrivateKey(t *testing.T) *Observer { tss := mocks.NewTSSFromPrivateKey(t, privateKey) // create Bitcoin observer with mock tss - ob := MockBTCObserverMainnet(t) - ob.WithTSS(tss) + ob := MockBTCObserverMainnet(t, tss) return ob } @@ -107,7 +110,7 @@ func TestCheckTSSVout(t *testing.T) { nonce := uint64(148) // create mainnet mock client - ob := MockBTCObserverMainnet(t) + ob := MockBTCObserverMainnet(t, nil) t.Run("valid TSS vout should pass", func(t *testing.T) { rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, TestDataDir, chainID, nonce) @@ -189,7 +192,7 @@ func TestCheckTSSVoutCancelled(t *testing.T) { nonce := uint64(148) // create mainnet mock client - ob := MockBTCObserverMainnet(t) + ob := MockBTCObserverMainnet(t, nil) t.Run("valid TSS vout should pass", func(t *testing.T) { // remove change vout to simulate cancelled tx diff --git a/zetaclient/chains/bitcoin/signer/signer.go b/zetaclient/chains/bitcoin/signer/signer.go index 1321b0c14f..c142756f2d 100644 --- a/zetaclient/chains/bitcoin/signer/signer.go +++ b/zetaclient/chains/bitcoin/signer/signer.go @@ -31,7 +31,6 @@ import ( "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" ) @@ -63,12 +62,11 @@ type Signer struct { func NewSigner( chain chains.Chain, tss interfaces.TSSSigner, - ts *metrics.TelemetryServer, logger base.Logger, cfg config.BTCConfig, ) (*Signer, error) { // create base signer - baseSigner := base.NewSigner(chain, tss, ts, logger) + baseSigner := base.NewSigner(chain, tss, logger) // create the bitcoin rpc client using the provided config connCfg := &rpcclient.ConnConfig{ diff --git a/zetaclient/chains/bitcoin/signer/signer_test.go b/zetaclient/chains/bitcoin/signer/signer_test.go index 131fbe963f..f06ad4a9c2 100644 --- a/zetaclient/chains/bitcoin/signer/signer_test.go +++ b/zetaclient/chains/bitcoin/signer/signer_test.go @@ -50,7 +50,6 @@ func (s *BTCSignerSuite) SetUpTest(c *C) { s.btcSigner, err = NewSigner( chains.Chain{}, tss, - nil, base.DefaultLogger(), config.BTCConfig{}, ) @@ -231,7 +230,6 @@ func TestAddWithdrawTxOutputs(t *testing.T) { signer, err := NewSigner( chains.BitcoinMainnet, mocks.NewTSS(t).FakePubKey(testutils.TSSPubKeyMainnet), - nil, base.DefaultLogger(), config.BTCConfig{}, ) @@ -392,7 +390,6 @@ func TestNewBTCSigner(t *testing.T) { btcSigner, err := NewSigner( chains.Chain{}, tss, - nil, base.DefaultLogger(), config.BTCConfig{}) require.NoError(t, err) diff --git a/zetaclient/chains/evm/observer/inbound_test.go b/zetaclient/chains/evm/observer/inbound_test.go index 1542e5fea1..e3b0a6e82c 100644 --- a/zetaclient/chains/evm/observer/inbound_test.go +++ b/zetaclient/chains/evm/observer/inbound_test.go @@ -1,7 +1,6 @@ package observer_test import ( - "context" "encoding/hex" "errors" "testing" @@ -9,17 +8,12 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/onrik/ethrpc" - "github.com/rs/zerolog" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - zctx "github.com/zeta-chain/node/zetaclient/context" - "github.com/zeta-chain/node/zetaclient/keys" - "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/zetaclient/chains/evm" - "github.com/zeta-chain/node/zetaclient/chains/interfaces" "github.com/zeta-chain/node/zetaclient/config" "github.com/zeta-chain/node/zetaclient/testutils" "github.com/zeta-chain/node/zetaclient/testutils/mocks" @@ -30,14 +24,12 @@ func Test_CheckAndVoteInboundTokenZeta(t *testing.T) { // load archived ZetaSent inbound, receipt and cctx // https://etherscan.io/tx/0xf3935200c80f98502d5edc7e871ffc40ca898e134525c42c2ae3cbc5725f9d76 chain := chains.Ethereum - confirmation := uint64(10) chainID := chain.ChainId - chainParam := mocks.MockChainParams(chain.ChainId, confirmation) inboundHash := "0xf3935200c80f98502d5edc7e871ffc40ca898e134525c42c2ae3cbc5725f9d76" - ctx, _ := makeAppContext(t) - t.Run("should pass for archived inbound, receipt and cctx", func(t *testing.T) { + ob := newTestSuite(t) + tx, receipt, cctx := testutils.LoadEVMInboundNReceiptNCctx( t, TestDataDir, @@ -46,16 +38,16 @@ func Test_CheckAndVoteInboundTokenZeta(t *testing.T) { coin.CoinType_Zeta, ) require.NoError(t, evm.ValidateEvmTransaction(tx)) - lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob, appContext := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - voteCtx := zctx.WithAppContext(context.Background(), appContext) + ob.WithLastBlock(receipt.BlockNumber.Uint64() + ob.chainParams.ConfirmationCount) - ballot, err := ob.CheckAndVoteInboundTokenZeta(voteCtx, tx, receipt, false) + ballot, err := ob.CheckAndVoteInboundTokenZeta(ob.ctx, tx, receipt, false) require.NoError(t, err) require.Equal(t, cctx.InboundParams.BallotIndex, ballot) }) t.Run("should fail on unconfirmed inbound", func(t *testing.T) { + ob := newTestSuite(t) + tx, receipt, _ := testutils.LoadEVMInboundNReceiptNCctx( t, TestDataDir, @@ -64,13 +56,15 @@ func Test_CheckAndVoteInboundTokenZeta(t *testing.T) { coin.CoinType_Zeta, ) require.NoError(t, evm.ValidateEvmTransaction(tx)) - lastBlock := receipt.BlockNumber.Uint64() + confirmation - 1 - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - _, err := ob.CheckAndVoteInboundTokenZeta(ctx, tx, receipt, false) + ob.WithLastBlock(receipt.BlockNumber.Uint64() + ob.chainParams.ConfirmationCount - 1) + + _, err := ob.CheckAndVoteInboundTokenZeta(ob.ctx, tx, receipt, false) require.ErrorContains(t, err, "not been confirmed") }) t.Run("should not act if no ZetaSent event", func(t *testing.T) { + ob := newTestSuite(t) + tx, receipt, _ := testutils.LoadEVMInboundNReceiptNCctx( t, TestDataDir, @@ -80,14 +74,18 @@ func Test_CheckAndVoteInboundTokenZeta(t *testing.T) { ) receipt.Logs = receipt.Logs[:2] // remove ZetaSent event require.NoError(t, evm.ValidateEvmTransaction(tx)) - lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - ballot, err := ob.CheckAndVoteInboundTokenZeta(ctx, tx, receipt, true) + ob.WithLastBlock(receipt.BlockNumber.Uint64() + ob.chainParams.ConfirmationCount) + + ballot, err := ob.CheckAndVoteInboundTokenZeta(ob.ctx, tx, receipt, true) require.NoError(t, err) require.Equal(t, "", ballot) }) t.Run("should not act if emitter is not ZetaConnector", func(t *testing.T) { + // Given observer with another chain to trigger logic for + // different evm address (based on mocked chain params) + ob := newTestSuite(t, func(cfg *testSuiteConfig) { cfg.chain = &chains.BscMainnet }) + // Given tx from ETH tx, receipt, _ := testutils.LoadEVMInboundNReceiptNCctx(t, TestDataDir, @@ -96,25 +94,11 @@ func Test_CheckAndVoteInboundTokenZeta(t *testing.T) { coin.CoinType_Zeta, ) require.NoError(t, evm.ValidateEvmTransaction(tx)) - lastBlock := receipt.BlockNumber.Uint64() + confirmation - // Given BSC observer - chain := chains.BscMainnet - params := mocks.MockChainParams(chain.ChainId, confirmation) - - ob, _ := MockEVMObserver( - t, - chain, - nil, - nil, - nil, - nil, - lastBlock, - params, - ) + ob.WithLastBlock(receipt.BlockNumber.Uint64() + ob.chainParams.ConfirmationCount) // ACT - _, err := ob.CheckAndVoteInboundTokenZeta(ctx, tx, receipt, true) + _, err := ob.CheckAndVoteInboundTokenZeta(ob.ctx, tx, receipt, true) // ASSERT require.ErrorContains(t, err, "emitter address mismatch") @@ -125,14 +109,12 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) { // load archived ERC20 inbound, receipt and cctx // https://etherscan.io/tx/0x4ea69a0e2ff36f7548ab75791c3b990e076e2a4bffeb616035b239b7d33843da chain := chains.Ethereum - confirmation := uint64(10) chainID := chain.ChainId - chainParam := mocks.MockChainParams(chain.ChainId, confirmation) inboundHash := "0x4ea69a0e2ff36f7548ab75791c3b990e076e2a4bffeb616035b239b7d33843da" - ctx := context.Background() - t.Run("should pass for archived inbound, receipt and cctx", func(t *testing.T) { + ob := newTestSuite(t) + tx, receipt, cctx := testutils.LoadEVMInboundNReceiptNCctx( t, TestDataDir, @@ -141,14 +123,16 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) { coin.CoinType_ERC20, ) require.NoError(t, evm.ValidateEvmTransaction(tx)) - lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - ballot, err := ob.CheckAndVoteInboundTokenERC20(ctx, tx, receipt, false) + ob.WithLastBlock(receipt.BlockNumber.Uint64() + ob.chainParams.ConfirmationCount) + + ballot, err := ob.CheckAndVoteInboundTokenERC20(ob.ctx, tx, receipt, false) require.NoError(t, err) require.Equal(t, cctx.InboundParams.BallotIndex, ballot) }) t.Run("should fail on unconfirmed inbound", func(t *testing.T) { + ob := newTestSuite(t) + tx, receipt, _ := testutils.LoadEVMInboundNReceiptNCctx( t, TestDataDir, @@ -157,13 +141,15 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) { coin.CoinType_ERC20, ) require.NoError(t, evm.ValidateEvmTransaction(tx)) - lastBlock := receipt.BlockNumber.Uint64() + confirmation - 1 - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - _, err := ob.CheckAndVoteInboundTokenERC20(ctx, tx, receipt, false) + ob.WithLastBlock(receipt.BlockNumber.Uint64() + ob.chainParams.ConfirmationCount - 1) + + _, err := ob.CheckAndVoteInboundTokenERC20(ob.ctx, tx, receipt, false) require.ErrorContains(t, err, "not been confirmed") }) t.Run("should not act if no Deposit event", func(t *testing.T) { + ob := newTestSuite(t) + tx, receipt, _ := testutils.LoadEVMInboundNReceiptNCctx( t, TestDataDir, @@ -173,15 +159,18 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) { ) receipt.Logs = receipt.Logs[:1] // remove Deposit event require.NoError(t, evm.ValidateEvmTransaction(tx)) - lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - ballot, err := ob.CheckAndVoteInboundTokenERC20(ctx, tx, receipt, true) + ob.WithLastBlock(receipt.BlockNumber.Uint64() + ob.chainParams.ConfirmationCount) + + ballot, err := ob.CheckAndVoteInboundTokenERC20(ob.ctx, tx, receipt, true) require.NoError(t, err) require.Equal(t, "", ballot) }) t.Run("should not act if emitter is not ERC20 Custody", func(t *testing.T) { // ARRANGE + // Given observer with different chain (thus chain params) to have different evm addresses + ob := newTestSuite(t, func(cfg *testSuiteConfig) { cfg.chain = &chains.BscMainnet }) + // Given tx from ETH tx, receipt, _ := testutils.LoadEVMInboundNReceiptNCctx( t, @@ -191,25 +180,11 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) { coin.CoinType_ERC20, ) require.NoError(t, evm.ValidateEvmTransaction(tx)) - lastBlock := receipt.BlockNumber.Uint64() + confirmation - // Given BSC observer - chain := chains.BscMainnet - params := mocks.MockChainParams(chain.ChainId, confirmation) - - ob, _ := MockEVMObserver( - t, - chain, - nil, - nil, - nil, - nil, - lastBlock, - params, - ) + ob.WithLastBlock(receipt.BlockNumber.Uint64() + ob.chainParams.ConfirmationCount) // ACT - _, err := ob.CheckAndVoteInboundTokenERC20(ctx, tx, receipt, true) + _, err := ob.CheckAndVoteInboundTokenERC20(ob.ctx, tx, receipt, true) // ASSERT require.ErrorContains(t, err, "emitter address mismatch") @@ -222,11 +197,8 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { chain := chains.Ethereum confirmation := uint64(10) chainID := chain.ChainId - chainParam := mocks.MockChainParams(chain.ChainId, confirmation) inboundHash := "0xeaec67d5dd5d85f27b21bef83e01cbdf59154fd793ea7a22c297f7c3a722c532" - ctx := context.Background() - t.Run("should pass for archived inbound, receipt and cctx", func(t *testing.T) { tx, receipt, cctx := testutils.LoadEVMInboundNReceiptNCctx( t, @@ -238,8 +210,10 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - ballot, err := ob.CheckAndVoteInboundTokenGas(ctx, tx, receipt, false) + ob := newTestSuite(t) + ob.WithLastBlock(lastBlock) + + ballot, err := ob.CheckAndVoteInboundTokenGas(ob.ctx, tx, receipt, false) require.NoError(t, err) require.Equal(t, cctx.InboundParams.BallotIndex, ballot) }) @@ -248,8 +222,10 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - 1 - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - _, err := ob.CheckAndVoteInboundTokenGas(ctx, tx, receipt, false) + ob := newTestSuite(t) + ob.WithLastBlock(lastBlock) + + _, err := ob.CheckAndVoteInboundTokenGas(ob.ctx, tx, receipt, false) require.ErrorContains(t, err, "not been confirmed") }) t.Run("should not act if receiver is not TSS", func(t *testing.T) { @@ -258,8 +234,10 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - ballot, err := ob.CheckAndVoteInboundTokenGas(ctx, tx, receipt, false) + ob := newTestSuite(t) + ob.WithLastBlock(lastBlock) + + ballot, err := ob.CheckAndVoteInboundTokenGas(ob.ctx, tx, receipt, false) require.ErrorContains(t, err, "not TSS address") require.Equal(t, "", ballot) }) @@ -269,8 +247,10 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - ballot, err := ob.CheckAndVoteInboundTokenGas(ctx, tx, receipt, false) + ob := newTestSuite(t) + ob.WithLastBlock(lastBlock) + + ballot, err := ob.CheckAndVoteInboundTokenGas(ob.ctx, tx, receipt, false) require.ErrorContains(t, err, "not a successful tx") require.Equal(t, "", ballot) }) @@ -280,8 +260,10 @@ func Test_CheckAndVoteInboundTokenGas(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(tx)) lastBlock := receipt.BlockNumber.Uint64() + confirmation - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam) - ballot, err := ob.CheckAndVoteInboundTokenGas(ctx, tx, receipt, false) + ob := newTestSuite(t) + ob.WithLastBlock(lastBlock) + + ballot, err := ob.CheckAndVoteInboundTokenGas(ob.ctx, tx, receipt, false) require.NoError(t, err) require.Equal(t, "", ballot) }) @@ -291,13 +273,13 @@ func Test_BuildInboundVoteMsgForZetaSentEvent(t *testing.T) { // load archived ZetaSent receipt // https://etherscan.io/tx/0xf3935200c80f98502d5edc7e871ffc40ca898e134525c42c2ae3cbc5725f9d76 chainID := int64(1) - chain := chains.Ethereum inboundHash := "0xf3935200c80f98502d5edc7e871ffc40ca898e134525c42c2ae3cbc5725f9d76" receipt := testutils.LoadEVMInboundReceipt(t, TestDataDir, chainID, inboundHash, coin.CoinType_Zeta) cctx := testutils.LoadCctxByInbound(t, chainID, coin.CoinType_Zeta, inboundHash) // parse ZetaSent event - ob, app := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, mocks.MockChainParams(1, 1)) + ob := newTestSuite(t) + connector := mocks.MockConnectorNonEth(t, chainID) event := testutils.ParseReceiptZetaSent(receipt, connector) @@ -307,7 +289,7 @@ func Test_BuildInboundVoteMsgForZetaSentEvent(t *testing.T) { } t.Run("should return vote msg for archived ZetaSent event", func(t *testing.T) { - msg := ob.BuildInboundVoteMsgForZetaSentEvent(app, event) + msg := ob.BuildInboundVoteMsgForZetaSentEvent(ob.appContext, event) require.NotNil(t, msg) require.Equal(t, cctx.InboundParams.BallotIndex, msg.Digest()) }) @@ -315,21 +297,21 @@ func Test_BuildInboundVoteMsgForZetaSentEvent(t *testing.T) { sender := event.ZetaTxSenderAddress.Hex() cfg.ComplianceConfig.RestrictedAddresses = []string{sender} config.LoadComplianceConfig(cfg) - msg := ob.BuildInboundVoteMsgForZetaSentEvent(app, event) + msg := ob.BuildInboundVoteMsgForZetaSentEvent(ob.appContext, event) require.Nil(t, msg) }) t.Run("should return nil msg if receiver is restricted", func(t *testing.T) { receiver := clienttypes.BytesToEthHex(event.DestinationAddress) cfg.ComplianceConfig.RestrictedAddresses = []string{receiver} config.LoadComplianceConfig(cfg) - msg := ob.BuildInboundVoteMsgForZetaSentEvent(app, event) + msg := ob.BuildInboundVoteMsgForZetaSentEvent(ob.appContext, event) require.Nil(t, msg) }) t.Run("should return nil msg if txOrigin is restricted", func(t *testing.T) { txOrigin := event.SourceTxOriginAddress.Hex() cfg.ComplianceConfig.RestrictedAddresses = []string{txOrigin} config.LoadComplianceConfig(cfg) - msg := ob.BuildInboundVoteMsgForZetaSentEvent(app, event) + msg := ob.BuildInboundVoteMsgForZetaSentEvent(ob.appContext, event) require.Nil(t, msg) }) } @@ -344,7 +326,7 @@ func Test_BuildInboundVoteMsgForDepositedEvent(t *testing.T) { cctx := testutils.LoadCctxByInbound(t, chainID, coin.CoinType_ERC20, inboundHash) // parse Deposited event - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, mocks.MockChainParams(1, 1)) + ob := newTestSuite(t) custody := mocks.MockERC20Custody(t, chainID) event := testutils.ParseReceiptERC20Deposited(receipt, custody) sender := ethcommon.HexToAddress(tx.From) @@ -402,7 +384,7 @@ func Test_BuildInboundVoteMsgForTokenSentToTSS(t *testing.T) { require.NoError(t, evm.ValidateEvmTransaction(txDonation)) // create test compliance config - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, mocks.MockChainParams(1, 1)) + ob := newTestSuite(t) cfg := config.Config{ ComplianceConfig: config.ComplianceConfig{}, } @@ -451,8 +433,6 @@ func Test_ObserveTSSReceiveInBlock(t *testing.T) { // https://etherscan.io/tx/0xeaec67d5dd5d85f27b21bef83e01cbdf59154fd793ea7a22c297f7c3a722c532 chain := chains.Ethereum chainID := chain.ChainId - confirmation := uint64(1) - chainParam := mocks.MockChainParams(chain.ChainId, confirmation) inboundHash := "0xeaec67d5dd5d85f27b21bef83e01cbdf59154fd793ea7a22c297f7c3a722c532" // load archived tx and receipt @@ -464,77 +444,68 @@ func Test_ObserveTSSReceiveInBlock(t *testing.T) { blockNumber := receipt.BlockNumber.Uint64() block := testutils.LoadEVMBlock(t, TestDataDir, chainID, blockNumber, true) - // create mock zetacore client - tss := mocks.NewTSS(t).FakePubKey(testutils.TSSPubKeyMainnet) - lastBlock := receipt.BlockNumber.Uint64() + confirmation - zetacoreClient := mocks.NewZetacoreClient(t). - WithKeys(&keys.Keys{}). - WithZetaChain(). - WithPostVoteInbound("", ""). - WithPostVoteInbound("", "") - // test cases tests := []struct { - name string - evmClient interfaces.EVMRPCClient - jsonClient interfaces.EVMJSONRPCClient - errMsg string + name string + mockEVMClient func(m *mocks.EVMRPCClient) + mockJSONClient func(m *mocks.MockJSONRPCClient) + errMsg string }{ { name: "should observe TSS receive in block", - evmClient: func() interfaces.EVMRPCClient { + mockEVMClient: func(m *mocks.EVMRPCClient) { // feed block number and receipt to mock client - evmClient := mocks.NewEVMRPCClient(t) - evmClient.On("BlockNumber", mock.Anything).Return(uint64(1000), nil) - evmClient.On("TransactionReceipt", mock.Anything, mock.Anything).Return(receipt, nil) - return evmClient - }(), - jsonClient: mocks.NewMockJSONRPCClient().WithBlock(block), - errMsg: "", + m.On("BlockNumber", mock.Anything).Return(uint64(1000), nil) + m.On("TransactionReceipt", mock.Anything, mock.Anything).Return(receipt, nil) + }, + mockJSONClient: func(m *mocks.MockJSONRPCClient) { + m.WithBlock(block) + }, + errMsg: "", }, { name: "should not observe on error getting block", - evmClient: func() interfaces.EVMRPCClient { + mockEVMClient: func(m *mocks.EVMRPCClient) { // feed block number to allow construction of observer - evmClient := mocks.NewEVMRPCClient(t) - evmClient.On("BlockNumber", mock.Anything).Return(uint64(1000), nil) - return evmClient - }(), - jsonClient: mocks.NewMockJSONRPCClient(), // no block - errMsg: "error getting block", + m.On("BlockNumber", mock.Anything).Return(uint64(1000), nil) + }, + mockJSONClient: nil, // no block + errMsg: "error getting block", }, { name: "should not observe on error getting receipt", - evmClient: func() interfaces.EVMRPCClient { + mockEVMClient: func(m *mocks.EVMRPCClient) { // feed block number but RPC error on getting receipt - evmClient := mocks.NewEVMRPCClient(t) - evmClient.On("BlockNumber", mock.Anything).Return(uint64(1000), nil) - evmClient.On("TransactionReceipt", mock.Anything, mock.Anything).Return(nil, errors.New("RPC error")) - return evmClient - }(), - jsonClient: mocks.NewMockJSONRPCClient().WithBlock(block), - errMsg: "error getting receipt", + m.On("BlockNumber", mock.Anything).Return(uint64(1000), nil) + m.On("TransactionReceipt", mock.Anything, mock.Anything).Return(nil, errors.New("RPC error")) + }, + mockJSONClient: func(m *mocks.MockJSONRPCClient) { + m.WithBlock(block) + }, + errMsg: "error getting receipt", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ob, _ := MockEVMObserver(t, chain, tt.evmClient, tt.jsonClient, zetacoreClient, tss, lastBlock, chainParam) - err := ob.ObserveTSSReceiveInBlock(context.Background(), blockNumber) + ob := newTestSuite(t) + ob.WithLastBlock(receipt.BlockNumber.Uint64() + ob.chainParams.ConfirmationCount) + + if tt.mockEVMClient != nil { + tt.mockEVMClient(ob.evmClient) + } + + if tt.mockJSONClient != nil { + tt.mockJSONClient(ob.rpcClient) + } + + err := ob.ObserveTSSReceiveInBlock(ob.ctx, blockNumber) if tt.errMsg != "" { require.ErrorContains(t, err, tt.errMsg) - } else { - require.NoError(t, err) + return } + + require.NoError(t, err) }) } } - -func makeAppContext(t *testing.T) (context.Context, *zctx.AppContext) { - var ( - app = zctx.New(config.New(false), nil, zerolog.New(zerolog.NewTestWriter(t))) - ctx = context.Background() - ) - - return zctx.WithAppContext(ctx, app), app -} diff --git a/zetaclient/chains/evm/observer/observer.go b/zetaclient/chains/evm/observer/observer.go index 06f2df0506..79ffd40545 100644 --- a/zetaclient/chains/evm/observer/observer.go +++ b/zetaclient/chains/evm/observer/observer.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "math" - "math/big" "strings" ethcommon "github.com/ethereum/go-ethereum/common" @@ -82,7 +81,6 @@ func NewObserver( zetacoreClient, tss, base.DefaultBlockCacheSize, - base.DefaultHeaderCacheSize, rpcAlertLatency, ts, database, @@ -110,16 +108,6 @@ func NewObserver( return ob, nil } -// WithEvmClient attaches a new evm client to the observer -func (ob *Observer) WithEvmClient(client interfaces.EVMRPCClient) { - ob.evmClient = client -} - -// WithEvmJSONRPC attaches a new evm json rpc client to the observer -func (ob *Observer) WithEvmJSONRPC(client interfaces.EVMJSONRPCClient) { - ob.evmJSONRPC = client -} - // GetConnectorContract returns the non-Eth connector address and binder func (ob *Observer) GetConnectorContract() (ethcommon.Address, *zetaconnector.ZetaConnectorNonEth, error) { addr := ethcommon.HexToAddress(ob.ChainParams().ConnectorContractAddress) @@ -255,20 +243,8 @@ func (ob *Observer) TransactionByHash(txHash string) (*ethrpc.Transaction, bool, return tx, tx.BlockNumber == nil, nil } -// GetBlockHeaderCached get block header by number from cache -func (ob *Observer) GetBlockHeaderCached(ctx context.Context, blockNumber uint64) (*ethtypes.Header, error) { - if result, ok := ob.HeaderCache().Get(blockNumber); ok { - if header, ok := result.(*ethtypes.Header); ok { - return header, nil - } - return nil, errors.New("cached value is not of type *ethtypes.Header") - } - header, err := ob.evmClient.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber)) - if err != nil { - return nil, err - } - ob.HeaderCache().Add(blockNumber, header) - return header, nil +func (ob *Observer) TransactionReceipt(ctx context.Context, hash ethcommon.Hash) (*ethtypes.Receipt, error) { + return ob.evmClient.TransactionReceipt(ctx, hash) } // GetBlockByNumberCached get block by number from cache diff --git a/zetaclient/chains/evm/observer/observer_gas_test.go b/zetaclient/chains/evm/observer/observer_gas_test.go index da64d32972..d2a61f1e3e 100644 --- a/zetaclient/chains/evm/observer/observer_gas_test.go +++ b/zetaclient/chains/evm/observer/observer_gas_test.go @@ -8,41 +8,27 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/zeta-chain/node/pkg/chains" - "github.com/zeta-chain/node/zetaclient/testutils/mocks" ) func TestPostGasPrice(t *testing.T) { const ( - gwei = 10e9 - blockNumber = 1000 - anything = mock.Anything + gwei = 10e9 + anything = mock.Anything ) ctx := context.Background() t.Run("Pre EIP-1559 doesn't support priorityFee", func(t *testing.T) { // ARRANGE - // Given ETH rpc mock - ethRPC := mocks.NewEVMRPCClient(t) - ethRPC.On("BlockNumber", mock.Anything).Return(uint64(blockNumber), nil) - - // Given zetacore client mock - zetacoreClient := mocks.NewZetacoreClient(t).WithZetaChain() - // Given an observer - chain := chains.Ethereum - confirmation := uint64(10) - chainParam := mocks.MockChainParams(chain.ChainId, confirmation) - - observer, _ := MockEVMObserver(t, chain, ethRPC, nil, zetacoreClient, nil, blockNumber, chainParam) + observer := newTestSuite(t) // Given empty baseFee from RPC - ethRPC.On("HeaderByNumber", anything, anything).Return(ðtypes.Header{BaseFee: nil}, nil) + observer.evmClient.On("HeaderByNumber", anything, anything).Return(ðtypes.Header{BaseFee: nil}, nil) // Given gasPrice and priorityFee from RPC - ethRPC.On("SuggestGasPrice", anything).Return(big.NewInt(3*gwei), nil) - ethRPC.On("SuggestGasTipCap", anything).Return(big.NewInt(0), nil) + observer.evmClient.On("SuggestGasPrice", anything).Return(big.NewInt(3*gwei), nil) + observer.evmClient.On("SuggestGasTipCap", anything).Return(big.NewInt(0), nil) // Given mock collector for zetacore call // PostVoteGasPrice(ctx, chain, gasPrice, priorityFee, blockNum) @@ -52,7 +38,7 @@ func TestPostGasPrice(t *testing.T) { priorityFee = args.Get(3).(uint64) } - zetacoreClient. + observer.zetacore. On("PostVoteGasPrice", anything, anything, anything, anything, anything). Run(collector). Return("0xABC123...", nil) @@ -70,26 +56,16 @@ func TestPostGasPrice(t *testing.T) { t.Run("Post EIP-1559 supports priorityFee", func(t *testing.T) { // ARRANGE - // Given ETH rpc mock - ethRPC := mocks.NewEVMRPCClient(t) - ethRPC.On("BlockNumber", mock.Anything).Return(uint64(blockNumber), nil) - - // Given zetacore client mock - zetacoreClient := mocks.NewZetacoreClient(t).WithZetaChain() - // Given an observer - chain := chains.Ethereum - confirmation := uint64(10) - chainParam := mocks.MockChainParams(chain.ChainId, confirmation) - - observer, _ := MockEVMObserver(t, chain, ethRPC, nil, zetacoreClient, nil, blockNumber, chainParam) + observer := newTestSuite(t) // Given 1 gwei baseFee from RPC - ethRPC.On("HeaderByNumber", anything, anything).Return(ðtypes.Header{BaseFee: big.NewInt(gwei)}, nil) + observer.evmClient.On("HeaderByNumber", anything, anything). + Return(ðtypes.Header{BaseFee: big.NewInt(gwei)}, nil) // Given gasPrice and priorityFee from RPC - ethRPC.On("SuggestGasPrice", anything).Return(big.NewInt(3*gwei), nil) - ethRPC.On("SuggestGasTipCap", anything).Return(big.NewInt(2*gwei), nil) + observer.evmClient.On("SuggestGasPrice", anything).Return(big.NewInt(3*gwei), nil) + observer.evmClient.On("SuggestGasTipCap", anything).Return(big.NewInt(2*gwei), nil) // Given mock collector for zetacore call // PostVoteGasPrice(ctx, chain, gasPrice, priorityFee, blockNum) @@ -99,7 +75,7 @@ func TestPostGasPrice(t *testing.T) { priorityFee = args.Get(3).(uint64) } - zetacoreClient. + observer.zetacore. On("PostVoteGasPrice", anything, anything, anything, anything, anything). Run(collector). Return("0xABC123...", nil) diff --git a/zetaclient/chains/evm/observer/observer_test.go b/zetaclient/chains/evm/observer/observer_test.go index e8fc39b9fc..10fbaced9f 100644 --- a/zetaclient/chains/evm/observer/observer_test.go +++ b/zetaclient/chains/evm/observer/observer_test.go @@ -3,13 +3,10 @@ package observer_test import ( "context" "fmt" - "math/big" "os" "testing" "cosmossdk.io/math" - ethtypes "github.com/ethereum/go-ethereum/core/types" - lru "github.com/hashicorp/golang-lru" "github.com/onrik/ethrpc" "github.com/rs/zerolog" "github.com/stretchr/testify/mock" @@ -80,72 +77,6 @@ func getAppContext( return appContext, cfg.EVMChainConfigs[evmChain.ChainId] } -// MockEVMObserver creates a mock ChainObserver with custom chain, TSS, params etc -func MockEVMObserver( - t *testing.T, - chain chains.Chain, - evmClient interfaces.EVMRPCClient, - evmJSONRPC interfaces.EVMJSONRPCClient, - zetacoreClient interfaces.ZetacoreClient, - tss interfaces.TSSSigner, - lastBlock uint64, - params observertypes.ChainParams, -) (*observer.Observer, *zctx.AppContext) { - ctx := context.Background() - - // use default mock evm client if not provided - if evmClient == nil { - evmClientDefault := mocks.NewEVMRPCClient(t) - evmClientDefault.On("BlockNumber", mock.Anything).Return(uint64(1000), nil) - evmClient = evmClientDefault - } - - // use default mock evm client if not provided - if evmJSONRPC == nil { - evmJSONRPC = mocks.NewMockJSONRPCClient() - } - - // use default mock zetacore client if not provided - if zetacoreClient == nil { - zetacoreClient = mocks.NewZetacoreClient(t). - WithKeys(&keys.Keys{}). - WithZetaChain(). - WithPostVoteInbound("", ""). - WithPostVoteOutbound("", "") - } - // use default mock tss if not provided - if tss == nil { - tss = mocks.NewTSS(t).FakePubKey(testutils.TSSPubKeyMainnet) - } - // create AppContext - appContext, _ := getAppContext(t, chain, "", ¶ms) - - database, err := db.NewFromSqliteInMemory(true) - require.NoError(t, err) - - testLogger := zerolog.New(zerolog.NewTestWriter(t)) - logger := base.Logger{Std: testLogger, Compliance: testLogger} - - // create observer - ob, err := observer.NewObserver( - ctx, - chain, - evmClient, - evmJSONRPC, - params, - zetacoreClient, - tss, - 60, - database, - logger, - nil, - ) - require.NoError(t, err) - ob.WithLastBlock(lastBlock) - - return ob, appContext -} - func Test_NewObserver(t *testing.T) { ctx := context.Background() @@ -274,14 +205,9 @@ func Test_NewObserver(t *testing.T) { func Test_LoadLastBlockScanned(t *testing.T) { ctx := context.Background() - // use Ethereum chain for testing - chain := chains.Ethereum - params := mocks.MockChainParams(chain.ChainId, 10) - // create observer using mock evm client - evmClient := mocks.NewEVMRPCClient(t) - evmClient.On("BlockNumber", mock.Anything).Return(uint64(100), nil) - ob, _ := MockEVMObserver(t, chain, evmClient, nil, nil, nil, 1, params) + ob := newTestSuite(t) + ob.evmClient.On("BlockNumber", mock.Anything).Return(uint64(100), nil) t.Run("should load last block scanned", func(t *testing.T) { // create db and write 123 as last block scanned @@ -294,7 +220,7 @@ func Test_LoadLastBlockScanned(t *testing.T) { }) t.Run("should fail on invalid env var", func(t *testing.T) { // set invalid environment variable - envvar := base.EnvVarLatestBlockByChain(chain) + envvar := base.EnvVarLatestBlockByChain(ob.Chain()) os.Setenv(envvar, "invalid") defer os.Unsetenv(envvar) @@ -304,17 +230,14 @@ func Test_LoadLastBlockScanned(t *testing.T) { }) t.Run("should fail on RPC error", func(t *testing.T) { // create observer on separate path, as we need to reset last block scanned - obOther, _ := MockEVMObserver(t, chain, evmClient, nil, nil, nil, 1, params) + obOther := newTestSuite(t) // reset last block scanned to 0 so that it will be loaded from RPC obOther.WithLastBlockScanned(0) - // create mock evm client with RPC error - evmClient := mocks.NewEVMRPCClient(t) - evmClient.On("BlockNumber", mock.Anything).Return(uint64(0), fmt.Errorf("error RPC")) - // attach mock evm client to observer - obOther.WithEvmClient(evmClient) + obOther.evmClient.On("BlockNumber", mock.Anything).Unset() + obOther.evmClient.On("BlockNumber", mock.Anything).Return(uint64(0), fmt.Errorf("error RPC")) // load last block scanned err := obOther.LoadLastBlockScanned(ctx) @@ -325,109 +248,54 @@ func Test_LoadLastBlockScanned(t *testing.T) { func Test_BlockCache(t *testing.T) { t.Run("should get block from cache", func(t *testing.T) { // create observer - ob := &observer.Observer{} - blockCache, err := lru.New(100) - require.NoError(t, err) - ob.WithBlockCache(blockCache) - - // create mock evm client - JSONRPC := mocks.NewMockJSONRPCClient() - ob.WithEvmJSONRPC(JSONRPC) + ts := newTestSuite(t) // feed block to JSON rpc client block := ðrpc.Block{Number: 100} - JSONRPC.WithBlock(block) + ts.rpcClient.WithBlock(block) // get block header from observer, fallback to JSON RPC - result, err := ob.GetBlockByNumberCached(uint64(100)) + result, err := ts.Observer.GetBlockByNumberCached(uint64(100)) require.NoError(t, err) require.EqualValues(t, block, result) // get block header from cache - result, err = ob.GetBlockByNumberCached(uint64(100)) + result, err = ts.Observer.GetBlockByNumberCached(uint64(100)) require.NoError(t, err) require.EqualValues(t, block, result) }) t.Run("should fail if stored type is not block", func(t *testing.T) { // create observer - ob := &observer.Observer{} - blockCache, err := lru.New(100) - require.NoError(t, err) - ob.WithBlockCache(blockCache) + ts := newTestSuite(t) // add a string to cache blockNumber := uint64(100) - blockCache.Add(blockNumber, "a string value") + ts.BlockCache().Add(blockNumber, "a string value") // get result header from cache - result, err := ob.GetBlockByNumberCached(blockNumber) + result, err := ts.Observer.GetBlockByNumberCached(blockNumber) require.ErrorContains(t, err, "cached value is not of type *ethrpc.Block") require.Nil(t, result) }) t.Run("should be able to remove block from cache", func(t *testing.T) { // create observer - ob := &observer.Observer{} - blockCache, err := lru.New(100) - require.NoError(t, err) - ob.WithBlockCache(blockCache) + ts := newTestSuite(t) // delete non-existing block should not panic blockNumber := uint64(123) - ob.RemoveCachedBlock(blockNumber) + ts.RemoveCachedBlock(blockNumber) // add a block block := ðrpc.Block{Number: 123} - blockCache.Add(blockNumber, block) - ob.WithBlockCache(blockCache) + ts.BlockCache().Add(blockNumber, block) // block should be in cache - result, err := ob.GetBlockByNumberCached(blockNumber) + result, err := ts.GetBlockByNumberCached(blockNumber) require.NoError(t, err) require.EqualValues(t, block, result) // delete the block should not panic - ob.RemoveCachedBlock(blockNumber) - }) -} - -func Test_HeaderCache(t *testing.T) { - ctx := context.Background() - - t.Run("should get block header from cache", func(t *testing.T) { - // create observer - ob := &observer.Observer{} - headerCache, err := lru.New(100) - require.NoError(t, err) - ob.WithHeaderCache(headerCache) - - // create mock evm client - evmClient := mocks.NewEVMRPCClient(t) - ob.WithEvmClient(evmClient) - - // feed block header to evm client - header := ðtypes.Header{Number: big.NewInt(100)} - evmClient.On("HeaderByNumber", mock.Anything, mock.Anything).Return(header, nil) - - // get block header from observer - resHeader, err := ob.GetBlockHeaderCached(ctx, uint64(100)) - require.NoError(t, err) - require.EqualValues(t, header, resHeader) - }) - t.Run("should fail if stored type is not block header", func(t *testing.T) { - // create observer - ob := &observer.Observer{} - headerCache, err := lru.New(100) - require.NoError(t, err) - ob.WithHeaderCache(headerCache) - - // add a string to cache - blockNumber := uint64(100) - headerCache.Add(blockNumber, "a string value") - - // get block header from cache - header, err := ob.GetBlockHeaderCached(ctx, blockNumber) - require.ErrorContains(t, err, "cached value is not of type *ethtypes.Header") - require.Nil(t, header) + ts.RemoveCachedBlock(blockNumber) }) } @@ -444,17 +312,14 @@ func Test_CheckTxInclusion(t *testing.T) { blockNumber := receipt.BlockNumber.Uint64() block := testutils.LoadEVMBlock(t, TestDataDir, chainID, blockNumber, true) - // create client - blockCache, err := lru.New(1000) - require.NoError(t, err) - ob := &observer.Observer{} + // create observer + ts := newTestSuite(t) // save block to cache - blockCache.Add(blockNumber, block) - ob.WithBlockCache(blockCache) + ts.BlockCache().Add(blockNumber, block) t.Run("should pass for archived outbound", func(t *testing.T) { - err := ob.CheckTxInclusion(tx, receipt) + err := ts.CheckTxInclusion(tx, receipt) require.NoError(t, err) }) t.Run("should fail on tx index out of range", func(t *testing.T) { @@ -462,22 +327,21 @@ func Test_CheckTxInclusion(t *testing.T) { copyReceipt := *receipt // #nosec G115 non negative value copyReceipt.TransactionIndex = uint(len(block.Transactions)) - err := ob.CheckTxInclusion(tx, ©Receipt) + err := ts.CheckTxInclusion(tx, ©Receipt) require.ErrorContains(t, err, "out of range") }) t.Run("should fail on tx hash mismatch", func(t *testing.T) { // change the tx at position 'receipt.TransactionIndex' to a different tx priorTx := block.Transactions[receipt.TransactionIndex-1] block.Transactions[receipt.TransactionIndex] = priorTx - blockCache.Add(blockNumber, block) - ob.WithBlockCache(blockCache) + ts.BlockCache().Add(blockNumber, block) // check inclusion should fail - err := ob.CheckTxInclusion(tx, receipt) + err := ts.CheckTxInclusion(tx, receipt) require.ErrorContains(t, err, "has different hash") // wrong block should be removed from cache - _, ok := blockCache.Get(blockNumber) + _, ok := ts.BlockCache().Get(blockNumber) require.False(t, ok) }) } @@ -511,3 +375,81 @@ func Test_VoteOutboundBallot(t *testing.T) { require.Equal(t, ballotExpected, msg.Digest()) }) } + +type testSuite struct { + *observer.Observer + ctx context.Context + appContext *zctx.AppContext + chainParams *observertypes.ChainParams + tss *mocks.TSS + zetacore *mocks.ZetacoreClient + rpcClient *mocks.MockJSONRPCClient + evmClient *mocks.EVMRPCClient +} + +type testSuiteConfig struct { + chain *chains.Chain +} + +func newTestSuite(t *testing.T, opts ...func(*testSuiteConfig)) *testSuite { + var cfg testSuiteConfig + for _, opt := range opts { + opt(&cfg) + } + + chain := chains.Ethereum + if cfg.chain != nil { + chain = *cfg.chain + } + + chainParams := mocks.MockChainParams(chain.ChainId, 10) + + appContext, _ := getAppContext(t, chain, "", &chainParams) + ctx := zctx.WithAppContext(context.Background(), appContext) + + evmClient := mocks.NewEVMRPCClient(t) + evmClient.On("BlockNumber", mock.Anything).Return(uint64(1000), nil) + + rpcClient := mocks.NewMockJSONRPCClient() + + zetacore := mocks.NewZetacoreClient(t). + WithKeys(&keys.Keys{}). + WithZetaChain(). + WithPostVoteInbound("", ""). + WithPostVoteOutbound("", "") + + tss := mocks.NewTSS(t).FakePubKey(testutils.TSSPubKeyMainnet) + + database, err := db.NewFromSqliteInMemory(true) + require.NoError(t, err) + + log := zerolog.New(zerolog.NewTestWriter(t)).With().Caller().Logger() + logger := base.Logger{Std: log, Compliance: log} + + ob, err := observer.NewObserver( + ctx, + chain, + evmClient, + rpcClient, + chainParams, + zetacore, + tss, + 60, + database, + logger, + nil, + ) + require.NoError(t, err) + ob.WithLastBlock(1) + + return &testSuite{ + Observer: ob, + ctx: ctx, + appContext: appContext, + chainParams: &chainParams, + tss: tss, + zetacore: zetacore, + rpcClient: rpcClient, + evmClient: evmClient, + } +} diff --git a/zetaclient/chains/evm/observer/outbound_test.go b/zetaclient/chains/evm/observer/outbound_test.go index 90a20c4cb7..1e22abf153 100644 --- a/zetaclient/chains/evm/observer/outbound_test.go +++ b/zetaclient/chains/evm/observer/outbound_test.go @@ -5,7 +5,6 @@ import ( "testing" ethcommon "github.com/ethereum/go-ethereum/common" - lru "github.com/hashicorp/golang-lru" "github.com/rs/zerolog" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -20,25 +19,11 @@ import ( "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zetaconnector.non-eth.sol" ) -// getContractsByChainID is a helper func to get contracts and addresses by chainID -func getContractsByChainID( - t *testing.T, - chainID int64, -) (*zetaconnector.ZetaConnectorNonEth, ethcommon.Address, *erc20custody.ERC20Custody, ethcommon.Address) { - connector := mocks.MockConnectorNonEth(t, chainID) - connectorAddress := testutils.ConnectorAddresses[chainID] - custody := mocks.MockERC20Custody(t, chainID) - custodyAddress := testutils.CustodyAddresses[chainID] - return connector, connectorAddress, custody, custodyAddress -} - func Test_IsOutboundProcessed(t *testing.T) { // load archived outbound receipt that contains ZetaReceived event // https://etherscan.io/tx/0x81342051b8a85072d3e3771c1a57c7bdb5318e8caf37f5a687b7a91e50a7257f - chain := chains.Ethereum chainID := chains.Ethereum.ChainId nonce := uint64(9718) - chainParam := mocks.MockChainParams(chain.ChainId, 1) outboundHash := "0x81342051b8a85072d3e3771c1a57c7bdb5318e8caf37f5a687b7a91e50a7257f" cctx := testutils.LoadCctxByNonce(t, chainID, nonce) receipt := testutils.LoadEVMOutboundReceipt( @@ -61,7 +46,7 @@ func Test_IsOutboundProcessed(t *testing.T) { t.Run("should post vote and return true if outbound is processed", func(t *testing.T) { // create evm observer and set outbound and receipt - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, chainParam) + ob := newTestSuite(t) ob.SetTxNReceipt(nonce, receipt, outbound) // post outbound vote @@ -77,7 +62,7 @@ func Test_IsOutboundProcessed(t *testing.T) { cctx.InboundParams.Sender = sample.EthAddress().Hex() // create evm observer and set outbound and receipt - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, chainParam) + ob := newTestSuite(t) ob.SetTxNReceipt(nonce, receipt, outbound) // modify compliance config to restrict sender address @@ -94,14 +79,14 @@ func Test_IsOutboundProcessed(t *testing.T) { }) t.Run("should return false if outbound is not confirmed", func(t *testing.T) { // create evm observer and DO NOT set outbound as confirmed - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, chainParam) + ob := newTestSuite(t) continueKeysign, err := ob.VoteOutboundIfConfirmed(ctx, cctx) require.NoError(t, err) require.True(t, continueKeysign) }) t.Run("should fail if unable to parse ZetaReceived event", func(t *testing.T) { // create evm observer and set outbound and receipt - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, chainParam) + ob := newTestSuite(t) ob.SetTxNReceipt(nonce, receipt, outbound) // set connector contract address to an arbitrary address to make event parsing fail @@ -124,10 +109,8 @@ func Test_IsOutboundProcessed_ContractError(t *testing.T) { // load archived outbound receipt that contains ZetaReceived event // https://etherscan.io/tx/0x81342051b8a85072d3e3771c1a57c7bdb5318e8caf37f5a687b7a91e50a7257f - chain := chains.Ethereum chainID := chains.Ethereum.ChainId nonce := uint64(9718) - chainParam := mocks.MockChainParams(chain.ChainId, 1) outboundHash := "0x81342051b8a85072d3e3771c1a57c7bdb5318e8caf37f5a687b7a91e50a7257f" cctx := testutils.LoadCctxByNonce(t, chainID, nonce) receipt := testutils.LoadEVMOutboundReceipt( @@ -150,7 +133,7 @@ func Test_IsOutboundProcessed_ContractError(t *testing.T) { t.Run("should fail if unable to get connector/custody contract", func(t *testing.T) { // create evm observer and set outbound and receipt - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, chainParam) + ob := newTestSuite(t) ob.SetTxNReceipt(nonce, receipt, outbound) abiConnector := zetaconnector.ZetaConnectorNonEthMetaData.ABI abiCustody := erc20custody.ERC20CustodyMetaData.ABI @@ -194,7 +177,7 @@ func Test_PostVoteOutbound(t *testing.T) { receiveStatus := chains.ReceiveStatus_success // create evm client using mock zetacore client and post outbound vote - ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, mocks.MockChainParams(chain.ChainId, 100)) + ob := newTestSuite(t) ob.PostVoteOutbound( ctx, cctx.Index, @@ -420,7 +403,6 @@ func Test_FilterTSSOutbound(t *testing.T) { // https://etherscan.io/block/19363323 chain := chains.Ethereum chainID := chain.ChainId - chainParam := mocks.MockChainParams(chainID, 1) // load archived evm block // https://etherscan.io/block/19363323 @@ -435,22 +417,18 @@ func Test_FilterTSSOutbound(t *testing.T) { ctx := context.Background() t.Run("should filter TSS outbound", func(t *testing.T) { - // create mock evm client with preloaded block, tx and receipt - evmClient := mocks.NewEVMRPCClient(t) - evmClient.On("BlockNumber", mock.Anything).Return(blockNumber+1, nil) // +1 confirmations - evmClient.On("TransactionByHash", mock.Anything, outboundHash).Return(tx, false, nil) - evmClient.On("TransactionReceipt", mock.Anything, outboundHash).Return(receipt, nil) - // create evm observer for testing - tss := mocks.NewTSS(t).FakePubKey(testutils.TSSPubKeyMainnet) + ob := newTestSuite(t) - ob, _ := MockEVMObserver(t, chain, evmClient, nil, nil, tss, 1, chainParam) + confirmations := ob.chainParams.ConfirmationCount - // feed archived block to observer cache - blockCache, err := lru.New(1000) - require.NoError(t, err) - blockCache.Add(blockNumber, block) - ob.WithBlockCache(blockCache) + // create mock evm client with preloaded block, tx and receipt + ob.evmClient.On("BlockNumber", mock.Anything).Unset() + ob.evmClient.On("BlockNumber", mock.Anything).Return(blockNumber+confirmations, nil) + ob.evmClient.On("TransactionByHash", mock.Anything, outboundHash).Return(tx, false, nil) + ob.evmClient.On("TransactionReceipt", mock.Anything, outboundHash).Return(receipt, nil) + + ob.BlockCache().Add(blockNumber, block) // filter TSS outbound ob.FilterTSSOutbound(ctx, blockNumber, blockNumber) @@ -460,7 +438,7 @@ func Test_FilterTSSOutbound(t *testing.T) { require.True(t, found) // retrieve tx and receipt - receipt, tx := ob.GetTxNReceipt(outboundNonce) + receipt, tx = ob.GetTxNReceipt(outboundNonce) require.NotNil(t, tx) require.NotNil(t, receipt) require.Equal(t, outboundHash, tx.Hash()) @@ -468,16 +446,7 @@ func Test_FilterTSSOutbound(t *testing.T) { }) t.Run("should filter nothing on RPC error", func(t *testing.T) { - // create mock evm client block number - evmClient := mocks.NewEVMRPCClient(t) - evmClient.On("BlockNumber", mock.Anything).Return(blockNumber+1, nil) - - // create evm JSON-RPC client without block to simulate RPC error - evmJSONRPC := mocks.NewMockJSONRPCClient() - - // create evm observer for testing - tss := mocks.NewTSS(t) - ob, _ := MockEVMObserver(t, chain, evmClient, evmJSONRPC, nil, tss, 1, chainParam) + ob := newTestSuite(t) // filter TSS outbound ob.FilterTSSOutbound(ctx, blockNumber, blockNumber) diff --git a/zetaclient/chains/evm/signer/sign_test.go b/zetaclient/chains/evm/signer/sign_test.go index d87badfe1d..0e408b3a57 100644 --- a/zetaclient/chains/evm/signer/sign_test.go +++ b/zetaclient/chains/evm/signer/sign_test.go @@ -8,21 +8,17 @@ import ( "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/zeta-chain/node/zetaclient/testutils/mocks" ) func TestSigner_SignConnectorOnReceive(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSS(t) - evmSigner, err := getNewEvmSigner(t, tss) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) - require.NoError(t, err) txData, skip, err := NewOutboundData(ctx, cctx, 123, zerolog.Logger{}) require.False(t, skip) require.NoError(t, err) @@ -33,17 +29,17 @@ func TestSigner_SignConnectorOnReceive(t *testing.T) { require.NoError(t, err) // Verify Signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) }) t.Run("SignConnectorOnReceive - should fail if keysign fails", func(t *testing.T) { // Pause tss to make keysign fail - tss.Pause() + evmSigner.tss.Pause() // Call SignConnectorOnReceive tx, err := evmSigner.SignConnectorOnReceive(ctx, txData) require.ErrorContains(t, err, "sign onReceive error") require.Nil(t, tx) - tss.Unpause() + evmSigner.tss.Unpause() }) t.Run("SignOutbound - should successfully sign LegacyTx", func(t *testing.T) { @@ -52,7 +48,7 @@ func TestSigner_SignConnectorOnReceive(t *testing.T) { require.NoError(t, err) // Verify Signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // check that by default tx type is legacy tx assert.Equal(t, ethtypes.LegacyTxType, int(tx.Type())) @@ -78,14 +74,14 @@ func TestSigner_SignConnectorOnReceive(t *testing.T) { require.NoError(t, err) // Given a working TSS - tss.Unpause() + evmSigner.tss.Unpause() // ACT tx, err := evmSigner.SignConnectorOnReceive(ctx, txData) require.NoError(t, err) // ASSERT - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // check that by default tx type is a dynamic fee tx assert.Equal(t, ethtypes.DynamicFeeTxType, int(tx.Type())) @@ -100,13 +96,10 @@ func TestSigner_SignConnectorOnRevert(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSS(t) - evmSigner, err := getNewEvmSigner(t, tss) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) - require.NoError(t, err) txData, skip, err := NewOutboundData(ctx, cctx, 123, zerolog.Logger{}) require.False(t, skip) require.NoError(t, err) @@ -117,7 +110,7 @@ func TestSigner_SignConnectorOnRevert(t *testing.T) { require.NoError(t, err) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Revert tx calls connector contract with 0 gas token @@ -125,7 +118,7 @@ func TestSigner_SignConnectorOnRevert(t *testing.T) { }) t.Run("SignConnectorOnRevert - should fail if keysign fails", func(t *testing.T) { // Pause tss to make keysign fail - tss.Pause() + evmSigner.tss.Pause() // Call SignConnectorOnRevert tx, err := evmSigner.SignConnectorOnRevert(ctx, txData) @@ -138,13 +131,10 @@ func TestSigner_SignCancel(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSS(t) - evmSigner, err := getNewEvmSigner(t, tss) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) - require.NoError(t, err) txData, skip, err := NewOutboundData(ctx, cctx, 123, zerolog.Logger{}) require.False(t, skip) require.NoError(t, err) @@ -155,15 +145,15 @@ func TestSigner_SignCancel(t *testing.T) { require.NoError(t, err) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Cancel tx sends 0 gas token to TSS self address - verifyTxBodyBasics(t, tx, tss.PubKey().AddressEVM(), txData.nonce, big.NewInt(0)) + verifyTxBodyBasics(t, tx, evmSigner.tss.PubKey().AddressEVM(), txData.nonce, big.NewInt(0)) }) t.Run("SignCancel - should fail if keysign fails", func(t *testing.T) { // Pause tss to make keysign fail - tss.Pause() + evmSigner.tss.Pause() // Call SignCancel tx, err := evmSigner.SignCancel(ctx, txData) @@ -176,13 +166,10 @@ func TestSigner_SignGasWithdraw(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSS(t) - evmSigner, err := getNewEvmSigner(t, tss) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) - require.NoError(t, err) txData, skip, err := NewOutboundData(ctx, cctx, 123, zerolog.Logger{}) require.False(t, skip) require.NoError(t, err) @@ -193,14 +180,14 @@ func TestSigner_SignGasWithdraw(t *testing.T) { require.NoError(t, err) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, txData.amount) }) t.Run("SignGasWithdraw - should fail if keysign fails", func(t *testing.T) { // Pause tss to make keysign fail - tss.Pause() + evmSigner.tss.Pause() // Call SignGasWithdraw tx, err := evmSigner.SignGasWithdraw(ctx, txData) @@ -213,9 +200,7 @@ func TestSigner_SignERC20Withdraw(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSS(t) - evmSigner, err := getNewEvmSigner(t, tss) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) @@ -229,7 +214,7 @@ func TestSigner_SignERC20Withdraw(t *testing.T) { require.NoError(t, err) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Withdraw tx calls erc20 custody contract with 0 gas token @@ -238,7 +223,7 @@ func TestSigner_SignERC20Withdraw(t *testing.T) { t.Run("SignERC20WithdrawTx - should fail if keysign fails", func(t *testing.T) { // pause tss to make keysign fail - tss.Pause() + evmSigner.tss.Pause() // Call SignERC20WithdrawTx tx, err := evmSigner.SignERC20Withdraw(ctx, txData) diff --git a/zetaclient/chains/evm/signer/signer.go b/zetaclient/chains/evm/signer/signer.go index e23203627a..4a6c194b21 100644 --- a/zetaclient/chains/evm/signer/signer.go +++ b/zetaclient/chains/evm/signer/signer.go @@ -75,7 +75,6 @@ func NewSigner( ctx context.Context, chain chains.Chain, tss interfaces.TSSSigner, - ts *metrics.TelemetryServer, logger base.Logger, endpoint string, zetaConnectorAddress ethcommon.Address, @@ -83,7 +82,7 @@ func NewSigner( gatewayAddress ethcommon.Address, ) (*Signer, error) { // create base signer - baseSigner := base.NewSigner(chain, tss, ts, logger) + baseSigner := base.NewSigner(chain, tss, logger) // create EVM client client, ethSigner, err := getEVMRPC(ctx, endpoint) @@ -101,11 +100,6 @@ func NewSigner( }, nil } -// WithEvmClient attaches a new client to the signer -func (signer *Signer) WithEvmClient(client interfaces.EVMRPCClient) { - signer.client = client -} - // SetZetaConnectorAddress sets the zeta connector address func (signer *Signer) SetZetaConnectorAddress(addr ethcommon.Address) { // noop @@ -546,11 +540,6 @@ func (signer *Signer) BroadcastOutbound( } } -// EvmClient returns the EVM RPC client -func (signer *Signer) EvmClient() interfaces.EVMRPCClient { - return signer.client -} - // EvmSigner returns the EVM signer object for the signer func (signer *Signer) EvmSigner() ethtypes.Signer { // TODO(revamp): rename field into evmSigner diff --git a/zetaclient/chains/evm/signer/signer_admin_test.go b/zetaclient/chains/evm/signer/signer_admin_test.go index c466b69240..0e3575cf17 100644 --- a/zetaclient/chains/evm/signer/signer_admin_test.go +++ b/zetaclient/chains/evm/signer/signer_admin_test.go @@ -9,21 +9,17 @@ import ( "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/testutils/mocks" ) func TestSigner_SignAdminTx(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSS(t) - evmSigner, err := getNewEvmSigner(t, tss) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) - require.NoError(t, err) txData, skip, err := NewOutboundData(ctx, cctx, 123, zerolog.Logger{}) require.False(t, skip) @@ -37,7 +33,7 @@ func TestSigner_SignAdminTx(t *testing.T) { require.NoError(t, err) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Revert tx calls erc20 custody contract with 0 gas token @@ -57,7 +53,7 @@ func TestSigner_SignAdminTx(t *testing.T) { require.NoError(t, err) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Revert tx calls erc20 custody contract with 0 gas token @@ -72,7 +68,7 @@ func TestSigner_SignAdminTx(t *testing.T) { require.NoError(t, err) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Revert tx calls erc20 custody contract with 0 gas token @@ -86,7 +82,7 @@ func TestSigner_SignAdminTx(t *testing.T) { require.NoError(t, err) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, txData.amount) @@ -97,15 +93,11 @@ func TestSigner_SignWhitelistERC20Cmd(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSS(t) - evmSigner, err := getNewEvmSigner(t, tss) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) - require.NoError(t, err) - txData, skip, err := NewOutboundData(ctx, cctx, 123, zerolog.Logger{}) require.NoError(t, err) @@ -118,7 +110,7 @@ func TestSigner_SignWhitelistERC20Cmd(t *testing.T) { require.NotNil(t, tx) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, zeroValue) @@ -132,7 +124,7 @@ func TestSigner_SignWhitelistERC20Cmd(t *testing.T) { t.Run("signWhitelistERC20Cmd - should fail if keysign fails", func(t *testing.T) { // Pause tss to make keysign fail - tss.Pause() + evmSigner.tss.Pause() // Call signWhitelistERC20Cmd tx, err := evmSigner.signWhitelistERC20Cmd(ctx, txData, sample.EthAddress().Hex()) @@ -145,15 +137,11 @@ func TestSigner_SignMigrateERC20CustodyFundsCmd(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSS(t) - evmSigner, err := getNewEvmSigner(t, tss) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) - require.NoError(t, err) - txData, skip, err := NewOutboundData(ctx, cctx, 123, zerolog.Logger{}) require.NoError(t, err) @@ -174,7 +162,7 @@ func TestSigner_SignMigrateERC20CustodyFundsCmd(t *testing.T) { require.NotNil(t, tx) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, zeroValue) @@ -190,7 +178,7 @@ func TestSigner_SignMigrateERC20CustodyFundsCmd(t *testing.T) { t.Run("signMigrateERC20CustodyFundsCmd - should fail if keysign fails", func(t *testing.T) { // Pause tss to make keysign fail - tss.Pause() + evmSigner.tss.Pause() params := fmt.Sprintf( "%s,%s,%s", @@ -210,14 +198,11 @@ func TestSigner_SignUpdateERC20CustodyPauseStatusCmd(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSS(t) - evmSigner, err := getNewEvmSigner(t, tss) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) - require.NoError(t, err) txData, skip, err := NewOutboundData(ctx, cctx, 123, zerolog.Logger{}) require.False(t, skip) @@ -233,7 +218,7 @@ func TestSigner_SignUpdateERC20CustodyPauseStatusCmd(t *testing.T) { require.NotNil(t, tx) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, zeroValue) @@ -249,7 +234,7 @@ func TestSigner_SignUpdateERC20CustodyPauseStatusCmd(t *testing.T) { require.NotNil(t, tx) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, zeroValue) @@ -271,7 +256,7 @@ func TestSigner_SignUpdateERC20CustodyPauseStatusCmd(t *testing.T) { t.Run("signUpdateERC20CustodyPauseStatusCmd - should fail if keysign fails", func(t *testing.T) { // Pause tss to make keysign fail - tss.Pause() + evmSigner.tss.Pause() params := constant.OptionPause @@ -286,14 +271,11 @@ func TestSigner_SignMigrateTssFundsCmd(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSS(t) - evmSigner, err := getNewEvmSigner(t, tss) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) - require.NoError(t, err) txData, skip, err := NewOutboundData(ctx, cctx, 123, zerolog.Logger{}) require.False(t, skip) @@ -306,7 +288,7 @@ func TestSigner_SignMigrateTssFundsCmd(t *testing.T) { require.NotNil(t, tx) // Verify tx signature - verifyTxSender(t, tx, tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, evmSigner.tss.PubKey().AddressEVM(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, txData.amount) @@ -314,7 +296,7 @@ func TestSigner_SignMigrateTssFundsCmd(t *testing.T) { t.Run("signMigrateTssFundsCmd - should fail if keysign fails", func(t *testing.T) { // Pause tss to make keysign fail - tss.Pause() + evmSigner.tss.Pause() // Call signMigrateTssFundsCmd tx, err := evmSigner.signMigrateTssFundsCmd(ctx, txData) diff --git a/zetaclient/chains/evm/signer/signer_test.go b/zetaclient/chains/evm/signer/signer_test.go index 4165021f0e..bcd1114b80 100644 --- a/zetaclient/chains/evm/signer/signer_test.go +++ b/zetaclient/chains/evm/signer/signer_test.go @@ -35,30 +35,38 @@ var ( ERC20CustodyAddress = sample.EthAddress() ) -// getNewEvmSigner creates a new EVM chain signer for testing -func getNewEvmSigner(t *testing.T, tss interfaces.TSSSigner) (*Signer, error) { - ctx := context.Background() - - // use default mock TSS if not provided - if tss == nil { - tss = mocks.NewTSS(t) - } +type testSuite struct { + *Signer + tss *mocks.TSS + client *mocks.EVMRPCClient +} - connectorAddress := ConnectorAddress - erc20CustodyAddress := ERC20CustodyAddress - logger := base.Logger{} +func newTestSuite(t *testing.T) *testSuite { + ctx := context.Background() + chain := chains.BscMainnet + tss := mocks.NewTSS(t) + logger := zerolog.New(zerolog.NewTestWriter(t)) - return NewSigner( + s, err := NewSigner( ctx, - chains.BscMainnet, + chain, tss, - nil, - logger, + base.Logger{Std: logger, Compliance: logger}, testutils.MockEVMRPCEndpoint, - connectorAddress, - erc20CustodyAddress, + ConnectorAddress, + ERC20CustodyAddress, sample.EthAddress(), ) + require.NoError(t, err) + + client, ok := s.client.(*mocks.EVMRPCClient) + require.True(t, ok) + + return &testSuite{ + Signer: s, + tss: tss, + client: client, + } } // getNewEvmChainObserver creates a new EVM chain observer for testing @@ -136,8 +144,8 @@ func verifyTxBodyBasics( } func TestSigner_SetGetConnectorAddress(t *testing.T) { - evmSigner, err := getNewEvmSigner(t, nil) - require.NoError(t, err) + evmSigner := newTestSuite(t) + // Get and compare require.Equal(t, ConnectorAddress, evmSigner.GetZetaConnectorAddress()) @@ -148,8 +156,7 @@ func TestSigner_SetGetConnectorAddress(t *testing.T) { } func TestSigner_SetGetERC20CustodyAddress(t *testing.T) { - evmSigner, err := getNewEvmSigner(t, nil) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Get and compare require.Equal(t, ERC20CustodyAddress, evmSigner.GetERC20CustodyAddress()) @@ -163,17 +170,14 @@ func TestSigner_TryProcessOutbound(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - evmSigner, err := getNewEvmSigner(t, nil) - require.NoError(t, err) + evmSigner := newTestSuite(t) cctx := getCCTX(t) processor := getNewOutboundProcessor() mockObserver, err := getNewEvmChainObserver(t, nil) require.NoError(t, err) // Attach mock EVM client to the signer - evmClient := mocks.NewEVMRPCClient(t) - evmClient.On("SendTransaction", mock.Anything, mock.Anything).Return(nil) - evmSigner.WithEvmClient(evmClient) + evmSigner.client.On("SendTransaction", mock.Anything, mock.Anything).Return(nil) // Test with mock client that has keys client := mocks.NewZetacoreClient(t). @@ -192,8 +196,7 @@ func TestSigner_BroadcastOutbound(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - evmSigner, err := getNewEvmSigner(t, nil) - require.NoError(t, err) + evmSigner := newTestSuite(t) // Setup txData struct cctx := getCCTX(t) @@ -202,9 +205,7 @@ func TestSigner_BroadcastOutbound(t *testing.T) { require.False(t, skip) // Attach mock EVM evmClient to the signer - evmClient := mocks.NewEVMRPCClient(t) - evmClient.On("SendTransaction", mock.Anything, mock.Anything).Return(nil) - evmSigner.WithEvmClient(evmClient) + evmSigner.client.On("SendTransaction", mock.Anything, mock.Anything).Return(nil) t.Run("BroadcastOutbound - should successfully broadcast", func(t *testing.T) { // Call SignERC20Withdraw diff --git a/zetaclient/chains/solana/observer/observer.go b/zetaclient/chains/solana/observer/observer.go index 6187ca2c39..0a9b2dcc3b 100644 --- a/zetaclient/chains/solana/observer/observer.go +++ b/zetaclient/chains/solana/observer/observer.go @@ -56,7 +56,6 @@ func NewObserver( zetacoreClient, tss, base.DefaultBlockCacheSize, - base.DefaultHeaderCacheSize, rpcAlertLatency, ts, db, @@ -86,16 +85,6 @@ func NewObserver( return ob, nil } -// SolClient returns the solana rpc client -func (ob *Observer) SolClient() interfaces.SolanaRPCClient { - return ob.solClient -} - -// WithSolClient attaches a new solana rpc client to the observer -func (ob *Observer) WithSolClient(client interfaces.SolanaRPCClient) { - ob.solClient = client -} - // Start starts the Go routine processes to observe the Solana chain func (ob *Observer) Start(ctx context.Context) { if ok := ob.Observer.Start(); !ok { diff --git a/zetaclient/chains/solana/signer/signer.go b/zetaclient/chains/solana/signer/signer.go index 1e3d6914f3..72174ab5e9 100644 --- a/zetaclient/chains/solana/signer/signer.go +++ b/zetaclient/chains/solana/signer/signer.go @@ -53,11 +53,10 @@ func NewSigner( solClient interfaces.SolanaRPCClient, tss interfaces.TSSSigner, relayerKey *keys.RelayerKey, - ts *metrics.TelemetryServer, logger base.Logger, ) (*Signer, error) { // create base signer - baseSigner := base.NewSigner(chain, tss, ts, logger) + baseSigner := base.NewSigner(chain, tss, logger) // parse gateway ID and PDA gatewayID, pda, err := contracts.ParseGatewayWithPDA(chainParams.GatewayAddress) diff --git a/zetaclient/chains/solana/signer/signer_test.go b/zetaclient/chains/solana/signer/signer_test.go index b05fc75638..dfb6d678a0 100644 --- a/zetaclient/chains/solana/signer/signer_test.go +++ b/zetaclient/chains/solana/signer/signer_test.go @@ -89,7 +89,7 @@ func Test_NewSigner(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s, err := signer.NewSigner(tt.chain, tt.chainParams, tt.solClient, tt.tss, tt.relayerKey, tt.ts, tt.logger) + s, err := signer.NewSigner(tt.chain, tt.chainParams, tt.solClient, tt.tss, tt.relayerKey, tt.logger) if tt.errMessage != "" { require.ErrorContains(t, err, tt.errMessage) require.Nil(t, s) @@ -110,7 +110,7 @@ func Test_SetGatewayAddress(t *testing.T) { // helper functor to create signer signerCreator := func() *signer.Signer { - s, err := signer.NewSigner(chain, *chainParams, nil, nil, nil, nil, base.DefaultLogger()) + s, err := signer.NewSigner(chain, *chainParams, nil, nil, nil, base.DefaultLogger()) require.NoError(t, err) return s } @@ -159,7 +159,7 @@ func Test_SetRelayerBalanceMetrics(t *testing.T) { mckClient.On("GetBalance", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("rpc error")) // create signer and set relayer balance metrics - s, err := signer.NewSigner(chain, *chainParams, mckClient, nil, relayerKey, nil, base.DefaultLogger()) + s, err := signer.NewSigner(chain, *chainParams, mckClient, nil, relayerKey, base.DefaultLogger()) require.NoError(t, err) s.SetRelayerBalanceMetrics(ctx) @@ -174,7 +174,7 @@ func Test_SetRelayerBalanceMetrics(t *testing.T) { }, nil) // create signer and set relayer balance metrics again - s, err = signer.NewSigner(chain, *chainParams, mckClient, nil, relayerKey, nil, base.DefaultLogger()) + s, err = signer.NewSigner(chain, *chainParams, mckClient, nil, relayerKey, base.DefaultLogger()) require.NoError(t, err) s.SetRelayerBalanceMetrics(ctx) diff --git a/zetaclient/chains/ton/observer/observer_test.go b/zetaclient/chains/ton/observer/observer_test.go index d08103ea63..808277c226 100644 --- a/zetaclient/chains/ton/observer/observer_test.go +++ b/zetaclient/chains/ton/observer/observer_test.go @@ -81,7 +81,6 @@ func newTestSuite(t *testing.T) *testSuite { zetacore, tss, 1, - 1, 60, nil, database, diff --git a/zetaclient/chains/ton/signer/signer_test.go b/zetaclient/chains/ton/signer/signer_test.go index ce0d4fef16..1ac464ca48 100644 --- a/zetaclient/chains/ton/signer/signer_test.go +++ b/zetaclient/chains/ton/signer/signer_test.go @@ -166,7 +166,7 @@ func newTestSuite(t *testing.T) *testSuite { proc: outboundprocessor.NewProcessor(logger.Std), gw: toncontracts.NewGateway(gwAccountID), - baseSigner: base.NewSigner(chain, tss, nil, logger), + baseSigner: base.NewSigner(chain, tss, logger), } // Setup mocks diff --git a/zetaclient/orchestrator/bootstap_test.go b/zetaclient/orchestrator/bootstap_test.go index 99f58b9e5b..0e36d4721d 100644 --- a/zetaclient/orchestrator/bootstap_test.go +++ b/zetaclient/orchestrator/bootstap_test.go @@ -29,7 +29,6 @@ const ( func TestCreateSignerMap(t *testing.T) { var ( - ts = metrics.NewTelemetryServer() tss = mocks.NewTSS(t) log = zerolog.New(zerolog.NewTestWriter(t)) baseLogger = base.Logger{Std: log, Compliance: log} @@ -64,7 +63,7 @@ func TestCreateSignerMap(t *testing.T) { }) // ACT - signers, err := CreateSignerMap(ctx, tss, baseLogger, ts) + signers, err := CreateSignerMap(ctx, tss, baseLogger) // ASSERT assert.NoError(t, err) @@ -82,7 +81,7 @@ func TestCreateSignerMap(t *testing.T) { }) // ACT - added, removed, err := syncSignerMap(ctx, tss, baseLogger, ts, &signers) + added, removed, err := syncSignerMap(ctx, tss, baseLogger, &signers) // ASSERT assert.NoError(t, err) @@ -101,7 +100,7 @@ func TestCreateSignerMap(t *testing.T) { }) // ACT - added, removed, err := syncSignerMap(ctx, tss, baseLogger, ts, &signers) + added, removed, err := syncSignerMap(ctx, tss, baseLogger, &signers) // ASSERT assert.NoError(t, err) @@ -122,7 +121,7 @@ func TestCreateSignerMap(t *testing.T) { }) // ACT - added, removed, err := syncSignerMap(ctx, tss, baseLogger, ts, &signers) + added, removed, err := syncSignerMap(ctx, tss, baseLogger, &signers) // ASSERT assert.NoError(t, err) @@ -142,7 +141,7 @@ func TestCreateSignerMap(t *testing.T) { }) // ACT - added, removed, err := syncSignerMap(ctx, tss, baseLogger, ts, &signers) + added, removed, err := syncSignerMap(ctx, tss, baseLogger, &signers) // ASSERT assert.NoError(t, err) @@ -164,7 +163,7 @@ func TestCreateSignerMap(t *testing.T) { }) // ACT - added, removed, err := syncSignerMap(ctx, tss, baseLogger, ts, &signers) + added, removed, err := syncSignerMap(ctx, tss, baseLogger, &signers) // ASSERT assert.NoError(t, err) @@ -181,7 +180,7 @@ func TestCreateSignerMap(t *testing.T) { before := len(signers) // ACT - added, removed, err := syncSignerMap(ctx, tss, baseLogger, ts, &signers) + added, removed, err := syncSignerMap(ctx, tss, baseLogger, &signers) // ASSERT assert.NoError(t, err) diff --git a/zetaclient/orchestrator/bootstrap.go b/zetaclient/orchestrator/bootstrap.go index 77793d341b..bfff2c3f65 100644 --- a/zetaclient/orchestrator/bootstrap.go +++ b/zetaclient/orchestrator/bootstrap.go @@ -40,10 +40,9 @@ func CreateSignerMap( ctx context.Context, tss interfaces.TSSSigner, logger base.Logger, - ts *metrics.TelemetryServer, ) (map[int64]interfaces.ChainSigner, error) { signers := make(map[int64]interfaces.ChainSigner) - _, _, err := syncSignerMap(ctx, tss, logger, ts, &signers) + _, _, err := syncSignerMap(ctx, tss, logger, &signers) if err != nil { return nil, err } @@ -58,7 +57,6 @@ func syncSignerMap( ctx context.Context, tss interfaces.TSSSigner, logger base.Logger, - ts *metrics.TelemetryServer, signers *map[int64]interfaces.ChainSigner, ) (int, int, error) { if signers == nil { @@ -128,7 +126,6 @@ func syncSignerMap( ctx, *rawChain, tss, - ts, logger, cfg.Endpoint, zetaConnectorAddress, @@ -148,7 +145,7 @@ func syncSignerMap( continue } - signer, err := btcsigner.NewSigner(*rawChain, tss, ts, logger, cfg) + signer, err := btcsigner.NewSigner(*rawChain, tss, logger, cfg) if err != nil { logger.Std.Error().Err(err).Msgf("Unable to construct signer for BTC chain %d", chainID) continue @@ -179,7 +176,7 @@ func syncSignerMap( } // create Solana signer - signer, err := solanasigner.NewSigner(*rawChain, *params, rpcClient, tss, relayerKey, ts, logger) + signer, err := solanasigner.NewSigner(*rawChain, *params, rpcClient, tss, relayerKey, logger) if err != nil { logger.Std.Error().Err(err).Msgf("Unable to construct signer for SOL chain %d", chainID) continue @@ -200,7 +197,7 @@ func syncSignerMap( } tonSigner := tonsigner.New( - base.NewSigner(*rawChain, tss, ts, logger), + base.NewSigner(*rawChain, tss, logger), tonClient, gateway, ) @@ -440,7 +437,6 @@ func syncObserverMap( client, tss, base.DefaultBlockCacheSize, - base.DefaultHeaderCacheSize, cfg.RPCAlertLatency, ts, database, diff --git a/zetaclient/orchestrator/orchestrator.go b/zetaclient/orchestrator/orchestrator.go index 2e73131357..0e50777f10 100644 --- a/zetaclient/orchestrator/orchestrator.go +++ b/zetaclient/orchestrator/orchestrator.go @@ -772,7 +772,7 @@ func (oc *Orchestrator) syncObserverSigner(ctx context.Context) error { Msg("synced observers") } - added, removed, err = syncSignerMap(ctx, oc.tss, oc.baseLogger, oc.ts, &oc.signerMap) + added, removed, err = syncSignerMap(ctx, oc.tss, oc.baseLogger, &oc.signerMap) if err != nil { return errors.Wrap(err, "syncSignerMap failed") }