mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 21:11:07 +00:00
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:
committed by
Gav Wood
parent
7f8ee0f53b
commit
fa84cec382
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>>,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user