Merge pull request #1554 from halseth/bitcoind-mempool-spends

Filter out bitcoind mempool spends
This commit is contained in:
Olaoluwa Osuntokun 2018-07-16 13:24:35 -07:00 committed by GitHub
commit 6dff599d21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 11 deletions

@ -352,16 +352,40 @@ func (b *BitcoindNotifier) handleRelevantTx(tx chain.RelevantTx, bestHeight int3
// TODO(roasbeef): after change to
// loadfilter, only notify on block
// inclusion?
confirmedSpend := false
if tx.Block != nil {
confirmedSpend = true
spendDetails.SpendingHeight = tx.Block.Height
} else {
spendDetails.SpendingHeight = bestHeight + 1
}
for _, ntfn := range clients {
chainntnfs.Log.Infof("Dispatching "+
// Keep spendNotifications that are
// waiting for a confirmation around.
// They will be notified when we find
// the spend within a block.
rem := make(map[uint64]*spendNotification)
for c, ntfn := range clients {
// If this is a mempool spend,
// and this client didn't want
// to be notified on mempool
// spends, store it for later.
if !confirmedSpend && !ntfn.mempool {
rem[c] = ntfn
continue
}
confStr := "unconfirmed"
if confirmedSpend {
confStr = "confirmed"
}
chainntnfs.Log.Infof("Dispatching %s "+
"spend notification for "+
"outpoint=%v", ntfn.targetOutpoint)
"outpoint=%v at height %v",
confStr, ntfn.targetOutpoint,
spendDetails.SpendingHeight)
ntfn.spendChan <- spendDetails
// Close spendChan to ensure that any calls to Cancel will not
@ -370,6 +394,12 @@ func (b *BitcoindNotifier) handleRelevantTx(tx chain.RelevantTx, bestHeight int3
close(ntfn.spendChan)
}
delete(b.spendNotifications, prevOut)
// If we had any clients left, add them
// back to the map.
if len(rem) > 0 {
b.spendNotifications[prevOut] = rem
}
}
}
}
@ -530,6 +560,8 @@ type spendNotification struct {
spendID uint64
heightHint uint32
mempool bool
}
// spendCancel is a message sent to the BitcoindNotifier when a client wishes
@ -548,12 +580,13 @@ type spendCancel struct {
// across the 'Spend' channel. The heightHint should represent the earliest
// height in the chain where the transaction could have been spent in.
func (b *BitcoindNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
heightHint uint32, _ bool) (*chainntnfs.SpendEvent, error) {
heightHint uint32, mempool bool) (*chainntnfs.SpendEvent, error) {
ntfn := &spendNotification{
targetOutpoint: outpoint,
spendChan: make(chan *chainntnfs.SpendDetail, 1),
spendID: atomic.AddUint64(&b.spendClientCounter, 1),
mempool: mempool,
}
select {

@ -425,14 +425,30 @@ func testSpendNotification(miner *rpctest.Harness,
t.Fatalf("tx not relayed to miner: %v", err)
}
// Make sure notifications are not yet sent.
// Make sure notifications are not yet sent. We launch a go routine for
// all the spend clients, such that we can wait for them all in
// parallel.
//
// Since bitcoind is at times very slow at notifying about txs in the
// mempool, we use a quite large timeout of 10 seconds.
// TODO(halseth): change this when mempool spends are removed.
mempoolSpendTimeout := 10 * time.Second
mempoolSpends := make(chan *chainntnfs.SpendDetail, numClients)
for _, c := range spendClients {
select {
case <-c.Spend:
t.Fatalf("did not expect to get notification before " +
"block was mined")
case <-time.After(50 * time.Millisecond):
}
go func(client *chainntnfs.SpendEvent) {
select {
case s := <-client.Spend:
mempoolSpends <- s
case <-time.After(mempoolSpendTimeout):
}
}(c)
}
select {
case <-mempoolSpends:
t.Fatalf("did not expect to get notification before " +
"block was mined")
case <-time.After(mempoolSpendTimeout):
}
// Now we mine a single block, which should include our spend. The