mirror of
https://github.com/mimblewimble/grin.git
synced 2025-03-07 01:21: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
Cargo.lockCargo.toml
api
chain
config
core
keychain
p2p
pool
Cargo.toml
tests
servers
src/bin
store
util
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