Skip to content

Commit 461b8fa

Browse files
committed
Handle fork in the wallet
1 parent 3e99975 commit 461b8fa

File tree

5 files changed

+328
-145
lines changed

5 files changed

+328
-145
lines changed

wallet/src/account/mod.rs

+213-91
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ use common::address::pubkeyhash::PublicKeyHash;
2222
use common::chain::block::timestamp::BlockTimestamp;
2323
use common::chain::classic_multisig::ClassicMultisigChallenge;
2424
use common::chain::htlc::HashedTimelockContract;
25-
use common::chain::{AccountCommand, AccountOutPoint, AccountSpending, OrderId, RpcOrderInfo};
25+
use common::chain::{
26+
AccountCommand, AccountOutPoint, AccountSpending, OrderAccountCommand, OrderId, RpcOrderInfo,
27+
};
2628
use common::primitives::id::WithId;
2729
use common::primitives::{Idable, H256};
2830
use common::size_estimation::{
@@ -981,14 +983,35 @@ impl<K: AccountKeyChains> Account<K> {
981983
outputs.push(TxOutput::Transfer(output_value, output_destination));
982984
}
983985

984-
let nonce = order_info
985-
.nonce
986-
.map_or(Some(AccountNonce::new(0)), |n| n.increment())
987-
.ok_or(WalletError::OrderNonceOverflow(order_id))?;
988-
let request = SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
989-
TxInput::AccountCommand(nonce, AccountCommand::ConcludeOrder(order_id)),
990-
order_info.conclude_key.clone(),
991-
)]);
986+
let version = self
987+
.chain_config
988+
.chainstate_upgrades()
989+
.version_at_height(self.account_info.best_block_height())
990+
.1
991+
.orders_version();
992+
993+
let request = match version {
994+
common::chain::OrdersVersion::V0 => {
995+
let nonce = order_info
996+
.nonce
997+
.map_or(Some(AccountNonce::new(0)), |n| n.increment())
998+
.ok_or(WalletError::OrderNonceOverflow(order_id))?;
999+
SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1000+
TxInput::AccountCommand(nonce, AccountCommand::ConcludeOrder(order_id)),
1001+
order_info.conclude_key.clone(),
1002+
)])
1003+
}
1004+
common::chain::OrdersVersion::V1 => {
1005+
SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1006+
TxInput::OrderAccountCommand(OrderAccountCommand::ConcludeOrder {
1007+
order_id,
1008+
filled_amount,
1009+
remaining_give_amount: order_info.give_balance,
1010+
}),
1011+
order_info.conclude_key.clone(),
1012+
)])
1013+
}
1014+
};
9921015

9931016
self.select_inputs_for_send_request(
9941017
request,
@@ -1019,33 +1042,66 @@ impl<K: AccountKeyChains> Account<K> {
10191042
self.get_new_address(db_tx, KeyPurpose::ReceiveFunds)?.1.into_object()
10201043
};
10211044

1022-
let filled_amount = orders_accounting::calculate_filled_amount(
1023-
order_info.ask_balance,
1024-
order_info.give_balance,
1025-
fill_amount_in_ask_currency,
1026-
)
1027-
.ok_or(WalletError::CalculateOrderFilledAmountFailed(order_id))?;
1028-
let output_value = match order_info.initially_given {
1029-
RpcOutputValue::Coin { .. } => OutputValue::Coin(filled_amount),
1030-
RpcOutputValue::Token { id, .. } => OutputValue::TokenV1(id, filled_amount),
1031-
};
1032-
let outputs = vec![TxOutput::Transfer(output_value, output_destination.clone())];
1033-
1034-
let nonce = order_info
1035-
.nonce
1036-
.map_or(Some(AccountNonce::new(0)), |n| n.increment())
1037-
.ok_or(WalletError::OrderNonceOverflow(order_id))?;
1038-
let request = SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1039-
TxInput::AccountCommand(
1040-
nonce,
1041-
AccountCommand::FillOrder(
1042-
order_id,
1045+
let version = self
1046+
.chain_config
1047+
.chainstate_upgrades()
1048+
.version_at_height(self.account_info.best_block_height())
1049+
.1
1050+
.orders_version();
1051+
1052+
let request = match version {
1053+
common::chain::OrdersVersion::V0 => {
1054+
let filled_amount = orders_accounting::calculate_filled_amount(
1055+
order_info.ask_balance,
1056+
order_info.give_balance,
10431057
fill_amount_in_ask_currency,
1044-
output_destination.clone(),
1045-
),
1046-
),
1047-
output_destination,
1048-
)]);
1058+
)
1059+
.ok_or(WalletError::CalculateOrderFilledAmountFailed(order_id))?;
1060+
let output_value = match order_info.initially_given {
1061+
RpcOutputValue::Coin { .. } => OutputValue::Coin(filled_amount),
1062+
RpcOutputValue::Token { id, .. } => OutputValue::TokenV1(id, filled_amount),
1063+
};
1064+
let outputs = vec![TxOutput::Transfer(output_value, output_destination.clone())];
1065+
1066+
let nonce = order_info
1067+
.nonce
1068+
.map_or(Some(AccountNonce::new(0)), |n| n.increment())
1069+
.ok_or(WalletError::OrderNonceOverflow(order_id))?;
1070+
SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1071+
TxInput::AccountCommand(
1072+
nonce,
1073+
AccountCommand::FillOrder(
1074+
order_id,
1075+
fill_amount_in_ask_currency,
1076+
output_destination.clone(),
1077+
),
1078+
),
1079+
output_destination,
1080+
)])
1081+
}
1082+
common::chain::OrdersVersion::V1 => {
1083+
let filled_amount = orders_accounting::calculate_filled_amount(
1084+
order_info.initially_asked.amount(),
1085+
order_info.initially_given.amount(),
1086+
fill_amount_in_ask_currency,
1087+
)
1088+
.ok_or(WalletError::CalculateOrderFilledAmountFailed(order_id))?;
1089+
let output_value = match order_info.initially_given {
1090+
RpcOutputValue::Coin { .. } => OutputValue::Coin(filled_amount),
1091+
RpcOutputValue::Token { id, .. } => OutputValue::TokenV1(id, filled_amount),
1092+
};
1093+
let outputs = vec![TxOutput::Transfer(output_value, output_destination.clone())];
1094+
1095+
SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1096+
TxInput::OrderAccountCommand(OrderAccountCommand::FillOrder(
1097+
order_id,
1098+
fill_amount_in_ask_currency,
1099+
output_destination.clone(),
1100+
)),
1101+
output_destination,
1102+
)])
1103+
}
1104+
};
10491105

10501106
self.select_inputs_for_send_request(
10511107
request,
@@ -1470,6 +1526,24 @@ impl<K: AccountKeyChains> Account<K> {
14701526
}
14711527
}
14721528

1529+
pub fn find_order_account_command_destination(
1530+
&self,
1531+
cmd: &OrderAccountCommand,
1532+
) -> WalletResult<Destination> {
1533+
match cmd {
1534+
OrderAccountCommand::FillOrder(_, _, destination) => Ok(destination.clone()),
1535+
OrderAccountCommand::ConcludeOrder {
1536+
order_id,
1537+
filled_amount: _,
1538+
remaining_give_amount: _,
1539+
} => self
1540+
.output_cache
1541+
.order_data(order_id)
1542+
.map(|data| data.conclude_key.clone())
1543+
.ok_or(WalletError::UnknownOrderId(*order_id)),
1544+
}
1545+
}
1546+
14731547
pub fn find_unspent_utxo_and_destination(
14741548
&self,
14751549
outpoint: &UtxoOutPoint,
@@ -1902,10 +1976,16 @@ impl<K: AccountKeyChains> Account<K> {
19021976
self.find_delegation(delegation_id).is_ok()
19031977
}
19041978
},
1905-
TxInput::OrderAccountCommand(..) => {
1906-
// TODO: support OrdersVersion::V1
1907-
unimplemented!()
1908-
}
1979+
TxInput::OrderAccountCommand(cmd) => match cmd {
1980+
OrderAccountCommand::FillOrder(order_id, _, dest) => {
1981+
self.find_order(order_id).is_ok() || self.is_destination_mine_or_watched(dest)
1982+
}
1983+
OrderAccountCommand::ConcludeOrder {
1984+
order_id,
1985+
filled_amount: _,
1986+
remaining_give_amount: _,
1987+
} => self.find_order(order_id).is_ok(),
1988+
},
19091989
TxInput::AccountCommand(_, op) => match op {
19101990
AccountCommand::MintTokens(token_id, _)
19111991
| AccountCommand::UnmintTokens(token_id)
@@ -2408,9 +2488,6 @@ fn group_preselected_inputs(
24082488
update_preselected_inputs(Currency::Coin, *amount, *fee, Amount::ZERO)?;
24092489
}
24102490
},
2411-
TxInput::OrderAccountCommand(..) => {
2412-
// TODO: support OrdersVersion::V1
2413-
}
24142491
TxInput::AccountCommand(_, op) => match op {
24152492
AccountCommand::MintTokens(token_id, amount) => {
24162493
update_preselected_inputs(
@@ -2460,59 +2537,43 @@ fn group_preselected_inputs(
24602537
)?;
24612538
}
24622539
AccountCommand::ConcludeOrder(order_id) => {
2463-
let order_info = order_info
2464-
.as_ref()
2465-
.and_then(|info| info.get(order_id))
2466-
.ok_or(WalletError::OrderInfoMissing(*order_id))?;
2467-
2468-
let given_currency =
2469-
Currency::from_rpc_output_value(&order_info.initially_given);
2470-
update_preselected_inputs(
2471-
given_currency,
2472-
order_info.give_balance,
2473-
Amount::ZERO,
2474-
Amount::ZERO,
2540+
handle_conclude_order(
2541+
*order_id,
2542+
order_info.as_ref(),
2543+
*fee,
2544+
&mut update_preselected_inputs,
24752545
)?;
2476-
2477-
let asked_currency =
2478-
Currency::from_rpc_output_value(&order_info.initially_asked);
2479-
let filled_amount = (order_info.initially_asked.amount()
2480-
- order_info.ask_balance)
2481-
.ok_or(WalletError::OutputAmountOverflow)?;
2482-
update_preselected_inputs(
2483-
asked_currency,
2484-
filled_amount,
2485-
Amount::ZERO,
2486-
Amount::ZERO,
2487-
)?;
2488-
2489-
// add fee
2490-
update_preselected_inputs(Currency::Coin, Amount::ZERO, *fee, Amount::ZERO)?;
24912546
}
24922547
AccountCommand::FillOrder(order_id, fill_amount_in_ask_currency, _) => {
2493-
let order_info = order_info
2494-
.as_ref()
2495-
.and_then(|info| info.get(order_id))
2496-
.ok_or(WalletError::OrderInfoMissing(*order_id))?;
2497-
2498-
let filled_amount = orders_accounting::calculate_filled_amount(
2499-
order_info.ask_balance,
2500-
order_info.give_balance,
2501-
*fill_amount_in_ask_currency,
2502-
)
2503-
.ok_or(WalletError::CalculateOrderFilledAmountFailed(*order_id))?;
2504-
2505-
let given_currency =
2506-
Currency::from_rpc_output_value(&order_info.initially_given);
2507-
update_preselected_inputs(given_currency, filled_amount, *fee, Amount::ZERO)?;
2508-
2509-
let asked_currency =
2510-
Currency::from_rpc_output_value(&order_info.initially_asked);
2511-
update_preselected_inputs(
2512-
asked_currency,
2513-
Amount::ZERO,
2514-
Amount::ZERO,
2548+
handle_fill_order_op(
2549+
*order_id,
25152550
*fill_amount_in_ask_currency,
2551+
order_info.as_ref(),
2552+
*fee,
2553+
&mut update_preselected_inputs,
2554+
)?;
2555+
}
2556+
},
2557+
TxInput::OrderAccountCommand(cmd) => match cmd {
2558+
OrderAccountCommand::FillOrder(id, amount, _) => {
2559+
handle_fill_order_op(
2560+
*id,
2561+
*amount,
2562+
order_info.as_ref(),
2563+
*fee,
2564+
&mut update_preselected_inputs,
2565+
)?;
2566+
}
2567+
OrderAccountCommand::ConcludeOrder {
2568+
order_id,
2569+
filled_amount: _,
2570+
remaining_give_amount: _,
2571+
} => {
2572+
handle_conclude_order(
2573+
*order_id,
2574+
order_info.as_ref(),
2575+
*fee,
2576+
&mut update_preselected_inputs,
25162577
)?;
25172578
}
25182579
},
@@ -2521,6 +2582,67 @@ fn group_preselected_inputs(
25212582
Ok(preselected_inputs)
25222583
}
25232584

2585+
fn handle_fill_order_op(
2586+
order_id: OrderId,
2587+
fill_amount_in_ask_currency: Amount,
2588+
order_info: Option<&BTreeMap<OrderId, &RpcOrderInfo>>,
2589+
fee: Amount,
2590+
update_preselected_inputs: &mut impl FnMut(Currency, Amount, Amount, Amount) -> WalletResult<()>,
2591+
) -> WalletResult<()> {
2592+
let order_info = order_info
2593+
.as_ref()
2594+
.and_then(|info| info.get(&order_id))
2595+
.ok_or(WalletError::OrderInfoMissing(order_id))?;
2596+
2597+
let filled_amount = orders_accounting::calculate_filled_amount(
2598+
order_info.ask_balance,
2599+
order_info.give_balance,
2600+
fill_amount_in_ask_currency,
2601+
)
2602+
.ok_or(WalletError::CalculateOrderFilledAmountFailed(order_id))?;
2603+
2604+
let given_currency = Currency::from_rpc_output_value(&order_info.initially_given);
2605+
update_preselected_inputs(given_currency, filled_amount, fee, Amount::ZERO)?;
2606+
2607+
let asked_currency = Currency::from_rpc_output_value(&order_info.initially_asked);
2608+
update_preselected_inputs(
2609+
asked_currency,
2610+
Amount::ZERO,
2611+
Amount::ZERO,
2612+
fill_amount_in_ask_currency,
2613+
)?;
2614+
Ok(())
2615+
}
2616+
2617+
fn handle_conclude_order(
2618+
order_id: OrderId,
2619+
order_info: Option<&BTreeMap<OrderId, &RpcOrderInfo>>,
2620+
fee: Amount,
2621+
update_preselected_inputs: &mut impl FnMut(Currency, Amount, Amount, Amount) -> WalletResult<()>,
2622+
) -> WalletResult<()> {
2623+
let order_info = order_info
2624+
.as_ref()
2625+
.and_then(|info| info.get(&order_id))
2626+
.ok_or(WalletError::OrderInfoMissing(order_id))?;
2627+
2628+
let given_currency = Currency::from_rpc_output_value(&order_info.initially_given);
2629+
update_preselected_inputs(
2630+
given_currency,
2631+
order_info.give_balance,
2632+
Amount::ZERO,
2633+
Amount::ZERO,
2634+
)?;
2635+
2636+
let asked_currency = Currency::from_rpc_output_value(&order_info.initially_asked);
2637+
let filled_amount = (order_info.initially_asked.amount() - order_info.ask_balance)
2638+
.ok_or(WalletError::OutputAmountOverflow)?;
2639+
update_preselected_inputs(asked_currency, filled_amount, Amount::ZERO, Amount::ZERO)?;
2640+
2641+
// add fee
2642+
update_preselected_inputs(Currency::Coin, Amount::ZERO, fee, Amount::ZERO)?;
2643+
Ok(())
2644+
}
2645+
25242646
/// Calculate the amount of fee that needs to be paid to add a change output
25252647
/// Returns the Amounts for Coin output and Token output
25262648
fn coin_and_token_output_change_fees(

0 commit comments

Comments
 (0)