Skip to content

Call blockprod::find_timestamps_for_staking directly from wallet cli #1748

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

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion node-gui/src/backend/backend_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1341,7 +1341,7 @@ async fn select_acc_and_execute_cmd<N>(
c: &mut CommandHandler<WalletRpcHandlesClient<N>>,
account_id: AccountId,
command: ManageableWalletCommand,
chain_config: &ChainConfig,
chain_config: &Arc<ChainConfig>,
) -> Result<ConsoleCommand, BackendError>
where
N: NodeInterface + Clone + Send + Sync + 'static + Debug,
Expand Down
1 change: 1 addition & 0 deletions wallet/wallet-cli-commands/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
46 changes: 37 additions & 9 deletions wallet/wallet-cli-commands/src/command_handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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};
Expand Down Expand Up @@ -646,7 +648,7 @@ where

pub async fn handle_wallet_command<N: NodeInterface>(
&mut self,
chain_config: &ChainConfig,
chain_config: &Arc<ChainConfig>,
command: WalletCommand,
) -> Result<ConsoleCommand, WalletCliCommandError<N>>
where
Expand Down Expand Up @@ -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::<PoSTimestampSearchInputData>(&encrypted_input_data)?;

Comment on lines +721 to +738
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't we pack all this in one function or something, instead of doing it here inline?

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:#?}")))
}

Expand Down Expand Up @@ -1637,7 +1665,7 @@ where

pub async fn handle_manageable_wallet_command<N: NodeInterface>(
&mut self,
chain_config: &ChainConfig,
chain_config: &Arc<ChainConfig>,
command: ManageableWalletCommand,
) -> Result<ConsoleCommand, WalletCliCommandError<N>>
where
Expand Down
7 changes: 6 additions & 1 deletion wallet/wallet-cli-commands/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -47,4 +48,8 @@ pub enum WalletCliCommandError<N: NodeInterface> {
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),
}
50 changes: 18 additions & 32 deletions wallet/wallet-controller/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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,
Expand Down Expand Up @@ -128,8 +127,6 @@ pub enum ControllerError<T: NodeInterface> {
WalletFileAlreadyOpen,
#[error("Please open or create wallet file first")]
NoWallet,
#[error("Search for timestamps failed: {0}")]
SearchForTimestampsFailed(BlockProductionError),
}

#[derive(Clone, Copy)]
Expand Down Expand Up @@ -522,24 +519,10 @@ impl<T: NodeInterface + Clone + Send + Sync + 'static, W: WalletEvents> 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<BlockHeight>,
seconds_to_check_for_height: u64,
check_all_timestamps_between_blocks: bool,
) -> Result<BTreeMap<BlockHeight, Vec<BlockTimestamp>>, ControllerError<T>> {
) -> Result<PoSTimestampSearchInputData, ControllerError<T>> {
let pos_data = self
.wallet
.get_pos_gen_block_data_by_pool_id(pool_id)
Expand All @@ -548,6 +531,17 @@ impl<T: NodeInterface + Clone + Send + Sync + 'static, W: WalletEvents> 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<BlockHeight>,
seconds_to_check_for_height: u64,
check_all_timestamps_between_blocks: bool,
) -> Result<TimestampSearchData, ControllerError<T>> {
let public_key = self
.rpc_client
.blockprod_e2e_public_key()
Expand All @@ -558,10 +552,10 @@ impl<T: NodeInterface + Clone + Send + Sync + 'static, W: WalletEvents> 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,
Expand All @@ -571,15 +565,7 @@ impl<T: NodeInterface + Clone + Send + Sync + 'static, W: WalletEvents> 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(
Expand Down
1 change: 1 addition & 0 deletions wallet/wallet-rpc-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
38 changes: 30 additions & 8 deletions wallet/wallet-rpc-client/src/handles_client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1260,23 +1264,41 @@ impl<N: NodeInterface + Clone + Send + Sync + 'static + Debug> WalletInterface
.map_err(WalletRpcHandlesClientError::WalletRpcError)
}

async fn node_find_timestamps_for_staking(
async fn e2e_public_key(&self) -> Result<HexEncoded<EndToEndPublicKey>, Self::Error> {
Ok(HexEncoded::new(self.wallet_rpc.e2e_public_key()))
}

async fn get_timestamp_search_input_data(
&self,
caller_public_key: HexEncoded<EndToEndPublicKey>,
pool_id: String,
) -> Result</*PoSTimestampSearchInputData*/ Vec<u8>, 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<EndToEndPublicKey>,
encrypted_input_data: /*PoSTimestampSearchInputData*/ Vec<u8>,
min_height: BlockHeight,
max_height: Option<BlockHeight>,
seconds_to_check_for_height: u64,
check_all_timestamps_between_blocks: bool,
) -> Result<BTreeMap<BlockHeight, Vec<BlockTimestamp>>, Self::Error> {
) -> Result<HexEncoded<TimestampSearchData>, 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)
}

Expand Down
43 changes: 33 additions & 10 deletions wallet/wallet-rpc-client/src/rpc_client/client_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<HexEncoded<EndToEndPublicKey>, 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<EndToEndPublicKey>,
pool_id: String,
) -> Result</*PoSTimestampSearchInputData*/ Vec<u8>, 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<EndToEndPublicKey>,
encrypted_input_data: /*PoSTimestampSearchInputData*/ Vec<u8>,
min_height: BlockHeight,
max_height: Option<BlockHeight>,
seconds_to_check_for_height: u64,
check_all_timestamps_between_blocks: bool,
) -> Result<BTreeMap<BlockHeight, Vec<BlockTimestamp>>, Self::Error> {
WalletRpcClient::node_find_timestamps_for_staking(
) -> Result<HexEncoded<TimestampSearchData>, 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,
Expand Down
Loading