Skip to content

Commit

Permalink
Fix FFI import UTXO
Browse files Browse the repository at this point in the history
- Fixed importing external UTXOs via the FFI
- Renamed import UTXO methods to be more descriptive
- Added a unit test to test importing external UTXOs via the FFI
  • Loading branch information
hansieodendaal committed Mar 24, 2022
1 parent c4070ff commit 2338cbd
Show file tree
Hide file tree
Showing 12 changed files with 319 additions and 56 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,11 @@ impl wallet_server::Wallet for WalletGrpcServer {
for o in unblinded_outputs.iter() {
tx_ids.push(
wallet
.import_unblinded_utxo(o.clone(), &CommsPublicKey::default(), "Imported via gRPC".to_string())
.import_unblinded_output_as_non_rewindable(
o.clone(),
&CommsPublicKey::default(),
"Imported via gRPC".to_string(),
)
.await
.map_err(|e| Status::internal(format!("{:?}", e)))?
.into(),
Expand Down
12 changes: 10 additions & 2 deletions base_layer/wallet/src/output_manager_service/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub enum OutputManagerRequest {
CalculateRecoveryByte {
spending_key: PrivateKey,
value: u64,
with_rewind_data: bool,
},
FeeEstimate {
amount: MicroTari,
Expand Down Expand Up @@ -178,7 +179,9 @@ impl fmt::Display for OutputManagerRequest {
RemoveEncryption => write!(f, "RemoveEncryption"),
GetCoinbaseTransaction(_) => write!(f, "GetCoinbaseTransaction"),
GetPublicRewindKeys => write!(f, "GetPublicRewindKeys"),
CalculateRecoveryByte { spending_key, value } => write!(
CalculateRecoveryByte {
spending_key, value, ..
} => write!(
f,
"CalculateRecoveryByte ({},{})",
spending_key.as_bytes().to_vec().to_hex(),
Expand Down Expand Up @@ -630,10 +633,15 @@ impl OutputManagerHandle {
&mut self,
spending_key: PrivateKey,
value: u64,
with_rewind_data: bool,
) -> Result<u8, OutputManagerError> {
match self
.handle
.call(OutputManagerRequest::CalculateRecoveryByte { spending_key, value })
.call(OutputManagerRequest::CalculateRecoveryByte {
spending_key,
value,
with_rewind_data,
})
.await??
{
OutputManagerResponse::RecoveryByte(rk) => Ok(rk),
Expand Down
30 changes: 23 additions & 7 deletions base_layer/wallet/src/output_manager_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,15 @@ where
OutputManagerRequest::GetPublicRewindKeys => Ok(OutputManagerResponse::PublicRewindKeys(Box::new(
self.get_rewind_public_keys(),
))),
OutputManagerRequest::CalculateRecoveryByte { spending_key, value } => Ok(
OutputManagerResponse::RecoveryByte(self.calculate_recovery_byte(spending_key, value)?),
),
OutputManagerRequest::CalculateRecoveryByte {
spending_key,
value,
with_rewind_data,
} => Ok(OutputManagerResponse::RecoveryByte(self.calculate_recovery_byte(
spending_key,
value,
with_rewind_data,
)?)),
OutputManagerRequest::ScanForRecoverableOutputs { outputs, tx_id } => StandardUtxoRecoverer::new(
self.resources.master_key_manager.clone(),
self.resources.rewind_data.clone(),
Expand Down Expand Up @@ -592,9 +598,19 @@ where
self.validate_outputs()
}

pub fn calculate_recovery_byte(&mut self, spending_key: PrivateKey, value: u64) -> Result<u8, OutputManagerError> {
pub fn calculate_recovery_byte(
&mut self,
spending_key: PrivateKey,
value: u64,
with_rewind_data: bool,
) -> Result<u8, OutputManagerError> {
let commitment = self.resources.factories.commitment.commit_value(&spending_key, value);
let recovery_byte = OutputFeatures::create_unique_recovery_byte(&commitment, Some(&self.resources.rewind_data));
let rewind_data = if with_rewind_data {
Some(&self.resources.rewind_data)
} else {
None
};
let recovery_byte = OutputFeatures::create_unique_recovery_byte(&commitment, rewind_data);
Ok(recovery_byte)
}

Expand Down Expand Up @@ -1325,7 +1341,7 @@ where
}

let (spending_key, script_private_key) = self.get_spend_and_script_keys().await?;
let recovery_byte = self.calculate_recovery_byte(spending_key.clone(), amount.as_u64())?;
let recovery_byte = self.calculate_recovery_byte(spending_key.clone(), amount.as_u64(), true)?;
let output_features = OutputFeatures {
recovery_byte,
unique_id: unique_id.clone(),
Expand Down Expand Up @@ -1671,7 +1687,7 @@ where
let output_amount = amount_per_split;

let (spending_key, script_private_key) = self.get_spend_and_script_keys().await?;
let recovery_byte = self.calculate_recovery_byte(spending_key.clone(), output_amount.as_u64())?;
let recovery_byte = self.calculate_recovery_byte(spending_key.clone(), output_amount.as_u64(), true)?;
let output_features = OutputFeatures {
recovery_byte,
..Default::default()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ impl OutputManagerBackend for OutputManagerSqliteDatabase {
if start.elapsed().as_millis() > 0 {
trace!(
target: LOG_TARGET,
"sqlite profile - reinstate_cancelled_inbound_output: lock {} + db_op {} = {} ms",
"sqlite profile - add_unvalidated_output: lock {} + db_op {} = {} ms",
acquire_lock.as_millis(),
(start.elapsed() - acquire_lock).as_millis(),
start.elapsed().as_millis()
Expand Down
24 changes: 13 additions & 11 deletions base_layer/wallet/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,10 @@ where
self.updater_service.clone().unwrap()
}

/// Import an external spendable UTXO into the wallet. The output will be added to the Output Manager and made
/// EncumberedToBeReceived. A faux incoming transaction will be created to provide a record of the event. The TxId
/// of the generated transaction is returned.

pub async fn import_utxo(
/// Import an external spendable UTXO into the wallet as a non-rewindable/non-recoverable UTXO. The output will be
/// added to the Output Manager and made EncumberedToBeReceived. A faux incoming transaction will be created to
/// provide a record of the event. The TxId of the generated transaction is returned.
pub async fn import_external_utxo_as_non_rewindable(
&mut self,
amount: MicroTari,
spending_key: &PrivateKey,
Expand Down Expand Up @@ -449,22 +448,24 @@ where
.map_err(WalletError::TransactionError)?
.to_hex();

// As non-rewindable
self.output_manager_service
.add_unvalidated_output(tx_id, unblinded_output, None)
.await?;

info!(
target: LOG_TARGET,
"UTXO (Commitment: {}) imported into wallet as 'ImportStatus::Imported'", commitment_hex
"UTXO (Commitment: {}) imported into wallet as 'ImportStatus::Imported' and is non-rewindable",
commitment_hex
);

Ok(tx_id)
}

/// Import an external spendable UTXO into the wallet. The output will be added to the Output Manager and made
/// spendable. A faux incoming transaction will be created to provide a record of the event. The TxId of the
/// generated transaction is returned.
pub async fn import_unblinded_utxo(
/// Import an external spendable UTXO into the wallet as a non-rewindable/non-recoverable UTXO. The output will be
/// added to the Output Manager and made spendable. A faux incoming transaction will be created to provide a record
/// of the event. The TxId of the generated transaction is returned.
pub async fn import_unblinded_output_as_non_rewindable(
&mut self,
unblinded_output: UnblindedOutput,
source_public_key: &CommsPublicKey,
Expand All @@ -483,13 +484,14 @@ where
)
.await?;

// As non-rewindable
self.output_manager_service
.add_output_with_tx_id(tx_id, unblinded_output.clone(), None)
.await?;

info!(
target: LOG_TARGET,
"UTXO (Commitment: {}) imported into wallet as 'ImportStatus::Imported'",
"UTXO (Commitment: {}) imported into wallet as 'ImportStatus::Imported' and is non-rewindable",
unblinded_output
.as_transaction_input(&self.factories.commitment)?
.commitment()
Expand Down
4 changes: 2 additions & 2 deletions base_layer/wallet/tests/support/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub async fn make_input<R: Rng + CryptoRng>(
// further down the line
if let Some(mut oms) = oms {
if let Ok(val) = oms
.calculate_recovery_byte(utxo.spending_key.clone(), utxo.value.clone().as_u64())
.calculate_recovery_byte(utxo.spending_key.clone(), utxo.value.clone().as_u64(), true)
.await
{
utxo.features.set_recovery_byte(val);
Expand Down Expand Up @@ -99,7 +99,7 @@ pub async fn make_input_with_features<R: Rng + CryptoRng>(
// 'TestParamsHelpers::new()'; this will influence validation of output features and the metadata signature
// further down the line
if let Ok(val) = oms
.calculate_recovery_byte(utxo.spending_key.clone(), utxo.value.clone().as_u64())
.calculate_recovery_byte(utxo.spending_key.clone(), utxo.value.clone().as_u64(), true)
.await
{
utxo.features.set_recovery_byte(val);
Expand Down
2 changes: 1 addition & 1 deletion base_layer/wallet/tests/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ async fn test_import_utxo() {
let expected_output_hash = output.hash();

let tx_id = alice_wallet
.import_utxo(
.import_external_utxo_as_non_rewindable(
utxo.value,
&utxo.spending_key,
script.clone(),
Expand Down
1 change: 1 addition & 0 deletions base_layer/wallet_ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ openssl = { version = "0.10", features = ["vendored"] }
rand = "0.8"
thiserror = "1.0.26"
tokio = "1.11"
env_logger = "0.7.0"

# <workaround>
# Temporary workaround until crates utilizing openssl have been updated from security-framework 2.4.0
Expand Down
Loading

0 comments on commit 2338cbd

Please sign in to comment.