From 0d346e0858cd4922e9c17235dadf5bc1a292e552 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 7 Jun 2024 22:29:04 +0300 Subject: [PATCH 1/4] plan --- chain-signatures/node/src/indexer.rs | 12 ++++++++++++ integration-tests/chain-signatures/src/utils.rs | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index 73b78ca6f..aec1ce654 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -87,10 +87,22 @@ struct Context { latest_block_height: Arc>, } +// TODO: +// 1. Spin LC docker image in tests, propagate IP address +// 2. Get a result from it in code +// 3. Make sure the flow is valid and actually making sure data is fine +// 4. Add Terraform config and other staff to run it in VMs + async fn handle_block( mut block: near_lake_primitives::block::Block, ctx: &Context, ) -> anyhow::Result<()> { + // Check block integrity/hash + // TODO + // Get proof using light client (internally - RPC): /proof TransactionOrReceiptId -> head_block_root: CryptoHash, proof: Box, (proof is RpcLightClientExecutionProofResponse) + // TODO + // Verify proof: /proof/verify head_block_root: CryptoHash, proof: Box -> bool + // TODO for action in block.actions().cloned().collect::>() { if action.receiver_id() == ctx.mpc_contract_id { let receipt = diff --git a/integration-tests/chain-signatures/src/utils.rs b/integration-tests/chain-signatures/src/utils.rs index 4691c17d3..07ab0cf72 100644 --- a/integration-tests/chain-signatures/src/utils.rs +++ b/integration-tests/chain-signatures/src/utils.rs @@ -1,5 +1,7 @@ use anyhow::Context; use hyper::{Body, Client, Method, Request, StatusCode, Uri}; +use near_lake_primitives::CryptoHash; +use near_primitives::types::TransactionOrReceiptId; use near_workspaces::result::ExecutionFinalResult; use near_workspaces::{Account, AccountId}; @@ -99,3 +101,12 @@ pub async fn ping_until_ok(addr: &str, timeout: u64) -> anyhow::Result<()> { .await?; Ok(()) } + +// TODO: Declare simlified types or import them from protocol trait +pub async fn get_proof(addr: &str, id: TransactionOrReceiptId) -> anyhow::Result { + todo!() +} + +pub async fn verify_proof(addr: &str, proof: Proof) -> anyhow::Result { + todo!() +} From 416d8a0dab5ea6b92cc8d931f50596b25b4ca2e4 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 11 Jun 2024 15:17:41 +0300 Subject: [PATCH 2/4] LightClient docker image added in tests --- .../chain-signatures/src/containers.rs | 70 +++++++++++++++++++ integration-tests/chain-signatures/src/lib.rs | 11 +++ .../chain-signatures/src/utils.rs | 12 ++-- 3 files changed, 87 insertions(+), 6 deletions(-) diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index 63275a103..e41f90b09 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -352,6 +352,76 @@ impl<'a> LakeIndexer<'a> { } } +pub struct LightClient<'a> { + pub container: Container<'a, GenericImage>, + pub bucket_name: String, // TODO: Do we need this? + pub region: String, // TODO: Do we need this? + pub address: String, + pub host_address: String, + // TODO: any additional fields? +} + +impl<'a> LightClient<'a> { + pub const CONTAINER_RPC_PORT: u16 = 3031; // TODO: is this port ok? + + pub async fn run( + docker_client: &'a DockerClient, + network: &str, + bucket_name: String, + region: String, + ) -> anyhow::Result> { + tracing::info!( + network, + bucket_name, + region, + "running LightClient container..." + ); + + let image = GenericImage::new("ghcr.io/near/near-light-client/light-client", "f4ce326d9c2a6728e8bc39b4d8720f81be87dc43") // TODO: deploy and update docker image version + // .with_env_var("AWS_ACCESS_KEY_ID", "FAKE_LOCALSTACK_KEY_ID") // Replace with LightCLient specific env vars if any + // .with_env_var("AWS_SECRET_ACCESS_KEY", "FAKE_LOCALSTACK_ACCESS_KEY") + .with_wait_for(WaitFor::message_on_stderr("Starting Streamer")) // TODO: replace with message from LightClient + .with_exposed_port(Self::CONTAINER_RPC_PORT); + let image: RunnableImage = ( + image, + vec![ + "--bucket".to_string(), // TODO: check if we need these args, what args do we need? + bucket_name.clone(), + "--region".to_string(), + region.clone(), + "--stream-while-syncing".to_string(), + "sync-from-latest".to_string(), + ], + ) + .into(); + let image = image.with_network(network); + let container = docker_client.cli.run(image); + let address = docker_client + .get_network_ip_address(&container, network) + .await?; + + // TODO: check address and host_port, is it what we need? + let address = format!("http://{}:{}", address, Self::CONTAINER_RPC_PORT); + let host_port = container.get_host_port_ipv4(Self::CONTAINER_RPC_PORT); + let host_address = format!("http://127.0.0.1:{host_port}"); + + tracing::info!( + bucket_name, + region, + address, + host_address, + "NEAR Lake Indexer container is running" + ); + Ok(LightClient { + container, + bucket_name, + region, + address, + host_address, + }) + } +} + pub struct DockerClient { pub docker: Docker, pub cli: Cli, diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index c4b12dc19..cdf0656e8 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -11,6 +11,7 @@ use crate::containers::LocalStack; use anyhow::Context as _; use bollard::exec::{CreateExecOptions, StartExecResults}; +use containers::LightClient; use futures::StreamExt; use mpc_contract::primitives::CandidateInfo; use mpc_recovery_node::gcp::GcpService; @@ -227,6 +228,7 @@ pub struct Context<'a> { pub mpc_contract: Contract, pub datastore: crate::containers::Datastore<'a>, pub storage_options: storage::Options, + pub light_client: LightClient<'a>, } pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> { @@ -240,6 +242,14 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> worker, } = initialize_lake_indexer(docker_client, docker_network).await?; + // TODO: should it be moved to LakeIndexerCtx? + let light_client = LightClient::run( + docker_client, + docker_network, + "bucket name".to_owned(), + "region".to_owned() + ).await?; + let mpc_contract = worker .dev_deploy(&std::fs::read( execute::target_dir() @@ -271,6 +281,7 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> mpc_contract, datastore, storage_options, + light_client, }) } diff --git a/integration-tests/chain-signatures/src/utils.rs b/integration-tests/chain-signatures/src/utils.rs index 07ab0cf72..1cf01861e 100644 --- a/integration-tests/chain-signatures/src/utils.rs +++ b/integration-tests/chain-signatures/src/utils.rs @@ -103,10 +103,10 @@ pub async fn ping_until_ok(addr: &str, timeout: u64) -> anyhow::Result<()> { } // TODO: Declare simlified types or import them from protocol trait -pub async fn get_proof(addr: &str, id: TransactionOrReceiptId) -> anyhow::Result { - todo!() -} +// pub async fn get_proof(addr: &str, id: TransactionOrReceiptId) -> anyhow::Result { +// todo!() +// } -pub async fn verify_proof(addr: &str, proof: Proof) -> anyhow::Result { - todo!() -} +// pub async fn verify_proof(addr: &str, proof: Proof) -> anyhow::Result { +// todo!() +// } From aad8e9e0608b77ace9958fcdc5abf80b960b81cf Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 11 Jun 2024 19:19:58 +0300 Subject: [PATCH 3/4] add light client address in node paramaters --- chain-signatures/node/src/cli.rs | 23 ++++++++++++++++++++++- chain-signatures/node/src/indexer.rs | 6 ++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index 3d5c4f1e1..a345adf7b 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -26,6 +26,13 @@ pub enum Cli { default_value("https://rpc.testnet.near.org") )] near_rpc: String, + /// Light client address + #[arg( + long, + env("MPC_RECOVERY_LIGHT_CLIENT_ADDR"), + default_value("http://localhost:3030") + )] + light_client_addr: String, /// MPC contract id #[arg( long, @@ -101,6 +108,7 @@ impl Cli { match self { Cli::Start { near_rpc, + light_client_addr, account_id, mpc_contract_id, account_sk, @@ -122,6 +130,8 @@ impl Cli { "start".to_string(), "--near-rpc".to_string(), near_rpc, + "--light-client-addr".to_string(), + light_client_addr, "--mpc-contract-id".to_string(), mpc_contract_id.to_string(), "--account-id".to_string(), @@ -178,6 +188,7 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { Cli::Start { near_rpc, web_port, + light_client_addr, mpc_contract_id, account_id, account_sk, @@ -208,7 +219,17 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { let account_id = account_id.clone(); let sign_queue = sign_queue.clone(); let gcp = gcp_service.clone(); - move || indexer::run(options, mpc_id, account_id, sign_queue, gcp).unwrap() + move || { + indexer::run( + options, + mpc_id, + account_id, + Url::parse(&light_client_addr).unwrap(), + sign_queue, + gcp, + ) + .unwrap() + } }); let key_storage = storage::secret_storage::init( diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index aec1ce654..f12bceb1d 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -12,6 +12,7 @@ use serde::{Deserialize, Serialize}; use std::sync::Arc; use std::time::Instant; use tokio::sync::RwLock; +use url::Url; /// Configures indexer. #[derive(Debug, Clone, clap::Parser)] @@ -82,6 +83,7 @@ pub struct ContractSignRequest { struct Context { mpc_contract_id: AccountId, node_account_id: AccountId, + light_client_addr: Url, gcp_service: GcpService, queue: Arc>, latest_block_height: Arc>, @@ -97,6 +99,8 @@ async fn handle_block( mut block: near_lake_primitives::block::Block, ctx: &Context, ) -> anyhow::Result<()> { + // log light client address + tracing::info!(light_client_addr = ctx.light_client_addr.as_str(), "lignt client address"); // Check block integrity/hash // TODO // Get proof using light client (internally - RPC): /proof TransactionOrReceiptId -> head_block_root: CryptoHash, proof: Box, (proof is RpcLightClientExecutionProofResponse) @@ -184,6 +188,7 @@ pub fn run( options: Options, mpc_contract_id: AccountId, node_account_id: AccountId, + light_client_addr: Url, queue: Arc>, gcp_service: crate::gcp::GcpService, ) -> anyhow::Result<()> { @@ -230,6 +235,7 @@ pub fn run( let context = Context { mpc_contract_id, node_account_id, + light_client_addr, gcp_service, queue, latest_block_height: Arc::new(RwLock::new(latest_block_height)), From c7906a144ce021ae715905380050d1b6edaa8ef8 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 12 Jun 2024 16:28:36 +0300 Subject: [PATCH 4/4] light client passed in tests --- chain-signatures/node/src/indexer.rs | 5 ++++- .../chain-signatures/src/containers.rs | 17 +++++++++++------ integration-tests/chain-signatures/src/lib.rs | 5 +++-- integration-tests/chain-signatures/src/local.rs | 2 ++ integration-tests/chain-signatures/src/utils.rs | 16 ++++++++-------- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index f12bceb1d..4621f5793 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -100,7 +100,10 @@ async fn handle_block( ctx: &Context, ) -> anyhow::Result<()> { // log light client address - tracing::info!(light_client_addr = ctx.light_client_addr.as_str(), "lignt client address"); + tracing::info!( + light_client_addr = ctx.light_client_addr.as_str(), + "lignt client address" + ); // Check block integrity/hash // TODO // Get proof using light client (internally - RPC): /proof TransactionOrReceiptId -> head_block_root: CryptoHash, proof: Box, (proof is RpcLightClientExecutionProofResponse) diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index e41f90b09..63842d9d6 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -55,6 +55,7 @@ impl<'a> Node<'a> { }; let args = mpc_recovery_node::cli::Cli::Start { near_rpc: near_rpc.clone(), + light_client_addr: ctx.light_client.address.clone(), mpc_contract_id: mpc_contract_id.clone(), account_id: account_id.clone(), account_sk: account_sk.to_string().parse()?, @@ -142,6 +143,7 @@ impl<'a> Node<'a> { near_crypto::SecretKey::from_seed(near_crypto::KeyType::ED25519, "integration-test"); let args = mpc_recovery_node::cli::Cli::Start { near_rpc: near_rpc.clone(), + light_client_addr: ctx.light_client.address.clone(), mpc_contract_id: mpc_contract_id.clone(), account_id: account_id.clone(), account_sk: account_sk.to_string().parse()?, @@ -355,7 +357,7 @@ impl<'a> LakeIndexer<'a> { pub struct LightClient<'a> { pub container: Container<'a, GenericImage>, pub bucket_name: String, // TODO: Do we need this? - pub region: String, // TODO: Do we need this? + pub region: String, // TODO: Do we need this? pub address: String, pub host_address: String, // TODO: any additional fields? @@ -377,11 +379,14 @@ impl<'a> LightClient<'a> { "running LightClient container..." ); - let image = GenericImage::new("ghcr.io/near/near-light-client/light-client", "f4ce326d9c2a6728e8bc39b4d8720f81be87dc43") // TODO: deploy and update docker image version - // .with_env_var("AWS_ACCESS_KEY_ID", "FAKE_LOCALSTACK_KEY_ID") // Replace with LightCLient specific env vars if any - // .with_env_var("AWS_SECRET_ACCESS_KEY", "FAKE_LOCALSTACK_ACCESS_KEY") - .with_wait_for(WaitFor::message_on_stderr("Starting Streamer")) // TODO: replace with message from LightClient - .with_exposed_port(Self::CONTAINER_RPC_PORT); + let image = GenericImage::new( + "ghcr.io/near/near-light-client/light-client", + "f4ce326d9c2a6728e8bc39b4d8720f81be87dc43", + ) // TODO: deploy and update docker image version + // .with_env_var("AWS_ACCESS_KEY_ID", "FAKE_LOCALSTACK_KEY_ID") // Replace with LightCLient specific env vars if any + // .with_env_var("AWS_SECRET_ACCESS_KEY", "FAKE_LOCALSTACK_ACCESS_KEY") + .with_wait_for(WaitFor::message_on_stderr("Starting Streamer")) // TODO: replace with message from LightClient + .with_exposed_port(Self::CONTAINER_RPC_PORT); let image: RunnableImage = ( image, vec![ diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index cdf0656e8..9df452c30 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -247,8 +247,9 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> docker_client, docker_network, "bucket name".to_owned(), - "region".to_owned() - ).await?; + "region".to_owned(), + ) + .await?; let mpc_contract = worker .dev_deploy(&std::fs::read( diff --git a/integration-tests/chain-signatures/src/local.rs b/integration-tests/chain-signatures/src/local.rs index 92ae63cc2..0bfdcb8e5 100644 --- a/integration-tests/chain-signatures/src/local.rs +++ b/integration-tests/chain-signatures/src/local.rs @@ -50,6 +50,7 @@ impl Node { let mpc_contract_id = ctx.mpc_contract.id().clone(); let cli = mpc_recovery_node::cli::Cli::Start { near_rpc: near_rpc.clone(), + light_client_addr: ctx.light_client.address.clone(), mpc_contract_id: mpc_contract_id.clone(), account_id: account_id.clone(), account_sk: account_sk.to_string().parse()?, @@ -108,6 +109,7 @@ impl Node { let mpc_contract_id = ctx.mpc_contract.id().clone(); let cli = mpc_recovery_node::cli::Cli::Start { near_rpc: near_rpc.clone(), + light_client_addr: ctx.light_client.address.clone(), mpc_contract_id: mpc_contract_id.clone(), account_id: account_id.clone(), account_sk: account_sk.to_string().parse()?, diff --git a/integration-tests/chain-signatures/src/utils.rs b/integration-tests/chain-signatures/src/utils.rs index 1cf01861e..b26377890 100644 --- a/integration-tests/chain-signatures/src/utils.rs +++ b/integration-tests/chain-signatures/src/utils.rs @@ -1,6 +1,5 @@ use anyhow::Context; use hyper::{Body, Client, Method, Request, StatusCode, Uri}; -use near_lake_primitives::CryptoHash; use near_primitives::types::TransactionOrReceiptId; use near_workspaces::result::ExecutionFinalResult; use near_workspaces::{Account, AccountId}; @@ -102,11 +101,12 @@ pub async fn ping_until_ok(addr: &str, timeout: u64) -> anyhow::Result<()> { Ok(()) } -// TODO: Declare simlified types or import them from protocol trait -// pub async fn get_proof(addr: &str, id: TransactionOrReceiptId) -> anyhow::Result { -// todo!() -// } +pub struct Proof {} -// pub async fn verify_proof(addr: &str, proof: Proof) -> anyhow::Result { -// todo!() -// } +pub async fn get_proof(_addr: &str, _id: TransactionOrReceiptId) -> anyhow::Result { + todo!() +} + +pub async fn verify_proof(_addr: &str, _proof: Proof) -> anyhow::Result { + todo!() +}