-
Notifications
You must be signed in to change notification settings - Fork 992
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f73a308
Showing
144 changed files
with
29,870 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.swp | ||
target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Grin | ||
|
||
Grin is an in-progress implementation of the MimbleWimble protocol. Many characteristics are still undefined but the following constitutes a first set of choices: | ||
|
||
* Clean and minimal implementation, aiming to stay as such. | ||
* Follows the MimbleWimble protocol, which provides great anonymity and scaling characteristics. | ||
* Cuckoo Cycle proof of work (at least to start with). | ||
* Relatively fast block time (a minute or less, possibly decreasing as networks improve). | ||
* Fixed block reward, both over time and in blocks (fees are not additive). | ||
* Transaction fees are based on the number of UTXO created/destroyed and total transaction size. | ||
* Smooth curve for difficulty adjustments. | ||
|
||
## Status | ||
|
||
Grin is still an infant, much is left to be done and contributions are welcome (see below). Our [status file](TODO.md) may help. | ||
|
||
## Contributing | ||
|
||
Find an area you can help with and do it. Open source is about collaboration and open participation. Try to make your code look like what already exists and submit a pull request. If you're looking for additional ideas, the code includes TODO comments for minor to major improvements. Grep is your friend. | ||
|
||
Additional tests are rewarded with an immense amount of positive karma. So is documentation. | ||
|
||
Find us on Gitter: https://gitter.im/grin_community | ||
|
||
## 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. | ||
|
||
We believe in pull requests, data and scientific research. We do not believe in unfounded beliefs. | ||
|
||
## Credits | ||
|
||
Tom Elvis Jedusor for the first formulation of MimbleWimble. | ||
Andrew Poelstra for his related work and improvements. | ||
John Tromp for the Cuckoo Cycles proof of work. | ||
J.K. Rowling for making it despite extraordinary adversity. | ||
|
||
## License | ||
|
||
Apache License v2.0. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Rolling up our sleeves | ||
|
||
Grin is still an infant, much is left to be done and contributions are welcome. Here's a (non exhaustive) list of what's left to implement: | ||
|
||
* Transaction signatures aggregation. | ||
* Proper API to author transactions. | ||
* Protocol layer (handshake, send blocks, ask for blocks, send txs, ask for them, sync, etc.). | ||
* Maintenance of the UTXO set and its Merkle tree. | ||
* Transaction pool and related validation. | ||
* Chain logic and related validation. | ||
* Efficient miner (as a distinct project). | ||
* User-friendly wallet (as a distinct project). | ||
* Figure out if the rangeproofs can be eliminated under some cicrumstances while keeping security guarantes. | ||
* Website, logo design and all the cool stuff. | ||
|
||
Don't worry, we'll get there, with your help. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "grin_chain" | ||
version = "0.1.0" | ||
authors = ["Ignotus Peverell <igno.peverell@protonmail.com>"] | ||
|
||
[dependencies] | ||
bitflags = "^0.7.0" | ||
byteorder = "^0.5" | ||
|
||
grin_core = { path = "../core" } | ||
grin_store = { path = "../store" } | ||
secp256k1zkp = { path = "../secp256k1zkp" } | ||
|
||
[dev-dependencies] | ||
rand = "^0.3" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
hard_tabs = true | ||
wrap_comments = true | ||
write_mode = "Overwrite" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
//! The block chain itself, validates and accepts new blocks, handles reorgs. | ||
|
||
#![deny(non_upper_case_globals)] | ||
#![deny(non_camel_case_types)] | ||
#![deny(non_snake_case)] | ||
#![deny(unused_mut)] | ||
#![warn(missing_docs)] | ||
|
||
#[macro_use] | ||
extern crate bitflags; | ||
extern crate byteorder; | ||
|
||
#[macro_use(try_m)] | ||
extern crate grin_core as core; | ||
extern crate grin_store; | ||
extern crate secp256k1zkp as secp; | ||
|
||
pub mod pipe; | ||
pub mod store; | ||
pub mod types; | ||
|
||
// Re-export the base interface | ||
|
||
pub use types::ChainStore; | ||
pub use chain::Options; | ||
pub use chain::process_block; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
//! Implementation of the chain block acceptance (or refusal) pipeline. | ||
|
||
use secp; | ||
|
||
use core::core::{Hash, BlockHeader, Block, Proof}; | ||
use core::pow; | ||
use types; | ||
use types::{Tip, ChainStore}; | ||
use store; | ||
|
||
bitflags! { | ||
/// Options for block validation | ||
pub flags Options: u32 { | ||
/// Runs with the easier version of the Proof of Work, mostly to make testing easier. | ||
const EASY_POW = 0b00000001, | ||
} | ||
} | ||
|
||
/// Contextual information required to process a new block and either reject or | ||
/// accept it. | ||
pub struct BlockContext<'a> { | ||
opts: Options, | ||
store: &'a ChainStore, | ||
head: Tip, | ||
tip: Option<Tip>, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub enum Error { | ||
/// The block doesn't fit anywhere in our chain | ||
Unfit(String), | ||
/// The proof of work is invalid | ||
InvalidPow, | ||
/// The block doesn't sum correctly or a tx signature is invalid | ||
InvalidBlockProof(secp::Error), | ||
/// Internal issue when trying to save the block | ||
StoreErr(types::Error), | ||
} | ||
|
||
pub fn process_block(b: &Block, store: &ChainStore, opts: Options) -> Option<Error> { | ||
// TODO should just take a promise for a block with a full header so we don't | ||
// spend resources reading the full block when its header is invalid | ||
|
||
let head = match store.head() { | ||
Ok(head) => head, | ||
Err(err) => return Some(Error::StoreErr(err)), | ||
}; | ||
let mut ctx = BlockContext { | ||
opts: opts, | ||
store: store, | ||
head: head, | ||
tip: None, | ||
}; | ||
|
||
try_m!(validate_header(&b, &mut ctx)); | ||
try_m!(set_tip(&b.header, &mut ctx)); | ||
try_m!(validate_block(b, &mut ctx)); | ||
try_m!(add_block(b, &mut ctx)); | ||
try_m!(update_tips(&mut ctx)); | ||
None | ||
} | ||
|
||
// block processing pipeline | ||
// 1. is the header valid (time, PoW, etc.) | ||
// 2. is it the next head, a new fork, or extension of a fork (not a too old | ||
// fork tho) | ||
// 3. ok fine, is all of it valid (txs, merkle, utxo merkle, etc.) | ||
// 4. add the sucker to the head/fork | ||
// 5. did we increase a fork difficulty over the head? | ||
// 6. ok fine, swap them up (can be tricky, think addresses invalidation) | ||
|
||
/// First level of black validation that only needs to act on the block header | ||
/// to make it as cheap as possible. The different validations are also | ||
/// arranged by order of cost to have as little DoS surface as possible. | ||
/// TODO actually require only the block header (with length information) | ||
fn validate_header(b: &Block, ctx: &mut BlockContext) -> Option<Error> { | ||
let header = &b.header; | ||
println!("{} {}", header.height, ctx.head.height); | ||
if header.height > ctx.head.height + 1 { | ||
// TODO actually handle orphans and add them to a size-limited set | ||
return Some(Error::Unfit("orphan".to_string())); | ||
} | ||
// TODO check time wrt to chain time, refuse older than 100 blocks or too far | ||
// in future | ||
|
||
// TODO maintain current difficulty | ||
let diff_target = Proof(pow::MAX_TARGET); | ||
|
||
if ctx.opts.intersects(EASY_POW) { | ||
if !pow::verify20(b, diff_target) { | ||
return Some(Error::InvalidPow); | ||
} | ||
} else if !pow::verify(b, diff_target) { | ||
return Some(Error::InvalidPow); | ||
} | ||
None | ||
} | ||
|
||
fn set_tip(h: &BlockHeader, ctx: &mut BlockContext) -> Option<Error> { | ||
ctx.tip = Some(ctx.head.clone()); | ||
None | ||
} | ||
|
||
fn validate_block(b: &Block, ctx: &mut BlockContext) -> Option<Error> { | ||
// TODO check tx merkle tree | ||
let curve = secp::Secp256k1::with_caps(secp::ContextFlag::Commit); | ||
try_m!(b.verify(&curve).err().map(&Error::InvalidBlockProof)); | ||
None | ||
} | ||
|
||
fn add_block(b: &Block, ctx: &mut BlockContext) -> Option<Error> { | ||
ctx.tip = ctx.tip.as_ref().map(|t| t.append(b.hash())); | ||
ctx.store.save_block(b).map(&Error::StoreErr) | ||
} | ||
|
||
fn update_tips(ctx: &mut BlockContext) -> Option<Error> { | ||
ctx.store.save_head(ctx.tip.as_ref().unwrap()).map(&Error::StoreErr) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
//! Implements storage primitives required by the chain | ||
|
||
use byteorder::{WriteBytesExt, BigEndian}; | ||
|
||
use types::*; | ||
use core::core::Block; | ||
use grin_store; | ||
|
||
const STORE_PATH: &'static str = ".grin/chain"; | ||
|
||
const SEP: u8 = ':' as u8; | ||
|
||
const BLOCK_PREFIX: u8 = 'B' as u8; | ||
const TIP_PREFIX: u8 = 'T' as u8; | ||
const HEAD_PREFIX: u8 = 'H' as u8; | ||
|
||
/// An implementation of the ChainStore trait backed by a simple key-value | ||
/// store. | ||
pub struct ChainKVStore { | ||
db: grin_store::Store, | ||
} | ||
|
||
impl ChainKVStore { | ||
pub fn new() -> Result<ChainKVStore, Error> { | ||
let db = try!(grin_store::Store::open(STORE_PATH).map_err(to_store_err)); | ||
Ok(ChainKVStore { db: db }) | ||
} | ||
} | ||
|
||
impl ChainStore for ChainKVStore { | ||
fn head(&self) -> Result<Tip, Error> { | ||
option_to_not_found(self.db.get_ser(&vec![HEAD_PREFIX])) | ||
} | ||
|
||
fn save_block(&self, b: &Block) -> Option<Error> { | ||
self.db.put_ser(&to_key(BLOCK_PREFIX, &mut b.hash().to_vec())[..], b).map(&to_store_err) | ||
} | ||
|
||
fn save_head(&self, t: &Tip) -> Option<Error> { | ||
try_m!(self.save_tip(t)); | ||
self.db.put_ser(&vec![HEAD_PREFIX], t).map(&to_store_err) | ||
} | ||
|
||
fn save_tip(&self, t: &Tip) -> Option<Error> { | ||
let last_branch = t.lineage.last_branch(); | ||
let mut k = vec![TIP_PREFIX, SEP]; | ||
k.write_u32::<BigEndian>(last_branch); | ||
self.db.put_ser(&mut k, t).map(&to_store_err) | ||
} | ||
} | ||
|
||
fn to_key(prefix: u8, val: &mut Vec<u8>) -> &mut Vec<u8> { | ||
val.insert(0, SEP); | ||
val.insert(0, prefix); | ||
val | ||
} | ||
|
||
fn to_store_err(e: grin_store::Error) -> Error { | ||
Error::StorageErr(format!("{:?}", e)) | ||
} | ||
|
||
/// unwraps the inner option by converting the none case to a not found error | ||
fn option_to_not_found<T>(res: Result<Option<T>, grin_store::Error>) -> Result<T, Error> { | ||
match res { | ||
Ok(None) => Err(Error::NotFoundErr), | ||
Ok(Some(o)) => Ok(o), | ||
Err(e) => Err(to_store_err(e)), | ||
} | ||
} |
Oops, something went wrong.