Bitcoin

An incorrect transaction ID is being calculated for the p2wpkh transaction.

RAW signed transaction (seal)

020000000001013ccb46c8366e39d7ff36df4f199813aa8b9dc4bed143a0eb9205cf698ca16298e400000000ffffffff0240420f00000000002200202d67ce38ba266a68f0f7c4668e9d0f5584c6da7c454bcc2368bf9fff10135157a086010000000000160014d765749aa66430b85765bdedee488f5fe3c82a8e02483045022100f71bd596f18d3caf1297a74f5619cd6c823d58acaf5f9172bea7d7d6ef82cfd502206c7c7960accd4409cccb1ca97d8268af12664de50b905d1c3579e6237c0fb823012102d3428014dd5ccf1927c6dc164e6324e2c0945a9f50b84769592e195ae6a40e8a00000000

Transaction ID returned.

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

Transaction ID calculated based on Raw_tx.

22d008e988b168165bd6c06dc4200ad57d456f1b152d25e540e75e38bb023c40

Transaction ID calculated by hashing the raw signed transaction

82fbc313fec14a7cf05309544b24bc97dc785bb82e4a9a713bb6e8d5f3cf4aeb

I followed the transaction format above. Signed raw transactions follow the specifications provided in the bicoin developer raw transaction format.

Here’s the implementation code in Rust:

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

    //adding version
    let version: u32 = 0x00000002;
    tx.extend_from_slice(&version.to_le_bytes());

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

    for input in inputs 
        tx.extend_from_slice(&input);
    

    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() 
        Ok(arr) => arr,
        Err(_) => panic!("Expected a Vec of length 32, but 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), value: u32) -> Vec<u8> 
    
    let mut output = Vec::new();
    let valhue: u64 = value 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

Input serialization

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

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

    //index
    let index_in_little_endian_bytes = index.to_le_bytes();  // fixed 4 bytes
    input.extend_from_slice(&index_in_little_endian_bytes);
    
    //script length (default is zero for us)
    input.push(0x00);

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

    input

    //OK

Related Articles

Back to top button