Cleaner GRANDPA RPC API for proving finality (#7339)

* grandpa: persist block number for last block of authority set

* grandpa: fix authority_set_changes field in tests

* grandpa: fix date on copyright notice

* grandpa-rpc: implement cleaner api for prove finality rpc

* grandpa-rpc: replace the old prove_finality with the new one

* grandpa: undo accidental whitespace change

* grandpa-rpc: start work on redo of the finality_proof RPC API

* grandpa: manual impl of Decode for AuthoritySet

* grandpa: add comment about appending changes for forced changes

* grandpa: flip order in set changes, tidy up some comments

* grandpa: update some of the doc comments

* grandpa: store authority set changes when applying forced changes

* grandpa: simplify finality_proof.rs

* grandpa: move checks and extend tests in finality_proof

* grandpa: address first set of review comments

* grandpa: check that set changes have well-defined start

* grandpa: rework prove_finality and assocated tests

* grandpa: make AuthoritySetChanges tuple struct

* grandpa: add assertions for tracking auth set changes

* grandpa: remove StorageAndProofProvider trait

* grandpa: return more informative results for unexpected input to RPC

* grandpa: tiny tweak to error msg

* grandpa: fix tests

* grandpa: add error specific to finality_proof

* grandpa: fix review comments

* grandpa: proper migration to new AuthoritySet

* grandpa: fix long lines

* grandpa: fix unused warning after merge

Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
Jon Häggblad
2021-01-21 23:06:40 +01:00
committed by GitHub
parent 87cc216774
commit 20f40fbd12
9 changed files with 855 additions and 925 deletions
+5 -2
View File
@@ -109,8 +109,11 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
let shared_voter_state = grandpa::SharedVoterState::empty();
let rpc_setup = shared_voter_state.clone();
let finality_proof_provider =
grandpa::FinalityProofProvider::new_for_service(backend.clone(), client.clone());
let finality_proof_provider = grandpa::FinalityProofProvider::new_for_service(
backend.clone(),
client.clone(),
Some(shared_authority_set.clone()),
);
let babe_config = babe_link.config().clone();
let shared_epoch_changes = babe_link.epoch_changes().clone();
@@ -30,7 +30,7 @@ pub enum Error {
VoterStateReportsUnreasonablyLargeNumbers,
/// GRANDPA prove finality failed.
#[display(fmt = "GRANDPA prove finality rpc failed: {}", _0)]
ProveFinalityFailed(sp_blockchain::Error),
ProveFinalityFailed(sc_finality_grandpa::FinalityProofError),
}
/// The error codes returned by jsonrpc.
@@ -22,18 +22,16 @@ use sc_finality_grandpa::FinalityProofProvider;
use sp_runtime::traits::{Block as BlockT, NumberFor};
#[derive(Serialize, Deserialize)]
pub struct EncodedFinalityProofs(pub sp_core::Bytes);
pub struct EncodedFinalityProof(pub sp_core::Bytes);
/// Local trait mainly to allow mocking in tests.
pub trait RpcFinalityProofProvider<Block: BlockT> {
/// Return finality proofs for the given authorities set id, if it is provided, otherwise the
/// current one will be used.
/// Prove finality for the given block number by returning a Justification for the last block of
/// the authority set.
fn rpc_prove_finality(
&self,
begin: Block::Hash,
end: Block::Hash,
authorities_set_id: u64,
) -> Result<Option<EncodedFinalityProofs>, sp_blockchain::Error>;
block: NumberFor<Block>,
) -> Result<Option<EncodedFinalityProof>, sc_finality_grandpa::FinalityProofError>;
}
impl<B, Block> RpcFinalityProofProvider<Block> for FinalityProofProvider<B, Block>
@@ -44,11 +42,9 @@ where
{
fn rpc_prove_finality(
&self,
begin: Block::Hash,
end: Block::Hash,
authorities_set_id: u64,
) -> Result<Option<EncodedFinalityProofs>, sp_blockchain::Error> {
self.prove_finality(begin, end, authorities_set_id)
.map(|x| x.map(|y| EncodedFinalityProofs(y.into())))
block: NumberFor<Block>,
) -> Result<Option<EncodedFinalityProof>, sc_finality_grandpa::FinalityProofError> {
self.prove_finality(block)
.map(|x| x.map(|y| EncodedFinalityProof(y.into())))
}
}
@@ -37,9 +37,9 @@ mod notification;
mod report;
use sc_finality_grandpa::GrandpaJustificationStream;
use sp_runtime::traits::Block as BlockT;
use sp_runtime::traits::{Block as BlockT, NumberFor};
use finality::{EncodedFinalityProofs, RpcFinalityProofProvider};
use finality::{EncodedFinalityProof, RpcFinalityProofProvider};
use report::{ReportAuthoritySet, ReportVoterState, ReportedRoundStates};
use notification::JustificationNotification;
@@ -48,7 +48,7 @@ type FutureResult<T> =
/// Provides RPC methods for interacting with GRANDPA.
#[rpc]
pub trait GrandpaApi<Notification, Hash> {
pub trait GrandpaApi<Notification, Hash, Number> {
/// RPC Metadata
type Metadata;
@@ -82,15 +82,13 @@ pub trait GrandpaApi<Notification, Hash> {
id: SubscriptionId
) -> jsonrpc_core::Result<bool>;
/// Prove finality for the range (begin; end] hash. Returns None if there are no finalized blocks
/// unknown in the range. If no authorities set is provided, the current one will be attempted.
/// Prove finality for the given block number by returning the Justification for the last block
/// in the set and all the intermediary headers to link them together.
#[rpc(name = "grandpa_proveFinality")]
fn prove_finality(
&self,
begin: Hash,
end: Hash,
authorities_set_id: Option<u64>,
) -> FutureResult<Option<EncodedFinalityProofs>>;
block: Number,
) -> FutureResult<Option<EncodedFinalityProof>>;
}
/// Implements the GrandpaApi RPC trait for interacting with GRANDPA.
@@ -127,7 +125,8 @@ impl<AuthoritySet, VoterState, Block: BlockT, ProofProvider>
}
}
impl<AuthoritySet, VoterState, Block, ProofProvider> GrandpaApi<JustificationNotification, Block::Hash>
impl<AuthoritySet, VoterState, Block, ProofProvider>
GrandpaApi<JustificationNotification, Block::Hash, NumberFor<Block>>
for GrandpaRpcHandler<AuthoritySet, VoterState, Block, ProofProvider>
where
VoterState: ReportVoterState + Send + Sync + 'static,
@@ -171,16 +170,9 @@ where
fn prove_finality(
&self,
begin: Block::Hash,
end: Block::Hash,
authorities_set_id: Option<u64>,
) -> FutureResult<Option<EncodedFinalityProofs>> {
// If we are not provided a set_id, try with the current one.
let authorities_set_id = authorities_set_id
.unwrap_or_else(|| self.authority_set.get().0);
let result = self
.finality_proof_provider
.rpc_prove_finality(begin, end, authorities_set_id);
block: NumberFor<Block>,
) -> FutureResult<Option<EncodedFinalityProof>> {
let result = self.finality_proof_provider.rpc_prove_finality(block);
let future = async move { result }.boxed();
Box::new(
future
@@ -204,7 +196,7 @@ mod tests {
use sc_block_builder::BlockBuilder;
use sc_finality_grandpa::{
report, AuthorityId, GrandpaJustificationSender, GrandpaJustification,
FinalityProofFragment,
FinalityProof,
};
use sp_blockchain::HeaderBackend;
use sp_consensus::RecordProof;
@@ -223,7 +215,7 @@ mod tests {
struct EmptyVoterState;
struct TestFinalityProofProvider {
finality_proofs: Vec<FinalityProofFragment<Header>>,
finality_proof: Option<FinalityProof<Header>>,
}
fn voters() -> HashSet<AuthorityId> {
@@ -262,11 +254,15 @@ mod tests {
impl<Block: BlockT> RpcFinalityProofProvider<Block> for TestFinalityProofProvider {
fn rpc_prove_finality(
&self,
_begin: Block::Hash,
_end: Block::Hash,
_authoritites_set_id: u64,
) -> Result<Option<EncodedFinalityProofs>, sp_blockchain::Error> {
Ok(Some(EncodedFinalityProofs(self.finality_proofs.encode().into())))
_block: NumberFor<Block>
) -> Result<Option<EncodedFinalityProof>, sc_finality_grandpa::FinalityProofError> {
Ok(Some(EncodedFinalityProof(
self.finality_proof
.as_ref()
.expect("Don't call rpc_prove_finality without setting the FinalityProof")
.encode()
.into()
)))
}
}
@@ -308,12 +304,12 @@ mod tests {
) where
VoterState: ReportVoterState + Send + Sync + 'static,
{
setup_io_handler_with_finality_proofs(voter_state, Default::default())
setup_io_handler_with_finality_proofs(voter_state, None)
}
fn setup_io_handler_with_finality_proofs<VoterState>(
voter_state: VoterState,
finality_proofs: Vec<FinalityProofFragment<Header>>,
finality_proof: Option<FinalityProof<Header>>,
) -> (
jsonrpc_core::MetaIoHandler<sc_rpc::Metadata>,
GrandpaJustificationSender<Block>,
@@ -321,7 +317,7 @@ mod tests {
VoterState: ReportVoterState + Send + Sync + 'static,
{
let (justification_sender, justification_stream) = GrandpaJustificationStream::channel();
let finality_proof_provider = Arc::new(TestFinalityProofProvider { finality_proofs });
let finality_proof_provider = Arc::new(TestFinalityProofProvider { finality_proof });
let handler = GrandpaRpcHandler::new(
TestAuthoritySet,
@@ -520,29 +516,24 @@ mod tests {
#[test]
fn prove_finality_with_test_finality_proof_provider() {
let finality_proofs = vec![FinalityProofFragment {
let finality_proof = FinalityProof {
block: header(42).hash(),
justification: create_justification().encode(),
unknown_headers: vec![header(2)],
authorities_proof: None,
}];
};
let (io, _) = setup_io_handler_with_finality_proofs(
TestVoterState,
finality_proofs.clone(),
Some(finality_proof.clone()),
);
let request = "{\"jsonrpc\":\"2.0\",\"method\":\"grandpa_proveFinality\",\"params\":[\
\"0x0000000000000000000000000000000000000000000000000000000000000000\",\
\"0x0000000000000000000000000000000000000000000000000000000000000001\",\
42\
],\"id\":1}";
let request =
"{\"jsonrpc\":\"2.0\",\"method\":\"grandpa_proveFinality\",\"params\":[42],\"id\":1}";
let meta = sc_rpc::Metadata::default();
let resp = io.handle_request_sync(request, meta);
let mut resp: serde_json::Value = serde_json::from_str(&resp.unwrap()).unwrap();
let result: sp_core::Bytes = serde_json::from_value(resp["result"].take()).unwrap();
let fragments: Vec<FinalityProofFragment<Header>> =
Decode::decode(&mut &result[..]).unwrap();
assert_eq!(fragments, finality_proofs);
let finality_proof_rpc: FinalityProof<Header> = Decode::decode(&mut &result[..]).unwrap();
assert_eq!(finality_proof_rpc, finality_proof);
}
}
@@ -114,6 +114,11 @@ where N: Add<Output=N> + Ord + Clone + Debug,
pub fn clone_inner(&self) -> AuthoritySet<H, N> {
self.inner.read().clone()
}
/// Clone the inner `AuthoritySetChanges`.
pub fn authority_set_changes(&self) -> AuthoritySetChanges<N> {
self.inner.read().authority_set_changes.clone()
}
}
impl<H, N> From<AuthoritySet<H, N>> for SharedAuthoritySet<H, N> {
@@ -152,12 +157,16 @@ pub struct AuthoritySet<H, N> {
/// is lower than the last finalized block (as signaled in the forced
/// change) must be applied beforehand.
pending_forced_changes: Vec<PendingChange<H, N>>,
/// Track at which blocks the set id changed. This is useful when we need to prove finality for a
/// given block since we can figure out what set the block belongs to and when the set
/// started/ended.
authority_set_changes: AuthoritySetChanges<N>,
}
impl<H, N> AuthoritySet<H, N>
where
H: PartialEq,
N: Ord,
N: Ord + Clone,
{
// authority sets must be non-empty and all weights must be greater than 0
fn invalid_authority_list(authorities: &AuthorityList) -> bool {
@@ -175,6 +184,7 @@ where
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
})
}
@@ -184,6 +194,7 @@ where
set_id: u64,
pending_standard_changes: ForkTree<H, N, PendingChange<H, N>>,
pending_forced_changes: Vec<PendingChange<H, N>>,
authority_set_changes: AuthoritySetChanges<N>,
) -> Option<Self> {
if Self::invalid_authority_list(&authorities) {
return None;
@@ -194,6 +205,7 @@ where
set_id,
pending_standard_changes,
pending_forced_changes,
authority_set_changes,
})
}
@@ -454,6 +466,9 @@ where
"block" => ?change.canon_height
);
let mut authority_set_changes = self.authority_set_changes.clone();
authority_set_changes.append(self.set_id, median_last_finalized.clone());
new_set = Some((
median_last_finalized,
AuthoritySet {
@@ -461,6 +476,7 @@ where
set_id: self.set_id + 1,
pending_standard_changes: ForkTree::new(), // new set, new changes.
pending_forced_changes: Vec::new(),
authority_set_changes,
},
));
@@ -532,6 +548,9 @@ where
"block" => ?change.canon_height
);
// Store the set_id together with the last block_number for the set
self.authority_set_changes.append(self.set_id, finalized_number.clone());
self.current_authorities = change.next_authorities;
self.set_id += 1;
@@ -631,6 +650,45 @@ impl<H, N: Add<Output=N> + Clone> PendingChange<H, N> {
}
}
// Tracks historical authority set changes. We store the block numbers for the first block of each
// authority set, once they have been finalized.
#[derive(Debug, Encode, Decode, Clone, PartialEq)]
pub struct AuthoritySetChanges<N>(pub Vec<(u64, N)>);
impl<N: Ord + Clone> AuthoritySetChanges<N> {
pub(crate) fn empty() -> Self {
Self(Default::default())
}
pub(crate) fn append(&mut self, set_id: u64, block_number: N) {
self.0.push((set_id, block_number));
}
pub(crate) fn get_set_id(&self, block_number: N) -> Option<(u64, N)> {
let idx = self.0
.binary_search_by_key(&block_number, |(_, n)| n.clone())
.unwrap_or_else(|b| b);
if idx < self.0.len() {
let (set_id, block_number) = self.0[idx].clone();
// To make sure we have the right set we need to check that the one before it also exists.
if idx > 0 {
let (prev_set_id, _) = self.0[idx - 1usize];
if set_id != prev_set_id + 1u64 {
// Without the preceding set_id we don't have a well-defined start.
return None;
}
} else if set_id != 0 {
// If this is the first index, yet not the first set id then it's not well-defined
// that we are in the right set id.
return None;
}
Some((set_id, block_number))
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -657,6 +715,7 @@ mod tests {
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
};
let change = |height| {
@@ -704,6 +763,7 @@ mod tests {
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
};
let change_a = PendingChange {
@@ -772,6 +832,7 @@ mod tests {
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
};
let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)];
@@ -820,6 +881,7 @@ mod tests {
authorities.pending_changes().collect::<Vec<_>>(),
vec![&change_a],
);
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges::empty());
// finalizing "hash_d" will enact the change signaled at "hash_a"
let status = authorities.apply_standard_changes(
@@ -838,6 +900,7 @@ mod tests {
assert_eq!(authorities.current_authorities, set_a);
assert_eq!(authorities.set_id, 1);
assert_eq!(authorities.pending_changes().count(), 0);
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges(vec![(0, 15)]));
}
#[test]
@@ -847,6 +910,7 @@ mod tests {
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
};
let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)];
@@ -889,6 +953,7 @@ mod tests {
authorities.apply_standard_changes("hash_d", 40, &is_descendent_of, false),
Err(Error::ForkTree(fork_tree::Error::UnfinalizedAncestor))
));
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges::empty());
let status = authorities.apply_standard_changes(
"hash_b",
@@ -902,6 +967,7 @@ mod tests {
assert_eq!(authorities.current_authorities, set_a);
assert_eq!(authorities.set_id, 1);
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges(vec![(0, 15)]));
// after finalizing `change_a` it should be possible to finalize `change_c`
let status = authorities.apply_standard_changes(
@@ -916,6 +982,7 @@ mod tests {
assert_eq!(authorities.current_authorities, set_c);
assert_eq!(authorities.set_id, 2);
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges(vec![(0, 15), (1, 40)]));
}
#[test]
@@ -925,6 +992,7 @@ mod tests {
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
};
let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)];
@@ -991,6 +1059,7 @@ mod tests {
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
};
let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)];
@@ -1074,6 +1143,7 @@ mod tests {
set_id: 1,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges(vec![(0, 42)]),
},
)
);
@@ -1087,6 +1157,7 @@ mod tests {
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
};
let set_a = vec![(AuthorityId::from_slice(&[1; 32]), 5)];
@@ -1125,6 +1196,7 @@ mod tests {
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
};
// effective at #15
@@ -1179,22 +1251,26 @@ mod tests {
authorities.apply_forced_changes("hash_d45", 45, &static_is_descendent_of(true), false),
Err(Error::ForcedAuthoritySetChangeDependencyUnsatisfied(15))
));
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges::empty());
// we apply the first pending standard change at #15
authorities
.apply_standard_changes("hash_a15", 15, &static_is_descendent_of(true), false)
.unwrap();
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges(vec![(0, 15)]));
// but the forced change still depends on the next standard change
assert!(matches!(
authorities.apply_forced_changes("hash_d", 45, &static_is_descendent_of(true), false),
Err(Error::ForcedAuthoritySetChangeDependencyUnsatisfied(20))
));
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges(vec![(0, 15)]));
// we apply the pending standard change at #20
authorities
.apply_standard_changes("hash_b", 20, &static_is_descendent_of(true), false)
.unwrap();
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges(vec![(0, 15), (1, 20)]));
// afterwards the forced change at #45 can already be applied since it signals
// that finality stalled at #31, and the next pending standard change is effective
@@ -1211,9 +1287,11 @@ mod tests {
set_id: 3,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges(vec![(0, 15), (1, 20), (2, 31)]),
}
),
);
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges(vec![(0, 15), (1, 20)]));
}
#[test]
@@ -1225,6 +1303,7 @@ mod tests {
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
};
let new_set = current_authorities.clone();
@@ -1343,7 +1422,13 @@ mod tests {
// empty authority lists are invalid
assert_eq!(AuthoritySet::<(), ()>::genesis(vec![]), None);
assert_eq!(
AuthoritySet::<(), ()>::new(vec![], 0, ForkTree::new(), Vec::new()),
AuthoritySet::<(), ()>::new(
vec![],
0,
ForkTree::new(),
Vec::new(),
AuthoritySetChanges::empty(),
),
None,
);
@@ -1362,7 +1447,8 @@ mod tests {
invalid_authorities_weight.clone(),
0,
ForkTree::new(),
Vec::new()
Vec::new(),
AuthoritySetChanges::empty(),
),
None,
);
@@ -1417,6 +1503,7 @@ mod tests {
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
authority_set_changes: AuthoritySetChanges::empty(),
};
let new_set = current_authorities.clone();
@@ -1512,4 +1599,32 @@ mod tests {
"D"
);
}
#[test]
fn authority_set_changes_for_complete_data() {
let mut authority_set_changes = AuthoritySetChanges::empty();
authority_set_changes.append(0, 41);
authority_set_changes.append(1, 81);
authority_set_changes.append(2, 121);
assert_eq!(authority_set_changes.get_set_id(20), Some((0, 41)));
assert_eq!(authority_set_changes.get_set_id(40), Some((0, 41)));
assert_eq!(authority_set_changes.get_set_id(41), Some((0, 41)));
assert_eq!(authority_set_changes.get_set_id(42), Some((1, 81)));
assert_eq!(authority_set_changes.get_set_id(141), None);
}
#[test]
fn authority_set_changes_for_incomplete_data() {
let mut authority_set_changes = AuthoritySetChanges::empty();
authority_set_changes.append(2, 41);
authority_set_changes.append(3, 81);
authority_set_changes.append(4, 121);
assert_eq!(authority_set_changes.get_set_id(20), None);
assert_eq!(authority_set_changes.get_set_id(40), None);
assert_eq!(authority_set_changes.get_set_id(41), None);
assert_eq!(authority_set_changes.get_set_id(42), Some((3, 81)));
assert_eq!(authority_set_changes.get_set_id(141), None);
}
}
@@ -28,7 +28,9 @@ use sp_runtime::traits::{Block as BlockT, NumberFor};
use log::{info, warn};
use sp_finality_grandpa::{AuthorityList, SetId, RoundNumber};
use crate::authorities::{AuthoritySet, SharedAuthoritySet, PendingChange, DelayKind};
use crate::authorities::{
AuthoritySet, AuthoritySetChanges, SharedAuthoritySet, PendingChange, DelayKind,
};
use crate::environment::{
CompletedRound, CompletedRounds, CurrentRounds, HasVoted, SharedVoterSetState, VoterSetState,
};
@@ -39,7 +41,7 @@ const SET_STATE_KEY: &[u8] = b"grandpa_completed_round";
const CONCLUDED_ROUNDS: &[u8] = b"grandpa_concluded_rounds";
const AUTHORITY_SET_KEY: &[u8] = b"grandpa_voters";
const CURRENT_VERSION: u32 = 2;
const CURRENT_VERSION: u32 = 3;
/// The voter set state.
#[derive(Debug, Clone, Encode, Decode)]
@@ -69,7 +71,8 @@ struct V0AuthoritySet<H, N> {
}
impl<H, N> Into<AuthoritySet<H, N>> for V0AuthoritySet<H, N>
where H: Clone + Debug + PartialEq,
where
H: Clone + Debug + PartialEq,
N: Clone + Debug + Ord,
{
fn into(self) -> AuthoritySet<H, N> {
@@ -101,19 +104,46 @@ where H: Clone + Debug + PartialEq,
self.set_id,
pending_standard_changes,
Vec::new(),
AuthoritySetChanges::empty(),
);
authority_set.expect("current_authorities is non-empty and weights are non-zero; qed.")
}
}
pub(crate) fn load_decode<B: AuxStore, T: Decode>(backend: &B, key: &[u8]) -> ClientResult<Option<T>> {
impl<H, N> Into<AuthoritySet<H, N>> for V2AuthoritySet<H, N>
where
H: Clone + Debug + PartialEq,
N: Clone + Debug + Ord,
{
fn into(self) -> AuthoritySet<H, N> {
AuthoritySet::new(
self.current_authorities,
self.set_id,
self.pending_standard_changes,
self.pending_forced_changes,
AuthoritySetChanges::empty(),
)
.expect("current_authorities is non-empty and weights are non-zero; qed.")
}
}
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
struct V2AuthoritySet<H, N> {
current_authorities: AuthorityList,
set_id: u64,
pending_standard_changes: ForkTree<H, N, PendingChange<H, N>>,
pending_forced_changes: Vec<PendingChange<H, N>>,
}
pub(crate) fn load_decode<B: AuxStore, T: Decode>(
backend: &B,
key: &[u8]
) -> ClientResult<Option<T>> {
match backend.get_aux(key)? {
None => Ok(None),
Some(t) => T::decode(&mut &t[..])
.map_err(
|e| ClientError::Backend(format!("GRANDPA DB is corrupted: {}", e.what())),
)
.map_err(|e| ClientError::Backend(format!("GRANDPA DB is corrupted: {}", e.what())))
.map(Some)
}
}
@@ -127,10 +157,14 @@ pub(crate) struct PersistentData<Block: BlockT> {
fn migrate_from_version0<Block: BlockT, B, G>(
backend: &B,
genesis_round: &G,
) -> ClientResult<Option<(
) -> ClientResult<
Option<(
AuthoritySet<Block::Hash, NumberFor<Block>>,
VoterSetState<Block>,
)>> where B: AuxStore,
)>,
>
where
B: AuxStore,
G: Fn() -> RoundState<Block::Hash, NumberFor<Block>>,
{
CURRENT_VERSION.using_encoded(|s|
@@ -144,18 +178,20 @@ fn migrate_from_version0<Block: BlockT, B, G>(
let new_set: AuthoritySet<Block::Hash, NumberFor<Block>> = old_set.into();
backend.insert_aux(&[(AUTHORITY_SET_KEY, new_set.encode().as_slice())], &[])?;
let (last_round_number, last_round_state) = match load_decode::<_, V0VoterSetState<Block::Hash, NumberFor<Block>>>(
backend,
SET_STATE_KEY,
)? {
let (last_round_number, last_round_state) = match load_decode::<
_,
V0VoterSetState<Block::Hash, NumberFor<Block>>,
>(backend, SET_STATE_KEY)?
{
Some((number, state)) => (number, state),
None => (0, genesis_round()),
};
let set_id = new_set.set_id;
let base = last_round_state.prevote_ghost
.expect("state is for completed round; completed rounds must have a prevote ghost; qed.");
let base = last_round_state.prevote_ghost.expect(
"state is for completed round; completed rounds must have a prevote ghost; qed."
);
let mut current_rounds = CurrentRounds::new();
current_rounds.insert(last_round_number + 1, HasVoted::No);
@@ -185,10 +221,14 @@ fn migrate_from_version0<Block: BlockT, B, G>(
fn migrate_from_version1<Block: BlockT, B, G>(
backend: &B,
genesis_round: &G,
) -> ClientResult<Option<(
) -> ClientResult<
Option<(
AuthoritySet<Block::Hash, NumberFor<Block>>,
VoterSetState<Block>,
)>> where B: AuxStore,
)>,
>
where
B: AuxStore,
G: Fn() -> RoundState<Block::Hash, NumberFor<Block>>,
{
CURRENT_VERSION.using_encoded(|s|
@@ -257,15 +297,62 @@ fn migrate_from_version1<Block: BlockT, B, G>(
Ok(None)
}
fn migrate_from_version2<Block: BlockT, B, G>(
backend: &B,
genesis_round: &G,
) -> ClientResult<
Option<(
AuthoritySet<Block::Hash, NumberFor<Block>>,
VoterSetState<Block>,
)>,
>
where
B: AuxStore,
G: Fn() -> RoundState<Block::Hash, NumberFor<Block>>,
{
CURRENT_VERSION.using_encoded(|s|
backend.insert_aux(&[(VERSION_KEY, s)], &[])
)?;
if let Some(old_set) = load_decode::<_, V2AuthoritySet<Block::Hash, NumberFor<Block>>>(
backend,
AUTHORITY_SET_KEY,
)? {
let new_set: AuthoritySet<Block::Hash, NumberFor<Block>> = old_set.into();
backend.insert_aux(&[(AUTHORITY_SET_KEY, new_set.encode().as_slice())], &[])?;
let set_state = match load_decode::<_, VoterSetState<Block>>(
backend,
SET_STATE_KEY,
)? {
Some(state) => state,
None => {
let state = genesis_round();
let base = state.prevote_ghost
.expect("state is for completed round; completed rounds must have a prevote ghost; qed.");
VoterSetState::live(
new_set.set_id,
&new_set,
base,
)
}
};
return Ok(Some((new_set, set_state)));
}
Ok(None)
}
/// Load or initialize persistent data from backend.
pub(crate) fn load_persistent<Block: BlockT, B, G>(
backend: &B,
genesis_hash: Block::Hash,
genesis_number: NumberFor<Block>,
genesis_authorities: G,
)
-> ClientResult<PersistentData<Block>>
where
) -> ClientResult<PersistentData<Block>>
where
B: AuxStore,
G: FnOnce() -> ClientResult<AuthorityList>,
{
@@ -275,7 +362,9 @@ pub(crate) fn load_persistent<Block: BlockT, B, G>(
match version {
None => {
if let Some((new_set, set_state)) = migrate_from_version0::<Block, _, _>(backend, &make_genesis_round)? {
if let Some((new_set, set_state)) =
migrate_from_version0::<Block, _, _>(backend, &make_genesis_round)?
{
return Ok(PersistentData {
authority_set: new_set.into(),
set_state: set_state.into(),
@@ -283,7 +372,9 @@ pub(crate) fn load_persistent<Block: BlockT, B, G>(
}
},
Some(1) => {
if let Some((new_set, set_state)) = migrate_from_version1::<Block, _, _>(backend, &make_genesis_round)? {
if let Some((new_set, set_state)) =
migrate_from_version1::<Block, _, _>(backend, &make_genesis_round)?
{
return Ok(PersistentData {
authority_set: new_set.into(),
set_state: set_state.into(),
@@ -291,6 +382,16 @@ pub(crate) fn load_persistent<Block: BlockT, B, G>(
}
},
Some(2) => {
if let Some((new_set, set_state)) =
migrate_from_version2::<Block, _, _>(backend, &make_genesis_round)?
{
return Ok(PersistentData {
authority_set: new_set.into(),
set_state: set_state.into(),
});
}
}
Some(3) => {
if let Some(set) = load_decode::<_, AuthoritySet<Block::Hash, NumberFor<Block>>>(
backend,
AUTHORITY_SET_KEY,
@@ -364,7 +465,8 @@ pub(crate) fn update_authority_set<Block: BlockT, F, R>(
set: &AuthoritySet<Block::Hash, NumberFor<Block>>,
new_set: Option<&NewAuthoritySet<Block::Hash, NumberFor<Block>>>,
write_aux: F
) -> R where
) -> R
where
F: FnOnce(&[(&'static [u8], &[u8])]) -> R,
{
// write new authority set state to disk.
@@ -414,8 +516,9 @@ pub(crate) fn write_concluded_round<Block: BlockT, B: AuxStore>(
}
#[cfg(test)]
pub(crate) fn load_authorities<B: AuxStore, H: Decode, N: Decode>(backend: &B)
-> Option<AuthoritySet<H, N>> {
pub(crate) fn load_authorities<B: AuxStore, H: Decode, N: Decode + Clone + Ord>(
backend: &B
) -> Option<AuthoritySet<H, N>> {
load_decode::<_, AuthoritySet<H, N>>(backend, AUTHORITY_SET_KEY)
.expect("backend error")
}
@@ -474,10 +577,14 @@ mod test {
assert_eq!(
load_decode::<_, u32>(&client, VERSION_KEY).unwrap(),
Some(2),
Some(3),
);
let PersistentData { authority_set, set_state, .. } = load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
let PersistentData {
authority_set,
set_state,
..
} = load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
&client,
H256::random(),
0,
@@ -491,6 +598,7 @@ mod test {
set_id,
ForkTree::new(),
Vec::new(),
AuthoritySetChanges::empty(),
).unwrap(),
);
@@ -535,6 +643,7 @@ mod test {
set_id,
ForkTree::new(),
Vec::new(),
AuthoritySetChanges::empty(),
).unwrap();
let voter_set_state = V1VoterSetState::Live(round_number, round_state.clone());
@@ -564,10 +673,14 @@ mod test {
assert_eq!(
load_decode::<_, u32>(&client, VERSION_KEY).unwrap(),
Some(2),
Some(3),
);
let PersistentData { authority_set, set_state, .. } = load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
let PersistentData {
authority_set,
set_state,
..
} = load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
&client,
H256::random(),
0,
@@ -581,6 +694,7 @@ mod test {
set_id,
ForkTree::new(),
Vec::new(),
AuthoritySetChanges::empty(),
).unwrap(),
);
@@ -605,6 +719,79 @@ mod test {
);
}
#[test]
fn load_decode_from_v2_migrates_data_format() {
let client = substrate_test_runtime_client::new();
let authorities = vec![(AuthorityId::default(), 100)];
let set_id = 3;
{
let authority_set = V2AuthoritySet::<H256, u64> {
current_authorities: authorities.clone(),
set_id,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
};
let genesis_state = (H256::random(), 32);
let voter_set_state: VoterSetState<substrate_test_runtime_client::runtime::Block> =
VoterSetState::live(
set_id,
&authority_set.clone().into(), // Note the conversion!
genesis_state
);
client.insert_aux(
&[
(AUTHORITY_SET_KEY, authority_set.encode().as_slice()),
(SET_STATE_KEY, voter_set_state.encode().as_slice()),
(VERSION_KEY, 2u32.encode().as_slice()),
],
&[],
).unwrap();
}
assert_eq!(
load_decode::<_, u32>(&client, VERSION_KEY).unwrap(),
Some(2),
);
// should perform the migration
load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
&client,
H256::random(),
0,
|| unreachable!(),
).unwrap();
assert_eq!(
load_decode::<_, u32>(&client, VERSION_KEY).unwrap(),
Some(3),
);
let PersistentData {
authority_set,
..
} = load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
&client,
H256::random(),
0,
|| unreachable!(),
).unwrap();
assert_eq!(
*authority_set.inner().read(),
AuthoritySet::new(
authorities.clone(),
set_id,
ForkTree::new(),
Vec::new(),
AuthoritySetChanges::empty(),
).unwrap(),
);
}
#[test]
fn write_read_concluded_rounds() {
let client = substrate_test_runtime_client::new();
@@ -625,7 +812,9 @@ mod test {
round_number.using_encoded(|n| key.extend(n));
assert_eq!(
load_decode::<_, CompletedRound::<substrate_test_runtime_client::runtime::Block>>(&client, &key).unwrap(),
load_decode::<_, CompletedRound::<substrate_test_runtime_client::runtime::Block>>(
&client, &key
).unwrap(),
Some(completed_round),
);
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -122,7 +122,7 @@ mod until_imported;
mod voting_rule;
pub use authorities::{SharedAuthoritySet, AuthoritySet};
pub use finality_proof::{FinalityProofFragment, FinalityProofProvider, StorageAndProofProvider};
pub use finality_proof::{FinalityProof, FinalityProofProvider, FinalityProofError};
pub use notification::{GrandpaJustificationSender, GrandpaJustificationStream};
pub use import::GrandpaBlockImport;
pub use justification::GrandpaJustification;
+2 -44
View File
@@ -32,25 +32,20 @@ use tokio::runtime::{Runtime, Handle};
use sp_keyring::Ed25519Keyring;
use sc_client_api::backend::TransactionFor;
use sp_blockchain::Result;
use sp_api::{ApiRef, StorageProof, ProvideRuntimeApi};
use sp_api::{ApiRef, ProvideRuntimeApi};
use substrate_test_runtime_client::runtime::BlockNumber;
use sp_consensus::{
BlockOrigin, ForkChoiceStrategy, ImportedAux, BlockImportParams, ImportResult, BlockImport,
import_queue::BoxJustificationImport,
};
use std::{collections::{HashMap, HashSet}, pin::Pin};
use parity_scale_codec::Decode;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, HashFor};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use sp_runtime::generic::{BlockId, DigestItem};
use sp_core::H256;
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
use sp_finality_grandpa::{GRANDPA_ENGINE_ID, AuthorityList, EquivocationProof, GrandpaApi, OpaqueKeyOwnershipProof};
use sp_state_machine::{InMemoryBackend, prove_read, read_proof_check};
use authorities::AuthoritySet;
use finality_proof::{
AuthoritySetForFinalityProver, AuthoritySetForFinalityChecker,
};
use sc_block_builder::BlockBuilderProvider;
use sc_consensus::LongestChain;
use sc_keystore::LocalKeystore;
@@ -207,43 +202,6 @@ impl GenesisAuthoritySetProvider<Block> for TestApi {
}
}
impl AuthoritySetForFinalityProver<Block> for TestApi {
fn authorities(&self, _block: &BlockId<Block>) -> Result<AuthorityList> {
Ok(self.genesis_authorities.clone())
}
fn prove_authorities(&self, block: &BlockId<Block>) -> Result<StorageProof> {
let authorities = self.authorities(block)?;
let backend = <InMemoryBackend<HashFor<Block>>>::from(vec![
(None, vec![(b"authorities".to_vec(), Some(authorities.encode()))])
]);
let proof = prove_read(backend, vec![b"authorities"])
.expect("failure proving read from in-memory storage backend");
Ok(proof)
}
}
impl AuthoritySetForFinalityChecker<Block> for TestApi {
fn check_authorities_proof(
&self,
_hash: <Block as BlockT>::Hash,
header: <Block as BlockT>::Header,
proof: StorageProof,
) -> Result<AuthorityList> {
let results = read_proof_check::<HashFor<Block>, _>(
*header.state_root(), proof, vec![b"authorities"]
)
.expect("failure checking read proof for authorities");
let encoded = results.get(&b"authorities"[..])
.expect("returned map must contain all proof keys")
.as_ref()
.expect("authorities in proof is None");
let authorities = Decode::decode(&mut &encoded[..])
.expect("failure decoding authorities read from proof");
Ok(authorities)
}
}
const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500);
fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList {