Skip to content

Commit 6e4bf6f

Browse files
committed
Handle fork in the wallet
1 parent b6d9b5d commit 6e4bf6f

File tree

2 files changed

+243
-109
lines changed

2 files changed

+243
-109
lines changed

wallet/src/account/mod.rs

+209-95
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ use common::chain::block::timestamp::BlockTimestamp;
2323
use common::chain::classic_multisig::ClassicMultisigChallenge;
2424
use common::chain::htlc::HashedTimelockContract;
2525
use common::chain::partially_signed_transaction::PartiallySignedTransaction;
26-
use common::chain::{AccountCommand, AccountOutPoint, AccountSpending, OrderId, RpcOrderInfo};
26+
use common::chain::{
27+
AccountCommand, AccountOutPoint, AccountSpending, OrderAccountCommand, OrderId, RpcOrderInfo,
28+
};
2729
use common::primitives::id::WithId;
2830
use common::primitives::{Idable, H256};
2931
use common::size_estimation::{
@@ -1084,14 +1086,35 @@ impl Account {
10841086
outputs.push(TxOutput::Transfer(output_value, output_destination));
10851087
}
10861088

1087-
let nonce = order_info
1088-
.nonce
1089-
.map_or(Some(AccountNonce::new(0)), |n| n.increment())
1090-
.ok_or(WalletError::OrderNonceOverflow(order_id))?;
1091-
let request = SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1092-
TxInput::AccountCommand(nonce, AccountCommand::ConcludeOrder(order_id)),
1093-
order_info.conclude_key.clone(),
1094-
)]);
1089+
let version = self
1090+
.chain_config
1091+
.chainstate_upgrades()
1092+
.version_at_height(self.account_info.best_block_height())
1093+
.1
1094+
.orders_version();
1095+
1096+
let request = match version {
1097+
common::chain::OrdersVersion::V0 => {
1098+
let nonce = order_info
1099+
.nonce
1100+
.map_or(Some(AccountNonce::new(0)), |n| n.increment())
1101+
.ok_or(WalletError::OrderNonceOverflow(order_id))?;
1102+
SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1103+
TxInput::AccountCommand(nonce, AccountCommand::ConcludeOrder(order_id)),
1104+
order_info.conclude_key.clone(),
1105+
)])
1106+
}
1107+
common::chain::OrdersVersion::V1 => {
1108+
SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1109+
TxInput::OrderAccountCommand(OrderAccountCommand::ConcludeOrder {
1110+
order_id,
1111+
filled_amount,
1112+
remaining_give_amount: order_info.give_balance,
1113+
}),
1114+
order_info.conclude_key.clone(),
1115+
)])
1116+
}
1117+
};
10951118

10961119
self.select_inputs_for_send_request(
10971120
request,
@@ -1122,33 +1145,66 @@ impl Account {
11221145
self.get_new_address(db_tx, KeyPurpose::ReceiveFunds)?.1.into_object()
11231146
};
11241147

1125-
let filled_amount = orders_accounting::calculate_filled_amount(
1126-
order_info.ask_balance,
1127-
order_info.give_balance,
1128-
fill_amount_in_ask_currency,
1129-
)
1130-
.ok_or(WalletError::CalculateOrderFilledAmountFailed(order_id))?;
1131-
let output_value = match order_info.initially_given {
1132-
RpcOutputValue::Coin { .. } => OutputValue::Coin(filled_amount),
1133-
RpcOutputValue::Token { id, .. } => OutputValue::TokenV1(id, filled_amount),
1134-
};
1135-
let outputs = vec![TxOutput::Transfer(output_value, output_destination.clone())];
1136-
1137-
let nonce = order_info
1138-
.nonce
1139-
.map_or(Some(AccountNonce::new(0)), |n| n.increment())
1140-
.ok_or(WalletError::OrderNonceOverflow(order_id))?;
1141-
let request = SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1142-
TxInput::AccountCommand(
1143-
nonce,
1144-
AccountCommand::FillOrder(
1145-
order_id,
1148+
let version = self
1149+
.chain_config
1150+
.chainstate_upgrades()
1151+
.version_at_height(self.account_info.best_block_height())
1152+
.1
1153+
.orders_version();
1154+
1155+
let request = match version {
1156+
common::chain::OrdersVersion::V0 => {
1157+
let filled_amount = orders_accounting::calculate_filled_amount(
1158+
order_info.ask_balance,
1159+
order_info.give_balance,
11461160
fill_amount_in_ask_currency,
1147-
output_destination.clone(),
1148-
),
1149-
),
1150-
output_destination,
1151-
)]);
1161+
)
1162+
.ok_or(WalletError::CalculateOrderFilledAmountFailed(order_id))?;
1163+
let output_value = match order_info.initially_given {
1164+
RpcOutputValue::Coin { .. } => OutputValue::Coin(filled_amount),
1165+
RpcOutputValue::Token { id, .. } => OutputValue::TokenV1(id, filled_amount),
1166+
};
1167+
let outputs = vec![TxOutput::Transfer(output_value, output_destination.clone())];
1168+
1169+
let nonce = order_info
1170+
.nonce
1171+
.map_or(Some(AccountNonce::new(0)), |n| n.increment())
1172+
.ok_or(WalletError::OrderNonceOverflow(order_id))?;
1173+
SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1174+
TxInput::AccountCommand(
1175+
nonce,
1176+
AccountCommand::FillOrder(
1177+
order_id,
1178+
fill_amount_in_ask_currency,
1179+
output_destination.clone(),
1180+
),
1181+
),
1182+
output_destination,
1183+
)])
1184+
}
1185+
common::chain::OrdersVersion::V1 => {
1186+
let filled_amount = orders_accounting::calculate_filled_amount(
1187+
order_info.initially_asked.amount(),
1188+
order_info.initially_given.amount(),
1189+
fill_amount_in_ask_currency,
1190+
)
1191+
.ok_or(WalletError::CalculateOrderFilledAmountFailed(order_id))?;
1192+
let output_value = match order_info.initially_given {
1193+
RpcOutputValue::Coin { .. } => OutputValue::Coin(filled_amount),
1194+
RpcOutputValue::Token { id, .. } => OutputValue::TokenV1(id, filled_amount),
1195+
};
1196+
let outputs = vec![TxOutput::Transfer(output_value, output_destination.clone())];
1197+
1198+
SendRequest::new().with_outputs(outputs).with_inputs_and_destinations([(
1199+
TxInput::OrderAccountCommand(OrderAccountCommand::FillOrder(
1200+
order_id,
1201+
fill_amount_in_ask_currency,
1202+
output_destination.clone(),
1203+
)),
1204+
output_destination,
1205+
)])
1206+
}
1207+
};
11521208

11531209
self.select_inputs_for_send_request(
11541210
request,
@@ -1498,10 +1554,20 @@ impl Account {
14981554
.ok_or(WalletError::DelegationNotFound(*delegation_id)),
14991555
}
15001556
}
1501-
TxInput::OrderAccountCommand(..) => {
1502-
// TODO: support OrdersVersion::V1
1503-
unimplemented!()
1504-
}
1557+
TxInput::OrderAccountCommand(cmd) => match cmd {
1558+
OrderAccountCommand::FillOrder(_, _, destination) => {
1559+
Ok((None, Some(destination.clone())))
1560+
}
1561+
OrderAccountCommand::ConcludeOrder {
1562+
order_id,
1563+
filled_amount: _,
1564+
remaining_give_amount: _,
1565+
} => self
1566+
.output_cache
1567+
.order_data(order_id)
1568+
.map(|data| (None, Some(data.conclude_key.clone())))
1569+
.ok_or(WalletError::UnknownOrderId(*order_id)),
1570+
},
15051571
TxInput::AccountCommand(_, cmd) => {
15061572
match cmd {
15071573
// find authority of the token
@@ -2008,10 +2074,16 @@ impl Account {
20082074
self.find_delegation(delegation_id).is_ok()
20092075
}
20102076
},
2011-
TxInput::OrderAccountCommand(..) => {
2012-
// TODO: support OrdersVersion::V1
2013-
unimplemented!()
2014-
}
2077+
TxInput::OrderAccountCommand(cmd) => match cmd {
2078+
OrderAccountCommand::FillOrder(order_id, _, dest) => {
2079+
self.find_order(order_id).is_ok() || self.is_destination_mine_or_watched(dest)
2080+
}
2081+
OrderAccountCommand::ConcludeOrder {
2082+
order_id,
2083+
filled_amount: _,
2084+
remaining_give_amount: _,
2085+
} => self.find_order(order_id).is_ok(),
2086+
},
20152087
TxInput::AccountCommand(_, op) => match op {
20162088
AccountCommand::MintTokens(token_id, _)
20172089
| AccountCommand::UnmintTokens(token_id)
@@ -2424,9 +2496,6 @@ fn group_preselected_inputs(
24242496
update_preselected_inputs(Currency::Coin, *amount, *fee, Amount::ZERO)?;
24252497
}
24262498
},
2427-
TxInput::OrderAccountCommand(..) => {
2428-
// TODO: support OrdersVersion::V1
2429-
}
24302499
TxInput::AccountCommand(_, op) => match op {
24312500
AccountCommand::MintTokens(token_id, amount) => {
24322501
update_preselected_inputs(
@@ -2476,59 +2545,43 @@ fn group_preselected_inputs(
24762545
)?;
24772546
}
24782547
AccountCommand::ConcludeOrder(order_id) => {
2479-
let order_info = order_info
2480-
.as_ref()
2481-
.and_then(|info| info.get(order_id))
2482-
.ok_or(WalletError::OrderInfoMissing(*order_id))?;
2483-
2484-
let given_currency =
2485-
Currency::from_rpc_output_value(&order_info.initially_given);
2486-
update_preselected_inputs(
2487-
given_currency,
2488-
order_info.give_balance,
2489-
Amount::ZERO,
2490-
Amount::ZERO,
2548+
handle_conclude_order(
2549+
*order_id,
2550+
order_info.as_ref(),
2551+
*fee,
2552+
&mut update_preselected_inputs,
24912553
)?;
2492-
2493-
let asked_currency =
2494-
Currency::from_rpc_output_value(&order_info.initially_asked);
2495-
let filled_amount = (order_info.initially_asked.amount()
2496-
- order_info.ask_balance)
2497-
.ok_or(WalletError::OutputAmountOverflow)?;
2498-
update_preselected_inputs(
2499-
asked_currency,
2500-
filled_amount,
2501-
Amount::ZERO,
2502-
Amount::ZERO,
2503-
)?;
2504-
2505-
// add fee
2506-
update_preselected_inputs(Currency::Coin, Amount::ZERO, *fee, Amount::ZERO)?;
25072554
}
25082555
AccountCommand::FillOrder(order_id, fill_amount_in_ask_currency, _) => {
2509-
let order_info = order_info
2510-
.as_ref()
2511-
.and_then(|info| info.get(order_id))
2512-
.ok_or(WalletError::OrderInfoMissing(*order_id))?;
2513-
2514-
let filled_amount = orders_accounting::calculate_filled_amount(
2515-
order_info.ask_balance,
2516-
order_info.give_balance,
2517-
*fill_amount_in_ask_currency,
2518-
)
2519-
.ok_or(WalletError::CalculateOrderFilledAmountFailed(*order_id))?;
2520-
2521-
let given_currency =
2522-
Currency::from_rpc_output_value(&order_info.initially_given);
2523-
update_preselected_inputs(given_currency, filled_amount, *fee, Amount::ZERO)?;
2524-
2525-
let asked_currency =
2526-
Currency::from_rpc_output_value(&order_info.initially_asked);
2527-
update_preselected_inputs(
2528-
asked_currency,
2529-
Amount::ZERO,
2530-
Amount::ZERO,
2556+
handle_fill_order_op(
2557+
*order_id,
25312558
*fill_amount_in_ask_currency,
2559+
order_info.as_ref(),
2560+
*fee,
2561+
&mut update_preselected_inputs,
2562+
)?;
2563+
}
2564+
},
2565+
TxInput::OrderAccountCommand(cmd) => match cmd {
2566+
OrderAccountCommand::FillOrder(id, amount, _) => {
2567+
handle_fill_order_op(
2568+
*id,
2569+
*amount,
2570+
order_info.as_ref(),
2571+
*fee,
2572+
&mut update_preselected_inputs,
2573+
)?;
2574+
}
2575+
OrderAccountCommand::ConcludeOrder {
2576+
order_id,
2577+
filled_amount: _,
2578+
remaining_give_amount: _,
2579+
} => {
2580+
handle_conclude_order(
2581+
*order_id,
2582+
order_info.as_ref(),
2583+
*fee,
2584+
&mut update_preselected_inputs,
25322585
)?;
25332586
}
25342587
},
@@ -2537,6 +2590,67 @@ fn group_preselected_inputs(
25372590
Ok(preselected_inputs)
25382591
}
25392592

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

0 commit comments

Comments
 (0)