Skip to content

Conversation

ariard
Copy link

@ariard ariard commented Aug 15, 2019

While working on #15931, I've tried to rationalize tx state management to ease integration of block height tracking per-wallet tx. We currently rely on a combination of hashBlock and nIndex with magic value to determine tx confirmation, conflicted or abandoned state. It's hard to reason and error-prone. To solve that, we encapsulate these fields in a TxConfirmation struct and introduce a TxState member that we update accordingly at block connection/disconnection.

Following jnewbery recommendation, I've taken these changes in its own commit, and open a PR to get them first. It would ease review of aforementioned PR, but above all should ease fixing of long-term issues like :

Main changes of this PR to get right are tx update in AddToWallet and serialization/deserialization logic.

@ariard ariard changed the title wallet : encapsulate trransactions state wallet : encapsulate transactions state Aug 15, 2019
@ariard ariard force-pushed the 2019-08-encapsulate-tx-state branch from 3f2eb1d to 0e3212a Compare August 15, 2019 21:23
@ariard
Copy link
Author

ariard commented Aug 15, 2019

Travis is stalling yet another time..

@jnewbery
Copy link
Contributor

Concept ACK

@DrahtBot
Copy link
Contributor

DrahtBot commented Aug 16, 2019

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #15931 (Remove GetDepthInMainChain dependency on locked chain interface by ariard)
  • #15129 (rpc: Added ability to remove watch only addresses by benthecarman)
  • #9381 (Remove CWalletTx merging logic from AddToWallet by ryanofsky)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@ryanofsky
Copy link
Contributor

Concept ACK. This overlaps (but is compatible) with #9381

Copy link
Member

@Sjors Sjors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK. I added tests for backwards compatibility of abandoned and conflicted wallet transactions to #12134. Those still pass if I apply this PR, which gives some assurance we didn't break the serialization.

@@ -396,7 +396,7 @@ class CWalletTx
private:
const CWallet* pwallet;

/** Constant used in hashBlock to indicate tx has been abandoned */
/** Constant used in hashBlock to indicate tx has been abandoned, */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: why the trailing comma?

@@ -477,16 +475,46 @@ class CWalletTx
fInMempool = false;
nChangeCached = 0;
nOrderPos = -1;
tx_state.hashBlock = uint256();
tx_state.nIndex = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the default initialization changed to 0?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the default initialization changed to 0?

From what I can tell in this PR, the convention mostly adhered to in this PR is to stop using -1 and ABANDON_HASH values at runtime, and restrict them only to the serialization code. This seems like a pretty good convention if it's followed consistently. I also think it'd be nice to explicitly say what values the block and index values should have for different states in a comment.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes see comment on top of TxConfirmation, should be improved ?

* Older clients interpret nIndex == -1 as unconfirmed for backward
* compatibility (pre-commit 9ac63d6).
*/
int nIndex;
Copy link
Member

@Sjors Sjors Aug 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this backwards compatibility feature entirely to the serialization code, and then make nIndex a uint (for clarity)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this backwards compatibility feature entirely to the serialization code, and then make nIndex a uint (for clarity)?

Personally -0 on this. Imo, unsigned types provide no safety and are terrible for everything except bitfields.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean here by moving this backwards compatibility feature entirely to the serialization code ? If changes are right this logic should only lived in serialization code now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See below, it depends on if nIndex has any meaning.

uint256 hashBlock;
/* At serialization/deserialization, an nIndex == -1 means that hashBlock refers to
* the earliest block in the chain we know this or any in-wallet dependency conflicts
* with, but if hashBlock is null it means transaction is abandoned. An nIndex >= 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention that nIndex is a block height?

Copy link
Author

@ariard ariard Aug 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With these changes, but even before, nIndex never referred directly to a block height. When set at -1, it's interpreted as a magic value meaning the hashBlock is one of the deepest conflicting tx. This PR intents to scope this logic only to serialization/deserialization.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If nIndex doesn't mean a block height, then why not remove the instance variable altogether? We can still (de)serialize in a backwards compatible way.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I think we need to keep nIndex at least it's used by RPCs in WalletTxToJSON ? Or getting it out of new TxConfirmation struct ?

Copy link
Member

@Sjors Sjors Aug 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should figure out what it means in the RPC, consider deprecating that field, and then having an explicit backwards compatible workaround.

In the backwards compatiblity tests I wrote it seems blockindex is absent for uncofirmned or abandoned transactions. It was 1 for a confirmed transaction.

void setConflicted() { tx_state.state = CWalletTx::CONFLICTED; }
bool isUnconfirmed() const { return tx_state.state == CWalletTx::UNCONFIRMED; }
void setUnconfirmed() { tx_state.state = CWalletTx::UNCONFIRMED; }
bool isConfirmed() const { return tx_state.state == CWalletTx::CONFIRMED; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isConfirmed() does not seem to be tested as the others. Add a test? :-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed for now, I've added it for further changes were ABANDON state was dual-set with other states, but drop if for now, would have been too big changes at once.

/* New transactions start in the UNCONFIRMED. At BlockConnected,
* they will transition to CONFIRMED. In case of reorg, at BlockDisconnected,
* they rollback to UNCONFIRMED. If we detect a conflicting transaction at
* block connection, we update conflited tx and its dependencies as CONFLICTED.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be "conflicted"? :-)

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some questions, but this looks very good and is a welcome change that should make code more readable.

uint256 hashBlock;
/* At serialization/deserialization, an nIndex == -1 means that hashBlock refers to
* the earliest block in the chain we know this or any in-wallet dependency conflicts
* with, but if hashBlock is null it means transaction is abandoned. An nIndex >= 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if hashBlock is null it means transaction is abandoned

Could you clarify this part of the comment. Doesn't 1 not 0 mean abandoned?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, AbandonTransaction set nIndex as -1 and this value is kept at serialization/deserialization. I'm not sure if it make sense for older client, because an abandoned transaction can be also confirmed/unconfirmed/conflicted at same time. Nevertheless, I've tried to keep same behavior for now, so hashBlock set as ABANDON_HASH is used to avoid deserialization ambiguity with conflicted.

I've clarified this comment, the ABANDON_HASH one and also reset abandon txn hashBlock at deserialization. ABANDON_HASH should be scoped at serialization/deserialization.

@@ -1249,8 +1238,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const uint256
CWalletTx wtx(this, ptx);

// Get merkle branch if transaction was found in a block
if (!block_hash.IsNull())
wtx.SetMerkleBranch(block_hash, posInBlock);
wtx.SetMerkleBranch(state, block_hash, posInBlock);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment above about "if transaction was found in a block" no longer makes sense without the if condition.

Also, it seems like now when an abandoned, conflicted, or confirmed transaction is added to the mempool, and this is called, the transaction will now be marked unconfirmed instead of left in the previous state.

This seems logical, but I'm wondering if it is a change in behavior. It'd be helpful if the PR description or commit message would say explicitly whether any of this changes wallet behavior, and what the changes are if it does.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified in commit message that is a change in behavior where at block disconnection, previous tx state is override by UNCONFIRMED one. I think right now, we don't track at all the fact that tx has been disconnected, and that's why we don't undo conflicts, or make it hard to solve them. The only direct consequence of these changes I can think of is a user having to call abandontransaction a 2nd time if block get disconnected and transaction is not back in mempool.

This change would make easier to track conflicts, where if conflicting transaction get UNCONFIRMED, iterate on conflicted outpoints and make them free.

Maybe, I can avoid update right now for UNCONFIRMED state, so a tx is born in this state but never go backward to it, and save implications for a later PR ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can live with changing it now, but we should drop the comment then.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In commit "Encapsulate tx state in a TxConfirmation struct" (8a7d26d)

On the surface it seems like improved behavior to not consider a transaction conflicted or abandoned when it's in the mempool. So just removing or updating the comment above seems good for that case. If this can mark a transaction not abandoned when it's not actually in the mempool that also seems ok but might be worth noting in a comment.

Ideally this commit might just be a pure refactor, and behavior changes could be left for other commits or PRs, but I think it's fine to have changes here if they're explicitly noted.

* Older clients interpret nIndex == -1 as unconfirmed for backward
* compatibility (pre-commit 9ac63d6).
*/
int nIndex;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this backwards compatibility feature entirely to the serialization code, and then make nIndex a uint (for clarity)?

Personally -0 on this. Imo, unsigned types provide no safety and are terrible for everything except bitfields.

* Older clients interpret nIndex == -1 as unconfirmed for backward
* compatibility (pre-commit 9ac63d6).
*/
int nIndex;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a suggestion, but I'd add = 0 here and = UNCONFIRMED on the line below to simplify constructor and deserialization code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -477,16 +475,46 @@ class CWalletTx
fInMempool = false;
nChangeCached = 0;
nOrderPos = -1;
tx_state.hashBlock = uint256();
tx_state.nIndex = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the default initialization changed to 0?

From what I can tell in this PR, the convention mostly adhered to in this PR is to stop using -1 and ABANDON_HASH values at runtime, and restrict them only to the serialization code. This seems like a pretty good convention if it's followed consistently. I also think it'd be nice to explicitly say what values the block and index values should have for different states in a comment.

tx_state.nIndex = 0;
setAbandoned();
} else if (serializedIndex == -1) {
tx_state.nIndex = -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we set 0 here, or change MarkConflicted to set -1? I think it'd be good to be consistent about what conflicted transactions look like.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right that an inconsistency from my part. Corrected.

@@ -1415,7 +1415,6 @@ void CWallet::BlockConnected(const CBlock& block, const std::vector<CTransaction
// the notification that the conflicted transaction was evicted.

for (const CTransactionRef& ptx : vtxConflicted) {
SyncTransaction(ptx, CWalletTx::TxState::CONFLICTED, {} /* block hash */, 0 /* position in block */);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In commit "Remove SyncTransaction for conflicted txn in CWallet::BlockConnected" (0e3212a)

I don't think I understand this change. Commit description suggests why it is ok, but I don't understand what motivates it. Is it just cleanup? Is it maybe a minor bugfix, or needed for a future change?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated commit message. I think this redundant, as conflicts tagging logic is triggered by connection of conflicting transaction. AFAIK, it's not a bugfix but a cleanup. And as it was same issue than major commit, I bundled them together.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify why we keep the first loop at all? Why not call TransactionRemovedFromMempool before SyncTransaction in the second loop?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extended commit message, we keep the loop because set of conflicted txn isn't same as txn included in a block.

@ariard ariard force-pushed the 2019-08-encapsulate-tx-state branch from 0e3212a to ba86976 Compare August 16, 2019 19:24
@ariard
Copy link
Author

ariard commented Aug 16, 2019

Thanks all for reviews, updated with comments corrected at 6cc34fc.

@ariard ariard force-pushed the 2019-08-encapsulate-tx-state branch from ba86976 to 6cc34fc Compare August 16, 2019 20:35
@meshcollider
Copy link
Contributor

Concept ACK

Copy link
Member

@Sjors Sjors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 6cc34fc

@@ -1415,7 +1415,6 @@ void CWallet::BlockConnected(const CBlock& block, const std::vector<CTransaction
// the notification that the conflicted transaction was evicted.

for (const CTransactionRef& ptx : vtxConflicted) {
SyncTransaction(ptx, CWalletTx::TxState::CONFLICTED, {} /* block hash */, 0 /* position in block */);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify why we keep the first loop at all? Why not call TransactionRemovedFromMempool before SyncTransaction in the second loop?

int nIndex;
struct TxConfirmation {
uint256 hashBlock;
/* At serialization/deserialization, an nIndex == -1 means that hashBlock refers to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above this comment: For a CONFIRMED transaction, nIndex is the position inside the block, used in merkle proofs.

This had me confused before; I assumed it referred to a block height.

This serialization comment can be moved to the serialization code, because with this change nIndex is never -1; only serializedIndex is.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to the deserialization code!

{
// Update the tx's hashBlock
hashBlock = block_hash;
tx_state.hashBlock = block_hash;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TxConfirmation tx_state is now a confusingly named variable.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I've struggled hard on naming, TxConfirmation is struct with tx state + its values (block hash, position in block). If you have any better names, I'll take it :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name tx_state is the confusing part, because it's not a TxState

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name tx_state is the confusing part, because it's not a TxState

I think the current naming is ok, but if it I had to choose, I would probably do something like:

class CWalletTx
{
public:
    enum Status { UNCONFIRMED, CONFIRMED, CONFLICTED, ABANDONED };
    struct Confirmation {
        Status status;
        uint256 block_hash
        int pos_in_block;
    }
    ...
    Confirmation m_confirm;
    ...
};

Copy link
Author

@ariard ariard Aug 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced by tx_conf on f9f4926

@@ -1249,8 +1238,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const uint256
CWalletTx wtx(this, ptx);

// Get merkle branch if transaction was found in a block
if (!block_hash.IsNull())
wtx.SetMerkleBranch(block_hash, posInBlock);
wtx.SetMerkleBranch(state, block_hash, posInBlock);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can live with changing it now, but we should drop the comment then.

@@ -1383,8 +1372,9 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
}

void CWallet::SyncTransaction(const CTransactionRef& ptx, const uint256& block_hash, int posInBlock, bool update_tx) {
if (!AddToWalletIfInvolvingMe(ptx, block_hash, posInBlock, update_tx))
void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::TxState state, const uint256& block_hash, int posInBlock, bool update_tx)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

posInBlock could be a good rename candidate for nIndex, though probably not worth making the diff bigger.

@ariard ariard force-pushed the 2019-08-encapsulate-tx-state branch from 6cc34fc to 3e027c7 Compare August 19, 2019 14:20
@ariard
Copy link
Author

ariard commented Aug 19, 2019

Thanks @Sjors for review, pushed some corrections on de4459c

@ariard ariard force-pushed the 2019-08-encapsulate-tx-state branch 2 times, most recently from de4459c to f9f4926 Compare August 19, 2019 17:19
Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK 3e027c7

@@ -1249,8 +1238,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const uint256
CWalletTx wtx(this, ptx);

// Get merkle branch if transaction was found in a block
if (!block_hash.IsNull())
wtx.SetMerkleBranch(block_hash, posInBlock);
wtx.SetMerkleBranch(state, block_hash, posInBlock);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In commit "Encapsulate tx state in a TxConfirmation struct" (8a7d26d)

On the surface it seems like improved behavior to not consider a transaction conflicted or abandoned when it's in the mempool. So just removing or updating the comment above seems good for that case. If this can mark a transaction not abandoned when it's not actually in the mempool that also seems ok but might be worth noting in a comment.

Ideally this commit might just be a pure refactor, and behavior changes could be left for other commits or PRs, but I think it's fine to have changes here if they're explicitly noted.

if (wtxIn.tx_state.state != wtx.tx_state.state) {
wtx.tx_state.state = wtxIn.tx_state.state;
wtx.tx_state.nIndex = wtxIn.tx_state.nIndex;
wtx.tx_state.hashBlock = wtxIn.tx_state.hashBlock;
fUpdated = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In commit "Encapsulate tx state in a TxConfirmation struct" (8a7d26d)

Should we maybe add

} else {
    assert(wtx.tx_state.nIndex == wtxIn.tx_state.nIndex);
    assert(wtx.tx_state.hashBlock = wtxIn.tx_state.hashBlock);
}

My concern is that the new behavior might be less robust than previous behavior if there is a bug in higher level code that marks a transaction as confirmed in two different blocks without marking the transaction as unconfirmed in between.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

@jnewbery jnewbery Aug 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(re: #16624 (comment))

I don't like these new asserts. I think they could be triggered under the following scenario:

  1. a wallet tx is confirmed in a block
  2. the wallet is shut down
  3. the block chain re-orgs and the tx is included in a different block
  4. the wallet file is loaded on a sync'ed node

All this code is trying to do is update an existing wallet tx's Confirmation status with the new Confirmation status. I think we can just change it to:

if (wtxIn.tx_state.state != wtx.tx_state.state || wtxIn.tx_state.hashBlock != wtx.tx_state.hashBlock || wtxIn.tx_state.nIndex != wtx.tx_state.nIndex) {

Copy link
Author

@ariard ariard Aug 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these new asserts get triggered it would mean we have bugs in higher level code, but yes aborting maybe too strong given that this kind of bugs could be due to some likely API misuse in RPCs ? What's about logging them with a warning ?

I'm not in favor of proposed alternative as it may cause hidden inconsistencies if these aforementioned high level bugs are present

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel strongly, but I think asserts are way to go because we should not allow bugs and uncertainty in wallet event processing code. It's hard for me to imagine a scenario where it would be a win to use defensive programming in a place like this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ryanofsky - do you agree that the scenario I describe above would trigger the assert?

Copy link
Contributor

@ryanofsky ryanofsky Aug 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I didn't realize #16624 (comment) was describing a specific scenario, not just a list of possible events. I could see that scenerio triggering these asserts, and making the change you suggested an improvement and bugfix. It is likely some change is needed here, and the suggested one seems ok.

More ideally, though, it'd be really nice to have a functional test that triggers these asserts, and instead of hiding the problem of an unconfirmed transaction being left in the CONFIRMED state after a reorg, there would be code on startup that marks reorged transactions UNCONFIRMED before rescanning (could basically be the same code from #15931 that looks up block heights on startup).

Nice catch though (assuming this a bug)!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize #16624 (comment) was describing a specific scenario

sorry - changed my unordered list to an ordered list and updated wording to make this clearer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there would be code on startup that marks reorged transactions UNCONFIRMED before rescanning

Yes - I think if the wallet rescans from block at height x, it should first change all transactions that are CONFIRMED at height >x to UNCOFIRMED.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I let asserts and move some bits from #15931 to transition status to UNCONFIRMED if blockHash not anymore in chain. Also added a wallet_reorgsrestore test with aforementioned scenario, without new code it triggers asserts

{
// Update the tx's hashBlock
hashBlock = block_hash;
tx_state.hashBlock = block_hash;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name tx_state is the confusing part, because it's not a TxState

I think the current naming is ok, but if it I had to choose, I would probably do something like:

class CWalletTx
{
public:
    enum Status { UNCONFIRMED, CONFIRMED, CONFLICTED, ABANDONED };
    struct Confirmation {
        Status status;
        uint256 block_hash
        int pos_in_block;
    }
    ...
    Confirmation m_confirm;
    ...
};

@@ -477,16 +477,37 @@ class CWalletTx
fInMempool = false;
nChangeCached = 0;
nOrderPos = -1;
tx_state.hashBlock = uint256();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In commit "Encapsulate tx state in a TxConfirmation struct" (8a7d26d)

It seems more safe to reset the whole struct instead of just one member. Maybe tx_state = TxConfirmation{};?

I think there may actually be a (theoretical) bug without this. If you unserialized an unconfirmed transaction into a CWalletTx that was not unconfirmed, deserialization code would not actually update the state to unconfirmed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well strictly speaking, given that Init set to unconfirmed, it would be more wrongly updating to confirmed. But if hash is set IMO we have database corruption or bug in higher tracking logic. Updated serialization logic with this and beneath to make it more robust.

tx_state.hashBlock = uint256();
setAbandoned();
} else if (serializedIndex == -1) {
tx_state.nIndex = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In commit "Remove SyncTransaction for conflicted txn in CWallet::BlockConnected" (3e027c7)

Can we drop these tx_state.nIndex = 0; assignments or set them in all cases consistently? (There is a missing assignment in the unconfirmed case). I'd have a slight preference for just dropping these and the Init() call above reset everything to default, instead of repeating same default values multiple places.

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK f9f4926. Only change since last review is renaming tx_state to tx_conf, which is reasonable. I left some comments with my previous review, but they aren't very important and are fine to ignore.

Copy link
Contributor

@meshcollider meshcollider left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, utACK f9f4926

@ryanofsky My concern is that the new behavior might be less robust than previous behavior if there is a bug in higher level code that marks a transaction as confirmed in two different blocks without marking the transaction as unconfirmed in between.

I agree, I was looking at this specific change too. I think it should be fine but the additional check wouldn't hurt 👍

@ariard ariard force-pushed the 2019-08-encapsulate-tx-state branch from f9f4926 to 5ef9e95 Compare August 20, 2019 18:53
@ariard
Copy link
Author

ariard commented Aug 20, 2019

Updated at 5ef9e95 with @ryanofsky comments. Main changes are a more robust serialization logic and assert for already present txn in AddToWallet. This last one flagged a misbehavior of AddToWallet in ComputeTimeSmart (see commit message), so was worth adding.

Stackout pushed a commit to VeriBlock/vbk-ri-btc that referenced this pull request Feb 17, 2022
At wallet loading, we rely on chain state querying to retrieve
height of txn, to do so we ensure that lock order is respected
between cs_main and cs_wallet.

If wallet loaded is the wallet-tool one, all wallet txn will
show up with a height of zero. It doesn't matter as confirmation
height is not used by wallet-tool.

Reorder arguments and document Confirmation calls to avoid
ambiguity.

Fixes nits left from bitcoin#16624
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Mar 5, 2022
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Mar 5, 2022
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
kwvg added a commit to kwvg/dash that referenced this pull request Apr 3, 2022
kwvg added a commit to kwvg/dash that referenced this pull request Apr 3, 2022
kwvg added a commit to kwvg/dash that referenced this pull request Apr 5, 2022
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
kwvg added a commit to kwvg/dash that referenced this pull request Apr 5, 2022
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
kwvg added a commit to kwvg/dash that referenced this pull request Apr 6, 2022
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
kwvg added a commit to kwvg/dash that referenced this pull request Apr 7, 2022
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
kwvg added a commit to kwvg/dash that referenced this pull request Apr 7, 2022
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
kwvg added a commit to kwvg/dash that referenced this pull request Apr 17, 2022
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
kwvg added a commit to kwvg/dash that referenced this pull request Apr 19, 2022
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
malbit added a commit to malbit/raptoreum that referenced this pull request Aug 7, 2022
[bitcoin#14624](bitcoin/bitcoin#14624)
bls refactoring to resolve clang warnings
[bitcoin#16426](bitcoin/bitcoin#16426) - cs_wallet lock order refactoring and reduce cs_main locking
atomic smartnode_connection (allow read/write by different threads simultaneously)
cs_mnauth locks on verifiedProRegTxHash read
RecursiveMutex at locking access to activeSmartNode
[bitcoin#14307](bitcoin/bitcoin#14307) - Consolidate redundant implementation of ParseHashStr
[bitcoin#13399](bitcoin/bitcoin#13399) - rpc: Add submitheader
built-in miner deleted
[bitcoin#17781](bitcoin/bitcoin#17781) - Remove mempool global from miner
[bitcoin#16623](bitcoin/bitcoin#16624) - encapsulate transactions state
[bitcoin#15931](bitcoin/bitcoin#15931) - Remove GetDepthInMainChain dependency on locked chain interface
Pass CConnman to function against global pointer
[bitcoin#16839](bitcoin/bitcoin#16839) - Replace Connman and BanMan globals with NodeContext local
[bitcoin#16034](bitcoin/bitcoin#16034) - refactoring: Rename LockAnnotation to LockAssertion and add run-time check to it
[bitcoin#17564](bitcoin/bitcoin#17564) - Use mempool from node context instead of global
[bitcoin#18740](bitcoin/bitcoin#18740) - Remove g_rpc_node global
[bitcoin#19096](bitcoin/bitcoin#19096) - Remove g_rpc_chain global
[bitcoin#18338](bitcoin/bitcoin#18338) - Fix wallet unload race condition
other fixes and tweaks
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Aug 16, 2022
knst pushed a commit to knst/dash that referenced this pull request Nov 7, 2023
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
knst pushed a commit to knst/dash that referenced this pull request Nov 7, 2023
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
knst pushed a commit to knst/dash that referenced this pull request Nov 9, 2023
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
knst pushed a commit to knst/dash that referenced this pull request Nov 17, 2023
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
vijaydasmp pushed a commit to vijaydasmp/dash that referenced this pull request Apr 12, 2024
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
vijaydasmp pushed a commit to vijaydasmp/dash that referenced this pull request Apr 12, 2024
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
vijaydasmp pushed a commit to vijaydasmp/dash that referenced this pull request Apr 13, 2024
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
vijaydasmp pushed a commit to vijaydasmp/dash that referenced this pull request Apr 13, 2024
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
vijaydasmp pushed a commit to vijaydasmp/dash that referenced this pull request Apr 22, 2024
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
vijaydasmp pushed a commit to vijaydasmp/dash that referenced this pull request Apr 22, 2024
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
vijaydasmp pushed a commit to vijaydasmp/dash that referenced this pull request May 4, 2024
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
knst pushed a commit to knst/dash that referenced this pull request May 16, 2024
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07
knst pushed a commit to knst/dash that referenced this pull request May 20, 2024
…notifications

Backport notice:
we don't have bumpfee feature, so, only some part of code is backported

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07

fixup dashify of feature_notifications
knst pushed a commit to knst/dash that referenced this pull request May 21, 2024
…tions

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07

fixup dashify of feature_notifications
knst pushed a commit to knst/dash that referenced this pull request May 27, 2024
…notifications

Backport notice:
we don't have bumpfee feature, so, only some part of code is backported

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07

fixup dashify of feature_notifications
knst pushed a commit to knst/dash that referenced this pull request May 30, 2024
…notifications

Backport notice:
we don't have bumpfee feature, so, only some part of code is backported

f963a68 test: Add test for conflicted wallet tx notifications (Russell Yanofsky)

Pull request description:

  Add test coverage for conflicted wallet transaction notifications so we can improve current behavior and avoid future regressions

  bitcoin#9240 - accidental break
  bitcoin#9479 - bug report
  bitcoin#9371 - fix
  bitcoin#16624 - accidental break
  bitcoin#18325 - bug report
  bitcoin#18600 - potential fix

ACKs for top commit:
  laanwj:
    ACK f963a68
  jonatack:
    re-ACK f963a68
  MarcoFalke:
    ACK f963a68

Tree-SHA512: d3a7952a2d3dc2ff0800ef857575ea4ef9759c0917d58a7fc91e2db0ca3cc3baf0dd0cf9af61683f691e5fefb11afe8120bb5810c7037ed9ecedee385dd4aa07

fixup dashify of feature_notifications
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants