Skip to content
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

Mock the confidential datastore for Foundry #40

Merged
merged 7 commits into from Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/Test.sol
Expand Up @@ -10,8 +10,13 @@ interface ConfidentialInputsWrapperI {
function resetConfidentialInputs() external;
}

interface ConfidentialStoreI {
function reset() external;
}

contract SuaveEnabled is Test {
ConfidentialInputsWrapperI constant confInputsWrapper = ConfidentialInputsWrapperI(Suave.CONFIDENTIAL_INPUTS);
ConfidentialStoreI constant confStoreWrapper = ConfidentialStoreI(Registry.confidentialStoreAddr);

function setUp() public {
string[] memory inputs = new string[](3);
Expand Down Expand Up @@ -82,11 +87,6 @@ contract SuaveEnabled is Test {
}

function resetConfidentialStore() public {
string[] memory inputs = new string[](3);
inputs[0] = "suave-geth";
inputs[1] = "forge";
inputs[2] = "reset-conf-store";

vm.ffi(inputs);
confStoreWrapper.reset();
}
}
2 changes: 0 additions & 2 deletions src/Transactions.sol
Expand Up @@ -299,7 +299,6 @@ library Transactions {

function signTxn(Transactions.EIP1559Request memory request, string memory signingKey)
internal
view
returns (Transactions.EIP1559 memory response)
{
bytes memory rlp = Transactions.encodeRLP(request);
Expand All @@ -325,7 +324,6 @@ library Transactions {

function signTxn(Transactions.EIP155Request memory request, string memory signingKey)
internal
view
returns (Transactions.EIP155 memory response)
{
bytes memory rlp = Transactions.encodeRLP(request);
Expand Down
84 changes: 84 additions & 0 deletions src/forge/ConfidentialStore.sol
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: UNLICENSED

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to add a license?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing is licensed for now. I will bring this up during weekly tomorrow.

pragma solidity ^0.8.8;

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

// ConfidentialStore is an implementation of the confidential store in Solidity.
contract ConfidentialStore is Test {
mapping(bytes32 => Suave.DataRecord[]) private dataRecordsByConditionAndNamespace;
mapping(Suave.DataId => mapping(string => bytes)) private dataRecordsContent;
mapping(Suave.DataId => Suave.DataRecord) private dataRecords;

uint64 private numRecords;

type DataId is bytes16;

constructor() {
vm.record();
}

function newDataRecord(
uint64 decryptionCondition,
address[] memory allowedPeekers,
address[] memory allowedStores,
string memory dataType
) public returns (Suave.DataRecord memory) {
numRecords++;

// Use a counter of the records to create a unique key
Suave.DataId id = Suave.DataId.wrap(bytes16(keccak256(abi.encodePacked(numRecords))));
numRecords++;

Suave.DataRecord memory newRecord;
newRecord.id = id;
newRecord.decryptionCondition = decryptionCondition;
newRecord.allowedPeekers = allowedPeekers;
newRecord.allowedStores = allowedStores;
newRecord.version = dataType;

// Store the data record metadata
dataRecords[id] = newRecord;

// Use a composite index to store the records for the 'fetchDataRecords' function
bytes32 key = keccak256(abi.encodePacked(decryptionCondition, dataType));
dataRecordsByConditionAndNamespace[key].push(newRecord);

return newRecord;
}

function fetchDataRecords(uint64 cond, string memory namespace) public view returns (Suave.DataRecord[] memory) {
bytes32 key = keccak256(abi.encodePacked(cond, namespace));
return dataRecordsByConditionAndNamespace[key];
}

function confidentialStore(Suave.DataId dataId, string memory key, bytes memory value) public {
address[] memory allowedStores = dataRecords[dataId].allowedStores;
for (uint256 i = 0; i < allowedStores.length; i++) {
if (allowedStores[i] == msg.sender || allowedStores[i] == Suave.ANYALLOWED) {
dataRecordsContent[dataId][key] = value;
return;
}
}

revert("Not allowed to store");
}

function confidentialRetrieve(Suave.DataId dataId, string memory key) public view returns (bytes memory) {
address[] memory allowedPeekers = dataRecords[dataId].allowedPeekers;
for (uint256 i = 0; i < allowedPeekers.length; i++) {
if (allowedPeekers[i] == msg.sender || allowedPeekers[i] == Suave.ANYALLOWED) {
return dataRecordsContent[dataId][key];
}
}

revert("Not allowed to retrieve");
}

function reset() public {
(, bytes32[] memory writes) = vm.accesses(address(this));
for (uint256 i = 0; i < writes.length; i++) {
vm.store(address(this), writes[i], 0);
}
}
}
47 changes: 47 additions & 0 deletions src/forge/ConfidentialStoreConnector.sol
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.8;

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

contract ConfidentialStoreConnector {
fallback() external {
address confidentialStoreAddr = 0x0101010101010101010101010101010101010101;

address addr = address(this);
bytes4 sig;

// You can use 'forge selectors list' to retrieve the function signatures
if (addr == Suave.CONFIDENTIAL_STORE) {
sig = 0xd22a3b0b;
ferranbt marked this conversation as resolved.
Show resolved Hide resolved
} else if (addr == Suave.CONFIDENTIAL_RETRIEVE) {
sig = 0xe3b417bc;
} else if (addr == Suave.FETCH_DATA_RECORDS) {
sig = 0xccb885c4;
} else if (addr == Suave.NEW_DATA_RECORD) {
sig = 0xe3fbcfc3;
} else {
revert("function signature not found in the confidential store");
}

bytes memory input = msg.data;

// call 'confidentialStore' with the selector and the input data.
(bool success, bytes memory output) = confidentialStoreAddr.call(abi.encodePacked(sig, input));
if (!success) {
revert("Call to confidentialStore failed");
}

if (addr == Suave.CONFIDENTIAL_RETRIEVE) {
// special case we have to unroll the value from the abi
// since it comes encoded as tuple() but we return the value normally
// this was a special case that was not fixed yet in suave-geth.
output = abi.decode(output, (bytes));
}

assembly {
let location := output
let length := mload(output)
return(add(location, 0x20), length)
}
}
}
19 changes: 19 additions & 0 deletions src/forge/Registry.sol
Expand Up @@ -6,13 +6,16 @@ import "../suavelib/Suave.sol";
import "./Connector.sol";
import "./ConfidentialInputs.sol";
import "./SuaveAddrs.sol";
import "./ConfidentialStore.sol";
import "./ConfidentialStoreConnector.sol";

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

library Registry {
registryVM constant vm = registryVM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
address public constant confidentialStoreAddr = 0x0101010101010101010101010101010101010101;

function enable() public {
// enable all suave libraries
Expand All @@ -22,7 +25,23 @@ library Registry {
vm.etch(addrList[i], type(Connector).runtimeCode);
}

// enable the confidential store
deployCodeTo(type(ConfidentialStore).creationCode, confidentialStoreAddr);

// enable the confidential inputs wrapper
vm.etch(Suave.CONFIDENTIAL_RETRIEVE, type(ConfidentialStoreConnector).runtimeCode);
vm.etch(Suave.CONFIDENTIAL_STORE, type(ConfidentialStoreConnector).runtimeCode);
vm.etch(Suave.NEW_DATA_RECORD, type(ConfidentialStoreConnector).runtimeCode);
vm.etch(Suave.FETCH_DATA_RECORDS, type(ConfidentialStoreConnector).runtimeCode);

// enable is confidential wrapper
vm.etch(Suave.CONFIDENTIAL_INPUTS, type(ConfidentialInputsWrapper).runtimeCode);
}

function deployCodeTo(bytes memory creationCode, address where) internal {
vm.etch(where, creationCode);
(bool success, bytes memory runtimeBytecode) = where.call("");
require(success, "StdCheats deployCodeTo(string,bytes,uint256,address): Failed to create runtime bytecode.");
vm.etch(where, runtimeBytecode);
}
}
2 changes: 1 addition & 1 deletion src/protocols/Bundle.sol
Expand Up @@ -13,7 +13,7 @@ library Bundle {
bytes[] txns;
}

function sendBundle(string memory url, BundleObj memory bundle) internal view returns (bytes memory) {
function sendBundle(string memory url, BundleObj memory bundle) internal returns (bytes memory) {
Suave.HttpRequest memory request = encodeBundle(bundle);
request.url = url;
return Suave.doHTTPRequest(request);
Expand Down
2 changes: 1 addition & 1 deletion src/protocols/MevShare.sol
Expand Up @@ -71,7 +71,7 @@ library MevShare {
return request;
}

function sendBundle(string memory url, Bundle memory bundle) internal view {
function sendBundle(string memory url, Bundle memory bundle) internal {
Suave.HttpRequest memory request = encodeBundle(bundle);
request.url = url;
Suave.doHTTPRequest(request);
Expand Down