Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Commit 126208c

Browse files
authored
Backports for stable 2.1.7 (#9975)
* version: bump stable to 2.1.7 * Adjust requests costs for light client (#9925) * PIP Table Cost relative to average peers instead of max peers * Add tracing in PIP new_cost_table * Update stat peer_count * Use number of leeching peers for Light serve costs * Fix test::light_params_load_share_depends_on_max_peers (wrong type) * Remove (now) useless test * Remove `load_share` from LightParams.Config Prevent div. by 0 * Add LEECHER_COUNT_FACTOR * PR Grumble: u64 to u32 for f64 casting * Prevent u32 overflow for avg_peer_count * Add tests for LightSync::Statistics * Fix empty steps (#9939) * Don't send empty step twice or empty step then block. * Perform basic validation of locally sealed blocks. * Don't include empty step twice. * prevent silent errors in daemon mode, closes #9367 (#9946) * Fix light client informant while syncing (#9932) * Add `is_idle` to LightSync to check importing status * Use SyncStateWrapper to make sure is_idle gets updates * Update is_major_import to use verified queue size as well * Add comment for `is_idle` * Add Debug to `SyncStateWrapper` * `fn get` -> `fn into_inner` * ci: rearrange pipeline by logic (#9970) * ci: rearrange pipeline by logic * ci: rename docs script * Add readiness check for docker container (#9804) * Update Dockerfile Since parity is built for "mission critical use", I thought other operators may see the need for this. Adding the `curl` and `jq` commands allows for an extremely simple health check to be usable in container orchestrators. For example. Here is a health check for a parity docker container running in Kubernetes. This can be setup as a readiness Probe that would prevent clustered nodes that aren't ready from serving traffic. ```bash #!/bin/bash ETH_SYNCING=$(curl -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' http://localhost:8545 -H 'Content-Type: application/json') RESULT=$(echo "$ETH_SYNCING | jq -r .result) if [ "$RESULT" == "false" ]; then echo "Parity is ready to start accepting traffic" exit 0 else echo "Parity is still syncing the blockchain" exit 1 fi ``` * add sync check script * Fix docker script (#9854) * Dockerfile: change source path of the newly added check_sync.sh (#9869) * Do not use the home directory as the working dir in docker (#9834) * Do not create a home directory. * Re-add -m flag * fix docker build (#9971) * bump smallvec to 0.6 in ethcore-light, ethstore and whisper (#9588) * bump smallvec to 0.6 in ethcore-light, ethstore and whisper * bump transaction-pool * Fix test. * patch cargo to use tokio-proto from git repo this makes sure we no longer depend on smallvec 0.2.1 which is affected by servo/rust-smallvec#96 * use patched version of untrusted 0.5.1 * ci: allow audit to fail
1 parent 491f17f commit 126208c

File tree

22 files changed

+432
-220
lines changed

22 files changed

+432
-220
lines changed

.gitlab-ci.yml

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ test-linux:
4343
tags:
4444
- rust-stable
4545

46+
test-audit:
47+
stage: test
48+
script:
49+
- scripts/gitlab/cargo-audit.sh
50+
tags:
51+
- rust-stable
52+
allow_failure: true
53+
4654
build-linux:
4755
stage: build
4856
only: *releaseable_branches
@@ -103,25 +111,18 @@ publish-awss3:
103111
tags:
104112
- shell
105113

106-
docs-jsonrpc:
107-
stage: optional
114+
publish-docs:
115+
stage: publish
108116
only:
109117
- tags
110118
except:
111119
- nightly
112120
cache: {}
113121
script:
114-
- scripts/gitlab/docs-jsonrpc.sh
122+
- scripts/gitlab/publish-docs.sh
115123
tags:
116124
- shell
117125

118-
cargo-audit:
119-
stage: optional
120-
script:
121-
- scripts/gitlab/cargo-audit.sh
122-
tags:
123-
- rust-stable
124-
125126
build-android:
126127
stage: optional
127128
image: parity/rust-android:gitlab-ci
@@ -131,6 +132,7 @@ build-android:
131132
- scripts/gitlab/build-unix.sh
132133
tags:
133134
- rust-arm
135+
allow_failure: true
134136

135137
test-beta:
136138
stage: optional
@@ -140,6 +142,7 @@ test-beta:
140142
- scripts/gitlab/test-all.sh beta
141143
tags:
142144
- rust-beta
145+
allow_failure: true
143146

144147
test-nightly:
145148
stage: optional
@@ -149,3 +152,4 @@ test-nightly:
149152
- scripts/gitlab/test-all.sh nightly
150153
tags:
151154
- rust-nightly
155+
allow_failure: true

Cargo.lock

Lines changed: 29 additions & 48 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
description = "Parity Ethereum client"
33
name = "parity-ethereum"
44
# NOTE Make sure to update util/version/Cargo.toml as well
5-
version = "2.1.6"
5+
version = "2.1.7"
66
license = "GPL-3.0"
77
authors = ["Parity Technologies <[email protected]>"]
88

@@ -140,3 +140,5 @@ members = [
140140

141141
[patch.crates-io]
142142
ring = { git = "https://github.com/paritytech/ring" }
143+
tokio-proto = { git = "https://github.com/tokio-rs/tokio-proto.git", rev = "56c720e" }
144+
untrusted = { git = "https://github.com/paritytech/untrusted", branch = "0.5" }

ethcore/light/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ vm = { path = "../vm" }
2323
fastmap = { path = "../../util/fastmap" }
2424
rlp = { version = "0.2.4", features = ["ethereum"] }
2525
rlp_derive = { path = "../../util/rlp_derive" }
26-
smallvec = "0.4"
26+
smallvec = "0.6"
2727
futures = "0.1"
2828
rand = "0.4"
2929
itertools = "0.5"

ethcore/light/src/net/mod.rs

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use parking_lot::{Mutex, RwLock};
2828
use provider::Provider;
2929
use request::{Request, NetworkRequests as Requests, Response};
3030
use rlp::{RlpStream, Rlp};
31-
use std::collections::{HashMap, HashSet};
31+
use std::collections::{HashMap, HashSet, VecDeque};
3232
use std::fmt;
3333
use std::ops::{BitOr, BitAnd, Not};
3434
use std::sync::Arc;
@@ -38,7 +38,7 @@ use std::time::{Duration, Instant};
3838
use self::request_credits::{Credits, FlowParams};
3939
use self::context::{Ctx, TickCtx};
4040
use self::error::Punishment;
41-
use self::load_timer::{LoadDistribution, NullStore};
41+
use self::load_timer::{LoadDistribution, NullStore, MOVING_SAMPLE_SIZE};
4242
use self::request_set::RequestSet;
4343
use self::id_guard::IdGuard;
4444

@@ -70,6 +70,16 @@ const PROPAGATE_TIMEOUT_INTERVAL: Duration = Duration::from_secs(5);
7070
const RECALCULATE_COSTS_TIMEOUT: TimerToken = 3;
7171
const RECALCULATE_COSTS_INTERVAL: Duration = Duration::from_secs(60 * 60);
7272

73+
const STATISTICS_TIMEOUT: TimerToken = 4;
74+
const STATISTICS_INTERVAL: Duration = Duration::from_secs(15);
75+
76+
/// Maximum load share for the light server
77+
pub const MAX_LIGHTSERV_LOAD: f64 = 0.5;
78+
79+
/// Factor to multiply leecher count to cater for
80+
/// extra sudden connections (should be >= 1.0)
81+
pub const LEECHER_COUNT_FACTOR: f64 = 1.25;
82+
7383
// minimum interval between updates.
7484
const UPDATE_INTERVAL: Duration = Duration::from_millis(5000);
7585

@@ -256,18 +266,18 @@ pub trait Handler: Send + Sync {
256266
pub struct Config {
257267
/// How many stored seconds of credits peers should be able to accumulate.
258268
pub max_stored_seconds: u64,
259-
/// How much of the total load capacity each peer should be allowed to take.
260-
pub load_share: f64,
269+
/// The network config median peers (used as default peer count)
270+
pub median_peers: f64,
261271
}
262272

263273
impl Default for Config {
264274
fn default() -> Self {
265-
const LOAD_SHARE: f64 = 1.0 / 25.0;
275+
const MEDIAN_PEERS: f64 = 25.0;
266276
const MAX_ACCUMULATED: u64 = 60 * 5; // only charge for 5 minutes.
267277

268278
Config {
269279
max_stored_seconds: MAX_ACCUMULATED,
270-
load_share: LOAD_SHARE,
280+
median_peers: MEDIAN_PEERS,
271281
}
272282
}
273283
}
@@ -335,6 +345,42 @@ mod id_guard {
335345
}
336346
}
337347

348+
/// Provides various statistics that could
349+
/// be used to compute costs
350+
pub struct Statistics {
351+
/// Samples of peer count
352+
peer_counts: VecDeque<usize>,
353+
}
354+
355+
impl Statistics {
356+
/// Create a new Statistics instance
357+
pub fn new() -> Self {
358+
Statistics {
359+
peer_counts: VecDeque::with_capacity(MOVING_SAMPLE_SIZE),
360+
}
361+
}
362+
363+
/// Add a new peer_count sample
364+
pub fn add_peer_count(&mut self, peer_count: usize) {
365+
while self.peer_counts.len() >= MOVING_SAMPLE_SIZE {
366+
self.peer_counts.pop_front();
367+
}
368+
self.peer_counts.push_back(peer_count);
369+
}
370+
371+
/// Get the average peer count from previous samples. Is always >= 1.0
372+
pub fn avg_peer_count(&self) -> f64 {
373+
let len = self.peer_counts.len();
374+
if len == 0 {
375+
return 1.0;
376+
}
377+
let avg = self.peer_counts.iter()
378+
.fold(0, |sum: u32, &v| sum.saturating_add(v as u32)) as f64
379+
/ len as f64;
380+
avg.max(1.0)
381+
}
382+
}
383+
338384
/// This is an implementation of the light ethereum network protocol, abstracted
339385
/// over a `Provider` of data and a p2p network.
340386
///
@@ -359,6 +405,7 @@ pub struct LightProtocol {
359405
req_id: AtomicUsize,
360406
sample_store: Box<SampleStore>,
361407
load_distribution: LoadDistribution,
408+
statistics: RwLock<Statistics>,
362409
}
363410

364411
impl LightProtocol {
@@ -369,9 +416,11 @@ impl LightProtocol {
369416
let genesis_hash = provider.chain_info().genesis_hash;
370417
let sample_store = params.sample_store.unwrap_or_else(|| Box::new(NullStore));
371418
let load_distribution = LoadDistribution::load(&*sample_store);
419+
// Default load share relative to median peers
420+
let load_share = MAX_LIGHTSERV_LOAD / params.config.median_peers;
372421
let flow_params = FlowParams::from_request_times(
373422
|kind| load_distribution.expected_time(kind),
374-
params.config.load_share,
423+
load_share,
375424
Duration::from_secs(params.config.max_stored_seconds),
376425
);
377426

@@ -389,6 +438,7 @@ impl LightProtocol {
389438
req_id: AtomicUsize::new(0),
390439
sample_store,
391440
load_distribution,
441+
statistics: RwLock::new(Statistics::new()),
392442
}
393443
}
394444

@@ -408,6 +458,16 @@ impl LightProtocol {
408458
)
409459
}
410460

461+
/// Get the number of active light peers downloading from the
462+
/// node
463+
pub fn leecher_count(&self) -> usize {
464+
let credit_limit = *self.flow_params.read().limit();
465+
// Count the number of peers that used some credit
466+
self.peers.read().iter()
467+
.filter(|(_, p)| p.lock().local_credits.current() < credit_limit)
468+
.count()
469+
}
470+
411471
/// Make a request to a peer.
412472
///
413473
/// Fails on: nonexistent peer, network error, peer not server,
@@ -772,12 +832,16 @@ impl LightProtocol {
772832
fn begin_new_cost_period(&self, io: &IoContext) {
773833
self.load_distribution.end_period(&*self.sample_store);
774834

835+
let avg_peer_count = self.statistics.read().avg_peer_count();
836+
// Load share relative to average peer count +LEECHER_COUNT_FACTOR%
837+
let load_share = MAX_LIGHTSERV_LOAD / (avg_peer_count * LEECHER_COUNT_FACTOR);
775838
let new_params = Arc::new(FlowParams::from_request_times(
776839
|kind| self.load_distribution.expected_time(kind),
777-
self.config.load_share,
840+
load_share,
778841
Duration::from_secs(self.config.max_stored_seconds),
779842
));
780843
*self.flow_params.write() = new_params.clone();
844+
trace!(target: "pip", "New cost period: avg_peers={} ; cost_table:{:?}", avg_peer_count, new_params.cost_table());
781845

782846
let peers = self.peers.read();
783847
let now = Instant::now();
@@ -797,6 +861,11 @@ impl LightProtocol {
797861
peer_info.awaiting_acknowledge = Some((now, new_params.clone()));
798862
}
799863
}
864+
865+
fn tick_statistics(&self) {
866+
let leecher_count = self.leecher_count();
867+
self.statistics.write().add_peer_count(leecher_count);
868+
}
800869
}
801870

802871
impl LightProtocol {
@@ -1099,6 +1168,8 @@ impl NetworkProtocolHandler for LightProtocol {
10991168
.expect("Error registering sync timer.");
11001169
io.register_timer(RECALCULATE_COSTS_TIMEOUT, RECALCULATE_COSTS_INTERVAL)
11011170
.expect("Error registering request timer interval token.");
1171+
io.register_timer(STATISTICS_TIMEOUT, STATISTICS_INTERVAL)
1172+
.expect("Error registering statistics timer.");
11021173
}
11031174

11041175
fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) {
@@ -1119,6 +1190,7 @@ impl NetworkProtocolHandler for LightProtocol {
11191190
TICK_TIMEOUT => self.tick_handlers(&io),
11201191
PROPAGATE_TIMEOUT => self.propagate_transactions(&io),
11211192
RECALCULATE_COSTS_TIMEOUT => self.begin_new_cost_period(&io),
1193+
STATISTICS_TIMEOUT => self.tick_statistics(),
11221194
_ => warn!(target: "pip", "received timeout on unknown token {}", timer),
11231195
}
11241196
}

ethcore/light/src/net/tests/mod.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ use ethcore::client::{EachBlockWith, TestBlockChainClient};
2222
use ethcore::encoded;
2323
use ethcore::ids::BlockId;
2424
use ethereum_types::{H256, U256, Address};
25-
use net::{LightProtocol, Params, packet, Peer};
25+
use net::{LightProtocol, Params, packet, Peer, Statistics};
2626
use net::context::IoContext;
2727
use net::status::{Capabilities, Status};
28+
use net::load_timer::MOVING_SAMPLE_SIZE;
2829
use network::{PeerId, NodeId};
2930
use provider::Provider;
3031
use request;
@@ -780,3 +781,34 @@ fn get_transaction_index() {
780781
let expected = Expect::Respond(packet::RESPONSE, response);
781782
proto.handle_packet(&expected, 1, packet::REQUEST, &request_body);
782783
}
784+
785+
#[test]
786+
fn sync_statistics() {
787+
let mut stats = Statistics::new();
788+
789+
// Empty set should return 1.0
790+
assert_eq!(stats.avg_peer_count(), 1.0);
791+
792+
// Average < 1.0 should return 1.0
793+
stats.add_peer_count(0);
794+
assert_eq!(stats.avg_peer_count(), 1.0);
795+
796+
stats = Statistics::new();
797+
798+
const N: f64 = 50.0;
799+
800+
for i in 1..(N as usize + 1) {
801+
stats.add_peer_count(i);
802+
}
803+
804+
// Compute the average for the sum 1..N
805+
assert_eq!(stats.avg_peer_count(), N * (N + 1.0) / 2.0 / N);
806+
807+
for _ in 1..(MOVING_SAMPLE_SIZE + 1) {
808+
stats.add_peer_count(40);
809+
}
810+
811+
// Test that it returns the average of the last
812+
// `MOVING_SAMPLE_SIZE` values
813+
assert_eq!(stats.avg_peer_count(), 40.0);
814+
}

ethcore/src/client/client.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2252,35 +2252,44 @@ impl ImportSealedBlock for Client {
22522252
fn import_sealed_block(&self, block: SealedBlock) -> ImportResult {
22532253
let h = block.header().hash();
22542254
let start = Instant::now();
2255+
let header = block.header().clone();
22552256
let route = {
2257+
// Do a super duper basic verification to detect potential bugs
2258+
if let Err(e) = self.engine.verify_block_basic(&header) {
2259+
self.importer.bad_blocks.report(
2260+
block.rlp_bytes(),
2261+
format!("Detected an issue with locally sealed block: {}", e),
2262+
);
2263+
return Err(e.into());
2264+
}
2265+
22562266
// scope for self.import_lock
22572267
let _import_lock = self.importer.import_lock.lock();
22582268
trace_time!("import_sealed_block");
22592269

2260-
let number = block.header().number();
22612270
let block_data = block.rlp_bytes();
2262-
let header = block.header().clone();
22632271

22642272
let route = self.importer.commit_block(block, &header, encoded::Block::new(block_data), self);
2265-
trace!(target: "client", "Imported sealed block #{} ({})", number, h);
2273+
trace!(target: "client", "Imported sealed block #{} ({})", header.number(), header.hash());
22662274
self.state_db.write().sync_cache(&route.enacted, &route.retracted, false);
22672275
route
22682276
};
2277+
let h = header.hash();
22692278
let route = ChainRoute::from([route].as_ref());
22702279
self.importer.miner.chain_new_blocks(
22712280
self,
2272-
&[h.clone()],
2281+
&[h],
22732282
&[],
22742283
route.enacted(),
22752284
route.retracted(),
22762285
self.engine.seals_internally().is_some(),
22772286
);
22782287
self.notify(|notify| {
22792288
notify.new_blocks(
2280-
vec![h.clone()],
2289+
vec![h],
22812290
vec![],
22822291
route.clone(),
2283-
vec![h.clone()],
2292+
vec![h],
22842293
vec![],
22852294
start.elapsed(),
22862295
);

0 commit comments

Comments
 (0)