diff --git a/Cargo.lock b/Cargo.lock index f0a169fe9..643d15298 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7910,6 +7910,7 @@ dependencies = [ "scale-info", "serde", "sp-api", + "sp-core", "sp-inherents", "sp-runtime", "sp-std", diff --git a/tuxedo-core/aggregator/src/lib.rs b/tuxedo-core/aggregator/src/lib.rs index 079e00bb5..beadd1b8f 100644 --- a/tuxedo-core/aggregator/src/lib.rs +++ b/tuxedo-core/aggregator/src/lib.rs @@ -171,7 +171,7 @@ pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> Token fn create_inherents( authoring_inherent_data: &InherentData, - previous_inherents: Vec>, + previous_inherents: Vec<(tuxedo_core::types::Transaction<#verifier, #outer_type>, sp_core::H256)>, ) -> Vec> { let mut all_inherents = Vec::new(); @@ -179,20 +179,26 @@ pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> Token #( { // Filter the previous inherents down to just the ones that came from this piece - let previous_inherents = previous_inherents.iter().filter_map(|tx| { - match tx.checker { - #outer_type::#variants3(ref inner_checker) => Some( - tuxedo_core::types::Transaction { - inputs: tx.inputs.clone(), - peeks: tx.peeks.clone(), - outputs: tx.outputs.clone(), - checker: inner_checker.clone(), - } - ), - _ => None, - } - }) - .collect(); + let previous_inherents = previous_inherents + .iter() + .filter_map(|(tx, hash)| { + match tx.checker { + #outer_type::#variants3(ref inner_checker) => Some( + ( + tuxedo_core::types::Transaction { + inputs: tx.inputs.clone(), + peeks: tx.peeks.clone(), + outputs: tx.outputs.clone(), + checker: inner_checker.clone(), + }, + *hash, + ) + ), + _ => None, + } + }) + .collect(); + let inherents = <#inner_types3 as tuxedo_core::ConstraintChecker<#verifier>>::InherentHooks::create_inherents(authoring_inherent_data, previous_inherents) .iter() .map(|tx| tx.transform::<#outer_type>()) @@ -274,7 +280,7 @@ pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> Token Self::#variants6(inner) => <#inner_types6 as tuxedo_core::ConstraintChecker<#verifier>>::is_inherent(inner), )* } - + } } diff --git a/tuxedo-core/src/executive.rs b/tuxedo-core/src/executive.rs index bf9c64978..e92dc8705 100644 --- a/tuxedo-core/src/executive.rs +++ b/tuxedo-core/src/executive.rs @@ -19,6 +19,7 @@ use log::debug; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_api::{BlockT, HashT, HeaderT, TransactionValidity}; +use sp_core::H256; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{ traits::BlakeTwo256, @@ -423,13 +424,20 @@ impl< ); // Extract the beginning-of-block inherents from the previous block. - // The parent is already imported, so we know it is valid and we know its inherents came first + // The parent is already imported, so we know it is valid and we know its inherents came first. + // We also annotate each transaction with its original hash for purposes of constructing output refs later. + // This is necessary because the transaction hash changes as we unwrap layers of aggregation, + // and we need an original universal transaction id. // TODO Enforce that inherents are first in the execution path by making sure there are no more inherents after the first non-inherent. - let previous_blocks_inherents: Vec<::Extrinsic> = parent + let previous_blocks_inherents: Vec<(::Extrinsic, H256)> = parent .extrinsics() .iter() .cloned() .take_while(|tx| tx.checker.is_inherent()) + .map(|tx| { + let id = BlakeTwo256::hash_of(&tx.encode()); + (tx, id) + }) .collect(); log::info!( diff --git a/tuxedo-core/src/inherents.rs b/tuxedo-core/src/inherents.rs index b7a2eb937..a5cb2b6a1 100644 --- a/tuxedo-core/src/inherents.rs +++ b/tuxedo-core/src/inherents.rs @@ -44,6 +44,7 @@ use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; +use sp_core::H256; use sp_inherents::{ CheckInherentsResult, InherentData, InherentIdentifier, IsFatalError, MakeFatalError, }; @@ -112,7 +113,7 @@ pub trait TuxedoInherent>: Sized + TypeInfo // The option represents the so-called "first block hack". // We need a way to initialize the chain with a first inherent on block one // where there is no previous inherent. Once we introduce genesis extrinsics, this can be removed. - previous_inherent: Option>, + previous_inherent: Option<(Transaction, H256)>, ) -> Transaction; /// Perform off-chain pre-execution checks on the inherents. @@ -139,7 +140,7 @@ pub trait InherentInternal>: Sized + TypeIn /// The inherent data is supplied by the authoring node. fn create_inherents( authoring_inherent_data: &InherentData, - previous_inherents: Vec>, + previous_inherents: Vec<(Transaction, H256)>, ) -> Vec>; /// Perform off-chain pre-execution checks on the inherents. @@ -165,7 +166,7 @@ impl, T: TuxedoInherent + 'static> In fn create_inherents( authoring_inherent_data: &InherentData, - previous_inherents: Vec>, + previous_inherents: Vec<(Transaction, H256)>, ) -> Vec> { if previous_inherents.len() > 1 { panic!("Authoring a leaf inherent constraint checker, but multiple previous inherents were supplied.") @@ -220,7 +221,10 @@ impl, T: TuxedoInherent + 'static> In impl> InherentInternal for () { type Error = MakeFatalError<()>; - fn create_inherents(_: &InherentData, _: Vec>) -> Vec> { + fn create_inherents( + _: &InherentData, + _: Vec<(Transaction, H256)>, + ) -> Vec> { Vec::new() } diff --git a/wardrobe/timestamp/Cargo.toml b/wardrobe/timestamp/Cargo.toml index ab6d6b638..b679a28a8 100644 --- a/wardrobe/timestamp/Cargo.toml +++ b/wardrobe/timestamp/Cargo.toml @@ -16,6 +16,7 @@ sp-inherents = { default_features = false, workspace = true } sp-runtime = { default_features = false, workspace = true } sp-std = { default_features = false, workspace = true } sp-timestamp = { default_features = false, workspace = true } +sp-core = { default_features = false, workspace = true } tuxedo-core = { default-features = false, path = "../../tuxedo-core" } [features] @@ -27,6 +28,7 @@ std = [ "sp-inherents/std", "sp-runtime/std", "sp-std/std", + "sp-core/std", "sp-timestamp/std", "serde", ] diff --git a/wardrobe/timestamp/src/lib.rs b/wardrobe/timestamp/src/lib.rs index d2b7f3591..a2c7747ab 100644 --- a/wardrobe/timestamp/src/lib.rs +++ b/wardrobe/timestamp/src/lib.rs @@ -17,6 +17,7 @@ use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; +use sp_core::H256; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{traits::BlakeTwo256, transaction_validity::TransactionPriority}; use sp_std::{vec, vec::Vec}; @@ -27,7 +28,8 @@ use tuxedo_core::{ inherents::{TuxedoInherent, TuxedoInherentAdapter}, support_macros::{CloneNoBound, DebugNoBound, DefaultNoBound}, types::{Input, Output, Transaction}, - verifier::UpForGrabs, SimpleConstraintChecker, Verifier, + verifier::UpForGrabs, + SimpleConstraintChecker, Verifier, }; #[cfg(test)] @@ -271,19 +273,17 @@ impl> SimpleConstra fn is_inherent(&self) -> bool { true } - - } -impl, T: TimestampConfig + 'static> - TuxedoInherent for SetTimestamp +impl, T: TimestampConfig + 'static> TuxedoInherent + for SetTimestamp { type Error = sp_timestamp::InherentError; const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = sp_timestamp::INHERENT_IDENTIFIER; fn create_inherent( authoring_inherent_data: &InherentData, - previous_inherent: Option>, + previous_inherent: Option<(Transaction, H256)>, ) -> tuxedo_core::types::Transaction { // Extract the current timestamp from the inherent data let timestamp_millis: u64 = authoring_inherent_data @@ -308,7 +308,7 @@ impl, T: TimestampConfig + 'static> // We don't need any inputs, so just do nothing. } (None, _) => panic!("Attemping to construct timestamp inherent with no previous inherent (and not block 1)."), - (Some(previous_inherent), _) => { + (Some((previous_inherent, previous_id)), _) => { // This is the the normal case. We create a full previous input to consume. let prev_best_index = previous_inherent .outputs @@ -320,9 +320,8 @@ impl, T: TimestampConfig + 'static> .try_into() .expect("There should not be more than u32::max_value outputs in a transaction."); - // TODO should we have some generic way to refer to the hashing algo? let output_ref = OutputRef { - tx_hash: BlakeTwo256::hash_of(&previous_inherent.encode()), + tx_hash: previous_id, index: prev_best_index, }; @@ -333,7 +332,7 @@ impl, T: TimestampConfig + 'static> // Once this is fixed more properly (like by using evictions) // I should be able to not mention UpForGrabs here at all. redeemer: Vec::new(), - }; + }; inputs.push(input); }