Skip to content

Commit 52e680a

Browse files
committed
add configurable gas limits and failure on calls
1 parent 5cf22d9 commit 52e680a

File tree

6 files changed

+312
-14
lines changed

6 files changed

+312
-14
lines changed

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

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,15 @@ abstract contract Entropy is IEntropy, EntropyState {
470470
if (!req.isRequestWithCallback) {
471471
revert EntropyErrors.InvalidRevealCall();
472472
}
473+
// Invariant check: all callback requests should have useBlockhash set to false.
474+
if (req.useBlockhash) {
475+
revert EntropyErrors.InvalidRevealCall();
476+
}
477+
478+
if (req.reentryGuard) {
479+
revert EntropyErrors.InvalidRevealCall();
480+
}
481+
473482
bytes32 blockHash;
474483
bytes32 randomNumber;
475484
(randomNumber, blockHash) = revealHelper(
@@ -480,27 +489,60 @@ abstract contract Entropy is IEntropy, EntropyState {
480489

481490
address callAddress = req.requester;
482491

483-
emit RevealedWithCallback(
484-
req,
485-
userRandomNumber,
486-
providerRevelation,
487-
randomNumber
488-
);
489-
490-
clearRequest(provider, sequenceNumber);
491-
492492
// Check if the callAddress is a contract account.
493+
// TODO: this can probably be deleted.
493494
uint len;
494495
assembly {
495496
len := extcodesize(callAddress)
496497
}
498+
499+
bool success;
500+
bytes memory ret;
497501
if (len != 0) {
498-
IEntropyConsumer(callAddress)._entropyCallback(
499-
sequenceNumber,
500-
provider,
502+
uint64 gas;
503+
if (req.blockNumber != 0) {
504+
gas = req.blockNumber;
505+
} else {
506+
gas = gasLeft();
507+
}
508+
509+
req.reentryGuard = true;
510+
(success, ret) == callAddress.excessivelySafeCall(
511+
gas,
512+
32,
513+
abi.encodeWithSelector(
514+
IEntropyConsumer._entropyCallback.selector,
515+
sequenceNumber,
516+
provider,
517+
randomNumber
518+
)
519+
);
520+
req.reentryGuard = false;
521+
}
522+
523+
if (success) {
524+
emit RevealedWithCallback(
525+
req,
526+
userRandomNumber,
527+
providerRevelation,
501528
randomNumber
502529
);
530+
clearRequest(provider, sequenceNumber);
531+
} else {
532+
bytes32 errorReason;
533+
assembly {
534+
errorReason := mload(add(ret, 32));
535+
}
536+
537+
emit CallbackFailed(
538+
provider,
539+
req.requester,
540+
sequenceNumber,
541+
errorReason
542+
)
543+
req.callbackAttempted = true;
503544
}
545+
504546
}
505547

506548
function getProviderInfo(
@@ -625,6 +667,24 @@ abstract contract Entropy is IEntropy, EntropyState {
625667
);
626668
}
627669

670+
// Set the default gas limit for a request.
671+
function setDefaultGasLimit(uint64 gasLimit) external override {
672+
EntropyStructs.ProviderInfo storage provider = _state.providers[
673+
msg.sender
674+
];
675+
if (provider.sequenceNumber == 0) {
676+
revert EntropyErrors.NoSuchProvider();
677+
}
678+
679+
uint64 oldGasLimit = provider.defaultGasLimit;
680+
provider.defaultGasLimit = gasLimit;
681+
emit ProviderDefaultGasLimitUpdated(
682+
msg.sender,
683+
oldGasLimit,
684+
gasLimit
685+
);
686+
}
687+
628688
function constructUserCommitment(
629689
bytes32 userRandomness
630690
) public pure override returns (bytes32 userCommitment) {

target_chains/ethereum/contracts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"migrate": "truffle migrate",
2424
"receiver-submit-guardian-sets": "truffle exec scripts/receiverSubmitGuardianSetUpgrades.js",
2525
"verify": "truffle run verify $npm_config_module@$npm_config_contract_address --network $npm_config_network",
26-
"install-forge-deps": "forge install foundry-rs/[email protected] --no-git --no-commit",
26+
"install-forge-deps": "forge install foundry-rs/[email protected] nomad-xyz/ExcessivelySafeCall@81cd99c --no-git --no-commit",
2727
"coverage": "./coverage.sh",
2828
"test:format": "prettier --check .",
2929
"fix:format": "prettier --write ."

target_chains/ethereum/entropy_sdk/solidity/EntropyEvents.sol

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ interface EntropyEvents {
2828
bytes32 providerRevelation,
2929
bytes32 randomNumber
3030
);
31+
// TODO: indexing, other fields??
32+
event CallbackFailed(
33+
address indexed provider,
34+
address indexed requestor,
35+
uint64 indexed sequenceNumber,
36+
bytes32 errorCode
37+
);
3138

3239
event ProviderFeeUpdated(address provider, uint128 oldFee, uint128 newFee);
3340

@@ -44,6 +51,12 @@ interface EntropyEvents {
4451
uint32 newMaxNumHashes
4552
);
4653

54+
event ProviderDefaultGasLimitUpdated(
55+
address provider,
56+
uint64 oldDefaultGasLimit,
57+
uint64 newDefaultGasLimit
58+
);
59+
4760
event Withdrawal(
4861
address provider,
4962
address recipient,

target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ contract EntropyStructs {
3737
// Maximum number of hashes to record in a request. This should be set according to the maximum gas limit
3838
// the provider supports for callbacks.
3939
uint32 maxNumHashes;
40+
// Default gas limit to use for callbacks.
41+
uint64 defaultGasLimit;
4042
}
4143

4244
struct Request {
@@ -54,13 +56,19 @@ contract EntropyStructs {
5456
// Note that we're using a uint64 such that we have an additional space for an address and other fields in
5557
// this storage slot. Although block.number returns a uint256, 64 bits should be plenty to index all of the
5658
// blocks ever generated.
59+
//
60+
// Note: We are overloading this storage slot to also store a gas limit for callbacks, as we do not support
61+
// blockhashes in the callback case.
5762
uint64 blockNumber;
5863
// The address that requested this random number.
5964
address requester;
6065
// If true, incorporate the blockhash of blockNumber into the generated random value.
6166
bool useBlockhash;
6267
// If true, the requester will be called back with the generated random value.
6368
bool isRequestWithCallback;
64-
// There are 2 remaining bytes of free space in this slot.
69+
// If true, the callback has been attempted by the provider (and failed for some reason).
70+
bool callbackAttempted;
71+
// If true, a fulfillment request for this is already in-flight
72+
bool reentryGuard;
6573
}
6674
}

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

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,60 @@
11
[
2+
{
3+
"anonymous": false,
4+
"inputs": [
5+
{
6+
"indexed": true,
7+
"internalType": "address",
8+
"name": "provider",
9+
"type": "address"
10+
},
11+
{
12+
"indexed": true,
13+
"internalType": "address",
14+
"name": "requestor",
15+
"type": "address"
16+
},
17+
{
18+
"indexed": true,
19+
"internalType": "uint64",
20+
"name": "sequenceNumber",
21+
"type": "uint64"
22+
},
23+
{
24+
"indexed": false,
25+
"internalType": "bytes32",
26+
"name": "errorCode",
27+
"type": "bytes32"
28+
}
29+
],
30+
"name": "CallbackFailed",
31+
"type": "event"
32+
},
33+
{
34+
"anonymous": false,
35+
"inputs": [
36+
{
37+
"indexed": false,
38+
"internalType": "address",
39+
"name": "provider",
40+
"type": "address"
41+
},
42+
{
43+
"indexed": false,
44+
"internalType": "uint64",
45+
"name": "oldDefaultGasLimit",
46+
"type": "uint64"
47+
},
48+
{
49+
"indexed": false,
50+
"internalType": "uint64",
51+
"name": "newDefaultGasLimit",
52+
"type": "uint64"
53+
}
54+
],
55+
"name": "ProviderDefaultGasLimitUpdated",
56+
"type": "event"
57+
},
258
{
359
"anonymous": false,
460
"inputs": [
@@ -163,6 +219,11 @@
163219
"internalType": "uint32",
164220
"name": "maxNumHashes",
165221
"type": "uint32"
222+
},
223+
{
224+
"internalType": "uint64",
225+
"name": "defaultGasLimit",
226+
"type": "uint64"
166227
}
167228
],
168229
"indexed": false,
@@ -218,6 +279,16 @@
218279
"internalType": "bool",
219280
"name": "isRequestWithCallback",
220281
"type": "bool"
282+
},
283+
{
284+
"internalType": "bool",
285+
"name": "callbackAttempted",
286+
"type": "bool"
287+
},
288+
{
289+
"internalType": "bool",
290+
"name": "reentryGuard",
291+
"type": "bool"
221292
}
222293
],
223294
"indexed": false,
@@ -297,6 +368,16 @@
297368
"internalType": "bool",
298369
"name": "isRequestWithCallback",
299370
"type": "bool"
371+
},
372+
{
373+
"internalType": "bool",
374+
"name": "callbackAttempted",
375+
"type": "bool"
376+
},
377+
{
378+
"internalType": "bool",
379+
"name": "reentryGuard",
380+
"type": "bool"
300381
}
301382
],
302383
"indexed": false,
@@ -352,6 +433,16 @@
352433
"internalType": "bool",
353434
"name": "isRequestWithCallback",
354435
"type": "bool"
436+
},
437+
{
438+
"internalType": "bool",
439+
"name": "callbackAttempted",
440+
"type": "bool"
441+
},
442+
{
443+
"internalType": "bool",
444+
"name": "reentryGuard",
445+
"type": "bool"
355446
}
356447
],
357448
"indexed": false,
@@ -431,6 +522,16 @@
431522
"internalType": "bool",
432523
"name": "isRequestWithCallback",
433524
"type": "bool"
525+
},
526+
{
527+
"internalType": "bool",
528+
"name": "callbackAttempted",
529+
"type": "bool"
530+
},
531+
{
532+
"internalType": "bool",
533+
"name": "reentryGuard",
534+
"type": "bool"
434535
}
435536
],
436537
"indexed": false,

0 commit comments

Comments
 (0)