Implement skeleton for transaction index and epoch transition proof PIP messages (#5908)

* add transaction index message without implementing

* add epoch proof fetch and response messages
This commit is contained in:
Robert Habermeier 2017-07-03 12:25:10 +02:00 committed by Arkadiy Paronyan
parent f22745eb0a
commit 826a4ca0a2
5 changed files with 183 additions and 7 deletions

View File

@ -55,6 +55,7 @@ fn hardcoded_serve_time(kind: Kind) -> u64 {
match kind {
Kind::Headers => 500_000,
Kind::HeaderProof => 500_000,
Kind::TransactionIndex => 500_000,
Kind::Receipts => 1_000_000,
Kind::Body => 1_000_000,
Kind::Account => 1_500_000,

View File

@ -80,7 +80,7 @@ pub const PROTOCOL_VERSIONS: &'static [u8] = &[1];
pub const MAX_PROTOCOL_VERSION: u8 = 1;
/// Packet count for PIP.
pub const PACKET_COUNT: u8 = 5;
pub const PACKET_COUNT: u8 = 9;
// packet ID definitions.
mod packet {
@ -100,6 +100,10 @@ mod packet {
// relay transactions to peers.
pub const SEND_TRANSACTIONS: u8 = 0x06;
// request and respond with epoch transition proof
pub const REQUEST_EPOCH_PROOF: u8 = 0x07;
pub const EPOCH_PROOF: u8 = 0x08;
}
// timeouts for different kinds of requests. all values are in milliseconds.
@ -110,6 +114,7 @@ mod timeout {
// timeouts per request within packet.
pub const HEADERS: i64 = 250; // per header?
pub const TRANSACTION_INDEX: i64 = 100;
pub const BODY: i64 = 50;
pub const RECEIPT: i64 = 50;
pub const PROOF: i64 = 100; // state proof
@ -523,6 +528,12 @@ impl LightProtocol {
packet::SEND_TRANSACTIONS => self.relay_transactions(peer, io, rlp),
packet::REQUEST_EPOCH_PROOF | packet::EPOCH_PROOF => {
// ignore these for now, but leave them specified.
debug!(target: "pip", "Ignoring request/response for epoch proof");
Ok(())
}
other => {
Err(Error::UnrecognizedPacket(other))
}
@ -867,6 +878,7 @@ impl LightProtocol {
match complete_req {
CompleteRequest::Headers(req) => self.provider.block_headers(req).map(Response::Headers),
CompleteRequest::HeaderProof(req) => self.provider.header_proof(req).map(Response::HeaderProof),
CompleteRequest::TransactionIndex(_) => None, // don't answer these yet, but leave them in protocol.
CompleteRequest::Body(req) => self.provider.block_body(req).map(Response::Body),
CompleteRequest::Receipts(req) => self.provider.block_receipts(req).map(Response::Receipts),
CompleteRequest::Account(req) => self.provider.account_proof(req).map(Response::Account),

View File

@ -83,6 +83,7 @@ impl Credits {
pub struct CostTable {
base: U256, // cost per packet.
headers: U256, // cost per header
transaction_index: U256,
body: U256,
receipts: U256,
account: U256,
@ -98,6 +99,7 @@ impl Default for CostTable {
CostTable {
base: 100000.into(),
headers: 10000.into(),
transaction_index: 10000.into(),
body: 15000.into(),
receipts: 5000.into(),
account: 25000.into(),
@ -119,8 +121,9 @@ impl Encodable for CostTable {
s.append(cost);
}
s.begin_list(9).append(&self.base);
s.begin_list(10).append(&self.base);
append_cost(s, &self.headers, request::Kind::Headers);
append_cost(s, &self.transaction_index, request::Kind::TransactionIndex);
append_cost(s, &self.body, request::Kind::Body);
append_cost(s, &self.receipts, request::Kind::Receipts);
append_cost(s, &self.account, request::Kind::Account);
@ -136,6 +139,7 @@ impl Decodable for CostTable {
let base = rlp.val_at(0)?;
let mut headers = None;
let mut transaction_index = None;
let mut body = None;
let mut receipts = None;
let mut account = None;
@ -148,6 +152,7 @@ impl Decodable for CostTable {
let cost = cost_list.val_at(1)?;
match cost_list.val_at(0)? {
request::Kind::Headers => headers = Some(cost),
request::Kind::TransactionIndex => transaction_index = Some(cost),
request::Kind::Body => body = Some(cost),
request::Kind::Receipts => receipts = Some(cost),
request::Kind::Account => account = Some(cost),
@ -163,6 +168,7 @@ impl Decodable for CostTable {
Ok(CostTable {
base: base,
headers: unwrap_cost(headers)?,
transaction_index: unwrap_cost(transaction_index)?,
body: unwrap_cost(body)?,
receipts: unwrap_cost(receipts)?,
account: unwrap_cost(account)?,
@ -224,6 +230,7 @@ impl FlowParams {
let costs = CostTable {
base: 0.into(),
headers: cost_for_kind(Kind::Headers),
transaction_index: cost_for_kind(Kind::TransactionIndex),
body: cost_for_kind(Kind::Body),
receipts: cost_for_kind(Kind::Receipts),
account: cost_for_kind(Kind::Account),
@ -249,6 +256,7 @@ impl FlowParams {
costs: CostTable {
base: free_cost.clone(),
headers: free_cost.clone(),
transaction_index: free_cost.clone(),
body: free_cost.clone(),
receipts: free_cost.clone(),
account: free_cost.clone(),
@ -278,6 +286,7 @@ impl FlowParams {
match *request {
Request::Headers(ref req) => self.costs.headers * req.max.into(),
Request::HeaderProof(_) => self.costs.header_proof,
Request::TransactionIndex(_) => self.costs.transaction_index,
Request::Body(_) => self.costs.body,
Request::Receipts(_) => self.costs.receipts,
Request::Account(_) => self.costs.account,

View File

@ -132,6 +132,7 @@ fn compute_timeout(reqs: &Requests) -> Duration {
tm + match *req {
Request::Headers(_) => timeout::HEADERS,
Request::HeaderProof(_) => timeout::HEADER_PROOF,
Request::TransactionIndex(_) => timeout::TRANSACTION_INDEX,
Request::Receipts(_) => timeout::RECEIPT,
Request::Body(_) => timeout::BODY,
Request::Account(_) => timeout::PROOF,

View File

@ -32,6 +32,11 @@ pub use self::header_proof::{
Incomplete as IncompleteHeaderProofRequest,
Response as HeaderProofResponse
};
pub use self::transaction_index::{
Complete as CompleteTransactionIndexRequest,
Incomplete as IncompleteTransactionIndexRequest,
Response as TransactionIndexResponse
};
pub use self::block_body::{
Complete as CompleteBodyRequest,
Incomplete as IncompleteBodyRequest,
@ -242,7 +247,8 @@ pub enum Request {
Headers(IncompleteHeadersRequest),
/// A request for a header proof (from a CHT)
HeaderProof(IncompleteHeaderProofRequest),
// TransactionIndex,
/// A request for a transaction index by hash.
TransactionIndex(IncompleteTransactionIndexRequest),
/// A request for a block's receipts.
Receipts(IncompleteReceiptsRequest),
/// A request for a block body.
@ -264,7 +270,8 @@ pub enum CompleteRequest {
Headers(CompleteHeadersRequest),
/// A request for a header proof (from a CHT)
HeaderProof(CompleteHeaderProofRequest),
// TransactionIndex,
/// A request for a transaction index by hash.
TransactionIndex(CompleteTransactionIndexRequest),
/// A request for a block's receipts.
Receipts(CompleteReceiptsRequest),
/// A request for a block body.
@ -285,6 +292,7 @@ impl CompleteRequest {
match *self {
CompleteRequest::Headers(_) => Kind::Headers,
CompleteRequest::HeaderProof(_) => Kind::HeaderProof,
CompleteRequest::TransactionIndex(_) => Kind::TransactionIndex,
CompleteRequest::Receipts(_) => Kind::Receipts,
CompleteRequest::Body(_) => Kind::Body,
CompleteRequest::Account(_) => Kind::Account,
@ -301,6 +309,7 @@ impl Request {
match *self {
Request::Headers(_) => Kind::Headers,
Request::HeaderProof(_) => Kind::HeaderProof,
Request::TransactionIndex(_) => Kind::TransactionIndex,
Request::Receipts(_) => Kind::Receipts,
Request::Body(_) => Kind::Body,
Request::Account(_) => Kind::Account,
@ -316,6 +325,7 @@ impl Decodable for Request {
match rlp.val_at::<Kind>(0)? {
Kind::Headers => Ok(Request::Headers(rlp.val_at(1)?)),
Kind::HeaderProof => Ok(Request::HeaderProof(rlp.val_at(1)?)),
Kind::TransactionIndex => Ok(Request::TransactionIndex(rlp.val_at(1)?)),
Kind::Receipts => Ok(Request::Receipts(rlp.val_at(1)?)),
Kind::Body => Ok(Request::Body(rlp.val_at(1)?)),
Kind::Account => Ok(Request::Account(rlp.val_at(1)?)),
@ -336,6 +346,7 @@ impl Encodable for Request {
match *self {
Request::Headers(ref req) => s.append(req),
Request::HeaderProof(ref req) => s.append(req),
Request::TransactionIndex(ref req) => s.append(req),
Request::Receipts(ref req) => s.append(req),
Request::Body(ref req) => s.append(req),
Request::Account(ref req) => s.append(req),
@ -356,6 +367,7 @@ impl IncompleteRequest for Request {
match *self {
Request::Headers(ref req) => req.check_outputs(f),
Request::HeaderProof(ref req) => req.check_outputs(f),
Request::TransactionIndex(ref req) => req.check_outputs(f),
Request::Receipts(ref req) => req.check_outputs(f),
Request::Body(ref req) => req.check_outputs(f),
Request::Account(ref req) => req.check_outputs(f),
@ -369,6 +381,7 @@ impl IncompleteRequest for Request {
match *self {
Request::Headers(ref req) => req.note_outputs(f),
Request::HeaderProof(ref req) => req.note_outputs(f),
Request::TransactionIndex(ref req) => req.note_outputs(f),
Request::Receipts(ref req) => req.note_outputs(f),
Request::Body(ref req) => req.note_outputs(f),
Request::Account(ref req) => req.note_outputs(f),
@ -382,6 +395,7 @@ impl IncompleteRequest for Request {
match *self {
Request::Headers(ref mut req) => req.fill(oracle),
Request::HeaderProof(ref mut req) => req.fill(oracle),
Request::TransactionIndex(ref mut req) => req.fill(oracle),
Request::Receipts(ref mut req) => req.fill(oracle),
Request::Body(ref mut req) => req.fill(oracle),
Request::Account(ref mut req) => req.fill(oracle),
@ -395,6 +409,7 @@ impl IncompleteRequest for Request {
match self {
Request::Headers(req) => req.complete().map(CompleteRequest::Headers),
Request::HeaderProof(req) => req.complete().map(CompleteRequest::HeaderProof),
Request::TransactionIndex(req) => req.complete().map(CompleteRequest::TransactionIndex),
Request::Receipts(req) => req.complete().map(CompleteRequest::Receipts),
Request::Body(req) => req.complete().map(CompleteRequest::Body),
Request::Account(req) => req.complete().map(CompleteRequest::Account),
@ -408,6 +423,7 @@ impl IncompleteRequest for Request {
match *self {
Request::Headers(ref mut req) => req.adjust_refs(mapping),
Request::HeaderProof(ref mut req) => req.adjust_refs(mapping),
Request::TransactionIndex(ref mut req) => req.adjust_refs(mapping),
Request::Receipts(ref mut req) => req.adjust_refs(mapping),
Request::Body(ref mut req) => req.adjust_refs(mapping),
Request::Account(ref mut req) => req.adjust_refs(mapping),
@ -441,7 +457,8 @@ pub enum Kind {
Headers = 0,
/// A request for a header proof.
HeaderProof = 1,
// TransactionIndex = 2,
/// A request for a transaction index.
TransactionIndex = 2,
/// A request for block receipts.
Receipts = 3,
/// A request for a block body.
@ -461,7 +478,7 @@ impl Decodable for Kind {
match rlp.as_val::<u8>()? {
0 => Ok(Kind::Headers),
1 => Ok(Kind::HeaderProof),
// 2 => Ok(Kind::TransactionIndex),
2 => Ok(Kind::TransactionIndex),
3 => Ok(Kind::Receipts),
4 => Ok(Kind::Body),
5 => Ok(Kind::Account),
@ -486,7 +503,8 @@ pub enum Response {
Headers(HeadersResponse),
/// A response for a header proof (from a CHT)
HeaderProof(HeaderProofResponse),
// TransactionIndex,
/// A response for a transaction index.
TransactionIndex(TransactionIndexResponse),
/// A response for a block's receipts.
Receipts(ReceiptsResponse),
/// A response for a block body.
@ -507,6 +525,7 @@ impl ResponseLike for Response {
match *self {
Response::Headers(ref res) => res.fill_outputs(f),
Response::HeaderProof(ref res) => res.fill_outputs(f),
Response::TransactionIndex(ref res) => res.fill_outputs(f),
Response::Receipts(ref res) => res.fill_outputs(f),
Response::Body(ref res) => res.fill_outputs(f),
Response::Account(ref res) => res.fill_outputs(f),
@ -523,6 +542,7 @@ impl Response {
match *self {
Response::Headers(_) => Kind::Headers,
Response::HeaderProof(_) => Kind::HeaderProof,
Response::TransactionIndex(_) => Kind::TransactionIndex,
Response::Receipts(_) => Kind::Receipts,
Response::Body(_) => Kind::Body,
Response::Account(_) => Kind::Account,
@ -538,6 +558,7 @@ impl Decodable for Response {
match rlp.val_at::<Kind>(0)? {
Kind::Headers => Ok(Response::Headers(rlp.val_at(1)?)),
Kind::HeaderProof => Ok(Response::HeaderProof(rlp.val_at(1)?)),
Kind::TransactionIndex => Ok(Response::TransactionIndex(rlp.val_at(1)?)),
Kind::Receipts => Ok(Response::Receipts(rlp.val_at(1)?)),
Kind::Body => Ok(Response::Body(rlp.val_at(1)?)),
Kind::Account => Ok(Response::Account(rlp.val_at(1)?)),
@ -558,6 +579,7 @@ impl Encodable for Response {
match *self {
Response::Headers(ref res) => s.append(res),
Response::HeaderProof(ref res) => s.append(res),
Response::TransactionIndex(ref res) => s.append(res),
Response::Receipts(ref res) => s.append(res),
Response::Body(ref res) => s.append(res),
Response::Account(ref res) => s.append(res),
@ -864,6 +886,117 @@ pub mod header_proof {
}
}
/// Request and response for transaction index.
pub mod transaction_index {
use super::{Field, NoSuchOutput, OutputKind, Output};
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
use util::H256;
/// Potentially incomplete transaction index request.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Incomplete {
/// Transaction hash to get index for.
pub hash: Field<H256>,
}
impl Decodable for Incomplete {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
Ok(Incomplete {
hash: rlp.val_at(0)?,
})
}
}
impl Encodable for Incomplete {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(1).append(&self.hash);
}
}
impl super::IncompleteRequest for Incomplete {
type Complete = Complete;
type Response = Response;
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
{
match self.hash {
Field::Scalar(_) => Ok(()),
Field::BackReference(req, idx) => f(req, idx, OutputKind::Hash),
}
}
fn note_outputs<F>(&self, mut f: F) where F: FnMut(usize, OutputKind) {
f(0, OutputKind::Number);
f(1, OutputKind::Hash);
}
fn fill<F>(&mut self, oracle: F) where F: Fn(usize, usize) -> Result<Output, NoSuchOutput> {
if let Field::BackReference(req, idx) = self.hash {
self.hash = match oracle(req, idx) {
Ok(Output::Number(hash)) => Field::Scalar(hash.into()),
_ => Field::BackReference(req, idx),
}
}
}
fn complete(self) -> Result<Self::Complete, NoSuchOutput> {
Ok(Complete {
hash: self.hash.into_scalar()?,
})
}
fn adjust_refs<F>(&mut self, mapping: F) where F: FnMut(usize) -> usize {
self.hash.adjust_req(mapping)
}
}
/// A complete transaction index request.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Complete {
/// The transaction hash to get index for.
pub hash: H256,
}
/// The output of a request for transaction index.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Response {
/// Block number.
pub num: u64,
/// Block hash
pub hash: H256,
/// Index in block.
pub index: u64,
}
impl super::ResponseLike for Response {
/// Fill reusable outputs by providing them to the function.
fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
f(0, Output::Number(self.num));
f(1, Output::Hash(self.hash));
}
}
impl Decodable for Response {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
Ok(Response {
num: rlp.val_at(0)?,
hash: rlp.val_at(1)?,
index: rlp.val_at(2)?,
})
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(3)
.append(&self.num)
.append(&self.hash)
.append(&self.index);
}
}
}
/// Request and response for block receipts
pub mod block_receipts {
use super::{Field, NoSuchOutput, OutputKind, Output};
@ -1704,6 +1837,26 @@ mod tests {
check_roundtrip(full_res);
}
#[test]
fn transaction_index_roundtrip() {
let req = IncompleteTransactionIndexRequest {
hash: Field::Scalar(Default::default()),
};
let full_req = Request::TransactionIndex(req.clone());
let res = TransactionIndexResponse {
num: 1000,
hash: ::util::H256::random(),
index: 4,
};
let full_res = Response::TransactionIndex(res.clone());
check_roundtrip(req);
check_roundtrip(full_req);
check_roundtrip(res);
check_roundtrip(full_res);
}
#[test]
fn receipts_roundtrip() {
let req = IncompleteReceiptsRequest {