From dd5e43760d4255a5508b40fdd8d98b1958ea6e4d Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Mon, 17 Feb 2025 02:14:31 -0500 Subject: [PATCH] Add the UNIX timestamp (in milliseconds to the block This is read from the BABE pre-digest when converting from a SubstrateHeader. This causes the genesis block to have time 0 and all blocks produced with BABE to have a time of the slot time. While the slot time is in 6-second intervals (due to our target block time), defining in milliseconds preserves the ABI for long-term goals (sub-second blocks). Usage of the slot time deduplicates this field with BABE, and leaves the only possible manipulation to propose during a slot or to not propose during a slot. The actual reason this was implemented this way is because the Header trait is overly restrictive and doesn't allow definition with new fields. Even if we wanted to express the timestamp within the SubstrateHeader, we can't without replacing Header::new and making a variety of changes to the polkadot-sdk accordingly. Those aren't worth it at this moment compared to the solution implemented. --- substrate/abi/src/block.rs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/substrate/abi/src/block.rs b/substrate/abi/src/block.rs index 2fe103a9..04616aed 100644 --- a/substrate/abi/src/block.rs +++ b/substrate/abi/src/block.rs @@ -13,8 +13,11 @@ pub struct HeaderV1 { pub number: u64, /// The block this header builds upon. pub parent_hash: BlockHash, + /// The UNIX time in milliseconds this block was created at. + pub unix_time_in_millis: u64, /// The root of a Merkle tree commiting to the transactions within this block. - // TODO: Review the format of this defined by Substrate + // TODO: Review the format of this defined by Substrate. We don't want to commit to the signature + // TODO: Some transactions don't have unique hashes due to assuming vaalidators set unique keys pub transactions_root: [u8; 32], /// A commitment to the consensus data used to justify adding this block to the blockchain. pub consensus_commitment: [u8; 32], @@ -106,11 +109,33 @@ mod substrate { } impl From<&SubstrateHeader> for Header { - fn from(header: &SubstrateHeader) -> Header { + fn from(header: &SubstrateHeader) -> Self { + use sp_consensus_babe::SlotDuration; + use sc_consensus_babe::CompatibleDigestItem; + match header { SubstrateHeader::V1(header) => Header::V1(HeaderV1 { number: header.number, parent_hash: BlockHash(header.parent_hash.0), + unix_time_in_millis: header + .consensus + .digest + .logs() + .iter() + .find_map(|digest_item| { + digest_item.as_babe_pre_digest().map(|pre_digest| { + pre_digest + .slot() + .timestamp(SlotDuration::from_millis( + serai_primitives::constants::TARGET_BLOCK_TIME.as_millis().try_into().unwrap(), + )) + // This returns `None` if the slot is so far in the future, it'd cause an + // overflow. + .unwrap_or(sp_timestamp::Timestamp::new(u64::MAX)) + .as_millis() + }) + }) + .unwrap_or(0), transactions_root: header.transactions_root.0, consensus_commitment: sp_core::blake2_256(&header.consensus.encode()), }),