Skip to content

Commit

Permalink
fix: skip solana unsupported transaction version (#3206) (#3220)
Browse files Browse the repository at this point in the history
* fix solana testnet unsupported version 0

* add changelog entry

* correct variable name; explicitly return a 'skip' flag to be more redable

* fix unit test

* Simplify RPC API

* Comment test case

* clean up commented test

---------

Co-authored-by: Charlie Chen <[email protected]>
Co-authored-by: Dmitry S <[email protected]>
  • Loading branch information
3 people authored Nov 27, 2024
1 parent bccb1cc commit a87243a
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 116 deletions.
12 changes: 12 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# CHANGELOG

## v23.1.1

### Fixes

* [3206](https://github.com/zeta-chain/node/pull/3206) - skip Solana unsupported transaction version to not block inbound observation

## v23.1.0

### Chores

- [3215](https://github.com/zeta-chain/node/pull/3215) - revert go-tss to v21/v22 version to avoid keysign failures

## v23.0.0

### Features
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ require (
github.com/emicklei/proto v1.11.1
github.com/ethereum/go-ethereum v1.13.15
github.com/fatih/color v1.14.1
github.com/gagliardetto/solana-go v1.10.0
github.com/gagliardetto/solana-go v1.12.0
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.4
github.com/gorilla/mux v1.8.0
Expand Down Expand Up @@ -282,7 +282,7 @@ require (
github.com/zondax/hid v0.9.2 // indirect
github.com/zondax/ledger-go v0.14.3 // indirect
go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect
go.mongodb.org/mongo-driver v1.11.0 // indirect
go.mongodb.org/mongo-driver v1.12.2 // indirect
go.nhat.io/matcher/v2 v2.0.0 // indirect
go.nhat.io/wait v0.1.0 // indirect
go.opencensus.io v0.24.0 // indirect
Expand Down
13 changes: 6 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -597,8 +597,8 @@ github.com/gagliardetto/binary v0.8.0 h1:U9ahc45v9HW0d15LoN++vIXSJyqR/pWw8DDlhd7
github.com/gagliardetto/binary v0.8.0/go.mod h1:2tfj51g5o9dnvsc+fL3Jxr22MuWzYXwx9wEoN0XQ7/c=
github.com/gagliardetto/gofuzz v1.2.2 h1:XL/8qDMzcgvR4+CyRQW9UGdwPRPMHVJfqQ/uMvSUuQw=
github.com/gagliardetto/gofuzz v1.2.2/go.mod h1:bkH/3hYLZrMLbfYWA0pWzXmi5TTRZnu4pMGZBkqMKvY=
github.com/gagliardetto/solana-go v1.10.0 h1:lDuHGC+XLxw9j8fCHBZM9tv4trI0PVhev1m9NAMaIdM=
github.com/gagliardetto/solana-go v1.10.0/go.mod h1:afBEcIRrDLJst3lvAahTr63m6W2Ns6dajZxe2irF7Jg=
github.com/gagliardetto/solana-go v1.12.0 h1:rzsbilDPj6p+/DOPXBMLhwMZeBgeRuXjm5zQFCoXgsg=
github.com/gagliardetto/solana-go v1.12.0/go.mod h1:l/qqqIN6qJJPtxW/G1PF4JtcE3Zg2vD2EliZrr9Gn5k=
github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw=
github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok=
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8=
Expand Down Expand Up @@ -1460,7 +1460,6 @@ github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
Expand Down Expand Up @@ -1500,8 +1499,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
Expand Down Expand Up @@ -1543,8 +1542,8 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 h1:qxen9oVGzDdIRP6ejyAJc760RwW4SnVDiTYTzwnXuxo=
go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5/go.mod h1:eW0HG9/oHQhvRCvb1/pIXW4cOvtDqeQK+XSi3TnwaXY=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE=
go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
go.mongodb.org/mongo-driver v1.12.2 h1:gbWY1bJkkmUB9jjZzcdhOL8O85N9H+Vvsf2yFN0RDws=
go.mongodb.org/mongo-driver v1.12.2/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ=
go.nhat.io/aferomock v0.4.0 h1:gs3nJzIqAezglUuaPfautAmZwulwRWLcfSSzdK4YCC0=
go.nhat.io/aferomock v0.4.0/go.mod h1:msi5MDOtJ/AroUa/lDc3jVGOILM4SKP//4yBRImOvkI=
go.nhat.io/grpcmock v0.25.0 h1:zk03vvA60w7UrnurZbqL4wxnjmJz1Kuyb7ig2MF+n4c=
Expand Down
23 changes: 0 additions & 23 deletions pkg/crypto/privkey.go

This file was deleted.

67 changes: 0 additions & 67 deletions pkg/crypto/privkey_test.go

This file was deleted.

35 changes: 22 additions & 13 deletions zetaclient/chains/solana/observer/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,30 +100,39 @@ func (ob *Observer) ObserveInbound(ctx context.Context) error {

// process successfully signature only
if sig.Err == nil {
txResult, err := ob.solClient.GetTransaction(ctx, sig.Signature, &rpc.GetTransactionOpts{})
if err != nil {
// we have to re-scan this signature on next ticker
return errors.Wrapf(err, "error GetTransaction for chain %d sig %s", chainID, sigString)
}

// filter inbound events and vote
err = ob.FilterInboundEventsAndVote(ctx, txResult)
if err != nil {
txResult, err := solanarpc.GetTransaction(ctx, ob.solClient, sig.Signature)
switch {
case errors.Is(err, solanarpc.ErrUnsupportedTxVersion):
ob.Logger().Inbound.Warn().
Stringer("tx.signature", sig.Signature).
Msg("ObserveInbound: skip unsupported transaction")
// just save the sig to last scanned txs
case err != nil:
// we have to re-scan this signature on next ticker
return errors.Wrapf(err, "error FilterInboundEventAndVote for chain %d sig %s", chainID, sigString)
return errors.Wrapf(err, "error GetTransaction for sig %s", sigString)
default:
// filter inbound events and vote
if err = ob.FilterInboundEventsAndVote(ctx, txResult); err != nil {
// we have to re-scan this signature on next ticker
return errors.Wrapf(err, "error FilterInboundEventAndVote for sig %s", sigString)
}
}
}

// signature scanned; save last scanned signature to both memory and db, ignore db error
if err := ob.SaveLastTxScanned(sigString, sig.Slot); err != nil {
if err = ob.SaveLastTxScanned(sigString, sig.Slot); err != nil {
ob.Logger().
Inbound.Error().
Err(err).
Msgf("ObserveInbound: error saving last sig %s for chain %d", sigString, chainID)
Str("tx.signature", sigString).
Msg("ObserveInbound: error saving last sig")
}

ob.Logger().
Inbound.Info().
Msgf("ObserveInbound: last scanned sig is %s for chain %d in slot %d", sigString, chainID, sig.Slot)
Str("tx.signature", sigString).
Uint64("tx.slot", sig.Slot).
Msg("ObserveInbound: last scanned sig")

// take a rest if max signatures per ticker is reached
if len(signatures)-i >= MaxSignaturesPerTicker {
Expand Down
28 changes: 28 additions & 0 deletions zetaclient/chains/solana/rpc/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package rpc

import (
"context"
"strings"
"time"

"github.com/gagliardetto/solana-go"
Expand All @@ -18,8 +19,14 @@ const (
// RPCAlertLatency is the default threshold for RPC latency to be considered unhealthy and trigger an alert.
// The 'HEALTH_CHECK_SLOT_DISTANCE' is default to 150 slots, which is 150 * 0.4s = 60s
RPCAlertLatency = time.Duration(60) * time.Second

// see: https://github.com/solana-labs/solana/blob/master/rpc/src/rpc.rs#L7276
errorCodeUnsupportedTransactionVersion = "-32015"
)

// ErrUnsupportedTxVersion is returned when the transaction version is not supported by zetaclient
var ErrUnsupportedTxVersion = errors.New("unsupported tx version")

// GetFirstSignatureForAddress searches the first signature for the given address.
// Note: make sure that the rpc provider used has enough transaction history.
func GetFirstSignatureForAddress(
Expand Down Expand Up @@ -122,6 +129,27 @@ func GetSignaturesForAddressUntil(
return allSignatures, nil
}

// GetTransaction fetches a transaction with the given signature.
// Note that it might return ErrUnsupportedTxVersion (for tx that we don't support yet).
func GetTransaction(
ctx context.Context,
client interfaces.SolanaRPCClient,
sig solana.Signature,
) (*rpc.GetTransactionResult, error) {
txResult, err := client.GetTransaction(ctx, sig, &rpc.GetTransactionOpts{
MaxSupportedTransactionVersion: &rpc.MaxSupportedTransactionVersion0,
})

switch {
case err != nil && strings.Contains(err.Error(), errorCodeUnsupportedTransactionVersion):
return nil, ErrUnsupportedTxVersion
case err != nil:
return nil, err
default:
return txResult, nil
}
}

// CheckRPCStatus checks the RPC status of the solana chain
func CheckRPCStatus(ctx context.Context, client interfaces.SolanaRPCClient, privnet bool) (time.Time, error) {
// query solana health (always return "ok" unless --trusted-validator is provided)
Expand Down
19 changes: 19 additions & 0 deletions zetaclient/chains/solana/rpc/rpc_live_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,30 @@ func Test_SolanaRPCLive(t *testing.T) {
return
}

LiveTest_GetTransactionWithVersion(t)
LiveTest_GetFirstSignatureForAddress(t)
LiveTest_GetSignaturesForAddressUntil(t)
LiveTest_CheckRPCStatus(t)
}

func LiveTest_GetTransactionWithVersion(t *testing.T) {
// create a Solana devnet RPC client
client := solanarpc.New(solanarpc.DevNet_RPC)

// example transaction of version "0"
// https://explorer.solana.com/tx/Wqgj7hAaUUSfLzieN912G7GxyGHijzBZgY135NtuFtPRjevK8DnYjWwQZy7LAKFQZu582wsjuab2QP27VMUJzAi?cluster=devnet
txSig := solana.MustSignatureFromBase58(
"Wqgj7hAaUUSfLzieN912G7GxyGHijzBZgY135NtuFtPRjevK8DnYjWwQZy7LAKFQZu582wsjuab2QP27VMUJzAi",
)

t.Run("should get the transaction if the version is supported", func(t *testing.T) {
ctx := context.Background()
txResult, err := rpc.GetTransaction(ctx, client, txSig)
require.NoError(t, err)
require.NotNil(t, txResult)
})
}

func LiveTest_GetFirstSignatureForAddress(t *testing.T) {
// create a Solana devnet RPC client
client := solanarpc.New(solanarpc.DevNet_RPC)
Expand Down
4 changes: 2 additions & 2 deletions zetaclient/chains/solana/signer/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/zeta-chain/node/pkg/chains"
"github.com/zeta-chain/node/pkg/coin"
contracts "github.com/zeta-chain/node/pkg/contracts/solana"
"github.com/zeta-chain/node/pkg/crypto"
"github.com/zeta-chain/node/x/crosschain/types"
observertypes "github.com/zeta-chain/node/x/observer/types"
"github.com/zeta-chain/node/zetaclient/chains/base"
Expand Down Expand Up @@ -86,10 +85,11 @@ func NewSigner(

// construct Solana private key if present
if relayerKey != nil {
signer.relayerKey, err = crypto.SolanaPrivateKeyFromString(relayerKey.PrivateKey)
privKey, err := solana.PrivateKeyFromBase58(relayerKey.PrivateKey)
if err != nil {
return nil, errors.Wrap(err, "unable to construct solana private key")
}
signer.relayerKey = &privKey
logger.Std.Info().Msgf("Solana relayer address: %s", signer.relayerKey.PublicKey())
} else {
logger.Std.Info().Msg("Solana relayer key is not provided")
Expand Down
5 changes: 3 additions & 2 deletions zetaclient/keys/relayer_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"path/filepath"

"github.com/gagliardetto/solana-go"
"github.com/pkg/errors"

"github.com/zeta-chain/node/pkg/chains"
Expand All @@ -23,7 +24,7 @@ func (rk RelayerKey) ResolveAddress(network chains.Network) (string, string, err

switch network {
case chains.Network_solana:
privKey, err := crypto.SolanaPrivateKeyFromString(rk.PrivateKey)
privKey, err := solana.PrivateKeyFromBase58(rk.PrivateKey)
if err != nil {
return "", "", errors.Wrap(err, "unable to construct solana private key")
}
Expand Down Expand Up @@ -128,7 +129,7 @@ func ReadRelayerKeyFromFile(fileName string) (*RelayerKey, error) {
func IsRelayerPrivateKeyValid(privateKey string, network chains.Network) bool {
switch network {
case chains.Network_solana:
_, err := crypto.SolanaPrivateKeyFromString(privateKey)
_, err := solana.PrivateKeyFromBase58(privateKey)
if err != nil {
return false
}
Expand Down

0 comments on commit a87243a

Please sign in to comment.