Wallet+Keychain refactoring (#1035)

* beginning to refactor keychain into wallet lib

* rustfmt

* more refactor of aggsig lib, simplify aggsig context manager, hold instance statically for now

* clean some warnings

* clean some warnings

* fix wallet send test a bit

* fix core tests, move wallet dependent tests into integration tests

* repair chain tests

* refactor/fix pool tests

* fix wallet tests, moved from keychain

* add wallet tests
This commit is contained in:
Yeastplume
2018-05-09 10:15:58 +01:00
committed by GitHub
parent 982fdea636
commit 4121ea1240
44 changed files with 3599 additions and 3183 deletions
+33 -8
View File
@@ -1,11 +1,25 @@
// This file is (hopefully) temporary.
// Copyright 2018 The Grin Developers
//
// It contains a trait based on (but not exactly equal to) the trait defined
// for the blockchain Output set, discussed at
// https://github.com/ignopeverell/grin/issues/29, and a dummy implementation
// of said trait.
// Notably, OutputDiff has been left off, and the question of how to handle
// abstract return types has been deferred.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! This file is (hopefully) temporary.
//!
//! It contains a trait based on (but not exactly equal to) the trait defined
//! for the blockchain Output set, discussed at
//! https://github.com/ignopeverell/grin/issues/29, and a dummy implementation
//! of said trait.
//! Notably, OutputDiff has been left off, and the question of how to handle
//! abstract return types has been deferred.
use std::collections::HashMap;
use std::clone::Clone;
@@ -25,16 +39,19 @@ pub struct DummyOutputSet {
#[allow(dead_code)]
impl DummyOutputSet {
/// Empty output set
pub fn empty() -> DummyOutputSet {
DummyOutputSet {
outputs: HashMap::new(),
}
}
/// roots
pub fn root(&self) -> hash::Hash {
hash::ZERO_HASH
}
/// apply a block
pub fn apply(&self, b: &block::Block) -> DummyOutputSet {
let mut new_outputs = self.outputs.clone();
@@ -49,6 +66,7 @@ impl DummyOutputSet {
}
}
/// create with block
pub fn with_block(&mut self, b: &block::Block) {
for input in &b.inputs {
self.outputs.remove(&input.commitment());
@@ -58,12 +76,14 @@ impl DummyOutputSet {
}
}
/// rewind
pub fn rewind(&self, _: &block::Block) -> DummyOutputSet {
DummyOutputSet {
outputs: HashMap::new(),
}
}
/// get an output
pub fn get_output(&self, output_ref: &Commitment) -> Option<&transaction::Output> {
self.outputs.get(output_ref)
}
@@ -74,7 +94,7 @@ impl DummyOutputSet {
}
}
// 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) -> DummyOutputSet {
let mut new_outputs = self.outputs.clone();
new_outputs.insert(output.commitment(), output);
@@ -94,6 +114,7 @@ pub struct DummyChainImpl {
#[allow(dead_code)]
impl DummyChainImpl {
/// new dummy chain
pub fn new() -> DummyChainImpl {
DummyChainImpl {
output: RwLock::new(DummyOutputSet {
@@ -152,8 +173,12 @@ impl DummyChain for DummyChainImpl {
}
}
/// Dummy chain trait
pub trait DummyChain: BlockChain {
/// update output set
fn update_output_set(&mut self, new_output: DummyOutputSet);
/// apply a block
fn apply_block(&self, b: &block::Block);
/// store header
fn store_head_header(&self, block_header: &block::BlockHeader);
}
+8 -80
View File
@@ -139,13 +139,14 @@ impl fmt::Debug for Edge {
/// The generic graph container. Both graphs, the pool and orphans, embed this
/// structure and add additional capability on top of it.
pub struct DirectedGraph {
edges: HashMap<Commitment, Edge>,
vertices: Vec<PoolEntry>,
// A small optimization: keeping roots (vertices with in-degree 0) in a
// separate list makes topological sort a bit faster. (This is true for
// Kahn's, not sure about other implementations)
roots: Vec<PoolEntry>,
/// Edges
pub edges: HashMap<Commitment, Edge>,
/// Vertices
pub vertices: Vec<PoolEntry>,
/// A small optimization: keeping roots (vertices with in-degree 0) in a
/// separate list makes topological sort a bit faster. (This is true for
/// Kahn's, not sure about other implementations)
pub roots: Vec<PoolEntry>,
}
impl DirectedGraph {
@@ -290,76 +291,3 @@ pub fn transaction_identifier(tx: &core::transaction::Transaction) -> core::hash
// core::transaction::merkle_inputs_outputs(&tx.inputs, &tx.outputs)
tx.hash()
}
#[cfg(test)]
mod tests {
use super::*;
use keychain::Keychain;
use rand;
use core::core::OutputFeatures;
use core::core::transaction::ProofMessageElements;
#[test]
fn test_add_entry() {
let keychain = Keychain::from_random_seed().unwrap();
let key_id1 = keychain.derive_key_id(1).unwrap();
let key_id2 = keychain.derive_key_id(2).unwrap();
let key_id3 = keychain.derive_key_id(3).unwrap();
let output_commit = keychain.commit(70, &key_id1).unwrap();
let inputs = vec![
core::transaction::Input::new(
OutputFeatures::DEFAULT_OUTPUT,
keychain.commit(50, &key_id2).unwrap(),
None,
None,
),
core::transaction::Input::new(
OutputFeatures::DEFAULT_OUTPUT,
keychain.commit(25, &key_id3).unwrap(),
None,
None,
),
];
let msg = ProofMessageElements::new(100, &key_id1);
let output = core::transaction::Output {
features: OutputFeatures::DEFAULT_OUTPUT,
commit: output_commit,
proof: keychain
.range_proof(100, &key_id1, output_commit, None, msg.to_proof_message())
.unwrap(),
};
let kernel = core::transaction::TxKernel::empty()
.with_fee(5)
.with_lock_height(0);
let test_transaction =
core::transaction::Transaction::new(inputs, vec![output], vec![kernel]);
let test_pool_entry = PoolEntry::new(&test_transaction);
let incoming_edge_1 = Edge::new(
Some(random_hash()),
Some(core::hash::ZERO_HASH),
OutputIdentifier::from_output(&output),
);
let mut test_graph = DirectedGraph::empty();
test_graph.add_entry(test_pool_entry, vec![incoming_edge_1]);
assert_eq!(test_graph.vertices.len(), 1);
assert_eq!(test_graph.roots.len(), 0);
assert_eq!(test_graph.edges.len(), 1);
}
/// For testing/debugging: a random tx hash
fn random_hash() -> core::hash::Hash {
let hash_bytes: [u8; 32] = rand::random();
core::hash::Hash(hash_bytes)
}
}
+3 -3
View File
@@ -22,9 +22,9 @@
#![warn(missing_docs)]
pub mod graph;
mod types;
mod blockchain;
mod pool;
pub mod types;
pub mod blockchain;
pub mod pool;
extern crate blake2_rfc as blake2;
extern crate grin_core as core;
+7 -1120
View File
File diff suppressed because it is too large Load Diff
+32 -6
View File
@@ -92,11 +92,25 @@ pub struct TxSource {
/// This enum describes the parent for a given input of a transaction.
#[derive(Clone)]
pub enum Parent {
/// Unknown
Unknown,
/// Block Transaction
BlockTransaction,
PoolTransaction { tx_ref: hash::Hash },
StemPoolTransaction { tx_ref: hash::Hash },
AlreadySpent { other_tx: hash::Hash },
/// Pool Transaction
PoolTransaction {
/// Transaction reference
tx_ref: hash::Hash,
},
/// StemPool Transaction
StemPoolTransaction {
/// Transaction reference
tx_ref: hash::Hash,
},
/// AlreadySpent
AlreadySpent {
/// Other transaction reference
other_tx: hash::Hash,
},
}
impl fmt::Debug for Parent {
@@ -244,6 +258,7 @@ pub struct Pool {
}
impl Pool {
/// Return an empty pool
pub fn empty() -> Pool {
Pool {
graph: graph::DirectedGraph::empty(),
@@ -263,18 +278,22 @@ impl Pool {
.map(|x| x.destination_hash().unwrap())
}
/// Length of roots
pub fn len_roots(&self) -> usize {
self.graph.len_roots()
}
/// Length of vertices
pub fn len_vertices(&self) -> usize {
self.graph.len_vertices()
}
/// Consumed outputs
pub fn get_blockchain_spent(&self, c: &Commitment) -> Option<&graph::Edge> {
self.consumed_blockchain_outputs.get(c)
}
/// Add transaction
pub fn add_pool_transaction(
&mut self,
pool_entry: graph::PoolEntry,
@@ -309,9 +328,9 @@ impl Pool {
}
}
// More relax way for stempool transaction in order to accept scenario such as:
// Parent is in mempool, child is allowed in stempool
//
/// More relax way for stempool transaction in order to accept scenario such as:
/// Parent is in mempool, child is allowed in stempool
///
pub fn add_stempool_transaction(
&mut self,
pool_entry: graph::PoolEntry,
@@ -342,10 +361,12 @@ impl Pool {
}
}
/// Update roots
pub fn update_roots(&mut self) {
self.graph.update_roots()
}
/// Remove transaction
pub fn remove_pool_transaction(
&mut self,
tx: &transaction::Transaction,
@@ -429,6 +450,7 @@ pub struct Orphans {
}
impl Orphans {
/// empty set
pub fn empty() -> Orphans {
Orphans {
graph: graph::DirectedGraph::empty(),
@@ -450,6 +472,7 @@ impl Orphans {
.map(|x| x.destination_hash().unwrap())
}
/// unknown output
pub fn get_unknown_output(&self, output: &Commitment) -> Option<&graph::Edge> {
self.missing_outputs.get(output)
}
@@ -571,14 +594,17 @@ pub trait TransactionGraphContainer {
self.get_internal_spent_output(c)
}
/// number of root transactions
fn num_root_transactions(&self) -> usize {
self.get_graph().len_roots()
}
/// number of transactions
fn num_transactions(&self) -> usize {
self.get_graph().len_vertices()
}
/// number of output edges
fn num_output_edges(&self) -> usize {
self.get_graph().len_edges()
}