|
16 | 16 | //! |
17 | 17 |
|
18 | 18 | use std::{io, fmt}; |
| 19 | +use std::collections::HashMap; |
19 | 20 |
|
20 | 21 | use bitcoin::{self, BitcoinHash, Txid, VarInt}; |
21 | 22 | use bitcoin::blockdata::opcodes; |
22 | 23 | use bitcoin::blockdata::script::{Script, Instruction}; |
23 | | -use bitcoin::hashes::Hash; |
| 24 | +use bitcoin::hashes::{Hash, sha256, sha256d}; |
24 | 25 |
|
25 | 26 | use confidential; |
26 | 27 | use encode::{self, Encodable, Decodable}; |
| 28 | +use issuance::AssetId; |
27 | 29 |
|
28 | 30 | /// Description of an asset issuance in a transaction input |
29 | 31 | #[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)] |
@@ -613,10 +615,27 @@ impl Transaction { |
613 | 615 | bitcoin::Wtxid::from_engine(enc) |
614 | 616 | } |
615 | 617 |
|
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 |
620 | 639 | } |
621 | 640 | } |
622 | 641 |
|
@@ -751,7 +770,9 @@ mod tests { |
751 | 770 | assert_eq!(tx.output[1].value, confidential::Value::Explicit( 3300)); |
752 | 771 | assert_eq!(tx.output[0].minimum_value(), 9999996700); |
753 | 772 | 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); |
755 | 776 |
|
756 | 777 | // CT transaction with explicit input (with script witness) and confidential outputs |
757 | 778 | let tx: Transaction = hex_deserialize!( |
@@ -970,7 +991,9 @@ mod tests { |
970 | 991 | assert_eq!(tx.output[1].is_null_data(), false); |
971 | 992 | assert_eq!(tx.output[2].is_null_data(), false); |
972 | 993 |
|
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); |
974 | 997 |
|
975 | 998 | // Coinbase tx |
976 | 999 | let tx: Transaction = hex_deserialize!( |
@@ -1006,7 +1029,9 @@ mod tests { |
1006 | 1029 | assert_eq!(tx.output[1].is_pegout(), false); |
1007 | 1030 | assert_eq!(tx.output[0].pegout_data(), None); |
1008 | 1031 | 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()); |
1010 | 1035 | } |
1011 | 1036 |
|
1012 | 1037 | #[test] |
@@ -1130,7 +1155,9 @@ mod tests { |
1130 | 1155 | assert_eq!(tx.output[1].is_pegout(), false); |
1131 | 1156 | assert_eq!(tx.output[0].pegout_data(), None); |
1132 | 1157 | 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); |
1134 | 1161 | } |
1135 | 1162 |
|
1136 | 1163 | #[test] |
@@ -1158,7 +1185,9 @@ mod tests { |
1158 | 1185 | assert_eq!(tx.output.len(), 1); |
1159 | 1186 | assert_eq!(tx.output[0].is_null_data(), true); |
1160 | 1187 | 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()); |
1162 | 1191 | assert_eq!( |
1163 | 1192 | tx.output[0].pegout_data(), |
1164 | 1193 | Some(super::PegoutData { |
@@ -1510,7 +1539,9 @@ mod tests { |
1510 | 1539 | assert_eq!(tx.input.len(), 1); |
1511 | 1540 | assert_eq!(tx.output.len(), 3); |
1512 | 1541 | 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); |
1514 | 1545 | assert_eq!( |
1515 | 1546 | tx.input[0].asset_issuance, |
1516 | 1547 | AssetIssuance { |
@@ -1633,7 +1664,9 @@ mod tests { |
1633 | 1664 |
|
1634 | 1665 | assert_eq!(tx.output[0].asset, tx.output[1].asset); |
1635 | 1666 | 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); |
1637 | 1670 | } |
1638 | 1671 |
|
1639 | 1672 | #[test] |
@@ -1675,7 +1708,9 @@ mod tests { |
1675 | 1708 |
|
1676 | 1709 | assert_eq!(tx.output[0].asset, tx.output[1].asset); |
1677 | 1710 | 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); |
1679 | 1714 | } |
1680 | 1715 |
|
1681 | 1716 | #[test] |
@@ -1716,7 +1751,9 @@ mod tests { |
1716 | 1751 |
|
1717 | 1752 | assert_eq!(tx.output[0].asset, tx.output[1].asset); |
1718 | 1753 | 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); |
1720 | 1757 | } |
1721 | 1758 | } |
1722 | 1759 |
|
0 commit comments