diff --git a/core/capabilities/ccip/delegate.go b/core/capabilities/ccip/delegate.go index 02dff6a2c9c..16b67bbb36c 100644 --- a/core/capabilities/ccip/delegate.go +++ b/core/capabilities/ccip/delegate.go @@ -43,7 +43,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -251,10 +250,6 @@ func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job) error { func (d *Delegate) getOCRKeys(ocrKeyBundleIDs job.JSONConfig) (map[string]ocr2key.KeyBundle, error) { ocrKeys := make(map[string]ocr2key.KeyBundle) for networkType, bundleIDRaw := range ocrKeyBundleIDs { - if networkType != relay.NetworkEVM { - return nil, fmt.Errorf("unsupported chain type: %s", networkType) - } - bundleID, ok := bundleIDRaw.(string) if !ok { return nil, fmt.Errorf("OCRKeyBundleIDs must be a map of chain types to OCR key bundle IDs, got: %T", bundleIDRaw) diff --git a/core/capabilities/ccip/oraclecreator/bootstrap.go b/core/capabilities/ccip/oraclecreator/bootstrap.go index ca4cf9ec6cd..993cd46a672 100644 --- a/core/capabilities/ccip/oraclecreator/bootstrap.go +++ b/core/capabilities/ccip/oraclecreator/bootstrap.go @@ -11,6 +11,7 @@ import ( "time" mapset "github.com/deckarep/golang-set/v2" + logger2 "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/ethereum/go-ethereum/common/hexutil" diff --git a/core/capabilities/ccip/oraclecreator/plugin.go b/core/capabilities/ccip/oraclecreator/plugin.go index 57502d9aac0..a56ccf856f5 100644 --- a/core/capabilities/ccip/oraclecreator/plugin.go +++ b/core/capabilities/ccip/oraclecreator/plugin.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io" - "math/big" "time" "github.com/ethereum/go-ethereum/common" @@ -35,7 +34,6 @@ import ( evmconfig "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/configs/evm" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ocrimpls" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" @@ -44,7 +42,6 @@ import ( evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" - "github.com/smartcontractkit/chainlink/v2/evm/assets" ) var _ cctypes.OracleCreator = &pluginOracleCreator{} @@ -216,6 +213,37 @@ func (i *pluginOracleCreator) Create(ctx context.Context, donID uint32, config c return newWrappedOracle(oracle, closers), nil } +type plugin struct { + CommitPluginCodec cciptypes.CommitPluginCodec + ExecutePluginCodec cciptypes.ExecutePluginCodec + ExtraArgsCodec cciptypes.ExtraDataCodec + MessageHasher func(lggr logger.Logger) cciptypes.MessageHasher + TokenDataEncoder cciptypes.TokenDataEncoder + GasEstimateProvider cciptypes.EstimateProvider + RMNCrypto func(lggr logger.Logger) cciptypes.RMNCrypto +} + +var plugins = map[string]plugin{ + chainsel.FamilyEVM: { + CommitPluginCodec: ccipevm.NewCommitPluginCodecV1(), + ExecutePluginCodec: ccipevm.NewExecutePluginCodecV1(), + ExtraArgsCodec: ccipevm.ExtraArgsCodec{}, + MessageHasher: func(lggr logger.Logger) cciptypes.MessageHasher { return ccipevm.NewMessageHasherV1(lggr) }, + TokenDataEncoder: ccipevm.NewEVMTokenDataEncoder(), + GasEstimateProvider: ccipevm.NewGasEstimateProvider(), + RMNCrypto: func(lggr logger.Logger) cciptypes.RMNCrypto { return ccipevm.NewEVMRMNCrypto(lggr) }, + }, + chainsel.FamilySolana: { + CommitPluginCodec: nil, + ExecutePluginCodec: nil, + ExtraArgsCodec: nil, + MessageHasher: func(lggr logger.Logger) cciptypes.MessageHasher { return nil }, + TokenDataEncoder: nil, + GasEstimateProvider: nil, + RMNCrypto: func(lggr logger.Logger) cciptypes.RMNCrypto { return nil }, + }, +} + func (i *pluginOracleCreator) createFactoryAndTransmitter( donID uint32, config cctypes.OCR3ConfigWithMeta, @@ -234,6 +262,16 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( return nil, nil, fmt.Errorf("unsupported chain selector %d %w", config.Config.ChainSelector, err) } + chainFamily, err := chainsel.GetSelectorFamily(uint64(config.Config.ChainSelector)) + if err != nil { + return nil, nil, fmt.Errorf("unsupported chain selector %d %w", config.Config.ChainSelector, err) + } + plugin, exists := plugins[chainFamily] + if !exists { + return nil, nil, fmt.Errorf("unsupported chain %v", chainFamily) + } + messageHasher := plugin.MessageHasher(i.lggr.Named(chainFamily).Named("MessageHasherV1")) + if config.Config.PluginType == uint8(cctypes.PluginTypeCCIPCommit) { if !i.peerWrapper.IsStarted() { return nil, nil, fmt.Errorf("peer wrapper is not started") @@ -249,7 +287,7 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( publicConfig.DeltaRound, ) - rmnCrypto := ccipevm.NewEVMRMNCrypto(i.lggr.Named("EVMRMNCrypto")) + rmnCrypto := plugin.RMNCrypto(i.lggr.Named(chainFamily).Named("RMNCrypto")) factory = commitocr3.NewPluginFactory( i.lggr. @@ -259,9 +297,9 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( Named(hexutil.Encode(config.Config.OfframpAddress)), donID, ccipreaderpkg.OCR3ConfigWithMeta(config), - ccipevm.NewCommitPluginCodecV1(), - ccipevm.NewMessageHasherV1(i.lggr.Named("MessageHasherV1")), - ccipevm.NewExtraArgsCodec(), + plugin.CommitPluginCodec, + messageHasher, + plugin.ExtraArgsCodec, i.homeChainReader, i.homeChainSelector, contractReaders, @@ -282,12 +320,12 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( Named(hexutil.Encode(config.Config.OfframpAddress)), donID, ccipreaderpkg.OCR3ConfigWithMeta(config), - ccipevm.NewExecutePluginCodecV1(), - ccipevm.NewMessageHasherV1(i.lggr.Named("MessageHasherV1")), - ccipevm.NewExtraArgsCodec(), + plugin.ExecutePluginCodec, + messageHasher, + plugin.ExtraArgsCodec, i.homeChainReader, - ccipevm.NewEVMTokenDataEncoder(), - ccipevm.NewGasEstimateProvider(), + plugin.TokenDataEncoder, + plugin.GasEstimateProvider, contractReaders, chainWriters, ) @@ -328,9 +366,9 @@ func (i *pluginOracleCreator) createReadersAndWriters( execBatchGasLimit = defaultExecGasLimit } - homeChainID, err := i.getChainID(i.homeChainSelector) + homeChainID, err := chainsel.GetChainIDFromSelector(uint64(i.homeChainSelector)) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get chain ID from chain selector %d: %w", i.homeChainSelector, err) } contractReaders := make(map[cciptypes.ChainSelector]types.ContractReader) @@ -338,7 +376,8 @@ func (i *pluginOracleCreator) createReadersAndWriters( for relayID, relayer := range i.relayers { chainID := relayID.ChainID relayChainFamily := relayID.Network - chainSelector, err1 := i.getChainSelector(chainID, relayChainFamily) + chainDetails, err1 := chainsel.GetChainDetailsByChainIDAndFamily(chainID, relayChainFamily) + chainSelector := cciptypes.ChainSelector(chainDetails.ChainSelector) if err1 != nil { return nil, nil, fmt.Errorf("failed to get chain selector from chain ID %s: %w", chainID, err1) } @@ -421,22 +460,6 @@ func decodeAndValidateOffchainConfig( return ofc, nil } -func (i *pluginOracleCreator) getChainSelector(chainID string, chainFamily string) (cciptypes.ChainSelector, error) { - chainDetails, err := chainsel.GetChainDetailsByChainIDAndFamily(chainID, chainFamily) - if err != nil { - return 0, fmt.Errorf("failed to get chain selector from chain ID %s and family %s", chainID, chainFamily) - } - return cciptypes.ChainSelector(chainDetails.ChainSelector), nil -} - -func (i *pluginOracleCreator) getChainID(chainSelector cciptypes.ChainSelector) (string, error) { - chainID, err := chainsel.GetChainIDFromSelector(uint64(chainSelector)) - if err != nil { - return "", fmt.Errorf("failed to get chain ID from chain selector %d: %w", chainSelector, err) - } - return chainID, nil -} - func getChainReaderConfig( lggr logger.Logger, chainID string, @@ -520,33 +543,6 @@ func createChainWriter( return cw, nil } -func getKeySpecificMaxGasPrice(evmConfigs toml.EVMConfigs, chainID *big.Int, fromAddress common.Address) *assets.Wei { - var maxGasPrice *assets.Wei - - // If a chain is enabled it should have some configuration in the TOML config - // of the chainlink node. - for _, config := range evmConfigs { - if config.ChainID.ToInt().Cmp(chainID) != 0 { - continue - } - - // find the key-specific max gas price for the given fromAddress. - for _, keySpecific := range config.KeySpecific { - if keySpecific.Key.Address() == fromAddress { - maxGasPrice = keySpecific.GasEstimator.PriceMax - } - } - - // if we didn't find a key-specific max gas price, use the one specified - // in the gas estimator config, which should have a default value. - if maxGasPrice == nil { - maxGasPrice = config.GasEstimator.PriceMax - } - } - - return maxGasPrice -} - type offChainConfig struct { commitOffchainConfig *pluginconfig.CommitOffchainConfig execOffchainConfig *pluginconfig.ExecuteOffchainConfig diff --git a/core/services/keystore/keys/ocr2key/solana_keyring.go b/core/services/keystore/keys/ocr2key/solana_keyring.go index a5fa2f77dc0..e9a017c3ce5 100644 --- a/core/services/keystore/keys/ocr2key/solana_keyring.go +++ b/core/services/keystore/keys/ocr2key/solana_keyring.go @@ -7,7 +7,6 @@ import ( "io" "github.com/ethereum/go-ethereum/crypto" - "github.com/pkg/errors" "github.com/smartcontractkit/libocr/offchainreporting2/types" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -49,7 +48,15 @@ func (skr *solanaKeyring) Sign(reportCtx ocrtypes.ReportContext, report ocrtypes } func (skr *solanaKeyring) Sign3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) (signature []byte, err error) { - return nil, errors.New("not implemented") + return skr.signBlob(skr.reportToSigData3(digest, seqNr, r)) +} + +func (skr *solanaKeyring) reportToSigData3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) []byte { + rawReportContext := RawReportContext3(digest, seqNr) + sigData := crypto.Keccak256(r) + sigData = append(sigData, rawReportContext[0][:]...) + sigData = append(sigData, rawReportContext[1][:]...) + return crypto.Keccak256(sigData) } func (skr *solanaKeyring) signBlob(b []byte) (sig []byte, err error) { @@ -62,7 +69,8 @@ func (skr *solanaKeyring) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx } func (skr *solanaKeyring) Verify3(publicKey ocrtypes.OnchainPublicKey, cd ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report, signature []byte) bool { - return false + hash := skr.reportToSigData3(cd, seqNr, r) + return skr.verifyBlob(publicKey, hash, signature) } func (skr *solanaKeyring) verifyBlob(pubkey types.OnchainPublicKey, b, sig []byte) bool { diff --git a/deployment/ccip/changeset/cs_jobspec.go b/deployment/ccip/changeset/cs_jobspec.go index cc75ea31960..ffa331021c5 100644 --- a/deployment/ccip/changeset/cs_jobspec.go +++ b/deployment/ccip/changeset/cs_jobspec.go @@ -8,11 +8,12 @@ import ( "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" + chainsel "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/validate" corejob "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) var _ deployment.ChangeSet[any] = CCIPCapabilityJobspecChangeset @@ -54,6 +55,24 @@ func CCIPCapabilityJobspecChangeset(env deployment.Environment, _ any) (deployme // Find the bootstrap nodes nodesToJobSpecs := make(map[string][]string) for _, node := range nodes { + // pick first keybundle of each type (by default nodes will auto create one key of each type for each defined chain family) + keyBundles := map[string]string{} + for details, config := range node.SelToOCRConfig { + family, err := chainsel.GetSelectorFamily(details.ChainSelector) + if err != nil { + env.Logger.Warnf("skipping unknown/invalid chain family for selector %v", details.ChainSelector) + continue + } + _, exists := keyBundles[family] + if exists { + if keyBundles[family] != config.KeyBundleID { + return deployment.ChangesetOutput{}, fmt.Errorf("multiple different %v OCR keys found for node %v", family, node.PeerID) + } + continue + } + keyBundles[family] = config.KeyBundleID + } + var spec string var err error if !node.IsBootstrap { @@ -61,13 +80,10 @@ func CCIPCapabilityJobspecChangeset(env deployment.Environment, _ any) (deployme P2PV2Bootstrappers: nodes.BootstrapLocators(), CapabilityVersion: internal.CapabilityVersion, CapabilityLabelledName: internal.CapabilityLabelledName, - OCRKeyBundleIDs: map[string]string{ - // TODO: Validate that that all EVM chains are using the same keybundle. - relay.NetworkEVM: node.FirstOCRKeybundle().KeyBundleID, - }, - P2PKeyID: node.PeerID.String(), - RelayConfigs: nil, - PluginConfig: map[string]any{}, + OCRKeyBundleIDs: keyBundles, + P2PKeyID: node.PeerID.String(), + RelayConfigs: nil, + PluginConfig: map[string]any{}, }) } else { spec, err = validate.NewCCIPSpecToml(validate.SpecArgs{ @@ -75,10 +91,9 @@ func CCIPCapabilityJobspecChangeset(env deployment.Environment, _ any) (deployme CapabilityVersion: internal.CapabilityVersion, CapabilityLabelledName: internal.CapabilityLabelledName, OCRKeyBundleIDs: map[string]string{}, - // TODO: validate that all EVM chains are using the same keybundle - P2PKeyID: node.PeerID.String(), - RelayConfigs: nil, - PluginConfig: map[string]any{}, + P2PKeyID: node.PeerID.String(), + RelayConfigs: nil, + PluginConfig: map[string]any{}, }) } if err != nil { diff --git a/deployment/environment.go b/deployment/environment.go index 3d9c6c5420a..fc14101f7dc 100644 --- a/deployment/environment.go +++ b/deployment/environment.go @@ -316,13 +316,6 @@ func (n Node) OCRConfigForChainSelector(chainSel uint64) (OCRConfig, bool) { return c, ok } -func (n Node) FirstOCRKeybundle() OCRConfig { - for _, ocrConfig := range n.SelToOCRConfig { - return ocrConfig - } - return OCRConfig{} -} - func MustPeerIDFromString(s string) p2pkey.PeerID { p := p2pkey.PeerID{} if err := p.UnmarshalString(s); err != nil {