diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index f72c2f800..16d3e2216 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -182,6 +182,7 @@ impl<'x> OpenBlock<'x> { r.block.base.header.set_author(author); r.block.base.header.set_extra_data(extra_data); r.block.base.header.set_timestamp_now(parent.timestamp()); + r.block.base.header.set_parent_hash(parent.hash()); engine.populate_from_parent(&mut r.block.base.header, parent); engine.on_new_block(&mut r.block); @@ -308,10 +309,15 @@ impl ClosedBlock { pub fn try_seal(self, engine: &Engine, seal: Vec) -> Result { let mut s = self; s.block.base.header.set_seal(seal); - match engine.verify_block_basic(&s.block.base.header, None).is_err() || engine.verify_block_unordered(&s.block.base.header, None).is_err() { - false => Err(s), - true => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), + if let Err(e) = engine.verify_block_basic(&s.block.base.header, None) { + debug!("Failed to try_seal: {:?}", e); + return Err(s); } + if let Err(e) = engine.verify_block_unordered(&s.block.base.header, None) { + debug!("Failed to try_seal: {:?}", e); + return Err(s); + } + Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }) } /// Drop this object and return the underlieing database. diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index c5aa987f6..de875348a 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -196,6 +196,8 @@ pub struct Client { // for sealing... sealing_block: Mutex>, + author: RwLock
, + extra_data: RwLock, } const HISTORY: u64 = 1000; @@ -233,6 +235,8 @@ impl Client { import_lock: Mutex::new(()), panic_handler: panic_handler, sealing_block: Mutex::new(None), + author: RwLock::new(Address::new()), + extra_data: RwLock::new(Vec::new()), })) } @@ -364,7 +368,7 @@ impl Client { } if self.chain_info().best_block_hash != original_best { - self.new_chain_head(); + self.prepare_sealing(); } imported @@ -414,27 +418,55 @@ impl Client { } } - /// New chain head event. - pub fn new_chain_head(&self) { + /// Set the author that we will seal blocks as. + pub fn author(&self) -> Address { + self.author.read().unwrap().clone() + } + + /// Set the author that we will seal blocks as. + pub fn set_author(&self, author: Address) { + *self.author.write().unwrap() = author; + } + + /// Set the extra_data that we will seal blocks wuth. + pub fn extra_data(&self) -> Bytes { + self.extra_data.read().unwrap().clone() + } + + /// Set the extra_data that we will seal blocks with. + pub fn set_extra_data(&self, extra_data: Bytes) { + *self.extra_data.write().unwrap() = extra_data; + } + + /// New chain head event. Restart mining operation. + pub fn prepare_sealing(&self) { let h = self.chain.read().unwrap().best_block_hash(); - debug!("New best block: #{}: {}", self.chain.read().unwrap().best_block_number(), h); let b = OpenBlock::new( self.engine.deref().deref(), self.state_db.lock().unwrap().clone(), match self.chain.read().unwrap().block_header(&h) { Some(ref x) => x, None => {return;} }, - self.build_last_hashes(h.clone()), - x!("0037a6b811ffeb6e072da21179d11b1406371c63"), - b"Parity".to_vec() + self.build_last_hashes(h), + self.author(), + self.extra_data() ); + // TODO: push uncles. + // TODO: push transactions. let b = b.close(); - debug!("Sealing: hash={}, diff={}, number={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); + trace!("Sealing: number={}, hash={}, diff={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); + debug!("Header: {:?}", b.block().header()); *self.sealing_block.lock().unwrap() = Some(b); } /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. - pub fn sealing_block(&self) -> &Mutex> { &self.sealing_block } + pub fn sealing_block(&self) -> &Mutex> { + if self.sealing_block.lock().unwrap().is_none() { + self.prepare_sealing(); + } + &self.sealing_block + } /// Submit `seal` as a valid solution for the header of `pow_hash`. + /// Will check the seal, but not actually insert the block into the chain. pub fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result<(), Error> { let mut maybe_b = self.sealing_block.lock().unwrap(); match *maybe_b { diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 3db0be5ff..cc02d84db 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -102,10 +102,12 @@ impl Header { Self::default() } - /// Get the number field of the header. - pub fn number(&self) -> BlockNumber { self.number } + /// Get the parent_hash field of the header. + pub fn parent_hash(&self) -> &H256 { &self.parent_hash } /// Get the timestamp field of the header. pub fn timestamp(&self) -> u64 { self.timestamp } + /// Get the number field of the header. + pub fn number(&self) -> BlockNumber { self.number } /// Get the author field of the header. pub fn author(&self) -> &Address { &self.author } @@ -127,11 +129,13 @@ impl Header { // TODO: seal_at, set_seal_at &c. /// Set the number field of the header. - pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); } + pub fn set_parent_hash(&mut self, a: H256) { self.parent_hash = a; self.note_dirty(); } /// Set the timestamp field of the header. pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); } /// Set the timestamp field of the header to the current time. pub fn set_timestamp_now(&mut self, but_later_than: u64) { self.timestamp = max(now_utc().to_timespec().sec as u64, but_later_than + 1); self.note_dirty(); } + /// Set the number field of the header. + pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); } /// Set the author field of the header. pub fn set_author(&mut self, a: Address) { if a != self.author { self.author = a; self.note_dirty(); } } diff --git a/parity/main.rs b/parity/main.rs index 7241a2ac4..b991f36cd 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -85,6 +85,10 @@ Options: --jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545]. --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. + --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards + from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. + --extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters. + -l --logging LOGGING Specify the logging level. -v --version Show information about version. -h --help Show this screen. @@ -114,6 +118,8 @@ struct Args { flag_jsonrpc_cors: String, flag_logging: Option, flag_version: bool, + flag_author: String, + flag_extra_data: Option, } fn setup_log(init: &Option) { @@ -196,6 +202,18 @@ impl Configuration { self.args.flag_db_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } + fn author(&self) -> Address { + Address::from_str(&self.args.flag_author).unwrap_or_else(|_| die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", self.args.flag_author)) + } + + fn extra_data(&self) -> Bytes { + match self.args.flag_extra_data { + Some(ref x) if x.len() <= 32 => x.as_bytes().to_owned(), + None => version_data(), + Some(ref x) => { die!("{}: Extra data must be at most 32 characters.", x); } + } + } + fn _keys_path(&self) -> String { self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } @@ -296,6 +314,8 @@ impl Configuration { client_config.queue.max_mem_use = self.args.flag_queue_max_size; let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); let client = service.client().clone(); + client.set_author(self.author()); + client.set_extra_data(self.extra_data()); // Sync let sync = EthSync::register(service.network(), sync_config, client); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 24ecbe5f1..a7583ddf7 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -236,12 +236,12 @@ impl Eth for EthClient { } fn submit_work(&self, params: Params) -> Result { - // TODO: println! should be debug! - println!("Work submission: {:?}", params); from_params::<(H64, H256, H256)>(params).and_then(|(nonce, pow_hash, mix_hash)| { +// trace!("Decoded: nonce={}, pow_hash={}, mix_hash={}", nonce, pow_hash, mix_hash); let c = take_weak!(self.client); let seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()]; - to_value(&c.submit_seal(pow_hash, seal).is_ok()) + let r = c.submit_seal(pow_hash, seal); + to_value(&r.is_ok()) }) } diff --git a/util/src/misc.rs b/util/src/misc.rs index 35e1f3a75..d9f52fd71 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -18,6 +18,7 @@ use std::fs::File; use common::*; +use rlp::{Stream, RlpStream}; use target_info::Target; use rustc_version; @@ -70,4 +71,18 @@ pub fn contents(name: &str) -> Result { /// Get the standard version string for this software. pub fn version() -> String { format!("Parity//v{}-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) +} + +/// Get the standard version data for this software. +pub fn version_data() -> Bytes { + let mut s = RlpStream::new_list(4); + let v = + (u32::from_str(env!("CARGO_PKG_VERSION_MAJOR")).unwrap() << 16) + + (u32::from_str(env!("CARGO_PKG_VERSION_MINOR")).unwrap() << 8) + + u32::from_str(env!("CARGO_PKG_VERSION_PATCH")).unwrap(); + s.append(&v); + s.append(&"Parity"); + s.append(&format!("rustc{}", rustc_version::version())); + s.append(&Target::os()); + s.out() } \ No newline at end of file