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