mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 08:51:08 +03:00
Master merge 2.0.0 (#2927)
* create 2.0.0 branch * fix humansize version * update grin.yml version * PoW HardFork (#2866) * allow version 2 blocks for next 6 months * add cuckarood.rs with working tests * switch cuckaroo to cuckarood at right heights * reorder to reduce conditions * remove _ prefix on used args; fix typo * Make Valid Header Version dependant on ChainType * Rustfmt * Add tests, uncomment header v2 * Rustfmt * Add FLOONET_FIRST_HARD_FORK height and simplify logic * assume floonet stays closer to avg 60s block time * move floonet hf forward by half a day * update version in new block when previous no longer valid * my next commit:-) * micro optimization * Support new Bulletproof rewind scheme (#2848) * Update keychain with new rewind scheme * Refactor: proof builder trait * Update tests, cleanup * rustfmt * Move conversion of SwitchCommitmentType * Add proof build trait to tx builders * Cache hashes in proof builders * Proof builder tests * Add ViewKey struct * Fix some warnings * Zeroize proof builder secrets on drop * Modify mine_block to use wallet V2 API (#2892) * update mine_block to use V2 wallet API * rustfmt * Add version endpoint to node API, rename pool/push (#2897) * add node version API, tweak pool/push parameter * rustfmt * Upate version api call (#2899) * Update version number for next (potential) release * zeroize: Upgrade to v0.9 (#2914) * zeroize: Upgrade to v0.9 * missed Cargo.lock * [PENDING APPROVAL] put phase outs of C32 and beyond on hold (#2714) * put phase outs of C32 and beyond on hold * update tests for phaseouts on hold * Don't wait for p2p-server thread (#2917) Currently p2p.stop() stops and wait for all peers to exit, that's basically all we need. However we also run a TCP listener in this thread which is blocked on `accept` most of the time. We do an attempt to stop it but it would work only if we get an incoming connection during the shutdown, which is a week guarantee. This fix remove joining to p2p-server thread, it stops all peers and makes an attempt to stop the listener. Fixes [#2906] * rustfmt
This commit is contained in:
parent
fd6fe35777
commit
1609b041b1
55 changed files with 2456 additions and 844 deletions
988
Cargo.lock
generated
988
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
20
Cargo.toml
20
Cargo.toml
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin"
|
name = "grin"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -32,13 +32,13 @@ term = "0.5"
|
||||||
failure = "0.1"
|
failure = "0.1"
|
||||||
failure_derive = "0.1"
|
failure_derive = "0.1"
|
||||||
|
|
||||||
grin_api = { path = "./api", version = "1.1.1-beta.1" }
|
grin_api = { path = "./api", version = "2.0.0-beta.2" }
|
||||||
grin_config = { path = "./config", version = "1.1.1-beta.1" }
|
grin_config = { path = "./config", version = "2.0.0-beta.2" }
|
||||||
grin_core = { path = "./core", version = "1.1.1-beta.1" }
|
grin_core = { path = "./core", version = "2.0.0-beta.2" }
|
||||||
grin_keychain = { path = "./keychain", version = "1.1.1-beta.1" }
|
grin_keychain = { path = "./keychain", version = "2.0.0-beta.2" }
|
||||||
grin_p2p = { path = "./p2p", version = "1.1.1-beta.1" }
|
grin_p2p = { path = "./p2p", version = "2.0.0-beta.2" }
|
||||||
grin_servers = { path = "./servers", version = "1.1.1-beta.1" }
|
grin_servers = { path = "./servers", version = "2.0.0-beta.2" }
|
||||||
grin_util = { path = "./util", version = "1.1.1-beta.1" }
|
grin_util = { path = "./util", version = "2.0.0-beta.2" }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
cursive = { version = "0.12", default-features = false, features = ["pancurses-backend"] }
|
cursive = { version = "0.12", default-features = false, features = ["pancurses-backend"] }
|
||||||
|
@ -52,5 +52,5 @@ cursive = "0.12"
|
||||||
built = "0.3"
|
built = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
grin_chain = { path = "./chain", version = "1.1.1-beta.1" }
|
grin_chain = { path = "./chain", version = "2.0.0-beta.2" }
|
||||||
grin_store = { path = "./store", version = "1.1.1-beta.1" }
|
grin_store = { path = "./store", version = "2.0.0-beta.2" }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin_api"
|
name = "grin_api"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "APIs for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "APIs for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -30,9 +30,9 @@ futures = "0.1.21"
|
||||||
rustls = "0.13"
|
rustls = "0.13"
|
||||||
url = "1.7.0"
|
url = "1.7.0"
|
||||||
|
|
||||||
grin_core = { path = "../core", version = "1.1.1-beta.1" }
|
grin_core = { path = "../core", version = "2.0.0-beta.2" }
|
||||||
grin_chain = { path = "../chain", version = "1.1.1-beta.1" }
|
grin_chain = { path = "../chain", version = "2.0.0-beta.2" }
|
||||||
grin_p2p = { path = "../p2p", version = "1.1.1-beta.1" }
|
grin_p2p = { path = "../p2p", version = "2.0.0-beta.2" }
|
||||||
grin_pool = { path = "../pool", version = "1.1.1-beta.1" }
|
grin_pool = { path = "../pool", version = "2.0.0-beta.2" }
|
||||||
grin_store = { path = "../store", version = "1.1.1-beta.1" }
|
grin_store = { path = "../store", version = "2.0.0-beta.2" }
|
||||||
grin_util = { path = "../util", version = "1.1.1-beta.1" }
|
grin_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||||
|
|
|
@ -19,6 +19,7 @@ mod pool_api;
|
||||||
mod server_api;
|
mod server_api;
|
||||||
mod transactions_api;
|
mod transactions_api;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
mod version_api;
|
||||||
|
|
||||||
use self::blocks_api::BlockHandler;
|
use self::blocks_api::BlockHandler;
|
||||||
use self::blocks_api::HeaderHandler;
|
use self::blocks_api::HeaderHandler;
|
||||||
|
@ -32,9 +33,10 @@ use self::peers_api::PeersConnectedHandler;
|
||||||
use self::pool_api::PoolInfoHandler;
|
use self::pool_api::PoolInfoHandler;
|
||||||
use self::pool_api::PoolPushHandler;
|
use self::pool_api::PoolPushHandler;
|
||||||
use self::server_api::IndexHandler;
|
use self::server_api::IndexHandler;
|
||||||
use self::server_api::StatusHandler;
|
|
||||||
use self::server_api::KernelDownloadHandler;
|
use self::server_api::KernelDownloadHandler;
|
||||||
|
use self::server_api::StatusHandler;
|
||||||
use self::transactions_api::TxHashSetHandler;
|
use self::transactions_api::TxHashSetHandler;
|
||||||
|
use self::version_api::VersionHandler;
|
||||||
use crate::auth::{BasicAuthMiddleware, GRIN_BASIC_REALM};
|
use crate::auth::{BasicAuthMiddleware, GRIN_BASIC_REALM};
|
||||||
use crate::chain;
|
use crate::chain;
|
||||||
use crate::p2p;
|
use crate::p2p;
|
||||||
|
@ -104,12 +106,13 @@ pub fn build_router(
|
||||||
"get txhashset/outputs?start_index=1&max=100".to_string(),
|
"get txhashset/outputs?start_index=1&max=100".to_string(),
|
||||||
"get txhashset/merkleproof?n=1".to_string(),
|
"get txhashset/merkleproof?n=1".to_string(),
|
||||||
"get pool".to_string(),
|
"get pool".to_string(),
|
||||||
"post pool/push".to_string(),
|
"post pool/push_tx".to_string(),
|
||||||
"post peers/a.b.c.d:p/ban".to_string(),
|
"post peers/a.b.c.d:p/ban".to_string(),
|
||||||
"post peers/a.b.c.d:p/unban".to_string(),
|
"post peers/a.b.c.d:p/unban".to_string(),
|
||||||
"get peers/all".to_string(),
|
"get peers/all".to_string(),
|
||||||
"get peers/connected".to_string(),
|
"get peers/connected".to_string(),
|
||||||
"get peers/a.b.c.d".to_string(),
|
"get peers/a.b.c.d".to_string(),
|
||||||
|
"get version".to_string(),
|
||||||
];
|
];
|
||||||
let index_handler = IndexHandler { list: route_list };
|
let index_handler = IndexHandler { list: route_list };
|
||||||
|
|
||||||
|
@ -157,6 +160,9 @@ pub fn build_router(
|
||||||
let peer_handler = PeerHandler {
|
let peer_handler = PeerHandler {
|
||||||
peers: Arc::downgrade(&peers),
|
peers: Arc::downgrade(&peers),
|
||||||
};
|
};
|
||||||
|
let version_handler = VersionHandler {
|
||||||
|
chain: Arc::downgrade(&chain),
|
||||||
|
};
|
||||||
|
|
||||||
let mut router = Router::new();
|
let mut router = Router::new();
|
||||||
|
|
||||||
|
@ -171,9 +177,10 @@ pub fn build_router(
|
||||||
router.add_route("/v1/status", Arc::new(status_handler))?;
|
router.add_route("/v1/status", Arc::new(status_handler))?;
|
||||||
router.add_route("/v1/kerneldownload", Arc::new(kernel_download_handler))?;
|
router.add_route("/v1/kerneldownload", Arc::new(kernel_download_handler))?;
|
||||||
router.add_route("/v1/pool", Arc::new(pool_info_handler))?;
|
router.add_route("/v1/pool", Arc::new(pool_info_handler))?;
|
||||||
router.add_route("/v1/pool/push", Arc::new(pool_push_handler))?;
|
router.add_route("/v1/pool/push_tx", Arc::new(pool_push_handler))?;
|
||||||
router.add_route("/v1/peers/all", Arc::new(peers_all_handler))?;
|
router.add_route("/v1/peers/all", Arc::new(peers_all_handler))?;
|
||||||
router.add_route("/v1/peers/connected", Arc::new(peers_connected_handler))?;
|
router.add_route("/v1/peers/connected", Arc::new(peers_connected_handler))?;
|
||||||
router.add_route("/v1/peers/**", Arc::new(peer_handler))?;
|
router.add_route("/v1/peers/**", Arc::new(peer_handler))?;
|
||||||
|
router.add_route("/v1/version", Arc::new(version_handler))?;
|
||||||
Ok(router)
|
Ok(router)
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ struct TxWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push new transaction to our local transaction pool.
|
/// Push new transaction to our local transaction pool.
|
||||||
/// POST /v1/pool/push
|
/// POST /v1/pool/push_tx
|
||||||
pub struct PoolPushHandler {
|
pub struct PoolPushHandler {
|
||||||
pub tx_pool: Weak<RwLock<pool::TransactionPool>>,
|
pub tx_pool: Weak<RwLock<pool::TransactionPool>>,
|
||||||
}
|
}
|
||||||
|
|
49
api/src/handlers/version_api.rs
Normal file
49
api/src/handlers/version_api.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use super::utils::w;
|
||||||
|
use crate::chain;
|
||||||
|
use crate::rest::*;
|
||||||
|
use crate::router::{Handler, ResponseFuture};
|
||||||
|
use crate::types::Version;
|
||||||
|
use crate::web::*;
|
||||||
|
use hyper::{Body, Request};
|
||||||
|
use std::sync::Weak;
|
||||||
|
|
||||||
|
const CRATE_VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
/// Version handler. Get running node API version
|
||||||
|
/// GET /v1/version
|
||||||
|
pub struct VersionHandler {
|
||||||
|
pub chain: Weak<chain::Chain>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VersionHandler {
|
||||||
|
fn get_version(&self) -> Result<Version, Error> {
|
||||||
|
let head = w(&self.chain)?
|
||||||
|
.head_header()
|
||||||
|
.map_err(|e| ErrorKind::Internal(format!("can't get head: {}", e)))?;
|
||||||
|
|
||||||
|
Ok(Version {
|
||||||
|
node_version: CRATE_VERSION.to_owned(),
|
||||||
|
block_header_version: head.version.into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler for VersionHandler {
|
||||||
|
fn get(&self, _req: Request<Body>) -> ResponseFuture {
|
||||||
|
result_to_response(self.get_version())
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,15 @@ macro_rules! no_dup {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// API Version Information
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct Version {
|
||||||
|
/// Current node API Version (api crate version)
|
||||||
|
pub node_version: String,
|
||||||
|
/// Block header version
|
||||||
|
pub block_header_version: u16,
|
||||||
|
}
|
||||||
|
|
||||||
/// The state of the current fork tip
|
/// The state of the current fork tip
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Tip {
|
pub struct Tip {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin_chain"
|
name = "grin_chain"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -23,10 +23,10 @@ lru-cache = "0.1"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
|
|
||||||
grin_core = { path = "../core", version = "1.1.1-beta.1" }
|
grin_core = { path = "../core", version = "2.0.0-beta.2" }
|
||||||
grin_keychain = { path = "../keychain", version = "1.1.1-beta.1" }
|
grin_keychain = { path = "../keychain", version = "2.0.0-beta.2" }
|
||||||
grin_store = { path = "../store", version = "1.1.1-beta.1" }
|
grin_store = { path = "../store", version = "2.0.0-beta.2" }
|
||||||
grin_util = { path = "../util", version = "1.1.1-beta.1" }
|
grin_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.5"
|
env_logger = "0.5"
|
||||||
|
|
|
@ -76,7 +76,14 @@ fn data_files() {
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
||||||
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
|
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
|
||||||
let reward = libtx::reward::output(&keychain, &pk, 0, false).unwrap();
|
let reward = libtx::reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&pk,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let mut b =
|
let mut b =
|
||||||
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
|
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -154,7 +161,8 @@ fn _prepare_block_nosum(
|
||||||
let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier();
|
let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier();
|
||||||
|
|
||||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let reward = libtx::reward::output(kc, &key_id, fees, false).unwrap();
|
let reward =
|
||||||
|
libtx::reward::output(kc, &libtx::ProofBuilder::new(kc), &key_id, fees, false).unwrap();
|
||||||
let mut b = match core::core::Block::new(
|
let mut b = match core::core::Block::new(
|
||||||
prev,
|
prev,
|
||||||
txs.into_iter().cloned().collect(),
|
txs.into_iter().cloned().collect(),
|
||||||
|
|
|
@ -19,7 +19,7 @@ use self::core::core::verifier_cache::LruVerifierCache;
|
||||||
use self::core::core::{Block, BlockHeader, OutputIdentifier, Transaction};
|
use self::core::core::{Block, BlockHeader, OutputIdentifier, Transaction};
|
||||||
use self::core::genesis;
|
use self::core::genesis;
|
||||||
use self::core::global::ChainTypes;
|
use self::core::global::ChainTypes;
|
||||||
use self::core::libtx::{self, build, reward};
|
use self::core::libtx::{self, build, reward, ProofBuilder};
|
||||||
use self::core::pow::Difficulty;
|
use self::core::pow::Difficulty;
|
||||||
use self::core::{consensus, global, pow};
|
use self::core::{consensus, global, pow};
|
||||||
use self::keychain::{ExtKeychain, ExtKeychainPath, Keychain};
|
use self::keychain::{ExtKeychain, ExtKeychainPath, Keychain};
|
||||||
|
@ -106,7 +106,14 @@ fn mine_genesis_reward_chain() {
|
||||||
let mut genesis = genesis::genesis_dev();
|
let mut genesis = genesis::genesis_dev();
|
||||||
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
||||||
let key_id = keychain::ExtKeychain::derive_key_id(0, 1, 0, 0, 0);
|
let key_id = keychain::ExtKeychain::derive_key_id(0, 1, 0, 0, 0);
|
||||||
let reward = reward::output(&keychain, &key_id, 0, false).unwrap();
|
let reward = reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&key_id,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
genesis = genesis.with_reward(reward.0, reward.1);
|
genesis = genesis.with_reward(reward.0, reward.1);
|
||||||
|
|
||||||
let tmp_chain_dir = ".grin.tmp";
|
let tmp_chain_dir = ".grin.tmp";
|
||||||
|
@ -143,7 +150,9 @@ where
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
||||||
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
|
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
|
||||||
let reward = libtx::reward::output(keychain, &pk, 0, false).unwrap();
|
let reward =
|
||||||
|
libtx::reward::output(keychain, &libtx::ProofBuilder::new(keychain), &pk, 0, false)
|
||||||
|
.unwrap();
|
||||||
let mut b =
|
let mut b =
|
||||||
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
|
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -401,6 +410,7 @@ fn spend_in_fork_and_compact() {
|
||||||
let chain = setup(".grin6", pow::mine_genesis_block().unwrap());
|
let chain = setup(".grin6", pow::mine_genesis_block().unwrap());
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
let kc = ExtKeychain::from_random_seed(false).unwrap();
|
let kc = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let pb = ProofBuilder::new(&kc);
|
||||||
|
|
||||||
let mut fork_head = prev;
|
let mut fork_head = prev;
|
||||||
|
|
||||||
|
@ -434,6 +444,7 @@ fn spend_in_fork_and_compact() {
|
||||||
build::with_fee(20000),
|
build::with_fee(20000),
|
||||||
],
|
],
|
||||||
&kc,
|
&kc,
|
||||||
|
&pb,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -451,6 +462,7 @@ fn spend_in_fork_and_compact() {
|
||||||
build::with_fee(20000),
|
build::with_fee(20000),
|
||||||
],
|
],
|
||||||
&kc,
|
&kc,
|
||||||
|
&pb,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -540,7 +552,14 @@ fn output_header_mappings() {
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
||||||
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
|
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
|
||||||
let reward = libtx::reward::output(&keychain, &pk, 0, false).unwrap();
|
let reward = libtx::reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&pk,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
reward_outputs.push(reward.0.clone());
|
reward_outputs.push(reward.0.clone());
|
||||||
let mut b =
|
let mut b =
|
||||||
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
|
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
|
||||||
|
@ -643,7 +662,8 @@ where
|
||||||
let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier();
|
let key_id = ExtKeychainPath::new(1, diff as u32, 0, 0, 0).to_identifier();
|
||||||
|
|
||||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let reward = libtx::reward::output(kc, &key_id, fees, false).unwrap();
|
let reward =
|
||||||
|
libtx::reward::output(kc, &libtx::ProofBuilder::new(kc), &key_id, fees, false).unwrap();
|
||||||
let mut b = match core::core::Block::new(
|
let mut b = match core::core::Block::new(
|
||||||
prev,
|
prev,
|
||||||
txs.into_iter().cloned().collect(),
|
txs.into_iter().cloned().collect(),
|
||||||
|
|
|
@ -60,7 +60,14 @@ fn test_various_store_indices() {
|
||||||
|
|
||||||
setup_chain(&genesis, chain_store.clone()).unwrap();
|
setup_chain(&genesis, chain_store.clone()).unwrap();
|
||||||
|
|
||||||
let reward = libtx::reward::output(&keychain, &key_id, 0, false).unwrap();
|
let reward = libtx::reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&key_id,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let block = Block::new(&genesis.header, vec![], Difficulty::min(), reward).unwrap();
|
let block = Block::new(&genesis.header, vec![], Difficulty::min(), reward).unwrap();
|
||||||
let block_hash = block.hash();
|
let block_hash = block.hash();
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ use self::chain::types::NoopAdapter;
|
||||||
use self::chain::ErrorKind;
|
use self::chain::ErrorKind;
|
||||||
use self::core::core::verifier_cache::LruVerifierCache;
|
use self::core::core::verifier_cache::LruVerifierCache;
|
||||||
use self::core::global::{self, ChainTypes};
|
use self::core::global::{self, ChainTypes};
|
||||||
use self::core::libtx::{self, build};
|
use self::core::libtx::{self, build, ProofBuilder};
|
||||||
use self::core::pow::Difficulty;
|
use self::core::pow::Difficulty;
|
||||||
use self::core::{consensus, pow};
|
use self::core::{consensus, pow};
|
||||||
use self::keychain::{ExtKeychain, ExtKeychainPath, Keychain};
|
use self::keychain::{ExtKeychain, ExtKeychainPath, Keychain};
|
||||||
|
@ -59,13 +59,14 @@ fn test_coinbase_maturity() {
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
|
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||||
let key_id2 = ExtKeychainPath::new(1, 2, 0, 0, 0).to_identifier();
|
let key_id2 = ExtKeychainPath::new(1, 2, 0, 0, 0).to_identifier();
|
||||||
let key_id3 = ExtKeychainPath::new(1, 3, 0, 0, 0).to_identifier();
|
let key_id3 = ExtKeychainPath::new(1, 3, 0, 0, 0).to_identifier();
|
||||||
let key_id4 = ExtKeychainPath::new(1, 4, 0, 0, 0).to_identifier();
|
let key_id4 = ExtKeychainPath::new(1, 4, 0, 0, 0).to_identifier();
|
||||||
|
|
||||||
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
||||||
let reward = libtx::reward::output(&keychain, &key_id1, 0, false).unwrap();
|
let reward = libtx::reward::output(&keychain, &builder, &key_id1, 0, false).unwrap();
|
||||||
let mut block = core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap();
|
let mut block = core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap();
|
||||||
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
||||||
block.header.pow.secondary_scaling = next_header_info.secondary_scaling;
|
block.header.pow.secondary_scaling = next_header_info.secondary_scaling;
|
||||||
|
@ -104,12 +105,13 @@ fn test_coinbase_maturity() {
|
||||||
build::with_fee(2),
|
build::with_fee(2),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let txs = vec![coinbase_txn.clone()];
|
let txs = vec![coinbase_txn.clone()];
|
||||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let reward = libtx::reward::output(&keychain, &key_id3, fees, false).unwrap();
|
let reward = libtx::reward::output(&keychain, &builder, &key_id3, fees, false).unwrap();
|
||||||
let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap();
|
let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap();
|
||||||
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
||||||
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
||||||
|
@ -141,10 +143,11 @@ fn test_coinbase_maturity() {
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
|
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||||
|
|
||||||
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
||||||
let reward = libtx::reward::output(&keychain, &key_id1, 0, false).unwrap();
|
let reward = libtx::reward::output(&keychain, &builder, &key_id1, 0, false).unwrap();
|
||||||
let mut block =
|
let mut block =
|
||||||
core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap();
|
core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap();
|
||||||
|
|
||||||
|
@ -185,12 +188,13 @@ fn test_coinbase_maturity() {
|
||||||
build::with_fee(2),
|
build::with_fee(2),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let txs = vec![coinbase_txn.clone()];
|
let txs = vec![coinbase_txn.clone()];
|
||||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let reward = libtx::reward::output(&keychain, &key_id3, fees, false).unwrap();
|
let reward = libtx::reward::output(&keychain, &builder, &key_id3, fees, false).unwrap();
|
||||||
let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap();
|
let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap();
|
||||||
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
||||||
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
||||||
|
@ -222,9 +226,10 @@ fn test_coinbase_maturity() {
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
|
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let pk = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
let pk = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||||
|
|
||||||
let reward = libtx::reward::output(&keychain, &pk, 0, false).unwrap();
|
let reward = libtx::reward::output(&keychain, &builder, &pk, 0, false).unwrap();
|
||||||
let mut block =
|
let mut block =
|
||||||
core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap();
|
core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap();
|
||||||
let next_header_info =
|
let next_header_info =
|
||||||
|
@ -254,7 +259,7 @@ fn test_coinbase_maturity() {
|
||||||
let txs = vec![coinbase_txn];
|
let txs = vec![coinbase_txn];
|
||||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
|
||||||
let reward = libtx::reward::output(&keychain, &key_id4, fees, false).unwrap();
|
let reward = libtx::reward::output(&keychain, &builder, &key_id4, fees, false).unwrap();
|
||||||
let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap();
|
let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap();
|
||||||
|
|
||||||
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
block.header.timestamp = prev.timestamp + Duration::seconds(60);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin_config"
|
name = "grin_config"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "Configuration for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "Configuration for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -16,10 +16,10 @@ serde_derive = "1"
|
||||||
toml = "0.4"
|
toml = "0.4"
|
||||||
dirs = "1.0.3"
|
dirs = "1.0.3"
|
||||||
|
|
||||||
grin_core = { path = "../core", version = "1.1.1-beta.1" }
|
grin_core = { path = "../core", version = "2.0.0-beta.2" }
|
||||||
grin_servers = { path = "../servers", version = "1.1.1-beta.1" }
|
grin_servers = { path = "../servers", version = "2.0.0-beta.2" }
|
||||||
grin_p2p = { path = "../p2p", version = "1.1.1-beta.1" }
|
grin_p2p = { path = "../p2p", version = "2.0.0-beta.2" }
|
||||||
grin_util = { path = "../util", version = "1.1.1-beta.1" }
|
grin_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "0.5.1"
|
pretty_assertions = "0.5.1"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin_core"
|
name = "grin_core"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -27,9 +27,10 @@ siphasher = "0.2"
|
||||||
uuid = { version = "0.6", features = ["serde", "v4"] }
|
uuid = { version = "0.6", features = ["serde", "v4"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
chrono = { version = "0.4.4", features = ["serde"] }
|
chrono = { version = "0.4.4", features = ["serde"] }
|
||||||
|
zeroize = "0.9"
|
||||||
|
|
||||||
grin_keychain = { path = "../keychain", version = "1.1.1-beta.1" }
|
grin_keychain = { path = "../keychain", version = "2.0.0-beta.2" }
|
||||||
grin_util = { path = "../util", version = "1.1.1-beta.1" }
|
grin_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
|
|
@ -127,22 +127,42 @@ pub const MAX_BLOCK_WEIGHT: usize = 40_000;
|
||||||
/// Fork every 6 months.
|
/// Fork every 6 months.
|
||||||
pub const HARD_FORK_INTERVAL: u64 = YEAR_HEIGHT / 2;
|
pub const HARD_FORK_INTERVAL: u64 = YEAR_HEIGHT / 2;
|
||||||
|
|
||||||
|
/// Floonet first hard fork height, set to happen around 2019-06-20
|
||||||
|
pub const FLOONET_FIRST_HARD_FORK: u64 = 185_040;
|
||||||
|
|
||||||
/// Check whether the block version is valid at a given height, implements
|
/// Check whether the block version is valid at a given height, implements
|
||||||
/// 6 months interval scheduled hard forks for the first 2 years.
|
/// 6 months interval scheduled hard forks for the first 2 years.
|
||||||
pub fn valid_header_version(height: u64, version: HeaderVersion) -> bool {
|
pub fn valid_header_version(height: u64, version: HeaderVersion) -> bool {
|
||||||
// uncomment below as we go from hard fork to hard fork
|
let chain_type = global::CHAIN_TYPE.read().clone();
|
||||||
if height < HARD_FORK_INTERVAL {
|
match chain_type {
|
||||||
version == HeaderVersion::default()
|
global::ChainTypes::Floonet => {
|
||||||
/* } else if height < 2 * HARD_FORK_INTERVAL {
|
if height < FLOONET_FIRST_HARD_FORK {
|
||||||
version == 2
|
version == HeaderVersion::default()
|
||||||
} else if height < 3 * HARD_FORK_INTERVAL {
|
// add branches one by one as we go from hard fork to hard fork
|
||||||
version == 3
|
// } else if height < FLOONET_SECOND_HARD_FORK {
|
||||||
} else if height < 4 * HARD_FORK_INTERVAL {
|
} else if height < 2 * HARD_FORK_INTERVAL {
|
||||||
version == 4
|
version == HeaderVersion::new(2)
|
||||||
} else if height >= 5 * HARD_FORK_INTERVAL {
|
} else {
|
||||||
version > 4 */
|
false
|
||||||
} else {
|
}
|
||||||
false
|
}
|
||||||
|
// everything else just like mainnet
|
||||||
|
_ => {
|
||||||
|
if height < HARD_FORK_INTERVAL {
|
||||||
|
version == HeaderVersion::default()
|
||||||
|
} else if height < 2 * HARD_FORK_INTERVAL {
|
||||||
|
version == HeaderVersion::new(2)
|
||||||
|
// uncomment branches one by one as we go from hard fork to hard fork
|
||||||
|
/*} else if height < 3 * HARD_FORK_INTERVAL {
|
||||||
|
version == HeaderVersion::new(3)
|
||||||
|
} else if height < 4 * HARD_FORK_INTERVAL {
|
||||||
|
version == HeaderVersion::new(4)
|
||||||
|
} else {
|
||||||
|
version > HeaderVersion::new(4) */
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,14 +183,14 @@ pub const DIFFICULTY_DAMP_FACTOR: u64 = 3;
|
||||||
pub const AR_SCALE_DAMP_FACTOR: u64 = 13;
|
pub const AR_SCALE_DAMP_FACTOR: u64 = 13;
|
||||||
|
|
||||||
/// Compute weight of a graph as number of siphash bits defining the graph
|
/// Compute weight of a graph as number of siphash bits defining the graph
|
||||||
/// Must be made dependent on height to phase out smaller size over the years
|
/// Must be made dependent on height to phase out C31 in early 2020
|
||||||
/// This can wait until end of 2019 at latest
|
/// Later phase outs are on hold for now
|
||||||
pub fn graph_weight(height: u64, edge_bits: u8) -> u64 {
|
pub fn graph_weight(height: u64, edge_bits: u8) -> u64 {
|
||||||
let mut xpr_edge_bits = edge_bits as u64;
|
let mut xpr_edge_bits = edge_bits as u64;
|
||||||
|
|
||||||
let bits_over_min = edge_bits.saturating_sub(global::min_edge_bits());
|
let bits_over_min = edge_bits.saturating_sub(global::min_edge_bits());
|
||||||
let expiry_height = (1 << bits_over_min) * YEAR_HEIGHT;
|
let expiry_height = (1 << bits_over_min) * YEAR_HEIGHT;
|
||||||
if height >= expiry_height {
|
if edge_bits < 32 && height >= expiry_height {
|
||||||
xpr_edge_bits = xpr_edge_bits.saturating_sub(1 + (height - expiry_height) / WEEK_HEIGHT);
|
xpr_edge_bits = xpr_edge_bits.saturating_sub(1 + (height - expiry_height) / WEEK_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,23 +382,29 @@ mod test {
|
||||||
|
|
||||||
// 2 years in, 31 still at 0, 32 starts decreasing
|
// 2 years in, 31 still at 0, 32 starts decreasing
|
||||||
assert_eq!(graph_weight(2 * YEAR_HEIGHT, 31), 0);
|
assert_eq!(graph_weight(2 * YEAR_HEIGHT, 31), 0);
|
||||||
assert_eq!(graph_weight(2 * YEAR_HEIGHT, 32), 512 * 31);
|
assert_eq!(graph_weight(2 * YEAR_HEIGHT, 32), 512 * 32);
|
||||||
assert_eq!(graph_weight(2 * YEAR_HEIGHT, 33), 1024 * 33);
|
assert_eq!(graph_weight(2 * YEAR_HEIGHT, 33), 1024 * 33);
|
||||||
|
|
||||||
// 32 loses one factor per week
|
// 32 phaseout on hold
|
||||||
assert_eq!(graph_weight(2 * YEAR_HEIGHT + WEEK_HEIGHT, 32), 512 * 30);
|
assert_eq!(graph_weight(2 * YEAR_HEIGHT + WEEK_HEIGHT, 32), 512 * 32);
|
||||||
assert_eq!(graph_weight(2 * YEAR_HEIGHT + WEEK_HEIGHT, 31), 0);
|
assert_eq!(graph_weight(2 * YEAR_HEIGHT + WEEK_HEIGHT, 31), 0);
|
||||||
assert_eq!(graph_weight(2 * YEAR_HEIGHT + 30 * WEEK_HEIGHT, 32), 512);
|
assert_eq!(
|
||||||
assert_eq!(graph_weight(2 * YEAR_HEIGHT + 31 * WEEK_HEIGHT, 32), 0);
|
graph_weight(2 * YEAR_HEIGHT + 30 * WEEK_HEIGHT, 32),
|
||||||
|
512 * 32
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
graph_weight(2 * YEAR_HEIGHT + 31 * WEEK_HEIGHT, 32),
|
||||||
|
512 * 32
|
||||||
|
);
|
||||||
|
|
||||||
// 3 years in, nothing changes
|
// 3 years in, nothing changes
|
||||||
assert_eq!(graph_weight(3 * YEAR_HEIGHT, 31), 0);
|
assert_eq!(graph_weight(3 * YEAR_HEIGHT, 31), 0);
|
||||||
assert_eq!(graph_weight(3 * YEAR_HEIGHT, 32), 0);
|
assert_eq!(graph_weight(3 * YEAR_HEIGHT, 32), 512 * 32);
|
||||||
assert_eq!(graph_weight(3 * YEAR_HEIGHT, 33), 1024 * 33);
|
assert_eq!(graph_weight(3 * YEAR_HEIGHT, 33), 1024 * 33);
|
||||||
|
|
||||||
// 4 years in, 33 starts starts decreasing
|
// 4 years in, still on hold
|
||||||
assert_eq!(graph_weight(4 * YEAR_HEIGHT, 31), 0);
|
assert_eq!(graph_weight(4 * YEAR_HEIGHT, 31), 0);
|
||||||
assert_eq!(graph_weight(4 * YEAR_HEIGHT, 32), 0);
|
assert_eq!(graph_weight(4 * YEAR_HEIGHT, 32), 512 * 32);
|
||||||
assert_eq!(graph_weight(4 * YEAR_HEIGHT, 33), 1024 * 32);
|
assert_eq!(graph_weight(4 * YEAR_HEIGHT, 33), 1024 * 33);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,6 +178,13 @@ impl Default for HeaderVersion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// self-conscious increment function courtesy of Jasper
|
||||||
|
impl HeaderVersion {
|
||||||
|
fn next(&self) -> Self {
|
||||||
|
Self(self.0 + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl HeaderVersion {
|
impl HeaderVersion {
|
||||||
/// Constructor taking the provided version.
|
/// Constructor taking the provided version.
|
||||||
pub fn new(version: u16) -> HeaderVersion {
|
pub fn new(version: u16) -> HeaderVersion {
|
||||||
|
@ -565,6 +572,13 @@ impl Block {
|
||||||
vec![],
|
vec![],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
let height = prev.height + 1;
|
||||||
|
|
||||||
|
let mut version = prev.version;
|
||||||
|
if !consensus::valid_header_version(height, version) {
|
||||||
|
version = version.next();
|
||||||
|
}
|
||||||
|
|
||||||
let now = Utc::now().timestamp();
|
let now = Utc::now().timestamp();
|
||||||
let timestamp = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(now, 0), Utc);
|
let timestamp = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(now, 0), Utc);
|
||||||
|
|
||||||
|
@ -573,7 +587,8 @@ impl Block {
|
||||||
// Caller must validate the block as necessary.
|
// Caller must validate the block as necessary.
|
||||||
Block {
|
Block {
|
||||||
header: BlockHeader {
|
header: BlockHeader {
|
||||||
height: prev.height + 1,
|
version,
|
||||||
|
height,
|
||||||
timestamp,
|
timestamp,
|
||||||
prev_hash: prev.hash(),
|
prev_hash: prev.hash(),
|
||||||
total_kernel_offset,
|
total_kernel_offset,
|
||||||
|
|
|
@ -1499,14 +1499,16 @@ mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::core::hash::Hash;
|
use crate::core::hash::Hash;
|
||||||
use crate::core::id::{ShortId, ShortIdentifiable};
|
use crate::core::id::{ShortId, ShortIdentifiable};
|
||||||
use crate::keychain::{ExtKeychain, Keychain};
|
use crate::keychain::{ExtKeychain, Keychain, SwitchCommitmentType};
|
||||||
use crate::util::secp;
|
use crate::util::secp;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_kernel_ser_deser() {
|
fn test_kernel_ser_deser() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let commit = keychain.commit(5, &key_id).unwrap();
|
let commit = keychain
|
||||||
|
.commit(5, &key_id, &SwitchCommitmentType::Regular)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// just some bytes for testing ser/deser
|
// just some bytes for testing ser/deser
|
||||||
let sig = secp::Signature::from_raw_data(&[0; 64]).unwrap();
|
let sig = secp::Signature::from_raw_data(&[0; 64]).unwrap();
|
||||||
|
@ -1552,10 +1554,14 @@ mod test {
|
||||||
let keychain = ExtKeychain::from_seed(&[0; 32], false).unwrap();
|
let keychain = ExtKeychain::from_seed(&[0; 32], false).unwrap();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
|
|
||||||
let commit = keychain.commit(1003, &key_id).unwrap();
|
let commit = keychain
|
||||||
|
.commit(1003, &key_id, &SwitchCommitmentType::Regular)
|
||||||
|
.unwrap();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
|
|
||||||
let commit_2 = keychain.commit(1003, &key_id).unwrap();
|
let commit_2 = keychain
|
||||||
|
.commit(1003, &key_id, &SwitchCommitmentType::Regular)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(commit == commit_2);
|
assert!(commit == commit_2);
|
||||||
}
|
}
|
||||||
|
@ -1564,7 +1570,9 @@ mod test {
|
||||||
fn input_short_id() {
|
fn input_short_id() {
|
||||||
let keychain = ExtKeychain::from_seed(&[0; 32], false).unwrap();
|
let keychain = ExtKeychain::from_seed(&[0; 32], false).unwrap();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let commit = keychain.commit(5, &key_id).unwrap();
|
let commit = keychain
|
||||||
|
.commit(5, &key_id, &SwitchCommitmentType::Regular)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let input = Input {
|
let input = Input {
|
||||||
features: OutputFeatures::Plain,
|
features: OutputFeatures::Plain,
|
||||||
|
|
|
@ -16,13 +16,16 @@
|
||||||
//! having to pass them all over the place, but aren't consensus values.
|
//! having to pass them all over the place, but aren't consensus values.
|
||||||
//! should be used sparingly.
|
//! should be used sparingly.
|
||||||
|
|
||||||
use crate::consensus::HeaderInfo;
|
|
||||||
use crate::consensus::{
|
use crate::consensus::{
|
||||||
graph_weight, BASE_EDGE_BITS, BLOCK_TIME_SEC, COINBASE_MATURITY, CUT_THROUGH_HORIZON,
|
graph_weight, valid_header_version, HeaderInfo, BASE_EDGE_BITS, BLOCK_TIME_SEC,
|
||||||
DAY_HEIGHT, DEFAULT_MIN_EDGE_BITS, DIFFICULTY_ADJUST_WINDOW, INITIAL_DIFFICULTY,
|
COINBASE_MATURITY, CUT_THROUGH_HORIZON, DAY_HEIGHT, DEFAULT_MIN_EDGE_BITS,
|
||||||
MAX_BLOCK_WEIGHT, PROOFSIZE, SECOND_POW_EDGE_BITS, STATE_SYNC_THRESHOLD,
|
DIFFICULTY_ADJUST_WINDOW, INITIAL_DIFFICULTY, MAX_BLOCK_WEIGHT, PROOFSIZE,
|
||||||
|
SECOND_POW_EDGE_BITS, STATE_SYNC_THRESHOLD,
|
||||||
|
};
|
||||||
|
use crate::core::block::HeaderVersion;
|
||||||
|
use crate::pow::{
|
||||||
|
self, new_cuckaroo_ctx, new_cuckarood_ctx, new_cuckatoo_ctx, EdgeType, PoWContext,
|
||||||
};
|
};
|
||||||
use crate::pow::{self, new_cuckaroo_ctx, new_cuckatoo_ctx, EdgeType, PoWContext};
|
|
||||||
/// An enum collecting sets of parameters used throughout the
|
/// An enum collecting sets of parameters used throughout the
|
||||||
/// code wherever mining is needed. This should allow for
|
/// code wherever mining is needed. This should allow for
|
||||||
/// different sets of parameters for different purposes,
|
/// different sets of parameters for different purposes,
|
||||||
|
@ -144,7 +147,7 @@ pub fn set_mining_mode(mode: ChainTypes) {
|
||||||
/// Return either a cuckoo context or a cuckatoo context
|
/// Return either a cuckoo context or a cuckatoo context
|
||||||
/// Single change point
|
/// Single change point
|
||||||
pub fn create_pow_context<T>(
|
pub fn create_pow_context<T>(
|
||||||
_height: u64,
|
height: u64,
|
||||||
edge_bits: u8,
|
edge_bits: u8,
|
||||||
proof_size: usize,
|
proof_size: usize,
|
||||||
max_sols: u32,
|
max_sols: u32,
|
||||||
|
@ -154,13 +157,19 @@ where
|
||||||
{
|
{
|
||||||
let chain_type = CHAIN_TYPE.read().clone();
|
let chain_type = CHAIN_TYPE.read().clone();
|
||||||
match chain_type {
|
match chain_type {
|
||||||
// Mainnet has Cuckaroo29 for AR and Cuckatoo30+ for AF
|
// Mainnet has Cuckaroo(d)29 for AR and Cuckatoo31+ for AF
|
||||||
ChainTypes::Mainnet if edge_bits == 29 => new_cuckaroo_ctx(edge_bits, proof_size),
|
ChainTypes::Mainnet if edge_bits > 29 => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
|
||||||
ChainTypes::Mainnet => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
|
ChainTypes::Mainnet if valid_header_version(height, HeaderVersion::new(2)) => {
|
||||||
|
new_cuckarood_ctx(edge_bits, proof_size)
|
||||||
|
}
|
||||||
|
ChainTypes::Mainnet => new_cuckaroo_ctx(edge_bits, proof_size),
|
||||||
|
|
||||||
// Same for Floonet
|
// Same for Floonet
|
||||||
ChainTypes::Floonet if edge_bits == 29 => new_cuckaroo_ctx(edge_bits, proof_size),
|
ChainTypes::Floonet if edge_bits > 29 => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
|
||||||
ChainTypes::Floonet => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
|
ChainTypes::Floonet if valid_header_version(height, HeaderVersion::new(2)) => {
|
||||||
|
new_cuckarood_ctx(edge_bits, proof_size)
|
||||||
|
}
|
||||||
|
ChainTypes::Floonet => new_cuckaroo_ctx(edge_bits, proof_size),
|
||||||
|
|
||||||
// Everything else is Cuckatoo only
|
// Everything else is Cuckatoo only
|
||||||
_ => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
|
_ => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
|
||||||
|
|
|
@ -36,6 +36,7 @@ extern crate log;
|
||||||
use failure;
|
use failure;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate failure_derive;
|
extern crate failure_derive;
|
||||||
|
extern crate zeroize;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ use crate::libtx::error::{Error, ErrorKind};
|
||||||
use crate::util::secp::key::{PublicKey, SecretKey};
|
use crate::util::secp::key::{PublicKey, SecretKey};
|
||||||
use crate::util::secp::pedersen::Commitment;
|
use crate::util::secp::pedersen::Commitment;
|
||||||
use crate::util::secp::{self, aggsig, Message, Secp256k1, Signature};
|
use crate::util::secp::{self, aggsig, Message, Secp256k1, Signature};
|
||||||
|
use grin_keychain::SwitchCommitmentType;
|
||||||
|
|
||||||
/// Creates a new secure nonce (as a SecretKey), guaranteed to be usable during
|
/// Creates a new secure nonce (as a SecretKey), guaranteed to be usable during
|
||||||
/// aggsig creation.
|
/// aggsig creation.
|
||||||
|
@ -231,15 +232,17 @@ pub fn verify_partial_sig(
|
||||||
/// use core::libtx::{aggsig, proof};
|
/// use core::libtx::{aggsig, proof};
|
||||||
/// use core::core::transaction::{kernel_sig_msg, KernelFeatures};
|
/// use core::core::transaction::{kernel_sig_msg, KernelFeatures};
|
||||||
/// use core::core::{Output, OutputFeatures};
|
/// use core::core::{Output, OutputFeatures};
|
||||||
/// use keychain::{Keychain, ExtKeychain};
|
/// use keychain::{Keychain, ExtKeychain, SwitchCommitmentType};
|
||||||
///
|
///
|
||||||
/// let secp = Secp256k1::with_caps(ContextFlag::Commit);
|
/// let secp = Secp256k1::with_caps(ContextFlag::Commit);
|
||||||
/// let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
/// let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
/// let fees = 10_000;
|
/// let fees = 10_000;
|
||||||
/// let value = reward(fees);
|
/// let value = reward(fees);
|
||||||
/// let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
/// let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
/// let commit = keychain.commit(value, &key_id).unwrap();
|
/// let switch = &SwitchCommitmentType::Regular;
|
||||||
/// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap();
|
/// let commit = keychain.commit(value, &key_id, switch).unwrap();
|
||||||
|
/// let builder = proof::ProofBuilder::new(&keychain);
|
||||||
|
/// let rproof = proof::create(&keychain, &builder, value, &key_id, switch, commit, None).unwrap();
|
||||||
/// let output = Output {
|
/// let output = Output {
|
||||||
/// features: OutputFeatures::Coinbase,
|
/// features: OutputFeatures::Coinbase,
|
||||||
/// commit: commit,
|
/// commit: commit,
|
||||||
|
@ -266,7 +269,7 @@ pub fn sign_from_key_id<K>(
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let skey = k.derive_key(value, key_id)?;
|
let skey = k.derive_key(value, key_id, &SwitchCommitmentType::Regular)?; // TODO: proper support for different switch commitment schemes
|
||||||
let sig = aggsig::sign_single(secp, &msg, &skey, s_nonce, None, None, blind_sum, None)?;
|
let sig = aggsig::sign_single(secp, &msg, &skey, s_nonce, None, None, blind_sum, None)?;
|
||||||
Ok(sig)
|
Ok(sig)
|
||||||
}
|
}
|
||||||
|
@ -296,7 +299,7 @@ where
|
||||||
/// use util::secp::{ContextFlag, Secp256k1};
|
/// use util::secp::{ContextFlag, Secp256k1};
|
||||||
/// use core::core::transaction::{kernel_sig_msg, KernelFeatures};
|
/// use core::core::transaction::{kernel_sig_msg, KernelFeatures};
|
||||||
/// use core::core::{Output, OutputFeatures};
|
/// use core::core::{Output, OutputFeatures};
|
||||||
/// use keychain::{Keychain, ExtKeychain};
|
/// use keychain::{Keychain, ExtKeychain, SwitchCommitmentType};
|
||||||
///
|
///
|
||||||
/// // Create signature
|
/// // Create signature
|
||||||
/// let secp = Secp256k1::with_caps(ContextFlag::Commit);
|
/// let secp = Secp256k1::with_caps(ContextFlag::Commit);
|
||||||
|
@ -304,8 +307,10 @@ where
|
||||||
/// let fees = 10_000;
|
/// let fees = 10_000;
|
||||||
/// let value = reward(fees);
|
/// let value = reward(fees);
|
||||||
/// let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
/// let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
/// let commit = keychain.commit(value, &key_id).unwrap();
|
/// let switch = &SwitchCommitmentType::Regular;
|
||||||
/// let rproof = proof::create(&keychain, value, &key_id, commit, None).unwrap();
|
/// let commit = keychain.commit(value, &key_id, switch).unwrap();
|
||||||
|
/// let builder = proof::ProofBuilder::new(&keychain);
|
||||||
|
/// let rproof = proof::create(&keychain, &builder, value, &key_id, switch, commit, None).unwrap();
|
||||||
/// let output = Output {
|
/// let output = Output {
|
||||||
/// features: OutputFeatures::Coinbase,
|
/// features: OutputFeatures::Coinbase,
|
||||||
/// commit: commit,
|
/// commit: commit,
|
||||||
|
|
|
@ -27,33 +27,42 @@
|
||||||
|
|
||||||
use crate::core::{Input, Output, OutputFeatures, Transaction, TxKernel};
|
use crate::core::{Input, Output, OutputFeatures, Transaction, TxKernel};
|
||||||
use crate::keychain::{BlindSum, BlindingFactor, Identifier, Keychain};
|
use crate::keychain::{BlindSum, BlindingFactor, Identifier, Keychain};
|
||||||
use crate::libtx::{aggsig, proof, Error};
|
use crate::libtx::proof::{self, ProofBuild};
|
||||||
|
use crate::libtx::{aggsig, Error};
|
||||||
|
use grin_keychain::SwitchCommitmentType;
|
||||||
|
|
||||||
/// Context information available to transaction combinators.
|
/// Context information available to transaction combinators.
|
||||||
pub struct Context<'a, K>
|
pub struct Context<'a, K, B>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
/// The keychain used for key derivation
|
/// The keychain used for key derivation
|
||||||
pub keychain: &'a K,
|
pub keychain: &'a K,
|
||||||
|
/// The bulletproof builder
|
||||||
|
pub builder: &'a B,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function type returned by the transaction combinators. Transforms a
|
/// Function type returned by the transaction combinators. Transforms a
|
||||||
/// (Transaction, BlindSum) pair into another, provided some context.
|
/// (Transaction, BlindSum) pair into another, provided some context.
|
||||||
pub type Append<K> = dyn for<'a> Fn(
|
pub type Append<K, B> = dyn for<'a> Fn(
|
||||||
&'a mut Context<'_, K>,
|
&'a mut Context<'_, K, B>,
|
||||||
(Transaction, TxKernel, BlindSum),
|
(Transaction, TxKernel, BlindSum),
|
||||||
) -> (Transaction, TxKernel, BlindSum);
|
) -> (Transaction, TxKernel, BlindSum);
|
||||||
|
|
||||||
/// Adds an input with the provided value and blinding key to the transaction
|
/// Adds an input with the provided value and blinding key to the transaction
|
||||||
/// being built.
|
/// being built.
|
||||||
fn build_input<K>(value: u64, features: OutputFeatures, key_id: Identifier) -> Box<Append<K>>
|
fn build_input<K, B>(value: u64, features: OutputFeatures, key_id: Identifier) -> Box<Append<K, B>>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
let commit = build.keychain.commit(value, &key_id).unwrap();
|
let commit = build
|
||||||
|
.keychain
|
||||||
|
.commit(value, &key_id, &SwitchCommitmentType::Regular)
|
||||||
|
.unwrap(); // TODO: proper support for different switch commitment schemes
|
||||||
let input = Input::new(features, commit);
|
let input = Input::new(features, commit);
|
||||||
(
|
(
|
||||||
tx.with_input(input),
|
tx.with_input(input),
|
||||||
|
@ -66,9 +75,10 @@ where
|
||||||
|
|
||||||
/// Adds an input with the provided value and blinding key to the transaction
|
/// Adds an input with the provided value and blinding key to the transaction
|
||||||
/// being built.
|
/// being built.
|
||||||
pub fn input<K>(value: u64, key_id: Identifier) -> Box<Append<K>>
|
pub fn input<K, B>(value: u64, key_id: Identifier) -> Box<Append<K, B>>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
debug!(
|
debug!(
|
||||||
"Building input (spending regular output): {}, {}",
|
"Building input (spending regular output): {}, {}",
|
||||||
|
@ -78,9 +88,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a coinbase input spending a coinbase output.
|
/// Adds a coinbase input spending a coinbase output.
|
||||||
pub fn coinbase_input<K>(value: u64, key_id: Identifier) -> Box<Append<K>>
|
pub fn coinbase_input<K, B>(value: u64, key_id: Identifier) -> Box<Append<K, B>>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
debug!("Building input (spending coinbase): {}, {}", value, key_id);
|
debug!("Building input (spending coinbase): {}, {}", value, key_id);
|
||||||
build_input(value, OutputFeatures::Coinbase, key_id)
|
build_input(value, OutputFeatures::Coinbase, key_id)
|
||||||
|
@ -88,17 +99,30 @@ where
|
||||||
|
|
||||||
/// Adds an output with the provided value and key identifier from the
|
/// Adds an output with the provided value and key identifier from the
|
||||||
/// keychain.
|
/// keychain.
|
||||||
pub fn output<K>(value: u64, key_id: Identifier) -> Box<Append<K>>
|
pub fn output<K, B>(value: u64, key_id: Identifier) -> Box<Append<K, B>>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
let commit = build.keychain.commit(value, &key_id).unwrap();
|
// TODO: proper support for different switch commitment schemes
|
||||||
|
let switch = &SwitchCommitmentType::Regular;
|
||||||
|
|
||||||
|
let commit = build.keychain.commit(value, &key_id, switch).unwrap();
|
||||||
|
|
||||||
debug!("Building output: {}, {:?}", value, commit);
|
debug!("Building output: {}, {:?}", value, commit);
|
||||||
|
|
||||||
let rproof = proof::create(build.keychain, value, &key_id, commit, None).unwrap();
|
let rproof = proof::create(
|
||||||
|
build.keychain,
|
||||||
|
build.builder,
|
||||||
|
value,
|
||||||
|
&key_id,
|
||||||
|
switch,
|
||||||
|
commit,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
(
|
(
|
||||||
tx.with_output(Output {
|
tx.with_output(Output {
|
||||||
|
@ -114,9 +138,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the fee on the transaction being built.
|
/// Sets the fee on the transaction being built.
|
||||||
pub fn with_fee<K>(fee: u64) -> Box<Append<K>>
|
pub fn with_fee<K, B>(fee: u64) -> Box<Append<K, B>>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
|
@ -126,9 +151,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the lock_height on the transaction being built.
|
/// Sets the lock_height on the transaction being built.
|
||||||
pub fn with_lock_height<K>(lock_height: u64) -> Box<Append<K>>
|
pub fn with_lock_height<K, B>(lock_height: u64) -> Box<Append<K, B>>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
|
@ -140,9 +166,10 @@ where
|
||||||
/// Adds a known excess value on the transaction being built. Usually used in
|
/// Adds a known excess value on the transaction being built. Usually used in
|
||||||
/// combination with the initial_tx function when a new transaction is built
|
/// combination with the initial_tx function when a new transaction is built
|
||||||
/// by adding to a pre-existing one.
|
/// by adding to a pre-existing one.
|
||||||
pub fn with_excess<K>(excess: BlindingFactor) -> Box<Append<K>>
|
pub fn with_excess<K, B>(excess: BlindingFactor) -> Box<Append<K, B>>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
|
@ -152,9 +179,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a known tx "offset". Used in final step of tx construction.
|
/// Sets a known tx "offset". Used in final step of tx construction.
|
||||||
pub fn with_offset<K>(offset: BlindingFactor) -> Box<Append<K>>
|
pub fn with_offset<K, B>(offset: BlindingFactor) -> Box<Append<K, B>>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
|
@ -166,9 +194,10 @@ where
|
||||||
/// Sets an initial transaction to add to when building a new transaction.
|
/// Sets an initial transaction to add to when building a new transaction.
|
||||||
/// We currently only support building a tx with a single kernel with
|
/// We currently only support building a tx with a single kernel with
|
||||||
/// build::transaction()
|
/// build::transaction()
|
||||||
pub fn initial_tx<K>(mut tx: Transaction) -> Box<Append<K>>
|
pub fn initial_tx<K, B>(mut tx: Transaction) -> Box<Append<K, B>>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
assert_eq!(tx.kernels().len(), 1);
|
assert_eq!(tx.kernels().len(), 1);
|
||||||
let kern = tx.kernels_mut().remove(0);
|
let kern = tx.kernels_mut().remove(0);
|
||||||
|
@ -189,14 +218,16 @@ where
|
||||||
/// let (tx2, _) = build::transaction(vec![initial_tx(tx1), with_excess(sum),
|
/// let (tx2, _) = build::transaction(vec![initial_tx(tx1), with_excess(sum),
|
||||||
/// output_rand(2)], keychain).unwrap();
|
/// output_rand(2)], keychain).unwrap();
|
||||||
///
|
///
|
||||||
pub fn partial_transaction<K>(
|
pub fn partial_transaction<K, B>(
|
||||||
elems: Vec<Box<Append<K>>>,
|
elems: Vec<Box<Append<K, B>>>,
|
||||||
keychain: &K,
|
keychain: &K,
|
||||||
|
builder: &B,
|
||||||
) -> Result<(Transaction, BlindingFactor), Error>
|
) -> Result<(Transaction, BlindingFactor), Error>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
let mut ctx = Context { keychain };
|
let mut ctx = Context { keychain, builder };
|
||||||
let (tx, kern, sum) = elems.iter().fold(
|
let (tx, kern, sum) = elems.iter().fold(
|
||||||
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
||||||
|acc, elem| elem(&mut ctx, acc),
|
|acc, elem| elem(&mut ctx, acc),
|
||||||
|
@ -212,11 +243,16 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a complete transaction.
|
/// Builds a complete transaction.
|
||||||
pub fn transaction<K>(elems: Vec<Box<Append<K>>>, keychain: &K) -> Result<Transaction, Error>
|
pub fn transaction<K, B>(
|
||||||
|
elems: Vec<Box<Append<K, B>>>,
|
||||||
|
keychain: &K,
|
||||||
|
builder: &B,
|
||||||
|
) -> Result<Transaction, Error>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
let mut ctx = Context { keychain };
|
let mut ctx = Context { keychain, builder };
|
||||||
let (mut tx, mut kern, sum) = elems.iter().fold(
|
let (mut tx, mut kern, sum) = elems.iter().fold(
|
||||||
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
||||||
|acc, elem| elem(&mut ctx, acc),
|
|acc, elem| elem(&mut ctx, acc),
|
||||||
|
@ -260,6 +296,7 @@ mod test {
|
||||||
use crate::core::transaction::Weighting;
|
use crate::core::transaction::Weighting;
|
||||||
use crate::core::verifier_cache::{LruVerifierCache, VerifierCache};
|
use crate::core::verifier_cache::{LruVerifierCache, VerifierCache};
|
||||||
use crate::keychain::{ExtKeychain, ExtKeychainPath};
|
use crate::keychain::{ExtKeychain, ExtKeychainPath};
|
||||||
|
use crate::libtx::ProofBuilder;
|
||||||
|
|
||||||
fn verifier_cache() -> Arc<RwLock<dyn VerifierCache>> {
|
fn verifier_cache() -> Arc<RwLock<dyn VerifierCache>> {
|
||||||
Arc::new(RwLock::new(LruVerifierCache::new()))
|
Arc::new(RwLock::new(LruVerifierCache::new()))
|
||||||
|
@ -268,6 +305,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn blind_simple_tx() {
|
fn blind_simple_tx() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||||
let key_id2 = ExtKeychainPath::new(1, 2, 0, 0, 0).to_identifier();
|
let key_id2 = ExtKeychainPath::new(1, 2, 0, 0, 0).to_identifier();
|
||||||
let key_id3 = ExtKeychainPath::new(1, 3, 0, 0, 0).to_identifier();
|
let key_id3 = ExtKeychainPath::new(1, 3, 0, 0, 0).to_identifier();
|
||||||
|
@ -282,6 +320,7 @@ mod test {
|
||||||
with_fee(2),
|
with_fee(2),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -291,6 +330,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn blind_simple_tx_with_offset() {
|
fn blind_simple_tx_with_offset() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||||
let key_id2 = ExtKeychainPath::new(1, 2, 0, 0, 0).to_identifier();
|
let key_id2 = ExtKeychainPath::new(1, 2, 0, 0, 0).to_identifier();
|
||||||
let key_id3 = ExtKeychainPath::new(1, 3, 0, 0, 0).to_identifier();
|
let key_id3 = ExtKeychainPath::new(1, 3, 0, 0, 0).to_identifier();
|
||||||
|
@ -305,6 +345,7 @@ mod test {
|
||||||
with_fee(2),
|
with_fee(2),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -314,6 +355,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn blind_simpler_tx() {
|
fn blind_simpler_tx() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||||
let key_id2 = ExtKeychainPath::new(1, 2, 0, 0, 0).to_identifier();
|
let key_id2 = ExtKeychainPath::new(1, 2, 0, 0, 0).to_identifier();
|
||||||
|
|
||||||
|
@ -322,6 +364,7 @@ mod test {
|
||||||
let tx = transaction(
|
let tx = transaction(
|
||||||
vec![input(6, key_id1), output(2, key_id2), with_fee(4)],
|
vec![input(6, key_id1), output(2, key_id2), with_fee(4)],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub mod secp_ser;
|
||||||
use crate::consensus;
|
use crate::consensus;
|
||||||
use crate::core::Transaction;
|
use crate::core::Transaction;
|
||||||
|
|
||||||
|
pub use self::proof::ProofBuilder;
|
||||||
pub use crate::libtx::error::{Error, ErrorKind};
|
pub use crate::libtx::error::{Error, ErrorKind};
|
||||||
|
|
||||||
const DEFAULT_BASE_FEE: u64 = consensus::MILLI_GRIN;
|
const DEFAULT_BASE_FEE: u64 = consensus::MILLI_GRIN;
|
||||||
|
|
|
@ -14,31 +14,47 @@
|
||||||
|
|
||||||
//! Rangeproof library functions
|
//! Rangeproof library functions
|
||||||
|
|
||||||
use crate::keychain::{Identifier, Keychain};
|
use crate::blake2::blake2b::blake2b;
|
||||||
|
use crate::keychain::extkey_bip32::BIP32GrinHasher;
|
||||||
|
use crate::keychain::{Identifier, Keychain, SwitchCommitmentType, ViewKey};
|
||||||
use crate::libtx::error::{Error, ErrorKind};
|
use crate::libtx::error::{Error, ErrorKind};
|
||||||
use crate::util::secp::key::SecretKey;
|
use crate::util::secp::key::SecretKey;
|
||||||
use crate::util::secp::pedersen::{Commitment, ProofInfo, ProofMessage, RangeProof};
|
use crate::util::secp::pedersen::{Commitment, ProofMessage, RangeProof};
|
||||||
use crate::util::secp::{self, Secp256k1};
|
use crate::util::secp::{self, Secp256k1};
|
||||||
|
use crate::zeroize::Zeroize;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
/// Create a bulletproof
|
/// Create a bulletproof
|
||||||
pub fn create<K>(
|
pub fn create<K, B>(
|
||||||
k: &K,
|
k: &K,
|
||||||
|
b: &B,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
key_id: &Identifier,
|
key_id: &Identifier,
|
||||||
|
switch: &SwitchCommitmentType,
|
||||||
_commit: Commitment,
|
_commit: Commitment,
|
||||||
extra_data: Option<Vec<u8>>,
|
extra_data: Option<Vec<u8>>,
|
||||||
) -> Result<RangeProof, Error>
|
) -> Result<RangeProof, Error>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
let commit = k.commit(amount, key_id)?;
|
// TODO: proper support for different switch commitment schemes
|
||||||
let skey = k.derive_key(amount, key_id)?;
|
// The new bulletproof scheme encodes and decodes it, but
|
||||||
let nonce = k
|
// it is not supported at the wallet level (yet).
|
||||||
.create_nonce(&commit)
|
let secp = k.secp();
|
||||||
.map_err(|e| ErrorKind::RangeProof(e.to_string()))?;
|
let commit = k.commit(amount, key_id, switch)?;
|
||||||
let message = ProofMessage::from_bytes(&key_id.serialize_path());
|
let skey = k.derive_key(amount, key_id, switch)?;
|
||||||
Ok(k.secp()
|
let rewind_nonce = b.rewind_nonce(secp, &commit)?;
|
||||||
.bullet_proof(amount, skey, nonce, extra_data, Some(message)))
|
let private_nonce = b.private_nonce(secp, &commit)?;
|
||||||
|
let message = b.proof_message(secp, key_id, switch)?;
|
||||||
|
Ok(secp.bullet_proof(
|
||||||
|
amount,
|
||||||
|
skey,
|
||||||
|
rewind_nonce,
|
||||||
|
private_nonce,
|
||||||
|
extra_data,
|
||||||
|
Some(message),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a proof
|
/// Verify a proof
|
||||||
|
@ -55,35 +71,689 @@ pub fn verify(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rewind a rangeproof to retrieve the amount
|
/// Rewind a rangeproof to retrieve the amount, derivation path and switch commitment type
|
||||||
pub fn rewind<K>(
|
pub fn rewind<B>(
|
||||||
k: &K,
|
secp: &Secp256k1,
|
||||||
|
b: &B,
|
||||||
commit: Commitment,
|
commit: Commitment,
|
||||||
extra_data: Option<Vec<u8>>,
|
extra_data: Option<Vec<u8>>,
|
||||||
proof: RangeProof,
|
proof: RangeProof,
|
||||||
) -> Result<ProofInfo, Error>
|
) -> Result<Option<(u64, Identifier, SwitchCommitmentType)>, Error>
|
||||||
|
where
|
||||||
|
B: ProofBuild,
|
||||||
|
{
|
||||||
|
let nonce = b
|
||||||
|
.rewind_nonce(secp, &commit)
|
||||||
|
.map_err(|e| ErrorKind::RangeProof(e.to_string()))?;
|
||||||
|
let info = secp.rewind_bullet_proof(commit, nonce, extra_data, proof);
|
||||||
|
if info.is_err() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let info = info.unwrap();
|
||||||
|
|
||||||
|
let amount = info.value;
|
||||||
|
let check = b
|
||||||
|
.check_output(secp, &commit, amount, info.message)
|
||||||
|
.map_err(|e| ErrorKind::RangeProof(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(check.map(|(id, switch)| (amount, id, switch)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used for building proofs and checking if the output belongs to the wallet
|
||||||
|
pub trait ProofBuild {
|
||||||
|
/// Create a BP nonce that will allow to rewind the derivation path and flags
|
||||||
|
fn rewind_nonce(&self, secp: &Secp256k1, commit: &Commitment) -> Result<SecretKey, Error>;
|
||||||
|
|
||||||
|
/// Create a BP nonce that blinds the private key
|
||||||
|
fn private_nonce(&self, secp: &Secp256k1, commit: &Commitment) -> Result<SecretKey, Error>;
|
||||||
|
|
||||||
|
/// Create a BP message
|
||||||
|
fn proof_message(
|
||||||
|
&self,
|
||||||
|
secp: &Secp256k1,
|
||||||
|
id: &Identifier,
|
||||||
|
switch: &SwitchCommitmentType,
|
||||||
|
) -> Result<ProofMessage, Error>;
|
||||||
|
|
||||||
|
/// Check if the output belongs to this keychain
|
||||||
|
fn check_output(
|
||||||
|
&self,
|
||||||
|
secp: &Secp256k1,
|
||||||
|
commit: &Commitment,
|
||||||
|
amount: u64,
|
||||||
|
message: ProofMessage,
|
||||||
|
) -> Result<Option<(Identifier, SwitchCommitmentType)>, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The new, more flexible proof builder
|
||||||
|
pub struct ProofBuilder<'a, K>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let nonce = k
|
keychain: &'a K,
|
||||||
.create_nonce(&commit)
|
rewind_hash: Vec<u8>,
|
||||||
.map_err(|e| ErrorKind::RangeProof(e.to_string()))?;
|
private_hash: Vec<u8>,
|
||||||
let proof_message = k
|
}
|
||||||
.secp()
|
|
||||||
.rewind_bullet_proof(commit, nonce, extra_data, proof);
|
impl<'a, K> ProofBuilder<'a, K>
|
||||||
let proof_info = match proof_message {
|
where
|
||||||
Ok(p) => p,
|
K: Keychain,
|
||||||
Err(_) => ProofInfo {
|
{
|
||||||
success: false,
|
/// Creates a new instance of this proof builder
|
||||||
value: 0,
|
pub fn new(keychain: &'a K) -> Self {
|
||||||
message: ProofMessage::empty(),
|
let private_root_key = keychain
|
||||||
blinding: SecretKey([0; secp::constants::SECRET_KEY_SIZE]),
|
.derive_key(0, &K::root_key_id(), &SwitchCommitmentType::None)
|
||||||
mlen: 0,
|
.unwrap();
|
||||||
min: 0,
|
|
||||||
max: 0,
|
let private_hash = blake2b(32, &[], &private_root_key.0).as_bytes().to_vec();
|
||||||
exp: 0,
|
|
||||||
mantissa: 0,
|
let public_root_key = keychain
|
||||||
},
|
.public_root_key()
|
||||||
};
|
.serialize_vec(keychain.secp(), true);
|
||||||
return Ok(proof_info);
|
let rewind_hash = blake2b(32, &[], &public_root_key[..]).as_bytes().to_vec();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
keychain,
|
||||||
|
rewind_hash,
|
||||||
|
private_hash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nonce(&self, commit: &Commitment, private: bool) -> Result<SecretKey, Error> {
|
||||||
|
let hash = if private {
|
||||||
|
&self.private_hash
|
||||||
|
} else {
|
||||||
|
&self.rewind_hash
|
||||||
|
};
|
||||||
|
let res = blake2b(32, &commit.0, hash);
|
||||||
|
SecretKey::from_slice(self.keychain.secp(), res.as_bytes()).map_err(|e| {
|
||||||
|
ErrorKind::RangeProof(format!("Unable to create nonce: {:?}", e).to_string()).into()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K> ProofBuild for ProofBuilder<'a, K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
fn rewind_nonce(&self, _secp: &Secp256k1, commit: &Commitment) -> Result<SecretKey, Error> {
|
||||||
|
self.nonce(commit, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn private_nonce(&self, _secp: &Secp256k1, commit: &Commitment) -> Result<SecretKey, Error> {
|
||||||
|
self.nonce(commit, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Message bytes:
|
||||||
|
/// 0: reserved for future use
|
||||||
|
/// 1: wallet type (0 for standard)
|
||||||
|
/// 2: switch commitment type
|
||||||
|
/// 3: path depth
|
||||||
|
/// 4-19: derivation path
|
||||||
|
fn proof_message(
|
||||||
|
&self,
|
||||||
|
_secp: &Secp256k1,
|
||||||
|
id: &Identifier,
|
||||||
|
switch: &SwitchCommitmentType,
|
||||||
|
) -> Result<ProofMessage, Error> {
|
||||||
|
let mut msg = [0; 20];
|
||||||
|
msg[2] = u8::from(switch);
|
||||||
|
let id_bytes = id.to_bytes();
|
||||||
|
for i in 0..17 {
|
||||||
|
msg[i + 3] = id_bytes[i];
|
||||||
|
}
|
||||||
|
Ok(ProofMessage::from_bytes(&msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_output(
|
||||||
|
&self,
|
||||||
|
_secp: &Secp256k1,
|
||||||
|
commit: &Commitment,
|
||||||
|
amount: u64,
|
||||||
|
message: ProofMessage,
|
||||||
|
) -> Result<Option<(Identifier, SwitchCommitmentType)>, Error> {
|
||||||
|
if message.len() != 20 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let msg = message.as_bytes();
|
||||||
|
let exp: [u8; 2] = [0; 2];
|
||||||
|
if msg[..2] != exp {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let switch = match SwitchCommitmentType::try_from(msg[2]) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => return Ok(None),
|
||||||
|
};
|
||||||
|
let depth = u8::min(msg[3], 4);
|
||||||
|
let id = Identifier::from_serialized_path(depth, &msg[4..]);
|
||||||
|
|
||||||
|
let commit_exp = self.keychain.commit(amount, &id, &switch)?;
|
||||||
|
match commit == &commit_exp {
|
||||||
|
true => Ok(Some((id, switch))),
|
||||||
|
false => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K> Zeroize for ProofBuilder<'a, K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
fn zeroize(&mut self) {
|
||||||
|
self.rewind_hash.zeroize();
|
||||||
|
self.private_hash.zeroize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K> Drop for ProofBuilder<'a, K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.zeroize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The legacy proof builder, used before the first hard fork
|
||||||
|
pub struct LegacyProofBuilder<'a, K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
keychain: &'a K,
|
||||||
|
root_hash: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K> LegacyProofBuilder<'a, K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
/// Creates a new instance of this proof builder
|
||||||
|
pub fn new(keychain: &'a K) -> Self {
|
||||||
|
Self {
|
||||||
|
keychain,
|
||||||
|
root_hash: keychain
|
||||||
|
.derive_key(0, &K::root_key_id(), &SwitchCommitmentType::Regular)
|
||||||
|
.unwrap()
|
||||||
|
.0
|
||||||
|
.to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nonce(&self, commit: &Commitment) -> Result<SecretKey, Error> {
|
||||||
|
let res = blake2b(32, &commit.0, &self.root_hash);
|
||||||
|
SecretKey::from_slice(self.keychain.secp(), res.as_bytes()).map_err(|e| {
|
||||||
|
ErrorKind::RangeProof(format!("Unable to create nonce: {:?}", e).to_string()).into()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K> ProofBuild for LegacyProofBuilder<'a, K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
fn rewind_nonce(&self, _secp: &Secp256k1, commit: &Commitment) -> Result<SecretKey, Error> {
|
||||||
|
self.nonce(commit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn private_nonce(&self, _secp: &Secp256k1, commit: &Commitment) -> Result<SecretKey, Error> {
|
||||||
|
self.nonce(commit)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Message bytes:
|
||||||
|
/// 0-3: 0
|
||||||
|
/// 4-19: derivation path
|
||||||
|
/// All outputs with this scheme are assumed to use regular switch commitments
|
||||||
|
fn proof_message(
|
||||||
|
&self,
|
||||||
|
_secp: &Secp256k1,
|
||||||
|
id: &Identifier,
|
||||||
|
_switch: &SwitchCommitmentType,
|
||||||
|
) -> Result<ProofMessage, Error> {
|
||||||
|
let mut msg = [0; 20];
|
||||||
|
let id_ser = id.serialize_path();
|
||||||
|
for i in 0..16 {
|
||||||
|
msg[i + 4] = id_ser[i];
|
||||||
|
}
|
||||||
|
Ok(ProofMessage::from_bytes(&msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_output(
|
||||||
|
&self,
|
||||||
|
_secp: &Secp256k1,
|
||||||
|
commit: &Commitment,
|
||||||
|
amount: u64,
|
||||||
|
message: ProofMessage,
|
||||||
|
) -> Result<Option<(Identifier, SwitchCommitmentType)>, Error> {
|
||||||
|
if message.len() != 20 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let msg = message.as_bytes();
|
||||||
|
let id = Identifier::from_serialized_path(3, &msg[4..]);
|
||||||
|
let exp: [u8; 4] = [0; 4];
|
||||||
|
if msg[..4] != exp {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let commit_exp = self
|
||||||
|
.keychain
|
||||||
|
.commit(amount, &id, &SwitchCommitmentType::Regular)?;
|
||||||
|
match commit == &commit_exp {
|
||||||
|
true => Ok(Some((id, SwitchCommitmentType::Regular))),
|
||||||
|
false => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K> Zeroize for LegacyProofBuilder<'a, K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
fn zeroize(&mut self) {
|
||||||
|
self.root_hash.zeroize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, K> Drop for LegacyProofBuilder<'a, K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.zeroize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProofBuild for ViewKey {
|
||||||
|
fn rewind_nonce(&self, secp: &Secp256k1, commit: &Commitment) -> Result<SecretKey, Error> {
|
||||||
|
let res = blake2b(32, &commit.0, &self.rewind_hash);
|
||||||
|
SecretKey::from_slice(secp, res.as_bytes()).map_err(|e| {
|
||||||
|
ErrorKind::RangeProof(format!("Unable to create nonce: {:?}", e).to_string()).into()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn private_nonce(&self, _secp: &Secp256k1, _commit: &Commitment) -> Result<SecretKey, Error> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proof_message(
|
||||||
|
&self,
|
||||||
|
_secp: &Secp256k1,
|
||||||
|
_id: &Identifier,
|
||||||
|
_switch: &SwitchCommitmentType,
|
||||||
|
) -> Result<ProofMessage, Error> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_output(
|
||||||
|
&self,
|
||||||
|
secp: &Secp256k1,
|
||||||
|
commit: &Commitment,
|
||||||
|
amount: u64,
|
||||||
|
message: ProofMessage,
|
||||||
|
) -> Result<Option<(Identifier, SwitchCommitmentType)>, Error> {
|
||||||
|
if message.len() != 20 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let msg = message.as_bytes();
|
||||||
|
let exp: [u8; 2] = [0; 2];
|
||||||
|
if msg[..2] != exp {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let switch = match SwitchCommitmentType::try_from(msg[2]) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => return Ok(None),
|
||||||
|
};
|
||||||
|
let depth = u8::min(msg[3], 4);
|
||||||
|
let id = Identifier::from_serialized_path(depth, &msg[4..]);
|
||||||
|
|
||||||
|
let path = id.to_path();
|
||||||
|
if self.depth > path.depth {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-root key, check child number of current depth
|
||||||
|
if self.depth > 0
|
||||||
|
&& path.depth > 0
|
||||||
|
&& self.child_number != path.path[self.depth as usize - 1]
|
||||||
|
{
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut key = self.clone();
|
||||||
|
let mut hasher = BIP32GrinHasher::new(self.is_floo);
|
||||||
|
for i in self.depth..path.depth {
|
||||||
|
let child_number = path.path[i as usize];
|
||||||
|
if child_number.is_hardened() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
key = key.ckd_pub(&secp, &mut hasher, child_number)?;
|
||||||
|
}
|
||||||
|
let pub_key = key.commit(secp, amount, &switch)?;
|
||||||
|
if commit.to_pubkey(&secp)? == pub_key {
|
||||||
|
Ok(Some((id, switch)))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::keychain::ExtKeychain;
|
||||||
|
use grin_keychain::ChildNumber;
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn legacy_builder() {
|
||||||
|
let rng = &mut thread_rng();
|
||||||
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = LegacyProofBuilder::new(&keychain);
|
||||||
|
let amount = rng.gen();
|
||||||
|
let id = ExtKeychain::derive_key_id(3, rng.gen(), rng.gen(), rng.gen(), 0);
|
||||||
|
let switch = SwitchCommitmentType::Regular;
|
||||||
|
let commit = keychain.commit(amount, &id, &switch).unwrap();
|
||||||
|
let proof = create(
|
||||||
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
amount,
|
||||||
|
&id,
|
||||||
|
&switch,
|
||||||
|
commit.clone(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(verify(&keychain.secp(), commit.clone(), proof.clone(), None).is_ok());
|
||||||
|
let rewind = rewind(keychain.secp(), &builder, commit, None, proof).unwrap();
|
||||||
|
assert!(rewind.is_some());
|
||||||
|
let (r_amount, r_id, r_switch) = rewind.unwrap();
|
||||||
|
assert_eq!(r_amount, amount);
|
||||||
|
assert_eq!(r_id, id);
|
||||||
|
assert_eq!(r_switch, switch);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builder() {
|
||||||
|
let rng = &mut thread_rng();
|
||||||
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
|
let amount = rng.gen();
|
||||||
|
let id = ExtKeychain::derive_key_id(3, rng.gen(), rng.gen(), rng.gen(), 0);
|
||||||
|
// With switch commitment
|
||||||
|
let commit_a = {
|
||||||
|
let switch = SwitchCommitmentType::Regular;
|
||||||
|
let commit = keychain.commit(amount, &id, &switch).unwrap();
|
||||||
|
let proof = create(
|
||||||
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
amount,
|
||||||
|
&id,
|
||||||
|
&switch,
|
||||||
|
commit.clone(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(verify(&keychain.secp(), commit.clone(), proof.clone(), None).is_ok());
|
||||||
|
let rewind = rewind(keychain.secp(), &builder, commit.clone(), None, proof).unwrap();
|
||||||
|
assert!(rewind.is_some());
|
||||||
|
let (r_amount, r_id, r_switch) = rewind.unwrap();
|
||||||
|
assert_eq!(r_amount, amount);
|
||||||
|
assert_eq!(r_id, id);
|
||||||
|
assert_eq!(r_switch, switch);
|
||||||
|
commit
|
||||||
|
};
|
||||||
|
// Without switch commitment
|
||||||
|
let commit_b = {
|
||||||
|
let switch = SwitchCommitmentType::None;
|
||||||
|
let commit = keychain.commit(amount, &id, &switch).unwrap();
|
||||||
|
let proof = create(
|
||||||
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
amount,
|
||||||
|
&id,
|
||||||
|
&switch,
|
||||||
|
commit.clone(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(verify(&keychain.secp(), commit.clone(), proof.clone(), None).is_ok());
|
||||||
|
let rewind = rewind(keychain.secp(), &builder, commit.clone(), None, proof).unwrap();
|
||||||
|
assert!(rewind.is_some());
|
||||||
|
let (r_amount, r_id, r_switch) = rewind.unwrap();
|
||||||
|
assert_eq!(r_amount, amount);
|
||||||
|
assert_eq!(r_id, id);
|
||||||
|
assert_eq!(r_switch, switch);
|
||||||
|
commit
|
||||||
|
};
|
||||||
|
// The resulting pedersen commitments should be different
|
||||||
|
assert_ne!(commit_a, commit_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn view_key() {
|
||||||
|
// TODO
|
||||||
|
/*let rng = &mut thread_rng();
|
||||||
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
|
let mut hasher = keychain.hasher();
|
||||||
|
let view_key = ViewKey::create(&keychain, keychain.master.clone(), &mut hasher, false).unwrap();
|
||||||
|
assert_eq!(builder.rewind_hash, view_key.rewind_hash);
|
||||||
|
|
||||||
|
let amount = rng.gen();
|
||||||
|
//let id = ExtKeychain::derive_key_id(3, rng.gen::<u16>() as u32, rng.gen::<u16>() as u32, rng.gen::<u16>() as u32, 0);
|
||||||
|
let id = ExtKeychain::derive_key_id(0, 0, 0, 0, 0);
|
||||||
|
let switch = SwitchCommitmentType::Regular;
|
||||||
|
println!("commit_0 = {:?}", keychain.commit(amount, &id, &SwitchCommitmentType::None).unwrap().0.to_vec());
|
||||||
|
let commit = keychain.commit(amount, &id, &switch).unwrap();
|
||||||
|
|
||||||
|
// Generate proof with ProofBuilder..
|
||||||
|
let proof = create(&keychain, &builder, amount, &id, &switch, commit.clone(), None).unwrap();
|
||||||
|
// ..and rewind with ViewKey
|
||||||
|
let rewind = rewind(keychain.secp(), &view_key, commit.clone(), None, proof);
|
||||||
|
|
||||||
|
assert!(rewind.is_ok());
|
||||||
|
let rewind = rewind.unwrap();
|
||||||
|
assert!(rewind.is_some());
|
||||||
|
let (r_amount, r_id, r_switch) = rewind.unwrap();
|
||||||
|
assert_eq!(r_amount, amount);
|
||||||
|
assert_eq!(r_id, id);
|
||||||
|
assert_eq!(r_switch, switch);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn view_key_no_switch() {
|
||||||
|
let rng = &mut thread_rng();
|
||||||
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
|
let mut hasher = keychain.hasher();
|
||||||
|
let view_key =
|
||||||
|
ViewKey::create(&keychain, keychain.master.clone(), &mut hasher, false).unwrap();
|
||||||
|
assert_eq!(builder.rewind_hash, view_key.rewind_hash);
|
||||||
|
|
||||||
|
let amount = rng.gen();
|
||||||
|
let id = ExtKeychain::derive_key_id(
|
||||||
|
3,
|
||||||
|
rng.gen::<u16>() as u32,
|
||||||
|
rng.gen::<u16>() as u32,
|
||||||
|
rng.gen::<u16>() as u32,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
let switch = SwitchCommitmentType::None;
|
||||||
|
let commit = keychain.commit(amount, &id, &switch).unwrap();
|
||||||
|
|
||||||
|
// Generate proof with ProofBuilder..
|
||||||
|
let proof = create(
|
||||||
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
amount,
|
||||||
|
&id,
|
||||||
|
&switch,
|
||||||
|
commit.clone(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
// ..and rewind with ViewKey
|
||||||
|
let rewind = rewind(keychain.secp(), &view_key, commit.clone(), None, proof);
|
||||||
|
|
||||||
|
assert!(rewind.is_ok());
|
||||||
|
let rewind = rewind.unwrap();
|
||||||
|
assert!(rewind.is_some());
|
||||||
|
let (r_amount, r_id, r_switch) = rewind.unwrap();
|
||||||
|
assert_eq!(r_amount, amount);
|
||||||
|
assert_eq!(r_id, id);
|
||||||
|
assert_eq!(r_switch, switch);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn view_key_hardened() {
|
||||||
|
let rng = &mut thread_rng();
|
||||||
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
|
let mut hasher = keychain.hasher();
|
||||||
|
let view_key =
|
||||||
|
ViewKey::create(&keychain, keychain.master.clone(), &mut hasher, false).unwrap();
|
||||||
|
assert_eq!(builder.rewind_hash, view_key.rewind_hash);
|
||||||
|
|
||||||
|
let amount = rng.gen();
|
||||||
|
let id = ExtKeychain::derive_key_id(
|
||||||
|
3,
|
||||||
|
rng.gen::<u16>() as u32,
|
||||||
|
u32::max_value() - 2,
|
||||||
|
rng.gen::<u16>() as u32,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
let switch = SwitchCommitmentType::None;
|
||||||
|
let commit = keychain.commit(amount, &id, &switch).unwrap();
|
||||||
|
|
||||||
|
// Generate proof with ProofBuilder..
|
||||||
|
let proof = create(
|
||||||
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
amount,
|
||||||
|
&id,
|
||||||
|
&switch,
|
||||||
|
commit.clone(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
// ..and rewind with ViewKey
|
||||||
|
let rewind = rewind(keychain.secp(), &view_key, commit.clone(), None, proof);
|
||||||
|
|
||||||
|
assert!(rewind.is_ok());
|
||||||
|
let rewind = rewind.unwrap();
|
||||||
|
assert!(rewind.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn view_key_child() {
|
||||||
|
let rng = &mut thread_rng();
|
||||||
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
|
let mut hasher = keychain.hasher();
|
||||||
|
let view_key =
|
||||||
|
ViewKey::create(&keychain, keychain.master.clone(), &mut hasher, false).unwrap();
|
||||||
|
assert_eq!(builder.rewind_hash, view_key.rewind_hash);
|
||||||
|
|
||||||
|
// Same child
|
||||||
|
{
|
||||||
|
let child_view_key = view_key
|
||||||
|
.ckd_pub(
|
||||||
|
keychain.secp(),
|
||||||
|
&mut hasher,
|
||||||
|
ChildNumber::from_normal_idx(10),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(child_view_key.depth, 1);
|
||||||
|
|
||||||
|
let amount = rng.gen();
|
||||||
|
let id = ExtKeychain::derive_key_id(
|
||||||
|
3,
|
||||||
|
10,
|
||||||
|
rng.gen::<u16>() as u32,
|
||||||
|
rng.gen::<u16>() as u32,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
let switch = SwitchCommitmentType::None;
|
||||||
|
let commit = keychain.commit(amount, &id, &switch).unwrap();
|
||||||
|
|
||||||
|
// Generate proof with ProofBuilder..
|
||||||
|
let proof = create(
|
||||||
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
amount,
|
||||||
|
&id,
|
||||||
|
&switch,
|
||||||
|
commit.clone(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
// ..and rewind with child ViewKey
|
||||||
|
let rewind = rewind(
|
||||||
|
keychain.secp(),
|
||||||
|
&child_view_key,
|
||||||
|
commit.clone(),
|
||||||
|
None,
|
||||||
|
proof,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(rewind.is_ok());
|
||||||
|
let rewind = rewind.unwrap();
|
||||||
|
assert!(rewind.is_some());
|
||||||
|
let (r_amount, r_id, r_switch) = rewind.unwrap();
|
||||||
|
assert_eq!(r_amount, amount);
|
||||||
|
assert_eq!(r_id, id);
|
||||||
|
assert_eq!(r_switch, switch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Different child
|
||||||
|
{
|
||||||
|
let child_view_key = view_key
|
||||||
|
.ckd_pub(
|
||||||
|
keychain.secp(),
|
||||||
|
&mut hasher,
|
||||||
|
ChildNumber::from_normal_idx(11),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(child_view_key.depth, 1);
|
||||||
|
|
||||||
|
let amount = rng.gen();
|
||||||
|
let id = ExtKeychain::derive_key_id(
|
||||||
|
3,
|
||||||
|
10,
|
||||||
|
rng.gen::<u16>() as u32,
|
||||||
|
rng.gen::<u16>() as u32,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
let switch = SwitchCommitmentType::None;
|
||||||
|
let commit = keychain.commit(amount, &id, &switch).unwrap();
|
||||||
|
|
||||||
|
// Generate proof with ProofBuilder..
|
||||||
|
let proof = create(
|
||||||
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
amount,
|
||||||
|
&id,
|
||||||
|
&switch,
|
||||||
|
commit.clone(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
// ..and rewind with child ViewKey
|
||||||
|
let rewind = rewind(
|
||||||
|
keychain.secp(),
|
||||||
|
&child_view_key,
|
||||||
|
commit.clone(),
|
||||||
|
None,
|
||||||
|
proof,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(rewind.is_ok());
|
||||||
|
let rewind = rewind.unwrap();
|
||||||
|
assert!(rewind.is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,25 +19,33 @@ use crate::core::transaction::kernel_sig_msg;
|
||||||
use crate::core::{KernelFeatures, Output, OutputFeatures, TxKernel};
|
use crate::core::{KernelFeatures, Output, OutputFeatures, TxKernel};
|
||||||
use crate::keychain::{Identifier, Keychain};
|
use crate::keychain::{Identifier, Keychain};
|
||||||
use crate::libtx::error::Error;
|
use crate::libtx::error::Error;
|
||||||
use crate::libtx::{aggsig, proof};
|
use crate::libtx::{
|
||||||
|
aggsig,
|
||||||
|
proof::{self, ProofBuild},
|
||||||
|
};
|
||||||
use crate::util::{secp, static_secp_instance};
|
use crate::util::{secp, static_secp_instance};
|
||||||
|
use grin_keychain::SwitchCommitmentType;
|
||||||
|
|
||||||
/// output a reward output
|
/// output a reward output
|
||||||
pub fn output<K>(
|
pub fn output<K, B>(
|
||||||
keychain: &K,
|
keychain: &K,
|
||||||
|
builder: &B,
|
||||||
key_id: &Identifier,
|
key_id: &Identifier,
|
||||||
fees: u64,
|
fees: u64,
|
||||||
test_mode: bool,
|
test_mode: bool,
|
||||||
) -> Result<(Output, TxKernel), Error>
|
) -> Result<(Output, TxKernel), Error>
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
let value = reward(fees);
|
let value = reward(fees);
|
||||||
let commit = keychain.commit(value, key_id)?;
|
// TODO: proper support for different switch commitment schemes
|
||||||
|
let switch = &SwitchCommitmentType::Regular;
|
||||||
|
let commit = keychain.commit(value, key_id, switch)?;
|
||||||
|
|
||||||
trace!("Block reward - Pedersen Commit is: {:?}", commit,);
|
trace!("Block reward - Pedersen Commit is: {:?}", commit,);
|
||||||
|
|
||||||
let rproof = proof::create(keychain, value, key_id, commit, None)?;
|
let rproof = proof::create(keychain, builder, value, key_id, switch, commit, None)?;
|
||||||
|
|
||||||
let output = Output {
|
let output = Output {
|
||||||
features: OutputFeatures::Coinbase,
|
features: OutputFeatures::Coinbase,
|
||||||
|
|
|
@ -34,6 +34,7 @@ use num;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod common;
|
mod common;
|
||||||
pub mod cuckaroo;
|
pub mod cuckaroo;
|
||||||
|
pub mod cuckarood;
|
||||||
pub mod cuckatoo;
|
pub mod cuckatoo;
|
||||||
mod error;
|
mod error;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -49,6 +50,7 @@ use chrono::prelude::{DateTime, NaiveDateTime, Utc};
|
||||||
pub use self::common::EdgeType;
|
pub use self::common::EdgeType;
|
||||||
pub use self::types::*;
|
pub use self::types::*;
|
||||||
pub use crate::pow::cuckaroo::{new_cuckaroo_ctx, CuckarooContext};
|
pub use crate::pow::cuckaroo::{new_cuckaroo_ctx, CuckarooContext};
|
||||||
|
pub use crate::pow::cuckarood::{new_cuckarood_ctx, CuckaroodContext};
|
||||||
pub use crate::pow::cuckatoo::{new_cuckatoo_ctx, CuckatooContext};
|
pub use crate::pow::cuckatoo::{new_cuckatoo_ctx, CuckatooContext};
|
||||||
pub use crate::pow::error::Error;
|
pub use crate::pow::error::Error;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//! Common types and traits for cuckoo/cuckatoo family of solvers
|
//! Common types and traits for cuckoo family of solvers
|
||||||
|
|
||||||
use crate::blake2::blake2b::blake2b;
|
use crate::blake2::blake2b::blake2b;
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|
|
@ -43,7 +43,7 @@ where
|
||||||
Ok(Box::new(CuckarooContext { params }))
|
Ok(Box::new(CuckarooContext { params }))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cuckatoo cycle context. Only includes the verifier for now.
|
/// Cuckaroo cycle context. Only includes the verifier for now.
|
||||||
pub struct CuckarooContext<T>
|
pub struct CuckarooContext<T>
|
||||||
where
|
where
|
||||||
T: EdgeType,
|
T: EdgeType,
|
||||||
|
@ -84,7 +84,8 @@ where
|
||||||
if n > 0 && nonces[n] <= nonces[n - 1] {
|
if n > 0 && nonces[n] <= nonces[n - 1] {
|
||||||
return Err(ErrorKind::Verification("edges not ascending".to_owned()))?;
|
return Err(ErrorKind::Verification("edges not ascending".to_owned()))?;
|
||||||
}
|
}
|
||||||
let edge = to_edge!(T, siphash_block(&self.params.siphash_keys, nonces[n]));
|
// 21 is standard siphash rotation constant
|
||||||
|
let edge = to_edge!(T, siphash_block(&self.params.siphash_keys, nonces[n], 21));
|
||||||
uvs[2 * n] = to_u64!(edge & self.params.edge_mask);
|
uvs[2 * n] = to_u64!(edge & self.params.edge_mask);
|
||||||
uvs[2 * n + 1] = to_u64!((edge >> 32) & self.params.edge_mask);
|
uvs[2 * n + 1] = to_u64!((edge >> 32) & self.params.edge_mask);
|
||||||
xor0 ^= uvs[2 * n];
|
xor0 ^= uvs[2 * n];
|
||||||
|
|
195
core/src/pow/cuckarood.rs
Normal file
195
core/src/pow/cuckarood.rs
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//! Implementation of Cuckarood Cycle, based on Cuckoo Cycle designed by
|
||||||
|
//! John Tromp. Ported to Rust from https://github.com/tromp/cuckoo.
|
||||||
|
//!
|
||||||
|
//! Cuckarood is a variation of Cuckaroo that's tweaked at the first HardFork
|
||||||
|
//! to maintain ASIC-Resistance, as introduced in
|
||||||
|
//! https://www.grin-forum.org/t/mid-july-pow-hardfork-cuckaroo29-cuckarood29
|
||||||
|
//! It uses a tweaked siphash round in which the rotation by 21 is replaced by
|
||||||
|
//! a rotation by 25, halves the number of graph nodes in each partition,
|
||||||
|
//! and requires cycles to alternate between even- and odd-indexed edges.
|
||||||
|
|
||||||
|
use crate::global;
|
||||||
|
use crate::pow::common::{CuckooParams, EdgeType};
|
||||||
|
use crate::pow::error::{Error, ErrorKind};
|
||||||
|
use crate::pow::siphash::siphash_block;
|
||||||
|
use crate::pow::{PoWContext, Proof};
|
||||||
|
|
||||||
|
/// Instantiate a new CuckaroodContext as a PowContext. Note that this can't
|
||||||
|
/// be moved in the PoWContext trait as this particular trait needs to be
|
||||||
|
/// convertible to an object trait.
|
||||||
|
pub fn new_cuckarood_ctx<T>(
|
||||||
|
edge_bits: u8,
|
||||||
|
proof_size: usize,
|
||||||
|
) -> Result<Box<dyn PoWContext<T>>, Error>
|
||||||
|
where
|
||||||
|
T: EdgeType + 'static,
|
||||||
|
{
|
||||||
|
let params = CuckooParams::new(edge_bits, proof_size)?;
|
||||||
|
Ok(Box::new(CuckaroodContext { params }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cuckarood cycle context. Only includes the verifier for now.
|
||||||
|
pub struct CuckaroodContext<T>
|
||||||
|
where
|
||||||
|
T: EdgeType,
|
||||||
|
{
|
||||||
|
params: CuckooParams<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PoWContext<T> for CuckaroodContext<T>
|
||||||
|
where
|
||||||
|
T: EdgeType,
|
||||||
|
{
|
||||||
|
fn set_header_nonce(
|
||||||
|
&mut self,
|
||||||
|
header: Vec<u8>,
|
||||||
|
nonce: Option<u32>,
|
||||||
|
_solve: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.params.reset_header_nonce(header, nonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_cycles(&mut self) -> Result<Vec<Proof>, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify(&self, proof: &Proof) -> Result<(), Error> {
|
||||||
|
if proof.proof_size() != global::proofsize() {
|
||||||
|
return Err(ErrorKind::Verification("wrong cycle length".to_owned()))?;
|
||||||
|
}
|
||||||
|
let nonces = &proof.nonces;
|
||||||
|
let mut uvs = vec![0u64; 2 * proof.proof_size()];
|
||||||
|
let mut ndir = vec![0usize; 2];
|
||||||
|
let mut xor0: u64 = 0;
|
||||||
|
let mut xor1: u64 = 0;
|
||||||
|
let nodemask = self.params.edge_mask >> 1;
|
||||||
|
|
||||||
|
for n in 0..proof.proof_size() {
|
||||||
|
let dir = (nonces[n] & 1) as usize;
|
||||||
|
if ndir[dir] >= proof.proof_size() / 2 {
|
||||||
|
return Err(ErrorKind::Verification("edges not balanced".to_owned()))?;
|
||||||
|
}
|
||||||
|
if nonces[n] > to_u64!(self.params.edge_mask) {
|
||||||
|
return Err(ErrorKind::Verification("edge too big".to_owned()))?;
|
||||||
|
}
|
||||||
|
if n > 0 && nonces[n] <= nonces[n - 1] {
|
||||||
|
return Err(ErrorKind::Verification("edges not ascending".to_owned()))?;
|
||||||
|
}
|
||||||
|
let edge = to_edge!(T, siphash_block(&self.params.siphash_keys, nonces[n], 25));
|
||||||
|
let idx = 4 * ndir[dir] + 2 * dir;
|
||||||
|
uvs[idx] = to_u64!(edge & nodemask);
|
||||||
|
uvs[idx + 1] = to_u64!((edge >> 32) & nodemask);
|
||||||
|
xor0 ^= uvs[idx];
|
||||||
|
xor1 ^= uvs[idx + 1];
|
||||||
|
ndir[dir] += 1;
|
||||||
|
}
|
||||||
|
if xor0 | xor1 != 0 {
|
||||||
|
return Err(ErrorKind::Verification(
|
||||||
|
"endpoints don't match up".to_owned(),
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
let mut n = 0;
|
||||||
|
let mut i = 0;
|
||||||
|
let mut j;
|
||||||
|
loop {
|
||||||
|
// follow cycle
|
||||||
|
j = i;
|
||||||
|
for k in (((i % 4) ^ 2)..(2 * self.params.proof_size)).step_by(4) {
|
||||||
|
if uvs[k] == uvs[i] {
|
||||||
|
// find reverse edge endpoint identical to one at i
|
||||||
|
if j != i {
|
||||||
|
return Err(ErrorKind::Verification("branch in cycle".to_owned()))?;
|
||||||
|
}
|
||||||
|
j = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if j == i {
|
||||||
|
return Err(ErrorKind::Verification("cycle dead ends".to_owned()))?;
|
||||||
|
}
|
||||||
|
i = j ^ 1;
|
||||||
|
n += 1;
|
||||||
|
if i == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n == self.params.proof_size {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Verification("cycle too short".to_owned()))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
// empty header, nonce 64
|
||||||
|
static V1_19_HASH: [u64; 4] = [
|
||||||
|
0x89f81d7da5e674df,
|
||||||
|
0x7586b93105a5fd13,
|
||||||
|
0x6fbe212dd4e8c001,
|
||||||
|
0x8800c93a8431f938,
|
||||||
|
];
|
||||||
|
static V1_19_SOL: [u64; 42] = [
|
||||||
|
0xa00, 0x3ffb, 0xa474, 0xdc27, 0x182e6, 0x242cc, 0x24de4, 0x270a2, 0x28356, 0x2951f,
|
||||||
|
0x2a6ae, 0x2c889, 0x355c7, 0x3863b, 0x3bd7e, 0x3cdbc, 0x3ff95, 0x430b6, 0x4ba1a, 0x4bd7e,
|
||||||
|
0x4c59f, 0x4f76d, 0x52064, 0x5378c, 0x540a3, 0x5af6b, 0x5b041, 0x5e9d3, 0x64ec7, 0x6564b,
|
||||||
|
0x66763, 0x66899, 0x66e80, 0x68e4e, 0x69133, 0x6b20a, 0x6c2d7, 0x6fd3b, 0x79a8a, 0x79e29,
|
||||||
|
0x7ae52, 0x7defe,
|
||||||
|
];
|
||||||
|
|
||||||
|
// empty header, nonce 15
|
||||||
|
static V2_29_HASH: [u64; 4] = [
|
||||||
|
0xe2f917b2d79492ed,
|
||||||
|
0xf51088eaaa3a07a0,
|
||||||
|
0xaf4d4288d36a4fa8,
|
||||||
|
0xc8cdfd30a54e0581,
|
||||||
|
];
|
||||||
|
static V2_29_SOL: [u64; 42] = [
|
||||||
|
0x1a9629, 0x1fb257, 0x5dc22a, 0xf3d0b0, 0x200c474, 0x24bd68f, 0x48ad104, 0x4a17170,
|
||||||
|
0x4ca9a41, 0x55f983f, 0x6076c91, 0x6256ffc, 0x63b60a1, 0x7fd5b16, 0x985bff8, 0xaae71f3,
|
||||||
|
0xb71f7b4, 0xb989679, 0xc09b7b8, 0xd7601da, 0xd7ab1b6, 0xef1c727, 0xf1e702b, 0xfd6d961,
|
||||||
|
0xfdf0007, 0x10248134, 0x114657f6, 0x11f52612, 0x12887251, 0x13596b4b, 0x15e8d831,
|
||||||
|
0x16b4c9e5, 0x17097420, 0x1718afca, 0x187fc40c, 0x19359788, 0x1b41d3f1, 0x1bea25a7,
|
||||||
|
0x1d28df0f, 0x1ea6c4a0, 0x1f9bf79f, 0x1fa005c6,
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cuckarood19_29_vectors() {
|
||||||
|
let mut ctx19 = new_impl::<u64>(19, 42);
|
||||||
|
ctx19.params.siphash_keys = V1_19_HASH.clone();
|
||||||
|
assert!(ctx19
|
||||||
|
.verify(&Proof::new(V1_19_SOL.to_vec().clone()))
|
||||||
|
.is_ok());
|
||||||
|
assert!(ctx19.verify(&Proof::zero(42)).is_err());
|
||||||
|
let mut ctx29 = new_impl::<u64>(29, 42);
|
||||||
|
ctx29.params.siphash_keys = V2_29_HASH.clone();
|
||||||
|
assert!(ctx29
|
||||||
|
.verify(&Proof::new(V2_29_SOL.to_vec().clone()))
|
||||||
|
.is_ok());
|
||||||
|
assert!(ctx29.verify(&Proof::zero(42)).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_impl<T>(edge_bits: u8, proof_size: usize) -> CuckaroodContext<T>
|
||||||
|
where
|
||||||
|
T: EdgeType,
|
||||||
|
{
|
||||||
|
let params = CuckooParams::new(edge_bits, proof_size).unwrap();
|
||||||
|
CuckaroodContext { params }
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,14 +32,14 @@ macro_rules! rotl {
|
||||||
/// a nonce
|
/// a nonce
|
||||||
pub fn siphash24(v: &[u64; 4], nonce: u64) -> u64 {
|
pub fn siphash24(v: &[u64; 4], nonce: u64) -> u64 {
|
||||||
let mut siphash = SipHash24::new(v);
|
let mut siphash = SipHash24::new(v);
|
||||||
siphash.hash(nonce);
|
siphash.hash(nonce, 21); // 21 is standard rotation constant
|
||||||
siphash.digest()
|
siphash.digest()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a block of siphash values by repeatedly hashing from the nonce
|
/// Builds a block of siphash values by repeatedly hashing from the nonce
|
||||||
/// truncated to its closest block start, up to the end of the block. Returns
|
/// truncated to its closest block start, up to the end of the block. Returns
|
||||||
/// the resulting hash at the nonce's position.
|
/// the resulting hash at the nonce's position.
|
||||||
pub fn siphash_block(v: &[u64; 4], nonce: u64) -> u64 {
|
pub fn siphash_block(v: &[u64; 4], nonce: u64, rot_e: u8) -> u64 {
|
||||||
// beginning of the block of hashes
|
// beginning of the block of hashes
|
||||||
let nonce0 = nonce & !SIPHASH_BLOCK_MASK;
|
let nonce0 = nonce & !SIPHASH_BLOCK_MASK;
|
||||||
let mut nonce_hash = 0;
|
let mut nonce_hash = 0;
|
||||||
|
@ -47,7 +47,7 @@ pub fn siphash_block(v: &[u64; 4], nonce: u64) -> u64 {
|
||||||
// repeated hashing over the whole block
|
// repeated hashing over the whole block
|
||||||
let mut siphash = SipHash24::new(v);
|
let mut siphash = SipHash24::new(v);
|
||||||
for n in nonce0..(nonce0 + SIPHASH_BLOCK_SIZE) {
|
for n in nonce0..(nonce0 + SIPHASH_BLOCK_SIZE) {
|
||||||
siphash.hash(n);
|
siphash.hash(n, rot_e);
|
||||||
if n == nonce {
|
if n == nonce {
|
||||||
nonce_hash = siphash.digest();
|
nonce_hash = siphash.digest();
|
||||||
}
|
}
|
||||||
|
@ -80,16 +80,16 @@ impl SipHash24 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One siphash24 hashing, consisting of 2 and then 4 rounds
|
/// One siphash24 hashing, consisting of 2 and then 4 rounds
|
||||||
pub fn hash(&mut self, nonce: u64) {
|
pub fn hash(&mut self, nonce: u64, rot_e: u8) {
|
||||||
self.3 ^= nonce;
|
self.3 ^= nonce;
|
||||||
self.round();
|
self.round(rot_e);
|
||||||
self.round();
|
self.round(rot_e);
|
||||||
|
|
||||||
self.0 ^= nonce;
|
self.0 ^= nonce;
|
||||||
self.2 ^= 0xff;
|
self.2 ^= 0xff;
|
||||||
|
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
self.round();
|
self.round(rot_e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ impl SipHash24 {
|
||||||
(self.0 ^ self.1) ^ (self.2 ^ self.3)
|
(self.0 ^ self.1) ^ (self.2 ^ self.3)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn round(&mut self) {
|
fn round(&mut self, rot_e: u8) {
|
||||||
self.0 = self.0.wrapping_add(self.1);
|
self.0 = self.0.wrapping_add(self.1);
|
||||||
self.2 = self.2.wrapping_add(self.3);
|
self.2 = self.2.wrapping_add(self.3);
|
||||||
rotl!(self.1, 13);
|
rotl!(self.1, 13);
|
||||||
|
@ -109,7 +109,7 @@ impl SipHash24 {
|
||||||
self.2 = self.2.wrapping_add(self.1);
|
self.2 = self.2.wrapping_add(self.1);
|
||||||
self.0 = self.0.wrapping_add(self.3);
|
self.0 = self.0.wrapping_add(self.3);
|
||||||
rotl!(self.1, 17);
|
rotl!(self.1, 17);
|
||||||
rotl!(self.3, 21);
|
rotl!(self.3, rot_e);
|
||||||
self.1 ^= self.2;
|
self.1 ^= self.2;
|
||||||
self.3 ^= self.0;
|
self.3 ^= self.0;
|
||||||
rotl!(self.2, 32);
|
rotl!(self.2, 32);
|
||||||
|
@ -130,8 +130,8 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hash_block() {
|
fn hash_block() {
|
||||||
assert_eq!(siphash_block(&[1, 2, 3, 4], 10), 1182162244994096396);
|
assert_eq!(siphash_block(&[1, 2, 3, 4], 10, 21), 1182162244994096396);
|
||||||
assert_eq!(siphash_block(&[1, 2, 3, 4], 123), 11303676240481718781);
|
assert_eq!(siphash_block(&[1, 2, 3, 4], 123, 21), 11303676240481718781);
|
||||||
assert_eq!(siphash_block(&[9, 7, 6, 7], 12), 4886136884237259030);
|
assert_eq!(siphash_block(&[9, 7, 6, 7], 12, 21), 4886136884237259030);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ use crate::core::core::{
|
||||||
Block, BlockHeader, CompactBlock, HeaderVersion, KernelFeatures, OutputFeatures,
|
Block, BlockHeader, CompactBlock, HeaderVersion, KernelFeatures, OutputFeatures,
|
||||||
};
|
};
|
||||||
use crate::core::libtx::build::{self, input, output, with_fee};
|
use crate::core::libtx::build::{self, input, output, with_fee};
|
||||||
|
use crate::core::libtx::ProofBuilder;
|
||||||
use crate::core::{global, ser};
|
use crate::core::{global, ser};
|
||||||
use crate::keychain::{BlindingFactor, ExtKeychain, Keychain};
|
use crate::keychain::{BlindingFactor, ExtKeychain, Keychain};
|
||||||
use crate::util::secp;
|
use crate::util::secp;
|
||||||
|
@ -45,6 +46,7 @@ fn verifier_cache() -> Arc<RwLock<dyn VerifierCache>> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn too_large_block() {
|
fn too_large_block() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let max_out = global::max_block_weight() / BLOCK_OUTPUT_WEIGHT;
|
let max_out = global::max_block_weight() / BLOCK_OUTPUT_WEIGHT;
|
||||||
|
|
||||||
let mut pks = vec![];
|
let mut pks = vec![];
|
||||||
|
@ -59,12 +61,12 @@ fn too_large_block() {
|
||||||
|
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
parts.append(&mut vec![input(500000, pks.pop().unwrap()), with_fee(2)]);
|
parts.append(&mut vec![input(500000, pks.pop().unwrap()), with_fee(2)]);
|
||||||
let tx = build::transaction(parts, &keychain).unwrap();
|
let tx = build::transaction(parts, &keychain, &builder).unwrap();
|
||||||
println!("Build tx: {}", now.elapsed().as_secs());
|
println!("Build tx: {}", now.elapsed().as_secs());
|
||||||
|
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![&tx], &keychain, &prev, &key_id);
|
let b = new_block(vec![&tx], &keychain, &builder, &prev, &key_id);
|
||||||
assert!(b
|
assert!(b
|
||||||
.validate(&BlindingFactor::zero(), verifier_cache())
|
.validate(&BlindingFactor::zero(), verifier_cache())
|
||||||
.is_err());
|
.is_err());
|
||||||
|
@ -86,6 +88,7 @@ fn very_empty_block() {
|
||||||
// builds a block with a tx spending another and check that cut_through occurred
|
// builds a block with a tx spending another and check that cut_through occurred
|
||||||
fn block_with_cut_through() {
|
fn block_with_cut_through() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
@ -94,17 +97,19 @@ fn block_with_cut_through() {
|
||||||
let mut btx2 = build::transaction(
|
let mut btx2 = build::transaction(
|
||||||
vec![input(7, key_id1), output(5, key_id2.clone()), with_fee(2)],
|
vec![input(7, key_id1), output(5, key_id2.clone()), with_fee(2)],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// spending tx2 - reuse key_id2
|
// spending tx2 - reuse key_id2
|
||||||
|
|
||||||
let mut btx3 = txspend1i1o(5, &keychain, key_id2.clone(), key_id3);
|
let mut btx3 = txspend1i1o(5, &keychain, &builder, key_id2.clone(), key_id3);
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(
|
let b = new_block(
|
||||||
vec![&mut btx1, &mut btx2, &mut btx3],
|
vec![&mut btx1, &mut btx2, &mut btx3],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
&prev,
|
&prev,
|
||||||
&key_id,
|
&key_id,
|
||||||
);
|
);
|
||||||
|
@ -120,9 +125,10 @@ fn block_with_cut_through() {
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_block_with_coinbase_is_valid() {
|
fn empty_block_with_coinbase_is_valid() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
let b = new_block(vec![], &keychain, &builder, &prev, &key_id);
|
||||||
|
|
||||||
assert_eq!(b.inputs().len(), 0);
|
assert_eq!(b.inputs().len(), 0);
|
||||||
assert_eq!(b.outputs().len(), 1);
|
assert_eq!(b.outputs().len(), 1);
|
||||||
|
@ -157,9 +163,10 @@ fn empty_block_with_coinbase_is_valid() {
|
||||||
// additionally verifying the merkle_inputs_outputs also fails
|
// additionally verifying the merkle_inputs_outputs also fails
|
||||||
fn remove_coinbase_output_flag() {
|
fn remove_coinbase_output_flag() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let mut b = new_block(vec![], &keychain, &prev, &key_id);
|
let mut b = new_block(vec![], &keychain, &builder, &prev, &key_id);
|
||||||
|
|
||||||
assert!(b.outputs()[0].is_coinbase());
|
assert!(b.outputs()[0].is_coinbase());
|
||||||
b.outputs_mut()[0].features = OutputFeatures::Plain;
|
b.outputs_mut()[0].features = OutputFeatures::Plain;
|
||||||
|
@ -179,9 +186,10 @@ fn remove_coinbase_output_flag() {
|
||||||
// invalidates the block and specifically it causes verify_coinbase to fail
|
// invalidates the block and specifically it causes verify_coinbase to fail
|
||||||
fn remove_coinbase_kernel_flag() {
|
fn remove_coinbase_kernel_flag() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let mut b = new_block(vec![], &keychain, &prev, &key_id);
|
let mut b = new_block(vec![], &keychain, &builder, &prev, &key_id);
|
||||||
|
|
||||||
assert!(b.kernels()[0].is_coinbase());
|
assert!(b.kernels()[0].is_coinbase());
|
||||||
b.kernels_mut()[0].features = KernelFeatures::Plain;
|
b.kernels_mut()[0].features = KernelFeatures::Plain;
|
||||||
|
@ -220,9 +228,10 @@ fn serialize_deserialize_header_version() {
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_deserialize_block_header() {
|
fn serialize_deserialize_block_header() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
let b = new_block(vec![], &keychain, &builder, &prev, &key_id);
|
||||||
let header1 = b.header;
|
let header1 = b.header;
|
||||||
|
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
|
@ -237,9 +246,10 @@ fn serialize_deserialize_block_header() {
|
||||||
fn serialize_deserialize_block() {
|
fn serialize_deserialize_block() {
|
||||||
let tx1 = tx1i2o();
|
let tx1 = tx1i2o();
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![&tx1], &keychain, &prev, &key_id);
|
let b = new_block(vec![&tx1], &keychain, &builder, &prev, &key_id);
|
||||||
|
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &b).expect("serialization failed");
|
ser::serialize(&mut vec, &b).expect("serialization failed");
|
||||||
|
@ -255,9 +265,10 @@ fn serialize_deserialize_block() {
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_block_serialized_size() {
|
fn empty_block_serialized_size() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
let b = new_block(vec![], &keychain, &builder, &prev, &key_id);
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &b).expect("serialization failed");
|
ser::serialize(&mut vec, &b).expect("serialization failed");
|
||||||
let target_len = 1_265;
|
let target_len = 1_265;
|
||||||
|
@ -267,10 +278,11 @@ fn empty_block_serialized_size() {
|
||||||
#[test]
|
#[test]
|
||||||
fn block_single_tx_serialized_size() {
|
fn block_single_tx_serialized_size() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let tx1 = tx1i2o();
|
let tx1 = tx1i2o();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![&tx1], &keychain, &prev, &key_id);
|
let b = new_block(vec![&tx1], &keychain, &builder, &prev, &key_id);
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &b).expect("serialization failed");
|
ser::serialize(&mut vec, &b).expect("serialization failed");
|
||||||
let target_len = 2_847;
|
let target_len = 2_847;
|
||||||
|
@ -280,9 +292,10 @@ fn block_single_tx_serialized_size() {
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_compact_block_serialized_size() {
|
fn empty_compact_block_serialized_size() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
let b = new_block(vec![], &keychain, &builder, &prev, &key_id);
|
||||||
let cb: CompactBlock = b.into();
|
let cb: CompactBlock = b.into();
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
||||||
|
@ -293,10 +306,11 @@ fn empty_compact_block_serialized_size() {
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_block_single_tx_serialized_size() {
|
fn compact_block_single_tx_serialized_size() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let tx1 = tx1i2o();
|
let tx1 = tx1i2o();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![&tx1], &keychain, &prev, &key_id);
|
let b = new_block(vec![&tx1], &keychain, &builder, &prev, &key_id);
|
||||||
let cb: CompactBlock = b.into();
|
let cb: CompactBlock = b.into();
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
||||||
|
@ -307,6 +321,7 @@ fn compact_block_single_tx_serialized_size() {
|
||||||
#[test]
|
#[test]
|
||||||
fn block_10_tx_serialized_size() {
|
fn block_10_tx_serialized_size() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
global::set_mining_mode(global::ChainTypes::Mainnet);
|
global::set_mining_mode(global::ChainTypes::Mainnet);
|
||||||
|
|
||||||
let mut txs = vec![];
|
let mut txs = vec![];
|
||||||
|
@ -316,7 +331,7 @@ fn block_10_tx_serialized_size() {
|
||||||
}
|
}
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(txs.iter().collect(), &keychain, &prev, &key_id);
|
let b = new_block(txs.iter().collect(), &keychain, &builder, &prev, &key_id);
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &b).expect("serialization failed");
|
ser::serialize(&mut vec, &b).expect("serialization failed");
|
||||||
let target_len = 17_085;
|
let target_len = 17_085;
|
||||||
|
@ -326,6 +341,7 @@ fn block_10_tx_serialized_size() {
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_block_10_tx_serialized_size() {
|
fn compact_block_10_tx_serialized_size() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
|
|
||||||
let mut txs = vec![];
|
let mut txs = vec![];
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
|
@ -334,7 +350,7 @@ fn compact_block_10_tx_serialized_size() {
|
||||||
}
|
}
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(txs.iter().collect(), &keychain, &prev, &key_id);
|
let b = new_block(txs.iter().collect(), &keychain, &builder, &prev, &key_id);
|
||||||
let cb: CompactBlock = b.into();
|
let cb: CompactBlock = b.into();
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
||||||
|
@ -345,10 +361,11 @@ fn compact_block_10_tx_serialized_size() {
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_block_hash_with_nonce() {
|
fn compact_block_hash_with_nonce() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let tx = tx1i2o();
|
let tx = tx1i2o();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![&tx], &keychain, &prev, &key_id);
|
let b = new_block(vec![&tx], &keychain, &builder, &prev, &key_id);
|
||||||
let cb1: CompactBlock = b.clone().into();
|
let cb1: CompactBlock = b.clone().into();
|
||||||
let cb2: CompactBlock = b.clone().into();
|
let cb2: CompactBlock = b.clone().into();
|
||||||
|
|
||||||
|
@ -375,10 +392,11 @@ fn compact_block_hash_with_nonce() {
|
||||||
#[test]
|
#[test]
|
||||||
fn convert_block_to_compact_block() {
|
fn convert_block_to_compact_block() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let tx1 = tx1i2o();
|
let tx1 = tx1i2o();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![&tx1], &keychain, &prev, &key_id);
|
let b = new_block(vec![&tx1], &keychain, &builder, &prev, &key_id);
|
||||||
let cb: CompactBlock = b.clone().into();
|
let cb: CompactBlock = b.clone().into();
|
||||||
|
|
||||||
assert_eq!(cb.out_full().len(), 1);
|
assert_eq!(cb.out_full().len(), 1);
|
||||||
|
@ -398,9 +416,10 @@ fn convert_block_to_compact_block() {
|
||||||
#[test]
|
#[test]
|
||||||
fn hydrate_empty_compact_block() {
|
fn hydrate_empty_compact_block() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
let b = new_block(vec![], &keychain, &builder, &prev, &key_id);
|
||||||
let cb: CompactBlock = b.clone().into();
|
let cb: CompactBlock = b.clone().into();
|
||||||
let hb = Block::hydrate_from(cb, vec![]).unwrap();
|
let hb = Block::hydrate_from(cb, vec![]).unwrap();
|
||||||
assert_eq!(hb.header, b.header);
|
assert_eq!(hb.header, b.header);
|
||||||
|
@ -411,10 +430,11 @@ fn hydrate_empty_compact_block() {
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_deserialize_compact_block() {
|
fn serialize_deserialize_compact_block() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let tx1 = tx1i2o();
|
let tx1 = tx1i2o();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let b = new_block(vec![&tx1], &keychain, &prev, &key_id);
|
let b = new_block(vec![&tx1], &keychain, &builder, &prev, &key_id);
|
||||||
|
|
||||||
let mut cb1: CompactBlock = b.into();
|
let mut cb1: CompactBlock = b.into();
|
||||||
|
|
||||||
|
@ -437,6 +457,7 @@ fn serialize_deserialize_compact_block() {
|
||||||
#[test]
|
#[test]
|
||||||
fn same_amount_outputs_copy_range_proof() {
|
fn same_amount_outputs_copy_range_proof() {
|
||||||
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
@ -449,6 +470,7 @@ fn same_amount_outputs_copy_range_proof() {
|
||||||
with_fee(1),
|
with_fee(1),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -468,6 +490,7 @@ fn same_amount_outputs_copy_range_proof() {
|
||||||
kernels.clone(),
|
kernels.clone(),
|
||||||
)],
|
)],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
&prev,
|
&prev,
|
||||||
&key_id,
|
&key_id,
|
||||||
);
|
);
|
||||||
|
@ -484,6 +507,7 @@ fn same_amount_outputs_copy_range_proof() {
|
||||||
#[test]
|
#[test]
|
||||||
fn wrong_amount_range_proof() {
|
fn wrong_amount_range_proof() {
|
||||||
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
@ -496,6 +520,7 @@ fn wrong_amount_range_proof() {
|
||||||
with_fee(1),
|
with_fee(1),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let tx2 = build::transaction(
|
let tx2 = build::transaction(
|
||||||
|
@ -506,6 +531,7 @@ fn wrong_amount_range_proof() {
|
||||||
with_fee(1),
|
with_fee(1),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -525,6 +551,7 @@ fn wrong_amount_range_proof() {
|
||||||
kernels.clone(),
|
kernels.clone(),
|
||||||
)],
|
)],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
&prev,
|
&prev,
|
||||||
&key_id,
|
&key_id,
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,6 +21,7 @@ use grin_core::core::{
|
||||||
};
|
};
|
||||||
use grin_core::libtx::{
|
use grin_core::libtx::{
|
||||||
build::{self, input, output, with_fee},
|
build::{self, input, output, with_fee},
|
||||||
|
proof::{ProofBuild, ProofBuilder},
|
||||||
reward,
|
reward,
|
||||||
};
|
};
|
||||||
use grin_core::pow::Difficulty;
|
use grin_core::pow::Difficulty;
|
||||||
|
@ -29,6 +30,7 @@ use grin_keychain as keychain;
|
||||||
// utility producing a transaction with 2 inputs and a single outputs
|
// utility producing a transaction with 2 inputs and a single outputs
|
||||||
pub fn tx2i1o() -> Transaction {
|
pub fn tx2i1o() -> Transaction {
|
||||||
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
@ -41,6 +43,7 @@ pub fn tx2i1o() -> Transaction {
|
||||||
with_fee(2),
|
with_fee(2),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
@ -48,12 +51,14 @@ pub fn tx2i1o() -> Transaction {
|
||||||
// utility producing a transaction with a single input and output
|
// utility producing a transaction with a single input and output
|
||||||
pub fn tx1i1o() -> Transaction {
|
pub fn tx1i1o() -> Transaction {
|
||||||
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
|
|
||||||
build::transaction(
|
build::transaction(
|
||||||
vec![input(5, key_id1), output(3, key_id2), with_fee(2)],
|
vec![input(5, key_id1), output(3, key_id2), with_fee(2)],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
@ -63,6 +68,7 @@ pub fn tx1i1o() -> Transaction {
|
||||||
// Note: this tx has an "offset" kernel
|
// Note: this tx has an "offset" kernel
|
||||||
pub fn tx1i2o() -> Transaction {
|
pub fn tx1i2o() -> Transaction {
|
||||||
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
@ -75,23 +81,26 @@ pub fn tx1i2o() -> Transaction {
|
||||||
with_fee(2),
|
with_fee(2),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// utility to create a block without worrying about the key or previous
|
// utility to create a block without worrying about the key or previous
|
||||||
// header
|
// header
|
||||||
pub fn new_block<K>(
|
pub fn new_block<K, B>(
|
||||||
txs: Vec<&Transaction>,
|
txs: Vec<&Transaction>,
|
||||||
keychain: &K,
|
keychain: &K,
|
||||||
|
builder: &B,
|
||||||
previous_header: &BlockHeader,
|
previous_header: &BlockHeader,
|
||||||
key_id: &Identifier,
|
key_id: &Identifier,
|
||||||
) -> Block
|
) -> Block
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let reward_output = reward::output(keychain, &key_id, fees, false).unwrap();
|
let reward_output = reward::output(keychain, builder, &key_id, fees, false).unwrap();
|
||||||
Block::new(
|
Block::new(
|
||||||
&previous_header,
|
&previous_header,
|
||||||
txs.into_iter().cloned().collect(),
|
txs.into_iter().cloned().collect(),
|
||||||
|
@ -103,13 +112,21 @@ where
|
||||||
|
|
||||||
// utility producing a transaction that spends an output with the provided
|
// utility producing a transaction that spends an output with the provided
|
||||||
// value and blinding key
|
// value and blinding key
|
||||||
pub fn txspend1i1o<K>(v: u64, keychain: &K, key_id1: Identifier, key_id2: Identifier) -> Transaction
|
pub fn txspend1i1o<K, B>(
|
||||||
|
v: u64,
|
||||||
|
keychain: &K,
|
||||||
|
builder: &B,
|
||||||
|
key_id1: Identifier,
|
||||||
|
key_id2: Identifier,
|
||||||
|
) -> Transaction
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
build::transaction(
|
build::transaction(
|
||||||
vec![input(v, key_id1), output(3, key_id2), with_fee(2)],
|
vec![input(v, key_id1), output(3, key_id2), with_fee(2)],
|
||||||
keychain,
|
keychain,
|
||||||
|
builder,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
@ -618,38 +618,75 @@ fn test_secondary_pow_scale() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hard_forks() {
|
fn hard_forks() {
|
||||||
assert!(valid_header_version(0, HeaderVersion::new(1)));
|
// Tests for mainnet chain type.
|
||||||
assert!(valid_header_version(10, HeaderVersion::new(1)));
|
{
|
||||||
assert!(!valid_header_version(10, HeaderVersion::new(2)));
|
global::set_mining_mode(global::ChainTypes::Mainnet);
|
||||||
assert!(valid_header_version(
|
assert_eq!(global::is_floonet(), false);
|
||||||
YEAR_HEIGHT / 2 - 1,
|
assert!(valid_header_version(0, HeaderVersion::new(1)));
|
||||||
HeaderVersion::new(1)
|
assert!(valid_header_version(10, HeaderVersion::new(1)));
|
||||||
));
|
assert!(!valid_header_version(10, HeaderVersion::new(2)));
|
||||||
// v2 not active yet
|
assert!(valid_header_version(
|
||||||
assert!(!valid_header_version(
|
YEAR_HEIGHT / 2 - 1,
|
||||||
YEAR_HEIGHT / 2,
|
HeaderVersion::new(1)
|
||||||
HeaderVersion::new(2)
|
));
|
||||||
));
|
assert!(valid_header_version(YEAR_HEIGHT / 2, HeaderVersion::new(2)));
|
||||||
assert!(!valid_header_version(
|
assert!(valid_header_version(
|
||||||
YEAR_HEIGHT / 2,
|
YEAR_HEIGHT / 2 + 1,
|
||||||
HeaderVersion::new(1)
|
HeaderVersion::new(2)
|
||||||
));
|
));
|
||||||
assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(1)));
|
assert!(!valid_header_version(
|
||||||
assert!(!valid_header_version(
|
YEAR_HEIGHT / 2,
|
||||||
YEAR_HEIGHT / 2 + 1,
|
HeaderVersion::new(1)
|
||||||
HeaderVersion::new(2)
|
));
|
||||||
));
|
assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(1)));
|
||||||
|
// v3 not active yet
|
||||||
|
assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(3)));
|
||||||
|
assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(2)));
|
||||||
|
assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(1)));
|
||||||
|
assert!(!valid_header_version(
|
||||||
|
YEAR_HEIGHT * 3 / 2,
|
||||||
|
HeaderVersion::new(2)
|
||||||
|
));
|
||||||
|
assert!(!valid_header_version(
|
||||||
|
YEAR_HEIGHT + 1,
|
||||||
|
HeaderVersion::new(2)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// Tests for floonet chain type.
|
||||||
|
{
|
||||||
|
global::set_mining_mode(global::ChainTypes::Floonet);
|
||||||
|
assert_eq!(global::is_floonet(), true);
|
||||||
|
assert!(valid_header_version(0, HeaderVersion::new(1)));
|
||||||
|
assert!(valid_header_version(10, HeaderVersion::new(1)));
|
||||||
|
assert!(!valid_header_version(10, HeaderVersion::new(2)));
|
||||||
|
assert!(valid_header_version(
|
||||||
|
FLOONET_FIRST_HARD_FORK - 1,
|
||||||
|
HeaderVersion::new(1)
|
||||||
|
));
|
||||||
|
assert!(valid_header_version(
|
||||||
|
FLOONET_FIRST_HARD_FORK,
|
||||||
|
HeaderVersion::new(2)
|
||||||
|
));
|
||||||
|
assert!(valid_header_version(
|
||||||
|
FLOONET_FIRST_HARD_FORK + 1,
|
||||||
|
HeaderVersion::new(2)
|
||||||
|
));
|
||||||
|
assert!(!valid_header_version(
|
||||||
|
FLOONET_FIRST_HARD_FORK,
|
||||||
|
HeaderVersion::new(1)
|
||||||
|
));
|
||||||
|
assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(1)));
|
||||||
|
// v3 not active yet
|
||||||
|
assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(3)));
|
||||||
|
assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(2)));
|
||||||
|
assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(1)));
|
||||||
|
assert!(!valid_header_version(
|
||||||
|
YEAR_HEIGHT * 3 / 2,
|
||||||
|
HeaderVersion::new(2)
|
||||||
|
));
|
||||||
|
assert!(!valid_header_version(
|
||||||
|
YEAR_HEIGHT + 1,
|
||||||
|
HeaderVersion::new(2)
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn hard_fork_2() {
|
|
||||||
// assert!(valid_header_version(0, 1));
|
|
||||||
// assert!(valid_header_version(10, 1));
|
|
||||||
// assert!(valid_header_version(10, 2));
|
|
||||||
// assert!(valid_header_version(250_000, 1));
|
|
||||||
// assert!(!valid_header_version(250_001, 1));
|
|
||||||
// assert!(!valid_header_version(500_000, 1));
|
|
||||||
// assert!(valid_header_version(250_001, 2));
|
|
||||||
// assert!(valid_header_version(500_000, 2));
|
|
||||||
// assert!(!valid_header_version(500_001, 2));
|
|
||||||
// }
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ use self::core::core::{aggregate, deaggregate, KernelFeatures, Output, Transacti
|
||||||
use self::core::libtx::build::{
|
use self::core::libtx::build::{
|
||||||
self, initial_tx, input, output, with_excess, with_fee, with_lock_height,
|
self, initial_tx, input, output, with_excess, with_fee, with_lock_height,
|
||||||
};
|
};
|
||||||
|
use self::core::libtx::ProofBuilder;
|
||||||
use self::core::ser;
|
use self::core::ser;
|
||||||
use self::keychain::{BlindingFactor, ExtKeychain, Keychain};
|
use self::keychain::{BlindingFactor, ExtKeychain, Keychain};
|
||||||
use self::util::static_secp_instance;
|
use self::util::static_secp_instance;
|
||||||
|
@ -75,18 +76,15 @@ fn tx_double_ser_deser() {
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Keychain Error")]
|
#[should_panic(expected = "Keychain Error")]
|
||||||
fn test_zero_commit_fails() {
|
fn test_zero_commit_fails() {
|
||||||
let mut keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
keychain.set_use_switch_commits(false);
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
|
|
||||||
// blinding should fail as signing with a zero r*G shouldn't work
|
// blinding should fail as signing with a zero r*G shouldn't work
|
||||||
build::transaction(
|
build::transaction(
|
||||||
vec![
|
vec![input(10, key_id1.clone()), output(10, key_id1.clone())],
|
||||||
input(10, key_id1.clone()),
|
|
||||||
output(9, key_id1.clone()),
|
|
||||||
with_fee(1),
|
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -98,6 +96,7 @@ fn verifier_cache() -> Arc<RwLock<dyn VerifierCache>> {
|
||||||
#[test]
|
#[test]
|
||||||
fn build_tx_kernel() {
|
fn build_tx_kernel() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
@ -111,6 +110,7 @@ fn build_tx_kernel() {
|
||||||
with_fee(2),
|
with_fee(2),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -350,6 +350,7 @@ fn basic_transaction_deaggregation() {
|
||||||
#[test]
|
#[test]
|
||||||
fn hash_output() {
|
fn hash_output() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
@ -362,6 +363,7 @@ fn hash_output() {
|
||||||
with_fee(1),
|
with_fee(1),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let h = tx.outputs()[0].hash();
|
let h = tx.outputs()[0].hash();
|
||||||
|
@ -407,6 +409,7 @@ fn tx_hash_diff() {
|
||||||
#[test]
|
#[test]
|
||||||
fn tx_build_exchange() {
|
fn tx_build_exchange() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
@ -419,9 +422,12 @@ fn tx_build_exchange() {
|
||||||
|
|
||||||
// Alice builds her transaction, with change, which also produces the sum
|
// Alice builds her transaction, with change, which also produces the sum
|
||||||
// of blinding factors before they're obscured.
|
// of blinding factors before they're obscured.
|
||||||
let (tx, sum) =
|
let (tx, sum) = build::partial_transaction(
|
||||||
build::partial_transaction(vec![in1, in2, output(1, key_id3), with_fee(2)], &keychain)
|
vec![in1, in2, output(1, key_id3), with_fee(2)],
|
||||||
.unwrap();
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
(tx, sum)
|
(tx, sum)
|
||||||
};
|
};
|
||||||
|
@ -436,6 +442,7 @@ fn tx_build_exchange() {
|
||||||
output(4, key_id4),
|
output(4, key_id4),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -447,11 +454,12 @@ fn tx_build_exchange() {
|
||||||
#[test]
|
#[test]
|
||||||
fn reward_empty_block() {
|
fn reward_empty_block() {
|
||||||
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
|
|
||||||
let previous_header = BlockHeader::default();
|
let previous_header = BlockHeader::default();
|
||||||
|
|
||||||
let b = new_block(vec![], &keychain, &previous_header, &key_id);
|
let b = new_block(vec![], &keychain, &builder, &previous_header, &key_id);
|
||||||
|
|
||||||
b.cut_through()
|
b.cut_through()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -462,6 +470,7 @@ fn reward_empty_block() {
|
||||||
#[test]
|
#[test]
|
||||||
fn reward_with_tx_block() {
|
fn reward_with_tx_block() {
|
||||||
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
|
|
||||||
let vc = verifier_cache();
|
let vc = verifier_cache();
|
||||||
|
@ -471,7 +480,13 @@ fn reward_with_tx_block() {
|
||||||
|
|
||||||
let previous_header = BlockHeader::default();
|
let previous_header = BlockHeader::default();
|
||||||
|
|
||||||
let block = new_block(vec![&mut tx1], &keychain, &previous_header, &key_id);
|
let block = new_block(
|
||||||
|
vec![&mut tx1],
|
||||||
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
&previous_header,
|
||||||
|
&key_id,
|
||||||
|
);
|
||||||
block
|
block
|
||||||
.cut_through()
|
.cut_through()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -482,6 +497,7 @@ fn reward_with_tx_block() {
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_block() {
|
fn simple_block() {
|
||||||
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
|
|
||||||
let vc = verifier_cache();
|
let vc = verifier_cache();
|
||||||
|
@ -493,6 +509,7 @@ fn simple_block() {
|
||||||
let b = new_block(
|
let b = new_block(
|
||||||
vec![&mut tx1, &mut tx2],
|
vec![&mut tx1, &mut tx2],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
&previous_header,
|
&previous_header,
|
||||||
&key_id,
|
&key_id,
|
||||||
);
|
);
|
||||||
|
@ -503,7 +520,7 @@ fn simple_block() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_block_with_timelocked_tx() {
|
fn test_block_with_timelocked_tx() {
|
||||||
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
|
||||||
|
let builder = ProofBuilder::new(&keychain);
|
||||||
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
@ -520,12 +537,19 @@ fn test_block_with_timelocked_tx() {
|
||||||
with_lock_height(1),
|
with_lock_height(1),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let previous_header = BlockHeader::default();
|
let previous_header = BlockHeader::default();
|
||||||
|
|
||||||
let b = new_block(vec![&tx1], &keychain, &previous_header, &key_id3.clone());
|
let b = new_block(
|
||||||
|
vec![&tx1],
|
||||||
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
&previous_header,
|
||||||
|
&key_id3.clone(),
|
||||||
|
);
|
||||||
b.validate(&BlindingFactor::zero(), vc.clone()).unwrap();
|
b.validate(&BlindingFactor::zero(), vc.clone()).unwrap();
|
||||||
|
|
||||||
// now try adding a timelocked tx where lock height is greater than current
|
// now try adding a timelocked tx where lock height is greater than current
|
||||||
|
@ -538,11 +562,18 @@ fn test_block_with_timelocked_tx() {
|
||||||
with_lock_height(2),
|
with_lock_height(2),
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let previous_header = BlockHeader::default();
|
let previous_header = BlockHeader::default();
|
||||||
let b = new_block(vec![&tx1], &keychain, &previous_header, &key_id3.clone());
|
let b = new_block(
|
||||||
|
vec![&tx1],
|
||||||
|
&keychain,
|
||||||
|
&builder,
|
||||||
|
&previous_header,
|
||||||
|
&key_id3.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
match b.validate(&BlindingFactor::zero(), vc.clone()) {
|
match b.validate(&BlindingFactor::zero(), vc.clone()) {
|
||||||
Err(KernelLockHeight(height)) => {
|
Err(KernelLockHeight(height)) => {
|
||||||
|
|
|
@ -27,8 +27,10 @@ use grin_keychain as keychain;
|
||||||
fn test_output_ser_deser() {
|
fn test_output_ser_deser() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let commit = keychain.commit(5, &key_id).unwrap();
|
let switch = &keychain::SwitchCommitmentType::Regular;
|
||||||
let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap();
|
let commit = keychain.commit(5, &key_id, switch).unwrap();
|
||||||
|
let builder = proof::ProofBuilder::new(&keychain);
|
||||||
|
let proof = proof::create(&keychain, &builder, 5, &key_id, switch, commit, None).unwrap();
|
||||||
|
|
||||||
let out = Output {
|
let out = Output {
|
||||||
features: OutputFeatures::Plain,
|
features: OutputFeatures::Plain,
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub mod common;
|
||||||
use self::core::core::verifier_cache::{LruVerifierCache, VerifierCache};
|
use self::core::core::verifier_cache::{LruVerifierCache, VerifierCache};
|
||||||
use self::core::core::{Output, OutputFeatures};
|
use self::core::core::{Output, OutputFeatures};
|
||||||
use self::core::libtx::proof;
|
use self::core::libtx::proof;
|
||||||
use self::keychain::{ExtKeychain, Keychain};
|
use self::keychain::{ExtKeychain, Keychain, SwitchCommitmentType};
|
||||||
use self::util::RwLock;
|
use self::util::RwLock;
|
||||||
use grin_core as core;
|
use grin_core as core;
|
||||||
use grin_keychain as keychain;
|
use grin_keychain as keychain;
|
||||||
|
@ -34,8 +34,10 @@ fn test_verifier_cache_rangeproofs() {
|
||||||
|
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let commit = keychain.commit(5, &key_id).unwrap();
|
let switch = &SwitchCommitmentType::Regular;
|
||||||
let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap();
|
let commit = keychain.commit(5, &key_id, switch).unwrap();
|
||||||
|
let builder = proof::ProofBuilder::new(&keychain);
|
||||||
|
let proof = proof::create(&keychain, &builder, 5, &key_id, switch, commit, None).unwrap();
|
||||||
|
|
||||||
let out = Output {
|
let out = Output {
|
||||||
features: OutputFeatures::Plain,
|
features: OutputFeatures::Plain,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin_keychain"
|
name = "grin_keychain"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -19,7 +19,7 @@ serde_derive = "1"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
uuid = { version = "0.6", features = ["serde", "v4"] }
|
uuid = { version = "0.6", features = ["serde", "v4"] }
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
zeroize = "0.8.0"
|
zeroize = "0.9"
|
||||||
|
|
||||||
digest = "0.7"
|
digest = "0.7"
|
||||||
hmac = "0.6"
|
hmac = "0.6"
|
||||||
|
@ -27,4 +27,4 @@ ripemd160 = "0.7"
|
||||||
sha2 = "0.7"
|
sha2 = "0.7"
|
||||||
pbkdf2 = "0.2"
|
pbkdf2 = "0.2"
|
||||||
|
|
||||||
grin_util = { path = "../util", version = "1.1.1-beta.1" }
|
grin_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||||
|
|
|
@ -149,7 +149,7 @@ impl BIP32Hasher for BIP32GrinHasher {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extended private key
|
/// Extended private key
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct ExtendedPrivKey {
|
pub struct ExtendedPrivKey {
|
||||||
/// The network this key is to be used on
|
/// The network this key is to be used on
|
||||||
pub network: [u8; 4],
|
pub network: [u8; 4],
|
||||||
|
@ -399,7 +399,7 @@ impl ExtendedPrivKey {
|
||||||
where
|
where
|
||||||
H: BIP32Hasher,
|
H: BIP32Hasher,
|
||||||
{
|
{
|
||||||
let mut sk: ExtendedPrivKey = *self;
|
let mut sk: ExtendedPrivKey = self.clone();
|
||||||
for cnum in cnums {
|
for cnum in cnums {
|
||||||
sk = sk.ckd_priv(secp, hasher, *cnum)?;
|
sk = sk.ckd_priv(secp, hasher, *cnum)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,22 +17,33 @@
|
||||||
use rand::distributions::Alphanumeric;
|
use rand::distributions::Alphanumeric;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
use crate::blake2;
|
use crate::blake2::blake2b::blake2b;
|
||||||
|
|
||||||
use crate::extkey_bip32::{BIP32GrinHasher, ExtendedPrivKey};
|
use crate::extkey_bip32::{BIP32GrinHasher, ExtendedPrivKey, ExtendedPubKey};
|
||||||
use crate::types::{BlindSum, BlindingFactor, Error, ExtKeychainPath, Identifier, Keychain};
|
use crate::types::{
|
||||||
use crate::util::secp::key::SecretKey;
|
BlindSum, BlindingFactor, Error, ExtKeychainPath, Identifier, Keychain, SwitchCommitmentType,
|
||||||
|
};
|
||||||
|
use crate::util::secp::key::{PublicKey, SecretKey};
|
||||||
use crate::util::secp::pedersen::Commitment;
|
use crate::util::secp::pedersen::Commitment;
|
||||||
use crate::util::secp::{self, Message, Secp256k1, Signature};
|
use crate::util::secp::{self, Message, Secp256k1, Signature};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ExtKeychain {
|
pub struct ExtKeychain {
|
||||||
secp: Secp256k1,
|
secp: Secp256k1,
|
||||||
master: ExtendedPrivKey,
|
pub master: ExtendedPrivKey,
|
||||||
use_switch_commits: bool,
|
|
||||||
hasher: BIP32GrinHasher,
|
hasher: BIP32GrinHasher,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ExtKeychain {
|
||||||
|
pub fn pub_root_key(&mut self) -> ExtendedPubKey {
|
||||||
|
ExtendedPubKey::from_private(&self.secp, &self.master, &mut self.hasher)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hasher(&self) -> BIP32GrinHasher {
|
||||||
|
self.hasher.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Keychain for ExtKeychain {
|
impl Keychain for ExtKeychain {
|
||||||
fn from_seed(seed: &[u8], is_floo: bool) -> Result<ExtKeychain, Error> {
|
fn from_seed(seed: &[u8], is_floo: bool) -> Result<ExtKeychain, Error> {
|
||||||
let mut h = BIP32GrinHasher::new(is_floo);
|
let mut h = BIP32GrinHasher::new(is_floo);
|
||||||
|
@ -41,7 +52,6 @@ impl Keychain for ExtKeychain {
|
||||||
let keychain = ExtKeychain {
|
let keychain = ExtKeychain {
|
||||||
secp: secp,
|
secp: secp,
|
||||||
master: master,
|
master: master,
|
||||||
use_switch_commits: true,
|
|
||||||
hasher: h,
|
hasher: h,
|
||||||
};
|
};
|
||||||
Ok(keychain)
|
Ok(keychain)
|
||||||
|
@ -54,7 +64,6 @@ impl Keychain for ExtKeychain {
|
||||||
let keychain = ExtKeychain {
|
let keychain = ExtKeychain {
|
||||||
secp: secp,
|
secp: secp,
|
||||||
master: master,
|
master: master,
|
||||||
use_switch_commits: true,
|
|
||||||
hasher: h,
|
hasher: h,
|
||||||
};
|
};
|
||||||
Ok(keychain)
|
Ok(keychain)
|
||||||
|
@ -63,7 +72,7 @@ impl Keychain for ExtKeychain {
|
||||||
/// For testing - probably not a good idea to use outside of tests.
|
/// For testing - probably not a good idea to use outside of tests.
|
||||||
fn from_random_seed(is_floo: bool) -> Result<ExtKeychain, Error> {
|
fn from_random_seed(is_floo: bool) -> Result<ExtKeychain, Error> {
|
||||||
let seed: String = thread_rng().sample_iter(&Alphanumeric).take(16).collect();
|
let seed: String = thread_rng().sample_iter(&Alphanumeric).take(16).collect();
|
||||||
let seed = blake2::blake2b::blake2b(32, &[], seed.as_bytes());
|
let seed = blake2b(32, &[], seed.as_bytes());
|
||||||
ExtKeychain::from_seed(seed.as_bytes(), is_floo)
|
ExtKeychain::from_seed(seed.as_bytes(), is_floo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,22 +84,39 @@ impl Keychain for ExtKeychain {
|
||||||
ExtKeychainPath::new(depth, d1, d2, d3, d4).to_identifier()
|
ExtKeychainPath::new(depth, d1, d2, d3, d4).to_identifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_key(&self, amount: u64, id: &Identifier) -> Result<SecretKey, Error> {
|
fn public_root_key(&self) -> PublicKey {
|
||||||
|
let mut hasher = self.hasher.clone();
|
||||||
|
ExtendedPubKey::from_private(&self.secp, &self.master, &mut hasher).public_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn derive_key(
|
||||||
|
&self,
|
||||||
|
amount: u64,
|
||||||
|
id: &Identifier,
|
||||||
|
switch: &SwitchCommitmentType,
|
||||||
|
) -> Result<SecretKey, Error> {
|
||||||
let mut h = self.hasher.clone();
|
let mut h = self.hasher.clone();
|
||||||
let p = id.to_path();
|
let p = id.to_path();
|
||||||
let mut ext_key = self.master;
|
let mut ext_key = self.master.clone();
|
||||||
for i in 0..p.depth {
|
for i in 0..p.depth {
|
||||||
ext_key = ext_key.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 {
|
match *switch {
|
||||||
true => Ok(self.secp.blind_switch(amount, ext_key.secret_key)?),
|
SwitchCommitmentType::Regular => {
|
||||||
false => Ok(ext_key.secret_key),
|
Ok(self.secp.blind_switch(amount, ext_key.secret_key)?)
|
||||||
|
}
|
||||||
|
SwitchCommitmentType::None => Ok(ext_key.secret_key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit(&self, amount: u64, id: &Identifier) -> Result<Commitment, Error> {
|
fn commit(
|
||||||
let key = self.derive_key(amount, id)?;
|
&self,
|
||||||
|
amount: u64,
|
||||||
|
id: &Identifier,
|
||||||
|
switch: &SwitchCommitmentType,
|
||||||
|
) -> Result<Commitment, Error> {
|
||||||
|
let key = self.derive_key(amount, id, switch)?;
|
||||||
let commit = self.secp.commit(amount, key)?;
|
let commit = self.secp.commit(amount, key)?;
|
||||||
Ok(commit)
|
Ok(commit)
|
||||||
}
|
}
|
||||||
|
@ -100,7 +126,11 @@ impl Keychain for ExtKeychain {
|
||||||
.positive_key_ids
|
.positive_key_ids
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|k| {
|
.filter_map(|k| {
|
||||||
let res = self.derive_key(k.value, &Identifier::from_path(&k.ext_keychain_path));
|
let res = self.derive_key(
|
||||||
|
k.value,
|
||||||
|
&Identifier::from_path(&k.ext_keychain_path),
|
||||||
|
&k.switch,
|
||||||
|
);
|
||||||
if let Ok(s) = res {
|
if let Ok(s) = res {
|
||||||
Some(s)
|
Some(s)
|
||||||
} else {
|
} else {
|
||||||
|
@ -113,7 +143,11 @@ impl Keychain for ExtKeychain {
|
||||||
.negative_key_ids
|
.negative_key_ids
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|k| {
|
.filter_map(|k| {
|
||||||
let res = self.derive_key(k.value, &Identifier::from_path(&k.ext_keychain_path));
|
let res = self.derive_key(
|
||||||
|
k.value,
|
||||||
|
&Identifier::from_path(&k.ext_keychain_path),
|
||||||
|
&k.switch,
|
||||||
|
);
|
||||||
if let Ok(s) = res {
|
if let Ok(s) = res {
|
||||||
Some(s)
|
Some(s)
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,37 +156,32 @@ impl Keychain for ExtKeychain {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
pos_keys.extend(
|
let keys = blind_sum
|
||||||
&blind_sum
|
.positive_blinding_factors
|
||||||
.positive_blinding_factors
|
.iter()
|
||||||
.iter()
|
.filter_map(|b| b.secret_key(&self.secp).ok().clone())
|
||||||
.filter_map(|b| b.secret_key(&self.secp).ok())
|
.collect::<Vec<SecretKey>>();
|
||||||
.collect::<Vec<SecretKey>>(),
|
pos_keys.extend(keys);
|
||||||
);
|
|
||||||
|
|
||||||
neg_keys.extend(
|
let keys = blind_sum
|
||||||
&blind_sum
|
.negative_blinding_factors
|
||||||
.negative_blinding_factors
|
.iter()
|
||||||
.iter()
|
.filter_map(|b| b.secret_key(&self.secp).ok().clone())
|
||||||
.filter_map(|b| b.secret_key(&self.secp).ok())
|
.collect::<Vec<SecretKey>>();
|
||||||
.collect::<Vec<SecretKey>>(),
|
neg_keys.extend(keys);
|
||||||
);
|
|
||||||
|
|
||||||
let sum = self.secp.blind_sum(pos_keys, neg_keys)?;
|
let sum = self.secp.blind_sum(pos_keys, neg_keys)?;
|
||||||
Ok(BlindingFactor::from_secret_key(sum))
|
Ok(BlindingFactor::from_secret_key(sum))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_nonce(&self, commit: &Commitment) -> Result<SecretKey, Error> {
|
fn sign(
|
||||||
// hash(commit|wallet root secret key (m)) as nonce
|
&self,
|
||||||
let root_key = self.derive_key(0, &Self::root_key_id())?;
|
msg: &Message,
|
||||||
let res = blake2::blake2b::blake2b(32, &commit.0, &root_key.0[..]);
|
amount: u64,
|
||||||
let res = res.as_bytes();
|
id: &Identifier,
|
||||||
SecretKey::from_slice(&self.secp, &res)
|
switch: &SwitchCommitmentType,
|
||||||
.map_err(|e| Error::RangeProof(format!("Unable to create nonce: {:?}", e).to_string()))
|
) -> Result<Signature, Error> {
|
||||||
}
|
let skey = self.derive_key(amount, id, switch)?;
|
||||||
|
|
||||||
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)?;
|
let sig = self.secp.sign(msg, &skey)?;
|
||||||
Ok(sig)
|
Ok(sig)
|
||||||
}
|
}
|
||||||
|
@ -167,10 +196,6 @@ impl Keychain for ExtKeychain {
|
||||||
Ok(sig)
|
Ok(sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_use_switch_commits(&mut self, value: bool) {
|
|
||||||
self.use_switch_commits = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn secp(&self) -> &Secp256k1 {
|
fn secp(&self) -> &Secp256k1 {
|
||||||
&self.secp
|
&self.secp
|
||||||
}
|
}
|
||||||
|
@ -182,11 +207,13 @@ mod test {
|
||||||
use crate::types::{BlindSum, BlindingFactor, ExtKeychainPath, Keychain};
|
use crate::types::{BlindSum, BlindingFactor, ExtKeychainPath, Keychain};
|
||||||
use crate::util::secp;
|
use crate::util::secp;
|
||||||
use crate::util::secp::key::SecretKey;
|
use crate::util::secp::key::SecretKey;
|
||||||
|
use crate::SwitchCommitmentType;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_derivation() {
|
fn test_key_derivation() {
|
||||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||||
let secp = keychain.secp();
|
let secp = keychain.secp();
|
||||||
|
let switch = &SwitchCommitmentType::None;
|
||||||
|
|
||||||
let path = ExtKeychainPath::new(1, 1, 0, 0, 0);
|
let path = ExtKeychainPath::new(1, 1, 0, 0, 0);
|
||||||
let key_id = path.to_identifier();
|
let key_id = path.to_identifier();
|
||||||
|
@ -196,10 +223,10 @@ mod test {
|
||||||
|
|
||||||
// now create a zero commitment using the key on the keychain associated with
|
// now create a zero commitment using the key on the keychain associated with
|
||||||
// the key_id
|
// the key_id
|
||||||
let commit = keychain.commit(0, &key_id).unwrap();
|
let commit = keychain.commit(0, &key_id, switch).unwrap();
|
||||||
|
|
||||||
// now check we can use our key to verify a signature from this zero commitment
|
// now check we can use our key to verify a signature from this zero commitment
|
||||||
let sig = keychain.sign(&msg, 0, &key_id).unwrap();
|
let sig = keychain.sign(&msg, 0, &key_id, switch).unwrap();
|
||||||
secp.verify_from_commit(&msg, &sig, &commit).unwrap();
|
secp.verify_from_commit(&msg, &sig, &commit).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,9 +262,9 @@ mod test {
|
||||||
|
|
||||||
// create commitments for secret keys 1, 2 and 3
|
// create commitments for secret keys 1, 2 and 3
|
||||||
// all committing to the value 0 (which is what we do for tx_kernels)
|
// all committing to the value 0 (which is what we do for tx_kernels)
|
||||||
let commit_1 = keychain.secp.commit(0, skey1).unwrap();
|
let commit_1 = keychain.secp.commit(0, skey1.clone()).unwrap();
|
||||||
let commit_2 = keychain.secp.commit(0, skey2).unwrap();
|
let commit_2 = keychain.secp.commit(0, skey2.clone()).unwrap();
|
||||||
let commit_3 = keychain.secp.commit(0, skey3).unwrap();
|
let commit_3 = keychain.secp.commit(0, skey3.clone()).unwrap();
|
||||||
|
|
||||||
// now sum commitments for keys 1 and 2
|
// now sum commitments for keys 1 and 2
|
||||||
let sum = keychain
|
let sum = keychain
|
||||||
|
|
|
@ -25,14 +25,19 @@ extern crate serde_derive;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
|
extern crate sha2;
|
||||||
|
|
||||||
mod base58;
|
mod base58;
|
||||||
pub mod extkey_bip32;
|
pub mod extkey_bip32;
|
||||||
pub mod mnemonic;
|
pub mod mnemonic;
|
||||||
mod types;
|
mod types;
|
||||||
|
pub mod view_key;
|
||||||
|
|
||||||
pub mod keychain;
|
pub mod keychain;
|
||||||
pub use crate::extkey_bip32::ChildNumber;
|
pub use crate::extkey_bip32::ChildNumber;
|
||||||
pub use crate::keychain::ExtKeychain;
|
pub use crate::keychain::ExtKeychain;
|
||||||
pub use crate::types::{
|
pub use crate::types::{
|
||||||
BlindSum, BlindingFactor, Error, ExtKeychainPath, Identifier, Keychain, IDENTIFIER_SIZE,
|
BlindSum, BlindingFactor, Error, ExtKeychainPath, Identifier, Keychain, SwitchCommitmentType,
|
||||||
|
IDENTIFIER_SIZE,
|
||||||
};
|
};
|
||||||
|
pub use crate::view_key::ViewKey;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
/// Keychain trait and its main supporting types. The Identifier is a
|
/// Keychain trait and its main supporting types. The Identifier is a
|
||||||
|
@ -129,9 +130,12 @@ impl Identifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_value_path(&self, value: u64) -> ValueExtKeychainPath {
|
pub fn to_value_path(&self, value: u64) -> ValueExtKeychainPath {
|
||||||
|
// TODO: proper support for different switch commitment schemes
|
||||||
|
// For now it is assumed all outputs are using the regular switch commitment scheme
|
||||||
ValueExtKeychainPath {
|
ValueExtKeychainPath {
|
||||||
value,
|
value,
|
||||||
ext_keychain_path: self.to_path(),
|
ext_keychain_path: self.to_path(),
|
||||||
|
switch: SwitchCommitmentType::Regular,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,6 +233,7 @@ impl fmt::Display for Identifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, PartialEq, Serialize, Deserialize, Zeroize)]
|
#[derive(Default, Clone, PartialEq, Serialize, Deserialize, Zeroize)]
|
||||||
|
#[zeroize(drop)]
|
||||||
pub struct BlindingFactor([u8; SECRET_KEY_SIZE]);
|
pub struct BlindingFactor([u8; SECRET_KEY_SIZE]);
|
||||||
|
|
||||||
// Dummy `Debug` implementation that prevents secret leakage.
|
// Dummy `Debug` implementation that prevents secret leakage.
|
||||||
|
@ -318,7 +323,7 @@ impl BlindingFactor {
|
||||||
|
|
||||||
// use blind_sum to subtract skey_1 from our key (to give k = k1 + k2)
|
// use blind_sum to subtract skey_1 from our key (to give k = k1 + k2)
|
||||||
let skey = self.secret_key(secp)?;
|
let skey = self.secret_key(secp)?;
|
||||||
let skey_2 = secp.blind_sum(vec![skey], vec![skey_1])?;
|
let skey_2 = secp.blind_sum(vec![skey], vec![skey_1.clone()])?;
|
||||||
|
|
||||||
let blind_1 = BlindingFactor::from_secret_key(skey_1);
|
let blind_1 = BlindingFactor::from_secret_key(skey_1);
|
||||||
let blind_2 = BlindingFactor::from_secret_key(skey_2);
|
let blind_2 = BlindingFactor::from_secret_key(skey_2);
|
||||||
|
@ -443,11 +448,12 @@ impl ExtKeychainPath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper for amount + path
|
/// Wrapper for amount + switch + path
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Deserialize)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Deserialize)]
|
||||||
pub struct ValueExtKeychainPath {
|
pub struct ValueExtKeychainPath {
|
||||||
pub value: u64,
|
pub value: u64,
|
||||||
pub ext_keychain_path: ExtKeychainPath,
|
pub ext_keychain_path: ExtKeychainPath,
|
||||||
|
pub switch: SwitchCommitmentType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Keychain: Sync + Send + Clone {
|
pub trait Keychain: Sync + Send + Clone {
|
||||||
|
@ -467,16 +473,61 @@ pub trait Keychain: Sync + Send + Clone {
|
||||||
/// Derives a key id from the depth of the keychain and the values at each
|
/// Derives a key id from the depth of the keychain and the values at each
|
||||||
/// depth level. See `KeychainPath` for more information.
|
/// depth level. See `KeychainPath` for more information.
|
||||||
fn derive_key_id(depth: u8, d1: u32, d2: u32, d3: u32, d4: u32) -> Identifier;
|
fn derive_key_id(depth: u8, d1: u32, d2: u32, d3: u32, d4: u32) -> Identifier;
|
||||||
fn derive_key(&self, amount: u64, id: &Identifier) -> Result<SecretKey, Error>;
|
|
||||||
fn commit(&self, amount: u64, id: &Identifier) -> Result<Commitment, Error>;
|
/// The public root key
|
||||||
|
fn public_root_key(&self) -> PublicKey;
|
||||||
|
|
||||||
|
fn derive_key(
|
||||||
|
&self,
|
||||||
|
amount: u64,
|
||||||
|
id: &Identifier,
|
||||||
|
switch: &SwitchCommitmentType,
|
||||||
|
) -> Result<SecretKey, Error>;
|
||||||
|
fn commit(
|
||||||
|
&self,
|
||||||
|
amount: u64,
|
||||||
|
id: &Identifier,
|
||||||
|
switch: &SwitchCommitmentType,
|
||||||
|
) -> Result<Commitment, Error>;
|
||||||
fn blind_sum(&self, blind_sum: &BlindSum) -> Result<BlindingFactor, Error>;
|
fn blind_sum(&self, blind_sum: &BlindSum) -> Result<BlindingFactor, Error>;
|
||||||
fn create_nonce(&self, commit: &Commitment) -> Result<SecretKey, Error>;
|
fn sign(
|
||||||
fn sign(&self, msg: &Message, amount: u64, id: &Identifier) -> Result<Signature, Error>;
|
&self,
|
||||||
|
msg: &Message,
|
||||||
|
amount: u64,
|
||||||
|
id: &Identifier,
|
||||||
|
switch: &SwitchCommitmentType,
|
||||||
|
) -> Result<Signature, Error>;
|
||||||
fn sign_with_blinding(&self, _: &Message, _: &BlindingFactor) -> Result<Signature, Error>;
|
fn sign_with_blinding(&self, _: &Message, _: &BlindingFactor) -> Result<Signature, Error>;
|
||||||
fn set_use_switch_commits(&mut self, value: bool);
|
|
||||||
fn secp(&self) -> &Secp256k1;
|
fn secp(&self) -> &Secp256k1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum SwitchCommitmentType {
|
||||||
|
None,
|
||||||
|
Regular,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for SwitchCommitmentType {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0 => Ok(SwitchCommitmentType::None),
|
||||||
|
1 => Ok(SwitchCommitmentType::Regular),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&SwitchCommitmentType> for u8 {
|
||||||
|
fn from(switch: &SwitchCommitmentType) -> Self {
|
||||||
|
match *switch {
|
||||||
|
SwitchCommitmentType::None => 0,
|
||||||
|
SwitchCommitmentType::Regular => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
|
@ -519,7 +570,7 @@ mod test {
|
||||||
fn split_blinding_factor() {
|
fn split_blinding_factor() {
|
||||||
let secp = Secp256k1::new();
|
let secp = Secp256k1::new();
|
||||||
let skey_in = SecretKey::new(&secp, &mut thread_rng());
|
let skey_in = SecretKey::new(&secp, &mut thread_rng());
|
||||||
let blind = BlindingFactor::from_secret_key(skey_in);
|
let blind = BlindingFactor::from_secret_key(skey_in.clone());
|
||||||
let split = blind.split(&secp).unwrap();
|
let split = blind.split(&secp).unwrap();
|
||||||
|
|
||||||
// split a key, sum the split keys and confirm the sum matches the original key
|
// split a key, sum the split keys and confirm the sum matches the original key
|
||||||
|
|
195
keychain/src/view_key.rs
Normal file
195
keychain/src/view_key.rs
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
use crate::blake2::blake2b::blake2b;
|
||||||
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
|
//use crate::sha2::{Digest, Sha256};
|
||||||
|
use super::extkey_bip32::{
|
||||||
|
BIP32Hasher, ChainCode, ChildNumber, Error as BIP32Error, ExtendedPrivKey, ExtendedPubKey,
|
||||||
|
Fingerprint,
|
||||||
|
};
|
||||||
|
use super::types::{Error, Keychain};
|
||||||
|
use crate::util::secp::constants::GENERATOR_PUB_J_RAW;
|
||||||
|
use crate::util::secp::ffi;
|
||||||
|
use crate::util::secp::key::{PublicKey, SecretKey};
|
||||||
|
use crate::util::secp::Secp256k1;
|
||||||
|
use crate::SwitchCommitmentType;
|
||||||
|
|
||||||
|
/*const VERSION_FLOO_NS: [u8;4] = [0x03, 0x27, 0x3E, 0x4B];
|
||||||
|
const VERSION_FLOO: [u8;4] = [0x03, 0x27, 0x3E, 0x4B];
|
||||||
|
const VERSION_MAIN_NS: [u8;4] = [0x03, 0x3C, 0x08, 0xDF];
|
||||||
|
const VERSION_MAIN: [u8;4] = [0x03, 0x3C, 0x08, 0xDF];*/
|
||||||
|
|
||||||
|
/// Key that can be used to scan the chain for owned outputs
|
||||||
|
/// This is a public key, meaning it cannot be used to spend those outputs
|
||||||
|
/// At the moment only depth 0 keys can be used
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct ViewKey {
|
||||||
|
/// Whether this view key is meant for floonet or not
|
||||||
|
pub is_floo: bool,
|
||||||
|
/// How many derivations this key is from the master (which is 0)
|
||||||
|
pub depth: u8,
|
||||||
|
/// Fingerprint of the parent key
|
||||||
|
parent_fingerprint: Fingerprint,
|
||||||
|
/// Child number of the key used to derive from parent (0 for master)
|
||||||
|
pub child_number: ChildNumber,
|
||||||
|
/// Public key
|
||||||
|
public_key: PublicKey,
|
||||||
|
/// Switch public key, required to view outputs that use switch commitment
|
||||||
|
switch_public_key: Option<PublicKey>,
|
||||||
|
/// Chain code
|
||||||
|
chain_code: ChainCode,
|
||||||
|
/// Hash used to generate rewind nonce
|
||||||
|
pub rewind_hash: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewKey {
|
||||||
|
pub fn create<K, H>(
|
||||||
|
keychain: &K,
|
||||||
|
ext_key: ExtendedPrivKey,
|
||||||
|
hasher: &mut H,
|
||||||
|
is_floo: bool,
|
||||||
|
) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
H: BIP32Hasher,
|
||||||
|
{
|
||||||
|
let secp = keychain.secp();
|
||||||
|
|
||||||
|
let ExtendedPubKey {
|
||||||
|
network: _,
|
||||||
|
depth,
|
||||||
|
parent_fingerprint,
|
||||||
|
child_number,
|
||||||
|
public_key,
|
||||||
|
chain_code,
|
||||||
|
} = ExtendedPubKey::from_private(secp, &ext_key, hasher);
|
||||||
|
|
||||||
|
let mut switch_public_key = PublicKey(ffi::PublicKey(GENERATOR_PUB_J_RAW));
|
||||||
|
switch_public_key.mul_assign(secp, &ext_key.secret_key)?;
|
||||||
|
let switch_public_key = Some(switch_public_key);
|
||||||
|
|
||||||
|
let rewind_hash = Self::rewind_hash(secp, keychain.public_root_key());
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
is_floo,
|
||||||
|
depth,
|
||||||
|
parent_fingerprint,
|
||||||
|
child_number,
|
||||||
|
public_key,
|
||||||
|
switch_public_key,
|
||||||
|
chain_code,
|
||||||
|
rewind_hash,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rewind_hash(secp: &Secp256k1, public_root_key: PublicKey) -> Vec<u8> {
|
||||||
|
let ser = public_root_key.serialize_vec(secp, true);
|
||||||
|
blake2b(32, &[], &ser[..]).as_bytes().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ckd_pub_tweak<H>(
|
||||||
|
&self,
|
||||||
|
secp: &Secp256k1,
|
||||||
|
hasher: &mut H,
|
||||||
|
i: ChildNumber,
|
||||||
|
) -> Result<(SecretKey, ChainCode), Error>
|
||||||
|
where
|
||||||
|
H: BIP32Hasher,
|
||||||
|
{
|
||||||
|
match i {
|
||||||
|
ChildNumber::Hardened { .. } => Err(BIP32Error::CannotDeriveFromHardenedKey.into()),
|
||||||
|
ChildNumber::Normal { index: n } => {
|
||||||
|
hasher.init_sha512(&self.chain_code[..]);
|
||||||
|
hasher.append_sha512(&self.public_key.serialize_vec(secp, true)[..]);
|
||||||
|
let mut be_n = [0; 4];
|
||||||
|
BigEndian::write_u32(&mut be_n, n);
|
||||||
|
hasher.append_sha512(&be_n);
|
||||||
|
|
||||||
|
let result = hasher.result_sha512();
|
||||||
|
|
||||||
|
let secret_key = SecretKey::from_slice(secp, &result[..32])?;
|
||||||
|
let chain_code = ChainCode::from(&result[32..]);
|
||||||
|
Ok((secret_key, chain_code))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ckd_pub<H>(
|
||||||
|
&self,
|
||||||
|
secp: &Secp256k1,
|
||||||
|
hasher: &mut H,
|
||||||
|
i: ChildNumber,
|
||||||
|
) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
H: BIP32Hasher,
|
||||||
|
{
|
||||||
|
let (secret_key, chain_code) = self.ckd_pub_tweak(secp, hasher, i)?;
|
||||||
|
|
||||||
|
let mut public_key = self.public_key.clone();
|
||||||
|
public_key.add_exp_assign(secp, &secret_key)?;
|
||||||
|
|
||||||
|
let switch_public_key = match &self.switch_public_key {
|
||||||
|
Some(p) => {
|
||||||
|
let mut j = PublicKey(ffi::PublicKey(GENERATOR_PUB_J_RAW));
|
||||||
|
j.mul_assign(secp, &secret_key)?;
|
||||||
|
Some(PublicKey::from_combination(secp, vec![p, &j])?)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
is_floo: self.is_floo,
|
||||||
|
depth: self.depth + 1,
|
||||||
|
parent_fingerprint: self.fingerprint(secp, hasher),
|
||||||
|
child_number: i,
|
||||||
|
public_key,
|
||||||
|
switch_public_key,
|
||||||
|
chain_code,
|
||||||
|
rewind_hash: self.rewind_hash.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit(
|
||||||
|
&self,
|
||||||
|
secp: &Secp256k1,
|
||||||
|
amount: u64,
|
||||||
|
switch: &SwitchCommitmentType,
|
||||||
|
) -> Result<PublicKey, Error> {
|
||||||
|
let value_key = secp.commit_value(amount)?.to_pubkey(secp)?;
|
||||||
|
let pub_key = PublicKey::from_combination(secp, vec![&self.public_key, &value_key])?;
|
||||||
|
match *switch {
|
||||||
|
SwitchCommitmentType::None => Ok(pub_key),
|
||||||
|
SwitchCommitmentType::Regular => {
|
||||||
|
// TODO: replace this whole block by a libsecp function
|
||||||
|
/*let switch_pub = self.switch_public_key.ok_or(Error::SwitchCommitment)?;
|
||||||
|
let switch_ser: Vec<u8> = switch_pub.serialize_vec(secp, true)[..].to_vec();
|
||||||
|
|
||||||
|
let mut commit_ser: Vec<u8> = pub_key.serialize_vec(secp, true)[..].to_vec();
|
||||||
|
commit_ser[0] += 6; // This only works sometimes
|
||||||
|
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.input(&commit_ser);
|
||||||
|
hasher.input(&switch_ser);
|
||||||
|
let blind = SecretKey::from_slice(secp, &hasher.result()[..])?;
|
||||||
|
let mut pub_key = pub_key;
|
||||||
|
pub_key.add_exp_assign(secp, &blind)?;
|
||||||
|
|
||||||
|
Ok(pub_key)*/
|
||||||
|
Err(Error::SwitchCommitment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn identifier<H>(&self, secp: &Secp256k1, hasher: &mut H) -> [u8; 20]
|
||||||
|
where
|
||||||
|
H: BIP32Hasher,
|
||||||
|
{
|
||||||
|
let sha2_res = hasher.sha_256(&self.public_key.serialize_vec(secp, true)[..]);
|
||||||
|
hasher.ripemd_160(&sha2_res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fingerprint<H>(&self, secp: &Secp256k1, hasher: &mut H) -> Fingerprint
|
||||||
|
where
|
||||||
|
H: BIP32Hasher,
|
||||||
|
{
|
||||||
|
Fingerprint::from(&self.identifier(secp, hasher)[0..4])
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin_p2p"
|
name = "grin_p2p"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -22,10 +22,10 @@ tempfile = "3.0.5"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
chrono = { version = "0.4.4", features = ["serde"] }
|
chrono = { version = "0.4.4", features = ["serde"] }
|
||||||
|
|
||||||
grin_core = { path = "../core", version = "1.1.1-beta.1" }
|
grin_core = { path = "../core", version = "2.0.0-beta.2" }
|
||||||
grin_store = { path = "../store", version = "1.1.1-beta.1" }
|
grin_store = { path = "../store", version = "2.0.0-beta.2" }
|
||||||
grin_util = { path = "../util", version = "1.1.1-beta.1" }
|
grin_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||||
grin_chain = { path = "../chain", version = "1.1.1-beta.1" }
|
grin_chain = { path = "../chain", version = "2.0.0-beta.2" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
grin_pool = { path = "../pool", version = "1.1.1-beta.1" }
|
grin_pool = { path = "../pool", version = "2.0.0-beta.2" }
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::conn::{Message, MessageHandler, Response, Tracker};
|
use crate::conn::{Message, MessageHandler, Response, Tracker};
|
||||||
use crate::core::core::{self, hash::Hash, hash::Hashed, CompactBlock};
|
use crate::core::core::{self, hash::Hash, CompactBlock};
|
||||||
|
|
||||||
use crate::msg::{
|
use crate::msg::{
|
||||||
BanReason, GetPeerAddrs, Headers, KernelDataResponse, Locator, PeerAddrs, Ping, Pong,
|
BanReason, GetPeerAddrs, Headers, KernelDataResponse, Locator, PeerAddrs, Ping, Pong,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin_pool"
|
name = "grin_pool"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -19,10 +19,10 @@ chrono = "0.4.4"
|
||||||
failure = "0.1"
|
failure = "0.1"
|
||||||
failure_derive = "0.1"
|
failure_derive = "0.1"
|
||||||
|
|
||||||
grin_core = { path = "../core", version = "1.1.1-beta.1" }
|
grin_core = { path = "../core", version = "2.0.0-beta.2" }
|
||||||
grin_keychain = { path = "../keychain", version = "1.1.1-beta.1" }
|
grin_keychain = { path = "../keychain", version = "2.0.0-beta.2" }
|
||||||
grin_store = { path = "../store", version = "1.1.1-beta.1" }
|
grin_store = { path = "../store", version = "2.0.0-beta.2" }
|
||||||
grin_util = { path = "../util", version = "1.1.1-beta.1" }
|
grin_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
grin_chain = { path = "../chain", version = "1.1.1-beta.1" }
|
grin_chain = { path = "../chain", version = "2.0.0-beta.2" }
|
||||||
|
|
|
@ -47,7 +47,14 @@ fn test_transaction_pool_block_building() {
|
||||||
let height = prev_header.height + 1;
|
let height = prev_header.height + 1;
|
||||||
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
||||||
let fee = txs.iter().map(|x| x.fee()).sum();
|
let fee = txs.iter().map(|x| x.fee()).sum();
|
||||||
let reward = libtx::reward::output(&keychain, &key_id, fee, false).unwrap();
|
let reward = libtx::reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&key_id,
|
||||||
|
fee,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let mut block = Block::new(&prev_header, txs, Difficulty::min(), reward).unwrap();
|
let mut block = Block::new(&prev_header, txs, Difficulty::min(), reward).unwrap();
|
||||||
|
|
||||||
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
|
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
|
||||||
|
|
|
@ -51,7 +51,14 @@ fn test_block_building_max_weight() {
|
||||||
let height = prev_header.height + 1;
|
let height = prev_header.height + 1;
|
||||||
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
||||||
let fee = txs.iter().map(|x| x.fee()).sum();
|
let fee = txs.iter().map(|x| x.fee()).sum();
|
||||||
let reward = libtx::reward::output(&keychain, &key_id, fee, false).unwrap();
|
let reward = libtx::reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&key_id,
|
||||||
|
fee,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let mut block = Block::new(&prev_header, txs, Difficulty::min(), reward).unwrap();
|
let mut block = Block::new(&prev_header, txs, Difficulty::min(), reward).unwrap();
|
||||||
|
|
||||||
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
|
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
|
||||||
|
|
|
@ -45,7 +45,14 @@ fn test_transaction_pool_block_reconciliation() {
|
||||||
let header = {
|
let header = {
|
||||||
let height = 1;
|
let height = 1;
|
||||||
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
||||||
let reward = libtx::reward::output(&keychain, &key_id, 0, false).unwrap();
|
let reward = libtx::reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&key_id,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let genesis = BlockHeader::default();
|
let genesis = BlockHeader::default();
|
||||||
let mut block = Block::new(&genesis, vec![], Difficulty::min(), reward).unwrap();
|
let mut block = Block::new(&genesis, vec![], Difficulty::min(), reward).unwrap();
|
||||||
|
|
||||||
|
@ -65,7 +72,14 @@ fn test_transaction_pool_block_reconciliation() {
|
||||||
let block = {
|
let block = {
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
let fees = initial_tx.fee();
|
let fees = initial_tx.fee();
|
||||||
let reward = libtx::reward::output(&keychain, &key_id, fees, false).unwrap();
|
let reward = libtx::reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&key_id,
|
||||||
|
fees,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let mut block =
|
let mut block =
|
||||||
Block::new(&header, vec![initial_tx], Difficulty::min(), reward).unwrap();
|
Block::new(&header, vec![initial_tx], Difficulty::min(), reward).unwrap();
|
||||||
|
|
||||||
|
@ -159,7 +173,14 @@ fn test_transaction_pool_block_reconciliation() {
|
||||||
let block = {
|
let block = {
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
let fees = block_txs.iter().map(|tx| tx.fee()).sum();
|
let fees = block_txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let reward = libtx::reward::output(&keychain, &key_id, fees, false).unwrap();
|
let reward = libtx::reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&key_id,
|
||||||
|
fees,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let mut block = Block::new(&header, block_txs, Difficulty::min(), reward).unwrap();
|
let mut block = Block::new(&header, block_txs, Difficulty::min(), reward).unwrap();
|
||||||
|
|
||||||
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
|
// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
|
||||||
|
|
|
@ -195,7 +195,7 @@ where
|
||||||
|
|
||||||
tx_elements.push(libtx::build::with_fee(fees as u64));
|
tx_elements.push(libtx::build::with_fee(fees as u64));
|
||||||
|
|
||||||
libtx::build::transaction(tx_elements, keychain).unwrap()
|
libtx::build::transaction(tx_elements, keychain, &libtx::ProofBuilder::new(keychain)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_transaction<K>(
|
pub fn test_transaction<K>(
|
||||||
|
@ -225,7 +225,7 @@ where
|
||||||
}
|
}
|
||||||
tx_elements.push(libtx::build::with_fee(fees as u64));
|
tx_elements.push(libtx::build::with_fee(fees as u64));
|
||||||
|
|
||||||
libtx::build::transaction(tx_elements, keychain).unwrap()
|
libtx::build::transaction(tx_elements, keychain, &libtx::ProofBuilder::new(keychain)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_source() -> TxSource {
|
pub fn test_source() -> TxSource {
|
||||||
|
|
|
@ -44,7 +44,14 @@ fn test_the_transaction_pool() {
|
||||||
let header = {
|
let header = {
|
||||||
let height = 1;
|
let height = 1;
|
||||||
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
||||||
let reward = libtx::reward::output(&keychain, &key_id, 0, false).unwrap();
|
let reward = libtx::reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&key_id,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let block = Block::new(&BlockHeader::default(), vec![], Difficulty::min(), reward).unwrap();
|
let block = Block::new(&BlockHeader::default(), vec![], Difficulty::min(), reward).unwrap();
|
||||||
|
|
||||||
chain.update_db_for_block(&block);
|
chain.update_db_for_block(&block);
|
||||||
|
@ -246,7 +253,14 @@ fn test_the_transaction_pool() {
|
||||||
let header = {
|
let header = {
|
||||||
let height = 1;
|
let height = 1;
|
||||||
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
|
||||||
let reward = libtx::reward::output(&keychain, &key_id, 0, false).unwrap();
|
let reward = libtx::reward::output(
|
||||||
|
&keychain,
|
||||||
|
&libtx::ProofBuilder::new(&keychain),
|
||||||
|
&key_id,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let block =
|
let block =
|
||||||
Block::new(&BlockHeader::default(), vec![], Difficulty::min(), reward).unwrap();
|
Block::new(&BlockHeader::default(), vec![], Difficulty::min(), reward).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin_servers"
|
name = "grin_servers"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -25,11 +25,11 @@ serde_json = "1"
|
||||||
chrono = "0.4.4"
|
chrono = "0.4.4"
|
||||||
tokio = "0.1.11"
|
tokio = "0.1.11"
|
||||||
|
|
||||||
grin_api = { path = "../api", version = "1.1.1-beta.1" }
|
grin_api = { path = "../api", version = "2.0.0-beta.2" }
|
||||||
grin_chain = { path = "../chain", version = "1.1.1-beta.1" }
|
grin_chain = { path = "../chain", version = "2.0.0-beta.2" }
|
||||||
grin_core = { path = "../core", version = "1.1.1-beta.1" }
|
grin_core = { path = "../core", version = "2.0.0-beta.2" }
|
||||||
grin_keychain = { path = "../keychain", version = "1.1.1-beta.1" }
|
grin_keychain = { path = "../keychain", version = "2.0.0-beta.2" }
|
||||||
grin_p2p = { path = "../p2p", version = "1.1.1-beta.1" }
|
grin_p2p = { path = "../p2p", version = "2.0.0-beta.2" }
|
||||||
grin_pool = { path = "../pool", version = "1.1.1-beta.1" }
|
grin_pool = { path = "../pool", version = "2.0.0-beta.2" }
|
||||||
grin_store = { path = "../store", version = "1.1.1-beta.1" }
|
grin_store = { path = "../store", version = "2.0.0-beta.2" }
|
||||||
grin_util = { path = "../util", version = "1.1.1-beta.1" }
|
grin_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||||
|
|
|
@ -73,7 +73,6 @@ pub struct Server {
|
||||||
connect_thread: Option<JoinHandle<()>>,
|
connect_thread: Option<JoinHandle<()>>,
|
||||||
sync_thread: JoinHandle<()>,
|
sync_thread: JoinHandle<()>,
|
||||||
dandelion_thread: JoinHandle<()>,
|
dandelion_thread: JoinHandle<()>,
|
||||||
p2p_thread: JoinHandle<()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
|
@ -256,7 +255,7 @@ impl Server {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let p2p_inner = p2p_server.clone();
|
let p2p_inner = p2p_server.clone();
|
||||||
let p2p_thread = thread::Builder::new()
|
let _ = thread::Builder::new()
|
||||||
.name("p2p-server".to_string())
|
.name("p2p-server".to_string())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
if let Err(e) = p2p_inner.listen() {
|
if let Err(e) = p2p_inner.listen() {
|
||||||
|
@ -315,7 +314,6 @@ impl Server {
|
||||||
lock_file,
|
lock_file,
|
||||||
connect_thread,
|
connect_thread,
|
||||||
sync_thread,
|
sync_thread,
|
||||||
p2p_thread,
|
|
||||||
dandelion_thread,
|
dandelion_thread,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -530,11 +528,9 @@ impl Server {
|
||||||
Ok(_) => info!("dandelion_monitor thread stopped"),
|
Ok(_) => info!("dandelion_monitor thread stopped"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// this call is blocking and makes sure all peers stop, however
|
||||||
|
// we can't be sure that we stoped a listener blocked on accept, so we don't join the p2p thread
|
||||||
self.p2p.stop();
|
self.p2p.stop();
|
||||||
match self.p2p_thread.join() {
|
|
||||||
Err(e) => error!("failed to join to p2p thread: {:?}", e),
|
|
||||||
Ok(_) => info!("p2p thread stopped"),
|
|
||||||
}
|
|
||||||
let _ = self.lock_file.unlock();
|
let _ = self.lock_file.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
use crate::util::RwLock;
|
use crate::util::RwLock;
|
||||||
use chrono::prelude::{DateTime, NaiveDateTime, Utc};
|
use chrono::prelude::{DateTime, NaiveDateTime, Utc};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
use serde_json::{json, Value};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -28,6 +29,7 @@ use crate::common::types::Error;
|
||||||
use crate::core::core::verifier_cache::VerifierCache;
|
use crate::core::core::verifier_cache::VerifierCache;
|
||||||
use crate::core::core::{Output, TxKernel};
|
use crate::core::core::{Output, TxKernel};
|
||||||
use crate::core::libtx::secp_ser;
|
use crate::core::libtx::secp_ser;
|
||||||
|
use crate::core::libtx::ProofBuilder;
|
||||||
use crate::core::{consensus, core, global};
|
use crate::core::{consensus, core, global};
|
||||||
use crate::keychain::{ExtKeychain, Identifier, Keychain};
|
use crate::keychain::{ExtKeychain, Identifier, Keychain};
|
||||||
use crate::pool;
|
use crate::pool;
|
||||||
|
@ -223,8 +225,14 @@ fn burn_reward(block_fees: BlockFees) -> Result<(core::Output, core::TxKernel, B
|
||||||
warn!("Burning block fees: {:?}", block_fees);
|
warn!("Burning block fees: {:?}", block_fees);
|
||||||
let keychain = ExtKeychain::from_random_seed(global::is_floonet())?;
|
let keychain = ExtKeychain::from_random_seed(global::is_floonet())?;
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
let (out, kernel) =
|
let (out, kernel) = crate::core::libtx::reward::output(
|
||||||
crate::core::libtx::reward::output(&keychain, &key_id, block_fees.fees, false).unwrap();
|
&keychain,
|
||||||
|
&ProofBuilder::new(&keychain),
|
||||||
|
&key_id,
|
||||||
|
block_fees.fees,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
Ok((out, kernel, block_fees))
|
Ok((out, kernel, block_fees))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,15 +266,48 @@ fn get_coinbase(
|
||||||
/// Call the wallet API to create a coinbase output for the given block_fees.
|
/// Call the wallet API to create a coinbase output for the given block_fees.
|
||||||
/// Will retry based on default "retry forever with backoff" behavior.
|
/// Will retry based on default "retry forever with backoff" behavior.
|
||||||
fn create_coinbase(dest: &str, block_fees: &BlockFees) -> Result<CbData, Error> {
|
fn create_coinbase(dest: &str, block_fees: &BlockFees) -> Result<CbData, Error> {
|
||||||
let url = format!("{}/v1/wallet/foreign/build_coinbase", dest);
|
let url = format!("{}/v2/foreign", dest);
|
||||||
match api::client::post(&url, None, &block_fees) {
|
let req_body = json!({
|
||||||
Err(e) => {
|
"jsonrpc": "2.0",
|
||||||
error!(
|
"method": "build_coinbase",
|
||||||
"Failed to get coinbase from {}. Is the wallet listening?",
|
"id": 1,
|
||||||
url
|
"params": {
|
||||||
);
|
"block_fees": block_fees
|
||||||
Err(Error::WalletComm(format!("{}", e)))
|
|
||||||
}
|
}
|
||||||
Ok(res) => Ok(res),
|
});
|
||||||
|
|
||||||
|
trace!("Sending build_coinbase request: {}", req_body);
|
||||||
|
let req = api::client::create_post_request(url.as_str(), None, &req_body)?;
|
||||||
|
let res: String = api::client::send_request(req).map_err(|e| {
|
||||||
|
let report = format!(
|
||||||
|
"Failed to get coinbase from {}. Is the wallet listening? {}",
|
||||||
|
dest, e
|
||||||
|
);
|
||||||
|
error!("{}", report);
|
||||||
|
Error::WalletComm(report)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let res: Value = serde_json::from_str(&res).unwrap();
|
||||||
|
trace!("Response: {}", res);
|
||||||
|
if res["error"] != json!(null) {
|
||||||
|
let report = format!(
|
||||||
|
"Failed to get coinbase from {}: Error: {}, Message: {}",
|
||||||
|
dest, res["error"]["code"], res["error"]["message"]
|
||||||
|
);
|
||||||
|
error!("{}", report);
|
||||||
|
return Err(Error::WalletComm(report));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cb_data = res["result"]["Ok"].clone();
|
||||||
|
trace!("cb_data: {}", cb_data);
|
||||||
|
let ret_val = match serde_json::from_value::<CbData>(cb_data) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
let report = format!("Couldn't deserialize CbData: {}", e);
|
||||||
|
error!("{}", report);
|
||||||
|
return Err(Error::WalletComm(report));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ret_val)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: grin
|
name: grin
|
||||||
version: "1.1.1-beta.1"
|
version: "2.0.0-beta.2"
|
||||||
about: Lightweight implementation of the MimbleWimble protocol.
|
about: Lightweight implementation of the MimbleWimble protocol.
|
||||||
author: The Grin Team
|
author: The Grin Team
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin_store"
|
name = "grin_store"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -23,8 +23,8 @@ serde = "1"
|
||||||
serde_derive = "1"
|
serde_derive = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
grin_core = { path = "../core", version = "1.1.1-beta.1" }
|
grin_core = { path = "../core", version = "2.0.0-beta.2" }
|
||||||
grin_util = { path = "../util", version = "1.1.1-beta.1" }
|
grin_util = { path = "../util", version = "2.0.0-beta.2" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
chrono = "0.4.4"
|
chrono = "0.4.4"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "grin_util"
|
name = "grin_util"
|
||||||
version = "1.1.1-beta.1"
|
version = "2.0.0-beta.2"
|
||||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||||
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -22,11 +22,11 @@ log = "0.4"
|
||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
zip = { version = "0.4", default-features = false }
|
zip = { version = "0.4", default-features = false }
|
||||||
parking_lot = {version = "0.6"}
|
parking_lot = {version = "0.6"}
|
||||||
zeroize = "0.5.2"
|
zeroize = "0.9"
|
||||||
|
|
||||||
[dependencies.grin_secp256k1zkp]
|
[dependencies.grin_secp256k1zkp]
|
||||||
#git = "https://github.com/mimblewimble/rust-secp256k1-zkp"
|
#git = "https://github.com/mimblewimble/rust-secp256k1-zkp"
|
||||||
#tag = "grin_integration_29"
|
#tag = "grin_integration_29"
|
||||||
#path = "../../rust-secp256k1-zkp"
|
#path = "../../rust-secp256k1-zkp"
|
||||||
version = "0.7.5"
|
version = "0.7.7"
|
||||||
features = ["bullet-proof-sizing"]
|
features = ["bullet-proof-sizing"]
|
||||||
|
|
Loading…
Reference in a new issue