Monday, December 23, 2024

Incorrect Transaction ID being calculated for a p2wpkh transaction

RAW Signed transaction (signet)

020000000001013ccb46c8366e39d7ff36df4f199813aa8b9dc4bed143a0eb9205cf698ca16298e400000000ffffffff0240420f00000000002200202d67ce38ba266a68f0f7c4668e9d0f5584c6da7c454bcc2368bf9fff10135157a086010000000000160014d765749aa66430b85765bdedee488f5fe3c82a8e02483045022100f71bd596f18d3caf1297a74f5619cd6c823d58acaf5f9172bea7d7d6ef82cfd502206c7c7960accd4409cccb1ca97d8268af12664de50b905d1c3579e6237c0fb823012102d3428014dd5ccf1927c6dc164e6324e2c0945a9f50b84769592e195ae6a40e8a00000000

Transaction id returned .

    "txid": "1d81e1dae9d956fd61cf79efa6a64de11465d6a1ead46e24ba043e278360fb35",
    "wtxid": "d9e69e8d05c61c78796b2d73b731a705334e07c013e7e714e10eaf45885a144c"

Transaction id calculated by following Raw_tx.

22d008e988b168165bd6c06dc4200ad57d456f1b152d25e540e75e38bb023c40

Transaction id calculated by hashing the Uncooked signed transaction

82fbc313fec14a7cf05309544b24bc97dc785bb82e4a9a713bb6e8d5f3cf4aeb

I’ve adopted the above transaction codecs. The signed uncooked transaction follows the specification given in bicoin builders uncooked transaction format.

Given are the implementation codes in Rust

fn get_txid(inputs: Vec<Vec<u8>>, outputs: Vec<Vec<u8>>) -> [u8; 32] {
    let mut tx = Vec::new();

    //including model
    let model: u32 = 0x00000002;
    tx.extend_from_slice(&model.to_le_bytes());

    let inputs_length: u32 = inputs.len() as u32;
    tx.extend_from_slice(&inputs_length.to_le_bytes());

    for enter in inputs {
        tx.extend_from_slice(&enter);
    }

    let outputs_length: u32 = outputs.len() as u32;
    tx.extend_from_slice(&outputs_length.to_le_bytes());

    for output in outputs {
        tx.extend_from_slice(&output);
    }

    let locktime: u32 = 0x00000000;
    tx.extend_from_slice(&locktime.to_le_bytes());
    let txid = sha256_hash(&sha256_hash(&tx));
    //output

    let tx_array: [u8; 32] = match txid.try_into() {
        Okay(arr) => arr,
        Err(_) => panic!("Anticipated a Vec of size 32, nevertheless it was {}", tx.len()),
    };

    // reverse txid
    let mut reversed_txid = [0; 32];
    for i in 0..32 {
        reversed_txid[i] = tx_array[31 - i];
    }

    reversed_txid
}

Output serialization

fn output_from_options(script: &[u8], worth: u32) -> Vec<u8> {
    
    let mut output = Vec::new();
    let valhue: u64 = worth as u64;
    let value_in_8_bytes_in_little_endian = valhue.to_le_bytes();
    output.extend_from_slice(&value_in_8_bytes_in_little_endian);

    let script_length = script.len() as u64; 
    let script_length_varint = turn_to_varint(script_length);
    
    output.extend_from_slice(&script_length_varint);
    output.extend_from_slice(script); //scriptpubkey {p2wpkh and p2wsh}
    output

    //OK
}

Enter Serialization

fn input_from_utxo(txid: &[u8], index: u32) -> Vec<u8> {
    let mut enter = Vec::new();

    //txid
    let reversed_txid: Vec<u8> = txid.iter().rev().cloned().accumulate();
    enter.extend_from_slice(&reversed_txid);

    //index
    let index_in_little_endian_bytes = index.to_le_bytes();  // mounted 4 bytes
    enter.extend_from_slice(&index_in_little_endian_bytes);
    
    //script size (default is zero for us)
    enter.push(0x00);

    //sequence
    let sequence: u32 = 0xffffffff;
    enter.extend_from_slice(&sequence.to_le_bytes());

    enter

    //OK
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles