Skip to content

Commit

Permalink
refactor so txm owns blockhash assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
Farber98 committed Nov 15, 2024
1 parent 65ae137 commit f0cf198
Show file tree
Hide file tree
Showing 11 changed files with 416 additions and 358 deletions.
42 changes: 10 additions & 32 deletions pkg/solana/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"sync"
"time"

"github.com/gagliardetto/solana-go"
solanago "github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/programs/system"
"github.com/gagliardetto/solana-go/rpc"
Expand Down Expand Up @@ -530,11 +531,6 @@ func (c *chain) HealthReport() map[string]error {
}

func (c *chain) sendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error {
reader, err := c.Reader()
if err != nil {
return fmt.Errorf("chain unreachable: %w", err)
}

fromKey, err := solanago.PublicKeyFromBase58(from)
if err != nil {
return fmt.Errorf("failed to parse from key: %w", err)
Expand All @@ -548,10 +544,6 @@ func (c *chain) sendTx(ctx context.Context, from, to string, amount *big.Int, ba
}
amountI := amount.Uint64()

blockhash, err := reader.LatestBlockhash(ctx)
if err != nil {
return fmt.Errorf("failed to get latest block hash: %w", err)
}
tx, err := solanago.NewTransaction(
[]solanago.Instruction{
system.NewTransferInstruction(
Expand All @@ -560,21 +552,24 @@ func (c *chain) sendTx(ctx context.Context, from, to string, amount *big.Int, ba
toKey,
).Build(),
},
blockhash.Value.Blockhash,
solana.Hash{}, // Will be set within sendWithRetry txm function.
solanago.TransactionPayer(fromKey),
)
if err != nil {
return fmt.Errorf("failed to create tx: %w", err)
}

if balanceCheck {
if err = solanaValidateBalance(ctx, reader, fromKey, amountI, tx.Message.ToBase64()); err != nil {
return fmt.Errorf("failed to validate balance: %w", err)
}
msg := &txm.PendingTx{
Tx: *tx,
// To perform balanceCheck we need a blockhash.
// Storing values to perform balanceCheck within sendWithRetry txm function before sending tx.
BalanceCheck: balanceCheck,
From: fromKey,
Amount: amountI,
}

chainTxm := c.TxManager()
err = chainTxm.Enqueue(ctx, "", tx, nil,
err = chainTxm.Enqueue(ctx, "", msg,
txm.SetComputeUnitLimit(500), // reduce from default 200K limit - should only take 450 compute units
// no fee bumping and no additional fee - makes validating balance accurate
txm.SetComputeUnitPriceMax(0),
Expand All @@ -587,20 +582,3 @@ func (c *chain) sendTx(ctx context.Context, from, to string, amount *big.Int, ba
}
return nil
}

func solanaValidateBalance(ctx context.Context, reader client.Reader, from solanago.PublicKey, amount uint64, msg string) error {
balance, err := reader.Balance(ctx, from)
if err != nil {
return err
}

fee, err := reader.GetFeeForMessage(ctx, msg)
if err != nil {
return err
}

if balance < (amount + fee) {
return fmt.Errorf("balance %d is too low for this transaction to be executed: amount %d + fee %d", balance, amount, fee)
}
return nil
}
23 changes: 11 additions & 12 deletions pkg/solana/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,20 @@ import (
"github.com/gagliardetto/solana-go/programs/system"
"github.com/gagliardetto/solana-go/rpc"
"github.com/google/uuid"
"github.com/smartcontractkit/chainlink-common/pkg/config"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zapcore"

"github.com/smartcontractkit/chainlink-common/pkg/config"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"

"github.com/smartcontractkit/chainlink-solana/pkg/solana/client"
mn "github.com/smartcontractkit/chainlink-solana/pkg/solana/client/multinode"
solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/fees"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/txm"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/txm/mocks"
)

Expand Down Expand Up @@ -536,11 +538,8 @@ func TestSolanaChain_MultiNode_Txm(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, uint64(0), receiverBal)

createTx := func(signer solana.PublicKey, sender solana.PublicKey, receiver solana.PublicKey, amt uint64) *solana.Transaction {
selectedClient, err = testChain.getClient()
createMsgWithTx := func(signer solana.PublicKey, sender solana.PublicKey, receiver solana.PublicKey, amt uint64) *txm.PendingTx {
assert.NoError(t, err)
hash, hashErr := selectedClient.LatestBlockhash(tests.Context(t))
assert.NoError(t, hashErr)
tx, txErr := solana.NewTransaction(
[]solana.Instruction{
system.NewTransferInstruction(
Expand All @@ -549,15 +548,15 @@ func TestSolanaChain_MultiNode_Txm(t *testing.T) {
receiver,
).Build(),
},
hash.Value.Blockhash,
solana.Hash{},
solana.TransactionPayer(signer),
)
require.NoError(t, txErr)
return tx
return &txm.PendingTx{Tx: *tx}
}

// Send funds twice, along with an invalid transaction
require.NoError(t, testChain.txm.Enqueue(tests.Context(t), "test_success", createTx(pubKey, pubKey, pubKeyReceiver, solana.LAMPORTS_PER_SOL), nil))
require.NoError(t, testChain.txm.Enqueue(tests.Context(t), "test_success", createMsgWithTx(pubKey, pubKey, pubKeyReceiver, solana.LAMPORTS_PER_SOL)))

// Wait for new block hash
currentBh, err := selectedClient.LatestBlockhash(tests.Context(t))
Expand All @@ -578,8 +577,8 @@ NewBlockHash:
}
}

require.NoError(t, testChain.txm.Enqueue(tests.Context(t), "test_success_2", createTx(pubKey, pubKey, pubKeyReceiver, solana.LAMPORTS_PER_SOL), nil))
require.Error(t, testChain.txm.Enqueue(tests.Context(t), "test_invalidSigner", createTx(pubKeyReceiver, pubKey, pubKeyReceiver, solana.LAMPORTS_PER_SOL), nil)) // cannot sign tx before enqueuing
require.NoError(t, testChain.txm.Enqueue(tests.Context(t), "test_success_2", createMsgWithTx(pubKey, pubKey, pubKeyReceiver, solana.LAMPORTS_PER_SOL)))
require.Error(t, testChain.txm.Enqueue(tests.Context(t), "test_invalidSigner", createMsgWithTx(pubKeyReceiver, pubKey, pubKeyReceiver, solana.LAMPORTS_PER_SOL))) // cannot sign tx before enqueuing

// wait for all txes to finish
ctx, cancel := context.WithCancel(tests.Context(t))
Expand Down
2 changes: 1 addition & 1 deletion pkg/solana/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
var _ TxManager = (*txm.Txm)(nil)

type TxManager interface {
Enqueue(ctx context.Context, accountID string, tx *solana.Transaction, txID *string, txCfgs ...txm.SetTxConfig) error
Enqueue(ctx context.Context, accountID string, msg *txm.PendingTx, txCfgs ...txm.SetTxConfig) error
}

var _ relaytypes.Relayer = &Relayer{} //nolint:staticcheck
Expand Down
18 changes: 7 additions & 11 deletions pkg/solana/transmitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package solana
import (
"bytes"
"context"
"errors"
"fmt"

"github.com/gagliardetto/solana-go"
Expand All @@ -13,6 +12,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/utils"

"github.com/smartcontractkit/chainlink-solana/pkg/solana/client"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/txm"
)

var _ types.ContractTransmitter = (*Transmitter)(nil)
Expand All @@ -32,14 +32,6 @@ func (c *Transmitter) Transmit(
report types.Report,
sigs []types.AttributedOnchainSignature,
) error {
blockhash, err := c.reader.LatestBlockhash(ctx)
if err != nil {
return fmt.Errorf("error on Transmit.GetRecentBlockhash: %w", err)
}
if blockhash == nil || blockhash.Value == nil {
return errors.New("nil pointer returned from Transmit.GetRecentBlockhash")
}

// Determine store authority
seeds := [][]byte{[]byte("store"), c.stateID.Bytes()}
storeAuthority, storeNonce, err := solana.FindProgramAddress(seeds, c.programID)
Expand Down Expand Up @@ -75,16 +67,20 @@ func (c *Transmitter) Transmit(
[]solana.Instruction{
solana.NewInstruction(c.programID, accounts, data.Bytes()),
},
blockhash.Value.Blockhash,
solana.Hash{}, // Will be set within sendWithRetry txm function.
solana.TransactionPayer(c.transmissionSigner),
)
if err != nil {
return fmt.Errorf("error on Transmit.NewTransaction: %w", err)
}

msg := &txm.PendingTx{
Tx: *tx,
}

// pass transmit payload to tx manager queue
c.lggr.Debugf("Queuing transmit tx: state (%s) + transmissions (%s)", c.stateID.String(), c.transmissionsID.String())
if err = c.txManager.Enqueue(ctx, c.stateID.String(), tx, nil); err != nil {
if err = c.txManager.Enqueue(ctx, c.stateID.String(), msg); err != nil {
return fmt.Errorf("error on Transmit.txManager.Enqueue: %w", err)
}
return nil
Expand Down
8 changes: 2 additions & 6 deletions pkg/solana/transmitter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import (
"testing"

"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"
"github.com/smartcontractkit/libocr/offchainreporting2/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
Expand All @@ -26,8 +24,9 @@ type verifyTxSize struct {
s *solana.PrivateKey
}

func (txm verifyTxSize) Enqueue(_ context.Context, _ string, tx *solana.Transaction, txID *string, _ ...txm.SetTxConfig) error {
func (txm verifyTxSize) Enqueue(_ context.Context, _ string, msg *txm.PendingTx, _ ...txm.SetTxConfig) error {
// additional components that transaction manager adds to the transaction
tx := &msg.Tx
require.NoError(txm.t, fees.SetComputeUnitPrice(tx, 0))
require.NoError(txm.t, fees.SetComputeUnitLimit(tx, 0))

Expand Down Expand Up @@ -58,9 +57,6 @@ func TestTransmitter_TxSize(t *testing.T) {
}

rw := clientmocks.NewReaderWriter(t)
rw.On("LatestBlockhash", mock.Anything).Return(&rpc.GetLatestBlockhashResult{
Value: &rpc.LatestBlockhashResult{},
}, nil)

transmitter := Transmitter{
stateID: mustNewRandomPublicKey(),
Expand Down
Loading

0 comments on commit f0cf198

Please sign in to comment.