refactor: Replace chain relayTransactions/submitMemoryPool by higher method #15713

pull ariard wants to merge 5 commits into bitcoin:master from ariard:2019-03-refactor-relay-tx-submit-pool changing 7 files +87 −97
  1. ariard commented at 1:22 am on April 1, 2019: member

    Remove CWalletTx::AcceptToMemoryPool

    Replace CWalletTx::RelayWalletTransaction by SubmitMemoryPoolAndRelay

    Add a relay flag to broadcastTransaction because wasn’t sure of ReacceptWalletTransactions semantic.

    Obviously, working on implementing #14978 (comment) to add the new higher-method in Node interface, will add a commit, just need more thought to do it cleanly

  2. fanquake added the label Refactoring on Apr 1, 2019
  3. fanquake added the label Wallet on Apr 1, 2019
  4. DrahtBot commented at 2:38 am on April 1, 2019: member

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

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #16528 ([WIP] Native Descriptor Wallets (take 2) by achow101)
    • #16521 (wallet/rpc: Use the default maxfeerate value as BTC/kB by Remagpie)
    • #16503 (Remove p2pEnabled from Chain interface by ariard)
    • #16341 (Introduce ScriptPubKeyMan interface and use it for key and script management (aka wallet boxes) by achow101)
    • #15169 (Parallelize CheckInputs() in AcceptToMemoryPool() by sdaftuar)
    • #14920 (Build: enable -Wdocumentation via isystem by Empact)
    • #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.

  5. DrahtBot added the label Needs rebase on Apr 1, 2019
  6. in src/interfaces/chain.cpp:304 in abae70356f outdated
    300@@ -306,10 +301,58 @@ class ChainImpl : public Chain
    301         auto it = ::mempool.GetIter(txid);
    302         return it && (*it)->GetCountWithDescendants() > 1;
    303     }
    304-    void relayTransaction(const uint256& txid) override
    305+    bool broadcastTransaction(const CTransactionRef& tx, const uint256& txid, CValidationState& state, const CAmount& absurdfee, bool relay) override
    


    ryanofsky commented at 10:47 pm on April 2, 2019:

    Thanks for consolidating the code from relayTransaction and submitToMemoryPool in interfaces/chain.cpp and from BroadcastTransaction in node/transaction.cpp.

    I do think the right place for all this code to live is in node/transaction.cpp, though. interfaces/chain.cpp is really just meant to be a simple glue file with lines like:

    0bool broadcastTransaction(...) override { return BroadcastTransaction(...); }
    

    Also, I didn’t look closely yet, but it seems like this refactoring might be changing wallet behavior (this could explain travis test failures). It would probably be better if this PR avoided changing behavior to the extent possible. This might require adding some extra options to the existing BroadcastTransaction function in node/transaction.cpp, or adding a second broadcast function there that can hopefully share some code with the current one.


    ariard commented at 3:04 am on April 3, 2019:
    Okay was thinking than node/transaction.cpp was temporary and long term goal was to aggregate it to interfaces/node.cpp. Didn’t want to change wallet behavior, fixed it by adding options in the existing BroadcastTransaction (but still not sure of ReacceptWalletTransactions, should we broadcast txn there ?), functional tests should be good now. Also rebased

    ryanofsky commented at 3:43 am on April 3, 2019:

    re: #15713 (review)

    Thanks! This looks good and now net removes code (+63/-83).

    Okay was thinking than node/transaction.cpp was temporary

    Yeah, that may have been the original thought. But I think it could be a reasonable long term location if more things are moved around it. In any case it’s where the BroadcastTransaction function currently lives, so it’s easier not to move in this PR, which is more about simplifying wallet code.

    and long term goal was to aggregate it to interfaces/node.cpp

    Everything in interfaces/, including interfaces/node.cpp is just supposed to be very short glue code (the files would be huge otherwise). The interfaces are a way of letting wallet, node, and gui code run in different processes, and a way of preventing them from accessing each others internal state.

  7. ariard force-pushed on Apr 3, 2019
  8. DrahtBot removed the label Needs rebase on Apr 3, 2019
  9. in src/interfaces/chain.cpp:207 in 322638ca7b outdated
    204@@ -210,8 +205,7 @@ class NotificationsHandlerImpl : public Handler, CValidationInterface
    205         // should be able to be removed entirely if `ResendWalletTransactions`
    206         // is replaced by a wallet timer as suggested in
    207         // https://github.com/bitcoin/bitcoin/issues/15619
    


    ryanofsky commented at 3:44 am on April 3, 2019:
    Can drop this whole comment since assumeLocked call is removed.

    ariard commented at 11:22 pm on April 3, 2019:
    Done
  10. in src/wallet/wallet.cpp:1871 in 322638ca7b outdated
    1872-    for (std::pair<const uint256, CWalletTx>& item : mapWallet)
    1873     {
    1874-        const uint256& wtxid = item.first;
    1875-        CWalletTx& wtx = item.second;
    1876-        assert(wtx.GetHash() == wtxid);
    1877+        auto locked_chain = chain().lock();
    


    ryanofsky commented at 3:55 am on April 3, 2019:
    Should be no need to lock again because locked_chain is passed as an argument above. Guessing this is a rebase issue after 0440481c6bf5683eff669c789bdf6a306d99adc5 (#15652)

    ariard commented at 0:24 am on April 4, 2019:
    Yes on my own, should be corrected!
  11. jnewbery commented at 8:32 pm on April 3, 2019: member

    Thanks for looking at this @ariard. My view is different from @ryanofsky’s. I think rather than trying to maintain existing behaviour, we should use this interface tidyup to better define the relationship between the wallet and the node, ie to answer the question “What services should the node offer to the wallet?” Currently, the node exposes two methods to the wallet for sending a transaction:

    1. submitToMemoryPool(const CTransactionRef& tx, CAmount absurd_fee, CValidationState& state): Add transaction to memory pool if the transaction fee is below the amount specified by absurd_fee. Returns false if the transaction could not be added due to the fee or for another reason. This is only called in CWalletTx::AcceptToMemoryPool()
    2. relayTransaction(const uint256& txid): adds the txid to the INV queue for each peer. This is only called in CWalletTx::RelayWalletTransaction() (which also calls CWalletTx::AcceptToMemoryPool())

    Note that to relay an INV for the transaction to peers (2), the transaction must already be in the mempool. See:

    https://github.com/bitcoin/bitcoin/blob/ba54342c9dd3f2e5cdeed9ac57f1924f0d885cc6/src/net_processing.cpp#L3804

    relayTransaction() is only ever called if InMempool() || AcceptToMemoryPool() is true.

    The wallet currently calls CWalletTx::AcceptToMemoryPool() in the following places:

    1a. In CWallet::ReacceptWalletTransactions(), called after the wallet has started up to make sure that its transactions are added to the mempool at start. 2a. In CWalletTx::RelayWalletTransaction(), mentioned above. 3a. In CWallet::CommitTransaction(), when a transaction is to be broadcast to the network for the first time.

    The wallet currently calls CWalletTx::RelayWalletTransaction() in the following places:

    2a. In CWallet::ResendWalletTransactions(), called on a timer to rebroadcast unconfirmed transactions. 2b. In CWallet::CommitTransaction(), but only if the transaction is successfully added to the mempool.

    I’ve been thinking about this in the context of the wallet rebroadcasting transactions (see discussion here: http://www.erisian.com.au/meetbot/bitcoin-core-dev/2019/bitcoin-core-dev.2019-03-29-19.10.log.html#l-9). My view now is that the wallet should not have any access to relay functionality. It should be able to submit transactions to the node’s mempool, and it should then be the mempool’s responsibility to broadcast/rebroadcast the transaction (see comment here: http://www.erisian.com.au/meetbot/bitcoin-core-dev/2019/bitcoin-core-dev.2019-03-29-19.10.log.html#l-92). That seems like a much cleaner divide of responsibility.

    This PR seems like a simplification in terms of combining submitToMemoryPool() and relayTransaction() into a single method, but I don’t think that it moves us towards a point where the node<->wallet interface is simpler to understand.

  12. ryanofsky commented at 8:45 pm on April 3, 2019: member

    John are you just saying that this PR does not go far enough, or that it does something bad or makes things more complicated?

    I haven’t looked closely enough at this yet but if it exposes one node method node instead of two, and reduces the amount of code without changing behavior, it would seem like a strict improvement. Is your rebroadcast proposal harder to implement after this PR?

  13. jnewbery commented at 9:24 pm on April 3, 2019: member

    I haven’t looked closely enough at this yet but if it exposes one node method node instead of two, and reduces the amount of code without changing behavior, it would seem like a strict improvement.

    It does reduce the number of node methods exposed, but does so by adding a flag to one of them which toggles the behaviour. I’m not sure if that counts as a simplification, or it’s just moving the complexity around. I’m also not sure if this maintains existing behaviour. For example, the GetDepthInMainChain(locked_chain) == 0 in RelayWalletTransaction() seems to have gone and not been replaced by anything.

  14. ariard force-pushed on Apr 3, 2019
  15. ariard commented at 11:55 pm on April 3, 2019: member
    I kinda agree with @jnewbery here, wallet shouldn’t have access to relay, because if so it may add complexity of proper tx rebroadcasting tracking, notably in privacy-enhancing context in referenced discussions ? Have taken GetDepthInMainChain and IsCoinbase out, because seems it’s cleaner to let the mempool do the checks, in AcceptToMemoryPoolWorker if I understand it well. And not multiply spurious wallet accesses to chain state. Sorry scope of PR wasn’t clear, would happily change it to underline the real issue I guess.
  16. ariard force-pushed on Apr 4, 2019
  17. DrahtBot added the label Needs rebase on Apr 9, 2019
  18. ryanofsky commented at 2:48 pm on April 9, 2019: member

    Ariard or John, what are next steps? Should this PR be closed and revisited in the future if rebroadcasting is improved? Should the current code comment about this be removed or clarified?

    https://github.com/bitcoin/bitcoin/blob/f3ecf3025f82f84d42ec463990ff787647cc7bf5/src/interfaces/chain.h#L52-L54

  19. jnewbery commented at 3:06 pm on April 9, 2019: member

    I don’t want to discourage @ariard from making this change if you both think it’s an improvement over the existing code. It certainly doesn’t preclude us from makeing the changes that I proposed in #15713 (comment) at a later time. @ariard - if you think this should still go in, can you perhaps break up the PR into commits and justify any changes (eg why remove GetDepthInMainChain and IsCoinbase from RelayWalletTransaction().

    Note that this conflicts with my #15728 which I think is a useful tidy-up in itself.

  20. ariard commented at 10:30 pm on April 9, 2019: member
    Okay will keep working on it by breaking up the PR and justify changes. Had a look on #15728, IMO conflicts should be solved smoothly once yours get into it. @jnewbery I’ve taken notes of your proposed changes of preventing wallet access to relay functionality but as far as I understand it would need first implementation of relay responsibility in mempool, something not submit yet ? Once that done, removing relay from this code path seems really straightforward changes.
  21. ariard force-pushed on Apr 11, 2019
  22. ariard commented at 4:22 pm on April 11, 2019: member
    Rebased, splitted the commits, added justifications. Note that I removed relay flag in BroadcastTransaction, if I get John opinion submitting tx to memory pool should imply relay if it’s a valid one.
  23. DrahtBot removed the label Needs rebase on Apr 11, 2019
  24. in src/interfaces/chain.cpp:299 in 56286233ab outdated
    295@@ -301,10 +296,13 @@ class ChainImpl : public Chain
    296         auto it = ::mempool.GetIter(txid);
    297         return it && (*it)->GetCountWithDescendants() > 1;
    298     }
    299-    void relayTransaction(const uint256& txid) override
    300+    bool broadcastTransaction(const CTransactionRef& tx, uint256& txid, std::string& err_string, const CAmount& absurdfee, bool wait_callback) override
    


    jnewbery commented at 5:08 pm on April 11, 2019:
    This interface function doesn’t need to expose the wait_callback bool since it’s only ever called with wait_callback set to false.

    ariard commented at 1:52 pm on April 12, 2019:
    Ah yes, thanks done
  25. in src/interfaces/chain.cpp:302 in 56286233ab outdated
    300+    bool broadcastTransaction(const CTransactionRef& tx, uint256& txid, std::string& err_string, const CAmount& absurdfee, bool wait_callback) override
    301     {
    302-        CInv inv(MSG_TX, txid);
    303-        g_connman->ForEachNode([&inv](CNode* node) { node->PushInventory(inv); });
    304+        const TransactionError err = BroadcastTransaction(tx, txid, err_string, absurdfee, wait_callback);
    305+        if (TransactionError::OK == err) {
    


    jnewbery commented at 5:09 pm on April 11, 2019:
    nit: return TransactionError::OK == err;

    ariard commented at 1:52 pm on April 12, 2019:
    Yes
  26. in src/wallet/wallet.cpp:2167 in 56286233ab outdated
    1906-    // Don't relay coinbase transactions outside blocks
    1907-    if (IsCoinBase()) return false;
    1908     // Don't relay abandoned transactions
    1909     if (isAbandoned()) return false;
    1910-    // Don't relay conflicted or already confirmed transactions
    1911-    if (GetDepthInMainChain(locked_chain) != 0) return false;
    


    ariard commented at 5:28 pm on April 11, 2019:
    I still have a doubt on BroadcastTransaction HaveChain check behavior. HaveChain = !existingCoin.IsSpent() doesn’t mean if tx is in chain, but all of its outputs has been spent, we accept it again to mempool/relay ?

    Sjors commented at 5:03 pm on July 26, 2019:

    @ariard wrote:

    I still have a doubt on BroadcastTransaction HaveChain check behavior. HaveChain = !existingCoin.IsSpent() doesn’t mean if tx is in chain, but all of its outputs has been spent, we accept it again to mempool/relay ?

    IsSpent() is “misleadingly” named. Because we use AccessCoin: Return a reference to Coin in the cache, or a pruned one if not found.. Pruned in this case means all its CTxOut are IsNull(), and IsSpent() just calls IsNull().


    jnewbery commented at 9:34 pm on July 26, 2019:

    Thanks @Sjors . I agree with you that IsSpent() is a misleading name. A more accurate name would be DoesNotExist(). Negating the function here determines whether the coin exists in the current UTXO set.

    The check in BroadcastTransaction() is an optimization: if any of the outputs from the tx still exist in the UTXO set then the tx must be confirmed. If the coin has been confirmed but it’s outputs don’t exist, then it’ll fail later (because its inputs can’t exist if it has already been spent).

    This check in RelayWalletTransaction() is also an optimization. If the transaction has been confirmed (or a conflicting transaction has been confirmed), then the block hash will be recorded in the CMerkleTx, and we can check in the chain whether that block exists.

    An alternative to removing this call to GetDepthInMainChain() would be to merge #15931 first, which removes GetDepthInMainChain’s requirement on locking the chain.


    jonatack commented at 10:09 am on July 27, 2019:

    Thanks @Sjors . I agree with you that IsSpent() is a misleading name. A more accurate name would be DoesNotExist(). Negating the function here determines whether the coin exists in the current UTXO set.

    The check in BroadcastTransaction() is an optimization: if any of the outputs from the tx still exist in the UTXO set then the tx must be confirmed. If the coin has been confirmed but it’s outputs don’t exist, then it’ll fail later (because its inputs can’t exist if it has already been spent).

    It might be useful to enhance the code documentation added in 976d1e485 with this information (if it isn’t expected to change soon). I found it v helpful to understanding the !existingCoin.IsSpent()) optimisation.

  27. in src/node/transaction.cpp:66 in 56286233ab outdated
    63     }
    64 
    65     } // cs_main
    66 
    67-    promise.get_future().wait();
    68+    if (wait_callback) {
    


    jnewbery commented at 5:32 pm on April 11, 2019:
    I think you can make this slightly clearer by adding a local variable callback_set{false}, setting it to true in the first else if (wait_callback) block, removing the second else if (wait_callback) block, and then testing for it here.

    ariard commented at 1:53 pm on April 12, 2019:
    Okay, also add params comments on it in.h
  28. in src/interfaces/chain.h:186 in 56286233ab outdated
    179@@ -189,8 +180,10 @@ class Chain
    180     //! Check if transaction has descendants in mempool.
    181     virtual bool hasDescendantsInMempool(const uint256& txid) = 0;
    182 
    183-    //! Relay transaction.
    184-    virtual void relayTransaction(const uint256& txid) = 0;
    185+    //! Transaction is added to memory pool, if the transdaction fee is below the
    186+    //! amount specified by absurdfee, and broadcast to all nodes.
    187+    //! Return false if the transaction could not be added due to the fee or for another reason.
    188+    virtual bool broadcastTransaction(const CTransactionRef& tx, uint256& txid, std::string& err_string, const CAmount& absurdfee, bool wait_callback) = 0;
    


    jnewbery commented at 5:34 pm on April 11, 2019:
    nit: I’d prefer to standardise on the name max_tx_fee (rather than max_tx_fee, highfee, absurdfee, etc)
  29. jnewbery commented at 5:34 pm on April 11, 2019: member

    opinion submitting tx to memory pool should imply relay if it’s a valid one

    No, this would cause the wallet to rebroadcast all of its unconfirmed transactions at startup. That’s a change in behaviour and a potentially bad privacy leak.

  30. ariard force-pushed on Apr 12, 2019
  31. in src/interfaces/chain.cpp:302 in bcbc316b6b outdated
    300+    bool broadcastTransaction(const CTransactionRef& tx, uint256& txid, std::string& err_string, const CAmount& max_tx_fee, bool relay) override
    301     {
    302-        CInv inv(MSG_TX, txid);
    303-        g_connman->ForEachNode([&inv](CNode* node) { node->PushInventory(inv); });
    304+        const TransactionError err = BroadcastTransaction(tx, txid, err_string, max_tx_fee, relay, false);
    305+	return TransactionError::OK == err;
    


    jnewbery commented at 3:09 pm on April 12, 2019:
    no tabs please :)

    ariard commented at 3:26 pm on April 13, 2019:
    Thanks, configured my editor accordingly!
  32. in src/interfaces/chain.h:184 in bcbc316b6b outdated
    179@@ -189,8 +180,10 @@ class Chain
    180     //! Check if transaction has descendants in mempool.
    181     virtual bool hasDescendantsInMempool(const uint256& txid) = 0;
    182 
    183-    //! Relay transaction.
    184-    virtual void relayTransaction(const uint256& txid) = 0;
    185+    //! Transaction is added to memory pool, if the transdaction fee is below the
    186+    //! amount specified by max_tx_fee, and broadcast to all nodes.
    


    jnewbery commented at 3:10 pm on April 12, 2019:
    s/broadcast to all nodes/broadcast to all peers if relay is set to true/
  33. in src/node/transaction.cpp:56 in bcbc316b6b outdated
    52@@ -52,6 +53,7 @@ TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx,
    53             CallFunctionInValidationInterfaceQueue([&promise] {
    54                 promise.set_value();
    55             });
    56+	    callback_set = true;
    


    jnewbery commented at 3:12 pm on April 12, 2019:
    tab
  34. in src/node/transaction.cpp:73 in bcbc316b6b outdated
    64@@ -63,7 +65,9 @@ TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx,
    65 
    66     } // cs_main
    67 
    68-    promise.get_future().wait();
    69+    if (callback_set) {
    


    jnewbery commented at 3:12 pm on April 12, 2019:
    you can remove the else block in LL60-64
  35. in src/node/transaction.h:20 in bcbc316b6b outdated
    15@@ -16,9 +16,11 @@
    16  * @param[in]  tx the transaction to broadcast
    17  * @param[out] &txid the txid of the transaction, if successfully broadcast
    18  * @param[out] &err_string reference to std::string to fill with error string if available
    19- * @param[in]  highfee Reject txs with fees higher than this (if 0, accept any fee)
    20+ * @param[in]  max_tx_fee reject txs with fees higher than this (if 0, accept any fee)
    21+ * @param[in]  relay flag if both mempool insertion and p2p relay  are requested
    


    jnewbery commented at 3:13 pm on April 12, 2019:
    nit: two spaces

    ariard commented at 3:28 pm on April 13, 2019:
    Corrected but was to align with other descriptions?

    jnewbery commented at 2:09 pm on April 15, 2019:
    sorry, I meant the two spaces between relay and are. I think two spaces at the front to align with the other params is fine.
  36. in src/rpc/rawtransaction.cpp:34 in bcbc316b6b outdated
    35@@ -36,7 +36,6 @@
    36 #include <validation.h>
    37 #include <validationinterface.h>
    38 
    39-
    


    jnewbery commented at 3:14 pm on April 12, 2019:
    nit: don’t include unnecessary whitespace changes
  37. in src/node/transaction.cpp:16 in bcbc316b6b outdated
    12@@ -13,10 +13,11 @@
    13 
    14 #include <future>
    15 
    16-TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx, std::string& err_string, const CAmount& highfee)
    17+TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
    


    jnewbery commented at 3:15 pm on April 12, 2019:
    You’ve added the relay bool but you’re not using it.

    jnewbery commented at 3:53 pm on April 16, 2019:
    You could remove the hashTx parameter from this interface method. The only caller of the method supplies an unused uint256 and then throws it away.
  38. in src/wallet/wallet.h:518 in bcbc316b6b outdated
    514@@ -515,11 +515,8 @@ class CWalletTx : public CMerkleTx
    515 
    516     int64_t GetTxTime() const;
    517 
    518-    // Pass this transaction to the node to relay to its peers
    519-    bool RelayWalletTransaction(interfaces::Chain::Lock& locked_chain);
    520-
    521-    /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
    522-    bool AcceptToMemoryPool(interfaces::Chain::Lock& locked_chain, CValidationState& state);
    523+    // SubmitMemoryPoolAndRelay may only be called if fBroadcastTransactions!
    


    jnewbery commented at 3:17 pm on April 12, 2019:

    This comment is incorrect. The function will just return immediately if fBroadcastTransactions is set to false.

    (I think this is from a bad rebase. The comment was changed to Pass this transaction to the node to relay to its peers in a more recent version.)

  39. in src/wallet/wallet.cpp:1895 in bcbc316b6b outdated
    1890@@ -1892,30 +1891,27 @@ void CWallet::ReacceptWalletTransactions(interfaces::Chain::Lock& locked_chain)
    1891     // Try to add wallet transactions to memory pool
    1892     for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
    1893         CWalletTx& wtx = *(item.second);
    1894-        CValidationState state;
    1895-        wtx.AcceptToMemoryPool(locked_chain, state);
    1896+        std::string err_string;
    1897+        wtx.SubmitMemoryPoolAndRelay(err_string);
    


    jnewbery commented at 3:18 pm on April 12, 2019:
    This is a behaviour change. You’re relaying the transaction instead of just adding it to the mempool.
  40. in src/wallet/wallet.cpp:1914 in bcbc316b6b outdated
    1925+    // We must set fInMempool here - while it will be re-set to true by the
    1926+    // entered-mempool callback, if we did not there would be a race where a
    1927+    // user could call sendmoney in a loop and hit spurious out of funds errors
    1928+    // because we think that this newly generated transaction's change is
    1929+    // unavailable as we're not yet aware that it is in the mempool.
    1930+    if (!(fInMempool |= pwallet->chain().broadcastTransaction(tx, txid, err_string, pwallet->chain().maxTxFee(), false))) return false;
    


    jnewbery commented at 3:24 pm on April 12, 2019:
    Review note: This is a minor behaviour change. chain().broadcastTransaction() could return false if BroadcastTransaction() returned TransactionError::P2P_DISABLED (ie the transaction is added to the mempool but not relayed).

    jnewbery commented at 5:01 pm on April 12, 2019:

    This is also a behaviour change because previously, AcceptToMemoryPool() would return false if submitToMemoryPool() returned false. Now, if fInMempool is set to true but broadcastTransaction() returns false, then it’ll return true.

    I think it makes sense to stick with the structure of the old AcceptToMemoryPool() function.


    ariard commented at 3:30 pm on April 13, 2019:
    What’s your take on returning a pair of boolean from chain().broadcastTransaction() to encode both mempool/relay results ?

    ariard commented at 3:30 pm on April 13, 2019:
    Okay back to AcceptToMemoryPool structure

    jnewbery commented at 2:15 pm on April 15, 2019:
    In the existing code there’s not a return code for chain::relayTransaction(). I think it’s fine for the new broadcastTransaction interface method to only return false if the transaction failed to get into the mempool, and treat TransactionError::P2P_DISABLED as success. That way, fInMempool will get updated in exactly the same way as the existing code.

    ariard commented at 1:30 pm on April 16, 2019:
    Good, added TransactionError::P2P_DISABLED == err check in broadcastTransaction interface
  41. in src/wallet/wallet.cpp:1894 in bcbc316b6b outdated
    1890@@ -1892,30 +1891,27 @@ void CWallet::ReacceptWalletTransactions(interfaces::Chain::Lock& locked_chain)
    1891     // Try to add wallet transactions to memory pool
    1892     for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
    1893         CWalletTx& wtx = *(item.second);
    1894-        CValidationState state;
    1895-        wtx.AcceptToMemoryPool(locked_chain, state);
    1896+        std::string err_string;
    


    jnewbery commented at 3:27 pm on April 12, 2019:
    Consider naming thuis unused_err_string to indicate that we throw it away without using it.
  42. in src/wallet/wallet.cpp:2158 in bcbc316b6b outdated
    2154@@ -2160,9 +2155,10 @@ void CWallet::ResendWalletTransactions()
    2155             // only rebroadcast unconfirmed txes older than 5 minutes before the
    2156             // last block was found
    2157             if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
    2158-            if (wtx.RelayWalletTransaction(*locked_chain)) ++relayed_tx_count;
    2159+            std::string err_string;
    


    jnewbery commented at 3:27 pm on April 12, 2019:
    Consider naming thuis unused_err_string to indicate that we throw it away without using it.
  43. ariard force-pushed on Apr 12, 2019
  44. in src/node/transaction.h:21 in 94623bd791 outdated
    15@@ -16,9 +16,11 @@
    16  * @param[in]  tx the transaction to broadcast
    17  * @param[out] &txid the txid of the transaction, if successfully broadcast
    18  * @param[out] &err_string reference to std::string to fill with error string if available
    19- * @param[in]  highfee Reject txs with fees higher than this (if 0, accept any fee)
    20+ * @param[in]  max_tx_fee reject txs with fees higher than this (if 0, accept any fee)
    21+ * @param[in]  relay flag if both mempool insertion and p2p relay  are requested
    22+ * @param[in]  wait_callback, wait until callbacks have been processed to avoid stale result due to a sequentially RPC
    


    jnewbery commented at 5:08 pm on April 12, 2019:
    Thanks for adding comments. I’d add to the description of the wait_callback param that this must not be set while cs_main, cs_mempool or cs_wallet is being held or there’ll be a deadlock.
  45. jnewbery commented at 5:10 pm on April 12, 2019: member
    A few comments inline. The intermediate commit 07d5787041461bcfb8b5777809d874869710aa1e does not build because locked_chain is not defined in SubmitMemoryPoolAndRelay().
  46. ariard force-pushed on Apr 13, 2019
  47. ariard commented at 3:32 pm on April 13, 2019: member
    Thanks @jnewbery for the review and sorry for the ugly commit split. I think I’ve addressed all your points except this one : #15713 (review) ?
  48. in src/interfaces/chain.h:183 in 602e38d0a7 outdated
    179@@ -189,8 +180,10 @@ class Chain
    180     //! Check if transaction has descendants in mempool.
    181     virtual bool hasDescendantsInMempool(const uint256& txid) = 0;
    182 
    183-    //! Relay transaction.
    184-    virtual void relayTransaction(const uint256& txid) = 0;
    185+    //! Transaction is added to memory pool, if the transdaction fee is below the
    


    practicalswift commented at 2:00 pm on April 15, 2019:
    Nit: Should be “transaction” :-)

    ariard commented at 1:30 pm on April 16, 2019:
    Thanks, good catch!
  49. in src/wallet/wallet.cpp:1899 in 602e38d0a7 outdated
    1897+        wtx.SubmitMemoryPoolAndRelay(unused_err_string, false, locked_chain);
    1898     }
    1899 }
    1900 
    1901-bool CWalletTx::RelayWalletTransaction(interfaces::Chain::Lock& locked_chain)
    1902+bool CWalletTx::SubmitMemoryPoolAndRelay(std::string& err_string, bool relay, interfaces::Chain::Lock& locked_chain)
    


    jnewbery commented at 2:16 pm on April 15, 2019:
    You now have locked_chain as a parameter, even though it’s unused in this function in the final commit.

    ariard commented at 1:31 pm on April 16, 2019:
    Yes rebase issue, should be solved
  50. jnewbery commented at 2:17 pm on April 15, 2019: member
    Still a couple of minor issues to fix up.
  51. ariard force-pushed on Apr 16, 2019
  52. in src/interfaces/chain.cpp:33 in b857c21ffd outdated
    29@@ -30,6 +30,7 @@
    30 #include <util/system.h>
    31 #include <validation.h>
    32 #include <validationinterface.h>
    33+#include <node/transaction.h>
    


    jnewbery commented at 3:40 pm on April 16, 2019:
    nit: sort includes
  53. in src/interfaces/chain.cpp:301 in b857c21ffd outdated
    295@@ -301,10 +296,10 @@ class ChainImpl : public Chain
    296         auto it = ::mempool.GetIter(txid);
    297         return it && (*it)->GetCountWithDescendants() > 1;
    298     }
    299-    void relayTransaction(const uint256& txid) override
    300+    bool broadcastTransaction(const CTransactionRef& tx, uint256& txid, std::string& err_string, const CAmount& max_tx_fee, bool relay) override
    301     {
    302-        CInv inv(MSG_TX, txid);
    303-        g_connman->ForEachNode([&inv](CNode* node) { node->PushInventory(inv); });
    304+        const TransactionError err = BroadcastTransaction(tx, txid, err_string, max_tx_fee, relay, false);
    


    jnewbery commented at 3:42 pm on April 16, 2019:

    nit: could include an inline comment for the last parameter:

    0const TransactionError err = BroadcastTransaction(tx, txid, err_string, max_tx_fee, relay, /*wait_callback*/ false);
    
  54. in src/node/transaction.cpp:78 in b857c21ffd outdated
    68-    promise.get_future().wait();
    69+    if (callback_set) {
    70+        promise.get_future().wait();
    71+    }
    72 
    73     if (!g_connman) {
    


    jnewbery commented at 3:45 pm on April 16, 2019:
    Should this also be within the if (relay) block? Returning a TransactionError::P2P_DISABLED error when the caller hasn’t asked for the transaction to be relayed seems wrong.
  55. in src/wallet/wallet.cpp:1908 in b857c21ffd outdated
    1920-    pwallet->chain().relayTransaction(GetHash());
    1921 
    1922-    return true;
    1923+    // Submit transaction to mempool for relay
    1924+    pwallet->WalletLogPrintf("Submitting wtx %s to mempool for relay\n", GetHash().ToString());
    1925+    uint256 txid;
    


    jnewbery commented at 3:51 pm on April 16, 2019:
    See comment in interface/chain.h. I recommend you remove the unused uint256 from the interface method.
  56. in src/interfaces/chain.cpp:295 in b857c21ffd outdated
    300+    bool broadcastTransaction(const CTransactionRef& tx, uint256& txid, std::string& err_string, const CAmount& max_tx_fee, bool relay) override
    301     {
    302-        CInv inv(MSG_TX, txid);
    303-        g_connman->ForEachNode([&inv](CNode* node) { node->PushInventory(inv); });
    304+        const TransactionError err = BroadcastTransaction(tx, txid, err_string, max_tx_fee, relay, false);
    305+        return TransactionError::OK == err || TransactionError::P2P_DISABLED == err;
    


    jnewbery commented at 3:56 pm on April 16, 2019:

    This is exactly right, but I think it could do with a comment. Something like:

    0// Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures
    1// Note: this will need to be updated if BroadcastTransaction() is updated to return other non-mempool failures
    2// that Chain clients do not need to know about.
    
  57. jnewbery commented at 3:56 pm on April 16, 2019: member
    Looking really good. Just a few more nits!
  58. ariard force-pushed on Apr 17, 2019
  59. ariard commented at 1:11 pm on April 17, 2019: member

    a00303c updated with @jnewbery last review comments, specially removing unused uint256 from BroadcastTransaction interface

    And “Initial build successful, but not enough time remains to run later build stages and tests. Please manually re-run this job by using the travis restart button or asking a bitcoin maintainer to restart. The next run should not time out because the build cache has been saved.”

  60. ryanofsky commented at 4:48 pm on April 17, 2019: member
    Looks like this might also help a little bit with #14912, since right now it’s adding another broadcastTransaction method (a7678372bd8b4ef4ce33a406559a0ea860ce1abf).
  61. jnewbery commented at 5:10 pm on April 17, 2019: member

    Looks good. utACK e5b0fe904a9c6186b8273c61e93ee1538418b245

    (I was only suggesting to remove the uint256 from the interface broadcastTransaction() method, not the BroadcastTransaction() function in node/transaction, but removing it there is also fine I think.)

  62. DrahtBot added the label Needs rebase on Apr 27, 2019
  63. Sjors commented at 2:28 pm on April 30, 2019: member

    Concept ACK on adding this as an interface method (I haven’t studied the rest). I helps me drop one commit from the hardware wallet support PR #14912.

    It makes sense to filter some error messages in BroadcastTransaction, but for those that do make it through, at least the err_string - but probably also TransactionError - is useful for the client. So maybe it’s better to change TransactionError::OK and erase the error message for errors that we don’t want to propagate.

  64. ariard commented at 3:58 pm on May 2, 2019: member
    @Sjors you mean erasing errors which seems to be used by no one right now (like TransactionError::MEMPOOL_ERROR) and just return a generic error for these cases ? Or returning errors from broadcastTransactions instead of a boolean and let caller to filter ?
  65. ariard force-pushed on May 2, 2019
  66. DrahtBot removed the label Needs rebase on May 2, 2019
  67. Sjors commented at 1:11 pm on May 12, 2019: member
    @ariard I think it should return a TransactionError. You can filter it before returning, based on what you don’t want callers to see. But not based on what’s “used by no one right now”.
  68. jnewbery commented at 3:35 pm on May 16, 2019: member

    You can filter it before returning, based on what you don’t want callers to see. But not based on what’s “used by no one right now”.

    I think it’s fine to have the broadcastTransaction interface return what’s most useful to our wallet right now. This interface is meant to be private, so having it customized to our needs is ok, and if future changes to the wallet require the interface method to be changed to return more information, that’s also fine.

  69. ariard commented at 4:03 am on May 17, 2019: member
    Okay, well let it as of 0a1f4d9 with broadcastTransaction returning a boolean. But I checked failures, and seems like #15696 is causing functional test failures even locally..
  70. Sjors commented at 2:46 pm on May 17, 2019: member
    Boolean is fine for my purposes as well.
  71. DrahtBot added the label Needs rebase on May 17, 2019
  72. ariard force-pushed on May 18, 2019
  73. ariard commented at 1:29 am on May 18, 2019: member
    Rebased.
  74. DrahtBot removed the label Needs rebase on May 18, 2019
  75. DrahtBot added the label Needs rebase on May 23, 2019
  76. ariard force-pushed on May 29, 2019
  77. DrahtBot removed the label Needs rebase on May 29, 2019
  78. ariard force-pushed on May 30, 2019
  79. ariard force-pushed on Jul 9, 2019
  80. ariard force-pushed on Jul 10, 2019
  81. fanquake added this to the "Blockers" column in a project

  82. in src/interfaces/chain.cpp:295 in f2da7210c8 outdated
    300+    {
    301+        const TransactionError err = BroadcastTransaction(tx, err_string, max_tx_fee, relay, /*wait_callback*/ false);
    302+        // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.
    303+        // Note: this will need to be updated if BroadcastTransactions() is updated to return other non-mempool failures
    304+        // that Chain clients do not need to know about.
    305+        return TransactionError::OK == err || TransactionError::P2P_DISABLED == err;
    


    ajtowns commented at 4:20 am on July 23, 2019:

    Might be better to do:

     0switch(err) {
     1    case TransactionError::OK:
     2    case TransactionError::P2P_DISABLED:
     3        return true;
     4    case TransactionError::MISSING_INPUTS:
     5    case TransactionError::ALREADY_IN_CHAIN:
     6    case TransactionError::MEMPOOL_REJECTED:
     7    case TransactionError::MEMPOOL_ERROR:
     8    case TransactionError::INVALID_PSBT:
     9    case TransactionError::PSBT_MISMATCH:
    10    case TransactionError::SIGHASH_MISMATCH:
    11    case TransactionError::MAX_FEE_EXCEEDED:
    12        return false;
    13}
    

    That way you get a warning if there’s other values added that you haven’t handled.


    jnewbery commented at 3:52 pm on July 23, 2019:
    I don’t think it really matters too much. If new TransactionError values are added that the wallet needs to handle, this interface can be updated.
  83. jnewbery commented at 11:01 pm on July 23, 2019: member
    utACK 67c7db7a22e18cee5364652b9a1ab102c9fb1858
  84. in src/node/transaction.cpp:79 in 67c7db7a22 outdated
    75 
    76-    CInv inv(MSG_TX, hashTx);
    77-    g_connman->ForEachNode([&inv](CNode* pnode) {
    78-        pnode->PushInventory(inv);
    79-    });
    80+    if (relay) {
    


    amitiuttarwar commented at 11:14 pm on July 23, 2019:
    could this use the relay txn method in net_processing?

    ariard commented at 5:35 pm on July 24, 2019:
    why not, see #16452 because it can go on its own
  85. jonatack commented at 6:13 pm on July 24, 2019: member
    utACK 67c7db7a22e18cee5364652b9a1ab102c9fb1858. Reviewed, built, ran all unit/functional tests. Agree with @ajtowns concerning #15713 (review) to have a bit of a safety rail.
  86. amitiuttarwar commented at 7:08 pm on July 24, 2019: contributor
    utACK 67c7db7a22e18cee5364652b9a1ab102c9fb1858. Carefully read the code, built & ran all tests.
  87. ariard force-pushed on Jul 24, 2019
  88. ariard commented at 8:21 pm on July 24, 2019: member
    New tip at c1351e2 with @jnewbery BroadcastTransaction cleaning commit
  89. jnewbery commented at 8:27 pm on July 24, 2019: member

    ACK c1351e28fd2e38a928b322456038198aa0e847bd

    (but I don’t think it’s necessary to take that commit and invalidate @amitiuttarwar and @jonatack reviews)

  90. ariard force-pushed on Jul 24, 2019
  91. jonatack commented at 3:10 pm on July 25, 2019: member

    ACK 976d1e4858df00c031ef2c07790862948dbc04cf, all tests pass, local git range-diff shows no change in previously-ACKed commits.

    New commit makes doc-only changes in src/node/transaction.h and cleans up the BroadcastTransaction logic in src/node/transaction.cpp + improves code documentation.

    I found #15713 (review) helpful in reviewing the last commit – this info could be added to the code documentation.

    IIUC the logic changes in 976d1e4858 are

    before

    0if txn not in mempool and coin does not exist in the current UTXO set
    1  submit txn
    2else if coin exists in the current UTXO set
    3  return "already in chain" txn error
    4else
    5  ensure we don't block if re-sending a transaction already in mempool
    6end
    

    now

    0exit loop and return "already in chain" txn error if coin exists in the current UTXO set
    1
    2if txn not in mempool
    3  submit txn
    4end
    

    EDIT: upgraded from partial ACK to ACK after re-review based on #15713 (review).

  92. jnewbery commented at 3:32 pm on July 25, 2019: member
    ACK 976d1e485
  93. in src/rpc/rawtransaction.cpp:814 in 87cca293d5 outdated
    806@@ -807,14 +807,13 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
    807         max_raw_tx_fee = fr.GetFee((weight+3)/4);
    808     }
    809 
    810-    uint256 txid;
    811     std::string err_string;
    812-    const TransactionError err = BroadcastTransaction(tx, txid, err_string, max_raw_tx_fee);
    813+    const TransactionError err = BroadcastTransaction(tx, err_string, max_raw_tx_fee, true, true);
    


    promag commented at 4:15 pm on July 26, 2019:

    87cca293d5b127e43e35d866167893454658eacd

    nit, could add a comment on the last 2 args.

  94. in src/node/transaction.cpp:73 in 87cca293d5 outdated
    80+    if (relay) {
    81+        if (!g_connman) {
    82+            return TransactionError::P2P_DISABLED;
    83+        }
    84+        CInv inv(MSG_TX, hashTx);
    85+        g_connman->ForEachNode([&inv](CNode* pnode) {
    


    promag commented at 4:17 pm on July 26, 2019:

    87cca293d5b127e43e35d866167893454658eacd

    just noting that this must be changed in #16452 to RelayTransaction.

  95. in src/node/transaction.h:26 in 87cca293d5 outdated
    13@@ -14,11 +14,13 @@
    14  * Broadcast a transaction
    15  *
    16  * @param[in]  tx the transaction to broadcast
    17- * @param[out] &txid the txid of the transaction, if successfully broadcast
    18  * @param[out] &err_string reference to std::string to fill with error string if available
    19- * @param[in]  highfee Reject txs with fees higher than this (if 0, accept any fee)
    20+ * @param[in]  max_tx_fee reject txs with fees higher than this (if 0, accept any fee)
    21+ * @param[in]  relay flag if both mempool insertion and p2p relay are requested
    22+ * @param[in]  wait_callback, wait until callbacks have been processed to avoid stale result due to a sequentially RPC.
    


    promag commented at 4:18 pm on July 26, 2019:

    87cca293d5b127e43e35d866167893454658eacd

    I think a better description/use-case is needed here.


  96. in src/node/transaction.cpp:30 in 976d1e4858 outdated
    25+    // and return early.
    26     CCoinsViewCache &view = *pcoinsTip;
    27-    bool fHaveChain = false;
    28-    for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
    29+    for (size_t o = 0; o < tx->vout.size(); o++) {
    30         const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
    


    Sjors commented at 5:07 pm on July 26, 2019:
    Nit: add comment explaining IsSpent() doesn’t mean the coin is spent; it means the output doesn’t exist. So if the output does exist, then this transaction exists in the chain, i.e. it’s already confirmed.

    jnewbery commented at 9:34 pm on July 26, 2019:
    Agree that a comment here would be helpful in a follow-up commit.

    ariard commented at 11:49 pm on July 26, 2019:
    Yes agree better documentation and refactoring of BroadcastTransaction can be pushed further in latter work.
  97. Sjors approved
  98. Sjors commented at 5:08 pm on July 26, 2019: member

    Code review ACK 976d1e4.

    As to why dropping if (GetDepthInMainChain(locked_chain) != 0) return false; is safe, IIUC because BroadcastTransaction loops through the transaction outputs and checks if they exist at the chain tip. By the way, the use of AccessCoin and IsSpent (actually meaning: “does not exist”) in BroadcastTransaction seems a needlessly confusing optimization.

  99. mzumsande commented at 8:31 pm on July 26, 2019: member

    I’m not sure if broadcastTransaction should suppress TransactionError::P2P_DISABLED. From the old discussion with @jnewbery above I gather that this is the case because the old relayTransaction() didn’t have a return code, and so that we can update fInMempool conveniently.

    However, the old CWalletTx::RelayWalletTransaction() had an explicite check for P2P (if (!pwallet->chain().p2pEnabled()) return false;) so if the node was not connected to the p2p network it would not call relayTransaction() and return false. Its replacement function SubmitMemoryPoolAndRelay doesn’t have this check and will return true in this case, so this looks like a change in behavior ( minor because its return value is only used for log messages as far as I can see).

  100. jnewbery commented at 9:41 pm on July 26, 2019: member

    Its replacement function SubmitMemoryPoolAndRelay doesn’t have this check and will return true in this case, so this looks like a change in behavior ( minor because its return value is only used for log messages as far as I can see).

    Great catch @mzumsande! I agree that this is a slight change in behaviour, but that it’s only used for logging in ResendWalletTransactions() (The return value in CommitTransaction() should be the same as before).

  101. ariard commented at 11:41 pm on July 26, 2019: member
    Thanks for review @mzumsande, I agree that’s a light change in behavior even it was only logs. IMO p2pEnabled is just there when wallet is init before g_connman, and a quick look at init.cpp I’m not even sure that’s something possible. In future works, I’m thinking to remove p2pEnabled once we have the wallet registering its current height with Chain interface at handleNotifications. Wallet will only submit tx to the mempool and shouldn’t be aware of P2P state.
  102. mzumsande commented at 9:58 pm on July 28, 2019: member
    Thanks for the answer. In light of the intended future direction it makes sense not to implement a more fine-grained error handling with separate errors for mempool and relay. ACK 976d1e4858df00c031ef2c07790862948dbc04cf (reviewed the code and ran tests).
  103. in src/node/transaction.h:19 in 976d1e4858 outdated
    15+ * Submit a transaction to the mempool and (optionally) relay it to all P2P peers.
    16+ *
    17+ * Mempool submission can be synchronous (will await mempool entry notification
    18+ * over the CValidationInterface) or asynchronous (will submit and not wait for
    19+ * notification), depending on the value of wait_callback. wait_callback MUST
    20+ * NOT be set while cs_main, cs_mempool or cs_wallet are held to avoid
    


    MarcoFalke commented at 12:41 pm on July 30, 2019:
    Why not assert this with an AssertLockNotHeld?

    ariard commented at 8:37 pm on July 30, 2019:
    Yes, we should do that in sendrawtransaction, which is out of scope for this PR (but glad to address it in another PR if you think that’s relevant)

    MarcoFalke commented at 2:45 pm on July 31, 2019:
    Ok, lets do this in a follow-up

    ariard commented at 3:53 pm on July 31, 2019:
    @MarcoFalke should I include headers for mempool and wallet to AssertLockNotHeld these locks too ?
  104. in src/wallet/wallet.cpp:2356 in 655170a3bd outdated
    2351@@ -2353,7 +2352,8 @@ void CWallet::ResendWalletTransactions()
    2352             // only rebroadcast unconfirmed txes older than 5 minutes before the
    2353             // last block was found
    2354             if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
    2355-            if (wtx.RelayWalletTransaction(*locked_chain)) ++relayed_tx_count;
    2356+            std::string unused_err_string;
    2357+            if (wtx.SubmitMemoryPoolAndRelay(unused_err_string, true, *locked_chain)) ++relayed_tx_count;
    


    MarcoFalke commented at 3:39 pm on July 30, 2019:
    This counts txs even if p2p is disabled? Previously we wouldn’t.

    ariard commented at 8:48 pm on July 30, 2019:
    I guess we should recall it submitted_count ? Wallet is just submitting to mempool and that’s mempool job to pass it to P2P. We don’t dissociate errors here anyways

    MarcoFalke commented at 9:12 pm on July 30, 2019:
    I don’t care. It is only a log print, so can be done later. Though, I wanted to point out the change in behavior, since you tagged this with “refactor”.

    ariard commented at 10:47 pm on July 30, 2019:
    Yes sorry for that, I modified the PR a bit since opening, so it’s no more a refactor I guess..

    MarcoFalke commented at 2:45 pm on July 31, 2019:
    Lets do this in a follow-up, if important enough
  105. in src/wallet/wallet.cpp:2166 in 655170a3bd outdated
    2150-    pwallet->chain().relayTransaction(GetHash());
    2151 
    2152-    return true;
    2153+    // Submit transaction to mempool for relay
    2154+    pwallet->WalletLogPrintf("Submitting wtx %s to mempool for relay\n", GetHash().ToString());
    2155+    // We must set fInMempool here - while it will be re-set to true by the
    


    MarcoFalke commented at 3:43 pm on July 30, 2019:

    Would be nice to update the comment here. This has been forgotten in 6ef86c92e7fcba866160d7a346fb260d7e4ab5bb

    I guess you can just copy the commit body or something.


    ariard commented at 9:01 pm on July 30, 2019:
    Noted if I have to rebase, or if I can throw it in one of my other PR touching this code

    MarcoFalke commented at 2:46 pm on July 31, 2019:
    Lets do this in a follow up
  106. in src/wallet/wallet.cpp:2163 in 06519838e0 outdated
    2134+bool CWalletTx::SubmitMemoryPoolAndRelay(std::string& err_string, bool relay)
    2135 {
    2136     // Can't relay if wallet is not broadcasting
    2137     if (!pwallet->GetBroadcastTransactions()) return false;
    2138-    // Don't relay coinbase transactions outside blocks
    2139-    if (IsCoinBase()) return false;
    


    MarcoFalke commented at 3:48 pm on July 30, 2019:
    Why is this trivial check removed? It avoids a lookup in the utxo database, no?

    ariard commented at 8:57 pm on July 30, 2019:
    You mean compare to the one at beginning of ATMP ?

    MarcoFalke commented at 9:10 pm on July 30, 2019:
    BroadcastTransaction does a convenience check that is only used in the sendrawtransaction (to notify a user of a transaction that is already confirmed). This is done by looking up if at least one of the outputs is in the utxo set. For the purpose of the wallet, this check is completely useless. Previously we wouldn’t call it and now we do (even for coinbase txs), where it can be trivially avoided.

    ariard commented at 10:54 pm on July 30, 2019:
    Ah yes, should the wallet try to check as much as confirmation rules it can, like the coinbase one ? It’s a layer violation, but that’s trivial as you said.

    MarcoFalke commented at 1:06 am on July 31, 2019:
    Why is it a layer violation of the wallet to call a pure method on one of it’s txs?

    ariard commented at 1:36 am on July 31, 2019:
    Really IMO, it’s a layer violation because the wallet is doing the job of the node to check consensus rules instead of relying on what the node says.

    ariard commented at 1:37 am on July 31, 2019:
    Do you want I update to get back the check ? Wallet are not going to broadcast thousands of coinbase transactions to this be real performance issue.

    jnewbery commented at 2:14 pm on July 31, 2019:

    I agree with Marco that this isn’t a layer violation. IsCoinBase() is a pure utility function and can be called anywhere.

    But I also agree with ariard that this isn’t a big deal. Calling IsCoinBase() here is an optimization that affects a tiny number of transactions for a tiny number of users.


    promag commented at 0:37 am on August 7, 2019:
    Reverted in #16557.
  107. in src/wallet/wallet.cpp:2167 in 976d1e4858 outdated
    2139-    // Don't relay coinbase transactions outside blocks
    2140-    if (IsCoinBase()) return false;
    2141     // Don't relay abandoned transactions
    2142     if (isAbandoned()) return false;
    2143-    // Don't relay conflicted or already confirmed transactions
    2144-    if (GetDepthInMainChain(locked_chain) != 0) return false;
    


    MarcoFalke commented at 3:56 pm on July 30, 2019:
    Looks like you are replacing a map lookup (LookupBlockIndex) with an utxo lookup. So going from memory to disk. Is this going to have a performance penalty?

    ariard commented at 9:11 pm on July 30, 2019:
    You mean relying on AccessCoin in BroadcastTransaction. Isn’t CCoinsViewCache a in-memory cache? Is the wallet broadcasting that much transactions so it can be a performance penalty ? GetDepthInMainChain is also currently locking the chain via getBlockHeight

    Sjors commented at 10:04 am on August 2, 2019:
    CCoinsViewCache hits disk if the in memory cache doesn’t contain the coin we’re looking for. I doubt the performance matters for the wallet, unlike e.g. peer to peer mempool relay.
  108. MarcoFalke commented at 4:00 pm on July 30, 2019: member

    ACK 976d1e4858df00c031ef2c07790862948dbc04cf, some questions

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK 976d1e4858df00c031ef2c07790862948dbc04cf, some questions
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUiQegv/UAc28xrmuUqCZFUkvZtoLuw2Bq7qPa5zsh4Qr63OKNgh+BlzIh02YB3E
     8l+8XvwKaPIhEk+flUc5KrBHpCe5kbRe0sY3X1FFVCI5ENTSKmm2+9U81ISgEAaZR
     9nrZQL3kiwjSXN65k4lH3QfDgLJn5+LDZbW++Q/0NMFczMOPufEWZ168YXaZVnjpn
    10Ts5cqHG4wfCdpbWVq8fFLxIYSKQEbu55+nheGG2dbDKu+qVSxt1J2+1NnAsVWHmh
    11PTaUg9tmZqtpZuagHO7wGZj2Iwk7XZFjwi2htbKqoHjrOlov21FFZkcslAgc6Go4
    12tvz0S0Bo5Y2mGRJ4wrioTfoDs0WFci2zBFdE1EQ11+hSuDGTcny4CKcnSFmlRWlc
    13BD/34jM+55HM0okGs8lk6USeDsC7pn9Lzka6VOgM6D/N+O9nekimQvACdtY4/FHl
    145fFiZp4Jc6hiYMIqyJsy+ooFufQTX6pVvGBrk7OVBE9GvCWFLAbv+arfO+1z4UUU
    15uk0WUV1R
    16=wLf3
    17-----END PGP SIGNATURE-----
    

    Timestamp of file with hash 27c1d332b653a5bb053c1a397b8772ee22e02d0e8091c6dfbe094774aaab128f -

  109. MarcoFalke commented at 1:10 pm on July 31, 2019: member

    See a patch (on top of master and this pull) for what I was thinking:

    0001-Check-utxo-db-early-only-when-requested-in-Broadcast.patch.txt

  110. in src/interfaces/chain.cpp:290 in eda13b8679 outdated
    284@@ -290,10 +285,13 @@ class ChainImpl : public Chain
    285         auto it = ::mempool.GetIter(txid);
    286         return it && (*it)->GetCountWithDescendants() > 1;
    287     }
    288-    void relayTransaction(const uint256& txid) override
    289+    bool broadcastTransaction(const CTransactionRef& tx, std::string& err_string, const CAmount& max_tx_fee, bool relay) override
    290     {
    291-        CInv inv(MSG_TX, txid);
    292-        g_connman->ForEachNode([&inv](CNode* node) { node->PushInventory(inv); });
    293+        const TransactionError err = BroadcastTransaction(tx, err_string, max_tx_fee, relay, /*wait_callback*/ false, /*check_chain*/ false);
    


    MarcoFalke commented at 2:43 pm on July 31, 2019:

    Sorry, I think I got this wrong in my patch

    0        const TransactionError err = BroadcastTransaction(tx, err_string, max_tx_fee, relay, /*check_chain*/ false, /*wait_callback*/ false);
    
  111. ariard force-pushed on Jul 31, 2019
  112. ariard commented at 2:50 pm on July 31, 2019: member

    Okay pushed with your patch amended to invert comment on 4441ba6c.

    More I looking at BroadcastTransaction, more I think it needs a PR of its own, maybe I can take your commit here and try to simplify more things?

  113. MarcoFalke referenced this in commit 7821821a23 on Jul 31, 2019
  114. jnewbery commented at 2:53 pm on July 31, 2019: member

    I don’t like Marco’s suggested change. It’s leaking implementation detail to the caller and complicating the function interface. I also don’t understand the problem it’s supposed to be solving - is it just a performance optimization so that we don’t do the UTXO check for wallet-submitted transactions?

    This PR had a bunch of ACKs without that change. Does it need to be included before this PR can be merged?

  115. MarcoFalke commented at 2:57 pm on July 31, 2019: member

    This PR had a bunch of ACKs without that change. Does it need to be included before this PR can be merged?

    No, but I’d like to hear other’s opinion on it.

    Also, you have just requested the conflicting pull to be merged, so this needs re-ACK anyway:

  116. ariard force-pushed on Jul 31, 2019
  117. ariard force-pushed on Jul 31, 2019
  118. ariard force-pushed on Jul 31, 2019
  119. ariard commented at 4:55 pm on July 31, 2019: member

    Rebased at 5922315 with #15713 (review), #15713 (review), #15713 (review), #15713 (review), #15713 (review) addressed. Shouldn’t have functional changes since 976d1e4.

    Please review again, and let give your opinion on Marco patch : #15713 (comment).

  120. ariard force-pushed on Jul 31, 2019
  121. sidhujag referenced this in commit eb1cc54b8a on Aug 1, 2019
  122. jnewbery commented at 4:07 pm on August 1, 2019: member

    You seem to have lost the if (relay) conditional in BroadcastTransaction(). I think that’s a rebase error.

    You’ve also lost the g_connman error checking block:

    0        if (!g_connman) {
    1            return TransactionError::P2P_DISABLED;
    2        }
    

    Alternatively, you could assert that g_connman is non-null at the top of this function. It’s only called by RPCs and the wallet scheduler, both of which are initialized after g_connman is assigned and stopped before g_connman is reset.

  123. ariard force-pushed on Aug 1, 2019
  124. Add BroadcastTransaction utility usage in Chain interface
    Access through a broadcastTransaction method.
    Add a wait_callback flag to turn off race protection when wallet
    already track its tx being in mempool
    
    Standardise highfee, absurdfee variable name to max_tx_fee
    
    We drop the P2P check in BroadcastTransaction as g_connman is only
    called by RPCs and the wallet scheduler, both of which are initialized
    after g_connman is assigned and stopped before g_connman is reset.
    8c8aa19b4b
  125. Introduce CWalletTx::SubmitMemoryPoolAndRelay
    Higher wallet-tx method combining RelayWalletTransactions and
    AcceptToMemoryPool, using new Chain::broadcastTransaction
    611291c198
  126. Remove duplicate checks in SubmitMemoryPoolAndRelay
    IsCoinBase check is already performed early by
    AcceptToMemoryPoolWorker
    GetDepthInMainChain check is already perfomed by
    BroadcastTransaction
    
    To avoid deadlock we MUST keep lock order in
    ResendWalletTransactions and CommitTransaction,
    even if we lock cs_main again further.
    in BroadcastTransaction. Lock order will need
    to be clean at once in a future refactoring
    8753f5652b
  127. Remove unused submitToMemoryPool and relayTransactions Chain interfaces b8eecf8e79
  128. Tidy up BroadcastTransaction() fb62f128bb
  129. ariard force-pushed on Aug 1, 2019
  130. ariard commented at 5:47 pm on August 1, 2019: member

    Oooops, thanks to pointing me the error, remove the check to be replaced by an assertion as it’s less checks in BroadcastTransaction at fb62f12.

    Note : currently P2P_DISABLED error is still there even if it’s not used. It can be clean in a later commit if we agree that disabling P2P is not a thing.

  131. MarcoFalke commented at 5:53 pm on August 1, 2019: member

    re-ACK fb62f128bbfd8c6cd72ea8e23331a4bae23883ab

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3re-ACK fb62f128bbfd8c6cd72ea8e23331a4bae23883ab
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUgBCAv/bnyyRCCqUH8PSxg2lces1K5Z5M/Nb+eT5O2JQhQb1EfY+NckIcAqPmZz
     8ffhn6qmibcfEUWVnhBdGD/8xZOdUM37IPs1xCVFt7kYdTIDkLGKKZqg9z9R14CZd
     9aivpQia09e6zURD6a/d7qB8isfRCTNe3a29dcZv43oW2+WIStQGRBGswymI17k7C
    10fYPsfWkAIru83VnoPCeziwXR85mRTXmKfVSQbgM/Qned2NDGGqZRZ6YH8KdtyPpP
    11e3p0EAYMB+6aXum3Ky+u5gu9yRbx5pjBebBzQKbHHFHMLXxIBKAHml6qK7zqiO87
    12Sg5fSDEQ/NC2DFfarRVWNT36UAhUqxpKwQptpWzMvgLXc2HYOR6MQrKM+eg/x84M
    13YN5b9zlKXGySUWVZWqk+mL9ELUPDxZu6zRtzEK1TI8WXQi+bqqQrjV6rp8ZqGj+s
    14M11E+efGRFL1qYOMEs0lHHcdqODkUoOJP1csVAGTDvFNJSDvbHMuqGUuObCHU8V1
    15uqYjCCQV
    16=XQET
    17-----END PGP SIGNATURE-----
    

    Timestamp of file with hash 9cd92754a615d69deebd843e2a0522965f52b1cf18a0916f147bb00a450d5790 -

  132. in src/node/transaction.cpp:69 in 8c8aa19b4b outdated
    67 
    68     } // cs_main
    69 
    70-    promise.get_future().wait();
    71-
    72-    if (!g_connman) {
    


    Sjors commented at 10:19 am on August 2, 2019:

    This check was added by @theuni in 53347f0cb99e514815e44a56439a4a10012238f8. Why wasn’t this an assert in the first place?

    Nit: this change could use its own commit.

  133. in src/node/transaction.cpp:31 in fb62f128bb
    31-    bool fHaveChain = false;
    32-    for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
    33+    for (size_t o = 0; o < tx->vout.size(); o++) {
    34         const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
    35-        fHaveChain = !existingCoin.IsSpent();
    36+        // IsSpent doesnt mean the coin is spent, it means the output doesnt' exist.
    


    Sjors commented at 10:24 am on August 2, 2019:
    Nit: misspelled doesn't twice.
  134. Sjors approved
  135. Sjors commented at 10:32 am on August 2, 2019: member

    re-ACK fb62f128bbfd8c6cd72ea8e23331a4bae23883ab

    Let’s not bother with the check_chain patch 4441ba6cd940cf70b59182373cefeb28c22da4be (it’s not in the current version of this PR).

  136. MarcoFalke commented at 1:12 pm on August 2, 2019: member
    This (seemingly simple) change has already 132 comments. I am going to merge it now, because I believe it is a step in the right direction. We can fix up typos and other stuff later, if needed.
  137. MarcoFalke referenced this in commit be0e8b4bff on Aug 2, 2019
  138. MarcoFalke merged this on Aug 2, 2019
  139. MarcoFalke closed this on Aug 2, 2019

  140. in src/interfaces/chain.cpp:292 in fb62f128bb
    285@@ -291,9 +286,13 @@ class ChainImpl : public Chain
    286         auto it = ::mempool.GetIter(txid);
    287         return it && (*it)->GetCountWithDescendants() > 1;
    288     }
    289-    void relayTransaction(const uint256& txid) override
    290+    bool broadcastTransaction(const CTransactionRef& tx, std::string& err_string, const CAmount& max_tx_fee, bool relay) override
    291     {
    292-        RelayTransaction(txid, *g_connman);
    293+        const TransactionError err = BroadcastTransaction(tx, err_string, max_tx_fee, relay, /*wait_callback*/ false);
    294+        // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.
    


    jnewbery commented at 1:42 pm on August 2, 2019:
    I think this line can be removed now. The only failures that BroadcastTransaction() can return are mempool-related failures.
  141. in src/node/transaction.cpp:19 in fb62f128bb
    13@@ -14,26 +14,30 @@
    14 
    15 #include <future>
    16 
    17-TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx, std::string& err_string, const CAmount& highfee)
    18+TransactionError BroadcastTransaction(const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
    19 {
    20+    assert(g_connman);
    


    jnewbery commented at 1:43 pm on August 2, 2019:
    nit: I’d prefer to see a comment next to this assert to explain why g_connman must always be assigned here.

    MarcoFalke commented at 1:48 pm on August 2, 2019:
    Should be part of #16503, maybe
  142. jnewbery commented at 1:44 pm on August 2, 2019: member

    post-merge ACK fb62f128bbfd8c6cd72ea8e23331a4bae23883ab.

    A couple of nits inline that could be cleaned up in a subsequent PR.

  143. fanquake removed this from the "Blockers" column in a project

  144. jnewbery commented at 5:09 pm on August 6, 2019: member
    I was wrong about this: #15713 (review). Apparently removing that check causes log spam, particularly for test nodes.
  145. MarcoFalke referenced this in commit 9ab9d63569 on Aug 9, 2019
  146. deadalnix referenced this in commit 861bd1645c on May 28, 2020
  147. deadalnix referenced this in commit 5bdc385b0f on Jun 7, 2020
  148. deadalnix referenced this in commit 552ce234fb on Jun 7, 2020
  149. deadalnix referenced this in commit f62324ecde on Jun 7, 2020
  150. deadalnix referenced this in commit 60df8b1002 on Jun 7, 2020
  151. ShengguangXiao referenced this in commit f826027e2f on Aug 28, 2020
  152. monstrobishi referenced this in commit 69a4b51afe on Sep 6, 2020
  153. Munkybooty referenced this in commit 5d4969b10b on Nov 25, 2021
  154. Munkybooty referenced this in commit 420ddf58ff on Nov 25, 2021
  155. kittywhiskers referenced this in commit 42a26e96b9 on Dec 3, 2021
  156. kittywhiskers referenced this in commit be6720a460 on Dec 4, 2021
  157. kittywhiskers referenced this in commit 40ca2aa42e on Dec 6, 2021
  158. kittywhiskers referenced this in commit 288cf23136 on Dec 8, 2021
  159. kittywhiskers referenced this in commit 2358e13dcb on Dec 8, 2021
  160. kittywhiskers referenced this in commit 096abc9742 on Dec 8, 2021
  161. kittywhiskers referenced this in commit fdfa1c1239 on Dec 11, 2021
  162. kittywhiskers referenced this in commit 9cb1d25e59 on Dec 12, 2021
  163. kittywhiskers referenced this in commit 635d04337a on Dec 12, 2021
  164. kittywhiskers referenced this in commit 0b5f527d93 on Dec 12, 2021
  165. kittywhiskers referenced this in commit 09338f1199 on Dec 12, 2021
  166. kittywhiskers referenced this in commit 880f6d0afb on Dec 12, 2021
  167. kittywhiskers referenced this in commit 8ccf4f67de on Dec 12, 2021
  168. kittywhiskers referenced this in commit 0187d2e597 on Dec 12, 2021
  169. MarcoFalke locked this on Dec 16, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-26 03:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me