-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add the ability to run benchmarks on the QGB contract #218
Merged
Changes from 3 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
ba76508
feat: add the ability to run benchmarks on the QGB contract
rach-id 3b20de7
chore: rename benchmark test not to be run
rach-id b4db380
chore: make the benhcmark always run
rach-id 7aa8641
chore: fmt
rach-id 9797bae
chore: only sign the necessary number
rach-id 01438eb
Merge branch 'master' into benchmark
rach-id 37cd436
chore: rename test file to Blobstream prefix
rach-id File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
[profile.default] | ||
solc_version = "0.8.20" | ||
via_ir = true | ||
gas_reports = ["*"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.19; | ||
|
||
import "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol"; | ||
|
||
import "../Constants.sol"; | ||
import "../DataRootTuple.sol"; | ||
import "../QuantumGravityBridge.sol"; | ||
import "../lib/tree/binary/BinaryMerkleProof.sol"; | ||
|
||
import "ds-test/test.sol"; | ||
|
||
interface CheatCodes { | ||
function addr(uint256 privateKey) external returns (address); | ||
function sign(uint256 privateKey, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); | ||
function deriveKey(string calldata, string calldata, uint32) external returns (uint256); | ||
} | ||
|
||
/// @notice Example command to run the benchmark: | ||
/// `forge test --match-test testBenchmarkSubmitDataRootTupleRoot -vvvvvv --gas-report`. | ||
/// To change the validator set size, change the `numberOfValidators` constant. | ||
/// To make custom calculations of the gas, you can use the `gasleft()` solidity | ||
/// built-in function. | ||
/// The following answer has some insights on using that: | ||
/// https://ethereum.stackexchange.com/a/132325/65649 | ||
/// The gas estimations might not be accurate to the real cost in a real network, | ||
/// and that's because foundry doesn't track calldata cost. source: | ||
/// https://github.com/foundry-rs/foundry/issues/3475#issuecomment-1469940917 | ||
/// To have accurate results, make sure to add the following costs: | ||
/// A byte of calldata costs either 4 gas (if it is zero) or 16 gas (if it is any other value). | ||
contract Benchmark is DSTest { | ||
uint256 private constant numberOfValidators = 1; | ||
|
||
// Private keys used for test signatures. | ||
uint256[] private privateKeys; | ||
|
||
QuantumGravityBridge private bridge; | ||
|
||
Validator[] private validators; | ||
uint256 private votingPower = 5000; | ||
uint256 private dataTupleRootNonce = 0; | ||
|
||
// Set up Foundry cheatcodes. | ||
CheatCodes cheats = CheatCodes(HEVM_ADDRESS); | ||
|
||
function setUp() public { | ||
uint256 initialVelsetNonce = 0; | ||
privateKeys = derivePrivateKeys(numberOfValidators); | ||
validators = initializeValidators(privateKeys); | ||
|
||
bytes32 hash = computeValidatorSetHash(validators); | ||
bridge = new QuantumGravityBridge(); | ||
bridge.initialize(initialVelsetNonce, (2 * votingPower * numberOfValidators) / 3, hash); | ||
} | ||
|
||
function testBenchmarkSubmitDataRootTupleRoot() public { | ||
uint256 initialVelsetNonce = 0; | ||
uint256 nonce = 1; | ||
|
||
// 32 bytes, chosen at random. | ||
bytes32 newTupleRoot = 0x0de92bac0b356560d821f8e7b6f5c9fe4f3f88f6c822283efd7ab51ad56a640e; | ||
bytes32 newDataRootTupleRoot = domainSeparateDataRootTupleRoot(nonce, newTupleRoot); | ||
|
||
// Signature for the update. | ||
Signature[] memory sigs = new Signature[](numberOfValidators); | ||
bytes32 digest_eip191 = ECDSA.toEthSignedMessageHash(newDataRootTupleRoot); | ||
for (uint256 i = 0; i < numberOfValidators; i++) { | ||
(uint8 v, bytes32 r, bytes32 s) = cheats.sign(privateKeys[i], digest_eip191); | ||
sigs[i] = Signature(v, r, s); | ||
} | ||
|
||
// these are called here so that they're part of the gas report. | ||
// uint256 currentPowerThreshold = (2 * votingPower * numberOfValidators) / 3; | ||
// bytes32 currentValidatorSetHash = bridge.computeValidatorSetHash(validators); | ||
// bridge.domainSeparateValidatorSetHash(nonce, currentPowerThreshold, currentValidatorSetHash); | ||
// bridge.checkValidatorSignatures(validators, sigs, newDataRootTupleRoot, currentPowerThreshold); | ||
|
||
bridge.submitDataRootTupleRoot(nonce, initialVelsetNonce, newTupleRoot, validators, sigs); | ||
} | ||
|
||
function computeValidatorSetHash(Validator[] memory _validators) private pure returns (bytes32) { | ||
return keccak256(abi.encode(_validators)); | ||
} | ||
|
||
function domainSeparateDataRootTupleRoot(uint256 _nonce, bytes32 _dataRootTupleRoot) | ||
private | ||
pure | ||
returns (bytes32) | ||
{ | ||
bytes32 c = keccak256(abi.encode(DATA_ROOT_TUPLE_ROOT_DOMAIN_SEPARATOR, _nonce, _dataRootTupleRoot)); | ||
|
||
return c; | ||
} | ||
|
||
function derivePrivateKeys(uint256 count) private returns (uint256[] memory) { | ||
string memory mnemonic = "test test test test test test test test test test test junk"; | ||
uint256[] memory keys = new uint256[](count); | ||
for (uint32 i = 0; i < count; i++) { | ||
keys[i] = cheats.deriveKey(mnemonic, "m/44'/60'/0'/0", i); | ||
} | ||
return keys; | ||
} | ||
|
||
function initializeValidators(uint256[] memory keys) private returns (Validator[] memory) { | ||
Validator[] memory vs = new Validator[](keys.length); | ||
for (uint256 i = 0; i < keys.length; i++) { | ||
vs[i] = Validator(cheats.addr(keys[i]), votingPower); | ||
} | ||
return vs; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[note for reviewers]
This is always run, but it only takes
5.71ms
, so I guess it's okey. we can leave it running with the tests.