Skip to content

Commit e367945

Browse files
committed
fix: overflow, DRY
1 parent d391075 commit e367945

File tree

2 files changed

+62
-87
lines changed

2 files changed

+62
-87
lines changed

target_chains/ethereum/contracts/contracts/pulse/scheduler/Scheduler.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ abstract contract Scheduler is IScheduler, SchedulerState {
673673
) external pure override returns (uint256 minimumBalanceInWei) {
674674
// Placeholder implementation
675675
// TODO: make this governable
676-
return numPriceFeeds * 1 wei;
676+
return uint256(numPriceFeeds) * 0.01 ether;
677677
}
678678

679679
// ACCESS CONTROL MODIFIERS

target_chains/ethereum/contracts/forge-test/PulseSchedulerGasBenchmark.t.sol

Lines changed: 61 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -17,69 +17,44 @@ import "./utils/PulseSchedulerTestUtils.t.sol";
1717
contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils {
1818
ERC1967Proxy public proxy;
1919
SchedulerUpgradeable public scheduler;
20-
address public owner;
20+
address public manager;
2121
address public admin;
2222
address public pyth;
23-
address public pusher;
2423

2524
// Constants
26-
uint96 constant PYTH_FEE = 1 wei;
25+
uint96 constant PYTH_FEE = 10 wei;
2726

2827
function setUp() public {
29-
owner = address(1);
28+
manager = address(1);
3029
admin = address(2);
3130
pyth = address(3);
32-
pusher = address(4);
3331

3432
SchedulerUpgradeable _scheduler = new SchedulerUpgradeable();
3533
proxy = new ERC1967Proxy(address(_scheduler), "");
3634
scheduler = SchedulerUpgradeable(address(proxy));
3735

38-
scheduler.initialize(owner, admin, pyth);
36+
scheduler.initialize(manager, admin, pyth);
3937

4038
// Start tests at a high timestamp to avoid underflow when we set
4139
// `minPublishTime = timestamp - 1 hour` in updatePriceFeeds
4240
vm.warp(100000);
4341

44-
// Give pusher and owner 1000 ETH for testing
45-
vm.deal(pusher, 1000 ether);
46-
vm.deal(owner, 1000 ether);
42+
// Give manager 1000 ETH for testing
43+
vm.deal(manager, 1000 ether);
4744
}
4845

4946
// Helper function to run the price feed update benchmark with a specified number of feeds
5047
function _runUpdateAndQueryPriceFeedsBenchmark(uint8 numFeeds) internal {
51-
// Setup: Create subscription and initial price update
52-
vm.prank(owner);
53-
uint256 subscriptionId = addTestSubscriptionWithFeeds(
54-
scheduler,
55-
numFeeds,
56-
address(owner)
57-
);
58-
59-
// Fetch the price IDS
48+
// Setup: Create subscription and perform initial update
49+
vm.prank(manager);
50+
uint256 subscriptionId = _setupSubscriptionWithInitialUpdate(numFeeds);
6051
(SchedulerState.SubscriptionParams memory params, ) = scheduler
6152
.getSubscription(subscriptionId);
62-
bytes32[] memory priceIds = params.priceIds;
63-
64-
// Create initial price feed updates
65-
uint64 publishTime = SafeCast.toUint64(block.timestamp);
66-
PythStructs.PriceFeed[] memory priceFeeds;
67-
uint64[] memory slots;
68-
69-
(priceFeeds, slots) = createMockPriceFeedsWithSlots(
70-
publishTime,
71-
numFeeds
72-
);
73-
74-
mockParsePriceFeedUpdatesWithSlots(pyth, priceFeeds, slots);
75-
bytes[] memory updateData1 = createMockUpdateData(priceFeeds);
76-
vm.prank(pusher);
77-
scheduler.updatePriceFeeds(subscriptionId, updateData1, priceIds);
7853

7954
// Advance time to meet heartbeat criteria
8055
vm.warp(block.timestamp + 100);
8156

82-
// Create new price feed updates with updated timestamp and prices
57+
// Create new price feed updates with updated timestamp
8358
uint64 newPublishTime = SafeCast.toUint64(block.timestamp);
8459
PythStructs.PriceFeed[] memory newPriceFeeds;
8560
uint64[] memory newSlots;
@@ -89,24 +64,16 @@ contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils {
8964
numFeeds
9065
);
9166

92-
// Apply price deviation to ensure update criteria is met
93-
for (uint i = 0; i < numFeeds; i++) {
94-
// Apply a 200 bps price increase (satisfies update criteria)
95-
int64 priceDiff = int64(
96-
(uint64(newPriceFeeds[i].price.price) * 200) / 10_000
97-
);
98-
newPriceFeeds[i].price.price =
99-
newPriceFeeds[i].price.price +
100-
priceDiff;
101-
}
102-
67+
// Mock Pyth response for the benchmark
10368
mockParsePriceFeedUpdatesWithSlots(pyth, newPriceFeeds, newSlots);
104-
bytes[] memory updateData2 = createMockUpdateData(newPriceFeeds);
10569

10670
// Actual benchmark: Measure gas for updating price feeds
107-
vm.prank(pusher);
10871
uint256 startGas = gasleft();
109-
scheduler.updatePriceFeeds(subscriptionId, updateData2, priceIds);
72+
scheduler.updatePriceFeeds(
73+
subscriptionId,
74+
createMockUpdateData(newPriceFeeds),
75+
params.priceIds
76+
);
11077
uint256 updateGasUsed = startGas - gasleft();
11178

11279
console.log(
@@ -117,7 +84,7 @@ contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils {
11784

11885
// Benchmark querying the price feeds after updating
11986
uint256 queryStartGas = gasleft();
120-
scheduler.getPricesUnsafe(subscriptionId, priceIds);
87+
scheduler.getPricesUnsafe(subscriptionId, params.priceIds);
12188
uint256 queryGasUsed = queryStartGas - gasleft();
12289

12390
console.log(
@@ -132,52 +99,60 @@ contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils {
13299
);
133100
}
134101

102+
// Helper function to set up a subscription with initial price update
103+
function _setupSubscriptionWithInitialUpdate(
104+
uint8 numFeeds
105+
) internal returns (uint256) {
106+
uint256 subscriptionId = addTestSubscriptionWithFeeds(
107+
scheduler,
108+
numFeeds,
109+
address(manager)
110+
);
111+
112+
// Fetch the price IDs
113+
(SchedulerState.SubscriptionParams memory params, ) = scheduler
114+
.getSubscription(subscriptionId);
115+
116+
// Create initial price feed updates
117+
uint64 publishTime = SafeCast.toUint64(block.timestamp);
118+
PythStructs.PriceFeed[] memory priceFeeds;
119+
uint64[] memory slots;
120+
121+
(priceFeeds, slots) = createMockPriceFeedsWithSlots(
122+
publishTime,
123+
numFeeds
124+
);
125+
126+
mockParsePriceFeedUpdatesWithSlots(pyth, priceFeeds, slots);
127+
bytes[] memory updateData = createMockUpdateData(priceFeeds);
128+
129+
scheduler.updatePriceFeeds(subscriptionId, updateData, params.priceIds);
130+
return subscriptionId;
131+
}
132+
133+
// Helper function to create updated price feeds for benchmark
134+
function _createUpdatedPriceFeeds(
135+
uint8 numFeeds
136+
) internal returns (PythStructs.PriceFeed[] memory, uint64[] memory) {}
137+
135138
/// Helper function for benchmarking querying active subscriptions with a specified number of total subscriptions.
136139
/// Half of them will be inactive to simulate gaps in the subscriptions list.
137140
/// Keepers will poll this function to get the list of active subscriptions.
138141
function _runGetActiveSubscriptionsBenchmark(
139142
uint256 numSubscriptions
140143
) internal {
141-
// Setup: Create subscriptions and then deactivate every other one.
142-
vm.startPrank(owner);
144+
// Setup: As manager, create subscriptions and then deactivate every other one.
145+
vm.startPrank(manager);
143146

144147
// Array to store subscription IDs
145148
uint256[] memory subscriptionIds = new uint256[](numSubscriptions);
146149

147-
// First create all subscriptions as active with 2 price feeds
150+
// First create all subscriptions as active (with default 2 price feeds)
148151
for (uint256 i = 0; i < numSubscriptions; i++) {
149-
bytes32[] memory priceIds = createPriceIds();
150-
address[] memory readerWhitelist = new address[](0);
151-
152-
SchedulerState.UpdateCriteria memory updateCriteria = SchedulerState
153-
.UpdateCriteria({
154-
updateOnHeartbeat: true,
155-
heartbeatSeconds: 60,
156-
updateOnDeviation: true,
157-
deviationThresholdBps: 100
158-
});
159-
160-
SchedulerState.GasConfig memory gasConfig = SchedulerState
161-
.GasConfig({
162-
maxBaseFeeMultiplierCapPct: 10_000,
163-
maxPriorityFeeMultiplierCapPct: 10_000
164-
});
165-
166-
SchedulerState.SubscriptionParams memory params = SchedulerState
167-
.SubscriptionParams({
168-
priceIds: priceIds,
169-
readerWhitelist: readerWhitelist,
170-
whitelistEnabled: false,
171-
isActive: true, // All start as active
172-
isPermanent: false,
173-
updateCriteria: updateCriteria,
174-
gasConfig: gasConfig
175-
});
176-
177-
uint256 minimumBalance = scheduler.getMinimumBalance(2);
178-
subscriptionIds[i] = scheduler.createSubscription{
179-
value: minimumBalance
180-
}(params);
152+
subscriptionIds[i] = addTestSubscription(
153+
scheduler,
154+
address(manager)
155+
);
181156
}
182157

183158
// Deactivate every other subscription
@@ -198,7 +173,7 @@ contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils {
198173

199174
console.log(
200175
"Gas used for fetching %s active subscriptions out of %s total: %s",
201-
vm.toString((numSubscriptions + 1) / 2), // Only half are active (rounded up)
176+
vm.toString((numSubscriptions + 1) / 2),
202177
vm.toString(numSubscriptions),
203178
vm.toString(gasUsed)
204179
);

0 commit comments

Comments
 (0)