Skip to content

Commit

Permalink
Merge branch 'btcsuite:master' into bug/rescan-data-race
Browse files Browse the repository at this point in the history
  • Loading branch information
MStreet3 authored Dec 2, 2022
2 parents 49e8366 + 0f34c5c commit c5e8a86
Show file tree
Hide file tree
Showing 13 changed files with 276 additions and 124 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/btcsuite/btcwallet
require (
github.com/btcsuite/btcd v0.23.4
github.com/btcsuite/btcd/btcec/v2 v2.2.2
github.com/btcsuite/btcd/btcutil v1.1.1
github.com/btcsuite/btcd/btcutil v1.1.3
github.com/btcsuite/btcd/btcutil/psbt v1.1.4
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f
Expand Down
3 changes: 2 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ github.com/btcsuite/btcd/btcec/v2 v2.2.2 h1:5uxe5YjoCq+JeOpg0gZSNHuFgeogrocBYxvg
github.com/btcsuite/btcd/btcec/v2 v2.2.2/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8=
github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=
github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
github.com/btcsuite/btcd/btcutil v1.1.1 h1:hDcDaXiP0uEzR8Biqo2weECKqEw0uHDZ9ixIWevVQqY=
github.com/btcsuite/btcd/btcutil v1.1.1/go.mod h1:nbKlBMNm9FGsdvKvu0essceubPiAcI57pYBNnsLAa34=
github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ=
github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0=
github.com/btcsuite/btcd/btcutil/psbt v1.1.4 h1:Edx4AfBn+YPam2KP5AobDitulGp4r1Oibm8oruzkMdI=
github.com/btcsuite/btcd/btcutil/psbt v1.1.4/go.mod h1:9AyU6EQVJ9Iw9zPyNT1lcdHd6cnEZdno5wLu5FY74os=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
Expand Down
22 changes: 12 additions & 10 deletions wallet/createtx.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ func (s secretSource) GetScript(addr btcutil.Address) ([]byte, error) {
// NOTE: The dryRun argument can be set true to create a tx that doesn't alter
// the database. A tx created with this set to true will intentionally have no
// input scripts added and SHOULD NOT be broadcasted.
func (w *Wallet) txToOutputs(outputs []*wire.TxOut, keyScope *waddrmgr.KeyScope,
func (w *Wallet) txToOutputs(outputs []*wire.TxOut,
coinSelectKeyScope, changeKeyScope *waddrmgr.KeyScope,
account uint32, minconf int32, feeSatPerKb btcutil.Amount,
coinSelectionStrategy CoinSelectionStrategy, dryRun bool) (
*txauthor.AuthoredTx, error) {
Expand All @@ -125,14 +126,14 @@ func (w *Wallet) txToOutputs(outputs []*wire.TxOut, keyScope *waddrmgr.KeyScope,
var tx *txauthor.AuthoredTx
err = walletdb.Update(w.db, func(dbtx walletdb.ReadWriteTx) error {
addrmgrNs, changeSource, err := w.addrMgrWithChangeSource(
dbtx, keyScope, account,
dbtx, changeKeyScope, account,
)
if err != nil {
return err
}

eligible, err := w.findEligibleOutputs(
dbtx, keyScope, account, minconf, bs,
dbtx, coinSelectKeyScope, account, minconf, bs,
)
if err != nil {
return err
Expand Down Expand Up @@ -201,17 +202,17 @@ func (w *Wallet) txToOutputs(outputs []*wire.TxOut, keyScope *waddrmgr.KeyScope,
// the inputs are part of a watch-only account, there's no
// private key information stored, so we'll skip signing such.
var watchOnly bool
if keyScope == nil {
if coinSelectKeyScope == nil {
// If a key scope wasn't specified, then coin selection
// was performed from the default wallet accounts
// (NP2WKH, P2WKH), so any key scope provided doesn't
// impact the result of this call.
// (NP2WKH, P2WKH, P2TR), so any key scope provided
// doesn't impact the result of this call.
watchOnly, err = w.Manager.IsWatchOnlyAccount(
addrmgrNs, waddrmgr.KeyScopeBIP0084, account,
addrmgrNs, waddrmgr.KeyScopeBIP0086, account,
)
} else {
watchOnly, err = w.Manager.IsWatchOnlyAccount(
addrmgrNs, *keyScope, account,
addrmgrNs, *coinSelectKeyScope, account,
)
}
if err != nil {
Expand Down Expand Up @@ -352,9 +353,10 @@ func (w *Wallet) addrMgrWithChangeSource(dbtx walletdb.ReadWriteTx,
changeKeyScope *waddrmgr.KeyScope, account uint32) (
walletdb.ReadWriteBucket, *txauthor.ChangeSource, error) {

// Determine the address type for change addresses of the given account.
// Determine the address type for change addresses of the given
// account.
if changeKeyScope == nil {
changeKeyScope = &waddrmgr.KeyScopeBIP0084
changeKeyScope = &waddrmgr.KeyScopeBIP0086
}
addrType := waddrmgr.ScopeAddrMap[*changeKeyScope].InternalAddrType

Expand Down
108 changes: 104 additions & 4 deletions wallet/createtx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ var (
// request a dry run of the txToOutputs call. It also makes sure a subsequent
// non-dry run call produces a similar transaction to the dry-run.
func TestTxToOutputsDryRun(t *testing.T) {
t.Parallel()

w, cleanup := testWallet(t)
defer cleanup()

Expand Down Expand Up @@ -76,7 +78,7 @@ func TestTxToOutputsDryRun(t *testing.T) {
// First do a few dry-runs, making sure the number of addresses in the
// database us not inflated.
dryRunTx, err := w.txToOutputs(
txOuts, nil, 0, 1, 1000, CoinSelectionLargest, true,
txOuts, nil, nil, 0, 1, 1000, CoinSelectionLargest, true,
)
if err != nil {
t.Fatalf("unable to author tx: %v", err)
Expand All @@ -93,7 +95,7 @@ func TestTxToOutputsDryRun(t *testing.T) {
}

dryRunTx2, err := w.txToOutputs(
txOuts, nil, 0, 1, 1000, CoinSelectionLargest, true,
txOuts, nil, nil, 0, 1, 1000, CoinSelectionLargest, true,
)
if err != nil {
t.Fatalf("unable to author tx: %v", err)
Expand Down Expand Up @@ -128,7 +130,7 @@ func TestTxToOutputsDryRun(t *testing.T) {
// Now we do a proper, non-dry run. This should add a change address
// to the database.
tx, err := w.txToOutputs(
txOuts, nil, 0, 1, 1000, CoinSelectionLargest, false,
txOuts, nil, nil, 0, 1, 1000, CoinSelectionLargest, false,
)
if err != nil {
t.Fatalf("unable to author tx: %v", err)
Expand Down Expand Up @@ -208,6 +210,8 @@ func addUtxo(t *testing.T, w *Wallet, incomingTx *wire.MsgTx) {

// TestInputYield verifies the functioning of the inputYieldsPositively.
func TestInputYield(t *testing.T) {
t.Parallel()

addr, _ := btcutil.DecodeAddress("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", &chaincfg.MainNetParams)
pkScript, err := txscript.PayToAddrScript(addr)
require.NoError(t, err)
Expand All @@ -226,6 +230,8 @@ func TestInputYield(t *testing.T) {

// TestTxToOutputsRandom tests random coin selection.
func TestTxToOutputsRandom(t *testing.T) {
t.Parallel()

w, cleanup := testWallet(t)
defer cleanup()

Expand Down Expand Up @@ -273,7 +279,8 @@ func TestTxToOutputsRandom(t *testing.T) {

createTx := func() *txauthor.AuthoredTx {
tx, err := w.txToOutputs(
txOuts, nil, 0, 1, feeSatPerKb, CoinSelectionRandom, true,
txOuts, nil, nil, 0, 1, feeSatPerKb,
CoinSelectionRandom, true,
)
require.NoError(t, err)
return tx
Expand All @@ -299,3 +306,96 @@ func TestTxToOutputsRandom(t *testing.T) {

require.True(t, isRandom)
}

// TestCreateSimpleCustomChange tests that it's possible to let the
// CreateSimpleTx use all coins for coin selection, but specify a custom scope
// that isn't the current default scope.
func TestCreateSimpleCustomChange(t *testing.T) {
t.Parallel()

w, cleanup := testWallet(t)
defer cleanup()

// First, we'll make a P2TR and a P2WKH address to send some coins to
// (two different coin scopes).
p2wkhAddr, err := w.CurrentAddress(0, waddrmgr.KeyScopeBIP0084)
require.NoError(t, err)

p2trAddr, err := w.CurrentAddress(0, waddrmgr.KeyScopeBIP0086)
require.NoError(t, err)

// We'll now make a transaction that'll send coins to both outputs,
// then "credit" the wallet for that send.
p2wkhScript, err := txscript.PayToAddrScript(p2wkhAddr)
require.NoError(t, err)
p2trScript, err := txscript.PayToAddrScript(p2trAddr)
require.NoError(t, err)

const testAmt = 1_000_000

incomingTx := &wire.MsgTx{
TxIn: []*wire.TxIn{
{},
},
TxOut: []*wire.TxOut{
wire.NewTxOut(testAmt, p2wkhScript),
wire.NewTxOut(testAmt, p2trScript),
},
}
addUtxo(t, w, incomingTx)

// With the amounts credited to the wallet, we'll now do a dry run coin
// selection w/o any default args.
targetTxOut := &wire.TxOut{
Value: 1_500_000,
PkScript: p2trScript,
}
tx1, err := w.txToOutputs(
[]*wire.TxOut{targetTxOut}, nil, nil, 0, 1, 1000,
CoinSelectionLargest, true,
)
require.NoError(t, err)

// We expect that all inputs were used and also the change output is a
// taproot output (the current default).
require.Len(t, tx1.Tx.TxIn, 2)
require.Len(t, tx1.Tx.TxOut, 2)
for _, txOut := range tx1.Tx.TxOut {
scriptType, _, _, err := txscript.ExtractPkScriptAddrs(
txOut.PkScript, w.chainParams,
)
require.NoError(t, err)

require.Equal(t, scriptType, txscript.WitnessV1TaprootTy)
}

// Next, we'll do another dry run, but this time, specify a custom
// change key scope. We'll also require that only inputs of P2TR are used.
targetTxOut = &wire.TxOut{
Value: 500_000,
PkScript: p2trScript,
}
tx2, err := w.txToOutputs(
[]*wire.TxOut{targetTxOut}, &waddrmgr.KeyScopeBIP0086,
&waddrmgr.KeyScopeBIP0084, 0, 1, 1000, CoinSelectionLargest,
true,
)
require.NoError(t, err)

// The resulting transaction should spend a single input, and use P2WKH
// as the output script.
require.Len(t, tx2.Tx.TxIn, 1)
require.Len(t, tx2.Tx.TxOut, 2)
for i, txOut := range tx2.Tx.TxOut {
if i != tx2.ChangeIndex {
continue
}

scriptType, _, _, err := txscript.ExtractPkScriptAddrs(
txOut.PkScript, w.chainParams,
)
require.NoError(t, err)

require.Equal(t, scriptType, txscript.WitnessV0PubKeyHashTy)
}
}
2 changes: 2 additions & 0 deletions wallet/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ var (
// TestImportAccount tests that extended public keys can successfully be
// imported into both watch only and normal wallets.
func TestImportAccount(t *testing.T) {
t.Parallel()

for _, tc := range testCases {
tc := tc

Expand Down
Loading

0 comments on commit c5e8a86

Please sign in to comment.