-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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 plugin codec implementation #15816
Open
huangzhen1997
wants to merge
51
commits into
solana-offchain-plugin
Choose a base branch
from
NONEVM-935/implement-ccip-solana-plugin-codec
base: solana-offchain-plugin
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+740
−58
Open
Changes from 44 commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
71b06dc
add solana commit codec, need to add test
huangzhen1997 c79a406
ccipsolana: Import bindings
archseer 0fe505c
Merge branch 'develop' into NONEVM-935/implement-ccip-solana-plugin-c…
huangzhen1997 de95bf1
update go list
huangzhen1997 e51bd46
add test and update commit price processing logic
huangzhen1997 86c9c17
fix lint
huangzhen1997 237e4f4
add exec, and test in progress
huangzhen1997 7ae43ed
added unit tests for execute, need clean up and verify requirements
huangzhen1997 4e2ea85
fix go mod in deployment
huangzhen1997 0d49c2e
fix lint
huangzhen1997 5849b3b
lint
huangzhen1997 70db87e
go mod
huangzhen1997 d2a7a39
update
huangzhen1997 ae3e43c
Merge branch 'develop' of github.com:smartcontractkit/chainlink into …
huangzhen1997 11cd2f3
add extra args and destExec support
huangzhen1997 40abc5c
minor
huangzhen1997 4e2f647
cleanup
huangzhen1997 558c0ff
update
huangzhen1997 07acdb1
fix mod
huangzhen1997 0c0b802
update
huangzhen1997 f0a5a0e
Merge branch 'develop' of github.com:smartcontractkit/chainlink into …
huangzhen1997 22ad68c
revert mod change
huangzhen1997 effd030
add changeset
huangzhen1997 26e9cb3
fix smoke test
huangzhen1997 b988745
fix lint
huangzhen1997 56d85d5
revert go mod
huangzhen1997 75ae059
fix
huangzhen1997 0272e75
revert
huangzhen1997 465d69c
revert
huangzhen1997 f314edc
again
huangzhen1997 a712c88
update
huangzhen1997 8c02e8b
remove file
huangzhen1997 bad1acb
revert
huangzhen1997 6023de7
update
huangzhen1997 23d9c80
update
huangzhen1997 82185a0
update version
huangzhen1997 8f42923
revert
huangzhen1997 4fdf7f7
downgrade version
huangzhen1997 b0b8d31
go mod tidy
huangzhen1997 85dfafd
tidy
huangzhen1997 9ec6505
add token indexes
huangzhen1997 a5b661d
update comment
huangzhen1997 e169af2
Merge branch 'solana-offchain-plugin' into NONEVM-935/implement-ccip-…
huangzhen1997 a52044d
gomod
huangzhen1997 3f4929a
part 1
huangzhen1997 d5413ae
fix lint
huangzhen1997 03ae3ee
data type
huangzhen1997 6ecbec2
make generate
huangzhen1997 67d689c
update with new generated go binding
huangzhen1997 e9abe63
Merge branch 'solana-offchain-plugin' into NONEVM-935/implement-ccip-…
huangzhen1997 9497f40
mod tidy
huangzhen1997 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"chainlink": minor | ||
--- | ||
|
||
Solana CCIP plugin codec support for both commit and execute report #added |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package ccipsolana | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"fmt" | ||
"math/big" | ||
|
||
agbinary "github.com/gagliardetto/binary" | ||
"github.com/gagliardetto/solana-go" | ||
|
||
"github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router" | ||
"github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common" | ||
cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" | ||
) | ||
|
||
// CommitPluginCodecV1 is a codec for encoding and decoding commit plugin reports. | ||
// Compatible with: | ||
// - "OffRamp 1.6.0-dev" | ||
type CommitPluginCodecV1 struct{} | ||
|
||
func NewCommitPluginCodecV1() *CommitPluginCodecV1 { | ||
return &CommitPluginCodecV1{} | ||
} | ||
|
||
func (c *CommitPluginCodecV1) Encode(ctx context.Context, report cciptypes.CommitPluginReport) ([]byte, error) { | ||
var buf bytes.Buffer | ||
encoder := agbinary.NewBorshEncoder(&buf) | ||
mr := ccip_router.MerkleRoot{} | ||
|
||
if len(report.MerkleRoots) != 0 { | ||
huangzhen1997 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
mr = ccip_router.MerkleRoot{ | ||
SourceChainSelector: uint64(report.MerkleRoots[0].ChainSel), | ||
OnRampAddress: report.MerkleRoots[0].OnRampAddress, | ||
MinSeqNr: uint64(report.MerkleRoots[0].SeqNumsRange.Start()), | ||
MaxSeqNr: uint64(report.MerkleRoots[0].SeqNumsRange.End()), | ||
MerkleRoot: report.MerkleRoots[0].MerkleRoot, | ||
} | ||
} | ||
|
||
tpu := make([]ccip_router.TokenPriceUpdate, 0, len(report.PriceUpdates.TokenPriceUpdates)) | ||
for _, update := range report.PriceUpdates.TokenPriceUpdates { | ||
token, err := solana.PublicKeyFromBase58(string(update.TokenID)) | ||
if err != nil { | ||
return nil, fmt.Errorf("invalid token address: %s, %w", update.TokenID, err) | ||
} | ||
if update.Price.IsEmpty() { | ||
return nil, fmt.Errorf("empty price for token: %s", update.TokenID) | ||
} | ||
tpu = append(tpu, ccip_router.TokenPriceUpdate{ | ||
SourceToken: token, | ||
UsdPerToken: common.To28BytesBE(update.Price.Int.Uint64()), | ||
}) | ||
} | ||
|
||
gpu := make([]ccip_router.GasPriceUpdate, 0, len(report.PriceUpdates.GasPriceUpdates)) | ||
for _, update := range report.PriceUpdates.GasPriceUpdates { | ||
gpu = append(gpu, ccip_router.GasPriceUpdate{ | ||
DestChainSelector: uint64(update.ChainSel), | ||
UsdPerUnitGas: common.To28BytesBE(update.GasPrice.Int.Uint64()), | ||
huangzhen1997 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}) | ||
} | ||
|
||
commit := ccip_router.CommitInput{ | ||
MerkleRoot: mr, | ||
PriceUpdates: ccip_router.PriceUpdates{ | ||
TokenPriceUpdates: tpu, | ||
GasPriceUpdates: gpu, | ||
}, | ||
} | ||
|
||
err := commit.MarshalWithEncoder(encoder) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return buf.Bytes(), nil | ||
} | ||
|
||
func (c *CommitPluginCodecV1) Decode(ctx context.Context, bytes []byte) (cciptypes.CommitPluginReport, error) { | ||
decoder := agbinary.NewBorshDecoder(bytes) | ||
commitReport := ccip_router.CommitInput{} | ||
err := commitReport.UnmarshalWithDecoder(decoder) | ||
if err != nil { | ||
return cciptypes.CommitPluginReport{}, err | ||
} | ||
|
||
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)) | ||
for _, update := range commitReport.PriceUpdates.TokenPriceUpdates { | ||
tokenPriceUpdates = append(tokenPriceUpdates, cciptypes.TokenPrice{ | ||
TokenID: cciptypes.UnknownEncodedAddress(update.SourceToken.String()), | ||
Price: priceHelper(update.UsdPerToken[:]), | ||
}) | ||
} | ||
|
||
gasPriceUpdates := make([]cciptypes.GasPriceChain, 0, len(commitReport.PriceUpdates.GasPriceUpdates)) | ||
for _, update := range commitReport.PriceUpdates.GasPriceUpdates { | ||
gasPriceUpdates = append(gasPriceUpdates, cciptypes.GasPriceChain{ | ||
GasPrice: priceHelper(update.UsdPerUnitGas[:]), | ||
ChainSel: cciptypes.ChainSelector(update.DestChainSelector), | ||
}) | ||
} | ||
|
||
return cciptypes.CommitPluginReport{ | ||
MerkleRoots: merkleRoots, | ||
PriceUpdates: cciptypes.PriceUpdates{ | ||
TokenPriceUpdates: tokenPriceUpdates, | ||
GasPriceUpdates: gasPriceUpdates, | ||
}, | ||
}, nil | ||
} | ||
|
||
func priceHelper(input []byte) cciptypes.BigInt { | ||
var tokenPrice cciptypes.BigInt | ||
price := new(big.Int).SetBytes(input) | ||
if price.Int64() == 0 { | ||
tokenPrice = cciptypes.NewBigInt(big.NewInt(0)) | ||
} else { | ||
tokenPrice = cciptypes.NewBigInt(price) | ||
} | ||
|
||
return tokenPrice | ||
} | ||
|
||
// Ensure CommitPluginCodec implements the CommitPluginCodec interface | ||
var _ cciptypes.CommitPluginCodec = (*CommitPluginCodecV1)(nil) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package ccipsolana | ||
|
||
import ( | ||
"math/big" | ||
"math/rand" | ||
"testing" | ||
|
||
solanago "github.com/gagliardetto/solana-go" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" | ||
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" | ||
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils" | ||
) | ||
|
||
var randomCommitReport = func() cciptypes.CommitPluginReport { | ||
pubkey, err := solanago.NewRandomPrivateKey() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
return cciptypes.CommitPluginReport{ | ||
MerkleRoots: []cciptypes.MerkleRootChain{ | ||
{ | ||
OnRampAddress: cciptypes.UnknownAddress(pubkey.PublicKey().String()), | ||
ChainSel: cciptypes.ChainSelector(rand.Uint64()), | ||
SeqNumsRange: cciptypes.NewSeqNumRange( | ||
cciptypes.SeqNum(rand.Uint64()), | ||
cciptypes.SeqNum(rand.Uint64()), | ||
), | ||
MerkleRoot: utils.RandomBytes32(), | ||
}, | ||
}, | ||
PriceUpdates: cciptypes.PriceUpdates{ | ||
TokenPriceUpdates: []cciptypes.TokenPrice{ | ||
{ | ||
TokenID: "C8WSPj3yyus1YN3yNB6YA5zStYtbjQWtpmKadmvyUXq8", | ||
Price: cciptypes.NewBigInt(big.NewInt(rand.Int63())), | ||
}, | ||
}, | ||
GasPriceUpdates: []cciptypes.GasPriceChain{ | ||
{GasPrice: cciptypes.NewBigInt(big.NewInt(rand.Int63())), ChainSel: cciptypes.ChainSelector(rand.Uint64())}, | ||
{GasPrice: cciptypes.NewBigInt(big.NewInt(rand.Int63())), ChainSel: cciptypes.ChainSelector(rand.Uint64())}, | ||
{GasPrice: cciptypes.NewBigInt(big.NewInt(rand.Int63())), ChainSel: cciptypes.ChainSelector(rand.Uint64())}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func TestCommitPluginCodecV1(t *testing.T) { | ||
testCases := []struct { | ||
name string | ||
report func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport | ||
expErr bool | ||
}{ | ||
{ | ||
name: "base report", | ||
report: func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport { | ||
return report | ||
}, | ||
}, | ||
{ | ||
name: "empty token address", | ||
report: func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport { | ||
report.PriceUpdates.TokenPriceUpdates[0].TokenID = "" | ||
return report | ||
}, | ||
expErr: true, | ||
}, | ||
{ | ||
name: "empty merkle root", | ||
report: func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport { | ||
report.MerkleRoots[0].MerkleRoot = cciptypes.Bytes32{} | ||
return report | ||
}, | ||
}, | ||
{ | ||
name: "zero token price", | ||
report: func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport { | ||
report.PriceUpdates.TokenPriceUpdates[0].Price = cciptypes.NewBigInt(big.NewInt(0)) | ||
return report | ||
}, | ||
}, | ||
{ | ||
name: "zero gas price", | ||
huangzhen1997 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
report: func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport { | ||
report.PriceUpdates.GasPriceUpdates[0].GasPrice = cciptypes.NewBigInt(big.NewInt(0)) | ||
return report | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
report := tc.report(randomCommitReport()) | ||
commitCodec := NewCommitPluginCodecV1() | ||
ctx := testutils.Context(t) | ||
encodedReport, err := commitCodec.Encode(ctx, report) | ||
if tc.expErr { | ||
assert.Error(t, err) | ||
return | ||
} | ||
require.NoError(t, err) | ||
decodedReport, err := commitCodec.Decode(ctx, encodedReport) | ||
require.NoError(t, err) | ||
require.Equal(t, report, decodedReport) | ||
}) | ||
} | ||
} | ||
|
||
func BenchmarkCommitPluginCodecV1_Encode(b *testing.B) { | ||
huangzhen1997 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
commitCodec := NewCommitPluginCodecV1() | ||
ctx := testutils.Context(b) | ||
|
||
rep := randomCommitReport() | ||
for i := 0; i < b.N; i++ { | ||
_, err := commitCodec.Encode(ctx, rep) | ||
require.NoError(b, err) | ||
} | ||
} | ||
|
||
func BenchmarkCommitPluginCodecV1_Decode(b *testing.B) { | ||
commitCodec := NewCommitPluginCodecV1() | ||
ctx := testutils.Context(b) | ||
encodedReport, err := commitCodec.Encode(ctx, randomCommitReport()) | ||
require.NoError(b, err) | ||
|
||
for i := 0; i < b.N; i++ { | ||
_, err := commitCodec.Decode(ctx, encodedReport) | ||
require.NoError(b, err) | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why can't we use the Solana Codec for this? Just define the IDL for these types, I haven't looked closely into the types being encodec, so I may be missing something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could try Solana codec, @archseer suggested to use the generated gobinding for this earlier, and I also think it makes sense as the EVM codec right now is using similar approach with the generated type.