diff --git a/Cargo.lock b/Cargo.lock index 6de773c77..1ecb5579a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -284,7 +284,7 @@ dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)", - "parity-dapps-builtins 0.5.1 (git+https://github.com/ethcore/parity-dapps-builtins-rs.git)", + "parity-dapps-builtins 0.5.2 (git+https://github.com/ethcore/parity-dapps-builtins-rs.git)", "parity-dapps-status 0.5.0 (git+https://github.com/ethcore/parity-dapps-status-rs.git)", "parity-dapps-wallet 0.6.1 (git+https://github.com/ethcore/parity-dapps-wallet-rs.git)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -909,8 +909,8 @@ dependencies = [ [[package]] name = "parity-dapps-builtins" -version = "0.5.1" -source = "git+https://github.com/ethcore/parity-dapps-builtins-rs.git#7408838e8ca3b57c6b0cf5da2e31e0e275959955" +version = "0.5.2" +source = "git+https://github.com/ethcore/parity-dapps-builtins-rs.git#01af2091d5d70dfe0aecbfd96308f0ae79fc61e6" dependencies = [ "parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)", ] diff --git a/appveyor.yml b/appveyor.yml index b51bb506c..b2b91155c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,13 +1,27 @@ environment: matrix: - TARGET: x86_64-pc-windows-msvc + cert: + secure: ESPpYVVAMG1fbJx6kq4ct/g9SQTXac4Hs6xXr6Oh4Zrk2dwYglNjxmzErdPnvu7gs/gekzrJ6KEQHYRc+5+4dKg6rRADQ681NLVx9vOggBs= + certpass: + secure: 0BgXJqxq9Ei34/hZ7121FQ== + keyfile: C:\users\appveyor\Certificates.p12 + +branches: + only: + - master + - /^beta-.*$/ + - /^stable-.*$/ + - /^beta$/ + - /^stable$/ + install: - git submodule update --init --recursive - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.9.0-x86_64-pc-windows-msvc.exe" - ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -FileName nsis\SimpleFC.dll - ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -FileName nsis\vc_redist.x64.exe - rust-1.9.0-x86_64-pc-windows-msvc.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin;C:\Program Files (x86)\NSIS + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin;C:\Program Files (x86)\NSIS;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin - rustc -V - cargo -V @@ -18,7 +32,10 @@ test_script: after_test: - cargo build --verbose --release + - ps: if($env:cert) { Start-FileDownload $env:cert -FileName $env:keyfile } + - ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass target\release\parity.exe } - makensis.exe nsis\installer.nsi + - ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass nsis\installer.exe } artifacts: - path: nsis\installer.exe diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index 4cc4bc472..5e890472c 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -23,7 +23,7 @@ ethcore-util = { path = "../util" } parity-dapps = { git = "https://github.com/ethcore/parity-dapps-rs.git", version = "0.3" } # List of apps parity-dapps-status = { git = "https://github.com/ethcore/parity-dapps-status-rs.git", version = "0.5.0" } -parity-dapps-builtins = { git = "https://github.com/ethcore/parity-dapps-builtins-rs.git", version = "0.5.0" } +parity-dapps-builtins = { git = "https://github.com/ethcore/parity-dapps-builtins-rs.git", version = "0.5.2" } parity-dapps-wallet = { git = "https://github.com/ethcore/parity-dapps-wallet-rs.git", version = "0.6.0", optional = true } parity-dapps-dao = { git = "https://github.com/ethcore/parity-dapps-dao-rs.git", version = "0.4.0", optional = true } parity-dapps-makerotc = { git = "https://github.com/ethcore/parity-dapps-makerotc-rs.git", version = "0.3.0", optional = true } diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs index d0628436d..2edbf87ae 100644 --- a/ethcore/src/account.rs +++ b/ethcore/src/account.rs @@ -108,6 +108,12 @@ impl Account { self.code_cache = code; } + /// Reset this account's code to the given code. + pub fn reset_code(&mut self, code: Bytes) { + self.code_hash = None; + self.init_code(code); + } + /// Set (and cache) the contents of the trie's storage at `key` to `value`. pub fn set_storage(&mut self, key: H256, value: H256) { self.storage_overlay.borrow_mut().insert(key, (Filth::Dirty, value)); @@ -336,6 +342,21 @@ mod tests { assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb"); } + #[test] + fn reset_code() { + let mut a = Account::new_contract(69.into(), 0.into()); + let mut db = MemoryDB::new(); + let mut db = AccountDBMut::new(&mut db, &Address::new()); + a.init_code(vec![0x55, 0x44, 0xffu8]); + assert_eq!(a.code_hash(), SHA3_EMPTY); + a.commit_code(&mut db); + assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb"); + a.reset_code(vec![0x55]); + assert_eq!(a.code_hash(), SHA3_EMPTY); + a.commit_code(&mut db); + assert_eq!(a.code_hash().hex(), "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be"); + } + #[test] fn rlpio() { let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new()); @@ -348,7 +369,6 @@ mod tests { #[test] fn new_account() { - let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new()); assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); assert_eq!(a.balance(), &U256::from(69u8)); @@ -359,7 +379,6 @@ mod tests { #[test] fn create_account() { - let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new()); assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 1a437bfac..5d157b654 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -515,9 +515,6 @@ impl BlockChainClient for Client { ret } - fn vm_factory(&self) -> &EvmFactory { - &self.vm_factory - } fn block_header(&self, id: BlockID) -> Option { Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) @@ -829,6 +826,10 @@ impl MiningBlockChainClient for Client { open_block } + + fn vm_factory(&self) -> &EvmFactory { + &self.vm_factory + } } impl MayPanic for Client { diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 2098d8a2f..bef814b4e 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -172,9 +172,6 @@ pub trait BlockChainClient : Sync + Send { // TODO: should be able to accept blockchain location for call. fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result; - /// Returns EvmFactory. - fn vm_factory(&self) -> &EvmFactory; - /// Returns traces matching given filter. fn filter_traces(&self, filter: TraceFilter) -> Option>; @@ -253,4 +250,7 @@ pub trait MiningBlockChainClient : BlockChainClient { /// Returns OpenBlock prepared for closing. fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock; + + /// Returns EvmFactory. + fn vm_factory(&self) -> &EvmFactory; } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index a7f508a51..ed1f10e09 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -244,6 +244,10 @@ impl MiningBlockChainClient for TestBlockChainClient { fn prepare_open_block(&self, _author: Address, _gas_range_target: (U256, U256), _extra_data: Bytes) -> OpenBlock { unimplemented!(); } + + fn vm_factory(&self) -> &EvmFactory { + unimplemented!(); + } } impl BlockChainClient for TestBlockChainClient { @@ -463,10 +467,6 @@ impl BlockChainClient for TestBlockChainClient { } } - fn vm_factory(&self) -> &EvmFactory { - unimplemented!(); - } - fn filter_traces(&self, _filter: TraceFilter) -> Option> { unimplemented!(); } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 803706c56..4518e416a 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -16,6 +16,7 @@ use rayon::prelude::*; use std::sync::atomic::AtomicBool; +use std::time::{Instant, Duration}; use util::*; use account_provider::AccountProvider; @@ -50,12 +51,16 @@ pub struct MinerOptions { pub reseal_on_external_tx: bool, /// Reseal on receipt of new local transactions. pub reseal_on_own_tx: bool, + /// Minimum period between transaction-inspired reseals. + pub reseal_min_period: Duration, /// Maximum amount of gas to bother considering for block insertion. pub tx_gas_limit: U256, /// Maximum size of the transaction queue. pub tx_queue_size: usize, /// Whether we should fallback to providing all the queue's transactions or just pending. pub pending_set: PendingSet, + /// How many historical work packages can we store before running out? + pub work_queue_size: usize, } impl Default for MinerOptions { @@ -67,6 +72,8 @@ impl Default for MinerOptions { tx_gas_limit: !U256::zero(), tx_queue_size: 1024, pending_set: PendingSet::AlwaysQueue, + reseal_min_period: Duration::from_secs(0), + work_queue_size: 20, } } } @@ -80,6 +87,7 @@ pub struct Miner { // for sealing... options: MinerOptions, sealing_enabled: AtomicBool, + next_allowed_reseal: Mutex, sealing_block_last_request: Mutex, gas_range_target: RwLock<(U256, U256)>, author: RwLock
, @@ -96,8 +104,9 @@ impl Miner { transaction_queue: Mutex::new(TransactionQueue::new()), options: Default::default(), sealing_enabled: AtomicBool::new(false), + next_allowed_reseal: Mutex::new(Instant::now()), sealing_block_last_request: Mutex::new(0), - sealing_work: Mutex::new(UsingQueue::new(5)), + sealing_work: Mutex::new(UsingQueue::new(20)), gas_range_target: RwLock::new((U256::zero(), U256::zero())), author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), @@ -111,13 +120,14 @@ impl Miner { Arc::new(Miner { transaction_queue: Mutex::new(TransactionQueue::with_limits(options.tx_queue_size, options.tx_gas_limit)), sealing_enabled: AtomicBool::new(options.force_sealing), - options: options, + next_allowed_reseal: Mutex::new(Instant::now()), sealing_block_last_request: Mutex::new(0), - sealing_work: Mutex::new(UsingQueue::new(5)), + sealing_work: Mutex::new(UsingQueue::new(options.work_queue_size)), gas_range_target: RwLock::new((U256::zero(), U256::zero())), author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), accounts: accounts, + options: options, spec: spec, }) } @@ -261,6 +271,9 @@ impl Miner { // Return if !have_work } + + /// Are we allowed to do a non-mandatory reseal? + fn tx_reseal_allowed(&self) -> bool { Instant::now() > *self.next_allowed_reseal.lock().unwrap() } } const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5; @@ -431,7 +444,7 @@ impl MinerService for Miner { .map(|tx| transaction_queue.add(tx, &fetch_account, TransactionOrigin::External)) .collect() }; - if !results.is_empty() && self.options.reseal_on_external_tx { + if !results.is_empty() && self.options.reseal_on_external_tx && self.tx_reseal_allowed() { self.update_sealing(chain); } results @@ -466,7 +479,7 @@ impl MinerService for Miner { import }; - if imported.is_ok() && self.options.reseal_on_own_tx { + if imported.is_ok() && self.options.reseal_on_own_tx && self.tx_reseal_allowed() { // Make sure to do it after transaction is imported and lock is droped. // We need to create pending block and enable sealing let prepared = self.enable_and_prepare_sealing(chain); @@ -559,6 +572,7 @@ impl MinerService for Miner { self.sealing_enabled.store(false, atomic::Ordering::Relaxed); self.sealing_work.lock().unwrap().reset(); } else { + *self.next_allowed_reseal.lock().unwrap() = Instant::now() + self.options.reseal_min_period; self.prepare_sealing(chain); } } diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index 17ca18272..7f5b59c38 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -441,7 +441,7 @@ impl TransactionQueue { trace!(target: "miner", "Importing: {:?}", tx.hash()); - if tx.gas_price < self.minimal_gas_price { + if tx.gas_price < self.minimal_gas_price && origin != TransactionOrigin::Local { trace!(target: "miner", "Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})", tx.hash(), @@ -1055,7 +1055,7 @@ mod test { } #[test] - fn should_not_import_transaction_below_min_gas_price_threshold() { + fn should_not_import_transaction_below_min_gas_price_threshold_if_external() { // given let mut txq = TransactionQueue::new(); let tx = new_tx(); @@ -1074,6 +1074,23 @@ mod test { assert_eq!(stats.future, 0); } + #[test] + fn should_import_transaction_below_min_gas_price_threshold_if_local() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + txq.set_minimal_gas_price(tx.gas_price + U256::one()); + + // when + let res = txq.add(tx, &default_nonce, TransactionOrigin::Local); + + // then + assert_eq!(res.unwrap(), TransactionImportResult::Current); + let stats = txq.status(); + assert_eq!(stats.pending, 1); + assert_eq!(stats.future, 0); + } + #[test] fn should_reject_incorectly_signed_transaction() { // given diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index e7981abba..0c086ffc3 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -208,12 +208,17 @@ impl State { self.require(a, false).set_storage(key, value) } - /// Initialise the code of account `a` so that it is `value` for `key`. + /// Initialise the code of account `a` so that it is `code`. /// NOTE: Account should have been created with `new_contract`. pub fn init_code(&mut self, a: &Address, code: Bytes) { self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{}).init_code(code); } + /// Reset the code of account `a` so that it is `code`. + pub fn reset_code(&mut self, a: &Address, code: Bytes) { + self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{}).reset_code(code); + } + /// Execute a given transaction. /// This will change the state accordingly. pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, vm_factory: &EvmFactory, t: &SignedTransaction, tracing: bool) -> ApplyResult { diff --git a/parity/cli.rs b/parity/cli.rs index 3ee6f31c8..a48ce3aa7 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -42,14 +42,12 @@ Protocol Options: --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.parity/keys]. --identity NAME Specify your node's name. - -DAO-Rescue Soft-fork Options: - --help-rescue-dao Does nothing - on by default. - --dont-help-rescue-dao Votes against the DAO-rescue soft-fork, but supports - it if it is triggered anyway. - Equivalent to --gas-floor-target=3141592. - --dogmatic Ignores all DAO-rescue soft-fork behaviour. Even if - it means losing mining rewards. + --fork POLICY Specifies the client's fork policy. POLICY must be + one of: + dogmatic - sticks rigidly to the standard chain. + dao-soft - votes for the DAO-rescue soft-fork. + normal - goes with whatever fork is decided but + votes for none. [default: normal]. Account Options: --unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution. @@ -139,6 +137,13 @@ Sealing/Mining Options: own - reseal only on a new local transaction; ext - reseal only on a new external transaction; all - reseal on all new transactions [default: all]. + --reseal-min-period MS Specify the minimum time between reseals from + incoming transactions. MS is time measured in + milliseconds [default: 2000]. + --work-queue-size ITEMS Specify the number of historical work packages + which are kept cached lest a solution is found for + them later. High values take more memory but result + in fewer unusable solutions [default: 20]. --tx-gas-limit GAS Apply a limit of GAS as the maximum amount of gas a single transaction may have for it to be mined. --relay-set SET Set of transactions to relay. SET may be: @@ -157,9 +162,9 @@ Sealing/Mining Options: web service in turn and fallback on the last known good value [default: auto]. --gas-floor-target GAS Amount of gas per block to target when sealing a new - block [default: 3141592]. + block [default: 4700000]. --gas-cap GAS A cap on how large we will raise the gas limit per - block due to transaction volume [default: 3141592]. + block due to transaction volume [default: 6283184]. --extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters. --tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting @@ -262,8 +267,7 @@ pub struct Args { pub flag_chain: String, pub flag_db_path: String, pub flag_identity: String, - pub flag_dont_help_rescue_dao: bool, - pub flag_dogmatic: bool, + pub flag_fork: String, pub flag_unlock: Option, pub flag_password: Vec, pub flag_cache: Option, @@ -305,6 +309,8 @@ pub struct Args { pub flag_no_token: bool, pub flag_force_sealing: bool, pub flag_reseal_on_txs: String, + pub flag_reseal_min_period: u64, + pub flag_work_queue_size: usize, pub flag_tx_gas_limit: Option, pub flag_relay_set: String, pub flag_author: Option, diff --git a/parity/configuration.rs b/parity/configuration.rs index 4bd0cd493..e95ef4233 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -16,6 +16,7 @@ use std::env; use std::fs::File; +use std::time::Duration; use std::io::{BufRead, BufReader}; use std::net::{SocketAddr, IpAddr}; use std::path::PathBuf; @@ -45,6 +46,13 @@ pub struct Directories { pub signer: String, } +#[derive(Eq, PartialEq, Debug)] +pub enum Policy { + DaoSoft, + Normal, + Dogmatic, +} + impl Configuration { pub fn parse() -> Self { Configuration { @@ -96,6 +104,8 @@ impl Configuration { "lenient" => PendingSet::SealingOrElseQueue, x => die!("{}: Invalid value for --relay-set option. Use --help for more information.", x) }, + reseal_min_period: Duration::from_millis(self.args.flag_reseal_min_period), + work_queue_size: self.args.flag_work_queue_size, } } @@ -107,9 +117,18 @@ impl Configuration { })) } + pub fn policy(&self) -> Policy { + match self.args.flag_fork.as_str() { + "dao-soft" => Policy::DaoSoft, + "normal" => Policy::Normal, + "dogmatic" => Policy::Dogmatic, + x => die!("{}: Invalid value given for --policy option. Use --help for more info.", x) + } + } + pub fn gas_floor_target(&self) -> U256 { - if self.args.flag_dont_help_rescue_dao || self.args.flag_dogmatic { - 4_700_000.into() + if self.policy() == Policy::DaoSoft { + 3_141_592.into() } else { let d = &self.args.flag_gas_floor_target; U256::from_dec_str(d).unwrap_or_else(|_| { @@ -119,8 +138,8 @@ impl Configuration { } pub fn gas_ceil_target(&self) -> U256 { - if self.args.flag_dont_help_rescue_dao || self.args.flag_dogmatic { - 10_000_000.into() + if self.policy() == Policy::DaoSoft { + 3_141_592.into() } else { let d = &self.args.flag_gas_cap; U256::from_dec_str(d).unwrap_or_else(|_| { @@ -172,7 +191,7 @@ impl Configuration { pub fn spec(&self) -> Spec { match self.chain().as_str() { - "frontier" | "homestead" | "mainnet" => ethereum::new_frontier(!self.args.flag_dogmatic), + "frontier" | "homestead" | "mainnet" => ethereum::new_frontier(self.policy() != Policy::Dogmatic), "morden" | "testnet" => ethereum::new_morden(), "olympic" => ethereum::new_olympic(), f => Spec::load(contents(f).unwrap_or_else(|_| { diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index fdd2de8fa..1a6b1c398 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -165,7 +165,7 @@ fn transaction_error(error: EthcoreError) -> Error { "There is too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into() }, InsufficientGasPrice { minimal, got } => { - format!("Transaction fee is to low. It does not satisfy your node's minimal fee (minimal: {}, got: {}). Try increasing the fee.", minimal, got) + format!("Transaction fee is too low. It does not satisfy your node's minimal fee (minimal: {}, got: {}). Try increasing the fee.", minimal, got) }, InsufficientBalance { balance, cost } => { format!("Insufficient funds. Account you try to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 88a12a74f..59d06e84a 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -17,6 +17,7 @@ //! rpc integration tests. use std::sync::Arc; use std::str::FromStr; +use std::time::Duration; use ethcore::client::{BlockChainClient, Client, ClientConfig}; use ethcore::ids::BlockID; @@ -57,6 +58,8 @@ fn miner_service(spec: Spec, accounts: Arc) -> Arc { tx_queue_size: 1024, tx_gas_limit: !U256::zero(), pending_set: PendingSet::SealingOrElseQueue, + reseal_min_period: Duration::from_secs(0), + work_queue_size: 50, }, spec, Some(accounts)