Skip to content

Commit 3528e2c

Browse files
committed
Fix comments
1 parent 7371002 commit 3528e2c

File tree

6 files changed

+238
-70
lines changed

6 files changed

+238
-70
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wallet/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ thiserror.workspace = true
3737
zeroize.workspace = true
3838

3939
[dev-dependencies]
40+
chainstate-test-framework = { path = "../chainstate/test-framework" }
4041
test-utils = { path = "../test-utils" }
42+
4143
serial_test = "3.2"
4244

4345
rstest.workspace = true

wallet/src/account/mod.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -2020,9 +2020,9 @@ impl<K: AccountKeyChains> Account<K> {
20202020
let conflicting_txs =
20212021
self.output_cache.update_conflicting_txs(confirmed_tx, block.get_id().into())?;
20222022

2023-
for tx_id in conflicting_txs {
2024-
let id = AccountWalletCreatedTxId::new(acc_id.clone(), tx_id);
2025-
db_tx.del_user_transaction(&id)?;
2023+
for (tx_id, tx) in conflicting_txs {
2024+
db_tx.set_transaction(&AccountWalletTxId::new(acc_id.clone(), tx.id()), &tx)?;
2025+
db_tx.del_user_transaction(&AccountWalletCreatedTxId::new(acc_id.clone(), tx_id))?;
20262026
}
20272027

20282028
Ok(())
@@ -2182,9 +2182,9 @@ impl<K: AccountKeyChains> Account<K> {
21822182
let abandoned_txs = self.output_cache.abandon_transaction(tx_id)?;
21832183
let acc_id = self.get_account_id();
21842184

2185-
for tx_id in abandoned_txs {
2186-
let id = AccountWalletCreatedTxId::new(acc_id.clone(), tx_id);
2187-
db_tx.del_user_transaction(&id)?;
2185+
for (tx_id, tx) in abandoned_txs {
2186+
db_tx.set_transaction(&AccountWalletTxId::new(acc_id.clone(), tx.id()), &tx)?;
2187+
db_tx.del_user_transaction(&AccountWalletCreatedTxId::new(acc_id.clone(), tx_id))?;
21882188
}
21892189

21902190
Ok(())

wallet/src/account/output_cache/mod.rs

+86-62
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
use std::{
1717
cmp::Reverse,
18-
collections::{btree_map::Entry, BTreeMap, BTreeSet},
18+
collections::{btree_map::Entry, BTreeMap, BTreeSet, VecDeque},
1919
ops::Add,
2020
};
2121

@@ -749,7 +749,7 @@ impl OutputCache {
749749
&mut self,
750750
confirmed_tx: &Transaction,
751751
block_id: Id<GenBlock>,
752-
) -> WalletResult<Vec<Id<Transaction>>> {
752+
) -> WalletResult<Vec<(Id<Transaction>, WalletTx)>> {
753753
struct ConflictCheck {
754754
frozen_token_id: Option<TokenId>,
755755
confirmed_account_nonce: Option<(AccountType, AccountNonce)>,
@@ -800,58 +800,67 @@ impl OutputCache {
800800
for unconfirmed in self.unconfirmed_descendants.keys() {
801801
let unconfirmed_tx = self.txs.get(unconfirmed).expect("must be present");
802802

803-
if let WalletTx::Tx(tx) = unconfirmed_tx {
804-
if let Some(frozen_token_id) = conflict_check.frozen_token_id {
805-
if self.violates_frozen_token(unconfirmed_tx, &frozen_token_id) {
806-
conflicting_txs.insert(tx.get_transaction().get_id());
807-
continue;
803+
match unconfirmed_tx {
804+
WalletTx::Tx(tx) => {
805+
if let Some(frozen_token_id) = conflict_check.frozen_token_id {
806+
if self.violates_frozen_token(unconfirmed_tx, &frozen_token_id) {
807+
conflicting_txs.insert(tx.get_transaction().get_id());
808+
continue;
809+
}
808810
}
809-
}
810811

811-
if let Some((confirmed_account, confirmed_account_nonce)) =
812-
conflict_check.confirmed_account_nonce
813-
{
814-
if confirmed_tx.get_id() != tx.get_transaction().get_id()
815-
&& uses_conflicting_nonce(
816-
unconfirmed_tx,
817-
confirmed_account,
818-
confirmed_account_nonce,
819-
)
812+
if let Some((confirmed_account, confirmed_account_nonce)) =
813+
conflict_check.confirmed_account_nonce
820814
{
821-
conflicting_txs.insert(tx.get_transaction().get_id());
822-
continue;
815+
if confirmed_tx.get_id() != tx.get_transaction().get_id()
816+
&& uses_conflicting_nonce(
817+
unconfirmed_tx,
818+
confirmed_account,
819+
confirmed_account_nonce,
820+
)
821+
{
822+
conflicting_txs.insert(tx.get_transaction().get_id());
823+
continue;
824+
}
823825
}
824826
}
825-
}
827+
WalletTx::Block(_) => {
828+
utils::debug_panic_or_log!("Cannot be block reward");
829+
}
830+
};
826831
}
827832
}
828833

829834
// Remove all descendants of conflicting txs
835+
let mut conflicting_tx_ids_with_descendants = vec![];
830836
let mut conflicting_txs_with_descendants = vec![];
831837

832838
for conflicting_tx in conflicting_txs {
833-
let txs_to_rollback = self.remove_from_unconfirmed_descendants(conflicting_tx);
839+
let tx_ids_to_rollback = self.remove_from_unconfirmed_descendants(conflicting_tx);
834840

835841
// Mark conflicting tx and its descendants as Conflicting and update OutputCache data accordingly
836842
let mut tx_to_rollback_data = vec![];
837-
for tx_id in txs_to_rollback.iter().rev().copied() {
843+
for tx_id in tx_ids_to_rollback.iter().rev().copied() {
838844
match self.txs.entry(tx_id.into()) {
839845
Entry::Occupied(mut entry) => match entry.get_mut() {
840846
WalletTx::Block(_) => {
841847
Err(WalletError::TransactionIdCannotMapToBlock(tx_id))
842848
}
843-
WalletTx::Tx(tx) => match tx.state() {
844-
TxState::Inactive(_) | TxState::InMempool(_) => {
845-
tx.set_state(TxState::Conflicted(block_id));
846-
tx_to_rollback_data.push(entry.get().clone());
847-
Ok(())
849+
WalletTx::Tx(tx) => {
850+
conflicting_txs_with_descendants.push(WalletTx::Tx(tx.clone()));
851+
match tx.state() {
852+
TxState::Inactive(_) | TxState::InMempool(_) => {
853+
tx.set_state(TxState::Conflicted(block_id));
854+
tx_to_rollback_data.push(entry.get().clone());
855+
Ok(())
856+
}
857+
TxState::Conflicted(..)
858+
| TxState::Abandoned
859+
| TxState::Confirmed(..) => {
860+
Err(WalletError::CannotMarkTxAsConflictedIfInState(*tx.state()))
861+
}
848862
}
849-
TxState::Conflicted(..)
850-
| TxState::Abandoned
851-
| TxState::Confirmed(..) => {
852-
Err(WalletError::CannotMarkTxAsConflictedIfInState(*tx.state()))
853-
}
854-
},
863+
}
855864
},
856865
Entry::Vacant(_) => {
857866
Err(WalletError::CannotFindDescendantTransactionWithId(tx_id))
@@ -863,10 +872,13 @@ impl OutputCache {
863872
self.rollback_tx_data(&tx)?;
864873
}
865874

866-
conflicting_txs_with_descendants.extend(txs_to_rollback.into_iter());
875+
conflicting_tx_ids_with_descendants.extend(tx_ids_to_rollback.into_iter());
867876
}
868877

869-
Ok(conflicting_txs_with_descendants)
878+
Ok(conflicting_tx_ids_with_descendants
879+
.into_iter()
880+
.zip_eq(conflicting_txs_with_descendants.into_iter())
881+
.collect())
870882
}
871883

872884
fn violates_frozen_token(&self, unconfirmed_tx: &WalletTx, frozen_token_id: &TokenId) -> bool {
@@ -933,9 +945,9 @@ impl OutputCache {
933945
TxState::Confirmed(_, _, _) => false,
934946
};
935947

936-
if is_unconfirmed && !already_present {
937-
self.unconfirmed_descendants.insert(tx_id.clone(), BTreeSet::new());
938-
} else if !is_unconfirmed {
948+
if is_unconfirmed {
949+
self.unconfirmed_descendants.entry(tx_id.clone()).or_default();
950+
} else {
939951
self.unconfirmed_descendants.remove(&tx_id);
940952
}
941953

@@ -1438,16 +1450,21 @@ impl OutputCache {
14381450
}
14391451

14401452
// Removes a tx and all its descendants from unconfirmed descendants collection.
1441-
// Returns provided tx and all the descendants in that specific order.
1453+
// Returns provided tx and all the descendants in such way that parent always comes before its
1454+
// descendants. Returned collection contains no duplicates.
14421455
fn remove_from_unconfirmed_descendants(
14431456
&mut self,
14441457
tx_id: Id<Transaction>,
14451458
) -> Vec<Id<Transaction>> {
14461459
let mut all_txs = Vec::new();
1447-
let mut to_update = BTreeSet::from_iter([OutPointSourceId::from(tx_id)]);
1460+
let mut all_txs_as_set = BTreeSet::new();
1461+
let mut to_update: VecDeque<OutPointSourceId> = [tx_id.into()].into();
14481462

1449-
while let Some(outpoint_source_id) = to_update.pop_first() {
1450-
all_txs.push(*outpoint_source_id.get_tx_id().expect("must be a transaction"));
1463+
while let Some(outpoint_source_id) = to_update.pop_front() {
1464+
let tx_id = *outpoint_source_id.get_tx_id().expect("must be a transaction");
1465+
if all_txs_as_set.insert(tx_id) {
1466+
all_txs.push(tx_id);
1467+
}
14511468

14521469
if let Some(descendants) = self.unconfirmed_descendants.remove(&outpoint_source_id) {
14531470
to_update.extend(descendants.into_iter())
@@ -1501,7 +1518,7 @@ impl OutputCache {
15011518
}
15021519
}
15031520

1504-
for output in tx.outputs() {
1521+
for output in tx.outputs().iter().rev() {
15051522
match output {
15061523
TxOutput::CreateStakePool(pool_id, _) => {
15071524
self.pools.remove(pool_id);
@@ -1542,43 +1559,47 @@ impl OutputCache {
15421559
}
15431560

15441561
/// Mark a transaction and its descendants as abandoned
1545-
/// Returns a Vec of the transaction Ids that have been abandoned
1562+
/// Returns a Vec of the transactions and the Ids that have been abandoned
15461563
pub fn abandon_transaction(
15471564
&mut self,
15481565
tx_id: Id<Transaction>,
1549-
) -> WalletResult<Vec<Id<Transaction>>> {
1566+
) -> WalletResult<Vec<(Id<Transaction>, WalletTx)>> {
15501567
let all_abandoned = self.remove_from_unconfirmed_descendants(tx_id);
1568+
let mut all_abandoned_txs = Vec::with_capacity(all_abandoned.len());
15511569

15521570
let mut txs_to_rollback = vec![];
15531571
for tx_id in all_abandoned.iter().rev().copied() {
15541572
match self.txs.entry(tx_id.into()) {
15551573
Entry::Occupied(mut entry) => match entry.get_mut() {
15561574
WalletTx::Block(_) => Err(WalletError::CannotFindTransactionWithId(tx_id)),
1557-
WalletTx::Tx(tx) => match tx.state() {
1558-
TxState::Inactive(_) => {
1559-
tx.set_state(TxState::Abandoned);
1560-
txs_to_rollback.push(entry.get().clone());
1561-
Ok(())
1562-
}
1563-
TxState::Conflicted(_) => {
1564-
tx.set_state(TxState::Abandoned);
1565-
Ok(())
1575+
WalletTx::Tx(tx) => {
1576+
all_abandoned_txs.push(WalletTx::Tx(tx.clone()));
1577+
match tx.state() {
1578+
TxState::Inactive(_) => {
1579+
tx.set_state(TxState::Abandoned);
1580+
txs_to_rollback.push(entry.get().clone());
1581+
Ok(())
1582+
}
1583+
TxState::Conflicted(_) => {
1584+
tx.set_state(TxState::Abandoned);
1585+
Ok(())
1586+
}
1587+
state => Err(WalletError::CannotChangeTransactionState(
1588+
*state,
1589+
TxState::Abandoned,
1590+
)),
15661591
}
1567-
state => Err(WalletError::CannotChangeTransactionState(
1568-
*state,
1569-
TxState::Abandoned,
1570-
)),
1571-
},
1592+
}
15721593
},
15731594
Entry::Vacant(_) => Err(WalletError::CannotFindTransactionWithId(tx_id)),
15741595
}?;
15751596
}
15761597

1577-
for tx in txs_to_rollback {
1578-
self.rollback_tx_data(&tx)?;
1598+
for tx in &txs_to_rollback {
1599+
self.rollback_tx_data(tx)?;
15791600
}
15801601

1581-
Ok(all_abandoned)
1602+
Ok(all_abandoned.into_iter().zip_eq(all_abandoned_txs.into_iter()).collect())
15821603
}
15831604

15841605
pub fn get_transaction(&self, transaction_id: Id<Transaction>) -> WalletResult<&TxData> {
@@ -1840,3 +1861,6 @@ fn uses_conflicting_nonce(
18401861
}
18411862
})
18421863
}
1864+
1865+
#[cfg(test)]
1866+
mod tests;

0 commit comments

Comments
 (0)