Skip to content

Commit d08454e

Browse files
committed
gas tests
1 parent 293c8a6 commit d08454e

File tree

1 file changed

+133
-12
lines changed

1 file changed

+133
-12
lines changed

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

Lines changed: 133 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,7 +1003,9 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
10031003
assertEq(reqAfterReveal.sequenceNumber, 0);
10041004
}
10051005

1006-
function testRequestWithCallbackAndRevealWithCallbackWithGasLimitAndFailure() public {
1006+
function testRequestWithCallbackAndRevealWithCallbackWithGasLimitAndFailure()
1007+
public
1008+
{
10071009
uint64 defaultGasLimit = 100000;
10081010
vm.prank(provider1);
10091011
random.setDefaultGasLimit(defaultGasLimit);
@@ -1025,7 +1027,10 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
10251027
assertEq(req.blockNumberOrGasLimit, defaultGasLimit);
10261028

10271029
// On the first attempt, the transaction should succeed and emit CallbackFailed event.
1028-
bytes memory revertReason = abi.encodeWithSelector(0x08c379a0, "Callback failed");
1030+
bytes memory revertReason = abi.encodeWithSelector(
1031+
0x08c379a0,
1032+
"Callback failed"
1033+
);
10291034
vm.expectEmit(false, false, false, true, address(random));
10301035
emit CallbackFailed(
10311036
provider1,
@@ -1058,15 +1063,11 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
10581063
);
10591064

10601065
// Again, request stays active after failure
1061-
reqAfterFailure = random.getRequest(
1062-
provider1,
1063-
assignedSequenceNumber
1064-
);
1066+
reqAfterFailure = random.getRequest(provider1, assignedSequenceNumber);
10651067
assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber);
10661068
assertTrue(reqAfterFailure.callbackFailed);
10671069

1068-
// If the callback starts succeeding, we can invoke it and
1069-
// it emits RevealedWithCallback event.
1070+
// If the callback starts succeeding, we can invoke it and it emits the usual RevealedWithCallback event.
10701071
consumer.setReverts(false);
10711072
vm.expectEmit(false, false, false, true, address(random));
10721073
emit RevealedWithCallback(
@@ -1097,10 +1098,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
10971098
function testRequestWithCallbackAndRevealWithCallbackFailing() public {
10981099
bytes32 userRandomNumber = bytes32(uint(42));
10991100
uint fee = random.getFee(provider1);
1100-
EntropyConsumer consumer = new EntropyConsumer(
1101-
address(random),
1102-
true
1103-
);
1101+
EntropyConsumer consumer = new EntropyConsumer(address(random), true);
11041102
vm.deal(address(consumer), fee);
11051103
vm.startPrank(address(consumer));
11061104
uint64 assignedSequenceNumber = random.requestWithCallback{value: fee}(
@@ -1431,6 +1429,108 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
14311429
// Fee should be the same as base fee since we're using less gas than default
14321430
assertEq(fee, random.getFee(provider1));
14331431
}
1432+
1433+
function testRequestWithCallbackAndRevealWithCallbackWithGasLimitAndFailureWithGasUsage()
1434+
public
1435+
{
1436+
uint64 defaultGasLimit = 100000;
1437+
vm.prank(provider1);
1438+
random.setDefaultGasLimit(defaultGasLimit);
1439+
1440+
bytes32 userRandomNumber = bytes32(uint(42));
1441+
uint fee = random.getFee(provider1);
1442+
EntropyConsumer consumer = new EntropyConsumer(address(random), false);
1443+
// Consumer callback uses ~10% more gas than the provider's default
1444+
consumer.setTargetGasUsage((defaultGasLimit * 110) / 100);
1445+
1446+
vm.deal(user1, fee);
1447+
vm.prank(user1);
1448+
uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}(
1449+
userRandomNumber
1450+
);
1451+
EntropyStructs.Request memory req = random.getRequest(
1452+
provider1,
1453+
assignedSequenceNumber
1454+
);
1455+
1456+
// Verify the gas limit was set correctly
1457+
assertEq(req.blockNumberOrGasLimit, defaultGasLimit);
1458+
1459+
// The transaction reverts if the provider does not provide enough gas to forward
1460+
// the gasLimit to the callback transaction.
1461+
vm.expectRevert();
1462+
random.revealWithCallback{gas: defaultGasLimit - 10000}(
1463+
provider1,
1464+
assignedSequenceNumber,
1465+
userRandomNumber,
1466+
provider1Proofs[assignedSequenceNumber]
1467+
);
1468+
1469+
// If called with enough gas, the transaction should succeed, but the callback should fail because
1470+
// it uses too much gas.
1471+
vm.expectEmit(false, false, false, true, address(random));
1472+
emit CallbackFailed(
1473+
provider1,
1474+
address(consumer),
1475+
assignedSequenceNumber,
1476+
// out-of-gas reverts have an empty bytes array as the return value.
1477+
""
1478+
);
1479+
random.revealWithCallback(
1480+
provider1,
1481+
assignedSequenceNumber,
1482+
userRandomNumber,
1483+
provider1Proofs[assignedSequenceNumber]
1484+
);
1485+
1486+
// Verify request is still active after failure
1487+
EntropyStructs.Request memory reqAfterFailure = random.getRequest(
1488+
provider1,
1489+
assignedSequenceNumber
1490+
);
1491+
assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber);
1492+
assertTrue(reqAfterFailure.callbackFailed);
1493+
1494+
// A subsequent attempt passing insufficient gas should also revert
1495+
vm.expectRevert();
1496+
random.revealWithCallback{gas: defaultGasLimit - 10000}(
1497+
provider1,
1498+
assignedSequenceNumber,
1499+
userRandomNumber,
1500+
provider1Proofs[assignedSequenceNumber]
1501+
);
1502+
1503+
// Again, request stays active after failure
1504+
reqAfterFailure = random.getRequest(provider1, assignedSequenceNumber);
1505+
assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber);
1506+
assertTrue(reqAfterFailure.callbackFailed);
1507+
1508+
// Calling without a gas limit should succeed
1509+
vm.expectEmit(false, false, false, true, address(random));
1510+
emit RevealedWithCallback(
1511+
reqAfterFailure,
1512+
userRandomNumber,
1513+
provider1Proofs[assignedSequenceNumber],
1514+
random.combineRandomValues(
1515+
userRandomNumber,
1516+
provider1Proofs[assignedSequenceNumber],
1517+
0
1518+
)
1519+
);
1520+
random.revealWithCallback(
1521+
provider1,
1522+
assignedSequenceNumber,
1523+
userRandomNumber,
1524+
provider1Proofs[assignedSequenceNumber]
1525+
);
1526+
1527+
// Verify request is cleared after successful reveal
1528+
EntropyStructs.Request memory reqAfterReveal = random.getRequest(
1529+
provider1,
1530+
assignedSequenceNumber
1531+
);
1532+
assertEq(reqAfterReveal.sequenceNumber, 0);
1533+
}
14341534
}
14351535

14361536
contract EntropyConsumer is IEntropyConsumer {
@@ -1439,10 +1539,13 @@ contract EntropyConsumer is IEntropyConsumer {
14391539
address public entropy;
14401540
address public provider;
14411541
bool public reverts;
1542+
uint256 public gasUsed;
1543+
uint256 public targetGasUsage;
14421544

14431545
constructor(address _entropy, bool _reverts) {
14441546
entropy = _entropy;
14451547
reverts = _reverts;
1548+
targetGasUsage = 0; // Default target
14461549
}
14471550

14481551
function requestEntropy(
@@ -1462,11 +1565,29 @@ contract EntropyConsumer is IEntropyConsumer {
14621565
reverts = _reverts;
14631566
}
14641567

1568+
function setTargetGasUsage(uint256 _targetGasUsage) public {
1569+
targetGasUsage = _targetGasUsage;
1570+
}
1571+
14651572
function entropyCallback(
14661573
uint64 _sequence,
14671574
address _provider,
14681575
bytes32 _randomness
14691576
) internal override {
1577+
uint256 startGas = gasleft();
1578+
uint256 currentGasUsed = 0;
1579+
1580+
// Keep consuming gas until we reach our target
1581+
while (currentGasUsed < targetGasUsage) {
1582+
// Consume gas with a hash operation
1583+
bytes32 hash = keccak256(
1584+
abi.encodePacked(currentGasUsed, _randomness)
1585+
);
1586+
currentGasUsed = startGas - gasleft();
1587+
}
1588+
1589+
gasUsed = currentGasUsed;
1590+
14701591
if (!reverts) {
14711592
sequence = _sequence;
14721593
provider = _provider;

0 commit comments

Comments
 (0)