2016-08-15 06:19:28 -07:00
|
|
|
//! Bitcoin trainsaction.
|
|
|
|
//! https://en.bitcoin.it/wiki/Protocol_documentation#tx
|
|
|
|
|
2016-10-30 16:28:50 -07:00
|
|
|
use std::io;
|
2016-10-19 03:07:11 -07:00
|
|
|
use heapsize::HeapSizeOf;
|
2016-09-12 13:20:01 -07:00
|
|
|
use hex::FromHex;
|
2016-09-19 05:56:45 -07:00
|
|
|
use bytes::Bytes;
|
2016-09-18 09:12:45 -07:00
|
|
|
use ser::{
|
|
|
|
Deserializable, Reader, Error as ReaderError, deserialize,
|
2016-10-17 02:17:00 -07:00
|
|
|
Serializable, Stream, serialize, serialized_list_size
|
2016-09-18 09:12:45 -07:00
|
|
|
};
|
2016-09-09 01:49:08 -07:00
|
|
|
use crypto::dhash256;
|
2016-08-16 03:09:40 -07:00
|
|
|
use hash::H256;
|
2016-08-15 06:19:28 -07:00
|
|
|
|
2016-09-08 06:05:57 -07:00
|
|
|
// Below flags apply in the context of BIP 68
|
|
|
|
// If this flag set, CTxIn::nSequence is NOT interpreted as a
|
|
|
|
// relative lock-time.
|
|
|
|
pub const SEQUENCE_LOCKTIME_DISABLE_FLAG: u32 = 1u32 << 31;
|
|
|
|
|
2016-09-15 02:45:31 -07:00
|
|
|
// Setting nSequence to this value for every input in a transaction
|
|
|
|
// disables nLockTime.
|
|
|
|
pub const SEQUENCE_FINAL: u32 = 0xffffffff;
|
|
|
|
|
|
|
|
// If CTxIn::nSequence encodes a relative lock-time and this flag
|
|
|
|
// is set, the relative lock-time has units of 512 seconds,
|
|
|
|
// otherwise it specifies blocks with a granularity of 1.
|
|
|
|
pub const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = (1 << 22);
|
|
|
|
|
|
|
|
// If CTxIn::nSequence encodes a relative lock-time, this mask is
|
|
|
|
// applied to extract that lock-time from the sequence field.
|
|
|
|
pub const SEQUENCE_LOCKTIME_MASK: u32 = 0x0000ffff;
|
|
|
|
|
2016-11-27 06:05:49 -08:00
|
|
|
/// Threshold for `nLockTime`: below this value it is interpreted as block number,
|
|
|
|
/// otherwise as UNIX timestamp.
|
|
|
|
pub const LOCKTIME_THRESHOLD: u32 = 500000000; // Tue Nov 5 00:53:20 1985 UTC
|
2016-09-15 02:45:31 -07:00
|
|
|
|
2016-12-02 03:45:14 -08:00
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, Default)]
|
2016-08-15 06:19:28 -07:00
|
|
|
pub struct OutPoint {
|
2016-09-12 14:11:36 -07:00
|
|
|
pub hash: H256,
|
|
|
|
pub index: u32,
|
2016-08-15 06:19:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for OutPoint {
|
|
|
|
fn serialize(&self, stream: &mut Stream) {
|
|
|
|
stream
|
2016-09-19 02:58:53 -07:00
|
|
|
.append(&self.hash)
|
2016-08-15 06:19:28 -07:00
|
|
|
.append(&self.index);
|
|
|
|
}
|
2016-10-17 02:17:00 -07:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn serialized_size(&self) -> usize {
|
|
|
|
self.hash.serialized_size() + self.index.serialized_size()
|
|
|
|
}
|
2016-08-15 06:19:28 -07:00
|
|
|
}
|
|
|
|
|
2016-08-15 07:35:07 -07:00
|
|
|
impl Deserializable for OutPoint {
|
2016-10-30 16:28:50 -07:00
|
|
|
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, ReaderError> where T: io::Read {
|
2016-08-15 07:35:07 -07:00
|
|
|
let result = OutPoint {
|
2016-09-19 05:37:53 -07:00
|
|
|
hash: try!(reader.read()),
|
|
|
|
index: try!(reader.read()),
|
2016-08-15 07:35:07 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-12 06:09:32 -07:00
|
|
|
impl OutPoint {
|
|
|
|
pub fn hash(&self) -> &H256 {
|
|
|
|
&self.hash
|
|
|
|
}
|
|
|
|
|
2016-11-17 15:42:31 -08:00
|
|
|
pub fn is_null(&self) -> bool {
|
|
|
|
self.hash.is_zero() && self.index == u32::max_value()
|
|
|
|
}
|
2016-09-12 06:09:32 -07:00
|
|
|
}
|
|
|
|
|
2016-10-20 07:21:28 -07:00
|
|
|
#[derive(Debug, PartialEq, Default, Clone)]
|
2016-08-15 06:19:28 -07:00
|
|
|
pub struct TransactionInput {
|
2016-09-12 13:20:01 -07:00
|
|
|
pub previous_output: OutPoint,
|
2016-09-18 04:30:00 -07:00
|
|
|
pub script_sig: Bytes,
|
2016-09-12 13:20:01 -07:00
|
|
|
pub sequence: u32,
|
2016-08-15 06:19:28 -07:00
|
|
|
}
|
|
|
|
|
2016-11-27 06:05:49 -08:00
|
|
|
impl TransactionInput {
|
|
|
|
pub fn is_final(&self) -> bool {
|
|
|
|
self.sequence == SEQUENCE_FINAL
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-15 06:19:28 -07:00
|
|
|
impl Serializable for TransactionInput {
|
|
|
|
fn serialize(&self, stream: &mut Stream) {
|
|
|
|
stream
|
|
|
|
.append(&self.previous_output)
|
2016-09-18 04:30:00 -07:00
|
|
|
.append(&self.script_sig)
|
2016-08-15 06:19:28 -07:00
|
|
|
.append(&self.sequence);
|
|
|
|
}
|
2016-10-17 02:17:00 -07:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn serialized_size(&self) -> usize {
|
|
|
|
self.previous_output.serialized_size() +
|
|
|
|
self.script_sig.serialized_size() +
|
|
|
|
self.sequence.serialized_size()
|
|
|
|
}
|
2016-08-15 06:19:28 -07:00
|
|
|
}
|
|
|
|
|
2016-08-15 07:35:07 -07:00
|
|
|
impl Deserializable for TransactionInput {
|
2016-10-30 16:28:50 -07:00
|
|
|
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, ReaderError> where T: io::Read {
|
2016-08-15 07:35:07 -07:00
|
|
|
let result = TransactionInput {
|
2016-09-19 05:37:53 -07:00
|
|
|
previous_output: try!(reader.read()),
|
|
|
|
script_sig: try!(reader.read()),
|
|
|
|
sequence: try!(reader.read()),
|
2016-08-15 07:35:07 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-19 03:07:11 -07:00
|
|
|
impl HeapSizeOf for TransactionInput {
|
|
|
|
fn heap_size_of_children(&self) -> usize {
|
|
|
|
self.script_sig.heap_size_of_children()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-03 14:36:22 -07:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2016-08-15 06:19:28 -07:00
|
|
|
pub struct TransactionOutput {
|
2016-09-12 14:11:36 -07:00
|
|
|
pub value: u64,
|
2016-09-18 04:30:00 -07:00
|
|
|
pub script_pubkey: Bytes,
|
2016-08-15 06:19:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for TransactionOutput {
|
|
|
|
fn serialize(&self, stream: &mut Stream) {
|
|
|
|
stream
|
|
|
|
.append(&self.value)
|
2016-09-18 04:30:00 -07:00
|
|
|
.append(&self.script_pubkey);
|
2016-08-15 06:19:28 -07:00
|
|
|
}
|
2016-10-17 02:17:00 -07:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn serialized_size(&self) -> usize {
|
|
|
|
self.value.serialized_size() +
|
|
|
|
self.script_pubkey.serialized_size()
|
|
|
|
}
|
2016-08-15 06:19:28 -07:00
|
|
|
}
|
|
|
|
|
2016-08-15 07:35:07 -07:00
|
|
|
impl Deserializable for TransactionOutput {
|
2016-10-30 16:28:50 -07:00
|
|
|
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, ReaderError> where T: io::Read {
|
2016-08-15 07:35:07 -07:00
|
|
|
let result = TransactionOutput {
|
2016-09-19 05:37:53 -07:00
|
|
|
value: try!(reader.read()),
|
|
|
|
script_pubkey: try!(reader.read()),
|
2016-08-15 07:35:07 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-12 13:20:01 -07:00
|
|
|
impl Default for TransactionOutput {
|
|
|
|
fn default() -> Self {
|
|
|
|
TransactionOutput {
|
|
|
|
value: 0xffffffffffffffffu64,
|
2016-09-18 04:30:00 -07:00
|
|
|
script_pubkey: Bytes::default(),
|
2016-09-12 13:20:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-19 03:07:11 -07:00
|
|
|
impl HeapSizeOf for TransactionOutput {
|
|
|
|
fn heap_size_of_children(&self) -> usize {
|
|
|
|
self.script_pubkey.heap_size_of_children()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-20 07:21:28 -07:00
|
|
|
#[derive(Debug, PartialEq, Default, Clone)]
|
2016-08-15 06:19:28 -07:00
|
|
|
pub struct Transaction {
|
2016-09-12 13:20:01 -07:00
|
|
|
pub version: i32,
|
2016-09-13 03:31:06 -07:00
|
|
|
pub inputs: Vec<TransactionInput>,
|
|
|
|
pub outputs: Vec<TransactionOutput>,
|
2016-09-12 13:20:01 -07:00
|
|
|
pub lock_time: u32,
|
2016-08-15 06:19:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Serializable for Transaction {
|
|
|
|
fn serialize(&self, stream: &mut Stream) {
|
|
|
|
stream
|
|
|
|
.append(&self.version)
|
2016-09-13 03:31:06 -07:00
|
|
|
.append_list(&self.inputs)
|
|
|
|
.append_list(&self.outputs)
|
2016-08-15 06:19:28 -07:00
|
|
|
.append(&self.lock_time);
|
|
|
|
}
|
2016-10-17 02:17:00 -07:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn serialized_size(&self) -> usize {
|
|
|
|
self.version.serialized_size() +
|
|
|
|
serialized_list_size(&self.inputs) +
|
|
|
|
serialized_list_size(&self.outputs) +
|
|
|
|
self.lock_time.serialized_size()
|
|
|
|
}
|
2016-08-15 06:19:28 -07:00
|
|
|
}
|
2016-08-15 07:35:07 -07:00
|
|
|
|
|
|
|
impl Deserializable for Transaction {
|
2016-10-30 16:28:50 -07:00
|
|
|
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, ReaderError> where T: io::Read {
|
2016-08-15 07:35:07 -07:00
|
|
|
let result = Transaction {
|
2016-09-19 05:37:53 -07:00
|
|
|
version: try!(reader.read()),
|
|
|
|
inputs: try!(reader.read_list()),
|
|
|
|
outputs: try!(reader.read_list()),
|
|
|
|
lock_time: try!(reader.read()),
|
2016-08-15 07:35:07 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
}
|
2016-08-16 03:09:40 -07:00
|
|
|
|
2016-09-12 13:20:01 -07:00
|
|
|
impl From<&'static str> for Transaction {
|
|
|
|
fn from(s: &'static str) -> Self {
|
2016-10-30 16:28:50 -07:00
|
|
|
deserialize(&s.from_hex().unwrap() as &[u8]).unwrap()
|
2016-09-12 13:20:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-19 03:07:11 -07:00
|
|
|
impl HeapSizeOf for Transaction {
|
|
|
|
fn heap_size_of_children(&self) -> usize {
|
|
|
|
self.inputs.heap_size_of_children() + self.outputs.heap_size_of_children()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-16 03:09:40 -07:00
|
|
|
impl Transaction {
|
|
|
|
pub fn hash(&self) -> H256 {
|
2016-09-09 01:49:08 -07:00
|
|
|
dhash256(&serialize(self))
|
2016-08-16 03:09:40 -07:00
|
|
|
}
|
2016-09-11 03:22:25 -07:00
|
|
|
|
2016-09-13 03:31:06 -07:00
|
|
|
pub fn inputs(&self) -> &[TransactionInput] {
|
|
|
|
&self.inputs
|
2016-09-11 03:22:25 -07:00
|
|
|
}
|
|
|
|
|
2016-09-13 03:31:06 -07:00
|
|
|
pub fn outputs(&self) -> &[TransactionOutput] {
|
|
|
|
&self.outputs
|
2016-09-11 03:22:25 -07:00
|
|
|
}
|
2016-10-24 07:58:38 -07:00
|
|
|
|
|
|
|
pub fn is_coinbase(&self) -> bool {
|
2016-11-17 15:42:31 -08:00
|
|
|
self.inputs.len() == 1 && self.inputs[0].previous_output.is_null()
|
2016-10-24 07:58:38 -07:00
|
|
|
}
|
2016-11-10 08:19:47 -08:00
|
|
|
|
2016-11-27 06:05:49 -08:00
|
|
|
pub fn is_final(&self, block_height: u32, block_time: u32) -> bool {
|
|
|
|
if self.lock_time == 0 {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
let max_lock_time = if self.lock_time < LOCKTIME_THRESHOLD {
|
|
|
|
block_height
|
|
|
|
} else {
|
|
|
|
block_time
|
|
|
|
};
|
|
|
|
|
|
|
|
if self.lock_time < max_lock_time {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.inputs.iter().all(TransactionInput::is_final)
|
|
|
|
}
|
|
|
|
|
2016-11-10 08:19:47 -08:00
|
|
|
pub fn total_spends(&self) -> u64 {
|
|
|
|
self.outputs
|
|
|
|
.iter()
|
|
|
|
.fold(0u64, |acc, out| acc + out.value)
|
|
|
|
}
|
2016-08-16 03:09:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2016-09-19 05:37:53 -07:00
|
|
|
use hash::H256;
|
2016-10-17 02:17:00 -07:00
|
|
|
use ser::Serializable;
|
2016-08-16 03:09:40 -07:00
|
|
|
use super::Transaction;
|
|
|
|
|
|
|
|
// real transaction from block 80000
|
|
|
|
// https://blockchain.info/rawtx/5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2
|
|
|
|
// https://blockchain.info/rawtx/5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2?format=hex
|
|
|
|
#[test]
|
|
|
|
fn test_transaction_reader() {
|
2016-09-19 05:37:53 -07:00
|
|
|
let t: Transaction = "0100000001a6b97044d03da79c005b20ea9c0e1a6d9dc12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac00000000".into();
|
2016-08-16 03:09:40 -07:00
|
|
|
assert_eq!(t.version, 1);
|
|
|
|
assert_eq!(t.lock_time, 0);
|
2016-09-13 03:31:06 -07:00
|
|
|
assert_eq!(t.inputs.len(), 1);
|
|
|
|
assert_eq!(t.outputs.len(), 1);
|
|
|
|
let tx_input = &t.inputs[0];
|
2016-08-16 03:09:40 -07:00
|
|
|
assert_eq!(tx_input.sequence, 4294967295);
|
2016-09-18 04:30:00 -07:00
|
|
|
assert_eq!(tx_input.script_sig, "48304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501".into());
|
2016-09-13 03:31:06 -07:00
|
|
|
let tx_output = &t.outputs[0];
|
2016-08-16 03:09:40 -07:00
|
|
|
assert_eq!(tx_output.value, 5000000000);
|
2016-09-18 04:30:00 -07:00
|
|
|
assert_eq!(tx_output.script_pubkey, "76a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac".into());
|
2016-08-16 03:09:40 -07:00
|
|
|
}
|
2016-08-19 05:50:22 -07:00
|
|
|
|
2016-08-16 03:09:40 -07:00
|
|
|
#[test]
|
|
|
|
fn test_transaction_hash() {
|
2016-09-19 05:37:53 -07:00
|
|
|
let t: Transaction = "0100000001a6b97044d03da79c005b20ea9c0e1a6d9dc12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac00000000".into();
|
|
|
|
let hash = H256::from_reversed_str("5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2");
|
2016-08-16 09:00:26 -07:00
|
|
|
assert_eq!(t.hash(), hash);
|
2016-08-16 03:09:40 -07:00
|
|
|
}
|
2016-10-17 02:17:00 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_transaction_serialized_len() {
|
|
|
|
let raw_tx: &'static str = "0100000001a6b97044d03da79c005b20ea9c0e1a6d9dc12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac00000000";
|
|
|
|
let tx: Transaction = raw_tx.into();
|
|
|
|
assert_eq!(tx.serialized_size(), raw_tx.len() / 2);
|
|
|
|
}
|
2016-08-16 03:09:40 -07:00
|
|
|
}
|