Skip to content

Commit

Permalink
Gas benchmarks + updated README
Browse files Browse the repository at this point in the history
  • Loading branch information
0xvv committed Oct 1, 2023
1 parent 9f03603 commit f8dde3c
Show file tree
Hide file tree
Showing 6 changed files with 638 additions and 55 deletions.
130 changes: 75 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,83 +1,103 @@
<img align="right" width="150" height="150" top="100" src="./assets/blueprint.png">

# huff-project-template • [![ci](https://github.com/huff-language/huff-project-template/actions/workflows/ci.yaml/badge.svg)](https://github.com/huff-language/huff-project-template/actions/workflows/ci.yaml) ![license](https://img.shields.io/github/license/huff-language/huff-project-template.svg) ![solidity](https://img.shields.io/badge/solidity-^0.8.15-lightgrey)

Versatile Huff Project Template using Foundry.


## Getting Started

### Requirements

The following will need to be installed in order to use this template. Please follow the links and instructions.
The following will need to be installed in order to use this repo.

- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
- You'll know you've done it right if you can run `git --version`
- [Foundry / Foundryup](https://github.com/gakonst/foundry)
- This will install `forge`, `cast`, and `anvil`
- You can test you've installed them right by running `forge --version` and get an output like: `forge 0.2.0 (92f8951 2022-08-06T00:09:32.96582Z)`
- To get the latest of each, just run `foundryup`
- [Huff Compiler](https://docs.huff.sh/get-started/installing/)
- You'll know you've done it right if you can run `huffc --version` and get an output like: `huffc 0.3.0`

### Quickstart

1. Clone this repo or use template

Click "Use this template" on [GitHub](https://github.com/huff-language/huff-project-template) to create a new repository with this repo as the initial state.

Or run:
## Quickstart

```
git clone https://github.com/huff-language/huff-project-template
cd huff-project-template
```

2. Install dependencies

Once you've cloned and entered into your repository, you need to install the necessary dependencies. In order to do so, simply run:

```shell
forge install
```

3. Build & Test

To build and test your contracts, you can run:

```shell
forge build
forge test
```

For more information on how to use Foundry, check out the [Foundry Github Repository](https://github.com/foundry-rs/foundry/tree/master/forge) and the [foundry-huff library repository](https://github.com/huff-language/foundry-huff).
To run the benchmark script :
```
FORK_URL=$ETH_RPC_URL make benchmark
```

## Usage
Only the arguments encoding matter, the signature is not checked.
If you wish to deploy the contract, on a testnet you have to change the hard-coded deposit contract address in the contract.

## Blueprint
### HuffClassic interface :
```
anySignature(bytes pubkeys, bytes withdrawal_creds, bytes signatures, bytes32[] deposit_data_roots)
```
`pubkeys` : concatenation of the public keys of the validators
`withdrawal_creds` : concatenation of the withdrawal credentials of the validators
`signatures` : concatenation of the signatures of the validators
`deposit_data_roots` : concatenation of the deposit data roots of the validators

```ml
lib
├─ forge-std — https://github.com/foundry-rs/forge-std
├─ foundry-huff — https://github.com/huff-language/foundry-huff
scripts
├─ Deploy.s.sol — Deployment Script
src
├─ SimpleStore — A Simple Storage Contract in Huff
test
└─ SimpleStore.t — SimpleStoreTests
### HuffCompact interface :
```
any_signature(bytes data)
```
`data` : concatenation of the pubkeys, withdrawal_creds, signatures and deposit_data_roots of the validators

## Benchmark
Ran against a fork at block `18255674`
### Benchmark results HuffCompact :
```
1 => 65605
2 => 91302
3 => 120344
4 => 144104
5 => 176922
10 => 307011
20 => 589729
30 => 845282
40 => 1118022
50 => 1393065
75 => 2050698
100 => 2726240
200 => 5411233
```

## License
### Benchmark results HuffClassic :
```
1 => 66730
2 => 92441
3 => 121521
4 => 145307
5 => 178163
10 => 308406
20 => 591372
30 => 847197
40 => 1120173
50 => 1395488
75 => 2053783
100 => 2729963
200 => 5417544
```

[The Unlicense](https://github.com/huff-language/huff-project-template/blob/master/LICENSE)
### Benchmark results [Solidity](https://etherscan.io/address/0x9b8c989FF27e948F55B53Bb19B3cC1947852E394#code) :
```
1 => 76074
2 => 107877
3 => 142933
4 => 172835
5 => 211715
10 => 372342
20 => 715792
30 => 1032305
40 => 1365669
50 => 1701816
75 => 2511743
100 => 3338663
200 => 6631612
```

HuffCompact is 18.4 % more efficient than the given solidity implementation.

## Acknowledgements
HuffClassic is 18.3 % more efficient than the given solidity implementation.

- [forge-template](https://github.com/foundry-rs/forge-template)
- [femplate](https://github.com/abigger87/femplate)
## License

TODO

## Disclaimer

Expand Down
2 changes: 2 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
benchmark:
sh script/benchmark.sh
114 changes: 114 additions & 0 deletions script/BenchmarkClassic.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;

import "forge-std/Script.sol";
import "foundry-huff/HuffDeployer.sol";

interface IBatchDeposit {
function d(
bytes calldata pubkeys,
bytes calldata withdrawal_credentialss,
bytes calldata signatures,
bytes32[] calldata deposit_data_roots
) external payable;
}

contract BenchmarkClassic is Script {
address public huffCompact;
uint256 public runCount = 13;
function setUp() public { }

function run() public {

uint256[] memory validatorsCount = getValidatorsCount();

// Deploy BatchDeposit
address huff = HuffDeployer.broadcast("BatchDeposit");
console.log("BatchDeposit: ", huff);

{
for(uint256 i = 0; i < runCount; i++) {
uint256 count = validatorsCount[i];
bytes memory publicKeys = publicKeys(count);
bytes memory withdrawalCredentials = withdrawalCredentials(count);
bytes memory signatures = signatures(count);
bytes32[] memory depositDataRoots = depositDataRoots(count);

console.log("huff");
vm.startBroadcast();
IBatchDeposit(huff).d{value: 32 ether * count}(publicKeys, withdrawalCredentials, signatures, depositDataRoots);
vm.stopBroadcast();
}
}

console.log("Done!");
}

function getValidatorsCount() public view returns (uint256[] memory) {
uint256[] memory validatorsCount = new uint256[](runCount);
validatorsCount[0] = 1;
validatorsCount[1] = 2;
validatorsCount[2] = 3;
validatorsCount[3] = 4;
validatorsCount[4] = 5;
validatorsCount[5] = 10;
validatorsCount[6] = 20;
validatorsCount[7] = 30;
validatorsCount[8] = 40;
validatorsCount[9] = 50;
validatorsCount[10] = 75;
validatorsCount[11] = 100;
validatorsCount[12] = 200;
return validatorsCount;
}


function publicKeys(uint256 count) public pure returns (bytes memory) {
bytes memory publicKeys = new bytes(0);
for (uint256 i = 0; i < count; i++) {
publicKeys = bytes.concat(publicKeys, genPubkey());
}
return publicKeys;
}

function withdrawalCredentials(uint256 count) public pure returns (bytes memory) {
bytes memory withdrawalCredentials = new bytes(0);
for (uint256 i = 0; i < count; i++) {
withdrawalCredentials = bytes.concat(withdrawalCredentials, genWC());
}
return withdrawalCredentials;
}

function signatures(uint256 count) public pure returns (bytes memory) {
bytes memory signatures = new bytes(0);
for (uint256 i = 0; i < count; i++) {
signatures = bytes.concat(signatures, genSig());
}
return signatures;
}

function depositDataRoots(uint256 count) public pure returns (bytes32[] memory) {
bytes32[] memory depositDataRoots = new bytes32[](count);
for (uint256 i = 0; i < count; i++) {
depositDataRoots[i] = genBytes32();
}
return depositDataRoots;
}

}

function genPubkey() pure returns (bytes memory) {
return hex'97eda78a0c1c3746d429451f194cce479b9aac7770eae790c638014087aceebcb4c68236e99e65f645fc1a436f059ab9';
}

function genWC() pure returns (bytes memory) {
return hex'01000000000000000000000034e9cb03516a70466d5c6d25c0f37cf622c43242';
}

function genSig() pure returns (bytes memory) {
return hex'b81b4423943820252a4a266a88eec5a87753191bd1838ffd3297dc44981368b186eae4f1fe0174b337c94064cf78f18f087785f60aa97db10e9e9d3826d1fc48baae3f9f94c7eb293354f56921a675db19f683ee12ec5508cdfb42805244d06f';
}

function genBytes32() pure returns (bytes32) {
return bytes32(hex'f1b0122e593763eb4fbe7b345f4fa9ec77f3096cbaec29bcec94b83b42d13579');
}
90 changes: 90 additions & 0 deletions script/BenchmarkCompact.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;

import "forge-std/Script.sol";
import "foundry-huff/HuffDeployer.sol";

interface IBatchDeposit {
function d(
bytes calldata pubkeys,
bytes calldata withdrawal_credentialss,
bytes calldata signatures,
bytes32[] calldata deposit_data_roots
) external payable;

function d(bytes calldata args) external payable;
}

contract BenchmarkCompact is Script {
address public huffCompact;
uint256 public runCount = 13;
function setUp() public { }

function run() public {

uint256[] memory validatorsCount = getValidatorsCount();

// Deploy BatchDepositCompact
huffCompact = HuffDeployer.broadcast("BatchDepositCompact");
console.log("BatchDepositCompact: ", huffCompact);

{
for(uint256 i = 0; i < runCount; i++) {
uint256 count = validatorsCount[i];
bytes memory args = makeArg(count);

console.log("compact huff");
vm.startBroadcast();
IBatchDeposit(huffCompact).d{value: 32 ether * count}(args);
vm.stopBroadcast();
}
}


console.log("Done!");
}

function getValidatorsCount() public view returns (uint256[] memory) {
uint256[] memory validatorsCount = new uint256[](runCount);
validatorsCount[0] = 1;
validatorsCount[1] = 2;
validatorsCount[2] = 3;
validatorsCount[3] = 4;
validatorsCount[4] = 5;
validatorsCount[5] = 10;
validatorsCount[6] = 20;
validatorsCount[7] = 30;
validatorsCount[8] = 40;
validatorsCount[9] = 50;
validatorsCount[10] = 75;
validatorsCount[11] = 100;
validatorsCount[12] = 200;
return validatorsCount;
}

function makeArg(uint256 count) public pure returns (bytes memory args) {
args = new bytes(0);
for (uint256 i = 0; i < count; i++) {
args = bytes.concat(args, genPubkey());
args = bytes.concat(args, genWC());
args = bytes.concat(args, genSig());
args = bytes.concat(args, genBytes32());
}
}
}

function genPubkey() pure returns (bytes memory) {
return hex'97eda78a0c1c3746d429451f194cce479b9aac7770eae790c638014087aceebcb4c68236e99e65f645fc1a436f059ab9';
}

function genWC() pure returns (bytes memory) {
return hex'01000000000000000000000034e9cb03516a70466d5c6d25c0f37cf622c43242';
}

function genSig() pure returns (bytes memory) {
return hex'b81b4423943820252a4a266a88eec5a87753191bd1838ffd3297dc44981368b186eae4f1fe0174b337c94064cf78f18f087785f60aa97db10e9e9d3826d1fc48baae3f9f94c7eb293354f56921a675db19f683ee12ec5508cdfb42805244d06f';
}

function genBytes32() pure returns (bytes32) {
return bytes32(hex'f1b0122e593763eb4fbe7b345f4fa9ec77f3096cbaec29bcec94b83b42d13579');
}
Loading

0 comments on commit f8dde3c

Please sign in to comment.