Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions wallet/createtx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,47 @@ func addUtxo(t *testing.T, w *Wallet, incomingTx *wire.MsgTx) {
}
}

// addTxAndCredit adds the given transaction to the wallet's database marked as
// a confirmed UTXO specified by the creditIndex.
func addTxAndCredit(t *testing.T, w *Wallet, tx *wire.MsgTx,
creditIndex uint32) {

var b bytes.Buffer
require.NoError(t, tx.Serialize(&b), "unable to serialize tx")

txBytes := b.Bytes()

rec, err := wtxmgr.NewTxRecord(txBytes, time.Now())
require.NoError(t, err)

// The block meta will be inserted to tell the wallet this is a
// confirmed transaction.
block := &wtxmgr.BlockMeta{
Block: wtxmgr.Block{
Hash: *testBlockHash,
Height: testBlockHeight,
},
Time: time.Unix(1387737310, 0),
}

err = walletdb.Update(w.db, func(dbTx walletdb.ReadWriteTx) error {
ns := dbTx.ReadWriteBucket(wtxmgrNamespaceKey)
err = w.TxStore.InsertTx(ns, rec, block)
if err != nil {
return err
}

// Add the specified output as credit.
err = w.TxStore.AddCredit(ns, rec, block, creditIndex, false)
if err != nil {
return err
}

return nil
})
require.NoError(t, err, "failed inserting tx")
}

// TestInputYield verifies the functioning of the inputYieldsPositively.
func TestInputYield(t *testing.T) {
t.Parallel()
Expand Down
23 changes: 23 additions & 0 deletions wallet/utxos.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/btcsuite/btcwallet/wtxmgr"
)

var (
Expand Down Expand Up @@ -174,6 +175,12 @@ func (w *Wallet) FetchOutpointInfo(prevOut *wire.OutPoint) (*wire.MsgTx,
numOutputs)
}

// Exit early if the output doesn't belong to our wallet. We know it's
// our UTXO iff the `TxDetails` has a credit record on this output.
if !hasOutput(txDetail, prevOut.Index) {
return nil, nil, 0, ErrNotMine
}

pkScript := txDetail.TxRecord.MsgTx.TxOut[prevOut.Index].PkScript

// Determine the number of confirmations the output currently has.
Expand Down Expand Up @@ -224,3 +231,19 @@ func (w *Wallet) FetchDerivationInfo(pkScript []byte) (*psbt.Bip32Derivation,

return derivation, nil
}

// hasOutpoint takes an output identified by its output index and determines
// whether the TxDetails contains this output. If the TxDetails doesn't have
// this output, it means this output doesn't belong to our wallet.
//
// TODO(yy): implement this method on `TxDetails` and update the package
// `wtxmgr` instead.
func hasOutput(t *wtxmgr.TxDetails, outputIndex uint32) bool {
for _, cred := range t.Credits {
if outputIndex == cred.Index {
return true
}
}

return false
}
79 changes: 79 additions & 0 deletions wallet/utxos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"testing"

"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcwallet/waddrmgr"
Expand Down Expand Up @@ -129,6 +130,84 @@ func TestFetchOutpointInfo(t *testing.T) {
require.Equal(t, int64(0-testBlockHeight), confirmations)
}

// TestFetchOutpointInfoErr checks when the wallet cannot find an output, a
// proper error is returned.
func TestFetchOutpointInfoErr(t *testing.T) {
t.Parallel()

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

// Create an address we can use to send some coins to.
addr, err := w.CurrentAddress(0, waddrmgr.KeyScopeBIP0084)
require.NoError(t, err)
p2shAddr, err := txscript.PayToAddrScript(addr)
require.NoError(t, err)

// Create a tx that has two outputs - output1 belongs to the wallet,
// output2 is external.
output1 := wire.NewTxOut(100000, p2shAddr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm why do they they pay to the same addr thought therefore we created addr above ?

Copy link
Contributor

Choose a reason for hiding this comment

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

doesn't matter but still better to have a proper logic in.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

they are dummy values - techinically they should be the same so we know the result doesn't depend on the pkscript, but again I don't think it matters.

output2 := wire.NewTxOut(100000, p2shAddr)
tx := &wire.MsgTx{
TxIn: []*wire.TxIn{{}},
TxOut: []*wire.TxOut{
output1,
output2,
},
}

// Add the tx and its first output as the credit.
addTxAndCredit(t, w, tx, 0)

testCases := []struct {
name string
prevOut *wire.OutPoint

// TODO(yy): refator `FetchOutpointInfo` to return wrapped
// errors.
errExpected string
}{
{
name: "no tx details",
prevOut: &wire.OutPoint{
Hash: chainhash.Hash{1, 2, 3},
Index: 0,
},
errExpected: "does not belong to the wallet",
},
{
name: "invalid output index",
prevOut: &wire.OutPoint{
Hash: tx.TxHash(),
Index: 1000,
},
errExpected: "invalid output index",
},
{
name: "no credit found",
prevOut: &wire.OutPoint{
Hash: tx.TxHash(),
Index: 1,
},
errExpected: "does not belong to the wallet",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

// Look up the UTXO for the outpoint now and compare it
// to the expected error.
tx, out, conf, err := w.FetchOutpointInfo(tc.prevOut)
require.ErrorContains(t, err, tc.errExpected)
require.Nil(t, tx)
require.Nil(t, out)
require.Zero(t, conf)
})
}
}

// TestFetchDerivationInfo checks that the wallet can gather the derivation
// info about an output based on the pkScript.
func TestFetchDerivationInfo(t *testing.T) {
Expand Down
Loading