Skip to content

Commit 6ae77cd

Browse files
committed
ensure that donFamily is always a string
1 parent 2582475 commit 6ae77cd

File tree

6 files changed

+411
-151
lines changed

6 files changed

+411
-151
lines changed

contracts/gas-snapshots/workflow.gas-snapshot

Lines changed: 142 additions & 134 deletions
Large diffs are not rendered by default.

contracts/src/v0.8/workflow/dev/v2/WorkflowRegistry.sol

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,27 +1489,28 @@ contract WorkflowRegistry is Ownable2StepMsgSender, ITypeAndVersion {
14891489
/// @notice Fetch a paginated slice of **all** workflows (active *and*
14901490
/// paused) that belong to a given DON.
14911491
/// @dev
1492-
/// * Reads the RID set `s_allDONRids[donFamily]`, which tracks every
1492+
/// * Reads the RID set `s_allDONRids[donHash]` derived from the donFamily, which tracks every
14931493
/// workflow ever registered to that DON, regardless of status.
14941494
/// * Does **not** revert on out-of-range requests; instead it returns
14951495
/// the largest sub-range that fits inside the set.
14961496
///
1497-
/// @param donFamily bytes32-encoded DON label used as the secondary key.
1497+
/// @param donFamily Human readable string of the DON family.
14981498
/// @param start Zero-based index into the RID set.
14991499
/// @param limit Bathc size for the workflows
15001500
/// @return list Array of `WorkflowMetadataView` structs whose length is
15011501
/// `min(limit, total-start)`.
15021502
function getWorkflowListByDON(
1503-
bytes32 donFamily,
1503+
string calldata donFamily,
15041504
uint256 start,
15051505
uint256 limit
15061506
) external view returns (WorkflowMetadataView[] memory list) {
1507-
uint256 total = s_allDONRids[donFamily].length();
1507+
bytes32 donHash = _hash(donFamily);
1508+
uint256 total = s_allDONRids[donHash].length();
15081509
uint256 count = _getPageCount(total, start, limit);
15091510

15101511
list = new WorkflowMetadataView[](count);
15111512
for (uint256 i = 0; i < count; ++i) {
1512-
bytes32 rid = s_allDONRids[donFamily].at(start + i);
1513+
bytes32 rid = s_allDONRids[donHash].at(start + i);
15131514
list[i] = _workflowMetadataView(rid);
15141515
}
15151516

@@ -1571,10 +1572,6 @@ contract WorkflowRegistry is Ownable2StepMsgSender, ITypeAndVersion {
15711572
WorkflowMetadata storage rec = s_workflows[rid];
15721573
if (rec.owner == address(0)) return v;
15731574

1574-
// For ACTIVE workflows this will resolve to the correct DON label.
1575-
// For PAUSED/never‑assigned workflows the label is the empty string.;
1576-
string memory family = s_donConfigs[s_donByWorkflowRid[rid]].family;
1577-
15781575
return WorkflowMetadataView({
15791576
workflowId: rec.workflowId,
15801577
owner: rec.owner,
@@ -1585,7 +1582,9 @@ contract WorkflowRegistry is Ownable2StepMsgSender, ITypeAndVersion {
15851582
configUrl: rec.configUrl,
15861583
tag: rec.tag,
15871584
attributes: rec.attributes,
1588-
donFamily: family
1585+
// For ACTIVE workflows this will resolve to the correct DON label.
1586+
// For PAUSED/never‑assigned workflows the label is the empty string.;
1587+
donFamily: s_donConfigs[s_donByWorkflowRid[rid]].family
15891588
});
15901589
}
15911590

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
// SPDX-License-Identifier: BUSL 1.1
2+
pragma solidity 0.8.26;
3+
4+
import {WorkflowRegistry} from "../../WorkflowRegistry.sol";
5+
import {WorkflowRegistrySetup} from "./WorkflowRegistrySetup.t.sol";
6+
7+
contract WorkflowRegistry_getWorkflowListByDON is WorkflowRegistrySetup {
8+
address private s_owner1 = makeAddr("owner1");
9+
address private s_owner2 = makeAddr("owner2");
10+
string private s_donFamily1 = "DON-Family-1";
11+
string private s_donFamily2 = "DON-Family-2";
12+
13+
function test_getWorkflowListByDON_WhenTheDONFamilyHasNoWorkflowsRegistered() external view {
14+
// it should return an empty array
15+
WorkflowRegistry.WorkflowMetadataView[] memory workflows = s_registry.getWorkflowListByDON(s_donFamily1, 0, 10);
16+
assertEq(workflows.length, 0, "Expected no workflows");
17+
18+
workflows = s_registry.getWorkflowListByDON(s_donFamily1, 0, 1);
19+
assertEq(workflows.length, 0, "Expected no workflows");
20+
21+
workflows = s_registry.getWorkflowListByDON(s_donFamily1, 5, 10);
22+
assertEq(workflows.length, 0, "Expected no workflows");
23+
}
24+
25+
modifier whenTheDONFamilyHasWorkflowsRegistered() {
26+
// Set up DON limits for both families
27+
vm.startPrank(s_owner);
28+
s_registry.setDONLimit(s_donFamily1, 10, true);
29+
s_registry.setDONLimit(s_donFamily2, 5, true);
30+
vm.stopPrank();
31+
32+
// Link owners and create workflows for DON Family 1
33+
_linkOwner(s_owner1);
34+
_linkOwner(s_owner2);
35+
36+
// Create 5 workflows for DON Family 1
37+
vm.startPrank(s_owner1);
38+
_createWorkflowForDON("Workflow-1", "tag1", keccak256("id1"), s_donFamily1);
39+
_createWorkflowForDON("Workflow-2", "tag2", keccak256("id2"), s_donFamily1);
40+
_createWorkflowForDON("Workflow-3", "tag3", keccak256("id3"), s_donFamily1);
41+
vm.stopPrank();
42+
43+
vm.startPrank(s_owner2);
44+
_createWorkflowForDON("Workflow-4", "tag4", keccak256("id4"), s_donFamily1);
45+
_createWorkflowForDON("Workflow-5", "tag5", keccak256("id5"), s_donFamily1);
46+
vm.stopPrank();
47+
48+
// Create 2 workflows for DON Family 2 (different DON)
49+
vm.startPrank(s_owner1);
50+
_createWorkflowForDON("Other-Workflow-1", "other1", keccak256("other1"), s_donFamily2);
51+
_createWorkflowForDON("Other-Workflow-2", "other2", keccak256("other2"), s_donFamily2);
52+
vm.stopPrank();
53+
_;
54+
}
55+
56+
function test_getWorkflowListByDON_WhenStartIsGreaterThanOrEqualToTotalWorkflows()
57+
external
58+
whenTheDONFamilyHasWorkflowsRegistered
59+
{
60+
// it should return an empty array
61+
WorkflowRegistry.WorkflowMetadataView[] memory workflows = s_registry.getWorkflowListByDON(s_donFamily1, 5, 10);
62+
assertEq(workflows.length, 0, "Expected no workflows when start equals total");
63+
64+
workflows = s_registry.getWorkflowListByDON(s_donFamily1, 6, 5);
65+
assertEq(workflows.length, 0, "Expected no workflows when start is greater than total");
66+
67+
workflows = s_registry.getWorkflowListByDON(s_donFamily1, 10, 1);
68+
assertEq(workflows.length, 0, "Expected no workflows when start is much greater than total");
69+
}
70+
71+
modifier whenStartIsLessThanTotalWorkflows() {
72+
_;
73+
}
74+
75+
function test_getWorkflowListByDON_WhenLimitIsZero()
76+
external
77+
whenTheDONFamilyHasWorkflowsRegistered
78+
whenStartIsLessThanTotalWorkflows
79+
{
80+
// it should return an empty array
81+
WorkflowRegistry.WorkflowMetadataView[] memory workflows = s_registry.getWorkflowListByDON(s_donFamily1, 0, 0);
82+
assertEq(workflows.length, 0, "Expected no workflows when limit is 0");
83+
84+
workflows = s_registry.getWorkflowListByDON(s_donFamily1, 2, 0);
85+
assertEq(workflows.length, 0, "Expected no workflows when limit is 0");
86+
}
87+
88+
function test_getWorkflowListByDON_WhenLimitIsLessThanTotalMinusStart()
89+
external
90+
whenTheDONFamilyHasWorkflowsRegistered
91+
whenStartIsLessThanTotalWorkflows
92+
{
93+
// it should return exactly limit workflows starting from start index
94+
WorkflowRegistry.WorkflowMetadataView[] memory workflows = s_registry.getWorkflowListByDON(s_donFamily1, 0, 2);
95+
assertEq(workflows.length, 2, "Expected exactly 2 workflows");
96+
assertEq(workflows[0].workflowName, "Workflow-1", "Expected first workflow");
97+
assertEq(workflows[1].workflowName, "Workflow-2", "Expected second workflow");
98+
99+
workflows = s_registry.getWorkflowListByDON(s_donFamily1, 1, 2);
100+
assertEq(workflows.length, 2, "Expected exactly 2 workflows starting from index 1");
101+
assertEq(workflows[0].workflowName, "Workflow-2", "Expected second workflow at index 0");
102+
assertEq(workflows[1].workflowName, "Workflow-3", "Expected third workflow at index 1");
103+
104+
workflows = s_registry.getWorkflowListByDON(s_donFamily1, 3, 1);
105+
assertEq(workflows.length, 1, "Expected exactly 1 workflow");
106+
assertEq(workflows[0].workflowName, "Workflow-4", "Expected fourth workflow");
107+
}
108+
109+
function test_getWorkflowListByDON_WhenLimitIsGreaterThanOrEqualToTotalMinusStart()
110+
external
111+
whenTheDONFamilyHasWorkflowsRegistered
112+
whenStartIsLessThanTotalWorkflows
113+
{
114+
// it should return all workflows from start index to the end
115+
WorkflowRegistry.WorkflowMetadataView[] memory workflows = s_registry.getWorkflowListByDON(s_donFamily1, 0, 5);
116+
assertEq(workflows.length, 5, "Expected all 5 workflows");
117+
assertEq(workflows[0].workflowName, "Workflow-1", "Expected first workflow");
118+
assertEq(workflows[1].workflowName, "Workflow-2", "Expected second workflow");
119+
assertEq(workflows[2].workflowName, "Workflow-3", "Expected third workflow");
120+
assertEq(workflows[3].workflowName, "Workflow-4", "Expected fourth workflow");
121+
assertEq(workflows[4].workflowName, "Workflow-5", "Expected fifth workflow");
122+
123+
workflows = s_registry.getWorkflowListByDON(s_donFamily1, 0, 10);
124+
assertEq(workflows.length, 5, "Expected all 5 workflows when limit exceeds total");
125+
126+
workflows = s_registry.getWorkflowListByDON(s_donFamily1, 2, 10);
127+
assertEq(workflows.length, 3, "Expected last 3 workflows");
128+
assertEq(workflows[0].workflowName, "Workflow-3", "Expected third workflow");
129+
assertEq(workflows[1].workflowName, "Workflow-4", "Expected fourth workflow");
130+
assertEq(workflows[2].workflowName, "Workflow-5", "Expected fifth workflow");
131+
132+
workflows = s_registry.getWorkflowListByDON(s_donFamily1, 4, 5);
133+
assertEq(workflows.length, 1, "Expected last workflow");
134+
assertEq(workflows[0].workflowName, "Workflow-5", "Expected fifth workflow");
135+
}
136+
137+
function test_getWorkflowListByDON_ShouldOnlyReturnWorkflowsFromSpecifiedDON()
138+
external
139+
whenTheDONFamilyHasWorkflowsRegistered
140+
{
141+
// Verify DON Family 1 workflows
142+
WorkflowRegistry.WorkflowMetadataView[] memory workflows1 = s_registry.getWorkflowListByDON(s_donFamily1, 0, 10);
143+
assertEq(workflows1.length, 5, "Expected 5 workflows for DON Family 1");
144+
145+
// Verify DON Family 2 workflows
146+
WorkflowRegistry.WorkflowMetadataView[] memory workflows2 = s_registry.getWorkflowListByDON(s_donFamily2, 0, 10);
147+
assertEq(workflows2.length, 2, "Expected 2 workflows for DON Family 2");
148+
assertEq(workflows2[0].workflowName, "Other-Workflow-1", "Expected first other workflow");
149+
assertEq(workflows2[1].workflowName, "Other-Workflow-2", "Expected second other workflow");
150+
151+
// Verify workflow names don't overlap
152+
for (uint256 i = 0; i < workflows1.length; i++) {
153+
for (uint256 j = 0; j < workflows2.length; j++) {
154+
assertTrue(
155+
keccak256(bytes(workflows1[i].workflowName)) != keccak256(bytes(workflows2[j].workflowName)),
156+
"Workflows from different DONs should not have the same name"
157+
);
158+
}
159+
}
160+
}
161+
162+
function test_getWorkflowListByDON_ShouldReturnWorkflowsWithCorrectStatus()
163+
external
164+
whenTheDONFamilyHasWorkflowsRegistered
165+
{
166+
// All workflows should be PAUSED by default from our setup
167+
WorkflowRegistry.WorkflowMetadataView[] memory workflows = s_registry.getWorkflowListByDON(s_donFamily1, 0, 10);
168+
169+
for (uint256 i = 0; i < workflows.length; i++) {
170+
assertEq(
171+
uint256(workflows[i].status), uint256(WorkflowRegistry.WorkflowStatus.PAUSED), "Expected workflow to be PAUSED"
172+
);
173+
}
174+
}
175+
176+
function test_getWorkflowListByDON_ShouldIncludeBothActiveAndPausedWorkflows() external {
177+
// Set up DON limit
178+
vm.prank(s_owner);
179+
s_registry.setDONLimit(s_donFamily1, 10, true);
180+
181+
// Link owner and create workflows
182+
_linkOwner(s_owner1);
183+
184+
vm.startPrank(s_owner1);
185+
// Create PAUSED workflow
186+
_createWorkflowForDON("Paused-Workflow", "paused", keccak256("paused"), s_donFamily1);
187+
188+
// Create ACTIVE workflow
189+
bytes32 activeId = keccak256("active");
190+
s_registry.upsertWorkflow(
191+
"Active-Workflow",
192+
"active",
193+
activeId,
194+
WorkflowRegistry.WorkflowStatus.ACTIVE,
195+
s_donFamily1,
196+
s_binaryUrl,
197+
s_configUrl,
198+
s_attributes,
199+
true
200+
);
201+
vm.stopPrank();
202+
203+
WorkflowRegistry.WorkflowMetadataView[] memory workflows = s_registry.getWorkflowListByDON(s_donFamily1, 0, 10);
204+
assertEq(workflows.length, 2, "Expected 2 workflows (ACTIVE and PAUSED)");
205+
206+
// Verify we have both statuses
207+
bool hasPaused = false;
208+
bool hasActive = false;
209+
for (uint256 i = 0; i < workflows.length; i++) {
210+
if (workflows[i].status == WorkflowRegistry.WorkflowStatus.PAUSED) {
211+
hasPaused = true;
212+
}
213+
if (workflows[i].status == WorkflowRegistry.WorkflowStatus.ACTIVE) {
214+
hasActive = true;
215+
}
216+
}
217+
assertTrue(hasPaused, "Expected to find PAUSED workflow");
218+
assertTrue(hasActive, "Expected to find ACTIVE workflow");
219+
}
220+
221+
// Helper function to create a workflow for a specific DON
222+
function _createWorkflowForDON(
223+
string memory workflowName,
224+
string memory tag,
225+
bytes32 workflowId,
226+
string memory donFamily
227+
) internal {
228+
s_registry.upsertWorkflow(
229+
workflowName,
230+
tag,
231+
workflowId,
232+
WorkflowRegistry.WorkflowStatus.PAUSED,
233+
donFamily,
234+
s_binaryUrl,
235+
s_configUrl,
236+
s_attributes,
237+
true
238+
);
239+
}
240+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
WorkflowRegistry.getWorkflowListByDON
2+
├── when the DON family has no workflows registered
3+
│ └── it should return an empty array
4+
└── when the DON family has workflows registered
5+
├── when start is greater than or equal to total workflows
6+
│ └── it should return an empty array
7+
└── when start is less than total workflows
8+
├── when limit is 0
9+
│ └── it should return an empty array
10+
├── when limit is less than (total - start)
11+
│ └── it should return exactly limit workflows starting from start index
12+
└── when limit is greater than or equal to (total - start)
13+
└── it should return all workflows from start index to the end

gethwrappers/workflow/generated/workflow_registry_wrapper_v2/workflow_registry_wrapper_v2.go

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
GETH_VERSION: 1.15.3
22
capabilities_registry_wrapper_v2: ../../contracts/solc/workflow/dev/v2/CapabilitiesRegistry/CapabilitiesRegistry.sol/CapabilitiesRegistry.abi.json ../../contracts/solc/workflow/dev/v2/CapabilitiesRegistry/CapabilitiesRegistry.sol/CapabilitiesRegistry.bin 69614cd90cc8bcf751f35b6b8ffe3111a535f0aab5676a8aa4b633252ca00549
33
workflow_registry_wrapper_v1: ../../contracts/solc/workflow/v1/WorkflowRegistry/WorkflowRegistry.sol/WorkflowRegistry.abi.json ../../contracts/solc/workflow/v1/WorkflowRegistry/WorkflowRegistry.sol/WorkflowRegistry.bin 5adc185ac7dabf6f75297855adc0d77e0bfe64af6491de944083fb10f6f9fb06
4-
workflow_registry_wrapper_v2: ../../contracts/solc/workflow/dev/v2/WorkflowRegistry/WorkflowRegistry.sol/WorkflowRegistry.abi.json ../../contracts/solc/workflow/dev/v2/WorkflowRegistry/WorkflowRegistry.sol/WorkflowRegistry.bin 15e6a9582a9d56921603f35255237d6792ee907438c665e1b6210911e90ea325
4+
workflow_registry_wrapper_v2: ../../contracts/solc/workflow/dev/v2/WorkflowRegistry/WorkflowRegistry.sol/WorkflowRegistry.abi.json ../../contracts/solc/workflow/dev/v2/WorkflowRegistry/WorkflowRegistry.sol/WorkflowRegistry.bin 3bf709d2bad625178e104c0e79c19b2321c85828c2dcf0bf9df5308db8e16e0c

0 commit comments

Comments
 (0)