Skip to content

Commit

Permalink
Use outpoint as utreexo leaf
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kus committed Aug 15, 2024
1 parent 801b0a7 commit 582acba
Show file tree
Hide file tree
Showing 10 changed files with 2,503 additions and 2,464 deletions.
10 changes: 4 additions & 6 deletions scripts/data/block_filter.jq
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ def txin_coinbase:
previous_output: OutPoint {
txid: 0_u256,
vout: 0xffffffff_u32,
txo_index: 0,
txo_index: Option::None,
amount: 0,
data: Default::default(),
block_height: Default::default(),
},
witness: array![].span()
}"
Expand All @@ -20,8 +19,8 @@ def txin_regular:
previous_output: OutPoint {
txid: 0x\(.txid),
vout: \(.vout),
txo_index: Option::None,
amount: 0,
data: Default::default(),
block_height: Default::default(),
},
witness: array![].span()
}"
Expand Down Expand Up @@ -76,4 +75,3 @@ pub fn block_\(.height)() -> Block {
;

.result | fixture

2 changes: 1 addition & 1 deletion scripts/data/get_block.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -e;
set -o pipefail;

HEIGHT=$(curl -s --user $USERPWD -s -d '{"jsonrpc": "1.0", "id":"curltest", "method": "getblockheader", "params": ["'${1}'"] }' -H 'content-type: text/plain;' $BITCOIN_RPC | jq -r '.result.height')
HEIGHT=$(curl -s --user $USERPWD -d '{"jsonrpc": "1.0", "id":"curltest", "method": "getblockheader", "params": ["'${1}'"] }' -H 'content-type: text/plain;' $BITCOIN_RPC | jq -r '.result.height')

curl \
-s \
Expand Down
60 changes: 51 additions & 9 deletions src/state.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -72,45 +72,87 @@ pub struct Transaction {

/// Output of a transaction.
/// https://learnmeabitcoin.com/technical/transaction/output/
///
/// Upon processing (validating) an output one of three actions must be taken:
/// - Add output with some extra info (see [OutPoint]) to the Utreexo accumulator
/// - Add output to the cache in case it is going to be spent in the same block
/// - Do nothing in case of a provably unspendable output
///
/// Read more: https://en.bitcoin.it/wiki/Script#Provably_Unspendable/Prunable_Outputs
#[derive(Drop, Copy)]
pub struct TxOut {
/// The value of the output in satoshis.
/// The protocol allows zero outputs.
pub value: u64,
/// The spending script (aka locking code) for this output.
pub pk_script: @ByteArray,
/// Meta flag indicating that this output will be spent within the current block(s).
/// It won't be added to the utreexo accumulator in that case.
/// This output won't be added to the utreexo accumulator.
/// Note that coinbase outputs cannot be spent sooner than 100 blocks after inclusion.
pub cached: bool,
}

/// Input of a transaction.
/// https://learnmeabitcoin.com/technical/transaction/input/
///
/// NOTE that `txid` and `vout` fields can be resolved via Utreexo set using the TXO index.
#[derive(Drop, Copy)]
pub struct TxIn {
/// 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.
pub sequence: u32,
/// The reference to the previous output that is being used as an input.
/// The reference to the previous output that is being spent by this input.
pub previous_output: OutPoint,
/// The witness data for transactions.
/// A list of items (of different size) pushed onto stack before sig script execution.
pub witness: Span<ByteArray>,
}

/// A reference to a transaction output.
///
/// NOTE that `data` and `block_height` meta fields are not serialized with the rest of
/// the transaction and hence are not constrained with the transaction hash.
///
/// There are four possible cases:
/// 1. Coinbase input that does not spend any outputs (zero txid)
/// 2. Input that spends an output created within the same block (cached)
/// 3. Input that spends a coinbase output
/// 4. Input that spends an output from a past block
///
/// For (1) we don't need to add extra constraints, because meta fields are not used.
/// For (2) we need to check that the referenced output is indeed cached:
/// * Calculate cache key by hashing (txid, vout, data)
/// * Check if the key is present in the cache
/// * Remove item from the cache
/// For (3) we need to check that the referenced output is in the utreexo accumulator:
/// * Calculate utreexo leaf hash from (txid, vout, data, block_height)
/// * Verify inclusion proof (either individual or batched) against the roots
/// * Delete the leaf from the accumulator
/// For (4) we need to additionally check if the coinbase output is older than 100 blocks
///
/// IMPORTANT:
/// * Utreexo proofs can be verified at any point of block validation because accumulator
/// is not changing until the end of the block;
/// * Cache lookups MUST be done in a sequential order, i.e. transactions are validated
/// one by one, first inputs then outputs. Output validation might put something to the
/// cache while input validation might remove an item, thus it's important to maintain
/// the order.
#[derive(Drop, Copy)]
pub struct OutPoint {
/// The hash of the referenced transaction.
pub txid: u256,
/// The index of the specific output in the transaction.
pub vout: u32,
/// It's important to verify that txid and vout match the ones in resolved item.
/// If field is set to None then it is a cached output (not in the utreexo set).
pub txo_index: Option<u64>,
// Amount calculated with the txid and vout
pub amount: u64,
/// Referenced output data (meta field).
/// Must be set to default for coinbase inputs.
pub data: TxOut,
/// The height of the block that contains this output (meta field).
/// Must be set to None for all inputs except for the ones that spend coinbase outputs.
pub block_height: Option<u32>,
}

impl TxOutDefault of Default<TxOut> {
fn default() -> TxOut {
TxOut { value: 0, pk_script: @"", cached: false, }
}
}
24 changes: 4 additions & 20 deletions src/utreexo.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
//!
//! Read more about utreexo: https://eprint.iacr.org/2019/611.pdf

use super::state::TxOut;
use super::state::OutPoint;

/// Accumulator representation of the state aka "Compact State Node".
/// Part of the chain state.
Expand All @@ -49,11 +49,11 @@ pub trait UtreexoAccumulator {
///
/// Note that this call also pushes old UTXOs "to the left", to a larger subtree.
/// This mechanism ensures that short-lived outputs have small inclusion proofs.
fn add(ref self: UtreexoState, output: UtreexoOutput);
fn add(ref self: UtreexoState, output: OutPoint);

/// Verifies inclusion proof for a single output.
fn verify(
self: @UtreexoState, output: @UtreexoOutput, proof: @UtreexoProof
self: @UtreexoState, output: @OutPoint, proof: @UtreexoProof
) -> Result<(), UtreexoError>;

/// Removes single output from the accumlator (order is important).
Expand All @@ -64,7 +64,7 @@ pub trait UtreexoAccumulator {

/// Verifies batch proof for multiple outputs (e.g. all outputs in a block).
fn verify_batch(
self: @UtreexoState, outputs: Span<UtreexoOutput>, proof: @UtreexoBatchProof
self: @UtreexoState, outputs: Span<OutPoint>, proof: @UtreexoBatchProof
) -> Result<(), UtreexoError>;

/// Removes multiple outputs from the accumulator.
Expand All @@ -74,22 +74,6 @@ pub trait UtreexoAccumulator {
#[derive(Drop, Copy, PartialEq)]
pub enum UtreexoError {}

/// 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,
/// The height of the block this output was created at.
pub block_height: u32,
/// Flag indicating if this is a coinbase output.
pub is_coinbase: bool,
/// Transaction output.
pub output: TxOut,
}

/// Utreexo inclusion proof for a single transaction output.
#[derive(Drop, Copy)]
pub struct UtreexoProof {
Expand Down
6 changes: 3 additions & 3 deletions src/validation.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl TransactionValidatorImpl of TransactionValidator {
let outputs = *self.outputs;

for input in inputs {
let amount = *input.previous_output.amount;
let amount = *input.previous_output.data.value;
total_input_amount += amount;
};

Expand Down Expand Up @@ -282,8 +282,8 @@ mod tests {
previous_output: OutPoint {
txid: 0x0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9,
vout: 0x00000000,
txo_index: Option::None,
amount: 100
data: TxOut { value: 100, ..Default::default() },
block_height: Option::None,
},
witness: array![].span(),
}
Expand Down
7 changes: 5 additions & 2 deletions tests/blocks/block_0.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ pub fn block_0() -> Block {
),
sequence: 4294967295,
previous_output: OutPoint {
txid: 0_u256, vout: 0xffffffff_u32, txo_index: Option::None, amount: 0,
txid: 0_u256,
vout: 0xffffffff_u32,
data: Default::default(),
block_height: Default::default(),
},
witness: array![].span(),
witness: array![].span()
}
]
.span(),
Expand Down
13 changes: 8 additions & 5 deletions tests/blocks/block_170.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ pub fn block_170() -> Block {
script: from_base16("04ffff001d0102"),
sequence: 4294967295,
previous_output: OutPoint {
txid: 0_u256, vout: 0xffffffff_u32, txo_index: Option::None, amount: 0,
txid: 0_u256,
vout: 0xffffffff_u32,
data: Default::default(),
block_height: Default::default(),
},
witness: array![].span(),
witness: array![].span()
}
]
.span(),
Expand Down Expand Up @@ -47,10 +50,10 @@ pub fn block_170() -> Block {
previous_output: OutPoint {
txid: 0x0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9,
vout: 0,
txo_index: Option::None,
amount: 0,
data: Default::default(),
block_height: Default::default(),
},
witness: array![].span(),
witness: array![].span()
}
]
.span(),
Expand Down
Loading

0 comments on commit 582acba

Please sign in to comment.