Skip to content

Commit

Permalink
feat: unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rpalakkal committed Apr 22, 2024
1 parent 88be7ab commit bf446d0
Show file tree
Hide file tree
Showing 11 changed files with 271 additions and 28 deletions.
8 changes: 0 additions & 8 deletions circuit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,3 @@ codegen-units = 1
panic = "abort"
incremental = false

[[bin]]
name = "registration"
path = "src/registration.rs"

[[bin]]
name = "renewal"
path = "src/renewal.rs"

6 changes: 6 additions & 0 deletions circuit/src/bin/registration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use axiom_sdk::cmd::run_cli;
use circuit::registration::ENSRegistrationInput;

fn main() {
run_cli::<ENSRegistrationInput>();
}
6 changes: 6 additions & 0 deletions circuit/src/bin/renewal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use axiom_sdk::cmd::run_cli;
use circuit::renewal::ENSRenewalInput;

fn main() {
run_cli::<ENSRenewalInput>();
}
4 changes: 4 additions & 0 deletions circuit/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod registration;
pub mod renewal;
#[cfg(test)]
mod tests;
15 changes: 5 additions & 10 deletions circuit/src/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use axiom_circuit::{
use axiom_sdk::ethers::types::H256;
use axiom_sdk::{
axiom::{AxiomAPI, AxiomComputeFn, AxiomComputeInput, AxiomResult},
cmd::run_cli,
ethers::abi::Address,
halo2_base::{
gates::{GateInstructions, RangeInstructions},
Expand All @@ -28,17 +27,17 @@ lazy_static! {
}

#[AxiomComputeInput]
pub struct ENSReferralInput {
pub struct ENSRegistrationInput {
pub block_numbers: FixLenVec<usize, N>,
pub tx_idxs: FixLenVec<usize, N>,
pub log_idxs: FixLenVec<usize, N>,
pub num_claims: usize,
}

impl AxiomComputeFn for ENSReferralInput {
impl AxiomComputeFn for ENSRegistrationInput {
fn compute(
api: &mut AxiomAPI,
assigned_inputs: ENSReferralCircuitInput<AssignedValue<Fr>>,
assigned_inputs: ENSRegistrationCircuitInput<AssignedValue<Fr>>,
) -> Vec<AxiomResult> {
let gate = api.range.gate();
let two_pow_64 = gate.pow_of_two[64];
Expand Down Expand Up @@ -96,7 +95,7 @@ impl AxiomComputeFn for ENSReferralInput {
let five = api.ctx().load_constant(Fr::from(5u64));
let four = api.ctx().load_constant(Fr::from(4u64));
let six = api.ctx().load_constant(Fr::from(6u64));
let byte_checks = vec![0x80, 0xe0, 0xf0, 0xf8, 0xfc]
let byte_checks = [0x80, 0xe0, 0xf0, 0xf8, 0xfc]
.iter()
.map(|x| api.ctx().load_constant(Fr::from(*x as u64)))
.collect::<Vec<_>>();
Expand All @@ -109,7 +108,7 @@ impl AxiomComputeFn for ENSReferralInput {
let expires_256 = api
.get_receipt(assigned_inputs.block_numbers[i], assigned_inputs.tx_idxs[i])
.log(assigned_inputs.log_idxs[i])
.data(three, Some(REGISTRATION_EVENT_SCHEMA.clone()));
.data(three, Some(*REGISTRATION_EVENT_SCHEMA));
let expires = api.from_hi_lo(expires_256);
let now_256 = api
.get_header(assigned_inputs.block_numbers[i])
Expand Down Expand Up @@ -217,7 +216,3 @@ impl AxiomComputeFn for ENSReferralInput {
]
}
}

fn main() {
run_cli::<ENSReferralInput>();
}
15 changes: 5 additions & 10 deletions circuit/src/renewal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use axiom_circuit::{axiom_eth::halo2curves::ff::Field, input::flatten::FixLenVec
use axiom_sdk::ethers::types::H256;
use axiom_sdk::{
axiom::{AxiomAPI, AxiomComputeFn, AxiomComputeInput, AxiomResult},
cmd::run_cli,
ethers::abi::Address,
halo2_base::{
gates::{GateInstructions, RangeInstructions},
Expand All @@ -26,17 +25,17 @@ lazy_static! {
}

#[AxiomComputeInput]
pub struct ENSReferralInput {
pub struct ENSRenewalInput {
pub block_numbers: FixLenVec<usize, N>,
pub tx_idxs: FixLenVec<usize, N>,
pub log_idxs: FixLenVec<usize, N>,
pub num_claims: usize,
}

impl AxiomComputeFn for ENSReferralInput {
impl AxiomComputeFn for ENSRenewalInput {
fn compute(
api: &mut AxiomAPI,
assigned_inputs: ENSReferralCircuitInput<AssignedValue<Fr>>,
assigned_inputs: ENSRenewalCircuitInput<AssignedValue<Fr>>,
) -> Vec<AxiomResult> {
let gate = api.range.gate();
let two_pow_64 = gate.pow_of_two[64];
Expand Down Expand Up @@ -94,7 +93,7 @@ impl AxiomComputeFn for ENSReferralInput {
let three = api.ctx().load_constant(Fr::from(3u64));
let four = api.ctx().load_constant(Fr::from(4u64));
let six = api.ctx().load_constant(Fr::from(6u64));
let byte_checks = vec![0x80, 0xe0, 0xf0, 0xf8, 0xfc]
let byte_checks = [0x80, 0xe0, 0xf0, 0xf8, 0xfc]
.iter()
.map(|x| api.ctx().load_constant(Fr::from(*x as u64)))
.collect::<Vec<_>>();
Expand All @@ -107,7 +106,7 @@ impl AxiomComputeFn for ENSReferralInput {
let expires_256 = api
.get_receipt(assigned_inputs.block_numbers[i], assigned_inputs.tx_idxs[i])
.log(assigned_inputs.log_idxs[i])
.data(two, Some(RENEWAL_EVENT_SCHEMA.clone()));
.data(two, Some(*RENEWAL_EVENT_SCHEMA));
let expires = api.from_hi_lo(expires_256);
let (_, referrer_id_from_expires) = api.range.div_mod(api.ctx(), expires, 86400u64, 64);

Expand Down Expand Up @@ -208,7 +207,3 @@ impl AxiomComputeFn for ENSReferralInput {
]
}
}

fn main() {
run_cli::<ENSReferralInput>();
}
3 changes: 3 additions & 0 deletions circuit/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod registration;
mod renewal;
mod utils;
99 changes: 99 additions & 0 deletions circuit/src/tests/registration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use axiom_circuit::{
input::flatten::FixLenVec,
types::{AxiomCircuitParams, AxiomV2DataAndResults},
utils::get_provider,
};
use axiom_sdk::{
axiom::AxiomCompute, ethers::types::H256, halo2_base::gates::circuit::BaseCircuitParams,
};

use crate::{registration::ENSRegistrationInput, tests::utils::calculate_claim_id};

use super::utils::pad_input;

fn get_input(
block_number: Vec<usize>,
tx_idx: Vec<usize>,
log_idx: Vec<usize>,
) -> ENSRegistrationInput {
let (block_numbers, tx_idxs, log_idxs) = pad_input(block_number.clone(), tx_idx, log_idx);
ENSRegistrationInput {
block_numbers: FixLenVec::new(block_numbers).unwrap(),
tx_idxs: FixLenVec::new(tx_idxs).unwrap(),
log_idxs: FixLenVec::new(log_idxs).unwrap(),
num_claims: block_number.len(),
}
}

fn get_circuit_output(
block_number: Vec<usize>,
tx_idx: Vec<usize>,
log_idx: Vec<usize>,
) -> AxiomV2DataAndResults {
let params = BaseCircuitParams {
k: 12,
num_advice_per_phase: vec![4],
num_fixed: 1,
num_lookup_advice_per_phase: vec![1],
lookup_bits: Some(11),
num_instance_columns: 1,
};

let provider = get_provider();
let input = get_input(block_number, tx_idx, log_idx);
let compute = AxiomCompute::<ENSRegistrationInput>::new()
.use_params(AxiomCircuitParams::Base(params))
.use_provider(provider)
.use_inputs(input);
let circuit = compute.circuit();
circuit.scaffold_output()
}

#[test]
fn test_referral_id() {
let output = get_circuit_output(vec![5147955], vec![31], vec![0]);
assert_eq!(output.compute_results[2], H256::from_low_u64_be(1));
}

#[test]
fn test_claim_id() {
let block_number = 5147955;
let tx_idx = 31;
let log_idx = 0;
let output = get_circuit_output(vec![block_number], vec![tx_idx], vec![log_idx]);
let claim_id = calculate_claim_id(block_number, tx_idx, log_idx);
assert_eq!(output.compute_results[0], claim_id);
assert_eq!(output.compute_results[1], claim_id);
}

#[test]
fn test_full_fee() {
// https://sepolia.etherscan.io/tx/0x223e91d10d5786a33014646ae11fa58306672a3faebaccf677ff9c3e232505d8#eventlog
let output = get_circuit_output(vec![5750508], vec![6], vec![10]);
let full_cost: usize = 0x1b40f2169b330;
assert_eq!(
output.compute_results[3],
H256::from_low_u64_be(full_cost as u64)
);
}

#[test]
fn test_4_char_fee() {
// https://sepolia.etherscan.io/tx/0x223e91d10d5786a33014646ae11fa58306672a3faebaccf677ff9c3e232505d8#eventlog
let output = get_circuit_output(vec![5750330], vec![8], vec![10]);
let full_cost: usize = 38356164383559120;
let four_char_cost = full_cost / 32;
assert_eq!(
output.compute_results[3],
H256::from_low_u64_be(four_char_cost as u64)
);
}

#[test]
fn test_sum_volume() {
// tx1: https://sepolia.etherscan.io/tx/0x223e91d10d5786a33014646ae11fa58306672a3faebaccf677ff9c3e232505d8#eventlog
// tx2: https://sepolia.etherscan.io/tx/0x3fbd860c43626d7f4ca31a002cce9a396c7c3fa5582352a5c70dc90049d13c3b#eventlog
let output = get_circuit_output(vec![5750330, 5750508], vec![8, 6], vec![10, 10]);
let volume = 0x44225d3883a6e + 0x1b40f2169b330;
assert_eq!(output.compute_results[3], H256::from_low_u64_be(volume));
}
100 changes: 100 additions & 0 deletions circuit/src/tests/renewal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use axiom_circuit::{
input::flatten::FixLenVec,
types::{AxiomCircuitParams, AxiomV2DataAndResults},
utils::get_provider,
};
use axiom_sdk::{
axiom::AxiomCompute, ethers::types::H256, halo2_base::gates::circuit::BaseCircuitParams,
};

use crate::{renewal::ENSRenewalInput, tests::utils::calculate_claim_id};

use super::utils::pad_input;

fn get_input(block_number: Vec<usize>, tx_idx: Vec<usize>, log_idx: Vec<usize>) -> ENSRenewalInput {
let (block_numbers, tx_idxs, log_idxs) = pad_input(block_number.clone(), tx_idx, log_idx);
ENSRenewalInput {
block_numbers: FixLenVec::new(block_numbers).unwrap(),
tx_idxs: FixLenVec::new(tx_idxs).unwrap(),
log_idxs: FixLenVec::new(log_idxs).unwrap(),
num_claims: block_number.len(),
}
}

fn get_circuit_output(
block_number: Vec<usize>,
tx_idx: Vec<usize>,
log_idx: Vec<usize>,
) -> AxiomV2DataAndResults {
let params = BaseCircuitParams {
k: 12,
num_advice_per_phase: vec![4],
num_fixed: 1,
num_lookup_advice_per_phase: vec![1],
lookup_bits: Some(11),
num_instance_columns: 1,
};

let provider = get_provider();
let input = get_input(block_number, tx_idx, log_idx);
let compute = AxiomCompute::<ENSRenewalInput>::new()
.use_params(AxiomCircuitParams::Base(params))
.use_provider(provider)
.use_inputs(input);
let circuit = compute.circuit();
circuit.scaffold_output()
}

#[test]
fn test_referral_id() {
// https://sepolia.etherscan.io/tx/0xcae128087515abfcff4731ccd815f2c19611f882842c030af1e1bdb6e485af97#eventlog
let output = get_circuit_output(vec![5203518], vec![112], vec![1]);
let expiry = 1769941548;
assert_eq!(
output.compute_results[2],
H256::from_low_u64_be(expiry % 86400)
);
}

#[test]
fn test_claim_id() {
let block_number = 5203518;
let tx_idx = 112;
let log_idx = 1;
let output = get_circuit_output(vec![block_number], vec![tx_idx], vec![log_idx]);
let claim_id = calculate_claim_id(block_number, tx_idx, log_idx);
assert_eq!(output.compute_results[0], claim_id);
assert_eq!(output.compute_results[1], claim_id);
}

#[test]
fn test_full_fee() {
// https://sepolia.etherscan.io/tx/0xcae128087515abfcff4731ccd815f2c19611f882842c030af1e1bdb6e485af97#eventlog
let output = get_circuit_output(vec![5203518], vec![112], vec![1]);
let full_cost: usize = 3187500000003559;
assert_eq!(
output.compute_results[3],
H256::from_low_u64_be(full_cost as u64)
);
}

#[test]
fn test_4_char_fee() {
// https://sepolia.etherscan.io/tx/0x656ae52987a71d91aeebdb5fb0a62a485958125445a37aa8314593dcbacc91b4#eventlog
let output = get_circuit_output(vec![5647069], vec![120], vec![1]);
let full_cost: usize = 713999999999953018;
let four_char_cost = full_cost / 32;
assert_eq!(
output.compute_results[3],
H256::from_low_u64_be(four_char_cost as u64)
);
}

#[test]
fn test_sum_volume() {
// tx1: https://sepolia.etherscan.io/tx/0xcae128087515abfcff4731ccd815f2c19611f882842c030af1e1bdb6e485af97#eventlog
// tx2: https://sepolia.etherscan.io/tx/0x656ae52987a71d91aeebdb5fb0a62a485958125445a37aa8314593dcbacc91b4#eventlog
let output = get_circuit_output(vec![5203518, 5647069], vec![112, 120], vec![1, 1]);
let volume = 3187500000003559 + (713999999999953018 / 32);
assert_eq!(output.compute_results[3], H256::from_low_u64_be(volume));
}
23 changes: 23 additions & 0 deletions circuit/src/tests/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use axiom_sdk::ethers::types::{BigEndianHash, H256, U256};

pub fn pad_input(
block_number: Vec<usize>,
tx_idx: Vec<usize>,
log_idx: Vec<usize>,
) -> (Vec<usize>, Vec<usize>, Vec<usize>) {
let mut block_numbers = block_number.clone();
block_numbers.resize(10, block_number[0]);
let mut tx_idxs = tx_idx.clone();
tx_idxs.resize(10, tx_idx[0]);
let mut log_idxs = log_idx.clone();
log_idxs.resize(10, log_idx[0]);

(block_numbers, tx_idxs, log_idxs)
}

pub fn calculate_claim_id(block_number: usize, tx_idx: usize, log_idx: usize) -> H256 {
let claim_id_value = U256::from(block_number) * U256::from(2).pow(U256::from(128))
+ U256::from(tx_idx) * U256::from(2).pow(U256::from(64))
+ log_idx;
H256::from_uint(&claim_id_value)
}
20 changes: 20 additions & 0 deletions test/ENSReferrals.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,24 @@ contract ENSReferralsTest is AxiomTest {
"Last claim ID not updated"
);
}

function test_cantDoubleClaim() public {
Query memory q = query(renewalQuerySchema, abi.encode(renewalInput), address(referrals));
q.send();

bytes32[] memory results = q.prankFulfill();
require(
referrals.lastClaimedId(renewalQuerySchema, uint16(uint160(uint256(results[2])))) == uint256(results[1]),
"Last claim ID not updated"
);

FulfillCallbackArgs memory args = axiomVm.fulfillCallbackArgs(
q.querySchema, q.input, q.callbackTarget, q.callbackExtraData, q.feeData, msg.sender
);
vm.prank(axiomV2QueryAddress);
vm.expectRevert();
IAxiomV2Client(args.callbackTarget).axiomV2Callback{ gas: args.gasLimit }(
args.sourceChainId, args.caller, args.querySchema, args.queryId, args.axiomResults, args.callbackExtraData
);
}
}

0 comments on commit bf446d0

Please sign in to comment.