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

backports for 2.3.0 beta #10164

Merged
merged 7 commits into from Jan 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
65 changes: 31 additions & 34 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 3 additions & 9 deletions ethcore/res/ethereum/foundation.json
Expand Up @@ -9,8 +9,7 @@
"durationLimit": "0xd",
"blockReward": {
"0x0": "0x4563918244f40000",
"0x42ae50": "0x29a2241af62c0000",
"0x6c0840": "0x1bc16d674ec80000"
"0x42ae50": "0x29a2241af62c0000"
},
"homesteadTransition": "0x118c30",
"daoHardforkTransition": "0x1d4c00",
Expand Down Expand Up @@ -135,8 +134,7 @@
],
"eip100bTransition": "0x42ae50",
"difficultyBombDelays": {
"0x42ae50": "0x2dc6c0",
"0x6c0840": "0x1e8480"
"0x42ae50": "0x2dc6c0"
}
}
}
Expand All @@ -160,11 +158,7 @@
"eip140Transition": "0x42ae50",
"eip211Transition": "0x42ae50",
"eip214Transition": "0x42ae50",
"eip658Transition": "0x42ae50",
"eip145Transition": "0x6c0840",
"eip1014Transition": "0x6c0840",
"eip1052Transition": "0x6c0840",
"eip1283Transition": "0x6c0840"
"eip658Transition": "0x42ae50"
},
"genesis": {
"seal": {
Expand Down
2 changes: 1 addition & 1 deletion ethcore/res/ethereum/tests
Submodule tests updated 110 files
44 changes: 3 additions & 41 deletions ethcore/res/ethereum/tests-issues/currents.json
@@ -1,42 +1,4 @@
{ "block":
[
{
"reference": "None",
"comment": "This failing test is deemed skippable. Could not happen on a mainnet.",
"failing": "GeneralStateTest_stCreate2",
"subtests": ["RevertInCreateInInitCreate2_d0g0v0_Constantinople"]
},
{
"reference": "None",
"comment": "This failing test is deemed skippable. Could not happen on a mainnet.",
"failing": "GeneralStateTest_stRevertTest",
"subtests": ["RevertInCreateInInit_d0g0v0_Constantinople"]
}
],
"state":
[
{
"reference": "None",
"comment": "This failing test is deemed skippable. Could not happen on a mainnet.",
"failing": "stCreate2Test",
"subtests": {
"RevertInCreateInInitCreate2": {
"subnumbers": ["1"],
"chain": "Constantinople (test)"
}
}
},
{
"reference": "None",
"comment": "This failing test is deemed skippable. Could not happen on a mainnet.",
"failing": "stRevertTest",
"subtests": {
"RevertInCreateInInit": {
"subnumbers": ["1"],
"chain": "Constantinople (test)"
}
}
}

]
{
"block": [],
"state": []
}
7 changes: 6 additions & 1 deletion ethcore/src/externalities.rs
Expand Up @@ -116,7 +116,12 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
where T: Tracer, V: VMTracer, B: StateBackend
{
fn initial_storage_at(&self, key: &H256) -> vm::Result<H256> {
self.state.checkpoint_storage_at(0, &self.origin_info.address, key).map(|v| v.unwrap_or(H256::zero())).map_err(Into::into)
if self.state.is_base_storage_root_unchanged(&self.origin_info.address)? {
self.state.checkpoint_storage_at(0, &self.origin_info.address, key).map(|v| v.unwrap_or(H256::zero())).map_err(Into::into)
} else {
warn!(target: "externalities", "Detected existing account {:#x} where a forced contract creation happened.", self.origin_info.address);
Ok(H256::zero())
}
}

fn storage_at(&self, key: &H256) -> vm::Result<H256> {
Expand Down
5 changes: 5 additions & 0 deletions ethcore/src/state/account.rs
Expand Up @@ -451,6 +451,11 @@ impl Account {
}
}

/// Whether the base storage root of this account is unchanged.
pub fn is_base_storage_root_unchanged(&self) -> bool {
self.original_storage_cache.is_none()
}

/// Storage root where the account changes are based upon.
pub fn base_storage_root(&self) -> H256 {
self.storage_root
Expand Down
7 changes: 7 additions & 0 deletions ethcore/src/state/mod.rs
Expand Up @@ -539,6 +539,13 @@ impl<B: Backend> State<B> {
|a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce()))
}

/// Whether the base storage root of an account remains unchanged.
pub fn is_base_storage_root_unchanged(&self, a: &Address) -> TrieResult<bool> {
Ok(self.ensure_cached(a, RequireCache::None, true,
|a| a.as_ref().map(|account| account.is_base_storage_root_unchanged()))?
.unwrap_or(true))
}

/// Get the storage root of account `a`.
pub fn storage_root(&self, a: &Address) -> TrieResult<Option<H256>> {
self.ensure_cached(a, RequireCache::None, true,
Expand Down
93 changes: 73 additions & 20 deletions util/network-devp2p/src/discovery.rs
Expand Up @@ -53,12 +53,15 @@ const REQUEST_BACKOFF: [Duration; 4] = [
Duration::from_secs(64)
];

const NODE_LAST_SEEN_TIMEOUT: Duration = Duration::from_secs(24*60*60);

#[derive(Clone, Debug)]
pub struct NodeEntry {
pub id: NodeId,
pub endpoint: NodeEndpoint,
}

#[derive(Debug)]
pub struct BucketEntry {
pub address: NodeEntry,
pub id_hash: H256,
Expand Down Expand Up @@ -89,6 +92,12 @@ struct FindNodeRequest {
answered: bool,
}

#[derive(Clone, Copy)]
enum PingReason {
Default,
FromDiscoveryRequest(NodeId)
}

struct PingRequest {
// Time when the request was sent
sent_at: Instant,
Expand All @@ -99,8 +108,10 @@ struct PingRequest {
// The hash Parity used to respond with (until rev 01f825b0e1f1c4c420197b51fc801cbe89284b29)
#[deprecated()]
deprecated_echo_hash: H256,
reason: PingReason
}

#[derive(Debug)]
pub struct NodeBucket {
nodes: VecDeque<BucketEntry>, //sorted by last active
}
Expand Down Expand Up @@ -178,7 +189,7 @@ impl<'a> Discovery<'a> {
if self.node_buckets[dist].nodes.iter().any(|n| n.id_hash == id_hash) {
return;
}
self.try_ping(e);
self.try_ping(e, PingReason::Default);
}
}

Expand Down Expand Up @@ -221,7 +232,7 @@ impl<'a> Discovery<'a> {
} else { None }
};
if let Some(node) = ping {
self.try_ping(node);
self.try_ping(node, PingReason::Default);
}
Some(TableUpdates { added: added_map, removed: HashSet::new() })
}
Expand All @@ -244,7 +255,7 @@ impl<'a> Discovery<'a> {
fn update_new_nodes(&mut self) {
while self.in_flight_pings.len() < MAX_NODES_PING {
match self.adding_nodes.pop() {
Some(next) => self.try_ping(next),
Some(next) => self.try_ping(next, PingReason::Default),
None => break,
}
}
Expand Down Expand Up @@ -298,7 +309,7 @@ impl<'a> Discovery<'a> {
None // a and b are equal, so log distance is -inf
}

fn try_ping(&mut self, node: NodeEntry) {
fn try_ping(&mut self, node: NodeEntry, reason: PingReason) {
if !self.is_allowed(&node) {
trace!(target: "discovery", "Node {:?} not allowed", node);
return;
Expand All @@ -313,7 +324,7 @@ impl<'a> Discovery<'a> {
}

if self.in_flight_pings.len() < MAX_NODES_PING {
self.ping(&node)
self.ping(&node, reason)
.unwrap_or_else(|e| {
warn!(target: "discovery", "Error sending Ping packet: {:?}", e);
});
Expand All @@ -322,7 +333,7 @@ impl<'a> Discovery<'a> {
}
}

fn ping(&mut self, node: &NodeEntry) -> Result<(), Error> {
fn ping(&mut self, node: &NodeEntry, reason: PingReason) -> Result<(), Error> {
let mut rlp = RlpStream::new_list(4);
rlp.append(&PROTOCOL_VERSION);
self.public_endpoint.to_rlp_list(&mut rlp);
Expand All @@ -336,6 +347,7 @@ impl<'a> Discovery<'a> {
node: node.clone(),
echo_hash: hash,
deprecated_echo_hash: old_parity_hash,
reason: reason
});

trace!(target: "discovery", "Sent Ping to {:?} ; node_id={:#x}", &node.endpoint, node.id);
Expand Down Expand Up @@ -514,7 +526,7 @@ impl<'a> Discovery<'a> {
if request.deprecated_echo_hash == echo_hash {
trace!(target: "discovery", "Got Pong from an old parity-ethereum version.");
}
Some(request.node.clone())
Some((request.node.clone(), request.reason.clone()))
}
};

Expand All @@ -528,29 +540,70 @@ impl<'a> Discovery<'a> {
},
};

if let Some(node) = expected_node {
if let Some((node, ping_reason)) = expected_node {
if let PingReason::FromDiscoveryRequest(target) = ping_reason {
self.respond_with_discovery(target, &node)?;
}
Ok(self.update_node(node))
} else {
debug!(target: "discovery", "Got unexpected Pong from {:?} ; request not found", &from);
Ok(None)
}
}

fn on_find_node(&mut self, rlp: &Rlp, _node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, Error> {
fn on_find_node(&mut self, rlp: &Rlp, node_id: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, Error> {
trace!(target: "discovery", "Got FindNode from {:?}", &from);
let target: NodeId = rlp.val_at(0)?;
let timestamp: u64 = rlp.val_at(1)?;
self.check_timestamp(timestamp)?;

let node = NodeEntry {
id: node_id.clone(),
endpoint: NodeEndpoint {
address: *from,
udp_port: from.port()
}
};

if self.is_a_valid_known_node(&node) {
self.respond_with_discovery(target, &node)?;
} else {
// Make sure the request source is actually there and responds to pings before actually responding
self.try_ping(node, PingReason::FromDiscoveryRequest(target));
}
Ok(None)
}

fn is_a_valid_known_node(&self, node: &NodeEntry) -> bool {
let id_hash = keccak(node.id);
let dist = match Discovery::distance(&self.id_hash, &id_hash) {
Some(dist) => dist,
None => {
debug!(target: "discovery", "Got an incoming discovery request from self: {:?}", node);
return false;
}
};

let bucket = &self.node_buckets[dist];
if let Some(known_node) = bucket.nodes.iter().find(|n| n.address.id == node.id) {
debug!(target: "discovery", "Found a known node in a bucket when processing discovery: {:?}/{:?}", known_node, node);
(known_node.address.endpoint == node.endpoint) && (known_node.last_seen.elapsed() < NODE_LAST_SEEN_TIMEOUT)
} else {
false
}
}

fn respond_with_discovery(&mut self, target: NodeId, node: &NodeEntry) -> Result<(), Error> {
let nearest = self.nearest_node_entries(&target);
if nearest.is_empty() {
return Ok(None);
return Ok(());
}
let mut packets = Discovery::prepare_neighbours_packets(&nearest);
for p in packets.drain(..) {
self.send_packet(PACKET_NEIGHBOURS, from, &p)?;
self.send_packet(PACKET_NEIGHBOURS, &node.endpoint.address, &p)?;
}
trace!(target: "discovery", "Sent {} Neighbours to {:?}", nearest.len(), &from);
Ok(None)
trace!(target: "discovery", "Sent {} Neighbours to {:?}", nearest.len(), &node.endpoint);
Ok(())
}

fn prepare_neighbours_packets(nearest: &[NodeEntry]) -> Vec<Bytes> {
Expand Down Expand Up @@ -825,17 +878,17 @@ mod tests {
}

// After 4 discovery rounds, the first one should have learned about the rest.
for _round in 0 .. 4 {
for _round in 0 .. 5 {
discovery_handlers[0].round();

let mut continue_loop = true;
while continue_loop {
continue_loop = false;

// Process all queued messages.
for i in 0 .. 5 {
let src = discovery_handlers[i].public_endpoint.address.clone();
while let Some(datagram) = discovery_handlers[i].dequeue_send() {
for i in 0 .. 20 {
let src = discovery_handlers[i%5].public_endpoint.address.clone();
while let Some(datagram) = discovery_handlers[i%5].dequeue_send() {
let dest = discovery_handlers.iter_mut()
.find(|disc| datagram.address == disc.public_endpoint.address)
.unwrap();
Expand Down Expand Up @@ -927,14 +980,14 @@ mod tests {
let mut discovery = Discovery { request_backoff: &request_backoff, ..discovery };

for _ in 0..2 {
discovery.ping(&node_entries[101]).unwrap();
discovery.ping(&node_entries[101], PingReason::Default).unwrap();
let num_nodes = total_bucket_nodes(&discovery.node_buckets);
discovery.check_expired(Instant::now() + PING_TIMEOUT);
let removed = num_nodes - total_bucket_nodes(&discovery.node_buckets);
assert_eq!(removed, 0);
}

discovery.ping(&node_entries[101]).unwrap();
discovery.ping(&node_entries[101], PingReason::Default).unwrap();
let num_nodes = total_bucket_nodes(&discovery.node_buckets);
discovery.check_expired(Instant::now() + PING_TIMEOUT);
let removed = num_nodes - total_bucket_nodes(&discovery.node_buckets);
Expand Down Expand Up @@ -1121,7 +1174,7 @@ mod tests {
let mut discovery1 = Discovery::new(&key1, ep1.clone(), IpFilter::default());
let mut discovery2 = Discovery::new(&key2, ep2.clone(), IpFilter::default());

discovery1.ping(&NodeEntry { id: discovery2.id, endpoint: ep2.clone() }).unwrap();
discovery1.ping(&NodeEntry { id: discovery2.id, endpoint: ep2.clone() }, PingReason::Default).unwrap();
let ping_data = discovery1.dequeue_send().unwrap();
assert!(!discovery1.any_sends_queued());
let data = &ping_data.payload[(32 + 65)..];
Expand Down