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 TODOs #15726

Draft
wants to merge 22 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion core/scripts/setup_testdb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function exit_error {
}
# Create a new user and database for development
# This script is intended to be run on a local development machine
tdir=$(mktemp -d -t db-dev-user)
tdir=$(mktemp -d -t db-dev-user-XXXXXX)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, this worked for me when I ran it outside of nix


username="chainlink_dev"
password="insecurepassword"
Expand Down
2 changes: 2 additions & 0 deletions deployment/ccip/changeset/cs_add_lane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
)

// TODO: Solana re-write

func TestAddLanesWithTestRouter(t *testing.T) {
t.Parallel()
e := NewMemoryEnvironment(t)
Expand Down
3 changes: 2 additions & 1 deletion deployment/ccip/changeset/cs_ccip_home.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0"
capabilities_registry "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0"
)

var (
Expand Down Expand Up @@ -1051,6 +1051,7 @@ func (c UpdateChainConfigConfig) Validate(e deployment.Environment) error {
return nil
}

// TODO: can this handle solana stuff
func UpdateChainConfig(e deployment.Environment, cfg UpdateChainConfigConfig) (deployment.ChangesetOutput, error) {
if err := cfg.Validate(e); err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("%w: %w", deployment.ErrInvalidConfig, err)
Expand Down
231 changes: 231 additions & 0 deletions deployment/ccip/changeset/cs_chain_contracts_solana.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
package changeset

import (
"fmt"

"github.com/gagliardetto/solana-go"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router"
"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal"
)

// TODO:
// func (cfg UpdateOnRampDestsConfig) Validate(e deployment.Environment) error {
// state, err := LoadOnchainState(e)
// if err != nil {
// return err
// }
// supportedChains := state.SupportedChains()
// for chainSel, updates := range cfg.UpdatesByChain {
// chainState, ok := state.Chains[chainSel]
// if !ok {
// return fmt.Errorf("chain %d not found in onchain state", chainSel)
// }
// if chainState.TestRouter == nil {
// return fmt.Errorf("missing test router for chain %d", chainSel)
// }
// if chainState.Router == nil {
// return fmt.Errorf("missing router for chain %d", chainSel)
// }
// if chainState.OnRamp == nil {
// return fmt.Errorf("missing onramp onramp for chain %d", chainSel)
// }
// if err := commoncs.ValidateOwnership(e.GetContext(), cfg.MCMS != nil, e.Chains[chainSel].DeployerKey.From, chainState.Timelock.Address(), chainState.OnRamp); err != nil {
// return err
// }

// for destination := range updates {
// // Destination cannot be an unknown destination.
// if _, ok := supportedChains[destination]; !ok {
// return fmt.Errorf("destination chain %d is not a supported %s", destination, chainState.OnRamp.Address())
// }
// sc, err := chainState.OnRamp.GetStaticConfig(&bind.CallOpts{Context: e.GetContext()})
// if err != nil {
// return fmt.Errorf("failed to get onramp static config %s: %w", chainState.OnRamp.Address(), err)
// }
// if destination == sc.ChainSelector {
// return fmt.Errorf("cannot update onramp destination to the same chain")
// }
// }
// }
// return nil
// }

// UpdateOnRampsDests updates the onramp destinations for each onramp
// in the chains specified. Multichain support is important - consider when we add a new chain
// and need to update the onramp destinations for all chains to support the new chain.
func UpdateOnRampsDestsSolana(e deployment.Environment, cfg UpdateOnRampDestsConfig) (deployment.ChangesetOutput, error) {

s, err := LoadOnchainStateSolana(e)
if err != nil {
return deployment.ChangesetOutput{}, err
}
for chainSel, updates := range cfg.UpdatesByChain {
e.Logger.Infow("Updating onramp destinations", "chain", chainSel, "updates", updates)
chain := e.SolChains[chainSel]

validSourceChainConfig := ccip_router.SourceChainConfig{
OnRamp: []byte{1, 2, 3},
IsEnabled: true,
}

ccipRouterId := s.SolChains[chainSel].CcipRouter
// ccip_router.SetProgramID(ccipRouterId) //cannot set this again

for destination, update := range updates {
EvmSourceChainStatePDA := GetEvmSourceChainStatePDA(ccipRouterId, destination)
e.Logger.Infow("EvmSourceChainStatePDA", "EvmSourceChainStatePDA", EvmSourceChainStatePDA)
EvmDestChainStatePDA := GetEvmDestChainStatePDA(ccipRouterId, destination)
validDestChainConfig := ccip_router.DestChainConfig{
IsEnabled: update.IsEnabled,

// minimal valid config
DefaultTxGasLimit: 1,
MaxPerMsgGasLimit: 100,
MaxDataBytes: 32,
MaxNumberOfTokensPerMsg: 1,
// bytes4(keccak256("CCIP ChainFamilySelector EVM"))
ChainFamilySelector: [4]uint8{40, 18, 213, 44},
}

instruction, err := ccip_router.NewAddChainSelectorInstruction(
destination,
validSourceChainConfig,
validDestChainConfig,
EvmSourceChainStatePDA,
EvmDestChainStatePDA,
GetRouterConfigPDA(ccipRouterId),
chain.DeployerKey.PublicKey(),
solana.SystemProgramID,
).ValidateAndBuild()

if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %v", err)
}

err = chain.Confirm([]solana.Instruction{instruction})

if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %v", err)
} else {
e.Logger.Infow("Confirmed instruction", "instruction", instruction)
}
}
}

return deployment.ChangesetOutput{}, nil
}

func btoi(b bool) uint8 {
if b {
return 1
}
return 0
}

// SetOCR3OffRamp will set the OCR3 offramp for the given chain.
// to the active configuration on CCIPHome. This
// is used to complete the candidate->active promotion cycle, it's
// run after the candidate is confirmed to be working correctly.
// Multichain is especially helpful for NOP rotations where we have
// to touch all the chain to change signers.
func SetOCR3ConfigSolana(e deployment.Environment, cfg SetOCR3OffRampConfig) (deployment.ChangesetOutput, error) {
// if err := cfg.Validate(e); err != nil {
// return deployment.ChangesetOutput{}, err
// }

solState, err := LoadOnchainStateSolana(e)
if err != nil {
return deployment.ChangesetOutput{}, err
}
state, err := LoadOnchainState(e)
if err != nil {
return deployment.ChangesetOutput{}, err
}

// cfg.RemoteChainSels will be a bunch of solana chains
// can add this in validate
for _, remote := range cfg.RemoteChainSels {
donID, err := internal.DonIDForChain(
state.Chains[cfg.HomeChainSel].CapabilityRegistry,
state.Chains[cfg.HomeChainSel].CCIPHome,
remote)
if err != nil {
return deployment.ChangesetOutput{}, err
}
args, err := internal.BuildSetOCR3ConfigArgsSolana(donID, state.Chains[cfg.HomeChainSel].CCIPHome, remote)
if err != nil {
return deployment.ChangesetOutput{}, err
}
// set, err := isOCR3ConfigSetSolana(e.Logger, e.Chains[remote], state.Chains[remote].OffRamp, args)
// if err != nil {
// return deployment.ChangesetOutput{}, err
// }
// if set {
// e.Logger.Infof("OCR3 config already set on offramp for chain %d", remote)
// continue
// }
var instructions []solana.Instruction
ccipRouterId := solState.SolChains[remote].CcipRouter
for _, arg := range args {
instruction, err := ccip_router.NewSetOcrConfigInstruction(
uint8(arg.OcrPluginType),
ccip_router.Ocr3ConfigInfo{
ConfigDigest: arg.ConfigDigest,
F: arg.F,
IsSignatureVerificationEnabled: uint8(btoi(arg.IsSignatureVerificationEnabled)),
},
arg.Signers,
arg.Transmitters,
GetRouterConfigPDA(ccipRouterId),
GetRouterStatePDA(ccipRouterId),
e.SolChains[remote].DeployerKey.PublicKey(),
).ValidateAndBuild()
if err != nil {
return deployment.ChangesetOutput{}, err
}
instructions = append(instructions, instruction)
}
if cfg.MCMS == nil {
err := e.SolChains[remote].Confirm(instructions)
if err != nil {
return deployment.ChangesetOutput{}, err
}
}
}

return deployment.ChangesetOutput{}, nil

// var batches []timelock.BatchChainOperation
// timelocks := make(map[uint64]common.Address)
// proposers := make(map[uint64]*mcm.MCM)
// else {
// batches = append(batches, timelock.BatchChainOperation{
// ChainIdentifier: mcms.ChainIdentifier(remote),
// Batch: []mcms.Operation{
// {
// To: offRamp.Address(),
// Data: tx.Data(),
// Value: big.NewInt(0),
// },
// },
// })
// timelocks[remote] = state.Chains[remote].Timelock.Address()
// proposers[remote] = state.Chains[remote].ProposerMcm
// }
// p, err := proposalutils.BuildProposalFromBatches(
// timelocks,
// proposers,
// batches,
// "Update OCR3 config",
// cfg.MCMS.MinDelay,
// )
// if err != nil {
// return deployment.ChangesetOutput{}, err
// }
// e.Logger.Infof("Proposing OCR3 config update for", cfg.RemoteChainSels)
// return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{
// *p,
// }}, nil

}
89 changes: 89 additions & 0 deletions deployment/ccip/changeset/cs_chain_contracts_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
package changeset

import (
"fmt"
"testing"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zapcore"
"golang.org/x/exp/maps"

"github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext"

"github.com/smartcontractkit/chainlink/deployment"
commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset"
"github.com/smartcontractkit/chainlink/deployment/environment/memory"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter"
"github.com/smartcontractkit/chainlink/v2/core/logger"

solRpc "github.com/gagliardetto/solana-go/rpc"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router"
solCommomUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common"
)

func TestUpdateOnRampsDests(t *testing.T) {
Expand Down Expand Up @@ -362,3 +371,83 @@ func TestUpdateNonceManagersCS(t *testing.T) {
})
}
}

// TODO: skipping all mcms timelock stuff for now
func TestUpdateOnRampsDestsSolana(t *testing.T) {
lggr := logger.TestLogger(t)
e := memory.NewMemoryEnvironment(t, lggr, zapcore.InfoLevel, memory.MemoryEnvironmentConfig{
Bootstraps: 1,
Chains: 2,
Nodes: 4,
})
selectors := e.AllChainSelectors()
homeChainSel := selectors[0]
nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain)
require.NoError(t, err)
p2pIds := nodes.NonBootstraps().PeerIDs()
evmChainSel := selectors[0]
solChainSelector := deployment.SolanaChainSelector
lggr.Info(fmt.Sprintf("EVM: %v", evmChainSel))
lggr.Info(fmt.Sprintf("Solana: %v", solChainSelector))

e, err = commonchangeset.ApplyChangesets(t, e, nil, []commonchangeset.ChangesetApplication{
{
Changeset: commonchangeset.WrapChangeSet(DeployHomeChain),
Config: DeployHomeChainConfig{
HomeChainSel: homeChainSel,
RMNStaticConfig: NewTestRMNStaticConfig(),
RMNDynamicConfig: NewTestRMNDynamicConfig(),
NodeOperators: NewTestNodeOperator(e.Chains[homeChainSel].DeployerKey.From),
NodeP2PIDsPerNodeOpAdmin: map[string][][32]byte{
"NodeOperator": p2pIds,
},
},
},
{
Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployLinkTokenSolana),
Config: []uint64{deployment.SolanaChainSelector},
},
{
Changeset: commonchangeset.WrapChangeSet(DeployChainContractsSolana),
Config: DeployChainContractsConfig{
ChainSelectors: []uint64{deployment.SolanaChainSelector},
HomeChainSelector: homeChainSel,
},
},
{
Changeset: commonchangeset.WrapChangeSet(UpdateOnRampsDestsSolana),
Config: UpdateOnRampDestsConfig{
UpdatesByChain: map[uint64]map[uint64]OnRampDestinationUpdate{
// source: {
// dest: {
// IsEnabled: true,
// TestRouter: false,
// AllowListEnabled: false,
// },
// },
solChainSelector: {
evmChainSel: {
IsEnabled: true,
TestRouter: false,
AllowListEnabled: false,
},
},
},
MCMS: nil,
},
},
})

// UPDATE BINDINGS
require.NoError(t, err)
chain := e.SolChains[deployment.SolanaChainSelector]
state, _ := LoadOnchainStateSolana(e)
ccipRouterId := state.SolChains[deployment.SolanaChainSelector].CcipRouter
var sourceChainStateAccount ccip_router.SourceChain
err = solCommomUtil.GetAccountDataBorshInto(e.GetContext(), chain.Client, GetEvmSourceChainStatePDA(ccipRouterId, evmChainSel), solRpc.CommitmentConfirmed, &sourceChainStateAccount)
lggr.Infof(fmt.Sprintf("%+v", sourceChainStateAccount.State))
require.NoError(t, err)
require.Equal(t, uint64(1), sourceChainStateAccount.State.MinSeqNr)
require.Equal(t, true, sourceChainStateAccount.Config.IsEnabled)

}
Loading
Loading