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

add Blockscout verification #15958

Draft
wants to merge 10 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
23 changes: 23 additions & 0 deletions contracts/src/v0.8/keystone/KeystoneFeedsConsumer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ contract KeystoneFeedsConsumer is IReceiver, OwnerIsCreator {
uint32 Timestamp;
}

bytes32[] private s_feedReportsList;
mapping(bytes32 feedId => StoredFeedReport feedReport) internal s_feedReports;
address[] internal s_allowedSendersList;
mapping(address sender => bool) internal s_allowedSenders;
Expand Down Expand Up @@ -77,6 +78,7 @@ contract KeystoneFeedsConsumer is IReceiver, OwnerIsCreator {
ReceivedFeedReport[] memory feeds = abi.decode(rawReport, (ReceivedFeedReport[]));
for (uint256 i = 0; i < feeds.length; ++i) {
s_feedReports[feeds[i].FeedId] = StoredFeedReport(feeds[i].Price, feeds[i].Timestamp);
s_feedReportsList.push(feeds[i].FeedId);
emit FeedReceived(feeds[i].FeedId, feeds[i].Price, feeds[i].Timestamp);
}
}
Expand All @@ -101,6 +103,27 @@ contract KeystoneFeedsConsumer is IReceiver, OwnerIsCreator {
return (report.Price, report.Timestamp);
}

function getAllFeeds() external view returns (bytes32[] memory, uint224[] memory, uint32[] memory) {
uint256 count = s_feedReportsList.length;

// Create arrays for the results
bytes32[] memory ids = new bytes32[](count);
uint224[] memory prices = new uint224[](count);
uint32[] memory timestamps = new uint32[](count);

// Populate arrays from feed reports
for (uint256 i = 0; i < count; ++i) {
bytes32 feedId = s_feedReportsList[i];
StoredFeedReport memory report = s_feedReports[feedId];
ids[i] = feedId;
prices[i] = report.Price;
timestamps[i] = report.Timestamp;
}

return (ids, prices, timestamps);
}


function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return interfaceId == type(IReceiver).interfaceId || interfaceId == type(IERC165).interfaceId;
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
GETH_VERSION: 1.14.11
capabilities_registry: ../../../contracts/solc/v0.8.24/CapabilitiesRegistry/CapabilitiesRegistry.abi ../../../contracts/solc/v0.8.24/CapabilitiesRegistry/CapabilitiesRegistry.bin 07e0115065e833b29352017fe808dd149952b0b7fe73d0af87020966d2ece57c
feeds_consumer: ../../../contracts/solc/v0.8.24/KeystoneFeedsConsumer/KeystoneFeedsConsumer.abi ../../../contracts/solc/v0.8.24/KeystoneFeedsConsumer/KeystoneFeedsConsumer.bin 6ac5b12eff3b022a35c3c40d5ed0285bf9bfec0e3669a4b12307332a216048ca
feeds_consumer: ../../../contracts/solc/v0.8.24/KeystoneFeedsConsumer/KeystoneFeedsConsumer.abi ../../../contracts/solc/v0.8.24/KeystoneFeedsConsumer/KeystoneFeedsConsumer.bin 52760e0160e12ec83122fbff83d597cc1f9382f4dee1cf03c3fb089cc58897a4
forwarder: ../../../contracts/solc/v0.8.24/KeystoneForwarder/KeystoneForwarder.abi ../../../contracts/solc/v0.8.24/KeystoneForwarder/KeystoneForwarder.bin cb728d316f6392ae0d07e6ad94ec93897a4706f6ced7120f79f7e61282ef8152
ocr3_capability: ../../../contracts/solc/v0.8.24/OCR3Capability/OCR3Capability.abi ../../../contracts/solc/v0.8.24/OCR3Capability/OCR3Capability.bin a0adf579d004fe4d4116539cf4bc52d6b1cca9626e91329f552d04f89de9dc84
Binary file added integration-tests/capabilities/binary.wasm.br
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package capabilities_registry

import (
"context"
"fmt"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"

"github.com/smartcontractkit/chainlink-testing-framework/seth"
cr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
)

type CapabilitiesRegistryInstance struct {
Address common.Address
Contract *cr.CapabilitiesRegistry
sc *seth.Client
ExistingHashedCapabilitiesIDs [][32]byte
}

func Deploy(sc *seth.Client) (*CapabilitiesRegistryInstance, error) {
capabilitiesRegistryAddress, tx, capabilitiesRegistryContract, err := cr.DeployCapabilitiesRegistry(
sc.NewTXOpts(),
sc.Client,
)
if err != nil {
return nil, err
}

_, err = bind.WaitMined(context.Background(), sc.Client, tx)
if err != nil {
return nil, err
}

fmt.Printf("🚀 Deployed \033[1mcapabilities_registry\033[0m contract at \033[1m%s\033[0m\n", capabilitiesRegistryAddress)
return &CapabilitiesRegistryInstance{
sc: sc,
Address: capabilitiesRegistryAddress,
Contract: capabilitiesRegistryContract,
}, nil
}

func (cr *CapabilitiesRegistryInstance) AddCapabilities(capabilities []cr.CapabilitiesRegistryCapability) error {
tx, err := cr.Contract.AddCapabilities(
cr.sc.NewTXOpts(),
capabilities,
)
if err != nil {
return err
}

_, err = bind.WaitMined(context.Background(), cr.sc.Client, tx)
if err != nil {
return err
}

for _, capability := range capabilities {
hashedCapabilityID, err := cr.Contract.GetHashedCapabilityId(
cr.sc.NewCallOpts(),
capability.LabelledName,
capability.Version,
)
if err != nil {
return err
}
cr.ExistingHashedCapabilitiesIDs = append(cr.ExistingHashedCapabilitiesIDs, hashedCapabilityID)
}

return nil
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package forwarder

import (
"context"
"fmt"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"

"github.com/smartcontractkit/chainlink-testing-framework/seth"

forwarder_wrapper "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/forwarder"
)

type ForwarderInstance struct {
Address common.Address
Contract *forwarder_wrapper.KeystoneForwarder
sc *seth.Client
ExistingHashedCapabilitiesIDs [][32]byte
}

func Deploy(sc *seth.Client) (*ForwarderInstance, error) {
forwarderAddress, tx, forwarderContract, err := forwarder_wrapper.DeployKeystoneForwarder(
sc.NewTXOpts(),
sc.Client,
)
if err != nil {
return nil, err
}

_, err = bind.WaitMined(context.Background(), sc.Client, tx)
if err != nil {
return nil, err
}

fmt.Printf("🚀 Deployed \033[1mforwarder\033[0m contract at \033[1m%s\033[0m\n", forwarderAddress)
return &ForwarderInstance{
sc: sc,
Address: forwarderAddress,
Contract: forwarderContract,
}, nil
}

func (i *ForwarderInstance) SetConfig(
donID uint32,
configVersion uint32,
f uint8,
signers []common.Address,
) error {
tx, err := i.Contract.SetConfig(
i.sc.NewTXOpts(),
donID,
configVersion,
f,
signers,
)
if err != nil {
return err
}

_, err = bind.WaitMined(context.Background(), i.sc.Client, tx)
if err != nil {
return err
}

return nil
}
80 changes: 80 additions & 0 deletions integration-tests/capabilities/components/onchain/fund.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package onchain

import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"

"github.com/smartcontractkit/chainlink-testing-framework/framework"
"github.com/smartcontractkit/chainlink-testing-framework/framework/clclient"
"github.com/smartcontractkit/chainlink-testing-framework/seth"
)

func SendETH(client *ethclient.Client, privateKeyHex string, toAddress string, amount *big.Float) error {
privateKey, err := crypto.HexToECDSA(privateKeyHex)
if err != nil {
return fmt.Errorf("failed to parse private key: %w", err)
}
wei := new(big.Int)
amountWei := new(big.Float).Mul(amount, big.NewFloat(1e18))
amountWei.Int(wei)

publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
return fmt.Errorf("error casting public key to ECDSA")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
return fmt.Errorf("failed to fetch nonce: %w", err)
}

gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
return fmt.Errorf("failed to fetch gas price: %w", err)
}
gasLimit := uint64(21000) // Standard gas limit for ETH transfer

tx := types.NewTransaction(nonce, common.HexToAddress(toAddress), wei, gasLimit, gasPrice, nil)

chainID, err := client.NetworkID(context.Background())
if err != nil {
return fmt.Errorf("failed to fetch chain ID: %w", err)
}
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
if err != nil {
return fmt.Errorf("failed to sign transaction: %w", err)
}

err = client.SendTransaction(context.Background(), signedTx)
if err != nil {
return fmt.Errorf("failed to send transaction: %w", err)
}
framework.L.Info().Msgf("Transaction sent: %s", signedTx.Hash().Hex())
return nil
}

func FundNodes(sc *seth.Client, nodes []*clclient.ChainlinkClient, pkey string, ethAmount float64) error {
if ethAmount == 0 {
return errors.New("funds_eth is 0, set some value in config, ex.: funds_eth = 30.0")
}
for _, cl := range nodes {
ek, err := cl.ReadPrimaryETHKey(fmt.Sprint(sc.Cfg.Network.ChainID))
if err != nil {
return err
}
if err := SendETH(sc.Client, pkey, ek.Attributes.Address, big.NewFloat(ethAmount)); err != nil {
return fmt.Errorf("failed to fund CL node %s: %w", ek.Attributes.Address, err)
}
}
return nil
}
Binary file added integration-tests/capabilities/cron-linux-amd64
Binary file not shown.
116 changes: 116 additions & 0 deletions integration-tests/capabilities/environment-cache.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
[blockchain_a]
type = 'anvil'
image = 'f4hrenh9it/foundry:latest'
pull_image = false
port = '8545'
port_ws = ''
chain_id = '1337'
docker_cmd_params = ['-b', '5']
public_key = ''
contracts_dir = ''

[nodeset]
nodes = 5
http_port_range_start = 0
p2p_port_range_start = 0
dlv_port_range_start = 0
override_mode = 'each'

[nodeset.db]
image = 'postgres:15.6'
port = 0
name = ''
volume_name = ''
databases = 0
jd_database = false
pull_image = false

[[nodeset.node_specs]]
[nodeset.node_specs.node]
image = ''
name = ''
docker_file = 'plugins/chainlink.Dockerfile'
docker_ctx = '../..'
pull_image = false
capabilities = []
capabilities_container_dir = ''
test_config_overrides = ''
user_config_overrides = " [Feature]\n\t\t\tLogPoller = true\n\n\t\t\t[OCR2]\n\t\t\tEnabled = true\n\t\t\tDatabaseTimeout = '1s'\n\n\t\t\t[P2P.V2]\n\t\t\tEnabled = true\n\t\t\tListenAddresses = ['0.0.0.0:5001']\n "
test_secrets_overrides = ''
user_secrets_overrides = ''
port = 0
p2p_port = 0
custom_ports = []
debugger_port = 0

[[nodeset.node_specs]]
[nodeset.node_specs.node]
image = ''
name = ''
docker_file = 'plugins/chainlink.Dockerfile'
docker_ctx = '../..'
pull_image = false
capabilities = ['./streams-linux-amd64', './cron-linux-amd64']
capabilities_container_dir = ''
test_config_overrides = ''
user_config_overrides = " [Feature]\n\t\t\tLogPoller = true\n\n\t\t\t[OCR2]\n\t\t\tEnabled = true\n\t\t\tDatabaseTimeout = '1s'\n\n\t\t\t[P2P.V2]\n\t\t\tEnabled = true\n\t\t\tListenAddresses = ['0.0.0.0:5001']\n "
test_secrets_overrides = ''
user_secrets_overrides = ''
port = 0
p2p_port = 0
custom_ports = []
debugger_port = 0

[[nodeset.node_specs]]
[nodeset.node_specs.node]
image = ''
name = ''
docker_file = 'plugins/chainlink.Dockerfile'
docker_ctx = '../..'
pull_image = false
capabilities = ['./streams-linux-amd64', './cron-linux-amd64']
capabilities_container_dir = ''
test_config_overrides = ''
user_config_overrides = " [Feature]\n\t\t\tLogPoller = true\n\n\t\t\t[OCR2]\n\t\t\tEnabled = true\n\t\t\tDatabaseTimeout = '1s'\n\n\t\t\t[P2P.V2]\n\t\t\tEnabled = true\n\t\t\tListenAddresses = ['0.0.0.0:5001']\n "
test_secrets_overrides = ''
user_secrets_overrides = ''
port = 0
p2p_port = 0
custom_ports = []
debugger_port = 0

[[nodeset.node_specs]]
[nodeset.node_specs.node]
image = ''
name = ''
docker_file = 'plugins/chainlink.Dockerfile'
docker_ctx = '../..'
pull_image = false
capabilities = ['./streams-linux-amd64', './cron-linux-amd64']
capabilities_container_dir = ''
test_config_overrides = ''
user_config_overrides = " [Feature]\n\t\t\tLogPoller = true\n\n\t\t\t[OCR2]\n\t\t\tEnabled = true\n\t\t\tDatabaseTimeout = '1s'\n\n\t\t\t[P2P.V2]\n\t\t\tEnabled = true\n\t\t\tListenAddresses = ['0.0.0.0:5001']\n "
test_secrets_overrides = ''
user_secrets_overrides = ''
port = 0
p2p_port = 0
custom_ports = []
debugger_port = 0

[[nodeset.node_specs]]
[nodeset.node_specs.node]
image = ''
name = ''
docker_file = 'plugins/chainlink.Dockerfile'
docker_ctx = '../..'
pull_image = false
capabilities = ['./streams-linux-amd64', './cron-linux-amd64']
capabilities_container_dir = ''
test_config_overrides = ''
user_config_overrides = " [Feature]\n\t\t\tLogPoller = true\n\n\t\t\t[OCR2]\n\t\t\tEnabled = true\n\t\t\tDatabaseTimeout = '1s'\n\n\t\t\t[P2P.V2]\n\t\t\tEnabled = true\n\t\t\tListenAddresses = ['0.0.0.0:5001']\n "
test_secrets_overrides = ''
user_secrets_overrides = ''
port = 0
p2p_port = 0
custom_ports = []
debugger_port = 0
Loading
Loading