mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 03:21:08 +03:00
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:
commit
ecf736d78a
55 changed files with 978 additions and 453 deletions
28
Cargo.lock
generated
28
Cargo.lock
generated
|
@ -192,24 +192,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "cc"
|
||||
version = "1.0.25"
|
||||
|
@ -865,7 +847,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "grin_secp256k1zkp"
|
||||
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 = [
|
||||
"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)",
|
||||
|
@ -935,7 +917,7 @@ dependencies = [
|
|||
"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)",
|
||||
"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)",
|
||||
"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)",
|
||||
|
@ -2894,8 +2876,6 @@ name = "zip"
|
|||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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)",
|
||||
"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)",
|
||||
|
@ -2927,8 +2907,6 @@ dependencies = [
|
|||
"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 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 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"
|
||||
|
@ -2984,7 +2962,7 @@ dependencies = [
|
|||
"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 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 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"
|
||||
|
|
|
@ -13,6 +13,7 @@ edition = "2018"
|
|||
|
||||
[workspace]
|
||||
members = ["api", "chain", "config", "core", "keychain", "p2p", "servers", "store", "util", "pool", "wallet"]
|
||||
exclude = ["etc/gen_gen"]
|
||||
|
||||
[[bin]]
|
||||
name = "grin"
|
||||
|
|
|
@ -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
|
||||
// params)
|
||||
let outputs = [
|
||||
OutputIdentifier::new(OutputFeatures::DEFAULT_OUTPUT, &commit),
|
||||
OutputIdentifier::new(OutputFeatures::COINBASE_OUTPUT, &commit),
|
||||
OutputIdentifier::new(OutputFeatures::PLAIN, &commit),
|
||||
OutputIdentifier::new(OutputFeatures::COINBASE, &commit),
|
||||
];
|
||||
|
||||
for x in outputs.iter() {
|
||||
|
|
|
@ -251,10 +251,7 @@ impl OutputPrintable {
|
|||
block_header: Option<&core::BlockHeader>,
|
||||
include_proof: bool,
|
||||
) -> OutputPrintable {
|
||||
let output_type = if output
|
||||
.features
|
||||
.contains(core::transaction::OutputFeatures::COINBASE_OUTPUT)
|
||||
{
|
||||
let output_type = if output.is_coinbase() {
|
||||
OutputType::Coinbase
|
||||
} else {
|
||||
OutputType::Transaction
|
||||
|
@ -278,11 +275,7 @@ impl OutputPrintable {
|
|||
// We require the rewind() to be stable even after the PMMR is pruned and
|
||||
// compacted so we can still recreate the necessary proof.
|
||||
let mut merkle_proof = None;
|
||||
if output
|
||||
.features
|
||||
.contains(core::transaction::OutputFeatures::COINBASE_OUTPUT)
|
||||
&& !spent && block_header.is_some()
|
||||
{
|
||||
if output.is_coinbase() && !spent && block_header.is_some() {
|
||||
merkle_proof = chain.get_merkle_proof(&out_id, &block_header.unwrap()).ok()
|
||||
};
|
||||
|
||||
|
|
|
@ -1130,7 +1130,7 @@ impl Chain {
|
|||
|
||||
let (_, pos) = txhashset.is_unspent(output_ref)?;
|
||||
|
||||
let mut min = 1;
|
||||
let mut min = 0;
|
||||
let mut max = {
|
||||
let head = self.head()?;
|
||||
head.height
|
||||
|
@ -1139,6 +1139,9 @@ impl Chain {
|
|||
loop {
|
||||
let search_height = max - (max - min) / 2;
|
||||
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)?;
|
||||
if pos > h.output_mmr_size {
|
||||
min = search_height;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
use crate::core::core::hash::Hash;
|
||||
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::ser::PMMRIndexHashable;
|
||||
use crate::error::{Error, ErrorKind};
|
||||
|
@ -105,7 +105,7 @@ impl<'a> UTXOView<'a> {
|
|||
// outputs we are attempting to spend.
|
||||
let pos = inputs
|
||||
.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())
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
|
|
@ -83,7 +83,7 @@ fn data_files() {
|
|||
let prev = chain.head_header().unwrap();
|
||||
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 reward = libtx::reward::output(&keychain, &pk, 0, prev.height).unwrap();
|
||||
let reward = libtx::reward::output(&keychain, &pk, 0).unwrap();
|
||||
let mut b =
|
||||
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
|
||||
.unwrap();
|
||||
|
@ -159,7 +159,7 @@ fn _prepare_block_nosum(
|
|||
let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier();
|
||||
|
||||
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(
|
||||
prev,
|
||||
txs.into_iter().cloned().collect(),
|
||||
|
|
|
@ -70,7 +70,7 @@ fn mine_genesis_reward_chain() {
|
|||
let mut genesis = genesis::genesis_dev();
|
||||
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
|
||||
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);
|
||||
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ where
|
|||
let prev = chain.head_header().unwrap();
|
||||
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 reward = libtx::reward::output(keychain, &pk, 0, prev.height).unwrap();
|
||||
let reward = libtx::reward::output(keychain, &pk, 0).unwrap();
|
||||
let mut b =
|
||||
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
|
||||
.unwrap();
|
||||
|
@ -283,7 +283,7 @@ fn spend_in_fork_and_compact() {
|
|||
// so we can spend the coinbase later
|
||||
let b = prepare_block(&kc, &fork_head, &chain, 2);
|
||||
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();
|
||||
chain
|
||||
.process_block(b.clone(), chain::Options::SKIP_POW)
|
||||
|
@ -411,7 +411,7 @@ fn output_header_mappings() {
|
|||
let prev = chain.head_header().unwrap();
|
||||
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 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());
|
||||
let mut b =
|
||||
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 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(
|
||||
prev,
|
||||
txs.into_iter().cloned().collect(),
|
||||
|
|
|
@ -62,7 +62,7 @@ fn test_various_store_indices() {
|
|||
|
||||
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_hash = block.hash();
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
use self::chain::types::NoopAdapter;
|
||||
use self::chain::ErrorKind;
|
||||
use self::core::core::transaction;
|
||||
use self::core::core::verifier_cache::LruVerifierCache;
|
||||
use self::core::global::{self, ChainTypes};
|
||||
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 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();
|
||||
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
||||
block.header.pow.secondary_scaling = next_header_info.secondary_scaling;
|
||||
|
@ -85,9 +84,7 @@ fn test_coinbase_maturity() {
|
|||
|
||||
assert_eq!(block.outputs().len(), 1);
|
||||
let coinbase_output = block.outputs()[0];
|
||||
assert!(coinbase_output
|
||||
.features
|
||||
.contains(transaction::OutputFeatures::COINBASE_OUTPUT));
|
||||
assert!(coinbase_output.is_coinbase());
|
||||
|
||||
chain
|
||||
.process_block(block.clone(), chain::Options::MINE)
|
||||
|
@ -114,7 +111,7 @@ fn test_coinbase_maturity() {
|
|||
|
||||
let txs = vec![coinbase_txn.clone()];
|
||||
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 next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
|
||||
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
||||
|
@ -148,7 +145,7 @@ fn test_coinbase_maturity() {
|
|||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
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 next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
|
||||
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
||||
|
@ -176,7 +173,7 @@ fn test_coinbase_maturity() {
|
|||
let txs = vec![coinbase_txn];
|
||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||
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();
|
||||
|
||||
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
||||
|
|
|
@ -73,10 +73,7 @@ fn comments() -> HashMap<String, String> {
|
|||
#parameters used for mining as well as wallet output coinbase maturity. Can be:
|
||||
#AutomatedTesting - For CI builds and instant blockchain creation
|
||||
#UserTesting - For regular user testing (cuckoo 16)
|
||||
#Testnet1 - Testnet1 genesis block (cuckoo 16)
|
||||
#Testnet2 - Testnet2 genesis block (cuckoo 30)
|
||||
#Testnet3 - Testnet3 genesis block (cuckoo 30)
|
||||
#Testnet4 - Testnet4 genesis block (cuckatoo 29+)
|
||||
#Floonet - For the long term Floonet test network
|
||||
"
|
||||
.to_string(),
|
||||
);
|
||||
|
@ -403,6 +400,13 @@ fn comments() -> HashMap<String, String> {
|
|||
"dark_background_color_scheme".to_string(),
|
||||
"
|
||||
#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(),
|
||||
);
|
||||
|
|
|
@ -62,32 +62,13 @@ pub const COINBASE_MATURITY: u64 = DAY_HEIGHT;
|
|||
/// function of block height (time). Starts at 90% losing a percent
|
||||
/// approximately every week. Represented as an integer between 0 and 100.
|
||||
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))
|
||||
}
|
||||
} 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
|
||||
/// to account for pre HF behavior on testnet4.
|
||||
fn ar_scale_damp_factor(height: u64) -> u64 {
|
||||
if global::is_testnet() {
|
||||
if height < T4_CUCKAROO_HARDFORK {
|
||||
DIFFICULTY_DAMP_FACTOR
|
||||
} else {
|
||||
fn ar_scale_damp_factor(_height: u64) -> u64 {
|
||||
AR_SCALE_DAMP_FACTOR
|
||||
}
|
||||
} else {
|
||||
// Mainnet (or testing mainnet code).
|
||||
AR_SCALE_DAMP_FACTOR
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
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
|
||||
/// Cuckoo graph sizes, changing this would hard fork
|
||||
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.
|
||||
/// Note: we skip the first one, but testnet4 was incorrectly including it before
|
||||
/// the hardfork.
|
||||
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;
|
||||
}
|
||||
fn ar_count(_height: u64, diff_data: &[HeaderInfo]) -> u64 {
|
||||
100 * diff_data
|
||||
.iter()
|
||||
.skip(to_skip)
|
||||
.skip(1)
|
||||
.filter(|n| n.is_secondary)
|
||||
.count() as u64
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ use crate::core::compact_block::{CompactBlock, CompactBlockBody};
|
|||
use crate::core::hash::{Hash, Hashed, ZERO_HASH};
|
||||
use crate::core::verifier_cache::VerifierCache;
|
||||
use crate::core::{
|
||||
transaction, Commitment, Input, KernelFeatures, Output, OutputFeatures, Transaction,
|
||||
transaction, Commitment, Input, Output, Transaction,
|
||||
TransactionBody, TxKernel,
|
||||
};
|
||||
use crate::global;
|
||||
|
@ -535,8 +535,8 @@ impl Block {
|
|||
/// Consumes this block and returns a new block with the coinbase output
|
||||
/// and kernels added
|
||||
pub fn with_reward(mut self, reward_out: Output, reward_kern: TxKernel) -> Block {
|
||||
self.body.outputs.push(reward_out);
|
||||
self.body.kernels.push(reward_kern);
|
||||
self.body.outputs = vec![reward_out];
|
||||
self.body.kernels = vec![reward_kern];
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -663,14 +663,14 @@ impl Block {
|
|||
.body
|
||||
.outputs
|
||||
.iter()
|
||||
.filter(|out| out.features.contains(OutputFeatures::COINBASE_OUTPUT))
|
||||
.filter(|out| out.is_coinbase())
|
||||
.collect::<Vec<&Output>>();
|
||||
|
||||
let cb_kerns = self
|
||||
.body
|
||||
.kernels
|
||||
.iter()
|
||||
.filter(|kernel| kernel.features.contains(KernelFeatures::COINBASE_KERNEL))
|
||||
.filter(|kernel| kernel.is_coinbase())
|
||||
.collect::<Vec<&TxKernel>>();
|
||||
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@ use rand::{thread_rng, Rng};
|
|||
use crate::core::block::{Block, BlockHeader, Error};
|
||||
use crate::core::hash::Hashed;
|
||||
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};
|
||||
|
||||
/// 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
|
||||
.outputs()
|
||||
.iter()
|
||||
.filter(|x| x.features.contains(OutputFeatures::COINBASE_OUTPUT))
|
||||
.filter(|x| x.is_coinbase())
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
@ -176,7 +176,7 @@ impl From<Block> for CompactBlock {
|
|||
let mut kern_ids = vec![];
|
||||
|
||||
for k in block.kernels() {
|
||||
if k.features.contains(KernelFeatures::COINBASE_KERNEL) {
|
||||
if k.is_coinbase() {
|
||||
kern_full.push(k.clone());
|
||||
} else {
|
||||
kern_ids.push(k.short_id(&header.hash(), nonce));
|
||||
|
|
|
@ -40,10 +40,12 @@ bitflags! {
|
|||
/// Options for a kernel's structure or use
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct KernelFeatures: u8 {
|
||||
/// No flags
|
||||
const DEFAULT_KERNEL = 0b00000000;
|
||||
/// Kernel matching a coinbase output
|
||||
const COINBASE_KERNEL = 0b00000001;
|
||||
/// plain kernel has fee, but no lock_height
|
||||
const PLAIN = 0;
|
||||
/// coinbase kernel has neither fee nor lock_height (both zero)
|
||||
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 {
|
||||
/// 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.
|
||||
pub fn excess(&self) -> Commitment {
|
||||
self.excess
|
||||
|
@ -219,6 +253,10 @@ impl TxKernel {
|
|||
/// as a public key and checking the signature verifies with the fee as
|
||||
/// message.
|
||||
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 = secp.lock();
|
||||
let sig = &self.excess_sig;
|
||||
|
@ -242,7 +280,7 @@ impl TxKernel {
|
|||
/// Build an empty tx kernel with zero values.
|
||||
pub fn empty() -> TxKernel {
|
||||
TxKernel {
|
||||
features: KernelFeatures::DEFAULT_KERNEL,
|
||||
features: KernelFeatures::PLAIN,
|
||||
fee: 0,
|
||||
lock_height: 0,
|
||||
excess: Commitment::from_vec(vec![0; 33]),
|
||||
|
@ -258,6 +296,7 @@ impl TxKernel {
|
|||
/// Builds a new tx kernel with the provided lock_height.
|
||||
pub fn with_lock_height(self, lock_height: u64) -> TxKernel {
|
||||
TxKernel {
|
||||
features: kernel_features(lock_height),
|
||||
lock_height,
|
||||
..self
|
||||
}
|
||||
|
@ -586,25 +625,17 @@ impl TransactionBody {
|
|||
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> {
|
||||
if self
|
||||
.outputs
|
||||
.iter()
|
||||
.any(|x| x.features.contains(OutputFeatures::COINBASE_OUTPUT))
|
||||
{
|
||||
if self.outputs.iter().any(|x| x.is_coinbase()) {
|
||||
return Err(Error::InvalidOutputFeatures);
|
||||
}
|
||||
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> {
|
||||
if self
|
||||
.kernels
|
||||
.iter()
|
||||
.any(|x| x.features.contains(KernelFeatures::COINBASE_KERNEL))
|
||||
{
|
||||
if self.kernels.iter().any(|x| x.is_coinbase()) {
|
||||
return Err(Error::InvalidKernelFeatures);
|
||||
}
|
||||
Ok(())
|
||||
|
@ -1081,6 +1112,16 @@ impl Input {
|
|||
pub fn commitment(&self) -> Commitment {
|
||||
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! {
|
||||
|
@ -1088,9 +1129,9 @@ bitflags! {
|
|||
#[derive(Serialize, Deserialize)]
|
||||
pub struct OutputFeatures: u8 {
|
||||
/// No flags
|
||||
const DEFAULT_OUTPUT = 0b00000000;
|
||||
const PLAIN = 0;
|
||||
/// 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 {
|
||||
/// Commitment for the output
|
||||
pub fn commitment(&self) -> Commitment {
|
||||
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
|
||||
pub fn proof(&self) -> RangeProof {
|
||||
self.proof
|
||||
|
@ -1291,25 +1354,43 @@ impl From<Output> for OutputIdentifier {
|
|||
/// to produce a 32 byte message to sign.
|
||||
///
|
||||
/// 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(
|
||||
fee: u64,
|
||||
lock_height: u64,
|
||||
features: KernelFeatures,
|
||||
) -> 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 mut bytes = [0; 32];
|
||||
BigEndian::write_u64(&mut bytes[16..24], fee);
|
||||
BigEndian::write_u64(&mut bytes[24..], lock_height);
|
||||
secp::Message::from_slice(&bytes)?
|
||||
} 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())?
|
||||
};
|
||||
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)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -1328,7 +1409,7 @@ mod test {
|
|||
let sig = secp::Signature::from_raw_data(&[0; 64]).unwrap();
|
||||
|
||||
let kernel = TxKernel {
|
||||
features: KernelFeatures::DEFAULT_KERNEL,
|
||||
features: KernelFeatures::PLAIN,
|
||||
lock_height: 0,
|
||||
excess: commit,
|
||||
excess_sig: sig.clone(),
|
||||
|
@ -1338,7 +1419,7 @@ mod test {
|
|||
let mut vec = vec![];
|
||||
ser::serialize(&mut vec, &kernel).expect("serialized failed");
|
||||
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.excess, commit);
|
||||
assert_eq!(kernel2.excess_sig, sig.clone());
|
||||
|
@ -1346,7 +1427,7 @@ mod test {
|
|||
|
||||
// now check a kernel with lock_height serialize/deserialize correctly
|
||||
let kernel = TxKernel {
|
||||
features: KernelFeatures::DEFAULT_KERNEL,
|
||||
features: KernelFeatures::HEIGHT_LOCKED,
|
||||
lock_height: 100,
|
||||
excess: commit,
|
||||
excess_sig: sig.clone(),
|
||||
|
@ -1356,7 +1437,7 @@ mod test {
|
|||
let mut vec = vec![];
|
||||
ser::serialize(&mut vec, &kernel).expect("serialized failed");
|
||||
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.excess, commit);
|
||||
assert_eq!(kernel2.excess_sig, sig.clone());
|
||||
|
@ -1383,7 +1464,7 @@ mod test {
|
|||
let commit = keychain.commit(5, &key_id).unwrap();
|
||||
|
||||
let input = Input {
|
||||
features: OutputFeatures::DEFAULT_OUTPUT,
|
||||
features: OutputFeatures::PLAIN,
|
||||
commit: commit,
|
||||
};
|
||||
|
||||
|
@ -1394,16 +1475,16 @@ mod test {
|
|||
let nonce = 0;
|
||||
|
||||
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
|
||||
// different) and check it generates a different short_id
|
||||
let input = Input {
|
||||
features: OutputFeatures::COINBASE_OUTPUT,
|
||||
features: OutputFeatures::COINBASE,
|
||||
commit: commit,
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,12 +14,21 @@
|
|||
|
||||
//! Definition of the genesis block. Placeholder for now.
|
||||
|
||||
// required for genesis replacement
|
||||
//! #![allow(unused_imports)]
|
||||
|
||||
use chrono::prelude::{TimeZone, Utc};
|
||||
|
||||
use crate::consensus;
|
||||
use crate::core;
|
||||
use crate::global;
|
||||
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
|
||||
/// 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,
|
||||
/// will hopefully come before Christmas).
|
||||
pub fn genesis_testnet1() -> core::Block {
|
||||
core::Block::with_header(core::BlockHeader {
|
||||
/// Placeholder for floonet genesis block, will definitely change before
|
||||
/// release
|
||||
pub fn genesis_floo() -> core::Block {
|
||||
let gen = core::Block::with_header(core::BlockHeader {
|
||||
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 {
|
||||
total_difficulty: Difficulty::min(),
|
||||
secondary_scaling: 1,
|
||||
nonce: 28205,
|
||||
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,
|
||||
total_difficulty: Difficulty::from_num(10_u64.pow(6)),
|
||||
secondary_scaling: 1856,
|
||||
nonce: 22,
|
||||
proof: Proof {
|
||||
nonces: vec![
|
||||
0x46f3b4, 0x1135f8c, 0x1a1596f, 0x1e10f71, 0x41c03ea, 0x63fe8e7, 0x65af34f,
|
||||
0x73c16d3, 0x8216dc3, 0x9bc75d0, 0xae7d9ad, 0xc1cb12b, 0xc65e957, 0xf67a152,
|
||||
0xfac6559, 0x100c3d71, 0x11eea08b, 0x1225dfbb, 0x124d61a1, 0x132a14b4,
|
||||
0x13f4ec38, 0x1542d236, 0x155f2df0, 0x1577394e, 0x163c3513, 0x19349845,
|
||||
0x19d46953, 0x19f65ed4, 0x1a0411b9, 0x1a2fa039, 0x1a72a06c, 0x1b02ddd2,
|
||||
0x1b594d59, 0x1b7bffd3, 0x1befe12e, 0x1c82e4cd, 0x1d492478, 0x1de132a5,
|
||||
0x1e578b3c, 0x1ed96855, 0x1f222896, 0x1fea0da6,
|
||||
48398361, 50434294, 73758991, 93493375, 94716564, 101961133, 153506566,
|
||||
159476458, 164019912, 208165915, 216747111, 218441011, 221663358, 262514197,
|
||||
264746362, 278423427, 282069592, 284508695, 297003554, 327321117, 327780367,
|
||||
329474453, 333639856, 356316379, 366419120, 381872178, 386038638, 389726932,
|
||||
390055244, 392425788, 399530286, 426997994, 436531599, 456084550, 456375883,
|
||||
459156409, 474067792, 480904139, 487380747, 489307817, 496780560, 530227836,
|
||||
],
|
||||
edge_bits: 29,
|
||||
},
|
||||
},
|
||||
..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
|
||||
/// release so no use trying to pre-mine it.
|
||||
pub fn genesis_main() -> core::Block {
|
||||
core::Block::with_header(core::BlockHeader {
|
||||
let gen = core::Block::with_header(core::BlockHeader {
|
||||
height: 0,
|
||||
// previous: core::hash::Hash([0xff; 32]),
|
||||
timestamp: Utc.ymd(2018, 8, 14).and_hms(0, 0, 0),
|
||||
timestamp: Utc.ymd(2019, 1, 15).and_hms(12, 0, 0), // REPLACE
|
||||
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 {
|
||||
total_difficulty: Difficulty::from_num(global::initial_block_difficulty()),
|
||||
secondary_scaling: 1,
|
||||
nonce: global::get_genesis_nonce(),
|
||||
proof: Proof::zero(consensus::PROOFSIZE),
|
||||
total_difficulty: Difficulty::from_num(10_u64.pow(8)),
|
||||
secondary_scaling: 1856,
|
||||
nonce: 1, // REPLACE
|
||||
proof: Proof {
|
||||
nonces: vec![0; 42], // REPLACE
|
||||
edge_bits: 29,
|
||||
},
|
||||
},
|
||||
..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, "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::consensus::HeaderInfo;
|
|||
use crate::consensus::{
|
||||
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,
|
||||
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};
|
||||
/// 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
|
||||
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,
|
||||
/// 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;
|
||||
|
@ -79,13 +72,6 @@ const PEER_EXPIRATION_DAYS: i64 = 7 * 2;
|
|||
/// 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;
|
||||
|
||||
/// 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.
|
||||
/// Randomized per node - roll the dice on every block to decide.
|
||||
/// Will compact the txhashset to remove pruned data.
|
||||
|
@ -101,21 +87,15 @@ pub enum ChainTypes {
|
|||
AutomatedTesting,
|
||||
/// For User testing
|
||||
UserTesting,
|
||||
/// First test network
|
||||
Testnet1,
|
||||
/// Second test network
|
||||
Testnet2,
|
||||
/// Third test network
|
||||
Testnet3,
|
||||
/// Fourth test network
|
||||
Testnet4,
|
||||
/// Protocol testing network
|
||||
Floonet,
|
||||
/// Main production network
|
||||
Mainnet,
|
||||
}
|
||||
|
||||
impl Default for 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
|
||||
/// Single change point
|
||||
pub fn create_pow_context<T>(
|
||||
height: u64,
|
||||
_height: u64,
|
||||
edge_bits: u8,
|
||||
proof_size: usize,
|
||||
max_sols: u32,
|
||||
|
@ -163,12 +143,9 @@ where
|
|||
ChainTypes::Mainnet if edge_bits == 29 => new_cuckaroo_ctx(edge_bits, proof_size),
|
||||
ChainTypes::Mainnet => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
|
||||
|
||||
// T4 has Cuckatoo for everything up to hard fork, then Cuckaroo29 for AR
|
||||
// and Cuckatoo30+ for AF PoW
|
||||
ChainTypes::Testnet4 if edge_bits == 29 && height >= T4_CUCKAROO_HARDFORK => {
|
||||
new_cuckaroo_ctx(edge_bits, proof_size)
|
||||
}
|
||||
ChainTypes::Testnet4 => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
|
||||
// Same for Floonet
|
||||
ChainTypes::Floonet if edge_bits == 29 => new_cuckaroo_ctx(edge_bits, proof_size),
|
||||
ChainTypes::Floonet => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
|
||||
|
||||
// Everything else is Cuckatoo only
|
||||
_ => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
|
||||
|
@ -186,8 +163,6 @@ pub fn min_edge_bits() -> u8 {
|
|||
match *param_ref {
|
||||
ChainTypes::AutomatedTesting => AUTOMATED_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,
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +175,6 @@ pub fn base_edge_bits() -> u8 {
|
|||
match *param_ref {
|
||||
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS,
|
||||
ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS,
|
||||
ChainTypes::Testnet1 => USER_TESTING_MIN_EDGE_BITS,
|
||||
_ => BASE_EDGE_BITS,
|
||||
}
|
||||
}
|
||||
|
@ -231,10 +205,7 @@ pub fn initial_block_difficulty() -> u64 {
|
|||
match *param_ref {
|
||||
ChainTypes::AutomatedTesting => TESTING_INITIAL_DIFFICULTY,
|
||||
ChainTypes::UserTesting => TESTING_INITIAL_DIFFICULTY,
|
||||
ChainTypes::Testnet1 => TESTING_INITIAL_DIFFICULTY,
|
||||
ChainTypes::Testnet2 => TESTNET2_INITIAL_DIFFICULTY,
|
||||
ChainTypes::Testnet3 => TESTNET3_INITIAL_DIFFICULTY,
|
||||
ChainTypes::Testnet4 => TESTNET4_INITIAL_DIFFICULTY,
|
||||
ChainTypes::Floonet => INITIAL_DIFFICULTY,
|
||||
ChainTypes::Mainnet => INITIAL_DIFFICULTY,
|
||||
}
|
||||
}
|
||||
|
@ -244,10 +215,7 @@ pub fn initial_graph_weight() -> u32 {
|
|||
match *param_ref {
|
||||
ChainTypes::AutomatedTesting => TESTING_INITIAL_GRAPH_WEIGHT,
|
||||
ChainTypes::UserTesting => TESTING_INITIAL_GRAPH_WEIGHT,
|
||||
ChainTypes::Testnet1 => TESTING_INITIAL_GRAPH_WEIGHT,
|
||||
ChainTypes::Testnet2 => TESTING_INITIAL_GRAPH_WEIGHT,
|
||||
ChainTypes::Testnet3 => TESTING_INITIAL_GRAPH_WEIGHT,
|
||||
ChainTypes::Testnet4 => graph_weight(0, SECOND_POW_EDGE_BITS) as u32,
|
||||
ChainTypes::Floonet => 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.
|
||||
pub fn is_production_mode() -> bool {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
ChainTypes::Testnet1 == *param_ref
|
||||
|| ChainTypes::Testnet2 == *param_ref
|
||||
|| ChainTypes::Testnet3 == *param_ref
|
||||
|| ChainTypes::Testnet4 == *param_ref
|
||||
ChainTypes::Floonet == *param_ref
|
||||
|| ChainTypes::Mainnet == *param_ref
|
||||
}
|
||||
|
||||
/// Are we in one of our (many) testnets?
|
||||
pub fn is_testnet() -> bool {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
ChainTypes::Testnet1 == *param_ref
|
||||
|| ChainTypes::Testnet2 == *param_ref
|
||||
|| ChainTypes::Testnet3 == *param_ref
|
||||
|| ChainTypes::Testnet4 == *param_ref
|
||||
ChainTypes::Floonet == *param_ref
|
||||
}
|
||||
|
||||
/// 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,
|
||||
// Magic nonce for current genesis block at cuckatoo15
|
||||
ChainTypes::UserTesting => 27944,
|
||||
// Magic nonce for genesis block for testnet2 (cuckatoo29)
|
||||
_ => panic!("Pre-set"),
|
||||
// Placeholder, obviously not the right value
|
||||
ChainTypes::Floonet => 0,
|
||||
// Placeholder, obviously not the right value
|
||||
ChainTypes::Mainnet => 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -241,34 +241,35 @@ pub fn verify_partial_sig(
|
|||
/// let commit = keychain.commit(value, &key_id).unwrap();
|
||||
/// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap();
|
||||
/// let output = Output {
|
||||
/// features: OutputFeatures::COINBASE_OUTPUT,
|
||||
/// features: OutputFeatures::COINBASE,
|
||||
/// commit: commit,
|
||||
/// proof: rproof,
|
||||
/// };
|
||||
/// let height = 20;
|
||||
/// let over_commit = secp.commit_value(reward(fees)).unwrap();
|
||||
/// 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 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>(
|
||||
secp: &Secp256k1,
|
||||
k: &K,
|
||||
msg: &Message,
|
||||
value: u64,
|
||||
key_id: &Identifier,
|
||||
blind_sum: Option<&PublicKey>,
|
||||
) -> Result<Signature, Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let skey = k.derive_key(key_id)?;
|
||||
let skey = k.derive_key(value, key_id)?;
|
||||
let sig = aggsig::sign_single(
|
||||
secp,
|
||||
&msg,
|
||||
&skey.secret_key,
|
||||
&skey,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
|
@ -314,17 +315,17 @@ where
|
|||
/// let commit = keychain.commit(value, &key_id).unwrap();
|
||||
/// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap();
|
||||
/// let output = Output {
|
||||
/// features: OutputFeatures::COINBASE_OUTPUT,
|
||||
/// features: OutputFeatures::COINBASE,
|
||||
/// commit: commit,
|
||||
/// proof: rproof,
|
||||
/// };
|
||||
/// let height = 20;
|
||||
/// let over_commit = secp.commit_value(reward(fees)).unwrap();
|
||||
/// 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 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
|
||||
/// let sig_verifies =
|
||||
|
|
|
@ -54,7 +54,7 @@ where
|
|||
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||
let commit = build.keychain.commit(value, &key_id).unwrap();
|
||||
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): {}, {}",
|
||||
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.
|
||||
|
@ -78,7 +78,7 @@ where
|
|||
K: Keychain,
|
||||
{
|
||||
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
|
||||
|
@ -97,12 +97,12 @@ where
|
|||
|
||||
(
|
||||
tx.with_output(Output {
|
||||
features: OutputFeatures::DEFAULT_OUTPUT,
|
||||
features: OutputFeatures::PLAIN,
|
||||
commit: commit,
|
||||
proof: rproof,
|
||||
}),
|
||||
kern,
|
||||
sum.add_key_id(key_id.to_path()),
|
||||
sum.add_key_id(key_id.to_value_path(value)),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
|
@ -26,7 +26,7 @@ where
|
|||
K: Keychain,
|
||||
{
|
||||
// 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 = res.as_bytes();
|
||||
let mut ret_val = [0; 32];
|
||||
|
@ -53,11 +53,11 @@ where
|
|||
K: Keychain,
|
||||
{
|
||||
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 message = ProofMessage::from_bytes(&key_id.serialize_path());
|
||||
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
|
||||
|
|
|
@ -27,7 +27,6 @@ pub fn output<K>(
|
|||
keychain: &K,
|
||||
key_id: &Identifier,
|
||||
fees: u64,
|
||||
height: u64,
|
||||
) -> Result<(Output, TxKernel), Error>
|
||||
where
|
||||
K: Keychain,
|
||||
|
@ -40,7 +39,7 @@ where
|
|||
let rproof = proof::create(keychain, value, key_id, commit, None)?;
|
||||
|
||||
let output = Output {
|
||||
features: OutputFeatures::COINBASE_OUTPUT,
|
||||
features: OutputFeatures::COINBASE,
|
||||
commit: commit,
|
||||
proof: rproof,
|
||||
};
|
||||
|
@ -53,22 +52,18 @@ where
|
|||
let pubkey = excess.to_pubkey(&secp)?;
|
||||
|
||||
// NOTE: Remember we sign the fee *and* the lock_height.
|
||||
// For a coinbase output the fee is 0 and the lock_height is
|
||||
// the lock_height of the coinbase output itself,
|
||||
// not the lock_height of the tx (there is no tx for a coinbase output).
|
||||
// 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))?;
|
||||
// For a coinbase output the fee is 0 and the lock_height is 0
|
||||
let msg = kernel_sig_msg(0, 0, KernelFeatures::COINBASE)?;
|
||||
let sig = aggsig::sign_from_key_id(&secp, keychain, &msg, value, &key_id, Some(&pubkey))?;
|
||||
|
||||
let proof = TxKernel {
|
||||
features: KernelFeatures::COINBASE_KERNEL,
|
||||
features: KernelFeatures::COINBASE,
|
||||
excess: excess,
|
||||
excess_sig: sig,
|
||||
fee: 0,
|
||||
// lock_height here is the height of the block (tx should be valid immediately)
|
||||
// *not* the lock_height of the coinbase output (only spendable 1,000 blocks later)
|
||||
lock_height: height,
|
||||
// lock_height here is 0
|
||||
// *not* the maturity of the coinbase output (only spendable 1,440 blocks later)
|
||||
lock_height: 0,
|
||||
};
|
||||
Ok((output, proof))
|
||||
}
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
//! around during an interactive wallet exchange
|
||||
|
||||
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::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::libtx::error::{Error, ErrorKind};
|
||||
use crate::libtx::{aggsig, build, tx_fee};
|
||||
|
@ -160,8 +160,7 @@ impl Slate {
|
|||
// Currently includes the fee and the lock_height.
|
||||
fn msg_to_sign(&self) -> Result<secp::Message, Error> {
|
||||
// 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)?;
|
||||
Ok(msg)
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ pub fn verify_size(bh: &BlockHeader) -> Result<(), Error> {
|
|||
|
||||
/// Mines a genesis block using the internal miner
|
||||
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() {
|
||||
gen = genesis::genesis_dev();
|
||||
gen.header.timestamp = Utc::now();
|
||||
|
|
|
@ -131,7 +131,7 @@ fn empty_block_with_coinbase_is_valid() {
|
|||
let coinbase_outputs = b
|
||||
.outputs()
|
||||
.iter()
|
||||
.filter(|out| out.features.contains(OutputFeatures::COINBASE_OUTPUT))
|
||||
.filter(|out| out.is_coinbase())
|
||||
.map(|o| o.clone())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(coinbase_outputs.len(), 1);
|
||||
|
@ -139,7 +139,7 @@ fn empty_block_with_coinbase_is_valid() {
|
|||
let coinbase_kernels = b
|
||||
.kernels()
|
||||
.iter()
|
||||
.filter(|out| out.features.contains(KernelFeatures::COINBASE_KERNEL))
|
||||
.filter(|out| out.is_coinbase())
|
||||
.map(|o| o.clone())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(coinbase_kernels.len(), 1);
|
||||
|
@ -152,7 +152,7 @@ fn empty_block_with_coinbase_is_valid() {
|
|||
}
|
||||
|
||||
#[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
|
||||
// additionally verifying the merkle_inputs_outputs also fails
|
||||
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 mut b = new_block(vec![], &keychain, &prev, &key_id);
|
||||
|
||||
assert!(b.outputs()[0]
|
||||
.features
|
||||
.contains(OutputFeatures::COINBASE_OUTPUT));
|
||||
b.outputs_mut()[0]
|
||||
.features
|
||||
.remove(OutputFeatures::COINBASE_OUTPUT);
|
||||
assert!(b.outputs()[0].is_coinbase());
|
||||
b.outputs_mut()[0].features = OutputFeatures::PLAIN;
|
||||
|
||||
assert_eq!(b.verify_coinbase(), Err(Error::CoinbaseSumMismatch));
|
||||
assert!(b
|
||||
|
@ -179,7 +175,7 @@ fn remove_coinbase_output_flag() {
|
|||
}
|
||||
|
||||
#[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
|
||||
fn remove_coinbase_kernel_flag() {
|
||||
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 mut b = new_block(vec![], &keychain, &prev, &key_id);
|
||||
|
||||
assert!(b.kernels()[0]
|
||||
.features
|
||||
.contains(KernelFeatures::COINBASE_KERNEL));
|
||||
b.kernels_mut()[0]
|
||||
.features
|
||||
.remove(KernelFeatures::COINBASE_KERNEL);
|
||||
assert!(b.kernels()[0].is_coinbase());
|
||||
b.kernels_mut()[0].features = KernelFeatures::PLAIN;
|
||||
|
||||
// Flipping the coinbase flag results in kernels not summing correctly.
|
||||
assert_eq!(
|
||||
|
@ -380,7 +372,7 @@ fn convert_block_to_compact_block() {
|
|||
cb.kern_ids()[0],
|
||||
b.kernels()
|
||||
.iter()
|
||||
.find(|x| !x.features.contains(KernelFeatures::COINBASE_KERNEL))
|
||||
.find(|x| !x.is_coinbase())
|
||||
.unwrap()
|
||||
.short_id(&cb.hash(), cb.nonce)
|
||||
);
|
||||
|
|
|
@ -92,7 +92,7 @@ where
|
|||
K: Keychain,
|
||||
{
|
||||
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(
|
||||
&previous_header,
|
||||
txs.into_iter().cloned().collect(),
|
||||
|
|
|
@ -206,18 +206,6 @@ fn add_block(
|
|||
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
|
||||
fn add_block_repeated(
|
||||
interval: u64,
|
||||
|
@ -355,25 +343,6 @@ fn adjustment_scenarios() {
|
|||
print_chain_sim(chain_sim);
|
||||
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
|
||||
|
@ -526,7 +495,7 @@ fn test_secondary_pow_ratio() {
|
|||
|
||||
// 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!(secondary_pow_ratio(1), 90);
|
||||
|
@ -539,16 +508,16 @@ fn test_secondary_pow_ratio() {
|
|||
|
||||
let one_week = 60 * 24 * 7;
|
||||
assert_eq!(secondary_pow_ratio(one_week - 1), 90);
|
||||
assert_eq!(secondary_pow_ratio(one_week), 89);
|
||||
assert_eq!(secondary_pow_ratio(one_week + 1), 89);
|
||||
assert_eq!(secondary_pow_ratio(one_week), 90);
|
||||
assert_eq!(secondary_pow_ratio(one_week + 1), 90);
|
||||
|
||||
let two_weeks = one_week * 2;
|
||||
assert_eq!(secondary_pow_ratio(two_weeks - 1), 89);
|
||||
assert_eq!(secondary_pow_ratio(two_weeks), 88);
|
||||
assert_eq!(secondary_pow_ratio(two_weeks + 1), 88);
|
||||
assert_eq!(secondary_pow_ratio(two_weeks), 89);
|
||||
assert_eq!(secondary_pow_ratio(two_weeks + 1), 89);
|
||||
|
||||
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 + 1), 85);
|
||||
|
||||
|
@ -572,9 +541,9 @@ fn test_secondary_pow_scale() {
|
|||
let window = DIFFICULTY_ADJUST_WINDOW;
|
||||
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);
|
||||
|
||||
// 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;
|
||||
assert_eq!(
|
||||
secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect::<Vec<_>>()),
|
||||
147
|
||||
106
|
||||
);
|
||||
// all secondary on 90%, factor should go down a bit
|
||||
hi.is_secondary = true;
|
||||
assert_eq!(
|
||||
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)
|
||||
assert_eq!(
|
||||
|
@ -631,7 +600,7 @@ fn test_secondary_pow_scale() {
|
|||
.chain((0..(window * 95 / 100)).map(|_| hi.clone()))
|
||||
.collect::<Vec<_>>()
|
||||
),
|
||||
94
|
||||
96
|
||||
);
|
||||
// 40% secondary, should come up based on 70 average
|
||||
assert_eq!(
|
||||
|
@ -642,7 +611,7 @@ fn test_secondary_pow_scale() {
|
|||
.chain((0..(window * 4 / 10)).map(|_| hi.clone()))
|
||||
.collect::<Vec<_>>()
|
||||
),
|
||||
84
|
||||
72
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,8 @@ fn tx_double_ser_deser() {
|
|||
#[test]
|
||||
#[should_panic(expected = "Keychain Error")]
|
||||
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);
|
||||
|
||||
// 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];
|
||||
kern.verify().unwrap();
|
||||
|
||||
assert_eq!(kern.features, KernelFeatures::DEFAULT_KERNEL);
|
||||
assert_eq!(kern.features, KernelFeatures::PLAIN);
|
||||
assert_eq!(kern.fee, tx.fee());
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ fn test_output_ser_deser() {
|
|||
let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap();
|
||||
|
||||
let out = Output {
|
||||
features: OutputFeatures::DEFAULT_OUTPUT,
|
||||
features: OutputFeatures::PLAIN,
|
||||
commit: commit,
|
||||
proof: proof,
|
||||
};
|
||||
|
@ -40,7 +40,7 @@ fn test_output_ser_deser() {
|
|||
ser::serialize(&mut vec, &out).expect("serialized failed");
|
||||
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.proof, out.proof);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ fn test_verifier_cache_rangeproofs() {
|
|||
let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap();
|
||||
|
||||
let out = Output {
|
||||
features: OutputFeatures::DEFAULT_OUTPUT,
|
||||
features: OutputFeatures::PLAIN,
|
||||
commit: commit,
|
||||
proof: proof,
|
||||
};
|
||||
|
|
36
etc/gen_gen/Cargo.toml
Normal file
36
etc/gen_gen/Cargo.toml
Normal 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
18
etc/gen_gen/README.md
Normal 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>`
|
339
etc/gen_gen/src/bin/gen_gen.rs
Normal file
339
etc/gen_gen/src/bin/gen_gen.rs
Normal 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()
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ use crate::util::secp::{self, Message, Secp256k1, Signature};
|
|||
pub struct ExtKeychain {
|
||||
secp: Secp256k1,
|
||||
master: ExtendedPrivKey,
|
||||
use_switch_commits: bool,
|
||||
}
|
||||
|
||||
impl Keychain for ExtKeychain {
|
||||
|
@ -39,6 +40,7 @@ impl Keychain for ExtKeychain {
|
|||
let keychain = ExtKeychain {
|
||||
secp: secp,
|
||||
master: master,
|
||||
use_switch_commits: true,
|
||||
};
|
||||
Ok(keychain)
|
||||
}
|
||||
|
@ -49,6 +51,7 @@ impl Keychain for ExtKeychain {
|
|||
let keychain = ExtKeychain {
|
||||
secp: secp,
|
||||
master: master,
|
||||
use_switch_commits: true,
|
||||
};
|
||||
Ok(keychain)
|
||||
}
|
||||
|
@ -68,19 +71,23 @@ impl Keychain for ExtKeychain {
|
|||
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 p = id.to_path();
|
||||
let mut sk = self.master;
|
||||
let mut ext_key = self.master;
|
||||
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> {
|
||||
let key = self.derive_key(id)?;
|
||||
let commit = self.secp.commit(amount, key.secret_key)?;
|
||||
let key = self.derive_key(amount, id)?;
|
||||
let commit = self.secp.commit(amount, key)?;
|
||||
Ok(commit)
|
||||
}
|
||||
|
||||
|
@ -89,9 +96,9 @@ impl Keychain for ExtKeychain {
|
|||
.positive_key_ids
|
||||
.iter()
|
||||
.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 {
|
||||
Some(s.secret_key)
|
||||
Some(s)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -102,9 +109,9 @@ impl Keychain for ExtKeychain {
|
|||
.negative_key_ids
|
||||
.iter()
|
||||
.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 {
|
||||
Some(s.secret_key)
|
||||
Some(s)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -131,9 +138,9 @@ impl Keychain for ExtKeychain {
|
|||
Ok(BlindingFactor::from_secret_key(sum))
|
||||
}
|
||||
|
||||
fn sign(&self, msg: &Message, id: &Identifier) -> Result<Signature, Error> {
|
||||
let skey = self.derive_key(id)?;
|
||||
let sig = self.secp.sign(msg, &skey.secret_key)?;
|
||||
fn sign(&self, msg: &Message, amount: u64, id: &Identifier) -> Result<Signature, Error> {
|
||||
let skey = self.derive_key(amount, id)?;
|
||||
let sig = self.secp.sign(msg, &skey)?;
|
||||
Ok(sig)
|
||||
}
|
||||
|
||||
|
@ -147,6 +154,10 @@ impl Keychain for ExtKeychain {
|
|||
Ok(sig)
|
||||
}
|
||||
|
||||
fn set_use_switch_commits(&mut self, value: bool) {
|
||||
self.use_switch_commits = value;
|
||||
}
|
||||
|
||||
fn secp(&self) -> &Secp256k1 {
|
||||
&self.secp
|
||||
}
|
||||
|
@ -175,7 +186,7 @@ mod test {
|
|||
let commit = keychain.commit(0, &key_id).unwrap();
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ use std::ops::Add;
|
|||
use std::{error, fmt};
|
||||
|
||||
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 crate::util;
|
||||
|
@ -44,6 +44,7 @@ pub enum Error {
|
|||
KeyDerivation(extkey_bip32::Error),
|
||||
Transaction(String),
|
||||
RangeProof(String),
|
||||
SwitchCommitment,
|
||||
}
|
||||
|
||||
impl From<secp::Error> for Error {
|
||||
|
@ -126,6 +127,13 @@ impl Identifier {
|
|||
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
|
||||
/// recovery processes can grind through possiblities to find the
|
||||
/// correct length if required
|
||||
|
@ -327,8 +335,8 @@ pub struct SplitBlindingFactor {
|
|||
/// factor as well as the "sign" with which they should be combined.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct BlindSum {
|
||||
pub positive_key_ids: Vec<ExtKeychainPath>,
|
||||
pub negative_key_ids: Vec<ExtKeychainPath>,
|
||||
pub positive_key_ids: Vec<ValueExtKeychainPath>,
|
||||
pub negative_key_ids: Vec<ValueExtKeychainPath>,
|
||||
pub positive_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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -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 {
|
||||
fn from_seed(seed: &[u8]) -> Result<Self, Error>;
|
||||
fn from_mnemonic(word_list: &str, extension_word: &str) -> Result<Self, Error>;
|
||||
fn from_random_seed() -> Result<Self, Error>;
|
||||
fn root_key_id() -> 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 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 set_use_switch_commits(&mut self, value: bool);
|
||||
fn secp(&self) -> &Secp256k1;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ pub const PROTOCOL_VERSION: u32 = 1;
|
|||
pub const USER_AGENT: &'static str = concat!("MW/Grin ", env!("CARGO_PKG_VERSION"));
|
||||
|
||||
/// 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.
|
||||
const MAX_BLOCK_SIZE: u64 =
|
||||
|
|
|
@ -44,7 +44,7 @@ fn test_transaction_pool_block_building() {
|
|||
let height = prev_header.height + 1;
|
||||
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
||||
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();
|
||||
|
||||
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
|
||||
|
|
|
@ -44,7 +44,7 @@ fn test_transaction_pool_block_reconciliation() {
|
|||
let header = {
|
||||
let height = 1;
|
||||
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 mut block = Block::new(&genesis, vec![], Difficulty::min(), reward).unwrap();
|
||||
|
||||
|
@ -63,7 +63,7 @@ fn test_transaction_pool_block_reconciliation() {
|
|||
let block = {
|
||||
let key_id = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||
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();
|
||||
|
||||
// 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 key_id = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||
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();
|
||||
|
||||
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
|
||||
|
|
|
@ -43,7 +43,7 @@ fn test_the_transaction_pool() {
|
|||
let header = {
|
||||
let height = 1;
|
||||
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();
|
||||
|
||||
chain.update_db_for_block(&block);
|
||||
|
|
|
@ -24,14 +24,18 @@ use std::net::{SocketAddr, ToSocketAddrs};
|
|||
use std::sync::{mpsc, Arc};
|
||||
use std::{cmp, io, str, thread, time};
|
||||
|
||||
use crate::core::global;
|
||||
use crate::p2p;
|
||||
use crate::p2p::ChainAdapter;
|
||||
use crate::pool::DandelionConfig;
|
||||
use crate::util::{Mutex, StopState};
|
||||
|
||||
// DNS Seeds with contact email associated
|
||||
const DNS_SEEDS: &'static [&'static str] = &[
|
||||
"t4.seed.grin-tech.org", // igno.peverell@protonmail.com
|
||||
const MAINNET_DNS_SEEDS: &'static [&'static str] = &[
|
||||
"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(
|
||||
|
@ -331,7 +335,12 @@ fn listen_for_addrs(
|
|||
pub fn dns_seeds() -> Box<dyn Fn() -> Vec<SocketAddr> + Send> {
|
||||
Box::new(|| {
|
||||
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();
|
||||
debug!("Retrieving seed nodes from dns {}", dns_seed);
|
||||
match (dns_seed.to_owned(), 0).to_socket_addrs() {
|
||||
|
|
|
@ -133,13 +133,10 @@ impl Server {
|
|||
));
|
||||
|
||||
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::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());
|
||||
|
|
|
@ -173,7 +173,7 @@ fn burn_reward(block_fees: BlockFees) -> Result<(core::Output, core::TxKernel, B
|
|||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
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();
|
||||
Ok((out, kernel, block_fees))
|
||||
}
|
||||
|
|
|
@ -20,12 +20,12 @@ serde_derive = "1"
|
|||
log4rs = { version = "0.8.1", features = ["rolling_file_appender", "compound_policy", "size_trigger", "fixed_window_roller"] }
|
||||
log = "0.4"
|
||||
walkdir = "2"
|
||||
zip = "0.4"
|
||||
zip = { version = "0.4", default-features = false }
|
||||
parking_lot = {version = "0.6"}
|
||||
|
||||
[dependencies.grin_secp256k1zkp]
|
||||
#git = "https://github.com/mimblewimble/rust-secp256k1-zkp"
|
||||
#tag = "grin_integration_28"
|
||||
git = "https://github.com/mimblewimble/rust-secp256k1-zkp"
|
||||
tag = "grin_integration_29"
|
||||
#path = "../../rust-secp256k1-zkp"
|
||||
version = "0.7.1"
|
||||
#version = "0.7.1"
|
||||
features = ["bullet-proof-sizing"]
|
||||
|
|
|
@ -177,7 +177,7 @@ pub fn txs(
|
|||
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),
|
||||
None => "None".to_owned(),
|
||||
};
|
||||
|
|
|
@ -99,6 +99,7 @@ where
|
|||
/// use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
///
|
||||
/// 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
|
||||
/// // the wallet and the node.
|
||||
|
@ -148,6 +149,7 @@ where
|
|||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # 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 mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
|
@ -203,6 +205,7 @@ where
|
|||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # 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 mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
|
@ -256,6 +259,7 @@ where
|
|||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # 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 mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
|
@ -313,6 +317,7 @@ where
|
|||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # 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 mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
|
@ -389,6 +394,7 @@ where
|
|||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # 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 mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
|
@ -462,6 +468,7 @@ where
|
|||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # 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 mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
|
@ -575,6 +582,7 @@ where
|
|||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # 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 mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
|
|
|
@ -102,7 +102,7 @@ where
|
|||
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id);
|
||||
t.tx_slate_id = Some(slate_id);
|
||||
let filename = format!("{}.grintx", slate_id);
|
||||
t.tx_hex = Some(filename);
|
||||
t.stored_tx = Some(filename);
|
||||
t.fee = Some(fee);
|
||||
let mut amount_debited = 0;
|
||||
t.num_inputs = lock_inputs.len();
|
||||
|
|
|
@ -196,7 +196,7 @@ where
|
|||
return Err(ErrorKind::TransactionDoesntExist(tx_id.to_string()))?;
|
||||
}
|
||||
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)
|
||||
|
|
|
@ -458,13 +458,7 @@ where
|
|||
|
||||
debug!("receive_coinbase: {:?}", block_fees);
|
||||
|
||||
let (out, kern) = reward::output(
|
||||
wallet.keychain(),
|
||||
&key_id,
|
||||
block_fees.fees,
|
||||
block_fees.height,
|
||||
)
|
||||
.unwrap();
|
||||
let (out, kern) = reward::output(wallet.keychain(), &key_id, block_fees.fees).unwrap();
|
||||
/* .context(ErrorKind::Keychain)?; */
|
||||
Ok((out, kern, block_fees))
|
||||
}
|
||||
|
|
|
@ -600,9 +600,8 @@ pub struct TxLogEntry {
|
|||
pub amount_debited: u64,
|
||||
/// Fee
|
||||
pub fee: Option<u64>,
|
||||
// TODO: rename this to 'stored_tx_file' or something for mainnet
|
||||
/// The transaction json itself, stored for reference or resending
|
||||
pub tx_hex: Option<String>,
|
||||
/// Location of the store transaction, (reference or resending)
|
||||
pub stored_tx: Option<String>,
|
||||
}
|
||||
|
||||
impl ser::Writeable for TxLogEntry {
|
||||
|
@ -634,7 +633,7 @@ impl TxLogEntry {
|
|||
num_inputs: 0,
|
||||
num_outputs: 0,
|
||||
fee: None,
|
||||
tx_hex: None,
|
||||
stored_tx: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ use serde_json;
|
|||
use failure::ResultExt;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::blake2::blake2b::Blake2b;
|
||||
|
||||
use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain};
|
||||
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::types::{WalletConfig, WalletSeed};
|
||||
use crate::util;
|
||||
use crate::util::secp::constants::SECRET_KEY_SIZE;
|
||||
use crate::util::secp::pedersen;
|
||||
|
||||
pub const DB_DIR: &'static str = "db";
|
||||
|
@ -62,6 +65,39 @@ pub fn wallet_db_exists(config: WalletConfig) -> bool {
|
|||
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> {
|
||||
db: store::Store,
|
||||
config: WalletConfig,
|
||||
|
@ -140,8 +176,11 @@ where
|
|||
fn open_with_credentials(&mut self) -> Result<(), Error> {
|
||||
let wallet_seed = WalletSeed::from_file(&self.config, &self.passphrase)
|
||||
.context(ErrorKind::CallbackImpl("Error opening wallet"))?;
|
||||
let keychain = wallet_seed.derive_keychain();
|
||||
self.keychain = Some(keychain.context(ErrorKind::CallbackImpl("Error deriving keychain"))?);
|
||||
self.keychain = Some(
|
||||
wallet_seed
|
||||
.derive_keychain()
|
||||
.context(ErrorKind::CallbackImpl("Error deriving keychain"))?,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -229,11 +268,19 @@ where
|
|||
|
||||
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());
|
||||
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),
|
||||
&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> {
|
||||
|
@ -259,7 +306,7 @@ where
|
|||
}
|
||||
|
||||
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,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
@ -498,11 +545,21 @@ where
|
|||
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> {
|
||||
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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
fn get_output_local(chain: &chain::Chain, commit: &pedersen::Commitment) -> Option<api::Output> {
|
||||
let outputs = [
|
||||
OutputIdentifier::new(OutputFeatures::DEFAULT_OUTPUT, commit),
|
||||
OutputIdentifier::new(OutputFeatures::COINBASE_OUTPUT, commit),
|
||||
OutputIdentifier::new(OutputFeatures::PLAIN, commit),
|
||||
OutputIdentifier::new(OutputFeatures::COINBASE, commit),
|
||||
];
|
||||
|
||||
for x in outputs.iter() {
|
||||
|
|
|
@ -50,9 +50,9 @@ pub struct WalletConfig {
|
|||
pub check_node_api_http_addr: String,
|
||||
// The directory in which wallet files are stored
|
||||
pub data_file_dir: String,
|
||||
/// TLS ceritificate file
|
||||
/// TLS certificate file
|
||||
pub tls_certificate_file: Option<String>,
|
||||
/// TLS ceritificate private key file
|
||||
/// TLS certificate private key file
|
||||
pub tls_certificate_key: Option<String>,
|
||||
/// Whether to use the black background color scheme for command line
|
||||
/// if enabled, wallet command output color will be suitable for black background terminal
|
||||
|
@ -62,7 +62,7 @@ pub struct WalletConfig {
|
|||
impl Default for WalletConfig {
|
||||
fn default() -> WalletConfig {
|
||||
WalletConfig {
|
||||
chain_type: Some(ChainTypes::Testnet4),
|
||||
chain_type: Some(ChainTypes::Floonet),
|
||||
api_listen_interface: "127.0.0.1".to_string(),
|
||||
api_listen_port: 13415,
|
||||
api_secret_path: Some(".api_secret".to_string()),
|
||||
|
|
|
@ -26,7 +26,7 @@ use grin_wallet as wallet;
|
|||
use rand::thread_rng;
|
||||
|
||||
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]
|
||||
|
@ -38,8 +38,8 @@ fn aggsig_sender_receiver_interaction() {
|
|||
// Normally this would happen during transaction building.
|
||||
let kernel_excess = {
|
||||
let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
let skey1 = sender_keychain.derive_key(&id1).unwrap().secret_key;
|
||||
let skey2 = receiver_keychain.derive_key(&id1).unwrap().secret_key;
|
||||
let skey1 = sender_keychain.derive_key(0, &id1).unwrap();
|
||||
let skey2 = receiver_keychain.derive_key(0, &id1).unwrap();
|
||||
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let blinding_factor = keychain
|
||||
|
@ -62,7 +62,7 @@ fn aggsig_sender_receiver_interaction() {
|
|||
let (sender_pub_excess, _sender_pub_nonce) = {
|
||||
let keychain = sender_keychain.clone();
|
||||
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
|
||||
// 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 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);
|
||||
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.
|
||||
let kernel_excess = {
|
||||
let id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
let skey1 = sender_keychain.derive_key(&id1).unwrap().secret_key;
|
||||
let skey2 = receiver_keychain.derive_key(&id1).unwrap().secret_key;
|
||||
let skey1 = sender_keychain.derive_key(0, &id1).unwrap();
|
||||
let skey2 = receiver_keychain.derive_key(0, &id1).unwrap();
|
||||
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let blinding_factor = keychain
|
||||
|
@ -274,7 +274,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
|||
let (sender_pub_excess, _sender_pub_nonce) = {
|
||||
let keychain = sender_keychain.clone();
|
||||
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
|
||||
// rather than use it as is
|
||||
|
@ -301,7 +301,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
|||
let keychain = receiver_keychain.clone();
|
||||
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);
|
||||
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
|
||||
|
|
Loading…
Reference in a new issue