Skip to content

Commit

Permalink
Merge pull request #125 from gnosisguild/hmza/evm_caller
Browse files Browse the repository at this point in the history
Aggregator Publishing to Smart contract
  • Loading branch information
hmzakhalid authored Oct 1, 2024
2 parents 7bcb2b5 + b336b21 commit 6b05979
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 21 deletions.
1 change: 1 addition & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name: "INTEGRATION"
env:
HARDHAT_VAR_MNEMONIC: "test test test test test test test test test test test junk"
HARDHAT_VAR_INFURA_API_KEY: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
PRIVATE_KEY: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
# Uncomment the following lines to set your configuration variables using
# GitHub secrets (https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions)
#
Expand Down
1 change: 0 additions & 1 deletion packages/ciphernode/core/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use alloy::{hex, primitives::Uint};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::{
error::Error,
fmt::{self, Display},
hash::{DefaultHasher, Hash, Hasher},
};
Expand Down
153 changes: 153 additions & 0 deletions packages/ciphernode/core/src/evm_caller.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use actix::prelude::*;
use alloy::primitives::{Address, Bytes, U256};
use std::collections::HashMap;
use std::sync::Arc;

use crate::{
events::EnclaveEvent,
evm_contracts::EVMContract,
sortition::{GetNodes, Sortition},
EventBus,
};
pub struct EvmCaller {
contracts: HashMap<String, Arc<EVMContract>>,
bus: Addr<EventBus>,
sortition: Addr<Sortition>,
}

impl Actor for EvmCaller {
type Context = Context<Self>;
}

impl EvmCaller {
pub fn new(
bus: Addr<EventBus>,
sortition: Addr<Sortition>,
) -> Self {
Self {
contracts: HashMap::new(),
bus,
sortition,
}
}

pub fn add_contract(&mut self, name: &str, contract: Arc<EVMContract>) {
self.contracts.insert(name.to_string(), contract);
}

pub fn attach(
bus: Addr<EventBus>,
sortition: Addr<Sortition>,
) -> Addr<Self> {
let addr = Self::new(bus.clone(), sortition).start();

bus.do_send(crate::Subscribe::new(
"PublicKeyAggregated",
addr.clone().recipient(),
));

bus.do_send(crate::Subscribe::new(
"PlaintextAggregated",
addr.clone().recipient(),
));

addr
}
}

#[derive(Message)]
#[rtype(result = "()")]
pub struct AddContract {
pub name: String,
pub contract: Arc<EVMContract>,
}

impl Handler<AddContract> for EvmCaller {
type Result = ();

fn handle(&mut self, msg: AddContract, _: &mut Self::Context) -> Self::Result {
self.add_contract(&msg.name, msg.contract);
}
}

impl Handler<EnclaveEvent> for EvmCaller {
type Result = ResponseActFuture<Self, ()>;

fn handle(&mut self, msg: EnclaveEvent, _ctx: &mut Self::Context) -> Self::Result {
let contracts = self.contracts.clone();
let sortition = self.sortition.clone();

Box::pin(
async move {
match msg {
EnclaveEvent::PublicKeyAggregated { data, .. } => {
if let Some(contract) = contracts.get("registry") {
let nodes = sortition.send(GetNodes).await.unwrap_or_default();
let nodes: Vec<Address> = nodes
.into_iter()
.filter_map(|node| node.parse().ok())
.collect();

match contract
.publish_committee(
U256::from_str_radix(&data.e3_id.0, 10).unwrap(),
nodes,
Bytes::from(data.pubkey),
)
.await
{
Ok(tx) => println!("Published committee public key {:?}", tx.transaction_hash),
Err(e) => eprintln!("Failed to publish committee public key: {:?}", e),
}
}
}
EnclaveEvent::PlaintextAggregated { data, .. } => {
if let Some(contract) = contracts.get("enclave") {
println!("Publishing plaintext output {:?}", data.e3_id);
match contract
.publish_plaintext_output(
U256::from_str_radix(&data.e3_id.0, 10).unwrap(),
Bytes::from(data.decrypted_output),
Bytes::from(vec![1]), // TODO: Implement proof generation
)
.await
{
Ok(tx) => println!("Published plaintext output {:?}", tx.transaction_hash),
Err(e) => eprintln!("Failed to publish plaintext: {:?}", e),
}
}
}
_ => {}
}
}
.into_actor(self)
.map(|_, _, _| ()),
)
}
}


pub async fn connect_evm_caller(
bus: Addr<EventBus>,
sortition: Addr<Sortition>,
rpc_url: &str,
enclave_contract: Address,
registry_contract: Address,
) -> Result<Addr<EvmCaller>, anyhow::Error> {
let evm_caller = EvmCaller::attach(bus.clone(), sortition.clone());

let enclave_instance = EVMContract::new(rpc_url, enclave_contract).await?;
let registry_instance = EVMContract::new(rpc_url, registry_contract).await?;

evm_caller.send(AddContract {
name: "enclave".to_string(),
contract: Arc::new(enclave_instance),
}).await?;

evm_caller.send(AddContract {
name: "registry".to_string(),
contract: Arc::new(registry_instance),
}).await?;

Ok(evm_caller)
}
85 changes: 85 additions & 0 deletions packages/ciphernode/core/src/evm_contracts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use alloy::{
network::{Ethereum, EthereumWallet},
primitives::{Address, Bytes, U256},
providers::{
fillers::{ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, WalletFiller},
Identity, ProviderBuilder, RootProvider,
},
rpc::types::TransactionReceipt,
signers::local::PrivateKeySigner,
sol,
transports::BoxTransport,
};
use anyhow::Result;
use std::env;
use std::sync::Arc;

sol! {
#[derive(Debug)]
#[sol(rpc)]
contract Enclave {
function publishPlaintextOutput(uint256 e3Id, bytes memory plaintextOutput, bytes memory proof) external returns (bool success);
}

#[derive(Debug)]
#[sol(rpc)]
contract RegistryFilter {
function publishCommittee(uint256 e3Id, address[] memory nodes, bytes memory publicKey) external onlyOwner;
}
}

type ContractProvider = FillProvider<
JoinFill<
JoinFill<JoinFill<JoinFill<Identity, GasFiller>, NonceFiller>, ChainIdFiller>,
WalletFiller<EthereumWallet>,
>,
RootProvider<BoxTransport>,
BoxTransport,
Ethereum,
>;

pub struct EVMContract {
pub provider: Arc<ContractProvider>,
pub contract_address: Address,
}

impl EVMContract {
pub async fn new(rpc_url: &str, contract_address: Address) -> Result<Self> {
let signer: PrivateKeySigner = env::var("PRIVATE_KEY")?.parse()?;
let wallet = EthereumWallet::from(signer.clone());
let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(wallet)
.on_builtin(rpc_url)
.await?;

Ok(Self {
provider: Arc::new(provider),
contract_address: contract_address,
})
}

pub async fn publish_plaintext_output(
&self,
e3_id: U256,
plaintext_output: Bytes,
proof: Bytes,
) -> Result<TransactionReceipt> {
let contract = Enclave::new(self.contract_address, &self.provider);
let builder = contract.publishPlaintextOutput(e3_id, plaintext_output, proof);
let receipt = builder.send().await?.get_receipt().await?;
Ok(receipt)
}

pub async fn publish_committee(
&self,
e3_id: U256,
nodes: Vec<Address>,
public_key: Bytes,
) -> Result<TransactionReceipt> {
let contract = RegistryFilter::new(self.contract_address, &self.provider);
let builder = contract.publishCommittee(e3_id, nodes, public_key);
let receipt = builder.send().await?.get_receipt().await?;
Ok(receipt)
}
}
2 changes: 2 additions & 0 deletions packages/ciphernode/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ mod evm_ciphernode_registry;
mod evm_enclave;
mod evm_listener;
mod evm_manager;
mod evm_caller;
mod evm_contracts;
mod fhe;
mod keyshare;
mod logger;
Expand Down
3 changes: 3 additions & 0 deletions packages/ciphernode/core/src/main_aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{
evm_enclave::connect_evm_enclave, public_key_writer::PublicKeyWriter, E3RequestManager,
EventBus, FheFactory, P2p, PlaintextAggregatorFactory, PlaintextWriter,
PublicKeyAggregatorFactory, SimpleLogger, Sortition,
evm_caller::connect_evm_caller,
};
use actix::{Actor, Addr, Context};
use alloy::primitives::Address;
Expand Down Expand Up @@ -40,6 +41,7 @@ impl MainAggregator {
rpc_url: &str,
enclave_contract: Address,
registry_contract: Address,
registry_filter_contract: Address,
pubkey_write_path: Option<&str>,
plaintext_write_path: Option<&str>,
) -> (Addr<Self>, JoinHandle<()>) {
Expand All @@ -52,6 +54,7 @@ impl MainAggregator {

connect_evm_enclave(bus.clone(), rpc_url, enclave_contract).await;
let _ = connect_evm_ciphernode_registry(bus.clone(), rpc_url, registry_contract).await;
let _ = connect_evm_caller(bus.clone(), sortition.clone(), rpc_url, enclave_contract, registry_filter_contract).await;

let e3_manager = E3RequestManager::builder(bus.clone())
.add_hook(CommitteeMetaFactory::create())
Expand Down
6 changes: 3 additions & 3 deletions packages/ciphernode/core/src/main_ciphernode.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::sync::{Arc, Mutex};

use crate::{
evm_ciphernode_registry::connect_evm_ciphernode_registry, evm_enclave::connect_evm_enclave,
CiphernodeSelector, CommitteeMetaFactory, Data, E3RequestManager, EventBus, FheFactory,
KeyshareFactory, P2p, SimpleLogger, Sortition,
evm_ciphernode_registry::connect_evm_ciphernode_registry,
evm_enclave::connect_evm_enclave, CiphernodeSelector, CommitteeMetaFactory, Data,
E3RequestManager, EventBus, FheFactory, KeyshareFactory, P2p, SimpleLogger, Sortition,
};
use actix::{Actor, Addr, Context};
use alloy::primitives::Address;
Expand Down
18 changes: 18 additions & 0 deletions packages/ciphernode/core/src/sortition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ impl SortitionList<String> for SortitionModule {
}
}

#[derive(Message)]
#[rtype(result = "Vec<String>")]
pub struct GetNodes;


pub struct Sortition {
list: SortitionModule,
}
Expand All @@ -78,6 +83,10 @@ impl Sortition {
bus.do_send(Subscribe::new("CiphernodeAdded", addr.clone().into()));
addr
}

pub fn get_nodes(&self) -> Vec<String> {
self.list.nodes.clone().into_iter().collect()
}
}

impl Default for Sortition {
Expand Down Expand Up @@ -121,3 +130,12 @@ impl Handler<GetHasNode> for Sortition {
self.list.contains(msg.seed, msg.size, msg.address)
}
}

impl Handler<GetNodes> for Sortition {
type Result = Vec<String>;

fn handle(&mut self, _msg: GetNodes, _ctx: &mut Self::Context) -> Self::Result {
self.get_nodes()
}
}

16 changes: 12 additions & 4 deletions packages/ciphernode/enclave_node/src/bin/aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ use enclave_core::MainAggregator;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
#[arg(short = 'n', long)]
#[arg(short = 'r', long)]
rpc: String,
#[arg(short, long = "enclave-contract")]
#[arg(short = 'e', long = "enclave-contract")]
enclave_contract: String,
#[arg(short, long = "registry-contract")]
#[arg(short = 'c', long = "registry-contract")]
registry_contract: String,
#[arg(short, long = "pubkey-write-path")]
#[arg(short = 'f', long = "registry-filter-contract")]
registry_filter_contract: String,
#[arg(short = 'p', long = "pubkey-write-path")]
pubkey_write_path: Option<String>,
#[arg(short = 't', long = "plaintext-write-path")]
plaintext_write_path: Option<String>,
Expand All @@ -23,12 +25,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("LAUNCHING AGGREGATOR");
let registry_contract =
Address::parse_checksummed(&args.registry_contract, None).expect("Invalid address");
let registry_filter_contract = Address::parse_checksummed(
&args.registry_filter_contract,
None,
)
.expect("Invalid address");
let enclave_contract =
Address::parse_checksummed(&args.enclave_contract, None).expect("Invalid address");
let (_, handle) = MainAggregator::attach(
&args.rpc,
enclave_contract,
registry_contract,
registry_filter_contract,
args.pubkey_write_path.as_deref(),
args.plaintext_write_path.as_deref()
)
Expand Down
8 changes: 4 additions & 4 deletions packages/ciphernode/enclave_node/src/bin/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use enclave_core::MainCiphernode;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
#[arg(short, long)]
#[arg(short = 'a', long)]
address: String,
#[arg(short='n', long)]
#[arg(short='r', long)]
rpc: String,
#[arg(short, long="enclave-contract")]
#[arg(short = 'e', long = "enclave-contract")]
enclave_contract: String,
#[arg(short, long="registry-contract")]
#[arg(short = 'c', long = "registry-contract")]
registry_contract: String
}

Expand Down
Loading

0 comments on commit 6b05979

Please sign in to comment.