diff --git a/contracts/scripts/native_solc_compile_all_keystone b/contracts/scripts/native_solc_compile_all_keystone index 000ec0564c3..a42b06b8f67 100755 --- a/contracts/scripts/native_solc_compile_all_keystone +++ b/contracts/scripts/native_solc_compile_all_keystone @@ -33,4 +33,3 @@ compileContract keystone/CapabilitiesRegistry.sol compileContract keystone/KeystoneForwarder.sol compileContract keystone/OCR3Capability.sol compileContract keystone/KeystoneFeedsConsumer.sol -compileContract keystone/SimpleOCR.sol diff --git a/contracts/src/v0.8/keystone/ConfirmedOwnerWithProposal.sol b/contracts/src/v0.8/keystone/ConfirmedOwnerWithProposal.sol deleted file mode 100644 index a6e3c63f963..00000000000 --- a/contracts/src/v0.8/keystone/ConfirmedOwnerWithProposal.sol +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -/// @title The ConfirmedOwner contract -/// @notice A contract with helpers for basic contract ownership. -contract ConfirmedOwnerWithProposal { - address private s_owner; - address private s_pendingOwner; - - event OwnershipTransferRequested(address indexed from, address indexed to); - event OwnershipTransferred(address indexed from, address indexed to); - - constructor(address newOwner, address pendingOwner) { - // solhint-disable-next-line gas-custom-errors - require(newOwner != address(0), "Cannot set owner to zero"); - - s_owner = newOwner; - if (pendingOwner != address(0)) { - _transferOwnership(pendingOwner); - } - } - - /// @notice Allows an owner to begin transferring ownership to a new address. - function transferOwnership(address to) public onlyOwner { - _transferOwnership(to); - } - - /// @notice Allows an ownership transfer to be completed by the recipient. - function acceptOwnership() external { - // solhint-disable-next-line gas-custom-errors - require(msg.sender == s_pendingOwner, "Must be proposed owner"); - - address oldOwner = s_owner; - s_owner = msg.sender; - s_pendingOwner = address(0); - - emit OwnershipTransferred(oldOwner, msg.sender); - } - - /// @notice Get the current owner - function owner() public view returns (address) { - return s_owner; - } - - /// @notice validate, transfer ownership, and emit relevant events - function _transferOwnership(address to) private { - // solhint-disable-next-line gas-custom-errors - require(to != msg.sender, "Cannot transfer to self"); - - s_pendingOwner = to; - - emit OwnershipTransferRequested(s_owner, to); - } - - /// @notice validate access - function _validateOwnership() internal view { - // solhint-disable-next-line gas-custom-errors - require(msg.sender == s_owner, "Only callable by owner"); - } - - /// @notice Reverts if called by anyone other than the contract owner. - modifier onlyOwner() { - _validateOwnership(); - _; - } -} diff --git a/contracts/src/v0.8/keystone/SimpleOCR.sol b/contracts/src/v0.8/keystone/SimpleOCR.sol deleted file mode 100644 index d76add9c2ad..00000000000 --- a/contracts/src/v0.8/keystone/SimpleOCR.sol +++ /dev/null @@ -1,284 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.24; - -import {ConfirmedOwnerWithProposal} from "./ConfirmedOwnerWithProposal.sol"; - -/** - * @notice Onchain verification of reports from the offchain reporting protocol - * @dev For details on its operation, see the offchain reporting protocol design - * doc, which refers to this contract as simply the "contract". - */ -contract SimpleOCR is ConfirmedOwnerWithProposal { - error InvalidConfig(string message); - - /** - * @notice triggers a new run of the offchain reporting protocol - * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis - * @param configDigest configDigest of this configuration - * @param configCount ordinal number of this config setting among all config settings over the life of this contract - * @param signers ith element is address ith oracle uses to sign a report - * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method - * @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly - * @param onchainConfig serialized configuration used by the contract (and possibly oracles) - * @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter - * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract - */ - event ConfigSet( - uint32 previousConfigBlockNumber, - bytes32 configDigest, - uint64 configCount, - address[] signers, - address[] transmitters, - uint8 f, - bytes onchainConfig, - uint64 offchainConfigVersion, - bytes offchainConfig - ); - - constructor() ConfirmedOwnerWithProposal(msg.sender, address(0)) {} - - function typeAndVersion() external pure returns (string memory) { - return "Simple OCR 1.0.0"; - } - - // Maximum number of oracles the offchain reporting protocol is designed for - uint256 internal constant MAX_NUM_ORACLES = 31; - // incremented each time a new config is posted. This count is incorporated - // into the config digest, to prevent replay attacks. - uint32 internal s_configCount; - uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems - // to extract config from logs. - - // Storing these fields used on the hot path in a ConfigInfo variable reduces the - // retrieval of all of them to a single SLOAD. If any further fields are - // added, make sure that storage of the struct still takes at most 32 bytes. - struct ConfigInfo { - bytes32 latestConfigDigest; - uint8 f; - uint8 n; - } - ConfigInfo internal s_configInfo; - - // Used for s_oracles[a].role, where a is an address, to track the purpose - // of the address, or to indicate that the address is unset. - enum Role { - // No oracle role has been set for address a - Unset, - // Signing address for the s_oracles[a].index'th oracle. I.e., report - // signatures from this oracle should ecrecover back to address a. - Signer, - Transmitter - } - - struct Oracle { - uint8 index; // Index of oracle in s_signers/s_transmitters - Role role; // Role of the address which mapped to this struct - } - - mapping(address signerOrTransmitter => Oracle) internal s_oracles; - - // s_signers contains the signing address of each oracle - address[] internal s_signers; - - // s_transmitters contains the transmission address of each oracle, - // i.e. the address the oracle actually sends transactions to the contract from - address[] internal s_transmitters; - - /* - * Config logic - */ - - // Reverts transaction if config args are invalid - modifier checkConfigValid( - uint256 numSigners, - uint256 numTransmitters, - uint256 f - ) { - if (numSigners > MAX_NUM_ORACLES) - revert InvalidConfig("too many signers"); - if (f == 0) revert InvalidConfig("f must be positive"); - if (numSigners != numTransmitters) - revert InvalidConfig("oracle addresses out of registration"); - if (numSigners <= 3 * f) - revert InvalidConfig("faulty-oracle f too high"); - _; - } - - // solhint-disable-next-line gas-struct-packing - struct SetConfigArgs { - address[] signers; - address[] transmitters; - uint8 f; - bytes onchainConfig; - uint64 offchainConfigVersion; - bytes offchainConfig; - } - - /** - * @notice optionally returns the latest configDigest and epoch for which a - report was successfully transmitted. Alternatively, the contract may return - scanLogs set to true and use Transmitted events to provide this information - to offchain watchers. - * @return scanLogs indicates whether to rely on the configDigest and epoch - returned or whether to scan logs for the Transmitted event instead. - * @return configDigest - * @return epoch - */ - function latestConfigDigestAndEpoch() - external - view - virtual - returns (bool scanLogs, bytes32 configDigest, uint32 epoch) - { - return (true, bytes32(0), uint32(0)); - } - - /** - * @notice sets offchain reporting protocol configuration incl. participating oracles - * @param _signers addresses with which oracles sign the reports - * @param _transmitters addresses oracles use to transmit the reports - * @param _f number of faulty oracles the system can tolerate - * @param _onchainConfig encoded on-chain contract configuration - * @param _offchainConfigVersion version number for offchainEncoding schema - * @param _offchainConfig encoded off-chain oracle configuration - */ - function setConfig( - address[] memory _signers, - address[] memory _transmitters, - uint8 _f, - bytes memory _onchainConfig, - uint64 _offchainConfigVersion, - bytes memory _offchainConfig - ) - external - checkConfigValid(_signers.length, _transmitters.length, _f) - onlyOwner - { - SetConfigArgs memory args = SetConfigArgs({ - signers: _signers, - transmitters: _transmitters, - f: _f, - onchainConfig: _onchainConfig, - offchainConfigVersion: _offchainConfigVersion, - offchainConfig: _offchainConfig - }); - - while (s_signers.length != 0) { - // remove any old signer/transmitter addresses - uint256 lastIdx = s_signers.length - 1; - address signer = s_signers[lastIdx]; - address transmitter = s_transmitters[lastIdx]; - delete s_oracles[signer]; - delete s_oracles[transmitter]; - s_signers.pop(); - s_transmitters.pop(); - } - - // Bounded by MAX_NUM_ORACLES in OCR2Abstract.sol - for (uint256 i = 0; i < args.signers.length; i++) { - if (args.signers[i] == address(0)) - revert InvalidConfig("signer must not be empty"); - if (args.transmitters[i] == address(0)) - revert InvalidConfig("transmitter must not be empty"); - // add new signer/transmitter addresses - if (s_oracles[args.signers[i]].role != Role.Unset) - revert InvalidConfig("repeated signer address"); - s_oracles[args.signers[i]] = Oracle(uint8(i), Role.Signer); - if (s_oracles[args.transmitters[i]].role != Role.Unset) - revert InvalidConfig("repeated transmitter address"); - s_oracles[args.transmitters[i]] = Oracle( - uint8(i), - Role.Transmitter - ); - s_signers.push(args.signers[i]); - s_transmitters.push(args.transmitters[i]); - } - s_configInfo.f = args.f; - uint32 previousConfigBlockNumber = s_latestConfigBlockNumber; - s_latestConfigBlockNumber = uint32(block.number); - s_configCount += 1; - { - s_configInfo.latestConfigDigest = _configDigestFromConfigData( - block.chainid, - address(this), - s_configCount, - args.signers, - args.transmitters, - args.f, - args.onchainConfig, - args.offchainConfigVersion, - args.offchainConfig - ); - } - s_configInfo.n = uint8(args.signers.length); - - emit ConfigSet( - previousConfigBlockNumber, - s_configInfo.latestConfigDigest, - s_configCount, - args.signers, - args.transmitters, - args.f, - args.onchainConfig, - args.offchainConfigVersion, - args.offchainConfig - ); - } - - function _configDigestFromConfigData( - uint256 _chainId, - address _contractAddress, - uint64 _configCount, - address[] memory _signers, - address[] memory _transmitters, - uint8 _f, - bytes memory _onchainConfig, - uint64 _encodedConfigVersion, - bytes memory _encodedConfig - ) internal pure returns (bytes32) { - uint256 h = uint256( - keccak256( - abi.encode( - _chainId, - _contractAddress, - _configCount, - _signers, - _transmitters, - _f, - _onchainConfig, - _encodedConfigVersion, - _encodedConfig - ) - ) - ); - uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 - uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 - return bytes32((prefix & prefixMask) | (h & ~prefixMask)); - } - - /** - * @notice information about current offchain reporting protocol configuration - * @return configCount ordinal number of current config, out of all configs applied to this contract so far - * @return blockNumber block at which this config was set - * @return configDigest domain-separation tag for current config (see __configDigestFromConfigData) - */ - function latestConfigDetails() - external - view - returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) - { - return ( - s_configCount, - s_latestConfigBlockNumber, - s_configInfo.latestConfigDigest - ); - } - - /** - * @return list of addresses permitted to transmit reports to this contract - * @dev The list will match the order used to specify the transmitter during setConfig - */ - function transmitters() external view returns (address[] memory) { - return s_transmitters; - } -} diff --git a/core/capabilities/registry.go b/core/capabilities/registry.go index 1d263ebfb8c..0b49ac571a6 100644 --- a/core/capabilities/registry.go +++ b/core/capabilities/registry.go @@ -151,7 +151,6 @@ func (r *Registry) List(_ context.Context) ([]capabilities.BaseCapability, error func (r *Registry) Add(ctx context.Context, c capabilities.BaseCapability) error { r.mu.Lock() defer r.mu.Unlock() - r.lggr.Info("DSK: Adding capability") info, err := c.Info(ctx) if err != nil { @@ -159,8 +158,6 @@ func (r *Registry) Add(ctx context.Context, c capabilities.BaseCapability) error return err } - r.lggr.Infow("DSK: Adding capability", "id", info.ID, "type", info.CapabilityType, "description", info.Description, "version", info.Version()) - switch info.CapabilityType { case capabilities.CapabilityTypeTrigger: _, ok := c.(capabilities.TriggerCapability) diff --git a/core/services/ocr2/plugins/generic/oraclefactory.go b/core/services/ocr2/plugins/generic/oraclefactory.go index f5936bea7de..7d44a239d2e 100644 --- a/core/services/ocr2/plugins/generic/oraclefactory.go +++ b/core/services/ocr2/plugins/generic/oraclefactory.go @@ -5,12 +5,10 @@ import ( "encoding/json" "errors" "fmt" - "time" "github.com/prometheus/client_golang/prometheus" ocr "github.com/smartcontractkit/libocr/offchainreporting2plus" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" - ocr2plustypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -105,18 +103,9 @@ func (of *oracleFactory) NewOracle(ctx context.Context, args core.OracleArgs) (c oracle, err := ocr.NewOracle(ocr.OCR3OracleArgs[[]byte]{ // We are relying on the relayer plugin provider for the offchain config digester // and the contract config tracker to save time. - ContractConfigTracker: pluginProvider.ContractConfigTracker(), - OffchainConfigDigester: pluginProvider.OffchainConfigDigester(), - // TODO: Allow oracles to overwrite the local config - LocalConfig: ocr2plustypes.LocalConfig{ - BlockchainTimeout: time.Second * 20, - ContractConfigTrackerPollInterval: time.Second * 10, - ContractConfigLoadTimeout: time.Second * 10, - ContractConfigConfirmations: 1, - ContractTransmitterTransmitTimeout: time.Second * 10, - DatabaseTimeout: time.Second * 10, - DefaultMaxDurationInitialization: time.Second * 30, - }, + ContractConfigTracker: pluginProvider.ContractConfigTracker(), + OffchainConfigDigester: pluginProvider.OffchainConfigDigester(), + LocalConfig: args.LocalConfig, ContractTransmitter: NewContractTransmitter(of.transmitterID, args.ContractTransmitter), ReportingPluginFactory: args.ReportingPluginFactoryService, BinaryNetworkEndpointFactory: of.peerWrapper.Peer2, diff --git a/e2e/capabilities/kvstore b/e2e/capabilities/kvstore deleted file mode 100755 index b80b621296b..00000000000 Binary files a/e2e/capabilities/kvstore and /dev/null differ diff --git a/e2e/capabilities/workflow_test.go b/e2e/capabilities/workflow_test.go index 6c0f15ea3de..ba2b8122f69 100644 --- a/e2e/capabilities/workflow_test.go +++ b/e2e/capabilities/workflow_test.go @@ -254,6 +254,7 @@ func generateOCR3Config( func TestWorkflow(t *testing.T) { workflowOwner := "0x00000000000000000000000000000000000000aa" workflowName := "ccipethsep" + feedID := "0x0003fbba4fce42f65d6032b18aee53efdf526cc734ad296cb57565979d883bdd" t.Run("smoke test", func(t *testing.T) { in, err := framework.Load[WorkflowTestConfig](t) @@ -531,8 +532,7 @@ triggers: config: maxFrequencyMs: 15000 feedIds: - - '0x0003fbba4fce42f65d6032b18aee53efdf526cc734ad296cb57565979d883bdd' - - '0x0003c317fec7fad514c67aacc6366bf2f007ce37100e3cddcacd0ccaa1f3746d' + - '%s' consensus: - id: offchain_reporting@1.0.0 ref: ccip_feeds @@ -546,14 +546,10 @@ consensus: aggregation_config: allowedPartialStaleness: '0.5' feeds: - '0x0003fbba4fce42f65d6032b18aee53efdf526cc734ad296cb57565979d883bdd': + '%s': deviation: '0.05' heartbeat: 3600 remappedID: '0x666666666666' - '0x0003c317fec7fad514c67aacc6366bf2f007ce37100e3cddcacd0ccaa1f3746d': - deviation: '0.05' - heartbeat: 3600 - remappedID: '0x777777777777' encoder: EVM encoder_config: abi: '(bytes32 FeedID, uint224 Price, uint32 Timestamp)[] Reports' @@ -568,6 +564,8 @@ targets: """`, workflowName, workflowOwner, + feedID, + feedID, bc.ChainID, feedsConsumerAddress, ) @@ -704,25 +702,29 @@ targets: _, err = bind.WaitMined(context.Background(), sc.Client, tx) require.NoError(t, err) - // First rounds start after a delay of approx. 2 minutes! - - // ✅ Add bootstrap spec - // ✅ 1. Deploy mock streams capability - // ✅ 2. Add boostrap job spec - // ✅ - Starts successfully (search for "BootstrapperV2: Started listening") - // ✅ 3. Add OCR3 capability - // ✅ - This starts successfully (search for "OCREndpointV2: Initialized") - // ✅ 3. Deploy and configure OCR3 contract - // ✅ 4. Add chain write capabilities - // ✅ - Check if they are added (search for "capability added") - // ✅ - Check if they are added - // ✅ 5. Deploy capabilities registry - // ✅ - Add nodes to registry - // ✅ - Add capabilities to registry - // ✅ 6. Deploy Forwarder - // ✅ - Configure forwarder (search for "Transaction finalized") - // ✅ 7. Deploy Feeds Consumer - // ✅ - Add Keystone workflow (search for "Keystone CCIP Feeds Workflow") - // - Configure Feeds Consumer to allow workflow reports + // OCR rounds can take a while to start. I've observed 2+ minutes during local tests. + timeout := 3 * time.Minute + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + for { + select { + case <-ctx.Done(): + t.Fatalf("feed did not update, timeout after %s", timeout) + + case <-time.After(5 * time.Second): + price, timestamp, err := feedsConsumerContract.GetPrice( + sc.NewCallOpts(), + common.HexToHash(feedID), + ) + require.NoError(t, err) + if price.String() != "0" && timestamp != 0 { + fmt.Printf("Feed updated - price and timestamp set to %s and %d", price, timestamp) + return + } else { + fmt.Println("Feed not updated yet - price and timestamp not set yet") + } + } + } }) }