This page hosts a formal specification of Bitcoin Transaction using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#![allow(unused_imports)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(irrefutable_let_patterns)]
#![allow(unused_comparisons)]
extern crate kaitai;
use kaitai::*;
use std::convert::{TryFrom, TryInto};
use std::cell::{Ref, Cell, RefCell};
use std::rc::{Rc, Weak};
/**
* \sa https://bitcoin.org/en/developer-guide#transactions
* https://en.bitcoin.it/wiki/Transaction
* Source
*/
#[derive(Default, Debug, Clone)]
pub struct BitcoinTransaction {
pub _root: SharedType<BitcoinTransaction>,
pub _parent: SharedType<BitcoinTransaction>,
pub _self: SharedType<Self>,
version: RefCell<u32>,
num_vins: RefCell<u8>,
vins: RefCell<Vec<OptRc<BitcoinTransaction_Vin>>>,
num_vouts: RefCell<u8>,
vouts: RefCell<Vec<OptRc<BitcoinTransaction_Vout>>>,
locktime: RefCell<u32>,
_io: RefCell<BytesReader>,
}
impl KStruct for BitcoinTransaction {
type Root = BitcoinTransaction;
type Parent = BitcoinTransaction;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.version.borrow_mut() = _io.read_u4le()?.into();
*self_rc.num_vins.borrow_mut() = _io.read_u1()?.into();
*self_rc.vins.borrow_mut() = Vec::new();
let l_vins = *self_rc.num_vins();
for _i in 0..l_vins {
let t = Self::read_into::<_, BitcoinTransaction_Vin>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
self_rc.vins.borrow_mut().push(t);
}
*self_rc.num_vouts.borrow_mut() = _io.read_u1()?.into();
*self_rc.vouts.borrow_mut() = Vec::new();
let l_vouts = *self_rc.num_vouts();
for _i in 0..l_vouts {
let t = Self::read_into::<_, BitcoinTransaction_Vout>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
self_rc.vouts.borrow_mut().push(t);
}
*self_rc.locktime.borrow_mut() = _io.read_u4le()?.into();
Ok(())
}
}
impl BitcoinTransaction {
}
/**
* Version number.
*/
impl BitcoinTransaction {
pub fn version(&self) -> Ref<'_, u32> {
self.version.borrow()
}
}
/**
* Number of input transactions.
*/
impl BitcoinTransaction {
pub fn num_vins(&self) -> Ref<'_, u8> {
self.num_vins.borrow()
}
}
/**
* Input transactions.
* An input refers to an output from a previous transaction.
*/
impl BitcoinTransaction {
pub fn vins(&self) -> Ref<'_, Vec<OptRc<BitcoinTransaction_Vin>>> {
self.vins.borrow()
}
}
/**
* Number of output transactions.
*/
impl BitcoinTransaction {
pub fn num_vouts(&self) -> Ref<'_, u8> {
self.num_vouts.borrow()
}
}
/**
* Output transactions.
*/
impl BitcoinTransaction {
pub fn vouts(&self) -> Ref<'_, Vec<OptRc<BitcoinTransaction_Vout>>> {
self.vouts.borrow()
}
}
impl BitcoinTransaction {
pub fn locktime(&self) -> Ref<'_, u32> {
self.locktime.borrow()
}
}
impl BitcoinTransaction {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}
#[derive(Default, Debug, Clone)]
pub struct BitcoinTransaction_Vin {
pub _root: SharedType<BitcoinTransaction>,
pub _parent: SharedType<BitcoinTransaction>,
pub _self: SharedType<Self>,
txid: RefCell<Vec<u8>>,
output_id: RefCell<u32>,
len_script: RefCell<u8>,
script_sig: RefCell<OptRc<BitcoinTransaction_Vin_ScriptSignature>>,
end_of_vin: RefCell<Vec<u8>>,
_io: RefCell<BytesReader>,
script_sig_raw: RefCell<Vec<u8>>,
}
impl KStruct for BitcoinTransaction_Vin {
type Root = BitcoinTransaction;
type Parent = BitcoinTransaction;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.txid.borrow_mut() = _io.read_bytes(32 as usize)?.into();
*self_rc.output_id.borrow_mut() = _io.read_u4le()?.into();
*self_rc.len_script.borrow_mut() = _io.read_u1()?.into();
*self_rc.script_sig_raw.borrow_mut() = _io.read_bytes(*self_rc.len_script() as usize)?.into();
let script_sig_raw = self_rc.script_sig_raw.borrow();
let _t_script_sig_raw_io = BytesReader::from(script_sig_raw.clone());
let t = Self::read_into::<BytesReader, BitcoinTransaction_Vin_ScriptSignature>(&_t_script_sig_raw_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
*self_rc.script_sig.borrow_mut() = t;
*self_rc.end_of_vin.borrow_mut() = _io.read_bytes(4 as usize)?.into();
if !(*self_rc.end_of_vin() == vec![0xffu8, 0xffu8, 0xffu8, 0xffu8]) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::NotEqual, src_path: "/types/vin/seq/4".to_string() }));
}
Ok(())
}
}
impl BitcoinTransaction_Vin {
}
/**
* Previous transaction hash.
*/
impl BitcoinTransaction_Vin {
pub fn txid(&self) -> Ref<'_, Vec<u8>> {
self.txid.borrow()
}
}
/**
* ID indexing an ouput of the transaction refered by txid.
* This output will be used as an input in the present transaction.
*/
impl BitcoinTransaction_Vin {
pub fn output_id(&self) -> Ref<'_, u32> {
self.output_id.borrow()
}
}
/**
* ScriptSig's length.
*/
impl BitcoinTransaction_Vin {
pub fn len_script(&self) -> Ref<'_, u8> {
self.len_script.borrow()
}
}
/**
* ScriptSig.
* \sa https://en.bitcoin.it/wiki/Transaction#Input
* https://en.bitcoin.it/wiki/Script
* Source
*/
impl BitcoinTransaction_Vin {
pub fn script_sig(&self) -> Ref<'_, OptRc<BitcoinTransaction_Vin_ScriptSignature>> {
self.script_sig.borrow()
}
}
/**
* Magic number indicating the end of the current input.
*/
impl BitcoinTransaction_Vin {
pub fn end_of_vin(&self) -> Ref<'_, Vec<u8>> {
self.end_of_vin.borrow()
}
}
impl BitcoinTransaction_Vin {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}
impl BitcoinTransaction_Vin {
pub fn script_sig_raw(&self) -> Ref<'_, Vec<u8>> {
self.script_sig_raw.borrow()
}
}
#[derive(Default, Debug, Clone)]
pub struct BitcoinTransaction_Vin_ScriptSignature {
pub _root: SharedType<BitcoinTransaction>,
pub _parent: SharedType<BitcoinTransaction_Vin>,
pub _self: SharedType<Self>,
len_sig_stack: RefCell<u8>,
der_sig: RefCell<OptRc<BitcoinTransaction_Vin_ScriptSignature_DerSignature>>,
sig_type: RefCell<BitcoinTransaction_Vin_ScriptSignature_SighashType>,
len_pubkey_stack: RefCell<u8>,
pubkey: RefCell<OptRc<BitcoinTransaction_Vin_ScriptSignature_PublicKey>>,
_io: RefCell<BytesReader>,
}
impl KStruct for BitcoinTransaction_Vin_ScriptSignature {
type Root = BitcoinTransaction;
type Parent = BitcoinTransaction_Vin;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.len_sig_stack.borrow_mut() = _io.read_u1()?.into();
let t = Self::read_into::<_, BitcoinTransaction_Vin_ScriptSignature_DerSignature>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
*self_rc.der_sig.borrow_mut() = t;
*self_rc.sig_type.borrow_mut() = (_io.read_u1()? as i64).try_into()?;
*self_rc.len_pubkey_stack.borrow_mut() = _io.read_u1()?.into();
let t = Self::read_into::<_, BitcoinTransaction_Vin_ScriptSignature_PublicKey>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
*self_rc.pubkey.borrow_mut() = t;
Ok(())
}
}
impl BitcoinTransaction_Vin_ScriptSignature {
}
impl BitcoinTransaction_Vin_ScriptSignature {
pub fn len_sig_stack(&self) -> Ref<'_, u8> {
self.len_sig_stack.borrow()
}
}
/**
* DER-encoded ECDSA signature.
* \sa https://en.wikipedia.org/wiki/X.690#DER_encoding
* https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm
* Source
*/
impl BitcoinTransaction_Vin_ScriptSignature {
pub fn der_sig(&self) -> Ref<'_, OptRc<BitcoinTransaction_Vin_ScriptSignature_DerSignature>> {
self.der_sig.borrow()
}
}
/**
* Type of signature.
*/
impl BitcoinTransaction_Vin_ScriptSignature {
pub fn sig_type(&self) -> Ref<'_, BitcoinTransaction_Vin_ScriptSignature_SighashType> {
self.sig_type.borrow()
}
}
impl BitcoinTransaction_Vin_ScriptSignature {
pub fn len_pubkey_stack(&self) -> Ref<'_, u8> {
self.len_pubkey_stack.borrow()
}
}
/**
* Public key (bitcoin address of the recipient).
*/
impl BitcoinTransaction_Vin_ScriptSignature {
pub fn pubkey(&self) -> Ref<'_, OptRc<BitcoinTransaction_Vin_ScriptSignature_PublicKey>> {
self.pubkey.borrow()
}
}
impl BitcoinTransaction_Vin_ScriptSignature {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum BitcoinTransaction_Vin_ScriptSignature_SighashType {
SighashAll,
SighashNone,
SighashSingle,
SighashAnyonecanpay,
Unknown(i64),
}
impl TryFrom<i64> for BitcoinTransaction_Vin_ScriptSignature_SighashType {
type Error = KError;
fn try_from(flag: i64) -> KResult<BitcoinTransaction_Vin_ScriptSignature_SighashType> {
match flag {
1 => Ok(BitcoinTransaction_Vin_ScriptSignature_SighashType::SighashAll),
2 => Ok(BitcoinTransaction_Vin_ScriptSignature_SighashType::SighashNone),
3 => Ok(BitcoinTransaction_Vin_ScriptSignature_SighashType::SighashSingle),
80 => Ok(BitcoinTransaction_Vin_ScriptSignature_SighashType::SighashAnyonecanpay),
_ => Ok(BitcoinTransaction_Vin_ScriptSignature_SighashType::Unknown(flag)),
}
}
}
impl From<&BitcoinTransaction_Vin_ScriptSignature_SighashType> for i64 {
fn from(v: &BitcoinTransaction_Vin_ScriptSignature_SighashType) -> Self {
match *v {
BitcoinTransaction_Vin_ScriptSignature_SighashType::SighashAll => 1,
BitcoinTransaction_Vin_ScriptSignature_SighashType::SighashNone => 2,
BitcoinTransaction_Vin_ScriptSignature_SighashType::SighashSingle => 3,
BitcoinTransaction_Vin_ScriptSignature_SighashType::SighashAnyonecanpay => 80,
BitcoinTransaction_Vin_ScriptSignature_SighashType::Unknown(v) => v
}
}
}
impl Default for BitcoinTransaction_Vin_ScriptSignature_SighashType {
fn default() -> Self { BitcoinTransaction_Vin_ScriptSignature_SighashType::Unknown(0) }
}
#[derive(Default, Debug, Clone)]
pub struct BitcoinTransaction_Vin_ScriptSignature_DerSignature {
pub _root: SharedType<BitcoinTransaction>,
pub _parent: SharedType<BitcoinTransaction_Vin_ScriptSignature>,
pub _self: SharedType<Self>,
sequence: RefCell<Vec<u8>>,
len_sig: RefCell<u8>,
sep_1: RefCell<Vec<u8>>,
len_sig_r: RefCell<u8>,
sig_r: RefCell<Vec<u8>>,
sep_2: RefCell<Vec<u8>>,
len_sig_s: RefCell<u8>,
sig_s: RefCell<Vec<u8>>,
_io: RefCell<BytesReader>,
}
impl KStruct for BitcoinTransaction_Vin_ScriptSignature_DerSignature {
type Root = BitcoinTransaction;
type Parent = BitcoinTransaction_Vin_ScriptSignature;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.sequence.borrow_mut() = _io.read_bytes(1 as usize)?.into();
if !(*self_rc.sequence() == vec![0x30u8]) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::NotEqual, src_path: "/types/vin/types/script_signature/types/der_signature/seq/0".to_string() }));
}
*self_rc.len_sig.borrow_mut() = _io.read_u1()?.into();
*self_rc.sep_1.borrow_mut() = _io.read_bytes(1 as usize)?.into();
if !(*self_rc.sep_1() == vec![0x2u8]) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::NotEqual, src_path: "/types/vin/types/script_signature/types/der_signature/seq/2".to_string() }));
}
*self_rc.len_sig_r.borrow_mut() = _io.read_u1()?.into();
*self_rc.sig_r.borrow_mut() = _io.read_bytes(*self_rc.len_sig_r() as usize)?.into();
*self_rc.sep_2.borrow_mut() = _io.read_bytes(1 as usize)?.into();
if !(*self_rc.sep_2() == vec![0x2u8]) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::NotEqual, src_path: "/types/vin/types/script_signature/types/der_signature/seq/5".to_string() }));
}
*self_rc.len_sig_s.borrow_mut() = _io.read_u1()?.into();
*self_rc.sig_s.borrow_mut() = _io.read_bytes(*self_rc.len_sig_s() as usize)?.into();
Ok(())
}
}
impl BitcoinTransaction_Vin_ScriptSignature_DerSignature {
}
impl BitcoinTransaction_Vin_ScriptSignature_DerSignature {
pub fn sequence(&self) -> Ref<'_, Vec<u8>> {
self.sequence.borrow()
}
}
impl BitcoinTransaction_Vin_ScriptSignature_DerSignature {
pub fn len_sig(&self) -> Ref<'_, u8> {
self.len_sig.borrow()
}
}
impl BitcoinTransaction_Vin_ScriptSignature_DerSignature {
pub fn sep_1(&self) -> Ref<'_, Vec<u8>> {
self.sep_1.borrow()
}
}
/**
* 'r' value's length.
*/
impl BitcoinTransaction_Vin_ScriptSignature_DerSignature {
pub fn len_sig_r(&self) -> Ref<'_, u8> {
self.len_sig_r.borrow()
}
}
/**
* 'r' value of the ECDSA signature.
* \sa https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm Source
*/
impl BitcoinTransaction_Vin_ScriptSignature_DerSignature {
pub fn sig_r(&self) -> Ref<'_, Vec<u8>> {
self.sig_r.borrow()
}
}
impl BitcoinTransaction_Vin_ScriptSignature_DerSignature {
pub fn sep_2(&self) -> Ref<'_, Vec<u8>> {
self.sep_2.borrow()
}
}
/**
* 's' value's length.
*/
impl BitcoinTransaction_Vin_ScriptSignature_DerSignature {
pub fn len_sig_s(&self) -> Ref<'_, u8> {
self.len_sig_s.borrow()
}
}
/**
* 's' value of the ECDSA signature.
* \sa https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm Source
*/
impl BitcoinTransaction_Vin_ScriptSignature_DerSignature {
pub fn sig_s(&self) -> Ref<'_, Vec<u8>> {
self.sig_s.borrow()
}
}
impl BitcoinTransaction_Vin_ScriptSignature_DerSignature {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}
#[derive(Default, Debug, Clone)]
pub struct BitcoinTransaction_Vin_ScriptSignature_PublicKey {
pub _root: SharedType<BitcoinTransaction>,
pub _parent: SharedType<BitcoinTransaction_Vin_ScriptSignature>,
pub _self: SharedType<Self>,
type: RefCell<u8>,
x: RefCell<Vec<u8>>,
y: RefCell<Vec<u8>>,
_io: RefCell<BytesReader>,
}
impl KStruct for BitcoinTransaction_Vin_ScriptSignature_PublicKey {
type Root = BitcoinTransaction;
type Parent = BitcoinTransaction_Vin_ScriptSignature;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.type.borrow_mut() = _io.read_u1()?.into();
*self_rc.x.borrow_mut() = _io.read_bytes(32 as usize)?.into();
*self_rc.y.borrow_mut() = _io.read_bytes(32 as usize)?.into();
Ok(())
}
}
impl BitcoinTransaction_Vin_ScriptSignature_PublicKey {
}
impl BitcoinTransaction_Vin_ScriptSignature_PublicKey {
pub fn type(&self) -> Ref<'_, u8> {
self.type.borrow()
}
}
/**
* 'x' coordinate of the public key on the elliptic curve.
*/
impl BitcoinTransaction_Vin_ScriptSignature_PublicKey {
pub fn x(&self) -> Ref<'_, Vec<u8>> {
self.x.borrow()
}
}
/**
* 'y' coordinate of the public key on the elliptic curve.
*/
impl BitcoinTransaction_Vin_ScriptSignature_PublicKey {
pub fn y(&self) -> Ref<'_, Vec<u8>> {
self.y.borrow()
}
}
impl BitcoinTransaction_Vin_ScriptSignature_PublicKey {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}
#[derive(Default, Debug, Clone)]
pub struct BitcoinTransaction_Vout {
pub _root: SharedType<BitcoinTransaction>,
pub _parent: SharedType<BitcoinTransaction>,
pub _self: SharedType<Self>,
amount: RefCell<u64>,
len_script: RefCell<u8>,
script_pub_key: RefCell<Vec<u8>>,
_io: RefCell<BytesReader>,
}
impl KStruct for BitcoinTransaction_Vout {
type Root = BitcoinTransaction;
type Parent = BitcoinTransaction;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.amount.borrow_mut() = _io.read_u8le()?.into();
*self_rc.len_script.borrow_mut() = _io.read_u1()?.into();
*self_rc.script_pub_key.borrow_mut() = _io.read_bytes(*self_rc.len_script() as usize)?.into();
Ok(())
}
}
impl BitcoinTransaction_Vout {
}
/**
* Number of Satoshis to be transfered.
*/
impl BitcoinTransaction_Vout {
pub fn amount(&self) -> Ref<'_, u64> {
self.amount.borrow()
}
}
/**
* ScriptPubKey's length.
*/
impl BitcoinTransaction_Vout {
pub fn len_script(&self) -> Ref<'_, u8> {
self.len_script.borrow()
}
}
/**
* ScriptPubKey.
* \sa https://en.bitcoin.it/wiki/Transaction#Output
* https://en.bitcoin.it/wiki/Script
* Source
*/
impl BitcoinTransaction_Vout {
pub fn script_pub_key(&self) -> Ref<'_, Vec<u8>> {
self.script_pub_key.borrow()
}
}
impl BitcoinTransaction_Vout {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}