Skip to content

Commit

Permalink
Replace u64 with Amount type in TxOut
Browse files Browse the repository at this point in the history
Some places, most prominently TxOut, were still using u64s
for amounts (in sat). This PR replaces these with the
Amount newtype and also implements the consensus encode
traits for Amount to make it all work.
  • Loading branch information
sgeisler committed Apr 30, 2021
1 parent 4db4e60 commit 3b5f89f
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 25 deletions.
6 changes: 4 additions & 2 deletions src/blockdata/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn};
use blockdata::block::{Block, BlockHeader};
use network::constants::Network;
use util::uint::Uint256;
use Amount;

/// The maximum allowable sequence number
pub const MAX_SEQUENCE: u32 = 0xFFFFFFFF;
Expand Down Expand Up @@ -88,7 +89,7 @@ fn bitcoin_genesis_tx() -> Transaction {
.push_opcode(opcodes::all::OP_CHECKSIG)
.into_script();
ret.output.push(TxOut {
value: 50 * COIN_VALUE,
value: Amount::from_sat(50 * COIN_VALUE),
script_pubkey: out_script
});

Expand Down Expand Up @@ -166,6 +167,7 @@ mod test {
use consensus::encode::serialize;
use blockdata::constants::{genesis_block, bitcoin_genesis_tx};
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
use Amount;

#[test]
fn bitcoin_genesis_first_transaction() {
Expand All @@ -182,7 +184,7 @@ mod test {
assert_eq!(gen.output.len(), 1);
assert_eq!(serialize(&gen.output[0].script_pubkey),
Vec::from_hex("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac").unwrap());
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
assert_eq!(gen.output[0].value, Amount::from_sat(50 * COIN_VALUE));
assert_eq!(gen.lock_time, 0);

assert_eq!(format!("{:x}", gen.wtxid()),
Expand Down
6 changes: 3 additions & 3 deletions src/blockdata/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,8 +454,8 @@ impl Script {
/// * index - the input index in spending which is spending this transaction
/// * amount - the amount this script guards
/// * spending - the transaction that attempts to spend the output holding this script
pub fn verify (&self, index: usize, amount: u64, spending: &[u8]) -> Result<(), Error> {
Ok(bitcoinconsensus::verify (&self.0[..], amount, spending, index)?)
pub fn verify (&self, index: usize, amount: ::Amount, spending: &[u8]) -> Result<(), Error> {
Ok(bitcoinconsensus::verify (&self.0[..], amount.as_sat(), spending, index)?)
}

/// Write the assembly decoding of the script bytes to the formatter.
Expand Down Expand Up @@ -1243,7 +1243,7 @@ mod test {
// a random segwit transaction from the blockchain using native segwit
let spent = Builder::from(Vec::from_hex("0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d").unwrap()).into_script();
let spending = Vec::from_hex("010000000001011f97548fbbe7a0db7588a66e18d803d0089315aa7d4cc28360b6ec50ef36718a0100000000ffffffff02df1776000000000017a9146c002a686959067f4866b8fb493ad7970290ab728757d29f0000000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d04004730440220565d170eed95ff95027a69b313758450ba84a01224e1f7f130dda46e94d13f8602207bdd20e307f062594022f12ed5017bbf4a055a06aea91c10110a0e3bb23117fc014730440220647d2dc5b15f60bc37dc42618a370b2a1490293f9e5c8464f53ec4fe1dfe067302203598773895b4b16d37485cbe21b337f4e4b650739880098c592553add7dd4355016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000").unwrap();
spent.verify(0, 18393430, spending.as_slice()).unwrap();
spent.verify(0, ::Amount::from_sat(18393430), spending.as_slice()).unwrap();
}
}

7 changes: 4 additions & 3 deletions src/blockdata/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use blockdata::constants::WITNESS_SCALE_FACTOR;
use blockdata::script::Script;
use consensus::{encode, Decodable, Encodable};
use hash_types::{SigHash, Txid, Wtxid};
use VarInt;
use ::{VarInt, Amount};

/// A reference to a transaction output
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
Expand Down Expand Up @@ -210,15 +210,16 @@ impl Default for TxIn {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TxOut {
/// The value of the output, in satoshis
pub value: u64,
#[cfg_attr(feature = "serde", serde(with="::util::amount::serde::as_sat"))]
pub value: Amount,
/// The script which must satisfy for the output to be spent
pub script_pubkey: Script
}

// This is used as a "null txout" in consensus signing code
impl Default for TxOut {
fn default() -> TxOut {
TxOut { value: 0xffffffffffffffff, script_pubkey: Script::new() }
TxOut { value: Amount::from_sat(0xffffffffffffffff), script_pubkey: Script::new() }
}
}

Expand Down
14 changes: 14 additions & 0 deletions src/util/amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
use std::default;
use std::error;
use std::fmt::{self, Write};
use std::io;
use std::ops;
use std::str::FromStr;
use std::cmp::Ordering;
use consensus::{Encodable, Decodable, encode};

/// A set of denominations in which amounts can be expressed.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
Expand Down Expand Up @@ -446,6 +448,18 @@ impl fmt::Display for Amount {
}
}

impl Encodable for Amount {
fn consensus_encode<W: io::Write>(&self, writer: W) -> Result<usize, io::Error> {
self.0.consensus_encode(writer)
}
}

impl Decodable for Amount {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, encode::Error> {
Ok(Amount(u64::consensus_decode(d)?))
}
}

impl ops::Add for Amount {
type Output = Amount;

Expand Down
11 changes: 6 additions & 5 deletions src/util/bip143.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use consensus::{encode, Encodable};

use std::io;
use std::ops::{Deref, DerefMut};
use Amount;

/// Parts of a sighash which are common across inputs or signatures, and which are
/// sufficient (in conjunction with a private key) to sign the transaction
Expand Down Expand Up @@ -176,7 +177,7 @@ impl<R: Deref<Target=Transaction>> SigHashCache<R> {
mut writer: Write,
input_index: usize,
script_code: &Script,
value: u64,
value: Amount,
sighash_type: SigHashType,
) -> Result<(), encode::Error> {
let zero_hash = sha256d::Hash::default();
Expand Down Expand Up @@ -229,7 +230,7 @@ impl<R: Deref<Target=Transaction>> SigHashCache<R> {
&mut self,
input_index: usize,
script_code: &Script,
value: u64,
value: Amount,
sighash_type: SigHashType
) -> SigHash {
let mut enc = SigHash::engine();
Expand All @@ -247,15 +248,15 @@ impl<R: DerefMut<Target=Transaction>> SigHashCache<R> {
/// ```
/// use bitcoin::blockdata::transaction::{Transaction, SigHashType};
/// use bitcoin::util::bip143::SigHashCache;
/// use bitcoin::Script;
/// use bitcoin::{Script, Amount};
///
/// let mut tx_to_sign = Transaction { version: 2, lock_time: 0, input: Vec::new(), output: Vec::new() };
/// let input_count = tx_to_sign.input.len();
///
/// let mut sig_hasher = SigHashCache::new(&mut tx_to_sign);
/// for inp in 0..input_count {
/// let prevout_script = Script::new();
/// let _sighash = sig_hasher.signature_hash(inp, &prevout_script, 42, SigHashType::All);
/// let _sighash = sig_hasher.signature_hash(inp, &prevout_script, Amount::from_sat(42), SigHashType::All);
/// // ... sign the sighash
/// sig_hasher.access_witness(inp).push(Vec::new());
/// }
Expand Down Expand Up @@ -293,7 +294,7 @@ mod tests {
let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap();
let mut cache = SigHashCache::new(&tx);
let sighash_type = SigHashType::from_u32_consensus(hash_type);
let actual_result = cache.signature_hash(input_index, &script, value, sighash_type);
let actual_result = cache.signature_hash(input_index, &script, Amount::from_sat(value), sighash_type);
assert_eq!(actual_result, expected_result);
}

Expand Down
26 changes: 14 additions & 12 deletions src/util/psbt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ mod tests {

use super::PartiallySignedTransaction;
use util::psbt::raw::ProprietaryKey;
use Amount;

#[test]
fn trivial_psbt() {
Expand Down Expand Up @@ -316,13 +317,13 @@ mod tests {
}],
output: vec![
TxOut {
value: 99999699,
value: Amount::from_sat(99999699),
script_pubkey: hex_script!(
"76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac"
),
},
TxOut {
value: 100000000,
value: Amount::from_sat(100000000),
script_pubkey: hex_script!(
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787"
),
Expand Down Expand Up @@ -384,7 +385,7 @@ mod tests {
}],
output: vec![
TxOut {
value: 190303501938,
value: Amount::from_sat(190303501938),
script_pubkey: hex_script!("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587"),
},
],
Expand Down Expand Up @@ -429,7 +430,7 @@ mod tests {
inputs: vec![Input {
non_witness_utxo: Some(tx),
witness_utxo: Some(TxOut {
value: 190303501938,
value: Amount::from_sat(190303501938),
script_pubkey: hex_script!("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587"),
}),
sighash_type: Some("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse().unwrap()),
Expand Down Expand Up @@ -475,6 +476,7 @@ mod tests {
use util::psbt::map::{Map, Global, Input, Output};
use util::psbt::raw;
use util::psbt::{PartiallySignedTransaction, Error};
use Amount;

#[test]
#[should_panic(expected = "InvalidMagic")]
Expand Down Expand Up @@ -572,11 +574,11 @@ mod tests {
}],
output: vec![
TxOut {
value: 99999699,
value: Amount::from_sat(99999699),
script_pubkey: hex_script!("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac"),
},
TxOut {
value: 100000000,
value: Amount::from_sat(100000000),
script_pubkey: hex_script!("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787"),
},
],
Expand Down Expand Up @@ -620,11 +622,11 @@ mod tests {
}],
output: vec![
TxOut {
value: 200000000,
value: Amount::from_sat(200000000),
script_pubkey: hex_script!("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac"),
},
TxOut {
value: 190303501938,
value: Amount::from_sat(190303501938),
script_pubkey: hex_script!("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587"),
},
],
Expand Down Expand Up @@ -805,11 +807,11 @@ mod tests {
}],
output: vec![
TxOut {
value: 99999699,
value: Amount::from_sat(99999699),
script_pubkey: hex_script!("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac"),
},
TxOut {
value: 100000000,
value: Amount::from_sat(100000000),
script_pubkey: hex_script!("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787"),
},
],
Expand Down Expand Up @@ -853,11 +855,11 @@ mod tests {
}],
output: vec![
TxOut {
value: 200000000,
value: Amount::from_sat(200000000),
script_pubkey: hex_script!("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac"),
},
TxOut {
value: 190303501938,
value: Amount::from_sat(190303501938),
script_pubkey: hex_script!("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587"),
},
],
Expand Down

0 comments on commit 3b5f89f

Please sign in to comment.