Skip to content

Commit 6f5eafa

Browse files
committed
update benchmark tests
1 parent 945e081 commit 6f5eafa

File tree

2 files changed

+112
-64
lines changed

2 files changed

+112
-64
lines changed

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

Lines changed: 34 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ contract GasBenchmark is Test, WormholeTestUtils, PythTestUtils {
1919
// It is possible to have more signers but the median seems to be 13.
2020
uint8 constant NUM_GUARDIAN_SIGNERS = 13;
2121

22-
// We use 5 prices to form a batch of 5 prices, close to our mainnet transactions.
23-
uint8 constant NUM_PRICES = 5;
22+
// Our mainnet transactions use 5 prices to form a batch of 5 prices,
23+
// but Pulse allows parsing up to 10 requests in a single requests, so we set up 10 prices.
24+
uint8 constant NUM_PRICES = 10;
2425

25-
// We will have less than 512 price for a foreseeable future.
26-
uint8 constant MERKLE_TREE_DEPTH = 9;
26+
// We will have less than 2^11=2048 price for a foreseeable future.
27+
uint8 constant MERKLE_TREE_DEPTH = 11;
2728

2829
IWormhole public wormhole;
2930
IPyth public pyth;
@@ -265,10 +266,8 @@ contract GasBenchmark is Test, WormholeTestUtils, PythTestUtils {
265266
100
266267
);
267268
}
268-
269-
function testBenchmarkParsePriceFeedUpdates1() public {
270-
uint numIds = 1;
271-
269+
// Helper function to run price feed update benchmark with a specified number of feeds
270+
function _runParsePriceFeedUpdatesBenchmark(uint256 numIds) internal {
272271
bytes32[] memory ids = new bytes32[](numIds);
273272
for (uint i = 0; i < numIds; i++) {
274273
ids[i] = priceIds[i];
@@ -281,64 +280,44 @@ contract GasBenchmark is Test, WormholeTestUtils, PythTestUtils {
281280
);
282281
}
283282

284-
function testBenchmarkParsePriceFeedUpdates2() public {
285-
uint numIds = 2;
283+
function testBenchmarkParsePriceFeedUpdates1() public {
284+
_runParsePriceFeedUpdatesBenchmark(1);
285+
}
286286

287-
bytes32[] memory ids = new bytes32[](numIds);
288-
for (uint i = 0; i < numIds; i++) {
289-
ids[i] = priceIds[i];
290-
}
291-
pyth.parsePriceFeedUpdates{value: freshPricesUpdateFee[numIds - 1]}(
292-
freshPricesUpdateData[numIds - 1],
293-
ids,
294-
0,
295-
50
296-
);
287+
function testBenchmarkParsePriceFeedUpdates2() public {
288+
_runParsePriceFeedUpdatesBenchmark(2);
297289
}
298290

299291
function testBenchmarkParsePriceFeedUpdates3() public {
300-
uint numIds = 3;
301-
302-
bytes32[] memory ids = new bytes32[](numIds);
303-
for (uint i = 0; i < numIds; i++) {
304-
ids[i] = priceIds[i];
305-
}
306-
pyth.parsePriceFeedUpdates{value: freshPricesUpdateFee[numIds - 1]}(
307-
freshPricesUpdateData[numIds - 1],
308-
ids,
309-
0,
310-
50
311-
);
292+
_runParsePriceFeedUpdatesBenchmark(3);
312293
}
313294

314295
function testBenchmarkParsePriceFeedUpdates4() public {
315-
uint numIds = 4;
316-
317-
bytes32[] memory ids = new bytes32[](numIds);
318-
for (uint i = 0; i < numIds; i++) {
319-
ids[i] = priceIds[i];
320-
}
321-
pyth.parsePriceFeedUpdates{value: freshPricesUpdateFee[numIds - 1]}(
322-
freshPricesUpdateData[numIds - 1],
323-
ids,
324-
0,
325-
50
326-
);
296+
_runParsePriceFeedUpdatesBenchmark(4);
327297
}
328298

329299
function testBenchmarkParsePriceFeedUpdates5() public {
330-
uint numIds = 5;
300+
_runParsePriceFeedUpdatesBenchmark(5);
301+
}
331302

332-
bytes32[] memory ids = new bytes32[](numIds);
333-
for (uint i = 0; i < numIds; i++) {
334-
ids[i] = priceIds[i];
335-
}
336-
pyth.parsePriceFeedUpdates{value: freshPricesUpdateFee[numIds - 1]}(
337-
freshPricesUpdateData[numIds - 1],
338-
ids,
339-
0,
340-
50
341-
);
303+
function testBenchmarkParsePriceFeedUpdates6() public {
304+
_runParsePriceFeedUpdatesBenchmark(6);
305+
}
306+
307+
function testBenchmarkParsePriceFeedUpdates7() public {
308+
_runParsePriceFeedUpdatesBenchmark(7);
309+
}
310+
311+
function testBenchmarkParsePriceFeedUpdates8() public {
312+
_runParsePriceFeedUpdatesBenchmark(8);
313+
}
314+
315+
function testBenchmarkParsePriceFeedUpdates9() public {
316+
_runParsePriceFeedUpdatesBenchmark(9);
317+
}
318+
319+
function testBenchmarkParsePriceFeedUpdates10() public {
320+
_runParsePriceFeedUpdatesBenchmark(10);
342321
}
343322

344323
function testBenchmarkParsePriceFeedUpdatesForAllPriceFeedsShuffledSubsetPriceIds()

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

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,23 +98,23 @@ contract PulseGasBenchmark is Test, PulseTestUtils {
9898
);
9999
}
100100

101-
function testFlow_01_Feed() public {
101+
function testBasicFlowWith01Feeds() public {
102102
_runBenchmarkWithFeeds(1);
103103
}
104104

105-
function testFlow_02_Feeds() public {
105+
function testBasicFlowWith02Feeds() public {
106106
_runBenchmarkWithFeeds(2);
107107
}
108108

109-
function testFlow_04_Feeds() public {
109+
function testBasicFlowWith04Feeds() public {
110110
_runBenchmarkWithFeeds(4);
111111
}
112112

113-
function testFlow_08_Feeds() public {
113+
function testBasicFlowWith08Feeds() public {
114114
_runBenchmarkWithFeeds(8);
115115
}
116116

117-
function testFlow_10_Feeds() public {
117+
function testBasicFlowWith10Feeds() public {
118118
_runBenchmarkWithFeeds(10);
119119
}
120120

@@ -124,7 +124,9 @@ contract PulseGasBenchmark is Test, PulseTestUtils {
124124
// The last fulfillment will be the most expensive since it needs
125125
// to linearly scan through all the fulfilled requests in storage
126126
// in order to update _state.lastUnfulfilledReq
127-
// NOTE: Run test with -vv to see extra gas logs.
127+
//
128+
// NOTE: Run test with `forge test --gas-report --match-test testMultipleRequestsOutOfOrderFulfillment`
129+
// and observe the `max` value for `executeCallback` to see the cost of the most expensive request.
128130
function testMultipleRequestsOutOfOrderFulfillment() public {
129131
uint64 timestamp = SafeCast.toUint64(block.timestamp);
130132
bytes32[] memory priceIds = createPriceIds(2);
@@ -181,9 +183,76 @@ contract PulseGasBenchmark is Test, PulseTestUtils {
181183
uint endGas = gasleft();
182184

183185
// Log gas usage for the last callback which would be the most expensive
184-
// in the original implementation
185-
console.log("Gas used for last callback (seq 1):", midGas - endGas);
186-
console.log("Gas used for all other callbacks:", startGas - midGas);
186+
// in the original implementation (need to run test with -vv)
187+
console.log(
188+
"Gas used for last callback (seq 1): %s",
189+
vm.toString(midGas - endGas)
190+
);
191+
console.log(
192+
"Gas used for all other callbacks: %s",
193+
vm.toString(startGas - midGas)
194+
);
195+
}
196+
197+
// Helper function to run the overflow mapping benchmark with a specified number of feeds
198+
function _runOverflowBenchmarkWithFeeds(uint256 numFeeds) internal {
199+
uint64 timestamp = SafeCast.toUint64(block.timestamp);
200+
bytes32[] memory priceIds = createPriceIds(numFeeds);
201+
uint32 callbackGasLimit = 100000;
202+
uint128 totalFee = pulse.getFee(
203+
defaultProvider,
204+
callbackGasLimit,
205+
priceIds
206+
);
207+
208+
// Create NUM_REQUESTS requests to fill up the main array
209+
// The constant is defined in PulseState.sol as 32
210+
uint64[] memory sequenceNumbers = new uint64[](32);
211+
vm.deal(address(consumer), 50 ether);
212+
213+
// Use the same timestamp for all requests to avoid "Too far in future" error
214+
for (uint i = 0; i < 32; i++) {
215+
vm.prank(address(consumer));
216+
sequenceNumbers[i] = pulse.requestPriceUpdatesWithCallback{
217+
value: totalFee
218+
}(defaultProvider, timestamp, priceIds, callbackGasLimit);
219+
}
220+
221+
// Create one more request that will go to the overflow mapping
222+
// (This could potentially happen earlier if a shortKey collides,
223+
// but this guarantees it.)
224+
vm.prank(address(consumer));
225+
pulse.requestPriceUpdatesWithCallback{value: totalFee}(
226+
defaultProvider,
227+
timestamp,
228+
priceIds,
229+
callbackGasLimit
230+
);
231+
}
232+
233+
// These tests benchmark the gas usage when a new request overflows the fixed-size
234+
// request array and gets stored in the overflow mapping.
235+
//
236+
// NOTE: Run test with `forge test --gas-report --match-test testOverflowMappingGasUsageWithXXFeeds`
237+
// and observe the `max` value for `executeCallback` to see the cost of the overflowing request.
238+
function testOverflowMappingGasUsageWith01Feeds() public {
239+
_runOverflowBenchmarkWithFeeds(1);
240+
}
241+
242+
function testOverflowMappingGasUsageWith02Feeds() public {
243+
_runOverflowBenchmarkWithFeeds(2);
244+
}
245+
246+
function testOverflowMappingGasUsageWith04Feeds() public {
247+
_runOverflowBenchmarkWithFeeds(4);
248+
}
249+
250+
function testOverflowMappingGasUsageWith08Feeds() public {
251+
_runOverflowBenchmarkWithFeeds(8);
252+
}
253+
254+
function testOverflowMappingGasUsageWith10Feeds() public {
255+
_runOverflowBenchmarkWithFeeds(10);
187256
}
188257
}
189258

0 commit comments

Comments
 (0)