mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 03:21:08 +03:00
update wallet restore, generate new merkle proof for coinbase outputs (#1008)
This commit is contained in:
parent
820d55a532
commit
59664181e4
4 changed files with 112 additions and 13 deletions
|
@ -237,6 +237,10 @@ impl Handler for OutputHandler {
|
||||||
|
|
||||||
// UTXO traversal::
|
// UTXO traversal::
|
||||||
// GET /v1/txhashset/outputs?start_index=1&max=100
|
// GET /v1/txhashset/outputs?start_index=1&max=100
|
||||||
|
//
|
||||||
|
// Build a merkle proof for a given pos
|
||||||
|
// GET /v1/txhashset/merkleproof?n=1
|
||||||
|
|
||||||
struct TxHashSetHandler {
|
struct TxHashSetHandler {
|
||||||
chain: Weak<chain::Chain>,
|
chain: Weak<chain::Chain>,
|
||||||
}
|
}
|
||||||
|
@ -281,6 +285,25 @@ impl TxHashSetHandler {
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return a dummy output with merkle proof for position filled out
|
||||||
|
// (to avoid having to create a new type to pass around)
|
||||||
|
fn get_merkle_proof_for_output(&self, id: &str) -> Result<OutputPrintable, Error> {
|
||||||
|
let c = util::from_hex(String::from(id)).context(ErrorKind::Argument(format!(
|
||||||
|
"Not a valid commitment: {}",
|
||||||
|
id
|
||||||
|
)))?;
|
||||||
|
let commit = Commitment::from_vec(c);
|
||||||
|
let merkle_proof = chain::Chain::get_merkle_proof_for_pos(&w(&self.chain), commit).unwrap();
|
||||||
|
Ok(OutputPrintable {
|
||||||
|
output_type: OutputType::Coinbase,
|
||||||
|
commit: Commitment::from_vec(vec![]),
|
||||||
|
spent: false,
|
||||||
|
proof: None,
|
||||||
|
proof_hash: "".to_string(),
|
||||||
|
merkle_proof: Some(merkle_proof),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handler for TxHashSetHandler {
|
impl Handler for TxHashSetHandler {
|
||||||
|
@ -289,6 +312,7 @@ impl Handler for TxHashSetHandler {
|
||||||
let mut path_elems = url.path();
|
let mut path_elems = url.path();
|
||||||
let mut start_index = 1;
|
let mut start_index = 1;
|
||||||
let mut max = 100;
|
let mut max = 100;
|
||||||
|
let mut id = "";
|
||||||
if *path_elems.last().unwrap() == "" {
|
if *path_elems.last().unwrap() == "" {
|
||||||
path_elems.pop();
|
path_elems.pop();
|
||||||
}
|
}
|
||||||
|
@ -316,6 +340,11 @@ impl Handler for TxHashSetHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(ids) = params.get("id") {
|
||||||
|
for i in ids {
|
||||||
|
id = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
match *path_elems.last().unwrap() {
|
match *path_elems.last().unwrap() {
|
||||||
"roots" => json_response_pretty(&self.get_roots()),
|
"roots" => json_response_pretty(&self.get_roots()),
|
||||||
|
@ -323,6 +352,7 @@ impl Handler for TxHashSetHandler {
|
||||||
"lastrangeproofs" => json_response_pretty(&self.get_last_n_rangeproof(last_n)),
|
"lastrangeproofs" => json_response_pretty(&self.get_last_n_rangeproof(last_n)),
|
||||||
"lastkernels" => json_response_pretty(&self.get_last_n_kernel(last_n)),
|
"lastkernels" => json_response_pretty(&self.get_last_n_kernel(last_n)),
|
||||||
"outputs" => json_response_pretty(&self.outputs(start_index, max)),
|
"outputs" => json_response_pretty(&self.outputs(start_index, max)),
|
||||||
|
"merkleproof" => json_response_pretty(&self.get_merkle_proof_for_output(id).unwrap()),
|
||||||
_ => Ok(Response::with((status::BadRequest, ""))),
|
_ => Ok(Response::with((status::BadRequest, ""))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ use pipe;
|
||||||
use store;
|
use store;
|
||||||
use txhashset;
|
use txhashset;
|
||||||
use types::*;
|
use types::*;
|
||||||
use util::secp::pedersen::RangeProof;
|
use util::secp::pedersen::{Commitment, RangeProof};
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
|
||||||
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
||||||
|
@ -507,6 +507,13 @@ impl Chain {
|
||||||
Ok(merkle_proof)
|
Ok(merkle_proof)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a merkle proof valid for the current output pmmr state at the
|
||||||
|
/// given pos
|
||||||
|
pub fn get_merkle_proof_for_pos(&self, commit: Commitment) -> Result<MerkleProof, String> {
|
||||||
|
let mut txhashset = self.txhashset.write().unwrap();
|
||||||
|
txhashset.merkle_proof(commit)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns current txhashset roots
|
/// Returns current txhashset roots
|
||||||
pub fn get_txhashset_roots(&self) -> (Hash, Hash, Hash) {
|
pub fn get_txhashset_roots(&self) -> (Hash, Hash, Hash) {
|
||||||
let mut txhashset = self.txhashset.write().unwrap();
|
let mut txhashset = self.txhashset.write().unwrap();
|
||||||
|
|
|
@ -205,6 +205,14 @@ impl TxHashSet {
|
||||||
(output_pmmr.root(), rproof_pmmr.root(), kernel_pmmr.root())
|
(output_pmmr.root(), rproof_pmmr.root(), kernel_pmmr.root())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// build a new merkle proof for the given position
|
||||||
|
pub fn merkle_proof(&mut self, commit: Commitment) -> Result<MerkleProof, String> {
|
||||||
|
let pos = self.commit_index.get_output_pos(&commit).unwrap();
|
||||||
|
let output_pmmr: PMMR<OutputIdentifier, _> =
|
||||||
|
PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
|
||||||
|
output_pmmr.merkle_proof(pos)
|
||||||
|
}
|
||||||
|
|
||||||
/// Compact the MMR data files and flush the rm logs
|
/// Compact the MMR data files and flush the rm logs
|
||||||
pub fn compact(&mut self) -> Result<(), Error> {
|
pub fn compact(&mut self) -> Result<(), Error> {
|
||||||
let commit_index = self.commit_index.clone();
|
let commit_index = self.commit_index.clone();
|
||||||
|
|
|
@ -13,15 +13,17 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use failure::{Fail, ResultExt};
|
use failure::{Fail, ResultExt};
|
||||||
use keychain::{Identifier, Keychain};
|
use keychain::{Identifier, Keychain};
|
||||||
|
use util;
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
use util::secp::pedersen;
|
use util::secp::pedersen;
|
||||||
use api;
|
use api;
|
||||||
use core::global;
|
use core::global;
|
||||||
use core::core::transaction::ProofMessageElements;
|
use core::core::transaction::ProofMessageElements;
|
||||||
use types::{Error, ErrorKind, OutputData, OutputStatus, WalletConfig, WalletData};
|
use types::{Error, ErrorKind, MerkleProofWrapper, OutputData, OutputStatus, WalletConfig,
|
||||||
|
WalletData};
|
||||||
use byteorder::{BigEndian, ByteOrder};
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
|
|
||||||
pub fn _get_chain_height(config: &WalletConfig) -> Result<u64, Error> {
|
pub fn get_chain_height(config: &WalletConfig) -> Result<u64, Error> {
|
||||||
let url = format!("{}/v1/chain", config.check_node_api_http_addr);
|
let url = format!("{}/v1/chain", config.check_node_api_http_addr);
|
||||||
|
|
||||||
match api::client::get::<api::Tip>(url.as_str()) {
|
match api::client::get::<api::Tip>(url.as_str()) {
|
||||||
|
@ -39,6 +41,29 @@ pub fn _get_chain_height(config: &WalletConfig) -> Result<u64, Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_merkle_proof_for_commit(
|
||||||
|
config: &WalletConfig,
|
||||||
|
commit: &str,
|
||||||
|
) -> Result<MerkleProofWrapper, Error> {
|
||||||
|
let url = format!(
|
||||||
|
"{}/v1/txhashset/merkleproof?id={}",
|
||||||
|
config.check_node_api_http_addr, commit
|
||||||
|
);
|
||||||
|
|
||||||
|
match api::client::get::<api::OutputPrintable>(url.as_str()) {
|
||||||
|
Ok(output) => Ok(MerkleProofWrapper(output.merkle_proof.unwrap())),
|
||||||
|
Err(e) => {
|
||||||
|
// if we got anything other than 200 back from server, bye
|
||||||
|
error!(
|
||||||
|
LOGGER,
|
||||||
|
"get_merkle_proof_for_pos: Restore failed... unable to create merkle proof for commit {}. Error: {}",
|
||||||
|
commit,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
Err(e.context(ErrorKind::Node).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
fn coinbase_status(output: &api::OutputPrintable) -> bool {
|
fn coinbase_status(output: &api::OutputPrintable) -> bool {
|
||||||
match output.output_type {
|
match output.output_type {
|
||||||
api::OutputType::Coinbase => true,
|
api::OutputType::Coinbase => true,
|
||||||
|
@ -75,15 +100,38 @@ pub fn outputs_batch(
|
||||||
|
|
||||||
// TODO - wrap the many return values in a struct
|
// TODO - wrap the many return values in a struct
|
||||||
fn find_outputs_with_key(
|
fn find_outputs_with_key(
|
||||||
|
config: &WalletConfig,
|
||||||
keychain: &Keychain,
|
keychain: &Keychain,
|
||||||
outputs: Vec<api::OutputPrintable>,
|
outputs: Vec<api::OutputPrintable>,
|
||||||
) -> Vec<(pedersen::Commitment, Identifier, u32, u64, u64, u64, bool)> {
|
) -> Vec<
|
||||||
let mut wallet_outputs: Vec<(pedersen::Commitment, Identifier, u32, u64, u64, u64, bool)> =
|
(
|
||||||
Vec::new();
|
pedersen::Commitment,
|
||||||
|
Identifier,
|
||||||
|
u32,
|
||||||
|
u64,
|
||||||
|
u64,
|
||||||
|
u64,
|
||||||
|
bool,
|
||||||
|
Option<MerkleProofWrapper>,
|
||||||
|
),
|
||||||
|
> {
|
||||||
|
let mut wallet_outputs: Vec<
|
||||||
|
(
|
||||||
|
pedersen::Commitment,
|
||||||
|
Identifier,
|
||||||
|
u32,
|
||||||
|
u64,
|
||||||
|
u64,
|
||||||
|
u64,
|
||||||
|
bool,
|
||||||
|
Option<MerkleProofWrapper>,
|
||||||
|
),
|
||||||
|
> = Vec::new();
|
||||||
|
|
||||||
let max_derivations = 1_000_000;
|
let max_derivations = 1_000_000;
|
||||||
|
|
||||||
info!(LOGGER, "Scanning {} outputs", outputs.len(),);
|
info!(LOGGER, "Scanning {} outputs", outputs.len(),);
|
||||||
|
let current_chain_height = get_chain_height(config).unwrap();
|
||||||
|
|
||||||
// skey doesn't matter in this case
|
// skey doesn't matter in this case
|
||||||
let skey = keychain.derive_key_id(1).unwrap();
|
let skey = keychain.derive_key_id(1).unwrap();
|
||||||
|
@ -135,12 +183,18 @@ fn find_outputs_with_key(
|
||||||
.commit_with_key_index(BigEndian::read_u64(&commit_id), i as u32)
|
.commit_with_key_index(BigEndian::read_u64(&commit_id), i as u32)
|
||||||
.expect("commit with key index");
|
.expect("commit with key index");
|
||||||
|
|
||||||
//let height = outputs.header.height;
|
let mut merkle_proof = None;
|
||||||
let height = 0;
|
let commit_str = util::to_hex(output.commit.as_ref().to_vec());
|
||||||
|
|
||||||
|
if is_coinbase {
|
||||||
|
merkle_proof = Some(get_merkle_proof_for_commit(config, &commit_str).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let height = current_chain_height;
|
||||||
let lock_height = if is_coinbase {
|
let lock_height = if is_coinbase {
|
||||||
height + global::coinbase_maturity()
|
height + global::coinbase_maturity()
|
||||||
} else {
|
} else {
|
||||||
0
|
height
|
||||||
};
|
};
|
||||||
|
|
||||||
wallet_outputs.push((
|
wallet_outputs.push((
|
||||||
|
@ -151,6 +205,7 @@ fn find_outputs_with_key(
|
||||||
height,
|
height,
|
||||||
lock_height,
|
lock_height,
|
||||||
is_coinbase,
|
is_coinbase,
|
||||||
|
merkle_proof,
|
||||||
));
|
));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -200,12 +255,11 @@ pub fn restore(config: &WalletConfig, keychain: &Keychain) -> Result<(), Error>
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = WalletData::with_wallet(&config.data_file_dir, |wallet_data| {
|
let _ = WalletData::with_wallet(&config.data_file_dir, |wallet_data| {
|
||||||
let result_vec = find_outputs_with_key(keychain, output_listing.outputs.clone());
|
let result_vec =
|
||||||
|
find_outputs_with_key(config, keychain, output_listing.outputs.clone());
|
||||||
if result_vec.len() > 0 {
|
if result_vec.len() > 0 {
|
||||||
for output in result_vec.clone() {
|
for output in result_vec.clone() {
|
||||||
let root_key_id = keychain.root_key_id();
|
let root_key_id = keychain.root_key_id();
|
||||||
// Just plonk it in for now, and refresh actual values via wallet info
|
|
||||||
// command later
|
|
||||||
wallet_data.add_output(OutputData {
|
wallet_data.add_output(OutputData {
|
||||||
root_key_id: root_key_id.clone(),
|
root_key_id: root_key_id.clone(),
|
||||||
key_id: output.1.clone(),
|
key_id: output.1.clone(),
|
||||||
|
@ -216,7 +270,7 @@ pub fn restore(config: &WalletConfig, keychain: &Keychain) -> Result<(), Error>
|
||||||
lock_height: output.5,
|
lock_height: output.5,
|
||||||
is_coinbase: output.6,
|
is_coinbase: output.6,
|
||||||
block: None,
|
block: None,
|
||||||
merkle_proof: None,
|
merkle_proof: output.7,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue