From 4158693470035f9a6577b65f428b13a6ae506f3e Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sat, 25 Feb 2017 11:07:38 +0100 Subject: [PATCH] network messages for transaction proof --- ethcore/light/src/net/mod.rs | 88 +++++++++++++++++++++++- ethcore/light/src/net/request_credits.rs | 3 +- ethcore/light/src/net/tests/mod.rs | 6 +- ethcore/light/src/provider.rs | 2 +- 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index ad1eaac00..6bb1cb227 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -26,7 +26,7 @@ use io::TimerToken; use network::{NetworkProtocolHandler, NetworkContext, PeerId}; use rlp::{RlpStream, Stream, UntrustedRlp, View}; use util::hash::H256; -use util::{Bytes, Mutex, RwLock, U256}; +use util::{Bytes, DBValue, Mutex, RwLock, U256}; use time::{Duration, SteadyTime}; use std::collections::HashMap; @@ -211,6 +211,8 @@ pub trait Handler: Send + Sync { /// Called when a peer responds with header proofs. Each proof should be a block header coupled /// with a series of trie nodes is ascending order by distance from the root. fn on_header_proofs(&self, _ctx: &EventContext, _req_id: ReqId, _proofs: &[(Bytes, Vec)]) { } + /// Called when a peer responds with a transaction proof. Each proof is a vector of state items. + fn on_transaction_proof(&self, _ctx: &EventContext, _req_id: ReqId, _state_items: &[DBValue]) { } /// Called to "tick" the handler periodically. fn tick(&self, _ctx: &BasicContext) { } /// Called on abort. This signals to handlers that they should clean up @@ -535,6 +537,9 @@ impl LightProtocol { packet::GET_HEADER_PROOFS => self.get_header_proofs(peer, io, rlp), packet::HEADER_PROOFS => self.header_proofs(peer, io, rlp), + packet::GET_TRANSACTION_PROOF => self.get_transaction_proof(peer, io, rlp), + packet::TRANSACTION_PROOF => self.transaction_proof(peer, io, rlp), + packet::SEND_TRANSACTIONS => self.relay_transactions(peer, io, rlp), other => { @@ -1178,6 +1183,87 @@ impl LightProtocol { Ok(()) } + // Receive a request for proof-of-execution. + fn get_transaction_proof(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> { + const MAX_GAS: usize = 10_000_000; // refuse to execute more than this amount of gas at once. + use util::Uint; + + let peers = self.peers.read(); + let peer = match peers.get(peer) { + Some(peer) => peer, + None => { + debug!(target: "les", "Ignoring request from unknown peer"); + return Ok(()) + } + }; + let mut peer = peer.lock(); + + let req_id: u64 = raw.val_at(0)?; + + let req = { + let req_rlp = raw.at(1)?; + request::TransactionProof { + at: req_rlp.val_at(0)?, + from: req_rlp.val_at(1)?, + action: if req_rlp.at(2)?.is_empty() { + Action::Create + } else { + Action::Call(req_rlp.val_at(2)?) + }, + gas: ::std::cmp::min(req_rlp.val_at(3)?, MAX_GAS.into()), + gas_price: req_rlp.val_at(4)?, + value: req_rlp.val_at(5)?, + data: req_rlp.val_at(6)?, + } + }; + + // always charge the peer for all the gas. + peer.deduct_max(&self.flow_params, request::Kind::TransactionProof, req.gas.low_u64() as usize)?; + + let response = match self.provider.transaction_proof(req) { + Some(res) => res, + None => vec![], + }; + + let cur_credits = peer.local_credits.current(); + + io.respond(packet::TRANSACTION_PROOF, { + let mut stream = RlpStream::new_list(3); + stream.append(&req_id).append(&cur_credits).begin_list(response.len()); + + for state_item in response { + stream.append(&&state_item[..]); + } + + stream.out() + }); + + Ok(()) + } + + // Receive a response for proof-of-execution. + fn transaction_proof(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> { + let id_guard = self.pre_verify_response(peer, request::Kind::HeaderProofs, &raw)?; + let raw_proof: Vec = raw.at(2)?.iter() + .map(|rlp| { + let mut db_val = DBValue::new(); + db_val.append_slice(rlp.data()?); + Ok(db_val) + }) + .collect::, ::rlp::DecoderError>>()?; + + let req_id = id_guard.defuse(); + for handler in &self.handlers { + handler.on_transaction_proof(&Ctx { + peer: *peer, + io: io, + proto: self, + }, req_id, &raw_proof); + } + + Ok(()) + } + // Receive a set of transactions to relay. fn relay_transactions(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> { const MAX_TRANSACTIONS: usize = 256; diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index 3a1cb9996..97aa9b431 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -114,7 +114,7 @@ impl RlpEncodable for CostTable { .append(&cost.1); } - s.begin_list(6); + s.begin_list(7); append_cost(s, packet::GET_BLOCK_HEADERS, &self.headers); append_cost(s, packet::GET_BLOCK_BODIES, &self.bodies); @@ -122,6 +122,7 @@ impl RlpEncodable for CostTable { append_cost(s, packet::GET_PROOFS, &self.state_proofs); append_cost(s, packet::GET_CONTRACT_CODES, &self.contract_codes); append_cost(s, packet::GET_HEADER_PROOFS, &self.header_proofs); + append_cost(s, packet::GET_TRANSACTION_PROOF, &self.transaction_proof); } } diff --git a/ethcore/light/src/net/tests/mod.rs b/ethcore/light/src/net/tests/mod.rs index 4efa6f680..8faba0b00 100644 --- a/ethcore/light/src/net/tests/mod.rs +++ b/ethcore/light/src/net/tests/mod.rs @@ -32,7 +32,7 @@ use provider::Provider; use request::{self, Request, Headers}; use rlp::*; -use util::{Bytes, H256, U256}; +use util::{Bytes, DBValue, H256, U256}; use std::sync::Arc; @@ -127,6 +127,10 @@ impl Provider for TestProvider { None } + fn transaction_proof(&self, _req: request::TransactionProof) -> Option> { + None + } + fn ready_transactions(&self) -> Vec { self.0.client.ready_transactions() } diff --git a/ethcore/light/src/provider.rs b/ethcore/light/src/provider.rs index 2ef7f1f04..3f55a6b99 100644 --- a/ethcore/light/src/provider.rs +++ b/ethcore/light/src/provider.rs @@ -367,7 +367,7 @@ impl Provider for LightProvider { None } - fn transaction_proof(&self, req: request::TransactionProof) -> Option> { + fn transaction_proof(&self, _req: request::TransactionProof) -> Option> { None }