Skip to content

Commit 2c50e9e

Browse files
authored
Merge pull request #45 from stevenroose/fix-fee
Replace Transaction::fee with ::fee_in and ::all_fees
2 parents 9b7e431 + 1602562 commit 2c50e9e

File tree

3 files changed

+70
-24
lines changed

3 files changed

+70
-24
lines changed

src/confidential.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,12 @@ impl Asset {
231231
}
232232
}
233233

234-
/// Unwrap the explicit value of this type.
235-
/// Panics if [is_explicit] returns false.
236-
pub fn unwrap_explicit(&self) -> sha256d::Hash {
234+
/// Returns the explicit asset.
235+
/// Returns [None] if [is_explicit] returns false.
236+
pub fn explicit(&self) -> Option<sha256d::Hash> {
237237
match *self {
238-
Asset::Explicit(v) => v,
239-
_ => panic!("Called unwrap_explicit on non-explicit asset: {:?}", self),
238+
Asset::Explicit(v) => Some(v),
239+
_ => None,
240240
}
241241
}
242242
}
@@ -274,12 +274,12 @@ impl Nonce {
274274
}
275275
}
276276

277-
/// Unwrap the explicit value of this type.
278-
/// Panics if [is_explicit] returns false.
279-
pub fn unwrap_explicit(&self) -> sha256d::Hash {
277+
/// Returns the explicit nonce.
278+
/// Returns [None] if [is_explicit] returns false.
279+
pub fn explicit(&self) -> Option<sha256d::Hash> {
280280
match *self {
281-
Nonce::Explicit(v) => v,
282-
_ => panic!("Called unwrap_explicit on non-explicit nonce: {:?}", self),
281+
Nonce::Explicit(v) => Some(v),
282+
_ => None,
283283
}
284284
}
285285
}

src/issuance.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
//! Asset Issuance
1616
17+
use std::str::FromStr;
18+
1719
use bitcoin::util::hash::BitcoinHash;
1820
use bitcoin::hashes::{hex, sha256, Hash};
1921
use fast_merkle_root::fast_merkle_root;
@@ -110,6 +112,13 @@ impl ::std::fmt::LowerHex for AssetId {
110112
}
111113
}
112114

115+
impl FromStr for AssetId {
116+
type Err = hex::Error;
117+
fn from_str(s: &str) -> Result<Self, Self::Err> {
118+
hex::FromHex::from_hex(s)
119+
}
120+
}
121+
113122
#[cfg(feature = "serde")]
114123
impl ::serde::Serialize for AssetId {
115124
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {

src/transaction.rs

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616
//!
1717
1818
use std::{io, fmt};
19+
use std::collections::HashMap;
1920

2021
use bitcoin::{self, BitcoinHash, Txid, VarInt};
2122
use bitcoin::blockdata::opcodes;
2223
use bitcoin::blockdata::script::{Script, Instruction};
23-
use bitcoin::hashes::Hash;
24+
use bitcoin::hashes::{Hash, sha256, sha256d};
2425

2526
use confidential;
2627
use encode::{self, Encodable, Decodable};
28+
use issuance::AssetId;
2729

2830
/// Description of an asset issuance in a transaction input
2931
#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
@@ -613,10 +615,27 @@ impl Transaction {
613615
bitcoin::Wtxid::from_engine(enc)
614616
}
615617

616-
/// Get the total transaction fee.
617-
pub fn fee(&self) -> u64 {
618-
// All values should be explicit, so we don't have to assert that here.
619-
self.output.iter().filter(|o| o.is_fee()).filter_map(|o| o.value.explicit()).sum()
618+
/// Get the total transaction fee in the given asset.
619+
pub fn fee_in(&self, asset: AssetId) -> u64 {
620+
let asset = sha256d::Hash::from_inner(asset.into_inner().into_inner());
621+
// is_fee checks for explicit asset and value, so we can unwrap them here.
622+
self.output.iter()
623+
.filter(|o| o.is_fee() && o.asset.explicit().expect("is_fee") == asset)
624+
.map(|o| o.value.explicit().expect("is_fee"))
625+
.sum()
626+
}
627+
628+
/// Get all fees in all assets.
629+
pub fn all_fees(&self) -> HashMap<AssetId, u64> {
630+
let mut fees = HashMap::new();
631+
for out in self.output.iter().filter(|o| o.is_fee()) {
632+
// is_fee checks for explicit asset and value, so we can unwrap them here.
633+
let asset = out.asset.explicit().expect("is_fee").into_inner();
634+
let asset = AssetId::from_inner(sha256::Midstate::from_inner(asset));
635+
let entry = fees.entry(asset).or_insert(0);
636+
*entry += out.value.explicit().expect("is_fee");
637+
}
638+
fees
620639
}
621640
}
622641

@@ -751,7 +770,9 @@ mod tests {
751770
assert_eq!(tx.output[1].value, confidential::Value::Explicit( 3300));
752771
assert_eq!(tx.output[0].minimum_value(), 9999996700);
753772
assert_eq!(tx.output[1].minimum_value(), 3300);
754-
assert_eq!(tx.fee(), 3300);
773+
let fee_asset = "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23".parse().unwrap();
774+
assert_eq!(tx.fee_in(fee_asset), 3300);
775+
assert_eq!(tx.all_fees()[&fee_asset], 3300);
755776

756777
// CT transaction with explicit input (with script witness) and confidential outputs
757778
let tx: Transaction = hex_deserialize!(
@@ -970,7 +991,9 @@ mod tests {
970991
assert_eq!(tx.output[1].is_null_data(), false);
971992
assert_eq!(tx.output[2].is_null_data(), false);
972993

973-
assert_eq!(tx.fee(), 36480);
994+
let fee_asset = "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23".parse().unwrap();
995+
assert_eq!(tx.fee_in(fee_asset), 36480);
996+
assert_eq!(tx.all_fees()[&fee_asset], 36480);
974997

975998
// Coinbase tx
976999
let tx: Transaction = hex_deserialize!(
@@ -1006,7 +1029,9 @@ mod tests {
10061029
assert_eq!(tx.output[1].is_pegout(), false);
10071030
assert_eq!(tx.output[0].pegout_data(), None);
10081031
assert_eq!(tx.output[1].pegout_data(), None);
1009-
assert_eq!(tx.fee(), 0);
1032+
let fee_asset = "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23".parse().unwrap();
1033+
assert_eq!(tx.fee_in(fee_asset), 0);
1034+
assert!(tx.all_fees().is_empty());
10101035
}
10111036

10121037
#[test]
@@ -1130,7 +1155,9 @@ mod tests {
11301155
assert_eq!(tx.output[1].is_pegout(), false);
11311156
assert_eq!(tx.output[0].pegout_data(), None);
11321157
assert_eq!(tx.output[1].pegout_data(), None);
1133-
assert_eq!(tx.fee(), 6260);
1158+
let fee_asset = "630ed6f9b176af03c0cd3f8aa430f9e7b4d988cf2d0b2f204322488f03b00bf8".parse().unwrap();
1159+
assert_eq!(tx.fee_in(fee_asset), 6260);
1160+
assert_eq!(tx.all_fees()[&fee_asset], 6260);
11341161
}
11351162

11361163
#[test]
@@ -1158,7 +1185,9 @@ mod tests {
11581185
assert_eq!(tx.output.len(), 1);
11591186
assert_eq!(tx.output[0].is_null_data(), true);
11601187
assert_eq!(tx.output[0].is_pegout(), true);
1161-
assert_eq!(tx.fee(), 0);
1188+
let fee_asset = "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23".parse().unwrap();
1189+
assert_eq!(tx.fee_in(fee_asset), 0);
1190+
assert!(tx.all_fees().is_empty());
11621191
assert_eq!(
11631192
tx.output[0].pegout_data(),
11641193
Some(super::PegoutData {
@@ -1510,7 +1539,9 @@ mod tests {
15101539
assert_eq!(tx.input.len(), 1);
15111540
assert_eq!(tx.output.len(), 3);
15121541
assert_eq!(tx.input[0].has_issuance, true);
1513-
assert_eq!(tx.fee(), 56400);
1542+
let fee_asset = "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23".parse().unwrap();
1543+
assert_eq!(tx.fee_in(fee_asset), 56400);
1544+
assert_eq!(tx.all_fees()[&fee_asset], 56400);
15141545
assert_eq!(
15151546
tx.input[0].asset_issuance,
15161547
AssetIssuance {
@@ -1633,7 +1664,9 @@ mod tests {
16331664

16341665
assert_eq!(tx.output[0].asset, tx.output[1].asset);
16351666
assert_eq!(tx.output[2].asset, tx.output[1].asset);
1636-
assert_eq!(tx.fee(), 1788);
1667+
let fee_asset = "6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d".parse().unwrap();
1668+
assert_eq!(tx.fee_in(fee_asset), 1788);
1669+
assert_eq!(tx.all_fees()[&fee_asset], 1788);
16371670
}
16381671

16391672
#[test]
@@ -1675,7 +1708,9 @@ mod tests {
16751708

16761709
assert_eq!(tx.output[0].asset, tx.output[1].asset);
16771710
assert_eq!(tx.output[2].asset, tx.output[1].asset);
1678-
assert_eq!(tx.fee(), 1788);
1711+
let fee_asset = "6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d".parse().unwrap();
1712+
assert_eq!(tx.fee_in(fee_asset), 1788);
1713+
assert_eq!(tx.all_fees()[&fee_asset], 1788);
16791714
}
16801715

16811716
#[test]
@@ -1716,7 +1751,9 @@ mod tests {
17161751

17171752
assert_eq!(tx.output[0].asset, tx.output[1].asset);
17181753
assert_eq!(tx.output[2].asset, tx.output[1].asset);
1719-
assert_eq!(tx.fee(), 1788);
1754+
let fee_asset = "6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d".parse().unwrap();
1755+
assert_eq!(tx.fee_in(fee_asset), 1788);
1756+
assert_eq!(tx.all_fees()[&fee_asset], 1788);
17201757
}
17211758
}
17221759

0 commit comments

Comments
 (0)