diff --git a/integration/csv_fork_test.go b/integration/csv_fork_test.go index 3dd471b1..345217c8 100644 --- a/integration/csv_fork_test.go +++ b/integration/csv_fork_test.go @@ -53,7 +53,7 @@ func makeTestOutput(r *rpctest.Harness, t *testing.T, output := &wire.TxOut{PkScript: selfAddrScript, Value: 1e8} // Next, create and broadcast a transaction paying to the output. - fundTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + fundTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { return nil, nil, nil, err } @@ -316,7 +316,7 @@ func createCSVOutput(r *rpctest.Harness, t *testing.T, // Finally create a valid transaction which creates the output crafted // above. - tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { return nil, nil, nil, err } diff --git a/integration/rpctest/memwallet.go b/integration/rpctest/memwallet.go index 0dccde10..f1613075 100644 --- a/integration/rpctest/memwallet.go +++ b/integration/rpctest/memwallet.go @@ -374,12 +374,15 @@ func (m *memWallet) NewAddress() (btcutil.Address, error) { } // fundTx attempts to fund a transaction sending amt bitcoin. The coins are -// selected such that the final amount spent pays enough fees as dictated by -// the passed fee rate. The passed fee rate should be expressed in -// satoshis-per-byte. +// selected such that the final amount spent pays enough fees as dictated by the +// passed fee rate. The passed fee rate should be expressed in +// satoshis-per-byte. The transaction being funded can optionally include a +// change output indicated by the change boolean. // // NOTE: The memWallet's mutex must be held when this function is called. -func (m *memWallet) fundTx(tx *wire.MsgTx, amt btcutil.Amount, feeRate btcutil.Amount) error { +func (m *memWallet) fundTx(tx *wire.MsgTx, amt btcutil.Amount, + feeRate btcutil.Amount, change bool) error { + const ( // spendSize is the largest number of bytes of a sigScript // which spends a p2pkh output: OP_DATA_73 OP_DATA_33 @@ -415,10 +418,11 @@ func (m *memWallet) fundTx(tx *wire.MsgTx, amt btcutil.Amount, feeRate btcutil.A continue } - // If we have any change left over, then add an additional - // output to the transaction reserved for change. + // If we have any change left over and we should create a change + // output, then add an additional output to the transaction + // reserved for it. changeVal := amtSelected - amt - reqFee - if changeVal > 0 { + if changeVal > 0 && change { addr, err := m.newAddress() if err != nil { return err @@ -448,7 +452,21 @@ func (m *memWallet) fundTx(tx *wire.MsgTx, amt btcutil.Amount, feeRate btcutil.A func (m *memWallet) SendOutputs(outputs []*wire.TxOut, feeRate btcutil.Amount) (*chainhash.Hash, error) { - tx, err := m.CreateTransaction(outputs, feeRate) + tx, err := m.CreateTransaction(outputs, feeRate, true) + if err != nil { + return nil, err + } + + return m.rpc.SendRawTransaction(tx, true) +} + +// SendOutputsWithoutChange creates and sends a transaction that pays to the +// specified outputs while observing the passed fee rate and ignoring a change +// output. The passed fee rate should be expressed in sat/b. +func (m *memWallet) SendOutputsWithoutChange(outputs []*wire.TxOut, + feeRate btcutil.Amount) (*chainhash.Hash, error) { + + tx, err := m.CreateTransaction(outputs, feeRate, false) if err != nil { return nil, err } @@ -458,10 +476,13 @@ func (m *memWallet) SendOutputs(outputs []*wire.TxOut, // CreateTransaction returns a fully signed transaction paying to the specified // outputs while observing the desired fee rate. The passed fee rate should be -// expressed in satoshis-per-byte. +// expressed in satoshis-per-byte. The transaction being created can optionally +// include a change output indicated by the change boolean. // // This function is safe for concurrent access. -func (m *memWallet) CreateTransaction(outputs []*wire.TxOut, feeRate btcutil.Amount) (*wire.MsgTx, error) { +func (m *memWallet) CreateTransaction(outputs []*wire.TxOut, + feeRate btcutil.Amount, change bool) (*wire.MsgTx, error) { + m.Lock() defer m.Unlock() @@ -476,7 +497,7 @@ func (m *memWallet) CreateTransaction(outputs []*wire.TxOut, feeRate btcutil.Amo } // Attempt to fund the transaction with spendable utxos. - if err := m.fundTx(tx, outputAmt, feeRate); err != nil { + if err := m.fundTx(tx, outputAmt, feeRate, change); err != nil { return nil, err } diff --git a/integration/rpctest/rpc_harness.go b/integration/rpctest/rpc_harness.go index ea8868ce..1c2612e4 100644 --- a/integration/rpctest/rpc_harness.go +++ b/integration/rpctest/rpc_harness.go @@ -356,20 +356,32 @@ func (h *Harness) SendOutputs(targetOutputs []*wire.TxOut, return h.wallet.SendOutputs(targetOutputs, feeRate) } +// SendOutputsWithoutChange creates and sends a transaction that pays to the +// specified outputs while observing the passed fee rate and ignoring a change +// output. The passed fee rate should be expressed in sat/b. +// +// This function is safe for concurrent access. +func (h *Harness) SendOutputsWithoutChange(targetOutputs []*wire.TxOut, + feeRate btcutil.Amount) (*chainhash.Hash, error) { + + return h.wallet.SendOutputsWithoutChange(targetOutputs, feeRate) +} + // CreateTransaction returns a fully signed transaction paying to the specified // outputs while observing the desired fee rate. The passed fee rate should be -// expressed in satoshis-per-byte. Any unspent outputs selected as inputs for -// the crafted transaction are marked as unspendable in order to avoid -// potential double-spends by future calls to this method. If the created -// transaction is cancelled for any reason then the selected inputs MUST be -// freed via a call to UnlockOutputs. Otherwise, the locked inputs won't be +// expressed in satoshis-per-byte. The transaction being created can optionally +// include a change output indicated by the change boolean. Any unspent outputs +// selected as inputs for the crafted transaction are marked as unspendable in +// order to avoid potential double-spends by future calls to this method. If the +// created transaction is cancelled for any reason then the selected inputs MUST +// be freed via a call to UnlockOutputs. Otherwise, the locked inputs won't be // returned to the pool of spendable outputs. // // This function is safe for concurrent access. func (h *Harness) CreateTransaction(targetOutputs []*wire.TxOut, - feeRate btcutil.Amount) (*wire.MsgTx, error) { + feeRate btcutil.Amount, change bool) (*wire.MsgTx, error) { - return h.wallet.CreateTransaction(targetOutputs, feeRate) + return h.wallet.CreateTransaction(targetOutputs, feeRate, change) } // UnlockOutputs unlocks any outputs which were previously marked as diff --git a/integration/rpctest/rpc_harness_test.go b/integration/rpctest/rpc_harness_test.go index 20797d38..717f8f45 100644 --- a/integration/rpctest/rpc_harness_test.go +++ b/integration/rpctest/rpc_harness_test.go @@ -206,7 +206,7 @@ func testJoinMempools(r *Harness, t *testing.T) { t.Fatalf("unable to generate pkscript to addr: %v", err) } output := wire.NewTxOut(5e8, addrScript) - testTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + testTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { t.Fatalf("coinbase spend failed: %v", err) } @@ -340,7 +340,7 @@ func testGenerateAndSubmitBlock(r *Harness, t *testing.T) { const numTxns = 5 txns := make([]*btcutil.Tx, 0, numTxns) for i := 0; i < numTxns; i++ { - tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { t.Fatalf("unable to create tx: %v", err) } @@ -407,7 +407,7 @@ func testGenerateAndSubmitBlockWithCustomCoinbaseOutputs(r *Harness, const numTxns = 5 txns := make([]*btcutil.Tx, 0, numTxns) for i := 0; i < numTxns; i++ { - tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { t.Fatalf("unable to create tx: %v", err) } @@ -522,7 +522,7 @@ func testMemWalletLockedOutputs(r *Harness, t *testing.T) { } outputAmt := btcutil.Amount(50 * btcutil.SatoshiPerBitcoin) output := wire.NewTxOut(int64(outputAmt), pkScript) - tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) + tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) if err != nil { t.Fatalf("unable to create transaction: %v", err) }