Skip to content

Commit

Permalink
Adding changes to VRF coordinator (#12099)
Browse files Browse the repository at this point in the history
* VRF V2.5 gas optimisations (#11932)

* VRF V2.5 gas optimisations

* Minor changes

* Removed changes in SubscriptionAPI.sol due to no actual gain in hot paths

* Minor changes

* VRF-878 Gas Optimization V2 Plus (#11982)

* Optimize deregisterProvingKey

* Optimize fulfillRandomWords

* Optimize deregisterMigratableCoordinator

* Optimize _isTargetRegistered

* Optimize pendingRequestExists

* Optimize _deleteSubscription

* Optimize getActiveSubscriptionIds

* Optimize requestRandomWords

* Replace post-increment with pre-increment

* Optimize _getFeedData

* Optimize ownerCancelSubscription

* Optimize getSubscription

* Optimize createSubscription

* Optimize requestSubscriptionOwnerTransfer

* Optimize acceptSubscriptionOwnerTransfer

* Optimize addConsumer

* Update geth wrappers

* Remove proving keys length check in pendingRequestExists

* Add native payment to RandomWordsFulfilled event (#12085)

* Add native payment to RandomWordsFulfilled event

* Minor change

---------

Co-authored-by: Sri Kidambi <[email protected]>

---------

Co-authored-by: Sri Kidambi <[email protected]>
Co-authored-by: Lee Yik Jiun <[email protected]>
Co-authored-by: Lee Yik Jiun <[email protected]>
  • Loading branch information
4 people authored Feb 20, 2024
1 parent 902f3e7 commit 2b6fe5c
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 92 deletions.
67 changes: 67 additions & 0 deletions contracts/scripts/native_solc_compile_all_vrfv2plus
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env bash

set -e

echo " ┌──────────────────────────────────────────────┐"
echo " │ Compiling VRF contracts... │"
echo " └──────────────────────────────────────────────┘"

SOLC_VERSION="0.8.6"
OPTIMIZE_RUNS=1000000

SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )"
python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt

solc-select install $SOLC_VERSION
solc-select use $SOLC_VERSION
export SOLC_VERSION=$SOLC_VERSION

compileContract () {
local contract
contract=$(basename "$1" ".sol")

solc @openzeppelin/="$ROOT"/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \
-o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \
--abi --bin --allow-paths "$ROOT"/contracts/src/v0.8,"$ROOT"/contracts/node_modules\
"$ROOT"/contracts/src/v0.8/"$1"
}

compileContractAltOpts () {
local contract
contract=$(basename "$1" ".sol")

solc @openzeppelin/="$ROOT"/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs "$2" --metadata-hash none \
-o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \
--abi --bin --allow-paths "$ROOT"/contracts/src/v0.8,"$ROOT"/contracts/node_modules\
"$ROOT"/contracts/src/v0.8/"$1"
}

# VRF
compileContract vrf/VRFRequestIDBase.sol
compileContract vrf/VRFConsumerBase.sol
compileContract vrf/testhelpers/VRFConsumer.sol
compileContract vrf/testhelpers/VRFRequestIDBaseTestHelper.sol
compileContract vrf/mocks/VRFCoordinatorMock.sol

# VRF V2Plus
compileContract vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol
compileContract vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol
compileContractAltOpts vrf/dev/VRFCoordinatorV2_5.sol 50
compileContract vrf/dev/BatchVRFCoordinatorV2Plus.sol
compileContract vrf/dev/VRFV2PlusWrapper.sol
compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol
compileContract vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol
compileContract vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol
compileContract vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol
compileContract vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol
compileContract vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol
compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol
compileContract vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol
compileContract vrf/dev/libraries/VRFV2PlusClient.sol
compileContract vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol
compileContract vrf/dev/BlockhashStore.sol
compileContract vrf/dev/TrustedBlockhashStore.sol
compileContract vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol
compileContractAltOpts vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol 5
compileContract vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol
65 changes: 38 additions & 27 deletions contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,11 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr
* @dev notably can be called even if there are pending requests, outstanding ones may fail onchain
*/
function ownerCancelSubscription(uint256 subId) external onlyOwner {
if (s_subscriptionConfigs[subId].owner == address(0)) {
address owner = s_subscriptionConfigs[subId].owner;
if (owner == address(0)) {
revert InvalidSubscription();
}
_cancelSubscriptionHelper(subId, s_subscriptionConfigs[subId].owner);
_cancelSubscriptionHelper(subId, owner);
}

/**
Expand Down Expand Up @@ -306,14 +307,15 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr
override
returns (uint96 balance, uint96 nativeBalance, uint64 reqCount, address owner, address[] memory consumers)
{
if (s_subscriptionConfigs[subId].owner == address(0)) {
owner = s_subscriptionConfigs[subId].owner;
if (owner == address(0)) {
revert InvalidSubscription();
}
return (
s_subscriptions[subId].balance,
s_subscriptions[subId].nativeBalance,
s_subscriptions[subId].reqCount,
s_subscriptionConfigs[subId].owner,
owner,
s_subscriptionConfigs[subId].consumers
);
}
Expand All @@ -324,13 +326,14 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr
function getActiveSubscriptionIds(
uint256 startIndex,
uint256 maxCount
) external view override returns (uint256[] memory) {
) external view override returns (uint256[] memory ids) {
uint256 numSubs = s_subIds.length();
if (startIndex >= numSubs) revert IndexOutOfRange();
uint256 endIndex = startIndex + maxCount;
endIndex = endIndex > numSubs || maxCount == 0 ? numSubs : endIndex;
uint256[] memory ids = new uint256[](endIndex - startIndex);
for (uint256 idx = 0; idx < ids.length; idx++) {
uint256 idsLength = endIndex - startIndex;
ids = new uint256[](idsLength);
for (uint256 idx = 0; idx < idsLength; ++idx) {
ids[idx] = s_subIds.at(idx + startIndex);
}
return ids;
Expand All @@ -339,13 +342,14 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr
/**
* @inheritdoc IVRFSubscriptionV2Plus
*/
function createSubscription() external override nonReentrant returns (uint256) {
function createSubscription() external override nonReentrant returns (uint256 subId) {
// Generate a subscription id that is globally unique.
uint256 subId = uint256(
keccak256(abi.encodePacked(msg.sender, blockhash(block.number - 1), address(this), s_currentSubNonce))
uint64 currentSubNonce = s_currentSubNonce;
subId = uint256(
keccak256(abi.encodePacked(msg.sender, blockhash(block.number - 1), address(this), currentSubNonce))
);
// Increment the subscription nonce counter.
s_currentSubNonce++;
s_currentSubNonce = currentSubNonce + 1;
// Initialize storage variables.
address[] memory consumers = new address[](0);
s_subscriptions[subId] = Subscription({balance: 0, nativeBalance: 0, reqCount: 0});
Expand All @@ -369,8 +373,9 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr
address newOwner
) external override onlySubOwner(subId) nonReentrant {
// Proposing to address(0) would never be claimable so don't need to check.
if (s_subscriptionConfigs[subId].requestedOwner != newOwner) {
s_subscriptionConfigs[subId].requestedOwner = newOwner;
SubscriptionConfig storage subscriptionConfig = s_subscriptionConfigs[subId];
if (subscriptionConfig.requestedOwner != newOwner) {
subscriptionConfig.requestedOwner = newOwner;
emit SubscriptionOwnerTransferRequested(subId, msg.sender, newOwner);
}
}
Expand All @@ -379,13 +384,13 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr
* @inheritdoc IVRFSubscriptionV2Plus
*/
function acceptSubscriptionOwnerTransfer(uint256 subId) external override nonReentrant {
if (s_subscriptionConfigs[subId].owner == address(0)) {
address oldOwner = s_subscriptionConfigs[subId].owner;
if (oldOwner == address(0)) {
revert InvalidSubscription();
}
if (s_subscriptionConfigs[subId].requestedOwner != msg.sender) {
revert MustBeRequestedOwner(s_subscriptionConfigs[subId].requestedOwner);
}
address oldOwner = s_subscriptionConfigs[subId].owner;
s_subscriptionConfigs[subId].owner = msg.sender;
s_subscriptionConfigs[subId].requestedOwner = address(0);
emit SubscriptionOwnerTransferred(subId, oldOwner, msg.sender);
Expand All @@ -396,36 +401,42 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr
*/
function addConsumer(uint256 subId, address consumer) external override onlySubOwner(subId) nonReentrant {
// Already maxed, cannot add any more consumers.
if (s_subscriptionConfigs[subId].consumers.length == MAX_CONSUMERS) {
address[] storage consumers = s_subscriptionConfigs[subId].consumers;
if (consumers.length == MAX_CONSUMERS) {
revert TooManyConsumers();
}
if (s_consumers[consumer][subId] != 0) {
mapping(uint256 => uint64) storage nonces = s_consumers[consumer];
if (nonces[subId] != 0) {
// Idempotence - do nothing if already added.
// Ensures uniqueness in s_subscriptions[subId].consumers.
return;
}
// Initialize the nonce to 1, indicating the consumer is allocated.
s_consumers[consumer][subId] = 1;
s_subscriptionConfigs[subId].consumers.push(consumer);
nonces[subId] = 1;
consumers.push(consumer);

emit SubscriptionConsumerAdded(subId, consumer);
}

function _deleteSubscription(uint256 subId) internal returns (uint96 balance, uint96 nativeBalance) {
SubscriptionConfig memory subConfig = s_subscriptionConfigs[subId];
Subscription memory sub = s_subscriptions[subId];
balance = sub.balance;
nativeBalance = sub.nativeBalance;
address[] storage consumers = s_subscriptionConfigs[subId].consumers;
balance = s_subscriptions[subId].balance;
nativeBalance = s_subscriptions[subId].nativeBalance;
// Note bounded by MAX_CONSUMERS;
// If no consumers, does nothing.
for (uint256 i = 0; i < subConfig.consumers.length; i++) {
delete s_consumers[subConfig.consumers[i]][subId];
uint256 consumersLength = consumers.length;
for (uint256 i = 0; i < consumersLength; ++i) {
delete s_consumers[consumers[i]][subId];
}
delete s_subscriptionConfigs[subId];
delete s_subscriptions[subId];
s_subIds.remove(subId);
s_totalBalance -= balance;
s_totalNativeBalance -= nativeBalance;
if (balance != 0) {
s_totalBalance -= balance;
}
if (nativeBalance != 0) {
s_totalNativeBalance -= nativeBalance;
}
return (balance, nativeBalance);
}

Expand Down
Loading

0 comments on commit 2b6fe5c

Please sign in to comment.