Skip to content

Commit

Permalink
is_dao_worthy_recursive
Browse files Browse the repository at this point in the history
  • Loading branch information
akonior committed Jun 10, 2024
1 parent 71cf69e commit ee46af8
Show file tree
Hide file tree
Showing 16 changed files with 110 additions and 21 deletions.
27 changes: 26 additions & 1 deletion .github/workflows/circuits_e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,20 @@ jobs:
toolchain: nightly-2024-05-22

- name: Compile Circuit
run: nargo compile --workspace --deny-warnings
run: |
nargo compile --package get_header --deny-warnings
nargo compile --package get_account --deny-warnings
nargo compile --package get_storage --deny-warnings
nargo compile --package get_storage_recursive --deny-warnings
nargo compile --package get_receipt --deny-warnings
nargo compile --package get_transaction --deny-warnings
nargo compile --package get_log --deny-warnings
nargo compile --package is_dao_worthy --deny-warnings
nargo compile --package is_ape_owner --deny-warnings
# We cannot use the `--deny-warnings` option in `is_dao_worthy_recursive` because the `verify_proof` method generates warnings
# that are actually informational messages from the compiler and cannot be ignored.
nargo compile --package is_dao_worthy_recursive
- name: Start Oracle Server
working-directory: ethereum/oracles
Expand All @@ -54,6 +67,18 @@ jobs:
nargo prove --package is_dao_worthy --oracle-resolver=http://localhost:5555
nargo prove --package is_ape_owner --oracle-resolver=http://localhost:5555
- name: Generate verification key for recursive proof
working-directory: ethereum/oracles
run: |
# Verification key generation uses Barretenberg backend located at ~/.nargo/backends/acvm-backend-barretenberg/backend_binary.
# It is automatically installed during the execution of the `nargo prove` command in previous step.
yarn generate-get-storage-vk
- name: Generate Recursive Proof
run: |
export NARGO_FOREIGN_CALL_TIMEOUT=100000 # miliseconds
nargo prove --package is_dao_worthy_recursive --oracle-resolver=http://localhost:5555
- name: Verify Proof
run: |
nargo verify --package get_header
Expand Down
1 change: 1 addition & 0 deletions Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ members = [
"ethereum/circuits/get_log",
"vlayer/ethereum/circuits/lib",
"vlayer/examples/circuits/is_dao_worthy",
"vlayer/examples/circuits/is_dao_worthy_recursive",
"vlayer/examples/circuits/is_ape_owner",
"vlayer/examples/circuits/is_crypto_punk_owner",
]
Expand Down
10 changes: 4 additions & 6 deletions ethereum/circuits/lib/src/account_with_storage_recursive.nr
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::account_with_storage::StorageWithinBlock;
use crate::misc::{fragment::Fragment, types::{Address, Bytes32, ADDRESS_LENGTH, BYTES32_LENGTH}};
use crate::serde::STORAGE_BLOCK_LEN;
use dep::std::verify_proof;
use crate::account_with_storage::StorageWithinBlock;
use dep::std::unsafe::zeroed;
use dep::std::{verify_proof, unsafe::zeroed};

struct RecursiveProof {
key_hash: Field,
Expand All @@ -26,19 +25,18 @@ pub fn get_account_with_storage_recursive(
public_inputs.extend_back(address.serialize());
public_inputs.extend_back(storage_key.serialize());
public_inputs.extend_back(storage_within_block.serialize());
let public_inputs_array: [Field; NUM_PUBLIC_INPUTS] = public_inputs.to_array();

verify_proof(
verification_key.as_slice(),
proof.as_slice(),
public_inputs_array.as_slice(),
public_inputs.to_array::<NUM_PUBLIC_INPUTS>().as_slice(),
key_hash
);

storage_within_block
}

#[oracle(get_account_with_storage_recursive)]
#[oracle(get_storage_recursive)]
unconstrained fn get_account_with_storage_recursive_oracle(
chain_id: Field,
block_number: u64,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use crate::account_with_storage_recursive::{get_account_with_storage_recursive, RecursiveProof};
use crate::account_with_storage::StorageWithinBlock;
use crate::fixtures::mainnet::paris::usdc_circle::{header::{number, hash}, account::{address, account} storage::{keys, values}};
use crate::fixtures::mainnet::paris::usdc_circle::{header::{number, hash}, account::{address, account}, storage::{keys, values}};
use crate::chain::ETHEREUM_MAINNET_ID;
use crate::misc::types::{Bytes32, Address};
use dep::std::test::OracleMock;
use dep::std::unsafe::zeroed;

#[test]
fn success() {
let result = StorageWithinBlock { block_hash: hash, account, values };
let recursive_proof = RecursiveProof { key_hash: 1, verification_key: [0; 114], proof: [0; 93] };
// This is not a correct proof but it passes because nargo does not verify it. Nargo thinks that it's bb's job, but doesn't call bb.
let recursive_proof: RecursiveProof = zeroed();

let _ = OracleMock::mock("get_account_with_storage_recursive").returns((result.serialize(), recursive_proof));
let _ = OracleMock::mock("get_storage_recursive").returns((result.serialize(), recursive_proof));

get_account_with_storage_recursive(ETHEREUM_MAINNET_ID, number, address, keys[0]);
let _ = get_account_with_storage_recursive(ETHEREUM_MAINNET_ID, number, address, keys[0]);
}
2 changes: 1 addition & 1 deletion ethereum/oracles/src/noir/oracles/server/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jsonRPCServer.addMethod('get_account', getRpcOracleHandler.bind(this, getAccount
jsonRPCServer.addMethod('get_proof', getRpcOracleHandler.bind(this, getProofOracle));
jsonRPCServer.addMethod('get_receipt', getRpcOracleHandler.bind(this, getReceiptOracle));
jsonRPCServer.addMethod('get_transaction', getRpcOracleHandler.bind(this, getTransactionOracle));
jsonRPCServer.addMethod('recursive_get_storage', getOracleHandler.bind(this, getStorageOracle));
jsonRPCServer.addMethod('get_storage_recursive', getOracleHandler.bind(this, getStorageOracle));

export function buildOracleServer(
opts: Fastify.FastifyHttpOptions<http.Server> = {},
Expand Down
2 changes: 1 addition & 1 deletion ethereum/oracles/src/noir/oracles/server/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type JSONRPCServerMethods = {
get_proof(params: ForeignCallParams): ForeignCallResult;
get_receipt(params: ForeignCallParams): ForeignCallResult;
get_transaction(params: ForeignCallParams): ForeignCallResult;
recursive_get_storage(params: ForeignCallParams): ForeignCallResult;
get_storage_recursive(params: ForeignCallParams): ForeignCallResult;
};

export interface ServerParams {
Expand Down
2 changes: 1 addition & 1 deletion ethereum/oracles/src/script/generateGetStorageVK.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { MonorepoCircuit } from '../noir/circuit/circuit.js';
import { VerificationKey, generateVk } from '../noir/circuit/vk.js';

const circuit = await MonorepoCircuit.create('../../', 'get_storage');
const circuit = await MonorepoCircuit.create('../../', 'get_storage_recursive');
await generateVk(circuit.artefact.bytecode, circuit.vkPath(), circuit.vkAsFieldsPath());
const vk = await VerificationKey.create(circuit.vkAsFieldsPath());
// eslint-disable-next-line no-console
Expand Down
11 changes: 8 additions & 3 deletions vlayer/ethereum/circuits/lib/src/token.nr
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use dep::ethereum::{
account_with_storage::get_account_with_storage,
account_with_storage_recursive::get_account_with_storage_recursive, misc::types::Address,
misc::bytes32::address_to_bytes32
};
Expand All @@ -22,13 +23,17 @@ impl ERC20Token {
}

trait ERC20 {
fn get_balance(self, wallet_address: Address, block_number: u64) -> U128 ;
fn get_balance(self, wallet_address: Address, block_number: u64, recursive: bool) -> U128;
}

impl ERC20 for ERC20Token {
fn get_balance(self, wallet_address: Address, block_number: u64) -> U128 {
fn get_balance(self, wallet_address: Address, block_number: u64, recursive: bool) -> U128 {
let storage_key = self.calculate_balance_storage_key(wallet_address);
let account = get_account_with_storage_recursive(self.chain_id, block_number, self.address, U256::into(storage_key));
let account = if recursive {
get_account_with_storage_recursive(self.chain_id, block_number, self.address, U256::into(storage_key))
} else {
get_account_with_storage(self.chain_id, block_number, self.address, U256::into(storage_key))
};
let balance = account.values[TOKEN_BALANCE_INDEX];

U128::from_integer(bytes32_to_field(balance))
Expand Down
10 changes: 8 additions & 2 deletions vlayer/ethereum/circuits/lib/src/token_int_test.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@ mod test_ERC20Token {
use dep::ethereum::fixtures::mainnet::{
paris::usdc_circle::header::{block_header_partial as paris_block_header_partial, block_header_rlp as paris_block_header_rlp},
paris::usdc_circle::header::{hash, number, state_root, transactions_root, receipts_root},
paris::usdc_circle::account::account,
paris::usdc_circle::account::account, paris::usdc_circle::storage::values,
paris::usdc_circle::state_proof::proof_input_serialized as state_proof_input_serialized,
paris::usdc_circle::storage_proof::proofs_serialized
};
use dep::ethereum::uint256::U256;
use crate::chain_id::MAINNET;
use dep::ethereum::account_with_storage_recursive::RecursiveProof;
use dep::ethereum::account_with_storage::StorageWithinBlock;

#[test]
fn success() {
let result = StorageWithinBlock { block_hash: hash, account, values };
let recursive_proof = RecursiveProof { key_hash: 1, verification_key: [0; 114], proof: [0; 93] };

let _ = OracleMock::mock("get_storage_recursive").returns((result.serialize(), recursive_proof));
let _ = OracleMock::mock("get_header").returns((paris_block_header_partial, paris_block_header_rlp));
let _ = OracleMock::mock("get_proof").returns((account, state_proof_input_serialized, proofs_serialized[0]));

Expand All @@ -29,7 +35,7 @@ mod test_ERC20Token {
0x55, 0xFE, 0x00, 0x2a, 0xef, 0xF0, 0x2F, 0x77, 0x36, 0x4d, 0xe3, 0x39, 0xa1, 0x29, 0x29, 0x23, 0xA1, 0x58, 0x44, 0xB8
];
let block_number = 19000000;
let balance = usdc_token.get_balance(circle_address, block_number);
let balance = usdc_token.get_balance(circle_address, block_number, false);
let expected_usdc_balnce_of_circle = U128::from_integer(125761774888720);
assert_eq(expected_usdc_balnce_of_circle, balance);
}
Expand Down
2 changes: 1 addition & 1 deletion vlayer/examples/circuits/is_dao_worthy/Verifier.toml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
block_number = "0x000000000000000000000000000000000000000000000000000000000121eac0"
block_number = 19000000
2 changes: 1 addition & 1 deletion vlayer/examples/circuits/is_dao_worthy/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod main_test;
global MIN_BALANCE = U128::from_integer(100_000_000_000); // $100k

fn main(wallet_address: Address, block_number: pub u64) {
let wallet_balance = USDC.get_balance(wallet_address, block_number);
let wallet_balance = USDC.get_balance(wallet_address, block_number, false);
let is_balance_greater_or_equal = MIN_BALANCE <= wallet_balance;

assert(is_balance_greater_or_equal, "Insufficient USDC balance");
Expand Down
8 changes: 8 additions & 0 deletions vlayer/examples/circuits/is_dao_worthy_recursive/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "is_dao_worthy_recursive"
type = "bin"
compiler_version = ">=0.30.0"

[dependencies]
ethereum = { path = "../../../../ethereum/circuits/lib" }
token = { path = "../../../ethereum/circuits/lib" }
4 changes: 4 additions & 0 deletions vlayer/examples/circuits/is_dao_worthy_recursive/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
block_number = 19000000

# Circle address
wallet_address = [ 0x55, 0xfe, 0x00, 0x2a, 0xef, 0xf0, 0x2f, 0x77, 0x36, 0x4d, 0xe3, 0x39, 0xa1, 0x29, 0x29, 0x23, 0xa1, 0x58, 0x44, 0xb8 ]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
block_number = 19000000
12 changes: 12 additions & 0 deletions vlayer/examples/circuits/is_dao_worthy_recursive/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use dep::ethereum::misc::types::Address;
use dep::token::token_list::mainnet::USDC;

mod main_test;

global MIN_BALANCE = U128::from_integer(100_000_000_000); // $100k

fn main(wallet_address: Address, block_number: pub u64) {
let wallet_balance = USDC.get_balance(wallet_address, block_number, true);

assert(MIN_BALANCE <= wallet_balance, "Insufficient USDC balance");
}
27 changes: 27 additions & 0 deletions vlayer/examples/circuits/is_dao_worthy_recursive/src/main_test.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
mod is_dao_worthy_main {
use dep::std::test::OracleMock;
use dep::ethereum::fixtures::mainnet::{
paris::usdc_circle::header::{hash, block_header_partial as paris_block_header_partial, block_header_rlp as paris_block_header_rlp},
paris::usdc_circle::account::account, paris::usdc_circle::storage::values,
paris::usdc_circle::state_proof::proof_input_serialized as state_proof_input_serialized,
paris::usdc_circle::storage_proof::proofs_serialized
};
use dep::ethereum::{account_with_storage_recursive::RecursiveProof, account_with_storage::StorageWithinBlock};
use crate::main;

#[test]
fn success_greater_then() {
let result = StorageWithinBlock { block_hash: hash, account, values };
let recursive_proof = RecursiveProof { key_hash: 1, verification_key: [0; 114], proof: [0; 93] };

let _ = OracleMock::mock("get_storage_recursive").returns((result.serialize(), recursive_proof));
let _ = OracleMock::mock("get_header").returns((paris_block_header_partial, paris_block_header_rlp));
let _ = OracleMock::mock("get_proof").returns((account, state_proof_input_serialized, proofs_serialized[0]));

let block_number = 19_000_000;
let circle_address = [
0x55, 0xfe, 0x00, 0x2a, 0xef, 0xf0, 0x2f, 0x77, 0x36, 0x4d, 0xe3, 0x39, 0xa1, 0x29, 0x29, 0x23, 0xa1, 0x58, 0x44, 0xb8
];
main(circle_address, block_number);
}
}

0 comments on commit ee46af8

Please sign in to comment.