diff --git a/contract-tests/tests/rotation_input_encoding.rs b/contract-tests/tests/rotation_input_encoding.rs index e0e9296e..a2c38685 100644 --- a/contract-tests/tests/rotation_input_encoding.rs +++ b/contract-tests/tests/rotation_input_encoding.rs @@ -29,11 +29,20 @@ where [(); Spec::SYNC_COMMITTEE_SIZE]:, { fn from(args: CommitteeRotationArgs) -> Self { - let poseidon_commitment_le = poseidon_committee_commitment_from_compressed( + let poseidon_commitment_be = poseidon_committee_commitment_from_compressed( &args.pubkeys_compressed.iter().cloned().collect_vec(), ) + .unwrap() + .into_iter() + .rev() // need to reverse to match the endianness of the solidity encoding + .collect_vec() + .try_into() .unwrap(); + // Endianess here is super confusing + // This should be solved by having `committee_poseidong` only be `uint256` + // See https://github.com/ChainSafe/Spectre/pull/42 + let mut pk_vector: Vector, { Spec::SYNC_COMMITTEE_SIZE }> = args .pubkeys_compressed .iter() @@ -52,66 +61,71 @@ where RotateInput { sync_committee_ssz, - sync_committee_poseidon: poseidon_commitment_le, + sync_committee_poseidon: poseidon_commitment_be, } } } -#[rstest] -#[tokio::test] -async fn test_rotate_public_input_evm_equivalence( - #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] - #[exclude("deneb*")] - path: PathBuf, -) -> anyhow::Result<()> { - let (_, witness) = read_test_files_and_gen_witness(&path); - let accumulator = [bn256::Fr::zero(); 12]; // this can be anything.. The test is just checking it gets correctly concatenated to the start of the encoded input - - let instance = CommitteeUpdateCircuit::::instance(&witness, LIMB_BITS); - let finalized_block_root = witness - .finalized_header - .clone() - .hash_tree_root() - .unwrap() - .deref() - .try_into() - .unwrap(); +#[cfg(test)] +mod tests { + use super::*; - let (_anvil_instance, ethclient) = make_client(); - let contract = RotateExternal::deploy(ethclient, ())?.send().await?; + /// Convert a slice of field elements into an array of U256 ready to pass to a soliditiy call via ethers + fn solidity_encode_fr_array(frs: &[bn256::Fr]) -> [ethers::types::U256; N] { + frs.iter() + .map(|v| ethers::types::U256::from_little_endian(&v.to_bytes())) + .collect_vec() + .try_into() + .expect("incompatible input slice length with return type") + } - let result = contract - .to_public_inputs( - RotateInput::from(witness), - finalized_block_root, - solidity_encode_fr_array(&accumulator), - ) - .call() - .await?; - - let result_decoded = decode_solidity_u256_array(&result); - // The expected result is the concatenation of the accumulator and the instance - let expected: Vec<_> = accumulator.iter().chain(instance[0].iter()).collect(); - assert_eq!(result_decoded.iter().collect::>(), expected); - Ok(()) -} + fn decode_solidity_u256_array(uints: &[ethers::types::U256]) -> Vec { + uints + .iter() + .map(|v| { + let mut b = [0_u8; 32]; + v.to_little_endian(&mut b); + bn256::Fr::from_bytes(&b).expect("bad bn256::Fr encoding") + }) + .collect() + } -/// Convert a slice of field elements into an array of U256 ready to pass to a soliditiy call via ethers -fn solidity_encode_fr_array(frs: &[bn256::Fr]) -> [ethers::types::U256; N] { - frs.iter() - .map(|v| ethers::types::U256::from_little_endian(&v.to_bytes())) - .collect_vec() - .try_into() - .expect("incompatible input slice length with return type") -} + #[rstest] + #[tokio::test] + async fn test_rotate_public_input_evm_equivalence( + #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] + #[exclude("deneb*")] + path: PathBuf, + ) -> anyhow::Result<()> { + let (_, witness) = read_test_files_and_gen_witness(&path); + let accumulator = [bn256::Fr::zero(); 12]; // this can be anything.. The test is just checking it gets correctly concatenated to the start of the encoded input -fn decode_solidity_u256_array(uints: &[ethers::types::U256]) -> Vec { - uints - .iter() - .map(|v| { - let mut b = [0_u8; 32]; - v.to_little_endian(&mut b); - bn256::Fr::from_bytes(&b).expect("bad bn256::Fr encoding") - }) - .collect() + let instance = CommitteeUpdateCircuit::::instance(&witness, LIMB_BITS); + let finalized_block_root = witness + .finalized_header + .clone() + .hash_tree_root() + .unwrap() + .deref() + .try_into() + .unwrap(); + + let (_anvil_instance, ethclient) = make_client(); + let contract = RotateExternal::deploy(ethclient, ())?.send().await?; + + let result = contract + .to_public_inputs( + RotateInput::from(witness), + finalized_block_root, + solidity_encode_fr_array(&accumulator), + ) + .call() + .await?; + + let result_decoded = decode_solidity_u256_array(&result); + // The expected result is the concatenation of the accumulator and the instance + let expected: Vec<_> = accumulator.iter().chain(instance[0].iter()).collect(); + assert_eq!(result_decoded.iter().collect::>(), expected); + Ok(()) + } } diff --git a/prover/tests/rpc_step.rs b/prover/tests/rpc_step.rs deleted file mode 100644 index 1886ec2f..00000000 --- a/prover/tests/rpc_step.rs +++ /dev/null @@ -1,114 +0,0 @@ -// use std::sync::Arc; - -// use jsonrpc_v2::{Error, RequestObject}; -// use spectre_prover::rpc_api::{ -// EvmProofResult, GenProofRotationParams, GenProofRotationWithWitnessParams, GenProofStepParams, -// GenProofStepWithWitnessParams, SyncCommitteePoseidonParams, SyncCommitteePoseidonResult, -// EVM_PROOF_ROTATION_CIRCUIT, EVM_PROOF_ROTATION_CIRCUIT_WITH_WITNESS, EVM_PROOF_STEP_CIRCUIT, -// EVM_PROOF_STEP_CIRCUIT_WITH_WITNESS, SYNC_COMMITTEE_POSEIDON_COMPRESSED, -// SYNC_COMMITTEE_POSEIDON_UNCOMPRESSED, -// }; -// use url::Url; -// const SEPOLIA_BEACON_API: &str = "http://65.109.55.120:9596"; -// const SPECTRE_API: &str = "http://localhost:3000/rpc"; - -// use beacon_api_client::mainnet::Client as MainnetBeaconClient; -// use beacon_api_client::Client as BeaconClient; -// use beacon_api_client::{BlockId, ClientTypes, StateId, VersionedValue}; -// use jsonrpc_v2::{MapRouter as JsonRpcMapRouter, Server as JsonRpcServer}; -// use serde::{de::DeserializeOwned, Deserialize, Serialize}; -// use spectre_prover::rpc_client::{Client as SpectreClient, JsonRpcResponse}; -// /// RPC client to send JSON-RPC requests to the prover -// pub struct MockClient { -// pub server: JsonRpcServer, -// } - -// impl MockClient { -// pub fn new(server: JsonRpcServer) -> Self { -// Self { server } -// } -// /// Generates a proof along with instance values for committee Rotation circuit -// pub async fn gen_evm_proof_rotation_circuit( -// &self, -// params: GenProofRotationParams, -// ) -> Result { -// self.call(EVM_PROOF_ROTATION_CIRCUIT, params).await -// } - -// /// Generates a proof along with instance values for Step circuit -// pub async fn gen_evm_proof_step_circuit( -// &self, -// params: GenProofStepParams, -// ) -> Result { -// self.call(EVM_PROOF_STEP_CIRCUIT, params).await -// } - -// /// Generates a proof along with instance values for committee Rotation circuit -// pub async fn gen_evm_proof_rotation_circuit_with_witness( -// &self, -// params: GenProofRotationWithWitnessParams, -// ) -> Result { -// self.call(EVM_PROOF_ROTATION_CIRCUIT_WITH_WITNESS, params) -// .await -// } - -// /// Generates a proof along with instance values for Step circuit -// pub async fn gen_evm_proof_step_circuit_with_witness( -// &self, -// params: GenProofStepWithWitnessParams, -// ) -> Result { -// self.call(EVM_PROOF_STEP_CIRCUIT_WITH_WITNESS, params).await -// } - -// pub async fn sync_committee_poseidon_compressed( -// &self, -// params: SyncCommitteePoseidonParams, -// ) -> Result { -// self.call(SYNC_COMMITTEE_POSEIDON_COMPRESSED, params).await -// } - -// pub async fn sync_committee_poseidon_uncompressed( -// &self, -// params: SyncCommitteePoseidonParams, -// ) -> Result { -// self.call(SYNC_COMMITTEE_POSEIDON_UNCOMPRESSED, params) -// .await -// } - -// /// Utility method for sending RPC requests over HTTP -// async fn call(&self, method_name: &str, params: P) -> Result -// where -// P: Serialize, -// R: DeserializeOwned, -// { -// let rpc_req = RequestObject::request() -// .with_method(method_name) -// .with_params(serde_json::to_value(params)?) -// .finish(); - -// let response = self.server.handle(rpc_req).await; -// match response { -// jsonrpc_v2::ResponseObjects::One(r) => Ok(r), -// jsonrpc_v2::ResponseObjects::Many(_) => unreachable!(), -// jsonrpc_v2::ResponseObjects::Empty => Err("Empty".to_string()), -// } -// // let response_str = serde_json::to_string(&response); -// // log::debug!("RPC response: {:?}", response_str); - -// // match response_str { -// // Ok(result) => Ok(result), -// // Err(err) => ( -// // Err(err.to_string()), -// // ), -// // } -// } -// } - -// #[tokio::test] -// async fn e2e_step() { -// let reqwest_client = reqwest::Client::new(); -// let beacon_client = Arc::new(MainnetBeaconClient::new_with_client( -// reqwest_client.clone(), -// Url::parse(SEPOLIA_BEACON_API).unwrap(), -// )); -// }