Skip to content

Commit c193bc7

Browse files
committed
Replace u64 with Amount type in TxOut
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.
1 parent 052aaf1 commit c193bc7

6 files changed

Lines changed: 46 additions & 26 deletions

File tree

src/blockdata/constants.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn};
2929
use blockdata::block::{Block, BlockHeader};
3030
use network::constants::Network;
3131
use util::uint::Uint256;
32+
use Amount;
3233

3334
/// The maximum allowable sequence number
3435
pub const MAX_SEQUENCE: u32 = 0xFFFFFFFF;
@@ -88,7 +89,7 @@ fn bitcoin_genesis_tx() -> Transaction {
8889
.push_opcode(opcodes::all::OP_CHECKSIG)
8990
.into_script();
9091
ret.output.push(TxOut {
91-
value: 50 * COIN_VALUE,
92+
value: Amount::from_sat(50 * COIN_VALUE),
9293
script_pubkey: out_script
9394
});
9495

@@ -166,6 +167,7 @@ mod test {
166167
use consensus::encode::serialize;
167168
use blockdata::constants::{genesis_block, bitcoin_genesis_tx};
168169
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
170+
use Amount;
169171

170172
#[test]
171173
fn bitcoin_genesis_first_transaction() {
@@ -182,7 +184,7 @@ mod test {
182184
assert_eq!(gen.output.len(), 1);
183185
assert_eq!(serialize(&gen.output[0].script_pubkey),
184186
Vec::from_hex("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac").unwrap());
185-
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
187+
assert_eq!(gen.output[0].value, Amount::from_sat(50 * COIN_VALUE));
186188
assert_eq!(gen.lock_time, 0);
187189

188190
assert_eq!(format!("{:x}", gen.wtxid()),

src/blockdata/script.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,8 @@ impl Script {
450450

451451
#[cfg(feature="bitcoinconsensus")]
452452
/// Shorthand for [Self::verify_with_flags] with flag [bitcoinconsensus::VERIFY_ALL]
453-
pub fn verify (&self, index: usize, amount: u64, spending: &[u8]) -> Result<(), Error> {
454-
self.verify_with_flags(index, ::Amount::from_sat(amount), spending, ::bitcoinconsensus::VERIFY_ALL)
453+
pub fn verify (&self, index: usize, amount: ::Amount, spending: &[u8]) -> Result<(), Error> {
454+
self.verify_with_flags(index, amount, spending, ::bitcoinconsensus::VERIFY_ALL)
455455
}
456456

457457
#[cfg(feature="bitcoinconsensus")]
@@ -1250,7 +1250,7 @@ mod test {
12501250
// a random segwit transaction from the blockchain using native segwit
12511251
let spent = Builder::from(Vec::from_hex("0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d").unwrap()).into_script();
12521252
let spending = Vec::from_hex("010000000001011f97548fbbe7a0db7588a66e18d803d0089315aa7d4cc28360b6ec50ef36718a0100000000ffffffff02df1776000000000017a9146c002a686959067f4866b8fb493ad7970290ab728757d29f0000000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d04004730440220565d170eed95ff95027a69b313758450ba84a01224e1f7f130dda46e94d13f8602207bdd20e307f062594022f12ed5017bbf4a055a06aea91c10110a0e3bb23117fc014730440220647d2dc5b15f60bc37dc42618a370b2a1490293f9e5c8464f53ec4fe1dfe067302203598773895b4b16d37485cbe21b337f4e4b650739880098c592553add7dd4355016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000").unwrap();
1253-
spent.verify(0, 18393430, spending.as_slice()).unwrap();
1253+
spent.verify(0, ::Amount::from_sat(18393430), spending.as_slice()).unwrap();
12541254
}
12551255

12561256
#[test]

src/blockdata/transaction.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use blockdata::script::Script;
3636
use consensus::{encode, Decodable, Encodable};
3737
use consensus::encode::MAX_VEC_SIZE;
3838
use hash_types::{SigHash, Txid, Wtxid};
39-
use VarInt;
39+
use ::{VarInt, Amount};
4040

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

219220
// This is used as a "null txout" in consensus signing code
220221
impl Default for TxOut {
221222
fn default() -> TxOut {
222-
TxOut { value: 0xffffffffffffffff, script_pubkey: Script::new() }
223+
TxOut { value: Amount::from_sat(0xffffffffffffffff), script_pubkey: Script::new() }
223224
}
224225
}
225226

@@ -479,7 +480,7 @@ impl Transaction {
479480
let flags: u32 = flags.into();
480481
for (idx, input) in self.input.iter().enumerate() {
481482
if let Some(output) = spent(&input.previous_output) {
482-
output.script_pubkey.verify_with_flags(idx, ::Amount::from_sat(output.value), tx.as_slice(), flags)?;
483+
output.script_pubkey.verify_with_flags(idx, output.value, tx.as_slice(), flags)?;
483484
} else {
484485
return Err(script::Error::UnknownSpentOutput(input.previous_output.clone()));
485486
}

src/util/amount.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
use std::default;
1818
use std::error;
1919
use std::fmt::{self, Write};
20+
use std::io;
2021
use std::ops;
2122
use std::str::FromStr;
2223
use std::cmp::Ordering;
24+
use consensus::{Encodable, Decodable, encode};
2325

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

451+
impl Encodable for Amount {
452+
fn consensus_encode<W: io::Write>(&self, writer: W) -> Result<usize, io::Error> {
453+
self.0.consensus_encode(writer)
454+
}
455+
}
456+
457+
impl Decodable for Amount {
458+
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, encode::Error> {
459+
Ok(Amount(u64::consensus_decode(d)?))
460+
}
461+
}
462+
449463
impl ops::Add for Amount {
450464
type Output = Amount;
451465

src/util/bip143.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use consensus::{encode, Encodable};
2727

2828
use std::io;
2929
use std::ops::{Deref, DerefMut};
30+
use Amount;
3031

3132
/// Parts of a sighash which are common across inputs or signatures, and which are
3233
/// sufficient (in conjunction with a private key) to sign the transaction
@@ -176,7 +177,7 @@ impl<R: Deref<Target=Transaction>> SigHashCache<R> {
176177
mut writer: Write,
177178
input_index: usize,
178179
script_code: &Script,
179-
value: u64,
180+
value: Amount,
180181
sighash_type: SigHashType,
181182
) -> Result<(), encode::Error> {
182183
let zero_hash = sha256d::Hash::default();
@@ -229,7 +230,7 @@ impl<R: Deref<Target=Transaction>> SigHashCache<R> {
229230
&mut self,
230231
input_index: usize,
231232
script_code: &Script,
232-
value: u64,
233+
value: Amount,
233234
sighash_type: SigHashType
234235
) -> SigHash {
235236
let mut enc = SigHash::engine();
@@ -247,15 +248,15 @@ impl<R: DerefMut<Target=Transaction>> SigHashCache<R> {
247248
/// ```
248249
/// use bitcoin::blockdata::transaction::{Transaction, SigHashType};
249250
/// use bitcoin::util::bip143::SigHashCache;
250-
/// use bitcoin::Script;
251+
/// use bitcoin::{Script, Amount};
251252
///
252253
/// let mut tx_to_sign = Transaction { version: 2, lock_time: 0, input: Vec::new(), output: Vec::new() };
253254
/// let input_count = tx_to_sign.input.len();
254255
///
255256
/// let mut sig_hasher = SigHashCache::new(&mut tx_to_sign);
256257
/// for inp in 0..input_count {
257258
/// let prevout_script = Script::new();
258-
/// let _sighash = sig_hasher.signature_hash(inp, &prevout_script, 42, SigHashType::All);
259+
/// let _sighash = sig_hasher.signature_hash(inp, &prevout_script, Amount::from_sat(42), SigHashType::All);
259260
/// // ... sign the sighash
260261
/// sig_hasher.access_witness(inp).push(Vec::new());
261262
/// }
@@ -293,7 +294,7 @@ mod tests {
293294
let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap();
294295
let mut cache = SigHashCache::new(&tx);
295296
let sighash_type = SigHashType::from_u32_consensus(hash_type);
296-
let actual_result = cache.signature_hash(input_index, &script, value, sighash_type);
297+
let actual_result = cache.signature_hash(input_index, &script, Amount::from_sat(value), sighash_type);
297298
assert_eq!(actual_result, expected_result);
298299
}
299300

src/util/psbt/mod.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ mod tests {
230230

231231
use super::PartiallySignedTransaction;
232232
use util::psbt::raw::ProprietaryKey;
233+
use Amount;
233234

234235
#[test]
235236
fn trivial_psbt() {
@@ -318,13 +319,13 @@ mod tests {
318319
}],
319320
output: vec![
320321
TxOut {
321-
value: 99999699,
322+
value: Amount::from_sat(99999699),
322323
script_pubkey: hex_script!(
323324
"76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac"
324325
),
325326
},
326327
TxOut {
327-
value: 100000000,
328+
value: Amount::from_sat(100000000),
328329
script_pubkey: hex_script!(
329330
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787"
330331
),
@@ -386,7 +387,7 @@ mod tests {
386387
}],
387388
output: vec![
388389
TxOut {
389-
value: 190303501938,
390+
value: Amount::from_sat(190303501938),
390391
script_pubkey: hex_script!("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587"),
391392
},
392393
],
@@ -431,7 +432,7 @@ mod tests {
431432
inputs: vec![Input {
432433
non_witness_utxo: Some(tx),
433434
witness_utxo: Some(TxOut {
434-
value: 190303501938,
435+
value: Amount::from_sat(190303501938),
435436
script_pubkey: hex_script!("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587"),
436437
}),
437438
sighash_type: Some("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse().unwrap()),
@@ -477,6 +478,7 @@ mod tests {
477478
use util::psbt::map::{Map, Global, Input, Output};
478479
use util::psbt::raw;
479480
use util::psbt::{PartiallySignedTransaction, Error};
481+
use Amount;
480482

481483
#[test]
482484
#[should_panic(expected = "InvalidMagic")]
@@ -574,11 +576,11 @@ mod tests {
574576
}],
575577
output: vec![
576578
TxOut {
577-
value: 99999699,
579+
value: Amount::from_sat(99999699),
578580
script_pubkey: hex_script!("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac"),
579581
},
580582
TxOut {
581-
value: 100000000,
583+
value: Amount::from_sat(100000000),
582584
script_pubkey: hex_script!("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787"),
583585
},
584586
],
@@ -622,11 +624,11 @@ mod tests {
622624
}],
623625
output: vec![
624626
TxOut {
625-
value: 200000000,
627+
value: Amount::from_sat(200000000),
626628
script_pubkey: hex_script!("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac"),
627629
},
628630
TxOut {
629-
value: 190303501938,
631+
value: Amount::from_sat(190303501938),
630632
script_pubkey: hex_script!("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587"),
631633
},
632634
],
@@ -807,11 +809,11 @@ mod tests {
807809
}],
808810
output: vec![
809811
TxOut {
810-
value: 99999699,
812+
value: Amount::from_sat(99999699),
811813
script_pubkey: hex_script!("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac"),
812814
},
813815
TxOut {
814-
value: 100000000,
816+
value: Amount::from_sat(100000000),
815817
script_pubkey: hex_script!("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787"),
816818
},
817819
],
@@ -855,11 +857,11 @@ mod tests {
855857
}],
856858
output: vec![
857859
TxOut {
858-
value: 200000000,
860+
value: Amount::from_sat(200000000),
859861
script_pubkey: hex_script!("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac"),
860862
},
861863
TxOut {
862-
value: 190303501938,
864+
value: Amount::from_sat(190303501938),
863865
script_pubkey: hex_script!("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587"),
864866
},
865867
],

0 commit comments

Comments
 (0)