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:
+33
-8
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+32
-6
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user