Skip to content

Commit

Permalink
Support new Bulletproof rewind scheme (#122)
Browse files Browse the repository at this point in the history
* Restore with LegacyProofBuilder

* Switch to ProofBuilder at HF block

* Switch proof builder for coinbase outputs at hard fork

* Use valid_header_version to switch proof builder

* Fix compilation errors

* Use legacy proof builder for AutomatedTesting chain type

* Add macro to avoid duplicate code
  • Loading branch information
jaspervdm authored and yeastplume committed Jun 13, 2019
1 parent 59940b0 commit 101d062
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 92 deletions.
26 changes: 14 additions & 12 deletions Cargo.lock

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

9 changes: 6 additions & 3 deletions impls/src/backends/lmdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use uuid::Uuid;

use crate::blake2::blake2b::Blake2b;

use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain};
use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain, SwitchCommitmentType};
use crate::store::{self, option_to_not_found, to_key, to_key_u64};

use crate::core::core::Transaction;
Expand Down Expand Up @@ -68,7 +68,7 @@ fn private_ctx_xor_keys<K>(
where
K: Keychain,
{
let root_key = keychain.derive_key(0, &K::root_key_id())?;
let root_key = keychain.derive_key(0, &K::root_key_id(), &SwitchCommitmentType::Regular)?;

// derive XOR values for storing secret values in DB
// h(root_key|slate_id|"blind")
Expand Down Expand Up @@ -203,7 +203,10 @@ where
Ok(None)
} else {
Ok(Some(util::to_hex(
self.keychain().commit(amount, &id)?.0.to_vec(),
self.keychain()
.commit(amount, &id, &SwitchCommitmentType::Regular)?
.0
.to_vec(), // TODO: proper support for different switch commitment schemes
)))
}
}
Expand Down
35 changes: 22 additions & 13 deletions libwallet/src/internal/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
// limitations under the License.
//! Functions to restore a wallet's outputs from just the master seed
use crate::grin_core::consensus::valid_header_version;
use crate::grin_core::core::HeaderVersion;
use crate::grin_core::global;
use crate::grin_core::libtx::proof;
use crate::grin_keychain::{ExtKeychain, Identifier, Keychain};
use crate::grin_util::secp::{key::SecretKey, pedersen};
use crate::grin_keychain::{ExtKeychain, Identifier, Keychain, SwitchCommitmentType};
use crate::grin_util::secp::pedersen;
use crate::internal::{keys, updater};
use crate::types::*;
use crate::{Error, OutputCommitMapping};
Expand All @@ -41,8 +43,6 @@ struct OutputResult {
pub lock_height: u64,
///
pub is_coinbase: bool,
///
pub blinding: SecretKey,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -73,40 +73,49 @@ where
outputs.len(),
);

let keychain = wallet.keychain();
let legacy_builder = proof::LegacyProofBuilder::new(keychain);
let builder = proof::ProofBuilder::new(keychain);
let legacy_version = HeaderVersion(1);

for output in outputs.iter() {
let (commit, proof, is_coinbase, height, mmr_index) = output;
// attempt to unwind message from the RP and get a value
// will fail if it's not ours
let info = proof::rewind(wallet.keychain(), *commit, None, *proof)?;
let info = if valid_header_version(*height, legacy_version) {
proof::rewind(keychain.secp(), &legacy_builder, *commit, None, *proof)
} else {
proof::rewind(keychain.secp(), &builder, *commit, None, *proof)
}?;

if !info.success {
if info.is_none() {
continue;
}
let (amount, key_id, switch) = info.unwrap();

let lock_height = if *is_coinbase {
*height + global::coinbase_maturity()
} else {
*height
};

// TODO: Output paths are always going to be length 3 for now, but easy enough to grind
// through to find the right path if required later
let key_id = Identifier::from_serialized_path(3u8, &info.message.as_bytes());

info!(
"Output found: {:?}, amount: {:?}, key_id: {:?}, mmr_index: {},",
commit, info.value, key_id, mmr_index,
commit, amount, key_id, mmr_index,
);

if switch != SwitchCommitmentType::Regular {
warn!("Unexpected switch commitment type {:?}", switch);
}

wallet_outputs.push(OutputResult {
commit: *commit,
key_id: key_id.clone(),
n_child: key_id.to_path().last_path_index(),
value: info.value,
value: amount,
height: *height,
lock_height: lock_height,
is_coinbase: *is_coinbase,
blinding: info.blinding,
mmr_index: *mmr_index,
});
}
Expand Down
82 changes: 65 additions & 17 deletions libwallet/src/internal/selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,45 @@
use crate::error::{Error, ErrorKind};
use crate::grin_core::core::amount_to_hr_string;
use crate::grin_core::libtx::{build, tx_fee};
use crate::grin_core::global;
use crate::grin_core::libtx::{
build,
proof::{LegacyProofBuilder, ProofBuild, ProofBuilder},
tx_fee,
};
use crate::grin_keychain::{Identifier, Keychain};
use crate::internal::keys;
use crate::slate::Slate;
use crate::types::*;
use std::collections::HashMap;

macro_rules! add_transaction_elements {
($a:expr, $b:ident) => {{
let slate = $a.1;
let (elems, inputs, change_amounts_derivations, fee) = select_send_tx(
$a.0,
slate.amount,
slate.height,
$a.2,
slate.lock_height,
$a.3,
$a.4,
$a.5,
$a.6,
)?;
let keychain = $a.0.keychain();
let blinding = slate.add_transaction_elements(keychain, &$b::new(keychain), elems)?;
(
$a.0,
slate,
inputs,
change_amounts_derivations,
fee,
blinding,
)
}};
}

/// Initialize a transaction on the sender side, returns a corresponding
/// libwallet transaction slate with the appropriate inputs selected,
/// and saves the private wallet identifiers of our selected outputs
Expand All @@ -43,26 +75,29 @@ where
C: NodeClient,
K: Keychain,
{
let (elems, inputs, change_amounts_derivations, fee) = select_send_tx(
let chain_type = global::CHAIN_TYPE.read().clone();
let args = (
wallet,
slate.amount,
slate.height,
slate,
minimum_confirmations,
slate.lock_height,
max_outputs,
change_outputs,
selection_strategy_is_use_all,
&parent_key_id,
)?;
);
let (wallet, mut slate, inputs, change_amounts_derivations, fee, blinding) =
if chain_type == global::ChainTypes::AutomatedTesting {
add_transaction_elements!(args, LegacyProofBuilder)
} else {
add_transaction_elements!(args, ProofBuilder)
};

let keychain = wallet.keychain();
slate.fee = fee;

let keychain = wallet.keychain().clone();
let blinding = slate.add_transaction_elements(&keychain, elems)?;

// Create our own private context
let mut context = Context::new(
wallet.keychain().secp(),
keychain.secp(),
blinding.secret_key(&keychain.secp()).unwrap(),
&parent_key_id,
use_test_nonce,
Expand Down Expand Up @@ -182,15 +217,26 @@ where
{
// Create a potential output for this transaction
let key_id = keys::next_available_key(wallet).unwrap();

let keychain = wallet.keychain().clone();
let key_id_inner = key_id.clone();
let amount = slate.amount;
let height = slate.height;

let slate_id = slate.id.clone();
let blinding =
slate.add_transaction_elements(&keychain, vec![build::output(amount, key_id.clone())])?;
let chain_type = global::CHAIN_TYPE.read().clone();
let blinding = if chain_type == global::ChainTypes::AutomatedTesting {
slate.add_transaction_elements(
&keychain,
&LegacyProofBuilder::new(&keychain),
vec![build::output(amount, key_id.clone())],
)
} else {
slate.add_transaction_elements(
&keychain,
&ProofBuilder::new(&keychain),
vec![build::output(amount, key_id.clone())],
)
}?;

// Add blinding sum to our context
let mut context = Context::new(
Expand Down Expand Up @@ -235,7 +281,7 @@ where
/// Builds a transaction to send to someone from the HD seed associated with the
/// wallet and the amount to send. Handles reading through the wallet data file,
/// selecting outputs to spend and building the change.
pub fn select_send_tx<T: ?Sized, C, K>(
pub fn select_send_tx<T: ?Sized, C, K, B>(
wallet: &mut T,
amount: u64,
current_height: u64,
Expand All @@ -247,7 +293,7 @@ pub fn select_send_tx<T: ?Sized, C, K>(
parent_key_id: &Identifier,
) -> Result<
(
Vec<Box<build::Append<K>>>,
Vec<Box<build::Append<K, B>>>,
Vec<OutputData>,
Vec<(u64, Identifier, Option<u64>)>, // change amounts and derivations
u64, // fee
Expand All @@ -258,6 +304,7 @@ where
T: WalletBackend<C, K>,
C: NodeClient,
K: Keychain,
B: ProofBuild,
{
let (coins, _total, amount, fee) = select_coins_and_fee(
wallet,
Expand Down Expand Up @@ -387,15 +434,15 @@ where
}

/// Selects inputs and change for a transaction
pub fn inputs_and_change<T: ?Sized, C, K>(
pub fn inputs_and_change<T: ?Sized, C, K, B>(
coins: &Vec<OutputData>,
wallet: &mut T,
amount: u64,
fee: u64,
num_change_outputs: usize,
) -> Result<
(
Vec<Box<build::Append<K>>>,
Vec<Box<build::Append<K, B>>>,
Vec<(u64, Identifier, Option<u64>)>,
),
Error,
Expand All @@ -404,6 +451,7 @@ where
T: WalletBackend<C, K>,
C: NodeClient,
K: Keychain,
B: ProofBuild,
{
let mut parts = vec![];

Expand Down
Loading

0 comments on commit 101d062

Please sign in to comment.