Skip to content

Commit

Permalink
Merge branch 'develop' into tt_922_automation_seth
Browse files Browse the repository at this point in the history
  • Loading branch information
Tofel committed May 7, 2024
2 parents 86f638a + ac89336 commit daaf9d3
Show file tree
Hide file tree
Showing 74 changed files with 2,957 additions and 463 deletions.
6 changes: 6 additions & 0 deletions .changeset/funny-tips-promise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"chainlink": patch
---

#added
compare user-defined max gas price with current gas price in automation simulation pipeline
5 changes: 5 additions & 0 deletions .changeset/mighty-flies-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

#added ORM and corresponding tables for CCIP gas prices and token prices
5 changes: 5 additions & 0 deletions .changeset/modern-trainers-hear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

#internal Generate gethwrappers for capability registry changes
6 changes: 6 additions & 0 deletions .changeset/neat-pianos-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"chainlink": patch
---

#added
pass a gas estimator to registry 2.1 pipeline
5 changes: 5 additions & 0 deletions .changeset/ten-dodos-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

#internal Normalize keystone workflow ref regex property to match id regex
5 changes: 5 additions & 0 deletions .changeset/witty-weeks-kneel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

#added an integration test for max gas price check
4 changes: 2 additions & 2 deletions .github/workflows/ci-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ jobs:
env:
OUTPUT_FILE: ./output.txt
USE_TEE: false
CL_DATABASE_URL: ${{ env.DB_URL }}
CL_DATABASE_URL: ${{ env.DB_URL }}
run: ./tools/bin/${{ matrix.type.cmd }} ./...
- name: Print Filtered Test Results
if: ${{ failure() && matrix.type.cmd == 'go_core_tests' && needs.filter.outputs.changes == 'true' }}
Expand Down Expand Up @@ -203,7 +203,7 @@ jobs:
./coverage.txt
./postgres_logs.txt
- name: Notify Slack
if: ${{ failure() && steps.print-races.outputs.post_to_slack == 'true' && matrix.type.cmd == 'go_core_race_tests' && (github.event_name == 'merge_group' || github.base_ref == 'develop') && needs.filter.outputs.changes == 'true' }}
if: ${{ failure() && steps.print-races.outputs.post_to_slack == 'true' && matrix.type.cmd == 'go_core_race_tests' && (github.event_name == 'merge_group' || github.event.branch == 'develop') && needs.filter.outputs.changes == 'true' }}
uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
env:
SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}
Expand Down
8 changes: 5 additions & 3 deletions common/client/poller.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ type Poller[T any] struct {
wg sync.WaitGroup
}

// NewPoller creates a new Poller instance
// NewPoller creates a new Poller instance and returns a channel to receive the polled data
func NewPoller[
T any,
](pollingInterval time.Duration, pollingFunc func(ctx context.Context) (T, error), pollingTimeout time.Duration, channel chan<- T, logger logger.Logger) Poller[T] {
](pollingInterval time.Duration, pollingFunc func(ctx context.Context) (T, error), pollingTimeout time.Duration, logger logger.Logger) (Poller[T], <-chan T) {
channel := make(chan T)
return Poller[T]{
pollingInterval: pollingInterval,
pollingFunc: pollingFunc,
Expand All @@ -39,7 +40,7 @@ func NewPoller[
logger: logger,
errCh: make(chan error),
stopCh: make(chan struct{}),
}
}, channel
}

var _ types.Subscription = &Poller[any]{}
Expand All @@ -58,6 +59,7 @@ func (p *Poller[T]) Unsubscribe() {
close(p.stopCh)
p.wg.Wait()
close(p.errCh)
close(p.channel)
return nil
})
}
Expand Down
40 changes: 9 additions & 31 deletions common/client/poller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ func Test_Poller(t *testing.T) {
return nil, nil
}

channel := make(chan Head, 1)
defer close(channel)

poller := NewPoller[Head](time.Millisecond, pollFunc, time.Second, channel, lggr)
poller, _ := NewPoller[Head](time.Millisecond, pollFunc, time.Second, lggr)
err := poller.Start()
require.NoError(t, err)

Expand All @@ -50,12 +47,8 @@ func Test_Poller(t *testing.T) {
return h.ToMockHead(t), nil
}

// data channel to receive updates from the poller
channel := make(chan Head, 1)
defer close(channel)

// Create poller and start to receive data
poller := NewPoller[Head](time.Millisecond, pollFunc, time.Second, channel, lggr)
poller, channel := NewPoller[Head](time.Millisecond, pollFunc, time.Second, lggr)
require.NoError(t, poller.Start())
defer poller.Unsubscribe()

Expand All @@ -79,14 +72,10 @@ func Test_Poller(t *testing.T) {
return nil, fmt.Errorf("polling error %d", pollNumber)
}

// data channel to receive updates from the poller
channel := make(chan Head, 1)
defer close(channel)

olggr, observedLogs := logger.TestObserved(t, zap.WarnLevel)

// Create poller and subscribe to receive data
poller := NewPoller[Head](time.Millisecond, pollFunc, time.Second, channel, olggr)
poller, _ := NewPoller[Head](time.Millisecond, pollFunc, time.Second, olggr)
require.NoError(t, poller.Start())
defer poller.Unsubscribe()

Expand Down Expand Up @@ -114,14 +103,10 @@ func Test_Poller(t *testing.T) {
// Set instant timeout
pollingTimeout := time.Duration(0)

// data channel to receive updates from the poller
channel := make(chan Head, 1)
defer close(channel)

olggr, observedLogs := logger.TestObserved(t, zap.WarnLevel)

// Create poller and subscribe to receive data
poller := NewPoller[Head](time.Millisecond, pollFunc, pollingTimeout, channel, olggr)
poller, _ := NewPoller[Head](time.Millisecond, pollFunc, pollingTimeout, olggr)
require.NoError(t, poller.Start())
defer poller.Unsubscribe()

Expand All @@ -146,14 +131,10 @@ func Test_Poller(t *testing.T) {
// Set long timeout
pollingTimeout := time.Minute

// data channel to receive updates from the poller
channel := make(chan Head, 1)
defer close(channel)

olggr, observedLogs := logger.TestObserved(t, zap.WarnLevel)

// Create poller and subscribe to receive data
poller := NewPoller[Head](time.Millisecond, pollFunc, pollingTimeout, channel, olggr)
poller, _ := NewPoller[Head](time.Millisecond, pollFunc, pollingTimeout, olggr)
require.NoError(t, poller.Start())

// Unsubscribe while blocked in polling function
Expand Down Expand Up @@ -184,8 +165,7 @@ func Test_Poller_Unsubscribe(t *testing.T) {
}

t.Run("Test multiple unsubscribe", func(t *testing.T) {
channel := make(chan Head, 1)
poller := NewPoller[Head](time.Millisecond, pollFunc, time.Second, channel, lggr)
poller, channel := NewPoller[Head](time.Millisecond, pollFunc, time.Second, lggr)
err := poller.Start()
require.NoError(t, err)

Expand All @@ -194,14 +174,12 @@ func Test_Poller_Unsubscribe(t *testing.T) {
poller.Unsubscribe()
})

t.Run("Test unsubscribe with closed channel", func(t *testing.T) {
channel := make(chan Head, 1)
poller := NewPoller[Head](time.Millisecond, pollFunc, time.Second, channel, lggr)
t.Run("Read channel after unsubscribe", func(t *testing.T) {
poller, channel := NewPoller[Head](time.Millisecond, pollFunc, time.Second, lggr)
err := poller.Start()
require.NoError(t, err)

<-channel
close(channel)
poller.Unsubscribe()
require.Equal(t, <-channel, nil)
})
}
5 changes: 5 additions & 0 deletions contracts/.changeset/three-hotels-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chainlink/contracts": patch
---

Add function to update nodes in capability registry
46 changes: 45 additions & 1 deletion contracts/src/v0.8/keystone/CapabilityRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface {
/// @param nodeOperatorId The ID of the node operator that manages this node
event NodeAdded(bytes32 p2pId, uint256 nodeOperatorId);

/// @notice This event is emitted when a node is updated
/// @param p2pId The P2P ID of the node
/// @param nodeOperatorId The ID of the node operator that manages this node
/// @param signer The node's signer address
event NodeUpdated(bytes32 p2pId, uint256 nodeOperatorId, address signer);

/// @notice This error is thrown when trying to set the node's
/// signer address to zero
error InvalidNodeSigner();

/// @notice This error is thrown when trying add a capability that already
/// exists.
error CapabilityAlreadyExists();
Expand Down Expand Up @@ -236,12 +246,16 @@ contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface {
for (uint256 i; i < nodes.length; ++i) {
Node memory node = nodes[i];

bool isOwner = msg.sender == owner();

NodeOperator memory nodeOperator = s_nodeOperators[node.nodeOperatorId];
if (msg.sender != nodeOperator.admin) revert AccessForbidden();
if (!isOwner && msg.sender != nodeOperator.admin) revert AccessForbidden();

bool nodeExists = s_nodes[node.p2pId].supportedHashedCapabilityIds.length > 0;
if (nodeExists || bytes32(node.p2pId) == bytes32("")) revert InvalidNodeP2PId(node.p2pId);

if (node.signer == address(0)) revert InvalidNodeSigner();

if (node.supportedHashedCapabilityIds.length == 0)
revert InvalidNodeCapabilities(node.supportedHashedCapabilityIds);

Expand All @@ -255,6 +269,36 @@ contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface {
}
}

/// @notice Updates nodes. The node admin can update the node's signer address
/// and reconfigure its supported capabilities
/// @param nodes The nodes to update
function updateNodes(Node[] calldata nodes) external {
for (uint256 i; i < nodes.length; ++i) {
Node memory node = nodes[i];

bool isOwner = msg.sender == owner();

NodeOperator memory nodeOperator = s_nodeOperators[node.nodeOperatorId];
if (!isOwner && msg.sender != nodeOperator.admin) revert AccessForbidden();

bool nodeExists = s_nodes[node.p2pId].supportedHashedCapabilityIds.length > 0;
if (!nodeExists) revert InvalidNodeP2PId(node.p2pId);

if (node.signer == address(0)) revert InvalidNodeSigner();

if (node.supportedHashedCapabilityIds.length == 0)
revert InvalidNodeCapabilities(node.supportedHashedCapabilityIds);

for (uint256 j; j < node.supportedHashedCapabilityIds.length; ++j) {
if (!s_hashedCapabilityIds.contains(node.supportedHashedCapabilityIds[j]))
revert InvalidNodeCapabilities(node.supportedHashedCapabilityIds);
}

s_nodes[node.p2pId] = node;
emit NodeUpdated(node.p2pId, node.nodeOperatorId, node.signer);
}
}

/// @notice Gets a node's data
/// @param p2pId The P2P ID of the node to query for
/// @return Node The node data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ contract CapabilityRegistry_AddNodesTest is BaseTest {
s_capabilityRegistry.addCapability(s_capabilityWithConfigurationContract);
}

function test_RevertWhen_CalledByNonNodeOperatorAdmin() public {
function test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() public {
changePrank(STRANGER);
CapabilityRegistry.Node[] memory nodes = new CapabilityRegistry.Node[](1);

Expand All @@ -36,6 +36,24 @@ contract CapabilityRegistry_AddNodesTest is BaseTest {
s_capabilityRegistry.addNodes(nodes);
}

function test_RevertWhen_SignerAddressEmpty() public {
changePrank(NODE_OPERATOR_ONE_ADMIN);
CapabilityRegistry.Node[] memory nodes = new CapabilityRegistry.Node[](1);

bytes32[] memory hashedCapabilityIds = new bytes32[](1);
hashedCapabilityIds[0] = s_basicHashedCapabilityId;

nodes[0] = CapabilityRegistry.Node({
nodeOperatorId: TEST_NODE_OPERATOR_ONE_ID,
p2pId: P2P_ID,
signer: address(0),
supportedHashedCapabilityIds: hashedCapabilityIds
});

vm.expectRevert(abi.encodeWithSelector(CapabilityRegistry.InvalidNodeSigner.selector));
s_capabilityRegistry.addNodes(nodes);
}

function test_RevertWhen_AddingDuplicateP2PId() public {
changePrank(NODE_OPERATOR_ONE_ADMIN);
CapabilityRegistry.Node[] memory nodes = new CapabilityRegistry.Node[](1);
Expand Down Expand Up @@ -133,4 +151,31 @@ contract CapabilityRegistry_AddNodesTest is BaseTest {
assertEq(node.supportedHashedCapabilityIds[0], s_basicHashedCapabilityId);
assertEq(node.supportedHashedCapabilityIds[1], s_capabilityWithConfigurationContractId);
}

function test_OwnerCanAddNodes() public {
changePrank(ADMIN);

CapabilityRegistry.Node[] memory nodes = new CapabilityRegistry.Node[](1);
bytes32[] memory hashedCapabilityIds = new bytes32[](2);
hashedCapabilityIds[0] = s_basicHashedCapabilityId;
hashedCapabilityIds[1] = s_capabilityWithConfigurationContractId;

nodes[0] = CapabilityRegistry.Node({
nodeOperatorId: TEST_NODE_OPERATOR_ONE_ID,
p2pId: P2P_ID,
signer: NODE_OPERATOR_ONE_SIGNER_ADDRESS,
supportedHashedCapabilityIds: hashedCapabilityIds
});

vm.expectEmit(address(s_capabilityRegistry));
emit NodeAdded(P2P_ID, TEST_NODE_OPERATOR_ONE_ID);
s_capabilityRegistry.addNodes(nodes);

CapabilityRegistry.Node memory node = s_capabilityRegistry.getNode(P2P_ID);
assertEq(node.nodeOperatorId, TEST_NODE_OPERATOR_ONE_ID);
assertEq(node.p2pId, P2P_ID);
assertEq(node.supportedHashedCapabilityIds.length, 2);
assertEq(node.supportedHashedCapabilityIds[0], s_basicHashedCapabilityId);
assertEq(node.supportedHashedCapabilityIds[1], s_capabilityWithConfigurationContractId);
}
}
Loading

0 comments on commit daaf9d3

Please sign in to comment.