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

feat: Tree trait #179

Merged
merged 20 commits into from
Nov 10, 2023
Merged
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
15a6d0a
chore: add audit comments (#168)
sifnoc Nov 3, 2023
400fc49
Refactor backend by following internal audit comments (#173)
sifnoc Nov 3, 2023
d538b28
feat: added mutex lock to signer; used it as ref
sifnoc Nov 1, 2023
c750083
fix: mutex deadlock in signer
sifnoc Nov 3, 2023
be0f52d
chore: minor updates
sifnoc Nov 4, 2023
022dde6
feat: `Tree` trait
enricobottazzi Nov 6, 2023
b3990eb
fix: move `verify_proof` logic to `Tree` trait
enricobottazzi Nov 6, 2023
35478ec
feat: added method implementation to `Tree` trait and moved outside o…
enricobottazzi Nov 6, 2023
e17e493
refactor: signer spawn provider internally; updated comments
sifnoc Nov 7, 2023
d3c5562
Merge branch 'shared-signer' into enrico-tree-trait
sifnoc Nov 7, 2023
391f37c
fix: round now use Tree trait
sifnoc Nov 7, 2023
2f14b36
refactor: Round needs MST and Assets instead of csv files path
sifnoc Nov 7, 2023
3e8c855
fix: rollback applying csv_parser for AddressOwnership and Assets in …
sifnoc Nov 8, 2023
c80e964
fix: Solvency::init fn accept type that has Tree trait
sifnoc Nov 8, 2023
d42af95
Merge branch 'v1-improvements-and-consolidation' into enrico-tree-trait
sifnoc Nov 8, 2023
0c5153b
fix: updates for summa solvency contract v1.1
sifnoc Nov 8, 2023
4e180b2
chore: rename `compute_leaves` api
enricobottazzi Nov 9, 2023
5a9120f
fix: Rounds accept 'Tree' trait object
sifnoc Nov 9, 2023
c575a29
chore: removed and updated comments
sifnoc Nov 9, 2023
3afa5d7
chore: removed env variables 'SIGNATURE_VERIFICATION_MESSAGE'
sifnoc Nov 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: added mutex lock to signer; used it as ref
  • Loading branch information
sifnoc committed Nov 3, 2023
commit d538b28ac412249d9b4b17281b7f94a84dfa9243
31 changes: 12 additions & 19 deletions backend/examples/summa_solvency_flow.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#![feature(generic_const_exprs)]
use std::{error::Error, fs::File, io::BufReader, io::Write};
use std::{error::Error, fs::File, io::BufReader, io::Write, sync::Arc};

use ethers::types::U256;
use ethers::{providers::Provider, types::U256};
use serde_json::{from_reader, to_string_pretty};

use summa_backend::{
apis::{
address_ownership::AddressOwnership,
round::{MstInclusionProof, Round},
},
contracts::signer::AddressInput,
contracts::signer::{AddressInput, SummaSigner},
tests::initialize_test_env,
};
use summa_solvency::merkle_sum_tree::utils::generate_leaf_hash;
@@ -27,17 +27,20 @@ async fn main() -> Result<(), Box<dyn Error>> {
// Each CEX prepares its own `signature` CSV file.
let signature_csv_path = "src/apis/csv/signatures.csv";

// The signer would be using `provider` that shared with `address_ownership` and `round` instances.
let provider = Arc::new(Provider::try_from(anvil.endpoint().as_str())?);

// Using AddressInput::Address to directly provide the summa_contract's address.
// For deployed contracts, if the address is stored in a config file,
// you can alternatively use AddressInput::Path to specify the file's path.
Copy link
Member Author

Choose a reason for hiding this comment

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

Do we have an example of such config file? Can you add it to the comments if possible?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, there is "backend/src/contracts/deployments.json".
I will add comment

Copy link
Member

Choose a reason for hiding this comment

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

Updated c575a29

let mut address_ownership_client = AddressOwnership::new(
let signer = SummaSigner::new(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
anvil.chain_id(),
anvil.endpoint().as_str(),
provider,
AddressInput::Address(summa_contract.address()),
signature_csv_path,
)
.unwrap();
);

let mut address_ownership_client = AddressOwnership::new(&signer, signature_csv_path).unwrap();

// Dispatch the proof of address ownership.
// the `dispatch_proof_of_address_ownership` function sends a transaction to the Summa contract.
@@ -55,17 +58,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
let params_path = "ptau/hermez-raw-11";

// Using the `round` instance, the solvency proof is dispatched to the Summa contract with the `dispatch_solvency_proof` method.
let mut round = Round::<4, 2, 14>::new(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", // anvil account [0]
anvil.chain_id(),
anvil.endpoint().as_str(),
AddressInput::Address(summa_contract.address()),
entry_csv,
asset_csv,
params_path,
1,
)
.unwrap();
let mut round = Round::<4, 2, 14>::new(&signer, entry_csv, asset_csv, params_path, 1).unwrap();

// Sends the solvency proof, which should ideally complete without errors.
round.dispatch_solvency_proof().await?;
22 changes: 8 additions & 14 deletions backend/src/apis/address_ownership.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
use crate::contracts::{
generated::summa_contract::AddressOwnershipProof,
signer::{AddressInput, SummaSigner},
};
use crate::contracts::{generated::summa_contract::AddressOwnershipProof, signer::SummaSigner};
use std::{error::Error, result::Result};

use super::csv_parser::parse_signature_csv;

pub struct AddressOwnership {
pub struct AddressOwnership<'a> {
address_ownership_proofs: Vec<AddressOwnershipProof>,
signer: SummaSigner,
signer: &'a SummaSigner,
}

impl AddressOwnership {
pub fn new(
signer_key: &str,
chain_id: u64,
rpc_url: &str,
summa_address_input: AddressInput,
impl AddressOwnership<'_> {
pub fn new<'a>(
signer: &'a SummaSigner,
signature_csv_path: &str,
) -> Result<AddressOwnership, Box<dyn Error>> {
) -> Result<AddressOwnership<'a>, Box<dyn Error>> {
let address_ownership_proofs = parse_signature_csv(signature_csv_path)?;

Ok(AddressOwnership {
address_ownership_proofs,
signer: SummaSigner::new(signer_key, chain_id, rpc_url, summa_address_input),
signer,
})
}

22 changes: 8 additions & 14 deletions backend/src/apis/round.rs
Original file line number Diff line number Diff line change
@@ -8,10 +8,7 @@ use serde::{Deserialize, Serialize};
use std::error::Error;

use super::csv_parser::parse_asset_csv;
use crate::contracts::{
generated::summa_contract::summa::Asset,
signer::{AddressInput, SummaSigner},
};
use crate::contracts::{generated::summa_contract::summa::Asset, signer::SummaSigner};
use summa_solvency::{
circuits::{
merkle_sum_tree::MstInclusionCircuit,
@@ -65,28 +62,25 @@ pub struct Snapshot<const LEVELS: usize, const N_ASSETS: usize, const N_BYTES: u
trusted_setup: [SetupArtifacts; 2],
}

pub struct Round<const LEVELS: usize, const N_ASSETS: usize, const N_BYTES: usize> {
pub struct Round<'a, const LEVELS: usize, const N_ASSETS: usize, const N_BYTES: usize> {
timestamp: u64,
snapshot: Snapshot<LEVELS, N_ASSETS, N_BYTES>,
signer: SummaSigner,
signer: &'a SummaSigner,
}

impl<const LEVELS: usize, const N_ASSETS: usize, const N_BYTES: usize>
Round<LEVELS, N_ASSETS, N_BYTES>
Round<'_, LEVELS, N_ASSETS, N_BYTES>
where
[usize; N_ASSETS + 1]: Sized,
[usize; 2 * (1 + N_ASSETS)]: Sized,
{
pub fn new(
signer_key: &str,
chain_id: u64,
rpc_url: &str,
summa_address_input: AddressInput,
pub fn new<'a>(
Copy link
Member Author

Choose a reason for hiding this comment

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

The main point of the PR for me was that Round should accept as input an object binded to the Tree trait. Similarly to what you applied to Solvency::init. But I don't know why you applied it to Solvency which is now dismissed

Copy link
Member

Choose a reason for hiding this comment

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

Ah, that's what you were looking for. Honestly, I was trying to figure out how to define the Tree trait as a concrete type in the SolvencyCircuit struct, but I realized it's impossible without using Box, which is kind of smart pointer.

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

It because the merkle_sum_tree in the solvency::init evaluates some values, like root_hash, not assign into SolvencyCircuit. Anyway I fixed like this:

pub struct Snapshot<const LEVELS: usize, const N_ASSETS: usize, const N_BYTES: usize> {
    mst: Box<dyn Tree<N_ASSETS, N_BYTES>>, // Instead of MerkleSumTree<N_ASSETS, N_BYTES>,
    assets_state: [Asset; N_ASSETS],
    trusted_setup: SetupArtifacts,
}

Copy link
Member

Choose a reason for hiding this comment

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

Updated at 5a9120f

signer: &'a SummaSigner,
entry_csv_path: &str,
asset_csv_path: &str,
params_path: &str,
timestamp: u64,
) -> Result<Round<LEVELS, N_ASSETS, N_BYTES>, Box<dyn Error>> {
) -> Result<Round<'a, LEVELS, N_ASSETS, N_BYTES>, Box<dyn Error>> {
Ok(Round {
timestamp,
snapshot: Snapshot::<LEVELS, N_ASSETS, N_BYTES>::new(
@@ -95,7 +89,7 @@ where
params_path,
)
.unwrap(),
signer: SummaSigner::new(signer_key, chain_id, rpc_url, summa_address_input),
signer: &signer,
})
}

29 changes: 19 additions & 10 deletions backend/src/contracts/signer.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,12 @@ use ethers::{
};
use serde_json::Value;
use std::{
error::Error, fs::File, io::BufReader, path::Path, str::FromStr, sync::Arc, time::Duration,
error::Error,
fs::File,
io::BufReader,
path::Path,
str::FromStr,
sync::{Arc, Mutex},
};

use super::generated::summa_contract::{AddressOwnershipProof, Asset};
@@ -19,27 +24,25 @@ pub enum AddressInput {

#[derive(Debug)]
pub struct SummaSigner {
summa_contract: Summa<SignerMiddleware<Provider<Http>, LocalWallet>>,
nonce_lock: Mutex<()>, // To prevent running `submit` methods concurrently
summa_contract: Summa<SignerMiddleware<Arc<Provider<Http>>, LocalWallet>>,
}

impl SummaSigner {
/// Creates a new SummaSigner instance
/// # Arguments
/// * `signer_key` - The private key of wallet that will interact with the chain on behalf of the exchange
/// * `chain_id` - The chain id of the network
/// * `rpc_url` - The RPC URL of the network
/// * `address_input` - Either the contract's direct address or a path to its config file.
/// * `provider` - The provider
/// * `address` - The address of the Summa contract
pub fn new(
signer_key: &str,
chain_id: u64,
rpc_url: &str,
provider: Arc<Provider<Http>>,
address_input: AddressInput,
) -> Self {
let wallet: LocalWallet = LocalWallet::from_str(signer_key).unwrap();

let provider = Provider::<Http>::try_from(rpc_url)
.unwrap()
.interval(Duration::from_millis(10u64));
let client = Arc::new(SignerMiddleware::new(
provider,
wallet.with_chain_id(chain_id),
@@ -53,9 +56,9 @@ impl SummaSigner {
}
};

let contract = Summa::new(address, client);
Self {
summa_contract: contract,
nonce_lock: Mutex::new(()),
summa_contract: Summa::new(address, client),
}
}

@@ -94,6 +97,9 @@ impl SummaSigner {
let submit_proof_of_address_ownership = &self
.summa_contract
.submit_proof_of_address_ownership(address_ownership_proofs);

// To prevent nonce collision, we lock the nonce before sending the transaction
let _lock = self.nonce_lock.lock().unwrap();
let tx = submit_proof_of_address_ownership.send().await?;

// Wait for the pending transaction to be mined
@@ -112,6 +118,9 @@ impl SummaSigner {
let submit_proof_of_solvency_call = &self
.summa_contract
.submit_proof_of_solvency(mst_root, assets, proof, timestamp);

// To prevent nonce collision, we lock the nonce before sending the transaction
let _lock = self.nonce_lock.lock().unwrap();
let tx = submit_proof_of_solvency_call.send().await?;

// Wait for the pending transaction to be mined
32 changes: 13 additions & 19 deletions backend/src/tests.rs
Original file line number Diff line number Diff line change
@@ -102,8 +102,8 @@ pub async fn initialize_test_env() -> (

#[cfg(test)]
mod test {
use ethers::{abi::AbiEncode, types::U256, utils::to_checksum};
use std::error::Error;
use ethers::{abi::AbiEncode, providers::Provider, types::U256, utils::to_checksum};
use std::{convert::TryFrom, error::Error, sync::Arc};

use crate::apis::{address_ownership::AddressOwnership, round::Round};
use crate::contracts::{
@@ -124,10 +124,11 @@ mod test {
// the address gets updated in `backend/src/contracts/deployments.json`.
let contract_address = summa_contract.address();

let provider = Arc::new(Provider::try_from(anvil.endpoint().as_str())?);
let summa_signer = SummaSigner::new(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
anvil.chain_id(),
anvil.endpoint().as_str(),
provider,
AddressInput::Path("./src/contracts/deployments.json".into()), // the file contains the address of the deployed contract
);

@@ -140,14 +141,16 @@ mod test {
async fn test_round_features() -> Result<(), Box<dyn Error>> {
let (anvil, cex_addr_1, cex_addr_2, _, summa_contract) = initialize_test_env().await;

let mut address_ownership_client = AddressOwnership::new(
let provider = Arc::new(Provider::try_from(anvil.endpoint().as_str())?);
let signer = SummaSigner::new(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
anvil.chain_id(),
anvil.endpoint().as_str(),
provider,
AddressInput::Address(summa_contract.address()),
"src/apis/csv/signatures.csv",
)
.unwrap();
);

let mut address_ownership_client =
AddressOwnership::new(&signer, "src/apis/csv/signatures.csv").unwrap();

address_ownership_client
.dispatch_proof_of_address_ownership()
@@ -184,17 +187,8 @@ mod test {
let entry_csv = "../zk_prover/src/merkle_sum_tree/csv/entry_16.csv";
let params_path = "ptau/hermez-raw-11";

let mut round = Round::<4, 2, 14>::new(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", // anvil account [0]
anvil.chain_id(),
anvil.endpoint().as_str(),
AddressInput::Address(summa_contract.address()),
entry_csv,
asset_csv,
params_path,
1,
)
.unwrap();
let mut round =
Round::<4, 2, 14>::new(&signer, entry_csv, asset_csv, params_path, 1).unwrap();

// Verify solvency proof
let mut solvency_proof_logs = summa_contract