Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solana ccip_messaging_test #15965

Draft
wants to merge 62 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
28a062f
ccip_messaging_test: Make messagingTestCase receiver chain agnostic
archseer Jan 17, 2025
05e844f
Test_CCIPMessaging_Solana skeleton
archseer Jan 17, 2025
78804c7
Draft Solana versions of commit and exec confirmers
archseer Jan 22, 2025
f95de43
extract sourceDest
archseer Jan 23, 2025
844a062
Implement getLatestNonce for Solana
archseer Jan 24, 2025
06fc172
Implement WaitForTheToken balance for Solana
archseer Jan 24, 2025
ea542e9
Update ConfirmMultipleCommits with Solana support
archseer Jan 28, 2025
4b621b3
wip
archseer Jan 31, 2025
40640e2
Include SVM extra args
archseer Feb 3, 2025
738de23
wip
archseer Feb 3, 2025
d21e778
fix for startBlock(s) potentially being nil
archseer Feb 4, 2025
6ffd5a4
fix SVM extra args serialization
archseer Feb 4, 2025
6766aaa
only replay blocks on EVM chains, this is EVM specific
archseer Feb 4, 2025
1400e3d
Add a LatestBlock helper
archseer Feb 4, 2025
1c84eb4
Fix post-rebase
archseer Feb 5, 2025
f607e22
Refactor: use []byte for addresses when asserting balances
archseer Feb 6, 2025
70297c5
Add TestTokenTransfer_Solana
archseer Feb 7, 2025
b8ef636
nonce account may not exist yet
archseer Feb 10, 2025
60d871d
TEMP: disable Solana token transfer test until code is merged
archseer Feb 11, 2025
53b8276
fix: Use correct chain family when fetching CR config
archseer Feb 11, 2025
5201829
oraclecreator: Only initialize CR/CW instances for relayers with CCIP…
archseer Feb 11, 2025
9de9b85
Rename DoSendRequest to SendRequest
archseer Feb 11, 2025
2f7ca51
Avoid panic on solana getting passed EVm offramp address
archseer Feb 12, 2025
66078bf
fix: use string encoding for EVM accounts too, fixes Solana addrs bei…
archseer Feb 13, 2025
2ce68ee
Don't fail if the block doesn't contain that event type
archseer Feb 13, 2025
72a7737
solana: Handle OCR3 producing empty reports
archseer Feb 14, 2025
8555f5f
image hotfix
tt-cll Feb 14, 2025
3702e70
Fix codec modifiers for OffRamp Source Chain Config
ilija42 Feb 15, 2025
a8c66ae
Allow commit with price updates only, no merkle roots
archseer Feb 16, 2025
bfcd6a0
Fix MethodNameGetLatestPriceSequenceNumber cfg
ilija42 Feb 16, 2025
65789f8
Disable RMN verification on Solana destination
archseer Feb 17, 2025
e0b3019
CR needs to read both Config and State properties of the config
archseer Feb 17, 2025
0066e0b
ccip: solan: Handle merkle root being zeroed on price updates
archseer Feb 17, 2025
2adbeb9
Configure TokenInfo for Solana
archseer Feb 17, 2025
888ca78
Option to send price only commit reports to a different method.
winder Feb 14, 2025
7cd0236
Update test compilation.
winder Feb 14, 2025
41e7db2
Lint
winder Feb 15, 2025
c06fc88
Updated commit remaining accounts to be writable
amit-momin Feb 19, 2025
30b06a0
Updated ChainConfigGasPrice account config
amit-momin Feb 19, 2025
5fb204b
Fix commit price only report encoding
archseer Feb 19, 2025
a817135
solana: Fix OCR3 report hashing
archseer Feb 19, 2025
f4ad998
environment/memory: Fund the solana transmitter keys
archseer Feb 19, 2025
27b11e3
fix ChainConfigGasPriceConfig lookup
archseer Feb 19, 2025
0c58118
Backport Ilija's change
archseer Feb 20, 2025
a0e8aeb
Add EventNameExecutionStateChanged to Solana dest chain cfg
ilija42 Feb 20, 2025
a34a084
Use correct address transforms
archseer Feb 20, 2025
d2ee0b5
correct IndexedField0
archseer Feb 20, 2025
2b3dd21
Read events from offramp, not router
archseer Feb 20, 2025
1eedb7c
allow v0 transactions
archseer Feb 20, 2025
2bf5e1a
skip price-only events
archseer Feb 20, 2025
6808063
Fix config for GetTokenPrice
archseer Feb 20, 2025
d19b85b
Extract the token field
archseer Feb 20, 2025
610fb1a
solana: Set gas helpers to non-zero to appease the CCIP plugin
archseer Feb 21, 2025
86050f2
Fix the LinkTokenMint property
archseer Feb 21, 2025
849376a
Return router as the nonce manager
archseer Feb 21, 2025
598aafb
Use a custom workaround in chainlink-solana to return the right confi…
archseer Feb 21, 2025
70eb82d
Set a non-zero execution fee estimate
archseer Feb 21, 2025
276b9b0
CW: mark as optional
archseer Feb 22, 2025
a8bdb8e
ccipsolana: Add OnRampAddress and MerkleRoot to report
archseer Feb 24, 2025
3ee00d4
wip rm
archseer Feb 25, 2025
72919fb
solana: fix GetTokenPrice for source chain reader too
archseer Feb 26, 2025
eea6fa4
Update OnRampAddress and Root handling to match upstream contract cha…
archseer Feb 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions core/capabilities/ccip/ccipsolana/commitcodec.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,23 @@ func (c *CommitPluginCodecV1) Encode(ctx context.Context, report cciptypes.Commi
encoder := agbinary.NewBorshEncoder(&buf)
combinedRoots := report.BlessedMerkleRoots
combinedRoots = append(combinedRoots, report.UnblessedMerkleRoots...)
if len(combinedRoots) != 1 {
return nil, fmt.Errorf("unexpected merkle root length in report: %d", len(combinedRoots))
}
var mr *ccip_offramp.MerkleRoot
switch len(combinedRoots) {
case 0:
// price updates only, zero the root
case 1:
// valid
merkleRoot := combinedRoots[0]
mr = &ccip_offramp.MerkleRoot{
SourceChainSelector: uint64(merkleRoot.ChainSel),
OnRampAddress: merkleRoot.OnRampAddress,
MinSeqNr: uint64(merkleRoot.SeqNumsRange.Start()),
MaxSeqNr: uint64(merkleRoot.SeqNumsRange.End()),
MerkleRoot: merkleRoot.MerkleRoot,
}

merkleRoot := combinedRoots[0]
mr := &ccip_offramp.MerkleRoot{
SourceChainSelector: uint64(merkleRoot.ChainSel),
OnRampAddress: merkleRoot.OnRampAddress,
MinSeqNr: uint64(merkleRoot.SeqNumsRange.Start()),
MaxSeqNr: uint64(merkleRoot.SeqNumsRange.End()),
MerkleRoot: merkleRoot.MerkleRoot,
default:
return nil, fmt.Errorf("unexpected merkle root length in report: %d", len(combinedRoots))
}

tpu := make([]ccip_offramp.TokenPriceUpdate, 0, len(report.PriceUpdates.TokenPriceUpdates))
Expand Down Expand Up @@ -110,16 +116,18 @@ func (c *CommitPluginCodecV1) Decode(ctx context.Context, bytes []byte) (cciptyp
return cciptypes.CommitPluginReport{}, err
}

merkleRoots := []cciptypes.MerkleRootChain{
{
merkleRoots := make([]cciptypes.MerkleRootChain, 0, 1)
// if the merkle root is nil, ignore it
if commitReport.MerkleRoot != nil {
merkleRoots = append(merkleRoots, cciptypes.MerkleRootChain{
ChainSel: cciptypes.ChainSelector(commitReport.MerkleRoot.SourceChainSelector),
OnRampAddress: commitReport.MerkleRoot.OnRampAddress,
SeqNumsRange: cciptypes.NewSeqNumRange(
cciptypes.SeqNum(commitReport.MerkleRoot.MinSeqNr),
cciptypes.SeqNum(commitReport.MerkleRoot.MaxSeqNr),
),
MerkleRoot: commitReport.MerkleRoot.MerkleRoot,
},
})
}

tokenPriceUpdates := make([]cciptypes.TokenPrice, 0, len(commitReport.PriceUpdates.TokenPriceUpdates))
Expand Down
11 changes: 11 additions & 0 deletions core/capabilities/ccip/ccipsolana/executecodec.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ func NewExecutePluginCodecV1(extraDataCodec common.ExtraDataCodec) *ExecutePlugi
}

func (e *ExecutePluginCodecV1) Encode(ctx context.Context, report cciptypes.ExecutePluginReport) ([]byte, error) {
if len(report.ChainReports) == 0 {
// OCR3 runs in a constant loop and will produce empty reports, so we need to handle this case
// return an empty report, CCIP will discard it on ShouldAcceptAttestedReport/ShouldTransmitAcceptedReport
// via validateReport before attempting to decode
return nil, nil
}

if len(report.ChainReports) != 1 {
return nil, fmt.Errorf("unexpected chain report length: %d", len(report.ChainReports))
}
Expand Down Expand Up @@ -88,6 +95,8 @@ func (e *ExecutePluginCodecV1) Encode(ctx context.Context, report cciptypes.Exec
return nil, fmt.Errorf("invalid receiver address: %v", msg.Receiver)
}

fmt.Printf("ONRAMP %+v\n", msg.Header.OnRamp)

message = ccip_offramp.Any2SVMRampMessage{
Header: ccip_offramp.RampMessageHeader{
MessageId: msg.Header.MessageID,
Expand All @@ -101,6 +110,8 @@ func (e *ExecutePluginCodecV1) Encode(ctx context.Context, report cciptypes.Exec
TokenReceiver: solana.PublicKeyFromBytes(msg.Receiver),
TokenAmounts: tokenAmounts,
ExtraArgs: extraArgs,
// TODO: is this available?
OnRampAddress: msg.Header.OnRamp,
}

// should only have an offchain token data if there are tokens as part of the message
Expand Down
4 changes: 2 additions & 2 deletions core/capabilities/ccip/ccipsolana/gas_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ type EstimateProvider struct {

// CalculateMerkleTreeGas is not implemented
func (gp EstimateProvider) CalculateMerkleTreeGas(numRequests int) uint64 {
return 0
return 1
}

// CalculateMessageMaxGas is not implemented.
func (gp EstimateProvider) CalculateMessageMaxGas(msg cciptypes.Message) uint64 {
return 0
return 1
}
31 changes: 16 additions & 15 deletions core/capabilities/ccip/configs/solana/chain_writer.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package solana

import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
Expand All @@ -28,8 +27,7 @@
merkleRoot = "Info.MerkleRoots.MerkleRoot"
)

func getCommitMethodConfig(fromAddress string, offrampProgramAddress string, destChainSelector uint64, priceOnly bool) chainwriter.MethodConfig {
destChainSelectorBytes := binary.LittleEndian.AppendUint64([]byte{}, destChainSelector)
func getCommitMethodConfig(fromAddress string, offrampProgramAddress string, priceOnly bool) chainwriter.MethodConfig {
chainSpecificName := "commit"
if priceOnly {
chainSpecificName = "commitPriceOnly"
Expand All @@ -45,17 +43,18 @@
},
},
ChainSpecificName: chainSpecificName,
ArgsTransform: "CCIPCommit",
LookupTables: chainwriter.LookupTables{
DerivedLookupTables: []chainwriter.DerivedLookupTable{
getCommonAddressLookupTableConfig(offrampProgramAddress),
},
},
Accounts: buildCommitAccountsList(fromAddress, offrampProgramAddress, destChainSelectorBytes, priceOnly),
Accounts: buildCommitAccountsList(fromAddress, offrampProgramAddress, priceOnly),
DebugIDLocation: "",
}
}

func buildCommitAccountsList(fromAddress, offrampProgramAddress string, destChainSelectorBytes []byte, priceOnly bool) []chainwriter.Lookup {
func buildCommitAccountsList(fromAddress, offrampProgramAddress string, priceOnly bool) []chainwriter.Lookup {
accounts := []chainwriter.Lookup{}
accounts = append(accounts,
getOfframpAccountConfig(offrampProgramAddress),
Expand Down Expand Up @@ -100,7 +99,7 @@
getFeeQuoterConfigLookup(offrampProgramAddress),
getGlobalStateConfig(offrampProgramAddress),
getBillingTokenConfig(offrampProgramAddress),
getChainConfigGasPriceConfig(offrampProgramAddress, destChainSelectorBytes),
getChainConfigGasPriceConfig(offrampProgramAddress),
)
return accounts
}
Expand All @@ -117,7 +116,7 @@
},
},
ChainSpecificName: "execute",
ArgsTransform: "CCIP",
ArgsTransform: "CCIPExecute",
LookupTables: chainwriter.LookupTables{
DerivedLookupTables: []chainwriter.DerivedLookupTable{
{
Expand All @@ -140,6 +139,7 @@
},
},
},
Optional: true, // Lookup table is optional if DestTokenAddress is not present in report
},
getCommonAddressLookupTableConfig(offrampProgramAddress),
},
Expand All @@ -155,6 +155,7 @@
},
},
MintAddress: chainwriter.Lookup{AccountLookup: &chainwriter.AccountLookup{Location: destTokenAddress}},
Optional: true, // ATA lookup is optional if DestTokenAddress is not present in report

Check failure on line 158 in core/capabilities/ccip/configs/solana/chain_writer.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests_integration)

unknown field Optional in struct literal of type chainwriter.ATALookup

Check failure on line 158 in core/capabilities/ccip/configs/solana/chain_writer.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

unknown field Optional in struct literal of type chainwriter.ATALookup

Check failure on line 158 in core/capabilities/ccip/configs/solana/chain_writer.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_fuzz)

unknown field Optional in struct literal of type chainwriter.ATALookup

Check failure on line 158 in core/capabilities/ccip/configs/solana/chain_writer.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

unknown field Optional in struct literal of type chainwriter.ATALookup
},
},
Accounts: []chainwriter.Lookup{
Expand Down Expand Up @@ -307,7 +308,7 @@
}
}

func GetSolanaChainWriterConfig(offrampProgramAddress string, fromAddress string, destChainSelector uint64) (chainwriter.ChainWriterConfig, error) {
func GetSolanaChainWriterConfig(offrampProgramAddress string, fromAddress string) (chainwriter.ChainWriterConfig, error) {
// check fromAddress
pk, err := solana.PublicKeyFromBase58(fromAddress)
if err != nil {
Expand All @@ -333,8 +334,8 @@
ccipconsts.ContractNameOffRamp: {
Methods: map[string]chainwriter.MethodConfig{
ccipconsts.MethodExecute: getExecuteMethodConfig(fromAddress, offrampProgramAddress),
ccipconsts.MethodCommit: getCommitMethodConfig(fromAddress, offrampProgramAddress, destChainSelector, false),
ccipconsts.MethodCommitPriceOnly: getCommitMethodConfig(fromAddress, offrampProgramAddress, destChainSelector, true),
ccipconsts.MethodCommit: getCommitMethodConfig(fromAddress, offrampProgramAddress, false),
ccipconsts.MethodCommitPriceOnly: getCommitMethodConfig(fromAddress, offrampProgramAddress, true),
},
IDL: ccipOfframpIDL,
},
Expand Down Expand Up @@ -484,7 +485,7 @@
{Static: []byte("state")},
},
IsSigner: false,
IsWritable: false,
IsWritable: true,
},
Optional: true,
}
Expand All @@ -500,23 +501,23 @@
{Dynamic: chainwriter.Lookup{AccountLookup: &chainwriter.AccountLookup{Location: "Info.TokenPrices.TokenID"}}},
},
IsSigner: false,
IsWritable: false,
IsWritable: true,
},
Optional: true,
}
}

func getChainConfigGasPriceConfig(offrampProgramAddress string, destChainSelector []byte) chainwriter.Lookup {
func getChainConfigGasPriceConfig(offrampProgramAddress string) chainwriter.Lookup {
return chainwriter.Lookup{
PDALookups: &chainwriter.PDALookups{
Name: "ChainConfigGasPrice",
PublicKey: getFeeQuoterProgramAccount(offrampProgramAddress),
Seeds: []chainwriter.Seed{
{Static: []byte("dest_chain")},
{Static: destChainSelector},
{Dynamic: chainwriter.Lookup{AccountLookup: &chainwriter.AccountLookup{Location: "Info.GasPrices.ChainSel"}}},
},
IsSigner: false,
IsWritable: false,
IsWritable: true,
},
Optional: true,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestChainWriterConfigRaw(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config, err := GetSolanaChainWriterConfig("4Nn9dsYBcSTzRbK9hg9kzCUdrCSkMZq1UR6Vw1Tkaf6H", tt.fromAddress, 0)
config, err := GetSolanaChainWriterConfig("4Nn9dsYBcSTzRbK9hg9kzCUdrCSkMZq1UR6Vw1Tkaf6H", tt.fromAddress)
if tt.expectedError != "" {
assert.EqualError(t, err, tt.expectedError)
} else {
Expand Down
Loading
Loading