Skip to content

Conversation

ryanofsky
Copy link
Contributor

@ryanofsky ryanofsky commented Feb 3, 2017

Two commits:

  • Construct CWalletTx objects in CommitTransaction moves a bunch of CWalletTx initialization into CWallet::CommitTransaction to dedup some code and avoid future inconsistencies in how wallet transactions are created.
  • Get rid of CWalletTx default constructor does what is described and eliminates the possibility of empty transaction entries being inadvertently created by mapWallet[hash] accesses.

Both of these changes were originally part of #9381

@fanquake fanquake added the Wallet label Feb 3, 2017
@ryanofsky ryanofsky changed the title Unify CWalletTx construction (on top of #9673) Unify CWalletTx construction Feb 6, 2017
Copy link
Contributor

@promag promag left a comment

Choose a reason for hiding this comment

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

mapWallet.at() can throw so I guess it should be avoided and replaced with mapWallet.find(), to test the returned iterator.

Needs rebase.

@@ -578,9 +578,9 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect
for (const COutPoint& outpoint : vOutpoints)
{
if (!wallet->mapWallet.count(outpoint.hash)) continue;
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
int nDepth = wallet->mapWallet.at(outpoint.hash).GetDepthInMainChain();
if (nDepth < 0) continue;
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this condition taking advantage of the dummy CWalletTx? If so replace .at() with .find() and test the iterator.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Isn't this condition taking advantage of the dummy CWalletTx? If so replace .at() with .find() and test the iterator.

Dummy constructor isn't called here because of the count check above.

if (nDepth < 0) continue;
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
COutput out(&wallet->mapWallet.at(outpoint.hash), outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
Copy link
Contributor

Choose a reason for hiding this comment

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

Another lookup? With the above suggestion it can be avoided.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another lookup? With the above suggestion it can be avoided.

It looks like this is done in your PR #11039. I'll review that PR, so this PR can be limited to replacing [] lookups with at() lookups.

@@ -246,7 +246,7 @@ bool CFeeBumper::commit(CWallet *pWallet)
currentResult = BumpFeeResult::MISC_ERROR;
return false;
}
CWalletTx& oldWtx = pWallet->mapWallet[txid];
CWalletTx& oldWtx = pWallet->mapWallet.at(txid);
Copy link
Contributor

Choose a reason for hiding this comment

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

Replace with .find(txid) above (before .count()) and test if exists, also avoids 2nd lookup.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Replace with .find(txid) above (before .count()) and test if exists, also avoids 2nd lookup.

Also seems to be taken care of in #11039.

Copy link
Contributor Author

@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.

Thanks very much for the review. Rebased 2245b37 -> 51b93a9 (pr/makewtx.4 -> pr/makewtx.5), just fixing minor merge conflicts.

@@ -578,9 +578,9 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect
for (const COutPoint& outpoint : vOutpoints)
{
if (!wallet->mapWallet.count(outpoint.hash)) continue;
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
int nDepth = wallet->mapWallet.at(outpoint.hash).GetDepthInMainChain();
if (nDepth < 0) continue;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Isn't this condition taking advantage of the dummy CWalletTx? If so replace .at() with .find() and test the iterator.

Dummy constructor isn't called here because of the count check above.

if (nDepth < 0) continue;
COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
COutput out(&wallet->mapWallet.at(outpoint.hash), outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another lookup? With the above suggestion it can be avoided.

It looks like this is done in your PR #11039. I'll review that PR, so this PR can be limited to replacing [] lookups with at() lookups.

@@ -246,7 +246,7 @@ bool CFeeBumper::commit(CWallet *pWallet)
currentResult = BumpFeeResult::MISC_ERROR;
return false;
}
CWalletTx& oldWtx = pWallet->mapWallet[txid];
CWalletTx& oldWtx = pWallet->mapWallet.at(txid);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Replace with .find(txid) above (before .count()) and test if exists, also avoids 2nd lookup.

Also seems to be taken care of in #11039.

@laanwj
Copy link
Member

laanwj commented Aug 18, 2017

Get rid of CWalletTx default constructor does what is described and eliminates the possibility of empty transaction entries being inadvertently created by mapWallet[hash] accesses.

Great! I've always been wary of this projects' gratuitous use of [] for retrieval, as we don't want to accidentally create empty objects and because it generates more code. The second is true even when it's shielded with .count() or such. .at/.find is better.

So concept ACK at least - haven't been able to review all the changes in detail.

@ryanofsky ryanofsky force-pushed the pr/makewtx branch 2 times, most recently from 8fc4343 to 0a8204b Compare August 25, 2017 21:36
@@ -379,7 +379,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
return ret;
}

static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, const CCoinControl& coin_control)
static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue, std::string fromAccount, CTransactionRef& txNew)
Copy link
Member

Choose a reason for hiding this comment

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

Given that the argument txNew seems to be only used to store the resulting output in, wouldn't it be more convenient to make it the return type rather than an argument?

Copy link
Contributor Author

@ryanofsky ryanofsky Dec 1, 2017

Choose a reason for hiding this comment

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

Given that the argument txNew seems to be only used to store the resulting output in, wouldn't it be more convenient to make it the return type rather than an argument?

Forgot to respond to this comment, but this was a good idea, and I implemented it in a previous update to the PR: a0a4d82 -> f16d28c (pr/makewtx.11 -> pr/makewtx.12)

@jonasschnelli
Copy link
Contributor

Nice!
Concept ACK.

@ryanofsky ryanofsky force-pushed the pr/makewtx branch 3 times, most recently from a0a4d82 to f16d28c Compare November 20, 2017 22:08
Copy link
Member

@sipa sipa left a comment

Choose a reason for hiding this comment

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

utACK f16d28c

return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(state.GetRejectReason()));

CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << *newTx->tx;
ssTx << **newTx;
Copy link
Member

Choose a reason for hiding this comment

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

I think the extra dereference isn't needed here; serializing a std::shared_ptr<X> should work, if X is serializable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in d070a69

Copy link
Contributor Author

@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.

Copy link
Contributor

@jamesob jamesob 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 7bae52b

@@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)

wtx.mapValue["comment"] = "z";
pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx.push_back(&pwalletMain->mapWallet.at(wtx.GetHash()));
Copy link
Contributor

Choose a reason for hiding this comment

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

The commit message seems to suggest .at() will cause compile-time errors for non-existent keys, but from what I understand at() will throw runtime out_of_range exceptions. This change in behavior seems okay, but I don't have great context here -- are we alright with these lines now being liable to throw runtime exceptions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, commit message is mistaken, it should say "runtime exceptions" not "compile errors". But the change is intentional because it should be preferable to throw exceptions if invalid txids are looked up instead of creating empty map entries with null CTransactionRef pointers that might later get dereferenced.

@jamesob
Copy link
Contributor

jamesob commented Mar 6, 2018

ACK 7bae52b

Cloned this branch, compiled, and ran bitcoin-qt.

@ryanofsky
Copy link
Contributor Author

Updated commit message 7bae52b -> a5a2e7e (pr/makewtx.21 -> pr/makewtx.22), no other changes.

@jamesob
Copy link
Contributor

jamesob commented Mar 6, 2018

ACK a5a2e7e

@ryanofsky
Copy link
Contributor Author

ryanofsky commented Mar 7, 2018

Rebased a5a2e7e -> da94a51 (pr/makewtx.22 -> pr/makewtx.23) due to conflict with #12421 causing travis build failures.
Rebased da94a51 -> 8fcd24e (pr/makewtx.23 -> pr/makewtx.24) due to conflict with #11687.

Construct CWalletTx objects in CWallet::CommitTransaction, instead of having
callers do it. This ensures CWalletTx objects are constructed in a uniform way
and all fields are set.

This also makes it possible to avoid confusing and wasteful CWalletTx copies in
bitcoin#9381

There is no change in behavior.
No change in behavior in the normal case. But buggy mapWallet lookups with
invalid txids will now throw exceptions instead of inserting dummy entries into
the map, and potentially causing segfaults and other failures.

This also makes it a compiler error to use the mapWallet[hash] syntax which
could create dummy entries.
@maflcko
Copy link
Member

maflcko commented Mar 8, 2018

Needs rebase

@ryanofsky
Copy link
Contributor Author

ryanofsky commented Mar 12, 2018

Needs rebase

Rebased 8fcd24e -> 2c08d0b (pr/makewtx.24 -> pr/makewtx.25) for #12607.

@ryanofsky
Copy link
Contributor Author

Added 1 commits 2c08d0b -> d0b8536 (pr/makewtx.25 -> pr/makewtx.26, compare) implementing suggestion from #9381 (comment).
Squashed d0b8536 -> b4bc32a (pr/makewtx.26 -> pr/makewtx.27)

Copy link
Contributor

@kallewoof kallewoof left a comment

Choose a reason for hiding this comment

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

utACK a128bdc

@sipa
Copy link
Member

sipa commented Mar 14, 2018

utACK b4bc32a

@sipa sipa merged commit b4bc32a into bitcoin:master Mar 14, 2018
sipa added a commit that referenced this pull request Mar 14, 2018
b4bc32a [wallet] Get rid of CWalletTx default constructor (Russell Yanofsky)
a128bdc [wallet] Construct CWalletTx objects in CommitTransaction (Russell Yanofsky)

Pull request description:

  Two commits:

  - `Construct CWalletTx objects in CommitTransaction` moves a bunch of CWalletTx initialization into CWallet::CommitTransaction to dedup some code and avoid future inconsistencies in how wallet transactions are created.
  - `Get rid of CWalletTx default constructor` does what is described and eliminates the possibility of empty transaction entries being inadvertently created by mapWallet[hash] accesses.

  Both of these changes were originally part of #9381

Tree-SHA512: af3841c4f0539e0662d81b33c5369fc70aa06ddde1c59cb00fb21c9e4c7d9ff47f1edc5040cb463af1333838802c56b3ef875b939e2b804ee45b8e0294a4371c
UdjinM6 added a commit to dashpay/dash that referenced this pull request Sep 21, 2020
* [wallet] Construct CWalletTx objects in CommitTransaction

Construct CWalletTx objects in CWallet::CommitTransaction, instead of having
callers do it. This ensures CWalletTx objects are constructed in a uniform way
and all fields are set.

This also makes it possible to avoid confusing and wasteful CWalletTx copies in
bitcoin#9381

There is no change in behavior.

* [wallet] Get rid of CWalletTx default constructor

No change in behavior in the normal case. But buggy mapWallet lookups with
invalid txids will now throw exceptions instead of inserting dummy entries into
the map, and potentially causing segfaults and other failures.

This also makes it a compiler error to use the mapWallet[hash] syntax which
could create dummy entries.

* Apply suggestions from code review

Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>

Co-authored-by: Russell Yanofsky <russ@yanofsky.org>
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants