Merge pull request #2196 from mimblewimble/floonet

* Get last bitcon block hash, setup genesis header without PoW (for now)
* More a few properties to mainnet genesis. Don't get too excited, several are placeholders.
* Mine a valid Cuckaroo solution for genesis block
* Use miner as library to get a solution for genesis. Replace final values in genesis.rs before committing it.
* Complete genesis replacement
* Fixed various replacements to obtain a compilable, well-formed genesis
* Check plugin errors, uncomment PoW validation
* Fixes to nonce handling in genesis mining
* Also produce full block hashes
* Fix genesis hash test
* Switch commitments (#2157)
* [Floonet] Use switch commits for all blinding factors (#2178)
* move wallet mods back into dirs
* use switched keys for blinding factor in all cases
* re-implement flag to turn off switch commit derivation
* rename tx log entry field tx_hex -> stored_tx (#2181)
* [Floonet] add feature for height locked kernels (#2168)
* add feature for height locked kernels
* add function to compute kernel features appropriate for lock height, and use it
* only sign kernel-features relevant fields; refactor Features
* simplify invalid kernel logic
* remove unused height arg to reward::output and run some rustfmt
* replace nested if/else by match
* Floonet chain type and genesis, testnets cleanup (#2182)
* [Floonet] Encrypt private slate data upon storage in DB (#2189)
* xor encrypt stored nonce and blind sum in transaction data
* stop doc tests splatting wallet files throughout
* Remove bzip2 dependency
* Changed magic number and seeds for Floonet (#2188)
* Genesis generator now loads a local wallet seed to build coinbase.
* Floonet genesis block
* Add floonet to generated grin-server.toml comments
* Test with final Floonet genesis hashes
* Fix get_header_for_output for genesis (#2192)
* start search with min height 0 (#2195)
This commit is contained in:
Ignotus Peverell 2018-12-20 18:12:08 -08:00 committed by GitHub
commit ecf736d78a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 978 additions and 453 deletions

28
Cargo.lock generated
View file

@ -192,24 +192,6 @@ dependencies = [
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "bzip2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bzip2-sys"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.25" version = "1.0.25"
@ -865,7 +847,7 @@ dependencies = [
[[package]] [[package]]
name = "grin_secp256k1zkp" name = "grin_secp256k1zkp"
version = "0.7.2" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/mimblewimble/rust-secp256k1-zkp?tag=grin_integration_29#a245051ce72524696a787e60ff7a7e2a9551c699"
dependencies = [ dependencies = [
"arrayvec 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)",
@ -935,7 +917,7 @@ dependencies = [
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"grin_secp256k1zkp 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "grin_secp256k1zkp 0.7.2 (git+https://github.com/mimblewimble/rust-secp256k1-zkp?tag=grin_integration_29)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log4rs 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "log4rs 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2894,8 +2876,6 @@ name = "zip"
version = "0.4.2" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2927,8 +2907,6 @@ dependencies = [
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
"checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
"checksum bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6584aa36f5ad4c9247f5323b0a42f37802b37a836f0ad87084d7a33961abe25f"
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" "checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c"
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
@ -2984,7 +2962,7 @@ dependencies = [
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
"checksum git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "591f8be1674b421644b6c030969520bc3fa12114d2eb467471982ed3e9584e71" "checksum git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "591f8be1674b421644b6c030969520bc3fa12114d2eb467471982ed3e9584e71"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum grin_secp256k1zkp 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aea95f8b846440f6a9caf0fd4c22c91c124f2a896d69d781f7dc0fa88e33b0ff" "checksum grin_secp256k1zkp 0.7.2 (git+https://github.com/mimblewimble/rust-secp256k1-zkp?tag=grin_integration_29)" = "<none>"
"checksum h2 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1ac030ae20dee464c5d0f36544d8b914a6bc606da44a57e052d2b0f5dae129e0" "checksum h2 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1ac030ae20dee464c5d0f36544d8b914a6bc606da44a57e052d2b0f5dae129e0"
"checksum hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "733e1b3ac906631ca01ebb577e9bb0f5e37a454032b9036b5eaea4013ed6f99a" "checksum hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "733e1b3ac906631ca01ebb577e9bb0f5e37a454032b9036b5eaea4013ed6f99a"
"checksum http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "02096a6d2c55e63f7fcb800690e4f889a25f6ec342e3adb4594e293b625215ab" "checksum http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "02096a6d2c55e63f7fcb800690e4f889a25f6ec342e3adb4594e293b625215ab"

View file

@ -13,6 +13,7 @@ edition = "2018"
[workspace] [workspace]
members = ["api", "chain", "config", "core", "keychain", "p2p", "servers", "store", "util", "pool", "wallet"] members = ["api", "chain", "config", "core", "keychain", "p2p", "servers", "store", "util", "pool", "wallet"]
exclude = ["etc/gen_gen"]
[[bin]] [[bin]]
name = "grin" name = "grin"

View file

@ -44,8 +44,8 @@ pub fn get_output(
// For now we can just try both (but this probably needs to be part of the api // For now we can just try both (but this probably needs to be part of the api
// params) // params)
let outputs = [ let outputs = [
OutputIdentifier::new(OutputFeatures::DEFAULT_OUTPUT, &commit), OutputIdentifier::new(OutputFeatures::PLAIN, &commit),
OutputIdentifier::new(OutputFeatures::COINBASE_OUTPUT, &commit), OutputIdentifier::new(OutputFeatures::COINBASE, &commit),
]; ];
for x in outputs.iter() { for x in outputs.iter() {

View file

@ -251,10 +251,7 @@ impl OutputPrintable {
block_header: Option<&core::BlockHeader>, block_header: Option<&core::BlockHeader>,
include_proof: bool, include_proof: bool,
) -> OutputPrintable { ) -> OutputPrintable {
let output_type = if output let output_type = if output.is_coinbase() {
.features
.contains(core::transaction::OutputFeatures::COINBASE_OUTPUT)
{
OutputType::Coinbase OutputType::Coinbase
} else { } else {
OutputType::Transaction OutputType::Transaction
@ -278,11 +275,7 @@ impl OutputPrintable {
// We require the rewind() to be stable even after the PMMR is pruned and // We require the rewind() to be stable even after the PMMR is pruned and
// compacted so we can still recreate the necessary proof. // compacted so we can still recreate the necessary proof.
let mut merkle_proof = None; let mut merkle_proof = None;
if output if output.is_coinbase() && !spent && block_header.is_some() {
.features
.contains(core::transaction::OutputFeatures::COINBASE_OUTPUT)
&& !spent && block_header.is_some()
{
merkle_proof = chain.get_merkle_proof(&out_id, &block_header.unwrap()).ok() merkle_proof = chain.get_merkle_proof(&out_id, &block_header.unwrap()).ok()
}; };

View file

@ -1130,7 +1130,7 @@ impl Chain {
let (_, pos) = txhashset.is_unspent(output_ref)?; let (_, pos) = txhashset.is_unspent(output_ref)?;
let mut min = 1; let mut min = 0;
let mut max = { let mut max = {
let head = self.head()?; let head = self.head()?;
head.height head.height
@ -1139,6 +1139,9 @@ impl Chain {
loop { loop {
let search_height = max - (max - min) / 2; let search_height = max - (max - min) / 2;
let h = txhashset.get_header_by_height(search_height)?; let h = txhashset.get_header_by_height(search_height)?;
if search_height == 0 {
return Ok(h);
}
let h_prev = txhashset.get_header_by_height(search_height - 1)?; let h_prev = txhashset.get_header_by_height(search_height - 1)?;
if pos > h.output_mmr_size { if pos > h.output_mmr_size {
min = search_height; min = search_height;

View file

@ -16,7 +16,7 @@
use crate::core::core::hash::Hash; use crate::core::core::hash::Hash;
use crate::core::core::pmmr::{self, ReadonlyPMMR}; use crate::core::core::pmmr::{self, ReadonlyPMMR};
use crate::core::core::{Block, BlockHeader, Input, Output, OutputFeatures, Transaction}; use crate::core::core::{Block, BlockHeader, Input, Output, Transaction};
use crate::core::global; use crate::core::global;
use crate::core::ser::PMMRIndexHashable; use crate::core::ser::PMMRIndexHashable;
use crate::error::{Error, ErrorKind}; use crate::error::{Error, ErrorKind};
@ -105,7 +105,7 @@ impl<'a> UTXOView<'a> {
// outputs we are attempting to spend. // outputs we are attempting to spend.
let pos = inputs let pos = inputs
.iter() .iter()
.filter(|x| x.features.contains(OutputFeatures::COINBASE_OUTPUT)) .filter(|x| x.is_coinbase())
.filter_map(|x| self.batch.get_output_pos(&x.commitment()).ok()) .filter_map(|x| self.batch.get_output_pos(&x.commitment()).ok())
.max() .max()
.unwrap_or(0); .unwrap_or(0);

View file

@ -83,7 +83,7 @@ fn data_files() {
let prev = chain.head_header().unwrap(); let prev = chain.head_header().unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier(); let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
let reward = libtx::reward::output(&keychain, &pk, 0, prev.height).unwrap(); let reward = libtx::reward::output(&keychain, &pk, 0).unwrap();
let mut b = let mut b =
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward) core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
.unwrap(); .unwrap();
@ -159,7 +159,7 @@ fn _prepare_block_nosum(
let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier(); let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier();
let fees = txs.iter().map(|tx| tx.fee()).sum(); let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward = libtx::reward::output(kc, &key_id, fees, prev.height).unwrap(); let reward = libtx::reward::output(kc, &key_id, fees).unwrap();
let mut b = match core::core::Block::new( let mut b = match core::core::Block::new(
prev, prev,
txs.into_iter().cloned().collect(), txs.into_iter().cloned().collect(),

View file

@ -70,7 +70,7 @@ fn mine_genesis_reward_chain() {
let mut genesis = genesis::genesis_dev(); let mut genesis = genesis::genesis_dev();
let keychain = keychain::ExtKeychain::from_random_seed().unwrap(); let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
let key_id = keychain::ExtKeychain::derive_key_id(0, 1, 0, 0, 0); let key_id = keychain::ExtKeychain::derive_key_id(0, 1, 0, 0, 0);
let reward = reward::output(&keychain, &key_id, 0, 0).unwrap(); let reward = reward::output(&keychain, &key_id, 0).unwrap();
genesis = genesis.with_reward(reward.0, reward.1); genesis = genesis.with_reward(reward.0, reward.1);
{ {
@ -103,7 +103,7 @@ where
let prev = chain.head_header().unwrap(); let prev = chain.head_header().unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier(); let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
let reward = libtx::reward::output(keychain, &pk, 0, prev.height).unwrap(); let reward = libtx::reward::output(keychain, &pk, 0).unwrap();
let mut b = let mut b =
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward) core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
.unwrap(); .unwrap();
@ -283,7 +283,7 @@ fn spend_in_fork_and_compact() {
// so we can spend the coinbase later // so we can spend the coinbase later
let b = prepare_block(&kc, &fork_head, &chain, 2); let b = prepare_block(&kc, &fork_head, &chain, 2);
let out_id = OutputIdentifier::from_output(&b.outputs()[0]); let out_id = OutputIdentifier::from_output(&b.outputs()[0]);
assert!(out_id.features.contains(OutputFeatures::COINBASE_OUTPUT)); assert!(out_id.features.is_coinbase());
fork_head = b.header.clone(); fork_head = b.header.clone();
chain chain
.process_block(b.clone(), chain::Options::SKIP_POW) .process_block(b.clone(), chain::Options::SKIP_POW)
@ -411,7 +411,7 @@ fn output_header_mappings() {
let prev = chain.head_header().unwrap(); let prev = chain.head_header().unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier(); let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
let reward = libtx::reward::output(&keychain, &pk, 0, prev.height).unwrap(); let reward = libtx::reward::output(&keychain, &pk, 0).unwrap();
reward_outputs.push(reward.0.clone()); reward_outputs.push(reward.0.clone());
let mut b = let mut b =
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward) core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
@ -511,7 +511,7 @@ where
let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier(); let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier();
let fees = txs.iter().map(|tx| tx.fee()).sum(); let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward = libtx::reward::output(kc, &key_id, fees, prev.height).unwrap(); let reward = libtx::reward::output(kc, &key_id, fees).unwrap();
let mut b = match core::core::Block::new( let mut b = match core::core::Block::new(
prev, prev,
txs.into_iter().cloned().collect(), txs.into_iter().cloned().collect(),

View file

@ -62,7 +62,7 @@ fn test_various_store_indices() {
setup_chain(&genesis, chain_store.clone()).unwrap(); setup_chain(&genesis, chain_store.clone()).unwrap();
let reward = libtx::reward::output(&keychain, &key_id, 0, 1).unwrap(); let reward = libtx::reward::output(&keychain, &key_id, 0).unwrap();
let block = Block::new(&genesis.header, vec![], Difficulty::min(), reward).unwrap(); let block = Block::new(&genesis.header, vec![], Difficulty::min(), reward).unwrap();
let block_hash = block.hash(); let block_hash = block.hash();

View file

@ -14,7 +14,6 @@
use self::chain::types::NoopAdapter; use self::chain::types::NoopAdapter;
use self::chain::ErrorKind; use self::chain::ErrorKind;
use self::core::core::transaction;
use self::core::core::verifier_cache::LruVerifierCache; use self::core::core::verifier_cache::LruVerifierCache;
use self::core::global::{self, ChainTypes}; use self::core::global::{self, ChainTypes};
use self::core::libtx::{self, build}; use self::core::libtx::{self, build};
@ -68,7 +67,7 @@ fn test_coinbase_maturity() {
let key_id4 = ExtKeychainPath::new(1, 4, 0, 0, 0).to_identifier(); let key_id4 = ExtKeychainPath::new(1, 4, 0, 0, 0).to_identifier();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
let reward = libtx::reward::output(&keychain, &key_id1, 0, prev.height).unwrap(); let reward = libtx::reward::output(&keychain, &key_id1, 0).unwrap();
let mut block = core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap(); let mut block = core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap();
block.header.timestamp = prev.timestamp + Duration::seconds(60); block.header.timestamp = prev.timestamp + Duration::seconds(60);
block.header.pow.secondary_scaling = next_header_info.secondary_scaling; block.header.pow.secondary_scaling = next_header_info.secondary_scaling;
@ -85,9 +84,7 @@ fn test_coinbase_maturity() {
assert_eq!(block.outputs().len(), 1); assert_eq!(block.outputs().len(), 1);
let coinbase_output = block.outputs()[0]; let coinbase_output = block.outputs()[0];
assert!(coinbase_output assert!(coinbase_output.is_coinbase());
.features
.contains(transaction::OutputFeatures::COINBASE_OUTPUT));
chain chain
.process_block(block.clone(), chain::Options::MINE) .process_block(block.clone(), chain::Options::MINE)
@ -114,7 +111,7 @@ fn test_coinbase_maturity() {
let txs = vec![coinbase_txn.clone()]; let txs = vec![coinbase_txn.clone()];
let fees = txs.iter().map(|tx| tx.fee()).sum(); let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward = libtx::reward::output(&keychain, &key_id3, fees, prev.height).unwrap(); let reward = libtx::reward::output(&keychain, &key_id3, fees).unwrap();
let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap(); let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
block.header.timestamp = prev.timestamp + Duration::seconds(60); block.header.timestamp = prev.timestamp + Duration::seconds(60);
@ -148,7 +145,7 @@ fn test_coinbase_maturity() {
let keychain = ExtKeychain::from_random_seed().unwrap(); let keychain = ExtKeychain::from_random_seed().unwrap();
let pk = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier(); let pk = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
let reward = libtx::reward::output(&keychain, &pk, 0, prev.height).unwrap(); let reward = libtx::reward::output(&keychain, &pk, 0).unwrap();
let mut block = core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap(); let mut block = core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
block.header.timestamp = prev.timestamp + Duration::seconds(60); block.header.timestamp = prev.timestamp + Duration::seconds(60);
@ -176,7 +173,7 @@ fn test_coinbase_maturity() {
let txs = vec![coinbase_txn]; let txs = vec![coinbase_txn];
let fees = txs.iter().map(|tx| tx.fee()).sum(); let fees = txs.iter().map(|tx| tx.fee()).sum();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
let reward = libtx::reward::output(&keychain, &key_id4, fees, prev.height).unwrap(); let reward = libtx::reward::output(&keychain, &key_id4, fees).unwrap();
let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap(); let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap();
block.header.timestamp = prev.timestamp + Duration::seconds(60); block.header.timestamp = prev.timestamp + Duration::seconds(60);

View file

@ -73,10 +73,7 @@ fn comments() -> HashMap<String, String> {
#parameters used for mining as well as wallet output coinbase maturity. Can be: #parameters used for mining as well as wallet output coinbase maturity. Can be:
#AutomatedTesting - For CI builds and instant blockchain creation #AutomatedTesting - For CI builds and instant blockchain creation
#UserTesting - For regular user testing (cuckoo 16) #UserTesting - For regular user testing (cuckoo 16)
#Testnet1 - Testnet1 genesis block (cuckoo 16) #Floonet - For the long term Floonet test network
#Testnet2 - Testnet2 genesis block (cuckoo 30)
#Testnet3 - Testnet3 genesis block (cuckoo 30)
#Testnet4 - Testnet4 genesis block (cuckatoo 29+)
" "
.to_string(), .to_string(),
); );
@ -403,6 +400,13 @@ fn comments() -> HashMap<String, String> {
"dark_background_color_scheme".to_string(), "dark_background_color_scheme".to_string(),
" "
#Whether to use the black background color scheme for command line #Whether to use the black background color scheme for command line
"
.to_string(),
);
retval.insert(
"use_switch_commitments".to_string(),
"
#Whether to use switch commitments for this wallet
" "
.to_string(), .to_string(),
); );

View file

@ -62,32 +62,13 @@ pub const COINBASE_MATURITY: u64 = DAY_HEIGHT;
/// function of block height (time). Starts at 90% losing a percent /// function of block height (time). Starts at 90% losing a percent
/// approximately every week. Represented as an integer between 0 and 100. /// approximately every week. Represented as an integer between 0 and 100.
pub fn secondary_pow_ratio(height: u64) -> u64 { pub fn secondary_pow_ratio(height: u64) -> u64 {
if global::is_testnet() {
if height < T4_CUCKAROO_HARDFORK {
// Maintaining pre hardfork testnet4 behavior
90u64.saturating_sub(height / WEEK_HEIGHT)
} else {
90u64.saturating_sub(height / (2 * YEAR_HEIGHT / 90)) 90u64.saturating_sub(height / (2 * YEAR_HEIGHT / 90))
}
} else {
// Mainnet (or testing mainnet code).
90u64.saturating_sub(height / (2 * YEAR_HEIGHT / 90))
}
} }
/// The AR scale damping factor to use. Dependent on block height /// The AR scale damping factor to use. Dependent on block height
/// to account for pre HF behavior on testnet4. /// to account for pre HF behavior on testnet4.
fn ar_scale_damp_factor(height: u64) -> u64 { fn ar_scale_damp_factor(_height: u64) -> u64 {
if global::is_testnet() {
if height < T4_CUCKAROO_HARDFORK {
DIFFICULTY_DAMP_FACTOR
} else {
AR_SCALE_DAMP_FACTOR AR_SCALE_DAMP_FACTOR
}
} else {
// Mainnet (or testing mainnet code).
AR_SCALE_DAMP_FACTOR
}
} }
/// Cuckoo-cycle proof size (cycle length) /// Cuckoo-cycle proof size (cycle length)
@ -99,10 +80,6 @@ pub const DEFAULT_MIN_EDGE_BITS: u8 = 31;
/// Cuckaroo proof-of-work edge_bits, meant to be ASIC resistant. /// Cuckaroo proof-of-work edge_bits, meant to be ASIC resistant.
pub const SECOND_POW_EDGE_BITS: u8 = 29; pub const SECOND_POW_EDGE_BITS: u8 = 29;
/// Block height at which testnet 4 hard forks to use Cuckaroo instead of
/// Cuckatoo for ASIC-resistant PoW
pub const T4_CUCKAROO_HARDFORK: u64 = 64_000;
/// Original reference edge_bits to compute difficulty factors for higher /// Original reference edge_bits to compute difficulty factors for higher
/// Cuckoo graph sizes, changing this would hard fork /// Cuckoo graph sizes, changing this would hard fork
pub const BASE_EDGE_BITS: u8 = 24; pub const BASE_EDGE_BITS: u8 = 24;
@ -332,15 +309,10 @@ where
/// Count the number of "secondary" (AR) blocks in the provided window of blocks. /// Count the number of "secondary" (AR) blocks in the provided window of blocks.
/// Note: we skip the first one, but testnet4 was incorrectly including it before /// Note: we skip the first one, but testnet4 was incorrectly including it before
/// the hardfork. /// the hardfork.
fn ar_count(height: u64, diff_data: &[HeaderInfo]) -> u64 { fn ar_count(_height: u64, diff_data: &[HeaderInfo]) -> u64 {
let mut to_skip = 1;
if global::is_testnet() && height < T4_CUCKAROO_HARDFORK {
// Maintain behavior of testnet4 pre-HF.
to_skip = 0;
}
100 * diff_data 100 * diff_data
.iter() .iter()
.skip(to_skip) .skip(1)
.filter(|n| n.is_secondary) .filter(|n| n.is_secondary)
.count() as u64 .count() as u64
} }

View file

@ -28,7 +28,7 @@ use crate::core::compact_block::{CompactBlock, CompactBlockBody};
use crate::core::hash::{Hash, Hashed, ZERO_HASH}; use crate::core::hash::{Hash, Hashed, ZERO_HASH};
use crate::core::verifier_cache::VerifierCache; use crate::core::verifier_cache::VerifierCache;
use crate::core::{ use crate::core::{
transaction, Commitment, Input, KernelFeatures, Output, OutputFeatures, Transaction, transaction, Commitment, Input, Output, Transaction,
TransactionBody, TxKernel, TransactionBody, TxKernel,
}; };
use crate::global; use crate::global;
@ -535,8 +535,8 @@ impl Block {
/// Consumes this block and returns a new block with the coinbase output /// Consumes this block and returns a new block with the coinbase output
/// and kernels added /// and kernels added
pub fn with_reward(mut self, reward_out: Output, reward_kern: TxKernel) -> Block { pub fn with_reward(mut self, reward_out: Output, reward_kern: TxKernel) -> Block {
self.body.outputs.push(reward_out); self.body.outputs = vec![reward_out];
self.body.kernels.push(reward_kern); self.body.kernels = vec![reward_kern];
self self
} }
@ -663,14 +663,14 @@ impl Block {
.body .body
.outputs .outputs
.iter() .iter()
.filter(|out| out.features.contains(OutputFeatures::COINBASE_OUTPUT)) .filter(|out| out.is_coinbase())
.collect::<Vec<&Output>>(); .collect::<Vec<&Output>>();
let cb_kerns = self let cb_kerns = self
.body .body
.kernels .kernels
.iter() .iter()
.filter(|kernel| kernel.features.contains(KernelFeatures::COINBASE_KERNEL)) .filter(|kernel| kernel.is_coinbase())
.collect::<Vec<&TxKernel>>(); .collect::<Vec<&TxKernel>>();
{ {

View file

@ -19,7 +19,7 @@ use rand::{thread_rng, Rng};
use crate::core::block::{Block, BlockHeader, Error}; use crate::core::block::{Block, BlockHeader, Error};
use crate::core::hash::Hashed; use crate::core::hash::Hashed;
use crate::core::id::ShortIdentifiable; use crate::core::id::ShortIdentifiable;
use crate::core::{KernelFeatures, Output, OutputFeatures, ShortId, TxKernel}; use crate::core::{Output, ShortId, TxKernel};
use crate::ser::{self, read_multi, Readable, Reader, VerifySortedAndUnique, Writeable, Writer}; use crate::ser::{self, read_multi, Readable, Reader, VerifySortedAndUnique, Writeable, Writer};
/// Container for full (full) outputs and kernels and kern_ids for a compact block. /// Container for full (full) outputs and kernels and kern_ids for a compact block.
@ -168,7 +168,7 @@ impl From<Block> for CompactBlock {
let out_full = block let out_full = block
.outputs() .outputs()
.iter() .iter()
.filter(|x| x.features.contains(OutputFeatures::COINBASE_OUTPUT)) .filter(|x| x.is_coinbase())
.cloned() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -176,7 +176,7 @@ impl From<Block> for CompactBlock {
let mut kern_ids = vec![]; let mut kern_ids = vec![];
for k in block.kernels() { for k in block.kernels() {
if k.features.contains(KernelFeatures::COINBASE_KERNEL) { if k.is_coinbase() {
kern_full.push(k.clone()); kern_full.push(k.clone());
} else { } else {
kern_ids.push(k.short_id(&header.hash(), nonce)); kern_ids.push(k.short_id(&header.hash(), nonce));

View file

@ -40,10 +40,12 @@ bitflags! {
/// Options for a kernel's structure or use /// Options for a kernel's structure or use
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct KernelFeatures: u8 { pub struct KernelFeatures: u8 {
/// No flags /// plain kernel has fee, but no lock_height
const DEFAULT_KERNEL = 0b00000000; const PLAIN = 0;
/// Kernel matching a coinbase output /// coinbase kernel has neither fee nor lock_height (both zero)
const COINBASE_KERNEL = 0b00000001; const COINBASE = 1;
/// absolute height locked kernel; has fee and lock_height
const HEIGHT_LOCKED = 2;
} }
} }
@ -202,7 +204,39 @@ impl PMMRable for TxKernel {
} }
} }
impl KernelFeatures {
/// Is this a coinbase kernel?
pub fn is_coinbase(&self) -> bool {
self.contains(KernelFeatures::COINBASE)
}
/// Is this a plain kernel?
pub fn is_plain(&self) -> bool {
!self.is_coinbase() && !self.is_height_locked()
}
/// Is this a height locked kernel?
pub fn is_height_locked(&self) -> bool {
self.contains(KernelFeatures::HEIGHT_LOCKED)
}
}
impl TxKernel { impl TxKernel {
/// Is this a coinbase kernel?
pub fn is_coinbase(&self) -> bool {
self.features.is_coinbase()
}
/// Is this a plain kernel?
pub fn is_plain(&self) -> bool {
self.features.is_plain()
}
/// Is this a height locked kernel?
pub fn is_height_locked(&self) -> bool {
self.features.is_height_locked()
}
/// Return the excess commitment for this tx_kernel. /// Return the excess commitment for this tx_kernel.
pub fn excess(&self) -> Commitment { pub fn excess(&self) -> Commitment {
self.excess self.excess
@ -219,6 +253,10 @@ impl TxKernel {
/// as a public key and checking the signature verifies with the fee as /// as a public key and checking the signature verifies with the fee as
/// message. /// message.
pub fn verify(&self) -> Result<(), Error> { pub fn verify(&self) -> Result<(), Error> {
if self.is_coinbase() && self.fee != 0 || !self.is_height_locked() && self.lock_height != 0
{
return Err(Error::InvalidKernelFeatures);
}
let secp = static_secp_instance(); let secp = static_secp_instance();
let secp = secp.lock(); let secp = secp.lock();
let sig = &self.excess_sig; let sig = &self.excess_sig;
@ -242,7 +280,7 @@ impl TxKernel {
/// Build an empty tx kernel with zero values. /// Build an empty tx kernel with zero values.
pub fn empty() -> TxKernel { pub fn empty() -> TxKernel {
TxKernel { TxKernel {
features: KernelFeatures::DEFAULT_KERNEL, features: KernelFeatures::PLAIN,
fee: 0, fee: 0,
lock_height: 0, lock_height: 0,
excess: Commitment::from_vec(vec![0; 33]), excess: Commitment::from_vec(vec![0; 33]),
@ -258,6 +296,7 @@ impl TxKernel {
/// Builds a new tx kernel with the provided lock_height. /// Builds a new tx kernel with the provided lock_height.
pub fn with_lock_height(self, lock_height: u64) -> TxKernel { pub fn with_lock_height(self, lock_height: u64) -> TxKernel {
TxKernel { TxKernel {
features: kernel_features(lock_height),
lock_height, lock_height,
..self ..self
} }
@ -586,25 +625,17 @@ impl TransactionBody {
Ok(()) Ok(())
} }
// Verify we have no outputs tagged as COINBASE_OUTPUT. // Verify we have no outputs tagged as COINBASE.
fn verify_output_features(&self) -> Result<(), Error> { fn verify_output_features(&self) -> Result<(), Error> {
if self if self.outputs.iter().any(|x| x.is_coinbase()) {
.outputs
.iter()
.any(|x| x.features.contains(OutputFeatures::COINBASE_OUTPUT))
{
return Err(Error::InvalidOutputFeatures); return Err(Error::InvalidOutputFeatures);
} }
Ok(()) Ok(())
} }
// Verify we have no kernels tagged as COINBASE_KERNEL. // Verify we have no kernels tagged as COINBASE.
fn verify_kernel_features(&self) -> Result<(), Error> { fn verify_kernel_features(&self) -> Result<(), Error> {
if self if self.kernels.iter().any(|x| x.is_coinbase()) {
.kernels
.iter()
.any(|x| x.features.contains(KernelFeatures::COINBASE_KERNEL))
{
return Err(Error::InvalidKernelFeatures); return Err(Error::InvalidKernelFeatures);
} }
Ok(()) Ok(())
@ -1081,6 +1112,16 @@ impl Input {
pub fn commitment(&self) -> Commitment { pub fn commitment(&self) -> Commitment {
self.commit self.commit
} }
/// Is this a coinbase input?
pub fn is_coinbase(&self) -> bool {
self.features.is_coinbase()
}
/// Is this a plain input?
pub fn is_plain(&self) -> bool {
self.features.is_plain()
}
} }
bitflags! { bitflags! {
@ -1088,9 +1129,9 @@ bitflags! {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct OutputFeatures: u8 { pub struct OutputFeatures: u8 {
/// No flags /// No flags
const DEFAULT_OUTPUT = 0b00000000; const PLAIN = 0;
/// Output is a coinbase output, must not be spent until maturity /// Output is a coinbase output, must not be spent until maturity
const COINBASE_OUTPUT = 0b00000001; const COINBASE = 1;
} }
} }
@ -1160,12 +1201,34 @@ impl PMMRable for Output {
} }
} }
impl OutputFeatures {
/// Is this a coinbase output?
pub fn is_coinbase(&self) -> bool {
self.contains(OutputFeatures::COINBASE)
}
/// Is this a plain output?
pub fn is_plain(&self) -> bool {
!self.contains(OutputFeatures::COINBASE)
}
}
impl Output { impl Output {
/// Commitment for the output /// Commitment for the output
pub fn commitment(&self) -> Commitment { pub fn commitment(&self) -> Commitment {
self.commit self.commit
} }
/// Is this a coinbase kernel?
pub fn is_coinbase(&self) -> bool {
self.features.is_coinbase()
}
/// Is this a plain kernel?
pub fn is_plain(&self) -> bool {
self.features.is_plain()
}
/// Range proof for the output /// Range proof for the output
pub fn proof(&self) -> RangeProof { pub fn proof(&self) -> RangeProof {
self.proof self.proof
@ -1291,25 +1354,43 @@ impl From<Output> for OutputIdentifier {
/// to produce a 32 byte message to sign. /// to produce a 32 byte message to sign.
/// ///
/// testnet4: msg = (fee || lock_height) /// testnet4: msg = (fee || lock_height)
/// mainnet: msg = hash(fee || lock_height || features) /// mainnet: msg = hash(features) for coinbase kernels
/// hash(features || fee) for plain kernels
/// hash(features || fee || lock_height) for height locked kernels
/// ///
pub fn kernel_sig_msg( pub fn kernel_sig_msg(
fee: u64, fee: u64,
lock_height: u64, lock_height: u64,
features: KernelFeatures, features: KernelFeatures,
) -> Result<secp::Message, Error> { ) -> Result<secp::Message, Error> {
if features.is_coinbase() && fee != 0 || !features.is_height_locked() && lock_height != 0 {
return Err(Error::InvalidKernelFeatures);
}
let msg = if global::is_testnet() { let msg = if global::is_testnet() {
let mut bytes = [0; 32]; let mut bytes = [0; 32];
BigEndian::write_u64(&mut bytes[16..24], fee); BigEndian::write_u64(&mut bytes[16..24], fee);
BigEndian::write_u64(&mut bytes[24..], lock_height); BigEndian::write_u64(&mut bytes[24..], lock_height);
secp::Message::from_slice(&bytes)? secp::Message::from_slice(&bytes)?
} else { } else {
let hash = (fee, lock_height, features).hash(); let hash = match features {
KernelFeatures::COINBASE => (features).hash(),
KernelFeatures::PLAIN => (features, fee).hash(),
_ => (features, fee, lock_height).hash(),
};
secp::Message::from_slice(&hash.as_bytes())? secp::Message::from_slice(&hash.as_bytes())?
}; };
Ok(msg) Ok(msg)
} }
/// kernel features as determined by lock height
pub fn kernel_features(lock_height: u64) -> KernelFeatures {
if lock_height > 0 {
KernelFeatures::HEIGHT_LOCKED
} else {
KernelFeatures::PLAIN
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -1328,7 +1409,7 @@ mod test {
let sig = secp::Signature::from_raw_data(&[0; 64]).unwrap(); let sig = secp::Signature::from_raw_data(&[0; 64]).unwrap();
let kernel = TxKernel { let kernel = TxKernel {
features: KernelFeatures::DEFAULT_KERNEL, features: KernelFeatures::PLAIN,
lock_height: 0, lock_height: 0,
excess: commit, excess: commit,
excess_sig: sig.clone(), excess_sig: sig.clone(),
@ -1338,7 +1419,7 @@ mod test {
let mut vec = vec![]; let mut vec = vec![];
ser::serialize(&mut vec, &kernel).expect("serialized failed"); ser::serialize(&mut vec, &kernel).expect("serialized failed");
let kernel2: TxKernel = ser::deserialize(&mut &vec[..]).unwrap(); let kernel2: TxKernel = ser::deserialize(&mut &vec[..]).unwrap();
assert_eq!(kernel2.features, KernelFeatures::DEFAULT_KERNEL); assert_eq!(kernel2.features, KernelFeatures::PLAIN);
assert_eq!(kernel2.lock_height, 0); assert_eq!(kernel2.lock_height, 0);
assert_eq!(kernel2.excess, commit); assert_eq!(kernel2.excess, commit);
assert_eq!(kernel2.excess_sig, sig.clone()); assert_eq!(kernel2.excess_sig, sig.clone());
@ -1346,7 +1427,7 @@ mod test {
// now check a kernel with lock_height serialize/deserialize correctly // now check a kernel with lock_height serialize/deserialize correctly
let kernel = TxKernel { let kernel = TxKernel {
features: KernelFeatures::DEFAULT_KERNEL, features: KernelFeatures::HEIGHT_LOCKED,
lock_height: 100, lock_height: 100,
excess: commit, excess: commit,
excess_sig: sig.clone(), excess_sig: sig.clone(),
@ -1356,7 +1437,7 @@ mod test {
let mut vec = vec![]; let mut vec = vec![];
ser::serialize(&mut vec, &kernel).expect("serialized failed"); ser::serialize(&mut vec, &kernel).expect("serialized failed");
let kernel2: TxKernel = ser::deserialize(&mut &vec[..]).unwrap(); let kernel2: TxKernel = ser::deserialize(&mut &vec[..]).unwrap();
assert_eq!(kernel2.features, KernelFeatures::DEFAULT_KERNEL); assert_eq!(kernel2.features, KernelFeatures::HEIGHT_LOCKED);
assert_eq!(kernel2.lock_height, 100); assert_eq!(kernel2.lock_height, 100);
assert_eq!(kernel2.excess, commit); assert_eq!(kernel2.excess, commit);
assert_eq!(kernel2.excess_sig, sig.clone()); assert_eq!(kernel2.excess_sig, sig.clone());
@ -1383,7 +1464,7 @@ mod test {
let commit = keychain.commit(5, &key_id).unwrap(); let commit = keychain.commit(5, &key_id).unwrap();
let input = Input { let input = Input {
features: OutputFeatures::DEFAULT_OUTPUT, features: OutputFeatures::PLAIN,
commit: commit, commit: commit,
}; };
@ -1394,16 +1475,16 @@ mod test {
let nonce = 0; let nonce = 0;
let short_id = input.short_id(&block_hash, nonce); let short_id = input.short_id(&block_hash, nonce);
assert_eq!(short_id, ShortId::from_hex("df31d96e3cdb").unwrap()); assert_eq!(short_id, ShortId::from_hex("c4b05f2ba649").unwrap());
// now generate the short_id for a *very* similar output (single feature flag // now generate the short_id for a *very* similar output (single feature flag
// different) and check it generates a different short_id // different) and check it generates a different short_id
let input = Input { let input = Input {
features: OutputFeatures::COINBASE_OUTPUT, features: OutputFeatures::COINBASE,
commit: commit, commit: commit,
}; };
let short_id = input.short_id(&block_hash, nonce); let short_id = input.short_id(&block_hash, nonce);
assert_eq!(short_id, ShortId::from_hex("784fc5afd5d9").unwrap()); assert_eq!(short_id, ShortId::from_hex("3f0377c624e9").unwrap());
} }
} }

View file

@ -14,12 +14,21 @@
//! Definition of the genesis block. Placeholder for now. //! Definition of the genesis block. Placeholder for now.
// required for genesis replacement
//! #![allow(unused_imports)]
use chrono::prelude::{TimeZone, Utc}; use chrono::prelude::{TimeZone, Utc};
use crate::consensus;
use crate::core; use crate::core;
use crate::global; use crate::global;
use crate::pow::{Difficulty, Proof, ProofOfWork}; use crate::pow::{Difficulty, Proof, ProofOfWork};
use crate::util;
use crate::util::secp::constants::SINGLE_BULLET_PROOF_SIZE;
use crate::util::secp::pedersen::{Commitment, RangeProof};
use crate::util::secp::Signature;
use crate::core::hash::Hash;
use crate::keychain::BlindingFactor;
/// Genesis block definition for development networks. The proof of work size /// Genesis block definition for development networks. The proof of work size
/// is small enough to mine it on the fly, so it does not contain its own /// is small enough to mine it on the fly, so it does not contain its own
@ -37,114 +46,196 @@ pub fn genesis_dev() -> core::Block {
}) })
} }
/// First testnet genesis block, still subject to change (especially the date, /// Placeholder for floonet genesis block, will definitely change before
/// will hopefully come before Christmas). /// release
pub fn genesis_testnet1() -> core::Block { pub fn genesis_floo() -> core::Block {
core::Block::with_header(core::BlockHeader { let gen = core::Block::with_header(core::BlockHeader {
height: 0, height: 0,
timestamp: Utc.ymd(2017, 11, 16).and_hms(20, 0, 0), timestamp: Utc.ymd(2018, 12, 20).and_hms(20, 58, 32),
prev_root: Hash::from_hex(
"ae144568a9ec32faf57e9ca5b5f0997d33f30bd3352fd84c953e6526d847c26b",
)
.unwrap(),
output_root: Hash::from_hex(
"47d2570266451203c62cd003c706e3ec37e9cb4292316744abfa68a1b133bc1c",
)
.unwrap(),
range_proof_root: Hash::from_hex(
"53ea93e80fe37e9a0cbb9c1a1ddf467213922481a4435921aacf55ffb3f388fc",
)
.unwrap(),
kernel_root: Hash::from_hex(
"3ff7655b2846a1313dd72e1c516a2fa262638fabc8e0d4c1dddf80773bbd472d",
)
.unwrap(),
total_kernel_offset: BlindingFactor::from_hex(
"0000000000000000000000000000000000000000000000000000000000000000",
)
.unwrap(),
output_mmr_size: 1,
kernel_mmr_size: 1,
pow: ProofOfWork { pow: ProofOfWork {
total_difficulty: Difficulty::min(), total_difficulty: Difficulty::from_num(10_u64.pow(6)),
secondary_scaling: 1, secondary_scaling: 1856,
nonce: 28205, nonce: 22,
proof: Proof::new(vec![
0x21e, 0x7a2, 0xeae, 0x144e, 0x1b1c, 0x1fbd, 0x203a, 0x214b, 0x293b, 0x2b74,
0x2bfa, 0x2c26, 0x32bb, 0x346a, 0x34c7, 0x37c5, 0x4164, 0x42cc, 0x4cc3, 0x55af,
0x5a70, 0x5b14, 0x5e1c, 0x5f76, 0x6061, 0x60f9, 0x61d7, 0x6318, 0x63a1, 0x63fb,
0x649b, 0x64e5, 0x65a1, 0x6b69, 0x70f8, 0x71c7, 0x71cd, 0x7492, 0x7b11, 0x7db8,
0x7f29, 0x7ff8,
]),
},
..Default::default()
})
}
/// Second testnet genesis block (cuckoo30).
pub fn genesis_testnet2() -> core::Block {
core::Block::with_header(core::BlockHeader {
height: 0,
// previous: core::hash::Hash([0xff; 32]),
timestamp: Utc.ymd(2018, 3, 26).and_hms(16, 0, 0),
pow: ProofOfWork {
total_difficulty: Difficulty::from_num(global::initial_block_difficulty()),
secondary_scaling: 1,
nonce: 1060,
proof: Proof::new(vec![
0x1940730, 0x333b9d0, 0x4739d6f, 0x4c6cfb1, 0x6e3d6c3, 0x74408a3, 0x7ba2bd2,
0x83e2024, 0x8ca22b5, 0x9d39ab8, 0xb6646dd, 0xc6698b6, 0xc6f78fe, 0xc99b662,
0xcf2ae8c, 0xcf41eed, 0xdd073e6, 0xded6af8, 0xf08d1a5, 0x1156a144, 0x11d1160a,
0x131bb0a5, 0x137ad703, 0x13b0831f, 0x1421683f, 0x147e3c1f, 0x1496fda0, 0x150ba22b,
0x15cc5bc6, 0x16edf697, 0x17ced40c, 0x17d84f9e, 0x18a515c1, 0x19320d9c, 0x19da4f6d,
0x1b50bcb1, 0x1b8bc72f, 0x1c7b6964, 0x1d07b3a9, 0x1d189d4d, 0x1d1f9a15, 0x1dafcd41,
]),
},
..Default::default()
})
}
/// Second testnet genesis block (cuckoo30). Temporary values for now.
pub fn genesis_testnet3() -> core::Block {
core::Block::with_header(core::BlockHeader {
height: 0,
// previous: core::hash::Hash([0xff; 32]),
timestamp: Utc.ymd(2018, 7, 8).and_hms(18, 0, 0),
pow: ProofOfWork {
total_difficulty: Difficulty::from_num(global::initial_block_difficulty()),
secondary_scaling: 1,
nonce: 4956988373127691,
proof: Proof::new(vec![
0xa420dc, 0xc8ffee, 0x10e433e, 0x1de9428, 0x2ed4cea, 0x52d907b, 0x5af0e3f,
0x6b8fcae, 0x8319b53, 0x845ca8c, 0x8d2a13e, 0x8d6e4cc, 0x9349e8d, 0xa7a33c5,
0xaeac3cb, 0xb193e23, 0xb502e19, 0xb5d9804, 0xc9ac184, 0xd4f4de3, 0xd7a23b8,
0xf1d8660, 0xf443756, 0x10b833d2, 0x11418fc5, 0x11b8aeaf, 0x131836ec, 0x132ab818,
0x13a46a55, 0x13df89fe, 0x145d65b5, 0x166f9c3a, 0x166fe0ef, 0x178cb36f, 0x185baf68,
0x1bbfe563, 0x1bd637b4, 0x1cfc8382, 0x1d1ed012, 0x1e391ca5, 0x1e999b4c, 0x1f7c6d21,
]),
},
..Default::default()
})
}
/// 4th testnet genesis block (cuckatoo29 AR, 30+ AF). Temporary values for now (Pow won't verify)
/// NB: Currently set to intenal pre-testnet values
pub fn genesis_testnet4() -> core::Block {
core::Block::with_header(core::BlockHeader {
height: 0,
// previous: core::hash::Hash([0xff; 32]),
timestamp: Utc.ymd(2018, 10, 17).and_hms(20, 0, 0),
pow: ProofOfWork {
total_difficulty: Difficulty::from_num(global::initial_block_difficulty()),
secondary_scaling: global::initial_graph_weight(),
nonce: 8612241555342799290,
proof: Proof { proof: Proof {
nonces: vec![ nonces: vec![
0x46f3b4, 0x1135f8c, 0x1a1596f, 0x1e10f71, 0x41c03ea, 0x63fe8e7, 0x65af34f, 48398361, 50434294, 73758991, 93493375, 94716564, 101961133, 153506566,
0x73c16d3, 0x8216dc3, 0x9bc75d0, 0xae7d9ad, 0xc1cb12b, 0xc65e957, 0xf67a152, 159476458, 164019912, 208165915, 216747111, 218441011, 221663358, 262514197,
0xfac6559, 0x100c3d71, 0x11eea08b, 0x1225dfbb, 0x124d61a1, 0x132a14b4, 264746362, 278423427, 282069592, 284508695, 297003554, 327321117, 327780367,
0x13f4ec38, 0x1542d236, 0x155f2df0, 0x1577394e, 0x163c3513, 0x19349845, 329474453, 333639856, 356316379, 366419120, 381872178, 386038638, 389726932,
0x19d46953, 0x19f65ed4, 0x1a0411b9, 0x1a2fa039, 0x1a72a06c, 0x1b02ddd2, 390055244, 392425788, 399530286, 426997994, 436531599, 456084550, 456375883,
0x1b594d59, 0x1b7bffd3, 0x1befe12e, 0x1c82e4cd, 0x1d492478, 0x1de132a5, 459156409, 474067792, 480904139, 487380747, 489307817, 496780560, 530227836,
0x1e578b3c, 0x1ed96855, 0x1f222896, 0x1fea0da6,
], ],
edge_bits: 29, edge_bits: 29,
}, },
}, },
..Default::default() ..Default::default()
}) });
let kernel = core::TxKernel {
features: core::KernelFeatures::COINBASE,
fee: 0,
lock_height: 0,
excess: Commitment::from_vec(
util::from_hex(
"0817a9e97a070ba5f9fa185c093b4b13b262ed4b4712b6f7c92881b27168f9a2cb".to_string(),
)
.unwrap(),
),
excess_sig: Signature::from_raw_data(&[
172, 131, 105, 224, 31, 11, 0, 70, 109, 54, 230, 184, 177, 138, 46, 137, 202, 215, 152,
37, 192, 132, 88, 254, 110, 76, 57, 32, 42, 13, 19, 89, 82, 89, 116, 66, 30, 132, 120,
148, 122, 100, 97, 38, 141, 219, 57, 184, 171, 130, 213, 235, 83, 202, 69, 13, 213, 60,
150, 172, 33, 37, 209, 57,
])
.unwrap(),
};
let output = core::Output {
features: core::OutputFeatures::COINBASE,
commit: Commitment::from_vec(
util::from_hex(
"08f5523cbd8b2e1dae3eefdd9dd1069e0c8a7f055a0611da79f42530c5de0d044b".to_string(),
)
.unwrap(),
),
proof: RangeProof {
plen: SINGLE_BULLET_PROOF_SIZE,
proof: [
47, 196, 194, 238, 233, 164, 218, 64, 54, 92, 83, 248, 225, 116, 189, 225, 202, 66,
213, 63, 195, 209, 238, 189, 153, 198, 231, 219, 3, 146, 102, 67, 26, 7, 199, 150,
160, 244, 48, 166, 113, 6, 241, 49, 133, 248, 201, 80, 34, 19, 118, 249, 44, 213,
215, 235, 228, 187, 215, 116, 212, 203, 232, 183, 12, 66, 29, 11, 28, 17, 212, 104,
126, 203, 103, 60, 176, 149, 182, 206, 70, 138, 180, 213, 76, 99, 25, 184, 40, 177,
197, 179, 71, 63, 19, 72, 253, 129, 115, 107, 90, 249, 39, 108, 134, 10, 231, 172,
172, 59, 207, 118, 175, 124, 197, 132, 73, 154, 148, 8, 73, 26, 231, 75, 24, 134,
199, 93, 15, 43, 45, 49, 69, 167, 194, 23, 114, 16, 117, 209, 127, 123, 18, 209,
12, 34, 219, 196, 37, 7, 226, 132, 70, 111, 113, 164, 203, 175, 105, 175, 196, 62,
225, 138, 162, 176, 190, 109, 96, 210, 15, 38, 245, 200, 83, 155, 185, 111, 85,
234, 6, 3, 246, 98, 175, 127, 94, 65, 29, 78, 27, 53, 32, 230, 85, 91, 195, 112,
84, 135, 56, 207, 213, 165, 40, 248, 238, 202, 225, 142, 79, 89, 81, 197, 138, 65,
14, 232, 145, 44, 73, 6, 43, 8, 43, 42, 127, 151, 68, 18, 19, 83, 14, 142, 180, 75,
25, 4, 97, 166, 237, 212, 187, 106, 154, 36, 223, 231, 177, 58, 70, 1, 195, 113,
144, 151, 45, 185, 0, 174, 116, 212, 122, 239, 96, 1, 122, 211, 41, 96, 230, 110,
242, 145, 176, 230, 55, 143, 142, 234, 151, 49, 151, 109, 252, 120, 147, 244, 178,
73, 196, 221, 150, 85, 69, 113, 50, 166, 92, 91, 98, 188, 77, 76, 48, 192, 112,
184, 108, 143, 134, 56, 46, 119, 21, 71, 247, 119, 133, 225, 72, 15, 158, 60, 64,
71, 57, 134, 243, 228, 58, 13, 58, 209, 71, 4, 72, 87, 129, 51, 46, 64, 188, 60,
157, 56, 120, 23, 2, 47, 143, 79, 176, 54, 3, 47, 227, 124, 70, 242, 8, 59, 113,
203, 51, 65, 138, 131, 121, 45, 131, 132, 171, 161, 49, 235, 129, 39, 164, 234, 69,
172, 95, 28, 180, 118, 163, 151, 148, 66, 65, 104, 222, 232, 154, 22, 30, 149, 196,
214, 163, 93, 76, 128, 142, 233, 106, 171, 213, 148, 59, 101, 56, 22, 127, 232, 4,
63, 111, 9, 188, 163, 40, 158, 24, 65, 81, 203, 231, 93, 197, 102, 170, 70, 239,
229, 13, 172, 110, 157, 226, 112, 182, 28, 150, 222, 62, 224, 94, 182, 220, 243,
236, 62, 156, 129, 220, 127, 155, 141, 0, 243, 159, 113, 28, 158, 95, 205, 35, 72,
132, 46, 235, 176, 146, 233, 93, 111, 4, 105, 236, 176, 165, 102, 168, 188, 121,
105, 175, 197, 114, 97, 40, 2, 165, 153, 85, 135, 114, 147, 95, 216, 50, 108, 52,
225, 186, 215, 110, 122, 230, 14, 246, 141, 180, 41, 22, 132, 58, 8, 31, 187, 221,
231, 14, 33, 52, 88, 219, 200, 77, 246, 134, 18, 0, 113, 144, 6, 146, 54, 24, 113,
14, 64, 182, 116, 229, 250, 201, 126, 84, 192, 80, 13, 57, 232, 55, 113, 139, 249,
166, 231, 123, 101, 236, 147, 144, 2, 9, 51, 2, 189, 188, 200, 66, 29, 16, 22, 150,
45, 220, 15, 161, 180, 214, 244, 104, 41, 77, 171, 246, 243, 56, 47, 63, 103, 216,
151, 199, 249, 169, 165, 119, 200, 243, 161, 83, 46, 225, 195, 92, 96, 150, 0, 165,
170, 14, 211, 226, 244, 70, 218, 137, 254, 197, 175, 208, 119, 199, 121, 4, 7, 190,
118, 55, 197, 208, 41, 109, 161, 34, 33, 210, 58, 99, 81, 97, 57, 156, 57, 144, 83,
97, 49, 248, 89, 201, 88, 169, 9, 211, 34, 136, 174, 195, 224, 51, 103, 12, 237,
172, 46, 216, 5, 168,
],
},
};
gen.with_reward(output, kernel)
} }
/// Placeholder for mainnet genesis block, will definitely change before /// Placeholder for mainnet genesis block, will definitely change before
/// release so no use trying to pre-mine it. /// release so no use trying to pre-mine it.
pub fn genesis_main() -> core::Block { pub fn genesis_main() -> core::Block {
core::Block::with_header(core::BlockHeader { let gen = core::Block::with_header(core::BlockHeader {
height: 0, height: 0,
// previous: core::hash::Hash([0xff; 32]), timestamp: Utc.ymd(2019, 1, 15).and_hms(12, 0, 0), // REPLACE
timestamp: Utc.ymd(2018, 8, 14).and_hms(0, 0, 0), prev_root: Hash::default(), // REPLACE
output_root: Hash::default(), // REPLACE
range_proof_root: Hash::default(), // REPLACE
kernel_root: Hash::default(), // REPLACE
total_kernel_offset: BlindingFactor::zero(), // REPLACE
output_mmr_size: 1,
kernel_mmr_size: 1,
pow: ProofOfWork { pow: ProofOfWork {
total_difficulty: Difficulty::from_num(global::initial_block_difficulty()), total_difficulty: Difficulty::from_num(10_u64.pow(8)),
secondary_scaling: 1, secondary_scaling: 1856,
nonce: global::get_genesis_nonce(), nonce: 1, // REPLACE
proof: Proof::zero(consensus::PROOFSIZE), proof: Proof {
nonces: vec![0; 42], // REPLACE
edge_bits: 29,
},
}, },
..Default::default() ..Default::default()
}) });
let kernel = core::TxKernel {
features: core::KernelFeatures::COINBASE,
fee: 0,
lock_height: 0,
excess: Commitment::from_vec(vec![]), // REPLACE
excess_sig: Signature::from_raw_data(&[0; 64]).unwrap(), //REPLACE
};
let output = core::Output {
features: core::OutputFeatures::COINBASE,
commit: Commitment::from_vec(vec![]), // REPLACE
proof: RangeProof {
plen: SINGLE_BULLET_PROOF_SIZE,
proof: [0; SINGLE_BULLET_PROOF_SIZE], // REPLACE
},
};
gen.with_reward(output, kernel)
}
#[cfg(test)]
mod test {
use super::*;
use crate::core::hash::Hashed;
use crate::ser;
#[test]
fn floonet_genesis_hash() {
let gen_hash = genesis_floo().hash();
println!("floonet genesis hash: {}", gen_hash.to_hex());
let gen_bin = ser::ser_vec(&genesis_floo()).unwrap();
println!("floonet genesis full hash: {}\n", gen_bin.hash().to_hex());
assert_eq!(
gen_hash.to_hex(),
"cb272478ee4abbf41a3d8cc8f2f828785cf38bd7f0dcacfdd6db5f8f2d8f6e24"
);
assert_eq!(
gen_bin.hash().to_hex(),
"5fcc7afebc2dcfb98f982dd4d9ff7878fca45038d22677ef6360745c90505035"
);
}
// TODO hardcode the hashes once genesis is set
#[test]
fn mainnet_genesis_hash() {
let gen_hash = genesis_main().hash();
println!("mainnet genesis hash: {}", gen_hash.to_hex());
let gen_bin = ser::ser_vec(&genesis_main()).unwrap();
println!("mainnet genesis full hash: {}\n", gen_bin.hash().to_hex());
//assert_eq!(gene_hash.to_hex, "");
}
} }

View file

@ -20,7 +20,7 @@ use crate::consensus::HeaderInfo;
use crate::consensus::{ use crate::consensus::{
graph_weight, BASE_EDGE_BITS, BLOCK_TIME_SEC, COINBASE_MATURITY, CUT_THROUGH_HORIZON, graph_weight, BASE_EDGE_BITS, BLOCK_TIME_SEC, COINBASE_MATURITY, CUT_THROUGH_HORIZON,
DAY_HEIGHT, DEFAULT_MIN_EDGE_BITS, DIFFICULTY_ADJUST_WINDOW, INITIAL_DIFFICULTY, PROOFSIZE, DAY_HEIGHT, DEFAULT_MIN_EDGE_BITS, DIFFICULTY_ADJUST_WINDOW, INITIAL_DIFFICULTY, PROOFSIZE,
SECOND_POW_EDGE_BITS, STATE_SYNC_THRESHOLD, T4_CUCKAROO_HARDFORK, UNIT_DIFFICULTY, SECOND_POW_EDGE_BITS, STATE_SYNC_THRESHOLD,
}; };
use crate::pow::{self, new_cuckaroo_ctx, new_cuckatoo_ctx, EdgeType, PoWContext}; use crate::pow::{self, new_cuckaroo_ctx, new_cuckatoo_ctx, EdgeType, PoWContext};
/// An enum collecting sets of parameters used throughout the /// An enum collecting sets of parameters used throughout the
@ -62,13 +62,6 @@ pub const TESTING_INITIAL_GRAPH_WEIGHT: u32 = 1;
/// Testing initial block difficulty /// Testing initial block difficulty
pub const TESTING_INITIAL_DIFFICULTY: u64 = 1; pub const TESTING_INITIAL_DIFFICULTY: u64 = 1;
/// Testnet 2 initial block difficulty, high to see how it goes
pub const TESTNET2_INITIAL_DIFFICULTY: u64 = 1000;
/// Testnet 3 initial block difficulty, moderately high, taking into account
/// a 30x Cuckoo adjustment factor
pub const TESTNET3_INITIAL_DIFFICULTY: u64 = 30000;
/// If a peer's last updated difficulty is 2 hours ago and its difficulty's lower than ours, /// If a peer's last updated difficulty is 2 hours ago and its difficulty's lower than ours,
/// we're sure this peer is a stuck node, and we will kick out such kind of stuck peers. /// we're sure this peer is a stuck node, and we will kick out such kind of stuck peers.
pub const STUCK_PEER_KICK_TIME: i64 = 2 * 3600 * 1000; pub const STUCK_PEER_KICK_TIME: i64 = 2 * 3600 * 1000;
@ -79,13 +72,6 @@ const PEER_EXPIRATION_DAYS: i64 = 7 * 2;
/// Constant that expresses defunct peer timeout in seconds to be used in checks. /// Constant that expresses defunct peer timeout in seconds to be used in checks.
pub const PEER_EXPIRATION_REMOVE_TIME: i64 = PEER_EXPIRATION_DAYS * 24 * 3600; pub const PEER_EXPIRATION_REMOVE_TIME: i64 = PEER_EXPIRATION_DAYS * 24 * 3600;
/// Testnet 4 initial block difficulty
/// 1_000 times natural scale factor for cuckatoo29
pub const TESTNET4_INITIAL_DIFFICULTY: u64 = 1_000 * UNIT_DIFFICULTY;
/// Cuckatoo edge_bits on T4
pub const TESTNET4_MIN_EDGE_BITS: u8 = 30;
/// Trigger compaction check on average every day for all nodes. /// Trigger compaction check on average every day for all nodes.
/// Randomized per node - roll the dice on every block to decide. /// Randomized per node - roll the dice on every block to decide.
/// Will compact the txhashset to remove pruned data. /// Will compact the txhashset to remove pruned data.
@ -101,21 +87,15 @@ pub enum ChainTypes {
AutomatedTesting, AutomatedTesting,
/// For User testing /// For User testing
UserTesting, UserTesting,
/// First test network /// Protocol testing network
Testnet1, Floonet,
/// Second test network
Testnet2,
/// Third test network
Testnet3,
/// Fourth test network
Testnet4,
/// Main production network /// Main production network
Mainnet, Mainnet,
} }
impl Default for ChainTypes { impl Default for ChainTypes {
fn default() -> ChainTypes { fn default() -> ChainTypes {
ChainTypes::Testnet4 ChainTypes::Floonet
} }
} }
@ -149,7 +129,7 @@ pub fn set_mining_mode(mode: ChainTypes) {
/// Return either a cuckoo context or a cuckatoo context /// Return either a cuckoo context or a cuckatoo context
/// Single change point /// Single change point
pub fn create_pow_context<T>( pub fn create_pow_context<T>(
height: u64, _height: u64,
edge_bits: u8, edge_bits: u8,
proof_size: usize, proof_size: usize,
max_sols: u32, max_sols: u32,
@ -163,12 +143,9 @@ where
ChainTypes::Mainnet if edge_bits == 29 => new_cuckaroo_ctx(edge_bits, proof_size), ChainTypes::Mainnet if edge_bits == 29 => new_cuckaroo_ctx(edge_bits, proof_size),
ChainTypes::Mainnet => new_cuckatoo_ctx(edge_bits, proof_size, max_sols), ChainTypes::Mainnet => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
// T4 has Cuckatoo for everything up to hard fork, then Cuckaroo29 for AR // Same for Floonet
// and Cuckatoo30+ for AF PoW ChainTypes::Floonet if edge_bits == 29 => new_cuckaroo_ctx(edge_bits, proof_size),
ChainTypes::Testnet4 if edge_bits == 29 && height >= T4_CUCKAROO_HARDFORK => { ChainTypes::Floonet => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
new_cuckaroo_ctx(edge_bits, proof_size)
}
ChainTypes::Testnet4 => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
// Everything else is Cuckatoo only // Everything else is Cuckatoo only
_ => new_cuckatoo_ctx(edge_bits, proof_size, max_sols), _ => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
@ -186,8 +163,6 @@ pub fn min_edge_bits() -> u8 {
match *param_ref { match *param_ref {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS, ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS,
ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS, ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS,
ChainTypes::Testnet1 => USER_TESTING_MIN_EDGE_BITS,
ChainTypes::Testnet4 => TESTNET4_MIN_EDGE_BITS,
_ => DEFAULT_MIN_EDGE_BITS, _ => DEFAULT_MIN_EDGE_BITS,
} }
} }
@ -200,7 +175,6 @@ pub fn base_edge_bits() -> u8 {
match *param_ref { match *param_ref {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS, ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS,
ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS, ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS,
ChainTypes::Testnet1 => USER_TESTING_MIN_EDGE_BITS,
_ => BASE_EDGE_BITS, _ => BASE_EDGE_BITS,
} }
} }
@ -231,10 +205,7 @@ pub fn initial_block_difficulty() -> u64 {
match *param_ref { match *param_ref {
ChainTypes::AutomatedTesting => TESTING_INITIAL_DIFFICULTY, ChainTypes::AutomatedTesting => TESTING_INITIAL_DIFFICULTY,
ChainTypes::UserTesting => TESTING_INITIAL_DIFFICULTY, ChainTypes::UserTesting => TESTING_INITIAL_DIFFICULTY,
ChainTypes::Testnet1 => TESTING_INITIAL_DIFFICULTY, ChainTypes::Floonet => INITIAL_DIFFICULTY,
ChainTypes::Testnet2 => TESTNET2_INITIAL_DIFFICULTY,
ChainTypes::Testnet3 => TESTNET3_INITIAL_DIFFICULTY,
ChainTypes::Testnet4 => TESTNET4_INITIAL_DIFFICULTY,
ChainTypes::Mainnet => INITIAL_DIFFICULTY, ChainTypes::Mainnet => INITIAL_DIFFICULTY,
} }
} }
@ -244,10 +215,7 @@ pub fn initial_graph_weight() -> u32 {
match *param_ref { match *param_ref {
ChainTypes::AutomatedTesting => TESTING_INITIAL_GRAPH_WEIGHT, ChainTypes::AutomatedTesting => TESTING_INITIAL_GRAPH_WEIGHT,
ChainTypes::UserTesting => TESTING_INITIAL_GRAPH_WEIGHT, ChainTypes::UserTesting => TESTING_INITIAL_GRAPH_WEIGHT,
ChainTypes::Testnet1 => TESTING_INITIAL_GRAPH_WEIGHT, ChainTypes::Floonet => graph_weight(0, SECOND_POW_EDGE_BITS) as u32,
ChainTypes::Testnet2 => TESTING_INITIAL_GRAPH_WEIGHT,
ChainTypes::Testnet3 => TESTING_INITIAL_GRAPH_WEIGHT,
ChainTypes::Testnet4 => graph_weight(0, SECOND_POW_EDGE_BITS) as u32,
ChainTypes::Mainnet => graph_weight(0, SECOND_POW_EDGE_BITS) as u32, ChainTypes::Mainnet => graph_weight(0, SECOND_POW_EDGE_BITS) as u32,
} }
} }
@ -288,20 +256,14 @@ pub fn is_user_testing_mode() -> bool {
/// Production defined as a live public network, testnet[n] or mainnet. /// Production defined as a live public network, testnet[n] or mainnet.
pub fn is_production_mode() -> bool { pub fn is_production_mode() -> bool {
let param_ref = CHAIN_TYPE.read(); let param_ref = CHAIN_TYPE.read();
ChainTypes::Testnet1 == *param_ref ChainTypes::Floonet == *param_ref
|| ChainTypes::Testnet2 == *param_ref
|| ChainTypes::Testnet3 == *param_ref
|| ChainTypes::Testnet4 == *param_ref
|| ChainTypes::Mainnet == *param_ref || ChainTypes::Mainnet == *param_ref
} }
/// Are we in one of our (many) testnets? /// Are we in one of our (many) testnets?
pub fn is_testnet() -> bool { pub fn is_testnet() -> bool {
let param_ref = CHAIN_TYPE.read(); let param_ref = CHAIN_TYPE.read();
ChainTypes::Testnet1 == *param_ref ChainTypes::Floonet == *param_ref
|| ChainTypes::Testnet2 == *param_ref
|| ChainTypes::Testnet3 == *param_ref
|| ChainTypes::Testnet4 == *param_ref
} }
/// Helper function to get a nonce known to create a valid POW on /// Helper function to get a nonce known to create a valid POW on
@ -315,8 +277,10 @@ pub fn get_genesis_nonce() -> u64 {
ChainTypes::AutomatedTesting => 0, ChainTypes::AutomatedTesting => 0,
// Magic nonce for current genesis block at cuckatoo15 // Magic nonce for current genesis block at cuckatoo15
ChainTypes::UserTesting => 27944, ChainTypes::UserTesting => 27944,
// Magic nonce for genesis block for testnet2 (cuckatoo29) // Placeholder, obviously not the right value
_ => panic!("Pre-set"), ChainTypes::Floonet => 0,
// Placeholder, obviously not the right value
ChainTypes::Mainnet => 0,
} }
} }

View file

@ -241,34 +241,35 @@ pub fn verify_partial_sig(
/// let commit = keychain.commit(value, &key_id).unwrap(); /// let commit = keychain.commit(value, &key_id).unwrap();
/// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap(); /// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap();
/// let output = Output { /// let output = Output {
/// features: OutputFeatures::COINBASE_OUTPUT, /// features: OutputFeatures::COINBASE,
/// commit: commit, /// commit: commit,
/// proof: rproof, /// proof: rproof,
/// }; /// };
/// let height = 20; /// let height = 20;
/// let over_commit = secp.commit_value(reward(fees)).unwrap(); /// let over_commit = secp.commit_value(reward(fees)).unwrap();
/// let out_commit = output.commitment(); /// let out_commit = output.commitment();
/// let msg = kernel_sig_msg(0, height, KernelFeatures::DEFAULT_KERNEL).unwrap(); /// let msg = kernel_sig_msg(0, height, KernelFeatures::HEIGHT_LOCKED).unwrap();
/// let excess = secp.commit_sum(vec![out_commit], vec![over_commit]).unwrap(); /// let excess = secp.commit_sum(vec![out_commit], vec![over_commit]).unwrap();
/// let pubkey = excess.to_pubkey(&secp).unwrap(); /// let pubkey = excess.to_pubkey(&secp).unwrap();
/// let sig = aggsig::sign_from_key_id(&secp, &keychain, &msg, &key_id, Some(&pubkey)).unwrap(); /// let sig = aggsig::sign_from_key_id(&secp, &keychain, &msg, value, &key_id, Some(&pubkey)).unwrap();
/// ``` /// ```
pub fn sign_from_key_id<K>( pub fn sign_from_key_id<K>(
secp: &Secp256k1, secp: &Secp256k1,
k: &K, k: &K,
msg: &Message, msg: &Message,
value: u64,
key_id: &Identifier, key_id: &Identifier,
blind_sum: Option<&PublicKey>, blind_sum: Option<&PublicKey>,
) -> Result<Signature, Error> ) -> Result<Signature, Error>
where where
K: Keychain, K: Keychain,
{ {
let skey = k.derive_key(key_id)?; let skey = k.derive_key(value, key_id)?;
let sig = aggsig::sign_single( let sig = aggsig::sign_single(
secp, secp,
&msg, &msg,
&skey.secret_key, &skey,
None, None,
None, None,
None, None,
@ -314,17 +315,17 @@ where
/// let commit = keychain.commit(value, &key_id).unwrap(); /// let commit = keychain.commit(value, &key_id).unwrap();
/// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap(); /// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap();
/// let output = Output { /// let output = Output {
/// features: OutputFeatures::COINBASE_OUTPUT, /// features: OutputFeatures::COINBASE,
/// commit: commit, /// commit: commit,
/// proof: rproof, /// proof: rproof,
/// }; /// };
/// let height = 20; /// let height = 20;
/// let over_commit = secp.commit_value(reward(fees)).unwrap(); /// let over_commit = secp.commit_value(reward(fees)).unwrap();
/// let out_commit = output.commitment(); /// let out_commit = output.commitment();
/// let msg = kernel_sig_msg(0, height, KernelFeatures::DEFAULT_KERNEL).unwrap(); /// let msg = kernel_sig_msg(0, height, KernelFeatures::HEIGHT_LOCKED).unwrap();
/// let excess = secp.commit_sum(vec![out_commit], vec![over_commit]).unwrap(); /// let excess = secp.commit_sum(vec![out_commit], vec![over_commit]).unwrap();
/// let pubkey = excess.to_pubkey(&secp).unwrap(); /// let pubkey = excess.to_pubkey(&secp).unwrap();
/// let sig = aggsig::sign_from_key_id(&secp, &keychain, &msg, &key_id, Some(&pubkey)).unwrap(); /// let sig = aggsig::sign_from_key_id(&secp, &keychain, &msg, value, &key_id, Some(&pubkey)).unwrap();
/// ///
/// // Verify the signature from the excess commit /// // Verify the signature from the excess commit
/// let sig_verifies = /// let sig_verifies =

View file

@ -54,7 +54,7 @@ where
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) { move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
let commit = build.keychain.commit(value, &key_id).unwrap(); let commit = build.keychain.commit(value, &key_id).unwrap();
let input = Input::new(features, commit); let input = Input::new(features, commit);
(tx.with_input(input), kern, sum.sub_key_id(key_id.to_path())) (tx.with_input(input), kern, sum.sub_key_id(key_id.to_value_path(value)))
}, },
) )
} }
@ -69,7 +69,7 @@ where
"Building input (spending regular output): {}, {}", "Building input (spending regular output): {}, {}",
value, key_id value, key_id
); );
build_input(value, OutputFeatures::DEFAULT_OUTPUT, key_id) build_input(value, OutputFeatures::PLAIN, key_id)
} }
/// Adds a coinbase input spending a coinbase output. /// Adds a coinbase input spending a coinbase output.
@ -78,7 +78,7 @@ where
K: Keychain, K: Keychain,
{ {
debug!("Building input (spending coinbase): {}, {}", value, key_id); debug!("Building input (spending coinbase): {}, {}", value, key_id);
build_input(value, OutputFeatures::COINBASE_OUTPUT, key_id) build_input(value, OutputFeatures::COINBASE, key_id)
} }
/// Adds an output with the provided value and key identifier from the /// Adds an output with the provided value and key identifier from the
@ -97,12 +97,12 @@ where
( (
tx.with_output(Output { tx.with_output(Output {
features: OutputFeatures::DEFAULT_OUTPUT, features: OutputFeatures::PLAIN,
commit: commit, commit: commit,
proof: rproof, proof: rproof,
}), }),
kern, kern,
sum.add_key_id(key_id.to_path()), sum.add_key_id(key_id.to_value_path(value)),
) )
}, },
) )

View file

@ -26,7 +26,7 @@ where
K: Keychain, K: Keychain,
{ {
// hash(commit|wallet root secret key (m)) as nonce // hash(commit|wallet root secret key (m)) as nonce
let root_key = k.derive_key(&K::root_key_id())?.secret_key; let root_key = k.derive_key(0, &K::root_key_id())?;
let res = blake2::blake2b::blake2b(32, &commit.0, &root_key.0[..]); let res = blake2::blake2b::blake2b(32, &commit.0, &root_key.0[..]);
let res = res.as_bytes(); let res = res.as_bytes();
let mut ret_val = [0; 32]; let mut ret_val = [0; 32];
@ -53,11 +53,11 @@ where
K: Keychain, K: Keychain,
{ {
let commit = k.commit(amount, key_id)?; let commit = k.commit(amount, key_id)?;
let skey = k.derive_key(key_id)?; let skey = k.derive_key(amount, key_id)?;
let nonce = create_nonce(k, &commit)?; let nonce = create_nonce(k, &commit)?;
let message = ProofMessage::from_bytes(&key_id.serialize_path()); let message = ProofMessage::from_bytes(&key_id.serialize_path());
Ok(k.secp() Ok(k.secp()
.bullet_proof(amount, skey.secret_key, nonce, extra_data, Some(message))) .bullet_proof(amount, skey, nonce, extra_data, Some(message)))
} }
/// Verify a proof /// Verify a proof

View file

@ -27,7 +27,6 @@ pub fn output<K>(
keychain: &K, keychain: &K,
key_id: &Identifier, key_id: &Identifier,
fees: u64, fees: u64,
height: u64,
) -> Result<(Output, TxKernel), Error> ) -> Result<(Output, TxKernel), Error>
where where
K: Keychain, K: Keychain,
@ -40,7 +39,7 @@ where
let rproof = proof::create(keychain, value, key_id, commit, None)?; let rproof = proof::create(keychain, value, key_id, commit, None)?;
let output = Output { let output = Output {
features: OutputFeatures::COINBASE_OUTPUT, features: OutputFeatures::COINBASE,
commit: commit, commit: commit,
proof: rproof, proof: rproof,
}; };
@ -53,22 +52,18 @@ where
let pubkey = excess.to_pubkey(&secp)?; let pubkey = excess.to_pubkey(&secp)?;
// NOTE: Remember we sign the fee *and* the lock_height. // NOTE: Remember we sign the fee *and* the lock_height.
// For a coinbase output the fee is 0 and the lock_height is // For a coinbase output the fee is 0 and the lock_height is 0
// the lock_height of the coinbase output itself, let msg = kernel_sig_msg(0, 0, KernelFeatures::COINBASE)?;
// not the lock_height of the tx (there is no tx for a coinbase output). let sig = aggsig::sign_from_key_id(&secp, keychain, &msg, value, &key_id, Some(&pubkey))?;
// This output will not be spendable earlier than lock_height (and we sign this
// here).
let msg = kernel_sig_msg(0, height, KernelFeatures::COINBASE_KERNEL)?;
let sig = aggsig::sign_from_key_id(&secp, keychain, &msg, &key_id, Some(&pubkey))?;
let proof = TxKernel { let proof = TxKernel {
features: KernelFeatures::COINBASE_KERNEL, features: KernelFeatures::COINBASE,
excess: excess, excess: excess,
excess_sig: sig, excess_sig: sig,
fee: 0, fee: 0,
// lock_height here is the height of the block (tx should be valid immediately) // lock_height here is 0
// *not* the lock_height of the coinbase output (only spendable 1,000 blocks later) // *not* the maturity of the coinbase output (only spendable 1,440 blocks later)
lock_height: height, lock_height: 0,
}; };
Ok((output, proof)) Ok((output, proof))
} }

View file

@ -16,10 +16,10 @@
//! around during an interactive wallet exchange //! around during an interactive wallet exchange
use crate::blake2::blake2b::blake2b; use crate::blake2::blake2b::blake2b;
use crate::core::committed::Committed;
use crate::core::transaction::{kernel_sig_msg, KernelFeatures, Transaction};
use crate::core::verifier_cache::LruVerifierCache;
use crate::core::amount_to_hr_string; use crate::core::amount_to_hr_string;
use crate::core::committed::Committed;
use crate::core::transaction::{kernel_features, kernel_sig_msg, Transaction};
use crate::core::verifier_cache::LruVerifierCache;
use crate::keychain::{BlindSum, BlindingFactor, Keychain}; use crate::keychain::{BlindSum, BlindingFactor, Keychain};
use crate::libtx::error::{Error, ErrorKind}; use crate::libtx::error::{Error, ErrorKind};
use crate::libtx::{aggsig, build, tx_fee}; use crate::libtx::{aggsig, build, tx_fee};
@ -160,8 +160,7 @@ impl Slate {
// Currently includes the fee and the lock_height. // Currently includes the fee and the lock_height.
fn msg_to_sign(&self) -> Result<secp::Message, Error> { fn msg_to_sign(&self) -> Result<secp::Message, Error> {
// Currently we only support interactively creating a tx with a "default" kernel. // Currently we only support interactively creating a tx with a "default" kernel.
let features = KernelFeatures::DEFAULT_KERNEL; let features = kernel_features(self.lock_height);
let msg = kernel_sig_msg(self.fee, self.lock_height, features)?; let msg = kernel_sig_msg(self.fee, self.lock_height, features)?;
Ok(msg) Ok(msg)
} }

View file

@ -69,7 +69,7 @@ pub fn verify_size(bh: &BlockHeader) -> Result<(), Error> {
/// Mines a genesis block using the internal miner /// Mines a genesis block using the internal miner
pub fn mine_genesis_block() -> Result<Block, Error> { pub fn mine_genesis_block() -> Result<Block, Error> {
let mut gen = genesis::genesis_testnet2(); let mut gen = genesis::genesis_dev();
if global::is_user_testing_mode() || global::is_automated_testing_mode() { if global::is_user_testing_mode() || global::is_automated_testing_mode() {
gen = genesis::genesis_dev(); gen = genesis::genesis_dev();
gen.header.timestamp = Utc::now(); gen.header.timestamp = Utc::now();

View file

@ -131,7 +131,7 @@ fn empty_block_with_coinbase_is_valid() {
let coinbase_outputs = b let coinbase_outputs = b
.outputs() .outputs()
.iter() .iter()
.filter(|out| out.features.contains(OutputFeatures::COINBASE_OUTPUT)) .filter(|out| out.is_coinbase())
.map(|o| o.clone()) .map(|o| o.clone())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!(coinbase_outputs.len(), 1); assert_eq!(coinbase_outputs.len(), 1);
@ -139,7 +139,7 @@ fn empty_block_with_coinbase_is_valid() {
let coinbase_kernels = b let coinbase_kernels = b
.kernels() .kernels()
.iter() .iter()
.filter(|out| out.features.contains(KernelFeatures::COINBASE_KERNEL)) .filter(|out| out.is_coinbase())
.map(|o| o.clone()) .map(|o| o.clone())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!(coinbase_kernels.len(), 1); assert_eq!(coinbase_kernels.len(), 1);
@ -152,7 +152,7 @@ fn empty_block_with_coinbase_is_valid() {
} }
#[test] #[test]
// test that flipping the COINBASE_OUTPUT flag on the output features // test that flipping the COINBASE flag on the output features
// invalidates the block and specifically it causes verify_coinbase to fail // invalidates the block and specifically it causes verify_coinbase to fail
// additionally verifying the merkle_inputs_outputs also fails // additionally verifying the merkle_inputs_outputs also fails
fn remove_coinbase_output_flag() { fn remove_coinbase_output_flag() {
@ -161,12 +161,8 @@ fn remove_coinbase_output_flag() {
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let mut b = new_block(vec![], &keychain, &prev, &key_id); let mut b = new_block(vec![], &keychain, &prev, &key_id);
assert!(b.outputs()[0] assert!(b.outputs()[0].is_coinbase());
.features b.outputs_mut()[0].features = OutputFeatures::PLAIN;
.contains(OutputFeatures::COINBASE_OUTPUT));
b.outputs_mut()[0]
.features
.remove(OutputFeatures::COINBASE_OUTPUT);
assert_eq!(b.verify_coinbase(), Err(Error::CoinbaseSumMismatch)); assert_eq!(b.verify_coinbase(), Err(Error::CoinbaseSumMismatch));
assert!(b assert!(b
@ -179,7 +175,7 @@ fn remove_coinbase_output_flag() {
} }
#[test] #[test]
// test that flipping the COINBASE_KERNEL flag on the kernel features // test that flipping the COINBASE flag on the kernel features
// invalidates the block and specifically it causes verify_coinbase to fail // invalidates the block and specifically it causes verify_coinbase to fail
fn remove_coinbase_kernel_flag() { fn remove_coinbase_kernel_flag() {
let keychain = ExtKeychain::from_random_seed().unwrap(); let keychain = ExtKeychain::from_random_seed().unwrap();
@ -187,12 +183,8 @@ fn remove_coinbase_kernel_flag() {
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let mut b = new_block(vec![], &keychain, &prev, &key_id); let mut b = new_block(vec![], &keychain, &prev, &key_id);
assert!(b.kernels()[0] assert!(b.kernels()[0].is_coinbase());
.features b.kernels_mut()[0].features = KernelFeatures::PLAIN;
.contains(KernelFeatures::COINBASE_KERNEL));
b.kernels_mut()[0]
.features
.remove(KernelFeatures::COINBASE_KERNEL);
// Flipping the coinbase flag results in kernels not summing correctly. // Flipping the coinbase flag results in kernels not summing correctly.
assert_eq!( assert_eq!(
@ -380,7 +372,7 @@ fn convert_block_to_compact_block() {
cb.kern_ids()[0], cb.kern_ids()[0],
b.kernels() b.kernels()
.iter() .iter()
.find(|x| !x.features.contains(KernelFeatures::COINBASE_KERNEL)) .find(|x| !x.is_coinbase())
.unwrap() .unwrap()
.short_id(&cb.hash(), cb.nonce) .short_id(&cb.hash(), cb.nonce)
); );

View file

@ -92,7 +92,7 @@ where
K: Keychain, K: Keychain,
{ {
let fees = txs.iter().map(|tx| tx.fee()).sum(); let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward_output = reward::output(keychain, &key_id, fees, previous_header.height).unwrap(); let reward_output = reward::output(keychain, &key_id, fees).unwrap();
Block::new( Block::new(
&previous_header, &previous_header,
txs.into_iter().cloned().collect(), txs.into_iter().cloned().collect(),

View file

@ -206,18 +206,6 @@ fn add_block(
ret_chain_sim ret_chain_sim
} }
// Adds many defined blocks
fn add_blocks(
intervals: Vec<u64>,
chain_sim: Vec<(HeaderInfo, DiffStats)>,
) -> Vec<(HeaderInfo, DiffStats)> {
let mut return_chain = chain_sim.clone();
for i in intervals {
return_chain = add_block(i, return_chain.clone());
}
return_chain
}
// Adds another n 'blocks' to the iterator, with difficulty calculated // Adds another n 'blocks' to the iterator, with difficulty calculated
fn add_block_repeated( fn add_block_repeated(
interval: u64, interval: u64,
@ -355,25 +343,6 @@ fn adjustment_scenarios() {
print_chain_sim(chain_sim); print_chain_sim(chain_sim);
println!("*********************************************************"); println!("*********************************************************");
// Actual testnet 2 timings
let testnet2_intervals = [
2880, 16701, 1882, 3466, 614, 605, 1551, 538, 931, 23, 690, 1397, 2112, 2058, 605, 721,
2148, 1605, 134, 1234, 1569, 482, 1775, 2732, 540, 958, 883, 3475, 518, 1346, 1926, 780,
865, 269, 1079, 141, 105, 781, 289, 256, 709, 68, 165, 1813, 3899, 1458, 955, 2336, 239,
674, 1059, 157, 214, 15, 157, 558, 1945, 1677, 1825, 1307, 1973, 660, 77, 3134, 410, 347,
537, 649, 325, 370, 2271, 106, 19, 329,
];
global::set_mining_mode(global::ChainTypes::Testnet2);
let chain_sim = create_chain_sim(global::initial_block_difficulty());
let chain_sim = add_blocks(testnet2_intervals.to_vec(), chain_sim);
println!("");
println!("*********************************************************");
println!("Scenario 6) Testnet2");
println!("*********************************************************");
print_chain_sim(chain_sim);
println!("*********************************************************");
} }
/// Checks different next_target adjustments and difficulty boundaries /// Checks different next_target adjustments and difficulty boundaries
@ -526,7 +495,7 @@ fn test_secondary_pow_ratio() {
// Tests for testnet4 chain type (covers pre and post hardfork). // Tests for testnet4 chain type (covers pre and post hardfork).
{ {
global::set_mining_mode(global::ChainTypes::Testnet4); global::set_mining_mode(global::ChainTypes::Floonet);
assert_eq!(global::is_testnet(), true); assert_eq!(global::is_testnet(), true);
assert_eq!(secondary_pow_ratio(1), 90); assert_eq!(secondary_pow_ratio(1), 90);
@ -539,16 +508,16 @@ fn test_secondary_pow_ratio() {
let one_week = 60 * 24 * 7; let one_week = 60 * 24 * 7;
assert_eq!(secondary_pow_ratio(one_week - 1), 90); assert_eq!(secondary_pow_ratio(one_week - 1), 90);
assert_eq!(secondary_pow_ratio(one_week), 89); assert_eq!(secondary_pow_ratio(one_week), 90);
assert_eq!(secondary_pow_ratio(one_week + 1), 89); assert_eq!(secondary_pow_ratio(one_week + 1), 90);
let two_weeks = one_week * 2; let two_weeks = one_week * 2;
assert_eq!(secondary_pow_ratio(two_weeks - 1), 89); assert_eq!(secondary_pow_ratio(two_weeks - 1), 89);
assert_eq!(secondary_pow_ratio(two_weeks), 88); assert_eq!(secondary_pow_ratio(two_weeks), 89);
assert_eq!(secondary_pow_ratio(two_weeks + 1), 88); assert_eq!(secondary_pow_ratio(two_weeks + 1), 89);
let t4_fork_height = 64_000; let t4_fork_height = 64_000;
assert_eq!(secondary_pow_ratio(t4_fork_height - 1), 84); assert_eq!(secondary_pow_ratio(t4_fork_height - 1), 85);
assert_eq!(secondary_pow_ratio(t4_fork_height), 85); assert_eq!(secondary_pow_ratio(t4_fork_height), 85);
assert_eq!(secondary_pow_ratio(t4_fork_height + 1), 85); assert_eq!(secondary_pow_ratio(t4_fork_height + 1), 85);
@ -572,9 +541,9 @@ fn test_secondary_pow_scale() {
let window = DIFFICULTY_ADJUST_WINDOW; let window = DIFFICULTY_ADJUST_WINDOW;
let mut hi = HeaderInfo::from_diff_scaling(Difficulty::from_num(10), 100); let mut hi = HeaderInfo::from_diff_scaling(Difficulty::from_num(10), 100);
// testnet4 testing // floonet testing
{ {
global::set_mining_mode(global::ChainTypes::Testnet4); global::set_mining_mode(global::ChainTypes::Floonet);
assert_eq!(global::is_testnet(), true); assert_eq!(global::is_testnet(), true);
// all primary, factor should increase so it becomes easier to find a high // all primary, factor should increase so it becomes easier to find a high
@ -582,13 +551,13 @@ fn test_secondary_pow_scale() {
hi.is_secondary = false; hi.is_secondary = false;
assert_eq!( assert_eq!(
secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect::<Vec<_>>()), secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect::<Vec<_>>()),
147 106
); );
// all secondary on 90%, factor should go down a bit // all secondary on 90%, factor should go down a bit
hi.is_secondary = true; hi.is_secondary = true;
assert_eq!( assert_eq!(
secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect::<Vec<_>>()), secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect::<Vec<_>>()),
94 97
); );
// all secondary on 1%, factor should go down to bound (divide by 2) // all secondary on 1%, factor should go down to bound (divide by 2)
assert_eq!( assert_eq!(
@ -631,7 +600,7 @@ fn test_secondary_pow_scale() {
.chain((0..(window * 95 / 100)).map(|_| hi.clone())) .chain((0..(window * 95 / 100)).map(|_| hi.clone()))
.collect::<Vec<_>>() .collect::<Vec<_>>()
), ),
94 96
); );
// 40% secondary, should come up based on 70 average // 40% secondary, should come up based on 70 average
assert_eq!( assert_eq!(
@ -642,7 +611,7 @@ fn test_secondary_pow_scale() {
.chain((0..(window * 4 / 10)).map(|_| hi.clone())) .chain((0..(window * 4 / 10)).map(|_| hi.clone()))
.collect::<Vec<_>>() .collect::<Vec<_>>()
), ),
84 72
); );
} }

View file

@ -75,7 +75,8 @@ fn tx_double_ser_deser() {
#[test] #[test]
#[should_panic(expected = "Keychain Error")] #[should_panic(expected = "Keychain Error")]
fn test_zero_commit_fails() { fn test_zero_commit_fails() {
let keychain = ExtKeychain::from_random_seed().unwrap(); let mut keychain = ExtKeychain::from_random_seed().unwrap();
keychain.set_use_switch_commits(false);
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
// blinding should fail as signing with a zero r*G shouldn't work // blinding should fail as signing with a zero r*G shouldn't work
@ -121,7 +122,7 @@ fn build_tx_kernel() {
let kern = &tx.kernels()[0]; let kern = &tx.kernels()[0];
kern.verify().unwrap(); kern.verify().unwrap();
assert_eq!(kern.features, KernelFeatures::DEFAULT_KERNEL); assert_eq!(kern.features, KernelFeatures::PLAIN);
assert_eq!(kern.fee, tx.fee()); assert_eq!(kern.fee, tx.fee());
} }

View file

@ -31,7 +31,7 @@ fn test_output_ser_deser() {
let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap(); let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap();
let out = Output { let out = Output {
features: OutputFeatures::DEFAULT_OUTPUT, features: OutputFeatures::PLAIN,
commit: commit, commit: commit,
proof: proof, proof: proof,
}; };
@ -40,7 +40,7 @@ fn test_output_ser_deser() {
ser::serialize(&mut vec, &out).expect("serialized failed"); ser::serialize(&mut vec, &out).expect("serialized failed");
let dout: Output = ser::deserialize(&mut &vec[..]).unwrap(); let dout: Output = ser::deserialize(&mut &vec[..]).unwrap();
assert_eq!(dout.features, OutputFeatures::DEFAULT_OUTPUT); assert_eq!(dout.features, OutputFeatures::PLAIN);
assert_eq!(dout.commit, out.commit); assert_eq!(dout.commit, out.commit);
assert_eq!(dout.proof, out.proof); assert_eq!(dout.proof, out.proof);
} }

View file

@ -38,7 +38,7 @@ fn test_verifier_cache_rangeproofs() {
let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap(); let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap();
let out = Output { let out = Output {
features: OutputFeatures::DEFAULT_OUTPUT, features: OutputFeatures::PLAIN,
commit: commit, commit: commit,
proof: proof, proof: proof,
}; };

36
etc/gen_gen/Cargo.toml Normal file
View file

@ -0,0 +1,36 @@
[package]
name = "grin_gen_gen"
version = "0.0.1"
edition = "2018"
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
description = "Utility to automate the generation of Grin's genesis block"
license = "Apache-2.0"
repository = "https://github.com/mimblewimble/grin"
keywords = [ "crypto", "grin", "mimblewimble" ]
readme = "README.md"
[[bin]]
name = "gen_gen"
path = "src/bin/gen_gen.rs"
[dependencies]
chrono = "0.4.4"
cuckoo_miner = "0.4.2"
curl = "0.4.19"
grin_core = { path = "../../core" }
grin_chain = { path = "../../chain" }
grin_keychain = { path = "../../keychain" }
grin_miner_plugin = "0.4.2"
grin_store = { path = "../../store" }
grin_util = { path = "../../util" }
grin_wallet = { path = "../../wallet" }
rpassword = "2.0.0"
serde_json = "1"
[patch.crates-io]
grin_api = { path = "../../api" }
grin_core = { path = "../../core" }
grin_chain = { path = "../../chain" }
grin_keychain = { path = "../../keychain" }
grin_util = { path = "../../util" }
grin_wallet = { path = "../../wallet" }

18
etc/gen_gen/README.md Normal file
View file

@ -0,0 +1,18 @@
# Genesis Genesis
This crate isn't strictly part of grin but allows the generation and release of a new Grin Genesis in an automated fashion. The process is the following:
* Prepare a multisig output and kernel to use as coinbase. In the case of Grin mainnet, this is done and owned by the council treasurers. This can be down a few days prior.
* Grab the latest bitcoin block hash from publicly available APIs.
* Build a genesis block with the prepared coinbase and the bitcoin block hash as `prev_root`. The timestamp of the block is set to 30 min ahead to leave enough time to run a build and start a node.
* Mine the block so we have at least a valid Cuckatoo Cycle. We don't require a given difficulty for that solution.
* Finalize the block with the proof-of-work, setting a high-enough difficulty (to be agreed upon separately).
* Commit the block information to github.
* Tag version 1.0.0 (scary).
N.B. This was written while listening to Genesis. Unfortunately, I'm not rich enough to do it while driving a Genesis. And that'd be dangerous.
# Usage
1. Build this crate.
2. From its root run `./target/release/gen-gen --coinbase <file> --difficulty <u64> --tag <version>`

View file

@ -0,0 +1,339 @@
// Copyright 2018 The Grin Developers
//
// 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.
//! Main for building the genesis generation utility.
use std::io::{BufRead, Write};
use std::sync::Arc;
use std::{fs, io, path, process};
use chrono::prelude::Utc;
use chrono::{Datelike, Duration, Timelike};
use curl;
use rpassword;
use serde_json;
use cuckoo_miner as cuckoo;
use grin_chain as chain;
use grin_core as core;
use grin_miner_plugin as plugin;
use grin_store as store;
use grin_util as util;
use grin_wallet as wallet;
use grin_core::core::hash::Hashed;
use grin_core::core::verifier_cache::LruVerifierCache;
use grin_keychain::{BlindingFactor, ExtKeychain, Keychain};
static BCHAIN_INFO_URL: &str = "https://blockchain.info/latestblock";
static BCYPHER_URL: &str = "https://api.blockcypher.com/v1/btc/main";
static BCHAIR_URL: &str = "https://api.blockchair.com/bitcoin/blocks?limit=2";
static GENESIS_RS_PATH: &str = "../../core/src/genesis.rs";
static PLUGIN_PATH: &str = "./cuckaroo_mean_cuda_29.cuckooplugin";
static WALLET_SEED_PATH: &str = "./wallet.seed";
fn main() {
if !path::Path::new(GENESIS_RS_PATH).exists() {
panic!(
"File {} not found, make sure you're running this from the gen_gen directory",
GENESIS_RS_PATH
);
}
if !path::Path::new(PLUGIN_PATH).exists() {
panic!(
"File {} not found, make sure you're running this from the gen_gen directory",
PLUGIN_PATH
);
}
if !path::Path::new(WALLET_SEED_PATH).exists() {
panic!(
"File {} not found, make sure you're running this from the gen_gen directory",
WALLET_SEED_PATH
);
}
// get the latest bitcoin hash
let h1 = get_bchain_head();
let h2 = get_bcypher_head();
let h3 = get_bchair_head();
if h1 != h2 || h1 != h3 {
panic!(
"Bitcoin chain head is inconsistent, please retry ({}, {}, {}).",
h1, h2, h3
);
}
println!("Using bitcoin block hash {}", h1);
// build the basic parts of the genesis block header
let mut gen = core::genesis::genesis_main();
gen.header.timestamp = Utc::now() + Duration::minutes(30);
gen.header.prev_root = core::core::hash::Hash::from_hex(&h1).unwrap();
// build the wallet seed and derive a coinbase from local wallet.seed
let seed = wallet::WalletSeed::from_file(
&wallet::WalletConfig::default(),
&rpassword::prompt_password_stdout("Password: ").unwrap()
).unwrap();
let keychain: ExtKeychain = seed.derive_keychain().unwrap();
let key_id = ExtKeychain::derive_key_id(2, 1, 0, 0, 0);
let reward = core::libtx::reward::output(&keychain, &key_id, 0).unwrap();
gen = gen.with_reward(reward.0, reward.1);
{
// setup a tmp chain to set block header roots
core::global::set_mining_mode(core::global::ChainTypes::AutomatedTesting);
let tmp_chain = setup_chain(".grin.tmp", core::pow::mine_genesis_block().unwrap());
tmp_chain.set_txhashset_roots(&mut gen).unwrap();
}
// mine a Cuckaroo29 block
core::global::set_mining_mode(core::global::ChainTypes::Mainnet);
let plugin_lib = cuckoo::PluginLibrary::new(PLUGIN_PATH).unwrap();
let mut params = plugin_lib.get_default_params();
params.mutate_nonce = false;
let solver_ctx = plugin_lib.create_solver_ctx(&mut params);
let mut solver_sols = plugin::SolverSolutions::default();
let mut solver_stats = plugin::SolverStats::default();
let mut nonce = 0;
while solver_sols.num_sols == 0 {
solver_sols = plugin::SolverSolutions::default();
gen.header.pow.nonce = nonce;
let _ = plugin_lib.run_solver(
solver_ctx,
gen.header.pre_pow(),
nonce,
1,
&mut solver_sols,
&mut solver_stats,
);
if solver_stats.has_errored {
println!(
"Plugin {} has errored, device: {}. Reason: {}",
solver_stats.get_plugin_name(),
solver_stats.get_device_name(),
solver_stats.get_error_reason(),
);
return;
}
nonce += 1;
}
// Set the PoW solution and make sure the block is mostly valid
gen.header.pow.proof.nonces = solver_sols.sols[0].to_u64s();
assert!(gen.header.pow.is_secondary(), "Not a secondary header");
println!("Built genesis:\n{:?}", gen);
core::pow::verify_size(&gen.header).unwrap();
gen.validate(
&BlindingFactor::zero(),
Arc::new(util::RwLock::new(LruVerifierCache::new())),
)
.unwrap();
println!("\nFinal genesis cyclehash: {}", gen.hash().to_hex());
let gen_bin = core::ser::ser_vec(&gen).unwrap();
println!("Final genesis full hash: {}\n", gen_bin.hash().to_hex());
update_genesis_rs(&gen);
println!("genesis.rs has been updated, check it and run mainnet_genesis_hash test");
println!("also check bitcoin block {} hasn't been orphaned.", h1);
println!("press c+enter to proceed.");
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
if input != "c\n" {
return;
}
// Commit genesis block info in git and tag
process::Command::new("git")
.args(&["commit", "-am", "Minor: finalized genesis block"])
.status()
.expect("git commit failed");
process::Command::new("git")
.args(&["tag", "-a", "v1.0", "-m", "Mainnet release"])
.status()
.expect("git tag failed");
process::Command::new("git")
.args(&["push", "origin", "v1.0"])
.status()
.expect("git tag push failed");
println!("All done!");
}
fn update_genesis_rs(gen: &core::core::Block) {
// set the replacement patterns
let mut replacements = vec![];
replacements.push((
"timestamp".to_string(),
format!(
"Utc.ymd({}, {}, {}).and_hms({}, {}, {})",
gen.header.timestamp.date().year(),
gen.header.timestamp.date().month(),
gen.header.timestamp.date().day(),
gen.header.timestamp.time().hour(),
gen.header.timestamp.time().minute(),
gen.header.timestamp.time().second(),
),
));
replacements.push((
"prev_root".to_string(),
format!(
"Hash::from_hex(\"{}\").unwrap()",
gen.header.prev_root.to_hex()
),
));
replacements.push((
"output_root".to_string(),
format!(
"Hash::from_hex(\"{}\").unwrap()",
gen.header.output_root.to_hex()
),
));
replacements.push((
"range_proof_root".to_string(),
format!(
"Hash::from_hex(\"{}\").unwrap()",
gen.header.range_proof_root.to_hex()
),
));
replacements.push((
"kernel_root".to_string(),
format!(
"Hash::from_hex(\"{}\").unwrap()",
gen.header.kernel_root.to_hex()
),
));
replacements.push((
"total_kernel_offset".to_string(),
format!(
"BlindingFactor::from_hex(\"{}\").unwrap()",
gen.header.total_kernel_offset.to_hex()
),
));
replacements.push(("nonce".to_string(), format!("{}", gen.header.pow.nonce)));
replacements.push((
"nonces".to_string(),
format!("vec!{:?}", gen.header.pow.proof.nonces),
));
replacements.push((
"excess".to_string(),
format!(
"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
util::to_hex(gen.kernels()[0].excess.0.to_vec())
),
));
replacements.push((
"excess_sig".to_string(),
format!(
"Signature::from_raw_data(&{:?}).unwrap()",
gen.kernels()[0].excess_sig.to_raw_data().to_vec(),
),
));
replacements.push((
"commit".to_string(),
format!(
"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
util::to_hex(gen.outputs()[0].commitment().0.to_vec())
),
));
replacements.push((
"proof".to_string(),
format!("{:?}", gen.outputs()[0].proof.bytes().to_vec()),
));
// check each possible replacement in the file, remove the replacement from
// the list when found to avoid double replacements
let mut replaced = String::new();
{
let genesis_rs = fs::File::open(GENESIS_RS_PATH).unwrap();
let reader = io::BufReader::new(&genesis_rs);
for rline in reader.lines() {
let line = rline.unwrap();
let mut has_replaced = false;
if line.contains("REPLACE") {
for (pos, replacement) in replacements.iter().enumerate() {
if line.contains(&replacement.0) {
replaced.push_str(&format!("{}: {},\n", replacement.0, replacement.1));
replacements.remove(pos);
has_replaced = true;
break;
}
}
}
if !has_replaced {
replaced.push_str(&format!("{}\n", line));
}
}
}
let mut genesis_rs = fs::File::create(GENESIS_RS_PATH).unwrap();
genesis_rs.write_all(replaced.as_bytes()).unwrap();
}
fn setup_chain(dir_name: &str, genesis: core::core::Block) -> chain::Chain {
util::init_test_logger();
let _ = fs::remove_dir_all(dir_name);
let verifier_cache = Arc::new(util::RwLock::new(
core::core::verifier_cache::LruVerifierCache::new(),
));
let db_env = Arc::new(store::new_env(dir_name.to_string()));
chain::Chain::init(
dir_name.to_string(),
db_env,
Arc::new(chain::types::NoopAdapter {}),
genesis,
core::pow::verify_size,
verifier_cache,
false,
Arc::new(util::Mutex::new(util::StopState::new())),
)
.unwrap()
}
fn get_bchain_head() -> String {
get_json(BCHAIN_INFO_URL)["hash"]
.as_str()
.unwrap()
.to_string()
}
fn get_bcypher_head() -> String {
get_json(BCYPHER_URL)["hash"].as_str().unwrap().to_string()
}
fn get_bchair_head() -> String {
get_json(BCHAIR_URL)["data"][0]["hash"]
.as_str()
.unwrap()
.to_string()
}
fn get_json(url: &str) -> serde_json::Value {
let mut body = Vec::new();
let mut easy = curl::easy::Easy::new();
easy.url(url).unwrap();
{
let mut transfer = easy.transfer();
transfer
.write_function(|data| {
body.extend_from_slice(data);
Ok(data.len())
})
.unwrap();
transfer.perform().unwrap();
}
serde_json::from_slice(&body).unwrap()
}

View file

@ -29,6 +29,7 @@ use crate::util::secp::{self, Message, Secp256k1, Signature};
pub struct ExtKeychain { pub struct ExtKeychain {
secp: Secp256k1, secp: Secp256k1,
master: ExtendedPrivKey, master: ExtendedPrivKey,
use_switch_commits: bool,
} }
impl Keychain for ExtKeychain { impl Keychain for ExtKeychain {
@ -39,6 +40,7 @@ impl Keychain for ExtKeychain {
let keychain = ExtKeychain { let keychain = ExtKeychain {
secp: secp, secp: secp,
master: master, master: master,
use_switch_commits: true,
}; };
Ok(keychain) Ok(keychain)
} }
@ -49,6 +51,7 @@ impl Keychain for ExtKeychain {
let keychain = ExtKeychain { let keychain = ExtKeychain {
secp: secp, secp: secp,
master: master, master: master,
use_switch_commits: true,
}; };
Ok(keychain) Ok(keychain)
} }
@ -68,19 +71,23 @@ impl Keychain for ExtKeychain {
ExtKeychainPath::new(depth, d1, d2, d3, d4).to_identifier() ExtKeychainPath::new(depth, d1, d2, d3, d4).to_identifier()
} }
fn derive_key(&self, id: &Identifier) -> Result<ExtendedPrivKey, Error> { fn derive_key(&self, amount: u64, id: &Identifier) -> Result<SecretKey, Error> {
let mut h = BIP32GrinHasher::new(); let mut h = BIP32GrinHasher::new();
let p = id.to_path(); let p = id.to_path();
let mut sk = self.master; let mut ext_key = self.master;
for i in 0..p.depth { for i in 0..p.depth {
sk = sk.ckd_priv(&self.secp, &mut h, p.path[i as usize])?; ext_key = ext_key.ckd_priv(&self.secp, &mut h, p.path[i as usize])?;
}
match self.use_switch_commits {
true => Ok(self.secp.blind_switch(amount, ext_key.secret_key)?),
false => Ok(ext_key.secret_key),
} }
Ok(sk)
} }
fn commit(&self, amount: u64, id: &Identifier) -> Result<Commitment, Error> { fn commit(&self, amount: u64, id: &Identifier) -> Result<Commitment, Error> {
let key = self.derive_key(id)?; let key = self.derive_key(amount, id)?;
let commit = self.secp.commit(amount, key.secret_key)?; let commit = self.secp.commit(amount, key)?;
Ok(commit) Ok(commit)
} }
@ -89,9 +96,9 @@ impl Keychain for ExtKeychain {
.positive_key_ids .positive_key_ids
.iter() .iter()
.filter_map(|k| { .filter_map(|k| {
let res = self.derive_key(&Identifier::from_path(&k)); let res = self.derive_key(k.value, &Identifier::from_path(&k.ext_keychain_path));
if let Ok(s) = res { if let Ok(s) = res {
Some(s.secret_key) Some(s)
} else { } else {
None None
} }
@ -102,9 +109,9 @@ impl Keychain for ExtKeychain {
.negative_key_ids .negative_key_ids
.iter() .iter()
.filter_map(|k| { .filter_map(|k| {
let res = self.derive_key(&Identifier::from_path(&k)); let res = self.derive_key(k.value, &Identifier::from_path(&k.ext_keychain_path));
if let Ok(s) = res { if let Ok(s) = res {
Some(s.secret_key) Some(s)
} else { } else {
None None
} }
@ -131,9 +138,9 @@ impl Keychain for ExtKeychain {
Ok(BlindingFactor::from_secret_key(sum)) Ok(BlindingFactor::from_secret_key(sum))
} }
fn sign(&self, msg: &Message, id: &Identifier) -> Result<Signature, Error> { fn sign(&self, msg: &Message, amount: u64, id: &Identifier) -> Result<Signature, Error> {
let skey = self.derive_key(id)?; let skey = self.derive_key(amount, id)?;
let sig = self.secp.sign(msg, &skey.secret_key)?; let sig = self.secp.sign(msg, &skey)?;
Ok(sig) Ok(sig)
} }
@ -147,6 +154,10 @@ impl Keychain for ExtKeychain {
Ok(sig) Ok(sig)
} }
fn set_use_switch_commits(&mut self, value: bool) {
self.use_switch_commits = value;
}
fn secp(&self) -> &Secp256k1 { fn secp(&self) -> &Secp256k1 {
&self.secp &self.secp
} }
@ -175,7 +186,7 @@ mod test {
let commit = keychain.commit(0, &key_id).unwrap(); let commit = keychain.commit(0, &key_id).unwrap();
// now check we can use our key to verify a signature from this zero commitment // now check we can use our key to verify a signature from this zero commitment
let sig = keychain.sign(&msg, &key_id).unwrap(); let sig = keychain.sign(&msg, 0, &key_id).unwrap();
secp.verify_from_commit(&msg, &sig, &commit).unwrap(); secp.verify_from_commit(&msg, &sig, &commit).unwrap();
} }

View file

@ -23,7 +23,7 @@ use std::ops::Add;
use std::{error, fmt}; use std::{error, fmt};
use crate::blake2::blake2b::blake2b; use crate::blake2::blake2b::blake2b;
use crate::extkey_bip32::{self, ChildNumber, ExtendedPrivKey}; use crate::extkey_bip32::{self, ChildNumber};
use serde::{de, ser}; //TODO: Convert errors to use ErrorKind use serde::{de, ser}; //TODO: Convert errors to use ErrorKind
use crate::util; use crate::util;
@ -44,6 +44,7 @@ pub enum Error {
KeyDerivation(extkey_bip32::Error), KeyDerivation(extkey_bip32::Error),
Transaction(String), Transaction(String),
RangeProof(String), RangeProof(String),
SwitchCommitment,
} }
impl From<secp::Error> for Error { impl From<secp::Error> for Error {
@ -126,6 +127,13 @@ impl Identifier {
ExtKeychainPath::from_identifier(&self) ExtKeychainPath::from_identifier(&self)
} }
pub fn to_value_path(&self, value: u64) -> ValueExtKeychainPath {
ValueExtKeychainPath {
value,
ext_keychain_path: self.to_path(),
}
}
/// output the path itself, for insertion into bulletproof /// output the path itself, for insertion into bulletproof
/// recovery processes can grind through possiblities to find the /// recovery processes can grind through possiblities to find the
/// correct length if required /// correct length if required
@ -327,8 +335,8 @@ pub struct SplitBlindingFactor {
/// factor as well as the "sign" with which they should be combined. /// factor as well as the "sign" with which they should be combined.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct BlindSum { pub struct BlindSum {
pub positive_key_ids: Vec<ExtKeychainPath>, pub positive_key_ids: Vec<ValueExtKeychainPath>,
pub negative_key_ids: Vec<ExtKeychainPath>, pub negative_key_ids: Vec<ValueExtKeychainPath>,
pub positive_blinding_factors: Vec<BlindingFactor>, pub positive_blinding_factors: Vec<BlindingFactor>,
pub negative_blinding_factors: Vec<BlindingFactor>, pub negative_blinding_factors: Vec<BlindingFactor>,
} }
@ -344,12 +352,12 @@ impl BlindSum {
} }
} }
pub fn add_key_id(mut self, path: ExtKeychainPath) -> BlindSum { pub fn add_key_id(mut self, path: ValueExtKeychainPath) -> BlindSum {
self.positive_key_ids.push(path); self.positive_key_ids.push(path);
self self
} }
pub fn sub_key_id(mut self, path: ExtKeychainPath) -> BlindSum { pub fn sub_key_id(mut self, path: ValueExtKeychainPath) -> BlindSum {
self.negative_key_ids.push(path); self.negative_key_ids.push(path);
self self
} }
@ -430,17 +438,25 @@ impl ExtKeychainPath {
} }
} }
/// Wrapper for amount + path
#[derive(Copy, Clone, PartialEq, Eq, Debug, Deserialize)]
pub struct ValueExtKeychainPath {
pub value: u64,
pub ext_keychain_path: ExtKeychainPath,
}
pub trait Keychain: Sync + Send + Clone { pub trait Keychain: Sync + Send + Clone {
fn from_seed(seed: &[u8]) -> Result<Self, Error>; fn from_seed(seed: &[u8]) -> Result<Self, Error>;
fn from_mnemonic(word_list: &str, extension_word: &str) -> Result<Self, Error>; fn from_mnemonic(word_list: &str, extension_word: &str) -> Result<Self, Error>;
fn from_random_seed() -> Result<Self, Error>; fn from_random_seed() -> Result<Self, Error>;
fn root_key_id() -> Identifier; fn root_key_id() -> Identifier;
fn derive_key_id(depth: u8, d1: u32, d2: u32, d3: u32, d4: u32) -> Identifier; fn derive_key_id(depth: u8, d1: u32, d2: u32, d3: u32, d4: u32) -> Identifier;
fn derive_key(&self, id: &Identifier) -> Result<ExtendedPrivKey, Error>; fn derive_key(&self, amount: u64, id: &Identifier) -> Result<SecretKey, Error>;
fn commit(&self, amount: u64, id: &Identifier) -> Result<Commitment, Error>; fn commit(&self, amount: u64, id: &Identifier) -> Result<Commitment, Error>;
fn blind_sum(&self, blind_sum: &BlindSum) -> Result<BlindingFactor, Error>; fn blind_sum(&self, blind_sum: &BlindSum) -> Result<BlindingFactor, Error>;
fn sign(&self, msg: &Message, id: &Identifier) -> Result<Signature, Error>; fn sign(&self, msg: &Message, amount: u64, id: &Identifier) -> Result<Signature, Error>;
fn sign_with_blinding(&self, _: &Message, _: &BlindingFactor) -> Result<Signature, Error>; fn sign_with_blinding(&self, _: &Message, _: &BlindingFactor) -> Result<Signature, Error>;
fn set_use_switch_commits(&mut self, value: bool);
fn secp(&self) -> &Secp256k1; fn secp(&self) -> &Secp256k1;
} }

View file

@ -36,7 +36,7 @@ pub const PROTOCOL_VERSION: u32 = 1;
pub const USER_AGENT: &'static str = concat!("MW/Grin ", env!("CARGO_PKG_VERSION")); pub const USER_AGENT: &'static str = concat!("MW/Grin ", env!("CARGO_PKG_VERSION"));
/// Magic number expected in the header of every message /// Magic number expected in the header of every message
const MAGIC: [u8; 2] = [0x54, 0x34]; const MAGIC: [u8; 2] = [0x53, 0x35];
/// Max theoretical size of a block filled with outputs. /// Max theoretical size of a block filled with outputs.
const MAX_BLOCK_SIZE: u64 = const MAX_BLOCK_SIZE: u64 =

View file

@ -44,7 +44,7 @@ fn test_transaction_pool_block_building() {
let height = prev_header.height + 1; let height = prev_header.height + 1;
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0); let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
let fee = txs.iter().map(|x| x.fee()).sum(); let fee = txs.iter().map(|x| x.fee()).sum();
let reward = libtx::reward::output(&keychain, &key_id, fee, height).unwrap(); let reward = libtx::reward::output(&keychain, &key_id, fee).unwrap();
let mut block = Block::new(&prev_header, txs, Difficulty::min(), reward).unwrap(); let mut block = Block::new(&prev_header, txs, Difficulty::min(), reward).unwrap();
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from). // Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).

View file

@ -44,7 +44,7 @@ fn test_transaction_pool_block_reconciliation() {
let header = { let header = {
let height = 1; let height = 1;
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0); let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
let reward = libtx::reward::output(&keychain, &key_id, 0, height).unwrap(); let reward = libtx::reward::output(&keychain, &key_id, 0).unwrap();
let genesis = BlockHeader::default(); let genesis = BlockHeader::default();
let mut block = Block::new(&genesis, vec![], Difficulty::min(), reward).unwrap(); let mut block = Block::new(&genesis, vec![], Difficulty::min(), reward).unwrap();
@ -63,7 +63,7 @@ fn test_transaction_pool_block_reconciliation() {
let block = { let block = {
let key_id = ExtKeychain::derive_key_id(1, 2, 0, 0, 0); let key_id = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
let fees = initial_tx.fee(); let fees = initial_tx.fee();
let reward = libtx::reward::output(&keychain, &key_id, fees, 0).unwrap(); let reward = libtx::reward::output(&keychain, &key_id, fees).unwrap();
let mut block = Block::new(&header, vec![initial_tx], Difficulty::min(), reward).unwrap(); let mut block = Block::new(&header, vec![initial_tx], Difficulty::min(), reward).unwrap();
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from). // Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
@ -156,7 +156,7 @@ fn test_transaction_pool_block_reconciliation() {
let block = { let block = {
let key_id = ExtKeychain::derive_key_id(1, 3, 0, 0, 0); let key_id = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
let fees = block_txs.iter().map(|tx| tx.fee()).sum(); let fees = block_txs.iter().map(|tx| tx.fee()).sum();
let reward = libtx::reward::output(&keychain, &key_id, fees, 0).unwrap(); let reward = libtx::reward::output(&keychain, &key_id, fees).unwrap();
let mut block = Block::new(&header, block_txs, Difficulty::min(), reward).unwrap(); let mut block = Block::new(&header, block_txs, Difficulty::min(), reward).unwrap();
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from). // Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).

View file

@ -43,7 +43,7 @@ fn test_the_transaction_pool() {
let header = { let header = {
let height = 1; let height = 1;
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0); let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
let reward = libtx::reward::output(&keychain, &key_id, 0, height).unwrap(); let reward = libtx::reward::output(&keychain, &key_id, 0).unwrap();
let block = Block::new(&BlockHeader::default(), vec![], Difficulty::min(), reward).unwrap(); let block = Block::new(&BlockHeader::default(), vec![], Difficulty::min(), reward).unwrap();
chain.update_db_for_block(&block); chain.update_db_for_block(&block);

View file

@ -24,14 +24,18 @@ use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::{mpsc, Arc}; use std::sync::{mpsc, Arc};
use std::{cmp, io, str, thread, time}; use std::{cmp, io, str, thread, time};
use crate::core::global;
use crate::p2p; use crate::p2p;
use crate::p2p::ChainAdapter; use crate::p2p::ChainAdapter;
use crate::pool::DandelionConfig; use crate::pool::DandelionConfig;
use crate::util::{Mutex, StopState}; use crate::util::{Mutex, StopState};
// DNS Seeds with contact email associated // DNS Seeds with contact email associated
const DNS_SEEDS: &'static [&'static str] = &[ const MAINNET_DNS_SEEDS: &'static [&'static str] = &[
"t4.seed.grin-tech.org", // igno.peverell@protonmail.com "mainnet.seed.grin-tech.org", // igno.peverell@protonmail.com
];
const FLOONET_DNS_SEEDS: &'static [&'static str] = &[
"floonet.seed.grin-tech.org", // igno.peverell@protonmail.com
]; ];
pub fn connect_and_monitor( pub fn connect_and_monitor(
@ -331,7 +335,12 @@ fn listen_for_addrs(
pub fn dns_seeds() -> Box<dyn Fn() -> Vec<SocketAddr> + Send> { pub fn dns_seeds() -> Box<dyn Fn() -> Vec<SocketAddr> + Send> {
Box::new(|| { Box::new(|| {
let mut addresses: Vec<SocketAddr> = vec![]; let mut addresses: Vec<SocketAddr> = vec![];
for dns_seed in DNS_SEEDS { let net_seeds = if global::is_testnet() {
FLOONET_DNS_SEEDS
} else {
MAINNET_DNS_SEEDS
};
for dns_seed in net_seeds {
let temp_addresses = addresses.clone(); let temp_addresses = addresses.clone();
debug!("Retrieving seed nodes from dns {}", dns_seed); debug!("Retrieving seed nodes from dns {}", dns_seed);
match (dns_seed.to_owned(), 0).to_socket_addrs() { match (dns_seed.to_owned(), 0).to_socket_addrs() {

View file

@ -133,13 +133,10 @@ impl Server {
)); ));
let genesis = match config.chain_type { let genesis = match config.chain_type {
global::ChainTypes::Testnet1 => genesis::genesis_testnet1(),
global::ChainTypes::Testnet2 => genesis::genesis_testnet2(),
global::ChainTypes::Testnet3 => genesis::genesis_testnet3(),
global::ChainTypes::Testnet4 => genesis::genesis_testnet4(),
global::ChainTypes::AutomatedTesting => genesis::genesis_dev(), global::ChainTypes::AutomatedTesting => genesis::genesis_dev(),
global::ChainTypes::UserTesting => genesis::genesis_dev(), global::ChainTypes::UserTesting => genesis::genesis_dev(),
global::ChainTypes::Mainnet => genesis::genesis_testnet2(), //TODO: Fix, obviously global::ChainTypes::Floonet => genesis::genesis_floo(),
global::ChainTypes::Mainnet => genesis::genesis_main(),
}; };
info!("Starting server, genesis block: {}", genesis.hash()); info!("Starting server, genesis block: {}", genesis.hash());

View file

@ -173,7 +173,7 @@ fn burn_reward(block_fees: BlockFees) -> Result<(core::Output, core::TxKernel, B
let keychain = ExtKeychain::from_random_seed().unwrap(); let keychain = ExtKeychain::from_random_seed().unwrap();
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let (out, kernel) = let (out, kernel) =
crate::core::libtx::reward::output(&keychain, &key_id, block_fees.fees, block_fees.height) crate::core::libtx::reward::output(&keychain, &key_id, block_fees.fees)
.unwrap(); .unwrap();
Ok((out, kernel, block_fees)) Ok((out, kernel, block_fees))
} }

View file

@ -20,12 +20,12 @@ serde_derive = "1"
log4rs = { version = "0.8.1", features = ["rolling_file_appender", "compound_policy", "size_trigger", "fixed_window_roller"] } log4rs = { version = "0.8.1", features = ["rolling_file_appender", "compound_policy", "size_trigger", "fixed_window_roller"] }
log = "0.4" log = "0.4"
walkdir = "2" walkdir = "2"
zip = "0.4" zip = { version = "0.4", default-features = false }
parking_lot = {version = "0.6"} parking_lot = {version = "0.6"}
[dependencies.grin_secp256k1zkp] [dependencies.grin_secp256k1zkp]
#git = "https://github.com/mimblewimble/rust-secp256k1-zkp" git = "https://github.com/mimblewimble/rust-secp256k1-zkp"
#tag = "grin_integration_28" tag = "grin_integration_29"
#path = "../../rust-secp256k1-zkp" #path = "../../rust-secp256k1-zkp"
version = "0.7.1" #version = "0.7.1"
features = ["bullet-proof-sizing"] features = ["bullet-proof-sizing"]

View file

@ -177,7 +177,7 @@ pub fn txs(
core::amount_to_hr_string(t.amount_debited - t.amount_credited, true) core::amount_to_hr_string(t.amount_debited - t.amount_credited, true)
) )
}; };
let tx_data = match t.tx_hex { let tx_data = match t.stored_tx {
Some(t) => format!("{}", t), Some(t) => format!("{}", t),
None => "None".to_owned(), None => "None".to_owned(),
}; };

View file

@ -99,6 +99,7 @@ where
/// use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig}; /// use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// ///
/// let mut wallet_config = WalletConfig::default(); /// let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// ///
/// // A NodeClient must first be created to handle communication between /// // A NodeClient must first be created to handle communication between
/// // the wallet and the node. /// // the wallet and the node.
@ -148,6 +149,7 @@ where
/// # use wallet::libwallet::api::APIOwner; /// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig}; /// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default(); /// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); /// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> = /// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new( /// # Arc::new(Mutex::new(
@ -203,6 +205,7 @@ where
/// # use wallet::libwallet::api::APIOwner; /// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig}; /// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default(); /// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); /// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> = /// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new( /// # Arc::new(Mutex::new(
@ -256,6 +259,7 @@ where
/// # use wallet::libwallet::api::APIOwner; /// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig}; /// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default(); /// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); /// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> = /// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new( /// # Arc::new(Mutex::new(
@ -313,6 +317,7 @@ where
/// # use wallet::libwallet::api::APIOwner; /// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig}; /// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default(); /// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); /// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> = /// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new( /// # Arc::new(Mutex::new(
@ -389,6 +394,7 @@ where
/// # use wallet::libwallet::api::APIOwner; /// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig}; /// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default(); /// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); /// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> = /// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new( /// # Arc::new(Mutex::new(
@ -462,6 +468,7 @@ where
/// # use wallet::libwallet::api::APIOwner; /// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig}; /// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default(); /// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); /// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> = /// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new( /// # Arc::new(Mutex::new(
@ -575,6 +582,7 @@ where
/// # use wallet::libwallet::api::APIOwner; /// # use wallet::libwallet::api::APIOwner;
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig}; /// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
/// # let mut wallet_config = WalletConfig::default(); /// # let mut wallet_config = WalletConfig::default();
/// # wallet_config.data_file_dir = "test_output/doc/wallet1".to_owned();
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); /// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> = /// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
/// # Arc::new(Mutex::new( /// # Arc::new(Mutex::new(

View file

@ -102,7 +102,7 @@ where
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id); let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id);
t.tx_slate_id = Some(slate_id); t.tx_slate_id = Some(slate_id);
let filename = format!("{}.grintx", slate_id); let filename = format!("{}.grintx", slate_id);
t.tx_hex = Some(filename); t.stored_tx = Some(filename);
t.fee = Some(fee); t.fee = Some(fee);
let mut amount_debited = 0; let mut amount_debited = 0;
t.num_inputs = lock_inputs.len(); t.num_inputs = lock_inputs.len();

View file

@ -196,7 +196,7 @@ where
return Err(ErrorKind::TransactionDoesntExist(tx_id.to_string()))?; return Err(ErrorKind::TransactionDoesntExist(tx_id.to_string()))?;
} }
let tx = tx_vec[0].clone(); let tx = tx_vec[0].clone();
Ok((tx.confirmed, tx.tx_hex)) Ok((tx.confirmed, tx.stored_tx))
} }
/// Update the stored transaction (this update needs to happen when the TX is finalised) /// Update the stored transaction (this update needs to happen when the TX is finalised)

View file

@ -458,13 +458,7 @@ where
debug!("receive_coinbase: {:?}", block_fees); debug!("receive_coinbase: {:?}", block_fees);
let (out, kern) = reward::output( let (out, kern) = reward::output(wallet.keychain(), &key_id, block_fees.fees).unwrap();
wallet.keychain(),
&key_id,
block_fees.fees,
block_fees.height,
)
.unwrap();
/* .context(ErrorKind::Keychain)?; */ /* .context(ErrorKind::Keychain)?; */
Ok((out, kern, block_fees)) Ok((out, kern, block_fees))
} }

View file

@ -600,9 +600,8 @@ pub struct TxLogEntry {
pub amount_debited: u64, pub amount_debited: u64,
/// Fee /// Fee
pub fee: Option<u64>, pub fee: Option<u64>,
// TODO: rename this to 'stored_tx_file' or something for mainnet /// Location of the store transaction, (reference or resending)
/// The transaction json itself, stored for reference or resending pub stored_tx: Option<String>,
pub tx_hex: Option<String>,
} }
impl ser::Writeable for TxLogEntry { impl ser::Writeable for TxLogEntry {
@ -634,7 +633,7 @@ impl TxLogEntry {
num_inputs: 0, num_inputs: 0,
num_outputs: 0, num_outputs: 0,
fee: None, fee: None,
tx_hex: None, stored_tx: None,
} }
} }

View file

@ -26,6 +26,8 @@ use serde_json;
use failure::ResultExt; use failure::ResultExt;
use uuid::Uuid; use uuid::Uuid;
use crate::blake2::blake2b::Blake2b;
use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain}; use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain};
use crate::store::{self, option_to_not_found, to_key, to_key_u64}; use crate::store::{self, option_to_not_found, to_key, to_key_u64};
@ -35,6 +37,7 @@ use crate::libwallet::types::*;
use crate::libwallet::{internal, Error, ErrorKind}; use crate::libwallet::{internal, Error, ErrorKind};
use crate::types::{WalletConfig, WalletSeed}; use crate::types::{WalletConfig, WalletSeed};
use crate::util; use crate::util;
use crate::util::secp::constants::SECRET_KEY_SIZE;
use crate::util::secp::pedersen; use crate::util::secp::pedersen;
pub const DB_DIR: &'static str = "db"; pub const DB_DIR: &'static str = "db";
@ -62,6 +65,39 @@ pub fn wallet_db_exists(config: WalletConfig) -> bool {
db_path.exists() db_path.exists()
} }
/// Helper to derive XOR keys for storing private transaction keys in the DB
/// (blind_xor_key, nonce_xor_key)
fn private_ctx_xor_keys<K>(
keychain: &K,
slate_id: &[u8],
) -> Result<([u8; SECRET_KEY_SIZE], [u8; SECRET_KEY_SIZE]), Error>
where
K: Keychain,
{
let root_key = keychain.derive_key(0, &K::root_key_id())?;
// derive XOR values for storing secret values in DB
// h(root_key|slate_id|"blind")
let mut hasher = Blake2b::new(SECRET_KEY_SIZE);
hasher.update(&root_key.0[..]);
hasher.update(&slate_id[..]);
hasher.update(&"blind".as_bytes()[..]);
let blind_xor_key = hasher.finalize();
let mut ret_blind = [0; SECRET_KEY_SIZE];
ret_blind.copy_from_slice(&blind_xor_key.as_bytes()[0..SECRET_KEY_SIZE]);
// h(root_key|slate_id|"nonce")
let mut hasher = Blake2b::new(SECRET_KEY_SIZE);
hasher.update(&root_key.0[..]);
hasher.update(&slate_id[..]);
hasher.update(&"nonce".as_bytes()[..]);
let nonce_xor_key = hasher.finalize();
let mut ret_nonce = [0; SECRET_KEY_SIZE];
ret_nonce.copy_from_slice(&nonce_xor_key.as_bytes()[0..SECRET_KEY_SIZE]);
Ok((ret_blind, ret_nonce))
}
pub struct LMDBBackend<C, K> { pub struct LMDBBackend<C, K> {
db: store::Store, db: store::Store,
config: WalletConfig, config: WalletConfig,
@ -140,8 +176,11 @@ where
fn open_with_credentials(&mut self) -> Result<(), Error> { fn open_with_credentials(&mut self) -> Result<(), Error> {
let wallet_seed = WalletSeed::from_file(&self.config, &self.passphrase) let wallet_seed = WalletSeed::from_file(&self.config, &self.passphrase)
.context(ErrorKind::CallbackImpl("Error opening wallet"))?; .context(ErrorKind::CallbackImpl("Error opening wallet"))?;
let keychain = wallet_seed.derive_keychain(); self.keychain = Some(
self.keychain = Some(keychain.context(ErrorKind::CallbackImpl("Error deriving keychain"))?); wallet_seed
.derive_keychain()
.context(ErrorKind::CallbackImpl("Error deriving keychain"))?,
);
Ok(()) Ok(())
} }
@ -229,11 +268,19 @@ where
fn get_private_context(&mut self, slate_id: &[u8]) -> Result<Context, Error> { fn get_private_context(&mut self, slate_id: &[u8]) -> Result<Context, Error> {
let ctx_key = to_key(PRIVATE_TX_CONTEXT_PREFIX, &mut slate_id.to_vec()); let ctx_key = to_key(PRIVATE_TX_CONTEXT_PREFIX, &mut slate_id.to_vec());
option_to_not_found( let (blind_xor_key, nonce_xor_key) = private_ctx_xor_keys(self.keychain(), slate_id)?;
let mut ctx: Context = option_to_not_found(
self.db.get_ser(&ctx_key), self.db.get_ser(&ctx_key),
&format!("Slate id: {:x?}", slate_id.to_vec()), &format!("Slate id: {:x?}", slate_id.to_vec()),
) )?;
.map_err(|e| e.into())
for i in 0..SECRET_KEY_SIZE {
ctx.sec_key.0[i] = ctx.sec_key.0[i] ^ blind_xor_key[i];
ctx.sec_nonce.0[i] = ctx.sec_nonce.0[i] ^ nonce_xor_key[i];
}
Ok(ctx)
} }
fn acct_path_iter<'a>(&'a self) -> Box<dyn Iterator<Item = AcctPathMapping> + 'a> { fn acct_path_iter<'a>(&'a self) -> Box<dyn Iterator<Item = AcctPathMapping> + 'a> {
@ -259,7 +306,7 @@ where
} }
fn get_stored_tx(&self, entry: &TxLogEntry) -> Result<Option<Transaction>, Error> { fn get_stored_tx(&self, entry: &TxLogEntry) -> Result<Option<Transaction>, Error> {
let filename = match entry.tx_hex.clone() { let filename = match entry.stored_tx.clone() {
Some(f) => f, Some(f) => f,
None => return Ok(None), None => return Ok(None),
}; };
@ -498,11 +545,21 @@ where
self.save(out.clone()) self.save(out.clone())
} }
//TODO: Keys stored unencrypted in DB.. not good
// should store keys as derivation paths instead
fn save_private_context(&mut self, slate_id: &[u8], ctx: &Context) -> Result<(), Error> { fn save_private_context(&mut self, slate_id: &[u8], ctx: &Context) -> Result<(), Error> {
let ctx_key = to_key(PRIVATE_TX_CONTEXT_PREFIX, &mut slate_id.to_vec()); let ctx_key = to_key(PRIVATE_TX_CONTEXT_PREFIX, &mut slate_id.to_vec());
self.db.borrow().as_ref().unwrap().put_ser(&ctx_key, &ctx)?; let (blind_xor_key, nonce_xor_key) = private_ctx_xor_keys(self.keychain(), slate_id)?;
let mut s_ctx = ctx.clone();
for i in 0..SECRET_KEY_SIZE {
s_ctx.sec_key.0[i] = s_ctx.sec_key.0[i] ^ blind_xor_key[i];
s_ctx.sec_nonce.0[i] = s_ctx.sec_nonce.0[i] ^ nonce_xor_key[i];
}
self.db
.borrow()
.as_ref()
.unwrap()
.put_ser(&ctx_key, &s_ctx)?;
Ok(()) Ok(())
} }

View file

@ -45,8 +45,8 @@ pub use self::{testclient::LocalWalletClient, testclient::WalletProxy};
/// Get an output from the chain locally and present it back as an API output /// Get an output from the chain locally and present it back as an API output
fn get_output_local(chain: &chain::Chain, commit: &pedersen::Commitment) -> Option<api::Output> { fn get_output_local(chain: &chain::Chain, commit: &pedersen::Commitment) -> Option<api::Output> {
let outputs = [ let outputs = [
OutputIdentifier::new(OutputFeatures::DEFAULT_OUTPUT, commit), OutputIdentifier::new(OutputFeatures::PLAIN, commit),
OutputIdentifier::new(OutputFeatures::COINBASE_OUTPUT, commit), OutputIdentifier::new(OutputFeatures::COINBASE, commit),
]; ];
for x in outputs.iter() { for x in outputs.iter() {

View file

@ -50,9 +50,9 @@ pub struct WalletConfig {
pub check_node_api_http_addr: String, pub check_node_api_http_addr: String,
// The directory in which wallet files are stored // The directory in which wallet files are stored
pub data_file_dir: String, pub data_file_dir: String,
/// TLS ceritificate file /// TLS certificate file
pub tls_certificate_file: Option<String>, pub tls_certificate_file: Option<String>,
/// TLS ceritificate private key file /// TLS certificate private key file
pub tls_certificate_key: Option<String>, pub tls_certificate_key: Option<String>,
/// Whether to use the black background color scheme for command line /// Whether to use the black background color scheme for command line
/// if enabled, wallet command output color will be suitable for black background terminal /// if enabled, wallet command output color will be suitable for black background terminal
@ -62,7 +62,7 @@ pub struct WalletConfig {
impl Default for WalletConfig { impl Default for WalletConfig {
fn default() -> WalletConfig { fn default() -> WalletConfig {
WalletConfig { WalletConfig {
chain_type: Some(ChainTypes::Testnet4), chain_type: Some(ChainTypes::Floonet),
api_listen_interface: "127.0.0.1".to_string(), api_listen_interface: "127.0.0.1".to_string(),
api_listen_port: 13415, api_listen_port: 13415,
api_secret_path: Some(".api_secret".to_string()), api_secret_path: Some(".api_secret".to_string()),

View file

@ -26,7 +26,7 @@ use grin_wallet as wallet;
use rand::thread_rng; use rand::thread_rng;
fn kernel_sig_msg() -> secp::Message { fn kernel_sig_msg() -> secp::Message {
transaction::kernel_sig_msg(0, 0, transaction::KernelFeatures::DEFAULT_KERNEL).unwrap() transaction::kernel_sig_msg(0, 0, transaction::KernelFeatures::PLAIN).unwrap()
} }
#[test] #[test]
@ -38,8 +38,8 @@ fn aggsig_sender_receiver_interaction() {
// Normally this would happen during transaction building. // Normally this would happen during transaction building.
let kernel_excess = { let kernel_excess = {
let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let skey1 = sender_keychain.derive_key(&id1).unwrap().secret_key; let skey1 = sender_keychain.derive_key(0, &id1).unwrap();
let skey2 = receiver_keychain.derive_key(&id1).unwrap().secret_key; let skey2 = receiver_keychain.derive_key(0, &id1).unwrap();
let keychain = ExtKeychain::from_random_seed().unwrap(); let keychain = ExtKeychain::from_random_seed().unwrap();
let blinding_factor = keychain let blinding_factor = keychain
@ -62,7 +62,7 @@ fn aggsig_sender_receiver_interaction() {
let (sender_pub_excess, _sender_pub_nonce) = { let (sender_pub_excess, _sender_pub_nonce) = {
let keychain = sender_keychain.clone(); let keychain = sender_keychain.clone();
let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let skey = keychain.derive_key(&id1).unwrap().secret_key; let skey = keychain.derive_key(0, &id1).unwrap();
// dealing with an input here so we need to negate the blinding_factor // dealing with an input here so we need to negate the blinding_factor
// rather than use it as is // rather than use it as is
@ -85,7 +85,7 @@ fn aggsig_sender_receiver_interaction() {
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
// let blind = blind_sum.secret_key(&keychain.secp())?; // let blind = blind_sum.secret_key(&keychain.secp())?;
let blind = keychain.derive_key(&key_id).unwrap().secret_key; let blind = keychain.derive_key(0, &key_id).unwrap();
rx_cx = Context::new(&keychain.secp(), blind); rx_cx = Context::new(&keychain.secp(), blind);
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp()); let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
@ -247,8 +247,8 @@ fn aggsig_sender_receiver_interaction_offset() {
// Normally this would happen during transaction building. // Normally this would happen during transaction building.
let kernel_excess = { let kernel_excess = {
let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let skey1 = sender_keychain.derive_key(&id1).unwrap().secret_key; let skey1 = sender_keychain.derive_key(0, &id1).unwrap();
let skey2 = receiver_keychain.derive_key(&id1).unwrap().secret_key; let skey2 = receiver_keychain.derive_key(0, &id1).unwrap();
let keychain = ExtKeychain::from_random_seed().unwrap(); let keychain = ExtKeychain::from_random_seed().unwrap();
let blinding_factor = keychain let blinding_factor = keychain
@ -274,7 +274,7 @@ fn aggsig_sender_receiver_interaction_offset() {
let (sender_pub_excess, _sender_pub_nonce) = { let (sender_pub_excess, _sender_pub_nonce) = {
let keychain = sender_keychain.clone(); let keychain = sender_keychain.clone();
let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let skey = keychain.derive_key(&id1).unwrap().secret_key; let skey = keychain.derive_key(0, &id1).unwrap();
// dealing with an input here so we need to negate the blinding_factor // dealing with an input here so we need to negate the blinding_factor
// rather than use it as is // rather than use it as is
@ -301,7 +301,7 @@ fn aggsig_sender_receiver_interaction_offset() {
let keychain = receiver_keychain.clone(); let keychain = receiver_keychain.clone();
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let blind = keychain.derive_key(&key_id).unwrap().secret_key; let blind = keychain.derive_key(0, &key_id).unwrap();
rx_cx = Context::new(&keychain.secp(), blind); rx_cx = Context::new(&keychain.secp(), blind);
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp()); let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());