Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Aggsig Transactions #530

Merged
merged 18 commits into from Jan 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion chain/tests/mine_simple_chain.rs
Expand Up @@ -335,7 +335,10 @@ fn prepare_fork_block_tx(kc: &Keychain, prev: &BlockHeader, chain: &Chain, diff:
fn prepare_block_nosum(kc: &Keychain, prev: &BlockHeader, diff: u64, txs: Vec<&Transaction>) -> Block {
let key_id = kc.derive_key_id(diff as u32).unwrap();

let mut b = core::core::Block::new(prev, txs, kc, &key_id).unwrap();
let mut b = match core::core::Block::new(prev, txs, kc, &key_id) {
Err(e) => panic!("{:?}",e),
Ok(b) => b
};
b.header.timestamp = prev.timestamp + time::Duration::seconds(60);
b.header.total_difficulty = Difficulty::from_num(diff);
b
Expand Down
3 changes: 1 addition & 2 deletions core/src/core/block.rs
Expand Up @@ -341,7 +341,6 @@ impl Block {
kernels.sort();

// calculate the overall Merkle tree and fees (todo?)

Ok(
Block {
header: BlockHeader {
Expand Down Expand Up @@ -585,7 +584,7 @@ impl Block {
let excess = secp.commit_sum(vec![out_commit], vec![over_commit])?;

let msg = util::secp::Message::from_slice(&[0; secp::constants::MESSAGE_SIZE])?;
let sig = keychain.sign(&msg, &key_id)?;
let sig = keychain.aggsig_sign_from_key_id(&msg, &key_id).unwrap();

let excess_sig = sig.serialize_der(&secp);

Expand Down
5 changes: 2 additions & 3 deletions core/src/core/build.rs
Expand Up @@ -25,10 +25,9 @@
//! build::transaction(vec![input_rand(75), output_rand(42), output_rand(32),
//! with_fee(1)])

use util::{secp, static_secp_instance};
use util::{secp, static_secp_instance, kernel_sig_msg};

use core::{Input, Output, SwitchCommitHash, Transaction, DEFAULT_OUTPUT};
use core::transaction::kernel_sig_msg;
use util::LOGGER;
use keychain;
use keychain::{BlindSum, BlindingFactor, Identifier, Keychain};
Expand Down Expand Up @@ -138,7 +137,7 @@ pub fn transaction(
);
let blind_sum = ctx.keychain.blind_sum(&sum)?;
let msg = secp::Message::from_slice(&kernel_sig_msg(tx.fee, tx.lock_height))?;
let sig = ctx.keychain.sign_with_blinding(&msg, &blind_sum)?;
let sig = Keychain::aggsig_sign_with_blinding(&keychain.secp(), &msg, &blind_sum)?;

let secp = static_secp_instance();
let secp = secp.lock().unwrap();
Expand Down
30 changes: 10 additions & 20 deletions core/src/core/transaction.rs
Expand Up @@ -13,11 +13,9 @@
// limitations under the License.

//! Transactions

use byteorder::{BigEndian, ByteOrder};
use blake2::blake2b::blake2b;
use util::secp::{self, Message, Signature};
use util::static_secp_instance;
use util::{static_secp_instance, kernel_sig_msg};
use util::secp::pedersen::{Commitment, RangeProof};
use std::cmp::Ordering;
use std::ops;
Expand Down Expand Up @@ -92,14 +90,6 @@ impl From<consensus::Error> for Error {
}
}

/// Construct msg bytes from tx fee and lock_height
pub fn kernel_sig_msg(fee: u64, lock_height: u64) -> [u8; 32] {
let mut bytes = [0; 32];
BigEndian::write_u64(&mut bytes[16..24], fee);
BigEndian::write_u64(&mut bytes[24..], lock_height);
bytes
}

/// A proof that a transaction sums to zero. Includes both the transaction's
/// Pedersen commitment and the signature, that guarantees that the commitments
/// amount to zero.
Expand Down Expand Up @@ -166,7 +156,11 @@ impl TxKernel {
let secp = static_secp_instance();
let secp = secp.lock().unwrap();
let sig = try!(Signature::from_der(&secp, &self.excess_sig));
secp.verify_from_commit(&msg, &sig, &self.excess)
let valid = Keychain::aggsig_verify_single_from_commit(&secp, &sig, &msg, &self.excess);
if !valid{
return Err(secp::Error::IncorrectSignature);
}
Ok(())
}
}

Expand Down Expand Up @@ -330,16 +324,12 @@ impl Transaction {
let secp = static_secp_instance();
let secp = secp.lock().unwrap();
let sig = Signature::from_der(&secp, &self.excess_sig)?;

// pretend the sum is a public key (which it is, being of the form r.G) and
// verify the transaction sig with it
//
// we originally converted the commitment to a key_id here (commitment to zero)
// and then passed the key_id to secp.verify()
// the secp api no longer allows us to do this so we have wrapped the complexity
// of generating a public key from a commitment behind verify_from_commit
secp.verify_from_commit(&msg, &sig, &rsum)?;

let valid = Keychain::aggsig_verify_single_from_commit(&secp, &sig, &msg, &rsum);
if !valid{
return Err(secp::Error::IncorrectSignature);
}
Ok(rsum)
}

Expand Down
1 change: 1 addition & 0 deletions grin/Cargo.toml
Expand Up @@ -32,3 +32,4 @@ itertools = "~0.6.0"

[dev_dependencies]
blake2-rfc = "~0.2.17"
grin_config = { path = "../config" }
1 change: 0 additions & 1 deletion grin/src/lib.rs
Expand Up @@ -38,7 +38,6 @@ extern crate tokio_timer;

extern crate grin_api as api;
extern crate grin_chain as chain;
#[macro_use]
extern crate grin_core as core;
extern crate grin_keychain as keychain;
extern crate grin_p2p as p2p;
Expand Down
6 changes: 6 additions & 0 deletions grin/src/server.rs
Expand Up @@ -161,10 +161,16 @@ impl Server {
_ => {}
}

let skip_sync_wait = match config.skip_sync_wait {
None => false,
Some(b) => b,
};

sync::run_sync(
currently_syncing.clone(),
p2p_server.peers.clone(),
shared_chain.clone(),
skip_sync_wait,
);

evt_handle.spawn(p2p_server.start(evt_handle.clone()).map_err(|_| ()));
Expand Down
5 changes: 4 additions & 1 deletion grin/src/sync.rs
Expand Up @@ -30,6 +30,7 @@ pub fn run_sync(
currently_syncing: Arc<AtomicBool>,
peers: p2p::Peers,
chain: Arc<chain::Chain>,
skip_sync_wait: bool,
) {

let chain = chain.clone();
Expand All @@ -40,7 +41,9 @@ pub fn run_sync(
let mut prev_header_sync = prev_body_sync.clone();

// initial sleep to give us time to peer with some nodes
thread::sleep(Duration::from_secs(30));
if !skip_sync_wait {
thread::sleep(Duration::from_secs(30));
}

loop {
let syncing = needs_syncing(
Expand Down
5 changes: 5 additions & 0 deletions grin/src/types.rs
Expand Up @@ -136,6 +136,10 @@ pub struct ServerConfig {
/// Transaction pool configuration
#[serde(default)]
pub pool_config: pool::PoolConfig,

/// Whether to skip the sync timeout on startup
/// (To assist testing on solo chains)
pub skip_sync_wait: Option<bool>,
}

impl Default for ServerConfig {
Expand All @@ -150,6 +154,7 @@ impl Default for ServerConfig {
mining_config: Some(pow::types::MinerConfig::default()),
chain_type: ChainTypes::default(),
pool_config: pool::PoolConfig::default(),
skip_sync_wait: Some(true),
}
}
}
Expand Down
114 changes: 81 additions & 33 deletions grin/tests/framework/mod.rs
Expand Up @@ -34,12 +34,9 @@ use std::default::Default;
use std::fs;
use std::sync::{Arc, Mutex};

use tokio_core::reactor;
use tokio_timer::Timer;
use self::tokio_core::reactor;
use self::tokio_timer::Timer;

use util::secp::Secp256k1;
// TODO - why does this need self here? Missing something somewhere.
use self::keychain::Keychain;
use wallet::WalletConfig;

/// Just removes all results from previous runs
Expand Down Expand Up @@ -158,7 +155,10 @@ pub struct LocalServerContainer {
pub peer_list: Vec<String>,

// base directory for the server instance
working_dir: String,
pub working_dir: String,

// Wallet configuration
pub wallet_config:WalletConfig,
}

impl LocalServerContainer {
Expand All @@ -168,6 +168,11 @@ impl LocalServerContainer {

pub fn new(config: LocalServerContainerConfig) -> Result<LocalServerContainer, Error> {
let working_dir = format!("target/test_servers/{}", config.name);
let mut wallet_config = WalletConfig::default();

wallet_config.api_listen_port = format!("{}", config.wallet_port);
wallet_config.check_node_api_http_addr = config.wallet_validating_node_url.clone();
wallet_config.data_file_dir = working_dir.clone();
Ok(
(LocalServerContainer {
config: config,
Expand All @@ -178,6 +183,7 @@ impl LocalServerContainer {
wallet_is_running: false,
working_dir: working_dir,
peer_list: Vec::new(),
wallet_config:wallet_config,
}),
)
}
Expand Down Expand Up @@ -206,6 +212,7 @@ impl LocalServerContainer {
seeds: Some(seeds),
seeding_type: seeding_type,
chain_type: core::global::ChainTypes::AutomatedTesting,
skip_sync_wait:Some(true),
..Default::default()
},
&event_loop.handle(),
Expand Down Expand Up @@ -260,52 +267,93 @@ impl LocalServerContainer {
/// Starts a wallet daemon to receive and returns the
/// listening server url

pub fn run_wallet(&mut self, _duration_in_seconds: u64) {
pub fn run_wallet(&mut self, _duration_in_mills: u64) {
// URL on which to start the wallet listener (i.e. api server)
let url = format!("{}:{}", self.config.base_addr, self.config.wallet_port);
let _url = format!("{}:{}", self.config.base_addr, self.config.wallet_port);

// Just use the name of the server for a seed for now
let seed = format!("{}", self.config.name);

let seed = blake2::blake2b::blake2b(32, &[], seed.as_bytes());
let _seed = blake2::blake2b::blake2b(32, &[], seed.as_bytes());

// TODO - just use from_random_seed here?
let keychain =
Keychain::from_seed(seed.as_bytes()).expect("Error initializing keychain from seed");

println!(
"Starting the Grin wallet receiving daemon on {} ",
self.config.wallet_port
);

let mut wallet_config = WalletConfig::default();
self.wallet_config = WalletConfig::default();

wallet_config.api_listen_port = format!("{}", self.config.wallet_port);
wallet_config.check_node_api_http_addr = self.config.wallet_validating_node_url.clone();
wallet_config.data_file_dir = self.working_dir.clone();
self.wallet_config.api_listen_port = format!("{}", self.config.wallet_port);
self.wallet_config.check_node_api_http_addr = self.config.wallet_validating_node_url.clone();
self.wallet_config.data_file_dir = self.working_dir.clone();

let receive_tx_handler = wallet::WalletReceiver {
config: wallet_config.clone(),
keychain: keychain.clone(),
};
let router = router!(
receive_tx: get "/receive/transaction" => receive_tx_handler,
);
let _=fs::create_dir_all(self.wallet_config.clone().data_file_dir);
wallet::WalletSeed::init_file(&self.wallet_config);

let wallet_seed =
wallet::WalletSeed::from_file(&self.wallet_config).expect("Failed to read wallet seed file.");

let mut api_server = api::ApiServer::new("/v1".to_string());
api_server.register_handler(router);
api_server.start(url).unwrap_or_else(|e| {
println!("Failed to start Grin wallet receiver: {}.", e);
});
let keychain = wallet_seed.derive_keychain("grin_test").expect(
"Failed to derive keychain from seed file and passphrase.",
);

self.api_server = Some(api_server);
wallet::server::start_rest_apis(self.wallet_config.clone(), keychain);
self.wallet_is_running = true;
}

/// Stops the running wallet server

pub fn send_amount_to(config: &WalletConfig,
amount:&str,
minimum_confirmations: u64,
selection_strategy:&str,
dest: &str){

let amount = core::core::amount_from_hr_string(amount).expect(
"Could not parse amount as a number with optional decimal point.",
);

let wallet_seed =
wallet::WalletSeed::from_file(config).expect("Failed to read wallet seed file.");

let mut keychain = wallet_seed.derive_keychain("grin_test").expect(
"Failed to derive keychain from seed file and passphrase.",
);
let max_outputs = 500;
let result = wallet::issue_send_tx(
config,
&mut keychain,
amount,
minimum_confirmations,
dest.to_string(),
max_outputs,
(selection_strategy == "all"),
);
match result {
Ok(_) => {
println!(
"Tx sent: {} grin to {} (strategy '{}')",
core::core::amount_to_hr_string(amount),
dest,
selection_strategy,
)
}
Err(wallet::Error::NotEnoughFunds(available)) => {
println!(
"Tx not sent: insufficient funds (max: {})",
core::core::amount_to_hr_string(available),
);
}
Err(e) => {
println!("Tx not sent to {}: {:?}", dest, e);
}
};
}

/// Stops the running wallet server
pub fn stop_wallet(&mut self) {
let mut api_server = self.api_server.as_mut().unwrap();
println!("Stop wallet!");
let api_server = self.api_server.as_mut().unwrap();
api_server.stop();
}

Expand Down Expand Up @@ -497,8 +545,8 @@ impl LocalServerContainerPool {
}

pub fn connect_all_peers(&mut self) {
/// just pull out all currently active servers, build a list,
/// and feed into all servers
// just pull out all currently active servers, build a list,
// and feed into all servers
let mut server_addresses: Vec<String> = Vec::new();
for s in &self.server_containers {
let server_address = format!("{}:{}", s.config.base_addr, s.config.p2p_server_port);
Expand Down