Skip to content

Commit

Permalink
merge with btcwallet upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
losh11 committed Feb 18, 2024
2 parents 5b55b75 + 5df09dd commit dd8e712
Show file tree
Hide file tree
Showing 93 changed files with 13,333 additions and 2,615 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ env:
GOPATH: /home/runner/work/go
GO111MODULE: on

GO_VERSION: '^1.17.0'
GO_VERSION: 1.19.x
BITCOIND_VERSION: '22.0'
BITCOIND_IMAGE: 'lightninglabs/bitcoin-core'

jobs:
########################
Expand Down Expand Up @@ -59,6 +61,13 @@ jobs:
- unit-race
- unit-cover
steps:
- name: extract bitcoind from docker image
run: |-
docker pull ${{ env.BITCOIND_IMAGE }}:${{ env.BITCOIND_VERSION }}
CONTAINER_ID=$(docker create ${{ env.BITCOIND_IMAGE }}:${{ env.BITCOIND_VERSION }})
sudo docker cp $CONTAINER_ID:/opt/bitcoin-${{ env.BITCOIND_VERSION }}/bin/bitcoind /usr/local/bin/bitcoind
docker rm $CONTAINER_ID
- name: git checkout
uses: actions/checkout@v2

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ ltcwallet
vendor
.idea
coverage.txt
*.swp
.vscode
50 changes: 21 additions & 29 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,29 @@ linters-settings:
simplify: true

linters:
enable-all: true
disable:
# Global variables are used in many places throughout the code base.
- gochecknoglobals

# Some lines are over 80 characters on purpose and we don't want to make them
# even longer by marking them as 'nolint'.
- lll

# We don't care (enough) about misaligned structs to lint that.
- maligned

# We have long functions, especially in tests. Moving or renaming those would
# trigger funlen problems that we may not want to solve at that time.
- funlen

# Disable for now as we haven't yet tuned the sensitivity to our codebase
# yet. Enabling by default for example, would also force new contributors to
# potentially extensively refactor code, when they want to smaller change to
# land.
- gocyclo

# Instances of table driven tests that don't pre-allocate shouldn't trigger
# the linter.
disable-all: true
enable:
- asciicheck
- deadcode
- dupl
- errcheck
- goimports
- gosec
- gosimple
- govet
- ineffassign
- nolintlint
- prealloc

# Init functions are used by loggers throughout the codebase.
- gochecknoinits
- staticcheck
- structcheck
- typecheck
- unconvert
- unused
- varcheck

# Explicit types are okay.
- interfacer
# Others to consider that do not pass presently:
# - nilerr
# - makezero

issues:
exclude-rules:
Expand Down
17 changes: 12 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ GO_BIN := ${GOPATH}/bin
LINT_BIN := $(GO_BIN)/golangci-lint
GOACC_BIN := $(GO_BIN)/go-acc

LINT_COMMIT := v1.18.0
LINT_COMMIT := v1.46.0
GOACC_COMMIT := 80342ae2e0fcf265e99e76bcc4efd022c7c3811b
GOIMPORTS_COMMIT := v0.1.10

DEPGET := cd /tmp && GO111MODULE=on go get -v
GOBUILD := GO111MODULE=on go build -v
GOINSTALL := GO111MODULE=on go install -v
GOTEST := GO111MODULE=on go test
Expand Down Expand Up @@ -49,15 +49,15 @@ all: build check

$(LINT_BIN):
@$(call print, "Fetching linter")
$(DEPGET) $(LINT_PKG)@$(LINT_COMMIT)
$(GOINSTALL) $(LINT_PKG)@$(LINT_COMMIT)

$(GOACC_BIN):
@$(call print, "Fetching go-acc")
$(DEPGET) $(GOACC_PKG)@$(GOACC_COMMIT)
$(GOINSTALL) $(GOACC_PKG)@$(GOACC_COMMIT)

goimports:
@$(call print, "Installing goimports.")
$(DEPGET) $(GOIMPORTS_PKG)
$(GOINSTALL) $(GOIMPORTS_PKG)@${GOIMPORTS_COMMIT}

# ============
# INSTALLATION
Expand Down Expand Up @@ -109,6 +109,13 @@ clean:
@$(call print, "Cleaning source.$(NC)")
$(RM) coverage.txt

tidy-module:
echo "Running 'go mod tidy' for all modules"
scripts/tidy_modules.sh

tidy-module-check: tidy-module
if test -n "$$(git status --porcelain)"; then echo "modules not updated, please run `make tidy-module` again!"; git status; exit 1; fi

.PHONY: all \
default \
build \
Expand Down
5 changes: 2 additions & 3 deletions btcwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
package main

import (
"io/ioutil"
"net"
"net/http"
_ "net/http/pprof"
_ "net/http/pprof" // nolint:gosec
"os"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -248,7 +247,7 @@ func readCAFile() []byte {
var certs []byte
if !cfg.DisableClientTLS {
var err error
certs, err = ioutil.ReadFile(cfg.CAFile.Value)
certs, err = os.ReadFile(cfg.CAFile.Value)
if err != nil {
log.Warnf("Cannot open CA file: %v", err)
// If there's an error reading the CA file, continue
Expand Down
107 changes: 80 additions & 27 deletions chain/bitcoind_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,14 @@ type BitcoindClient struct {
// need to process earlier notifications still waiting to be processed.
notificationQueue *ConcurrentQueue

// zmqTxNtfns is a channel through which ZMQ transaction events will be
// retrieved from the backing bitcoind connection.
zmqTxNtfns chan *wire.MsgTx
// txNtfns is a channel through which transaction events will be
// retrieved from the backing bitcoind connection, either via ZMQ or
// polling RPC.
txNtfns chan *wire.MsgTx

// zmqBlockNtfns is a channel through which ZMQ block events will be
// retrieved from the backing bitcoind connection.
zmqBlockNtfns chan *wire.MsgBlock
// blockNtfns is a channel through block events will be retrieved from
// the backing bitcoind connection, either via ZMQ or polling RPC.
blockNtfns chan *wire.MsgBlock

quit chan struct{}
wg sync.WaitGroup
Expand All @@ -109,7 +110,7 @@ var _ Interface = (*BitcoindClient)(nil)

// BackEnd returns the name of the driver.
func (c *BitcoindClient) BackEnd() string {
return "bitcoind"
return "litecoind"
}

// GetBestBlock returns the highest block known to bitcoind.
Expand Down Expand Up @@ -183,13 +184,25 @@ func (c *BitcoindClient) IsCurrent() bool {
return bestHeader.Timestamp.After(time.Now().Add(-isCurrentDelta))
}

// GetRawTransactionVerbose returns a transaction from the tx hash.
// GetRawTransactionVerbose returns a TxRawResult from the tx hash.
func (c *BitcoindClient) GetRawTransactionVerbose(
hash *chainhash.Hash) (*btcjson.TxRawResult, error) {

return c.chainConn.client.GetRawTransactionVerbose(hash)
}

// GetRawTransaction returns a `ltcutil.Tx` from the tx hash.
func (c *BitcoindClient) GetRawTransaction(
hash *chainhash.Hash) (*ltcutil.Tx, error) {

return c.chainConn.client.GetRawTransaction(hash)
}

// GetRawMempool returns the raw mempool.
func (c *BitcoindClient) GetRawMempool() ([]*chainhash.Hash, error) {
return c.chainConn.client.GetRawMempool()
}

// GetTxOut returns a txout from the outpoint info provided.
func (c *BitcoindClient) GetTxOut(txHash *chainhash.Hash, index uint32,
mempool bool) (*btcjson.GetTxOutResult, error) {
Expand Down Expand Up @@ -232,12 +245,46 @@ func (c *BitcoindClient) NotifyReceived(addrs []ltcutil.Address) error {
func (c *BitcoindClient) NotifySpent(outPoints []*wire.OutPoint) error {
_ = c.NotifyBlocks()

// Send the outpoints so the client will cache them.
select {
case c.rescanUpdate <- outPoints:
case <-c.quit:
return ErrBitcoindClientShuttingDown
}

// Now we do a quick check in current mempool to see if we already have
// txes that spends the given outpoints.
for _, op := range outPoints {
op := op

// Check if the input is seen in mempool.
txid, found := c.chainConn.events.LookupInputSpend(*op)
if !found {
// Nothing found, continue to check the next.
continue
}

// Found the tx that spends the input, now we fetch the raw tx
// and send notification.
tx, err := c.GetRawTransaction(&txid)
if err != nil {
log.Errorf("Unable to get raw transaction for %v, "+
"err: %v", txid, err)
continue
}

// Construct a record.
rec, err := wtxmgr.NewTxRecordFromMsgTx(tx.MsgTx(), time.Now())
if err != nil {
log.Errorf("Cannot create transaction record for tx: "+
"%v, err: %v", tx.Hash(), err)
continue
}

// Send to notification immediately.
c.onRelevantTx(rec, nil)
}

return nil
}

Expand Down Expand Up @@ -310,6 +357,7 @@ func (c *BitcoindClient) shouldNotifyBlocks() bool {
// is used to reset the current filters.
//
// The current filters supported are of the following types:
//
// []ltcutil.Address
// []wire.OutPoint
// []*wire.OutPoint
Expand Down Expand Up @@ -597,12 +645,15 @@ func (c *BitcoindClient) ntfnHandler() {

for {
select {
case tx := <-c.zmqTxNtfns:
if _, _, err := c.filterTx(tx, nil, true); err != nil {
case tx := <-c.txNtfns:
txDetails := ltcutil.NewTx(tx)
_, _, err := c.filterTx(txDetails, nil, true)
if err != nil {
log.Errorf("Unable to filter transaction %v: %v",
tx.TxHash(), err)
txDetails.Hash(), err)
}
case newBlock := <-c.zmqBlockNtfns:

case newBlock := <-c.blockNtfns:
// If the new block's previous hash matches the best
// hash known to us, then the new block is the next
// successor, so we'll update our best block to reflect
Expand Down Expand Up @@ -752,7 +803,7 @@ func (c *BitcoindClient) onRescanProgress(hash *chainhash.Hash, height int32,

select {
case c.notificationQueue.ChanIn() <- &RescanProgress{
Hash: hash,
Hash: *hash,
Height: height,
Time: timestamp,
}:
Expand Down Expand Up @@ -1182,16 +1233,19 @@ func (c *BitcoindClient) filterBlock(block *wire.MsgBlock, height int32,
// Update the index in the block details with the index of this
// transaction.
blockDetails.Index = i
isRelevant, rec, err := c.filterTx(tx, blockDetails, notify)
txDetails := ltcutil.NewTx(tx)
isRelevant, rec, err := c.filterTx(
txDetails, blockDetails, notify,
)
if err != nil {
log.Warnf("Unable to filter transaction %v: %v",
tx.TxHash(), err)
*txDetails.Hash(), err)
continue
}

if isRelevant {
relevantTxs = append(relevantTxs, rec)
confirmedTxs[tx.TxHash()] = struct{}{}
confirmedTxs[*txDetails.Hash()] = struct{}{}
}
}

Expand All @@ -1218,11 +1272,10 @@ func (c *BitcoindClient) filterBlock(block *wire.MsgBlock, height int32,

// filterTx determines whether a transaction is relevant to the client by
// inspecting the client's different filters.
func (c *BitcoindClient) filterTx(tx *wire.MsgTx,
blockDetails *btcjson.BlockDetails,
notify bool) (bool, *wtxmgr.TxRecord, error) {
func (c *BitcoindClient) filterTx(txDetails *ltcutil.Tx,
blockDetails *btcjson.BlockDetails, notify bool) (bool,
*wtxmgr.TxRecord, error) {

txDetails := ltcutil.NewTx(tx)
if blockDetails != nil {
txDetails.SetIndex(blockDetails.Index)
}
Expand All @@ -1245,11 +1298,11 @@ func (c *BitcoindClient) filterTx(tx *wire.MsgTx,
// If we've already seen this transaction and it's now been confirmed,
// then we'll shortcut the filter process by immediately sending a
// notification to the caller that the filter matches.
if _, ok := c.mempool[tx.TxHash()]; ok {
if _, ok := c.mempool[*txDetails.Hash()]; ok {
if notify && blockDetails != nil {
c.onRelevantTx(rec, blockDetails)
return true, rec, nil
}
return true, rec, nil
}

// Otherwise, this is a new transaction we have yet to see. We'll need
Expand All @@ -1259,7 +1312,7 @@ func (c *BitcoindClient) filterTx(tx *wire.MsgTx,
// We'll start by checking all inputs and determining whether it spends
// an existing outpoint or a pkScript encoded as an address in our watch
// list.
for _, txIn := range tx.TxIn {
for _, txIn := range txDetails.MsgTx().TxIn {
// If it matches an outpoint in our watch list, we can exit our
// loop early.
if _, ok := c.watchedOutPoints[txIn.PreviousOutPoint]; ok {
Expand Down Expand Up @@ -1291,7 +1344,7 @@ func (c *BitcoindClient) filterTx(tx *wire.MsgTx,
// We'll also cycle through its outputs to determine if it pays to
// any of the currently watched addresses. If an output matches, we'll
// add it to our watch list.
for i, txOut := range tx.TxOut {
for i, txOut := range txDetails.MsgTx().TxOut {
_, addrs, _, err := txscript.ExtractPkScriptAddrs(
txOut.PkScript, c.chainConn.cfg.ChainParams,
)
Expand All @@ -1304,7 +1357,7 @@ func (c *BitcoindClient) filterTx(tx *wire.MsgTx,
if _, ok := c.watchedAddresses[addr.String()]; ok {
isRelevant = true
op := wire.OutPoint{
Hash: tx.TxHash(),
Hash: *txDetails.Hash(),
Index: uint32(i),
}
c.watchedOutPoints[op] = struct{}{}
Expand All @@ -1315,7 +1368,7 @@ func (c *BitcoindClient) filterTx(tx *wire.MsgTx,
// If the transaction didn't pay to any of our watched addresses, we'll
// check if we're currently watching for the hash of this transaction.
if !isRelevant {
if _, ok := c.watchedTxs[tx.TxHash()]; ok {
if _, ok := c.watchedTxs[*txDetails.Hash()]; ok {
isRelevant = true
}
}
Expand All @@ -1330,7 +1383,7 @@ func (c *BitcoindClient) filterTx(tx *wire.MsgTx,
// our mempool so that it can also be notified as part of
// FilteredBlockConnected once it confirms.
if blockDetails == nil {
c.mempool[tx.TxHash()] = struct{}{}
c.mempool[*txDetails.Hash()] = struct{}{}
}

c.onRelevantTx(rec, blockDetails)
Expand Down
Loading

0 comments on commit dd8e712

Please sign in to comment.