From 3822c05515497be8446ffcdbf275efaa08d138bd Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Mon, 5 Aug 2024 18:45:48 +0100 Subject: [PATCH 1/2] Extend Bitcoin types with extra fields for validation --- src/state.cairo | 54 +++++++++++++++++++++++++++++++------------- src/validation.cairo | 2 ++ 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/state.cairo b/src/state.cairo index eb9c1950..8928a518 100644 --- a/src/state.cairo +++ b/src/state.cairo @@ -1,3 +1,9 @@ +//! Bitcoin data type objects extended with validation context. +//! +//! The data is expected to be prepared in advance and passed as program arguments. +//! The extended set of fields allows to recursively validate entities in a stateless manner, +//! and to avoid repetitive computations. + /// Represents the state of the blockchain. #[derive(Drop, Copy)] pub struct ChainState { @@ -13,23 +19,21 @@ pub struct ChainState { pub epoch_start_time: u32, /// Previous timestamps. pub prev_timestamps: Span, - // TODO: utreexo_roots? + // Utreexo roots (for checking [TxIn] inclusion proofs) + pub utreexo_roots: Span } /// Represents a block in the blockchain. -/// #[derive(Drop, Copy)] pub struct Block { /// block header pub header: Header, - // TODO: how to handle coinbase transactions? - /// Transactions pub txs: Span, } /// Block header -/// https://developer.bitcoin.org/reference/block_chain.html#block-headers +/// https://learnmeabitcoin.com/technical/block/ #[derive(Drop, Copy)] pub struct Header { /// The version of the block. @@ -46,22 +50,34 @@ pub struct Header { pub nonce: u32, } -/// Transaction -/// https://developer.bitcoin.org/reference/transactions.html#raw-transaction-format +/// Extended transaction. +/// https://learnmeabitcoin.com/technical/transaction/ +/// +/// Contains additional "meta" fields required for validation. #[derive(Drop, Copy)] pub struct Transaction { /// The version of the transaction. pub version: i32, + /// Flag which indicates the presence of witness data. + /// Segwit marker and flag do not contribute to TXID (transaction hash), + /// but do contribute to wTXID. + pub is_segwit: bool, /// The inputs of the transaction. pub inputs: Span, /// The outputs of the transaction. pub outputs: Span, + /// The list of witnesses, one for each input. + /// Each witness is a list of elements that are to be pushed onto stack. + /// Witnesses do not contribute to TXID but do contribute to wTXID. + pub witnesses: Span>, /// The lock time of the transaction. pub lock_time: u32, + /// Transaction fee which is diff between total input and output amounts (meta field) + pub fee: i64, } /// Output of a transaction. -/// https://developer.bitcoin.org/reference/transactions.html#txout-a-transaction-output +/// https://learnmeabitcoin.com/technical/transaction/output/ #[derive(Drop, Copy)] pub struct TxOut { /// The value of the output. @@ -70,17 +86,23 @@ pub struct TxOut { pub pk_script: @ByteArray, } -/// Input of a transaction. -/// https://developer.bitcoin.org/reference/transactions.html#txin-a-transaction-input-non-coinbase +/// Extended input of a transaction. +/// https://learnmeabitcoin.com/technical/transaction/input/ +/// +/// Contains additional "meta" fields required for validation. #[derive(Drop, Copy)] pub struct TxIn { - /// The transaction ID of the input. + /// The previous TXID this input spends. pub txid: u256, - /// The index of the input. - pub index: u32, - /// The script of the input. + /// The previous transaction output index this input spends. + pub vout: u32, + /// The signature script which satisfies the conditions placed in the txo pubkey script + /// or coinbase script that contains block height (since 227,836) and miner nonce (optional). pub script: @ByteArray, - /// The sequence of the input. + /// The sequence number of the input (). pub sequence: u32, + /// The previous transaction output this input spends (meta field) + pub txo: @TxOut, + /// Utreexo inclusion proof of the spent output (meta field) + pub txo_proof: Span, } - diff --git a/src/validation.cairo b/src/validation.cairo index 68bf7eb8..427f387d 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -85,6 +85,7 @@ mod tests { current_target: 1, epoch_start_time: 1, prev_timestamps: array![1, 2, 3, 4, 5].span(), + utreexo_roots: array![].span(), }; let mut block = Block { header: Header { @@ -116,6 +117,7 @@ mod tests { current_target: 1, epoch_start_time: 1, prev_timestamps: array![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].span(), + utreexo_roots: array![].span(), }; let mut block = Block { header: Header { From 49c707da33e415b81f87443be722bd132617f5fc Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Tue, 6 Aug 2024 13:54:14 +0100 Subject: [PATCH 2/2] Introduce utreexo state, set, and abstract proofs --- src/state.cairo | 69 ++++++++++++++++++++++++++++++-------------- src/validation.cairo | 8 ++--- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/src/state.cairo b/src/state.cairo index 8928a518..2f5e3653 100644 --- a/src/state.cairo +++ b/src/state.cairo @@ -19,8 +19,43 @@ pub struct ChainState { pub epoch_start_time: u32, /// Previous timestamps. pub prev_timestamps: Span, - // Utreexo roots (for checking [TxIn] inclusion proofs) - pub utreexo_roots: Span + /// Utreexo state + pub utreexo_state: UtreexoState, +} + +/// Accumulator representation of the state aka "Compact State Node" +#[derive(Drop, Copy)] +pub struct UtreexoState { + /// Roots of Merkle tree forest + pub roots: Span, +} + +/// Utreexo set is used to retrieve TXOs spent by particular inputs +#[derive(Drop, Copy)] +pub struct UtreexoSet { + /// A list of extended transaction outputs spent in a particular block(s). + pub outputs: Span, +} + +/// TXO extended with info about parent transaction and the position within it. +/// The hash of this structure is a leaf node in the Utreexo Merkle tree forest. +#[derive(Drop, Copy)] +pub struct UtreexoOutput { + /// The TXID this output belongs to. + pub txid: u256, + /// The index of this output. + pub vout: u32, + /// Output data + pub output: TxOut, +} + +/// Inclusion proof for multiple leaves +#[derive(Drop, Copy)] +pub struct UtreexoBatchProof { + /// Indices of tree leaves, one for each output in the utreexo set + pub targets: Span, + /// All the nodes required to calculate the root + pub proof: Span, } /// Represents a block in the blockchain. @@ -50,15 +85,15 @@ pub struct Header { pub nonce: u32, } -/// Extended transaction. +/// Transaction /// https://learnmeabitcoin.com/technical/transaction/ -/// -/// Contains additional "meta" fields required for validation. #[derive(Drop, Copy)] pub struct Transaction { /// The version of the transaction. - pub version: i32, + pub version: u32, /// Flag which indicates the presence of witness data. + /// It combines `marker` and `flag` fields for now but in the future + /// we might need to separate them if transaction structure changes. /// Segwit marker and flag do not contribute to TXID (transaction hash), /// but do contribute to wTXID. pub is_segwit: bool, @@ -72,37 +107,29 @@ pub struct Transaction { pub witnesses: Span>, /// The lock time of the transaction. pub lock_time: u32, - /// Transaction fee which is diff between total input and output amounts (meta field) - pub fee: i64, } /// Output of a transaction. /// https://learnmeabitcoin.com/technical/transaction/output/ #[derive(Drop, Copy)] pub struct TxOut { - /// The value of the output. + /// The value of the output in satoshis. pub value: i64, - /// The public key script of the output. + /// The spending script (aka locking code) for this output. pub pk_script: @ByteArray, } -/// Extended input of a transaction. +/// Input of a transaction. /// https://learnmeabitcoin.com/technical/transaction/input/ /// -/// Contains additional "meta" fields required for validation. +/// NOTE that `txid` and `vout` fields can be resolved via Utreexo set using the TXO index. #[derive(Drop, Copy)] pub struct TxIn { - /// The previous TXID this input spends. - pub txid: u256, - /// The previous transaction output index this input spends. - pub vout: u32, /// The signature script which satisfies the conditions placed in the txo pubkey script /// or coinbase script that contains block height (since 227,836) and miner nonce (optional). pub script: @ByteArray, - /// The sequence number of the input (). + /// The sequence number of the input. pub sequence: u32, - /// The previous transaction output this input spends (meta field) - pub txo: @TxOut, - /// Utreexo inclusion proof of the spent output (meta field) - pub txo_proof: Span, + /// The index of output in the utreexo set (meta field). + pub txo_index: u64, } diff --git a/src/validation.cairo b/src/validation.cairo index 427f387d..2b65e832 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -1,4 +1,4 @@ -use super::state::{Block, ChainState}; +use super::state::{Block, ChainState, UtreexoState}; #[generate_trait] impl BlockValidatorImpl of BlockValidator { @@ -73,7 +73,7 @@ fn validate_merkle_root(self: @ChainState, block: @Block) -> Result<(), ByteArra #[cfg(test)] mod tests { use super::{validate_target, validate_timestamp}; - use super::{Block, ChainState}; + use super::{Block, ChainState, UtreexoState}; use super::super::state::{Header, Transaction, TxIn, TxOut}; #[test] @@ -85,7 +85,7 @@ mod tests { current_target: 1, epoch_start_time: 1, prev_timestamps: array![1, 2, 3, 4, 5].span(), - utreexo_roots: array![].span(), + utreexo_state: UtreexoState { roots: array![].span() }, }; let mut block = Block { header: Header { @@ -117,7 +117,7 @@ mod tests { current_target: 1, epoch_start_time: 1, prev_timestamps: array![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].span(), - utreexo_roots: array![].span(), + utreexo_state: UtreexoState { roots: array![].span() }, }; let mut block = Block { header: Header {