From c3c98bbc483dacfa02869ae669c06aac12d98e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Thu, 1 Aug 2024 14:09:41 +0200 Subject: [PATCH 1/7] wip --- Scarb.toml | 1 - src/lib.cairo | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Scarb.toml b/Scarb.toml index 76c84c49..1bb5fb6c 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -4,4 +4,3 @@ version = "0.1.0" edition = "2023_11" [dependencies] -starknet = "2.6.3" diff --git a/src/lib.cairo b/src/lib.cairo index 829eb99c..3138255b 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,3 +1,3 @@ pub mod engine; - +pub mod state; mod main; From 92a7b626d65a36df4436ef0d8bcda5e6d9ac9cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Thu, 1 Aug 2024 14:13:09 +0200 Subject: [PATCH 2/7] forgotten file --- src/state.cairo | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/state.cairo diff --git a/src/state.cairo b/src/state.cairo new file mode 100644 index 00000000..0768d190 --- /dev/null +++ b/src/state.cairo @@ -0,0 +1,59 @@ + + +// https://developer.bitcoin.org/reference/block_chain.html#block-headers +#[derive(Drop, Clone)] +struct Header { + pub version: u32, + pub prev_block_hash: u256, + pub merkle_root_hash: u256, + pub time: u32, + pub bits: u32, + pub nonce: u32 +} + +// https://developer.bitcoin.org/reference/transactions.html#txin-a-transaction-input-non-coinbase +#[derive(Drop, Clone)] +pub struct TxIn { + txid: u256, + index: u32, + script: ByteArray, + sequence: u32, +} + +// https://developer.bitcoin.org/reference/transactions.html#txout-a-transaction-output +#[derive(Drop, Clone)] +pub struct TxOut { + value: i64, // TODO: why signed? + pk_script: ByteArray +} + +// https://developer.bitcoin.org/reference/transactions.html#raw-transaction-format +#[derive(Drop, Clone)] +pub struct Transaction { + pub version: i32, + pub inputs: Span, + pub outputs: Span, + pub lock_time: u32, +} + +#[derive(Drop, Clone)] +pub struct Block { + pub header: Header, + // TODO: how to handle coinbase transactions? + pub txs: Span +} + +#[derive(Drop, Clone)] +pub struct ChainState { + pub block_height: u32, // not u256? + pub total_work: u256, + pub best_block_hash: u256, + pub current_target: u32, + pub epoch_start_time: u32, + pub prev_timestamps: Span, + // TODO: utreexo_roots? +} + +trait BlockValidator { + fn validate_and_apply(block: Block) -> Result; +} \ No newline at end of file From bf58b291b06219038324437e27b68321439ae1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Thu, 1 Aug 2024 14:14:09 +0200 Subject: [PATCH 3/7] fmt --- src/state.cairo | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/state.cairo b/src/state.cairo index 0768d190..cf7dfb80 100644 --- a/src/state.cairo +++ b/src/state.cairo @@ -1,5 +1,3 @@ - - // https://developer.bitcoin.org/reference/block_chain.html#block-headers #[derive(Drop, Clone)] struct Header { @@ -51,9 +49,9 @@ pub struct ChainState { pub current_target: u32, pub epoch_start_time: u32, pub prev_timestamps: Span, - // TODO: utreexo_roots? +// TODO: utreexo_roots? } trait BlockValidator { fn validate_and_apply(block: Block) -> Result; -} \ No newline at end of file +} From 1d7b6c5fc628bd2ef694cf7b37ccf2a00738a473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Thu, 1 Aug 2024 15:00:34 +0200 Subject: [PATCH 4/7] fix BlockValidator --- src/state.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state.cairo b/src/state.cairo index cf7dfb80..f207f391 100644 --- a/src/state.cairo +++ b/src/state.cairo @@ -53,5 +53,5 @@ pub struct ChainState { } trait BlockValidator { - fn validate_and_apply(block: Block) -> Result; + fn validate_and_apply(self: ChainState, block: Block) -> Result; } From 9e2ad3d927bf4b3f1efbefd4a9b23168a8081c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Fri, 2 Aug 2024 10:38:24 +0200 Subject: [PATCH 5/7] cleanup --- src/engine.cairo | 181 ----------------------------------------------- src/lib.cairo | 4 +- src/main.cairo | 33 --------- src/state.cairo | 105 +++++++++++++++++---------- 4 files changed, 69 insertions(+), 254 deletions(-) delete mode 100644 src/engine.cairo diff --git a/src/engine.cairo b/src/engine.cairo deleted file mode 100644 index 556fc702..00000000 --- a/src/engine.cairo +++ /dev/null @@ -1,181 +0,0 @@ -use core::result::Result; -use core::option::OptionTrait; -use core::traits::Into; -use core::byte_array::ByteArray; - -// Constants -const BLOCK_HEADER_SIZE: u32 = 80; -const MAX_BITS: u32 = 0x1d00FFFF; -const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000; -const EXPECTED_EPOCH_TIMESPAN: u32 = 60 * 60 * 24 * 14; // 2 weeks in seconds -const BLOCKS_PER_EPOCH: u32 = 2016; - -#[derive(Drop, Clone)] -struct BlockHeader { - version: u32, - prev_block_hash: ByteArray, - merkle_root_hash: ByteArray, - time: u32, - bits: u32, - nonce: u32 -} - -#[derive(Drop, Clone)] -pub struct ChainState { - pub block_height: u32, - pub total_work: u256, - pub best_block_hash: ByteArray, - pub current_target: u32, - pub epoch_start_time: u32, - pub prev_timestamps: Array -} - -#[derive(Drop)] -struct BlockHeaderValidationContext { - block_header: BlockHeader, - block_hash: ByteArray, - target: u256, - prev_chain_state: ChainState, - block_height: u32 -} - -#[generate_trait] -pub impl BlockHeaderImpl of BlockHeaderTrait { - fn new( - version: u32, - prev_block_hash: ByteArray, - merkle_root_hash: ByteArray, - time: u32, - bits: u32, - nonce: u32 - ) -> BlockHeader { - BlockHeader { version, prev_block_hash, merkle_root_hash, time, bits, nonce } - } -} - -#[generate_trait] -pub impl ChainStateImpl of ChainStateTrait { - fn new( - block_height: u32, - total_work: u256, - best_block_hash: ByteArray, - current_target: u32, - epoch_start_time: u32, - prev_timestamps: Array - ) -> ChainState { - ChainState { - block_height, - total_work, - best_block_hash, - current_target, - epoch_start_time, - prev_timestamps - } - } -} - -#[generate_trait] -pub impl BlockHeaderValidationContextImpl of BlockHeaderValidationContextTrait { - fn new( - block_header: BlockHeader, - block_hash: ByteArray, - target: u256, - prev_chain_state: ChainState, - block_height: u32 - ) -> BlockHeaderValidationContext { - BlockHeaderValidationContext { - block_header, block_hash, target, prev_chain_state, block_height - } - } -} - -// The main engine for block header validation -#[derive(Drop)] -struct BlockHeaderEngine { - context: BlockHeaderValidationContext -} - -#[generate_trait] -pub impl BlockHeaderEngineImpl of BlockHeaderEngineTrait { - fn new(context: BlockHeaderValidationContext) -> BlockHeaderEngine { - BlockHeaderEngine { context } - } - - fn validate_and_apply_block_header(ref self: BlockHeaderEngine) -> Result { - self.validate_prev_block_hash()?; - self.validate_proof_of_work()?; - self.validate_target()?; - self.validate_timestamp()?; - - let next_state = self.apply_block_header(); - Result::Ok(next_state) - } - - fn validate_prev_block_hash(ref self: BlockHeaderEngine) -> Result<(), felt252> { - if self - .context - .block_header - .prev_block_hash != self - .context - .prev_chain_state - .best_block_hash { - return Result::Err('Invalid prev_block_hash'); - } - Result::Ok(()) - } - - fn validate_proof_of_work(ref self: BlockHeaderEngine) -> Result<(), felt252> { - Result::Ok(()) - } - - fn validate_target(ref self: BlockHeaderEngine) -> Result<(), felt252> { - Result::Ok(()) - } - - fn validate_timestamp(ref self: BlockHeaderEngine) -> Result<(), felt252> { - Result::Ok(()) - } - - fn apply_block_header(ref self: BlockHeaderEngine) -> ChainState { - ChainState { - block_height: 0, - total_work: 0, - best_block_hash: "", - current_target: 0, - epoch_start_time: 0, - prev_timestamps: ArrayTrait::new() - } - } - - fn next_prev_timestamps(ref self: BlockHeaderEngine) -> Array { - let mut timestamps = ArrayTrait::new(); - - timestamps - } - - fn compute_total_work(ref self: BlockHeaderEngine) -> u256 { - let work_in_block = compute_work_from_target(self.context.target); - self.context.prev_chain_state.total_work + work_in_block - } - - fn adjust_difficulty(ref self: BlockHeaderEngine) -> (u32, u32) { - (0, 0) - } -} - -// Helper functions -fn bits_to_target(bits: u32) -> u256 { - 0 -} - -fn target_to_bits(target: u256) -> u32 { - 0 -} - -fn compute_work_from_target(target: u256) -> u256 { - 0 -} - -fn compute_timestamps_median(timestamps: Span) -> u32 { - 0 -} diff --git a/src/lib.cairo b/src/lib.cairo index 3138255b..8abc785f 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,3 +1,3 @@ -pub mod engine; -pub mod state; +mod state; +mod validation; mod main; diff --git a/src/main.cairo b/src/main.cairo index 7ad9b6cb..dc1a66e6 100644 --- a/src/main.cairo +++ b/src/main.cairo @@ -1,36 +1,3 @@ -use raito::engine::BlockHeaderEngineTrait; -use raito::engine::BlockHeaderEngineImpl; -use raito::engine::BlockHeaderValidationContextTrait; -use raito::engine::BlockHeaderValidationContextImpl; -use raito::engine::BlockHeaderTrait; -use raito::engine::BlockHeaderImpl; -use raito::engine::ChainStateTrait; -use raito::engine::ChainStateImpl; -use raito::engine::ChainState; - fn main() { println!("Running Raito Bitcoin ZK client"); - let block_header = BlockHeaderImpl::new(0, "", "", 0, 0, 0); - - // The Times 03/Jan/2009 Chancellor on brink of second bailout for banks - let GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"; - - let chain_state = ChainState { - block_height: 0, - total_work: 0, - best_block_hash: GENESIS, - current_target: 0, - epoch_start_time: 0, - prev_timestamps: ArrayTrait::new() - }; - - let mut context = BlockHeaderValidationContextImpl::new(block_header, "", 0, chain_state, 0); - let mut engine = BlockHeaderEngineImpl::new(context); - - let res = engine.validate_and_apply_block_header(); - if res.is_ok() { - println!("Execution successful"); - } else { - println!("Execution failed"); - } } diff --git a/src/state.cairo b/src/state.cairo index f207f391..b1a75261 100644 --- a/src/state.cairo +++ b/src/state.cairo @@ -1,57 +1,86 @@ -// https://developer.bitcoin.org/reference/block_chain.html#block-headers -#[derive(Drop, Clone)] +/// Represents the state of the blockchain. +#[derive(Drop, Copy)] +pub struct ChainState { + /// Height of the current block. + pub block_height: u32, // not u256? + /// Total work done. + pub total_work: u256, + /// Best block. + pub best_block_hash: u256, + /// Current block. + pub current_target: u32, + /// Start of the current epoch. + pub epoch_start_time: u32, + /// Previous timestamps. + pub prev_timestamps: Span, + // TODO: utreexo_roots? +} + +/// 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 +#[derive(Drop, Copy)] struct Header { + /// The version of the block. pub version: u32, + /// The hash of the previous block in the blockchain. pub prev_block_hash: u256, + /// The Merkle root hash of the transactions in the block. pub merkle_root_hash: u256, + /// The timestamp of the block. pub time: u32, + /// The difficulty target for mining the block. pub bits: u32, - pub nonce: u32 -} - -// https://developer.bitcoin.org/reference/transactions.html#txin-a-transaction-input-non-coinbase -#[derive(Drop, Clone)] -pub struct TxIn { - txid: u256, - index: u32, - script: ByteArray, - sequence: u32, + /// The nonce used in mining the block. + pub nonce: u32, } -// https://developer.bitcoin.org/reference/transactions.html#txout-a-transaction-output -#[derive(Drop, Clone)] -pub struct TxOut { - value: i64, // TODO: why signed? - pk_script: ByteArray -} - -// https://developer.bitcoin.org/reference/transactions.html#raw-transaction-format -#[derive(Drop, Clone)] +/// Transaction +/// https://developer.bitcoin.org/reference/transactions.html#raw-transaction-format +#[derive(Drop, Copy)] pub struct Transaction { + /// The version of the transaction. pub version: i32, + /// The inputs of the transaction. pub inputs: Span, + /// The outputs of the transaction. pub outputs: Span, + /// The lock time of the transaction. pub lock_time: u32, } -#[derive(Drop, Clone)] -pub struct Block { - pub header: Header, - // TODO: how to handle coinbase transactions? - pub txs: Span +/// Output of a transaction. +/// https://developer.bitcoin.org/reference/transactions.html#txout-a-transaction-output +#[derive(Drop, Copy)] +pub struct TxOut { + /// The value of the output. + value: i64, + /// The public key script of the output. + pk_script: @ByteArray, } -#[derive(Drop, Clone)] -pub struct ChainState { - pub block_height: u32, // not u256? - pub total_work: u256, - pub best_block_hash: u256, - pub current_target: u32, - pub epoch_start_time: u32, - pub prev_timestamps: Span, -// TODO: utreexo_roots? +/// Input of a transaction. +/// https://developer.bitcoin.org/reference/transactions.html#txin-a-transaction-input-non-coinbase +#[derive(Drop, Copy)] +pub struct TxIn { + /// The transaction ID of the input. + txid: u256, + /// The index of the input. + index: u32, + /// The script of the input. + script: @ByteArray, + /// The sequence of the input. + sequence: u32, } -trait BlockValidator { - fn validate_and_apply(self: ChainState, block: Block) -> Result; -} From 7a3fc5c4cb3ccac38e5bd431d24fbdeb8d3a311e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Fri, 2 Aug 2024 10:41:25 +0200 Subject: [PATCH 6/7] add missing file --- src/validation.cairo | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/validation.cairo diff --git a/src/validation.cairo b/src/validation.cairo new file mode 100644 index 00000000..f0e13c76 --- /dev/null +++ b/src/validation.cairo @@ -0,0 +1,60 @@ +use super::state::{Block, ChainState}; + +#[generate_trait] +impl BlockValidatorImpl of BlockValidator { + fn validate_and_apply(self: ChainState, block: Block) -> Result { + validate_prev_block_hash(@self, @block)?; + validate_proof_of_work(@self, @block)?; + validate_target(@self, @block)?; + validate_timestamp(@self, @block)?; + + // validate_merkle_root + // validate_and_apply_transactions + + let prev_timestamps = next_prev_timestamps(@self, @block); + let total_work = compute_total_work(@self, @block); + let (current_target, epoch_start_time) = adjust_difficulty(@self, @block); + + Result::Ok( + ChainState { total_work, current_target, epoch_start_time, prev_timestamps, ..self, } + ) + } +} + +fn validate_prev_block_hash(self: @ChainState, block: @Block) -> Result<(), ByteArray> { + if self.best_block_hash == block.header.prev_block_hash { + Result::Ok(()) + } else { + Result::Err("Invalid `prev_block_hash`. This block does not extend the current chain.") + } +} + +fn validate_proof_of_work(self: @ChainState, block: @Block) -> Result<(), ByteArray> { + // TODO: implement + Result::Ok(()) +} + +fn validate_target(self: @ChainState, block: @Block) -> Result<(), ByteArray> { + // TODO: implement + Result::Ok(()) +} + +fn validate_timestamp(self: @ChainState, block: @Block) -> Result<(), ByteArray> { + // TODO: implement + Result::Ok(()) +} + +fn next_prev_timestamps(self: @ChainState, block: @Block) -> Span { + // TODO: implement + *self.prev_timestamps +} + +fn compute_total_work(self: @ChainState, block: @Block) -> u256 { + // TODO: implement + *self.total_work +} + +fn adjust_difficulty(self: @ChainState, block: @Block) -> (u32, u32) { + // TODO: implement + (*self.current_target, *self.epoch_start_time) +} From 7ba48cc3ccdf906328f17bab508bfaa54ba4df62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Fri, 2 Aug 2024 10:45:13 +0200 Subject: [PATCH 7/7] bump scarb version --- .tool-versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.tool-versions b/.tool-versions index f239fe23..045dc3e7 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.6.3 +scarb 2.7.0