Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chainntnfs: ensure proper fallback to scanning tx manually #1585

Closed

Conversation

wpaulino
Copy link
Contributor

In this commit, we address a bug where it's possible that we still
attempt to manually scan for a transaction to determine whether it's
been included in the chain even after successfully checking the txindex
and not finding it there. Now, we'll short-circuit this process by
exiting early if the txindex lookup was successful but the transaction
in question was not found. Otherwise, we'll fall back to the manual
scan.

Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

Nice catch! The code reads well to me. However, ideally we also have a test that fails as is in the current master. See my comment in line which goes over how to write such a test.

// scanning the chain manually. We'll also need to look at the
// error message returned as the error code is used for multiple
// errors.
txNotFoundErr := "No such mempool or blockchain transaction"
Copy link
Member

Choose a reason for hiding this comment

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

Have we confirmed that this is the exact help text? Ideally we also have a test along with this PR which will fail if the backend detects a query to the GetBlocks when we query for a transaction that was never even broadcast. The test would need to skip the neutrino backend, and only execute for the btcd and bitocind backends.

@wpaulino wpaulino force-pushed the proper-txindex-fallback branch 2 times, most recently from 530f182 to 66439b3 Compare July 24, 2018 01:11
@wpaulino
Copy link
Contributor Author

Updated the PR to include some tests. I realize there's a lot of code duplication, but I have a branch locally where I've begun to refactor all the different ChainNotifier implementations into one. Then we can refactor our tests to include a set of white-box and black-box tests, like we do with invoices in zpay32.

// We'll then check the status of the transaction lookup returned to
// determine whether we should proceed with any fallback methods.
switch {
// The transaction was found within the node's txindex.
Copy link
Contributor

Choose a reason for hiding this comment

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

comment should say "mempool"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

if txConf != nil {
return txConf, nil
// The transaction was not found within the node's mempool or txindex.
case txStatus == txNotFoundIndex && err == nil:
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we return in the case of err != nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This indicates that the transaction simply doesn't exist, as it was not found within the txindex or mempool. The err != nil case is handled in the default case, as that means something went wrong when looking at the index (either because it's disabled or something else went wrong), so we should fall back to scanning manually.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should check the error first, as now it can return (_, 0, err) which will match the txFoundMempool case.

}

// Make sure we actually retrieved a transaction that is included in a
// block. Without this, we won't be able to retrieve its confirmation
// details.
if tx == nil || tx.BlockHash == "" {
return nil, nil
return nil, txFoundMempool, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it in the mempool in this case? Update comment to explain.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Doesn't the comment as is imply this though by it not being included in a block?

Copy link
Contributor

Choose a reason for hiding this comment

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

If tx == nil, does that mean it is in the mempool?

if err := waitForMempoolTx(miner, txid); err != nil {
t.Fatal(err)
}
if _, err := miner.Node.Generate(1); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Check the mempool case before generating a block?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can't do so for bitcoind at the moment until btcsuite/btcd#1222 is in as we'll need to wait for bitcoind to detect the transaction in its mempool.

// txConfStatus denotes the status of a transaction's lookup.
type txConfStatus uint8

const (
Copy link
Contributor

Choose a reason for hiding this comment

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

Note: as discussed, would be nice to later make these shared between all backends, and then include them in SpendEvents etc

// We'll then check the status of the transaction lookup returned to
// determine whether we should proceed with any fallback methods.
switch {
// The transaction was found within the node's txindex.
Copy link
Contributor

Choose a reason for hiding this comment

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

All the comments apply to btcd as well, I guess.

@Roasbeef
Copy link
Member

Build failing on all instances. Looks to be an issue with the commit of btcd it's targeting?

@wpaulino
Copy link
Contributor Author

It's due to the removal of extended filters in neutrino. This PR as is adds a lot of duplicate code for tests. After seeing how they've been handled in #1439, I'll be modifying this PR to closely follow that approach. Will ping once done.

@Roasbeef
Copy link
Member

Ping on rebase, almost forgot about this one!

@Roasbeef Roasbeef added notifications P2 should be fixed if one has time needs testing PR hasn't yet been actively tested on testnet/mainnet first pass review done PR has had first pass of review, needs more tho labels Aug 14, 2018
@Roasbeef Roasbeef added this to the 0.5 milestone Aug 14, 2018
@wpaulino wpaulino force-pushed the proper-txindex-fallback branch 2 times, most recently from a5acd1c to fd50eb0 Compare August 17, 2018 02:50
In this commit, we extract some of the helper test variables and
functions into their own file and guard them under a build flag. This is
needed as some unit tests will be introduced in a future commit where
most of the same functions within the interface tests are reused. In
order to prevent these variables and functions from being exportable, we
guard them by the "debug" build tag.
In this commit, we address a bug where it's possible that we still
attempt to manually scan for a transaction to determine whether it's
been included in the chain even after successfully checking the txindex
and not finding it there. Now, we'll short-circuit this process by
exiting early if the txindex lookup was successful but the transaction
in question was not found. Otherwise, we'll fall back to the manual
scan.
@halseth halseth added the needs rebase PR has merge conflicts label Aug 22, 2018
Copy link
Contributor

@halseth halseth left a comment

Choose a reason for hiding this comment

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

This looks pretty good 👍

One thing I that could be improved is to document more clearly the relation between the different conf states. A suggestion would be to make say confDetailsFromTxIndex return states [mempool, block, not-found], and confDetailsManually return states [found, not-found]. Then historicalConfDetails could use these values to determine which of the txConfStatuss to return (and then I believe we could replace all *notFound statuses there with a single txNotFound status.

Also needs a rebase!

@@ -431,84 +457,102 @@ func (b *BitcoindNotifier) handleRelevantTx(tx chain.RelevantTx, bestHeight int3
// historicalConfDetails looks up whether a transaction is already included in a
// block in the active chain and, if so, returns details about the confirmation.
func (b *BitcoindNotifier) historicalConfDetails(txid *chainhash.Hash,
heightHint, currentHeight uint32) (*chainntnfs.TxConfirmation, error) {
heightHint, currentHeight uint32) (*chainntnfs.TxConfirmation, txConfStatus, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: long line?

if txConf != nil {
return txConf, nil
// The transaction was not found within the node's mempool or txindex.
case txStatus == txNotFoundIndex && err == nil:
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should check the error first, as now it can return (_, 0, err) which will match the txFoundMempool case.

}

// Make sure we actually retrieved a transaction that is included in a
// block. Without this, we won't be able to retrieve its confirmation
// details.
if tx == nil || tx.BlockHash == "" {
return nil, nil
return nil, txFoundMempool, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

If tx == nil, does that mean it is in the mempool?

// Now, we'll create a test transaction, confirm it, and attempt to
// retrieve its confirmation details.
//
// TODO(wilmer): add mempool case once trickle timeout can be specified
Copy link
Contributor

Choose a reason for hiding this comment

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

this is now added.

@wpaulino wpaulino deleted the proper-txindex-fallback branch August 27, 2018 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
first pass review done PR has had first pass of review, needs more tho needs rebase PR has merge conflicts needs testing PR hasn't yet been actively tested on testnet/mainnet notifications P2 should be fixed if one has time
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants