serve epoch signals over network and check them
This commit is contained in:
parent
7f3e718851
commit
2ff3dff6ea
@ -16,9 +16,13 @@
|
|||||||
|
|
||||||
//! Trait for fetching chain data.
|
//! Trait for fetching chain data.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ethcore::engines::{Engine, StateDependentProof};
|
||||||
use ethcore::header::Header;
|
use ethcore::header::Header;
|
||||||
use ethcore::receipt::Receipt;
|
use ethcore::receipt::Receipt;
|
||||||
use futures::future::IntoFuture;
|
use futures::future::IntoFuture;
|
||||||
|
use util::H256;
|
||||||
|
|
||||||
/// Provides full chain data.
|
/// Provides full chain data.
|
||||||
pub trait ChainDataFetcher: Send + Sync + 'static {
|
pub trait ChainDataFetcher: Send + Sync + 'static {
|
||||||
@ -39,7 +43,7 @@ pub trait ChainDataFetcher: Send + Sync + 'static {
|
|||||||
fn block_receipts(&self, header: &Header) -> Self::Receipts;
|
fn block_receipts(&self, header: &Header) -> Self::Receipts;
|
||||||
|
|
||||||
/// Fetch epoch transition proof at given header.
|
/// Fetch epoch transition proof at given header.
|
||||||
fn epoch_transition(&self, header: &Header) -> Self::Transition;
|
fn epoch_transition(&self, hash: H256, engine: Arc<Engine>, checker: Arc<StateDependentProof>) -> Self::Transition;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetcher implementation which cannot fetch anything.
|
/// Fetcher implementation which cannot fetch anything.
|
||||||
@ -63,7 +67,7 @@ impl ChainDataFetcher for Unavailable {
|
|||||||
Err("fetching block receipts unavailable")
|
Err("fetching block receipts unavailable")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn epoch_transition(&self, _header: &Header) -> Self::Body {
|
fn epoch_transition(&self, _h: H256, _e: Arc<Engine>, _check: Arc<StateDependentProof>) -> Self::Transition {
|
||||||
Err("fetching epoch transition proofs unavailable")
|
Err("fetching epoch transition proofs unavailable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -508,14 +508,11 @@ impl<T: ChainDataFetcher> Client<T> {
|
|||||||
let proof = match proof {
|
let proof = match proof {
|
||||||
Proof::Known(known) => known,
|
Proof::Known(known) => known,
|
||||||
Proof::WithState(state_dependent) => {
|
Proof::WithState(state_dependent) => {
|
||||||
loop {
|
self.fetcher.epoch_transition(
|
||||||
let proof = self.fetcher.epoch_transition(header).into_future().wait()?;
|
header.hash(),
|
||||||
match state_dependent.check_proof(&*self.engine, &proof) {
|
self.engine.clone(),
|
||||||
Ok(()) => break proof,
|
state_dependent
|
||||||
Err(e) =>
|
).into_future().wait()?
|
||||||
debug!(target: "client", "Fetched bad epoch transition proof from network: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ fn hardcoded_serve_time(kind: Kind) -> u64 {
|
|||||||
Kind::Storage => 2_000_000,
|
Kind::Storage => 2_000_000,
|
||||||
Kind::Code => 1_500_000,
|
Kind::Code => 1_500_000,
|
||||||
Kind::Execution => 250, // per gas.
|
Kind::Execution => 250, // per gas.
|
||||||
|
Kind::Signal => 500_000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,9 +102,8 @@ mod packet {
|
|||||||
// relay transactions to peers.
|
// relay transactions to peers.
|
||||||
pub const SEND_TRANSACTIONS: u8 = 0x06;
|
pub const SEND_TRANSACTIONS: u8 = 0x06;
|
||||||
|
|
||||||
// request and respond with epoch transition proof
|
// two packets were previously meant to be reserved for epoch proofs.
|
||||||
pub const REQUEST_EPOCH_PROOF: u8 = 0x07;
|
// these have since been moved to requests.
|
||||||
pub const EPOCH_PROOF: u8 = 0x08;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// timeouts for different kinds of requests. all values are in milliseconds.
|
// timeouts for different kinds of requests. all values are in milliseconds.
|
||||||
@ -122,6 +121,7 @@ mod timeout {
|
|||||||
pub const CONTRACT_CODE: i64 = 100;
|
pub const CONTRACT_CODE: i64 = 100;
|
||||||
pub const HEADER_PROOF: i64 = 100;
|
pub const HEADER_PROOF: i64 = 100;
|
||||||
pub const TRANSACTION_PROOF: i64 = 1000; // per gas?
|
pub const TRANSACTION_PROOF: i64 = 1000; // per gas?
|
||||||
|
pub const EPOCH_SIGNAL: i64 = 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A request id.
|
/// A request id.
|
||||||
@ -582,12 +582,6 @@ impl LightProtocol {
|
|||||||
|
|
||||||
packet::SEND_TRANSACTIONS => self.relay_transactions(peer, io, rlp),
|
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 => {
|
other => {
|
||||||
Err(Error::UnrecognizedPacket(other))
|
Err(Error::UnrecognizedPacket(other))
|
||||||
}
|
}
|
||||||
@ -950,6 +944,7 @@ impl LightProtocol {
|
|||||||
CompleteRequest::Storage(req) => self.provider.storage_proof(req).map(Response::Storage),
|
CompleteRequest::Storage(req) => self.provider.storage_proof(req).map(Response::Storage),
|
||||||
CompleteRequest::Code(req) => self.provider.contract_code(req).map(Response::Code),
|
CompleteRequest::Code(req) => self.provider.contract_code(req).map(Response::Code),
|
||||||
CompleteRequest::Execution(req) => self.provider.transaction_proof(req).map(Response::Execution),
|
CompleteRequest::Execution(req) => self.provider.transaction_proof(req).map(Response::Execution),
|
||||||
|
CompleteRequest::Signal(req) => self.provider.epoch_signal(req).map(Response::Signal),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ pub struct CostTable {
|
|||||||
code: U256,
|
code: U256,
|
||||||
header_proof: U256,
|
header_proof: U256,
|
||||||
transaction_proof: U256, // cost per gas.
|
transaction_proof: U256, // cost per gas.
|
||||||
|
epoch_signal: U256,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CostTable {
|
impl Default for CostTable {
|
||||||
@ -107,6 +108,7 @@ impl Default for CostTable {
|
|||||||
code: 20000.into(),
|
code: 20000.into(),
|
||||||
header_proof: 15000.into(),
|
header_proof: 15000.into(),
|
||||||
transaction_proof: 2.into(),
|
transaction_proof: 2.into(),
|
||||||
|
epoch_signal: 10000.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +123,7 @@ impl Encodable for CostTable {
|
|||||||
s.append(cost);
|
s.append(cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
s.begin_list(10).append(&self.base);
|
s.begin_list(11).append(&self.base);
|
||||||
append_cost(s, &self.headers, request::Kind::Headers);
|
append_cost(s, &self.headers, request::Kind::Headers);
|
||||||
append_cost(s, &self.transaction_index, request::Kind::TransactionIndex);
|
append_cost(s, &self.transaction_index, request::Kind::TransactionIndex);
|
||||||
append_cost(s, &self.body, request::Kind::Body);
|
append_cost(s, &self.body, request::Kind::Body);
|
||||||
@ -131,6 +133,7 @@ impl Encodable for CostTable {
|
|||||||
append_cost(s, &self.code, request::Kind::Code);
|
append_cost(s, &self.code, request::Kind::Code);
|
||||||
append_cost(s, &self.header_proof, request::Kind::HeaderProof);
|
append_cost(s, &self.header_proof, request::Kind::HeaderProof);
|
||||||
append_cost(s, &self.transaction_proof, request::Kind::Execution);
|
append_cost(s, &self.transaction_proof, request::Kind::Execution);
|
||||||
|
append_cost(s, &self.epoch_signal, request::Kind::Signal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +150,7 @@ impl Decodable for CostTable {
|
|||||||
let mut code = None;
|
let mut code = None;
|
||||||
let mut header_proof = None;
|
let mut header_proof = None;
|
||||||
let mut transaction_proof = None;
|
let mut transaction_proof = None;
|
||||||
|
let mut epoch_signal = None;
|
||||||
|
|
||||||
for cost_list in rlp.iter().skip(1) {
|
for cost_list in rlp.iter().skip(1) {
|
||||||
let cost = cost_list.val_at(1)?;
|
let cost = cost_list.val_at(1)?;
|
||||||
@ -160,6 +164,7 @@ impl Decodable for CostTable {
|
|||||||
request::Kind::Code => code = Some(cost),
|
request::Kind::Code => code = Some(cost),
|
||||||
request::Kind::HeaderProof => header_proof = Some(cost),
|
request::Kind::HeaderProof => header_proof = Some(cost),
|
||||||
request::Kind::Execution => transaction_proof = Some(cost),
|
request::Kind::Execution => transaction_proof = Some(cost),
|
||||||
|
request::Kind::Signal => epoch_signal = Some(cost),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +181,7 @@ impl Decodable for CostTable {
|
|||||||
code: unwrap_cost(code)?,
|
code: unwrap_cost(code)?,
|
||||||
header_proof: unwrap_cost(header_proof)?,
|
header_proof: unwrap_cost(header_proof)?,
|
||||||
transaction_proof: unwrap_cost(transaction_proof)?,
|
transaction_proof: unwrap_cost(transaction_proof)?,
|
||||||
|
epoch_signal: unwrap_cost(epoch_signal)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,6 +244,7 @@ impl FlowParams {
|
|||||||
code: cost_for_kind(Kind::Code),
|
code: cost_for_kind(Kind::Code),
|
||||||
header_proof: cost_for_kind(Kind::HeaderProof),
|
header_proof: cost_for_kind(Kind::HeaderProof),
|
||||||
transaction_proof: cost_for_kind(Kind::Execution),
|
transaction_proof: cost_for_kind(Kind::Execution),
|
||||||
|
epoch_signal: cost_for_kind(Kind::Signal),
|
||||||
};
|
};
|
||||||
|
|
||||||
FlowParams {
|
FlowParams {
|
||||||
@ -263,7 +270,8 @@ impl FlowParams {
|
|||||||
storage: free_cost.clone(),
|
storage: free_cost.clone(),
|
||||||
code: free_cost.clone(),
|
code: free_cost.clone(),
|
||||||
header_proof: free_cost.clone(),
|
header_proof: free_cost.clone(),
|
||||||
transaction_proof: free_cost,
|
transaction_proof: free_cost.clone(),
|
||||||
|
epoch_signal: free_cost,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,6 +301,7 @@ impl FlowParams {
|
|||||||
Request::Storage(_) => self.costs.storage,
|
Request::Storage(_) => self.costs.storage,
|
||||||
Request::Code(_) => self.costs.code,
|
Request::Code(_) => self.costs.code,
|
||||||
Request::Execution(ref req) => self.costs.transaction_proof * req.gas,
|
Request::Execution(ref req) => self.costs.transaction_proof * req.gas,
|
||||||
|
Request::Signal(_) => self.costs.epoch_signal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ fn compute_timeout(reqs: &Requests) -> Duration {
|
|||||||
Request::Storage(_) => timeout::PROOF,
|
Request::Storage(_) => timeout::PROOF,
|
||||||
Request::Code(_) => timeout::CONTRACT_CODE,
|
Request::Code(_) => timeout::CONTRACT_CODE,
|
||||||
Request::Execution(_) => timeout::TRANSACTION_PROOF,
|
Request::Execution(_) => timeout::TRANSACTION_PROOF,
|
||||||
|
Request::Signal(_) => timeout::EPOCH_SIGNAL,
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,12 @@ impl Provider for TestProvider {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn epoch_signal(&self, _req: request::CompleteSignalRequest) -> Option<request::SignalResponse> {
|
||||||
|
Some(request::SignalResponse {
|
||||||
|
signal: vec![1, 2, 3, 4],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
self.0.client.ready_transactions()
|
self.0.client.ready_transactions()
|
||||||
}
|
}
|
||||||
@ -521,6 +527,50 @@ fn get_contract_code() {
|
|||||||
proto.handle_packet(&expected, &1, packet::REQUEST, &request_body);
|
proto.handle_packet(&expected, &1, packet::REQUEST, &request_body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn epoch_signal() {
|
||||||
|
let capabilities = capabilities();
|
||||||
|
|
||||||
|
let (provider, proto) = setup(capabilities.clone());
|
||||||
|
let flow_params = proto.flow_params.read().clone();
|
||||||
|
|
||||||
|
let cur_status = status(provider.client.chain_info());
|
||||||
|
|
||||||
|
{
|
||||||
|
let packet_body = write_handshake(&cur_status, &capabilities, &proto);
|
||||||
|
proto.on_connect(&1, &Expect::Send(1, packet::STATUS, packet_body.clone()));
|
||||||
|
proto.handle_packet(&Expect::Nothing, &1, packet::STATUS, &packet_body);
|
||||||
|
}
|
||||||
|
|
||||||
|
let req_id = 112;
|
||||||
|
let request = Request::Signal(request::IncompleteSignalRequest {
|
||||||
|
block_hash: H256([1; 32]).into(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let requests = encode_single(request.clone());
|
||||||
|
let request_body = make_packet(req_id, &requests);
|
||||||
|
|
||||||
|
let response = {
|
||||||
|
let response = vec![Response::Signal(SignalResponse {
|
||||||
|
signal: vec![1, 2, 3, 4],
|
||||||
|
})];
|
||||||
|
|
||||||
|
let limit = *flow_params.limit();
|
||||||
|
let cost = flow_params.compute_cost_multi(requests.requests());
|
||||||
|
|
||||||
|
println!("limit = {}, cost = {}", limit, cost);
|
||||||
|
let new_creds = limit - cost;
|
||||||
|
|
||||||
|
let mut response_stream = RlpStream::new_list(3);
|
||||||
|
response_stream.append(&req_id).append(&new_creds).append_list(&response);
|
||||||
|
|
||||||
|
response_stream.out()
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = Expect::Respond(packet::RESPONSE, response);
|
||||||
|
proto.handle_packet(&expected, &1, packet::REQUEST, &request_body);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn proof_of_execution() {
|
fn proof_of_execution() {
|
||||||
let capabilities = capabilities();
|
let capabilities = capabilities();
|
||||||
|
@ -195,6 +195,8 @@ fn guess_capabilities(requests: &[CheckedRequest]) -> Capabilities {
|
|||||||
caps.serve_headers = true,
|
caps.serve_headers = true,
|
||||||
CheckedRequest::HeaderByHash(_, _) =>
|
CheckedRequest::HeaderByHash(_, _) =>
|
||||||
caps.serve_headers = true,
|
caps.serve_headers = true,
|
||||||
|
CheckedRequest::Signal(_, _) =>
|
||||||
|
caps.serve_headers = true,
|
||||||
CheckedRequest::Body(ref req, _) => if let Ok(ref hdr) = req.0.as_ref() {
|
CheckedRequest::Body(ref req, _) => if let Ok(ref hdr) = req.0.as_ref() {
|
||||||
update_since(&mut caps.serve_chain_since, hdr.number());
|
update_since(&mut caps.serve_chain_since, hdr.number());
|
||||||
},
|
},
|
||||||
|
@ -20,7 +20,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use ethcore::basic_account::BasicAccount;
|
use ethcore::basic_account::BasicAccount;
|
||||||
use ethcore::encoded;
|
use ethcore::encoded;
|
||||||
use ethcore::engines::Engine;
|
use ethcore::engines::{Engine, StateDependentProof};
|
||||||
use ethcore::receipt::Receipt;
|
use ethcore::receipt::Receipt;
|
||||||
use ethcore::state::{self, ProvedExecution};
|
use ethcore::state::{self, ProvedExecution};
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::SignedTransaction;
|
||||||
@ -53,6 +53,8 @@ pub enum Request {
|
|||||||
Code(Code),
|
Code(Code),
|
||||||
/// A request for proof of execution.
|
/// A request for proof of execution.
|
||||||
Execution(TransactionProof),
|
Execution(TransactionProof),
|
||||||
|
/// A request for epoch change signal.
|
||||||
|
Signal(Signal),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A request argument.
|
/// A request argument.
|
||||||
@ -133,6 +135,7 @@ impl_single!(Body, Body, encoded::Block);
|
|||||||
impl_single!(Account, Account, Option<BasicAccount>);
|
impl_single!(Account, Account, Option<BasicAccount>);
|
||||||
impl_single!(Code, Code, Bytes);
|
impl_single!(Code, Code, Bytes);
|
||||||
impl_single!(Execution, TransactionProof, super::ExecutionResult);
|
impl_single!(Execution, TransactionProof, super::ExecutionResult);
|
||||||
|
impl_single!(Signal, Signal, Vec<u8>);
|
||||||
|
|
||||||
macro_rules! impl_args {
|
macro_rules! impl_args {
|
||||||
() => {
|
() => {
|
||||||
@ -241,6 +244,7 @@ pub enum CheckedRequest {
|
|||||||
Account(Account, net_request::IncompleteAccountRequest),
|
Account(Account, net_request::IncompleteAccountRequest),
|
||||||
Code(Code, net_request::IncompleteCodeRequest),
|
Code(Code, net_request::IncompleteCodeRequest),
|
||||||
Execution(TransactionProof, net_request::IncompleteExecutionRequest),
|
Execution(TransactionProof, net_request::IncompleteExecutionRequest),
|
||||||
|
Signal(Signal, net_request::IncompleteSignalRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Request> for CheckedRequest {
|
impl From<Request> for CheckedRequest {
|
||||||
@ -299,6 +303,12 @@ impl From<Request> for CheckedRequest {
|
|||||||
};
|
};
|
||||||
CheckedRequest::Execution(req, net_req)
|
CheckedRequest::Execution(req, net_req)
|
||||||
}
|
}
|
||||||
|
Request::Signal(req) => {
|
||||||
|
let net_req = net_request::IncompleteSignalRequest {
|
||||||
|
block_hash: req.hash.into(),
|
||||||
|
};
|
||||||
|
CheckedRequest::Signal(req, net_req)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,6 +326,7 @@ impl CheckedRequest {
|
|||||||
CheckedRequest::Account(_, req) => NetRequest::Account(req),
|
CheckedRequest::Account(_, req) => NetRequest::Account(req),
|
||||||
CheckedRequest::Code(_, req) => NetRequest::Code(req),
|
CheckedRequest::Code(_, req) => NetRequest::Code(req),
|
||||||
CheckedRequest::Execution(_, req) => NetRequest::Execution(req),
|
CheckedRequest::Execution(_, req) => NetRequest::Execution(req),
|
||||||
|
CheckedRequest::Signal(_, req) => NetRequest::Signal(req),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,6 +454,7 @@ macro_rules! match_me {
|
|||||||
CheckedRequest::Account($check, $req) => $e,
|
CheckedRequest::Account($check, $req) => $e,
|
||||||
CheckedRequest::Code($check, $req) => $e,
|
CheckedRequest::Code($check, $req) => $e,
|
||||||
CheckedRequest::Execution($check, $req) => $e,
|
CheckedRequest::Execution($check, $req) => $e,
|
||||||
|
CheckedRequest::Signal($check, $req) => $e,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,6 +482,7 @@ impl IncompleteRequest for CheckedRequest {
|
|||||||
CheckedRequest::Account(_, ref req) => req.check_outputs(f),
|
CheckedRequest::Account(_, ref req) => req.check_outputs(f),
|
||||||
CheckedRequest::Code(_, ref req) => req.check_outputs(f),
|
CheckedRequest::Code(_, ref req) => req.check_outputs(f),
|
||||||
CheckedRequest::Execution(_, ref req) => req.check_outputs(f),
|
CheckedRequest::Execution(_, ref req) => req.check_outputs(f),
|
||||||
|
CheckedRequest::Signal(_, ref req) => req.check_outputs(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,6 +503,7 @@ impl IncompleteRequest for CheckedRequest {
|
|||||||
CheckedRequest::Account(_, req) => req.complete().map(CompleteRequest::Account),
|
CheckedRequest::Account(_, req) => req.complete().map(CompleteRequest::Account),
|
||||||
CheckedRequest::Code(_, req) => req.complete().map(CompleteRequest::Code),
|
CheckedRequest::Code(_, req) => req.complete().map(CompleteRequest::Code),
|
||||||
CheckedRequest::Execution(_, req) => req.complete().map(CompleteRequest::Execution),
|
CheckedRequest::Execution(_, req) => req.complete().map(CompleteRequest::Execution),
|
||||||
|
CheckedRequest::Signal(_, req) => req.complete().map(CompleteRequest::Signal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,6 +555,9 @@ impl net_request::CheckedRequest for CheckedRequest {
|
|||||||
CheckedRequest::Execution(ref prover, _) =>
|
CheckedRequest::Execution(ref prover, _) =>
|
||||||
expect!((&NetResponse::Execution(ref res), _) =>
|
expect!((&NetResponse::Execution(ref res), _) =>
|
||||||
prover.check_response(cache, &res.items).map(Response::Execution)),
|
prover.check_response(cache, &res.items).map(Response::Execution)),
|
||||||
|
CheckedRequest::Signal(ref prover, _) =>
|
||||||
|
expect!((&NetResponse::Signal(ref res), _) =>
|
||||||
|
prover.check_response(cache, &res.signal).map(Response::Signal)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -564,6 +581,8 @@ pub enum Response {
|
|||||||
Code(Vec<u8>),
|
Code(Vec<u8>),
|
||||||
/// Response to a request for proved execution.
|
/// Response to a request for proved execution.
|
||||||
Execution(super::ExecutionResult),
|
Execution(super::ExecutionResult),
|
||||||
|
/// Response to a request for epoch change signal.
|
||||||
|
Signal(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl net_request::ResponseLike for Response {
|
impl net_request::ResponseLike for Response {
|
||||||
@ -847,6 +866,27 @@ impl TransactionProof {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request for epoch signal.
|
||||||
|
/// Provide engine and state-dependent proof checker.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Signal {
|
||||||
|
/// Block hash and number to fetch proof for.
|
||||||
|
pub hash: H256,
|
||||||
|
/// Consensus engine, used to check the proof.
|
||||||
|
pub engine: Arc<Engine>,
|
||||||
|
/// Special checker for the proof.
|
||||||
|
pub proof_check: Arc<StateDependentProof>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Signal {
|
||||||
|
/// Check the signal, returning the signal or indicate that it's bad.
|
||||||
|
pub fn check_response(&self, _: &Mutex<::cache::Cache>, signal: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
|
self.proof_check.check_proof(&*self.engine, signal)
|
||||||
|
.map(|_| signal.to_owned())
|
||||||
|
.map_err(|_| Error::BadProof)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -126,6 +126,9 @@ pub trait Provider: Send + Sync {
|
|||||||
/// Provide a proof-of-execution for the given transaction proof request.
|
/// Provide a proof-of-execution for the given transaction proof request.
|
||||||
/// Returns a vector of all state items necessary to execute the transaction.
|
/// Returns a vector of all state items necessary to execute the transaction.
|
||||||
fn transaction_proof(&self, req: request::CompleteExecutionRequest) -> Option<request::ExecutionResponse>;
|
fn transaction_proof(&self, req: request::CompleteExecutionRequest) -> Option<request::ExecutionResponse>;
|
||||||
|
|
||||||
|
/// Provide epoch signal data at given block hash. This should be just the
|
||||||
|
fn epoch_signal(&self, req: request::CompleteSignalRequest) -> Option<request::SignalResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of a light client data provider for a client.
|
// Implementation of a light client data provider for a client.
|
||||||
@ -264,6 +267,12 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
|||||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
BlockChainClient::ready_transactions(self)
|
BlockChainClient::ready_transactions(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn epoch_signal(&self, req: request::CompleteSignalRequest) -> Option<request::SignalResponse> {
|
||||||
|
self.epoch_signal(req.block_hash).map(|signal| request::SignalResponse {
|
||||||
|
signal: signal,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The light client "provider" implementation. This wraps a `LightClient` and
|
/// The light client "provider" implementation. This wraps a `LightClient` and
|
||||||
@ -329,6 +338,10 @@ impl<L: AsLightClient + Send + Sync> Provider for LightProvider<L> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn epoch_signal(&self, _req: request::CompleteSignalRequest) -> Option<request::SignalResponse> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
let chain_info = self.chain_info();
|
let chain_info = self.chain_info();
|
||||||
self.txqueue.read().ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp)
|
self.txqueue.read().ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp)
|
||||||
|
@ -67,6 +67,11 @@ pub use self::execution::{
|
|||||||
Incomplete as IncompleteExecutionRequest,
|
Incomplete as IncompleteExecutionRequest,
|
||||||
Response as ExecutionResponse,
|
Response as ExecutionResponse,
|
||||||
};
|
};
|
||||||
|
pub use self::epoch_signal::{
|
||||||
|
Complete as CompleteSignalRequest,
|
||||||
|
Incomplete as IncompleteSignalRequest,
|
||||||
|
Response as SignalResponse,
|
||||||
|
};
|
||||||
|
|
||||||
pub use self::builder::{RequestBuilder, Requests};
|
pub use self::builder::{RequestBuilder, Requests};
|
||||||
|
|
||||||
@ -261,6 +266,8 @@ pub enum Request {
|
|||||||
Code(IncompleteCodeRequest),
|
Code(IncompleteCodeRequest),
|
||||||
/// A request for proof of execution,
|
/// A request for proof of execution,
|
||||||
Execution(IncompleteExecutionRequest),
|
Execution(IncompleteExecutionRequest),
|
||||||
|
/// A request for an epoch signal.
|
||||||
|
Signal(IncompleteSignalRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All request types, in an answerable state.
|
/// All request types, in an answerable state.
|
||||||
@ -284,6 +291,8 @@ pub enum CompleteRequest {
|
|||||||
Code(CompleteCodeRequest),
|
Code(CompleteCodeRequest),
|
||||||
/// A request for proof of execution,
|
/// A request for proof of execution,
|
||||||
Execution(CompleteExecutionRequest),
|
Execution(CompleteExecutionRequest),
|
||||||
|
/// A request for an epoch signal.
|
||||||
|
Signal(CompleteSignalRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompleteRequest {
|
impl CompleteRequest {
|
||||||
@ -299,6 +308,7 @@ impl CompleteRequest {
|
|||||||
CompleteRequest::Storage(_) => Kind::Storage,
|
CompleteRequest::Storage(_) => Kind::Storage,
|
||||||
CompleteRequest::Code(_) => Kind::Code,
|
CompleteRequest::Code(_) => Kind::Code,
|
||||||
CompleteRequest::Execution(_) => Kind::Execution,
|
CompleteRequest::Execution(_) => Kind::Execution,
|
||||||
|
CompleteRequest::Signal(_) => Kind::Signal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,6 +326,7 @@ impl Request {
|
|||||||
Request::Storage(_) => Kind::Storage,
|
Request::Storage(_) => Kind::Storage,
|
||||||
Request::Code(_) => Kind::Code,
|
Request::Code(_) => Kind::Code,
|
||||||
Request::Execution(_) => Kind::Execution,
|
Request::Execution(_) => Kind::Execution,
|
||||||
|
Request::Signal(_) => Kind::Signal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -332,6 +343,7 @@ impl Decodable for Request {
|
|||||||
Kind::Storage => Ok(Request::Storage(rlp.val_at(1)?)),
|
Kind::Storage => Ok(Request::Storage(rlp.val_at(1)?)),
|
||||||
Kind::Code => Ok(Request::Code(rlp.val_at(1)?)),
|
Kind::Code => Ok(Request::Code(rlp.val_at(1)?)),
|
||||||
Kind::Execution => Ok(Request::Execution(rlp.val_at(1)?)),
|
Kind::Execution => Ok(Request::Execution(rlp.val_at(1)?)),
|
||||||
|
Kind::Signal => Ok(Request::Signal(rlp.val_at(1)?)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -353,6 +365,7 @@ impl Encodable for Request {
|
|||||||
Request::Storage(ref req) => s.append(req),
|
Request::Storage(ref req) => s.append(req),
|
||||||
Request::Code(ref req) => s.append(req),
|
Request::Code(ref req) => s.append(req),
|
||||||
Request::Execution(ref req) => s.append(req),
|
Request::Execution(ref req) => s.append(req),
|
||||||
|
Request::Signal(ref req) => s.append(req),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,6 +387,7 @@ impl IncompleteRequest for Request {
|
|||||||
Request::Storage(ref req) => req.check_outputs(f),
|
Request::Storage(ref req) => req.check_outputs(f),
|
||||||
Request::Code(ref req) => req.check_outputs(f),
|
Request::Code(ref req) => req.check_outputs(f),
|
||||||
Request::Execution(ref req) => req.check_outputs(f),
|
Request::Execution(ref req) => req.check_outputs(f),
|
||||||
|
Request::Signal(ref req) => req.check_outputs(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,6 +402,7 @@ impl IncompleteRequest for Request {
|
|||||||
Request::Storage(ref req) => req.note_outputs(f),
|
Request::Storage(ref req) => req.note_outputs(f),
|
||||||
Request::Code(ref req) => req.note_outputs(f),
|
Request::Code(ref req) => req.note_outputs(f),
|
||||||
Request::Execution(ref req) => req.note_outputs(f),
|
Request::Execution(ref req) => req.note_outputs(f),
|
||||||
|
Request::Signal(ref req) => req.note_outputs(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,6 +417,7 @@ impl IncompleteRequest for Request {
|
|||||||
Request::Storage(ref mut req) => req.fill(oracle),
|
Request::Storage(ref mut req) => req.fill(oracle),
|
||||||
Request::Code(ref mut req) => req.fill(oracle),
|
Request::Code(ref mut req) => req.fill(oracle),
|
||||||
Request::Execution(ref mut req) => req.fill(oracle),
|
Request::Execution(ref mut req) => req.fill(oracle),
|
||||||
|
Request::Signal(ref mut req) => req.fill(oracle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,6 +432,7 @@ impl IncompleteRequest for Request {
|
|||||||
Request::Storage(req) => req.complete().map(CompleteRequest::Storage),
|
Request::Storage(req) => req.complete().map(CompleteRequest::Storage),
|
||||||
Request::Code(req) => req.complete().map(CompleteRequest::Code),
|
Request::Code(req) => req.complete().map(CompleteRequest::Code),
|
||||||
Request::Execution(req) => req.complete().map(CompleteRequest::Execution),
|
Request::Execution(req) => req.complete().map(CompleteRequest::Execution),
|
||||||
|
Request::Signal(req) => req.complete().map(CompleteRequest::Signal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,6 +447,7 @@ impl IncompleteRequest for Request {
|
|||||||
Request::Storage(ref mut req) => req.adjust_refs(mapping),
|
Request::Storage(ref mut req) => req.adjust_refs(mapping),
|
||||||
Request::Code(ref mut req) => req.adjust_refs(mapping),
|
Request::Code(ref mut req) => req.adjust_refs(mapping),
|
||||||
Request::Execution(ref mut req) => req.adjust_refs(mapping),
|
Request::Execution(ref mut req) => req.adjust_refs(mapping),
|
||||||
|
Request::Signal(ref mut req) => req.adjust_refs(mapping),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -471,6 +489,8 @@ pub enum Kind {
|
|||||||
Code = 7,
|
Code = 7,
|
||||||
/// A request for transaction execution + state proof.
|
/// A request for transaction execution + state proof.
|
||||||
Execution = 8,
|
Execution = 8,
|
||||||
|
/// A request for epoch transition signal.
|
||||||
|
Signal = 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decodable for Kind {
|
impl Decodable for Kind {
|
||||||
@ -485,6 +505,7 @@ impl Decodable for Kind {
|
|||||||
6 => Ok(Kind::Storage),
|
6 => Ok(Kind::Storage),
|
||||||
7 => Ok(Kind::Code),
|
7 => Ok(Kind::Code),
|
||||||
8 => Ok(Kind::Execution),
|
8 => Ok(Kind::Execution),
|
||||||
|
9 => Ok(Kind::Signal),
|
||||||
_ => Err(DecoderError::Custom("Unknown PIP request ID.")),
|
_ => Err(DecoderError::Custom("Unknown PIP request ID.")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -517,6 +538,8 @@ pub enum Response {
|
|||||||
Code(CodeResponse),
|
Code(CodeResponse),
|
||||||
/// A response for proof of execution,
|
/// A response for proof of execution,
|
||||||
Execution(ExecutionResponse),
|
Execution(ExecutionResponse),
|
||||||
|
/// A response for epoch change signal.
|
||||||
|
Signal(SignalResponse),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseLike for Response {
|
impl ResponseLike for Response {
|
||||||
@ -532,6 +555,7 @@ impl ResponseLike for Response {
|
|||||||
Response::Storage(ref res) => res.fill_outputs(f),
|
Response::Storage(ref res) => res.fill_outputs(f),
|
||||||
Response::Code(ref res) => res.fill_outputs(f),
|
Response::Code(ref res) => res.fill_outputs(f),
|
||||||
Response::Execution(ref res) => res.fill_outputs(f),
|
Response::Execution(ref res) => res.fill_outputs(f),
|
||||||
|
Response::Signal(ref res) => res.fill_outputs(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -549,6 +573,7 @@ impl Response {
|
|||||||
Response::Storage(_) => Kind::Storage,
|
Response::Storage(_) => Kind::Storage,
|
||||||
Response::Code(_) => Kind::Code,
|
Response::Code(_) => Kind::Code,
|
||||||
Response::Execution(_) => Kind::Execution,
|
Response::Execution(_) => Kind::Execution,
|
||||||
|
Response::Signal(_) => Kind::Signal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -565,6 +590,7 @@ impl Decodable for Response {
|
|||||||
Kind::Storage => Ok(Response::Storage(rlp.val_at(1)?)),
|
Kind::Storage => Ok(Response::Storage(rlp.val_at(1)?)),
|
||||||
Kind::Code => Ok(Response::Code(rlp.val_at(1)?)),
|
Kind::Code => Ok(Response::Code(rlp.val_at(1)?)),
|
||||||
Kind::Execution => Ok(Response::Execution(rlp.val_at(1)?)),
|
Kind::Execution => Ok(Response::Execution(rlp.val_at(1)?)),
|
||||||
|
Kind::Signal => Ok(Response::Signal(rlp.val_at(1)?)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -586,6 +612,7 @@ impl Encodable for Response {
|
|||||||
Response::Storage(ref res) => s.append(res),
|
Response::Storage(ref res) => s.append(res),
|
||||||
Response::Code(ref res) => s.append(res),
|
Response::Code(ref res) => s.append(res),
|
||||||
Response::Execution(ref res) => s.append(res),
|
Response::Execution(ref res) => s.append(res),
|
||||||
|
Response::Signal(ref res) => s.append(res),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1756,6 +1783,104 @@ pub mod execution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A request for epoch signal data.
|
||||||
|
pub mod epoch_signal {
|
||||||
|
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||||
|
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
|
||||||
|
use util::{Bytes, H256};
|
||||||
|
|
||||||
|
/// Potentially incomplete epoch signal request.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Incomplete {
|
||||||
|
/// The block hash to request the signal for.
|
||||||
|
pub block_hash: Field<H256>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decodable for Incomplete {
|
||||||
|
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||||
|
Ok(Incomplete {
|
||||||
|
block_hash: rlp.val_at(0)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for Incomplete {
|
||||||
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
|
s.begin_list(1).append(&self.block_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>
|
||||||
|
{
|
||||||
|
if let Field::BackReference(req, idx) = self.block_hash {
|
||||||
|
f(req, idx, OutputKind::Hash)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn note_outputs<F>(&self, _: F) where F: FnMut(usize, OutputKind) {}
|
||||||
|
|
||||||
|
fn fill<F>(&mut self, oracle: F) where F: Fn(usize, usize) -> Result<Output, NoSuchOutput> {
|
||||||
|
if let Field::BackReference(req, idx) = self.block_hash {
|
||||||
|
self.block_hash = match oracle(req, idx) {
|
||||||
|
Ok(Output::Hash(block_hash)) => Field::Scalar(block_hash.into()),
|
||||||
|
_ => Field::BackReference(req, idx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete(self) -> Result<Self::Complete, NoSuchOutput> {
|
||||||
|
Ok(Complete {
|
||||||
|
block_hash: self.block_hash.into_scalar()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adjust_refs<F>(&mut self, mut mapping: F) where F: FnMut(usize) -> usize {
|
||||||
|
self.block_hash.adjust_req(&mut mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A complete request.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Complete {
|
||||||
|
/// The block hash to request the epoch signal for.
|
||||||
|
pub block_hash: H256,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The output of a request for an epoch signal.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Response {
|
||||||
|
/// The requested epoch signal.
|
||||||
|
pub signal: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::ResponseLike for Response {
|
||||||
|
/// Fill reusable outputs by providing them to the function.
|
||||||
|
fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decodable for Response {
|
||||||
|
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||||
|
|
||||||
|
Ok(Response {
|
||||||
|
signal: rlp.as_val()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for Response {
|
||||||
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
|
s.append(&self.signal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -2044,4 +2169,22 @@ mod tests {
|
|||||||
let raw = ::rlp::encode_list(&reqs);
|
let raw = ::rlp::encode_list(&reqs);
|
||||||
assert_eq!(::rlp::decode_list::<Response>(&raw), reqs);
|
assert_eq!(::rlp::decode_list::<Response>(&raw), reqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn epoch_signal_roundtrip() {
|
||||||
|
let req = IncompleteSignalRequest {
|
||||||
|
block_hash: Field::Scalar(Default::default()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let full_req = Request::Signal(req.clone());
|
||||||
|
let res = SignalResponse {
|
||||||
|
signal: vec![1, 2, 3, 4, 5, 6, 7, 6, 5, 4],
|
||||||
|
};
|
||||||
|
let full_res = Response::Signal(res.clone());
|
||||||
|
|
||||||
|
check_roundtrip(req);
|
||||||
|
check_roundtrip(full_req);
|
||||||
|
check_roundtrip(res);
|
||||||
|
check_roundtrip(full_res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1918,6 +1918,12 @@ impl ProvingBlockChainClient for Client {
|
|||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn epoch_signal(&self, hash: H256) -> Option<Vec<u8>> {
|
||||||
|
// pending transitions are never deleted, and do not contain
|
||||||
|
// finality proofs by definition.
|
||||||
|
self.chain.read().get_pending_transition(hash).map(|pending| pending.proof)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Client {
|
impl Drop for Client {
|
||||||
|
@ -778,6 +778,10 @@ impl ProvingBlockChainClient for TestBlockChainClient {
|
|||||||
fn prove_transaction(&self, _: SignedTransaction, _: BlockId) -> Option<(Bytes, Vec<DBValue>)> {
|
fn prove_transaction(&self, _: SignedTransaction, _: BlockId) -> Option<(Bytes, Vec<DBValue>)> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn epoch_signal(&self, _: H256) -> Option<Vec<u8>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::traits::EngineClient for TestBlockChainClient {
|
impl super::traits::EngineClient for TestBlockChainClient {
|
||||||
|
@ -353,4 +353,7 @@ pub trait ProvingBlockChainClient: BlockChainClient {
|
|||||||
/// Returns the output of the call and a vector of database items necessary
|
/// Returns the output of the call and a vector of database items necessary
|
||||||
/// to reproduce it.
|
/// to reproduce it.
|
||||||
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)>;
|
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)>;
|
||||||
|
|
||||||
|
/// Get an epoch change signal by block hash.
|
||||||
|
fn epoch_signal(&self, hash: H256) -> Option<Vec<u8>>;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ pub type Headers<'a> = Fn(H256) -> Option<Header> + 'a;
|
|||||||
pub type PendingTransitionStore<'a> = Fn(H256) -> Option<PendingTransition> + 'a;
|
pub type PendingTransitionStore<'a> = Fn(H256) -> Option<PendingTransition> + 'a;
|
||||||
|
|
||||||
/// Proof dependent on state.
|
/// Proof dependent on state.
|
||||||
pub trait StateDependentProof {
|
pub trait StateDependentProof: Send + Sync {
|
||||||
/// Generate a proof, given the state.
|
/// Generate a proof, given the state.
|
||||||
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String>;
|
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String>;
|
||||||
/// Check a proof generated elsewhere (potentially by a peer).
|
/// Check a proof generated elsewhere (potentially by a peer).
|
||||||
@ -135,7 +135,7 @@ pub enum Proof {
|
|||||||
/// Known proof (extracted from signal)
|
/// Known proof (extracted from signal)
|
||||||
Known(Vec<u8>),
|
Known(Vec<u8>),
|
||||||
/// State dependent proof.
|
/// State dependent proof.
|
||||||
WithState(Box<StateDependentProof>),
|
WithState(Arc<StateDependentProof>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generated epoch verifier.
|
/// Generated epoch verifier.
|
||||||
|
@ -47,19 +47,19 @@ lazy_static! {
|
|||||||
// state-dependent proofs for the safe contract:
|
// state-dependent proofs for the safe contract:
|
||||||
// only "first" proofs are such.
|
// only "first" proofs are such.
|
||||||
struct StateProof {
|
struct StateProof {
|
||||||
header: Header,
|
header: Mutex<Header>,
|
||||||
provider: Provider,
|
provider: Provider,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::engines::StateDependentProof for StateProof {
|
impl ::engines::StateDependentProof for StateProof {
|
||||||
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String> {
|
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String> {
|
||||||
prove_initial(&self.provider, &self.header, caller)
|
prove_initial(&self.provider, &*self.header.lock(), caller)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_proof(&self, engine: &Engine, proof: &[u8]) -> Result<(), String> {
|
fn check_proof(&self, engine: &Engine, proof: &[u8]) -> Result<(), String> {
|
||||||
let (header, state_items) = decode_first_proof(&UntrustedRlp::new(proof))
|
let (header, state_items) = decode_first_proof(&UntrustedRlp::new(proof))
|
||||||
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
|
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
|
||||||
if header != self.header {
|
if &header != &*self.header.lock(){
|
||||||
return Err("wrong header in proof".into());
|
return Err("wrong header in proof".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,11 +330,11 @@ impl ValidatorSet for ValidatorSafeContract {
|
|||||||
// transition to the first block of a contract requires finality but has no log event.
|
// transition to the first block of a contract requires finality but has no log event.
|
||||||
if first {
|
if first {
|
||||||
debug!(target: "engine", "signalling transition to fresh contract.");
|
debug!(target: "engine", "signalling transition to fresh contract.");
|
||||||
let state_proof = Box::new(StateProof {
|
let state_proof = Arc::new(StateProof {
|
||||||
header: header.clone(),
|
header: Mutex::new(header.clone()),
|
||||||
provider: self.provider.clone(),
|
provider: self.provider.clone(),
|
||||||
});
|
});
|
||||||
return ::engines::EpochChange::Yes(::engines::Proof::WithState(state_proof as Box<_>));
|
return ::engines::EpochChange::Yes(::engines::Proof::WithState(state_proof as Arc<_>));
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, we're checking for logs.
|
// otherwise, we're checking for logs.
|
||||||
|
Loading…
Reference in New Issue
Block a user