Skip to content
This repository has been archived by the owner on Nov 23, 2023. It is now read-only.

Commit

Permalink
feat: updated compile and deploy functions
Browse files Browse the repository at this point in the history
  • Loading branch information
brech1 committed Jul 13, 2023
1 parent 0f0209e commit 76aba92
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 119 deletions.
5 changes: 2 additions & 3 deletions client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ Open a new terminal to start interacting with the client through the CLI. Let's
cargo build --release
```

Once the project is built, we need to compile and deploy the contracts that the protocol is going to use to submit and verify the scores:
Once the project is built, we need to deploy the contracts that the protocol is going to use to submit and verify the scores:

```bash
./target/release/eigen-trust-client compile
./target/release/eigen-trust-client deploy
```

Expand Down Expand Up @@ -73,7 +72,7 @@ The command-line interface was built using [clap.rs](http://clap.rs/). There is
- `--action (add | remove)`: Defines the action to perform. You can choose to `add` a new member to a group or `remove` an existing member from it.
- `--ic`: Provides the identity commitment of the participant you intend to add or remove from the group.
- `--addr`: Specifies the participant's Ethereum address.
- `compile`: Compiles all the `.sol` and `.yul` contracts available in the `assets` folder. For `.sol` contracts, it generates an ABI JSON file and a Rust binding file. For `.yul` smart contracts, it compiles Yul code into binary.
- `compile`: Compiles the AttestationStation and stores the generated bindings.
- `deploy`: Deploys all the contracts.
- `proof`: Calculates the global scores, generates the zk proof and stores it in `et-proof.json` at the `assets` folder.
- `scores`: Calculates the global scores and stores them in the `scores.csv` file within the `assets` folder.
Expand Down
4 changes: 4 additions & 0 deletions client/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub enum EigenError {
TransactionError,
/// Contract compilation error
ContractCompilationError,
/// Path error
PathError,
/// Unknown error.
Unknown,
}
Expand All @@ -48,6 +50,7 @@ impl From<EigenError> for u8 {
EigenError::ParseError => 8,
EigenError::TransactionError => 9,
EigenError::ContractCompilationError => 10,
EigenError::PathError => 11,
EigenError::Unknown => 255,
}
}
Expand All @@ -67,6 +70,7 @@ impl From<u8> for EigenError {
8 => EigenError::ParseError,
9 => EigenError::TransactionError,
10 => EigenError::ContractCompilationError,
11 => EigenError::PathError,
_ => EigenError::Unknown,
}
}
Expand Down
122 changes: 59 additions & 63 deletions client/src/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,73 +18,36 @@ use ethers::{
prelude::{k256::ecdsa::SigningKey, Abigen, ContractFactory},
providers::Middleware,
signers::coins_bip39::{English, Mnemonic},
solc::{artifacts::ContractBytecode, Artifact, Solc},
solc::{Artifact, CompilerOutput, Solc},
types::TransactionRequest,
utils::keccak256,
};
use log::info;
use secp256k1::SecretKey;
use std::{fs::write, sync::Arc};
use std::sync::Arc;

/// Compiles the AttestationStation contract.
pub fn compile_as() -> Result<CompilerOutput, EigenError> {
let path =
get_assets_path().map_err(|_| EigenError::ParseError)?.join("AttestationStation.sol");

/// Deploys the AttestationStation contract.
pub async fn deploy_as(signer: Arc<ClientSigner>) -> Result<Address, EigenError> {
let path = get_assets_path().unwrap().join("AttestationStation.sol");
let compiler_output =
Solc::default().compile_source(&path).map_err(|_| EigenError::ContractCompilationError)?;

if !compiler_output.errors.is_empty() {
return Err(EigenError::ContractCompilationError);
}

let mut address: Option<Address> = None;
for (_, contract) in compiler_output.contracts_iter() {
let (abi, bytecode, _) = contract.clone().into_parts();
let abi = abi.ok_or(EigenError::ParseError)?;
let bytecode = bytecode.ok_or(EigenError::ParseError)?;

let factory = ContractFactory::new(abi, bytecode, signer.clone());

match factory.deploy(()).unwrap().send().await {
Ok(contract) => {
address = Some(contract.address());
break;
},
Err(_) => continue,
}
}

address.ok_or(EigenError::ParseError)
Ok(compiler_output)
}

/// Calls the EtVerifier contract.
pub async fn call_verifier(
signer: Arc<ClientSigner>, verifier_address: Address, proof: NativeProof,
) {
let calldata = encode_calldata::<Scalar>(&[proof.pub_ins], &proof.proof);

let tx = TransactionRequest::default().data(calldata).to(verifier_address);
let res = signer.send_transaction(tx, None).await.unwrap().await.unwrap();
info!("{:#?}", res);
}
/// Generates the bindings for the AttestationStation contract and save them into a file.
pub fn gen_as_bindings() -> Result<(), EigenError> {
let contracts = compile_as()?;

/// Compiles the AttestationStation contract.
pub fn compile_att_station() -> Result<(), EigenError> {
let path =
get_assets_path().map_err(|_| EigenError::ParseError)?.join("AttestationStation.sol");

// compile it
let contracts =
Solc::default().compile_source(&path).map_err(|_| EigenError::ContractCompilationError)?;

if !contracts.errors.is_empty() {
return Err(EigenError::ContractCompilationError);
}

for (name, contr) in contracts.contracts_iter() {
let contract: ContractBytecode = contr.clone().into();
let abi = contract.clone().abi.ok_or(EigenError::ParseError)?;
for (name, contract) in contracts.contracts_iter() {
let abi = contract.clone().abi.ok_or_else(|| EigenError::ParseError)?;
let abi_json = serde_json::to_string(&abi).map_err(|_| EigenError::ParseError)?;
let contract_json = serde_json::to_string(&contract).map_err(|_| EigenError::ParseError)?;

let bindings = Abigen::new(name, abi_json)
.map_err(|_| EigenError::ParseError)?
.generate()
Expand All @@ -93,24 +56,40 @@ pub fn compile_att_station() -> Result<(), EigenError> {
bindings
.write_to_file(get_file_path("attestation_station", FileType::Rs).unwrap())
.map_err(|_| EigenError::ParseError)?;
write(
get_file_path("attestation_station", FileType::Json).unwrap(),
contract_json,
)
.map_err(|_| EigenError::ParseError)?;
}

Ok(())
}

/// Deploys the AttestationStation contract.
pub async fn deploy_as(signer: Arc<ClientSigner>) -> Result<Address, EigenError> {
let contracts = compile_as()?;
let mut address: Option<Address> = None;

for (_, contract) in contracts.contracts_iter() {
let (abi, bytecode, _) = contract.clone().into_parts();
let abi = abi.ok_or_else(|| EigenError::ParseError)?;
let bytecode = bytecode.ok_or_else(|| EigenError::ParseError)?;

let factory = ContractFactory::new(abi, bytecode, signer.clone());

match factory.deploy(()).unwrap().send().await {
Ok(contract) => {
address = Some(contract.address());
break;
},
Err(_) => continue,
}
}

address.ok_or_else(|| EigenError::ParseError)
}

/// Deploys the EtVerifier contract.
pub async fn deploy_verifier(signer: Arc<ClientSigner>) -> Result<Address, EigenError> {
// Compile the et_verifier.yul contract
let path = get_assets_path().map_err(|_| EigenError::ParseError)?.join("et_verifier.yul");
let path_str = path.to_str().ok_or(EigenError::ParseError)?;
let compiled_contract =
compile_yul(&read_yul(path_str).map_err(|_| EigenError::ContractCompilationError)?);
let yul_result = read_yul("et_verifier").map_err(|_| EigenError::ContractCompilationError)?;
let compiled_contract = compile_yul(&yul_result);

// Deploy the contract
let tx = TransactionRequest::default().data(compiled_contract);
let pen_tx =
signer.send_transaction(tx, None).await.map_err(|_| EigenError::TransactionError)?;
Expand All @@ -121,6 +100,23 @@ pub async fn deploy_verifier(signer: Arc<ClientSigner>) -> Result<Address, Eigen
rec.contract_address.ok_or(EigenError::TransactionError)
}

/// Calls the EtVerifier contract.
pub async fn call_verifier(
signer: Arc<ClientSigner>, verifier_address: Address, proof: NativeProof,
) -> Result<(), EigenError> {
let calldata = encode_calldata::<Scalar>(&[proof.pub_ins], &proof.proof);
let tx = TransactionRequest::default().data(calldata).to(verifier_address);

// Send transaction
let tx_result =
signer.send_transaction(tx, None).await.map_err(|_| EigenError::TransactionError)?;

// Await for transaction confirmation
tx_result.await.map_err(|_| EigenError::TransactionError)?;

Ok(())
}

/// Returns a vector of ECDSA private keys derived from the given mnemonic phrase.
pub fn ecdsa_secret_from_mnemonic(
mnemonic: &str, count: u32,
Expand Down Expand Up @@ -256,7 +252,7 @@ mod tests {
// Read proof data and call verifier
let proof_raw: ProofRaw = read_json("et_proof").unwrap();
let proof = Proof::from(proof_raw);
call_verifier(client.get_signer(), addr, proof).await;
call_verifier(client.get_signer(), addr, proof).await.unwrap();

drop(anvil);
}
Expand Down
48 changes: 2 additions & 46 deletions client/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serde::de::DeserializeOwned;
use serde_json::from_reader;
use std::{
env::current_dir,
fs::{read, read_to_string, write, File},
fs::{read_to_string, File},
io::{BufReader, Result},
path::PathBuf,
};
Expand Down Expand Up @@ -50,18 +50,6 @@ pub fn get_file_path(file_name: &str, file_type: FileType) -> Result<PathBuf> {
Ok(assets_path.join(format!("{}.{}", file_name, file_type.as_str())))
}

/// Reads a binary file from the `assets` directory and returns its contents as bytes.
pub fn read_binary(file_name: &str) -> Result<Vec<u8>> {
let bin_path = get_file_path(file_name, FileType::Bin)?;
read(bin_path)
}

/// Writes bytes to a binary file in the `assets` directory.
pub fn write_binary(bytes: Vec<u8>, file_name: &str) -> Result<()> {
let bin_path = get_file_path(file_name, FileType::Bin)?;
write(bin_path, bytes)
}

/// Reads a JSON file from the `assets` directory and returns its deserialized contents.
pub fn read_json<T: DeserializeOwned>(file_name: &str) -> Result<T> {
let json_path = get_file_path(file_name, FileType::Json)?;
Expand All @@ -70,7 +58,7 @@ pub fn read_json<T: DeserializeOwned>(file_name: &str) -> Result<T> {
from_reader(reader).map_err(Into::into)
}

/// Reads a file from the `assets` directory and returns its contents as a string.
/// Reads a `.yul` file from the `assets` directory and returns its contents as a string.
pub fn read_yul(file_name: &str) -> Result<String> {
let yul_path = get_file_path(file_name, FileType::Yul)?;
read_to_string(yul_path)
Expand All @@ -88,38 +76,6 @@ mod tests {
field: String,
}

#[test]
fn test_read_binary() {
let file_name = "test_read_binary";

// Write test file
let mut file = File::create(get_file_path(file_name, FileType::Bin).unwrap()).unwrap();
file.write_all(b"binary data").unwrap();

// Test reading
let data = read_binary(file_name).unwrap();
assert_eq!(data, b"binary data");

// Cleanup
fs::remove_file(get_file_path(file_name, FileType::Bin).unwrap()).unwrap();
}

#[test]
fn test_write_binary() {
let file_name = "test_write_binary";
let binary_data: Vec<u8> = vec![0xff, 0x61, 0x4a, 0x6d, 0x59, 0x56, 0x2a, 0x42, 0x37, 0x72];

// Write binary data
write_binary(binary_data.clone(), file_name).unwrap();

// Test if the file was written correctly
let data = fs::read(get_file_path(file_name, FileType::Bin).unwrap()).unwrap();
assert_eq!(data, binary_data);

// Cleanup
fs::remove_file(get_file_path(file_name, FileType::Bin).unwrap()).unwrap();
}

#[test]
fn test_read_json() {
let file_name = "test_read_json";
Expand Down
10 changes: 5 additions & 5 deletions client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use clap::Parser;
use cli::*;
use dotenv::dotenv;
use eigen_trust_client::{
eth::{compile_att_station, deploy_as, deploy_verifier},
eth::{deploy_as, deploy_verifier, gen_as_bindings},
fs::read_json,
Client, ClientConfig,
};
Expand Down Expand Up @@ -53,10 +53,10 @@ async fn main() {
Err(e) => error!("Failed to execute bandada command: {:?}", e),
},
Mode::Compile => {
info!("Compiling contracts...");
match compile_att_station() {
Ok(_) => info!("AttestationStation Compilation successful"),
Err(e) => error!("Error during AttestationStation compilation: {}", e),
info!("Compiling AttestationStation...");
match gen_as_bindings() {
Ok(_) => info!("Compilation successful"),
Err(e) => error!("Error during compilation: {}", e),
}
info!("Done!");
},
Expand Down
4 changes: 2 additions & 2 deletions client/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,10 @@ impl AttestationRecord {

#[cfg(test)]
mod tests {
use crate::fs::get_assets_path;
use crate::storage::*;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;

// Define the test struct
#[derive(Debug, Deserialize, PartialEq, Clone, Serialize)]
Expand All @@ -272,7 +272,7 @@ mod tests {
fn test_csv_file_storage() {
// Create the CSV file
let filename = "test.csv";
let filepath = PathBuf::from("../data").join(filename);
let filepath = get_assets_path().unwrap().join(filename);
let mut csv_storage = CSVFileStorage::<Record>::new(filepath.clone());

let content = vec![Record {
Expand Down

0 comments on commit 76aba92

Please sign in to comment.