Merge branch 'master' into presale_wallet
This commit is contained in:
		
						commit
						927ffa7e9c
					
				
							
								
								
									
										10
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -630,7 +630,7 @@ dependencies = [
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "jsonrpc-http-server"
 | 
			
		||||
version = "5.1.0"
 | 
			
		||||
source = "git+https://github.com/ethcore/jsonrpc-http-server.git#6117b1d77b5a60d6fa2dc884f12aa7f5fd4585ca"
 | 
			
		||||
source = "git+https://github.com/ethcore/jsonrpc-http-server.git#0c99d308bc15e8fae50642eff77a3e1fd7610652"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "hyper 0.9.3 (git+https://github.com/ethcore/hyper)",
 | 
			
		||||
 "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
@ -936,7 +936,7 @@ dependencies = [
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "parity-dapps-builtins"
 | 
			
		||||
version = "0.5.1"
 | 
			
		||||
source = "git+https://github.com/ethcore/parity-dapps-builtins-rs.git#413ef9a6f9c46d16d578a48e39adb44d5650d7d7"
 | 
			
		||||
source = "git+https://github.com/ethcore/parity-dapps-builtins-rs.git#650b0d94d076635904b86c1fd45c5f4a2061463f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)",
 | 
			
		||||
]
 | 
			
		||||
@ -960,7 +960,7 @@ dependencies = [
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "parity-minimal-sysui"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
source = "git+https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git#4c704913f671060bb0e43b5ce4a68d02281115d5"
 | 
			
		||||
source = "git+https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git#3c6ad40680126a760eb867b07b506ea996819ce3"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "phf"
 | 
			
		||||
@ -1103,7 +1103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rocksdb"
 | 
			
		||||
version = "0.4.5"
 | 
			
		||||
source = "git+https://github.com/ethcore/rust-rocksdb#e0e6c099d8cd156fe446009fce241d57b00cd8f4"
 | 
			
		||||
source = "git+https://github.com/ethcore/rust-rocksdb#6f3c68f5f075433d206be4af6a620651cd9f8541"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)",
 | 
			
		||||
@ -1112,7 +1112,7 @@ dependencies = [
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rocksdb-sys"
 | 
			
		||||
version = "0.3.0"
 | 
			
		||||
source = "git+https://github.com/ethcore/rust-rocksdb#e0e6c099d8cd156fe446009fce241d57b00cd8f4"
 | 
			
		||||
source = "git+https://github.com/ethcore/rust-rocksdb#6f3c68f5f075433d206be4af6a620651cd9f8541"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
								
							@ -36,7 +36,7 @@ below to build from source.
 | 
			
		||||
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
## Building from source
 | 
			
		||||
## Build dependencies
 | 
			
		||||
 | 
			
		||||
Parity is fully compatible with Stable Rust.
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,19 @@ We recommend installing Rust through [rustup](https://www.rustup.rs/). If you do
 | 
			
		||||
	$ rustup default stable-x86_64-pc-windows-msvc
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
Once you have rustup, download and build parity:
 | 
			
		||||
Once you have rustup, install parity or download and build from source
 | 
			
		||||
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
## Quick install
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
cargo install --git https://github.com/ethcore/parity.git parity
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
## Build from source
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# download Parity code
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										25
									
								
								docker/centos/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								docker/centos/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
FROM centos:latest
 | 
			
		||||
WORKDIR /build
 | 
			
		||||
# install tools and dependencies
 | 
			
		||||
RUN yum -y update&& \
 | 
			
		||||
    yum install -y git make gcc-c++ gcc file 
 | 
			
		||||
# install rustup
 | 
			
		||||
RUN curl -sSf https://static.rust-lang.org/rustup.sh -o rustup.sh &&\
 | 
			
		||||
ls&&\ 
 | 
			
		||||
 sh rustup.sh -s -- --disable-sudo
 | 
			
		||||
# show backtraces
 | 
			
		||||
ENV RUST_BACKTRACE 1
 | 
			
		||||
ENV CXX g++
 | 
			
		||||
ENV CC gcc
 | 
			
		||||
RUN rustc -vV && \
 | 
			
		||||
cargo -V && \
 | 
			
		||||
gcc -v &&\
 | 
			
		||||
g++ -v
 | 
			
		||||
# git clone parity
 | 
			
		||||
RUN git clone https://github.com/ethcore/parity && \
 | 
			
		||||
	cd parity&&\
 | 
			
		||||
        ls -a&&\
 | 
			
		||||
        cargo build --release --verbose && \
 | 
			
		||||
	ls /build/parity/target/release/parity &&	\
 | 
			
		||||
	file /build/parity/target/release/parity && \
 | 
			
		||||
RUN file /build/parity/target/release/parity
 | 
			
		||||
@ -9,7 +9,8 @@
 | 
			
		||||
				"durationLimit": "0x0d",
 | 
			
		||||
				"blockReward": "0x4563918244F40000",
 | 
			
		||||
				"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0x118c30"
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0x118c30",
 | 
			
		||||
				"daoRescueSoftFork": false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26729
									
								
								ethcore/res/ethereum/frontier_dao_rescue.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26729
									
								
								ethcore/res/ethereum/frontier_dao_rescue.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -9,7 +9,8 @@
 | 
			
		||||
				"durationLimit": "0x0d",
 | 
			
		||||
				"blockReward": "0x4563918244F40000",
 | 
			
		||||
				"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0x118c30"
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0x118c30",
 | 
			
		||||
				"daoRescueSoftFork": false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										43
									
								
								ethcore/res/ethereum/frontier_like_test_dao_rescue.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								ethcore/res/ethereum/frontier_like_test_dao_rescue.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
{
 | 
			
		||||
	"name": "Frontier (Test)",
 | 
			
		||||
	"engine": {
 | 
			
		||||
		"Ethash": {
 | 
			
		||||
			"params": {
 | 
			
		||||
				"gasLimitBoundDivisor": "0x0400",
 | 
			
		||||
				"minimumDifficulty": "0x020000",
 | 
			
		||||
				"difficultyBoundDivisor": "0x0800",
 | 
			
		||||
				"durationLimit": "0x0d",
 | 
			
		||||
				"blockReward": "0x4563918244F40000",
 | 
			
		||||
				"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0x118c30",
 | 
			
		||||
				"daoRescueSoftFork": true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"params": {
 | 
			
		||||
		"accountStartNonce": "0x00",
 | 
			
		||||
		"maximumExtraDataSize": "0x20",
 | 
			
		||||
		"minGasLimit": "0x1388",
 | 
			
		||||
		"networkID" : "0x1"
 | 
			
		||||
	},
 | 
			
		||||
	"genesis": {
 | 
			
		||||
		"seal": {
 | 
			
		||||
			"ethereum": {
 | 
			
		||||
				"nonce": "0x0000000000000042",
 | 
			
		||||
				"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"difficulty": "0x400000000",
 | 
			
		||||
		"author": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
		"timestamp": "0x00",
 | 
			
		||||
		"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
 | 
			
		||||
		"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
 | 
			
		||||
		"gasLimit": "0x1388"
 | 
			
		||||
	},
 | 
			
		||||
	"accounts": {
 | 
			
		||||
		"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
 | 
			
		||||
		"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
 | 
			
		||||
		"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
 | 
			
		||||
		"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -9,7 +9,8 @@
 | 
			
		||||
				"durationLimit": "0x0d",
 | 
			
		||||
				"blockReward": "0x4563918244F40000",
 | 
			
		||||
				"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0xffffffffffffffff"
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0xffffffffffffffff",
 | 
			
		||||
				"daoRescueSoftFork": false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,8 @@
 | 
			
		||||
				"durationLimit": "0x0d",
 | 
			
		||||
				"blockReward": "0x4563918244F40000",
 | 
			
		||||
				"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
				"frontierCompatibilityModeLimit": 0
 | 
			
		||||
				"frontierCompatibilityModeLimit": 0,
 | 
			
		||||
				"daoRescueSoftFork": false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										43
									
								
								ethcore/res/ethereum/homestead_test_dao_rescue.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								ethcore/res/ethereum/homestead_test_dao_rescue.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
{
 | 
			
		||||
	"name": "Homestead (Test)",
 | 
			
		||||
	"engine": {
 | 
			
		||||
		"Ethash": {
 | 
			
		||||
			"params": {
 | 
			
		||||
				"gasLimitBoundDivisor": "0x0400",
 | 
			
		||||
				"minimumDifficulty": "0x020000",
 | 
			
		||||
				"difficultyBoundDivisor": "0x0800",
 | 
			
		||||
				"durationLimit": "0x0d",
 | 
			
		||||
				"blockReward": "0x4563918244F40000",
 | 
			
		||||
				"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
				"frontierCompatibilityModeLimit": 0,
 | 
			
		||||
				"daoRescueSoftFork": true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"params": {
 | 
			
		||||
		"accountStartNonce": "0x00",
 | 
			
		||||
		"maximumExtraDataSize": "0x20",
 | 
			
		||||
		"minGasLimit": "0x1388",
 | 
			
		||||
		"networkID" : "0x1"
 | 
			
		||||
	},
 | 
			
		||||
	"genesis": {
 | 
			
		||||
		"seal": {
 | 
			
		||||
			"ethereum": {
 | 
			
		||||
				"nonce": "0x0000000000000042",
 | 
			
		||||
				"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"difficulty": "0x400000000",
 | 
			
		||||
		"author": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
		"timestamp": "0x00",
 | 
			
		||||
		"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
 | 
			
		||||
		"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
 | 
			
		||||
		"gasLimit": "0x1388"
 | 
			
		||||
	},
 | 
			
		||||
	"accounts": {
 | 
			
		||||
		"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
 | 
			
		||||
		"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
 | 
			
		||||
		"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
 | 
			
		||||
		"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -9,7 +9,8 @@
 | 
			
		||||
				"durationLimit": "0x0d",
 | 
			
		||||
				"blockReward": "0x4563918244F40000",
 | 
			
		||||
				"registrar": "",
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0x789b0"
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0x789b0",
 | 
			
		||||
				"daoRescueSoftFork": false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,8 @@
 | 
			
		||||
				"durationLimit": "0x08",
 | 
			
		||||
				"blockReward": "0x14D1120D7B160000",
 | 
			
		||||
				"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0xffffffffffffffff"
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0xffffffffffffffff",
 | 
			
		||||
				"daoRescueSoftFork": false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@ -203,8 +203,9 @@ mod tests {
 | 
			
		||||
			timestamp: 0,
 | 
			
		||||
			difficulty: 0.into(),
 | 
			
		||||
			last_hashes: vec![],
 | 
			
		||||
			dao_rescue_block_gas_limit: None,
 | 
			
		||||
			gas_used: 0.into(),
 | 
			
		||||
			gas_limit: 0.into()
 | 
			
		||||
			gas_limit: 0.into(),
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		assert!(schedule.stack_limit > 0);
 | 
			
		||||
@ -253,7 +254,7 @@ mod tests {
 | 
			
		||||
		spec.ensure_db_good(db.as_hashdb_mut());
 | 
			
		||||
		let last_hashes = vec![genesis_header.hash()];
 | 
			
		||||
		let vm_factory = Default::default();
 | 
			
		||||
		let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, addr, 3141562.into(), vec![]).unwrap();
 | 
			
		||||
		let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, addr, 3141562.into(), vec![]).unwrap();
 | 
			
		||||
		let b = b.close_and_lock();
 | 
			
		||||
		let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
 | 
			
		||||
		assert!(b.try_seal(engine.deref(), seal).is_ok());
 | 
			
		||||
 | 
			
		||||
@ -177,6 +177,7 @@ pub struct OpenBlock<'x> {
 | 
			
		||||
	engine: &'x Engine,
 | 
			
		||||
	vm_factory: &'x EvmFactory,
 | 
			
		||||
	last_hashes: LastHashes,
 | 
			
		||||
	dao_rescue_block_gas_limit: Option<U256>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
 | 
			
		||||
@ -188,6 +189,7 @@ pub struct ClosedBlock {
 | 
			
		||||
	block: ExecutedBlock,
 | 
			
		||||
	uncle_bytes: Bytes,
 | 
			
		||||
	last_hashes: LastHashes,
 | 
			
		||||
	dao_rescue_block_gas_limit: Option<U256>,
 | 
			
		||||
	unclosed_state: State,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -198,7 +200,6 @@ pub struct ClosedBlock {
 | 
			
		||||
pub struct LockedBlock {
 | 
			
		||||
	block: ExecutedBlock,
 | 
			
		||||
	uncle_bytes: Bytes,
 | 
			
		||||
	last_hashes: LastHashes,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A block that has a valid seal.
 | 
			
		||||
@ -219,9 +220,10 @@ impl<'x> OpenBlock<'x> {
 | 
			
		||||
		db: Box<JournalDB>,
 | 
			
		||||
		parent: &Header,
 | 
			
		||||
		last_hashes: LastHashes,
 | 
			
		||||
		dao_rescue_block_gas_limit: Option<U256>,
 | 
			
		||||
		author: Address,
 | 
			
		||||
		gas_floor_target: U256,
 | 
			
		||||
		extra_data: Bytes
 | 
			
		||||
		extra_data: Bytes,
 | 
			
		||||
	) -> Result<Self, Error> {
 | 
			
		||||
		let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()));
 | 
			
		||||
		let mut r = OpenBlock {
 | 
			
		||||
@ -229,6 +231,7 @@ impl<'x> OpenBlock<'x> {
 | 
			
		||||
			engine: engine,
 | 
			
		||||
			vm_factory: vm_factory,
 | 
			
		||||
			last_hashes: last_hashes,
 | 
			
		||||
			dao_rescue_block_gas_limit: dao_rescue_block_gas_limit,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		r.block.base.header.parent_hash = parent.hash();
 | 
			
		||||
@ -293,6 +296,7 @@ impl<'x> OpenBlock<'x> {
 | 
			
		||||
			last_hashes: self.last_hashes.clone(),		// TODO: should be a reference.
 | 
			
		||||
			gas_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
 | 
			
		||||
			gas_limit: self.block.base.header.gas_limit.clone(),
 | 
			
		||||
			dao_rescue_block_gas_limit: if self.block.base.header.number == 1760000 { Some(self.block.base.header.gas_limit) } else { self.dao_rescue_block_gas_limit },
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -339,6 +343,7 @@ impl<'x> OpenBlock<'x> {
 | 
			
		||||
			block: s.block,
 | 
			
		||||
			uncle_bytes: uncle_bytes,
 | 
			
		||||
			last_hashes: s.last_hashes,
 | 
			
		||||
			dao_rescue_block_gas_limit: s.dao_rescue_block_gas_limit,
 | 
			
		||||
			unclosed_state: unclosed_state,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@ -360,7 +365,6 @@ impl<'x> OpenBlock<'x> {
 | 
			
		||||
		LockedBlock {
 | 
			
		||||
			block: s.block,
 | 
			
		||||
			uncle_bytes: uncle_bytes,
 | 
			
		||||
			last_hashes: s.last_hashes,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -386,7 +390,6 @@ impl ClosedBlock {
 | 
			
		||||
		LockedBlock {
 | 
			
		||||
			block: self.block,
 | 
			
		||||
			uncle_bytes: self.uncle_bytes,
 | 
			
		||||
			last_hashes: self.last_hashes,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -400,6 +403,7 @@ impl ClosedBlock {
 | 
			
		||||
			engine: engine,
 | 
			
		||||
			vm_factory: vm_factory,
 | 
			
		||||
			last_hashes: self.last_hashes,
 | 
			
		||||
			dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -456,7 +460,18 @@ impl IsBlock for SealedBlock {
 | 
			
		||||
 | 
			
		||||
/// Enact the block given by block header, transactions and uncles
 | 
			
		||||
#[cfg_attr(feature="dev", allow(too_many_arguments))]
 | 
			
		||||
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> {
 | 
			
		||||
pub fn enact(
 | 
			
		||||
	header: &Header,
 | 
			
		||||
	transactions: &[SignedTransaction],
 | 
			
		||||
	uncles: &[Header],
 | 
			
		||||
	engine: &Engine,
 | 
			
		||||
	tracing: bool,
 | 
			
		||||
	db: Box<JournalDB>,
 | 
			
		||||
	parent: &Header,
 | 
			
		||||
	last_hashes: LastHashes,
 | 
			
		||||
	dao_rescue_block_gas_limit: Option<U256>,
 | 
			
		||||
	vm_factory: &EvmFactory
 | 
			
		||||
) -> Result<LockedBlock, Error> {
 | 
			
		||||
	{
 | 
			
		||||
		if ::log::max_log_level() >= ::log::LogLevel::Trace {
 | 
			
		||||
			let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce()));
 | 
			
		||||
@ -464,7 +479,7 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone()));
 | 
			
		||||
	let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), 3141562.into(), header.extra_data().clone()));
 | 
			
		||||
	b.set_difficulty(*header.difficulty());
 | 
			
		||||
	b.set_gas_limit(*header.gas_limit());
 | 
			
		||||
	b.set_timestamp(header.timestamp());
 | 
			
		||||
@ -474,22 +489,49 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
 | 
			
		||||
pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> {
 | 
			
		||||
pub fn enact_bytes(
 | 
			
		||||
	block_bytes: &[u8],
 | 
			
		||||
	engine: &Engine,
 | 
			
		||||
	tracing: bool,
 | 
			
		||||
	db: Box<JournalDB>,
 | 
			
		||||
	parent: &Header,
 | 
			
		||||
	last_hashes: LastHashes,
 | 
			
		||||
	dao_rescue_block_gas_limit: Option<U256>,
 | 
			
		||||
	vm_factory: &EvmFactory
 | 
			
		||||
) -> Result<LockedBlock, Error> {
 | 
			
		||||
	let block = BlockView::new(block_bytes);
 | 
			
		||||
	let header = block.header();
 | 
			
		||||
	enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, vm_factory)
 | 
			
		||||
	enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
 | 
			
		||||
pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> {
 | 
			
		||||
pub fn enact_verified(
 | 
			
		||||
	block: &PreverifiedBlock,
 | 
			
		||||
	engine: &Engine,
 | 
			
		||||
	tracing: bool,
 | 
			
		||||
	db: Box<JournalDB>,
 | 
			
		||||
	parent: &Header,
 | 
			
		||||
	last_hashes: LastHashes,
 | 
			
		||||
	dao_rescue_block_gas_limit: Option<U256>,
 | 
			
		||||
	vm_factory: &EvmFactory
 | 
			
		||||
) -> Result<LockedBlock, Error> {
 | 
			
		||||
	let view = BlockView::new(&block.bytes);
 | 
			
		||||
	enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, vm_factory)
 | 
			
		||||
	enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
 | 
			
		||||
pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<SealedBlock, Error> {
 | 
			
		||||
pub fn enact_and_seal(
 | 
			
		||||
	block_bytes: &[u8],
 | 
			
		||||
	engine: &Engine,
 | 
			
		||||
	tracing: bool,
 | 
			
		||||
	db: Box<JournalDB>,
 | 
			
		||||
	parent: &Header,
 | 
			
		||||
	last_hashes: LastHashes,
 | 
			
		||||
	dao_rescue_block_gas_limit: Option<U256>,
 | 
			
		||||
	vm_factory: &EvmFactory
 | 
			
		||||
) -> Result<SealedBlock, Error> {
 | 
			
		||||
	let header = BlockView::new(block_bytes).header_view();
 | 
			
		||||
	Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, vm_factory)).seal(engine, header.seal())))
 | 
			
		||||
	Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)).seal(engine, header.seal())))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
@ -509,7 +551,7 @@ mod tests {
 | 
			
		||||
		spec.ensure_db_good(db.as_hashdb_mut());
 | 
			
		||||
		let last_hashes = vec![genesis_header.hash()];
 | 
			
		||||
		let vm_factory = Default::default();
 | 
			
		||||
		let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap();
 | 
			
		||||
		let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), 3141562.into(), vec![]).unwrap();
 | 
			
		||||
		let b = b.close_and_lock();
 | 
			
		||||
		let _ = b.seal(engine.deref(), vec![]);
 | 
			
		||||
	}
 | 
			
		||||
@ -525,7 +567,7 @@ mod tests {
 | 
			
		||||
		let mut db = db_result.take();
 | 
			
		||||
		spec.ensure_db_good(db.as_hashdb_mut());
 | 
			
		||||
		let vm_factory = Default::default();
 | 
			
		||||
		let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).unwrap()
 | 
			
		||||
		let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), 3141562.into(), vec![]).unwrap()
 | 
			
		||||
			.close_and_lock().seal(engine.deref(), vec![]).unwrap();
 | 
			
		||||
		let orig_bytes = b.rlp_bytes();
 | 
			
		||||
		let orig_db = b.drain();
 | 
			
		||||
@ -533,7 +575,7 @@ mod tests {
 | 
			
		||||
		let mut db_result = get_temp_journal_db();
 | 
			
		||||
		let mut db = db_result.take();
 | 
			
		||||
		spec.ensure_db_good(db.as_hashdb_mut());
 | 
			
		||||
		let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default()).unwrap();
 | 
			
		||||
		let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap();
 | 
			
		||||
 | 
			
		||||
		assert_eq!(e.rlp_bytes(), orig_bytes);
 | 
			
		||||
 | 
			
		||||
@ -553,7 +595,7 @@ mod tests {
 | 
			
		||||
		let mut db = db_result.take();
 | 
			
		||||
		spec.ensure_db_good(db.as_hashdb_mut());
 | 
			
		||||
		let vm_factory = Default::default();
 | 
			
		||||
		let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).unwrap();
 | 
			
		||||
		let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), 3141562.into(), vec![]).unwrap();
 | 
			
		||||
		let mut uncle1_header = Header::new();
 | 
			
		||||
		uncle1_header.extra_data = b"uncle1".to_vec();
 | 
			
		||||
		let mut uncle2_header = Header::new();
 | 
			
		||||
@ -568,7 +610,7 @@ mod tests {
 | 
			
		||||
		let mut db_result = get_temp_journal_db();
 | 
			
		||||
		let mut db = db_result.take();
 | 
			
		||||
		spec.ensure_db_good(db.as_hashdb_mut());
 | 
			
		||||
		let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default()).unwrap();
 | 
			
		||||
		let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap();
 | 
			
		||||
 | 
			
		||||
		let bytes = e.rlp_bytes();
 | 
			
		||||
		assert_eq!(bytes, orig_bytes);
 | 
			
		||||
 | 
			
		||||
@ -130,7 +130,9 @@ impl QueueSignal {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
 | 
			
		||||
			self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message");
 | 
			
		||||
			if let Err(e) = self.message_channel.send(UserMessage(SyncMessage::BlockVerified)) {
 | 
			
		||||
				debug!("Error sending BlockVerified message: {:?}", e);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -230,7 +230,7 @@ impl<V> Client<V> where V: Verifier {
 | 
			
		||||
		let last_hashes = self.build_last_hashes(header.parent_hash.clone());
 | 
			
		||||
		let db = self.state_db.lock().unwrap().boxed_clone();
 | 
			
		||||
 | 
			
		||||
		let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, &self.vm_factory);
 | 
			
		||||
		let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(), &self.vm_factory);
 | 
			
		||||
		if let Err(e) = enact_result {
 | 
			
		||||
			warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
 | 
			
		||||
			return Err(());
 | 
			
		||||
@ -381,7 +381,7 @@ impl<V> Client<V> where V: Verifier {
 | 
			
		||||
			balance: self.latest_balance(a),
 | 
			
		||||
		};
 | 
			
		||||
		let tx = transactions.iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect();
 | 
			
		||||
		let results = self.miner.import_transactions(tx, fetch_account);
 | 
			
		||||
		let results = self.miner.import_transactions(self, tx, fetch_account);
 | 
			
		||||
		results.len()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -486,6 +486,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
 | 
			
		||||
			last_hashes: last_hashes,
 | 
			
		||||
			gas_used: U256::zero(),
 | 
			
		||||
			gas_limit: U256::max_value(),
 | 
			
		||||
			dao_rescue_block_gas_limit: self.dao_rescue_block_gas_limit(),
 | 
			
		||||
		};
 | 
			
		||||
		// that's just a copy of the state.
 | 
			
		||||
		let mut state = self.state();
 | 
			
		||||
@ -771,7 +772,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
 | 
			
		||||
			nonce: self.latest_nonce(a),
 | 
			
		||||
			balance: self.latest_balance(a),
 | 
			
		||||
		};
 | 
			
		||||
		self.miner.import_transactions(transactions, fetch_account)
 | 
			
		||||
		self.miner.import_transactions(self, transactions, fetch_account)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn queue_transactions(&self, transactions: Vec<Bytes>) {
 | 
			
		||||
@ -807,6 +808,7 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
 | 
			
		||||
			self.state_db.lock().unwrap().boxed_clone(),
 | 
			
		||||
			&self.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"),
 | 
			
		||||
			self.build_last_hashes(h.clone()),
 | 
			
		||||
			self.dao_rescue_block_gas_limit(),
 | 
			
		||||
			author,
 | 
			
		||||
			gas_floor_target,
 | 
			
		||||
			extra_data,
 | 
			
		||||
 | 
			
		||||
@ -42,7 +42,7 @@ use header::{BlockNumber, Header};
 | 
			
		||||
use transaction::{LocalizedTransaction, SignedTransaction};
 | 
			
		||||
use log_entry::LocalizedLogEntry;
 | 
			
		||||
use filter::Filter;
 | 
			
		||||
use views::BlockView;
 | 
			
		||||
use views::{HeaderView, BlockView};
 | 
			
		||||
use error::{ImportResult, ExecutionError};
 | 
			
		||||
use receipt::LocalizedReceipt;
 | 
			
		||||
use trace::LocalizedTrace;
 | 
			
		||||
@ -224,6 +224,13 @@ pub trait BlockChainClient : Sync + Send {
 | 
			
		||||
			Err(())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/// Get `Some` gas limit of block 1_760_000, or `None` if chain is not yet that long.
 | 
			
		||||
	fn dao_rescue_block_gas_limit(&self) -> Option<U256> {
 | 
			
		||||
		self.block_header(BlockID::Number(1_760_000))
 | 
			
		||||
			.map(|header| HeaderView::new(&header).gas_limit())
 | 
			
		||||
	}	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Extended client interface used for mining
 | 
			
		||||
 | 
			
		||||
@ -490,7 +490,7 @@ impl BlockChainClient for TestBlockChainClient {
 | 
			
		||||
			balance: balances[a],
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		self.miner.import_transactions(transactions, &fetch_account)
 | 
			
		||||
		self.miner.import_transactions(self, transactions, &fetch_account)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn queue_transactions(&self, transactions: Vec<Bytes>) {
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,9 @@ pub struct EnvInfo {
 | 
			
		||||
	pub last_hashes: LastHashes,
 | 
			
		||||
	/// The gas used.
 | 
			
		||||
	pub gas_used: U256,
 | 
			
		||||
 | 
			
		||||
	/// Block gas limit at DAO rescue block #1760000 or None if not yet there.
 | 
			
		||||
	pub dao_rescue_block_gas_limit: Option<U256>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for EnvInfo {
 | 
			
		||||
@ -51,6 +54,7 @@ impl Default for EnvInfo {
 | 
			
		||||
			gas_limit: 0.into(),
 | 
			
		||||
			last_hashes: vec![],
 | 
			
		||||
			gas_used: 0.into(),
 | 
			
		||||
			dao_rescue_block_gas_limit: None,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -66,6 +70,7 @@ impl From<ethjson::vm::Env> for EnvInfo {
 | 
			
		||||
			timestamp: e.timestamp.into(),
 | 
			
		||||
			last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(),
 | 
			
		||||
			gas_used: U256::zero(),
 | 
			
		||||
			dao_rescue_block_gas_limit: None,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -41,6 +41,8 @@ pub struct EthashParams {
 | 
			
		||||
	pub registrar: Address,
 | 
			
		||||
	/// Homestead transition block number.
 | 
			
		||||
	pub frontier_compatibility_mode_limit: u64,
 | 
			
		||||
	/// Enable the soft-fork logic.
 | 
			
		||||
	pub dao_rescue_soft_fork: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ethjson::spec::EthashParams> for EthashParams {
 | 
			
		||||
@ -53,6 +55,7 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
 | 
			
		||||
			block_reward: p.block_reward.into(),
 | 
			
		||||
			registrar: p.registrar.into(),
 | 
			
		||||
			frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.into(),
 | 
			
		||||
			dao_rescue_soft_fork: p.dao_rescue_soft_fork.into(),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -102,8 +105,9 @@ impl Engine for Ethash {
 | 
			
		||||
			Schedule::new_frontier()
 | 
			
		||||
		} else {
 | 
			
		||||
			let mut s = Schedule::new_homestead();
 | 
			
		||||
			// TODO: make dependent on gaslimit > 4000000 of block 1760000.	
 | 
			
		||||
			s.reject_dao_transactions = env_info.number >= 1760000;
 | 
			
		||||
			if self.ethash_params.dao_rescue_soft_fork {
 | 
			
		||||
				s.reject_dao_transactions = env_info.dao_rescue_block_gas_limit.map(|x| x <= 4_000_000.into()).unwrap_or(false);
 | 
			
		||||
			}
 | 
			
		||||
			s
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@ -319,7 +323,7 @@ mod tests {
 | 
			
		||||
		spec.ensure_db_good(db.as_hashdb_mut());
 | 
			
		||||
		let last_hashes = vec![genesis_header.hash()];
 | 
			
		||||
		let vm_factory = Default::default();
 | 
			
		||||
		let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap();
 | 
			
		||||
		let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), 3141562.into(), vec![]).unwrap();
 | 
			
		||||
		let b = b.close();
 | 
			
		||||
		assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
 | 
			
		||||
	}
 | 
			
		||||
@ -334,7 +338,7 @@ mod tests {
 | 
			
		||||
		spec.ensure_db_good(db.as_hashdb_mut());
 | 
			
		||||
		let last_hashes = vec![genesis_header.hash()];
 | 
			
		||||
		let vm_factory = Default::default();
 | 
			
		||||
		let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap();
 | 
			
		||||
		let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), 3141562.into(), vec![]).unwrap();
 | 
			
		||||
		let mut uncle = Header::new();
 | 
			
		||||
		let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
 | 
			
		||||
		uncle.author = uncle_author.clone();
 | 
			
		||||
@ -362,7 +366,8 @@ mod tests {
 | 
			
		||||
			difficulty: 0.into(),
 | 
			
		||||
			last_hashes: vec![],
 | 
			
		||||
			gas_used: 0.into(),
 | 
			
		||||
			gas_limit: 0.into()
 | 
			
		||||
			gas_limit: 0.into(),
 | 
			
		||||
			dao_rescue_block_gas_limit: None,
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		assert!(schedule.stack_limit > 0);
 | 
			
		||||
@ -374,7 +379,8 @@ mod tests {
 | 
			
		||||
			difficulty: 0.into(),
 | 
			
		||||
			last_hashes: vec![],
 | 
			
		||||
			gas_used: 0.into(),
 | 
			
		||||
			gas_limit: 0.into()
 | 
			
		||||
			gas_limit: 0.into(),
 | 
			
		||||
			dao_rescue_block_gas_limit: None,
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		assert!(!schedule.have_delegate_call);
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,12 @@ use super::spec::*;
 | 
			
		||||
pub fn new_olympic() -> Spec { Spec::load(include_bytes!("../../res/ethereum/olympic.json")) }
 | 
			
		||||
 | 
			
		||||
/// Create a new Frontier mainnet chain spec.
 | 
			
		||||
pub fn new_frontier() -> Spec { Spec::load(include_bytes!("../../res/ethereum/frontier.json")) }
 | 
			
		||||
pub fn new_frontier(dao_rescue: bool) -> Spec {
 | 
			
		||||
	Spec::load(match dao_rescue {
 | 
			
		||||
		true => include_bytes!("../../res/ethereum/frontier_dao_rescue.json"),
 | 
			
		||||
		false => include_bytes!("../../res/ethereum/frontier.json"),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a new Frontier chain spec as though it never changes to Homestead.
 | 
			
		||||
pub fn new_frontier_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/frontier_test.json")) }
 | 
			
		||||
@ -84,7 +89,7 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn frontier() {
 | 
			
		||||
		let frontier = new_frontier();
 | 
			
		||||
		let frontier = new_frontier(true);
 | 
			
		||||
 | 
			
		||||
		assert_eq!(frontier.state_root(), H256::from_str("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544").unwrap());
 | 
			
		||||
		let genesis = frontier.genesis_block();
 | 
			
		||||
 | 
			
		||||
@ -318,7 +318,8 @@ mod tests {
 | 
			
		||||
			difficulty: 0.into(),
 | 
			
		||||
			last_hashes: vec![],
 | 
			
		||||
			gas_used: 0.into(),
 | 
			
		||||
			gas_limit: 0.into()
 | 
			
		||||
			gas_limit: 0.into(),
 | 
			
		||||
			dao_rescue_block_gas_limit: None,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -106,10 +106,11 @@ impl Miner {
 | 
			
		||||
	#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
 | 
			
		||||
	fn prepare_sealing(&self, chain: &MiningBlockChainClient) {
 | 
			
		||||
		trace!(target: "miner", "prepare_sealing: entering");
 | 
			
		||||
		let transactions = self.transaction_queue.lock().unwrap().top_transactions();
 | 
			
		||||
 | 
			
		||||
		let (transactions, mut open_block) = {
 | 
			
		||||
			let transactions = {self.transaction_queue.lock().unwrap().top_transactions()};
 | 
			
		||||
			let mut sealing_work = self.sealing_work.lock().unwrap();
 | 
			
		||||
			let best_hash = chain.best_block_header().sha3();
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
			// check to see if last ClosedBlock in would_seals is actually same parent block.
 | 
			
		||||
			// if so
 | 
			
		||||
@ -118,7 +119,7 @@ impl Miner {
 | 
			
		||||
			//   otherwise, leave everything alone.
 | 
			
		||||
			// otherwise, author a fresh block.
 | 
			
		||||
*/
 | 
			
		||||
		let mut open_block = match sealing_work.pop_if(|b| b.block().fields().header.parent_hash() == &best_hash) {
 | 
			
		||||
			let open_block = match sealing_work.pop_if(|b| b.block().fields().header.parent_hash() == &best_hash) {
 | 
			
		||||
				Some(old_block) => {
 | 
			
		||||
					trace!(target: "miner", "Already have previous work; updating and returning");
 | 
			
		||||
					// add transactions to old_block
 | 
			
		||||
@ -135,6 +136,8 @@ impl Miner {
 | 
			
		||||
					)
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
			(transactions, open_block)
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		let mut invalid_transactions = HashSet::new();
 | 
			
		||||
		let block_number = open_block.block().fields().header.number();
 | 
			
		||||
@ -163,15 +166,17 @@ impl Miner {
 | 
			
		||||
 | 
			
		||||
		let block = open_block.close();
 | 
			
		||||
 | 
			
		||||
		let mut queue = self.transaction_queue.lock().unwrap();
 | 
			
		||||
		let fetch_account = |a: &Address| AccountDetails {
 | 
			
		||||
			nonce: chain.latest_nonce(a),
 | 
			
		||||
			balance: chain.latest_balance(a),
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			let mut queue = self.transaction_queue.lock().unwrap();
 | 
			
		||||
			for hash in invalid_transactions.into_iter() {
 | 
			
		||||
				queue.remove_invalid(&hash, &fetch_account);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !block.transactions().is_empty() {
 | 
			
		||||
			trace!(target: "miner", "prepare_sealing: block has transaction - attempting internal seal.");
 | 
			
		||||
@ -196,6 +201,8 @@ impl Miner {
 | 
			
		||||
				trace!(target: "miner", "prepare_sealing: unable to generate seal internally");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		let mut sealing_work = self.sealing_work.lock().unwrap();
 | 
			
		||||
		if sealing_work.peek_last_ref().map_or(true, |pb| pb.block().fields().header.hash() != block.block().fields().header.hash()) {
 | 
			
		||||
			trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash());
 | 
			
		||||
			sealing_work.push(block);
 | 
			
		||||
@ -267,6 +274,7 @@ impl MinerService for Miner {
 | 
			
		||||
					last_hashes: last_hashes,
 | 
			
		||||
					gas_used: U256::zero(),
 | 
			
		||||
					gas_limit: U256::max_value(),
 | 
			
		||||
					dao_rescue_block_gas_limit: chain.dao_rescue_block_gas_limit(),
 | 
			
		||||
				};
 | 
			
		||||
				// that's just a copy of the state.
 | 
			
		||||
				let mut state = block.state().clone();
 | 
			
		||||
@ -376,13 +384,19 @@ impl MinerService for Miner {
 | 
			
		||||
		*self.gas_floor_target.read().unwrap()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) ->
 | 
			
		||||
	fn import_transactions<T>(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
 | 
			
		||||
		Vec<Result<TransactionImportResult, Error>>
 | 
			
		||||
		where T: Fn(&Address) -> AccountDetails {
 | 
			
		||||
		let results: Vec<Result<TransactionImportResult, Error>> = {
 | 
			
		||||
			let mut transaction_queue = self.transaction_queue.lock().unwrap();
 | 
			
		||||
			transactions.into_iter()
 | 
			
		||||
				.map(|tx| transaction_queue.add(tx, &fetch_account, TransactionOrigin::External))
 | 
			
		||||
				.collect()
 | 
			
		||||
		};
 | 
			
		||||
		if !results.is_empty() {
 | 
			
		||||
			self.update_sealing(chain);
 | 
			
		||||
		}
 | 
			
		||||
		results
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn import_own_transaction<T>(
 | 
			
		||||
@ -564,7 +578,7 @@ impl MinerService for Miner {
 | 
			
		||||
				for tx in &txs {
 | 
			
		||||
					let _sender = tx.sender();
 | 
			
		||||
				}
 | 
			
		||||
				let _ = self.import_transactions(txs, |a| AccountDetails {
 | 
			
		||||
				let _ = self.import_transactions(chain, txs, |a| AccountDetails {
 | 
			
		||||
					nonce: chain.latest_nonce(a),
 | 
			
		||||
					balance: chain.latest_balance(a),
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
@ -94,7 +94,7 @@ pub trait MinerService : Send + Sync {
 | 
			
		||||
	fn set_transactions_limit(&self, limit: usize);
 | 
			
		||||
 | 
			
		||||
	/// Imports transactions to transaction queue.
 | 
			
		||||
	fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) ->
 | 
			
		||||
	fn import_transactions<T>(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
 | 
			
		||||
		Vec<Result<TransactionImportResult, Error>>
 | 
			
		||||
		where T: Fn(&Address) -> AccountDetails, Self: Sized;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -657,8 +657,14 @@ impl TransactionQueue {
 | 
			
		||||
			.cloned()
 | 
			
		||||
			.map_or(state_nonce, |n| n + U256::one());
 | 
			
		||||
 | 
			
		||||
		// Check height
 | 
			
		||||
		if nonce > next_nonce {
 | 
			
		||||
		// The transaction might be old, let's check that.
 | 
			
		||||
		// This has to be the first test, otherwise calculating
 | 
			
		||||
		// nonce height would result in overflow.
 | 
			
		||||
		if nonce < state_nonce {
 | 
			
		||||
			// Droping transaction
 | 
			
		||||
			trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce);
 | 
			
		||||
			return Err(TransactionError::Old);
 | 
			
		||||
		} else if nonce > next_nonce {
 | 
			
		||||
			// We have a gap - put to future.
 | 
			
		||||
			// Update nonces of transactions in future (remove old transactions)
 | 
			
		||||
			self.update_future(&address, state_nonce);
 | 
			
		||||
@ -667,12 +673,7 @@ impl TransactionQueue {
 | 
			
		||||
			// Return an error if this transaction is not imported because of limit.
 | 
			
		||||
			try!(check_if_removed(&address, &nonce, self.future.enforce_limit(&mut self.by_hash)));
 | 
			
		||||
			return Ok(TransactionImportResult::Future);
 | 
			
		||||
		} else if nonce < state_nonce {
 | 
			
		||||
			// Droping transaction
 | 
			
		||||
			trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce);
 | 
			
		||||
			return Err(TransactionError::Old);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash)));
 | 
			
		||||
		// Keep track of highest nonce stored in current
 | 
			
		||||
		let new_max = self.last_nonces.get(&address).map_or(nonce, |n| cmp::max(nonce, *n));
 | 
			
		||||
 | 
			
		||||
@ -222,10 +222,15 @@ impl State {
 | 
			
		||||
		let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true };
 | 
			
		||||
		let e = try!(Executive::new(self, env_info, engine, vm_factory).transact(t, options));
 | 
			
		||||
 | 
			
		||||
		let broken_dao = H256::from("7278d050619a624f84f51987149ddb439cdaadfba5966f7cfaea7ad44340a4ba");
 | 
			
		||||
		let broken_dao = H256::from("6a5d24750f78441e56fec050dc52fe8e911976485b7472faac7464a176a67caa");
 | 
			
		||||
 | 
			
		||||
		// dao attack soft fork
 | 
			
		||||
		if engine.schedule(&env_info).reject_dao_transactions {
 | 
			
		||||
			let whitelisted = if let Action::Call(to) = t.action {
 | 
			
		||||
				to == Address::from("Da4a4626d3E16e094De3225A751aAb7128e96526") ||
 | 
			
		||||
				to == Address::from("2ba9D006C1D72E67A70b5526Fc6b4b0C0fd6D334")
 | 
			
		||||
			} else { false };
 | 
			
		||||
			if !whitelisted {
 | 
			
		||||
				// collect all the addresses which have changed.
 | 
			
		||||
				let addresses = self.cache.borrow().iter().map(|(addr, _)| addr.clone()).collect::<Vec<_>>();
 | 
			
		||||
 | 
			
		||||
@ -239,6 +244,7 @@ impl State {
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO uncomment once to_pod() works correctly.
 | 
			
		||||
//		trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
 | 
			
		||||
 | 
			
		||||
@ -179,6 +179,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
 | 
			
		||||
			db,
 | 
			
		||||
			&last_header,
 | 
			
		||||
			last_hashes.clone(),
 | 
			
		||||
			None,
 | 
			
		||||
			author.clone(),
 | 
			
		||||
			3141562.into(),
 | 
			
		||||
			vec![]
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,8 @@ mod tests {
 | 
			
		||||
					"durationLimit": "0x0d",
 | 
			
		||||
					"blockReward": "0x4563918244F40000",
 | 
			
		||||
					"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
					"frontierCompatibilityModeLimit" : "0x"
 | 
			
		||||
					"frontierCompatibilityModeLimit" : "0x",
 | 
			
		||||
					"daoRescueSoftFork": true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}"#;
 | 
			
		||||
 | 
			
		||||
@ -42,6 +42,9 @@ pub struct EthashParams {
 | 
			
		||||
	/// Homestead transition block number.
 | 
			
		||||
	#[serde(rename="frontierCompatibilityModeLimit")]
 | 
			
		||||
	pub frontier_compatibility_mode_limit: Uint,
 | 
			
		||||
	/// DAO rescue soft-fork?
 | 
			
		||||
	#[serde(rename="daoRescueSoftFork")]
 | 
			
		||||
	pub dao_rescue_soft_fork: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Ethash engine deserialization.
 | 
			
		||||
@ -65,8 +68,9 @@ mod tests {
 | 
			
		||||
				"difficultyBoundDivisor": "0x0800",
 | 
			
		||||
				"durationLimit": "0x0d",
 | 
			
		||||
				"blockReward": "0x4563918244F40000",
 | 
			
		||||
				"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
				"frontierCompatibilityModeLimit" : "0x42"
 | 
			
		||||
				"registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0x42",
 | 
			
		||||
				"daoRescueSoftFork": true
 | 
			
		||||
			}
 | 
			
		||||
		}"#;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -63,7 +63,8 @@ mod tests {
 | 
			
		||||
				"durationLimit": "0x0d",
 | 
			
		||||
				"blockReward": "0x4563918244F40000",
 | 
			
		||||
				"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
				"frontierCompatibilityModeLimit" : "0x"
 | 
			
		||||
				"frontierCompatibilityModeLimit" : "0x",
 | 
			
		||||
				"daoRescueSoftFork": false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,14 @@ Protocol Options:
 | 
			
		||||
                           [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.
 | 
			
		||||
 | 
			
		||||
Account Options:
 | 
			
		||||
  --unlock ACCOUNTS        Unlock ACCOUNTS for the duration of the execution.
 | 
			
		||||
                           ACCOUNTS is a comma-delimited list of addresses.
 | 
			
		||||
@ -230,6 +238,8 @@ 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_unlock: Option<String>,
 | 
			
		||||
	pub flag_password: Vec<String>,
 | 
			
		||||
	pub flag_cache: Option<usize>,
 | 
			
		||||
 | 
			
		||||
@ -75,11 +75,17 @@ impl Configuration {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pub fn gas_floor_target(&self) -> U256 {
 | 
			
		||||
		if self.args.flag_dont_help_rescue_dao || self.args.flag_dogmatic {
 | 
			
		||||
			4_700_000.into()
 | 
			
		||||
		} else {
 | 
			
		||||
			let d = &self.args.flag_gas_floor_target;
 | 
			
		||||
			U256::from_dec_str(d).unwrap_or_else(|_| {
 | 
			
		||||
				die!("{}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number.", d)
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	pub fn gas_price(&self) -> U256 {
 | 
			
		||||
		match self.args.flag_gasprice.as_ref() {
 | 
			
		||||
@ -115,16 +121,20 @@ impl Configuration {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pub fn extra_data(&self) -> Bytes {
 | 
			
		||||
		if !self.args.flag_dont_help_rescue_dao {
 | 
			
		||||
			(b"rescuedao"[..]).to_owned()
 | 
			
		||||
		} else {
 | 
			
		||||
			match self.args.flag_extradata.as_ref().or(self.args.flag_extra_data.as_ref()) {
 | 
			
		||||
				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); }
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pub fn spec(&self) -> Spec {
 | 
			
		||||
		match self.chain().as_str() {
 | 
			
		||||
			"frontier" | "homestead" | "mainnet" => ethereum::new_frontier(),
 | 
			
		||||
			"frontier" | "homestead" | "mainnet" => ethereum::new_frontier(!self.args.flag_dogmatic),
 | 
			
		||||
			"morden" | "testnet" => ethereum::new_morden(),
 | 
			
		||||
			"olympic" => ethereum::new_olympic(),
 | 
			
		||||
			f => Spec::load(contents(f).unwrap_or_else(|_| {
 | 
			
		||||
@ -155,7 +165,6 @@ impl Configuration {
 | 
			
		||||
 | 
			
		||||
	pub fn init_reserved_nodes(&self) -> Vec<String> {
 | 
			
		||||
		use std::fs::File;
 | 
			
		||||
		use std::io::BufRead;
 | 
			
		||||
 | 
			
		||||
		if let Some(ref path) = self.args.flag_reserved_peers {
 | 
			
		||||
			let mut buffer = String::new();
 | 
			
		||||
 | 
			
		||||
@ -150,7 +150,7 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
 | 
			
		||||
				server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
 | 
			
		||||
 | 
			
		||||
				if deps.signer_port.is_some() {
 | 
			
		||||
					server.add_delegate(EthSigningQueueClient::new(&deps.signer_queue, &deps.miner).to_delegate());
 | 
			
		||||
					server.add_delegate(EthSigningQueueClient::new(&deps.signer_queue, &deps.client, &deps.miner).to_delegate());
 | 
			
		||||
				} else {
 | 
			
		||||
					server.add_delegate(EthSigningUnsafeClient::new(&deps.client, &deps.secret_store, &deps.miner).to_delegate());
 | 
			
		||||
				}
 | 
			
		||||
@ -162,7 +162,8 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
 | 
			
		||||
				server.add_delegate(SignerClient::new(&deps.secret_store, &deps.client, &deps.miner, &deps.signer_queue).to_delegate());
 | 
			
		||||
			},
 | 
			
		||||
			Api::Ethcore => {
 | 
			
		||||
				server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate())
 | 
			
		||||
				let queue = deps.signer_port.map(|_| deps.signer_queue.clone());
 | 
			
		||||
				server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone(), queue).to_delegate())
 | 
			
		||||
			},
 | 
			
		||||
			Api::EthcoreSet => {
 | 
			
		||||
				server.add_delegate(EthcoreSetClient::new(&deps.miner, &deps.net_service).to_delegate())
 | 
			
		||||
 | 
			
		||||
@ -69,6 +69,12 @@ pub trait SigningQueue: Send + Sync {
 | 
			
		||||
 | 
			
		||||
	/// Return copy of all the requests in the queue.
 | 
			
		||||
	fn requests(&self) -> Vec<TransactionConfirmation>;
 | 
			
		||||
 | 
			
		||||
	/// Returns number of transactions awaiting confirmation.
 | 
			
		||||
	fn len(&self) -> usize;
 | 
			
		||||
 | 
			
		||||
	/// Returns true if there are no transactions awaiting confirmation.
 | 
			
		||||
	fn is_empty(&self) -> bool;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, PartialEq)]
 | 
			
		||||
@ -277,6 +283,16 @@ impl SigningQueue for  ConfirmationsQueue {
 | 
			
		||||
		let queue = self.queue.read().unwrap();
 | 
			
		||||
		queue.values().map(|token| token.request.clone()).collect()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn len(&self) -> usize {
 | 
			
		||||
		let queue = self.queue.read().unwrap();
 | 
			
		||||
		queue.len()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn is_empty(&self) -> bool {
 | 
			
		||||
		let queue = self.queue.read().unwrap();
 | 
			
		||||
		queue.is_empty()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ use ethcore::filter::Filter as EthcoreFilter;
 | 
			
		||||
use self::ethash::SeedHashCompute;
 | 
			
		||||
use v1::traits::Eth;
 | 
			
		||||
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, OptionalValue, Index, Filter, Log, Receipt};
 | 
			
		||||
use v1::impls::{dispatch_transaction, error_codes};
 | 
			
		||||
use v1::impls::{default_gas_price, dispatch_transaction, error_codes};
 | 
			
		||||
use serde;
 | 
			
		||||
 | 
			
		||||
/// Eth rpc implementation.
 | 
			
		||||
@ -153,23 +153,14 @@ impl<C, S, M, EM> EthClient<C, S, M, EM> where
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn default_gas_price(&self) -> Result<U256, Error> {
 | 
			
		||||
		let miner = take_weak!(self.miner);
 | 
			
		||||
		Ok(take_weak!(self.client)
 | 
			
		||||
			.gas_price_statistics(100, 8)
 | 
			
		||||
			.map(|x| x[4])
 | 
			
		||||
			.unwrap_or_else(|_| miner.sensible_gas_price())
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn sign_call(&self, request: CallRequest) -> Result<SignedTransaction, Error> {
 | 
			
		||||
		let client = take_weak!(self.client);
 | 
			
		||||
		let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
 | 
			
		||||
		let from = request.from.unwrap_or(Address::zero());
 | 
			
		||||
		Ok(EthTransaction {
 | 
			
		||||
			nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)),
 | 
			
		||||
			action: request.to.map_or(Action::Create, Action::Call),
 | 
			
		||||
			gas: request.gas.unwrap_or(U256::from(50_000_000)),
 | 
			
		||||
			gas_price: request.gas_price.unwrap_or_else(|| self.default_gas_price().expect("call only fails if client or miner are unavailable; client and miner are both available to be here; qed")),
 | 
			
		||||
			gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(&*client, &*miner)),
 | 
			
		||||
			value: request.value.unwrap_or_else(U256::zero),
 | 
			
		||||
			data: request.data.map_or_else(Vec::new, |d| d.to_vec())
 | 
			
		||||
		}.fake_sign(from))
 | 
			
		||||
@ -296,7 +287,10 @@ impl<C, S, M, EM> Eth for EthClient<C, S, M, EM> where
 | 
			
		||||
 | 
			
		||||
	fn gas_price(&self, params: Params) -> Result<Value, Error> {
 | 
			
		||||
		match params {
 | 
			
		||||
			Params::None => to_value(&try!(self.default_gas_price())),
 | 
			
		||||
			Params::None => {
 | 
			
		||||
				let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
 | 
			
		||||
				to_value(&default_gas_price(&*client, &*miner))
 | 
			
		||||
			}
 | 
			
		||||
			_ => Err(Error::invalid_params())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -25,38 +25,42 @@ use ethcore::account_provider::AccountProvider;
 | 
			
		||||
use v1::helpers::{SigningQueue, ConfirmationsQueue};
 | 
			
		||||
use v1::traits::EthSigning;
 | 
			
		||||
use v1::types::{TransactionRequest, Bytes};
 | 
			
		||||
use v1::impls::sign_and_dispatch;
 | 
			
		||||
use v1::impls::{default_gas_price, sign_and_dispatch};
 | 
			
		||||
 | 
			
		||||
fn fill_optional_fields<C, M>(request: &mut TransactionRequest, client: &C, miner: &M)
 | 
			
		||||
	where C: MiningBlockChainClient, M: MinerService {
 | 
			
		||||
	if request.gas.is_none() {
 | 
			
		||||
		request.gas = Some(miner.sensible_gas_limit());
 | 
			
		||||
	}
 | 
			
		||||
	if request.gas_price.is_none() {
 | 
			
		||||
		request.gas_price = Some(default_gas_price(client, miner));
 | 
			
		||||
	}
 | 
			
		||||
	if request.data.is_none() {
 | 
			
		||||
		request.data = Some(Bytes::new(Vec::new()));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Implementation of functions that require signing when no trusted signer is used.
 | 
			
		||||
pub struct EthSigningQueueClient<M: MinerService> {
 | 
			
		||||
pub struct EthSigningQueueClient<C, M> where C: MiningBlockChainClient, M: MinerService {
 | 
			
		||||
	queue: Weak<ConfirmationsQueue>,
 | 
			
		||||
	client: Weak<C>,
 | 
			
		||||
	miner: Weak<M>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<M: MinerService> EthSigningQueueClient<M> {
 | 
			
		||||
impl<C, M> EthSigningQueueClient<C, M> where C: MiningBlockChainClient, M: MinerService {
 | 
			
		||||
	/// Creates a new signing queue client given shared signing queue.
 | 
			
		||||
	pub fn new(queue: &Arc<ConfirmationsQueue>, miner: &Arc<M>) -> Self {
 | 
			
		||||
	pub fn new(queue: &Arc<ConfirmationsQueue>, client: &Arc<C>, miner: &Arc<M>) -> Self {
 | 
			
		||||
		EthSigningQueueClient {
 | 
			
		||||
			queue: Arc::downgrade(queue),
 | 
			
		||||
			client: Arc::downgrade(client),
 | 
			
		||||
			miner: Arc::downgrade(miner),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn fill_optional_fields(&self, miner: Arc<M>, mut request: TransactionRequest) -> TransactionRequest {
 | 
			
		||||
		if let None = request.gas {
 | 
			
		||||
			request.gas = Some(miner.sensible_gas_limit());
 | 
			
		||||
		}
 | 
			
		||||
		if let None = request.gas_price {
 | 
			
		||||
			request.gas_price = Some(miner.sensible_gas_price());
 | 
			
		||||
		}
 | 
			
		||||
		if let None = request.data {
 | 
			
		||||
			request.data = Some(Bytes::new(Vec::new()));
 | 
			
		||||
		}
 | 
			
		||||
		request
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<M: MinerService + 'static> EthSigning for EthSigningQueueClient<M>  {
 | 
			
		||||
impl<C, M> EthSigning for EthSigningQueueClient<C, M>
 | 
			
		||||
	where C: MiningBlockChainClient + 'static, M: MinerService + 'static
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	fn sign(&self, _params: Params) -> Result<Value, Error> {
 | 
			
		||||
		warn!("Invoking eth_sign is not yet supported with signer enabled.");
 | 
			
		||||
@ -66,10 +70,11 @@ impl<M: MinerService + 'static> EthSigning for EthSigningQueueClient<M>  {
 | 
			
		||||
 | 
			
		||||
	fn send_transaction(&self, params: Params) -> Result<Value, Error> {
 | 
			
		||||
		from_params::<(TransactionRequest, )>(params)
 | 
			
		||||
			.and_then(|(request, )| {
 | 
			
		||||
			.and_then(|(mut request, )| {
 | 
			
		||||
				let queue = take_weak!(self.queue);
 | 
			
		||||
				let miner = take_weak!(self.miner);
 | 
			
		||||
				let request = self.fill_optional_fields(miner, request);
 | 
			
		||||
				let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
 | 
			
		||||
 | 
			
		||||
				fill_optional_fields(&mut request, &*client, &*miner);
 | 
			
		||||
				let id = queue.add_request(request);
 | 
			
		||||
				let result = id.wait_with_timeout();
 | 
			
		||||
				result.unwrap_or_else(|| to_value(&H256::new()))
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,8 @@ use jsonrpc_core::*;
 | 
			
		||||
use ethcore::miner::MinerService;
 | 
			
		||||
use v1::traits::Ethcore;
 | 
			
		||||
use v1::types::{Bytes};
 | 
			
		||||
use v1::helpers::{SigningQueue, ConfirmationsQueue};
 | 
			
		||||
use v1::impls::error_codes;
 | 
			
		||||
 | 
			
		||||
/// Ethcore implementation.
 | 
			
		||||
pub struct EthcoreClient<C, M> where
 | 
			
		||||
@ -36,16 +38,18 @@ pub struct EthcoreClient<C, M> where
 | 
			
		||||
	miner: Weak<M>,
 | 
			
		||||
	logger: Arc<RotatingLogger>,
 | 
			
		||||
	settings: Arc<NetworkSettings>,
 | 
			
		||||
	confirmations_queue: Option<Arc<ConfirmationsQueue>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C, M> EthcoreClient<C, M> where C: MiningBlockChainClient, M: MinerService {
 | 
			
		||||
	/// Creates new `EthcoreClient`.
 | 
			
		||||
	pub fn new(client: &Arc<C>, miner: &Arc<M>, logger: Arc<RotatingLogger>, settings: Arc<NetworkSettings>) -> Self {
 | 
			
		||||
	pub fn new(client: &Arc<C>, miner: &Arc<M>, logger: Arc<RotatingLogger>, settings: Arc<NetworkSettings>, queue: Option<Arc<ConfirmationsQueue>>) -> Self {
 | 
			
		||||
		EthcoreClient {
 | 
			
		||||
			client: Arc::downgrade(client),
 | 
			
		||||
			miner: Arc::downgrade(miner),
 | 
			
		||||
			logger: logger,
 | 
			
		||||
			settings: settings,
 | 
			
		||||
			confirmations_queue: queue,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -120,4 +124,15 @@ impl<C, M> Ethcore for EthcoreClient<C, M> where M: MinerService + 'static, C: M
 | 
			
		||||
			_ => Err(Error::invalid_params()),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn unsigned_transactions_count(&self, _params: Params) -> Result<Value, Error> {
 | 
			
		||||
		match self.confirmations_queue {
 | 
			
		||||
			None => Err(Error {
 | 
			
		||||
				code: ErrorCode::ServerError(error_codes::SIGNER_DISABLED),
 | 
			
		||||
				message: "Trusted Signer is disabled. This API is not available.".into(),
 | 
			
		||||
				data: None
 | 
			
		||||
			}),
 | 
			
		||||
			Some(ref queue) => to_value(&queue.len()),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -71,6 +71,7 @@ mod error_codes {
 | 
			
		||||
	pub const UNKNOWN_ERROR: i64 = -32002;
 | 
			
		||||
	pub const TRANSACTION_ERROR: i64 = -32010;
 | 
			
		||||
	pub const ACCOUNT_LOCKED: i64 = -32020;
 | 
			
		||||
	pub const SIGNER_DISABLED: i64 = -32030;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<Value, Error>
 | 
			
		||||
@ -99,7 +100,7 @@ fn prepare_transaction<C, M>(client: &C, miner: &M, request: TransactionRequest)
 | 
			
		||||
 | 
			
		||||
		action: request.to.map_or(Action::Create, Action::Call),
 | 
			
		||||
		gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
 | 
			
		||||
		gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
 | 
			
		||||
		gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)),
 | 
			
		||||
		value: request.value.unwrap_or_else(U256::zero),
 | 
			
		||||
		data: request.data.map_or_else(Vec::new, |b| b.to_vec()),
 | 
			
		||||
	}
 | 
			
		||||
@ -133,6 +134,14 @@ fn sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionRequest, a
 | 
			
		||||
	dispatch_transaction(&*client, &*miner, signed_transaction)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn default_gas_price<C, M>(client: &C, miner: &M) -> U256 where C: MiningBlockChainClient, M: MinerService {
 | 
			
		||||
	client
 | 
			
		||||
		.gas_price_statistics(100, 8)
 | 
			
		||||
		.map(|x| x[4])
 | 
			
		||||
		.unwrap_or_else(|_| miner.sensible_gas_price())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
fn signing_error(error: AccountError) -> Error {
 | 
			
		||||
	Error {
 | 
			
		||||
		code: ErrorCode::ServerError(error_codes::ACCOUNT_LOCKED),
 | 
			
		||||
 | 
			
		||||
@ -183,7 +183,8 @@ const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{
 | 
			
		||||
				"durationLimit": "0x0d",
 | 
			
		||||
				"blockReward": "0x4563918244F40000",
 | 
			
		||||
				"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0xffffffffffffffff"
 | 
			
		||||
				"frontierCompatibilityModeLimit": "0xffffffffffffffff",
 | 
			
		||||
				"daoRescueSoftFork": false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@ -115,7 +115,7 @@ impl MinerService for TestMinerService {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Imports transactions to transaction queue.
 | 
			
		||||
	fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, fetch_account: T) ->
 | 
			
		||||
	fn import_transactions<T>(&self, _chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
 | 
			
		||||
		Vec<Result<TransactionImportResult, Error>>
 | 
			
		||||
		where T: Fn(&Address) -> AccountDetails {
 | 
			
		||||
		// lets assume that all txs are valid
 | 
			
		||||
 | 
			
		||||
@ -21,9 +21,11 @@ use v1::traits::EthSigning;
 | 
			
		||||
use v1::helpers::{ConfirmationsQueue, SigningQueue};
 | 
			
		||||
use v1::tests::helpers::TestMinerService;
 | 
			
		||||
use util::{Address, FixedHash};
 | 
			
		||||
use ethcore::client::TestBlockChainClient;
 | 
			
		||||
 | 
			
		||||
struct EthSigningTester {
 | 
			
		||||
	pub queue: Arc<ConfirmationsQueue>,
 | 
			
		||||
	pub client: Arc<TestBlockChainClient>,
 | 
			
		||||
	pub miner: Arc<TestMinerService>,
 | 
			
		||||
	pub io: IoHandler,
 | 
			
		||||
}
 | 
			
		||||
@ -31,12 +33,14 @@ struct EthSigningTester {
 | 
			
		||||
impl Default for EthSigningTester {
 | 
			
		||||
	fn default() -> Self {
 | 
			
		||||
		let queue = Arc::new(ConfirmationsQueue::default());
 | 
			
		||||
		let client = Arc::new(TestBlockChainClient::default());
 | 
			
		||||
		let miner = Arc::new(TestMinerService::default());
 | 
			
		||||
		let io = IoHandler::new();
 | 
			
		||||
		io.add_delegate(EthSigningQueueClient::new(&queue, &miner).to_delegate());
 | 
			
		||||
		io.add_delegate(EthSigningQueueClient::new(&queue, &client, &miner).to_delegate());
 | 
			
		||||
 | 
			
		||||
		EthSigningTester {
 | 
			
		||||
			queue: queue,
 | 
			
		||||
			client: client,
 | 
			
		||||
			miner: miner,
 | 
			
		||||
			io: io,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -15,17 +15,12 @@
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
use std::str::FromStr;
 | 
			
		||||
use jsonrpc_core::IoHandler;
 | 
			
		||||
use v1::{Ethcore, EthcoreClient, EthcoreSet, EthcoreSetClient};
 | 
			
		||||
use ethcore::miner::MinerService;
 | 
			
		||||
use ethcore::service::SyncMessage;
 | 
			
		||||
use v1::{Ethcore, EthcoreClient};
 | 
			
		||||
use v1::tests::helpers::TestMinerService;
 | 
			
		||||
use v1::helpers::ConfirmationsQueue;
 | 
			
		||||
use ethcore::client::{TestBlockChainClient};
 | 
			
		||||
use util::numbers::*;
 | 
			
		||||
use rustc_serialize::hex::FromHex;
 | 
			
		||||
use util::log::RotatingLogger;
 | 
			
		||||
use util::network::{NetworkConfiguration, NetworkService};
 | 
			
		||||
use util::network_settings::NetworkSettings;
 | 
			
		||||
 | 
			
		||||
fn miner_service() -> Arc<TestMinerService> {
 | 
			
		||||
@ -52,26 +47,16 @@ fn settings() -> Arc<NetworkSettings> {
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn network_service() -> Arc<NetworkService<SyncMessage>> {
 | 
			
		||||
	Arc::new(NetworkService::new(NetworkConfiguration::new()).unwrap())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn ethcore_client(client: &Arc<TestBlockChainClient>, miner: &Arc<TestMinerService>) -> EthcoreClient<TestBlockChainClient, TestMinerService> {
 | 
			
		||||
	EthcoreClient::new(client, miner, logger(), settings())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn ethcore_set_client(miner: &Arc<TestMinerService>, net: &Arc<NetworkService<SyncMessage>>) -> EthcoreSetClient<TestMinerService> {
 | 
			
		||||
	EthcoreSetClient::new(miner, net)
 | 
			
		||||
	EthcoreClient::new(client, miner, logger(), settings(), None)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_extra_data() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_extraData", "params": [], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":"0x01020304","id":1}"#;
 | 
			
		||||
@ -86,10 +71,8 @@ fn rpc_ethcore_default_extra_data() {
 | 
			
		||||
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_defaultExtraData", "params": [], "id": 1}"#;
 | 
			
		||||
	let response = format!(r#"{{"jsonrpc":"2.0","result":"0x{}","id":1}}"#, misc::version_data().to_hex());
 | 
			
		||||
@ -101,10 +84,8 @@ fn rpc_ethcore_default_extra_data() {
 | 
			
		||||
fn rpc_ethcore_gas_floor_target() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_gasFloorTarget", "params": [], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":"0x3039","id":1}"#;
 | 
			
		||||
@ -116,10 +97,8 @@ fn rpc_ethcore_gas_floor_target() {
 | 
			
		||||
fn rpc_ethcore_min_gas_price() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_minGasPrice", "params": [], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":"0x01312d00","id":1}"#;
 | 
			
		||||
@ -127,82 +106,16 @@ fn rpc_ethcore_min_gas_price() {
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_set_min_gas_price() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
	assert_eq!(miner.minimal_gas_price(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_set_gas_floor_target() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
	assert_eq!(miner.gas_floor_target(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_set_extra_data() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
	assert_eq!(miner.extra_data(), "cd1722f3947def4cf144679da39c4c32bdc35681".from_hex().unwrap());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_set_author() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
	assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_dev_logs() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let logger = logger();
 | 
			
		||||
	logger.append("a".to_owned());
 | 
			
		||||
	logger.append("b".to_owned());
 | 
			
		||||
	let ethcore = EthcoreClient::new(&client, &miner, logger.clone(), settings()).to_delegate();
 | 
			
		||||
	let ethcore = EthcoreClient::new(&client, &miner, logger.clone(), settings(), None).to_delegate();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore);
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogs", "params":[], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":["b","a"],"id":1}"#;
 | 
			
		||||
@ -214,40 +127,21 @@ fn rpc_ethcore_dev_logs() {
 | 
			
		||||
fn rpc_ethcore_dev_logs_levels() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogsLevels", "params":[], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":"rpc=trace","id":1}"#;
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_set_transactions_limit() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setTransactionsLimit", "params":[10240240], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
	assert_eq!(miner.transactions_limit(), 10_240_240);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_transactions_limit() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_transactionsLimit", "params":[], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":1024,"id":1}"#;
 | 
			
		||||
@ -259,10 +153,8 @@ fn rpc_ethcore_transactions_limit() {
 | 
			
		||||
fn rpc_ethcore_net_chain() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":"testchain","id":1}"#;
 | 
			
		||||
@ -274,10 +166,8 @@ fn rpc_ethcore_net_chain() {
 | 
			
		||||
fn rpc_ethcore_net_max_peers() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netMaxPeers", "params":[], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":25,"id":1}"#;
 | 
			
		||||
@ -289,10 +179,8 @@ fn rpc_ethcore_net_max_peers() {
 | 
			
		||||
fn rpc_ethcore_net_port() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":30303,"id":1}"#;
 | 
			
		||||
@ -304,10 +192,8 @@ fn rpc_ethcore_net_port() {
 | 
			
		||||
fn rpc_ethcore_rpc_settings() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_rpcSettings", "params":[], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":{"enabled":true,"interface":"all","port":8545},"id":1}"#;
 | 
			
		||||
@ -319,13 +205,39 @@ fn rpc_ethcore_rpc_settings() {
 | 
			
		||||
fn rpc_ethcore_node_name() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":"mynode","id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_unsigned_transactions_count() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	let queue = Arc::new(ConfirmationsQueue::default());
 | 
			
		||||
	let ethcore = EthcoreClient::new(&client, &miner, logger(), settings(), Some(queue)).to_delegate();
 | 
			
		||||
	io.add_delegate(ethcore);
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":0,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_unsigned_transactions_count_when_signer_disabled() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let client = client_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_client(&client, &miner).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","error":{"code":-32030,"message":"Trusted Signer is disabled. This API is not available.","data":null},"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										107
									
								
								rpc/src/v1/tests/mocked/ethcore_set.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								rpc/src/v1/tests/mocked/ethcore_set.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,107 @@
 | 
			
		||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
use std::str::FromStr;
 | 
			
		||||
use jsonrpc_core::IoHandler;
 | 
			
		||||
use v1::{EthcoreSet, EthcoreSetClient};
 | 
			
		||||
use ethcore::miner::MinerService;
 | 
			
		||||
use ethcore::service::SyncMessage;
 | 
			
		||||
use v1::tests::helpers::TestMinerService;
 | 
			
		||||
use util::numbers::*;
 | 
			
		||||
use util::network::{NetworkConfiguration, NetworkService};
 | 
			
		||||
use rustc_serialize::hex::FromHex;
 | 
			
		||||
 | 
			
		||||
fn miner_service() -> Arc<TestMinerService> {
 | 
			
		||||
	Arc::new(TestMinerService::default())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn network_service() -> Arc<NetworkService<SyncMessage>> {
 | 
			
		||||
	Arc::new(NetworkService::new(NetworkConfiguration::new()).unwrap())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn ethcore_set_client(miner: &Arc<TestMinerService>, net: &Arc<NetworkService<SyncMessage>>) -> EthcoreSetClient<TestMinerService> {
 | 
			
		||||
	EthcoreSetClient::new(miner, net)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_set_min_gas_price() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
	assert_eq!(miner.minimal_gas_price(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
 | 
			
		||||
}
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_set_gas_floor_target() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
	assert_eq!(miner.gas_floor_target(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_set_extra_data() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
	assert_eq!(miner.extra_data(), "cd1722f3947def4cf144679da39c4c32bdc35681".from_hex().unwrap());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_set_author() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
	assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_ethcore_set_transactions_limit() {
 | 
			
		||||
	let miner = miner_service();
 | 
			
		||||
	let network = network_service();
 | 
			
		||||
	let io = IoHandler::new();
 | 
			
		||||
	io.add_delegate(ethcore_set_client(&miner, &network).to_delegate());
 | 
			
		||||
 | 
			
		||||
	let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setTransactionsLimit", "params":[10240240], "id": 1}"#;
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
 | 
			
		||||
 | 
			
		||||
	assert_eq!(io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
	assert_eq!(miner.transactions_limit(), 10_240_240);
 | 
			
		||||
}
 | 
			
		||||
@ -24,4 +24,5 @@ mod web3;
 | 
			
		||||
mod personal;
 | 
			
		||||
mod personal_signer;
 | 
			
		||||
mod ethcore;
 | 
			
		||||
mod ethcore_set;
 | 
			
		||||
mod rpc;
 | 
			
		||||
 | 
			
		||||
@ -60,6 +60,10 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
 | 
			
		||||
	/// Returns distribution of gas price in latest blocks.
 | 
			
		||||
	fn gas_price_statistics(&self, _: Params) -> Result<Value, Error>;
 | 
			
		||||
 | 
			
		||||
	/// Returns number of unsigned transactions waiting in the signer queue (if signer enabled)
 | 
			
		||||
	/// Returns error when signer is disabled
 | 
			
		||||
	fn unsigned_transactions_count(&self, _: Params) -> Result<Value, Error>;
 | 
			
		||||
 | 
			
		||||
	/// Should be used to convert object to io delegate.
 | 
			
		||||
	fn to_delegate(self) -> IoDelegate<Self> {
 | 
			
		||||
		let mut delegate = IoDelegate::new(Arc::new(self));
 | 
			
		||||
@ -77,6 +81,7 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
 | 
			
		||||
		delegate.add_method("ethcore_nodeName", Ethcore::node_name);
 | 
			
		||||
		delegate.add_method("ethcore_defaultExtraData", Ethcore::default_extra_data);
 | 
			
		||||
		delegate.add_method("ethcore_gasPriceStatistics", Ethcore::gas_price_statistics);
 | 
			
		||||
		delegate.add_method("ethcore_unsignedTransactionsCount", Ethcore::unsigned_transactions_count);
 | 
			
		||||
 | 
			
		||||
		delegate
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -295,6 +295,10 @@ impl BlockCollection {
 | 
			
		||||
		let old_subchains: HashSet<_> = { self.heads.iter().cloned().collect() };
 | 
			
		||||
		for s in self.heads.drain(..) {
 | 
			
		||||
			let mut h = s.clone();
 | 
			
		||||
			if !self.blocks.contains_key(&h) {
 | 
			
		||||
				new_heads.push(h);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			loop {
 | 
			
		||||
				match self.parents.get(&h) {
 | 
			
		||||
					Some(next) => {
 | 
			
		||||
@ -394,7 +398,7 @@ mod test {
 | 
			
		||||
		assert_eq!(&bc.drain()[..], &blocks[6..16]);
 | 
			
		||||
		assert_eq!(hashes[15], bc.heads[0]);
 | 
			
		||||
 | 
			
		||||
		bc.insert_headers(headers[16..].to_vec());
 | 
			
		||||
		bc.insert_headers(headers[15..].to_vec());
 | 
			
		||||
		bc.drain();
 | 
			
		||||
		assert!(bc.is_empty());
 | 
			
		||||
	}
 | 
			
		||||
@ -420,5 +424,24 @@ mod test {
 | 
			
		||||
		assert!(bc.head.is_some());
 | 
			
		||||
		assert_eq!(hashes[21], bc.heads[0]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn insert_headers_no_gap() {
 | 
			
		||||
		let mut bc = BlockCollection::new();
 | 
			
		||||
		assert!(is_empty(&bc));
 | 
			
		||||
		let client = TestBlockChainClient::new();
 | 
			
		||||
		let nblocks = 200;
 | 
			
		||||
		client.add_blocks(nblocks, EachBlockWith::Nothing);
 | 
			
		||||
		let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockID::Number(i as BlockNumber)).unwrap()).collect();
 | 
			
		||||
		let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
 | 
			
		||||
		let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
 | 
			
		||||
		let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();
 | 
			
		||||
		bc.reset_to(heads);
 | 
			
		||||
 | 
			
		||||
		bc.insert_headers(headers[1..2].to_vec());
 | 
			
		||||
		assert!(bc.drain().is_empty());
 | 
			
		||||
		bc.insert_headers(headers[0..1].to_vec());
 | 
			
		||||
		assert_eq!(bc.drain().len(), 2);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -100,6 +100,7 @@ use io::SyncIo;
 | 
			
		||||
use time;
 | 
			
		||||
use super::SyncConfig;
 | 
			
		||||
use blocks::BlockCollection;
 | 
			
		||||
use rand::{thread_rng, Rng};
 | 
			
		||||
 | 
			
		||||
known_heap_size!(0, PeerInfo);
 | 
			
		||||
 | 
			
		||||
@ -308,7 +309,6 @@ impl ChainSync {
 | 
			
		||||
		}
 | 
			
		||||
		self.syncing_difficulty = From::from(0u64);
 | 
			
		||||
		self.state = SyncState::Idle;
 | 
			
		||||
		self.blocks.clear();
 | 
			
		||||
		self.active_peers = self.peers.keys().cloned().collect();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -393,7 +393,7 @@ impl ChainSync {
 | 
			
		||||
		self.clear_peer_download(peer_id);
 | 
			
		||||
		let expected_hash = self.peers.get(&peer_id).and_then(|p| p.asking_hash);
 | 
			
		||||
		let expected_asking = if self.state == SyncState::ChainHead { PeerAsking::Heads } else { PeerAsking::BlockHeaders };
 | 
			
		||||
		if !self.reset_peer_asking(peer_id, expected_asking) {
 | 
			
		||||
		if !self.reset_peer_asking(peer_id, expected_asking) || expected_hash.is_none() {
 | 
			
		||||
			trace!(target: "sync", "Ignored unexpected headers");
 | 
			
		||||
			self.continue_sync(io);
 | 
			
		||||
			return Ok(());
 | 
			
		||||
@ -533,10 +533,6 @@ impl ChainSync {
 | 
			
		||||
		let header_rlp = try!(block_rlp.at(0));
 | 
			
		||||
		let h = header_rlp.as_raw().sha3();
 | 
			
		||||
		trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h);
 | 
			
		||||
		if self.state != SyncState::Idle {
 | 
			
		||||
			trace!(target: "sync", "NewBlock ignored while seeking");
 | 
			
		||||
			return Ok(());
 | 
			
		||||
		}
 | 
			
		||||
		let header: BlockHeader = try!(header_rlp.as_val());
 | 
			
		||||
		let mut unknown = false;
 | 
			
		||||
		{
 | 
			
		||||
@ -544,7 +540,6 @@ impl ChainSync {
 | 
			
		||||
			peer.latest_hash = header.hash();
 | 
			
		||||
			peer.latest_number = Some(header.number());
 | 
			
		||||
		}
 | 
			
		||||
		if header.number <= self.last_imported_block + 1 {
 | 
			
		||||
		match io.chain().import_block(block_rlp.as_raw().to_vec()) {
 | 
			
		||||
			Err(Error::Import(ImportError::AlreadyInChain)) => {
 | 
			
		||||
				trace!(target: "sync", "New block already in chain {:?}", h);
 | 
			
		||||
@ -568,11 +563,10 @@ impl ChainSync {
 | 
			
		||||
				io.disable_peer(peer_id);
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			unknown = true;
 | 
			
		||||
		}
 | 
			
		||||
		if unknown {
 | 
			
		||||
			if self.state != SyncState::Idle {
 | 
			
		||||
				trace!(target: "sync", "NewBlock ignored while seeking");
 | 
			
		||||
			} else {
 | 
			
		||||
				trace!(target: "sync", "New unknown block {:?}", h);
 | 
			
		||||
				//TODO: handle too many unknown blocks
 | 
			
		||||
				let difficulty: U256 = try!(r.val_at(1));
 | 
			
		||||
@ -585,6 +579,7 @@ impl ChainSync {
 | 
			
		||||
				}
 | 
			
		||||
				self.sync_peer(io, peer_id, true);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		Ok(())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -661,7 +656,7 @@ impl ChainSync {
 | 
			
		||||
	/// Resume downloading
 | 
			
		||||
	fn continue_sync(&mut self, io: &mut SyncIo) {
 | 
			
		||||
		let mut peers: Vec<(PeerId, U256)> = self.peers.iter().map(|(k, p)| (*k, p.difficulty.unwrap_or_else(U256::zero))).collect();
 | 
			
		||||
		peers.sort_by(|&(_, d1), &(_, d2)| d1.cmp(&d2).reverse()); //TODO: sort by rating
 | 
			
		||||
		thread_rng().shuffle(&mut peers); //TODO: sort by rating
 | 
			
		||||
		trace!(target: "sync", "Syncing with {}/{} peers", self.active_peers.len(), peers.len());
 | 
			
		||||
		for (p, _) in peers {
 | 
			
		||||
			if self.active_peers.contains(&p) {
 | 
			
		||||
@ -688,6 +683,10 @@ impl ChainSync {
 | 
			
		||||
 | 
			
		||||
	/// Find something to do for a peer. Called for a new peer or when a peer is done with it's task.
 | 
			
		||||
	fn sync_peer(&mut self, io: &mut SyncIo, peer_id: PeerId, force: bool) {
 | 
			
		||||
		if !self.active_peers.contains(&peer_id) {
 | 
			
		||||
			trace!(target: "sync", "Skipping deactivated peer");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		let (peer_latest, peer_difficulty) = {
 | 
			
		||||
			let peer = self.peers.get_mut(&peer_id).unwrap();
 | 
			
		||||
			if peer.asking != PeerAsking::Nothing {
 | 
			
		||||
 | 
			
		||||
@ -44,8 +44,8 @@
 | 
			
		||||
//! 	let mut service = NetworkService::new(NetworkConfiguration::new()).unwrap();
 | 
			
		||||
//! 	service.start().unwrap();
 | 
			
		||||
//! 	let dir = env::temp_dir();
 | 
			
		||||
//! 	let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, Arc::new(Miner::default()), service.io().channel()).unwrap();
 | 
			
		||||
//! 	let miner = Miner::new(false, ethereum::new_frontier());
 | 
			
		||||
//! 	let client = Client::new(ClientConfig::default(), ethereum::new_frontier(true), &dir, Arc::new(Miner::default()), service.io().channel()).unwrap();
 | 
			
		||||
//! 	let miner = Miner::new(false, ethereum::new_frontier(true));
 | 
			
		||||
//! 	let sync = EthSync::new(SyncConfig::default(), client);
 | 
			
		||||
//! 	EthSync::register(&mut service, sync);
 | 
			
		||||
//! }
 | 
			
		||||
 | 
			
		||||
@ -425,12 +425,16 @@ macro_rules! uint_overflowing_mul_reg {
 | 
			
		||||
				let (c_u, overflow_u) = mul_u32(a, b_u, c_l >> 32);
 | 
			
		||||
				ret[i + j] = (c_l & 0xFFFFFFFF) + (c_u << 32);
 | 
			
		||||
 | 
			
		||||
				// Only single overflow possible here
 | 
			
		||||
				let carry = (c_u >> 32) + (overflow_u << 32) + overflow_l + carry2;
 | 
			
		||||
				let (carry, o) = carry.overflowing_add(ret[i + j + 1]);
 | 
			
		||||
				// No overflow here
 | 
			
		||||
				let res = (c_u >> 32) + (overflow_u << 32);
 | 
			
		||||
				// possible overflows
 | 
			
		||||
				let (res, o1) = res.overflowing_add(overflow_l);
 | 
			
		||||
				let (res, o2) = res.overflowing_add(carry2);
 | 
			
		||||
				let (res, o3) = res.overflowing_add(ret[i + j + 1]);
 | 
			
		||||
				ret[i + j + 1] = res;
 | 
			
		||||
 | 
			
		||||
				ret[i + j + 1] = carry;
 | 
			
		||||
				carry2 = o as u64;
 | 
			
		||||
				// Only single overflow possible there
 | 
			
		||||
				carry2 = (o1 | o2 | o3) as u64;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -1305,12 +1309,16 @@ impl U256 {
 | 
			
		||||
				let (c_u, overflow_u) = mul_u32(a, b_u, c_l >> 32);
 | 
			
		||||
				ret[i + j] = (c_l & 0xFFFFFFFF) + (c_u << 32);
 | 
			
		||||
 | 
			
		||||
				// Only single overflow possible here
 | 
			
		||||
				let carry = (c_u >> 32) + (overflow_u << 32) + overflow_l + carry2;
 | 
			
		||||
				let (carry, o) = carry.overflowing_add(ret[i + j + 1]);
 | 
			
		||||
				// No overflow here
 | 
			
		||||
				let res = (c_u >> 32) + (overflow_u << 32);
 | 
			
		||||
				// possible overflows
 | 
			
		||||
				let (res, o1) = res.overflowing_add(overflow_l);
 | 
			
		||||
				let (res, o2) = res.overflowing_add(carry2);
 | 
			
		||||
				let (res, o3) = res.overflowing_add(ret[i + j + 1]);
 | 
			
		||||
				ret[i + j + 1] = res;
 | 
			
		||||
 | 
			
		||||
				ret[i + j + 1] = carry;
 | 
			
		||||
				carry2 = o as u64;
 | 
			
		||||
				// Only single overflow possible there
 | 
			
		||||
				carry2 = (o1 | o2 | o3) as u64;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -109,6 +109,7 @@ impl Database {
 | 
			
		||||
	/// Open database file. Creates if it does not exist.
 | 
			
		||||
	pub fn open(config: &DatabaseConfig, path: &str) -> Result<Database, String> {
 | 
			
		||||
		let mut opts = Options::new();
 | 
			
		||||
		try!(opts.set_parsed_options("rate_limiter_bytes_per_sec=256000000"));
 | 
			
		||||
		opts.set_max_open_files(config.max_open_files);
 | 
			
		||||
		opts.create_if_missing(true);
 | 
			
		||||
		opts.set_use_fsync(false);
 | 
			
		||||
 | 
			
		||||
@ -191,7 +191,7 @@ pub struct NetworkContext<'s, Message> where Message: Send + Sync + Clone + 'sta
 | 
			
		||||
	sessions: Arc<RwLock<Slab<SharedSession>>>,
 | 
			
		||||
	session: Option<SharedSession>,
 | 
			
		||||
	session_id: Option<StreamToken>,
 | 
			
		||||
	reserved_peers: &'s HashSet<NodeId>,
 | 
			
		||||
	_reserved_peers: &'s HashSet<NodeId>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone + 'static, {
 | 
			
		||||
@ -207,7 +207,7 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone
 | 
			
		||||
			session_id: id,
 | 
			
		||||
			session: session,
 | 
			
		||||
			sessions: sessions,
 | 
			
		||||
			reserved_peers: reserved_peers,
 | 
			
		||||
			_reserved_peers: reserved_peers,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -837,9 +837,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
 | 
			
		||||
				let mut s = session.lock().unwrap();
 | 
			
		||||
				if !s.expired() {
 | 
			
		||||
					if s.is_ready() {
 | 
			
		||||
						self.num_sessions.fetch_sub(1, AtomicOrdering::SeqCst);
 | 
			
		||||
						for (p, _) in self.handlers.read().unwrap().iter() {
 | 
			
		||||
							if s.have_capability(p)  {
 | 
			
		||||
								self.num_sessions.fetch_sub(1, AtomicOrdering::SeqCst);
 | 
			
		||||
								to_disconnect.push(p);
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user