Fetch changes trie roots + CHT-based proof for these roots (#896)

* build CHT for changes tries roots

* collect chnages tries roots proof in key_changes_proof

* flush check_changes_proof

* fixed compilation

* LightDataChecker now has a ref to the blockchain

* continue passing proofs

* new light db tests

* more CHT tests

* more tests for key changes proof when headers are missing

* lost files
This commit is contained in:
Svyatoslav Nikolsky
2018-11-14 18:06:10 +03:00
committed by Gav Wood
parent 7f8ee0f53b
commit fa84cec382
19 changed files with 1035 additions and 313 deletions
+7 -4
View File
@@ -18,8 +18,9 @@
use client::{self, Client as SubstrateClient, ClientInfo, BlockStatus, CallExecutor};
use client::error::Error;
use client::light::fetcher::ChangesProof;
use consensus::BlockImport;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor};
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT};
use runtime_primitives::generic::{BlockId};
use consensus::{ImportBlock, ImportResult};
use runtime_primitives::Justification;
@@ -63,9 +64,10 @@ pub trait Client<Block: BlockT>: Send + Sync {
&self,
first: Block::Hash,
last: Block::Hash,
min: Block::Hash,
max: Block::Hash,
key: &[u8]
) -> Result<(NumberFor<Block>, Vec<Vec<u8>>), Error>;
) -> Result<ChangesProof<Block::Header>, Error>;
}
impl<B, E, Block, RA> Client<Block> for SubstrateClient<B, E, Block, RA> where
@@ -121,9 +123,10 @@ impl<B, E, Block, RA> Client<Block> for SubstrateClient<B, E, Block, RA> where
&self,
first: Block::Hash,
last: Block::Hash,
min: Block::Hash,
max: Block::Hash,
key: &[u8]
) -> Result<(NumberFor<Block>, Vec<Vec<u8>>), Error> {
(self as &SubstrateClient<B, E, Block, RA>).key_changes_proof(first, last, max, key)
) -> Result<ChangesProof<Block::Header>, Error> {
(self as &SubstrateClient<B, E, Block, RA>).key_changes_proof(first, last, min, max, key)
}
}
+9 -2
View File
@@ -189,7 +189,7 @@ pub mod generic {
/// Remote changes request.
RemoteChangesRequest(RemoteChangesRequest<Hash>),
/// Remote changes reponse.
RemoteChangesResponse(RemoteChangesResponse<Number>),
RemoteChangesResponse(RemoteChangesResponse<Number, Hash>),
/// Chain-specific message
#[codec(index = "255")]
ChainSpecific(Vec<u8>),
@@ -298,6 +298,9 @@ pub mod generic {
pub first: H,
/// Hash of the last block of the range (including last) where changes are requested.
pub last: H,
/// Hash of the first block for which the requester has the changes trie root. All other
/// affected roots must be proved.
pub min: H,
/// Hash of the last block that we can use when querying changes.
pub max: H,
/// Storage key which changes are requested.
@@ -306,7 +309,7 @@ pub mod generic {
#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
/// Remote changes response.
pub struct RemoteChangesResponse<N> {
pub struct RemoteChangesResponse<N, H> {
/// Id of a request this response was made for.
pub id: RequestId,
/// Proof has been generated using block with this number as a max block. Should be
@@ -314,5 +317,9 @@ pub mod generic {
pub max: N,
/// Changes proof.
pub proof: Vec<Vec<u8>>,
/// Changes tries roots missing on the requester' node.
pub roots: Vec<(N, H)>,
/// Missing changes tries roots proof.
pub roots_proof: Vec<Vec<u8>>,
}
}
+16 -8
View File
@@ -26,7 +26,7 @@ use linked_hash_map::Entry;
use parking_lot::Mutex;
use client::{self, error::{Error as ClientError, ErrorKind as ClientErrorKind}};
use client::light::fetcher::{Fetcher, FetchChecker, RemoteHeaderRequest,
RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest};
RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof};
use io::SyncIo;
use message;
use network_libp2p::{Severity, NodeIndex};
@@ -72,7 +72,7 @@ pub trait OnDemandService<Block: BlockT>: Send + Sync {
&self,
io: &mut SyncIo,
peer: NodeIndex,
response: message::RemoteChangesResponse<NumberFor<Block>>
response: message::RemoteChangesResponse<NumberFor<Block>, Block::Hash>
);
}
@@ -284,11 +284,15 @@ impl<B, E> OnDemandService<B> for OnDemand<B, E> where
})
}
fn on_remote_changes_response(&self, io: &mut SyncIo, peer: NodeIndex, response: message::RemoteChangesResponse<NumberFor<B>>) {
fn on_remote_changes_response(&self, io: &mut SyncIo, peer: NodeIndex, response: message::RemoteChangesResponse<NumberFor<B>, B::Hash>) {
self.accept_response("changes", io, peer, response.id, |request| match request.data {
RequestData::RemoteChanges(request, sender) => match self.checker.check_changes_proof(
&request, response.max, response.proof
) {
&request, ChangesProof {
max_block: response.max,
proof: response.proof,
roots: response.roots.into_iter().collect(),
roots_proof: response.roots_proof,
}) {
Ok(response) => {
// we do not bother if receiver has been dropped already
let _ = sender.send(Ok(response));
@@ -483,6 +487,7 @@ impl<Block: BlockT> Request<Block> {
id: self.id,
first: data.first_block.1.clone(),
last: data.last_block.1.clone(),
min: data.tries_roots.1.clone(),
max: data.max_block.1.clone(),
key: data.key.clone(),
}),
@@ -509,9 +514,10 @@ pub mod tests {
use std::time::Instant;
use futures::Future;
use parking_lot::RwLock;
use runtime_primitives::traits::NumberFor;
use client::{self, error::{ErrorKind as ClientErrorKind, Result as ClientResult}};
use client::light::fetcher::{Fetcher, FetchChecker, RemoteHeaderRequest,
RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest};
RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof};
use config::Roles;
use message;
use network_libp2p::NodeIndex;
@@ -557,7 +563,7 @@ pub mod tests {
}
}
fn check_changes_proof(&self, _: &RemoteChangesRequest<Header>, _: u64, _: Vec<Vec<u8>>) -> ClientResult<Vec<(u64, u32)>> {
fn check_changes_proof(&self, _: &RemoteChangesRequest<Header>, _: ChangesProof<Header>) -> ClientResult<Vec<(NumberFor<Block>, u32)>> {
match self.ok {
true => Ok(vec![(100, 2)]),
false => Err(ClientErrorKind::Backend("Test error".into()).into()),
@@ -855,7 +861,7 @@ pub mod tests {
first_block: (1, Default::default()),
last_block: (100, Default::default()),
max_block: (100, Default::default()),
tries_roots: vec![],
tries_roots: (1, Default::default(), vec![]),
key: vec![],
retry_count: None,
});
@@ -868,6 +874,8 @@ pub mod tests {
id: 0,
max: 1000,
proof: vec![vec![2]],
roots: vec![],
roots_proof: vec![],
});
thread.join().unwrap();
}
+16 -6
View File
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use std::collections::{HashMap, HashSet};
use std::collections::{HashMap, HashSet, BTreeMap};
use std::{mem, cmp};
use std::sync::Arc;
use std::time;
@@ -33,6 +33,7 @@ use service::{TransactionPool, ExHashT};
use import_queue::ImportQueue;
use config::{ProtocolConfig, Roles};
use chain::Client;
use client::light::fetcher::ChangesProof;
use on_demand::OnDemandService;
use io::SyncIo;
use error;
@@ -673,20 +674,29 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
fn on_remote_changes_request(&self, io: &mut SyncIo, who: NodeIndex, request: message::RemoteChangesRequest<B::Hash>) {
trace!(target: "sync", "Remote changes proof request {} from {} for key {} ({}..{})",
request.id, who, request.key.to_hex(), request.first, request.last);
let (max, proof) = match self.context_data.chain.key_changes_proof(request.first, request.last, request.max, &request.key) {
Ok((max, proof)) => (max, proof),
let proof = match self.context_data.chain.key_changes_proof(request.first, request.last, request.min, request.max, &request.key) {
Ok(proof) => proof,
Err(error) => {
trace!(target: "sync", "Remote changes proof request {} from {} for key {} ({}..{}) failed with: {}",
request.id, who, request.key.to_hex(), request.first, request.last, error);
(Zero::zero(), Default::default())
ChangesProof::<B::Header> {
max_block: Zero::zero(),
proof: vec![],
roots: BTreeMap::new(),
roots_proof: vec![],
}
},
};
self.send_message(io, who, GenericMessage::RemoteChangesResponse(message::RemoteChangesResponse {
id: request.id, max, proof,
id: request.id,
max: proof.max_block,
proof: proof.proof,
roots: proof.roots.into_iter().collect(),
roots_proof: proof.roots_proof,
}));
}
fn on_remote_changes_response(&self, io: &mut SyncIo, who: NodeIndex, response: message::RemoteChangesResponse<NumberFor<B>>) {
fn on_remote_changes_response(&self, io: &mut SyncIo, who: NodeIndex, response: message::RemoteChangesResponse<NumberFor<B>, B::Hash>) {
trace!(target: "sync", "Remote changes proof response {} from {} (max={})",
response.id, who, response.max);
self.on_demand.as_ref().map(|s| s.on_remote_changes_response(io, who, response));