network messages for transaction proof

This commit is contained in:
Robert Habermeier 2017-02-25 11:07:38 +01:00
parent 92e5982127
commit 4158693470
4 changed files with 95 additions and 4 deletions

View File

@ -26,7 +26,7 @@ use io::TimerToken;
use network::{NetworkProtocolHandler, NetworkContext, PeerId}; use network::{NetworkProtocolHandler, NetworkContext, PeerId};
use rlp::{RlpStream, Stream, UntrustedRlp, View}; use rlp::{RlpStream, Stream, UntrustedRlp, View};
use util::hash::H256; use util::hash::H256;
use util::{Bytes, Mutex, RwLock, U256}; use util::{Bytes, DBValue, Mutex, RwLock, U256};
use time::{Duration, SteadyTime}; use time::{Duration, SteadyTime};
use std::collections::HashMap; 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 /// 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. /// 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<Bytes>)]) { } fn on_header_proofs(&self, _ctx: &EventContext, _req_id: ReqId, _proofs: &[(Bytes, Vec<Bytes>)]) { }
/// 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. /// Called to "tick" the handler periodically.
fn tick(&self, _ctx: &BasicContext) { } fn tick(&self, _ctx: &BasicContext) { }
/// Called on abort. This signals to handlers that they should clean up /// 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::GET_HEADER_PROOFS => self.get_header_proofs(peer, io, rlp),
packet::HEADER_PROOFS => self.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), packet::SEND_TRANSACTIONS => self.relay_transactions(peer, io, rlp),
other => { other => {
@ -1178,6 +1183,87 @@ impl LightProtocol {
Ok(()) 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<DBValue> = raw.at(2)?.iter()
.map(|rlp| {
let mut db_val = DBValue::new();
db_val.append_slice(rlp.data()?);
Ok(db_val)
})
.collect::<Result<Vec<_>, ::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. // Receive a set of transactions to relay.
fn relay_transactions(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> { fn relay_transactions(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
const MAX_TRANSACTIONS: usize = 256; const MAX_TRANSACTIONS: usize = 256;

View File

@ -114,7 +114,7 @@ impl RlpEncodable for CostTable {
.append(&cost.1); .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_HEADERS, &self.headers);
append_cost(s, packet::GET_BLOCK_BODIES, &self.bodies); 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_PROOFS, &self.state_proofs);
append_cost(s, packet::GET_CONTRACT_CODES, &self.contract_codes); 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_HEADER_PROOFS, &self.header_proofs);
append_cost(s, packet::GET_TRANSACTION_PROOF, &self.transaction_proof);
} }
} }

View File

@ -32,7 +32,7 @@ use provider::Provider;
use request::{self, Request, Headers}; use request::{self, Request, Headers};
use rlp::*; use rlp::*;
use util::{Bytes, H256, U256}; use util::{Bytes, DBValue, H256, U256};
use std::sync::Arc; use std::sync::Arc;
@ -127,6 +127,10 @@ impl Provider for TestProvider {
None None
} }
fn transaction_proof(&self, _req: request::TransactionProof) -> Option<Vec<DBValue>> {
None
}
fn ready_transactions(&self) -> Vec<PendingTransaction> { fn ready_transactions(&self) -> Vec<PendingTransaction> {
self.0.client.ready_transactions() self.0.client.ready_transactions()
} }

View File

@ -367,7 +367,7 @@ impl<L: AsLightClient + Send + Sync> Provider for LightProvider<L> {
None None
} }
fn transaction_proof(&self, req: request::TransactionProof) -> Option<Vec<DBValue>> { fn transaction_proof(&self, _req: request::TransactionProof) -> Option<Vec<DBValue>> {
None None
} }