Skip to content

Commit 75a3c02

Browse files
committed
address PR comments
1 parent c9a81ca commit 75a3c02

File tree

5 files changed

+53
-8
lines changed

5 files changed

+53
-8
lines changed

target_chains/ethereum/contracts/contracts/entropy/Entropy.sol

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ import "@pythnetwork/entropy-sdk-solidity/EntropyStatusConstants.sol";
8080
abstract contract Entropy is IEntropy, EntropyState {
8181
using ExcessivelySafeCall for address;
8282

83+
uint32 public constant TEN_THOUSAND = 10000;
84+
uint32 public constant MAX_GAS_LIMIT =
85+
uint32(type(uint16).max) * TEN_THOUSAND;
86+
8387
function _initialize(
8488
address admin,
8589
uint128 pythFeeInWei,
@@ -267,7 +271,7 @@ abstract contract Entropy is IEntropy, EntropyState {
267271
// they still pay for the full gas limit. So we may as well give them the full limit here.
268272
// 2. If a provider has a defaultGasLimit != 0, we need to ensure that all requests have a >0 gas limit
269273
// so that we opt-in to the new callback failure state flow.
270-
req.gasLimit10k = roundGas(
274+
req.gasLimit10k = roundTo10kGas(
271275
callbackGasLimit < providerInfo.defaultGasLimit
272276
? providerInfo.defaultGasLimit
273277
: callbackGasLimit
@@ -546,7 +550,7 @@ abstract contract Entropy is IEntropy, EntropyState {
546550
// than the indicated gas limit. (See CALL opcode docs here https://www.evm.codes/?fork=cancun#f1)
547551
// Consequently, out-of-gas reverts need to be handled carefully to ensure that the callback
548552
// was truly provided with a sufficient amount of gas.
549-
uint256(req.gasLimit10k) * 10000,
553+
uint256(req.gasLimit10k) * TEN_THOUSAND,
550554
256, // copy at most 256 bytes of the return value into ret.
551555
abi.encodeWithSelector(
552556
IEntropyConsumer._entropyCallback.selector,
@@ -568,7 +572,8 @@ abstract contract Entropy is IEntropy, EntropyState {
568572
clearRequest(provider, sequenceNumber);
569573
} else if (
570574
ret.length > 0 ||
571-
(startingGas * 31) / 32 > uint256(req.gasLimit10k) * 10000
575+
(startingGas * 31) / 32 >
576+
uint256(req.gasLimit10k) * TEN_THOUSAND
572577
) {
573578
// The callback reverted for some reason.
574579
// If ret.length > 0, then we know the callback manually triggered a revert, so it's safe to mark it as failed.
@@ -668,7 +673,7 @@ abstract contract Entropy is IEntropy, EntropyState {
668673
// This approach may be somewhat simplistic, but it allows us to continue using the
669674
// existing feeInWei parameter for the callback failure flow instead of defining new
670675
// configuration values.
671-
uint32 roundedGasLimit = uint32(roundGas(gasLimit)) * 10000;
676+
uint32 roundedGasLimit = uint32(roundTo10kGas(gasLimit)) * TEN_THOUSAND;
672677
if (
673678
provider.defaultGasLimit > 0 &&
674679
roundedGasLimit > provider.defaultGasLimit
@@ -787,6 +792,10 @@ abstract contract Entropy is IEntropy, EntropyState {
787792
revert EntropyErrors.NoSuchProvider();
788793
}
789794

795+
// Check that we can round the gas limit into the 10k gas. This reverts
796+
// if the provided value exceeds the max.
797+
roundTo10kGas(gasLimit);
798+
790799
uint32 oldGasLimit = provider.defaultGasLimit;
791800
provider.defaultGasLimit = gasLimit;
792801
emit ProviderDefaultGasLimitUpdated(msg.sender, oldGasLimit, gasLimit);
@@ -810,11 +819,16 @@ abstract contract Entropy is IEntropy, EntropyState {
810819

811820
// Rounds the provided quantity of gas into units of 10k gas.
812821
// If gas is not evenly divisible by 10k, rounds up.
813-
function roundGas(uint32 gas) internal pure returns (uint16) {
814-
uint32 gas10k = gas / 10000;
815-
if (gas10k * 10000 < gas) {
822+
function roundTo10kGas(uint32 gas) internal pure returns (uint16) {
823+
if (gas > MAX_GAS_LIMIT) {
824+
revert EntropyErrors.MaxGasLimitExceeded();
825+
}
826+
827+
uint32 gas10k = gas / TEN_THOUSAND;
828+
if (gas10k * TEN_THOUSAND < gas) {
816829
gas10k += 1;
817830
}
831+
// Note: safe cast here should never revert due to the if statement above.
818832
return SafeCast.toUint16(gas10k);
819833
}
820834

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,19 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
14631463
random.setDefaultGasLimit(0);
14641464
info = random.getProviderInfo(provider1);
14651465
assertEq(info.defaultGasLimit, 0);
1466+
1467+
// Can set to maximum value.
1468+
uint32 maxLimit = random.MAX_GAS_LIMIT();
1469+
vm.prank(provider1);
1470+
random.setDefaultGasLimit(maxLimit);
1471+
info = random.getProviderInfo(provider1);
1472+
assertEq(info.defaultGasLimit, random.MAX_GAS_LIMIT());
1473+
1474+
// Reverts if max value is exceeded
1475+
uint32 exceedsGasLimit = random.MAX_GAS_LIMIT() + 1;
1476+
vm.prank(provider1);
1477+
vm.expectRevert(EntropyErrors.MaxGasLimitExceeded.selector);
1478+
random.setDefaultGasLimit(exceedsGasLimit);
14661479
}
14671480

14681481
function testSetDefaultGasLimitRevertIfNotFromProvider() public {
@@ -1528,6 +1541,17 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
15281541
uint128(type(uint16).max) / 2
15291542
);
15301543

1544+
// Test larger than max value reverts with expected error
1545+
uint32 exceedsGasLimit = uint32(type(uint16).max) * 10000 + 1;
1546+
vm.expectRevert(EntropyErrors.MaxGasLimitExceeded.selector);
1547+
random.getFeeForGas(provider1, exceedsGasLimit);
1548+
vm.expectRevert(EntropyErrors.MaxGasLimitExceeded.selector);
1549+
random.requestWithCallbackAndGasLimit{value: 10000000000000}(
1550+
provider1,
1551+
bytes32(uint(42)),
1552+
exceedsGasLimit
1553+
);
1554+
15311555
// A provider with a 0 gas limit is opted-out of the failure state flow, indicated by
15321556
// a 0 gas limit on all requests.
15331557
vm.prank(provider1);

target_chains/ethereum/entropy_sdk/solidity/EntropyErrors.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,6 @@ library EntropyErrors {
4545
error UpdateTooOld();
4646
// Not enough gas was provided to the function to execute the callback with the desired amount of gas.
4747
error InsufficientGas();
48+
// A gas limit value was provided that was greater than the maximum possible limit of 655,350,000
49+
error MaxGasLimitExceeded();
4850
}

target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ contract EntropyStructs {
6464
// Status flag for requests with callbacks. See EntropyConstants for the possible values of this flag.
6565
uint8 callbackStatus;
6666
// The gasLimit in units of 10k gas. (i.e., 2 = 20k gas). We're using units of 10k in order to fit this
67-
// field into the remaining 2 bytes of this storage slot. The dynamic range here is 10k - ~65M, which should
67+
// field into the remaining 2 bytes of this storage slot. The dynamic range here is 10k - 655M, which should
6868
// cover all real-world use cases.
6969
uint16 gasLimit10k;
7070
}

target_chains/ethereum/entropy_sdk/solidity/abis/EntropyErrors.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
"name": "LastRevealedTooOld",
4040
"type": "error"
4141
},
42+
{
43+
"inputs": [],
44+
"name": "MaxGasLimitExceeded",
45+
"type": "error"
46+
},
4247
{
4348
"inputs": [],
4449
"name": "NoSuchProvider",

0 commit comments

Comments
 (0)