enforce validity of on_demand requests

This commit is contained in:
Robert Habermeier 2017-02-07 16:13:56 +01:00
parent 9524ebbff1
commit b37124991c
2 changed files with 34 additions and 18 deletions

View File

@ -43,8 +43,6 @@ pub enum Error {
Canceled,
/// No suitable peers available to serve the request.
NoPeersAvailable,
/// Invalid request.
InvalidRequest,
/// Request timed out.
TimedOut,
}
@ -95,6 +93,7 @@ enum Pending {
pub struct OnDemand {
peers: RwLock<HashMap<PeerId, Peer>>,
pending_requests: RwLock<HashMap<ReqId, Pending>>,
orphaned_requests: RwLock<Vec<Pending>>,
}
impl Default for OnDemand {
@ -102,6 +101,7 @@ impl Default for OnDemand {
OnDemand {
peers: RwLock::new(HashMap::new()),
pending_requests: RwLock::new(HashMap::new()),
orphaned_requests: RwLock::new(Vec::new()),
}
}
}
@ -117,20 +117,13 @@ impl OnDemand {
// dispatch the request, completing the request if no peers available.
fn dispatch_header_by_number(&self, ctx: &BasicContext, req: request::HeaderByNumber, sender: Sender<(encoded::Header, U256)>) {
let num = req.num;
let cht_num = match ::cht::block_to_cht_number(req.num) {
Some(cht_num) => cht_num,
None => {
warn!(target: "on_demand", "Attempted to dispatch invalid header proof: req.num == 0");
sender.complete(Err(Error::InvalidRequest));
return;
}
};
let num = req.num();
let cht_num = req.cht_num();
let les_req = LesRequest::HeaderProofs(les_request::HeaderProofs {
requests: vec![les_request::HeaderProof {
cht_number: cht_num,
block_number: req.num,
block_number: num,
from_level: 0,
}],
});

View File

@ -59,12 +59,33 @@ impl From<Box<TrieError>> for Error {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HeaderByNumber {
/// The header's number.
pub num: u64,
num: u64,
/// The cht number for the given block number.
cht_num: u64,
/// The root of the CHT containing this header.
pub cht_root: H256,
cht_root: H256,
}
impl HeaderByNumber {
/// Construct a new header-by-number request. Fails if the given number is 0.
/// Provide the expected CHT root to compare against.
pub fn new(num: u64, cht_root: H256) -> Option<Self> {
::cht::block_to_cht_number(num).map(|cht_num| HeaderByNumber {
num: num,
cht_num: cht_num,
cht_root: cht_root,
})
}
/// Access the requested block number.
pub fn num(&self) -> u64 { self.num }
/// Access the CHT number.
pub fn cht_num(&self) -> u64 { self.cht_num }
/// Access the expected CHT root.
pub fn cht_root(&self) -> H256 { self.cht_root }
/// Check a response with a header and cht proof.
pub fn check_response(&self, header: &[u8], proof: &[Bytes]) -> Result<(encoded::Header, U256), Error> {
let (expected_hash, td) = match ::cht::check_proof(proof, self.num, self.cht_root) {
@ -222,6 +243,11 @@ mod tests {
use ethcore::encoded;
use ethcore::receipt::Receipt;
#[test]
fn no_invalid_header_by_number() {
assert!(HeaderByNumber::new(0, Default::default()).is_none())
}
#[test]
fn check_header_by_number() {
use ::cht;
@ -244,10 +270,7 @@ mod tests {
};
let proof = cht.prove(10_000, 0).unwrap().unwrap();
let req = HeaderByNumber {
num: 10_000,
cht_root: cht.root(),
};
let req = HeaderByNumber::new(10_000, cht.root()).unwrap();
let raw_header = test_client.block_header(::ethcore::ids::BlockId::Number(10_000)).unwrap();