diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index a057190f6b378..a8d2634ade560 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -253,7 +253,8 @@ mod tests { use sc_consensus::ImportedAux; use sc_transaction_pool::{BasicPool, Options, RevalidationType}; use sc_transaction_pool_api::{MaintainedTransactionPool, TransactionPool, TransactionSource}; - use sp_runtime::generic::BlockId; + use sp_inherents::InherentData; + use sp_runtime::generic::{BlockId, Digest, DigestItem}; use substrate_test_runtime_client::{ AccountKeyring::*, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt, }; @@ -265,6 +266,35 @@ mod tests { const SOURCE: TransactionSource = TransactionSource::External; + struct TestDigestProvider { + _client: Arc, + } + impl ConsensusDataProvider for TestDigestProvider + where + B: BlockT, + C: ProvideRuntimeApi + Send + Sync, + { + type Transaction = TransactionFor; + + fn create_digest( + &self, + _parent: &B::Header, + _inherents: &InherentData, + ) -> Result { + Ok(Digest { logs: vec![] }) + } + + fn append_block_import( + &self, + _parent: &B::Header, + params: &mut BlockImportParams, + _inherents: &InherentData, + ) -> Result<(), Error> { + params.post_digests.push(DigestItem::Other(vec![1])); + Ok(()) + } + } + #[tokio::test] async fn instant_seal() { let builder = TestClientBuilder::new(); @@ -519,4 +549,53 @@ mod tests { // assert that fork block is in the db assert!(client.header(&BlockId::Hash(imported.hash)).unwrap().is_some()) } + + #[tokio::test] + async fn manual_seal_post_hash() { + let builder = TestClientBuilder::new(); + let (client, select_chain) = builder.build_with_longest_chain(); + let client = Arc::new(client); + let spawner = sp_core::testing::TaskExecutor::new(); + let pool = Arc::new(BasicPool::with_revalidation_type( + Options::default(), + true.into(), + api(), + None, + RevalidationType::Full, + spawner.clone(), + 0, + )); + let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); + + let (mut sink, commands_stream) = futures::channel::mpsc::channel(1024); + let future = run_manual_seal(ManualSealParams { + block_import: client.clone(), + env, + client: client.clone(), + pool: pool.clone(), + commands_stream, + select_chain, + // use a provider that pushes some post digest data + consensus_data_provider: Some(Box::new(TestDigestProvider { _client: client.clone() })), + create_inherent_data_providers: |_, _| async { Ok(()) }, + }); + std::thread::spawn(|| { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(future); + }); + let (tx, rx) = futures::channel::oneshot::channel(); + sink.send(EngineCommand::SealNewBlock { + parent_hash: None, + sender: Some(tx), + create_empty: true, + finalize: false, + }) + .await + .unwrap(); + let created_block = rx.await.unwrap().unwrap(); + + // assert that the background task returned the actual header hash + let header = client.header(&BlockId::Number(1)).unwrap().unwrap(); + assert_eq!(header.hash(), created_block.hash); + } } diff --git a/client/consensus/manual-seal/src/seal_block.rs b/client/consensus/manual-seal/src/seal_block.rs index ad840bd102b3f..99b003c32f136 100644 --- a/client/consensus/manual-seal/src/seal_block.rs +++ b/client/consensus/manual-seal/src/seal_block.rs @@ -153,9 +153,14 @@ pub async fn seal_block( digest_provider.append_block_import(&parent, &mut params, &inherent_data)?; } + // Make sure we return the same post-hash that will be calculated when importing the block + // This is important in case the digest_provider added any signature, seal, ect. + let mut post_header = header.clone(); + post_header.digest_mut().logs.extend(params.post_digests.iter().cloned()); + match block_import.import_block(params, HashMap::new()).await? { ImportResult::Imported(aux) => - Ok(CreatedBlock { hash: ::Header::hash(&header), aux }), + Ok(CreatedBlock { hash: ::Header::hash(&post_header), aux }), other => Err(other.into()), } };