mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
parent
a3bc383d4c
commit
8f4dbfa540
48 changed files with 137 additions and 139 deletions
|
@ -11,11 +11,11 @@ Please be kind and courteous. There’s no need to be mean or rude. Respect that
|
|||
|
||||
Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
|
||||
|
||||
We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term “harassment” as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behavior that excludes people in socially marginalized groups.
|
||||
We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term “harassment” as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behavior that excludes people in socially marginalized groups.
|
||||
|
||||
Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the Grin moderation team immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back.
|
||||
|
||||
Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome.
|
||||
Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
|
||||
|
||||
Moderation
|
||||
----------
|
||||
|
|
|
@ -35,7 +35,7 @@ To build and try out Grin, see the [build docs](doc/build.md).
|
|||
|
||||
## Philosophy
|
||||
|
||||
Grin likes itself small and easy on the eyes. It wants to be inclusive and welcoming for all walks of life, without judgement. Grin is terribly ambitious, but not at the detriment of others, rather to further us all. It may have strong opinions to stay in line with its objectives, which doesn't mean disrepect of others' ideas.
|
||||
Grin likes itself small and easy on the eyes. It wants to be inclusive and welcoming for all walks of life, without judgement. Grin is terribly ambitious, but not at the detriment of others, rather to further us all. It may have strong opinions to stay in line with its objectives, which doesn't mean disrespect of others' ideas.
|
||||
|
||||
We believe in pull requests, data and scientific research. We do not believe in unfounded beliefs.
|
||||
|
||||
|
|
|
@ -20,10 +20,10 @@ use std::fs::File;
|
|||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use core::core::Committed;
|
||||
use core::core::hash::{Hash, Hashed};
|
||||
use core::core::pmmr::MerkleProof;
|
||||
use core::core::target::Difficulty;
|
||||
use core::core::Committed;
|
||||
use core::core::{Block, BlockHeader, Output, OutputIdentifier, Transaction, TxKernel};
|
||||
use core::global;
|
||||
use grin_store::Error::NotFoundErr;
|
||||
|
@ -31,8 +31,8 @@ use pipe;
|
|||
use store;
|
||||
use txhashset;
|
||||
use types::*;
|
||||
use util::LOGGER;
|
||||
use util::secp::pedersen::{Commitment, RangeProof};
|
||||
use util::LOGGER;
|
||||
|
||||
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
||||
pub const MAX_ORPHAN_SIZE: usize = 200;
|
||||
|
@ -659,7 +659,7 @@ impl Chain {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Triggers chain compaction, cleaning up some unecessary historical
|
||||
/// Triggers chain compaction, cleaning up some unnecessary historical
|
||||
/// information. We introduce a chain depth called horizon, which is
|
||||
/// typically in the range of a couple days. Before that horizon, this
|
||||
/// method will:
|
||||
|
|
|
@ -172,7 +172,7 @@ impl TxHashSet {
|
|||
output_pmmr.elements_from_insertion_index(start_index, max_count)
|
||||
}
|
||||
|
||||
/// highest output insertion index availalbe
|
||||
/// highest output insertion index available
|
||||
pub fn highest_output_insertion_index(&mut self) -> u64 {
|
||||
pmmr::n_leaves(self.output_pmmr_h.last_pos)
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ pub const CUT_THROUGH_HORIZON: u32 = 48 * 3600 / (BLOCK_TIME_SEC as u32);
|
|||
/// peer-to-peer networking layer only for DoS protection.
|
||||
pub const MAX_MSG_LEN: u64 = 20_000_000;
|
||||
|
||||
/// Weight of an input when counted against the max block weigth capacity
|
||||
/// Weight of an input when counted against the max block weight capacity
|
||||
pub const BLOCK_INPUT_WEIGHT: usize = 1;
|
||||
|
||||
/// Weight of an output when counted against the max block weight capacity
|
||||
|
@ -178,7 +178,7 @@ impl fmt::Display for TargetError {
|
|||
///
|
||||
/// The difficulty calculation is based on both Digishield and GravityWave
|
||||
/// family of difficulty computation, coming to something very close to Zcash.
|
||||
/// The refence difficulty is an average of the difficulty over a window of
|
||||
/// The reference difficulty is an average of the difficulty over a window of
|
||||
/// DIFFICULTY_ADJUST_WINDOW blocks. The corresponding timespan is calculated
|
||||
/// by using the difference between the median timestamps at the beginning
|
||||
/// and the end of the window.
|
||||
|
|
|
@ -561,7 +561,7 @@ impl Block {
|
|||
// on the block_header
|
||||
tx.validate()?;
|
||||
|
||||
// we will summ these later to give a single aggregate offset
|
||||
// we will sum these later to give a single aggregate offset
|
||||
kernel_offsets.push(tx.offset);
|
||||
|
||||
// add all tx inputs/outputs/kernels to the block
|
||||
|
@ -717,7 +717,7 @@ impl Block {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// Verify that no input is spending an ouput from the same block.
|
||||
// Verify that no input is spending an output from the same block.
|
||||
fn verify_cut_through(&self) -> Result<(), Error> {
|
||||
for inp in &self.inputs {
|
||||
if self.outputs
|
||||
|
|
|
@ -33,7 +33,7 @@ use util;
|
|||
pub const ZERO_HASH: Hash = Hash([0; 32]);
|
||||
|
||||
/// A hash to uniquely (or close enough) identify one of the main blockchain
|
||||
/// constructs. Used pervasively for blocks, transactions and ouputs.
|
||||
/// constructs. Used pervasively for blocks, transactions and outputs.
|
||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct Hash(pub [u8; 32]);
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ impl MerkleProof {
|
|||
util::to_hex(vec)
|
||||
}
|
||||
|
||||
/// Convert hex string represenation back to a Merkle proof instance
|
||||
/// Convert hex string representation back to a Merkle proof instance
|
||||
pub fn from_hex(hex: &str) -> Result<MerkleProof, String> {
|
||||
let bytes = util::from_hex(hex.to_string()).unwrap();
|
||||
let res = ser::deserialize(&mut &bytes[..])
|
||||
|
@ -206,7 +206,7 @@ impl MerkleProof {
|
|||
}
|
||||
|
||||
/// Verify the Merkle proof.
|
||||
/// We do this by verifying the folloiwing -
|
||||
/// We do this by verifying the following -
|
||||
/// * inclusion of the node beneath a peak (via the Merkle path/branch of
|
||||
/// siblings) * inclusion of the peak in the "bag of peaks" beneath the
|
||||
/// root
|
||||
|
@ -269,7 +269,7 @@ where
|
|||
/// The last position in the PMMR
|
||||
pub last_pos: u64,
|
||||
backend: &'a mut B,
|
||||
// only needed for parameterizing Backend
|
||||
// only needed to parameterise Backend
|
||||
_marker: marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
|
@ -718,7 +718,7 @@ impl PruneList {
|
|||
|
||||
let idx = pruned_idx.or(next_idx)?;
|
||||
Some(
|
||||
// skip by the number of leaf nodes pruned in the preceeding subtrees
|
||||
// skip by the number of leaf nodes pruned in the preceding subtrees
|
||||
// which just 2^height
|
||||
// except in the case of height==0
|
||||
// (where we want to treat the pruned tree as 0 leaves)
|
||||
|
|
|
@ -479,7 +479,7 @@ impl Transaction {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// Verify that no input is spending an ouput from the same block.
|
||||
// Verify that no input is spending an output from the same block.
|
||||
fn verify_cut_through(&self) -> Result<(), Error> {
|
||||
for inp in &self.inputs {
|
||||
if self.outputs
|
||||
|
@ -734,7 +734,7 @@ impl Input {
|
|||
self.commit
|
||||
}
|
||||
|
||||
/// Convenience functon to return the (optional) block_hash for this input.
|
||||
/// Convenience function to return the (optional) block_hash for this input.
|
||||
/// Will return the default hash if we do not have one.
|
||||
pub fn block_hash(&self) -> Hash {
|
||||
self.block_hash.unwrap_or_else(Hash::default)
|
||||
|
@ -983,7 +983,7 @@ impl Readable for OutputIdentifier {
|
|||
}
|
||||
}
|
||||
|
||||
/// A structure which contains fields that are to be commited to within
|
||||
/// A structure which contains fields that are to be committed to within
|
||||
/// an Output's range (bullet) proof.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct ProofMessageElements {
|
||||
|
@ -1077,12 +1077,12 @@ impl ProofMessageElements {
|
|||
true
|
||||
}
|
||||
|
||||
/// Serialise and return a ProofMessage
|
||||
/// Serialize and return a ProofMessage
|
||||
pub fn to_proof_message(&self) -> ProofMessage {
|
||||
ProofMessage::from_bytes(&ser_vec(self).unwrap())
|
||||
}
|
||||
|
||||
/// Deserialise and return the message elements
|
||||
/// Deserialize and return the message elements
|
||||
pub fn from_proof_message(
|
||||
proof_message: &ProofMessage,
|
||||
) -> Result<ProofMessageElements, ser::Error> {
|
||||
|
@ -1124,7 +1124,7 @@ mod test {
|
|||
assert_eq!(kernel2.excess_sig, sig.clone());
|
||||
assert_eq!(kernel2.fee, 10);
|
||||
|
||||
// now check a kernel with lock_height serializes/deserializes correctly
|
||||
// now check a kernel with lock_height serialize/deserialize correctly
|
||||
let kernel = TxKernel {
|
||||
features: KernelFeatures::DEFAULT_KERNEL,
|
||||
lock_height: 100,
|
||||
|
|
|
@ -339,7 +339,7 @@ mod test {
|
|||
0x701f37b,
|
||||
];
|
||||
|
||||
/// Find a 42-cycle on Cuckoo20 at 75% easiness and verifiy against a few
|
||||
/// Find a 42-cycle on Cuckoo20 at 75% easiness and verify against a few
|
||||
/// known cycle proofs
|
||||
/// generated by other implementations.
|
||||
#[test]
|
||||
|
|
|
@ -13,7 +13,7 @@ What's working so far?
|
|||
|
||||
Please note that all mining functions for Grin have moved into a separate, standalone package called
|
||||
[grin_miner](https://github.com/mimblewimble/grin-miner). Once your Grin code node is up and running,
|
||||
you can start mining by building and runing grin-miner against your running Grin node.
|
||||
you can start mining by building and running grin-miner against your running Grin node.
|
||||
|
||||
## Docker
|
||||
|
||||
|
@ -83,7 +83,7 @@ export PATH=/path/to/grin/dir/target/debug:$PATH
|
|||
You can then run `grin` directly (try `grin help` for more options).
|
||||
|
||||
*Important Note*: if you used Grin in testnet1, running the wallet listener
|
||||
manually isn't requred anymore. Grin will create a seed file and run the
|
||||
manually isn't required anymore. Grin will create a seed file and run the
|
||||
listener automatically on start.
|
||||
|
||||
# Configuration
|
||||
|
|
|
@ -8,7 +8,7 @@ following assumptions, which are all characteristics of Grin or MimbleWimble:
|
|||
* All block headers include the root hash of all unspent outputs in the chain at
|
||||
the time of that block.
|
||||
* Inputs or outputs cannot be tampered with or forged without invalidating the
|
||||
whole block state.
|
||||
whole block state.
|
||||
|
||||
We're purposefully only focusing on major node types and high level algorithms that
|
||||
may impact the security model. Detailed heuristics that can provide some additional
|
||||
|
@ -59,7 +59,7 @@ peers and learns about the head of the most worked chain. It asks for the block
|
|||
header at the horizon block, requiring peer agreement. If consensus is not reached
|
||||
at `h = H - Z`, the node gradually increases the horizon `Z`, moving `h` backward
|
||||
until consensus is reached. Then it gets the full UTXO set at the horizon block.
|
||||
With this information it can verify:
|
||||
With this information it can verify:
|
||||
|
||||
* the total difficulty on that chain (present in all block headers)
|
||||
* the sum of all UTXO commitments equals the expected money supply
|
||||
|
|
|
@ -36,7 +36,7 @@ After checking out grin, building and using, these are the folders you'll have:
|
|||
- .grin
|
||||
- chain - a Rocksdb with the blockchain blocks and related information
|
||||
- peers - a Rocksdb with the list of Grin peers you're connected to
|
||||
- txhashset - containts folders kernel, rangeproof and output that each have a pmmr_dat.bin
|
||||
- txhashset - contains folders kernel, rangeproof and output that each have a pmmr_dat.bin
|
||||
- src
|
||||
Code for the `grin` binary.
|
||||
- store
|
||||
|
|
|
@ -9,7 +9,7 @@ Note that this requires both chains to support hash preimages: all Bitcoin scrip
|
|||
|
||||
"Ok, so algebraically how do atomic swaps work in a scriptless way? Suppose I'm trying to send Igno 1 MW1 coin on one chain in exchange for MW2 coin on another. Then:
|
||||
|
||||
1. As before we send our coins to 2-of-2 outputs on each chain. Each of us refuses to move our coin until the other has given us a locktimed "refund" transaction; we set our locktimes so I can retrieve my coin before he can retrieve his.
|
||||
1. As before we send our coins to 2-of-2 outputs on each chain. Each of us refuses to move our coin until the other has given us a locktimed "refund" transaction; we set our locktimes so I can retrieve my coin before he can retrieve his.
|
||||
|
||||
(So far this is the same as the classic Bitcoin atomic swap by Tier Nolan [3]; the difference in locktimes is because during part of the protocol Igno can take his coins but I can't yet take mine, so I want to be sure he can't do this and simultaneously back out. This way ff he takes the coins, I can take mine, but if he backs out then I've long since backed out, and these are his only possibilities.)
|
||||
|
||||
|
@ -136,7 +136,7 @@ support in principle." - Andrew Poelstra
|
|||
|
||||
- https://lists.launchpad.net/mimblewimble/msg00029.html - bunch of replies, nothing super specific
|
||||
|
||||
"ecently I've found a different construction that behaves much more like
|
||||
"Recently I've found a different construction that behaves much more like
|
||||
a hash preimage challenge, and this can actually be used for Lightning.
|
||||
Further, it supports reblinding, so you can learn a preimage but hide
|
||||
which one you're looking for. (Ethan, one might actually overlap with
|
||||
|
@ -263,7 +263,7 @@ for Ethereum+Schnorr. Further, it can link transactions across chains." - Andre
|
|||
|
||||
3. I produce a transaction which sends these coins to Igno. With the excess I sign the hash e, leave the locktime blank, and do my part to sign.
|
||||
|
||||
At this point Igno can either (a) complete the transaction, doing his part of the signature and revealing the preimage to the network, including me; or (b) do nothing, in which case I'll take the coin back after the lock time." - Andrew Polestra
|
||||
At this point Igno can either (a) complete the transaction, doing his part of the signature and revealing the preimage to the network, including me; or (b) do nothing, in which case I'll take the coin back after the lock time." - Andrew Poelstra
|
||||
- https://lists.launchpad.net/mimblewimble/msg00022.html
|
||||
|
||||
- https://lists.launchpad.net/mimblewimble/msg00025.html
|
||||
|
@ -272,7 +272,7 @@ At this point Igno can either (a) complete the transaction, doing his part of th
|
|||
- https://lists.launchpad.net/mimblewimble/msg00050.html
|
||||
- https://lists.launchpad.net/mimblewimble/msg00102.html
|
||||
|
||||
## ZKCP (Zero-Knowledge Contigent Payments)
|
||||
## ZKCP (Zero-Knowledge Contingent Payments)
|
||||
|
||||
"Recall ZKCP, as written up here
|
||||
https://bitcoincore.org/en/2016/02/26/zero-knowledge-contingent-payments-announcement/
|
||||
|
|
|
@ -67,7 +67,7 @@ block height is rejected
|
|||
## Trustless Transactions
|
||||
|
||||
An aggregate (Schnorr) signature involving a single party is relatively simple
|
||||
but does not demonstrate the full flexibility of the contstruction. We show
|
||||
but does not demonstrate the full flexibility of the construction. We show
|
||||
here how to generalize it for use in outputs involving multiple parties.
|
||||
|
||||
As constructed in section 1.2, an aggregate signature requires trusting the
|
||||
|
|
|
@ -3,9 +3,9 @@ Dandelion in Grin: Privacy-Preserving Transaction Propagation
|
|||
This document describes the implementation of Dandelion in Grin.
|
||||
## Introduction
|
||||
|
||||
Dandelion is a new transaction broadcasting mechanism that reduces the risk of eavesdroppers linking transactions to the source IP. Moreover, it allows Grin transactions to be aggregated (removing input-output pairs) before being broadasted to the entire network giving an additional privacy perk.
|
||||
Dandelion is a new transaction broadcasting mechanism that reduces the risk of eavesdroppers linking transactions to the source IP. Moreover, it allows Grin transactions to be aggregated (removing input-output pairs) before being broadcasted to the entire network giving an additional privacy perk.
|
||||
|
||||
Dandelion was introduced in [1] by G. Fanti et al. and presented at ACM Sigmetrics 2017. On June 2017 a BIP was proposed introducing a more practical and robust variant of Dandelion called Dandelion++ [2]. This document is an adapation of this BIP for Grin.
|
||||
Dandelion was introduced in [1] by G. Fanti et al. and presented at ACM Sigmetrics 2017. On June 2017 a BIP was proposed introducing a more practical and robust variant of Dandelion called Dandelion++ [2]. This document is an adaptation of this BIP for Grin.
|
||||
|
||||
## Mechanism
|
||||
|
||||
|
@ -56,7 +56,7 @@ Two aggregation scenarios have been proposed.
|
|||
|
||||
In this scenario, transactions are aggregated during the stem phase and then broadcasted to the mempool only when the fluff phase happens.
|
||||
|
||||
Each node maintains a ```patience``` timer along with a ```max_patience``` value. When a node receives a stem transaction, its ```patience``` timer starts, waiting for more stem transactions to aggregate. Once the ```patience``` timer reachs the ```max_patience``` value, the node flips a coin to decide whether to send as stem or fluff.
|
||||
Each node maintains a ```patience``` timer along with a ```max_patience``` value. When a node receives a stem transaction, its ```patience``` timer starts, waiting for more stem transactions to aggregate. Once the ```patience``` timer reaches the ```max_patience``` value, the node flips a coin to decide whether to send as stem or fluff.
|
||||
In the of a stem transactions, the node starts an embargo timer which is defined in the Considerations part. The node need to track every stem transactions it receives aggregated or not in order to guarantee its propagation and be able to revert to a previous stempool state.
|
||||
|
||||
A simulation of this scenario is available [here](simulation.md).
|
||||
|
|
|
@ -2,7 +2,7 @@ Dandelion Simulation
|
|||
==================
|
||||
This document describes a network of node with Dandelion.
|
||||
|
||||
In this scenario, we simulate a successfull aggregation but a failed transaction cut-through forcing a node to revert its stempool state.
|
||||
In this scenario, we simulate a successful aggregation but a failed transaction cut-through forcing a node to revert its stempool state.
|
||||
|
||||
This document also helps visualizing all the timers in a simple way.
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ Maybe you've heard that MimbleWimble doesn't support scripts. And in some way, t
|
|||
* Time-locked transactions and outputs.
|
||||
* Lightning Network
|
||||
|
||||
## Emmission Rate
|
||||
## Emission Rate
|
||||
|
||||
Bitcoin's 10 minute block time has its initial 50 btc reward cut in half every 4 years until there are 21 million bitcoin in circulation. Grin's emission rate is linear, meaning it never drops. The block reward is currently set at 50 grin with a block goal of 60 seconds. This still works because 1) dilution trends toward zero and 2) a non-negligible amount of coins gets lost or destroyed every year.
|
||||
|
||||
|
|
|
@ -13,17 +13,17 @@ Given the focus of grin (and mimblewimble) on reduced resource consumption, the
|
|||
|
||||
## Design Overview
|
||||
|
||||
The primary structure of the transaction pool is a pair of Directed Acyclic Graphs. Since each transaction is rooted directly by its inputs in a non-cyclic way, this structure naturally encompasses the directionality of the chains of unconfirmed transactions. Defining this structure has a few other nice properties: descendent invalidation (when a conflicting transaction is accepted for a given input) is nearly free, and the mineability of a given transaction is clearly depicted in its location in the heirarchy.
|
||||
The primary structure of the transaction pool is a pair of Directed Acyclic Graphs. Since each transaction is rooted directly by its inputs in a non-cyclic way, this structure naturally encompasses the directionality of the chains of unconfirmed transactions. Defining this structure has a few other nice properties: descendent invalidation (when a conflicting transaction is accepted for a given input) is nearly free, and the mineability of a given transaction is clearly depicted in its location in the hierarchy.
|
||||
|
||||
Another, non-obvious reason for the choice of a DAG is that the acyclic nature of transactions is a necessary property but must be explicitly verified in a way that is not true of other UTXO-based cryptocurrencies. Consider the following loop of single-input single-output transactions in BTC:
|
||||
|
||||
A->B->C->A
|
||||
|
||||
Because each input in Bitcoin specifically references the hash and output index of the output in a preceding transaction, for a loop to exist, a transaction must reference (and know the hash of) a transaction that does not yet exist (C, in the trivial example.) Furthermore, the hash and output index pair (called an "outpoint" in Bitcoin) is covered by the transaction hash of A, such that any change to either causes the hash of A to change. Therefore, attempting to build such a loop by amending A with the proper outpoint in C after C has been built causes A's hash to change, invalidating B, and so forth.
|
||||
Because each input in Bitcoin specifically references the hash and output index of the output in a preceding transaction, for a loop to exist, a transaction must reference (and know the hash of) a transaction that does not yet exist (C, in the trivial example.) Furthermore, the hash and output index pair (called an "outpoint" in Bitcoin) is covered by the transaction hash of A, such that any change to either causes the hash of A to change. Therefore, attempting to build such a loop by amending A with the proper outpoint in C after C has been built causes A's hash to change, invalidating B, and so forth.
|
||||
|
||||
In grin, an input references an output by the output's own hash. Thus, the backreference does not include the situation the output was generated in, which allows (from a purely mechanical point of view) the creation of a loop without the ability to generate a specific hash from a tightly constrained preimage.
|
||||
In grin, an input references an output by the output's own hash. Thus, the backreference does not include the situation the output was generated in, which allows (from a purely mechanical point of view) the creation of a loop without the ability to generate a specific hash from a tightly constrained preimage.
|
||||
|
||||
The pair of graphs represents the connected graph and the orphans graph. (While it is possible to represent both groups of transactions in a single graph, it makes determination of orphan status of a given transaction non-trivial, requiring either the maintainence of a flag or traversal upwards of potentially many inputs.)
|
||||
The pair of graphs represents the connected graph and the orphans graph. (While it is possible to represent both groups of transactions in a single graph, it makes determination of orphan status of a given transaction non-trivial, requiring either the maintenance of a flag or traversal upwards of potentially many inputs.)
|
||||
|
||||
A transaction reference in the pool has parents, one for each input. The parents fall into one of four states:
|
||||
|
||||
|
@ -38,7 +38,7 @@ A mineable transaction is defined as a transaction which has met all of its lock
|
|||
|
||||
In terms of needs, preference should be given to older transactions; beyond this, it seems beneficial to target transactions that reduce the maximum depth of the transaction graph, as this reduces the computational complexity of traversing the graph and making changes to it. Since fees are largely static, there is no need for fee preference.
|
||||
|
||||
Kahn's algorithm with the parameters above to break ties could provide a efficient mechanism for producing a correctly ordrered transaction list while providing hooks for limited customization.
|
||||
Kahn's algorithm with the parameters above to break ties could provide a efficient mechanism for producing a correctly ordered transaction list while providing hooks for limited customization.
|
||||
|
||||
## Summary of Common Operations
|
||||
|
||||
|
@ -48,9 +48,9 @@ The most basic task of the transaction pool is to add an incoming transaction to
|
|||
|
||||
The first step is the validation of the transaction itself. This involves the enforcement of all consensus rules surrounding the construction of the transaction itself, and the verification of all relevant signatures and proofs.
|
||||
|
||||
The next step is enforcement of node-level transaction acceptability policy. These are generally weaker restrictions governing relay and inclusion that may be adjusted without the need of hard- or soft-forking mechanisms. Additionally, this will include toggles and customizations made by operators or fork maintainers. Bitcoin's "standardness" language is adopted here.
|
||||
The next step is enforcement of node-level transaction acceptability policy. These are generally weaker restrictions governing relay and inclusion that may be adjusted without the need of hard- or soft-forking mechanisms. Additionally, this will include toggles and customizations made by operators or fork maintainers. Bitcoin's "standardness" language is adopted here.
|
||||
|
||||
Note that there are some elements of node-level policy which are not enforced here, for example the maximum size of the pool in memory.
|
||||
Note that there are some elements of node-level policy which are not enforced here, for example the maximum size of the pool in memory.
|
||||
|
||||
Next, the state of the transaction and where it would be located in the graph is determined. Each of the transactions' inputs are resolved between the current blockchain UTXO set and the additional set of outputs generated by pool transactions.
|
||||
|
||||
|
|
|
@ -73,6 +73,6 @@ use node 2's API listener to validate our transaction inputs before sending:
|
|||
node1$ grin wallet -p "password" -a "http://127.0.0.1:20001" send 20000 -d "http://127.0.0.1:35000"
|
||||
|
||||
Your terminal windows should all light up now. Node 1 will check its inputs against node 2, and then send a partial transaction to node 3's wallet listener. Node 3 has been configured to
|
||||
send signed and finalised transactions to the api listener on node 1, which should then add the transaction to the next block and validate it via mining.
|
||||
send signed and finalized transactions to the api listener on node 1, which should then add the transaction to the next block and validate it via mining.
|
||||
|
||||
You can feel free to try any number of permutations or combinations of the above, just note that grin is very new and under active development, so your mileage may vary. You can also use a separate 'grin.toml' file in each server directory to simplify command line switches.
|
||||
|
|
|
@ -170,4 +170,3 @@ additional index over the whole key space is required. As an MMR is an append
|
|||
only binary tree, we can find a key in the tree by its insertion position. So a
|
||||
full index of keys inserted in the tree (i.e. an output commitment) to their
|
||||
insertion positions is also required.
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ i.e. you add more edges relative to the number of nodes in a graph.
|
|||
|
||||
## Cuckoo Cycle
|
||||
|
||||
The Cuckoo Cycle algorithm is a specialised algorithm designed to solve exactly this problem, and it does
|
||||
The Cuckoo Cycle algorithm is a specialized algorithm designed to solve exactly this problem, and it does
|
||||
so by inserting values into a structure called a 'Cuckoo Hashtable' according to a hash which maps nodes
|
||||
into possible locations in two separate arrays. This document won't go into detail on the base algorithm, as
|
||||
it's outlined plainly enough in section 5 of the
|
||||
|
@ -134,7 +134,7 @@ the proof difficulty is calculated as the maximum target hash (2^256) divided by
|
|||
rounded to give an integer. If this integer is larger than the evolving network difficulty, the POW
|
||||
is considered valid and the block is submit to the chain for validation.
|
||||
|
||||
In other words, a potential proof, as well as containting a valid Cuckoo Cycle, also needs to hash to a value higher than the target difficulty. This difficulty is derived from:
|
||||
In other words, a potential proof, as well as containing a valid Cuckoo Cycle, also needs to hash to a value higher than the target difficulty. This difficulty is derived from:
|
||||
|
||||
### Evolving Network Difficulty
|
||||
|
||||
|
@ -143,7 +143,7 @@ keeping the average block solution time within range of a target (currently 60 s
|
|||
to change).
|
||||
|
||||
The difficulty calculation is based on both Digishield and GravityWave family of difficulty computation,
|
||||
coming to something very close to ZCash. The refence difficulty is an average of the difficulty over a window of
|
||||
coming to something very close to ZCash. The reference difficulty is an average of the difficulty over a window of
|
||||
23 blocks (the current consensus value). The corresponding timespan is calculated by using the difference between
|
||||
the median timestamps at the beginning and the end of the window. If the timespan is higher or lower than a certain
|
||||
range, (adjusted with a dampening factor to allow for normal variation,) then the difficulty is raised or lowered
|
||||
|
@ -167,7 +167,7 @@ valid Proofs-of-Work to create the latest block in the chain. The following is a
|
|||
* Then, a sub-loop runs for a set amount of time, currently configured at 2 seconds, where the following happens:
|
||||
|
||||
* The new block header is hashed to create a hash value
|
||||
* The cuckoo graph generator is initialised, which accepts as parameters:
|
||||
* The cuckoo graph generator is initialized, which accepts as parameters:
|
||||
* The hash of the potential block header, which is to be used as the key to a SIPHASH function
|
||||
that will generate pairs of locations for each element in a set of nonces 0..N in the graph.
|
||||
* The size of the graph (a consensus value).
|
||||
|
@ -178,7 +178,7 @@ valid Proofs-of-Work to create the latest block in the chain. The following is a
|
|||
* If a cycle is found, a Blake2b hash of the proof is created and is compared to the current target
|
||||
difficulty, as outlined in [Additional Difficulty Control](#additional-difficulty-control) above.
|
||||
* If the Blake2b Hash difficulty is greater than or equal to the target difficulty, the block is sent to the
|
||||
transaction pool, propogated amongst peers for validation, and work begins on the next block.
|
||||
transaction pool, propagated amongst peers for validation, and work begins on the next block.
|
||||
* If the Blake2b Hash difficulty is less than the target difficulty, the proof is thrown out and the timed loop continues.
|
||||
* If no solution is found, increment the nonce in the header by 1, and update the header's timestamp so the next iteration
|
||||
hashes a different value for seeding the next loop's graph generation step.
|
||||
|
@ -210,8 +210,8 @@ long time to find a solution in a single graph, well outside a window in which y
|
|||
transactions.
|
||||
|
||||
These values are currently set to 2^12 for the graph size and 50% (as fixed by Cuckoo Cycle) for the easiness value,
|
||||
however the size is only a temporary values for testing. The current miner implementation is very unoptimised,
|
||||
and the graph size will need to be changed as faster and more optimised Cuckoo Cycle algorithms are put in place.
|
||||
however the size is only a temporary values for testing. The current miner implementation is very unoptimized,
|
||||
and the graph size will need to be changed as faster and more optimized Cuckoo Cycle algorithms are put in place.
|
||||
|
||||
### Pooling Capability
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# Range Proofs - A Primer
|
||||
|
||||
This document is intended to give the reader a high level conceptual overview of what range proofs are and how they're constructed. It's assumed that the reader has read and is familiar with more basic MimbleWimble concepts, in particular Pedersen commitments and MimbleWimble outputs as outlined in the [Introduction to MimbleWimble](intro.md).
|
||||
This document is intended to give the reader a high level conceptual overview of what range proofs are and how they're constructed. It's assumed that the reader has read and is familiar with more basic MimbleWimble concepts, in particular Pedersen commitments and MimbleWimble outputs as outlined in the [Introduction to MimbleWimble](intro.md).
|
||||
|
||||
While understanding range proofs is not 100% necessary in order to understand MimbleWimble, a few points about them should be noted, even if just from a 'black box' perspective:
|
||||
|
||||
* Range Proofs are used to prove, with zero-knowledge (i.e. without revealing the amount or the blinding factor), that the value committed to in a given commitment falls within a certain range. The inclusion of a range proof in a MimbleWimble commitment demonstrates that the amount committed to is positive, and therefore doesn't create any new money.
|
||||
|
||||
* The blinding factor used to create an output on the block chain must be known in order to create a valid range proof. The existence of a valid range proof therefore also proves that the signer has knowledge of the blinding factor and therefore all of the private keys used in the creation of a new output.
|
||||
* The blinding factor used to create an output on the block chain must be known in order to create a valid range proof. The existence of a valid range proof therefore also proves that the signer has knowledge of the blinding factor and therefore all of the private keys used in the creation of a new output.
|
||||
|
||||
The following outlines a simple example, which builds up the concept of a range proof and demonstrates why the blinding factor in an output must be known beforehand in order to create one.
|
||||
|
||||
|
@ -20,9 +20,9 @@ Say I have this output:
|
|||
C = (113G + 20H)
|
||||
```
|
||||
|
||||
And I want to prove that the amount I'm commiting to (20) is positive, and in within the range for my coin.
|
||||
And I want to prove that the amount I'm committing to (20) is positive, and in within the range for my coin.
|
||||
|
||||
Firstly, rember a commitment actually appears in the UTXO set as a large, mostly unintelligible number, for example:
|
||||
Firstly, remember a commitment actually appears in the UTXO set as a large, mostly unintelligible number, for example:
|
||||
|
||||
```
|
||||
C = 2342384723497239482384234....
|
||||
|
@ -54,7 +54,7 @@ Of course, that's not very useful in a blockchain context, as amounts will never
|
|||
C = (113G + 1H) -> Not a point on G or H
|
||||
```
|
||||
|
||||
Since C is not a point on G or H, on its own this output can't be signed for. However, I can easily prove it's a commitment to 1 without revealing the blinding factor by simply subtracting 1*H from it, and observing that the result is a valid key on G.
|
||||
Since C is not a point on G or H, on its own this output can't be signed for. However, I can easily prove it's a commitment to 1 without revealing the blinding factor by simply subtracting 1*H from it, and observing that the result is a valid key on G.
|
||||
|
||||
Consider:
|
||||
|
||||
|
@ -74,7 +74,7 @@ Of course, the problem here is that I'm also revealing the amount. What we need
|
|||
|
||||
To demonstrate how we do this, let's assume that the only valid values for v that we could have in our currency are zero and one. Therefore, to show that the value we've committed to is positive it's sufficient to demonstrate that either v is zero, or that v is one. And we need to do this without actually revealing which value it is.
|
||||
|
||||
In order to do this, we need another type of signature called a [ring signature](https://en.wikipedia.org/wiki/Ring_signature). For our purposes, a ring signature is a signature scheme where there are multiple public keys, and the signature proves that the signer knew the corresponding private key for at least one (but not necessarily more) of the public keys.
|
||||
In order to do this, we need another type of signature called a [ring signature](https://en.wikipedia.org/wiki/Ring_signature). For our purposes, a ring signature is a signature scheme where there are multiple public keys, and the signature proves that the signer knew the corresponding private key for at least one (but not necessarily more) of the public keys.
|
||||
|
||||
So, using a ring signature, it's possible to create what's called an OR proof that demonstrates C is either a commitment to zero OR a commitment to one as follows:
|
||||
|
||||
|
@ -90,7 +90,7 @@ Following from the example:
|
|||
C' = 113G + 1H - 1H
|
||||
```
|
||||
|
||||
If a ring signature is provided over {C, C'}, it proves that the signer knows the private key for either C or C', but not both. If C was a commitment to zero, the signer was able to use C to create the ring signature. If C was a commitment to one, the signer was able to use C' to create the ring signature. If C is neither a commitment to one or zero, the signer would not have been able to create the ring signature at all. However, no matter how the ring signature was created, the private key that was used to create it was not revealed. If a ring signature exists at all, C must have been either a commitment to zero, OR a commitment to one.
|
||||
If a ring signature is provided over {C, C'}, it proves that the signer knows the private key for either C or C', but not both. If C was a commitment to zero, the signer was able to use C to create the ring signature. If C was a commitment to one, the signer was able to use C' to create the ring signature. If C is neither a commitment to one or zero, the signer would not have been able to create the ring signature at all. However, no matter how the ring signature was created, the private key that was used to create it was not revealed. If a ring signature exists at all, C must have been either a commitment to zero, OR a commitment to one.
|
||||
|
||||
As before, this works for all values of v I can pick... I can choose v=256 and construct a similar ring signature that proves v was zero OR that v was 256. In this case, the verifier just needs to subtract 256H from C and verify the ring signature used to produce the resulting C'.
|
||||
|
||||
|
@ -132,7 +132,7 @@ Note that for efficiency reasons, the range proofs used in Grin actually build u
|
|||
|
||||
## FAQ
|
||||
|
||||
Q: If I have an output `C=bG+vH` on the blockchain, and there is only a finite number of usable amounts for vH, why can't I reveal the amount by just subtracting each possible vH value from C until I get a value that can be used to create a signature on H?
|
||||
Q: If I have an output `C=bG+vH` on the blockchain, and there is only a finite number of usable amounts for vH, why can't I reveal the amount by just subtracting each possible vH value from C until I get a value that can be used to create a signature on H?
|
||||
|
||||
A: Pedersen Commitments are information-theoretically private. For any value of v I choose in `bG+vH`, I can choose a value of b that will make the entire commitment sum to C. Even given infinite computing power, it remains impossible to determine what the intended value of v in a given commitment is without knowing the blinding factor.
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ hashes for *all* outputs, not only the unspent ones).
|
|||
In addition, all headers in the chain are required to anchor the above state
|
||||
with a valid proof of work (the state corresponds to the most worked chain).
|
||||
We note that once each range proof is validated and the sum of all kernels
|
||||
commitment is computed, range proofs and kernels are not stricly necessary for
|
||||
commitment is computed, range proofs and kernels are not strictly necessary for
|
||||
a node to function anymore.
|
||||
|
||||
### Validation
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Documentation structure
|
||||
|
||||
## Explaining grin
|
||||
- [intro](intro.md) - Technical introduciton to grin
|
||||
- [intro](intro.md) - Technical introduction to grin
|
||||
- [grin4bitcoiners](grin4bitcoiners.md) - Explaining grin from a bitcoiner's perspective
|
||||
|
||||
## Understand the grin implementation
|
||||
|
|
|
@ -4,7 +4,7 @@ Mode of Interactions
|
|||
|
||||
There's a variety of ways wallet software can be integrated with, from hardware
|
||||
to automated bots to the more classic desktop wallets. No single implementation
|
||||
can hope to accomodate all possible interactions, especially if it wants to
|
||||
can hope to accommodate all possible interactions, especially if it wants to
|
||||
remain user friendly (who or whatever the user may be). With that in mind, Grin
|
||||
needs to provide a healthy base for a more complete wallet ecosystem to
|
||||
develop.
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
use std::cmp;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::sync::{mpsc, Arc, Mutex};
|
||||
use std::net::TcpStream;
|
||||
use std::sync::{mpsc, Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time;
|
||||
|
||||
|
@ -39,21 +39,19 @@ pub trait MessageHandler: Send + 'static {
|
|||
fn consume<'a>(&self, msg: Message<'a>) -> Result<Option<Response<'a>>, Error>;
|
||||
}
|
||||
|
||||
// Macro to simplify the boilerplate around asyn I/O error handling,
|
||||
// Macro to simplify the boilerplate around async I/O error handling,
|
||||
// especially with WouldBlock kind of errors.
|
||||
macro_rules! try_break {
|
||||
($chan:ident, $inner:expr) => {
|
||||
match $inner {
|
||||
Ok(v) => Some(v),
|
||||
Err(Error::Connection(ref e)) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
None
|
||||
}
|
||||
Err(Error::Connection(ref e)) if e.kind() == io::ErrorKind::WouldBlock => None,
|
||||
Err(e) => {
|
||||
let _ = $chan.send(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// A message as received by the connection. Provides access to the message
|
||||
|
|
|
@ -279,7 +279,7 @@ impl Peers {
|
|||
}
|
||||
}
|
||||
|
||||
/// Unbans a peer, checks if it exists and banned then unban
|
||||
/// Unban a peer, checks if it exists and banned then unban
|
||||
pub fn unban_peer(&self, peer_addr: &SocketAddr) {
|
||||
match self.get_peer(peer_addr.clone()) {
|
||||
Ok(_) => {
|
||||
|
@ -553,7 +553,7 @@ impl ChainAdapter for Peers {
|
|||
let hash = b.hash();
|
||||
if !self.adapter.block_received(b, peer_addr) {
|
||||
// if the peer sent us a block that's intrinsically bad
|
||||
// they are either mistaken or manevolent, both of which require a ban
|
||||
// they are either mistaken or malevolent, both of which require a ban
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Received a bad block {} from {}, the peer will be banned", hash, peer_addr
|
||||
|
@ -569,7 +569,7 @@ impl ChainAdapter for Peers {
|
|||
let hash = cb.hash();
|
||||
if !self.adapter.compact_block_received(cb, peer_addr) {
|
||||
// if the peer sent us a block that's intrinsically bad
|
||||
// they are either mistaken or manevolent, both of which require a ban
|
||||
// they are either mistaken or malevolent, both of which require a ban
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Received a bad compact block {} from {}, the peer will be banned",
|
||||
|
@ -586,7 +586,7 @@ impl ChainAdapter for Peers {
|
|||
fn header_received(&self, bh: core::BlockHeader, peer_addr: SocketAddr) -> bool {
|
||||
if !self.adapter.header_received(bh, peer_addr) {
|
||||
// if the peer sent us a block header that's intrinsically bad
|
||||
// they are either mistaken or manevolent, both of which require a ban
|
||||
// they are either mistaken or malevolent, both of which require a ban
|
||||
self.ban_peer(&peer_addr, ReasonForBan::BadBlockHeader);
|
||||
false
|
||||
} else {
|
||||
|
|
|
@ -25,7 +25,7 @@ use core::core::transaction::Transaction;
|
|||
/// Dandelion relay timer
|
||||
const DANDELION_RELAY_SECS: u64 = 600;
|
||||
|
||||
/// Dandelion emabargo timer
|
||||
/// Dandelion embargo timer
|
||||
const DANDELION_EMBARGO_SECS: u64 = 180;
|
||||
|
||||
/// Dandelion patience timer
|
||||
|
@ -86,7 +86,7 @@ fn default_dandelion_stem_probability() -> Option<usize> {
|
|||
pub struct PoolConfig {
|
||||
/// Base fee for a transaction to be accepted by the pool. The transaction
|
||||
/// weight is computed from its number of inputs, outputs and kernels and
|
||||
/// multipled by the base fee to compare to the actual transaction fee.
|
||||
/// multiplied by the base fee to compare to the actual transaction fee.
|
||||
#[serde = "default_accept_fee_base"]
|
||||
pub accept_fee_base: u64,
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ use std::sync::{Arc, RwLock};
|
|||
|
||||
use core::core::{Block, BlockHeader};
|
||||
|
||||
use chain::ChainStore;
|
||||
use chain::txhashset;
|
||||
use chain::types::Tip;
|
||||
use chain::ChainStore;
|
||||
use core::core::target::Difficulty;
|
||||
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
|
@ -43,7 +43,7 @@ use common::*;
|
|||
fn test_transaction_pool_block_reconciliation() {
|
||||
let keychain: ExtKeychain = Keychain::from_random_seed().unwrap();
|
||||
|
||||
let db_root = ".grin_block_reconcilliation".to_string();
|
||||
let db_root = ".grin_block_reconciliation".to_string();
|
||||
clean_output_dir(db_root.clone());
|
||||
let chain = ChainAdapter::init(db_root.clone()).unwrap();
|
||||
|
||||
|
|
|
@ -35,8 +35,8 @@ use core::core::transaction::Transaction;
|
|||
use p2p;
|
||||
use pool;
|
||||
use store;
|
||||
use util::LOGGER;
|
||||
use util::OneTime;
|
||||
use util::LOGGER;
|
||||
|
||||
// All adapters use `Weak` references instead of `Arc` to avoid cycles that
|
||||
// can never be destroyed. These 2 functions are simple helpers to reduce the
|
||||
|
@ -295,7 +295,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
|||
}
|
||||
|
||||
/// 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 consistent state
|
||||
/// at the provided block hash.
|
||||
fn txhashset_read(&self, h: Hash) -> Option<p2p::TxHashSetRead> {
|
||||
match w(&self.chain).txhashset_read(h.clone()) {
|
||||
|
@ -613,7 +613,7 @@ impl ChainAdapter for ChainToPoolAndNetAdapter {
|
|||
}
|
||||
|
||||
impl ChainToPoolAndNetAdapter {
|
||||
/// Construct a ChainToPoolAndNetAdaper instance.
|
||||
/// Construct a ChainToPoolAndNetAdapter instance.
|
||||
pub fn new(
|
||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||
) -> ChainToPoolAndNetAdapter {
|
||||
|
@ -623,7 +623,7 @@ impl ChainToPoolAndNetAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Initialize a ChainToPoolAndNetAdapter instance with hanlde to a Peers
|
||||
/// Initialize a ChainToPoolAndNetAdapter instance with handle to a Peers
|
||||
/// object. Should only be called once.
|
||||
pub fn init(&self, peers: Weak<p2p::Peers>) {
|
||||
self.peers.init(peers);
|
||||
|
|
|
@ -40,7 +40,7 @@ impl Default for ServerStateInfo {
|
|||
}
|
||||
}
|
||||
}
|
||||
/// Simpler thread-unware version of above to be populated and retured to
|
||||
/// Simpler thread-unaware version of above to be populated and returned to
|
||||
/// consumers might be interested in, such as test results or UI
|
||||
#[derive(Clone)]
|
||||
pub struct ServerStats {
|
||||
|
|
|
@ -111,7 +111,7 @@ pub enum Seeding {
|
|||
List,
|
||||
/// Automatically download a text file with a list of server addresses
|
||||
WebStatic,
|
||||
/// Automatically get a list of seeds from mutliple DNS
|
||||
/// Automatically get a list of seeds from multiple DNS
|
||||
DNSSeed,
|
||||
/// Mostly for tests, where connections are initiated programmatically
|
||||
Programmatic,
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{cmp, thread};
|
||||
use time;
|
||||
|
@ -295,7 +295,7 @@ fn needs_syncing(
|
|||
let ch = chain.head().unwrap();
|
||||
info!(
|
||||
LOGGER,
|
||||
"synchronised at {} @ {} [{}]",
|
||||
"synchronized at {} @ {} [{}]",
|
||||
local_diff.to_num(),
|
||||
ch.height,
|
||||
ch.last_block_h
|
||||
|
@ -457,7 +457,7 @@ mod test {
|
|||
assert_eq!(
|
||||
get_locator_heights(10000),
|
||||
vec![
|
||||
10000, 9998, 9994, 9986, 9970, 9938, 9874, 9746, 9490, 8978, 7954, 5906, 1810, 0
|
||||
10000, 9998, 9994, 9986, 9970, 9938, 9874, 9746, 9490, 8978, 7954, 5906, 1810, 0,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
|
@ -598,7 +598,7 @@ impl StratumServer {
|
|||
let job_request_json = serde_json::to_string(&job_request).unwrap();
|
||||
|
||||
// Push the new block to all connected clients
|
||||
// NOTE: We do not give a uniqe nonce (should we?) so miners need
|
||||
// NOTE: We do not give a unique nonce (should we?) so miners need
|
||||
// to choose one for themselves
|
||||
let mut workers_l = self.workers.lock().unwrap();
|
||||
for num in 0..workers_l.len() {
|
||||
|
|
|
@ -301,7 +301,7 @@ fn main() {
|
|||
});
|
||||
|
||||
if global_config.using_config_file {
|
||||
// initialise the logger
|
||||
// initialize the logger
|
||||
let mut log_conf = global_config
|
||||
.members
|
||||
.as_mut()
|
||||
|
|
|
@ -41,28 +41,30 @@
|
|||
//! Adapted from https://github.com/behnam/rust-cursive-table-view
|
||||
//! A basic table view implementation for [cursive](https://crates.io/crates/cursive).
|
||||
|
||||
#![deny(missing_docs, missing_copy_implementations, trivial_casts, trivial_numeric_casts,
|
||||
unsafe_code, unused_import_braces, unused_qualifications)]
|
||||
#![deny(
|
||||
missing_docs, missing_copy_implementations, trivial_casts, trivial_numeric_casts, unsafe_code,
|
||||
unused_import_braces, unused_qualifications
|
||||
)]
|
||||
|
||||
// Crate Dependencies ---------------------------------------------------------
|
||||
extern crate cursive;
|
||||
|
||||
// STD Dependencies -----------------------------------------------------------
|
||||
use std::rc::Rc;
|
||||
use std::hash::Hash;
|
||||
use std::cmp::{self, Ordering};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
||||
// External Dependencies ------------------------------------------------------
|
||||
use cursive::With;
|
||||
use cursive::vec::Vec2;
|
||||
use cursive::align::HAlign;
|
||||
use cursive::theme::ColorStyle;
|
||||
use cursive::{Cursive, Printer};
|
||||
use cursive::direction::Direction;
|
||||
use cursive::view::{ScrollBase, View};
|
||||
use cursive::event::{Callback, Event, EventResult, Key};
|
||||
use cursive::theme::ColorStyle;
|
||||
use cursive::theme::PaletteColor::*;
|
||||
use cursive::vec::Vec2;
|
||||
use cursive::view::{ScrollBase, View};
|
||||
use cursive::With;
|
||||
use cursive::{Cursive, Printer};
|
||||
|
||||
/// A trait for displaying and sorting items inside a
|
||||
/// [`TableView`](struct.TableView.html).
|
||||
|
@ -80,7 +82,8 @@ where
|
|||
Self: Sized;
|
||||
}
|
||||
|
||||
/// View to select an item among a list, supporting multiple columns for sorting.
|
||||
/// View to select an item among a list, supporting multiple columns for
|
||||
/// sorting.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -144,7 +147,7 @@ pub struct TableView<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static>
|
|||
|
||||
column_select: bool,
|
||||
columns: Vec<TableColumn<H>>,
|
||||
column_indicies: HashMap<H, usize>,
|
||||
column_indices: HashMap<H, usize>,
|
||||
|
||||
focus: usize,
|
||||
items: Vec<T>,
|
||||
|
@ -170,7 +173,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
|
||||
column_select: false,
|
||||
columns: Vec::new(),
|
||||
column_indicies: HashMap::new(),
|
||||
column_indices: HashMap::new(),
|
||||
|
||||
focus: 0,
|
||||
items: Vec::new(),
|
||||
|
@ -182,7 +185,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
}
|
||||
}
|
||||
|
||||
/// Adds a column for the specified table colum from type `H` along with
|
||||
/// Adds a column for the specified table column from type `H` along with
|
||||
/// a title for its visual display.
|
||||
///
|
||||
/// The provided callback can be used to further configure the
|
||||
|
@ -193,11 +196,11 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
title: S,
|
||||
callback: C,
|
||||
) -> Self {
|
||||
self.column_indicies.insert(column, self.columns.len());
|
||||
self.column_indices.insert(column, self.columns.len());
|
||||
self.columns
|
||||
.push(callback(TableColumn::new(column, title.into())));
|
||||
|
||||
// Make the first colum the default one
|
||||
// Make the first column the default one
|
||||
if self.columns.len() == 1 {
|
||||
self.default_column(column)
|
||||
} else {
|
||||
|
@ -207,7 +210,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
|
||||
/// Sets the initially active column of the table.
|
||||
pub fn default_column(mut self, column: H) -> Self {
|
||||
if self.column_indicies.contains_key(&column) {
|
||||
if self.column_indices.contains_key(&column) {
|
||||
for c in &mut self.columns {
|
||||
c.selected = c.column == column;
|
||||
if c.selected {
|
||||
|
@ -223,7 +226,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
/// Sorts the table using the specified table `column` and the passed
|
||||
/// `order`.
|
||||
pub fn sort_by(&mut self, column: H, order: Ordering) {
|
||||
if self.column_indicies.contains_key(&column) {
|
||||
if self.column_indices.contains_key(&column) {
|
||||
for c in &mut self.columns {
|
||||
c.selected = c.column == column;
|
||||
if c.selected {
|
||||
|
@ -457,7 +460,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
self.with(|t| t.set_items(items))
|
||||
}
|
||||
|
||||
/// Returns a immmutable reference to the item at the specified index
|
||||
/// Returns a immutable reference to the item at the specified index
|
||||
/// within the underlying storage vector.
|
||||
pub fn borrow_item(&mut self, index: usize) -> Option<&T> {
|
||||
self.items.get(index)
|
||||
|
@ -469,7 +472,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
self.items.get_mut(index)
|
||||
}
|
||||
|
||||
/// Returns a immmutable reference to the items contained within the table.
|
||||
/// Returns a immutable reference to the items contained within the table.
|
||||
pub fn borrow_items(&mut self) -> &Vec<T> {
|
||||
&self.items
|
||||
}
|
||||
|
@ -740,7 +743,7 @@ impl<T: TableViewItem<H> + 'static, H: Eq + Hash + Copy + Clone + 'static> View
|
|||
.iter_mut()
|
||||
.partition(|c| c.requested_width.is_some());
|
||||
|
||||
// Subtract one for the seperators between our columns (that's column_count - 1)
|
||||
// Subtract one for the separators between our columns (that's column_count - 1)
|
||||
let mut available_width = size.x.saturating_sub(column_count.saturating_sub(1) * 3);
|
||||
|
||||
// Reduce the with in case we are displaying a scrollbar
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
//! Types specific to the UI module
|
||||
|
||||
use cursive::Cursive;
|
||||
use cursive::view::View;
|
||||
use cursive::Cursive;
|
||||
use servers::ServerStats;
|
||||
|
||||
/// Main message struct to communicate between the UI and
|
||||
|
@ -24,7 +24,7 @@ pub enum UIMessage {
|
|||
UpdateStatus(ServerStats),
|
||||
}
|
||||
|
||||
/// Trait for a UI element that recieves status update messages
|
||||
/// Trait for a UI element that receives status update messages
|
||||
/// and updates itself
|
||||
|
||||
pub trait TUIStatusListener {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
//! Globally accessible static instance of secp256k1, to avoid
|
||||
//! initialisation overhead
|
||||
//! initialization overhead
|
||||
|
||||
use rand::thread_rng;
|
||||
use secp_ as secp;
|
||||
|
|
|
@ -116,7 +116,7 @@ fn single_create_coinbase(url: &str, block_fees: &BlockFees) -> Result<CbData, E
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
/// Posts a tranaction to a grin node
|
||||
/// Posts a transaction to a grin node
|
||||
pub fn post_tx(dest: &str, tx: &TxWrapper, fluff: bool) -> Result<(), Error> {
|
||||
let url;
|
||||
if fluff {
|
||||
|
|
|
@ -14,9 +14,8 @@
|
|||
|
||||
use core::core;
|
||||
use core::core::amount_to_hr_string;
|
||||
use keychain::Keychain;
|
||||
use libwallet::Error;
|
||||
use libwallet::types::{OutputData, WalletInfo};
|
||||
use libwallet::Error;
|
||||
use prettytable;
|
||||
use std::io::prelude::*;
|
||||
use term;
|
||||
|
|
|
@ -17,15 +17,14 @@
|
|||
use rand::thread_rng;
|
||||
use uuid::Uuid;
|
||||
|
||||
use core::core::committed;
|
||||
use core::core::committed::Committed;
|
||||
use core::core::{amount_to_hr_string, Transaction};
|
||||
use keychain::{BlindSum, BlindingFactor, Keychain};
|
||||
use libtx::error::{Error, ErrorKind};
|
||||
use libtx::{aggsig, build, tx_fee};
|
||||
|
||||
use util::secp::Signature;
|
||||
use util::secp::key::{PublicKey, SecretKey};
|
||||
use util::secp::Signature;
|
||||
use util::{secp, LOGGER};
|
||||
|
||||
/// Public data for each participant in the slate
|
||||
|
@ -43,7 +42,7 @@ pub struct ParticipantData {
|
|||
}
|
||||
|
||||
impl ParticipantData {
|
||||
/// A helper to return whether this paricipant
|
||||
/// A helper to return whether this participant
|
||||
/// has completed round 1 and round 2;
|
||||
/// Round 1 has to be completed before instantiation of this struct
|
||||
/// anyhow, and for each participant consists of:
|
||||
|
@ -60,9 +59,9 @@ impl ParticipantData {
|
|||
}
|
||||
|
||||
/// A 'Slate' is passed around to all parties to build up all of the public
|
||||
/// tranaction data needed to create a finalised tranaction. Callers can pass
|
||||
/// transaction data needed to create a finalized transaction. Callers can pass
|
||||
/// the slate around by whatever means they choose, (but we can provide some
|
||||
/// binary or JSON serialisation helpers here).
|
||||
/// binary or JSON serialization helpers here).
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Slate {
|
||||
|
@ -211,7 +210,7 @@ impl Slate {
|
|||
|
||||
/// Adds participants public keys to the slate data
|
||||
/// and saves participant's transaction context
|
||||
/// sec_key can be overriden to replace the blinding
|
||||
/// sec_key can be overridden to replace the blinding
|
||||
/// factor (by whoever split the offset)
|
||||
fn add_participant_info<K>(
|
||||
&mut self,
|
||||
|
|
|
@ -24,8 +24,8 @@ use keychain::{Identifier, Keychain};
|
|||
use libtx::proof;
|
||||
use libwallet::types::*;
|
||||
use util;
|
||||
use util::LOGGER;
|
||||
use util::secp::pedersen;
|
||||
use util::LOGGER;
|
||||
|
||||
fn get_merkle_proof_for_commit(node_addr: &str, commit: &str) -> Result<MerkleProofWrapper, Error> {
|
||||
let url = format!("{}/v1/txhashset/merkleproof?id={}", node_addr, commit);
|
||||
|
@ -144,8 +144,8 @@ where
|
|||
|
||||
for i in start_index..max_derivations {
|
||||
// much faster than calling EC functions for each found key
|
||||
// Shouldn't be needed if assumtion about wallet key 'gaps' above
|
||||
// holds.. otherwise this is a good optimisation.. perhaps
|
||||
// Shouldn't be needed if assumption about wallet key 'gaps' above
|
||||
// holds.. otherwise this is a good optimization.. perhaps
|
||||
// provide a command line switch
|
||||
/*if found_key_index.contains(&(i as u32)) {
|
||||
continue;
|
||||
|
|
|
@ -15,12 +15,12 @@
|
|||
//! Selection of inputs for building transactions
|
||||
|
||||
use keychain::{Identifier, Keychain};
|
||||
use libtx::{build, tx_fee, slate::Slate};
|
||||
use libtx::{build, slate::Slate, tx_fee};
|
||||
use libwallet::error::{Error, ErrorKind};
|
||||
use libwallet::internal::{keys, sigcontext};
|
||||
use libwallet::types::*;
|
||||
|
||||
/// Initialise a transaction on the sender side, returns a corresponding
|
||||
/// Initialize a transaction on the sender side, returns a corresponding
|
||||
/// libwallet transaction slate with the appropriate inputs selected,
|
||||
/// and saves the private wallet identifiers of our selected outputs
|
||||
/// into our transaction context
|
||||
|
|
|
@ -23,7 +23,7 @@ use libwallet::types::{WalletBackend, WalletClient};
|
|||
use libwallet::{Error, ErrorKind};
|
||||
use util::LOGGER;
|
||||
|
||||
/// Receive a tranaction, modifying the slate accordingly (which can then be
|
||||
/// Receive a transaction, modifying the slate accordingly (which can then be
|
||||
/// sent back to sender for posting)
|
||||
pub fn receive_tx<T, K>(wallet: &mut T, slate: &mut Slate) -> Result<(), Error>
|
||||
where
|
||||
|
@ -78,7 +78,7 @@ where
|
|||
|
||||
let lock_height = current_height;
|
||||
|
||||
// Sender selects outputs into a new slate and save our corresponding keyss in
|
||||
// Sender selects outputs into a new slate and save our corresponding keys in
|
||||
// a transaction context. The secret key in our transaction context will be
|
||||
// randomly selected. This returns the public slate, and a closure that locks
|
||||
// our inputs and outputs once we're convinced the transaction exchange went
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
//! the wallet storage and update them.
|
||||
|
||||
use failure::ResultExt;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use core::consensus::reward;
|
||||
use core::core::{Output, TxKernel};
|
||||
|
@ -29,8 +29,8 @@ use libwallet::error::{Error, ErrorKind};
|
|||
use libwallet::internal::keys;
|
||||
use libwallet::types::*;
|
||||
use util;
|
||||
use util::LOGGER;
|
||||
use util::secp::pedersen;
|
||||
use util::LOGGER;
|
||||
|
||||
/// Retrieve all of the outputs (doesn't attempt to update from node)
|
||||
pub fn retrieve_outputs<T, K>(wallet: &mut T, show_spent: bool) -> Result<Vec<OutputData>, Error>
|
||||
|
@ -240,7 +240,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
/// Retrieve summar info about the wallet
|
||||
/// Retrieve summary info about the wallet
|
||||
pub fn retrieve_info<T, K>(wallet: &mut T) -> Result<WalletInfo, Error>
|
||||
where
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
|
|
|
@ -40,7 +40,7 @@ pub trait WalletBackend<K>
|
|||
where
|
||||
K: Keychain,
|
||||
{
|
||||
/// Initialise with whatever stored credentials we have
|
||||
/// Initialize with whatever stored credentials we have
|
||||
fn open_with_credentials(&mut self) -> Result<(), Error>;
|
||||
|
||||
/// Close wallet and remove any stored credentials (TBD)
|
||||
|
@ -107,7 +107,7 @@ pub trait WalletClient {
|
|||
/// TODO: Probably need a slate wrapper type
|
||||
fn send_tx_slate(&self, dest: &str, slate: &Slate) -> Result<Slate, Error>;
|
||||
|
||||
/// Posts a tranaction to a grin node
|
||||
/// Posts a transaction to a grin node
|
||||
fn post_tx(&self, dest: &str, tx: &TxWrapper, fluff: bool) -> Result<(), Error>;
|
||||
|
||||
/// retrieves the current tip from the specified grin node
|
||||
|
@ -144,7 +144,7 @@ pub trait WalletClient {
|
|||
}
|
||||
|
||||
/// Information about an output that's being tracked by the wallet. Must be
|
||||
/// enough to reconstruct the commitment associated with the ouput when the
|
||||
/// enough to reconstruct the commitment associated with the output when the
|
||||
/// root private key is known.*/
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
|
||||
|
@ -247,7 +247,7 @@ impl OutputData {
|
|||
pub enum OutputStatus {
|
||||
/// Unconfirmed
|
||||
Unconfirmed,
|
||||
/// Unspend
|
||||
/// Unspent
|
||||
Unspent,
|
||||
/// Locked
|
||||
Locked,
|
||||
|
|
|
@ -29,8 +29,8 @@ mod common;
|
|||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
|
||||
use chain::Chain;
|
||||
use chain::types::*;
|
||||
use chain::Chain;
|
||||
use core::global::ChainTypes;
|
||||
use core::{global, pow};
|
||||
use util::LOGGER;
|
||||
|
@ -114,7 +114,7 @@ fn build_transaction() {
|
|||
// Now, just like the sender did, recipient is going to select a target output,
|
||||
// add it to the transaction, and keep track of the corresponding wallet
|
||||
// Identifier Again, this is a helper to do that, which returns a closure that
|
||||
// creates the output when we're satisified the process was successful
|
||||
// creates the output when we're satisfied the process was successful
|
||||
let (_, mut recp_context, receiver_create_fn) =
|
||||
selection::build_recipient_output_with_slate(&mut wallet2, &mut slate).unwrap();
|
||||
|
||||
|
|
Loading…
Reference in a new issue