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

adding experiment with self calls #401

Merged
merged 11 commits into from
Jan 23, 2024
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ crate-type = ["cdylib", "lib"]
borsh = "1.3.0"
near-sdk = "5.0.0-alpha.1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
schemars = "0.8"

[profile.release]
Expand Down
35 changes: 30 additions & 5 deletions contract/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::LookupMap;
use near_sdk::serde::{Deserialize, Serialize};
use near_sdk::{env, near_bindgen, AccountId, PanicOnDefault, PublicKey};
use near_sdk::{env, near_bindgen, AccountId, PanicOnDefault, Promise, PromiseOrValue, PublicKey};
use std::collections::{BTreeMap, HashSet};

type ParticipantId = u32;
Expand Down Expand Up @@ -74,6 +75,7 @@ pub enum ProtocolContractState {
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
pub struct MpcContract {
protocol_state: ProtocolContractState,
pending_requests: LookupMap<[u8; 32], Option<(String, String)>>,
}

#[near_bindgen]
Expand All @@ -86,6 +88,7 @@ impl MpcContract {
threshold,
pk_votes: BTreeMap::new(),
}),
pending_requests: LookupMap::new(b"m"),
}
}

Expand Down Expand Up @@ -290,12 +293,33 @@ impl MpcContract {
}

#[allow(unused_variables)]
pub fn sign(&mut self, payload: [u8; 32], path: String) -> [u8; 32] {
near_sdk::env::random_seed_array()
pub fn sign(&mut self, payload: [u8; 32], path: String) -> Promise {
self.pending_requests.insert(&payload, &None);
Copy link

Choose a reason for hiding this comment

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

This allows two different accounts to submit the same payload simultaneously, but only one of the sign calls will return successfully, and possibly with the wrong signature.

pending_requests should either be keyed with the payload and the predecessor combined, or sign should reject duplicate, simultaneous payloads.

env::log_str(&serde_json::to_string(&near_sdk::env::random_seed_array()).unwrap());
Self::ext(env::current_account_id()).sign_helper(payload)
}

#[allow(unused_variables)]
pub fn respond(&mut self, receipt_id: [u8; 32], big_r: String, s: String) {}
pub fn sign_helper(&mut self, payload: [u8; 32]) -> PromiseOrValue<(String, String)> {
itegulov marked this conversation as resolved.
Show resolved Hide resolved
if let Some(signature) = self.pending_requests.get(&payload) {
match signature {
Some(signature) => {
self.pending_requests.remove(&payload);
PromiseOrValue::Value(signature)
}
None => {
env::log_str("not ready");
itegulov marked this conversation as resolved.
Show resolved Hide resolved
let account_id = env::current_account_id();
PromiseOrValue::Promise(Self::ext(account_id).sign_helper(payload))
}
}
} else {
env::panic_str("unexpected request");
}
}

pub fn respond(&mut self, payload: [u8; 32], big_r: String, s: String) {
self.pending_requests.insert(&payload, &Some((big_r, s)));
}

#[private]
#[init(ignore_state)]
Expand All @@ -305,6 +329,7 @@ impl MpcContract {
}
Self {
protocol_state: ProtocolContractState::NotInitialized,
pending_requests: LookupMap::new(b"m"),
}
}
}
100 changes: 0 additions & 100 deletions integration-tests/src/indexer.rs

This file was deleted.

1 change: 0 additions & 1 deletion integration-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use near_workspaces::types::NearToken;
use testcontainers::{Container, GenericImage};

pub mod env;
pub mod indexer;
pub mod mpc;
pub mod multichain;
pub mod sandbox;
Expand Down
57 changes: 7 additions & 50 deletions integration-tests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,10 @@ use mpc_recovery::{
ClaimOidcResponse, MpcPkResponse, NewAccountResponse, SignResponse, UserCredentialsResponse,
},
};
use mpc_recovery_integration_tests::env;
use mpc_recovery_integration_tests::env::containers::DockerClient;
use mpc_recovery_integration_tests::indexer::FullSignature;
use mpc_recovery_integration_tests::{env, indexer};
use near_primitives::hash::CryptoHash;
use near_jsonrpc_client::JsonRpcClient;
use near_workspaces::{network::Sandbox, Worker};
use std::collections::HashMap;
use std::sync::Arc;
use std::thread;
use tokio::sync::RwLock;

pub struct TestContext {
env: String,
Expand Down Expand Up @@ -68,8 +63,8 @@ where
pub struct MultichainTestContext<'a> {
nodes: mpc_recovery_integration_tests::multichain::Nodes<'a>,
rpc_client: near_fetch::Client,
jsonrpc_client: JsonRpcClient,
http_client: reqwest::Client,
responses: Arc<RwLock<HashMap<CryptoHash, FullSignature>>>,
}

async fn with_multichain_nodes<F>(nodes: usize, f: F) -> anyhow::Result<()>
Expand All @@ -79,30 +74,14 @@ where
let docker_client = DockerClient::default();
let nodes = mpc_recovery_integration_tests::multichain::run(nodes, &docker_client).await?;

let s3_bucket = nodes.ctx().localstack.s3_bucket.clone();
let s3_region = nodes.ctx().localstack.s3_region.clone();
let s3_url = nodes.ctx().localstack.s3_host_address.clone();
let mpc_contract_id = nodes.ctx().mpc_contract.id().clone();
let responses = Arc::new(RwLock::new(HashMap::new()));
let responses_clone = responses.clone();
thread::spawn(move || {
indexer::run(
&s3_bucket,
&s3_region,
0,
&s3_url,
mpc_contract_id,
responses_clone,
)
.unwrap();
});

let rpc_client = near_fetch::Client::new(&nodes.ctx().lake_indexer.rpc_host_address);
let connector = JsonRpcClient::new_client();
let jsonrpc_client = connector.connect(&nodes.ctx().lake_indexer.rpc_host_address);
let rpc_client = near_fetch::Client::from_client(jsonrpc_client.clone());
f(MultichainTestContext {
nodes,
rpc_client,
jsonrpc_client,
http_client: reqwest::Client::default(),
responses,
})
.await?;

Expand Down Expand Up @@ -217,9 +196,7 @@ mod wait_for {
use backon::Retryable;
use mpc_contract::ProtocolContractState;
use mpc_contract::RunningContractState;
use mpc_recovery_integration_tests::indexer::FullSignature;
use mpc_recovery_node::web::StateView;
use near_primitives::hash::CryptoHash;

pub async fn running_mpc<'a>(
ctx: &MultichainTestContext<'a>,
Expand Down Expand Up @@ -304,26 +281,6 @@ mod wait_for {
.await
.with_context(|| format!("mpc node '{id}' failed to generate '{expected_presignature_count}' presignatures before deadline"))
}

pub async fn has_response<'a>(
ctx: &MultichainTestContext<'a>,
receipt_id: CryptoHash,
) -> anyhow::Result<FullSignature> {
let is_enough_presignatures = || async {
let mut responses = ctx.responses.write().await;
if let Some(signature) = responses.remove(&receipt_id) {
return Ok(signature);
}
drop(responses);
anyhow::bail!("mpc has not responded yet")
};
is_enough_presignatures
.retry(&ExponentialBuilder::default().with_max_times(8))
.await
.with_context(|| {
format!("mpc failed to respond to receipt id '{receipt_id}' before deadline")
})
}
}

trait MpcCheck {
Expand Down
Loading
Loading