Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Implement txid function #44

Merged
merged 28 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/state.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ pub struct OutPoint {
pub vout: u32,
/// The index of output in the utreexo set (meta field).
pub txo_index: u64,
// Amount calculated with the txid and vout
/// Amount calculated with the txid and vout.
pub amount: u64
}

Expand Down
113 changes: 106 additions & 7 deletions src/validation.cairo
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use core::traits::Into;
use core::traits::TryInto;

use super::codec::Encode;
lana-shanghai marked this conversation as resolved.
Show resolved Hide resolved
use super::merkle_tree::merkle_root;
use super::utils::{shl, shr, Hash};
use super::utils::{double_sha256_byte_array, shl, shr, Hash};
use super::state::{Block, ChainState, Transaction, UtreexoState, UtreexoSet, TxIn, TxOut, OutPoint};

const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000;
Expand Down Expand Up @@ -41,11 +39,65 @@ impl BlockValidatorImpl of BlockValidator {
}

#[generate_trait]
impl TransactionValidatorImpl of TransactionValidator {
pub impl TransactionValidatorImpl of TransactionValidator {
// marker, flag, and witness fields in segwit transactions are not included
// this means txid computation is the same for legacy and segwit tx
fn txid(self: @Transaction) -> Hash {
// TODO: implement
Default::default()
// append version (4 bytes)
let mut hash256_input: ByteArray = "";
hash256_input.append_word_rev((*self.version).into(), 4);

// append inputs count (1 byte in our example) - TODO : use Encode<Span<TxIn>> once
// implemented
hash256_input.append_word_rev((*self.inputs).len().into(), 1);

// append inputs - TODO : this is also included in Encode<Span<TxIn>>
let mut inputs: Span<TxIn> = *self.inputs;
while let Option::Some(txin) = inputs.pop_front() {
// append txid (32 bytes)
let txid: u256 = (*(txin.previous_output.txid)).into();
hash256_input.append_word_rev(txid.low.into(), 16);
hash256_input.append_word_rev(txid.high.into(), 16);

// append VOUT (4 bytes)
hash256_input.append_word_rev((*txin.previous_output.vout).into(), 4);

// append ScriptSig size (1 byte in our example)
hash256_input.append_word_rev((*txin.script).len().into(), 1);

// append ScriptSig (variable size)
let rev_script = (*txin.script).rev();
hash256_input.append(@rev_script);

// append Sequence (4 bytes)
hash256_input.append_word_rev((*txin.sequence).into(), 4);
};

// append outputs count (1 byte in our example) - TODO : use Encode<Span<TxOut>> once
// implemented
hash256_input.append_word_rev((*self.outputs).len().into(), 1);

// append outputs - TODO this is also included in Encode<Span<TxOut>>
let mut outputs: Span<TxOut> = *self.outputs;
while let Option::Some(txout) = outputs.pop_front() {
// append amount (8 bytes)
hash256_input.append_word_rev((*txout.value).into(), 8);

// append ScriptPubKey size (1 byte in our exmaple)
hash256_input.append_word_rev((*txout.pk_script).len().into(), 1);

// append ScriptPubKey (variable size)
let rev_pk_script = (*txout.pk_script).rev();
hash256_input.append(@rev_pk_script);
};

// append locktime (4 bytes)
hash256_input.append_word_rev((*self.lock_time).into(), 4);

// Compute double sha256 and return the Hash result
double_sha256_byte_array(@hash256_input)
}

fn fee(self: @Transaction) -> u64 {
let mut total_input_amount = 0;
let mut total_output_amount = 0;
Expand Down Expand Up @@ -268,6 +320,7 @@ fn compute_block_reward(block_height: u32) -> u64 {
#[cfg(test)]
mod tests {
use raito::state::{Header, Transaction, TxIn, TxOut, OutPoint};
use raito::utils::Hash;
use raito::test_utils::from_hex;
use super::{
validate_timestamp, validate_proof_of_work, compute_block_reward, compute_total_work,
Expand Down Expand Up @@ -667,4 +720,50 @@ mod tests {

validate_coinbase(@block, total_fees, block_height).unwrap();
}

#[test]
fn test_txid() {
let tx: Transaction = Transaction {
version: 1,
is_segwit: false,
inputs: array![
TxIn {
script: @from_hex(
"01091d8d76a82122082246acbb6cc51c839d9012ddaca46048de07ca8eec221518200241cdb85fab4815c6c624d6e932774f3fdf5fa2a1d3a1614951afb83269e1454e2002443047"
),
sequence: 0xffffffff,
previous_output: OutPoint {
txid: 0x0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9_u256
.into(),
vout: 0x00000000,
txo_index: 0,
amount: 0_64 // set to 0 for the test
},
witness: @from_hex("")
}
]
.span(),
outputs: array![
TxOut {
value: 0x000000003b9aca00,
pk_script: @from_hex(
"ac4cd86c7e4f702ac7d5debaf126068a3b30b7c1212c145fdfa754f59773b3aae71484a22f30718d37cd74f325229b15f7a2996bf0075f90131bf5c509fe621aae0441"
),
},
TxOut {
value: 0x00000000ee6b2800,
pk_script: @from_hex(
"aca312b456f643869b993fc0d4f9648b9bfa0b162ef8644474f9cc84fbddeae0b25c9a90a648b1d7ca2e48b1972e388ab61ebc538c0f84496b018adbdce193db110441"
),
}
]
.span(),
lock_time: 0
};

let txid: Hash = TransactionValidatorImpl::txid(@tx);
assert_eq!(
txid, 0x169e1e83e930853391bc6f35f605c6754cfead57cf8387639d3b4096c54f18f4_u256.into()
);
}
}