Introduce inherent digests (#2466)

* Introduce inherent digests

* Implement inherent digests

* fix silly error

* Implementation of inherent digests in BABE

All tests pass. There are still limitations:

1. The runtime strips out inherent digests, so BABE must re-add them.
2. The test runtime checks that it can re-compute all digests.  It
   can’t, so I had to comment out that test.

* Fix compilation and seal import

Seals were not imported correctly: the pre-digest was imported twice,
instead of both it and the seal being imported.  Also, other parts of
the code did not compile due to incomplete refactoring.

* Remove bogus assertion

* Fix testsuite compilation

* Remove unused import

* Fix compiler diagnostics

* Add inherent digest parameters to block constructors

This enforces that inherent digests are added first.

* Fixup Cargo.lock

* Fix build errors

* Re-add an incorrectly removed import

* Bump primitive-types version

* Update Cargo.lock

* Refactoring

* Use inherent digests for AuRa

They do reach the runtime, but get stripped.  I have not figured out
where.

* Fix compilation errors

* Fix compilation errors due to incorrect types

* Fix whitespace

Suggested-by: Tomasz Drwiega <tomasz@parity.io>

* Add preamble

Suggested-by: Tomasz Drwiega <tomasz@parity.io>

* Fix silly compile error

* Refactor pre-digest finding code into a separate function

* Remove unwanted assertion

It is too likely to bring down the entire blockchain.

Suggested-by: Tomasz Drwiega <tomasz@parity.io>

* Use `find_pre_digest` after runtime, too

Also, use `Member` trait rather than rolling our own requirements.

Suggested-by: Tomasz Drwiega <tomasz@parity.io>

* Fix various warnings

mostly due to upgrading the dependency on `error_chain`.

* Pre-digests nearly complete

This nearly completes the implementation of pre-runtime digests.

* `Seal2` → `Seal` and fix test suite

* Try to fix the storage error

* Try to fix storage (again)

* Fix tests

* Hopefully finish pre-runtime digests

The key is to pass *only* the pre-runtime digests to the runtime.  The
others must be stripped out by `initialize_block`.

* Fix silly typo

* Fix another silly mistake

* Remove unnecessary filtering of BABE pre-digests

We no longer get duplicate BABE pre-digests, so if they appear, the
header should be rejected outright.

* Update Cargo.lock files

* Reformatting

* Fix silly typo in inherent digest code

Also, revert `error.rs` files that contained calls to the `error_chain!`
macro.

* Try to keep the runtime from stripping pre-digests

Currently runs into the “Storage root must match that calculated”
assertion.

* Don’t compute storage root until storage changes are done.

Also, fix a compilation error.

* Fix compile-time error

* Fix compilation errors

* Fix more compile errors

* Hopefully it compiles this time…

* Fix compilation and add docs

* Prevent BABE from adding duplicate pre-runtime digests

Found by comparing with the AuRa code.  I also did some refactoring.

* Respond to review and fix some warnings

* Delete some dead code introduced earlier

* More dead code goes away

* `ref mut` → `&mut`

* Respond to review and fix some warnings

* Fix compilation error

* Remove unneeded `HashT` type parameter

Suggested-by: Robert Habermeier <robert@parity.io>

* Remove spurious #[allow(deprecated)]

* Document inherent digest parameter to `build_block`

* Delete `Simple` trait

It wasn’t needed

* delete wrongly added files

* Fix trait bounds

* Digest serialization tests

I also did some reformatting and cleanup.

* Apply suggestions from code review

Reformatting

Co-Authored-By: André Silva <andre.beat@gmail.com>

* Swap two arguments to `propose` and `propose_with`

Also, remove some needless unsafe code.

* Remove bogus `#![allow(deprecated)]` annotations

With the removal of the deprecated `Seal` variant, these are not needed.

* Add a missing `#[allow(deprecated)]` in the AuRa tests

* Fix silly compile error

* Fix silly compiler error

RLS did not tell me that I hadn’t fixed `babe/lib.rs`, so I missed it.

* Fixes made automatically by Cargo
This commit is contained in:
DemiMarie-parity
2019-05-29 08:13:38 -04:00
committed by Gavin Wood
parent e9a4c80c40
commit c7d1204ce5
55 changed files with 1031 additions and 871 deletions
@@ -20,7 +20,7 @@ use parity_codec::Encode;
use runtime_primitives::ApplyOutcome;
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{
Header as HeaderT, Hash, Block as BlockT, One, HashFor, ProvideRuntimeApi, ApiRef
Header as HeaderT, Hash, Block as BlockT, One, HashFor, ProvideRuntimeApi, ApiRef, DigestFor,
};
use primitives::{H256, ExecutionContext};
use crate::blockchain::HeaderBackend;
@@ -41,10 +41,11 @@ where
A: ProvideRuntimeApi + HeaderBackend<Block> + 'a,
A::Api: BlockBuilderApi<Block>,
{
/// Create a new instance of builder from the given client, building on the latest block.
pub fn new(api: &'a A) -> error::Result<Self> {
/// Create a new instance of builder from the given client, building on the
/// latest block.
pub fn new(api: &'a A, inherent_digests: DigestFor<Block>) -> error::Result<Self> {
api.info().and_then(|i|
Self::at_block(&BlockId::Hash(i.best_hash), api, false)
Self::at_block(&BlockId::Hash(i.best_hash), api, false, inherent_digests)
)
}
@@ -57,7 +58,8 @@ where
pub fn at_block(
block_id: &BlockId<Block>,
api: &'a A,
proof_recording: bool
proof_recording: bool,
inherent_digests: DigestFor<Block>,
) -> error::Result<Self> {
let number = api.block_number_from_id(block_id)?
.ok_or_else(|| error::Error::UnknownBlock(format!("{}", block_id)))?
@@ -70,7 +72,7 @@ where
Default::default(),
Default::default(),
parent_hash,
Default::default()
inherent_digests,
);
let mut api = api.runtime_api();
@@ -80,7 +82,7 @@ where
}
api.initialize_block_with_context(
block_id, ExecutionContext::BlockConstruction, &header
block_id, ExecutionContext::BlockConstruction, &header,
)?;
Ok(BlockBuilder {
+48 -42
View File
@@ -37,7 +37,7 @@ use consensus::{
use runtime_primitives::traits::{
Block as BlockT, Header as HeaderT, Zero, NumberFor, CurrentHeight,
BlockNumberToHash, ApiRef, ProvideRuntimeApi, Digest, DigestItem,
SaturatedConversion, One
SaturatedConversion, One, DigestFor,
};
use runtime_primitives::BuildStorage;
use crate::runtime_api::{
@@ -695,26 +695,29 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
/// Create a new block, built on the head of the chain.
pub fn new_block(
&self
&self,
inherent_digests: DigestFor<Block>,
) -> error::Result<block_builder::BlockBuilder<Block, Self>> where
E: Clone + Send + Sync,
RA: Send + Sync,
Self: ProvideRuntimeApi,
<Self as ProvideRuntimeApi>::Api: BlockBuilderAPI<Block>
{
block_builder::BlockBuilder::new(self)
block_builder::BlockBuilder::new(self, inherent_digests)
}
/// Create a new block, built on top of `parent`.
pub fn new_block_at(
&self, parent: &BlockId<Block>
&self,
parent: &BlockId<Block>,
inherent_digests: DigestFor<Block>,
) -> error::Result<block_builder::BlockBuilder<Block, Self>> where
E: Clone + Send + Sync,
RA: Send + Sync,
Self: ProvideRuntimeApi,
<Self as ProvideRuntimeApi>::Api: BlockBuilderAPI<Block>
{
block_builder::BlockBuilder::at_block(parent, &self, false)
block_builder::BlockBuilder::at_block(parent, &self, false, inherent_digests)
}
/// Create a new block, built on top of `parent` with proof recording enabled.
@@ -723,14 +726,16 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
/// These recorded trie nodes can be used by a third party to proof the
/// output of this block builder without having access to the full storage.
pub fn new_block_at_with_proof_recording(
&self, parent: &BlockId<Block>
&self,
parent: &BlockId<Block>,
inherent_digests: DigestFor<Block>,
) -> error::Result<block_builder::BlockBuilder<Block, Self>> where
E: Clone + Send + Sync,
RA: Send + Sync,
Self: ProvideRuntimeApi,
<Self as ProvideRuntimeApi>::Api: BlockBuilderAPI<Block>
{
block_builder::BlockBuilder::at_block(parent, &self, true)
block_builder::BlockBuilder::at_block(parent, &self, true, inherent_digests)
}
/// Lock the import lock, and run operations inside.
@@ -1272,11 +1277,12 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
/// Prepare in-memory header that is used in execution environment.
fn prepare_environment_block(&self, parent: &BlockId<Block>) -> error::Result<Block::Header> {
let parent_header = self.backend().blockchain().expect_header(*parent)?;
Ok(<<Block as BlockT>::Header as HeaderT>::new(
self.backend.blockchain().expect_block_number_from_id(parent)? + One::one(),
Default::default(),
Default::default(),
self.backend.blockchain().expect_block_hash_from_id(&parent)?,
parent_header.hash(),
Default::default(),
))
}
@@ -1753,7 +1759,7 @@ pub(crate) mod tests {
let remote_client = test_client::new_with_changes_trie();
let mut nonces: HashMap<_, u64> = Default::default();
for (i, block_transfers) in blocks_transfers.into_iter().enumerate() {
let mut builder = remote_client.new_block().unwrap();
let mut builder = remote_client.new_block(Default::default()).unwrap();
for (from, to) in block_transfers {
builder.push_transfer(Transfer {
from: from.into(),
@@ -1828,7 +1834,7 @@ pub(crate) mod tests {
fn block_builder_works_with_no_transactions() {
let client = test_client::new();
let builder = client.new_block().unwrap();
let builder = client.new_block(Default::default()).unwrap();
client.import(BlockOrigin::Own, builder.bake().unwrap()).unwrap();
@@ -1839,7 +1845,7 @@ pub(crate) mod tests {
fn block_builder_works_with_transactions() {
let client = test_client::new();
let mut builder = client.new_block().unwrap();
let mut builder = client.new_block(Default::default()).unwrap();
builder.push_transfer(Transfer {
from: AccountKeyring::Alice.into(),
@@ -1872,7 +1878,7 @@ pub(crate) mod tests {
fn block_builder_does_not_include_invalid() {
let client = test_client::new();
let mut builder = client.new_block().unwrap();
let mut builder = client.new_block(Default::default()).unwrap();
builder.push_transfer(Transfer {
from: AccountKeyring::Alice.into(),
@@ -1921,7 +1927,7 @@ pub(crate) mod tests {
let client = test_client::new();
let uninserted_block = client.new_block().unwrap().bake().unwrap();
let uninserted_block = client.new_block(Default::default()).unwrap().bake().unwrap();
#[allow(deprecated)]
let backend = client.backend().as_in_memory();
#[allow(deprecated)]
@@ -1940,11 +1946,11 @@ pub(crate) mod tests {
let client = test_client::new();
// G -> A1
let a1 = client.new_block().unwrap().bake().unwrap();
let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a1.clone()).unwrap();
// A1 -> A2
let a2 = client.new_block().unwrap().bake().unwrap();
let a2 = client.new_block(Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a2.clone()).unwrap();
let v: Vec<H256> = Vec::new();
assert_eq!(v, client.uncles(a2.hash(), 3).unwrap());
@@ -1960,27 +1966,27 @@ pub(crate) mod tests {
let client = test_client::new();
// G -> A1
let a1 = client.new_block().unwrap().bake().unwrap();
let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a1.clone()).unwrap();
// A1 -> A2
let a2 = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap().bake().unwrap();
let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a2.clone()).unwrap();
// A2 -> A3
let a3 = client.new_block_at(&BlockId::Hash(a2.hash())).unwrap().bake().unwrap();
let a3 = client.new_block_at(&BlockId::Hash(a2.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a3.clone()).unwrap();
// A3 -> A4
let a4 = client.new_block_at(&BlockId::Hash(a3.hash())).unwrap().bake().unwrap();
let a4 = client.new_block_at(&BlockId::Hash(a3.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a4.clone()).unwrap();
// A4 -> A5
let a5 = client.new_block_at(&BlockId::Hash(a4.hash())).unwrap().bake().unwrap();
let a5 = client.new_block_at(&BlockId::Hash(a4.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a5.clone()).unwrap();
// A1 -> B2
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap();
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
builder.push_transfer(Transfer {
from: AccountKeyring::Alice.into(),
@@ -1992,15 +1998,15 @@ pub(crate) mod tests {
client.import(BlockOrigin::Own, b2.clone()).unwrap();
// B2 -> B3
let b3 = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap().bake().unwrap();
let b3 = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, b3.clone()).unwrap();
// B3 -> B4
let b4 = client.new_block_at(&BlockId::Hash(b3.hash())).unwrap().bake().unwrap();
let b4 = client.new_block_at(&BlockId::Hash(b3.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, b4.clone()).unwrap();
// // B2 -> C3
let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap();
let mut builder = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default()).unwrap();
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
builder.push_transfer(Transfer {
from: AccountKeyring::Alice.into(),
@@ -2012,7 +2018,7 @@ pub(crate) mod tests {
client.import(BlockOrigin::Own, c3.clone()).unwrap();
// A1 -> D2
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap();
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
builder.push_transfer(Transfer {
from: AccountKeyring::Alice.into(),
@@ -2052,11 +2058,11 @@ pub(crate) mod tests {
let client = test_client::new();
// G -> A1
let a1 = client.new_block().unwrap().bake().unwrap();
let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a1.clone()).unwrap();
// A1 -> A2
let a2 = client.new_block().unwrap().bake().unwrap();
let a2 = client.new_block(Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a2.clone()).unwrap();
let genesis_hash = client.info().unwrap().chain.genesis_hash;
@@ -2083,27 +2089,27 @@ pub(crate) mod tests {
let client = test_client::new();
// G -> A1
let a1 = client.new_block().unwrap().bake().unwrap();
let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a1.clone()).unwrap();
// A1 -> A2
let a2 = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap().bake().unwrap();
let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a2.clone()).unwrap();
// A2 -> A3
let a3 = client.new_block_at(&BlockId::Hash(a2.hash())).unwrap().bake().unwrap();
let a3 = client.new_block_at(&BlockId::Hash(a2.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a3.clone()).unwrap();
// A3 -> A4
let a4 = client.new_block_at(&BlockId::Hash(a3.hash())).unwrap().bake().unwrap();
let a4 = client.new_block_at(&BlockId::Hash(a3.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a4.clone()).unwrap();
// A4 -> A5
let a5 = client.new_block_at(&BlockId::Hash(a4.hash())).unwrap().bake().unwrap();
let a5 = client.new_block_at(&BlockId::Hash(a4.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a5.clone()).unwrap();
// A1 -> B2
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap();
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
builder.push_transfer(Transfer {
from: AccountKeyring::Alice.into(),
@@ -2115,15 +2121,15 @@ pub(crate) mod tests {
client.import(BlockOrigin::Own, b2.clone()).unwrap();
// B2 -> B3
let b3 = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap().bake().unwrap();
let b3 = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, b3.clone()).unwrap();
// B3 -> B4
let b4 = client.new_block_at(&BlockId::Hash(b3.hash())).unwrap().bake().unwrap();
let b4 = client.new_block_at(&BlockId::Hash(b3.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, b4.clone()).unwrap();
// // B2 -> C3
let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap();
let mut builder = client.new_block_at(&BlockId::Hash(b2.hash()), Default::default()).unwrap();
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
builder.push_transfer(Transfer {
from: AccountKeyring::Alice.into(),
@@ -2135,7 +2141,7 @@ pub(crate) mod tests {
client.import(BlockOrigin::Own, c3.clone()).unwrap();
// A1 -> D2
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap();
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
builder.push_transfer(Transfer {
from: AccountKeyring::Alice.into(),
@@ -2372,11 +2378,11 @@ pub(crate) mod tests {
let client = test_client::new();
// G -> A1
let a1 = client.new_block().unwrap().bake().unwrap();
let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a1.clone()).unwrap();
// A1 -> A2
let a2 = client.new_block().unwrap().bake().unwrap();
let a2 = client.new_block(Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a2.clone()).unwrap();
let genesis_hash = client.info().unwrap().chain.genesis_hash;
@@ -2412,16 +2418,16 @@ pub(crate) mod tests {
let client = test_client::new();
// G -> A1
let a1 = client.new_block().unwrap().bake().unwrap();
let a1 = client.new_block(Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a1.clone()).unwrap();
// A1 -> A2
let a2 = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap().bake().unwrap();
let a2 = client.new_block_at(&BlockId::Hash(a1.hash()), Default::default()).unwrap().bake().unwrap();
client.import(BlockOrigin::Own, a2.clone()).unwrap();
// A2 -> A3
let justification = vec![1, 2, 3];
let a3 = client.new_block_at(&BlockId::Hash(a2.hash())).unwrap().bake().unwrap();
let a3 = client.new_block_at(&BlockId::Hash(a2.hash()), Default::default()).unwrap().bake().unwrap();
client.import_justified(BlockOrigin::Own, a3.clone(), justification.clone()).unwrap();
#[allow(deprecated)]
@@ -448,7 +448,7 @@ pub fn check_execution_proof<Header, E, H>(
Default::default(),
Default::default(),
request.header.hash(),
Default::default(),
request.header.digest().clone(),
);
execution_proof_check_on_trie_backend::<H, _>(
&trie_backend,
@@ -525,7 +525,7 @@ mod tests {
for _ in 1..3 {
remote_client.import_justified(
BlockOrigin::Own,
remote_client.new_block().unwrap().bake().unwrap(),
remote_client.new_block(Default::default()).unwrap().bake().unwrap(),
Default::default(),
).unwrap();
}
+1 -1
View File
@@ -588,7 +588,7 @@ pub mod tests {
let remote_client = test_client::new();
let mut local_headers_hashes = Vec::new();
for i in 0..4 {
let builder = remote_client.new_block().unwrap();
let builder = remote_client.new_block(Default::default()).unwrap();
remote_client.import(BlockOrigin::Own, builder.bake().unwrap()).unwrap();
local_headers_hashes.push(remote_client.block_hash(i + 1)
.map_err(|_| ClientError::Backend("TestError".into())));