diff --git a/Cargo.lock b/Cargo.lock index 0aaf4c0dbb..613aaa31d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8437,6 +8437,7 @@ version = "0.4.2" dependencies = [ "async-trait", "base64 0.22.0", + "blockprod", "chainstate", "chainstate-storage", "common", @@ -8482,6 +8483,7 @@ version = "0.4.2" dependencies = [ "anyhow", "async-trait", + "blockprod", "chainstate", "clap", "common", diff --git a/node-gui/src/backend/backend_impl.rs b/node-gui/src/backend/backend_impl.rs index 5937d9f434..6f00baffa3 100644 --- a/node-gui/src/backend/backend_impl.rs +++ b/node-gui/src/backend/backend_impl.rs @@ -1341,7 +1341,7 @@ async fn select_acc_and_execute_cmd( c: &mut CommandHandler>, account_id: AccountId, command: ManageableWalletCommand, - chain_config: &ChainConfig, + chain_config: &Arc, ) -> Result where N: NodeInterface + Clone + Send + Sync + 'static + Debug, diff --git a/wallet/wallet-cli-commands/Cargo.toml b/wallet/wallet-cli-commands/Cargo.toml index fcb18049e8..885711a661 100644 --- a/wallet/wallet-cli-commands/Cargo.toml +++ b/wallet/wallet-cli-commands/Cargo.toml @@ -8,6 +8,7 @@ rust-version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +blockprod = { path = "../../blockprod" } chainstate = { path = "../../chainstate" } common = { path = "../../common" } consensus = { path = "../../consensus" } diff --git a/wallet/wallet-cli-commands/src/command_handler/mod.rs b/wallet/wallet-cli-commands/src/command_handler/mod.rs index 591c53b412..70b9179730 100644 --- a/wallet/wallet-cli-commands/src/command_handler/mod.rs +++ b/wallet/wallet-cli-commands/src/command_handler/mod.rs @@ -15,7 +15,7 @@ mod local_state; -use std::{fmt::Write, str::FromStr}; +use std::{fmt::Write, str::FromStr, sync::Arc}; use common::{ address::Address, @@ -26,10 +26,12 @@ use common::{ primitives::H256, text_summary::TextSummary, }; -use crypto::key::hdkd::u31::U31; +use consensus::PoSTimestampSearchInputData; +use crypto::{ephemeral_e2e::EndToEndPrivateKey, key::hdkd::u31::U31}; use itertools::Itertools; use mempool::tx_options::TxOptionsOverrides; use node_comm::node_traits::NodeInterface; +use randomness::make_true_rng; use serialization::{hex::HexEncode, hex_encoded::HexEncoded}; use utils::qrcode::{QrCode, QrCodeError}; use wallet::{account::PartiallySignedTransaction, version::get_version}; @@ -646,7 +648,7 @@ where pub async fn handle_wallet_command( &mut self, - chain_config: &ChainConfig, + chain_config: &Arc, command: WalletCommand, ) -> Result> where @@ -716,17 +718,43 @@ where seconds_to_check_for_height, check_all_timestamps_between_blocks, } => { - let timestamp_map = self - .wallet() - .await? - .node_find_timestamps_for_staking( + let mut rng = make_true_rng(); + let our_private_key = EndToEndPrivateKey::new_from_rng(&mut rng); + let our_public_key = our_private_key.public_key(); + + let wallet = self.wallet().await?; + + let callee_public_key = wallet.e2e_public_key().await?.take(); + + let encrypted_input_data = wallet + .get_timestamp_search_input_data( + HexEncoded::new(our_public_key.clone()), pool_id, + ) + .await?; + let shared_secret = our_private_key.shared_secret(&callee_public_key); + let secret_input_data = shared_secret + .decrypt_then_decode::(&encrypted_input_data)?; + + let search_data = wallet + .node_collect_timestamp_search_data( + HexEncoded::new(our_public_key), + encrypted_input_data, min_height, Some(max_height), seconds_to_check_for_height, check_all_timestamps_between_blocks.to_bool(), ) - .await?; + .await? + .take(); + + let timestamp_map = blockprod::find_timestamps_for_staking( + Arc::clone(chain_config), + secret_input_data, + search_data, + ) + .await + .map_err(|err| WalletCliCommandError::SearchForTimestampsFailed(err))?; Ok(ConsoleCommand::Print(format!("{timestamp_map:#?}"))) } @@ -1637,7 +1665,7 @@ where pub async fn handle_manageable_wallet_command( &mut self, - chain_config: &ChainConfig, + chain_config: &Arc, command: ManageableWalletCommand, ) -> Result> where diff --git a/wallet/wallet-cli-commands/src/errors.rs b/wallet/wallet-cli-commands/src/errors.rs index a9ef387c56..e0afcc8099 100644 --- a/wallet/wallet-cli-commands/src/errors.rs +++ b/wallet/wallet-cli-commands/src/errors.rs @@ -13,7 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crypto::key::hdkd::u31::U31; +use blockprod::BlockProductionError; +use crypto::{ephemeral_e2e, key::hdkd::u31::U31}; use node_comm::node_traits::NodeInterface; use utils::qrcode::QrCodeError; use wallet_rpc_client::{handles_client::WalletRpcHandlesClientError, rpc_client::WalletRpcError}; @@ -47,4 +48,8 @@ pub enum WalletCliCommandError { DifferentWalletWasOpened, #[error("The wallet has been closed between commands")] ExistingWalletWasClosed, + #[error("Search for timestamps failed: {0}")] + SearchForTimestampsFailed(BlockProductionError), + #[error(transparent)] + E2eError(#[from] ephemeral_e2e::error::Error), } diff --git a/wallet/wallet-controller/src/lib.rs b/wallet/wallet-controller/src/lib.rs index 4d56beaef8..90cdcd635a 100644 --- a/wallet/wallet-controller/src/lib.rs +++ b/wallet/wallet-controller/src/lib.rs @@ -24,7 +24,7 @@ pub mod types; const NORMAL_DELAY: Duration = Duration::from_secs(1); const ERROR_DELAY: Duration = Duration::from_secs(10); -use blockprod::BlockProductionError; +use blockprod::TimestampSearchData; use futures::{ never::Never, stream::{FuturesOrdered, FuturesUnordered}, @@ -51,7 +51,6 @@ use synced_controller::SyncedController; use common::{ address::AddressError, chain::{ - block::timestamp::BlockTimestamp, signature::{ inputsig::{standard_signature::StandardInputSignature, InputWitness}, sighash::signature_hash, @@ -128,8 +127,6 @@ pub enum ControllerError { WalletFileAlreadyOpen, #[error("Please open or create wallet file first")] NoWallet, - #[error("Search for timestamps failed: {0}")] - SearchForTimestampsFailed(BlockProductionError), } #[derive(Clone, Copy)] @@ -522,24 +519,10 @@ impl Controll self.sync_once().await } - /// For each block height in the specified range, find timestamps where staking is/was possible - /// for the given pool. - /// - /// `min_height` must not be zero; `max_height` must not exceed the best block height plus one. - /// - /// If `check_all_timestamps_between_blocks` is `false`, `seconds_to_check_for_height + 1` is the number - /// of seconds that will be checked at each height in the range. - /// If `check_all_timestamps_between_blocks` is `true`, `seconds_to_check_for_height` only applies to the - /// last height in the range; for all other heights the maximum timestamp is the timestamp - /// of the next block. - pub async fn find_timestamps_for_staking( + pub fn get_timestamp_search_input_data( &self, pool_id: PoolId, - min_height: BlockHeight, - max_height: Option, - seconds_to_check_for_height: u64, - check_all_timestamps_between_blocks: bool, - ) -> Result>, ControllerError> { + ) -> Result> { let pos_data = self .wallet .get_pos_gen_block_data_by_pool_id(pool_id) @@ -548,6 +531,17 @@ impl Controll let input_data = PoSTimestampSearchInputData::new(pool_id, pos_data.vrf_private_key().clone()); + Ok(input_data) + } + + pub async fn collect_timestamp_search_data( + &self, + search_input_data: PoSTimestampSearchInputData, + min_height: BlockHeight, + max_height: Option, + seconds_to_check_for_height: u64, + check_all_timestamps_between_blocks: bool, + ) -> Result> { let public_key = self .rpc_client .blockprod_e2e_public_key() @@ -558,10 +552,10 @@ impl Controll let ephemeral_private_key = EndToEndPrivateKey::new_from_rng(&mut rng); let ephemeral_public_key = ephemeral_private_key.public_key(); let shared_secret = ephemeral_private_key.shared_secret(&public_key); - let encrypted_input_data = shared_secret.encode_then_encrypt(&input_data, &mut rng)?; + let encrypted_input_data = + shared_secret.encode_then_encrypt(&search_input_data, &mut rng)?; - let search_data = self - .rpc_client + self.rpc_client .collect_timestamp_search_data_e2e( encrypted_input_data, ephemeral_public_key, @@ -571,15 +565,7 @@ impl Controll check_all_timestamps_between_blocks, ) .await - .map_err(ControllerError::NodeCallError)?; - - blockprod::find_timestamps_for_staking( - Arc::clone(&self.chain_config), - input_data, - search_data, - ) - .await - .map_err(|err| ControllerError::SearchForTimestampsFailed(err)) + .map_err(ControllerError::NodeCallError) } pub fn create_account( diff --git a/wallet/wallet-rpc-client/Cargo.toml b/wallet/wallet-rpc-client/Cargo.toml index c62e8133fd..b815342ed0 100644 --- a/wallet/wallet-rpc-client/Cargo.toml +++ b/wallet/wallet-rpc-client/Cargo.toml @@ -8,6 +8,7 @@ rust-version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +blockprod = { path = "../../blockprod" } chainstate = { path = "../../chainstate" } common = { path = "../../common" } crypto = { path = "../../crypto" } diff --git a/wallet/wallet-rpc-client/src/handles_client/mod.rs b/wallet/wallet-rpc-client/src/handles_client/mod.rs index 1a2655788a..304d9438b2 100644 --- a/wallet/wallet-rpc-client/src/handles_client/mod.rs +++ b/wallet/wallet-rpc-client/src/handles_client/mod.rs @@ -13,18 +13,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{collections::BTreeMap, fmt::Debug, num::NonZeroUsize, path::PathBuf, str::FromStr}; +use std::{fmt::Debug, num::NonZeroUsize, path::PathBuf, str::FromStr}; +use blockprod::TimestampSearchData; use chainstate::ChainInfo; use common::{ address::{dehexify::dehexify_all_addresses, AddressError}, chain::{ - block::timestamp::BlockTimestamp, tokens::IsTokenUnfreezable, Block, GenBlock, - SignedTransaction, Transaction, TxOutput, UtxoOutPoint, + tokens::IsTokenUnfreezable, Block, GenBlock, SignedTransaction, Transaction, TxOutput, + UtxoOutPoint, }, primitives::{BlockHeight, DecimalAmount, Id, Idable, H256}, }; -use crypto::key::{hdkd::u31::U31, PrivateKey}; +use crypto::{ + ephemeral_e2e::EndToEndPublicKey, + key::{hdkd::u31::U31, PrivateKey}, +}; use node_comm::node_traits::NodeInterface; use p2p_types::{bannable_address::BannableAddress, socket_address::SocketAddress, PeerId}; use rpc::types::RpcHexString; @@ -1260,23 +1264,41 @@ impl WalletInterface .map_err(WalletRpcHandlesClientError::WalletRpcError) } - async fn node_find_timestamps_for_staking( + async fn e2e_public_key(&self) -> Result, Self::Error> { + Ok(HexEncoded::new(self.wallet_rpc.e2e_public_key())) + } + + async fn get_timestamp_search_input_data( &self, + caller_public_key: HexEncoded, pool_id: String, + ) -> Result, Self::Error> { + self.wallet_rpc + .get_timestamp_search_input_data(caller_public_key.take(), pool_id.into()) + .await + .map_err(WalletRpcHandlesClientError::WalletRpcError) + } + + async fn node_collect_timestamp_search_data( + &self, + caller_public_key: HexEncoded, + encrypted_input_data: /*PoSTimestampSearchInputData*/ Vec, min_height: BlockHeight, max_height: Option, seconds_to_check_for_height: u64, check_all_timestamps_between_blocks: bool, - ) -> Result>, Self::Error> { + ) -> Result, Self::Error> { self.wallet_rpc - .find_timestamps_for_staking( - pool_id.into(), + .collect_timestamp_search_data( + caller_public_key.take(), + encrypted_input_data, min_height, max_height, seconds_to_check_for_height, check_all_timestamps_between_blocks, ) .await + .map(HexEncoded::new) .map_err(WalletRpcHandlesClientError::WalletRpcError) } diff --git a/wallet/wallet-rpc-client/src/rpc_client/client_impl.rs b/wallet/wallet-rpc-client/src/rpc_client/client_impl.rs index 8bbd34eb81..a2c9a75ef4 100644 --- a/wallet/wallet-rpc-client/src/rpc_client/client_impl.rs +++ b/wallet/wallet-rpc-client/src/rpc_client/client_impl.rs @@ -13,21 +13,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{collections::BTreeMap, future::pending, num::NonZeroUsize, path::PathBuf}; +use std::{future::pending, num::NonZeroUsize, path::PathBuf}; use crate::wallet_rpc_traits::{PartialOrSignedTx, SignRawTransactionResult, WalletInterface}; use super::{ClientWalletRpc, WalletRpcError}; +use blockprod::TimestampSearchData; use chainstate::ChainInfo; use common::{ - chain::{ - block::timestamp::BlockTimestamp, Block, GenBlock, SignedTransaction, Transaction, - TxOutput, UtxoOutPoint, - }, + chain::{Block, GenBlock, SignedTransaction, Transaction, TxOutput, UtxoOutPoint}, primitives::{BlockHeight, DecimalAmount, Id}, }; -use crypto::key::{hdkd::u31::U31, PrivateKey}; +use crypto::{ + ephemeral_e2e::EndToEndPublicKey, + key::{hdkd::u31::U31, PrivateKey}, +}; use p2p_types::{bannable_address::BannableAddress, socket_address::SocketAddress, PeerId}; use serialization::hex_encoded::HexEncoded; use serialization::DecodeAll; @@ -1202,17 +1203,39 @@ impl WalletInterface for ClientWalletRpc { .map_err(WalletRpcError::ResponseError) } - async fn node_find_timestamps_for_staking( + async fn e2e_public_key(&self) -> Result, Self::Error> { + WalletRpcClient::e2e_public_key(&self.http_client) + .await + .map_err(WalletRpcError::ResponseError) + } + + async fn get_timestamp_search_input_data( &self, + caller_public_key: HexEncoded, pool_id: String, + ) -> Result, Self::Error> { + WalletRpcClient::get_timestamp_search_input_data( + &self.http_client, + caller_public_key, + pool_id.into(), + ) + .await + .map_err(WalletRpcError::ResponseError) + } + + async fn node_collect_timestamp_search_data( + &self, + caller_public_key: HexEncoded, + encrypted_input_data: /*PoSTimestampSearchInputData*/ Vec, min_height: BlockHeight, max_height: Option, seconds_to_check_for_height: u64, check_all_timestamps_between_blocks: bool, - ) -> Result>, Self::Error> { - WalletRpcClient::node_find_timestamps_for_staking( + ) -> Result, Self::Error> { + WalletRpcClient::node_collect_timestamp_search_data( &self.http_client, - pool_id.into(), + caller_public_key, + encrypted_input_data, min_height, max_height, seconds_to_check_for_height, diff --git a/wallet/wallet-rpc-client/src/wallet_rpc_traits.rs b/wallet/wallet-rpc-client/src/wallet_rpc_traits.rs index 388d546da6..6aecfaa317 100644 --- a/wallet/wallet-rpc-client/src/wallet_rpc_traits.rs +++ b/wallet/wallet-rpc-client/src/wallet_rpc_traits.rs @@ -13,17 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{collections::BTreeMap, num::NonZeroUsize, path::PathBuf}; +use std::{num::NonZeroUsize, path::PathBuf}; +use blockprod::TimestampSearchData; use chainstate::ChainInfo; use common::{ - chain::{ - block::timestamp::BlockTimestamp, Block, GenBlock, SignedTransaction, Transaction, - TxOutput, UtxoOutPoint, - }, + chain::{Block, GenBlock, SignedTransaction, Transaction, TxOutput, UtxoOutPoint}, primitives::{BlockHeight, DecimalAmount, Id}, }; -use crypto::key::{hdkd::u31::U31, PrivateKey}; +use crypto::{ + ephemeral_e2e::EndToEndPublicKey, + key::{hdkd::u31::U31, PrivateKey}, +}; use p2p_types::{bannable_address::BannableAddress, socket_address::SocketAddress, PeerId}; use serialization::hex_encoded::HexEncoded; use utils_networking::IpOrSocketAddress; @@ -548,14 +549,23 @@ pub trait WalletInterface { block_count: u32, ) -> Result<(), Self::Error>; - async fn node_find_timestamps_for_staking( + async fn e2e_public_key(&self) -> Result, Self::Error>; + + async fn get_timestamp_search_input_data( &self, + caller_public_key: HexEncoded, pool_id: String, + ) -> Result, Self::Error>; + + async fn node_collect_timestamp_search_data( + &self, + caller_public_key: HexEncoded, + encrypted_input_data: /*PoSTimestampSearchInputData*/ Vec, min_height: BlockHeight, max_height: Option, seconds_to_check_for_height: u64, check_all_timestamps_between_blocks: bool, - ) -> Result>, Self::Error>; + ) -> Result, Self::Error>; async fn node_block(&self, block_id: String) -> Result, Self::Error>; diff --git a/wallet/wallet-rpc-daemon/docs/RPC.md b/wallet/wallet-rpc-daemon/docs/RPC.md index 4257de92eb..a714260277 100644 --- a/wallet/wallet-rpc-daemon/docs/RPC.md +++ b/wallet/wallet-rpc-daemon/docs/RPC.md @@ -1643,12 +1643,40 @@ Returns: nothing ``` -### Method `node_find_timestamps_for_staking` +### Method `e2e_public_key` + +Parameters: +``` +{} +``` + +Returns: +``` +hex string +``` + +### Method `get_timestamp_search_input_data` Parameters: ``` { + "caller_public_key": hex string, "pool_id": bech32 string, +} +``` + +Returns: +``` +[ number, .. ] +``` + +### Method `node_collect_timestamp_search_data` + +Parameters: +``` +{ + "caller_public_key": hex string, + "encrypted_input_data": [ number, .. ], "min_height": number, "max_height": EITHER OF 1) number @@ -1660,7 +1688,7 @@ Parameters: Returns: ``` -{ number: [ { "timestamp": number }, .. ], .. } +hex string ``` ### Method `node_get_block` diff --git a/wallet/wallet-rpc-lib/Cargo.toml b/wallet/wallet-rpc-lib/Cargo.toml index 728dedea7a..001624e6f0 100644 --- a/wallet/wallet-rpc-lib/Cargo.toml +++ b/wallet/wallet-rpc-lib/Cargo.toml @@ -6,8 +6,9 @@ version.workspace = true rust-version.workspace = true [dependencies] - +blockprod = { path = "../../blockprod" } common = { path = "../../common" } +consensus = { path = "../../consensus" } chainstate = { path = "../../chainstate" } crypto = { path = "../../crypto" } logging = { path = "../../logging" } diff --git a/wallet/wallet-rpc-lib/src/rpc/interface.rs b/wallet/wallet-rpc-lib/src/rpc/interface.rs index e76b715ed8..13bc61c939 100644 --- a/wallet/wallet-rpc-lib/src/rpc/interface.rs +++ b/wallet/wallet-rpc-lib/src/rpc/interface.rs @@ -13,17 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{collections::BTreeMap, num::NonZeroUsize}; +use std::num::NonZeroUsize; +use blockprod::TimestampSearchData; use common::{ address::RpcAddress, chain::{ - block::timestamp::BlockTimestamp, tokens::TokenId, Block, DelegationId, Destination, - GenBlock, PoolId, SignedTransaction, Transaction, TxOutput, + tokens::TokenId, Block, DelegationId, Destination, GenBlock, PoolId, SignedTransaction, + Transaction, TxOutput, }, primitives::{BlockHeight, Id}, }; -use crypto::key::PrivateKey; +use crypto::{ephemeral_e2e::EndToEndPublicKey, key::PrivateKey}; use p2p_types::{bannable_address::BannableAddress, socket_address::SocketAddress}; use rpc::types::RpcHexString; use wallet::account::{PartiallySignedTransaction, TxInfo}; @@ -799,25 +800,26 @@ trait WalletRpc { block_count: u32, ) -> rpc::RpcResult<()>; - /// For each block height in the specified range, find timestamps where staking is/was possible - /// for the given pool. - /// - /// `min_height` must not be zero; `max_height` must not exceed the best block height plus one. - /// - /// If `check_all_timestamps_between_blocks` is `false`, `seconds_to_check_for_height + 1` is the number - /// of seconds that will be checked at each height in the range. - /// If `check_all_timestamps_between_blocks` is `true`, `seconds_to_check_for_height` only applies to the - /// last height in the range; for all other heights the maximum timestamp is the timestamp - /// of the next block. - #[method(name = "node_find_timestamps_for_staking")] - async fn node_find_timestamps_for_staking( + #[method(name = "e2e_public_key")] + async fn e2e_public_key(&self) -> rpc::RpcResult>; + + #[method(name = "get_timestamp_search_input_data")] + async fn get_timestamp_search_input_data( &self, + caller_public_key: HexEncoded, pool_id: RpcAddress, + ) -> rpc::RpcResult>; + + #[method(name = "node_collect_timestamp_search_data")] + async fn node_collect_timestamp_search_data( + &self, + caller_public_key: HexEncoded, + encrypted_input_data: /*PoSTimestampSearchInputData*/ Vec, min_height: BlockHeight, max_height: Option, seconds_to_check_for_height: u64, check_all_timestamps_between_blocks: bool, - ) -> rpc::RpcResult>>; + ) -> rpc::RpcResult>; /// Get a block by its hash, represented with hex encoded bytes #[method(name = "node_get_block")] diff --git a/wallet/wallet-rpc-lib/src/rpc/mod.rs b/wallet/wallet-rpc-lib/src/rpc/mod.rs index 713c8bf2a9..e367afbb12 100644 --- a/wallet/wallet-rpc-lib/src/rpc/mod.rs +++ b/wallet/wallet-rpc-lib/src/rpc/mod.rs @@ -26,11 +26,17 @@ use std::{ time::Duration, }; +use blockprod::TimestampSearchData; use chainstate::{tx_verifier::check_transaction, ChainInfo, TokenIssuanceError}; -use crypto::key::{hdkd::u31::U31, PrivateKey, PublicKey}; +use consensus::PoSTimestampSearchInputData; +use crypto::{ + ephemeral_e2e::{EndToEndPrivateKey, EndToEndPublicKey}, + key::{hdkd::u31::U31, PrivateKey, PublicKey}, +}; use mempool::tx_accumulator::PackingStrategy; use mempool_types::tx_options::TxOptionsOverrides; use p2p_types::{bannable_address::BannableAddress, socket_address::SocketAddress, PeerId}; +use randomness::make_true_rng; use serialization::{hex_encoded::HexEncoded, Decode, DecodeAll}; use utils::{ensure, shallow_clone::ShallowClone}; use utils_networking::IpOrSocketAddress; @@ -45,7 +51,6 @@ use wallet::{ use common::{ address::Address, chain::{ - block::timestamp::BlockTimestamp, classic_multisig::ClassicMultisigChallenge, signature::inputsig::arbitrary_message::{ produce_message_challenge, ArbitraryMessageSignature, @@ -92,6 +97,9 @@ pub struct WalletRpc { wallet: WalletHandle, node: N, chain_config: Arc, + /// The private key to encrypt sensitive data when passing it through the wallet rpc. + /// Need to use `Arc`, because `EndToEndPrivateKey` is not `Clone`. + e2e_private_key: Arc, } type WRpcResult = Result>; @@ -102,6 +110,7 @@ impl WalletRpc { wallet, node, chain_config, + e2e_private_key: Arc::new(EndToEndPrivateKey::new_from_rng(&mut make_true_rng())), } } @@ -222,22 +231,46 @@ impl WalletRpc { .await? } - pub async fn find_timestamps_for_staking( + pub fn e2e_public_key(&self) -> EndToEndPublicKey { + self.e2e_private_key.public_key() + } + + pub async fn get_timestamp_search_input_data( &self, + caller_public_key: EndToEndPublicKey, pool_id: RpcAddress, + ) -> WRpcResult, N> { + let pool_id = + pool_id.decode_object(&self.chain_config).map_err(|_| RpcError::InvalidPoolId)?; + + let search_input_data = + self.wallet.call(move |w| w.get_timestamp_search_input_data(pool_id)).await??; + + let shared_secret = self.e2e_private_key.shared_secret(&caller_public_key); + let encrypted_data = + shared_secret.encode_then_encrypt(&search_input_data, &mut make_true_rng())?; + + Ok(encrypted_data) + } + + pub async fn collect_timestamp_search_data( + &self, + caller_public_key: EndToEndPublicKey, + encrypted_input_data: /*PoSTimestampSearchInputData*/ Vec, min_height: BlockHeight, max_height: Option, seconds_to_check_for_height: u64, check_all_timestamps_between_blocks: bool, - ) -> WRpcResult>, N> { - let pool_id = - pool_id.decode_object(&self.chain_config).map_err(|_| RpcError::InvalidPoolId)?; + ) -> WRpcResult { + let shared_secret = self.e2e_private_key.shared_secret(&caller_public_key); + let input_data = shared_secret + .decrypt_then_decode::(&encrypted_input_data)?; self.wallet .call_async(move |w| { Box::pin(async move { - w.find_timestamps_for_staking( - pool_id, + w.collect_timestamp_search_data( + input_data, min_height, max_height, seconds_to_check_for_height, diff --git a/wallet/wallet-rpc-lib/src/rpc/server_impl.rs b/wallet/wallet-rpc-lib/src/rpc/server_impl.rs index cb244530f4..51b91f678e 100644 --- a/wallet/wallet-rpc-lib/src/rpc/server_impl.rs +++ b/wallet/wallet-rpc-lib/src/rpc/server_impl.rs @@ -13,19 +13,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{collections::BTreeMap, fmt::Debug, num::NonZeroUsize, str::FromStr, time::Duration}; +use std::{fmt::Debug, num::NonZeroUsize, str::FromStr, time::Duration}; +use blockprod::TimestampSearchData; use common::{ address::dehexify::dehexify_all_addresses, chain::{ - block::timestamp::BlockTimestamp, tokens::{IsTokenUnfreezable, TokenId}, Block, DelegationId, Destination, GenBlock, PoolId, SignedTransaction, Transaction, TxOutput, }, primitives::{time::Time, BlockHeight, Id, Idable}, }; -use crypto::key::PrivateKey; +use crypto::{ephemeral_e2e::EndToEndPublicKey, key::PrivateKey}; use p2p_types::{bannable_address::BannableAddress, socket_address::SocketAddress, PeerId}; use serialization::{hex::HexEncode, json_encoded::JsonEncoded}; use utils_networking::IpOrSocketAddress; @@ -1162,23 +1162,40 @@ impl WalletRpcServer f ) } - async fn node_find_timestamps_for_staking( + async fn e2e_public_key(&self) -> rpc::RpcResult> { + Ok(HexEncoded::new(self.e2e_public_key())) + } + + async fn get_timestamp_search_input_data( &self, + caller_public_key: HexEncoded, pool_id: RpcAddress, + ) -> rpc::RpcResult> { + rpc::handle_result( + self.get_timestamp_search_input_data(caller_public_key.take(), pool_id).await, + ) + } + + async fn node_collect_timestamp_search_data( + &self, + caller_public_key: HexEncoded, + encrypted_input_data: /*PoSTimestampSearchInputData*/ Vec, min_height: BlockHeight, max_height: Option, seconds_to_check_for_height: u64, check_all_timestamps_between_blocks: bool, - ) -> rpc::RpcResult>> { + ) -> rpc::RpcResult> { rpc::handle_result( - self.find_timestamps_for_staking( - pool_id, + self.collect_timestamp_search_data( + caller_public_key.take(), + encrypted_input_data, min_height, max_height, seconds_to_check_for_height, check_all_timestamps_between_blocks, ) - .await, + .await + .map(HexEncoded::new), ) } diff --git a/wallet/wallet-rpc-lib/src/rpc/types.rs b/wallet/wallet-rpc-lib/src/rpc/types.rs index 7be3220dbc..4f35395a5e 100644 --- a/wallet/wallet-rpc-lib/src/rpc/types.rs +++ b/wallet/wallet-rpc-lib/src/rpc/types.rs @@ -28,6 +28,7 @@ use common::{ primitives::{per_thousand::PerThousand, Amount, BlockHeight, Id, Idable}, }; use crypto::{ + ephemeral_e2e, key::{ hdkd::{child_number::ChildNumber, u31::U31}, PublicKey, @@ -128,6 +129,9 @@ pub enum RpcError { #[error(transparent)] Address(#[from] AddressError), + + #[error(transparent)] + E2eError(#[from] ephemeral_e2e::error::Error), } impl From> for rpc::Error {