Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f2cabd6e3 | ||
|
|
65e4bad3dd | ||
|
|
a554b81f32 | ||
|
|
06be7271aa | ||
|
|
33a553726a | ||
|
|
fdc781dbfd | ||
|
|
2c95ee60b9 | ||
|
|
ac8533a56c | ||
|
|
8f75042fee | ||
|
|
3f7ac5c64b | ||
|
|
e23753eabd | ||
|
|
9f41af5077 | ||
|
|
28019a472a | ||
|
|
8116ad995d | ||
|
|
6a564f3334 | ||
|
|
2d7aecf5d9 | ||
|
|
2f066535cb | ||
|
|
e734ca4bf1 | ||
|
|
6f2ec07baa | ||
|
|
7ef4bbd5f7 | ||
|
|
96e60d9c91 | ||
|
|
ac02d12fa8 | ||
|
|
e7102d9f38 | ||
|
|
cabf626c61 | ||
|
|
91be3a4fc3 | ||
|
|
b9979137b7 | ||
|
|
4becd27029 | ||
|
|
54536dfa1b | ||
|
|
c4a58efed4 | ||
|
|
1f4d6fced3 |
@@ -77,8 +77,10 @@ linux-snap:
|
|||||||
- echo "Version:"$VER
|
- echo "Version:"$VER
|
||||||
- snapcraft
|
- snapcraft
|
||||||
- ls
|
- ls
|
||||||
- cp "parity_"$CI_BUILD"_REF_NAME_amd64.snap" "parity_"$VER"_amd64.snap"
|
#- cp "parity_"$CI_BUILD"_amd64.snap" "parity_"$VER"_amd64.snap"
|
||||||
- md5sum "parity_"$VER"_amd64.snap" > "parity_"$VER"_amd64.snap.md5"
|
- md5sum "parity_"$VER"_amd64.snap" > "parity_"$VER"_amd64.snap.md5"
|
||||||
|
- file "parity_"$VER"_amd64.snap.md5"
|
||||||
|
- cat "parity_"$VER"_amd64.snap.md5"
|
||||||
- aws configure set aws_access_key_id $s3_key
|
- aws configure set aws_access_key_id $s3_key
|
||||||
- aws configure set aws_secret_access_key $s3_secret
|
- aws configure set aws_secret_access_key $s3_secret
|
||||||
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi
|
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi
|
||||||
@@ -561,11 +563,9 @@ docker-build:
|
|||||||
- docker info
|
- docker info
|
||||||
script:
|
script:
|
||||||
- if [ "$CI_BUILD_REF_NAME" == "beta-release" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi
|
- if [ "$CI_BUILD_REF_NAME" == "beta-release" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi
|
||||||
- docker login -u $Docker_Hub_User -p $Docker_Hub_Pass
|
- echo "Tag:" $DOCKER_TAG
|
||||||
- sh scripts/docker-build.sh $DOCKER_TAG ethcore
|
|
||||||
- docker logout
|
|
||||||
- docker login -u $Docker_Hub_User_Parity -p $Docker_Hub_Pass_Parity
|
- docker login -u $Docker_Hub_User_Parity -p $Docker_Hub_Pass_Parity
|
||||||
- sh scripts/docker-build.sh $DOCKER_TAG parity
|
- sh scripts/docker-build.sh $DOCKER_TAG
|
||||||
- docker logout
|
- docker logout
|
||||||
tags:
|
tags:
|
||||||
- docker
|
- docker
|
||||||
|
|||||||
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -1950,7 +1950,7 @@ name = "parity-ui"
|
|||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-ui-dev 1.7.0",
|
"parity-ui-dev 1.7.0",
|
||||||
"parity-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git)",
|
"parity-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git?branch=beta)",
|
||||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1964,7 +1964,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-ui-precompiled"
|
name = "parity-ui-precompiled"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "git+https://github.com/paritytech/js-precompiled.git#b49a1d46cc6c545403d18579ef7ae9f9d14eea7e"
|
source = "git+https://github.com/paritytech/js-precompiled.git?branch=beta#917d53323bb0a5c1aeeeea651695897be854a239"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@@ -3200,7 +3200,7 @@ dependencies = [
|
|||||||
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||||
"checksum parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1d06f6ee0fda786df3784a96ee3f0629f529b91cbfb7d142f6410e6bcd1ce2c"
|
"checksum parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1d06f6ee0fda786df3784a96ee3f0629f529b91cbfb7d142f6410e6bcd1ce2c"
|
||||||
"checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "<none>"
|
"checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "<none>"
|
||||||
"checksum parity-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git)" = "<none>"
|
"checksum parity-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git?branch=beta)" = "<none>"
|
||||||
"checksum parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51104c8b8da5cd0ebe0ab765dfab37bc1927b4a01a3d870b0fe09d9ee65e35ea"
|
"checksum parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51104c8b8da5cd0ebe0ab765dfab37bc1927b4a01a3d870b0fe09d9ee65e35ea"
|
||||||
"checksum parity-wordlist 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "52142d717754f7ff7ef0fc8da1bdce4f302dd576fb9bf8b727d6a5fdef33348d"
|
"checksum parity-wordlist 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "52142d717754f7ff7ef0fc8da1bdce4f302dd576fb9bf8b727d6a5fdef33348d"
|
||||||
"checksum parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aebb68eebde2c99f89592d925288600fde220177e46b5c9a91ca218d245aeedf"
|
"checksum parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aebb68eebde2c99f89592d925288600fde220177e46b5c9a91ca218d245aeedf"
|
||||||
|
|||||||
@@ -100,6 +100,10 @@ impl SimpleNtp {
|
|||||||
impl Ntp for SimpleNtp {
|
impl Ntp for SimpleNtp {
|
||||||
fn drift(&self) -> BoxFuture<Duration, Error> {
|
fn drift(&self) -> BoxFuture<Duration, Error> {
|
||||||
let address = self.address.clone();
|
let address = self.address.clone();
|
||||||
|
if &*address == "none" {
|
||||||
|
return futures::future::err(Error::Ntp("NTP server is not provided.".into())).boxed();
|
||||||
|
}
|
||||||
|
|
||||||
self.pool.spawn_fn(move || {
|
self.pool.spawn_fn(move || {
|
||||||
let packet = ntp::request(&*address)?;
|
let packet = ntp::request(&*address)?;
|
||||||
let dest_time = ::time::now_utc().to_timespec();
|
let dest_time = ::time::now_utc().to_timespec();
|
||||||
@@ -114,7 +118,9 @@ impl Ntp for SimpleNtp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_RESULTS: usize = 4;
|
// NOTE In a positive scenario first results will be seen after:
|
||||||
|
// MAX_RESULTS * UPDATE_TIMEOUT_OK_SECS seconds.
|
||||||
|
const MAX_RESULTS: usize = 7;
|
||||||
const UPDATE_TIMEOUT_OK_SECS: u64 = 30;
|
const UPDATE_TIMEOUT_OK_SECS: u64 = 30;
|
||||||
const UPDATE_TIMEOUT_ERR_SECS: u64 = 2;
|
const UPDATE_TIMEOUT_ERR_SECS: u64 = 2;
|
||||||
|
|
||||||
@@ -225,7 +231,7 @@ mod tests {
|
|||||||
|
|
||||||
fn time_checker() -> TimeChecker<FakeNtp> {
|
fn time_checker() -> TimeChecker<FakeNtp> {
|
||||||
let last_result = Arc::new(RwLock::new(
|
let last_result = Arc::new(RwLock::new(
|
||||||
(Instant::now(), vec![Err(Error::Ntp("NTP server unavailable.".into()))].into())
|
(Instant::now(), vec![Err(Error::Ntp("NTP server unavailable".into()))].into())
|
||||||
));
|
));
|
||||||
|
|
||||||
TimeChecker {
|
TimeChecker {
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
|
|||||||
b"font-src 'self' data: https:;".to_vec(),
|
b"font-src 'self' data: https:;".to_vec(),
|
||||||
// Allow inline scripts and scripts eval (webpack/jsconsole)
|
// Allow inline scripts and scripts eval (webpack/jsconsole)
|
||||||
b"script-src 'self' 'unsafe-inline' 'unsafe-eval';".to_vec(),
|
b"script-src 'self' 'unsafe-inline' 'unsafe-eval';".to_vec(),
|
||||||
|
// Same restrictions as script-src (fallback) with additional
|
||||||
|
// blob: that is required for camera access (worker)
|
||||||
|
b"worker-src 'self' 'unsafe-inline' 'unsafe-eval' blob: ;".to_vec(),
|
||||||
// Restrict everything else to the same origin.
|
// Restrict everything else to the same origin.
|
||||||
b"default-src 'self';".to_vec(),
|
b"default-src 'self';".to_vec(),
|
||||||
// Run in sandbox mode (although it's not fully safe since we allow same-origin and script)
|
// Run in sandbox mode (although it's not fully safe since we allow same-origin and script)
|
||||||
@@ -140,4 +143,3 @@ pub fn convert_uri_to_url(uri: &uri::RequestUri, host: Option<&header::Host>) ->
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ rustc_version = "0.1"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
parity-ui-dev = { path = "../../js", optional = true }
|
parity-ui-dev = { path = "../../js", optional = true }
|
||||||
# This is managed by the js/scripts/release.sh script on CI - keep it in a single line
|
# This is managed by the js/scripts/release.sh script on CI - keep it in a single line
|
||||||
parity-ui-precompiled = { git = "https://github.com/paritytech/js-precompiled.git", optional = true, branch = "master" }
|
parity-ui-precompiled = { git = "https://github.com/paritytech/js-precompiled.git", optional = true, branch = "beta" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
no-precompiled-js = ["parity-ui-dev"]
|
no-precompiled-js = ["parity-ui-dev"]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ WORKDIR /build
|
|||||||
#ENV for build TAG
|
#ENV for build TAG
|
||||||
ARG BUILD_TAG
|
ARG BUILD_TAG
|
||||||
ENV BUILD_TAG ${BUILD_TAG:-master}
|
ENV BUILD_TAG ${BUILD_TAG:-master}
|
||||||
RUN echo $BUILD_TAG
|
RUN echo "Build tag:" $BUILD_TAG
|
||||||
# install tools and dependencies
|
# install tools and dependencies
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --force-yes --no-install-recommends \
|
apt-get install -y --force-yes --no-install-recommends \
|
||||||
@@ -48,7 +48,7 @@ RUN apt-get update && \
|
|||||||
# show backtraces
|
# show backtraces
|
||||||
RUST_BACKTRACE=1 && \
|
RUST_BACKTRACE=1 && \
|
||||||
# build parity
|
# build parity
|
||||||
cd /build&&git clone https://github.com/paritytech/parity && \
|
cd /build&&git clone https://github.com/paritytech/parity && \
|
||||||
cd parity && \
|
cd parity && \
|
||||||
git pull&& \
|
git pull&& \
|
||||||
git checkout $BUILD_TAG && \
|
git checkout $BUILD_TAG && \
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
|
if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
|
||||||
(instruction == instructions::CREATE2 && !schedule.have_create2) ||
|
(instruction == instructions::CREATE2 && !schedule.have_create2) ||
|
||||||
(instruction == instructions::STATICCALL && !schedule.have_static_call) ||
|
(instruction == instructions::STATICCALL && !schedule.have_static_call) ||
|
||||||
|
((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) ||
|
||||||
(instruction == instructions::REVERT && !schedule.have_revert) {
|
(instruction == instructions::REVERT && !schedule.have_revert) {
|
||||||
|
|
||||||
return Err(evm::Error::BadInstruction {
|
return Err(evm::Error::BadInstruction {
|
||||||
|
|||||||
@@ -107,6 +107,8 @@ pub struct Schedule {
|
|||||||
pub blockhash_gas: usize,
|
pub blockhash_gas: usize,
|
||||||
/// Static Call opcode enabled.
|
/// Static Call opcode enabled.
|
||||||
pub have_static_call: bool,
|
pub have_static_call: bool,
|
||||||
|
/// RETURNDATA and RETURNDATASIZE opcodes enabled.
|
||||||
|
pub have_return_data: bool,
|
||||||
/// Kill basic accounts below this balance if touched.
|
/// Kill basic accounts below this balance if touched.
|
||||||
pub kill_dust: CleanDustMode,
|
pub kill_dust: CleanDustMode,
|
||||||
}
|
}
|
||||||
@@ -140,6 +142,7 @@ impl Schedule {
|
|||||||
have_delegate_call: true,
|
have_delegate_call: true,
|
||||||
have_create2: false,
|
have_create2: false,
|
||||||
have_revert: false,
|
have_revert: false,
|
||||||
|
have_return_data: false,
|
||||||
stack_limit: 1024,
|
stack_limit: 1024,
|
||||||
max_depth: 1024,
|
max_depth: 1024,
|
||||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||||
@@ -190,6 +193,7 @@ impl Schedule {
|
|||||||
schedule.have_create2 = true;
|
schedule.have_create2 = true;
|
||||||
schedule.have_revert = true;
|
schedule.have_revert = true;
|
||||||
schedule.have_static_call = true;
|
schedule.have_static_call = true;
|
||||||
|
schedule.have_return_data = true;
|
||||||
schedule.blockhash_gas = 350;
|
schedule.blockhash_gas = 350;
|
||||||
schedule
|
schedule
|
||||||
}
|
}
|
||||||
@@ -200,6 +204,7 @@ impl Schedule {
|
|||||||
have_delegate_call: hdc,
|
have_delegate_call: hdc,
|
||||||
have_create2: false,
|
have_create2: false,
|
||||||
have_revert: false,
|
have_revert: false,
|
||||||
|
have_return_data: false,
|
||||||
stack_limit: 1024,
|
stack_limit: 1024,
|
||||||
max_depth: 1024,
|
max_depth: 1024,
|
||||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||||
|
|||||||
@@ -405,6 +405,7 @@ impl HeaderChain {
|
|||||||
|
|
||||||
match id {
|
match id {
|
||||||
BlockId::Earliest | BlockId::Number(0) => Some(self.genesis_header.clone()),
|
BlockId::Earliest | BlockId::Number(0) => Some(self.genesis_header.clone()),
|
||||||
|
BlockId::Hash(hash) if hash == self.genesis_hash() => { Some(self.genesis_header.clone()) }
|
||||||
BlockId::Hash(hash) => load_from_db(hash),
|
BlockId::Hash(hash) => load_from_db(hash),
|
||||||
BlockId::Number(num) => {
|
BlockId::Number(num) => {
|
||||||
if self.best_block.read().number < num { return None }
|
if self.best_block.read().number < num { return None }
|
||||||
@@ -781,4 +782,18 @@ mod tests {
|
|||||||
assert_eq!(chain.block_header(BlockId::Latest).unwrap().number(), 10);
|
assert_eq!(chain.block_header(BlockId::Latest).unwrap().number(), 10);
|
||||||
assert!(chain.candidates.read().get(&100).is_some())
|
assert!(chain.candidates.read().get(&100).is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn genesis_header_available() {
|
||||||
|
let spec = Spec::new_test();
|
||||||
|
let genesis_header = spec.genesis_header();
|
||||||
|
let db = make_db();
|
||||||
|
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
|
||||||
|
|
||||||
|
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache.clone()).unwrap();
|
||||||
|
|
||||||
|
assert!(chain.block_header(BlockId::Earliest).is_some());
|
||||||
|
assert!(chain.block_header(BlockId::Number(0)).is_some());
|
||||||
|
assert!(chain.block_header(BlockId::Hash(genesis_header.hash())).is_some());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ pub struct Config {
|
|||||||
pub db_wal: bool,
|
pub db_wal: bool,
|
||||||
/// Should it do full verification of blocks?
|
/// Should it do full verification of blocks?
|
||||||
pub verify_full: bool,
|
pub verify_full: bool,
|
||||||
|
/// Should it check the seal of blocks?
|
||||||
|
pub check_seal: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@@ -69,6 +71,7 @@ impl Default for Config {
|
|||||||
db_compaction: CompactionProfile::default(),
|
db_compaction: CompactionProfile::default(),
|
||||||
db_wal: true,
|
db_wal: true,
|
||||||
verify_full: true,
|
verify_full: true,
|
||||||
|
check_seal: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +171,7 @@ impl Client {
|
|||||||
let gh = ::rlp::encode(&spec.genesis_header());
|
let gh = ::rlp::encode(&spec.genesis_header());
|
||||||
|
|
||||||
Ok(Client {
|
Ok(Client {
|
||||||
queue: HeaderQueue::new(config.queue, spec.engine.clone(), io_channel, true),
|
queue: HeaderQueue::new(config.queue, spec.engine.clone(), io_channel, config.check_seal),
|
||||||
engine: spec.engine.clone(),
|
engine: spec.engine.clone(),
|
||||||
chain: HeaderChain::new(db.clone(), chain_col, &gh, cache)?,
|
chain: HeaderChain::new(db.clone(), chain_col, &gh, cache)?,
|
||||||
report: RwLock::new(ClientReport::default()),
|
report: RwLock::new(ClientReport::default()),
|
||||||
@@ -282,6 +285,7 @@ impl Client {
|
|||||||
let mut good = Vec::new();
|
let mut good = Vec::new();
|
||||||
for verified_header in self.queue.drain(MAX) {
|
for verified_header in self.queue.drain(MAX) {
|
||||||
let (num, hash) = (verified_header.number(), verified_header.hash());
|
let (num, hash) = (verified_header.number(), verified_header.hash());
|
||||||
|
trace!(target: "client", "importing block {}", num);
|
||||||
|
|
||||||
if self.verify_full && !self.check_header(&mut bad, &verified_header) {
|
if self.verify_full && !self.check_header(&mut bad, &verified_header) {
|
||||||
continue
|
continue
|
||||||
@@ -381,13 +385,17 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return true if should skip, false otherwise. may push onto bad if
|
// return false if should skip, true otherwise. may push onto bad if
|
||||||
// should skip.
|
// should skip.
|
||||||
fn check_header(&self, bad: &mut Vec<H256>, verified_header: &Header) -> bool {
|
fn check_header(&self, bad: &mut Vec<H256>, verified_header: &Header) -> bool {
|
||||||
let hash = verified_header.hash();
|
let hash = verified_header.hash();
|
||||||
let parent_header = match self.chain.block_header(BlockId::Hash(*verified_header.parent_hash())) {
|
let parent_header = match self.chain.block_header(BlockId::Hash(*verified_header.parent_hash())) {
|
||||||
Some(header) => header,
|
Some(header) => header,
|
||||||
None => return false, // skip import of block with missing parent.
|
None => {
|
||||||
|
trace!(target: "client", "No parent for block ({}, {})",
|
||||||
|
verified_header.number(), hash);
|
||||||
|
return false // skip import of block with missing parent.
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Verify Block Family
|
// Verify Block Family
|
||||||
|
|||||||
@@ -806,6 +806,9 @@ impl LightProtocol {
|
|||||||
trace!(target: "pip", "Connected peer with chain head {:?}", (status.head_hash, status.head_num));
|
trace!(target: "pip", "Connected peer with chain head {:?}", (status.head_hash, status.head_num));
|
||||||
|
|
||||||
if (status.network_id, status.genesis_hash) != (self.network_id, self.genesis_hash) {
|
if (status.network_id, status.genesis_hash) != (self.network_id, self.genesis_hash) {
|
||||||
|
trace!(target: "pip", "peer {} wrong network: network_id is {} vs our {}, gh is {} vs our {}",
|
||||||
|
peer, status.network_id, self.network_id, status.genesis_hash, self.genesis_hash);
|
||||||
|
|
||||||
return Err(Error::WrongNetwork);
|
return Err(Error::WrongNetwork);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,13 +54,21 @@ struct Peer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Peer {
|
impl Peer {
|
||||||
// whether this peer can fulfill the
|
// whether this peer can fulfill the necessary capabilities for the given
|
||||||
fn can_fulfill(&self, c: &Capabilities) -> bool {
|
// request.
|
||||||
let caps = &self.capabilities;
|
fn can_fulfill(&self, request: &Capabilities) -> bool {
|
||||||
|
let local_caps = &self.capabilities;
|
||||||
|
let can_serve_since = |req, local| {
|
||||||
|
match (req, local) {
|
||||||
|
(Some(request_block), Some(serve_since)) => request_block >= serve_since,
|
||||||
|
(Some(_), None) => false,
|
||||||
|
(None, _) => true,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
caps.serve_headers == c.serve_headers &&
|
local_caps.serve_headers >= request.serve_headers &&
|
||||||
caps.serve_chain_since >= c.serve_chain_since &&
|
can_serve_since(request.serve_chain_since, local_caps.serve_chain_since) &&
|
||||||
caps.serve_state_since >= c.serve_chain_since
|
can_serve_since(request.serve_state_since, local_caps.serve_state_since)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +252,7 @@ impl OnDemand {
|
|||||||
peers: RwLock::new(HashMap::new()),
|
peers: RwLock::new(HashMap::new()),
|
||||||
in_transit: RwLock::new(HashMap::new()),
|
in_transit: RwLock::new(HashMap::new()),
|
||||||
cache: cache,
|
cache: cache,
|
||||||
no_immediate_dispatch: true,
|
no_immediate_dispatch: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +274,6 @@ impl OnDemand {
|
|||||||
-> Result<Receiver<Vec<Response>>, basic_request::NoSuchOutput>
|
-> Result<Receiver<Vec<Response>>, basic_request::NoSuchOutput>
|
||||||
{
|
{
|
||||||
let (sender, receiver) = oneshot::channel();
|
let (sender, receiver) = oneshot::channel();
|
||||||
|
|
||||||
if requests.is_empty() {
|
if requests.is_empty() {
|
||||||
assert!(sender.send(Vec::new()).is_ok(), "receiver still in scope; qed");
|
assert!(sender.send(Vec::new()).is_ok(), "receiver still in scope; qed");
|
||||||
return Ok(receiver);
|
return Ok(receiver);
|
||||||
@@ -335,6 +342,7 @@ impl OnDemand {
|
|||||||
// dispatch pending requests, and discard those for which the corresponding
|
// dispatch pending requests, and discard those for which the corresponding
|
||||||
// receiver has been dropped.
|
// receiver has been dropped.
|
||||||
fn dispatch_pending(&self, ctx: &BasicContext) {
|
fn dispatch_pending(&self, ctx: &BasicContext) {
|
||||||
|
|
||||||
// wrapper future for calling `poll_cancel` on our `Senders` to preserve
|
// wrapper future for calling `poll_cancel` on our `Senders` to preserve
|
||||||
// the invariant that it's always within a task.
|
// the invariant that it's always within a task.
|
||||||
struct CheckHangup<'a, T: 'a>(&'a mut Sender<T>);
|
struct CheckHangup<'a, T: 'a>(&'a mut Sender<T>);
|
||||||
@@ -360,6 +368,8 @@ impl OnDemand {
|
|||||||
if self.pending.read().is_empty() { return }
|
if self.pending.read().is_empty() { return }
|
||||||
let mut pending = self.pending.write();
|
let mut pending = self.pending.write();
|
||||||
|
|
||||||
|
debug!(target: "on_demand", "Attempting to dispatch {} pending requests", pending.len());
|
||||||
|
|
||||||
// iterate over all pending requests, and check them for hang-up.
|
// iterate over all pending requests, and check them for hang-up.
|
||||||
// then, try and find a peer who can serve it.
|
// then, try and find a peer who can serve it.
|
||||||
let peers = self.peers.read();
|
let peers = self.peers.read();
|
||||||
@@ -378,16 +388,21 @@ impl OnDemand {
|
|||||||
|
|
||||||
match ctx.request_from(*peer_id, pending.net_requests.clone()) {
|
match ctx.request_from(*peer_id, pending.net_requests.clone()) {
|
||||||
Ok(req_id) => {
|
Ok(req_id) => {
|
||||||
|
trace!(target: "on_demand", "Dispatched request {} to peer {}", req_id, peer_id);
|
||||||
self.in_transit.write().insert(req_id, pending);
|
self.in_transit.write().insert(req_id, pending);
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
Err(net::Error::NoCredits) => {}
|
Err(net::Error::NoCredits) | Err(net::Error::NotServer) => {}
|
||||||
Err(e) => debug!(target: "on_demand", "Error dispatching request to peer: {}", e),
|
Err(e) => debug!(target: "on_demand", "Error dispatching request to peer: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: maximum number of failures _when we have peers_.
|
||||||
Some(pending)
|
Some(pending)
|
||||||
})
|
})
|
||||||
.collect(); // `pending` now contains all requests we couldn't dispatch.
|
.collect(); // `pending` now contains all requests we couldn't dispatch.
|
||||||
|
|
||||||
|
debug!(target: "on_demand", "Was unable to dispatch {} requests.", pending.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
// submit a pending request set. attempts to answer from cache before
|
// submit a pending request set. attempts to answer from cache before
|
||||||
@@ -395,6 +410,7 @@ impl OnDemand {
|
|||||||
fn submit_pending(&self, ctx: &BasicContext, mut pending: Pending) {
|
fn submit_pending(&self, ctx: &BasicContext, mut pending: Pending) {
|
||||||
// answer as many requests from cache as we can, and schedule for dispatch
|
// answer as many requests from cache as we can, and schedule for dispatch
|
||||||
// if incomplete.
|
// if incomplete.
|
||||||
|
|
||||||
pending.answer_from_cache(&*self.cache);
|
pending.answer_from_cache(&*self.cache);
|
||||||
if let Some(mut pending) = pending.try_complete() {
|
if let Some(mut pending) = pending.try_complete() {
|
||||||
pending.update_net_requests();
|
pending.update_net_requests();
|
||||||
|
|||||||
Submodule ethcore/res/ethereum/tests updated: 4e8b9be3fb...ef191fdc61
@@ -46,6 +46,9 @@ struct Guard(bool, PathBuf);
|
|||||||
impl Guard {
|
impl Guard {
|
||||||
fn new(path: PathBuf) -> Self { Guard(true, path) }
|
fn new(path: PathBuf) -> Self { Guard(true, path) }
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn benign() -> Self { Guard(false, PathBuf::default()) }
|
||||||
|
|
||||||
fn disarm(mut self) { self.0 = false }
|
fn disarm(mut self) { self.0 = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +126,7 @@ impl Restoration {
|
|||||||
|
|
||||||
// feeds a state chunk, aborts early if `flag` becomes false.
|
// feeds a state chunk, aborts early if `flag` becomes false.
|
||||||
fn feed_state(&mut self, hash: H256, chunk: &[u8], flag: &AtomicBool) -> Result<(), Error> {
|
fn feed_state(&mut self, hash: H256, chunk: &[u8], flag: &AtomicBool) -> Result<(), Error> {
|
||||||
if self.state_chunks_left.remove(&hash) {
|
if self.state_chunks_left.contains(&hash) {
|
||||||
let len = snappy::decompress_into(chunk, &mut self.snappy_buffer)?;
|
let len = snappy::decompress_into(chunk, &mut self.snappy_buffer)?;
|
||||||
|
|
||||||
self.state.feed(&self.snappy_buffer[..len], flag)?;
|
self.state.feed(&self.snappy_buffer[..len], flag)?;
|
||||||
@@ -131,6 +134,8 @@ impl Restoration {
|
|||||||
if let Some(ref mut writer) = self.writer.as_mut() {
|
if let Some(ref mut writer) = self.writer.as_mut() {
|
||||||
writer.write_state_chunk(hash, chunk)?;
|
writer.write_state_chunk(hash, chunk)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.state_chunks_left.remove(&hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -138,13 +143,15 @@ impl Restoration {
|
|||||||
|
|
||||||
// feeds a block chunk
|
// feeds a block chunk
|
||||||
fn feed_blocks(&mut self, hash: H256, chunk: &[u8], engine: &Engine, flag: &AtomicBool) -> Result<(), Error> {
|
fn feed_blocks(&mut self, hash: H256, chunk: &[u8], engine: &Engine, flag: &AtomicBool) -> Result<(), Error> {
|
||||||
if self.block_chunks_left.remove(&hash) {
|
if self.block_chunks_left.contains(&hash) {
|
||||||
let len = snappy::decompress_into(chunk, &mut self.snappy_buffer)?;
|
let len = snappy::decompress_into(chunk, &mut self.snappy_buffer)?;
|
||||||
|
|
||||||
self.secondary.feed(&self.snappy_buffer[..len], engine, flag)?;
|
self.secondary.feed(&self.snappy_buffer[..len], engine, flag)?;
|
||||||
if let Some(ref mut writer) = self.writer.as_mut() {
|
if let Some(ref mut writer) = self.writer.as_mut() {
|
||||||
writer.write_block_chunk(hash, chunk)?;
|
writer.write_block_chunk(hash, chunk)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.block_chunks_left.remove(&hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -558,9 +565,9 @@ impl SnapshotService for Service {
|
|||||||
self.reader.read().as_ref().map(|r| r.manifest().clone())
|
self.reader.read().as_ref().map(|r| r.manifest().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn min_supported_version(&self) -> Option<u64> {
|
fn supported_versions(&self) -> Option<(u64, u64)> {
|
||||||
self.engine.snapshot_components()
|
self.engine.snapshot_components()
|
||||||
.map(|c| c.min_supported_version())
|
.map(|c| (c.min_supported_version(), c.current_version()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chunk(&self, hash: H256) -> Option<Bytes> {
|
fn chunk(&self, hash: H256) -> Option<Bytes> {
|
||||||
@@ -668,4 +675,50 @@ mod tests {
|
|||||||
service.restore_state_chunk(Default::default(), vec![]);
|
service.restore_state_chunk(Default::default(), vec![]);
|
||||||
service.restore_block_chunk(Default::default(), vec![]);
|
service.restore_block_chunk(Default::default(), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cannot_finish_with_invalid_chunks() {
|
||||||
|
use util::H256;
|
||||||
|
use util::kvdb::DatabaseConfig;
|
||||||
|
|
||||||
|
let spec = get_test_spec();
|
||||||
|
let dir = RandomTempPath::new();
|
||||||
|
|
||||||
|
let state_hashes: Vec<_> = (0..5).map(|_| H256::random()).collect();
|
||||||
|
let block_hashes: Vec<_> = (0..5).map(|_| H256::random()).collect();
|
||||||
|
let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
|
||||||
|
let gb = spec.genesis_block();
|
||||||
|
let flag = ::std::sync::atomic::AtomicBool::new(true);
|
||||||
|
|
||||||
|
let params = RestorationParams {
|
||||||
|
manifest: ManifestData {
|
||||||
|
version: 2,
|
||||||
|
state_hashes: state_hashes.clone(),
|
||||||
|
block_hashes: block_hashes.clone(),
|
||||||
|
state_root: H256::default(),
|
||||||
|
block_number: 100000,
|
||||||
|
block_hash: H256::default(),
|
||||||
|
},
|
||||||
|
pruning: Algorithm::Archive,
|
||||||
|
db_path: dir.as_path().to_owned(),
|
||||||
|
db_config: &db_config,
|
||||||
|
writer: None,
|
||||||
|
genesis: &gb,
|
||||||
|
guard: Guard::benign(),
|
||||||
|
engine: &*spec.engine,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut restoration = Restoration::new(params).unwrap();
|
||||||
|
let definitely_bad_chunk = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
for hash in state_hashes {
|
||||||
|
assert!(restoration.feed_state(hash, &definitely_bad_chunk, &flag).is_err());
|
||||||
|
assert!(!restoration.is_done());
|
||||||
|
}
|
||||||
|
|
||||||
|
for hash in block_hashes {
|
||||||
|
assert!(restoration.feed_blocks(hash, &definitely_bad_chunk, &*spec.engine, &flag).is_err());
|
||||||
|
assert!(!restoration.is_done());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ pub trait SnapshotService : Sync + Send {
|
|||||||
/// Query the most recent manifest data.
|
/// Query the most recent manifest data.
|
||||||
fn manifest(&self) -> Option<ManifestData>;
|
fn manifest(&self) -> Option<ManifestData>;
|
||||||
|
|
||||||
/// Get the minimum supported snapshot version number.
|
/// Get the supported range of snapshot version numbers.
|
||||||
/// `None` indicates warp sync isn't supported by the consensus engine.
|
/// `None` indicates warp sync isn't supported by the consensus engine.
|
||||||
fn min_supported_version(&self) -> Option<u64>;
|
fn supported_versions(&self) -> Option<(u64, u64)>;
|
||||||
|
|
||||||
/// Get raw chunk for a given hash.
|
/// Get raw chunk for a given hash.
|
||||||
fn chunk(&self, hash: H256) -> Option<Bytes>;
|
fn chunk(&self, hash: H256) -> Option<Bytes>;
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ impl CommonParams {
|
|||||||
schedule.have_create2 = block_number >= self.eip86_transition;
|
schedule.have_create2 = block_number >= self.eip86_transition;
|
||||||
schedule.have_revert = block_number >= self.eip140_transition;
|
schedule.have_revert = block_number >= self.eip140_transition;
|
||||||
schedule.have_static_call = block_number >= self.eip214_transition;
|
schedule.have_static_call = block_number >= self.eip214_transition;
|
||||||
|
schedule.have_return_data = block_number >= self.eip211_transition;
|
||||||
if block_number >= self.eip210_transition {
|
if block_number >= self.eip210_transition {
|
||||||
schedule.blockhash_gas = 350;
|
schedule.blockhash_gas = 350;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,7 +209,7 @@
|
|||||||
"react-intl": "2.1.5",
|
"react-intl": "2.1.5",
|
||||||
"react-markdown": "2.4.4",
|
"react-markdown": "2.4.4",
|
||||||
"react-portal": "3.0.0",
|
"react-portal": "3.0.0",
|
||||||
"react-qr-reader": "1.0.3",
|
"react-qr-reader": "1.1.3",
|
||||||
"react-redux": "4.4.6",
|
"react-redux": "4.4.6",
|
||||||
"react-router": "3.0.0",
|
"react-router": "3.0.0",
|
||||||
"react-router-redux": "4.0.7",
|
"react-router-redux": "4.0.7",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -104,7 +104,7 @@ contract WalletLibrary is WalletEvents {
|
|||||||
|
|
||||||
// constructor is given number of sigs required to do protected "onlymanyowners" transactions
|
// constructor is given number of sigs required to do protected "onlymanyowners" transactions
|
||||||
// as well as the selection of addresses capable of confirming them.
|
// as well as the selection of addresses capable of confirming them.
|
||||||
function initMultiowned(address[] _owners, uint _required) {
|
function initMultiowned(address[] _owners, uint _required) only_uninitialized {
|
||||||
m_numOwners = _owners.length + 1;
|
m_numOwners = _owners.length + 1;
|
||||||
m_owners[1] = uint(msg.sender);
|
m_owners[1] = uint(msg.sender);
|
||||||
m_ownerIndex[uint(msg.sender)] = 1;
|
m_ownerIndex[uint(msg.sender)] = 1;
|
||||||
@@ -198,7 +198,7 @@ contract WalletLibrary is WalletEvents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// constructor - stores initial daily limit and records the present day's index.
|
// constructor - stores initial daily limit and records the present day's index.
|
||||||
function initDaylimit(uint _limit) {
|
function initDaylimit(uint _limit) only_uninitialized {
|
||||||
m_dailyLimit = _limit;
|
m_dailyLimit = _limit;
|
||||||
m_lastDay = today();
|
m_lastDay = today();
|
||||||
}
|
}
|
||||||
@@ -211,9 +211,12 @@ contract WalletLibrary is WalletEvents {
|
|||||||
m_spentToday = 0;
|
m_spentToday = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// throw unless the contract is not yet initialized.
|
||||||
|
modifier only_uninitialized { if (m_numOwners > 0) throw; _; }
|
||||||
|
|
||||||
// constructor - just pass on the owner array to the multiowned and
|
// constructor - just pass on the owner array to the multiowned and
|
||||||
// the limit to daylimit
|
// the limit to daylimit
|
||||||
function initWallet(address[] _owners, uint _required, uint _daylimit) {
|
function initWallet(address[] _owners, uint _required, uint _daylimit) only_uninitialized {
|
||||||
initDaylimit(_daylimit);
|
initDaylimit(_daylimit);
|
||||||
initMultiowned(_owners, _required);
|
initMultiowned(_owners, _required);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ export default class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@computed get qrAddressValid () {
|
@computed get qrAddressValid () {
|
||||||
console.log('qrValid', this.qrAddress, this._api.util.isAddressValid(this.qrAddress));
|
|
||||||
return this._api.util.isAddressValid(this.qrAddress);
|
return this._api.util.isAddressValid(this.qrAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +190,7 @@ export default class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Current native signer encoding is not 100% for EIP-55, lowercase for now
|
// FIXME: Current native signer encoding is not 100% for EIP-55, lowercase for now
|
||||||
this.qrAddress = this._api.util
|
this.qrAddress = qrAddress && this._api.util
|
||||||
? this._api.util.toChecksumAddress(qrAddress.toLowerCase())
|
? this._api.util.toChecksumAddress(qrAddress.toLowerCase())
|
||||||
: qrAddress;
|
: qrAddress;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,6 +191,8 @@ export default class CreateWalletStore {
|
|||||||
return null; // exception when registry is not available
|
return null; // exception when registry is not available
|
||||||
})
|
})
|
||||||
.then((address) => {
|
.then((address) => {
|
||||||
|
console.warn('WalletLibrary address in registry', address);
|
||||||
|
|
||||||
if (!address || /^(0x)?0*$/.test(address)) {
|
if (!address || /^(0x)?0*$/.test(address)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,34 +144,37 @@ export function updateTokensFilter (_addresses, _tokens, options = {}) {
|
|||||||
promises.push(api.eth.uninstallFilter(tokensFilter.filterToId));
|
promises.push(api.eth.uninstallFilter(tokensFilter.filterToId));
|
||||||
}
|
}
|
||||||
|
|
||||||
const promise = Promise.all(promises);
|
Promise
|
||||||
|
.all([
|
||||||
|
api.eth.blockNumber()
|
||||||
|
].concat(promises))
|
||||||
|
.then(([ block ]) => {
|
||||||
|
const topicsFrom = [ TRANSFER_SIGNATURE, addresses, null ];
|
||||||
|
const topicsTo = [ TRANSFER_SIGNATURE, null, addresses ];
|
||||||
|
|
||||||
const topicsFrom = [ TRANSFER_SIGNATURE, addresses, null ];
|
const filterOptions = {
|
||||||
const topicsTo = [ TRANSFER_SIGNATURE, null, addresses ];
|
fromBlock: block,
|
||||||
|
toBlock: 'pending',
|
||||||
|
address: tokenAddresses
|
||||||
|
};
|
||||||
|
|
||||||
const filterOptions = {
|
const optionsFrom = {
|
||||||
fromBlock: 0,
|
...filterOptions,
|
||||||
toBlock: 'pending',
|
topics: topicsFrom
|
||||||
address: tokenAddresses
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const optionsFrom = {
|
const optionsTo = {
|
||||||
...filterOptions,
|
...filterOptions,
|
||||||
topics: topicsFrom
|
topics: topicsTo
|
||||||
};
|
};
|
||||||
|
|
||||||
const optionsTo = {
|
const newFilters = Promise.all([
|
||||||
...filterOptions,
|
api.eth.newFilter(optionsFrom),
|
||||||
topics: topicsTo
|
api.eth.newFilter(optionsTo)
|
||||||
};
|
]);
|
||||||
|
|
||||||
const newFilters = Promise.all([
|
return newFilters;
|
||||||
api.eth.newFilter(optionsFrom),
|
})
|
||||||
api.eth.newFilter(optionsTo)
|
|
||||||
]);
|
|
||||||
|
|
||||||
promise
|
|
||||||
.then(() => newFilters)
|
|
||||||
.then(([ filterFromId, filterToId ]) => {
|
.then(([ filterFromId, filterToId ]) => {
|
||||||
const nextTokensFilter = {
|
const nextTokensFilter = {
|
||||||
filterFromId, filterToId,
|
filterFromId, filterToId,
|
||||||
|
|||||||
@@ -228,9 +228,10 @@ export default class Status {
|
|||||||
|
|
||||||
_overallStatus = (health) => {
|
_overallStatus = (health) => {
|
||||||
const all = [health.peers, health.sync, health.time].filter(x => x);
|
const all = [health.peers, health.sync, health.time].filter(x => x);
|
||||||
|
const allNoTime = [health.peers, health.sync].filter(x => x);
|
||||||
const statuses = all.map(x => x.status);
|
const statuses = all.map(x => x.status);
|
||||||
const bad = statuses.find(x => x === STATUS_BAD);
|
const bad = statuses.find(x => x === STATUS_BAD);
|
||||||
const needsAttention = statuses.find(x => x === STATUS_WARN);
|
const needsAttention = allNoTime.map(x => x.status).find(x => x === STATUS_WARN);
|
||||||
const message = all.map(x => x.message).filter(x => x);
|
const message = all.map(x => x.message).filter(x => x);
|
||||||
|
|
||||||
if (all.length) {
|
if (all.length) {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const initialState = {
|
|||||||
status: DEFAULT_STATUS
|
status: DEFAULT_STATUS
|
||||||
},
|
},
|
||||||
overall: {
|
overall: {
|
||||||
isReady: false,
|
isNotReady: true,
|
||||||
status: DEFAULT_STATUS,
|
status: DEFAULT_STATUS,
|
||||||
message: []
|
message: []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,13 +101,7 @@ export default class SecureApi extends Api {
|
|||||||
return 'dapps.parity';
|
return 'dapps.parity';
|
||||||
}
|
}
|
||||||
|
|
||||||
const { host } = this._dappsAddress;
|
return this._dappsAddress.host;
|
||||||
|
|
||||||
if (!host || host === '0.0.0.0') {
|
|
||||||
return window.location.hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
return host;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get isConnecting () {
|
get isConnecting () {
|
||||||
@@ -173,6 +167,25 @@ export default class SecureApi extends Api {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a wildcard address to `window.location.hostname`;
|
||||||
|
*/
|
||||||
|
_resolveHost (url) {
|
||||||
|
const parts = url ? url.split(':') : [];
|
||||||
|
const port = parts[1];
|
||||||
|
let host = parts[0];
|
||||||
|
|
||||||
|
if (!host) {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host === '0.0.0.0') {
|
||||||
|
host = window.location.hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
return port ? `${host}:${port}` : host;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a Promise that gets resolved with
|
* Returns a Promise that gets resolved with
|
||||||
* a boolean: `true` if the node is up, `false`
|
* a boolean: `true` if the node is up, `false`
|
||||||
@@ -316,8 +329,8 @@ export default class SecureApi extends Api {
|
|||||||
this._uiApi.parity.wsUrl()
|
this._uiApi.parity.wsUrl()
|
||||||
])
|
])
|
||||||
.then(([dappsUrl, wsUrl]) => {
|
.then(([dappsUrl, wsUrl]) => {
|
||||||
this._dappsUrl = dappsUrl;
|
this._dappsUrl = this._resolveHost(dappsUrl);
|
||||||
this._wsUrl = wsUrl;
|
this._wsUrl = this._resolveHost(wsUrl);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,14 +69,14 @@ export default class ConfirmDialog extends Component {
|
|||||||
<Portal
|
<Portal
|
||||||
buttons={ [
|
buttons={ [
|
||||||
<Button
|
<Button
|
||||||
disabled={ disabledDeny }
|
disabled={ disabledDeny || busy }
|
||||||
icon={ iconDeny || <CancelIcon /> }
|
icon={ iconDeny || <CancelIcon /> }
|
||||||
key='deny'
|
key='deny'
|
||||||
label={ labelDeny || DEFAULT_NO }
|
label={ labelDeny || DEFAULT_NO }
|
||||||
onClick={ onDeny }
|
onClick={ onDeny }
|
||||||
/>,
|
/>,
|
||||||
<Button
|
<Button
|
||||||
disabled={ disabledConfirm }
|
disabled={ disabledConfirm || busy }
|
||||||
icon={ iconConfirm || <CheckIcon /> }
|
icon={ iconConfirm || <CheckIcon /> }
|
||||||
key='confirm'
|
key='confirm'
|
||||||
label={ labelConfirm || DEFAULT_YES }
|
label={ labelConfirm || DEFAULT_YES }
|
||||||
|
|||||||
@@ -41,8 +41,13 @@ class Delete extends Component {
|
|||||||
newError: PropTypes.func
|
newError: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
isBusy: false
|
||||||
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { account, confirmMessage, visible } = this.props;
|
const { account, confirmMessage, visible } = this.props;
|
||||||
|
const { isBusy } = this.state;
|
||||||
|
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
return null;
|
return null;
|
||||||
@@ -50,6 +55,7 @@ class Delete extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
|
busy={ isBusy }
|
||||||
className={ styles.delete }
|
className={ styles.delete }
|
||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
@@ -99,6 +105,8 @@ class Delete extends Component {
|
|||||||
const { api, router } = this.context;
|
const { api, router } = this.context;
|
||||||
const { account, route, newError } = this.props;
|
const { account, route, newError } = this.props;
|
||||||
|
|
||||||
|
this.setState({ isBusy: true });
|
||||||
|
|
||||||
api.parity
|
api.parity
|
||||||
.removeAddress(account.address)
|
.removeAddress(account.address)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -407,7 +407,11 @@ export default class TransactionPendingFormConfirm extends Component {
|
|||||||
onScan = (signature) => {
|
onScan = (signature) => {
|
||||||
const { chainId, rlp, tx, data, decrypt } = this.state.qr;
|
const { chainId, rlp, tx, data, decrypt } = this.state.qr;
|
||||||
|
|
||||||
if (signature && signature.substr(0, 2) !== '0x') {
|
if (!signature) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signature.substr(0, 2) !== '0x') {
|
||||||
signature = `0x${signature}`;
|
signature = `0x${signature}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ class SyncWarning extends Component {
|
|||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const { health } = state.nodeStatus;
|
const { health } = state.nodeStatus;
|
||||||
const isNotAvailableYet = health.overall.isReady;
|
const isNotAvailableYet = health.overall.isNotReady;
|
||||||
const isOk = isNotAvailableYet || health.overall.status === 'ok';
|
const isOk = isNotAvailableYet || health.overall.status === 'ok';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ pub struct ImportBlockchain {
|
|||||||
pub check_seal: bool,
|
pub check_seal: bool,
|
||||||
pub with_color: bool,
|
pub with_color: bool,
|
||||||
pub verifier_settings: VerifierSettings,
|
pub verifier_settings: VerifierSettings,
|
||||||
|
pub light: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@@ -138,12 +139,165 @@ pub struct ExportState {
|
|||||||
pub fn execute(cmd: BlockchainCmd) -> Result<(), String> {
|
pub fn execute(cmd: BlockchainCmd) -> Result<(), String> {
|
||||||
match cmd {
|
match cmd {
|
||||||
BlockchainCmd::Kill(kill_cmd) => kill_db(kill_cmd),
|
BlockchainCmd::Kill(kill_cmd) => kill_db(kill_cmd),
|
||||||
BlockchainCmd::Import(import_cmd) => execute_import(import_cmd),
|
BlockchainCmd::Import(import_cmd) => {
|
||||||
|
if import_cmd.light {
|
||||||
|
execute_import_light(import_cmd)
|
||||||
|
} else {
|
||||||
|
execute_import(import_cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
BlockchainCmd::Export(export_cmd) => execute_export(export_cmd),
|
BlockchainCmd::Export(export_cmd) => execute_export(export_cmd),
|
||||||
BlockchainCmd::ExportState(export_cmd) => execute_export_state(export_cmd),
|
BlockchainCmd::ExportState(export_cmd) => execute_export_state(export_cmd),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> {
|
||||||
|
use light::client::{Service as LightClientService, Config as LightClientConfig};
|
||||||
|
use light::cache::Cache as LightDataCache;
|
||||||
|
|
||||||
|
let timer = Instant::now();
|
||||||
|
|
||||||
|
// load spec file
|
||||||
|
let spec = cmd.spec.spec(&cmd.dirs.cache)?;
|
||||||
|
|
||||||
|
// load genesis hash
|
||||||
|
let genesis_hash = spec.genesis_header().hash();
|
||||||
|
|
||||||
|
// database paths
|
||||||
|
let db_dirs = cmd.dirs.database(genesis_hash, None, spec.data_dir.clone());
|
||||||
|
|
||||||
|
// user defaults path
|
||||||
|
let user_defaults_path = db_dirs.user_defaults_path();
|
||||||
|
|
||||||
|
// load user defaults
|
||||||
|
let user_defaults = UserDefaults::load(&user_defaults_path)?;
|
||||||
|
|
||||||
|
fdlimit::raise_fd_limit();
|
||||||
|
|
||||||
|
// select pruning algorithm
|
||||||
|
let algorithm = cmd.pruning.to_algorithm(&user_defaults);
|
||||||
|
|
||||||
|
// prepare client and snapshot paths.
|
||||||
|
let client_path = db_dirs.client_path(algorithm);
|
||||||
|
|
||||||
|
// execute upgrades
|
||||||
|
let compaction = cmd.compaction.compaction_profile(db_dirs.db_root_path().as_path());
|
||||||
|
execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction)?;
|
||||||
|
|
||||||
|
// create dirs used by parity
|
||||||
|
cmd.dirs.create_dirs(false, false, false)?;
|
||||||
|
|
||||||
|
let cache = Arc::new(::util::Mutex::new(
|
||||||
|
LightDataCache::new(Default::default(), ::time::Duration::seconds(0))
|
||||||
|
));
|
||||||
|
|
||||||
|
let mut config = LightClientConfig {
|
||||||
|
queue: Default::default(),
|
||||||
|
chain_column: ::ethcore::db::COL_LIGHT_CHAIN,
|
||||||
|
db_cache_size: Some(cmd.cache_config.blockchain() as usize * 1024 * 1024),
|
||||||
|
db_compaction: compaction,
|
||||||
|
db_wal: cmd.wal,
|
||||||
|
verify_full: true,
|
||||||
|
check_seal: cmd.check_seal,
|
||||||
|
};
|
||||||
|
|
||||||
|
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
|
||||||
|
config.queue.verifier_settings = cmd.verifier_settings;
|
||||||
|
|
||||||
|
let service = LightClientService::start(config, &spec, &client_path, cache)
|
||||||
|
.map_err(|e| format!("Failed to start client: {}", e))?;
|
||||||
|
|
||||||
|
// free up the spec in memory.
|
||||||
|
drop(spec);
|
||||||
|
|
||||||
|
let client = service.client();
|
||||||
|
|
||||||
|
let mut instream: Box<io::Read> = match cmd.file_path {
|
||||||
|
Some(f) => Box::new(fs::File::open(&f).map_err(|_| format!("Cannot open given file: {}", f))?),
|
||||||
|
None => Box::new(io::stdin()),
|
||||||
|
};
|
||||||
|
|
||||||
|
const READAHEAD_BYTES: usize = 8;
|
||||||
|
|
||||||
|
let mut first_bytes: Vec<u8> = vec![0; READAHEAD_BYTES];
|
||||||
|
let mut first_read = 0;
|
||||||
|
|
||||||
|
let format = match cmd.format {
|
||||||
|
Some(format) => format,
|
||||||
|
None => {
|
||||||
|
first_read = instream.read(&mut first_bytes).map_err(|_| "Error reading from the file/stream.")?;
|
||||||
|
match first_bytes[0] {
|
||||||
|
0xf9 => DataFormat::Binary,
|
||||||
|
_ => DataFormat::Hex,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let do_import = |bytes: Vec<u8>| {
|
||||||
|
while client.queue_info().is_full() { sleep(Duration::from_secs(1)); }
|
||||||
|
|
||||||
|
let header: ::ethcore::header::Header = ::rlp::UntrustedRlp::new(&bytes).val_at(0)
|
||||||
|
.map_err(|e| format!("Bad block: {}", e))?;
|
||||||
|
|
||||||
|
if client.best_block_header().number() >= header.number() { return Ok(()) }
|
||||||
|
|
||||||
|
if header.number() % 10000 == 0 {
|
||||||
|
info!("#{}", header.number());
|
||||||
|
}
|
||||||
|
|
||||||
|
match client.import_header(header) {
|
||||||
|
Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {
|
||||||
|
trace!("Skipping block already in chain.");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(format!("Cannot import block: {:?}", e));
|
||||||
|
},
|
||||||
|
Ok(_) => {},
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
match format {
|
||||||
|
DataFormat::Binary => {
|
||||||
|
loop {
|
||||||
|
let mut bytes = if first_read > 0 {first_bytes.clone()} else {vec![0; READAHEAD_BYTES]};
|
||||||
|
let n = if first_read > 0 {
|
||||||
|
first_read
|
||||||
|
} else {
|
||||||
|
instream.read(&mut bytes).map_err(|_| "Error reading from the file/stream.")?
|
||||||
|
};
|
||||||
|
if n == 0 { break; }
|
||||||
|
first_read = 0;
|
||||||
|
let s = PayloadInfo::from(&bytes).map_err(|e| format!("Invalid RLP in the file/stream: {:?}", e))?.total();
|
||||||
|
bytes.resize(s, 0);
|
||||||
|
instream.read_exact(&mut bytes[n..]).map_err(|_| "Error reading from the file/stream.")?;
|
||||||
|
do_import(bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataFormat::Hex => {
|
||||||
|
for line in BufReader::new(instream).lines() {
|
||||||
|
let s = line.map_err(|_| "Error reading from the file/stream.")?;
|
||||||
|
let s = if first_read > 0 {from_utf8(&first_bytes).unwrap().to_owned() + &(s[..])} else {s};
|
||||||
|
first_read = 0;
|
||||||
|
let bytes = s.from_hex().map_err(|_| "Invalid hex in file/stream.")?;
|
||||||
|
do_import(bytes)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.flush_queue();
|
||||||
|
|
||||||
|
let ms = timer.elapsed().as_milliseconds();
|
||||||
|
let report = client.report();
|
||||||
|
|
||||||
|
info!("Import completed in {} seconds, {} headers, {} hdr/s",
|
||||||
|
ms / 1000,
|
||||||
|
report.blocks_imported,
|
||||||
|
(report.blocks_imported * 1000) as u64 / ms,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
|
fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
|
||||||
let timer = Instant::now();
|
let timer = Instant::now();
|
||||||
|
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ usage! {
|
|||||||
or |c: &Config| otry!(c.vm).jit.clone(),
|
or |c: &Config| otry!(c.vm).jit.clone(),
|
||||||
|
|
||||||
// -- Miscellaneous Options
|
// -- Miscellaneous Options
|
||||||
flag_ntp_server: String = "pool.ntp.org:123",
|
flag_ntp_server: String = "none",
|
||||||
or |c: &Config| otry!(c.misc).ntp_server.clone(),
|
or |c: &Config| otry!(c.misc).ntp_server.clone(),
|
||||||
flag_logging: Option<String> = None,
|
flag_logging: Option<String> = None,
|
||||||
or |c: &Config| otry!(c.misc).logging.clone().map(Some),
|
or |c: &Config| otry!(c.misc).logging.clone().map(Some),
|
||||||
@@ -897,7 +897,7 @@ mod tests {
|
|||||||
flag_dapps_apis_all: None,
|
flag_dapps_apis_all: None,
|
||||||
|
|
||||||
// -- Miscellaneous Options
|
// -- Miscellaneous Options
|
||||||
flag_ntp_server: "pool.ntp.org:123".into(),
|
flag_ntp_server: "none".into(),
|
||||||
flag_version: false,
|
flag_version: false,
|
||||||
flag_logging: Some("own_tx=trace".into()),
|
flag_logging: Some("own_tx=trace".into()),
|
||||||
flag_log_file: Some("/var/log/parity.log".into()),
|
flag_log_file: Some("/var/log/parity.log".into()),
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ impl Configuration {
|
|||||||
check_seal: !self.args.flag_no_seal_check,
|
check_seal: !self.args.flag_no_seal_check,
|
||||||
with_color: logger_config.color,
|
with_color: logger_config.color,
|
||||||
verifier_settings: self.verifier_settings(),
|
verifier_settings: self.verifier_settings(),
|
||||||
|
light: self.args.flag_light,
|
||||||
};
|
};
|
||||||
Cmd::Blockchain(BlockchainCmd::Import(import_cmd))
|
Cmd::Blockchain(BlockchainCmd::Import(import_cmd))
|
||||||
} else if self.args.cmd_export {
|
} else if self.args.cmd_export {
|
||||||
@@ -1179,6 +1180,7 @@ mod tests {
|
|||||||
check_seal: true,
|
check_seal: true,
|
||||||
with_color: !cfg!(windows),
|
with_color: !cfg!(windows),
|
||||||
verifier_settings: Default::default(),
|
verifier_settings: Default::default(),
|
||||||
|
light: false,
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1270,7 +1272,7 @@ mod tests {
|
|||||||
support_token_api: true
|
support_token_api: true
|
||||||
}, UiConfiguration {
|
}, UiConfiguration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
ntp_server: "pool.ntp.org:123".into(),
|
ntp_server: "none".into(),
|
||||||
interface: "127.0.0.1".into(),
|
interface: "127.0.0.1".into(),
|
||||||
port: 8180,
|
port: 8180,
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
@@ -1511,7 +1513,7 @@ mod tests {
|
|||||||
assert_eq!(conf0.directories().signer, "signer".to_owned());
|
assert_eq!(conf0.directories().signer, "signer".to_owned());
|
||||||
assert_eq!(conf0.ui_config(), UiConfiguration {
|
assert_eq!(conf0.ui_config(), UiConfiguration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
ntp_server: "pool.ntp.org:123".into(),
|
ntp_server: "none".into(),
|
||||||
interface: "127.0.0.1".into(),
|
interface: "127.0.0.1".into(),
|
||||||
port: 8180,
|
port: 8180,
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
@@ -1520,7 +1522,7 @@ mod tests {
|
|||||||
assert_eq!(conf1.directories().signer, "signer".to_owned());
|
assert_eq!(conf1.directories().signer, "signer".to_owned());
|
||||||
assert_eq!(conf1.ui_config(), UiConfiguration {
|
assert_eq!(conf1.ui_config(), UiConfiguration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
ntp_server: "pool.ntp.org:123".into(),
|
ntp_server: "none".into(),
|
||||||
interface: "127.0.0.1".into(),
|
interface: "127.0.0.1".into(),
|
||||||
port: 8180,
|
port: 8180,
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
@@ -1530,7 +1532,7 @@ mod tests {
|
|||||||
assert_eq!(conf2.directories().signer, "signer".to_owned());
|
assert_eq!(conf2.directories().signer, "signer".to_owned());
|
||||||
assert_eq!(conf2.ui_config(), UiConfiguration {
|
assert_eq!(conf2.ui_config(), UiConfiguration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
ntp_server: "pool.ntp.org:123".into(),
|
ntp_server: "none".into(),
|
||||||
interface: "127.0.0.1".into(),
|
interface: "127.0.0.1".into(),
|
||||||
port: 3123,
|
port: 3123,
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
@@ -1539,7 +1541,7 @@ mod tests {
|
|||||||
assert_eq!(conf3.directories().signer, "signer".to_owned());
|
assert_eq!(conf3.directories().signer, "signer".to_owned());
|
||||||
assert_eq!(conf3.ui_config(), UiConfiguration {
|
assert_eq!(conf3.ui_config(), UiConfiguration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
ntp_server: "pool.ntp.org:123".into(),
|
ntp_server: "none".into(),
|
||||||
interface: "test".into(),
|
interface: "test".into(),
|
||||||
port: 8180,
|
port: 8180,
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ impl Default for Configuration {
|
|||||||
let data_dir = default_data_path();
|
let data_dir = default_data_path();
|
||||||
Configuration {
|
Configuration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
ntp_server: "pool.ntp.org:123".into(),
|
ntp_server: "none".into(),
|
||||||
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
|
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
|
||||||
extra_dapps: vec![],
|
extra_dapps: vec![],
|
||||||
extra_embed_on: vec![],
|
extra_embed_on: vec![],
|
||||||
@@ -114,7 +114,7 @@ impl ContractClient for LightRegistrar {
|
|||||||
tx: Transaction {
|
tx: Transaction {
|
||||||
nonce: self.client.engine().account_start_nonce(header.number()),
|
nonce: self.client.engine().account_start_nonce(header.number()),
|
||||||
action: Action::Call(address),
|
action: Action::Call(address),
|
||||||
gas: 50_000_000.into(),
|
gas: 50_000.into(), // should be enough for all registry lookups. TODO: exponential backoff
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: data,
|
data: data,
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ impl InformantData for FullNodeInformantData {
|
|||||||
max_peers: status.current_max_peers(net_config.min_peers, net_config.max_peers),
|
max_peers: status.current_max_peers(net_config.min_peers, net_config.max_peers),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
_ => (is_major_importing(None, queue_info.clone()), None),
|
_ => (is_major_importing(self.sync.as_ref().map(|s| s.status().state), queue_info.clone()), None),
|
||||||
};
|
};
|
||||||
|
|
||||||
Report {
|
Report {
|
||||||
@@ -254,21 +254,22 @@ impl<T: InformantData> Informant<T> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (client_report, full_report) = {
|
||||||
|
let mut last_report = self.last_report.lock();
|
||||||
|
let full_report = self.target.report();
|
||||||
|
let diffed = full_report.client_report.clone() - &*last_report;
|
||||||
|
*last_report = full_report.client_report.clone();
|
||||||
|
(diffed, full_report)
|
||||||
|
};
|
||||||
|
|
||||||
let Report {
|
let Report {
|
||||||
importing,
|
importing,
|
||||||
chain_info,
|
chain_info,
|
||||||
client_report,
|
|
||||||
queue_info,
|
queue_info,
|
||||||
cache_sizes,
|
cache_sizes,
|
||||||
sync_info,
|
sync_info,
|
||||||
} = self.target.report();
|
..
|
||||||
|
} = full_report;
|
||||||
let client_report = {
|
|
||||||
let mut last_report = self.last_report.lock();
|
|
||||||
let diffed = client_report.clone() - &*last_report;
|
|
||||||
*last_report = client_report.clone();
|
|
||||||
diffed
|
|
||||||
};
|
|
||||||
|
|
||||||
let rpc_stats = self.rpc_stats.as_ref();
|
let rpc_stats = self.rpc_stats.as_ref();
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ impl Default for UiConfiguration {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
UiConfiguration {
|
UiConfiguration {
|
||||||
enabled: true && cfg!(feature = "ui-enabled"),
|
enabled: true && cfg!(feature = "ui-enabled"),
|
||||||
ntp_server: "pool.ntp.org:123".into(),
|
ntp_server: "none".into(),
|
||||||
port: 8180,
|
port: 8180,
|
||||||
interface: "127.0.0.1".into(),
|
interface: "127.0.0.1".into(),
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
|
|||||||
db_compaction: compaction,
|
db_compaction: compaction,
|
||||||
db_wal: cmd.wal,
|
db_wal: cmd.wal,
|
||||||
verify_full: true,
|
verify_full: true,
|
||||||
|
check_seal: cmd.check_seal,
|
||||||
};
|
};
|
||||||
|
|
||||||
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
|
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ use ethsync::SyncState;
|
|||||||
|
|
||||||
/// Check if client is during major sync or during block import.
|
/// Check if client is during major sync or during block import.
|
||||||
pub fn is_major_importing(sync_state: Option<SyncState>, queue_info: BlockQueueInfo) -> bool {
|
pub fn is_major_importing(sync_state: Option<SyncState>, queue_info: BlockQueueInfo) -> bool {
|
||||||
let is_syncing_state = sync_state.map_or(false, |s|
|
let is_syncing_state = sync_state.map_or(false, |s| match s {
|
||||||
s != SyncState::Idle && s != SyncState::NewBlocks
|
SyncState::Idle | SyncState::NewBlocks | SyncState::WaitingPeers => false,
|
||||||
);
|
_ => true,
|
||||||
|
});
|
||||||
let is_verifying = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3;
|
let is_verifying = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3;
|
||||||
is_verifying || is_syncing_state
|
is_verifying || is_syncing_state
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ pub fn fetch_gas_price_corpus(
|
|||||||
) -> BoxFuture<Corpus<U256>, Error> {
|
) -> BoxFuture<Corpus<U256>, Error> {
|
||||||
const GAS_PRICE_SAMPLE_SIZE: usize = 100;
|
const GAS_PRICE_SAMPLE_SIZE: usize = 100;
|
||||||
|
|
||||||
if let Some(cached) = cache.lock().gas_price_corpus() {
|
if let Some(cached) = { cache.lock().gas_price_corpus() } {
|
||||||
return future::ok(cached).boxed()
|
return future::ok(cached).boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ use ethcore::filter::Filter as EthcoreFilter;
|
|||||||
use ethcore::transaction::{Action, Transaction as EthTransaction};
|
use ethcore::transaction::{Action, Transaction as EthTransaction};
|
||||||
|
|
||||||
use futures::{future, Future, BoxFuture};
|
use futures::{future, Future, BoxFuture};
|
||||||
|
use futures::future::Either;
|
||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
use jsonrpc_macros::Trailing;
|
use jsonrpc_macros::Trailing;
|
||||||
|
|
||||||
@@ -159,7 +160,9 @@ impl LightFetch {
|
|||||||
|
|
||||||
/// helper for getting proved execution.
|
/// helper for getting proved execution.
|
||||||
pub fn proved_execution(&self, req: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<ExecutionResult, Error> {
|
pub fn proved_execution(&self, req: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<ExecutionResult, Error> {
|
||||||
const DEFAULT_GAS_PRICE: U256 = U256([0, 0, 0, 21_000_000]);
|
const DEFAULT_GAS_PRICE: u64 = 21_000;
|
||||||
|
// starting gas when gas not provided.
|
||||||
|
const START_GAS: u64 = 50_000;
|
||||||
|
|
||||||
let (sync, on_demand, client) = (self.sync.clone(), self.on_demand.clone(), self.client.clone());
|
let (sync, on_demand, client) = (self.sync.clone(), self.on_demand.clone(), self.client.clone());
|
||||||
let req: CallRequestHelper = req.into();
|
let req: CallRequestHelper = req.into();
|
||||||
@@ -167,21 +170,21 @@ impl LightFetch {
|
|||||||
|
|
||||||
let from = req.from.unwrap_or(Address::zero());
|
let from = req.from.unwrap_or(Address::zero());
|
||||||
let nonce_fut = match req.nonce {
|
let nonce_fut = match req.nonce {
|
||||||
Some(nonce) => future::ok(Some(nonce)).boxed(),
|
Some(nonce) => Either::A(future::ok(Some(nonce))),
|
||||||
None => self.account(from, id).map(|acc| acc.map(|a| a.nonce)).boxed(),
|
None => Either::B(self.account(from, id).map(|acc| acc.map(|a| a.nonce))),
|
||||||
};
|
};
|
||||||
|
|
||||||
let gas_price_fut = match req.gas_price {
|
let gas_price_fut = match req.gas_price {
|
||||||
Some(price) => future::ok(price).boxed(),
|
Some(price) => Either::A(future::ok(price)),
|
||||||
None => dispatch::fetch_gas_price_corpus(
|
None => Either::B(dispatch::fetch_gas_price_corpus(
|
||||||
self.sync.clone(),
|
self.sync.clone(),
|
||||||
self.client.clone(),
|
self.client.clone(),
|
||||||
self.on_demand.clone(),
|
self.on_demand.clone(),
|
||||||
self.cache.clone(),
|
self.cache.clone(),
|
||||||
).map(|corp| match corp.median() {
|
).map(|corp| match corp.median() {
|
||||||
Some(median) => *median,
|
Some(median) => *median,
|
||||||
None => DEFAULT_GAS_PRICE,
|
None => DEFAULT_GAS_PRICE.into(),
|
||||||
}).boxed()
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
// if nonce resolves, this should too since it'll be in the LRU-cache.
|
// if nonce resolves, this should too since it'll be in the LRU-cache.
|
||||||
@@ -190,22 +193,29 @@ impl LightFetch {
|
|||||||
// fetch missing transaction fields from the network.
|
// fetch missing transaction fields from the network.
|
||||||
nonce_fut.join(gas_price_fut).and_then(move |(nonce, gas_price)| {
|
nonce_fut.join(gas_price_fut).and_then(move |(nonce, gas_price)| {
|
||||||
let action = req.to.map_or(Action::Create, Action::Call);
|
let action = req.to.map_or(Action::Create, Action::Call);
|
||||||
let gas = req.gas.unwrap_or(U256::from(10_000_000)); // better gas amount?
|
|
||||||
let value = req.value.unwrap_or_else(U256::zero);
|
let value = req.value.unwrap_or_else(U256::zero);
|
||||||
let data = req.data.unwrap_or_default();
|
let data = req.data.unwrap_or_default();
|
||||||
|
|
||||||
future::done(match nonce {
|
future::done(match (nonce, req.gas) {
|
||||||
Some(n) => Ok(EthTransaction {
|
(Some(n), Some(gas)) => Ok((true, EthTransaction {
|
||||||
nonce: n,
|
nonce: n,
|
||||||
action: action,
|
action: action,
|
||||||
gas: gas,
|
gas: gas,
|
||||||
gas_price: gas_price,
|
gas_price: gas_price,
|
||||||
value: value,
|
value: value,
|
||||||
data: data,
|
data: data,
|
||||||
}.fake_sign(from)),
|
})),
|
||||||
None => Err(errors::unknown_block()),
|
(Some(n), None) => Ok((false, EthTransaction {
|
||||||
|
nonce: n,
|
||||||
|
action: action,
|
||||||
|
gas: START_GAS.into(),
|
||||||
|
gas_price: gas_price,
|
||||||
|
value: value,
|
||||||
|
data: data,
|
||||||
|
})),
|
||||||
|
(None, _) => Err(errors::unknown_block()),
|
||||||
})
|
})
|
||||||
}).join(header_fut).and_then(move |(tx, hdr)| {
|
}).join(header_fut).and_then(move |((gas_known, tx), hdr)| {
|
||||||
// then request proved execution.
|
// then request proved execution.
|
||||||
// TODO: get last-hashes from network.
|
// TODO: get last-hashes from network.
|
||||||
let env_info = match client.env_info(id) {
|
let env_info = match client.env_info(id) {
|
||||||
@@ -213,24 +223,15 @@ impl LightFetch {
|
|||||||
_ => return future::err(errors::unknown_block()).boxed(),
|
_ => return future::err(errors::unknown_block()).boxed(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let request = request::TransactionProof {
|
execute_tx(gas_known, ExecuteParams {
|
||||||
|
from: from,
|
||||||
tx: tx,
|
tx: tx,
|
||||||
header: hdr.into(),
|
hdr: hdr,
|
||||||
env_info: env_info,
|
env_info: env_info,
|
||||||
engine: client.engine().clone(),
|
engine: client.engine().clone(),
|
||||||
};
|
on_demand: on_demand,
|
||||||
|
sync: sync,
|
||||||
let proved_future = sync.with_context(move |ctx| {
|
})
|
||||||
on_demand
|
|
||||||
.request(ctx, request)
|
|
||||||
.expect("no back-references; therefore all back-refs valid; qed")
|
|
||||||
.map_err(errors::on_demand_cancel).boxed()
|
|
||||||
});
|
|
||||||
|
|
||||||
match proved_future {
|
|
||||||
Some(fut) => fut.boxed(),
|
|
||||||
None => future::err(errors::network_disabled()).boxed(),
|
|
||||||
}
|
|
||||||
}).boxed()
|
}).boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,3 +321,66 @@ impl LightFetch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ExecuteParams {
|
||||||
|
from: Address,
|
||||||
|
tx: EthTransaction,
|
||||||
|
hdr: encoded::Header,
|
||||||
|
env_info: ::evm::env_info::EnvInfo,
|
||||||
|
engine: Arc<::ethcore::engines::Engine>,
|
||||||
|
on_demand: Arc<OnDemand>,
|
||||||
|
sync: Arc<LightSync>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// has a peer execute the transaction with given params. If `gas_known` is false,
|
||||||
|
// this will double the gas on each `OutOfGas` error.
|
||||||
|
fn execute_tx(gas_known: bool, params: ExecuteParams) -> BoxFuture<ExecutionResult, Error> {
|
||||||
|
if !gas_known {
|
||||||
|
future::loop_fn(params, |mut params| {
|
||||||
|
execute_tx(true, params.clone()).and_then(move |res| {
|
||||||
|
match res {
|
||||||
|
Ok(executed) => {
|
||||||
|
// TODO: how to distinguish between actual OOG and
|
||||||
|
// exception?
|
||||||
|
if executed.exception.is_some() {
|
||||||
|
let old_gas = params.tx.gas;
|
||||||
|
params.tx.gas = params.tx.gas * 2.into();
|
||||||
|
if params.tx.gas > params.hdr.gas_limit() {
|
||||||
|
params.tx.gas = old_gas;
|
||||||
|
} else {
|
||||||
|
return Ok(future::Loop::Continue(params))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(future::Loop::Break(Ok(executed)))
|
||||||
|
}
|
||||||
|
failed => Ok(future::Loop::Break(failed)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).boxed()
|
||||||
|
} else {
|
||||||
|
trace!(target: "light_fetch", "Placing execution request for {} gas in on_demand",
|
||||||
|
params.tx.gas);
|
||||||
|
|
||||||
|
let request = request::TransactionProof {
|
||||||
|
tx: params.tx.fake_sign(params.from),
|
||||||
|
header: params.hdr.into(),
|
||||||
|
env_info: params.env_info,
|
||||||
|
engine: params.engine,
|
||||||
|
};
|
||||||
|
|
||||||
|
let on_demand = params.on_demand;
|
||||||
|
let proved_future = params.sync.with_context(move |ctx| {
|
||||||
|
on_demand
|
||||||
|
.request(ctx, request)
|
||||||
|
.expect("no back-references; therefore all back-refs valid; qed")
|
||||||
|
.map_err(errors::on_demand_cancel)
|
||||||
|
});
|
||||||
|
|
||||||
|
match proved_future {
|
||||||
|
Some(fut) => fut.boxed(),
|
||||||
|
None => future::err(errors::network_disabled()).boxed(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ impl TestSnapshotService {
|
|||||||
|
|
||||||
impl SnapshotService for TestSnapshotService {
|
impl SnapshotService for TestSnapshotService {
|
||||||
fn manifest(&self) -> Option<ManifestData> { None }
|
fn manifest(&self) -> Option<ManifestData> { None }
|
||||||
fn min_supported_version(&self) -> Option<u64> { None }
|
fn supported_versions(&self) -> Option<(u64, u64)> { None }
|
||||||
fn chunk(&self, _hash: H256) -> Option<Bytes> { None }
|
fn chunk(&self, _hash: H256) -> Option<Bytes> { None }
|
||||||
fn status(&self) -> RestorationStatus { self.status.lock().clone() }
|
fn status(&self) -> RestorationStatus { self.status.lock().clone() }
|
||||||
fn begin_restore(&self, _manifest: ManifestData) { }
|
fn begin_restore(&self, _manifest: ManifestData) { }
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd docker/hub
|
cd docker/hub
|
||||||
if [ "$1" == "latest" ]; then DOCKER_BUILD_TAG="beta-release"; fi
|
DOCKER_BUILD_TAG=$1
|
||||||
docker build --build-arg BUILD_TAG=$DOCKER_BUILD_TAG --no-cache=true --tag $2/parity:$1 .
|
echo "Docker build tag: " $DOCKER_BUILD_TAG
|
||||||
docker push $2/parity:$1
|
docker build --build-arg BUILD_TAG=$DOCKER_BUILD_TAG --no-cache=true --tag parity/parity:$DOCKER_BUILD_TAG .
|
||||||
|
docker run -it parity/parity:$DOCKER_BUILD_TAG -v
|
||||||
|
docker push parity/parity:$DOCKER_BUILD_TAG
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ apps:
|
|||||||
|
|
||||||
parts:
|
parts:
|
||||||
parity:
|
parity:
|
||||||
source: .
|
source: ..
|
||||||
plugin: rust
|
plugin: rust
|
||||||
build-packages: [g++, libudev-dev, libssl-dev, make, pkg-config]
|
build-packages: [g++, libudev-dev, libssl-dev, make, pkg-config]
|
||||||
|
|||||||
@@ -504,7 +504,7 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_start_snapshot_sync(&mut self, io: &mut SyncIo) {
|
fn maybe_start_snapshot_sync(&mut self, io: &mut SyncIo) {
|
||||||
if !self.enable_warp_sync || io.snapshot_service().min_supported_version().is_none() {
|
if !self.enable_warp_sync || io.snapshot_service().supported_versions().is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.state != SyncState::WaitingPeers && self.state != SyncState::Blocks && self.state != SyncState::Waiting {
|
if self.state != SyncState::WaitingPeers && self.state != SyncState::Blocks && self.state != SyncState::Waiting {
|
||||||
@@ -1044,11 +1044,11 @@ impl ChainSync {
|
|||||||
Ok(manifest) => manifest,
|
Ok(manifest) => manifest,
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_supported_version = io.snapshot_service().min_supported_version()
|
let is_supported_version = io.snapshot_service().supported_versions()
|
||||||
.map_or(false, |v| manifest.version >= v);
|
.map_or(false, |(l, h)| manifest.version >= l && manifest.version <= h);
|
||||||
|
|
||||||
if !is_supported_version {
|
if !is_supported_version {
|
||||||
trace!(target: "sync", "{}: Snapshot manifest version too low: {}", peer_id, manifest.version);
|
trace!(target: "sync", "{}: Snapshot manifest version not supported: {}", peer_id, manifest.version);
|
||||||
io.disable_peer(peer_id);
|
io.disable_peer(peer_id);
|
||||||
self.continue_sync(io);
|
self.continue_sync(io);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|||||||
@@ -285,6 +285,13 @@ impl<L: AsLightClient + Send + Sync> Handler for LightSync<L> {
|
|||||||
best.clone()
|
best.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut pending_reqs = self.pending_reqs.lock();
|
||||||
|
for unfulfilled in unfulfilled {
|
||||||
|
pending_reqs.remove(&unfulfilled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if new_best.is_none() {
|
if new_best.is_none() {
|
||||||
debug!(target: "sync", "No peers remain. Reverting to idle");
|
debug!(target: "sync", "No peers remain. Reverting to idle");
|
||||||
*self.state.lock() = SyncState::Idle;
|
*self.state.lock() = SyncState::Idle;
|
||||||
@@ -503,10 +510,12 @@ impl<L: AsLightClient> LightSync<L> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
let mut rng = self.rng.lock();
|
let mut rng = self.rng.lock();
|
||||||
|
let mut requested_from = HashSet::new();
|
||||||
|
|
||||||
// naive request dispatcher: just give to any peer which says it will
|
// naive request dispatcher: just give to any peer which says it will
|
||||||
// give us responses.
|
// give us responses. but only one request per peer per state transition.
|
||||||
let dispatcher = move |req: HeadersRequest| {
|
let dispatcher = move |req: HeadersRequest| {
|
||||||
rng.shuffle(&mut peer_ids);
|
rng.shuffle(&mut peer_ids);
|
||||||
|
|
||||||
@@ -521,9 +530,12 @@ impl<L: AsLightClient> LightSync<L> {
|
|||||||
builder.build()
|
builder.build()
|
||||||
};
|
};
|
||||||
for peer in &peer_ids {
|
for peer in &peer_ids {
|
||||||
|
if requested_from.contains(peer) { continue }
|
||||||
match ctx.request_from(*peer, request.clone()) {
|
match ctx.request_from(*peer, request.clone()) {
|
||||||
Ok(id) => {
|
Ok(id) => {
|
||||||
self.pending_reqs.lock().insert(id.clone());
|
self.pending_reqs.lock().insert(id.clone());
|
||||||
|
requested_from.insert(peer.clone());
|
||||||
|
|
||||||
return Some(id)
|
return Some(id)
|
||||||
}
|
}
|
||||||
Err(NetError::NoCredits) => {}
|
Err(NetError::NoCredits) => {}
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ impl SnapshotService for TestSnapshotService {
|
|||||||
self.manifest.as_ref().cloned()
|
self.manifest.as_ref().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn min_supported_version(&self) -> Option<u64> {
|
fn supported_versions(&self) -> Option<(u64, u64)> {
|
||||||
Some(1)
|
Some((1, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chunk(&self, hash: H256) -> Option<Bytes> {
|
fn chunk(&self, hash: H256) -> Option<Bytes> {
|
||||||
|
|||||||
@@ -857,11 +857,16 @@ impl Host {
|
|||||||
// Add it to the node table
|
// Add it to the node table
|
||||||
if !s.info.originated {
|
if !s.info.originated {
|
||||||
if let Ok(address) = s.remote_addr() {
|
if let Ok(address) = s.remote_addr() {
|
||||||
let entry = NodeEntry { id: id, endpoint: NodeEndpoint { address: address, udp_port: address.port() } };
|
// We can't know remote listening ports, so just assume defaults and hope for the best.
|
||||||
self.nodes.write().add_node(Node::new(entry.id.clone(), entry.endpoint.clone()));
|
let endpoint = NodeEndpoint { address: SocketAddr::new(address.ip(), DEFAULT_PORT), udp_port: DEFAULT_PORT };
|
||||||
let mut discovery = self.discovery.lock();
|
let entry = NodeEntry { id: id, endpoint: endpoint };
|
||||||
if let Some(ref mut discovery) = *discovery {
|
let mut nodes = self.nodes.write();
|
||||||
discovery.add_node(entry);
|
if !nodes.contains(&entry.id) {
|
||||||
|
nodes.add_node(Node::new(entry.id.clone(), entry.endpoint.clone()));
|
||||||
|
let mut discovery = self.discovery.lock();
|
||||||
|
if let Some(ref mut discovery) = *discovery {
|
||||||
|
discovery.add_node(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -236,6 +236,11 @@ impl NodeTable {
|
|||||||
self.nodes.get_mut(id)
|
self.nodes.get_mut(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if a node exists in the table.
|
||||||
|
pub fn contains(&self, id: &NodeId) -> bool {
|
||||||
|
self.nodes.contains_key(id)
|
||||||
|
}
|
||||||
|
|
||||||
/// Apply table changes coming from discovery
|
/// Apply table changes coming from discovery
|
||||||
pub fn update(&mut self, mut update: TableUpdates, reserved: &HashSet<NodeId>) {
|
pub fn update(&mut self, mut update: TableUpdates, reserved: &HashSet<NodeId>) {
|
||||||
for (_, node) in update.added.drain() {
|
for (_, node) in update.added.drain() {
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ pub struct MemoryLruCache<K: Eq + Hash, V: HeapSizeOf> {
|
|||||||
max_size: usize,
|
max_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// amount of memory used when the item will be put on the heap.
|
||||||
|
fn heap_size_of<T: HeapSizeOf>(val: &T) -> usize {
|
||||||
|
::std::mem::size_of::<T>() + val.heap_size_of_children()
|
||||||
|
}
|
||||||
|
|
||||||
impl<K: Eq + Hash, V: HeapSizeOf> MemoryLruCache<K, V> {
|
impl<K: Eq + Hash, V: HeapSizeOf> MemoryLruCache<K, V> {
|
||||||
/// Create a new cache with a maximum size in bytes.
|
/// Create a new cache with a maximum size in bytes.
|
||||||
pub fn new(max_size: usize) -> Self {
|
pub fn new(max_size: usize) -> Self {
|
||||||
@@ -52,15 +57,17 @@ impl<K: Eq + Hash, V: HeapSizeOf> MemoryLruCache<K, V> {
|
|||||||
self.inner.set_capacity(cap * 2);
|
self.inner.set_capacity(cap * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.cur_size += heap_size_of(&val);
|
||||||
|
|
||||||
// account for any element displaced from the cache.
|
// account for any element displaced from the cache.
|
||||||
if let Some(lru) = self.inner.insert(key, val) {
|
if let Some(lru) = self.inner.insert(key, val) {
|
||||||
self.cur_size -= lru.heap_size_of_children();
|
self.cur_size -= heap_size_of(&lru);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove elements until we are below the memory target.
|
// remove elements until we are below the memory target.
|
||||||
while self.cur_size > self.max_size {
|
while self.cur_size > self.max_size {
|
||||||
match self.inner.remove_lru() {
|
match self.inner.remove_lru() {
|
||||||
Some((_, v)) => self.cur_size -= v.heap_size_of_children(),
|
Some((_, v)) => self.cur_size -= heap_size_of(&v),
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,3 +84,27 @@ impl<K: Eq + Hash, V: HeapSizeOf> MemoryLruCache<K, V> {
|
|||||||
self.cur_size
|
self.cur_size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let mut cache = MemoryLruCache::new(256);
|
||||||
|
let val1 = vec![0u8; 100];
|
||||||
|
let size1 = heap_size_of(&val1);
|
||||||
|
cache.insert("hello", val1);
|
||||||
|
|
||||||
|
assert_eq!(cache.current_size(), size1);
|
||||||
|
|
||||||
|
let val2 = vec![0u8; 210];
|
||||||
|
let size2 = heap_size_of(&val2);
|
||||||
|
cache.insert("world", val2);
|
||||||
|
|
||||||
|
assert!(cache.get_mut(&"hello").is_none());
|
||||||
|
assert!(cache.get_mut(&"world").is_some());
|
||||||
|
|
||||||
|
assert_eq!(cache.current_size(), size2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ include!(concat!(env!("OUT_DIR"), "/version.rs"));
|
|||||||
include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
|
include!(concat!(env!("OUT_DIR"), "/rustc_version.rs"));
|
||||||
|
|
||||||
#[cfg(feature = "final")]
|
#[cfg(feature = "final")]
|
||||||
const THIS_TRACK: &'static str = "nightly";
|
const THIS_TRACK: &'static str = "beta";
|
||||||
// ^^^ should be reset to "stable" or "beta" according to the release branch.
|
// ^^^ should be reset to "stable" or "beta" according to the release branch.
|
||||||
|
|
||||||
#[cfg(not(feature = "final"))]
|
#[cfg(not(feature = "final"))]
|
||||||
|
|||||||
Reference in New Issue
Block a user