Skip to content

Commit

Permalink
Suave forge integration without SuaveForge.sol (#11)
Browse files Browse the repository at this point in the history
* Some hacks on forge

* return sig-stripped calldata from fallback (#10)

* Oh my... this really works

* Do not mirror SuaveForge.sol anymore

* More updates

* Write comment

* Fix CI

* Enable ffi on ci test

* Add REAMDE

* Add lang to readme code

---------

Co-authored-by: brock smedley <[email protected]>
  • Loading branch information
ferranbt and zeroXbrock authored Jan 5, 2024
1 parent 29416d4 commit ed5306e
Show file tree
Hide file tree
Showing 11 changed files with 363 additions and 170 deletions.
23 changes: 22 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Checkout suave-geth repo
uses: actions/checkout@v4
with:
repository: flashbots/suave-geth
path: suave-geth
persist-credentials: false
fetch-depth: 0

- name: Build suave
run: |
cd suave-geth
make suave
- name: Include the binary on $PATH
run: |
echo "$(pwd)/suave-geth/build/bin" >> $GITHUB_PATH
- name: Run suave
run: |
./suave-geth/build/bin/suave --suave.dev &
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
Expand All @@ -23,4 +44,4 @@ jobs:
run: forge install

- name: Run tests
run: forge test
run: forge test --ffi
2 changes: 0 additions & 2 deletions .github/workflows/suave-lib-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ jobs:
- name: Mirror
run: |
cp suave-geth/suave/sol/libraries/Suave.sol ./src/suavelib/Suave.sol
cp suave-geth/suave/sol/libraries/SuaveForge.sol ./src/suavelib/SuaveForge.sol
git add ./src/suavelib/Suave.sol
git add ./src/suavelib/SuaveForge.sol
rm -rf suave-geth
- name: Create Pull Request
Expand Down
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,38 @@ contract Example {
}
}
```

## Forge integration

In order to use `forge`, you need to have a running `Suave` node and the `suave` binary in your path.

To run `Suave` in development mode, use the following command:

```bash
$ suave --suave.dev
```

Then, your `forge` scripts/test must import the `SuaveEnabled` contract from the `suave-std/Test.sol` file.

```solidity
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "suave-std/Test.sol";
import "suave-std/Suave.sol";
contract TestForge is Test, SuaveEnabled {
address[] public addressList = [0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829];
function testConfidentialStore() public {
Suave.DataRecord memory record = Suave.newDataRecord(0, addressList, addressList, "namespace");
bytes memory value = abi.encode("suave works with forge!");
Suave.confidentialStore(record.id, "key1", value);
bytes memory found = Suave.confidentialRetrieve(record.id, "key1");
assertEq(keccak256(found), keccak256(value));
}
}
```
15 changes: 15 additions & 0 deletions src/Test.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.8;

import "./forge/Registry.sol";

contract SuaveEnabled {
function setUp() public {
// TODO: Add checks to validate that:
// - User is running the test with ffi. Since vm.ffi is deployed as a contract, the error if ffi is not active
// is reported as a Suave.PeekerReverted error and it is not clear what the problem is.
// - Suave binary is on $PATH and Suave is running. This could be done with ffi calls to the suave binary.
// Put this logic inside `enable` itself.
Registry.enable();
}
}
47 changes: 47 additions & 0 deletions src/forge/Connector.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.8;

interface connectorVM {
function ffi(string[] calldata commandInput) external view returns (bytes memory result);
}

contract Connector {
connectorVM constant vm = connectorVM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);

function forgeIt(bytes memory addr, bytes memory data) internal view returns (bytes memory) {
string memory addrHex = iToHex(addr);
string memory dataHex = iToHex(data);

string[] memory inputs = new string[](4);
inputs[0] = "suave";
inputs[1] = "forge";
inputs[2] = addrHex;
inputs[3] = dataHex;

bytes memory res = vm.ffi(inputs);
return res;
}

function iToHex(bytes memory buffer) public pure returns (string memory) {
bytes memory converted = new bytes(buffer.length * 2);

bytes memory _base = "0123456789abcdef";

for (uint256 i = 0; i < buffer.length; i++) {
converted[i * 2] = _base[uint8(buffer[i]) / _base.length];
converted[i * 2 + 1] = _base[uint8(buffer[i]) % _base.length];
}

return string(abi.encodePacked("0x", converted));
}

fallback() external {
bytes memory msgdata = forgeIt(abi.encodePacked(address(this)), msg.data);

assembly {
let location := msgdata
let length := mload(msgdata)
return(add(location, 0x20), length)
}
}
}
40 changes: 40 additions & 0 deletions src/forge/Registry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.8;

import "../suavelib/Suave.sol";

interface registryVM {
function etch(address, bytes calldata) external;
}

library Registry {
registryVM constant vm = registryVM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);

function enableLib(address addr) public {
// code for Wrapper
bytes memory code =
hex"608060405234801561001057600080fd5b506004361061002b5760003560e01c8063671ff786146100a1575b6040516bffffffffffffffffffffffff193060601b1660208201526000906100959060340160408051808303601f19018152602036601f8101829004820285018201909352828452909291600091819084018382808284376000920191909152506100ca92505050565b90508081518060208301f35b6100b46100af36600461048c565b610259565b6040516100c1919061055c565b60405180910390f35b606060006100d784610259565b905060006100e484610259565b60408051600480825260a0820190925291925060009190816020015b606081526020019060019003908161010057905050905060405180604001604052806005815260200164737561766560d81b8152508160008151811061014857610148610576565b602002602001018190525060405180604001604052806005815260200164666f72676560d81b8152508160018151811061018457610184610576565b602002602001018190525082816002815181106101a3576101a3610576565b602002602001018190525081816003815181106101c2576101c2610576565b6020908102919091010152604051638916046760e01b8152600090737109709ecfa91a80626ff3989d68f67f5b1dd12d9063891604679061020790859060040161058c565b600060405180830381865afa158015610224573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261024c91908101906105ee565b9450505050505b92915050565b606060008251600261026b919061067b565b67ffffffffffffffff8111156102835761028361041d565b6040519080825280601f01601f1916602001820160405280156102ad576020820181803683370190505b5060408051808201909152601081526f181899199a1a9b1b9c1cb0b131b232b360811b602082015290915060005b84518110156103f3578182518683815181106102f9576102f9610576565b016020015161030b919060f81c6106a8565b8151811061031b5761031b610576565b01602001516001600160f81b0319168361033683600261067b565b8151811061034657610346610576565b60200101906001600160f81b031916908160001a90535081825186838151811061037257610372610576565b0160200151610384919060f81c6106bc565b8151811061039457610394610576565b01602001516001600160f81b031916836103af83600261067b565b6103ba9060016106d0565b815181106103ca576103ca610576565b60200101906001600160f81b031916908160001a905350806103eb816106e3565b9150506102db565b508160405160200161040591906106fc565b60405160208183030381529060405292505050919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561045c5761045c61041d565b604052919050565b600067ffffffffffffffff82111561047e5761047e61041d565b50601f01601f191660200190565b60006020828403121561049e57600080fd5b813567ffffffffffffffff8111156104b557600080fd5b8201601f810184136104c657600080fd5b80356104d96104d482610464565b610433565b8181528560208385010111156104ee57600080fd5b81602084016020830137600091810160200191909152949350505050565b60005b8381101561052757818101518382015260200161050f565b50506000910152565b6000815180845261054881602086016020860161050c565b601f01601f19169290920160200192915050565b60208152600061056f6020830184610530565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156105e157603f198886030184526105cf858351610530565b945092850192908501906001016105b3565b5092979650505050505050565b60006020828403121561060057600080fd5b815167ffffffffffffffff81111561061757600080fd5b8201601f8101841361062857600080fd5b80516106366104d482610464565b81815285602083850101111561064b57600080fd5b61065c82602083016020860161050c565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761025357610253610665565b634e487b7160e01b600052601260045260246000fd5b6000826106b7576106b7610692565b500490565b6000826106cb576106cb610692565b500690565b8082018082111561025357610253610665565b6000600182016106f5576106f5610665565b5060010190565b61060f60f31b81526000825161071981600285016020870161050c565b919091016002019291505056fea2646970667358221220e66d500bc9a9ca9c0748086adfc51de57c85b7c9f66cc760e823099f0439820b64736f6c63430008130033";
vm.etch(addr, code);
}

function enable() public {
enableLib(Suave.IS_CONFIDENTIAL_ADDR);
enableLib(Suave.BUILD_ETH_BLOCK);
enableLib(Suave.CONFIDENTIAL_INPUTS);
enableLib(Suave.CONFIDENTIAL_RETRIEVE);
enableLib(Suave.CONFIDENTIAL_STORE);
enableLib(Suave.DO_HTTPREQUEST);
enableLib(Suave.ETHCALL);
enableLib(Suave.EXTRACT_HINT);
enableLib(Suave.FETCH_DATA_RECORDS);
enableLib(Suave.FILL_MEV_SHARE_BUNDLE);
enableLib(Suave.NEW_BUILDER);
enableLib(Suave.NEW_DATA_RECORD);
enableLib(Suave.SIGN_ETH_TRANSACTION);
enableLib(Suave.SIGN_MESSAGE);
enableLib(Suave.SIMULATE_BUNDLE);
enableLib(Suave.SIMULATE_TRANSACTION);
enableLib(Suave.SUBMIT_BUNDLE_JSON_RPC);
enableLib(Suave.SUBMIT_ETH_BLOCK_TO_RELAY);
}
}
167 changes: 0 additions & 167 deletions src/suavelib/SuaveForge.sol

This file was deleted.

20 changes: 20 additions & 0 deletions test/Forge.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "src/Test.sol";
import "src/suavelib/Suave.sol";

contract TestForge is Test, SuaveEnabled {
address[] public addressList = [0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829];

function testConfidentialStore() public {
Suave.DataRecord memory record = Suave.newDataRecord(0, addressList, addressList, "namespace");

bytes memory value = abi.encode("suave works with forge!");
Suave.confidentialStore(record.id, "key1", value);

bytes memory found = Suave.confidentialRetrieve(record.id, "key1");
assertEq(keccak256(found), keccak256(value));
}
}
13 changes: 13 additions & 0 deletions tools/forge-gen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Forge-gen command

In the `forge` integration, a `forge/Connector.sol` contract is deployed for each of the `Suave` precompiles. The contract uses the fallback function to make an `vm.ffi` call to the `suave forge` command to peform the logic request.

The `forge-gen` command creates the `forge/Registry.sol` contract which deploys the `Connector.sol` contract in all the precompile addresses using the `vm.etch` function.

## Usage

```bash
$ go run tools/forge-gen/main.go --apply
```

Use the `apply` flag to write the contract. Otherwise, it prints the contract on the standard output.
3 changes: 3 additions & 0 deletions tools/forge-gen/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/flashbots/suave-std/tools/forge-gen

go 1.21.0
Loading

0 comments on commit ed5306e

Please sign in to comment.