This commit is contained in:
Hanh 2022-11-05 17:29:16 +08:00
parent 74c26bf87d
commit d53b9446d3
4 changed files with 76 additions and 29 deletions

View File

@ -2,13 +2,14 @@ use std::cmp::min;
use zcash_address::{AddressKind, ZcashAddress};
use zcash_address::unified::{Container, Receiver};
use zcash_primitives::memo::MemoBytes;
use crate::note_selection::types::{PrivacyPolicy, Fill, Execution, Order, Pool, PoolAllocation, Destination, PoolPrecedence};
use crate::note_selection::types::{PrivacyPolicy, Fill, Execution, Order, Pool, PoolAllocation, Destination, PoolPrecedence, PoolPriority};
/// Decode address and return it as an order
///
pub fn decode(id: u32, address: &str, amount: u64, memo: MemoBytes) -> anyhow::Result<Order> {
let address = ZcashAddress::try_from_encoded(address)?;
let mut order = Order::default();
let mut precedence = order.priority.to_pool_precedence().clone();
order.id = id;
match address.kind {
AddressKind::Sprout(_) => {}
@ -17,7 +18,7 @@ pub fn decode(id: u32, address: &str, amount: u64, memo: MemoBytes) -> anyhow::R
order.destinations[Pool::Sapling as usize] = Some(destination);
}
AddressKind::Unified(unified_address) => {
for address in unified_address.items() {
for (i, address) in unified_address.items().into_iter().enumerate() {
match address {
Receiver::Orchard(data) => {
let destination = Destination::Orchard(data);
@ -54,11 +55,12 @@ pub fn execute_orders(orders: &mut [Order], initial_pool: &PoolAllocation, use_t
let mut fills = vec![];
for order in orders.iter_mut() {
let order_precedence = order.priority.to_pool_precedence();
// log::info!("Order {:?}", order);
// Direct Shielded Fill - s2s, o2o
// t2t only for fees
if use_shielded {
for &pool in precedence {
for &pool in order_precedence {
if pool == Pool::Transparent && !order.is_fee { continue }
if order.destinations[pool as usize].is_some() {
fill_order(pool, pool, order, initial_pool, &mut allocation, &mut fills);
@ -68,7 +70,7 @@ pub fn execute_orders(orders: &mut [Order], initial_pool: &PoolAllocation, use_t
if privacy_policy != PrivacyPolicy::SamePoolOnly {
// Indirect Shielded - z2z: s2o, o2s
for &pool in precedence {
for &pool in order_precedence {
if order.destinations[pool as usize].is_none() { continue }
if !use_shielded { continue }
if let Some(from_pool) = pool.other_shielded() {
@ -78,7 +80,7 @@ pub fn execute_orders(orders: &mut [Order], initial_pool: &PoolAllocation, use_t
if privacy_policy == PrivacyPolicy::AnyPool {
// Other - s2t, o2t, t2s, t2o
for &pool in precedence {
for &pool in order_precedence {
if order.destinations[pool as usize].is_none() { continue }
match pool {
Pool::Transparent if use_shielded => {
@ -94,12 +96,12 @@ pub fn execute_orders(orders: &mut [Order], initial_pool: &PoolAllocation, use_t
_ => {}
};
}
}
}
// t2t
if use_transparent && order.destinations[Pool::Transparent as usize].is_some() {
fill_order(Pool::Transparent, Pool::Transparent, order, initial_pool, &mut allocation, &mut fills);
// t2t
if use_transparent && order.destinations[Pool::Transparent as usize].is_some() {
fill_order(Pool::Transparent, Pool::Transparent, order, initial_pool, &mut allocation, &mut fills);
}
}
}
}

View File

@ -4,7 +4,7 @@ use zcash_primitives::memo::MemoBytes;
use crate::note_selection::decode;
use crate::note_selection::fee::FeeCalculator;
use crate::note_selection::fill::execute_orders;
use crate::note_selection::types::{NoteSelectConfig, Order, PoolAllocation, UTXO, Destination, TransactionPlan, Fill, PoolPrecedence};
use crate::note_selection::types::{NoteSelectConfig, Order, PoolAllocation, UTXO, Destination, TransactionPlan, Fill, PoolPrecedence, PoolPriority};
pub fn select_notes(allocation: &PoolAllocation, utxos: &[UTXO]) -> anyhow::Result<Vec<UTXO>> {
let mut allocation = allocation.clone();
@ -82,14 +82,6 @@ pub fn note_select_with_fee<F: FeeCalculator>(utxos: &[UTXO], orders: &mut [Orde
fee = F::calculate_fee(&notes, &executor.fills);
log::debug!("base fee: {}", fee);
}
let mut fee_order = Order {
id: u32::MAX,
destinations: ANY_DESTINATION,
amount: fee,
memo: MemoBytes::empty(),
is_fee: true, // do not include in fee calculation
filled: 0,
};
// Favor the pools that are already used, because it may cause lower fees
let pool_needed = executor.pool_used;
@ -97,6 +89,15 @@ pub fn note_select_with_fee<F: FeeCalculator>(utxos: &[UTXO], orders: &mut [Orde
let prec_2 = config.precedence.iter().filter(|&&p| pool_needed.0[p as usize] == 0);
let fee_precedence: PoolPrecedence = prec_1.chain(prec_2).cloned().collect::<Vec<_>>().try_into().unwrap();
log::debug!("Fee precedence: {:?}", fee_precedence);
let mut fee_order = Order {
id: u32::MAX,
destinations: ANY_DESTINATION,
priority: fee_precedence.try_into().unwrap(),
amount: fee,
memo: MemoBytes::empty(),
is_fee: true, // do not include in fee calculation
filled: 0,
};
if !executor.execute(slice::from_mut(&mut fee_order), &fee_precedence)? {
anyhow::bail!("Unsufficient Funds [fees]")

View File

@ -75,6 +75,7 @@ macro_rules! order {
id: $id,
amount: $q * 1000,
destinations: $destinations,
priority: PoolPriority::OST,
filled: 0,
is_fee: false,
memo: MemoBytes::empty(),
@ -176,7 +177,7 @@ fn test_example1() {
println!("{}", serde_json::to_string(&tx_plan).unwrap());
let tx_plan_json = serde_json::to_value(&tx_plan).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":1}},"amount":5000},{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":2}},"amount":7000},{"source":{"Sapling":{"id_note":3,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":12000},{"source":{"Orchard":{"id_note":4,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":10000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000},{"id_order":4294967295,"destination":{"Orchard":"2b6dca785c846b3752d13150e1c8f197ba9c8ead0a8bee1b3a52df0ad866362941e32d1b69d438b257cf82"},"amount":4000}],"fee":20000}"#).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":1}},"amount":5000},{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":2}},"amount":7000},{"source":{"Sapling":{"id_note":3,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":12000},{"source":{"Orchard":{"id_note":4,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":10000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000,"memo":[246]},{"id_order":4294967295,"destination":{"Orchard":"2b6dca785c846b3752d13150e1c8f197ba9c8ead0a8bee1b3a52df0ad866362941e32d1b69d438b257cf82"},"amount":4000,"memo":[246]}],"fee":20000}"#).unwrap();
assert_eq!(tx_plan_json, expected);
}
@ -193,7 +194,7 @@ fn test_example2() {
println!("{}", serde_json::to_string(&tx_plan).unwrap());
let tx_plan_json = serde_json::to_value(&tx_plan).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":1}},"amount":5000},{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":2}},"amount":7000},{"source":{"Sapling":{"id_note":3,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":12000},{"source":{"Orchard":{"id_note":4,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":10000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000},{"id_order":4294967295,"destination":{"Orchard":"2b6dca785c846b3752d13150e1c8f197ba9c8ead0a8bee1b3a52df0ad866362941e32d1b69d438b257cf82"},"amount":4000}],"fee":20000}"#).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":1}},"amount":5000},{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":2}},"amount":7000},{"source":{"Sapling":{"id_note":3,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":12000},{"source":{"Orchard":{"id_note":4,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":10000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000,"memo":[246]},{"id_order":4294967295,"destination":{"Orchard":"2b6dca785c846b3752d13150e1c8f197ba9c8ead0a8bee1b3a52df0ad866362941e32d1b69d438b257cf82"},"amount":4000,"memo":[246]}],"fee":20000}"#).unwrap();
assert_eq!(tx_plan_json, expected);
}
@ -212,7 +213,7 @@ fn test_example3() {
println!("{}", serde_json::to_string(&tx_plan).unwrap());
let tx_plan_json = serde_json::to_value(&tx_plan).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":1}},"amount":100000},{"source":{"Sapling":{"id_note":2,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":160000},{"source":{"Orchard":{"id_note":3,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":70000},{"source":{"Orchard":{"id_note":4,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000},{"id_order":2,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":20000},{"id_order":3,"destination":{"Orchard":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":30000},{"id_order":4,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":40000},{"id_order":5,"destination":{"Orchard":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":50000},{"id_order":6,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":60000},{"id_order":7,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":30000},{"id_order":7,"destination":{"Orchard":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":40000},{"id_order":4294967295,"destination":{"Transparent":"c7b7b3d299bd173ea278d792b1bd5fbdd11afe34"},"amount":55000}],"fee":45000}"#).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":1}},"amount":100000},{"source":{"Sapling":{"id_note":2,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":160000},{"source":{"Orchard":{"id_note":3,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":70000},{"source":{"Orchard":{"id_note":4,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000,"memo":[246]},{"id_order":2,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":20000,"memo":[246]},{"id_order":3,"destination":{"Orchard":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":30000,"memo":[246]},{"id_order":4,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":40000,"memo":[246]},{"id_order":5,"destination":{"Orchard":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":50000,"memo":[246]},{"id_order":6,"destination":{"Orchard":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":40000,"memo":[246]},{"id_order":6,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":20000,"memo":[246]},{"id_order":7,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":70000,"memo":[246]},{"id_order":4294967295,"destination":{"Transparent":"c7b7b3d299bd173ea278d792b1bd5fbdd11afe34"},"amount":55000,"memo":[246]}],"fee":45000}"#).unwrap();
assert_eq!(tx_plan_json, expected);
}
@ -223,6 +224,8 @@ fn test_example4() {
let _ = env_logger::try_init();
let mut config = NoteSelectConfig::new(CHANGE_ADDRESS);
config.use_transparent = true;
config.use_shielded = false;
config.privacy_policy = PrivacyPolicy::AnyPool;
let utxos = [utxo!(1, 50), sapling!(2, 50), orchard!(3, 50)];
let mut orders = [t!(1, 10)];
@ -231,7 +234,7 @@ fn test_example4() {
println!("{}", serde_json::to_string(&tx_plan).unwrap());
let tx_plan_json = serde_json::to_value(&tx_plan).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":1}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000},{"id_order":4294967295,"destination":{"Transparent":"c7b7b3d299bd173ea278d792b1bd5fbdd11afe34"},"amount":30000}],"fee":10000}"#).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":1}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000,"memo":[246]},{"id_order":4294967295,"destination":{"Transparent":"c7b7b3d299bd173ea278d792b1bd5fbdd11afe34"},"amount":30000,"memo":[246]}],"fee":10000}"#).unwrap();
assert_eq!(tx_plan_json, expected);
}
@ -250,7 +253,7 @@ fn test_example5() {
println!("{}", serde_json::to_string(&tx_plan).unwrap());
let tx_plan_json = serde_json::to_value(&tx_plan).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Sapling":{"id_note":2,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":10000},{"id_order":4294967295,"destination":{"Sapling":"9fae6f28c245e095abf8c6730098e110bb67ae3e73302406b2b9c6d6b672ca9e64e14ef0560062a91dd429"},"amount":30000}],"fee":10000}"#).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Sapling":{"id_note":2,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":10000,"memo":[246]},{"id_order":4294967295,"destination":{"Sapling":"9fae6f28c245e095abf8c6730098e110bb67ae3e73302406b2b9c6d6b672ca9e64e14ef0560062a91dd429"},"amount":30000,"memo":[246]}],"fee":10000}"#).unwrap();
assert_eq!(tx_plan_json, expected);
}
@ -269,7 +272,7 @@ fn test_example5b() {
println!("{}", serde_json::to_string(&tx_plan).unwrap());
let tx_plan_json = serde_json::to_value(&tx_plan).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Orchard":{"id_note":3,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Orchard":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":10000},{"id_order":4294967295,"destination":{"Orchard":"2b6dca785c846b3752d13150e1c8f197ba9c8ead0a8bee1b3a52df0ad866362941e32d1b69d438b257cf82"},"amount":30000}],"fee":10000}"#).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Orchard":{"id_note":3,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Orchard":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":10000,"memo":[246]},{"id_order":4294967295,"destination":{"Orchard":"2b6dca785c846b3752d13150e1c8f197ba9c8ead0a8bee1b3a52df0ad866362941e32d1b69d438b257cf82"},"amount":30000,"memo":[246]}],"fee":10000}"#).unwrap();
assert_eq!(tx_plan_json, expected);
}
/// A simple z2t sapling
@ -288,7 +291,7 @@ fn test_example6() {
println!("{}", serde_json::to_string(&tx_plan).unwrap());
let tx_plan_json = serde_json::to_value(&tx_plan).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Sapling":{"id_note":2,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000},{"id_order":4294967295,"destination":{"Sapling":"9fae6f28c245e095abf8c6730098e110bb67ae3e73302406b2b9c6d6b672ca9e64e14ef0560062a91dd429"},"amount":30000}],"fee":10000}"#).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Sapling":{"id_note":2,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000,"memo":[246]},{"id_order":4294967295,"destination":{"Sapling":"9fae6f28c245e095abf8c6730098e110bb67ae3e73302406b2b9c6d6b672ca9e64e14ef0560062a91dd429"},"amount":30000,"memo":[246]}],"fee":10000}"#).unwrap();
assert_eq!(tx_plan_json, expected);
}
@ -309,7 +312,7 @@ fn test_example7() {
println!("{}", serde_json::to_string(&tx_plan).unwrap());
let tx_plan_json = serde_json::to_value(&tx_plan).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Orchard":{"id_note":3,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000},{"id_order":4294967295,"destination":{"Orchard":"2b6dca785c846b3752d13150e1c8f197ba9c8ead0a8bee1b3a52df0ad866362941e32d1b69d438b257cf82"},"amount":30000}],"fee":10000}"#).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Orchard":{"id_note":3,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","rho":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Transparent":"0000000000000000000000000000000000000000"},"amount":10000,"memo":[246]},{"id_order":4294967295,"destination":{"Orchard":"2b6dca785c846b3752d13150e1c8f197ba9c8ead0a8bee1b3a52df0ad866362941e32d1b69d438b257cf82"},"amount":30000,"memo":[246]}],"fee":10000}"#).unwrap();
assert_eq!(tx_plan_json, expected);
}
@ -330,7 +333,7 @@ fn test_example8() {
println!("{}", serde_json::to_string(&tx_plan).unwrap());
let tx_plan_json = serde_json::to_value(&tx_plan).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":1}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":10000},{"id_order":4294967295,"destination":{"Transparent":"c7b7b3d299bd173ea278d792b1bd5fbdd11afe34"},"amount":30000}],"fee":10000}"#).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Transparent":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","index":1}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Sapling":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":10000,"memo":[246]},{"id_order":4294967295,"destination":{"Transparent":"c7b7b3d299bd173ea278d792b1bd5fbdd11afe34"},"amount":30000,"memo":[246]}],"fee":10000}"#).unwrap();
assert_eq!(tx_plan_json, expected);
}
@ -348,6 +351,6 @@ fn test_example9() {
println!("{}", serde_json::to_string(&tx_plan).unwrap());
let tx_plan_json = serde_json::to_value(&tx_plan).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Sapling":{"id_note":2,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Orchard":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":10000},{"id_order":4294967295,"destination":{"Sapling":"9fae6f28c245e095abf8c6730098e110bb67ae3e73302406b2b9c6d6b672ca9e64e14ef0560062a91dd429"},"amount":30000}],"fee":10000}"#).unwrap();
let expected: Value = serde_json::from_str(r#"{"spends":[{"source":{"Sapling":{"id_note":2,"diversifier":"0000000000000000000000","rseed":"0000000000000000000000000000000000000000000000000000000000000000","witness":""}},"amount":50000}],"outputs":[{"id_order":1,"destination":{"Orchard":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"amount":10000,"memo":[246]},{"id_order":4294967295,"destination":{"Sapling":"9fae6f28c245e095abf8c6730098e110bb67ae3e73302406b2b9c6d6b672ca9e64e14ef0560062a91dd429"},"amount":30000,"memo":[246]}],"fee":10000}"#).unwrap();
assert_eq!(tx_plan_json, expected);
}

View File

@ -1,4 +1,5 @@
use std::ops::{Add, Sub};
use anyhow::anyhow;
use zcash_primitives::memo::MemoBytes;
use serde::Serialize;
use serde_with::serde_as;
@ -52,6 +53,7 @@ pub enum Pool {
pub struct Order {
pub id: u32,
pub destinations: [Option<Destination>; 3],
pub priority: PoolPriority,
pub amount: u64,
#[serde(with = "MemoBytesProxy")] pub memo: MemoBytes,
pub is_fee: bool,
@ -83,6 +85,7 @@ impl Default for Order {
Order {
id: 0,
destinations: [None; 3],
priority: PoolPriority::OST,
amount: 0,
memo: MemoBytes::empty(),
is_fee: false,
@ -206,3 +209,41 @@ impl Destination {
}
}
}
#[derive(Clone, Copy, Serialize, Debug)]
pub enum PoolPriority {
TSO = 1,
OST = 2,
TOS = 3,
SOT = 4,
OTS = 5,
STO = 6,
}
impl PoolPriority {
const VALUES: [PoolPriority; 6] = [ PoolPriority::TSO, PoolPriority::OST, PoolPriority::TOS, PoolPriority::SOT, PoolPriority::OTS, PoolPriority::STO];
pub fn to_pool_precedence(&self) -> &'static PoolPrecedence {
match self {
PoolPriority::TSO => &[ Pool:: Transparent, Pool::Sapling, Pool::Orchard ],
PoolPriority::OST => &[ Pool::Orchard, Pool::Sapling, Pool:: Transparent ],
PoolPriority::TOS => &[ Pool:: Transparent, Pool::Orchard, Pool::Sapling ],
PoolPriority::SOT => &[ Pool::Sapling, Pool::Orchard, Pool:: Transparent ],
PoolPriority::OTS => &[ Pool::Orchard, Pool:: Transparent, Pool::Sapling ],
PoolPriority::STO => &[ Pool::Sapling, Pool:: Transparent, Pool::Orchard ],
}
}
}
impl TryFrom<PoolPrecedence> for PoolPriority {
type Error = anyhow::Error;
fn try_from(value: PoolPrecedence) -> Result<Self, Self::Error> {
let p: [Pool; 3] = value.try_into().unwrap();
for pp in PoolPriority::VALUES {
if p == *pp.to_pool_precedence() {
return Ok(pp)
}
}
Err(anyhow!("Pool preference invalid"))
}
}