mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
Remove Sumtree References and disambiguate some naming (#747)
* start of renamathon * api renaming * Rename UTXO-Output to lessen ambiguity * compile warning * compile error * readme fix * remove file commit in error
This commit is contained in:
parent
884906421c
commit
1143d84238
89 changed files with 591 additions and 591 deletions
|
@ -9,7 +9,7 @@ Grin is an in-progress implementation of the MimbleWimble protocol. Many charact
|
|||
* Cuckoo Cycle proof of work (at least to start with).
|
||||
* Relatively fast block time (a minute or less, possibly decreasing as networks improve).
|
||||
* Fixed block reward, both over time and in blocks (fees are not additive).
|
||||
* Transaction fees are based on the number of UTXO created/destroyed and total transaction size.
|
||||
* Transaction fees are based on the number of Outputs created/destroyed and total transaction size.
|
||||
* Smooth curve for difficulty adjustments.
|
||||
|
||||
To learn more, read our [introduction to MimbleWimble and Grin](doc/intro.md).
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -58,15 +58,15 @@ impl Handler for IndexHandler {
|
|||
}
|
||||
|
||||
// Supports retrieval of multiple outputs in a single request -
|
||||
// GET /v1/chain/utxos/byids?id=xxx,yyy,zzz
|
||||
// GET /v1/chain/utxos/byids?id=xxx&id=yyy&id=zzz
|
||||
// GET /v1/chain/utxos/byheight?start_height=101&end_height=200
|
||||
struct UtxoHandler {
|
||||
// GET /v1/chain/outputs/byids?id=xxx,yyy,zzz
|
||||
// GET /v1/chain/outputs/byids?id=xxx&id=yyy&id=zzz
|
||||
// GET /v1/chain/outputs/byheight?start_height=101&end_height=200
|
||||
struct OutputHandler {
|
||||
chain: Weak<chain::Chain>,
|
||||
}
|
||||
|
||||
impl UtxoHandler {
|
||||
fn get_utxo(&self, id: &str) -> Result<Utxo, Error> {
|
||||
impl OutputHandler {
|
||||
fn get_output(&self, id: &str) -> Result<Output, Error> {
|
||||
let c = util::from_hex(String::from(id))
|
||||
.map_err(|_| Error::Argument(format!("Not a valid commitment: {}", id)))?;
|
||||
let commit = Commitment::from_vec(c);
|
||||
|
@ -82,13 +82,13 @@ impl UtxoHandler {
|
|||
|
||||
for x in outputs.iter() {
|
||||
if let Ok(_) = w(&self.chain).is_unspent(&x) {
|
||||
return Ok(Utxo::new(&commit));
|
||||
return Ok(Output::new(&commit));
|
||||
}
|
||||
}
|
||||
Err(Error::NotFound)
|
||||
}
|
||||
|
||||
fn utxos_by_ids(&self, req: &mut Request) -> Vec<Utxo> {
|
||||
fn outputs_by_ids(&self, req: &mut Request) -> Vec<Output> {
|
||||
let mut commitments: Vec<&str> = vec![];
|
||||
if let Ok(params) = req.get_ref::<UrlEncodedQuery>() {
|
||||
if let Some(ids) = params.get("id") {
|
||||
|
@ -100,15 +100,15 @@ impl UtxoHandler {
|
|||
}
|
||||
}
|
||||
|
||||
debug!(LOGGER, "utxos_by_ids: {:?}", commitments);
|
||||
debug!(LOGGER, "outputs_by_ids: {:?}", commitments);
|
||||
|
||||
let mut utxos: Vec<Utxo> = vec![];
|
||||
let mut outputs: Vec<Output> = vec![];
|
||||
for x in commitments {
|
||||
if let Ok(utxo) = self.get_utxo(x) {
|
||||
utxos.push(utxo);
|
||||
if let Ok(output) = self.get_output(x) {
|
||||
outputs.push(output);
|
||||
}
|
||||
}
|
||||
utxos
|
||||
outputs
|
||||
}
|
||||
|
||||
fn outputs_at_height(
|
||||
|
@ -186,7 +186,7 @@ impl UtxoHandler {
|
|||
}
|
||||
}
|
||||
|
||||
impl Handler for UtxoHandler {
|
||||
impl Handler for OutputHandler {
|
||||
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||
let url = req.url.clone();
|
||||
let mut path_elems = url.path();
|
||||
|
@ -194,7 +194,7 @@ impl Handler for UtxoHandler {
|
|||
path_elems.pop();
|
||||
}
|
||||
match *path_elems.last().unwrap() {
|
||||
"byids" => json_response(&self.utxos_by_ids(req)),
|
||||
"byids" => json_response(&self.outputs_by_ids(req)),
|
||||
"byheight" => json_response(&self.outputs_block_batch(req)),
|
||||
_ => Ok(Response::with((status::BadRequest, ""))),
|
||||
}
|
||||
|
@ -202,40 +202,40 @@ impl Handler for UtxoHandler {
|
|||
}
|
||||
|
||||
// Sum tree handler. Retrieve the roots:
|
||||
// GET /v1/pmmrtrees/roots
|
||||
// GET /v1/txhashset/roots
|
||||
//
|
||||
// Last inserted nodes::
|
||||
// GET /v1/pmmrtrees/lastutxos (gets last 10)
|
||||
// GET /v1/pmmrtrees/lastutxos?n=5
|
||||
// GET /v1/pmmrtrees/lastrangeproofs
|
||||
// GET /v1/pmmrtrees/lastkernels
|
||||
struct SumTreeHandler {
|
||||
// GET /v1/txhashset/lastoutputs (gets last 10)
|
||||
// GET /v1/txhashset/lastoutputs?n=5
|
||||
// GET /v1/txhashset/lastrangeproofs
|
||||
// GET /v1/txhashset/lastkernels
|
||||
struct TxHashSetHandler {
|
||||
chain: Weak<chain::Chain>,
|
||||
}
|
||||
|
||||
impl SumTreeHandler {
|
||||
impl TxHashSetHandler {
|
||||
// gets roots
|
||||
fn get_roots(&self) -> SumTrees {
|
||||
SumTrees::from_head(w(&self.chain))
|
||||
fn get_roots(&self) -> TxHashSet {
|
||||
TxHashSet::from_head(w(&self.chain))
|
||||
}
|
||||
|
||||
// gets last n utxos inserted in to the tree
|
||||
fn get_last_n_utxo(&self, distance: u64) -> Vec<PmmrTreeNode> {
|
||||
PmmrTreeNode::get_last_n_utxo(w(&self.chain), distance)
|
||||
// gets last n outputs inserted in to the tree
|
||||
fn get_last_n_output(&self, distance: u64) -> Vec<TxHashSetNode> {
|
||||
TxHashSetNode::get_last_n_output(w(&self.chain), distance)
|
||||
}
|
||||
|
||||
// gets last n utxos inserted in to the tree
|
||||
fn get_last_n_rangeproof(&self, distance: u64) -> Vec<PmmrTreeNode> {
|
||||
PmmrTreeNode::get_last_n_rangeproof(w(&self.chain), distance)
|
||||
// gets last n outputs inserted in to the tree
|
||||
fn get_last_n_rangeproof(&self, distance: u64) -> Vec<TxHashSetNode> {
|
||||
TxHashSetNode::get_last_n_rangeproof(w(&self.chain), distance)
|
||||
}
|
||||
|
||||
// gets last n utxos inserted in to the tree
|
||||
fn get_last_n_kernel(&self, distance: u64) -> Vec<PmmrTreeNode> {
|
||||
PmmrTreeNode::get_last_n_kernel(w(&self.chain), distance)
|
||||
// gets last n outputs inserted in to the tree
|
||||
fn get_last_n_kernel(&self, distance: u64) -> Vec<TxHashSetNode> {
|
||||
TxHashSetNode::get_last_n_kernel(w(&self.chain), distance)
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for SumTreeHandler {
|
||||
impl Handler for TxHashSetHandler {
|
||||
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||
let url = req.url.clone();
|
||||
let mut path_elems = url.path();
|
||||
|
@ -255,7 +255,7 @@ impl Handler for SumTreeHandler {
|
|||
}
|
||||
match *path_elems.last().unwrap() {
|
||||
"roots" => json_response_pretty(&self.get_roots()),
|
||||
"lastutxos" => json_response_pretty(&self.get_last_n_utxo(last_n)),
|
||||
"lastoutputs" => json_response_pretty(&self.get_last_n_output(last_n)),
|
||||
"lastrangeproofs" => json_response_pretty(&self.get_last_n_rangeproof(last_n)),
|
||||
"lastkernels" => json_response_pretty(&self.get_last_n_kernel(last_n)),
|
||||
_ => Ok(Response::with((status::BadRequest, ""))),
|
||||
|
@ -572,7 +572,7 @@ pub fn start_rest_apis<T>(
|
|||
.name("apis".to_string())
|
||||
.spawn(move || {
|
||||
// build handlers and register them under the appropriate endpoint
|
||||
let utxo_handler = UtxoHandler {
|
||||
let output_handler = OutputHandler {
|
||||
chain: chain.clone(),
|
||||
};
|
||||
let block_handler = BlockHandler {
|
||||
|
@ -585,7 +585,7 @@ pub fn start_rest_apis<T>(
|
|||
chain: chain.clone(),
|
||||
peers: peers.clone(),
|
||||
};
|
||||
let sumtree_handler = SumTreeHandler {
|
||||
let txhashset_handler = TxHashSetHandler {
|
||||
chain: chain.clone(),
|
||||
};
|
||||
let pool_info_handler = PoolInfoHandler {
|
||||
|
@ -610,12 +610,12 @@ pub fn start_rest_apis<T>(
|
|||
let route_list = vec![
|
||||
"get blocks".to_string(),
|
||||
"get chain".to_string(),
|
||||
"get chain/utxos".to_string(),
|
||||
"get chain/outputs".to_string(),
|
||||
"get status".to_string(),
|
||||
"get pmmrtrees/roots".to_string(),
|
||||
"get pmmrtrees/lastutxos?n=10".to_string(),
|
||||
"get pmmrtrees/lastrangeproofs".to_string(),
|
||||
"get pmmrtrees/lastkernels".to_string(),
|
||||
"get txhashset/roots".to_string(),
|
||||
"get txhashset/lastoutputs?n=10".to_string(),
|
||||
"get txhashset/lastrangeproofs".to_string(),
|
||||
"get txhashset/lastkernels".to_string(),
|
||||
"get pool".to_string(),
|
||||
"post pool/push".to_string(),
|
||||
"post peers/a.b.c.d:p/ban".to_string(),
|
||||
|
@ -631,9 +631,9 @@ pub fn start_rest_apis<T>(
|
|||
index: get "/" => index_handler,
|
||||
blocks: get "/blocks/*" => block_handler,
|
||||
chain_tip: get "/chain" => chain_tip_handler,
|
||||
chain_utxos: get "/chain/utxos/*" => utxo_handler,
|
||||
chain_outputs: get "/chain/outputs/*" => output_handler,
|
||||
status: get "/status" => status_handler,
|
||||
sumtree_roots: get "/pmmrtrees/*" => sumtree_handler,
|
||||
txhashset_roots: get "/txhashset/*" => txhashset_handler,
|
||||
pool_info: get "/pool" => pool_info_handler,
|
||||
pool_push: post "/pool/push" => pool_push_handler,
|
||||
peers_all: get "/peers/all" => peers_all_handler,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -84,64 +84,64 @@ impl Status {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sumtrees
|
||||
/// TxHashSet
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct SumTrees {
|
||||
/// UTXO Root Hash
|
||||
pub utxo_root_hash: String,
|
||||
pub struct TxHashSet {
|
||||
/// Output Root Hash
|
||||
pub output_root_hash: String,
|
||||
// Rangeproof root hash
|
||||
pub range_proof_root_hash: String,
|
||||
// Kernel set root hash
|
||||
pub kernel_root_hash: String,
|
||||
}
|
||||
|
||||
impl SumTrees {
|
||||
pub fn from_head(head: Arc<chain::Chain>) -> SumTrees {
|
||||
let roots = head.get_sumtree_roots();
|
||||
SumTrees {
|
||||
utxo_root_hash: roots.0.to_hex(),
|
||||
impl TxHashSet {
|
||||
pub fn from_head(head: Arc<chain::Chain>) -> TxHashSet {
|
||||
let roots = head.get_txhashset_roots();
|
||||
TxHashSet {
|
||||
output_root_hash: roots.0.to_hex(),
|
||||
range_proof_root_hash: roots.1.to_hex(),
|
||||
kernel_root_hash: roots.2.to_hex(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around a list of sumtree nodes, so it can be
|
||||
/// Wrapper around a list of txhashset nodes, so it can be
|
||||
/// presented properly via json
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct PmmrTreeNode {
|
||||
pub struct TxHashSetNode {
|
||||
// The hash
|
||||
pub hash: String,
|
||||
}
|
||||
|
||||
impl PmmrTreeNode {
|
||||
pub fn get_last_n_utxo(chain: Arc<chain::Chain>, distance: u64) -> Vec<PmmrTreeNode> {
|
||||
impl TxHashSetNode {
|
||||
pub fn get_last_n_output(chain: Arc<chain::Chain>, distance: u64) -> Vec<TxHashSetNode> {
|
||||
let mut return_vec = Vec::new();
|
||||
let last_n = chain.get_last_n_utxo(distance);
|
||||
let last_n = chain.get_last_n_output(distance);
|
||||
for x in last_n {
|
||||
return_vec.push(PmmrTreeNode {
|
||||
return_vec.push(TxHashSetNode {
|
||||
hash: util::to_hex(x.0.to_vec()),
|
||||
});
|
||||
}
|
||||
return_vec
|
||||
}
|
||||
|
||||
pub fn get_last_n_rangeproof(head: Arc<chain::Chain>, distance: u64) -> Vec<PmmrTreeNode> {
|
||||
pub fn get_last_n_rangeproof(head: Arc<chain::Chain>, distance: u64) -> Vec<TxHashSetNode> {
|
||||
let mut return_vec = Vec::new();
|
||||
let last_n = head.get_last_n_rangeproof(distance);
|
||||
for elem in last_n {
|
||||
return_vec.push(PmmrTreeNode {
|
||||
return_vec.push(TxHashSetNode {
|
||||
hash: util::to_hex(elem.0.to_vec()),
|
||||
});
|
||||
}
|
||||
return_vec
|
||||
}
|
||||
|
||||
pub fn get_last_n_kernel(head: Arc<chain::Chain>, distance: u64) -> Vec<PmmrTreeNode> {
|
||||
pub fn get_last_n_kernel(head: Arc<chain::Chain>, distance: u64) -> Vec<TxHashSetNode> {
|
||||
let mut return_vec = Vec::new();
|
||||
let last_n = head.get_last_n_kernel(distance);
|
||||
for elem in last_n {
|
||||
return_vec.push(PmmrTreeNode {
|
||||
return_vec.push(TxHashSetNode {
|
||||
hash: util::to_hex(elem.0.to_vec()),
|
||||
});
|
||||
}
|
||||
|
@ -156,14 +156,14 @@ pub enum OutputType {
|
|||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Utxo {
|
||||
pub struct Output {
|
||||
/// The output commitment representing the amount
|
||||
pub commit: PrintableCommitment,
|
||||
}
|
||||
|
||||
impl Utxo {
|
||||
pub fn new(commit: &pedersen::Commitment) -> Utxo {
|
||||
Utxo {
|
||||
impl Output {
|
||||
pub fn new(commit: &pedersen::Commitment) -> Output {
|
||||
Output {
|
||||
commit: PrintableCommitment(commit.clone()),
|
||||
}
|
||||
}
|
||||
|
@ -503,11 +503,11 @@ pub struct BlockHeaderPrintable {
|
|||
pub previous: String,
|
||||
/// rfc3339 timestamp at which the block was built.
|
||||
pub timestamp: String,
|
||||
/// Merklish root of all the commitments in the UTXO set
|
||||
pub utxo_root: String,
|
||||
/// Merklish root of all range proofs in the UTXO set
|
||||
/// Merklish root of all the commitments in the TxHashSet
|
||||
pub output_root: String,
|
||||
/// Merklish root of all range proofs in the TxHashSet
|
||||
pub range_proof_root: String,
|
||||
/// Merklish root of all transaction kernels in the UTXO set
|
||||
/// Merklish root of all transaction kernels in the TxHashSet
|
||||
pub kernel_root: String,
|
||||
/// Nonce increment used to mine this block.
|
||||
pub nonce: u64,
|
||||
|
@ -525,7 +525,7 @@ impl BlockHeaderPrintable {
|
|||
height: h.height,
|
||||
previous: util::to_hex(h.previous.to_vec()),
|
||||
timestamp: h.timestamp.rfc3339().to_string(),
|
||||
utxo_root: util::to_hex(h.utxo_root.to_vec()),
|
||||
output_root: util::to_hex(h.output_root.to_vec()),
|
||||
range_proof_root: util::to_hex(h.range_proof_root.to_vec()),
|
||||
kernel_root: util::to_hex(h.kernel_root.to_vec()),
|
||||
nonce: h.nonce,
|
||||
|
@ -643,7 +643,7 @@ mod test {
|
|||
use serde_json;
|
||||
|
||||
#[test]
|
||||
fn serialize_output() {
|
||||
fn serialize_output_printable() {
|
||||
let hex_output =
|
||||
"{\
|
||||
\"output_type\":\"Coinbase\",\
|
||||
|
@ -660,10 +660,10 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_utxo() {
|
||||
fn serialize_output() {
|
||||
let hex_commit =
|
||||
"{\"commit\":\"083eafae5d61a85ab07b12e1a51b3918d8e6de11fc6cde641d54af53608aa77b9f\"}";
|
||||
let deserialized: Utxo = serde_json::from_str(&hex_commit).unwrap();
|
||||
let deserialized: Output = serde_json::from_str(&hex_commit).unwrap();
|
||||
let serialized = serde_json::to_string(&deserialized).unwrap();
|
||||
assert_eq!(serialized, hex_commit);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -29,7 +29,7 @@ use core::global;
|
|||
use grin_store::Error::NotFoundErr;
|
||||
use pipe;
|
||||
use store;
|
||||
use sumtree;
|
||||
use txhashset;
|
||||
use types::*;
|
||||
use util::secp::pedersen::RangeProof;
|
||||
use util::LOGGER;
|
||||
|
@ -110,7 +110,7 @@ impl OrphanBlockPool {
|
|||
}
|
||||
|
||||
/// Facade to the blockchain block processing pipeline and storage. Provides
|
||||
/// the current view of the UTXO set according to the chain state. Also
|
||||
/// the current view of the TxHashSet according to the chain state. Also
|
||||
/// maintains locking for the pipeline to avoid conflicting processing.
|
||||
pub struct Chain {
|
||||
db_root: String,
|
||||
|
@ -119,7 +119,7 @@ pub struct Chain {
|
|||
|
||||
head: Arc<Mutex<Tip>>,
|
||||
orphans: Arc<OrphanBlockPool>,
|
||||
sumtrees: Arc<RwLock<sumtree::SumTrees>>,
|
||||
txhashset: Arc<RwLock<txhashset::TxHashSet>>,
|
||||
|
||||
// POW verification function
|
||||
pow_verifier: fn(&BlockHeader, u32) -> bool,
|
||||
|
@ -156,13 +156,13 @@ impl Chain {
|
|||
|
||||
// check if we have a head in store, otherwise the genesis block is it
|
||||
let head = store.head();
|
||||
let sumtree_md = match head {
|
||||
let txhashset_md = match head {
|
||||
Ok(h) => Some(store.get_block_pmmr_file_metadata(&h.last_block_h)?),
|
||||
Err(NotFoundErr) => None,
|
||||
Err(e) => return Err(Error::StoreErr(e, "chain init load head".to_owned())),
|
||||
};
|
||||
|
||||
let mut sumtrees = sumtree::SumTrees::open(db_root.clone(), store.clone(), sumtree_md)?;
|
||||
let mut txhashset = txhashset::TxHashSet::open(db_root.clone(), store.clone(), txhashset_md)?;
|
||||
|
||||
let head = store.head();
|
||||
let head = match head {
|
||||
|
@ -172,7 +172,7 @@ impl Chain {
|
|||
store.save_block(&genesis)?;
|
||||
store.setup_height(&genesis.header, &tip)?;
|
||||
if genesis.kernels.len() > 0 {
|
||||
sumtree::extending(&mut sumtrees, |extension| extension.apply_block(&genesis))?;
|
||||
txhashset::extending(&mut txhashset, |extension| extension.apply_block(&genesis))?;
|
||||
}
|
||||
|
||||
// saving a new tip based on genesis
|
||||
|
@ -184,7 +184,7 @@ impl Chain {
|
|||
genesis.header.nonce,
|
||||
genesis.header.pow,
|
||||
);
|
||||
pipe::save_pmmr_metadata(&tip, &sumtrees, store.clone())?;
|
||||
pipe::save_pmmr_metadata(&tip, &txhashset, store.clone())?;
|
||||
tip
|
||||
}
|
||||
Err(e) => return Err(Error::StoreErr(e, "chain init load head".to_owned())),
|
||||
|
@ -202,7 +202,7 @@ impl Chain {
|
|||
adapter: adapter,
|
||||
head: Arc::new(Mutex::new(head)),
|
||||
orphans: Arc::new(OrphanBlockPool::new()),
|
||||
sumtrees: Arc::new(RwLock::new(sumtrees)),
|
||||
txhashset: Arc::new(RwLock::new(txhashset)),
|
||||
pow_verifier: pow_verifier,
|
||||
})
|
||||
}
|
||||
|
@ -349,7 +349,7 @@ impl Chain {
|
|||
store: self.store.clone(),
|
||||
head: head,
|
||||
pow_verifier: self.pow_verifier,
|
||||
sumtrees: self.sumtrees.clone(),
|
||||
txhashset: self.txhashset.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,15 +396,15 @@ impl Chain {
|
|||
/// This querying is done in a way that is consistent with the current chain state,
|
||||
/// specifically the current winning (valid, most work) fork.
|
||||
pub fn is_unspent(&self, output_ref: &OutputIdentifier) -> Result<Hash, Error> {
|
||||
let mut sumtrees = self.sumtrees.write().unwrap();
|
||||
sumtrees.is_unspent(output_ref)
|
||||
let mut txhashset = self.txhashset.write().unwrap();
|
||||
txhashset.is_unspent(output_ref)
|
||||
}
|
||||
|
||||
/// Validate the current chain state.
|
||||
pub fn validate(&self) -> Result<(), Error> {
|
||||
let header = self.store.head_header()?;
|
||||
let mut sumtrees = self.sumtrees.write().unwrap();
|
||||
sumtree::extending(&mut sumtrees, |extension| extension.validate(&header))
|
||||
let mut txhashset = self.txhashset.write().unwrap();
|
||||
txhashset::extending(&mut txhashset, |extension| extension.validate(&header))
|
||||
}
|
||||
|
||||
/// Check if the input has matured sufficiently for the given block height.
|
||||
|
@ -412,23 +412,23 @@ impl Chain {
|
|||
/// An input spending a non-coinbase output will always pass this check.
|
||||
pub fn is_matured(&self, input: &Input, height: u64) -> Result<(), Error> {
|
||||
if input.features.contains(OutputFeatures::COINBASE_OUTPUT) {
|
||||
let mut sumtrees = self.sumtrees.write().unwrap();
|
||||
let mut txhashset = self.txhashset.write().unwrap();
|
||||
let output = OutputIdentifier::from_input(&input);
|
||||
let hash = sumtrees.is_unspent(&output)?;
|
||||
let hash = txhashset.is_unspent(&output)?;
|
||||
let header = self.get_block_header(&input.block_hash())?;
|
||||
input.verify_maturity(hash, &header, height)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the sumtree roots on a brand new block by applying the block on the
|
||||
/// current sumtree state.
|
||||
pub fn set_sumtree_roots(&self, b: &mut Block, is_fork: bool) -> Result<(), Error> {
|
||||
let mut sumtrees = self.sumtrees.write().unwrap();
|
||||
/// Sets the txhashset roots on a brand new block by applying the block on the
|
||||
/// current txhashset state.
|
||||
pub fn set_txhashset_roots(&self, b: &mut Block, is_fork: bool) -> Result<(), Error> {
|
||||
let mut txhashset = self.txhashset.write().unwrap();
|
||||
let store = self.store.clone();
|
||||
|
||||
let roots = sumtree::extending(&mut sumtrees, |extension| {
|
||||
// apply the block on the sumtrees and check the resulting root
|
||||
let roots = txhashset::extending(&mut txhashset, |extension| {
|
||||
// apply the block on the txhashset and check the resulting root
|
||||
if is_fork {
|
||||
pipe::rewind_and_apply_fork(b, store, extension)?;
|
||||
}
|
||||
|
@ -437,7 +437,7 @@ impl Chain {
|
|||
Ok(extension.roots())
|
||||
})?;
|
||||
|
||||
b.header.utxo_root = roots.utxo_root;
|
||||
b.header.output_root = roots.output_root;
|
||||
b.header.range_proof_root = roots.rproof_root;
|
||||
b.header.kernel_root = roots.kernel_root;
|
||||
Ok(())
|
||||
|
@ -449,9 +449,9 @@ impl Chain {
|
|||
output: &OutputIdentifier,
|
||||
block: &Block,
|
||||
) -> Result<MerkleProof, Error> {
|
||||
let mut sumtrees = self.sumtrees.write().unwrap();
|
||||
let mut txhashset = self.txhashset.write().unwrap();
|
||||
|
||||
let merkle_proof = sumtree::extending(&mut sumtrees, |extension| {
|
||||
let merkle_proof = txhashset::extending(&mut txhashset, |extension| {
|
||||
extension.force_rollback();
|
||||
extension.merkle_proof_via_rewind(output, block)
|
||||
})?;
|
||||
|
@ -459,66 +459,66 @@ impl Chain {
|
|||
Ok(merkle_proof)
|
||||
}
|
||||
|
||||
/// Returns current sumtree roots
|
||||
pub fn get_sumtree_roots(&self) -> (Hash, Hash, Hash) {
|
||||
let mut sumtrees = self.sumtrees.write().unwrap();
|
||||
sumtrees.roots()
|
||||
/// Returns current txhashset roots
|
||||
pub fn get_txhashset_roots(&self) -> (Hash, Hash, Hash) {
|
||||
let mut txhashset = self.txhashset.write().unwrap();
|
||||
txhashset.roots()
|
||||
}
|
||||
|
||||
/// Provides a reading view into the current sumtree state as well as
|
||||
/// Provides a reading view into the current txhashset state as well as
|
||||
/// the required indexes for a consumer to rewind to a consistent state
|
||||
/// at the provided block hash.
|
||||
pub fn sumtrees_read(&self, h: Hash) -> Result<(u64, u64, File), Error> {
|
||||
pub fn txhashset_read(&self, h: Hash) -> Result<(u64, u64, File), Error> {
|
||||
let b = self.get_block(&h)?;
|
||||
|
||||
// get the indexes for the block
|
||||
let out_index: u64;
|
||||
let kernel_index: u64;
|
||||
{
|
||||
let sumtrees = self.sumtrees.read().unwrap();
|
||||
let (oi, ki) = sumtrees.indexes_at(&b)?;
|
||||
let txhashset = self.txhashset.read().unwrap();
|
||||
let (oi, ki) = txhashset.indexes_at(&b)?;
|
||||
out_index = oi;
|
||||
kernel_index = ki;
|
||||
}
|
||||
|
||||
// prepares the zip and return the corresponding Read
|
||||
let sumtree_reader = sumtree::zip_read(self.db_root.clone())?;
|
||||
Ok((out_index, kernel_index, sumtree_reader))
|
||||
let txhashset_reader = txhashset::zip_read(self.db_root.clone())?;
|
||||
Ok((out_index, kernel_index, txhashset_reader))
|
||||
}
|
||||
|
||||
/// Writes a reading view on a sumtree state that's been provided to us.
|
||||
/// Writes a reading view on a txhashset state that's been provided to us.
|
||||
/// If we're willing to accept that new state, the data stream will be
|
||||
/// read as a zip file, unzipped and the resulting state files should be
|
||||
/// rewound to the provided indexes.
|
||||
pub fn sumtrees_write(
|
||||
pub fn txhashset_write(
|
||||
&self,
|
||||
h: Hash,
|
||||
rewind_to_output: u64,
|
||||
rewind_to_kernel: u64,
|
||||
sumtree_data: File,
|
||||
txhashset_data: File,
|
||||
) -> Result<(), Error> {
|
||||
let head = self.head().unwrap();
|
||||
let header_head = self.get_header_head().unwrap();
|
||||
if header_head.height - head.height < global::cut_through_horizon() as u64 {
|
||||
return Err(Error::InvalidSumtree("not needed".to_owned()));
|
||||
return Err(Error::InvalidTxHashSet("not needed".to_owned()));
|
||||
}
|
||||
|
||||
let header = self.store.get_block_header(&h)?;
|
||||
sumtree::zip_write(self.db_root.clone(), sumtree_data)?;
|
||||
txhashset::zip_write(self.db_root.clone(), txhashset_data)?;
|
||||
|
||||
let mut sumtrees = sumtree::SumTrees::open(self.db_root.clone(), self.store.clone(), None)?;
|
||||
sumtree::extending(&mut sumtrees, |extension| {
|
||||
let mut txhashset = txhashset::TxHashSet::open(self.db_root.clone(), self.store.clone(), None)?;
|
||||
txhashset::extending(&mut txhashset, |extension| {
|
||||
extension.rewind_pos(header.height, rewind_to_output, rewind_to_kernel)?;
|
||||
extension.validate(&header)?;
|
||||
// TODO validate kernels and their sums with UTXOs
|
||||
// TODO validate kernels and their sums with Outputs
|
||||
extension.rebuild_index()?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// replace the chain sumtrees with the newly built one
|
||||
// replace the chain txhashset with the newly built one
|
||||
{
|
||||
let mut sumtrees_ref = self.sumtrees.write().unwrap();
|
||||
*sumtrees_ref = sumtrees;
|
||||
let mut txhashset_ref = self.txhashset.write().unwrap();
|
||||
*txhashset_ref = txhashset;
|
||||
}
|
||||
|
||||
// setup new head
|
||||
|
@ -534,22 +534,22 @@ impl Chain {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// returns the last n nodes inserted into the utxo sum tree
|
||||
pub fn get_last_n_utxo(&self, distance: u64) -> Vec<(Hash, Option<OutputStoreable>)> {
|
||||
let mut sumtrees = self.sumtrees.write().unwrap();
|
||||
sumtrees.last_n_utxo(distance)
|
||||
/// returns the last n nodes inserted into the output sum tree
|
||||
pub fn get_last_n_output(&self, distance: u64) -> Vec<(Hash, Option<OutputStoreable>)> {
|
||||
let mut txhashset = self.txhashset.write().unwrap();
|
||||
txhashset.last_n_output(distance)
|
||||
}
|
||||
|
||||
/// as above, for rangeproofs
|
||||
pub fn get_last_n_rangeproof(&self, distance: u64) -> Vec<(Hash, Option<RangeProof>)> {
|
||||
let mut sumtrees = self.sumtrees.write().unwrap();
|
||||
sumtrees.last_n_rangeproof(distance)
|
||||
let mut txhashset = self.txhashset.write().unwrap();
|
||||
txhashset.last_n_rangeproof(distance)
|
||||
}
|
||||
|
||||
/// as above, for kernels
|
||||
pub fn get_last_n_kernel(&self, distance: u64) -> Vec<(Hash, Option<TxKernel>)> {
|
||||
let mut sumtrees = self.sumtrees.write().unwrap();
|
||||
sumtrees.last_n_kernel(distance)
|
||||
let mut txhashset = self.txhashset.write().unwrap();
|
||||
txhashset.last_n_kernel(distance)
|
||||
}
|
||||
|
||||
/// Total difficulty at the head of the chain
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -37,7 +37,7 @@ extern crate grin_util as util;
|
|||
mod chain;
|
||||
pub mod pipe;
|
||||
pub mod store;
|
||||
pub mod sumtree;
|
||||
pub mod txhashset;
|
||||
pub mod types;
|
||||
|
||||
// Re-export the base interface
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -25,7 +25,7 @@ use core::core::target::Difficulty;
|
|||
use grin_store;
|
||||
use types::*;
|
||||
use store;
|
||||
use sumtree;
|
||||
use txhashset;
|
||||
use core::global;
|
||||
use util::LOGGER;
|
||||
|
||||
|
@ -41,7 +41,7 @@ pub struct BlockContext {
|
|||
/// The POW verification function
|
||||
pub pow_verifier: fn(&BlockHeader, u32) -> bool,
|
||||
/// MMR sum tree states
|
||||
pub sumtrees: Arc<RwLock<sumtree::SumTrees>>,
|
||||
pub txhashset: Arc<RwLock<txhashset::TxHashSet>>,
|
||||
}
|
||||
|
||||
/// Runs the block processing pipeline, including validation and finding a
|
||||
|
@ -85,8 +85,8 @@ pub fn process_block(b: &Block, mut ctx: BlockContext) -> Result<Option<Tip>, Er
|
|||
|
||||
// valid header and we have a previous block, time to take the lock on the sum
|
||||
// trees
|
||||
let local_sumtrees = ctx.sumtrees.clone();
|
||||
let mut sumtrees = local_sumtrees.write().unwrap();
|
||||
let local_txhashset = ctx.txhashset.clone();
|
||||
let mut txhashset = local_txhashset.write().unwrap();
|
||||
|
||||
// update head now that we're in the lock
|
||||
ctx.head = ctx.store
|
||||
|
@ -95,7 +95,7 @@ pub fn process_block(b: &Block, mut ctx: BlockContext) -> Result<Option<Tip>, Er
|
|||
|
||||
// start a chain extension unit of work dependent on the success of the
|
||||
// internal validation and saving operations
|
||||
let result = sumtree::extending(&mut sumtrees, |mut extension| {
|
||||
let result = txhashset::extending(&mut txhashset, |mut extension| {
|
||||
validate_block(b, &mut ctx, &mut extension)?;
|
||||
debug!(
|
||||
LOGGER,
|
||||
|
@ -114,7 +114,7 @@ pub fn process_block(b: &Block, mut ctx: BlockContext) -> Result<Option<Tip>, Er
|
|||
|
||||
match result {
|
||||
Ok(t) => {
|
||||
save_pmmr_metadata(&Tip::from_block(&b.header), &sumtrees, ctx.store.clone())?;
|
||||
save_pmmr_metadata(&Tip::from_block(&b.header), &txhashset, ctx.store.clone())?;
|
||||
Ok(t)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
|
@ -124,11 +124,11 @@ pub fn process_block(b: &Block, mut ctx: BlockContext) -> Result<Option<Tip>, Er
|
|||
/// Save pmmr index location for a given block
|
||||
pub fn save_pmmr_metadata(
|
||||
t: &Tip,
|
||||
sumtrees: &sumtree::SumTrees,
|
||||
txhashset: &txhashset::TxHashSet,
|
||||
store: Arc<ChainStore>,
|
||||
) -> Result<(), Error> {
|
||||
// Save pmmr file metadata for this block
|
||||
let block_file_md = sumtrees.last_file_metadata();
|
||||
let block_file_md = txhashset.last_file_metadata();
|
||||
store
|
||||
.save_block_pmmr_file_metadata(&t.last_block_h, &block_file_md)
|
||||
.map_err(|e| Error::StoreErr(e, "saving pmmr file metadata".to_owned()))?;
|
||||
|
@ -153,9 +153,9 @@ pub fn sync_block_header(
|
|||
add_block_header(bh, &mut sync_ctx)?;
|
||||
|
||||
// TODO - confirm this is needed during sync process (I don't see how it is)
|
||||
// we do not touch the sumtrees when syncing headers
|
||||
// we do not touch the txhashset when syncing headers
|
||||
// just taking the shared lock
|
||||
let _ = header_ctx.sumtrees.write().unwrap();
|
||||
let _ = header_ctx.txhashset.write().unwrap();
|
||||
|
||||
// now update the header_head (if new header with most work) and the sync_head
|
||||
// (always)
|
||||
|
@ -329,7 +329,7 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), E
|
|||
fn validate_block(
|
||||
b: &Block,
|
||||
ctx: &mut BlockContext,
|
||||
ext: &mut sumtree::Extension,
|
||||
ext: &mut txhashset::Extension,
|
||||
) -> Result<(), Error> {
|
||||
// main isolated block validation, checks all commitment sums and sigs
|
||||
b.validate().map_err(&Error::InvalidBlockProof)?;
|
||||
|
@ -342,14 +342,14 @@ fn validate_block(
|
|||
ext.apply_block(&b)?;
|
||||
|
||||
let roots = ext.roots();
|
||||
if roots.utxo_root != b.header.utxo_root || roots.rproof_root != b.header.range_proof_root
|
||||
if roots.output_root != b.header.output_root || roots.rproof_root != b.header.range_proof_root
|
||||
|| roots.kernel_root != b.header.kernel_root
|
||||
{
|
||||
ext.dump(false);
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"validate_block: utxo roots - {:?}, {:?}", roots.utxo_root, b.header.utxo_root,
|
||||
"validate_block: output roots - {:?}, {:?}", roots.output_root, b.header.output_root,
|
||||
);
|
||||
debug!(
|
||||
LOGGER,
|
||||
|
@ -489,13 +489,13 @@ fn update_header_head(bh: &BlockHeader, ctx: &mut BlockContext) -> Result<Option
|
|||
}
|
||||
|
||||
/// Utility function to handle forks. From the forked block, jump backward
|
||||
/// to find to fork root. Rewind the sumtrees to the root and apply all the
|
||||
/// forked blocks prior to the one being processed to set the sumtrees in
|
||||
/// to find to fork root. Rewind the txhashset to the root and apply all the
|
||||
/// forked blocks prior to the one being processed to set the txhashset in
|
||||
/// the expected state.
|
||||
pub fn rewind_and_apply_fork(
|
||||
b: &Block,
|
||||
store: Arc<ChainStore>,
|
||||
ext: &mut sumtree::Extension,
|
||||
ext: &mut txhashset::Extension,
|
||||
) -> Result<(), Error> {
|
||||
// extending a fork, first identify the block where forking occurred
|
||||
// keeping the hashes of blocks along the fork
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Utility structs to handle the 3 sumtrees (utxo, range proof, kernel) more
|
||||
//! Utility structs to handle the 3 hashtrees (output, range proof, kernel) more
|
||||
//! conveniently and transactionally.
|
||||
|
||||
use std::fs;
|
||||
|
@ -34,14 +34,14 @@ use core::ser::{self, PMMRable, PMMRIndexHashable};
|
|||
|
||||
use grin_store;
|
||||
use grin_store::pmmr::{PMMRBackend, PMMRFileMetadata};
|
||||
use types::{ChainStore, Error, PMMRFileMetadataCollection, SumTreeRoots};
|
||||
use types::{ChainStore, Error, PMMRFileMetadataCollection, TxHashSetRoots};
|
||||
use util::{zip, LOGGER};
|
||||
|
||||
const SUMTREES_SUBDIR: &'static str = "sumtrees";
|
||||
const UTXO_SUBDIR: &'static str = "utxo";
|
||||
const TXHASHSET_SUBDIR: &'static str = "txhashset";
|
||||
const OUTPUT_SUBDIR: &'static str = "output";
|
||||
const RANGE_PROOF_SUBDIR: &'static str = "rangeproof";
|
||||
const KERNEL_SUBDIR: &'static str = "kernel";
|
||||
const SUMTREES_ZIP: &'static str = "sumtrees_snapshot.zip";
|
||||
const TXHASHSET_ZIP: &'static str = "txhashset_snapshot.zip";
|
||||
|
||||
struct PMMRHandle<T>
|
||||
where
|
||||
|
@ -60,7 +60,7 @@ where
|
|||
file_name: &str,
|
||||
index_md: Option<PMMRFileMetadata>,
|
||||
) -> Result<PMMRHandle<T>, Error> {
|
||||
let path = Path::new(&root_dir).join(SUMTREES_SUBDIR).join(file_name);
|
||||
let path = Path::new(&root_dir).join(TXHASHSET_SUBDIR).join(file_name);
|
||||
fs::create_dir_all(path.clone())?;
|
||||
let be = PMMRBackend::new(path.to_str().unwrap().to_string(), index_md)?;
|
||||
let sz = be.unpruned_size()?;
|
||||
|
@ -77,7 +77,7 @@ where
|
|||
}
|
||||
|
||||
/// An easy to manipulate structure holding the 3 sum trees necessary to
|
||||
/// validate blocks and capturing the UTXO set, the range proofs and the
|
||||
/// validate blocks and capturing the Output set, the range proofs and the
|
||||
/// kernels. Also handles the index of Commitments to positions in the
|
||||
/// output and range proof pmmr trees.
|
||||
///
|
||||
|
@ -86,8 +86,8 @@ where
|
|||
/// may have commitments that have already been spent, even with
|
||||
/// pruning enabled.
|
||||
|
||||
pub struct SumTrees {
|
||||
utxo_pmmr_h: PMMRHandle<OutputStoreable>,
|
||||
pub struct TxHashSet {
|
||||
output_pmmr_h: PMMRHandle<OutputStoreable>,
|
||||
rproof_pmmr_h: PMMRHandle<RangeProof>,
|
||||
kernel_pmmr_h: PMMRHandle<TxKernel>,
|
||||
|
||||
|
@ -95,37 +95,37 @@ pub struct SumTrees {
|
|||
commit_index: Arc<ChainStore>,
|
||||
}
|
||||
|
||||
impl SumTrees {
|
||||
/// Open an existing or new set of backends for the SumTrees
|
||||
impl TxHashSet {
|
||||
/// Open an existing or new set of backends for the TxHashSet
|
||||
pub fn open(
|
||||
root_dir: String,
|
||||
commit_index: Arc<ChainStore>,
|
||||
last_file_positions: Option<PMMRFileMetadataCollection>,
|
||||
) -> Result<SumTrees, Error> {
|
||||
let utxo_file_path: PathBuf = [&root_dir, SUMTREES_SUBDIR, UTXO_SUBDIR].iter().collect();
|
||||
fs::create_dir_all(utxo_file_path.clone())?;
|
||||
) -> Result<TxHashSet, Error> {
|
||||
let output_file_path: PathBuf = [&root_dir, TXHASHSET_SUBDIR, OUTPUT_SUBDIR].iter().collect();
|
||||
fs::create_dir_all(output_file_path.clone())?;
|
||||
|
||||
let rproof_file_path: PathBuf = [&root_dir, SUMTREES_SUBDIR, RANGE_PROOF_SUBDIR]
|
||||
let rproof_file_path: PathBuf = [&root_dir, TXHASHSET_SUBDIR, RANGE_PROOF_SUBDIR]
|
||||
.iter()
|
||||
.collect();
|
||||
fs::create_dir_all(rproof_file_path.clone())?;
|
||||
|
||||
let kernel_file_path: PathBuf =
|
||||
[&root_dir, SUMTREES_SUBDIR, KERNEL_SUBDIR].iter().collect();
|
||||
[&root_dir, TXHASHSET_SUBDIR, KERNEL_SUBDIR].iter().collect();
|
||||
fs::create_dir_all(kernel_file_path.clone())?;
|
||||
|
||||
let mut utxo_md = None;
|
||||
let mut output_md = None;
|
||||
let mut rproof_md = None;
|
||||
let mut kernel_md = None;
|
||||
|
||||
if let Some(p) = last_file_positions {
|
||||
utxo_md = Some(p.utxo_file_md);
|
||||
output_md = Some(p.output_file_md);
|
||||
rproof_md = Some(p.rproof_file_md);
|
||||
kernel_md = Some(p.kernel_file_md);
|
||||
}
|
||||
|
||||
Ok(SumTrees {
|
||||
utxo_pmmr_h: PMMRHandle::new(root_dir.clone(), UTXO_SUBDIR, utxo_md)?,
|
||||
Ok(TxHashSet {
|
||||
output_pmmr_h: PMMRHandle::new(root_dir.clone(), OUTPUT_SUBDIR, output_md)?,
|
||||
rproof_pmmr_h: PMMRHandle::new(root_dir.clone(), RANGE_PROOF_SUBDIR, rproof_md)?,
|
||||
kernel_pmmr_h: PMMRHandle::new(root_dir.clone(), KERNEL_SUBDIR, kernel_md)?,
|
||||
commit_index: commit_index,
|
||||
|
@ -139,29 +139,29 @@ impl SumTrees {
|
|||
match self.commit_index.get_output_pos(&output_id.commit) {
|
||||
Ok(pos) => {
|
||||
let output_pmmr: PMMR<OutputStoreable, _> =
|
||||
PMMR::at(&mut self.utxo_pmmr_h.backend, self.utxo_pmmr_h.last_pos);
|
||||
PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
|
||||
if let Some((hash, _)) = output_pmmr.get(pos, false) {
|
||||
if hash == output_id.hash_with_index(pos) {
|
||||
Ok(hash)
|
||||
} else {
|
||||
Err(Error::SumTreeErr(format!("sumtree hash mismatch")))
|
||||
Err(Error::TxHashSetErr(format!("txhashset hash mismatch")))
|
||||
}
|
||||
} else {
|
||||
Err(Error::OutputNotFound)
|
||||
}
|
||||
}
|
||||
Err(grin_store::Error::NotFoundErr) => Err(Error::OutputNotFound),
|
||||
Err(e) => Err(Error::StoreErr(e, format!("sumtree unspent check"))),
|
||||
Err(e) => Err(Error::StoreErr(e, format!("txhashset unspent check"))),
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the last N nodes inserted into the tree (i.e. the 'bottom'
|
||||
/// nodes at level 0
|
||||
/// TODO: These need to return the actual data from the flat-files instead of hashes now
|
||||
pub fn last_n_utxo(&mut self, distance: u64) -> Vec<(Hash, Option<OutputStoreable>)> {
|
||||
let utxo_pmmr: PMMR<OutputStoreable, _> =
|
||||
PMMR::at(&mut self.utxo_pmmr_h.backend, self.utxo_pmmr_h.last_pos);
|
||||
utxo_pmmr.get_last_n_insertions(distance)
|
||||
pub fn last_n_output(&mut self, distance: u64) -> Vec<(Hash, Option<OutputStoreable>)> {
|
||||
let output_pmmr: PMMR<OutputStoreable, _> =
|
||||
PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
|
||||
output_pmmr.get_last_n_insertions(distance)
|
||||
}
|
||||
|
||||
/// as above, for range proofs
|
||||
|
@ -183,10 +183,10 @@ impl SumTrees {
|
|||
indexes_at(block, self.commit_index.deref())
|
||||
}
|
||||
|
||||
/// Last file positions of UTXO set.. hash file,data file
|
||||
/// Last file positions of Output set.. hash file,data file
|
||||
pub fn last_file_metadata(&self) -> PMMRFileMetadataCollection {
|
||||
PMMRFileMetadataCollection::new(
|
||||
self.utxo_pmmr_h.last_file_positions(),
|
||||
self.output_pmmr_h.last_file_positions(),
|
||||
self.rproof_pmmr_h.last_file_positions(),
|
||||
self.kernel_pmmr_h.last_file_positions(),
|
||||
)
|
||||
|
@ -196,7 +196,7 @@ impl SumTrees {
|
|||
/// TODO: Return data instead of hashes
|
||||
pub fn roots(&mut self) -> (Hash, Hash, Hash) {
|
||||
let output_pmmr: PMMR<OutputStoreable, _> =
|
||||
PMMR::at(&mut self.utxo_pmmr_h.backend, self.utxo_pmmr_h.last_pos);
|
||||
PMMR::at(&mut self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
|
||||
let rproof_pmmr: PMMR<RangeProof, _> =
|
||||
PMMR::at(&mut self.rproof_pmmr_h.backend, self.rproof_pmmr_h.last_pos);
|
||||
let kernel_pmmr: PMMR<TxKernel, _> =
|
||||
|
@ -208,11 +208,11 @@ impl SumTrees {
|
|||
/// Starts a new unit of work to extend the chain with additional blocks,
|
||||
/// accepting a closure that will work within that unit of work. The closure
|
||||
/// has access to an Extension object that allows the addition of blocks to
|
||||
/// the sumtrees and the checking of the current tree roots.
|
||||
/// the txhashset and the checking of the current tree roots.
|
||||
///
|
||||
/// If the closure returns an error, modifications are canceled and the unit
|
||||
/// of work is abandoned. Otherwise, the unit of work is permanently applied.
|
||||
pub fn extending<'a, F, T>(trees: &'a mut SumTrees, inner: F) -> Result<T, Error>
|
||||
pub fn extending<'a, F, T>(trees: &'a mut TxHashSet, inner: F) -> Result<T, Error>
|
||||
where
|
||||
F: FnOnce(&mut Extension) -> Result<T, Error>,
|
||||
{
|
||||
|
@ -222,7 +222,7 @@ where
|
|||
{
|
||||
let commit_index = trees.commit_index.clone();
|
||||
|
||||
debug!(LOGGER, "Starting new sumtree extension.");
|
||||
debug!(LOGGER, "Starting new txhashset extension.");
|
||||
let mut extension = Extension::new(trees, commit_index);
|
||||
res = inner(&mut extension);
|
||||
|
||||
|
@ -234,29 +234,29 @@ where
|
|||
}
|
||||
match res {
|
||||
Err(e) => {
|
||||
debug!(LOGGER, "Error returned, discarding sumtree extension.");
|
||||
trees.utxo_pmmr_h.backend.discard();
|
||||
debug!(LOGGER, "Error returned, discarding txhashset extension.");
|
||||
trees.output_pmmr_h.backend.discard();
|
||||
trees.rproof_pmmr_h.backend.discard();
|
||||
trees.kernel_pmmr_h.backend.discard();
|
||||
Err(e)
|
||||
}
|
||||
Ok(r) => {
|
||||
if rollback {
|
||||
debug!(LOGGER, "Rollbacking sumtree extension.");
|
||||
trees.utxo_pmmr_h.backend.discard();
|
||||
debug!(LOGGER, "Rollbacking txhashset extension.");
|
||||
trees.output_pmmr_h.backend.discard();
|
||||
trees.rproof_pmmr_h.backend.discard();
|
||||
trees.kernel_pmmr_h.backend.discard();
|
||||
} else {
|
||||
debug!(LOGGER, "Committing sumtree extension.");
|
||||
trees.utxo_pmmr_h.backend.sync()?;
|
||||
debug!(LOGGER, "Committing txhashset extension.");
|
||||
trees.output_pmmr_h.backend.sync()?;
|
||||
trees.rproof_pmmr_h.backend.sync()?;
|
||||
trees.kernel_pmmr_h.backend.sync()?;
|
||||
trees.utxo_pmmr_h.last_pos = sizes.0;
|
||||
trees.output_pmmr_h.last_pos = sizes.0;
|
||||
trees.rproof_pmmr_h.last_pos = sizes.1;
|
||||
trees.kernel_pmmr_h.last_pos = sizes.2;
|
||||
}
|
||||
|
||||
debug!(LOGGER, "Sumtree extension done.");
|
||||
debug!(LOGGER, "TxHashSet extension done.");
|
||||
Ok(r)
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ where
|
|||
/// reversible manner within a unit of work provided by the `extending`
|
||||
/// function.
|
||||
pub struct Extension<'a> {
|
||||
utxo_pmmr: PMMR<'a, OutputStoreable, PMMRBackend<OutputStoreable>>,
|
||||
output_pmmr: PMMR<'a, OutputStoreable, PMMRBackend<OutputStoreable>>,
|
||||
rproof_pmmr: PMMR<'a, RangeProof, PMMRBackend<RangeProof>>,
|
||||
kernel_pmmr: PMMR<'a, TxKernel, PMMRBackend<TxKernel>>,
|
||||
|
||||
|
@ -278,9 +278,9 @@ pub struct Extension<'a> {
|
|||
|
||||
impl<'a> Extension<'a> {
|
||||
// constructor
|
||||
fn new(trees: &'a mut SumTrees, commit_index: Arc<ChainStore>) -> Extension<'a> {
|
||||
fn new(trees: &'a mut TxHashSet, commit_index: Arc<ChainStore>) -> Extension<'a> {
|
||||
Extension {
|
||||
utxo_pmmr: PMMR::at(&mut trees.utxo_pmmr_h.backend, trees.utxo_pmmr_h.last_pos),
|
||||
output_pmmr: PMMR::at(&mut trees.output_pmmr_h.backend, trees.output_pmmr_h.last_pos),
|
||||
rproof_pmmr: PMMR::at(
|
||||
&mut trees.rproof_pmmr_h.backend,
|
||||
trees.rproof_pmmr_h.last_pos,
|
||||
|
@ -350,14 +350,14 @@ impl<'a> Extension<'a> {
|
|||
let pos_res = self.get_output_pos(&commit);
|
||||
if let Ok(pos) = pos_res {
|
||||
let output_id_hash = OutputIdentifier::from_input(input).hash_with_index(pos);
|
||||
if let Some((read_hash, read_elem)) = self.utxo_pmmr.get(pos, true) {
|
||||
if let Some((read_hash, read_elem)) = self.output_pmmr.get(pos, true) {
|
||||
// check hash from pmmr matches hash from input (or corresponding output)
|
||||
// if not then the input is not being honest about
|
||||
// what it is attempting to spend...
|
||||
if output_id_hash != read_hash
|
||||
|| output_id_hash != read_elem.expect("no output at position").hash_with_index(pos)
|
||||
{
|
||||
return Err(Error::SumTreeErr(format!("output pmmr hash mismatch")));
|
||||
return Err(Error::TxHashSetErr(format!("output pmmr hash mismatch")));
|
||||
}
|
||||
|
||||
// check coinbase maturity with the Merkle Proof on the input
|
||||
|
@ -367,17 +367,17 @@ impl<'a> Extension<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// Now prune the utxo_pmmr, rproof_pmmr and their storage.
|
||||
// Now prune the output_pmmr, rproof_pmmr and their storage.
|
||||
// Input is not valid if we cannot prune successfully (to spend an unspent
|
||||
// output).
|
||||
match self.utxo_pmmr.prune(pos, height as u32) {
|
||||
match self.output_pmmr.prune(pos, height as u32) {
|
||||
Ok(true) => {
|
||||
self.rproof_pmmr
|
||||
.prune(pos, height as u32)
|
||||
.map_err(|s| Error::SumTreeErr(s))?;
|
||||
.map_err(|s| Error::TxHashSetErr(s))?;
|
||||
}
|
||||
Ok(false) => return Err(Error::AlreadySpent(commit)),
|
||||
Err(s) => return Err(Error::SumTreeErr(s)),
|
||||
Err(s) => return Err(Error::TxHashSetErr(s)),
|
||||
}
|
||||
} else {
|
||||
return Err(Error::AlreadySpent(commit));
|
||||
|
@ -394,7 +394,7 @@ impl<'a> Extension<'a> {
|
|||
// (non-historical node will have a much smaller one)
|
||||
// note that this doesn't show the commitment *never* existed, just
|
||||
// that this is not an existing unspent commitment right now
|
||||
if let Some((hash, _)) = self.utxo_pmmr.get(pos, false) {
|
||||
if let Some((hash, _)) = self.output_pmmr.get(pos, false) {
|
||||
// processing a new fork so we may get a position on the old
|
||||
// fork that exists but matches a different node
|
||||
// filtering that case out
|
||||
|
@ -404,15 +404,15 @@ impl<'a> Extension<'a> {
|
|||
}
|
||||
}
|
||||
// push new outputs in their MMR and save them in the index
|
||||
let pos = self.utxo_pmmr
|
||||
let pos = self.output_pmmr
|
||||
.push(OutputStoreable::from_output(out))
|
||||
.map_err(&Error::SumTreeErr)?;
|
||||
.map_err(&Error::TxHashSetErr)?;
|
||||
self.new_output_commits.insert(out.commitment(), pos);
|
||||
|
||||
// push range proofs in their MMR and file
|
||||
self.rproof_pmmr
|
||||
.push(out.proof)
|
||||
.map_err(&Error::SumTreeErr)?;
|
||||
.map_err(&Error::TxHashSetErr)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -429,7 +429,7 @@ impl<'a> Extension<'a> {
|
|||
// push kernels in their MMR and file
|
||||
let pos = self.kernel_pmmr
|
||||
.push(kernel.clone())
|
||||
.map_err(&Error::SumTreeErr)?;
|
||||
.map_err(&Error::TxHashSetErr)?;
|
||||
self.new_kernel_excesses.insert(kernel.excess, pos);
|
||||
|
||||
Ok(())
|
||||
|
@ -447,16 +447,16 @@ impl<'a> Extension<'a> {
|
|||
) -> Result<MerkleProof, Error> {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"sumtree: merkle_proof_via_rewind: rewinding to block {:?}",
|
||||
"txhashset: merkle_proof_via_rewind: rewinding to block {:?}",
|
||||
block.hash()
|
||||
);
|
||||
// rewind to the specified block
|
||||
self.rewind(block)?;
|
||||
// then calculate the Merkle Proof based on the known pos
|
||||
let pos = self.get_output_pos(&output.commit)?;
|
||||
let merkle_proof = self.utxo_pmmr
|
||||
let merkle_proof = self.output_pmmr
|
||||
.merkle_proof(pos)
|
||||
.map_err(&Error::SumTreeErr)?;
|
||||
.map_err(&Error::TxHashSetErr)?;
|
||||
|
||||
Ok(merkle_proof)
|
||||
}
|
||||
|
@ -466,7 +466,7 @@ impl<'a> Extension<'a> {
|
|||
pub fn rewind(&mut self, block: &Block) -> Result<(), Error> {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Rewind sumtrees to header {} at {}",
|
||||
"Rewind txhashset to header {} at {}",
|
||||
block.header.hash(),
|
||||
block.header.height,
|
||||
);
|
||||
|
@ -487,18 +487,18 @@ impl<'a> Extension<'a> {
|
|||
) -> Result<(), Error> {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Rewind sumtrees to output pos: {}, kernel pos: {}", out_pos_rew, kern_pos_rew,
|
||||
"Rewind txhashset to output pos: {}, kernel pos: {}", out_pos_rew, kern_pos_rew,
|
||||
);
|
||||
|
||||
self.utxo_pmmr
|
||||
self.output_pmmr
|
||||
.rewind(out_pos_rew, height as u32)
|
||||
.map_err(&Error::SumTreeErr)?;
|
||||
.map_err(&Error::TxHashSetErr)?;
|
||||
self.rproof_pmmr
|
||||
.rewind(out_pos_rew, height as u32)
|
||||
.map_err(&Error::SumTreeErr)?;
|
||||
.map_err(&Error::TxHashSetErr)?;
|
||||
self.kernel_pmmr
|
||||
.rewind(kern_pos_rew, height as u32)
|
||||
.map_err(&Error::SumTreeErr)?;
|
||||
.map_err(&Error::TxHashSetErr)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -519,50 +519,50 @@ impl<'a> Extension<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Current root hashes and sums (if applicable) for the UTXO, range proof
|
||||
/// Current root hashes and sums (if applicable) for the Output, range proof
|
||||
/// and kernel sum trees.
|
||||
pub fn roots(&self) -> SumTreeRoots {
|
||||
SumTreeRoots {
|
||||
utxo_root: self.utxo_pmmr.root(),
|
||||
pub fn roots(&self) -> TxHashSetRoots {
|
||||
TxHashSetRoots {
|
||||
output_root: self.output_pmmr.root(),
|
||||
rproof_root: self.rproof_pmmr.root(),
|
||||
kernel_root: self.kernel_pmmr.root(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate the current sumtree state against a block header
|
||||
/// Validate the current txhashset state against a block header
|
||||
pub fn validate(&self, header: &BlockHeader) -> Result<(), Error> {
|
||||
// validate all hashes and sums within the trees
|
||||
if let Err(e) = self.utxo_pmmr.validate() {
|
||||
return Err(Error::InvalidSumtree(e));
|
||||
if let Err(e) = self.output_pmmr.validate() {
|
||||
return Err(Error::InvalidTxHashSet(e));
|
||||
}
|
||||
if let Err(e) = self.rproof_pmmr.validate() {
|
||||
return Err(Error::InvalidSumtree(e));
|
||||
return Err(Error::InvalidTxHashSet(e));
|
||||
}
|
||||
if let Err(e) = self.kernel_pmmr.validate() {
|
||||
return Err(Error::InvalidSumtree(e));
|
||||
return Err(Error::InvalidTxHashSet(e));
|
||||
}
|
||||
|
||||
// validate the tree roots against the block header
|
||||
let roots = self.roots();
|
||||
if roots.utxo_root != header.utxo_root || roots.rproof_root != header.range_proof_root
|
||||
if roots.output_root != header.output_root || roots.rproof_root != header.range_proof_root
|
||||
|| roots.kernel_root != header.kernel_root
|
||||
{
|
||||
return Err(Error::InvalidRoot);
|
||||
}
|
||||
|
||||
// the real magicking: the sum of all kernel excess should equal the sum
|
||||
// of all UTXO commitments, minus the total supply
|
||||
// of all Output commitments, minus the total supply
|
||||
let (kernel_sum, fees) = self.sum_kernels()?;
|
||||
let utxo_sum = self.sum_utxos()?;
|
||||
let output_sum = self.sum_outputs()?;
|
||||
{
|
||||
let secp = static_secp_instance();
|
||||
let secp = secp.lock().unwrap();
|
||||
let over_commit = secp.commit_value(header.height * reward(0) - fees / 2)?;
|
||||
let adjusted_sum_utxo = secp.commit_sum(vec![utxo_sum], vec![over_commit])?;
|
||||
let adjusted_sum_output = secp.commit_sum(vec![output_sum], vec![over_commit])?;
|
||||
|
||||
if adjusted_sum_utxo != kernel_sum {
|
||||
return Err(Error::InvalidSumtree(
|
||||
"Differing UTXO commitment and kernel excess sums.".to_owned(),
|
||||
if adjusted_sum_output != kernel_sum {
|
||||
return Err(Error::InvalidTxHashSet(
|
||||
"Differing Output commitment and kernel excess sums.".to_owned(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -570,14 +570,14 @@ impl<'a> Extension<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Rebuild the index of MMR positions to the corresponding UTXO and kernel
|
||||
/// Rebuild the index of MMR positions to the corresponding Output and kernel
|
||||
/// by iterating over the whole MMR data. This is a costly operation
|
||||
/// performed only when we receive a full new chain state.
|
||||
pub fn rebuild_index(&self) -> Result<(), Error> {
|
||||
for n in 1..self.utxo_pmmr.unpruned_size() + 1 {
|
||||
for n in 1..self.output_pmmr.unpruned_size() + 1 {
|
||||
// non-pruned leaves only
|
||||
if pmmr::bintree_postorder_height(n) == 0 {
|
||||
if let Some((_, out)) = self.utxo_pmmr.get(n, true) {
|
||||
if let Some((_, out)) = self.output_pmmr.get(n, true) {
|
||||
self.commit_index
|
||||
.save_output_pos(&out.expect("not a leaf node").commit, n)?;
|
||||
}
|
||||
|
@ -592,10 +592,10 @@ impl<'a> Extension<'a> {
|
|||
}
|
||||
|
||||
/// Dumps the state of the 3 sum trees to stdout for debugging. Short
|
||||
/// version only prints the UTXO tree.
|
||||
/// version only prints the Output tree.
|
||||
pub fn dump(&self, short: bool) {
|
||||
debug!(LOGGER, "-- outputs --");
|
||||
self.utxo_pmmr.dump(short);
|
||||
self.output_pmmr.dump(short);
|
||||
if !short {
|
||||
debug!(LOGGER, "-- range proofs --");
|
||||
self.rproof_pmmr.dump(short);
|
||||
|
@ -607,7 +607,7 @@ impl<'a> Extension<'a> {
|
|||
// Sizes of the sum trees, used by `extending` on rollback.
|
||||
fn sizes(&self) -> (u64, u64, u64) {
|
||||
(
|
||||
self.utxo_pmmr.unpruned_size(),
|
||||
self.output_pmmr.unpruned_size(),
|
||||
self.rproof_pmmr.unpruned_size(),
|
||||
self.kernel_pmmr.unpruned_size(),
|
||||
)
|
||||
|
@ -648,14 +648,14 @@ impl<'a> Extension<'a> {
|
|||
Ok((sum_kernel, fees))
|
||||
}
|
||||
|
||||
/// Sums all our UTXO commitments, checking range proofs at the same time
|
||||
fn sum_utxos(&self) -> Result<Commitment, Error> {
|
||||
let mut sum_utxo = None;
|
||||
let mut utxo_count = 0;
|
||||
/// Sums all our Output commitments, checking range proofs at the same time
|
||||
fn sum_outputs(&self) -> Result<Commitment, Error> {
|
||||
let mut sum_output = None;
|
||||
let mut output_count = 0;
|
||||
let secp = static_secp_instance();
|
||||
for n in 1..self.utxo_pmmr.unpruned_size() + 1 {
|
||||
for n in 1..self.output_pmmr.unpruned_size() + 1 {
|
||||
if pmmr::bintree_postorder_height(n) == 0 {
|
||||
if let Some((_, output)) = self.utxo_pmmr.get(n, true) {
|
||||
if let Some((_, output)) = self.output_pmmr.get(n, true) {
|
||||
let out = output.expect("not a leaf node");
|
||||
let commit = out.commit.clone();
|
||||
match self.rproof_pmmr.get(n, true) {
|
||||
|
@ -664,18 +664,18 @@ impl<'a> Extension<'a> {
|
|||
return Err(Error::OutputNotFound);
|
||||
}
|
||||
}
|
||||
if let None = sum_utxo {
|
||||
sum_utxo = Some(commit);
|
||||
if let None = sum_output {
|
||||
sum_output = Some(commit);
|
||||
} else {
|
||||
let secp = secp.lock().unwrap();
|
||||
sum_utxo = Some(secp.commit_sum(vec![sum_utxo.unwrap(), commit], vec![])?);
|
||||
sum_output = Some(secp.commit_sum(vec![sum_output.unwrap(), commit], vec![])?);
|
||||
}
|
||||
utxo_count += 1;
|
||||
output_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!(LOGGER, "Summed {} UTXOs", utxo_count);
|
||||
Ok(sum_utxo.unwrap())
|
||||
debug!(LOGGER, "Summed {} Outputs", output_count);
|
||||
Ok(sum_output.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -727,15 +727,15 @@ fn indexes_at(block: &Block, commit_index: &ChainStore) -> Result<(u64, u64), Er
|
|||
Ok((out_idx, kern_idx))
|
||||
}
|
||||
|
||||
/// Packages the sumtree data files into a zip and returns a Read to the
|
||||
/// Packages the txhashset data files into a zip and returns a Read to the
|
||||
/// resulting file
|
||||
pub fn zip_read(root_dir: String) -> Result<File, Error> {
|
||||
let sumtrees_path = Path::new(&root_dir).join(SUMTREES_SUBDIR);
|
||||
let zip_path = Path::new(&root_dir).join(SUMTREES_ZIP);
|
||||
let txhashset_path = Path::new(&root_dir).join(TXHASHSET_SUBDIR);
|
||||
let zip_path = Path::new(&root_dir).join(TXHASHSET_ZIP);
|
||||
|
||||
// create the zip archive
|
||||
{
|
||||
zip::compress(&sumtrees_path, &File::create(zip_path.clone())?)
|
||||
zip::compress(&txhashset_path, &File::create(zip_path.clone())?)
|
||||
.map_err(|ze| Error::Other(ze.to_string()))?;
|
||||
}
|
||||
|
||||
|
@ -744,11 +744,11 @@ pub fn zip_read(root_dir: String) -> Result<File, Error> {
|
|||
Ok(zip_file)
|
||||
}
|
||||
|
||||
/// Extract the sumtree data from a zip file and writes the content into the
|
||||
/// sumtree storage dir
|
||||
pub fn zip_write(root_dir: String, sumtree_data: File) -> Result<(), Error> {
|
||||
let sumtrees_path = Path::new(&root_dir).join(SUMTREES_SUBDIR);
|
||||
/// Extract the txhashset data from a zip file and writes the content into the
|
||||
/// txhashset storage dir
|
||||
pub fn zip_write(root_dir: String, txhashset_data: File) -> Result<(), Error> {
|
||||
let txhashset_path = Path::new(&root_dir).join(TXHASHSET_SUBDIR);
|
||||
|
||||
fs::create_dir_all(sumtrees_path.clone())?;
|
||||
zip::decompress(sumtree_data, &sumtrees_path).map_err(|ze| Error::Other(ze.to_string()))
|
||||
fs::create_dir_all(txhashset_path.clone())?;
|
||||
zip::decompress(txhashset_data, &txhashset_path).map_err(|ze| Error::Other(ze.to_string()))
|
||||
}
|
|
@ -41,11 +41,11 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
/// A helper to hold the roots of the sumtrees in order to keep them
|
||||
/// A helper to hold the roots of the txhashset in order to keep them
|
||||
/// readable
|
||||
pub struct SumTreeRoots {
|
||||
/// UTXO root
|
||||
pub utxo_root: Hash,
|
||||
pub struct TxHashSetRoots {
|
||||
/// Output root
|
||||
pub output_root: Hash,
|
||||
/// Range Proof root
|
||||
pub rproof_root: Hash,
|
||||
/// Kernel root
|
||||
|
@ -87,16 +87,16 @@ pub enum Error {
|
|||
OutputSpent,
|
||||
/// Invalid block version, either a mistake or outdated software
|
||||
InvalidBlockVersion(u16),
|
||||
/// We've been provided a bad sumtree
|
||||
InvalidSumtree(String),
|
||||
/// We've been provided a bad txhashset
|
||||
InvalidTxHashSet(String),
|
||||
/// Internal issue when trying to save or load data from store
|
||||
StoreErr(grin_store::Error, String),
|
||||
/// Internal issue when trying to save or load data from append only files
|
||||
FileReadErr(String),
|
||||
/// Error serializing or deserializing a type
|
||||
SerErr(ser::Error),
|
||||
/// Error with the sumtrees
|
||||
SumTreeErr(String),
|
||||
/// Error with the txhashset
|
||||
TxHashSetErr(String),
|
||||
/// No chain exists and genesis block is required
|
||||
GenesisBlockRequired,
|
||||
/// Error from underlying tx handling
|
||||
|
@ -117,12 +117,12 @@ impl From<ser::Error> for Error {
|
|||
}
|
||||
impl From<io::Error> for Error {
|
||||
fn from(e: io::Error) -> Error {
|
||||
Error::SumTreeErr(e.to_string())
|
||||
Error::TxHashSetErr(e.to_string())
|
||||
}
|
||||
}
|
||||
impl From<secp::Error> for Error {
|
||||
fn from(e: secp::Error) -> Error {
|
||||
Error::SumTreeErr(format!("Sum validation error: {}", e.to_string()))
|
||||
Error::TxHashSetErr(format!("Sum validation error: {}", e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ impl Error {
|
|||
| Error::Orphan
|
||||
| Error::StoreErr(_, _)
|
||||
| Error::SerErr(_)
|
||||
| Error::SumTreeErr(_)
|
||||
| Error::TxHashSetErr(_)
|
||||
| Error::GenesisBlockRequired
|
||||
| Error::Other(_) => false,
|
||||
_ => true,
|
||||
|
@ -276,19 +276,19 @@ pub trait ChainStore: Send + Sync {
|
|||
fn is_on_current_chain(&self, header: &BlockHeader) -> Result<(), store::Error>;
|
||||
|
||||
/// Saves the position of an output, represented by its commitment, in the
|
||||
/// UTXO MMR. Used as an index for spending and pruning.
|
||||
/// Output MMR. Used as an index for spending and pruning.
|
||||
fn save_output_pos(&self, commit: &Commitment, pos: u64) -> Result<(), store::Error>;
|
||||
|
||||
/// Gets the position of an output, represented by its commitment, in the
|
||||
/// UTXO MMR. Used as an index for spending and pruning.
|
||||
/// Output MMR. Used as an index for spending and pruning.
|
||||
fn get_output_pos(&self, commit: &Commitment) -> Result<u64, store::Error>;
|
||||
|
||||
/// Saves the position of a kernel, represented by its excess, in the
|
||||
/// UTXO MMR. Used as an index for spending and pruning.
|
||||
/// Kernel MMR. Used as an index for spending and pruning.
|
||||
fn save_kernel_pos(&self, commit: &Commitment, pos: u64) -> Result<(), store::Error>;
|
||||
|
||||
/// Gets the position of a kernel, represented by its excess, in the
|
||||
/// UTXO MMR. Used as an index for spending and pruning.
|
||||
/// Kernel MMR. Used as an index for spending and pruning.
|
||||
fn get_kernel_pos(&self, commit: &Commitment) -> Result<u64, store::Error>;
|
||||
|
||||
/// Saves information about the last written PMMR file positions for each
|
||||
|
@ -318,8 +318,8 @@ pub trait ChainStore: Send + Sync {
|
|||
/// for a given block
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct PMMRFileMetadataCollection {
|
||||
/// file metadata for the utxo file
|
||||
pub utxo_file_md: PMMRFileMetadata,
|
||||
/// file metadata for the output file
|
||||
pub output_file_md: PMMRFileMetadata,
|
||||
/// file metadata for the rangeproof file
|
||||
pub rproof_file_md: PMMRFileMetadata,
|
||||
/// file metadata for the kernel file
|
||||
|
@ -328,7 +328,7 @@ pub struct PMMRFileMetadataCollection {
|
|||
|
||||
impl Writeable for PMMRFileMetadataCollection {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
self.utxo_file_md.write(writer)?;
|
||||
self.output_file_md.write(writer)?;
|
||||
self.rproof_file_md.write(writer)?;
|
||||
self.kernel_file_md.write(writer)?;
|
||||
Ok(())
|
||||
|
@ -338,7 +338,7 @@ impl Writeable for PMMRFileMetadataCollection {
|
|||
impl Readable for PMMRFileMetadataCollection {
|
||||
fn read(reader: &mut Reader) -> Result<PMMRFileMetadataCollection, ser::Error> {
|
||||
Ok(PMMRFileMetadataCollection {
|
||||
utxo_file_md: PMMRFileMetadata::read(reader)?,
|
||||
output_file_md: PMMRFileMetadata::read(reader)?,
|
||||
rproof_file_md: PMMRFileMetadata::read(reader)?,
|
||||
kernel_file_md: PMMRFileMetadata::read(reader)?,
|
||||
})
|
||||
|
@ -349,7 +349,7 @@ impl PMMRFileMetadataCollection {
|
|||
/// Return empty with all file positions = 0
|
||||
pub fn empty() -> PMMRFileMetadataCollection {
|
||||
PMMRFileMetadataCollection {
|
||||
utxo_file_md: PMMRFileMetadata::empty(),
|
||||
output_file_md: PMMRFileMetadata::empty(),
|
||||
rproof_file_md: PMMRFileMetadata::empty(),
|
||||
kernel_file_md: PMMRFileMetadata::empty(),
|
||||
}
|
||||
|
@ -357,12 +357,12 @@ impl PMMRFileMetadataCollection {
|
|||
|
||||
/// Helper to create a new collection
|
||||
pub fn new(
|
||||
utxo_md: PMMRFileMetadata,
|
||||
output_md: PMMRFileMetadata,
|
||||
rproof_md: PMMRFileMetadata,
|
||||
kernel_md: PMMRFileMetadata,
|
||||
) -> PMMRFileMetadataCollection {
|
||||
PMMRFileMetadataCollection {
|
||||
utxo_file_md: utxo_md,
|
||||
output_file_md: output_md,
|
||||
rproof_file_md: rproof_md,
|
||||
kernel_file_md: kernel_md,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -93,7 +93,7 @@ fn data_files() {
|
|||
b.header.timestamp = prev.timestamp + time::Duration::seconds(60);
|
||||
|
||||
b.header.difficulty = difficulty.clone(); // TODO: overwrite here? really?
|
||||
chain.set_sumtree_roots(&mut b, false).unwrap();
|
||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||
|
||||
pow::pow_size(
|
||||
&mut cuckoo_miner,
|
||||
|
@ -131,7 +131,7 @@ fn data_files() {
|
|||
|
||||
fn prepare_block(kc: &Keychain, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block {
|
||||
let mut b = prepare_block_nosum(kc, prev, diff, vec![]);
|
||||
chain.set_sumtree_roots(&mut b, false).unwrap();
|
||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
|
@ -143,13 +143,13 @@ fn prepare_block_tx(
|
|||
txs: Vec<&Transaction>,
|
||||
) -> Block {
|
||||
let mut b = prepare_block_nosum(kc, prev, diff, txs);
|
||||
chain.set_sumtree_roots(&mut b, false).unwrap();
|
||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
fn prepare_fork_block(kc: &Keychain, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block {
|
||||
let mut b = prepare_block_nosum(kc, prev, diff, vec![]);
|
||||
chain.set_sumtree_roots(&mut b, true).unwrap();
|
||||
chain.set_txhashset_roots(&mut b, true).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ fn prepare_fork_block_tx(
|
|||
txs: Vec<&Transaction>,
|
||||
) -> Block {
|
||||
let mut b = prepare_block_nosum(kc, prev, diff, txs);
|
||||
chain.set_sumtree_roots(&mut b, true).unwrap();
|
||||
chain.set_txhashset_roots(&mut b, true).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -81,7 +81,7 @@ fn mine_empty_chain() {
|
|||
b.header.timestamp = prev.timestamp + time::Duration::seconds(60);
|
||||
|
||||
b.header.difficulty = difficulty.clone(); // TODO: overwrite here? really?
|
||||
chain.set_sumtree_roots(&mut b, false).unwrap();
|
||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||
|
||||
pow::pow_size(
|
||||
&mut cuckoo_miner,
|
||||
|
@ -193,7 +193,7 @@ fn mine_losing_fork() {
|
|||
#[test]
|
||||
fn longer_fork() {
|
||||
let kc = Keychain::from_random_seed().unwrap();
|
||||
// to make it easier to compute the sumtree roots in the test, we
|
||||
// to make it easier to compute the txhashset roots in the test, we
|
||||
// prepare 2 chains, the 2nd will be have the forked blocks we can
|
||||
// then send back on the 1st
|
||||
let chain = setup(".grin4");
|
||||
|
@ -370,7 +370,7 @@ fn spend_in_fork() {
|
|||
|
||||
fn prepare_block(kc: &Keychain, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block {
|
||||
let mut b = prepare_block_nosum(kc, prev, diff, vec![]);
|
||||
chain.set_sumtree_roots(&mut b, false).unwrap();
|
||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
|
@ -382,13 +382,13 @@ fn prepare_block_tx(
|
|||
txs: Vec<&Transaction>,
|
||||
) -> Block {
|
||||
let mut b = prepare_block_nosum(kc, prev, diff, txs);
|
||||
chain.set_sumtree_roots(&mut b, false).unwrap();
|
||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
fn prepare_fork_block(kc: &Keychain, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block {
|
||||
let mut b = prepare_block_nosum(kc, prev, diff, vec![]);
|
||||
chain.set_sumtree_roots(&mut b, true).unwrap();
|
||||
chain.set_txhashset_roots(&mut b, true).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
|
@ -400,7 +400,7 @@ fn prepare_fork_block_tx(
|
|||
txs: Vec<&Transaction>,
|
||||
) -> Block {
|
||||
let mut b = prepare_block_nosum(kc, prev, diff, txs);
|
||||
chain.set_sumtree_roots(&mut b, true).unwrap();
|
||||
chain.set_txhashset_roots(&mut b, true).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -82,7 +82,7 @@ fn test_coinbase_maturity() {
|
|||
|
||||
let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
|
||||
block.header.difficulty = difficulty.clone();
|
||||
chain.set_sumtree_roots(&mut block, false).unwrap();
|
||||
chain.set_txhashset_roots(&mut block, false).unwrap();
|
||||
|
||||
pow::pow_size(
|
||||
&mut cuckoo_miner,
|
||||
|
@ -140,7 +140,7 @@ fn test_coinbase_maturity() {
|
|||
let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
|
||||
block.header.difficulty = difficulty.clone();
|
||||
|
||||
match chain.set_sumtree_roots(&mut block, false) {
|
||||
match chain.set_txhashset_roots(&mut block, false) {
|
||||
Err(Error::Transaction(transaction::Error::ImmatureCoinbase)) => (),
|
||||
_ => panic!("expected ImmatureCoinbase error here"),
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ fn test_coinbase_maturity() {
|
|||
|
||||
let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
|
||||
block.header.difficulty = difficulty.clone();
|
||||
chain.set_sumtree_roots(&mut block, false).unwrap();
|
||||
chain.set_txhashset_roots(&mut block, false).unwrap();
|
||||
|
||||
pow::pow_size(
|
||||
&mut cuckoo_miner,
|
||||
|
@ -201,7 +201,7 @@ fn test_coinbase_maturity() {
|
|||
|
||||
let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
|
||||
block.header.difficulty = difficulty.clone();
|
||||
chain.set_sumtree_roots(&mut block, false).unwrap();
|
||||
chain.set_txhashset_roots(&mut block, false).unwrap();
|
||||
|
||||
pow::pow_size(
|
||||
&mut cuckoo_miner,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
@ -20,7 +20,7 @@ extern crate test;
|
|||
use rand::Rng;
|
||||
use test::Bencher;
|
||||
|
||||
use core::core::sumtree::{self, SumTree, Summable};
|
||||
use core::core::txhashset::{self, TxHashSet, Summable};
|
||||
use core::ser::{Error, Writeable, Writer};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -48,7 +48,7 @@ impl Writeable for TestElem {
|
|||
fn bench_small_tree(b: &mut Bencher) {
|
||||
let mut rng = rand::thread_rng();
|
||||
b.iter(|| {
|
||||
let mut big_tree = SumTree::new();
|
||||
let mut big_tree = TxHashSet::new();
|
||||
for i in 0..1000 {
|
||||
// To avoid RNG overflow we generate random elements that are small.
|
||||
// Though to avoid repeat elements they have to be reasonably big.
|
||||
|
|
|
@ -107,11 +107,11 @@ pub struct BlockHeader {
|
|||
pub previous: Hash,
|
||||
/// Timestamp at which the block was built.
|
||||
pub timestamp: time::Tm,
|
||||
/// Merklish root of all the commitments in the UTXO set
|
||||
pub utxo_root: Hash,
|
||||
/// Merklish root of all range proofs in the UTXO set
|
||||
/// Merklish root of all the commitments in the TxHashSet
|
||||
pub output_root: Hash,
|
||||
/// Merklish root of all range proofs in the TxHashSet
|
||||
pub range_proof_root: Hash,
|
||||
/// Merklish root of all transaction kernels in the UTXO set
|
||||
/// Merklish root of all transaction kernels in the TxHashSet
|
||||
pub kernel_root: Hash,
|
||||
/// Nonce increment used to mine this block.
|
||||
pub nonce: u64,
|
||||
|
@ -136,7 +136,7 @@ impl Default for BlockHeader {
|
|||
timestamp: time::at_utc(time::Timespec { sec: 0, nsec: 0 }),
|
||||
difficulty: Difficulty::one(),
|
||||
total_difficulty: Difficulty::one(),
|
||||
utxo_root: ZERO_HASH,
|
||||
output_root: ZERO_HASH,
|
||||
range_proof_root: ZERO_HASH,
|
||||
kernel_root: ZERO_HASH,
|
||||
nonce: 0,
|
||||
|
@ -155,7 +155,7 @@ impl Writeable for BlockHeader {
|
|||
[write_u64, self.height],
|
||||
[write_fixed_bytes, &self.previous],
|
||||
[write_i64, self.timestamp.to_timespec().sec],
|
||||
[write_fixed_bytes, &self.utxo_root],
|
||||
[write_fixed_bytes, &self.output_root],
|
||||
[write_fixed_bytes, &self.range_proof_root],
|
||||
[write_fixed_bytes, &self.kernel_root]
|
||||
);
|
||||
|
@ -178,7 +178,7 @@ impl Readable for BlockHeader {
|
|||
let (version, height) = ser_multiread!(reader, read_u16, read_u64);
|
||||
let previous = Hash::read(reader)?;
|
||||
let timestamp = reader.read_i64()?;
|
||||
let utxo_root = Hash::read(reader)?;
|
||||
let output_root = Hash::read(reader)?;
|
||||
let rproof_root = Hash::read(reader)?;
|
||||
let kernel_root = Hash::read(reader)?;
|
||||
let nonce = reader.read_u64()?;
|
||||
|
@ -195,7 +195,7 @@ impl Readable for BlockHeader {
|
|||
sec: timestamp,
|
||||
nsec: 0,
|
||||
}),
|
||||
utxo_root: utxo_root,
|
||||
output_root: output_root,
|
||||
range_proof_root: rproof_root,
|
||||
kernel_root: kernel_root,
|
||||
pow: pow,
|
||||
|
@ -654,7 +654,7 @@ impl Block {
|
|||
/// But we cannot check the following as we need data from the index and the PMMR.
|
||||
/// So we must be sure to check these at the appropriate point during block validation.
|
||||
/// * node is in the correct pos in the PMMR
|
||||
/// * block is the correct one (based on utxo_root from block_header via the index)
|
||||
/// * block is the correct one (based on output_root from block_header via the index)
|
||||
fn verify_inputs(&self) -> Result<(), Error> {
|
||||
let coinbase_inputs = self.inputs
|
||||
.iter()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -86,7 +86,7 @@ where
|
|||
/// A Merkle proof.
|
||||
/// Proves inclusion of an output (node) in the output MMR.
|
||||
/// We can use this to prove an output was unspent at the time of a given block
|
||||
/// as the root will match the utxo_root of the block header.
|
||||
/// as the root will match the output_root of the block header.
|
||||
/// The path and left_right can be used to reconstruct the peak hash for a given tree
|
||||
/// in the MMR.
|
||||
/// The root is the result of hashing all the peaks together.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -483,7 +483,7 @@ impl Transaction {
|
|||
/// But we cannot check the following as we need data from the index and the PMMR.
|
||||
/// So we must be sure to check these at the appropriate point during block validation.
|
||||
/// * node is in the correct pos in the PMMR
|
||||
/// * block is the correct one (based on utxo_root from block_header via the index)
|
||||
/// * block is the correct one (based on output_root from block_header via the index)
|
||||
fn verify_inputs(&self) -> Result<(), Error> {
|
||||
let coinbase_inputs = self.inputs
|
||||
.iter()
|
||||
|
@ -516,7 +516,7 @@ pub struct Input {
|
|||
/// Currently we only care about this for coinbase outputs.
|
||||
pub block_hash: Option<Hash>,
|
||||
/// The Merkle Proof that shows the output being spent by this input
|
||||
/// existed and was unspent at the time of this block (proof of inclusion in utxo_root)
|
||||
/// existed and was unspent at the time of this block (proof of inclusion in output_root)
|
||||
pub merkle_proof: Option<MerkleProof>,
|
||||
}
|
||||
|
||||
|
@ -619,15 +619,15 @@ impl Input {
|
|||
/// Only relevant for spending coinbase outputs currently (locked for 1,000 confirmations).
|
||||
///
|
||||
/// The proof associates the output with the root by its hash (and pos) in the MMR.
|
||||
/// The proof shows the output existed and was unspent at the time the utxo_root was built.
|
||||
/// The root associates the proof with a specific block header with that utxo_root.
|
||||
/// The proof shows the output existed and was unspent at the time the output_root was built.
|
||||
/// The root associates the proof with a specific block header with that output_root.
|
||||
/// So the proof shows the output was unspent at the time of the block
|
||||
/// and is at least as old as that block (may be older).
|
||||
///
|
||||
/// We can verify maturity of the output being spent by -
|
||||
///
|
||||
/// * verifying the Merkle Proof produces the correct root for the given hash (from MMR)
|
||||
/// * verifying the root matches the utxo_root in the block_header
|
||||
/// * verifying the root matches the output_root in the block_header
|
||||
/// * verifying the hash matches the node hash in the Merkle Proof
|
||||
/// * finally verify maturity rules based on height of the block header
|
||||
///
|
||||
|
@ -652,7 +652,7 @@ impl Input {
|
|||
}
|
||||
|
||||
// Is the root the correct root for the given block header?
|
||||
if merkle_proof.root != header.utxo_root {
|
||||
if merkle_proof.root != header.output_root {
|
||||
return Err(Error::MerkleProof);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -37,7 +37,7 @@ List of folders in the grin git repo, and the `wallet` and `server` folders whic
|
|||
- .grin
|
||||
- chain - a Rocksdb with the blockchain blocks and related information
|
||||
- peers - a Rocksdb with the list of Grin peers you're connected to
|
||||
- sumtrees - containts folders kernel, rangeproof and utxo that each have a pmmr_dat.bin
|
||||
- txhashset - containts folders kernel, rangeproof and output that each have a pmmr_dat.bin
|
||||
- src
|
||||
Code for the `grin` binary.
|
||||
- store
|
||||
|
|
|
@ -26,14 +26,14 @@ A Grin transaction consists of the following -
|
|||
* An explicit transaction fee in the clear.
|
||||
* A signature, computed by taking the excess blinding value (the sum of all outputs plus the fee, minus the inputs) and using it as the private key.
|
||||
|
||||
We can show the output is unspent by looking for the commitment in the current UTXO set. The UTXO set is authoritative; if the output exists in the UTXO set we know it has not yet been spent. If an output does not exist in the UTXO set we know it has either never existed, or that it previously existed and has been spent (we will not necessarily know which).
|
||||
We can show the output is unspent by looking for the commitment in the current Output set. The Output set is authoritative; if the output exists in the Output set we know it has not yet been spent. If an output does not exist in the Output set we know it has either never existed, or that it previously existed and has been spent (we will not necessarily know which).
|
||||
|
||||
To prove ownership we can verify the transaction signature. We can _only_ have signed the transaction if the transaction sums to zero _and_ we know both `v` and `r`.
|
||||
|
||||
Knowing `v` and `r` we can uniquely identify the output (via its commitment) _and_ we can prove ownership of the output by validating the signature on the original coinbase transaction.
|
||||
|
||||
Grin does not permit duplicate commitments to exist in the UTXO set at the same time.
|
||||
But once an output is spent it is removed from the UTXO set and a duplicate commitment can be added back into the UTXO set.
|
||||
Grin does not permit duplicate commitments to exist in the Output set at the same time.
|
||||
But once an output is spent it is removed from the Output set and a duplicate commitment can be added back into the Output set.
|
||||
This is not necessarily recommended but Grin must handle this situation in a way that does not break consensus across the network.
|
||||
|
||||
Several things complicate this situation -
|
||||
|
@ -42,8 +42,8 @@ Several things complicate this situation -
|
|||
1. It is possible for a non-coinbase output to have the same value as a coinbase output.
|
||||
1. It is possible (but not recommended) for a miner to reuse private keys.
|
||||
|
||||
Grin does not allow duplicate commitments to exist in the UTXO set simultaneously.
|
||||
But the UTXO set is specific to the state of a particular chain fork. It _is_ possible for duplicate _identical_ commitments to exist simultaneously on different concurrent forks.
|
||||
Grin does not allow duplicate commitments to exist in the Output set simultaneously.
|
||||
But the Output set is specific to the state of a particular chain fork. It _is_ possible for duplicate _identical_ commitments to exist simultaneously on different concurrent forks.
|
||||
And these duplicate commitments may have different "lock heights" at which they mature and become spendable on the different forks.
|
||||
|
||||
* Output O<sub>1</sub> from block B<sub>1</sub> spendable at height h<sub>1</sub> (on fork f<sub>1</sub>)
|
||||
|
@ -97,7 +97,7 @@ We maintain an index mapping commitment to position in the output MMR.
|
|||
|
||||
If no entry in the index exists or no entry in the output MMR exists for a given commitment then we now the output is not spendable (either it was spent previously or it never existed).
|
||||
|
||||
If we find an entry in the output MMR then we know a spendable output exists in the UTXO set _but_ we do not know if this is the correct one. We do not if it is a coinbase output or not and we do not know the height of the block it originated from.
|
||||
If we find an entry in the output MMR then we know a spendable output exists in the Output set _but_ we do not know if this is the correct one. We do not if it is a coinbase output or not and we do not know the height of the block it originated from.
|
||||
|
||||
If the hash stored in the output MMR covers both the commitment and the output features and we require an input to provide both the commitment and the feature then we can do a further validation step -
|
||||
* output exists in the output MMR (based on commitment), and
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -267,12 +267,12 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Provides a reading view into the current sumtree state as well as
|
||||
/// Provides a reading view into the current txhashset state as well as
|
||||
/// the required indexes for a consumer to rewind to a consistant state
|
||||
/// at the provided block hash.
|
||||
fn sumtrees_read(&self, h: Hash) -> Option<p2p::SumtreesRead> {
|
||||
match w(&self.chain).sumtrees_read(h.clone()) {
|
||||
Ok((out_index, kernel_index, read)) => Some(p2p::SumtreesRead {
|
||||
fn txhashset_read(&self, h: Hash) -> Option<p2p::TxHashSetRead> {
|
||||
match w(&self.chain).txhashset_read(h.clone()) {
|
||||
Ok((out_index, kernel_index, read)) => Some(p2p::TxHashSetRead {
|
||||
output_index: out_index,
|
||||
kernel_index: kernel_index,
|
||||
reader: read,
|
||||
|
@ -280,33 +280,33 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
|||
Err(e) => {
|
||||
warn!(
|
||||
LOGGER,
|
||||
"Couldn't produce sumtrees data for block {}: {:?}", h, e
|
||||
"Couldn't produce txhashset data for block {}: {:?}", h, e
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a reading view on a sumtree state that's been provided to us.
|
||||
/// Writes a reading view on a txhashset state that's been provided to us.
|
||||
/// If we're willing to accept that new state, the data stream will be
|
||||
/// read as a zip file, unzipped and the resulting state files should be
|
||||
/// rewound to the provided indexes.
|
||||
fn sumtrees_write(
|
||||
fn txhashset_write(
|
||||
&self,
|
||||
h: Hash,
|
||||
rewind_to_output: u64,
|
||||
rewind_to_kernel: u64,
|
||||
sumtree_data: File,
|
||||
txhashset_data: File,
|
||||
_peer_addr: SocketAddr,
|
||||
) -> bool {
|
||||
// TODO check whether we should accept any sumtree now
|
||||
// TODO check whether we should accept any txhashset now
|
||||
if let Err(e) =
|
||||
w(&self.chain).sumtrees_write(h, rewind_to_output, rewind_to_kernel, sumtree_data)
|
||||
w(&self.chain).txhashset_write(h, rewind_to_output, rewind_to_kernel, txhashset_data)
|
||||
{
|
||||
error!(LOGGER, "Failed to save sumtree archive: {:?}", e);
|
||||
error!(LOGGER, "Failed to save txhashset archive: {:?}", e);
|
||||
!e.is_bad_data()
|
||||
} else {
|
||||
info!(LOGGER, "Received valid sumtree data for {}.", h);
|
||||
info!(LOGGER, "Received valid txhashset data for {}.", h);
|
||||
self.currently_syncing.store(true, Ordering::Relaxed);
|
||||
true
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016-2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -633,7 +633,7 @@ impl Miner {
|
|||
b.header.difficulty = difficulty;
|
||||
b.header.timestamp = time::at_utc(time::Timespec::new(now_sec, 0));
|
||||
|
||||
let roots_result = self.chain.set_sumtree_roots(&mut b, false);
|
||||
let roots_result = self.chain.set_txhashset_roots(&mut b, false);
|
||||
|
||||
match roots_result {
|
||||
Ok(_) => Ok((b, block_fees)),
|
||||
|
@ -649,7 +649,7 @@ impl Miner {
|
|||
Err(e) => {
|
||||
error!(
|
||||
LOGGER,
|
||||
"Error setting sumtree root to build a block: {:?}", e
|
||||
"Error setting txhashset root to build a block: {:?}", e
|
||||
);
|
||||
Err(Error::Chain(chain::Error::Other(format!("{:?}", e))))
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -50,7 +50,7 @@ pub fn run_sync(
|
|||
|
||||
// fast sync has 3 states:
|
||||
// * syncing headers
|
||||
// * once all headers are sync'd, requesting the sumtree state
|
||||
// * once all headers are sync'd, requesting the txhashset state
|
||||
// * once we have the state, get blocks after that
|
||||
//
|
||||
// full sync gets rid of the middle step and just starts from
|
||||
|
@ -63,14 +63,14 @@ pub fn run_sync(
|
|||
|
||||
// in archival nodes (no fast sync) we just consider we have the whole
|
||||
// state already
|
||||
let have_sumtrees = !fast_sync
|
||||
let have_txhashset = !fast_sync
|
||||
|| head.height > 0 && header_head.height.saturating_sub(head.height) <= horizon;
|
||||
|
||||
let syncing = needs_syncing(
|
||||
currently_syncing.clone(),
|
||||
peers.clone(),
|
||||
chain.clone(),
|
||||
!have_sumtrees,
|
||||
!have_txhashset,
|
||||
);
|
||||
|
||||
let current_time = time::now_utc();
|
||||
|
@ -82,32 +82,32 @@ pub fn run_sync(
|
|||
}
|
||||
|
||||
// run the body_sync every 5s
|
||||
if have_sumtrees && current_time - prev_body_sync > time::Duration::seconds(5) {
|
||||
if have_txhashset && current_time - prev_body_sync > time::Duration::seconds(5) {
|
||||
body_sync(peers.clone(), chain.clone());
|
||||
prev_body_sync = current_time;
|
||||
}
|
||||
} else if !have_sumtrees
|
||||
} else if !have_txhashset
|
||||
&& current_time - prev_state_sync > time::Duration::seconds(5 * 60)
|
||||
{
|
||||
if let Some(peer) = peers.most_work_peer() {
|
||||
if let Ok(p) = peer.try_read() {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Header head before sumtree request: {} / {}",
|
||||
"Header head before txhashset request: {} / {}",
|
||||
header_head.height,
|
||||
header_head.last_block_h
|
||||
);
|
||||
|
||||
// just to handle corner case of a too early start
|
||||
if header_head.height > horizon {
|
||||
// ask for sumtree at horizon
|
||||
let mut sumtree_head =
|
||||
// ask for txhashset at horizon
|
||||
let mut txhashset_head =
|
||||
chain.get_block_header(&header_head.prev_block_h).unwrap();
|
||||
for _ in 0..horizon - 2 {
|
||||
sumtree_head =
|
||||
chain.get_block_header(&sumtree_head.previous).unwrap();
|
||||
txhashset_head =
|
||||
chain.get_block_header(&txhashset_head.previous).unwrap();
|
||||
}
|
||||
p.send_sumtrees_request(sumtree_head.height, sumtree_head.hash())
|
||||
p.send_txhashset_request(txhashset_head.height, txhashset_head.hash())
|
||||
.unwrap();
|
||||
prev_state_sync = current_time;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -107,32 +107,32 @@ fn simple_server_wallet() {
|
|||
get_block_by_hash_compact(&base_addr, api_server_port, &block_hash);
|
||||
assert!(last_block_by_hash_compact.is_ok());
|
||||
|
||||
warn!(LOGGER, "Testing chain utxo handler");
|
||||
warn!(LOGGER, "Testing chain output handler");
|
||||
let start_height = 0;
|
||||
let end_height = current_tip.height;
|
||||
let utxos_by_height =
|
||||
get_utxos_by_height(&base_addr, api_server_port, start_height, end_height);
|
||||
assert!(utxos_by_height.is_ok());
|
||||
let ids = get_ids_from_block_outputs(utxos_by_height.unwrap());
|
||||
let utxos_by_ids1 = get_utxos_by_ids1(&base_addr, api_server_port, ids.clone());
|
||||
assert!(utxos_by_ids1.is_ok());
|
||||
let utxos_by_ids2 = get_utxos_by_ids2(&base_addr, api_server_port, ids.clone());
|
||||
assert!(utxos_by_ids2.is_ok());
|
||||
let outputs_by_height =
|
||||
get_outputs_by_height(&base_addr, api_server_port, start_height, end_height);
|
||||
assert!(outputs_by_height.is_ok());
|
||||
let ids = get_ids_from_block_outputs(outputs_by_height.unwrap());
|
||||
let outputs_by_ids1 = get_outputs_by_ids1(&base_addr, api_server_port, ids.clone());
|
||||
assert!(outputs_by_ids1.is_ok());
|
||||
let outputs_by_ids2 = get_outputs_by_ids2(&base_addr, api_server_port, ids.clone());
|
||||
assert!(outputs_by_ids2.is_ok());
|
||||
|
||||
warn!(LOGGER, "Testing sumtree handler");
|
||||
let roots = get_sumtree_roots(&base_addr, api_server_port);
|
||||
warn!(LOGGER, "Testing txhashset handler");
|
||||
let roots = get_txhashset_roots(&base_addr, api_server_port);
|
||||
assert!(roots.is_ok());
|
||||
let last_10_utxos = get_sumtree_lastutxos(&base_addr, api_server_port, 0);
|
||||
assert!(last_10_utxos.is_ok());
|
||||
let last_5_utxos = get_sumtree_lastutxos(&base_addr, api_server_port, 5);
|
||||
assert!(last_5_utxos.is_ok());
|
||||
let last_10_rangeproofs = get_sumtree_lastrangeproofs(&base_addr, api_server_port, 0);
|
||||
let last_10_outputs = get_txhashset_lastoutputs(&base_addr, api_server_port, 0);
|
||||
assert!(last_10_outputs.is_ok());
|
||||
let last_5_outputs = get_txhashset_lastoutputs(&base_addr, api_server_port, 5);
|
||||
assert!(last_5_outputs.is_ok());
|
||||
let last_10_rangeproofs = get_txhashset_lastrangeproofs(&base_addr, api_server_port, 0);
|
||||
assert!(last_10_rangeproofs.is_ok());
|
||||
let last_5_rangeproofs = get_sumtree_lastrangeproofs(&base_addr, api_server_port, 5);
|
||||
let last_5_rangeproofs = get_txhashset_lastrangeproofs(&base_addr, api_server_port, 5);
|
||||
assert!(last_5_rangeproofs.is_ok());
|
||||
let last_10_kernels = getsumtree_lastkernels(&base_addr, api_server_port, 0);
|
||||
let last_10_kernels = gettxhashset_lastkernels(&base_addr, api_server_port, 0);
|
||||
assert!(last_10_kernels.is_ok());
|
||||
let last_5_kernels = getsumtree_lastkernels(&base_addr, api_server_port, 5);
|
||||
let last_5_kernels = gettxhashset_lastkernels(&base_addr, api_server_port, 5);
|
||||
assert!(last_5_kernels.is_ok());
|
||||
|
||||
//let some more mining happen, make sure nothing pukes
|
||||
|
@ -295,26 +295,26 @@ fn get_block_by_hash_compact(
|
|||
api::client::get::<api::CompactBlockPrintable>(url.as_str()).map_err(|e| Error::API(e))
|
||||
}
|
||||
|
||||
// Chain utxo handler functions
|
||||
fn get_utxos_by_ids1(
|
||||
// Chain output handler functions
|
||||
fn get_outputs_by_ids1(
|
||||
base_addr: &String,
|
||||
api_server_port: u16,
|
||||
ids: Vec<String>,
|
||||
) -> Result<Vec<api::Utxo>, Error> {
|
||||
) -> Result<Vec<api::Output>, Error> {
|
||||
let url = format!(
|
||||
"http://{}:{}/v1/chain/utxos/byids?id={}",
|
||||
"http://{}:{}/v1/chain/outputs/byids?id={}",
|
||||
base_addr,
|
||||
api_server_port,
|
||||
ids.join(",")
|
||||
);
|
||||
api::client::get::<Vec<api::Utxo>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
api::client::get::<Vec<api::Output>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
}
|
||||
|
||||
fn get_utxos_by_ids2(
|
||||
fn get_outputs_by_ids2(
|
||||
base_addr: &String,
|
||||
api_server_port: u16,
|
||||
ids: Vec<String>,
|
||||
) -> Result<Vec<api::Utxo>, Error> {
|
||||
) -> Result<Vec<api::Output>, Error> {
|
||||
let mut ids_string: String = String::from("");
|
||||
for id in ids {
|
||||
ids_string = ids_string + "?id=" + &id;
|
||||
|
@ -322,92 +322,92 @@ fn get_utxos_by_ids2(
|
|||
let ids_string = String::from(&ids_string[1..ids_string.len()]);
|
||||
println!("{}", ids_string);
|
||||
let url = format!(
|
||||
"http://{}:{}/v1/chain/utxos/byids?{}",
|
||||
"http://{}:{}/v1/chain/outputs/byids?{}",
|
||||
base_addr, api_server_port, ids_string
|
||||
);
|
||||
api::client::get::<Vec<api::Utxo>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
api::client::get::<Vec<api::Output>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
}
|
||||
|
||||
fn get_utxos_by_height(
|
||||
fn get_outputs_by_height(
|
||||
base_addr: &String,
|
||||
api_server_port: u16,
|
||||
start_height: u64,
|
||||
end_height: u64,
|
||||
) -> Result<Vec<api::BlockOutputs>, Error> {
|
||||
let url = format!(
|
||||
"http://{}:{}/v1/chain/utxos/byheight?start_height={}&end_height={}",
|
||||
"http://{}:{}/v1/chain/outputs/byheight?start_height={}&end_height={}",
|
||||
base_addr, api_server_port, start_height, end_height
|
||||
);
|
||||
api::client::get::<Vec<api::BlockOutputs>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
}
|
||||
|
||||
// Sumtree handler functions
|
||||
fn get_sumtree_roots(base_addr: &String, api_server_port: u16) -> Result<api::SumTrees, Error> {
|
||||
// TxHashSet handler functions
|
||||
fn get_txhashset_roots(base_addr: &String, api_server_port: u16) -> Result<api::TxHashSet, Error> {
|
||||
let url = format!(
|
||||
"http://{}:{}/v1/pmmrtrees/roots",
|
||||
"http://{}:{}/v1/txhashset/roots",
|
||||
base_addr, api_server_port
|
||||
);
|
||||
api::client::get::<api::SumTrees>(url.as_str()).map_err(|e| Error::API(e))
|
||||
api::client::get::<api::TxHashSet>(url.as_str()).map_err(|e| Error::API(e))
|
||||
}
|
||||
|
||||
fn get_sumtree_lastutxos(
|
||||
fn get_txhashset_lastoutputs(
|
||||
base_addr: &String,
|
||||
api_server_port: u16,
|
||||
n: u64,
|
||||
) -> Result<Vec<api::PmmrTreeNode>, Error> {
|
||||
) -> Result<Vec<api::TxHashSetNode>, Error> {
|
||||
let url: String;
|
||||
if n == 0 {
|
||||
url = format!(
|
||||
"http://{}:{}/v1/pmmrtrees/lastutxos",
|
||||
"http://{}:{}/v1/txhashset/lastoutputs",
|
||||
base_addr, api_server_port
|
||||
);
|
||||
} else {
|
||||
url = format!(
|
||||
"http://{}:{}/v1/pmmrtrees/lastutxos?n={}",
|
||||
"http://{}:{}/v1/txhashset/lastoutputs?n={}",
|
||||
base_addr, api_server_port, n
|
||||
);
|
||||
}
|
||||
api::client::get::<Vec<api::PmmrTreeNode>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
api::client::get::<Vec<api::TxHashSetNode>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
}
|
||||
|
||||
fn get_sumtree_lastrangeproofs(
|
||||
fn get_txhashset_lastrangeproofs(
|
||||
base_addr: &String,
|
||||
api_server_port: u16,
|
||||
n: u64,
|
||||
) -> Result<Vec<api::PmmrTreeNode>, Error> {
|
||||
) -> Result<Vec<api::TxHashSetNode>, Error> {
|
||||
let url: String;
|
||||
if n == 0 {
|
||||
url = format!(
|
||||
"http://{}:{}/v1/pmmrtrees/lastrangeproofs",
|
||||
"http://{}:{}/v1/txhashset/lastrangeproofs",
|
||||
base_addr, api_server_port
|
||||
);
|
||||
} else {
|
||||
url = format!(
|
||||
"http://{}:{}/v1/pmmrtrees/lastrangeproofs?n={}",
|
||||
"http://{}:{}/v1/txhashset/lastrangeproofs?n={}",
|
||||
base_addr, api_server_port, n
|
||||
);
|
||||
}
|
||||
api::client::get::<Vec<api::PmmrTreeNode>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
api::client::get::<Vec<api::TxHashSetNode>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
}
|
||||
|
||||
fn getsumtree_lastkernels(
|
||||
fn gettxhashset_lastkernels(
|
||||
base_addr: &String,
|
||||
api_server_port: u16,
|
||||
n: u64,
|
||||
) -> Result<Vec<api::PmmrTreeNode>, Error> {
|
||||
) -> Result<Vec<api::TxHashSetNode>, Error> {
|
||||
let url: String;
|
||||
if n == 0 {
|
||||
url = format!(
|
||||
"http://{}:{}/v1/pmmrtrees/lastkernels",
|
||||
"http://{}:{}/v1/txhashset/lastkernels",
|
||||
base_addr, api_server_port
|
||||
);
|
||||
} else {
|
||||
url = format!(
|
||||
"http://{}:{}/v1/pmmrtrees/lastkernels?n={}",
|
||||
"http://{}:{}/v1/txhashset/lastkernels?n={}",
|
||||
base_addr, api_server_port, n
|
||||
);
|
||||
}
|
||||
api::client::get::<Vec<api::PmmrTreeNode>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
api::client::get::<Vec<api::TxHashSetNode>>(url.as_str()).map_err(|e| Error::API(e))
|
||||
}
|
||||
|
||||
// Helper function to get a vec of commitment output ids from a vec of block
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016-2018 The Grin Developers
|
||||
// Copyright 2018-2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -52,6 +52,6 @@ mod types;
|
|||
pub use serv::{DummyAdapter, Server};
|
||||
pub use peers::Peers;
|
||||
pub use peer::Peer;
|
||||
pub use types::{Capabilities, ChainAdapter, Error, P2PConfig, PeerInfo, SumtreesRead,
|
||||
pub use types::{Capabilities, ChainAdapter, Error, P2PConfig, PeerInfo, TxHashSetRead,
|
||||
MAX_BLOCK_HEADERS, MAX_PEER_ADDRS};
|
||||
pub use store::{PeerData, State};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016-2018 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -65,8 +65,8 @@ enum_from_primitive! {
|
|||
GetCompactBlock,
|
||||
CompactBlock,
|
||||
Transaction,
|
||||
SumtreesRequest,
|
||||
SumtreesArchive
|
||||
TxHashSetRequest,
|
||||
TxHashSetArchive
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -642,16 +642,16 @@ impl Readable for Pong {
|
|||
}
|
||||
}
|
||||
|
||||
/// Request to get an archive of the full sumtree store, required to sync
|
||||
/// Request to get an archive of the full txhashset store, required to sync
|
||||
/// a new node.
|
||||
pub struct SumtreesRequest {
|
||||
/// Hash of the block for which the sumtrees should be provided
|
||||
pub struct TxHashSetRequest {
|
||||
/// Hash of the block for which the txhashset should be provided
|
||||
pub hash: Hash,
|
||||
/// Height of the corresponding block
|
||||
pub height: u64,
|
||||
}
|
||||
|
||||
impl Writeable for SumtreesRequest {
|
||||
impl Writeable for TxHashSetRequest {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
self.hash.write(writer)?;
|
||||
writer.write_u64(self.height)?;
|
||||
|
@ -659,19 +659,19 @@ impl Writeable for SumtreesRequest {
|
|||
}
|
||||
}
|
||||
|
||||
impl Readable for SumtreesRequest {
|
||||
fn read(reader: &mut Reader) -> Result<SumtreesRequest, ser::Error> {
|
||||
Ok(SumtreesRequest {
|
||||
impl Readable for TxHashSetRequest {
|
||||
fn read(reader: &mut Reader) -> Result<TxHashSetRequest, ser::Error> {
|
||||
Ok(TxHashSetRequest {
|
||||
hash: Hash::read(reader)?,
|
||||
height: reader.read_u64()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Response to a sumtree archive request, must include a zip stream of the
|
||||
/// Response to a txhashset archive request, must include a zip stream of the
|
||||
/// archive after the message body.
|
||||
pub struct SumtreesArchive {
|
||||
/// Hash of the block for which the sumtrees are provided
|
||||
pub struct TxHashSetArchive {
|
||||
/// Hash of the block for which the txhashset are provided
|
||||
pub hash: Hash,
|
||||
/// Height of the corresponding block
|
||||
pub height: u64,
|
||||
|
@ -683,7 +683,7 @@ pub struct SumtreesArchive {
|
|||
pub bytes: u64,
|
||||
}
|
||||
|
||||
impl Writeable for SumtreesArchive {
|
||||
impl Writeable for TxHashSetArchive {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
self.hash.write(writer)?;
|
||||
ser_multiwrite!(
|
||||
|
@ -697,13 +697,13 @@ impl Writeable for SumtreesArchive {
|
|||
}
|
||||
}
|
||||
|
||||
impl Readable for SumtreesArchive {
|
||||
fn read(reader: &mut Reader) -> Result<SumtreesArchive, ser::Error> {
|
||||
impl Readable for TxHashSetArchive {
|
||||
fn read(reader: &mut Reader) -> Result<TxHashSetArchive, ser::Error> {
|
||||
let hash = Hash::read(reader)?;
|
||||
let (height, rewind_to_output, rewind_to_kernel, bytes) =
|
||||
ser_multiread!(reader, read_u64, read_u64, read_u64, read_u64);
|
||||
|
||||
Ok(SumtreesArchive {
|
||||
Ok(TxHashSetArchive {
|
||||
hash,
|
||||
height,
|
||||
rewind_to_output,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -277,14 +277,14 @@ impl Peer {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn send_sumtrees_request(&self, height: u64, hash: Hash) -> Result<(), Error> {
|
||||
pub fn send_txhashset_request(&self, height: u64, hash: Hash) -> Result<(), Error> {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Asking {} for sumtree archive at {} {}.", self.info.addr, height, hash
|
||||
"Asking {} for txhashset archive at {} {}.", self.info.addr, height, hash
|
||||
);
|
||||
self.connection.as_ref().unwrap().send(
|
||||
&SumtreesRequest { hash, height },
|
||||
msg::Type::SumtreesRequest,
|
||||
&TxHashSetRequest { hash, height },
|
||||
msg::Type::TxHashSetRequest,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -388,23 +388,23 @@ impl ChainAdapter for TrackingAdapter {
|
|||
self.adapter.get_block(h)
|
||||
}
|
||||
|
||||
fn sumtrees_read(&self, h: Hash) -> Option<SumtreesRead> {
|
||||
self.adapter.sumtrees_read(h)
|
||||
fn txhashset_read(&self, h: Hash) -> Option<TxHashSetRead> {
|
||||
self.adapter.txhashset_read(h)
|
||||
}
|
||||
|
||||
fn sumtrees_write(
|
||||
fn txhashset_write(
|
||||
&self,
|
||||
h: Hash,
|
||||
rewind_to_output: u64,
|
||||
rewind_to_kernel: u64,
|
||||
sumtree_data: File,
|
||||
txhashset_data: File,
|
||||
peer_addr: SocketAddr,
|
||||
) -> bool {
|
||||
self.adapter.sumtrees_write(
|
||||
self.adapter.txhashset_write(
|
||||
h,
|
||||
rewind_to_output,
|
||||
rewind_to_kernel,
|
||||
sumtree_data,
|
||||
txhashset_data,
|
||||
peer_addr,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -492,27 +492,27 @@ impl ChainAdapter for Peers {
|
|||
fn get_block(&self, h: Hash) -> Option<core::Block> {
|
||||
self.adapter.get_block(h)
|
||||
}
|
||||
fn sumtrees_read(&self, h: Hash) -> Option<SumtreesRead> {
|
||||
self.adapter.sumtrees_read(h)
|
||||
fn txhashset_read(&self, h: Hash) -> Option<TxHashSetRead> {
|
||||
self.adapter.txhashset_read(h)
|
||||
}
|
||||
fn sumtrees_write(
|
||||
fn txhashset_write(
|
||||
&self,
|
||||
h: Hash,
|
||||
rewind_to_output: u64,
|
||||
rewind_to_kernel: u64,
|
||||
sumtree_data: File,
|
||||
txhashset_data: File,
|
||||
peer_addr: SocketAddr,
|
||||
) -> bool {
|
||||
if !self.adapter.sumtrees_write(
|
||||
if !self.adapter.txhashset_write(
|
||||
h,
|
||||
rewind_to_output,
|
||||
rewind_to_kernel,
|
||||
sumtree_data,
|
||||
txhashset_data,
|
||||
peer_addr,
|
||||
) {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Received a bad sumtree data from {}, the peer will be banned", &peer_addr
|
||||
"Received a bad txhashset data from {}, the peer will be banned", &peer_addr
|
||||
);
|
||||
self.ban_peer(&peer_addr);
|
||||
false
|
||||
|
|
|
@ -174,39 +174,39 @@ impl MessageHandler for Protocol {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
Type::SumtreesRequest => {
|
||||
let sm_req: SumtreesRequest = msg.body()?;
|
||||
Type::TxHashSetRequest => {
|
||||
let sm_req: TxHashSetRequest = msg.body()?;
|
||||
debug!(
|
||||
LOGGER,
|
||||
"handle_payload: sumtree req for {} at {}", sm_req.hash, sm_req.height
|
||||
"handle_payload: txhashset req for {} at {}", sm_req.hash, sm_req.height
|
||||
);
|
||||
|
||||
let sumtrees = self.adapter.sumtrees_read(sm_req.hash);
|
||||
let txhashset = self.adapter.txhashset_read(sm_req.hash);
|
||||
|
||||
if let Some(sumtrees) = sumtrees {
|
||||
let file_sz = sumtrees.reader.metadata()?.len();
|
||||
if let Some(txhashset) = txhashset {
|
||||
let file_sz = txhashset.reader.metadata()?.len();
|
||||
let mut resp = msg.respond(
|
||||
Type::SumtreesArchive,
|
||||
&SumtreesArchive {
|
||||
Type::TxHashSetArchive,
|
||||
&TxHashSetArchive {
|
||||
height: sm_req.height as u64,
|
||||
hash: sm_req.hash,
|
||||
rewind_to_output: sumtrees.output_index,
|
||||
rewind_to_kernel: sumtrees.kernel_index,
|
||||
rewind_to_output: txhashset.output_index,
|
||||
rewind_to_kernel: txhashset.kernel_index,
|
||||
bytes: file_sz,
|
||||
},
|
||||
);
|
||||
resp.add_attachment(sumtrees.reader);
|
||||
resp.add_attachment(txhashset.reader);
|
||||
Ok(Some(resp))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
Type::SumtreesArchive => {
|
||||
let sm_arch: SumtreesArchive = msg.body()?;
|
||||
Type::TxHashSetArchive => {
|
||||
let sm_arch: TxHashSetArchive = msg.body()?;
|
||||
debug!(
|
||||
LOGGER,
|
||||
"handle_payload: sumtree archive for {} at {} rewind to {}/{}",
|
||||
"handle_payload: txhashset archive for {} at {} rewind to {}/{}",
|
||||
sm_arch.hash,
|
||||
sm_arch.height,
|
||||
sm_arch.rewind_to_output,
|
||||
|
@ -214,7 +214,7 @@ impl MessageHandler for Protocol {
|
|||
);
|
||||
|
||||
let mut tmp = env::temp_dir();
|
||||
tmp.push("sumtree.zip");
|
||||
tmp.push("txhashset.zip");
|
||||
{
|
||||
let mut tmp_zip = File::create(tmp.clone())?;
|
||||
msg.copy_attachment(sm_arch.bytes as usize, &mut tmp_zip)?;
|
||||
|
@ -222,7 +222,7 @@ impl MessageHandler for Protocol {
|
|||
}
|
||||
|
||||
let tmp_zip = File::open(tmp)?;
|
||||
self.adapter.sumtrees_write(
|
||||
self.adapter.txhashset_write(
|
||||
sm_arch.hash,
|
||||
sm_arch.rewind_to_output,
|
||||
sm_arch.rewind_to_kernel,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016-2018 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -222,16 +222,16 @@ impl ChainAdapter for DummyAdapter {
|
|||
fn get_block(&self, _: Hash) -> Option<core::Block> {
|
||||
None
|
||||
}
|
||||
fn sumtrees_read(&self, _h: Hash) -> Option<SumtreesRead> {
|
||||
fn txhashset_read(&self, _h: Hash) -> Option<TxHashSetRead> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn sumtrees_write(
|
||||
fn txhashset_write(
|
||||
&self,
|
||||
_h: Hash,
|
||||
_rewind_to_output: u64,
|
||||
_rewind_to_kernel: u64,
|
||||
_sumtree_data: File,
|
||||
_txhashset_data: File,
|
||||
_peer_addr: SocketAddr,
|
||||
) -> bool {
|
||||
false
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016-2018 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -113,14 +113,14 @@ bitflags! {
|
|||
const UNKNOWN = 0b00000000;
|
||||
/// Full archival node, has the whole history without any pruning.
|
||||
const FULL_HIST = 0b00000001;
|
||||
/// Can provide block headers and the UTXO set for some recent-enough
|
||||
/// Can provide block headers and the TxHashSet for some recent-enough
|
||||
/// height.
|
||||
const UTXO_HIST = 0b00000010;
|
||||
const TXHASHSET_HIST = 0b00000010;
|
||||
/// Can provide a list of healthy peers
|
||||
const PEER_LIST = 0b00000100;
|
||||
|
||||
const FULL_NODE = Capabilities::FULL_HIST.bits
|
||||
| Capabilities::UTXO_HIST.bits
|
||||
| Capabilities::TXHASHSET_HIST.bits
|
||||
| Capabilities::PEER_LIST.bits;
|
||||
}
|
||||
}
|
||||
|
@ -145,14 +145,14 @@ pub struct PeerInfo {
|
|||
pub direction: Direction,
|
||||
}
|
||||
|
||||
/// The full sumtree data along with indexes required for a consumer to
|
||||
/// The full txhashset data along with indexes required for a consumer to
|
||||
/// rewind to a consistant requested state.
|
||||
pub struct SumtreesRead {
|
||||
pub struct TxHashSetRead {
|
||||
/// Output tree index the receiver should rewind to
|
||||
pub output_index: u64,
|
||||
/// Kernel tree index the receiver should rewind to
|
||||
pub kernel_index: u64,
|
||||
/// Binary stream for the sumtree zipped data
|
||||
/// Binary stream for the txhashset zipped data
|
||||
pub reader: File,
|
||||
}
|
||||
|
||||
|
@ -192,21 +192,21 @@ pub trait ChainAdapter: Sync + Send {
|
|||
/// Gets a full block by its hash.
|
||||
fn get_block(&self, h: Hash) -> Option<core::Block>;
|
||||
|
||||
/// Provides a reading view into the current sumtree state as well as
|
||||
/// Provides a reading view into the current txhashset state as well as
|
||||
/// the required indexes for a consumer to rewind to a consistant state
|
||||
/// at the provided block hash.
|
||||
fn sumtrees_read(&self, h: Hash) -> Option<SumtreesRead>;
|
||||
fn txhashset_read(&self, h: Hash) -> Option<TxHashSetRead>;
|
||||
|
||||
/// Writes a reading view on a sumtree state that's been provided to us.
|
||||
/// Writes a reading view on a txhashset state that's been provided to us.
|
||||
/// If we're willing to accept that new state, the data stream will be
|
||||
/// read as a zip file, unzipped and the resulting state files should be
|
||||
/// rewound to the provided indexes.
|
||||
fn sumtrees_write(
|
||||
fn txhashset_write(
|
||||
&self,
|
||||
h: Hash,
|
||||
rewind_to_output: u64,
|
||||
rewind_to_kernel: u64,
|
||||
sumtree_data: File,
|
||||
txhashset_data: File,
|
||||
peer_addr: SocketAddr,
|
||||
) -> bool;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// This file is (hopefully) temporary.
|
||||
//
|
||||
// It contains a trait based on (but not exactly equal to) the trait defined
|
||||
// for the blockchain UTXO set, discussed at
|
||||
// for the blockchain Output set, discussed at
|
||||
// https://github.com/ignopeverell/grin/issues/29, and a dummy implementation
|
||||
// of said trait.
|
||||
// Notably, UtxoDiff has been left off, and the question of how to handle
|
||||
// Notably, OutputDiff has been left off, and the question of how to handle
|
||||
// abstract return types has been deferred.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
@ -18,15 +18,15 @@ use core::core::hash::Hashed;
|
|||
use types::{BlockChain, PoolError};
|
||||
use util::secp::pedersen::Commitment;
|
||||
|
||||
/// A DummyUtxoSet for mocking up the chain
|
||||
pub struct DummyUtxoSet {
|
||||
/// A DummyOutputSet for mocking up the chain
|
||||
pub struct DummyOutputSet {
|
||||
outputs: HashMap<Commitment, transaction::Output>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl DummyUtxoSet {
|
||||
pub fn empty() -> DummyUtxoSet {
|
||||
DummyUtxoSet {
|
||||
impl DummyOutputSet {
|
||||
pub fn empty() -> DummyOutputSet {
|
||||
DummyOutputSet {
|
||||
outputs: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ impl DummyUtxoSet {
|
|||
hash::ZERO_HASH
|
||||
}
|
||||
|
||||
pub fn apply(&self, b: &block::Block) -> DummyUtxoSet {
|
||||
pub fn apply(&self, b: &block::Block) -> DummyOutputSet {
|
||||
let mut new_outputs = self.outputs.clone();
|
||||
|
||||
for input in &b.inputs {
|
||||
|
@ -44,7 +44,7 @@ impl DummyUtxoSet {
|
|||
for output in &b.outputs {
|
||||
new_outputs.insert(output.commitment(), output.clone());
|
||||
}
|
||||
DummyUtxoSet {
|
||||
DummyOutputSet {
|
||||
outputs: new_outputs,
|
||||
}
|
||||
}
|
||||
|
@ -58,8 +58,8 @@ impl DummyUtxoSet {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn rewind(&self, _: &block::Block) -> DummyUtxoSet {
|
||||
DummyUtxoSet {
|
||||
pub fn rewind(&self, _: &block::Block) -> DummyOutputSet {
|
||||
DummyOutputSet {
|
||||
outputs: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
@ -68,17 +68,17 @@ impl DummyUtxoSet {
|
|||
self.outputs.get(output_ref)
|
||||
}
|
||||
|
||||
fn clone(&self) -> DummyUtxoSet {
|
||||
DummyUtxoSet {
|
||||
fn clone(&self) -> DummyOutputSet {
|
||||
DummyOutputSet {
|
||||
outputs: self.outputs.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
// only for testing: add an output to the map
|
||||
pub fn with_output(&self, output: transaction::Output) -> DummyUtxoSet {
|
||||
pub fn with_output(&self, output: transaction::Output) -> DummyOutputSet {
|
||||
let mut new_outputs = self.outputs.clone();
|
||||
new_outputs.insert(output.commitment(), output);
|
||||
DummyUtxoSet {
|
||||
DummyOutputSet {
|
||||
outputs: new_outputs,
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ impl DummyUtxoSet {
|
|||
/// need
|
||||
#[allow(dead_code)]
|
||||
pub struct DummyChainImpl {
|
||||
utxo: RwLock<DummyUtxoSet>,
|
||||
output: RwLock<DummyOutputSet>,
|
||||
block_headers: RwLock<Vec<block::BlockHeader>>,
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ pub struct DummyChainImpl {
|
|||
impl DummyChainImpl {
|
||||
pub fn new() -> DummyChainImpl {
|
||||
DummyChainImpl {
|
||||
utxo: RwLock::new(DummyUtxoSet {
|
||||
output: RwLock::new(DummyOutputSet {
|
||||
outputs: HashMap::new(),
|
||||
}),
|
||||
block_headers: RwLock::new(vec![]),
|
||||
|
@ -106,7 +106,7 @@ impl DummyChainImpl {
|
|||
|
||||
impl BlockChain for DummyChainImpl {
|
||||
fn is_unspent(&self, output_ref: &OutputIdentifier) -> Result<hash::Hash, PoolError> {
|
||||
match self.utxo.read().unwrap().get_output(&output_ref.commit) {
|
||||
match self.output.read().unwrap().get_output(&output_ref.commit) {
|
||||
Some(_) => Ok(hash::Hash::zero()),
|
||||
None => Err(PoolError::GenericPoolError),
|
||||
}
|
||||
|
@ -137,12 +137,12 @@ impl BlockChain for DummyChainImpl {
|
|||
}
|
||||
|
||||
impl DummyChain for DummyChainImpl {
|
||||
fn update_utxo_set(&mut self, new_utxo: DummyUtxoSet) {
|
||||
self.utxo = RwLock::new(new_utxo);
|
||||
fn update_output_set(&mut self, new_output: DummyOutputSet) {
|
||||
self.output = RwLock::new(new_output);
|
||||
}
|
||||
|
||||
fn apply_block(&self, b: &block::Block) {
|
||||
self.utxo.write().unwrap().with_block(b);
|
||||
self.output.write().unwrap().with_block(b);
|
||||
self.store_head_header(&b.header)
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ impl DummyChain for DummyChainImpl {
|
|||
}
|
||||
|
||||
pub trait DummyChain: BlockChain {
|
||||
fn update_utxo_set(&mut self, new_utxo: DummyUtxoSet);
|
||||
fn update_output_set(&mut self, new_output: DummyOutputSet);
|
||||
fn apply_block(&self, b: &block::Block);
|
||||
fn store_head_header(&self, block_header: &block::BlockHeader);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -100,7 +100,7 @@ where
|
|||
}
|
||||
|
||||
/// Searches for an output, designated by its commitment, from the current
|
||||
/// best UTXO view, presented by taking the best blockchain UTXO set (as
|
||||
/// best Output view, presented by taking the best blockchain Output set (as
|
||||
/// determined by the blockchain component) and rectifying pool spent and
|
||||
/// unspents.
|
||||
/// Detects double spends and unknown references from the pool and
|
||||
|
@ -456,7 +456,7 @@ where
|
|||
) -> Result<Vec<Box<transaction::Transaction>>, PoolError> {
|
||||
// If this pool has been kept in sync correctly, serializing all
|
||||
// updates, then the inputs must consume only members of the blockchain
|
||||
// utxo set.
|
||||
// output set.
|
||||
// If the block has been resolved properly and reduced fully to its
|
||||
// canonical form, no inputs may consume outputs generated by previous
|
||||
// transactions in the block; they would be cut-through. TODO: If this
|
||||
|
@ -467,11 +467,11 @@ where
|
|||
// consumes the same blockchain output.
|
||||
// If one exists, we mark the transaction and then examine its
|
||||
// children. Recursively, we mark each child until a child is
|
||||
// fully satisfied by outputs in the updated utxo view (after
|
||||
// fully satisfied by outputs in the updated output view (after
|
||||
// reconciliation of the block), or there are no more children.
|
||||
//
|
||||
// Additionally, to protect our invariant dictating no duplicate
|
||||
// outputs, each output generated by the new utxo set is checked
|
||||
// outputs, each output generated by the new output set is checked
|
||||
// against outputs generated by the pool and the corresponding
|
||||
// transactions are also marked.
|
||||
//
|
||||
|
@ -525,7 +525,7 @@ where
|
|||
/// The transaction designated by conflicting_tx is immediately marked.
|
||||
/// Each output of this transaction is then examined; if a transaction in
|
||||
/// the pool spends this output and the output is not replaced by an
|
||||
/// identical output included in the updated UTXO set, the child is marked
|
||||
/// identical output included in the updated Output set, the child is marked
|
||||
/// as well and the process continues recursively.
|
||||
///
|
||||
/// Marked transactions are added to the mutable marked_txs HashMap which
|
||||
|
@ -630,7 +630,7 @@ mod tests {
|
|||
use super::*;
|
||||
use core::core::build;
|
||||
use core::global;
|
||||
use blockchain::{DummyChain, DummyChainImpl, DummyUtxoSet};
|
||||
use blockchain::{DummyChain, DummyChainImpl, DummyOutputSet};
|
||||
use util::secp;
|
||||
use keychain::Keychain;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
@ -669,7 +669,7 @@ mod tests {
|
|||
|
||||
let parent_transaction = test_transaction(vec![5, 6, 7], vec![11, 3]);
|
||||
// We want this transaction to be rooted in the blockchain.
|
||||
let new_utxo = DummyUtxoSet::empty()
|
||||
let new_output = DummyOutputSet::empty()
|
||||
.with_output(test_output(5))
|
||||
.with_output(test_output(6))
|
||||
.with_output(test_output(7))
|
||||
|
@ -678,7 +678,7 @@ mod tests {
|
|||
// Prepare a second transaction, connected to the first.
|
||||
let child_transaction = test_transaction(vec![11, 3], vec![12]);
|
||||
|
||||
dummy_chain.update_utxo_set(new_utxo);
|
||||
dummy_chain.update_output_set(new_output);
|
||||
|
||||
// To mirror how this construction is intended to be used, the pool
|
||||
// is placed inside a RwLock.
|
||||
|
@ -727,12 +727,12 @@ mod tests {
|
|||
};
|
||||
dummy_chain.store_head_header(&head_header);
|
||||
|
||||
let new_utxo = DummyUtxoSet::empty()
|
||||
let new_output = DummyOutputSet::empty()
|
||||
.with_output(test_output(5))
|
||||
.with_output(test_output(6))
|
||||
.with_output(test_output(7));
|
||||
|
||||
dummy_chain.update_utxo_set(new_utxo);
|
||||
dummy_chain.update_output_set(new_output);
|
||||
|
||||
let pool = RwLock::new(test_setup(&Arc::new(dummy_chain)));
|
||||
{
|
||||
|
@ -838,7 +838,7 @@ mod tests {
|
|||
assert_eq!(lock_height, 4);
|
||||
|
||||
let coinbase_output = test_coinbase_output(15);
|
||||
dummy_chain.update_utxo_set(DummyUtxoSet::empty().with_output(coinbase_output));
|
||||
dummy_chain.update_output_set(DummyOutputSet::empty().with_output(coinbase_output));
|
||||
|
||||
let chain_ref = Arc::new(dummy_chain);
|
||||
let pool = RwLock::new(test_setup(&chain_ref));
|
||||
|
@ -895,15 +895,15 @@ mod tests {
|
|||
};
|
||||
dummy_chain.store_head_header(&head_header);
|
||||
|
||||
// single UTXO
|
||||
let new_utxo = DummyUtxoSet::empty().with_output(test_output(100));
|
||||
// single Output
|
||||
let new_output = DummyOutputSet::empty().with_output(test_output(100));
|
||||
|
||||
dummy_chain.update_utxo_set(new_utxo);
|
||||
dummy_chain.update_output_set(new_output);
|
||||
let chain_ref = Arc::new(dummy_chain);
|
||||
let pool = RwLock::new(test_setup(&chain_ref));
|
||||
|
||||
// now create two txs
|
||||
// tx1 spends the UTXO
|
||||
// tx1 spends the Output
|
||||
// tx2 spends output from tx1
|
||||
let tx1 = test_transaction(vec![100], vec![90]);
|
||||
let tx2 = test_transaction(vec![90], vec![80]);
|
||||
|
@ -973,13 +973,13 @@ mod tests {
|
|||
};
|
||||
dummy_chain.store_head_header(&head_header);
|
||||
|
||||
let new_utxo = DummyUtxoSet::empty()
|
||||
let new_output = DummyOutputSet::empty()
|
||||
.with_output(test_output(10))
|
||||
.with_output(test_output(20))
|
||||
.with_output(test_output(30))
|
||||
.with_output(test_output(40));
|
||||
|
||||
dummy_chain.update_utxo_set(new_utxo);
|
||||
dummy_chain.update_output_set(new_output);
|
||||
|
||||
let chain_ref = Arc::new(dummy_chain);
|
||||
|
||||
|
@ -1127,13 +1127,13 @@ mod tests {
|
|||
};
|
||||
dummy_chain.store_head_header(&head_header);
|
||||
|
||||
let new_utxo = DummyUtxoSet::empty()
|
||||
let new_output = DummyOutputSet::empty()
|
||||
.with_output(test_output(10))
|
||||
.with_output(test_output(20))
|
||||
.with_output(test_output(30))
|
||||
.with_output(test_output(40));
|
||||
|
||||
dummy_chain.update_utxo_set(new_utxo);
|
||||
dummy_chain.update_output_set(new_output);
|
||||
|
||||
let chain_ref = Arc::new(dummy_chain);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -182,7 +182,7 @@ impl PoolAdapter for NoopAdapter {
|
|||
/// not respected.
|
||||
/// Spending references (input -> output) exist in two structures: internal
|
||||
/// graph references are contained in the pool edge sets, while references
|
||||
/// sourced from the blockchain's UTXO set are contained in the
|
||||
/// sourced from the blockchain's Output set are contained in the
|
||||
/// blockchain_connections set.
|
||||
/// Spent by references (output-> input) exist in two structures: pool-pool
|
||||
/// connections are in the pool edge set, while unspent (dangling) references
|
||||
|
@ -195,7 +195,7 @@ pub struct Pool {
|
|||
// output's hash.
|
||||
available_outputs: HashMap<Commitment, graph::Edge>,
|
||||
|
||||
// Consumed blockchain utxo's are kept in a separate map.
|
||||
// Consumed blockchain output's are kept in a separate map.
|
||||
consumed_blockchain_outputs: HashMap<Commitment, graph::Edge>,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
@ -300,7 +300,7 @@ where
|
|||
|
||||
/// Checks the length of the remove log to see if it should get compacted.
|
||||
/// If so, the remove log is flushed into the pruned list, which itself gets
|
||||
/// saved, and the main hashsum data file is rewritten, cutting the removed
|
||||
/// saved, and the hash and data files are rewritten, cutting the removed
|
||||
/// data.
|
||||
///
|
||||
/// If a max_len strictly greater than 0 is provided, the value will be used
|
||||
|
@ -310,7 +310,7 @@ where
|
|||
/// A cutoff limits compaction on recent data. Provided as an indexed value
|
||||
/// on pruned data (practically a block height), it forces compaction to
|
||||
/// ignore any prunable data beyond the cutoff. This is used to enforce
|
||||
/// an horizon after which the local node should have all the data to allow
|
||||
/// a horizon after which the local node should have all the data to allow
|
||||
/// rewinding.
|
||||
///
|
||||
/// TODO whatever is calling this should also clean up the commit to
|
||||
|
@ -336,7 +336,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// 1. save hashsum file to a compact copy, skipping data that's in the
|
||||
// 1. save hash file to a compact copy, skipping data that's in the
|
||||
// remove list
|
||||
let tmp_prune_file_hash = format!("{}/{}.hashprune", self.data_dir, PMMR_HASH_FILE);
|
||||
let record_len = 32;
|
||||
|
@ -375,7 +375,7 @@ where
|
|||
&self.pruned_nodes.pruned_nodes,
|
||||
)?;
|
||||
|
||||
// 4. move the compact copy of hashes to the hashsum file and re-open it
|
||||
// 4. move the compact copy of hashes to the hash file and re-open it
|
||||
fs::rename(
|
||||
tmp_prune_file_hash.clone(),
|
||||
format!("{}/{}", self.data_dir, PMMR_HASH_FILE),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -34,7 +34,7 @@ fn mark_unspent_output(out: &mut OutputData) {
|
|||
}
|
||||
}
|
||||
|
||||
// Transitions a local wallet output (based on it not being in the node utxo
|
||||
// Transitions a local wallet output (based on it not being in the node output
|
||||
// set) -
|
||||
// Unspent -> Spent
|
||||
// Locked -> Spent
|
||||
|
@ -97,7 +97,7 @@ fn refresh_missing_block_hashes(config: &WalletConfig, keychain: &Keychain) -> R
|
|||
query_params.append(&mut id_params);
|
||||
|
||||
let url = format!(
|
||||
"{}/v1/chain/utxos/byheight?{}",
|
||||
"{}/v1/chain/outputs/byheight?{}",
|
||||
config.check_node_api_http_addr,
|
||||
query_params.join("&"),
|
||||
);
|
||||
|
@ -175,18 +175,18 @@ fn refresh_output_state(config: &WalletConfig, keychain: &Keychain) -> Result<()
|
|||
.collect();
|
||||
|
||||
// build a map of api outputs by commit so we can look them up efficiently
|
||||
let mut api_utxos: HashMap<pedersen::Commitment, api::Utxo> = HashMap::new();
|
||||
let mut api_outputs: HashMap<pedersen::Commitment, api::Output> = HashMap::new();
|
||||
|
||||
let query_string = query_params.join("&");
|
||||
|
||||
let url = format!(
|
||||
"{}/v1/chain/utxos/byids?{}",
|
||||
"{}/v1/chain/outputs/byids?{}",
|
||||
config.check_node_api_http_addr, query_string,
|
||||
);
|
||||
|
||||
match api::client::get::<Vec<api::Utxo>>(url.as_str()) {
|
||||
match api::client::get::<Vec<api::Output>>(url.as_str()) {
|
||||
Ok(outputs) => for out in outputs {
|
||||
api_utxos.insert(out.commit.commit(), out);
|
||||
api_outputs.insert(out.commit.commit(), out);
|
||||
},
|
||||
Err(e) => {
|
||||
// if we got anything other than 200 back from server, don't attempt to refresh
|
||||
|
@ -203,7 +203,7 @@ fn refresh_output_state(config: &WalletConfig, keychain: &Keychain) -> Result<()
|
|||
for commit in wallet_outputs.keys() {
|
||||
let id = wallet_outputs.get(&commit).unwrap();
|
||||
if let Entry::Occupied(mut output) = wallet_data.outputs.entry(id.to_hex()) {
|
||||
match api_utxos.get(&commit) {
|
||||
match api_outputs.get(&commit) {
|
||||
Some(_) => mark_unspent_output(&mut output.get_mut()),
|
||||
None => mark_spent_output(&mut output.get_mut()),
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -46,7 +46,7 @@ fn output_with_range_proof(
|
|||
height: u64,
|
||||
) -> Result<api::OutputPrintable, Error> {
|
||||
let url = format!(
|
||||
"{}/v1/chain/utxos/byheight?start_height={}&end_height={}&id={}&include_rp",
|
||||
"{}/v1/chain/outputs/byheight?start_height={}&end_height={}&id={}&include_rp",
|
||||
config.check_node_api_http_addr, height, height, commit_id,
|
||||
);
|
||||
|
||||
|
@ -107,7 +107,7 @@ fn retrieve_amount_and_coinbase_status(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn utxos_batch_block(
|
||||
pub fn outputs_batch_block(
|
||||
config: &WalletConfig,
|
||||
start_height: u64,
|
||||
end_height: u64,
|
||||
|
@ -115,7 +115,7 @@ pub fn utxos_batch_block(
|
|||
let query_param = format!("start_height={}&end_height={}", start_height, end_height);
|
||||
|
||||
let url = format!(
|
||||
"{}/v1/chain/utxos/byheight?{}",
|
||||
"{}/v1/chain/outputs/byheight?{}",
|
||||
config.check_node_api_http_addr, query_param,
|
||||
);
|
||||
|
||||
|
@ -125,7 +125,7 @@ pub fn utxos_batch_block(
|
|||
// if we got anything other than 200 back from server, bye
|
||||
error!(
|
||||
LOGGER,
|
||||
"utxos_batch_block: Restore failed... unable to contact API {}. Error: {}",
|
||||
"outputs_batch_block: Restore failed... unable to contact API {}. Error: {}",
|
||||
config.check_node_api_http_addr,
|
||||
e
|
||||
);
|
||||
|
@ -135,7 +135,7 @@ pub fn utxos_batch_block(
|
|||
}
|
||||
|
||||
// TODO - wrap the many return values in a struct
|
||||
fn find_utxos_with_key(
|
||||
fn find_outputs_with_key(
|
||||
config: &WalletConfig,
|
||||
keychain: &Keychain,
|
||||
switch_commit_cache: &Vec<pedersen::Commitment>,
|
||||
|
@ -279,12 +279,12 @@ pub fn restore(
|
|||
} else {
|
||||
h = 0;
|
||||
}
|
||||
let mut blocks = utxos_batch_block(config, h + 1, end_batch)?;
|
||||
let mut blocks = outputs_batch_block(config, h + 1, end_batch)?;
|
||||
blocks.reverse();
|
||||
|
||||
let _ = WalletData::with_wallet(&config.data_file_dir, |wallet_data| {
|
||||
for block in blocks {
|
||||
let result_vec = find_utxos_with_key(
|
||||
let result_vec = find_outputs_with_key(
|
||||
config,
|
||||
keychain,
|
||||
&switch_commit_cache,
|
||||
|
|
|
@ -30,7 +30,7 @@ use failure::ResultExt;
|
|||
|
||||
/// Issue a new transaction to the provided sender by spending some of our
|
||||
/// wallet
|
||||
/// UTXOs. The destination can be "stdout" (for command line) (currently disabled) or a URL to the
|
||||
/// Outputs. The destination can be "stdout" (for command line) (currently disabled) or a URL to the
|
||||
/// recipients wallet receiver (to be implemented).
|
||||
pub fn issue_send_tx(
|
||||
config: &WalletConfig,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Grin Developers
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -659,7 +659,7 @@ impl WalletData {
|
|||
// use a sliding window to identify potential sets of possible outputs to spend
|
||||
// Case of amount > total amount of max_outputs(500):
|
||||
// The limit exists because by default, we always select as many inputs as
|
||||
// possible in a transaction, to reduce both the UTXO set and the fees.
|
||||
// possible in a transaction, to reduce both the Output set and the fees.
|
||||
// But that only makes sense up to a point, hence the limit to avoid being too
|
||||
// greedy. But if max_outputs(500) is actually not enought to cover the whole
|
||||
// amount, the wallet should allow going over it to satisfy what the user
|
||||
|
|
Loading…
Reference in a new issue