Skip to content

Commit

Permalink
node/solana: consistency defense-in-depth check
Browse files Browse the repository at this point in the history
  • Loading branch information
evan-gray authored and bruce-riley committed Nov 30, 2023
1 parent a23d028 commit 585fff5
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 2 deletions.
77 changes: 77 additions & 0 deletions node/hack/solana/account_lookup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package main

import (
"context"
"fmt"
"log"

"github.com/gagliardetto/solana-go"
lookup "github.com/gagliardetto/solana-go/programs/address-lookup-table"
"github.com/gagliardetto/solana-go/rpc"
)

func populateLookupTableAccounts(ctx context.Context, tx *solana.Transaction, rpcClient *rpc.Client) error {
if !tx.Message.IsVersioned() {
return nil
}

tblKeys := tx.Message.GetAddressTableLookups().GetTableIDs()
if len(tblKeys) == 0 {
return nil
}

resolutions := make(map[solana.PublicKey]solana.PublicKeySlice)
for _, key := range tblKeys {
fmt.Println(key)
info, err := rpcClient.GetAccountInfo(ctx, key)
if err != nil {
fmt.Println("We errored here!")
return err
}

tableContent, err := lookup.DecodeAddressLookupTableState(info.GetBinary())
if err != nil {
return err
}

resolutions[key] = tableContent.Addresses
}

err := tx.Message.SetAddressTables(resolutions)
if err != nil {
return err
}

err = tx.Message.ResolveLookups()
if err != nil {
return err
}

return nil
}

func main() {
ctx := context.Background()
testTx, err := solana.SignatureFromBase58("2Jr3bAuEKwYBKmaqSmmFQ2R7xxxQpmjY8g3N3gMH49C62kBaweUgc9UCEcFhqcewAVnDLcBGWUSQrKZ7vdxpBbq4")
if (err != nil) {
log.Fatal("SignatureFromBase58 errored", err)
}
rpcClient := rpc.New("https://api.devnet.solana.com")
maxSupportedTransactionVersion := uint64(0)
tx, err := rpcClient.GetTransaction(ctx, testTx, &rpc.GetTransactionOpts{
Encoding: solana.EncodingBase64,
MaxSupportedTransactionVersion: &maxSupportedTransactionVersion,
})
if (err != nil) {
log.Fatal("getTransaction errored", err)
}
realTx, err := tx.Transaction.GetTransaction()
if (err != nil) {
log.Fatal("GetTransaction errored", err)
}
err = populateLookupTableAccounts(ctx, realTx, rpcClient)
if (err != nil) {
log.Fatal("populateLookupTableAccounts errored", err)
}

}
28 changes: 26 additions & 2 deletions node/pkg/watchers/solana/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ type (
}

MessagePublicationAccount struct {
VaaVersion uint8
// Borsh does not seem to support booleans, so 0=false / 1=true
VaaVersion uint8
ConsistencyLevel uint8
EmitterAuthority vaa.Address
MessageStatus uint8
Expand Down Expand Up @@ -166,6 +165,17 @@ func (c ConsistencyLevel) Commitment() (rpc.CommitmentType, error) {
}
}

func accountConsistencyLevelToCommitment(c uint8) (rpc.CommitmentType, error) {
switch c {
case 1:
return rpc.CommitmentConfirmed, nil
case 32:
return rpc.CommitmentFinalized, nil
default:
return "", fmt.Errorf("unsupported consistency level: %d", c)
}
}

const (
postMessageInstructionMinNumAccounts = 8
postMessageInstructionID = 0x01
Expand Down Expand Up @@ -802,6 +812,20 @@ func (s *SolanaWatcher) processMessageAccount(logger *zap.Logger, data []byte, a
return
}

// SECURITY: defense-in-depth, ensure the consistency level in the account matches the consistency level of the watcher
commitment, err := accountConsistencyLevelToCommitment(proposal.ConsistencyLevel)
if err != nil {
logger.Error(
"failed to parse proposal consistency level",
zap.Any("proposal", proposal),
zap.Error(err))
return
}
if commitment != s.commitment {
logger.Debug("skipping message which does not match the watcher commitment", zap.Stringer("account", acc), zap.String("message commitment", string(commitment)), zap.String("watcher commitment", string(s.commitment)))
return
}

// As of 2023-11-09, Pythnet has a bug which is not zeroing out these fields appropriately. This carve out should be removed after a fix is deployed.
if s.chainID != vaa.ChainIDPythNet {
// SECURITY: ensure these fields are zeroed out. in the legacy solana program they were always zero, and in the 2023 rewrite they are zeroed once the account is finalized
Expand Down

0 comments on commit 585fff5

Please sign in to comment.