From 53d2640f18804ac95bae15684d4d6f632a162b87 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 24 May 2024 15:03:26 +0000 Subject: [PATCH 1/9] tuple replaced with struct for signature result --- contract/src/lib.rs | 45 +++++++++++++++++++------------------- contract/src/primitives.rs | 6 +++++ 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/contract/src/lib.rs b/contract/src/lib.rs index 20d8b5215..856e4e497 100644 --- a/contract/src/lib.rs +++ b/contract/src/lib.rs @@ -5,7 +5,9 @@ use near_sdk::collections::LookupMap; use near_sdk::serde::{Deserialize, Serialize}; use near_sdk::{env, near_bindgen, AccountId, Promise, PromiseOrValue, PublicKey}; use near_sdk::{log, Gas}; -use primitives::{CandidateInfo, Candidates, ParticipantInfo, Participants, PkVotes, Votes}; +use primitives::{ + CandidateInfo, Candidates, ParticipantInfo, Participants, PkVotes, SignResult, Votes, +}; use std::collections::{BTreeMap, HashSet}; const GAS_FOR_SIGN_CALL: Gas = Gas::from_tgas(250); @@ -62,19 +64,19 @@ impl Default for VersionedMpcContract { #[derive(BorshDeserialize, BorshSerialize, Debug)] pub struct MpcContract { protocol_state: ProtocolContractState, - pending_requests: LookupMap<[u8; 32], Option<(String, String)>>, + pending_requests: LookupMap<[u8; 32], Option>, request_counter: u32, } impl MpcContract { - fn add_request(&mut self, payload: &[u8; 32], signature: &Option<(String, String)>) { + fn add_request(&mut self, payload: &[u8; 32], sign_result: &Option) { if self.request_counter > 8 { env::panic_str("Too many pending requests. Please, try again later."); } if !self.pending_requests.contains_key(payload) { self.request_counter += 1; } - self.pending_requests.insert(payload, signature); + self.pending_requests.insert(payload, sign_result); } fn remove_request(&mut self, payload: &[u8; 32]) { @@ -82,9 +84,9 @@ impl MpcContract { self.request_counter -= 1; } - fn add_signature(&mut self, payload: &[u8; 32], signature: (String, String)) { + fn add_sig_result(&mut self, payload: &[u8; 32], sign_result: SignResult) { if self.pending_requests.contains_key(payload) { - self.pending_requests.insert(payload, &Some(signature)); + self.pending_requests.insert(payload, &Some(sign_result)); } } @@ -135,9 +137,9 @@ impl VersionedMpcContract { path, key_version ); - match self.signature_per_payload(payload) { + match self.sign_result(payload) { None => { - self.add_request(&payload, &None); + self.add_sign_request(&payload, &None); log!(&serde_json::to_string(&near_sdk::env::random_seed_array()).unwrap()); Self::ext(env::current_account_id()).sign_helper(payload, 0) } @@ -172,6 +174,7 @@ impl VersionedMpcContract { #[near_bindgen] impl VersionedMpcContract { pub fn respond(&mut self, payload: [u8; 32], big_r: String, s: String) { + // TODO: change to SignResult let protocol_state = self.mutable_state(); if let ProtocolContractState::Running(state) = protocol_state { let signer = env::signer_account_id(); @@ -183,7 +186,7 @@ impl VersionedMpcContract { big_r, s ); - self.add_signature(&payload, (big_r, s)); + self.add_sign_result(&payload, SignResult { big_r, s }); } else { env::panic_str("only participants can respond"); } @@ -462,12 +465,8 @@ impl VersionedMpcContract { } #[private] - pub fn sign_helper( - &mut self, - payload: [u8; 32], - depth: usize, - ) -> PromiseOrValue<(String, String)> { - if let Some(signature) = self.signature_per_payload(payload) { + pub fn sign_helper(&mut self, payload: [u8; 32], depth: usize) -> PromiseOrValue { + if let Some(signature) = self.sign_result(payload) { match signature { Some(signature) => { log!( @@ -475,7 +474,7 @@ impl VersionedMpcContract { signature, depth ); - self.remove_request(&payload); + self.remove_sign_request(&payload); PromiseOrValue::Value(signature) } None => { @@ -484,7 +483,7 @@ impl VersionedMpcContract { // We keep one call back so we can cleanup then call panic on the next call // Start cleaning up if there's less than 25 teragas left regardless of how deep you are. if depth > 30 || env::prepaid_gas() < Gas::from_tgas(25) { - self.remove_request(&payload); + self.remove_sign_request(&payload); let self_id = env::current_account_id(); PromiseOrValue::Promise(Self::ext(self_id).fail_helper( "Signature was not provided in time. Please, try again.".to_string(), @@ -556,7 +555,7 @@ impl VersionedMpcContract { // Helper functions #[near_bindgen] impl VersionedMpcContract { - fn remove_request(&mut self, payload: &[u8; 32]) { + fn remove_sign_request(&mut self, payload: &[u8; 32]) { match self { Self::V0(mpc_contract) => { mpc_contract.remove_request(payload); @@ -564,18 +563,18 @@ impl VersionedMpcContract { } } - fn add_request(&mut self, payload: &[u8; 32], signature: &Option<(String, String)>) { + fn add_sign_request(&mut self, payload: &[u8; 32], sign_result: &Option) { match self { Self::V0(mpc_contract) => { - mpc_contract.add_request(payload, signature); + mpc_contract.add_request(payload, sign_result); } } } - fn add_signature(&mut self, payload: &[u8; 32], signature: (String, String)) { + fn add_sign_result(&mut self, payload: &[u8; 32], sign_result: SignResult) { match self { Self::V0(mpc_contract) => { - mpc_contract.add_signature(payload, signature); + mpc_contract.add_sig_result(payload, sign_result); } } } @@ -586,7 +585,7 @@ impl VersionedMpcContract { } } - fn signature_per_payload(&self, payload: [u8; 32]) -> Option> { + fn sign_result(&self, payload: [u8; 32]) -> Option> { match self { Self::V0(mpc_contract) => mpc_contract.pending_requests.get(&payload), } diff --git a/contract/src/primitives.rs b/contract/src/primitives.rs index da64800b6..358fc3395 100644 --- a/contract/src/primitives.rs +++ b/contract/src/primitives.rs @@ -207,3 +207,9 @@ impl PkVotes { self.votes.entry(public_key).or_default() } } + +#[derive(BorshDeserialize, BorshSerialize, Debug)] +pub struct SignResult { + pub big_r: String, + pub s: String, +} From 3fafe29904537d740d165be6c7259b4b10bca1cc Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 24 May 2024 15:23:11 +0000 Subject: [PATCH 2/9] SignResult traits --- contract/src/primitives.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/src/primitives.rs b/contract/src/primitives.rs index 358fc3395..65c3f42db 100644 --- a/contract/src/primitives.rs +++ b/contract/src/primitives.rs @@ -208,7 +208,7 @@ impl PkVotes { } } -#[derive(BorshDeserialize, BorshSerialize, Debug)] +#[derive(Serialize, Deserialize, BorshDeserialize, BorshSerialize, Debug)] pub struct SignResult { pub big_r: String, pub s: String, From e91c2d2e58e2b9d75f3e8cde02794d013ffb47dc Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 28 May 2024 12:32:13 +0300 Subject: [PATCH 3/9] typing fixed --- .../tests/multichain/actions/wait_for.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/integration-tests/tests/multichain/actions/wait_for.rs b/integration-tests/tests/multichain/actions/wait_for.rs index da98423a9..38c4f7c3c 100644 --- a/integration-tests/tests/multichain/actions/wait_for.rs +++ b/integration-tests/tests/multichain/actions/wait_for.rs @@ -14,6 +14,8 @@ use near_jsonrpc_client::methods::tx::TransactionInfo; use near_lake_primitives::CryptoHash; use near_primitives::views::FinalExecutionStatus; use near_workspaces::Account; +use serde::Deserialize; +use serde::Serialize; pub async fn running_mpc<'a>( ctx: &MultichainTestContext<'a>, @@ -199,6 +201,13 @@ pub async fn has_at_least_mine_presignatures<'a>( Ok(state_views) } +// TODO: use structur efrom contract one the internal types are the same +#[derive(Serialize, Deserialize, Debug)] +pub struct SignResult { + pub big_r: AffinePoint, + pub s: Scalar, +} + pub async fn signature_responded( ctx: &MultichainTestContext<'_>, tx_hash: CryptoHash, @@ -216,8 +225,11 @@ pub async fn signature_responded( let FinalExecutionStatus::SuccessValue(payload) = outcome_view.status else { anyhow::bail!("tx finished unsuccessfully: {:?}", outcome_view.status); }; - let (big_r, s): (AffinePoint, Scalar) = serde_json::from_slice(&payload)?; - let signature = cait_sith::FullSignature:: { big_r, s }; + let result: SignResult = serde_json::from_slice(&payload)?; + let signature = cait_sith::FullSignature:: { + big_r: result.big_r, + s: result.s, + }; Ok(signature) }; From b44f80d6087738b3fb76f27fd7e2164a3dc29bcd Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 28 May 2024 09:36:51 +0000 Subject: [PATCH 4/9] typed sign request --- contract/src/lib.rs | 83 ++++++++++++++++++++------------------ contract/src/primitives.rs | 7 ++++ 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/contract/src/lib.rs b/contract/src/lib.rs index 856e4e497..7ff942e64 100644 --- a/contract/src/lib.rs +++ b/contract/src/lib.rs @@ -6,7 +6,8 @@ use near_sdk::serde::{Deserialize, Serialize}; use near_sdk::{env, near_bindgen, AccountId, Promise, PromiseOrValue, PublicKey}; use near_sdk::{log, Gas}; use primitives::{ - CandidateInfo, Candidates, ParticipantInfo, Participants, PkVotes, SignResult, Votes, + CandidateInfo, Candidates, ParticipantInfo, Participants, PkVotes, SignRequest, SignResult, + Votes, }; use std::collections::{BTreeMap, HashSet}; @@ -64,35 +65,35 @@ impl Default for VersionedMpcContract { #[derive(BorshDeserialize, BorshSerialize, Debug)] pub struct MpcContract { protocol_state: ProtocolContractState, - pending_requests: LookupMap<[u8; 32], Option>, + pending_requests: LookupMap>, request_counter: u32, } impl MpcContract { - fn add_request(&mut self, payload: &[u8; 32], sign_result: &Option) { + fn add_request(&mut self, request: &SignRequest, sign_result: &Option) { if self.request_counter > 8 { env::panic_str("Too many pending requests. Please, try again later."); } - if !self.pending_requests.contains_key(payload) { + if !self.pending_requests.contains_key(request) { self.request_counter += 1; } - self.pending_requests.insert(payload, sign_result); + self.pending_requests.insert(request, sign_result); } - fn remove_request(&mut self, payload: &[u8; 32]) { - self.pending_requests.remove(payload); + fn remove_request(&mut self, request: &SignRequest) { + self.pending_requests.remove(request); self.request_counter -= 1; } - fn add_sig_result(&mut self, payload: &[u8; 32], sign_result: SignResult) { - if self.pending_requests.contains_key(payload) { - self.pending_requests.insert(payload, &Some(sign_result)); + fn add_sig_result(&mut self, request: &SignRequest, sign_result: SignResult) { + if self.pending_requests.contains_key(request) { + self.pending_requests.insert(request, &Some(sign_result)); } } - fn clean_payloads(&mut self, payloads: Vec<[u8; 32]>, counter: u32) { + fn clean_payloads(&mut self, requests: Vec, counter: u32) { log!("clean_payloads"); - for payload in payloads.iter() { + for payload in requests.iter() { self.pending_requests.remove(payload); } self.request_counter = counter; @@ -116,10 +117,10 @@ impl MpcContract { impl VersionedMpcContract { #[allow(unused_variables)] /// `key_version` must be less than or equal to the value at `latest_key_version` - pub fn sign(&mut self, payload: [u8; 32], path: String, key_version: u32) -> Promise { + pub fn sign(&mut self, request: SignRequest) -> Promise { let latest_key_version: u32 = self.latest_key_version(); assert!( - key_version <= latest_key_version, + request.key_version <= latest_key_version, "This version of the signer contract doesn't support versions greater than {}", latest_key_version, ); @@ -133,15 +134,15 @@ impl VersionedMpcContract { log!( "sign: signer={}, payload={:?}, path={:?}, key_version={}", env::signer_account_id(), - payload, - path, - key_version + request.payload, + request.path, + request.key_version ); - match self.sign_result(payload) { + match self.sign_result(&request) { None => { - self.add_sign_request(&payload, &None); + self.add_sign_request(&request, &None); log!(&serde_json::to_string(&near_sdk::env::random_seed_array()).unwrap()); - Self::ext(env::current_account_id()).sign_helper(payload, 0) + Self::ext(env::current_account_id()).sign_helper(request, 0) } Some(_) => env::panic_str("Signature for this payload already requested"), } @@ -173,20 +174,20 @@ impl VersionedMpcContract { // MPC Node API #[near_bindgen] impl VersionedMpcContract { - pub fn respond(&mut self, payload: [u8; 32], big_r: String, s: String) { + pub fn respond(&mut self, request: SignRequest, big_r: String, s: String) { // TODO: change to SignResult let protocol_state = self.mutable_state(); if let ProtocolContractState::Running(state) = protocol_state { let signer = env::signer_account_id(); if state.participants.contains_key(&signer) { log!( - "respond: signer={}, payload={:?} big_r={} s={}", + "respond: signer={}, request={:?} big_r={} s={}", signer, - payload, + request, big_r, s ); - self.add_sign_result(&payload, SignResult { big_r, s }); + self.add_sign_result(&request, SignResult { big_r, s }); } else { env::panic_str("only participants can respond"); } @@ -465,8 +466,12 @@ impl VersionedMpcContract { } #[private] - pub fn sign_helper(&mut self, payload: [u8; 32], depth: usize) -> PromiseOrValue { - if let Some(signature) = self.sign_result(payload) { + pub fn sign_helper( + &mut self, + request: SignRequest, + depth: usize, + ) -> PromiseOrValue { + if let Some(signature) = self.sign_result(&request) { match signature { Some(signature) => { log!( @@ -474,7 +479,7 @@ impl VersionedMpcContract { signature, depth ); - self.remove_sign_request(&payload); + self.remove_sign_request(&request); PromiseOrValue::Value(signature) } None => { @@ -483,7 +488,7 @@ impl VersionedMpcContract { // We keep one call back so we can cleanup then call panic on the next call // Start cleaning up if there's less than 25 teragas left regardless of how deep you are. if depth > 30 || env::prepaid_gas() < Gas::from_tgas(25) { - self.remove_sign_request(&payload); + self.remove_sign_request(&request); let self_id = env::current_account_id(); PromiseOrValue::Promise(Self::ext(self_id).fail_helper( "Signature was not provided in time. Please, try again.".to_string(), @@ -495,7 +500,7 @@ impl VersionedMpcContract { )); let account_id = env::current_account_id(); PromiseOrValue::Promise( - Self::ext(account_id).sign_helper(payload, depth + 1), + Self::ext(account_id).sign_helper(request, depth + 1), ) } } @@ -532,10 +537,10 @@ impl VersionedMpcContract { } #[private] - pub fn clean_payloads(&mut self, payloads: Vec<[u8; 32]>, counter: u32) { + pub fn clean_payloads(&mut self, requests: Vec, counter: u32) { match self { Self::V0(mpc_contract) => { - mpc_contract.clean_payloads(payloads, counter); + mpc_contract.clean_payloads(requests, counter); } } } @@ -555,26 +560,26 @@ impl VersionedMpcContract { // Helper functions #[near_bindgen] impl VersionedMpcContract { - fn remove_sign_request(&mut self, payload: &[u8; 32]) { + fn remove_sign_request(&mut self, request: &SignRequest) { match self { Self::V0(mpc_contract) => { - mpc_contract.remove_request(payload); + mpc_contract.remove_request(request); } } } - fn add_sign_request(&mut self, payload: &[u8; 32], sign_result: &Option) { + fn add_sign_request(&mut self, request: &SignRequest, sign_result: &Option) { match self { Self::V0(mpc_contract) => { - mpc_contract.add_request(payload, sign_result); + mpc_contract.add_request(request, sign_result); } } } - fn add_sign_result(&mut self, payload: &[u8; 32], sign_result: SignResult) { + fn add_sign_result(&mut self, request: &SignRequest, sign_result: SignResult) { match self { Self::V0(mpc_contract) => { - mpc_contract.add_sig_result(payload, sign_result); + mpc_contract.add_sig_result(request, sign_result); } } } @@ -585,9 +590,9 @@ impl VersionedMpcContract { } } - fn sign_result(&self, payload: [u8; 32]) -> Option> { + fn sign_result(&self, request: &SignRequest) -> Option> { match self { - Self::V0(mpc_contract) => mpc_contract.pending_requests.get(&payload), + Self::V0(mpc_contract) => mpc_contract.pending_requests.get(request), } } } diff --git a/contract/src/primitives.rs b/contract/src/primitives.rs index 65c3f42db..5427032f9 100644 --- a/contract/src/primitives.rs +++ b/contract/src/primitives.rs @@ -208,6 +208,13 @@ impl PkVotes { } } +#[derive(Serialize, Deserialize, BorshDeserialize, BorshSerialize, Debug)] +pub struct SignRequest { + pub payload: [u8; 32], + pub path: String, + pub key_version: u32, +} + #[derive(Serialize, Deserialize, BorshDeserialize, BorshSerialize, Debug)] pub struct SignResult { pub big_r: String, From 7b1ac639dcf8477e61c8992b260d07af79a65a22 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 28 May 2024 12:57:16 +0300 Subject: [PATCH 5/9] merge conflict fix --- .../chain-signatures/tests/actions/wait_for.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/integration-tests/chain-signatures/tests/actions/wait_for.rs b/integration-tests/chain-signatures/tests/actions/wait_for.rs index 1e7d0bd40..8fb0f0a8a 100644 --- a/integration-tests/chain-signatures/tests/actions/wait_for.rs +++ b/integration-tests/chain-signatures/tests/actions/wait_for.rs @@ -233,22 +233,19 @@ pub async fn signature_responded( let Some(outcome) = outcome_view.final_execution_outcome else { anyhow::bail!("final execution outcome not available"); }; -<<<<<<< HEAD:integration-tests/tests/multichain/actions/wait_for.rs - let result: SignResult = serde_json::from_slice(&payload)?; - let signature = cait_sith::FullSignature:: { - big_r: result.big_r, - s: result.s, - }; -======= + let outcome = outcome.into_outcome(); let FinalExecutionStatus::SuccessValue(payload) = outcome.status else { anyhow::bail!("tx finished unsuccessfully: {:?}", outcome.status); }; - let (big_r, s): (AffinePoint, Scalar) = serde_json::from_slice(&payload)?; - let signature = cait_sith::FullSignature:: { big_r, s }; ->>>>>>> develop:integration-tests/chain-signatures/tests/actions/wait_for.rs + let result: SignResult = serde_json::from_slice(&payload)?; + let signature = cait_sith::FullSignature:: { + big_r: result.big_r, + s: result.s, + }; + Ok(signature) }; From 976f60dc1c86f73aa3d3015c2e568394969fd03e Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 28 May 2024 13:57:15 +0300 Subject: [PATCH 6/9] use struct when calling sign --- .vscode/settings.json | 1 + .../chain-signatures/tests/actions/mod.rs | 30 +++++++++++++++---- load-tests/src/multichain/mod.rs | 19 ++++++++++-- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d611c29b5..1cceca8ee 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,6 @@ "integration-tests/chain-signatures/Cargo.toml", "integration-tests/fastauth/Cargo.toml", "mpc-recovery/Cargo.toml", + "load-tests/Cargo.toml", ], } diff --git a/integration-tests/chain-signatures/tests/actions/mod.rs b/integration-tests/chain-signatures/tests/actions/mod.rs index c7ea89ee5..9f887eb67 100644 --- a/integration-tests/chain-signatures/tests/actions/mod.rs +++ b/integration-tests/chain-signatures/tests/actions/mod.rs @@ -21,6 +21,7 @@ use near_primitives::transaction::{Action, FunctionCallAction, Transaction}; use near_workspaces::Account; use rand::Rng; use secp256k1::XOnlyPublicKey; +use serde::{Deserialize, Serialize}; use std::time::Duration; @@ -31,6 +32,14 @@ use k256::{ PublicKey as K256PublicKey, }; +// TODO: use struct from contract +#[derive(Serialize, Deserialize, Debug)] +pub struct SignRequest { + pub payload: [u8; 32], + pub path: String, + pub key_version: u32, +} + pub async fn request_sign( ctx: &MultichainTestContext<'_>, ) -> anyhow::Result<([u8; 32], [u8; 32], Account, CryptoHash)> { @@ -48,6 +57,12 @@ pub async fn request_sign( .rpc_client .fetch_nonce(&signer.account_id, &signer.public_key) .await?; + + let request = SignRequest { + payload: payload_hashed, + path: "test".to_string(), + key_version: 0, + }; let tx_hash = ctx .jsonrpc_client .call(&RpcBroadcastTxAsyncRequest { @@ -60,9 +75,7 @@ pub async fn request_sign( actions: vec![Action::FunctionCall(Box::new(FunctionCallAction { method_name: "sign".to_string(), args: serde_json::to_vec(&serde_json::json!({ - "payload": payload_hashed, - "path": "test", - "key_version": 0, + "request": request, }))?, gas: 300_000_000_000_000, deposit: 0, @@ -118,6 +131,13 @@ pub async fn request_sign_non_random( .rpc_client .fetch_nonce(&signer.account_id, &signer.public_key) .await?; + + let request = SignRequest { + payload: payload_hashed, + path: "test".to_string(), + key_version: 0, + }; + let tx_hash = ctx .jsonrpc_client .call(&RpcBroadcastTxAsyncRequest { @@ -130,9 +150,7 @@ pub async fn request_sign_non_random( actions: vec![Action::FunctionCall(Box::new(FunctionCallAction { method_name: "sign".to_string(), args: serde_json::to_vec(&serde_json::json!({ - "payload": payload_hashed, - "path": "test", - "key_version": 0, + "request": request, }))?, gas: 300_000_000_000_000, deposit: 0, diff --git a/load-tests/src/multichain/mod.rs b/load-tests/src/multichain/mod.rs index e8125a4af..7b01d755c 100644 --- a/load-tests/src/multichain/mod.rs +++ b/load-tests/src/multichain/mod.rs @@ -10,9 +10,18 @@ use near_primitives::{ }; use rand::Rng; use reqwest::header::CONTENT_TYPE; +use serde::{Deserialize, Serialize}; use crate::fastauth::primitives::UserSession; +// TODO: declare this struct in one place and reuse it +#[derive(Serialize, Deserialize, Debug)] +pub struct SignRequest { + pub payload: [u8; 32], + pub path: String, + pub key_version: u32, +} + pub async fn multichain_sign(user: &mut GooseUser) -> TransactionResult { tracing::info!("multichain_sign"); @@ -42,6 +51,12 @@ pub async fn multichain_sign(user: &mut GooseUser) -> TransactionResult { let payload_hashed: [u8; 32] = rand::thread_rng().gen(); tracing::info!("requesting signature for: {:?}", payload_hashed); + let request = SignRequest { + payload: payload_hashed, + path: "test".to_string(), + key_version: 0, + }; + let transaction = Transaction { signer_id: session.near_account_id.clone(), public_key: session.fa_sk.public_key(), @@ -51,9 +66,7 @@ pub async fn multichain_sign(user: &mut GooseUser) -> TransactionResult { actions: vec![Action::FunctionCall(FunctionCallAction { method_name: "sign".to_string(), args: serde_json::to_vec(&serde_json::json!({ - "payload": payload_hashed, - "path": "test", - "key_version": 0, + "request": request, })) .unwrap(), gas: 300_000_000_000_000, From b0694a36c1da6f6c7bf01bcbb414c6e1c3a51f29 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 30 May 2024 18:23:30 +0300 Subject: [PATCH 7/9] use struct instead of payload on the ndoe --- contract/src/lib.rs | 10 ++--- load-tests/Cargo.lock | 72 ++++++---------------------------- node/src/indexer.rs | 14 +++---- node/src/protocol/message.rs | 5 ++- node/src/protocol/signature.rs | 63 ++++++++++++++--------------- 5 files changed, 58 insertions(+), 106 deletions(-) diff --git a/contract/src/lib.rs b/contract/src/lib.rs index fc6b6f4d5..3f29adebd 100644 --- a/contract/src/lib.rs +++ b/contract/src/lib.rs @@ -182,20 +182,18 @@ impl VersionedMpcContract { // MPC Node API #[near_bindgen] impl VersionedMpcContract { - pub fn respond(&mut self, request: SignRequest, big_r: String, s: String) { - // TODO: change to SignResult + pub fn respond(&mut self, request: SignRequest, result: SignResult) { let protocol_state = self.mutable_state(); if let ProtocolContractState::Running(state) = protocol_state { let signer = env::signer_account_id(); if state.participants.contains_key(&signer) { log!( - "respond: signer={}, request={:?} big_r={} s={}", + "respond: signer={}, request={:?} result:{:?}", signer, request, - big_r, - s + result ); - self.add_sign_result(&request, SignResult { big_r, s }); + self.add_sign_result(&request, result); } else { env::panic_str("only participants can respond"); } diff --git a/load-tests/Cargo.lock b/load-tests/Cargo.lock index aba47c8d4..ccf543eca 100644 --- a/load-tests/Cargo.lock +++ b/load-tests/Cargo.lock @@ -2836,7 +2836,7 @@ dependencies = [ "google-apis-common", "http", "hyper", - "hyper-rustls 0.24.2", + "hyper-rustls", "itertools 0.10.5", "mime", "serde", @@ -2856,7 +2856,7 @@ dependencies = [ "google-apis-common", "http", "hyper", - "hyper-rustls 0.24.2", + "hyper-rustls", "itertools 0.10.5", "mime", "serde", @@ -3191,21 +3191,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" -dependencies = [ - "http", - "hyper", - "log", - "rustls 0.20.9", - "rustls-native-certs", - "tokio", - "tokio-rustls 0.23.4", -] - [[package]] name = "hyper-rustls" version = "0.24.2" @@ -3216,10 +3201,10 @@ dependencies = [ "http", "hyper", "log", - "rustls 0.21.12", + "rustls", "rustls-native-certs", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls", ] [[package]] @@ -3971,7 +3956,7 @@ dependencies = [ "google-secretmanager1", "hex 0.4.3", "hyper", - "hyper-rustls 0.23.2", + "hyper-rustls", "jsonwebtoken", "lazy_static", "multi-party-eddsa", @@ -6780,7 +6765,7 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-rustls 0.24.2", + "hyper-rustls", "hyper-tls", "ipnet", "js-sys", @@ -6790,7 +6775,7 @@ dependencies = [ "once_cell", "percent-encoding 2.3.1", "pin-project-lite", - "rustls 0.21.12", + "rustls", "rustls-pemfile", "serde", "serde_json", @@ -6799,7 +6784,7 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls 0.24.1", + "tokio-rustls", "tokio-util 0.7.11", "tower-service", "url 2.5.0", @@ -6962,18 +6947,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" -dependencies = [ - "log", - "ring 0.16.20", - "sct", - "webpki", -] - [[package]] name = "rustls" version = "0.21.12" @@ -8101,24 +8074,13 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls 0.20.9", - "tokio", - "webpki", -] - [[package]] name = "tokio-rustls" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.12", + "rustls", "tokio", ] @@ -8621,7 +8583,7 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.21.12", + "rustls", "rustls-webpki", "url 2.5.0", "webpki-roots", @@ -9324,16 +9286,6 @@ dependencies = [ "url 2.5.0", ] -[[package]] -name = "webpki" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - [[package]] name = "webpki-roots" version = "0.25.4" @@ -9598,11 +9550,11 @@ dependencies = [ "futures", "http", "hyper", - "hyper-rustls 0.24.2", + "hyper-rustls", "itertools 0.10.5", "log", "percent-encoding 2.3.1", - "rustls 0.21.12", + "rustls", "rustls-pemfile", "seahash", "serde", diff --git a/node/src/indexer.rs b/node/src/indexer.rs index 02b339fc0..f4b9ef7a2 100644 --- a/node/src/indexer.rs +++ b/node/src/indexer.rs @@ -66,11 +66,11 @@ impl Options { } } -#[derive(Debug, Serialize, Deserialize)] -struct SignPayload { - payload: [u8; 32], - path: String, - key_version: u32, +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct ContractSignRequest { + pub payload: [u8; 32], + pub path: String, + pub key_version: u32, } #[derive(LakeContext)] @@ -101,7 +101,7 @@ async fn handle_block( if let Some(function_call) = action.as_function_call() { if function_call.method_name() == "sign" { if let Ok(sign_payload) = - serde_json::from_slice::<'_, SignPayload>(function_call.args()) + serde_json::from_slice::<'_, ContractSignRequest>(function_call.args()) { if receipt.logs().is_empty() { tracing::warn!("`sign` did not produce entropy"); @@ -130,7 +130,7 @@ async fn handle_block( let mut queue = ctx.queue.write().await; queue.add(SignRequest { receipt_id, - msg_hash: sign_payload.payload, + request: sign_payload, epsilon, delta, entropy, diff --git a/node/src/protocol/message.rs b/node/src/protocol/message.rs index 5864a8d57..2328a04b9 100644 --- a/node/src/protocol/message.rs +++ b/node/src/protocol/message.rs @@ -4,6 +4,7 @@ use super::state::{GeneratingState, NodeState, ResharingState, RunningState}; use super::triple::TripleId; use crate::gcp::error::SecretStorageError; use crate::http_client::SendError; +use crate::indexer::ContractSignRequest; use crate::mesh::Mesh; use crate::util; @@ -65,7 +66,7 @@ pub struct SignatureMessage { pub receipt_id: CryptoHash, pub proposer: Participant, pub presignature_id: PresignatureId, - pub msg_hash: [u8; 32], + pub request: ContractSignRequest, pub epsilon: Scalar, pub delta: Scalar, pub epoch: u64, @@ -347,7 +348,7 @@ impl MessageHandler for RunningState { *receipt_id, message.proposer, message.presignature_id, - message.msg_hash, + message.request.clone(), message.epsilon, message.delta, &mut presignature_manager, diff --git a/node/src/protocol/signature.rs b/node/src/protocol/signature.rs index 3e5be85ab..e59020e3f 100644 --- a/node/src/protocol/signature.rs +++ b/node/src/protocol/signature.rs @@ -1,6 +1,7 @@ use super::contract::primitives::Participants; use super::message::SignatureMessage; use super::presignature::{Presignature, PresignatureId, PresignatureManager}; +use crate::indexer::ContractSignRequest; use crate::kdf; use crate::types::{PublicKey, SignatureProtocol}; use crate::util::{AffinePointExt, ScalarExt}; @@ -25,7 +26,7 @@ pub const COMPLETION_EXISTENCE_TIMEOUT: Duration = Duration::from_secs(120 * 60) pub struct SignRequest { pub receipt_id: CryptoHash, - pub msg_hash: [u8; 32], + pub request: ContractSignRequest, pub epsilon: Scalar, pub delta: Scalar, pub entropy: [u8; 32], @@ -54,7 +55,7 @@ impl SignQueue { pub fn add(&mut self, request: SignRequest) { tracing::info!( receipt_id = %request.receipt_id, - payload = hex::encode(request.msg_hash), + payload = hex::encode(request.request.payload), entropy = hex::encode(request.entropy), "new sign request" ); @@ -115,7 +116,7 @@ pub struct SignatureGenerator { pub participants: Vec, pub proposer: Participant, pub presignature_id: PresignatureId, - pub msg_hash: [u8; 32], + pub request: ContractSignRequest, pub epsilon: Scalar, pub delta: Scalar, pub sign_request_timestamp: Instant, @@ -129,7 +130,7 @@ impl SignatureGenerator { participants: Vec, proposer: Participant, presignature_id: PresignatureId, - msg_hash: [u8; 32], + request: ContractSignRequest, epsilon: Scalar, delta: Scalar, sign_request_timestamp: Instant, @@ -139,7 +140,7 @@ impl SignatureGenerator { participants, proposer, presignature_id, - msg_hash, + request, epsilon, delta, sign_request_timestamp, @@ -163,7 +164,7 @@ impl SignatureGenerator { /// for starting up this failed signature once again. pub struct GenerationRequest { pub proposer: Participant, - pub msg_hash: [u8; 32], + pub request: ContractSignRequest, pub epsilon: Scalar, pub delta: Scalar, pub sign_request_timestamp: Instant, @@ -177,8 +178,13 @@ pub struct SignatureManager { /// Set of completed signatures completed: HashMap, /// Generated signatures assigned to the current node that are yet to be published. - /// Vec<(receipt_id, msg_hash, timestamp, output)> - signatures: Vec<(CryptoHash, [u8; 32], Instant, FullSignature)>, + /// Vec<(receipt_id, sign_request, timestamp, output)> + signatures: Vec<( + CryptoHash, + ContractSignRequest, + Instant, + FullSignature, + )>, me: Participant, public_key: PublicKey, epoch: u64, @@ -216,7 +222,7 @@ impl SignatureManager { let participants = participants.keys_vec(); let GenerationRequest { proposer, - msg_hash, + request, epsilon, delta, sign_request_timestamp, @@ -233,14 +239,14 @@ impl SignatureManager { me, kdf::derive_key(public_key, epsilon), output, - Scalar::from_bytes(&msg_hash), + Scalar::from_bytes(&request.payload), )?); Ok(SignatureGenerator::new( protocol, participants, proposer, presignature.id, - msg_hash, + request, epsilon, delta, sign_request_timestamp, @@ -268,7 +274,7 @@ impl SignatureManager { participants: &Participants, receipt_id: CryptoHash, presignature: Presignature, - msg_hash: [u8; 32], + request: ContractSignRequest, epsilon: Scalar, delta: Scalar, sign_request_timestamp: Instant, @@ -287,7 +293,7 @@ impl SignatureManager { presignature, GenerationRequest { proposer: self.me, - msg_hash, + request, epsilon, delta, sign_request_timestamp, @@ -310,7 +316,7 @@ impl SignatureManager { receipt_id: CryptoHash, proposer: Participant, presignature_id: PresignatureId, - msg_hash: [u8; 32], + request: ContractSignRequest, epsilon: Scalar, delta: Scalar, presignature_manager: &mut PresignatureManager, @@ -330,7 +336,7 @@ impl SignatureManager { presignature, GenerationRequest { proposer, - msg_hash, + request, epsilon, delta, sign_request_timestamp: Instant::now(), @@ -362,7 +368,7 @@ impl SignatureManager { *receipt_id, GenerationRequest { proposer: generator.proposer, - msg_hash: generator.msg_hash, + request: generator.request.clone(), epsilon: generator.epsilon, delta: generator.delta, sign_request_timestamp: generator.sign_request_timestamp @@ -386,7 +392,7 @@ impl SignatureManager { receipt_id: *receipt_id, proposer: generator.proposer, presignature_id: generator.presignature_id, - msg_hash: generator.msg_hash, + request: generator.request.clone(), epsilon: generator.epsilon, delta: generator.delta, epoch: self.epoch, @@ -403,7 +409,7 @@ impl SignatureManager { receipt_id: *receipt_id, proposer: generator.proposer, presignature_id: generator.presignature_id, - msg_hash: generator.msg_hash, + request: generator.request.clone(), epsilon: generator.epsilon, delta: generator.delta, epoch: self.epoch, @@ -424,7 +430,7 @@ impl SignatureManager { self.completed.insert(generator.presignature_id, Instant::now()); if generator.proposer == self.me { self.signatures - .push((*receipt_id, generator.msg_hash, generator.sign_request_timestamp, output)); + .push((*receipt_id, generator.request.clone(), generator.sign_request_timestamp, output)); } // Do not retain the protocol return false; @@ -491,7 +497,7 @@ impl SignatureManager { &sig_participants, receipt_id, presignature, - my_request.msg_hash, + my_request.request, my_request.epsilon, my_request.delta, my_request.time_added, @@ -514,20 +520,15 @@ impl SignatureManager { mpc_contract_id: &AccountId, my_account_id: &AccountId, ) -> Result<(), near_fetch::Error> { - for (receipt_id, payload, time_added, signature) in self.signatures.drain(..) { - // TODO: Figure out how to properly serialize the signature - // let r_s = signature.big_r.x().concat(signature.s.to_bytes()); - // let tag = - // ConditionallySelectable::conditional_select(&2u8, &3u8, signature.big_r.y_is_odd()); - // let signature = r_s.append(tag); - // let signature = Secp256K1Signature::try_from(signature.as_slice()).unwrap(); - // let signature = Signature::SECP256K1(signature); + for (receipt_id, request, time_added, signature) in self.signatures.drain(..) { let response = rpc_client .call(signer, mpc_contract_id, "respond") .args_json(serde_json::json!({ - "payload": payload, - "big_r": signature.big_r, - "s": signature.s + "request": request, + "result": { + "big_r": signature.big_r, + "s": signature.s, + }, })) .max_gas() .transact() From 317d879eec8624f892f353f6c4d7190878eaec2c Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 30 May 2024 20:25:41 +0300 Subject: [PATCH 8/9] args fix --- node/src/indexer.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/node/src/indexer.rs b/node/src/indexer.rs index f4b9ef7a2..5dd1758fb 100644 --- a/node/src/indexer.rs +++ b/node/src/indexer.rs @@ -66,6 +66,11 @@ impl Options { } } +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct SignArguments { + pub request: ContractSignRequest, +} + #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct ContractSignRequest { pub payload: [u8; 32], @@ -100,8 +105,8 @@ async fn handle_block( }; if let Some(function_call) = action.as_function_call() { if function_call.method_name() == "sign" { - if let Ok(sign_payload) = - serde_json::from_slice::<'_, ContractSignRequest>(function_call.args()) + if let Ok(aruments) = + serde_json::from_slice::<'_, SignArguments>(function_call.args()) { if receipt.logs().is_empty() { tracing::warn!("`sign` did not produce entropy"); @@ -116,21 +121,21 @@ async fn handle_block( continue; }; let epsilon = - kdf::derive_epsilon(&action.predecessor_id(), &sign_payload.path); + kdf::derive_epsilon(&action.predecessor_id(), &aruments.request.path); let delta = kdf::derive_delta(receipt_id, entropy); tracing::info!( receipt_id = %receipt_id, caller_id = receipt.predecessor_id().to_string(), our_account = ctx.node_account_id.to_string(), - payload = hex::encode(sign_payload.payload), - key_version = sign_payload.key_version, + payload = hex::encode(aruments.request.payload), + key_version = aruments.request.key_version, entropy = hex::encode(entropy), "indexed new `sign` function call" ); let mut queue = ctx.queue.write().await; queue.add(SignRequest { receipt_id, - request: sign_payload, + request: aruments.request, epsilon, delta, entropy, From 98dabae2b4271fce42dd459a09697d723b99c55d Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 30 May 2024 20:45:00 +0300 Subject: [PATCH 9/9] redundant structs removed --- .../chain-signatures/tests/actions/mod.rs | 10 +--------- .../chain-signatures/tests/actions/wait_for.rs | 2 +- load-tests/src/multichain/mod.rs | 1 - 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/integration-tests/chain-signatures/tests/actions/mod.rs b/integration-tests/chain-signatures/tests/actions/mod.rs index 9f887eb67..4fea333e3 100644 --- a/integration-tests/chain-signatures/tests/actions/mod.rs +++ b/integration-tests/chain-signatures/tests/actions/mod.rs @@ -11,6 +11,7 @@ use k256::elliptic_curve::scalar::FromUintUnchecked; use k256::elliptic_curve::sec1::FromEncodedPoint; use k256::elliptic_curve::ProjectivePoint; use k256::{AffinePoint, EncodedPoint, Scalar, Secp256k1}; +use mpc_contract::primitives::SignRequest; use mpc_contract::RunningContractState; use mpc_recovery_node::kdf; use mpc_recovery_node::util::ScalarExt; @@ -21,7 +22,6 @@ use near_primitives::transaction::{Action, FunctionCallAction, Transaction}; use near_workspaces::Account; use rand::Rng; use secp256k1::XOnlyPublicKey; -use serde::{Deserialize, Serialize}; use std::time::Duration; @@ -32,14 +32,6 @@ use k256::{ PublicKey as K256PublicKey, }; -// TODO: use struct from contract -#[derive(Serialize, Deserialize, Debug)] -pub struct SignRequest { - pub payload: [u8; 32], - pub path: String, - pub key_version: u32, -} - pub async fn request_sign( ctx: &MultichainTestContext<'_>, ) -> anyhow::Result<([u8; 32], [u8; 32], Account, CryptoHash)> { diff --git a/integration-tests/chain-signatures/tests/actions/wait_for.rs b/integration-tests/chain-signatures/tests/actions/wait_for.rs index 8fb0f0a8a..8c03009c9 100644 --- a/integration-tests/chain-signatures/tests/actions/wait_for.rs +++ b/integration-tests/chain-signatures/tests/actions/wait_for.rs @@ -205,7 +205,7 @@ pub async fn has_at_least_mine_presignatures<'a>( Ok(state_views) } -// TODO: use structur efrom contract one the internal types are the same +// TODO: use structure from contract when the internal types are the same #[derive(Serialize, Deserialize, Debug)] pub struct SignResult { pub big_r: AffinePoint, diff --git a/load-tests/src/multichain/mod.rs b/load-tests/src/multichain/mod.rs index 7b01d755c..e49472b91 100644 --- a/load-tests/src/multichain/mod.rs +++ b/load-tests/src/multichain/mod.rs @@ -14,7 +14,6 @@ use serde::{Deserialize, Serialize}; use crate::fastauth::primitives::UserSession; -// TODO: declare this struct in one place and reuse it #[derive(Serialize, Deserialize, Debug)] pub struct SignRequest { pub payload: [u8; 32],