integration/rpctest: add ability to create txs without change outputs

This commit is contained in:
Wilmer Paulino 2018-07-23 16:55:01 -07:00
parent 9aa83ad423
commit dfd7f6caf8
No known key found for this signature in database
GPG key ID: 6DF57B9F9514972F
4 changed files with 57 additions and 24 deletions

View file

@ -53,7 +53,7 @@ func makeTestOutput(r *rpctest.Harness, t *testing.T,
output := &wire.TxOut{PkScript: selfAddrScript, Value: 1e8} output := &wire.TxOut{PkScript: selfAddrScript, Value: 1e8}
// Next, create and broadcast a transaction paying to the output. // 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 { if err != nil {
return nil, nil, nil, err 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 // Finally create a valid transaction which creates the output crafted
// above. // above.
tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10) tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }

View file

@ -374,12 +374,15 @@ func (m *memWallet) NewAddress() (btcutil.Address, error) {
} }
// fundTx attempts to fund a transaction sending amt bitcoin. The coins are // 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 // selected such that the final amount spent pays enough fees as dictated by the
// the passed fee rate. The passed fee rate should be expressed in // passed fee rate. The passed fee rate should be expressed in
// satoshis-per-byte. // 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. // 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 ( const (
// spendSize is the largest number of bytes of a sigScript // spendSize is the largest number of bytes of a sigScript
// which spends a p2pkh output: OP_DATA_73 <sig> OP_DATA_33 <pubkey> // which spends a p2pkh output: OP_DATA_73 <sig> OP_DATA_33 <pubkey>
@ -415,10 +418,11 @@ func (m *memWallet) fundTx(tx *wire.MsgTx, amt btcutil.Amount, feeRate btcutil.A
continue continue
} }
// If we have any change left over, then add an additional // If we have any change left over and we should create a change
// output to the transaction reserved for change. // output, then add an additional output to the transaction
// reserved for it.
changeVal := amtSelected - amt - reqFee changeVal := amtSelected - amt - reqFee
if changeVal > 0 { if changeVal > 0 && change {
addr, err := m.newAddress() addr, err := m.newAddress()
if err != nil { if err != nil {
return err 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, func (m *memWallet) SendOutputs(outputs []*wire.TxOut,
feeRate btcutil.Amount) (*chainhash.Hash, error) { 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 { if err != nil {
return nil, err return nil, err
} }
@ -458,10 +476,13 @@ func (m *memWallet) SendOutputs(outputs []*wire.TxOut,
// CreateTransaction returns a fully signed transaction paying to the specified // CreateTransaction returns a fully signed transaction paying to the specified
// outputs while observing the desired fee rate. The passed fee rate should be // 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. // 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() m.Lock()
defer m.Unlock() 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. // 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 return nil, err
} }

View file

@ -356,20 +356,32 @@ func (h *Harness) SendOutputs(targetOutputs []*wire.TxOut,
return h.wallet.SendOutputs(targetOutputs, feeRate) 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 // CreateTransaction returns a fully signed transaction paying to the specified
// outputs while observing the desired fee rate. The passed fee rate should be // 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 // expressed in satoshis-per-byte. The transaction being created can optionally
// the crafted transaction are marked as unspendable in order to avoid // include a change output indicated by the change boolean. Any unspent outputs
// potential double-spends by future calls to this method. If the created // selected as inputs for the crafted transaction are marked as unspendable in
// transaction is cancelled for any reason then the selected inputs MUST be // order to avoid potential double-spends by future calls to this method. If the
// freed via a call to UnlockOutputs. Otherwise, the locked inputs won't be // 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. // returned to the pool of spendable outputs.
// //
// This function is safe for concurrent access. // This function is safe for concurrent access.
func (h *Harness) CreateTransaction(targetOutputs []*wire.TxOut, 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 // UnlockOutputs unlocks any outputs which were previously marked as

View file

@ -206,7 +206,7 @@ func testJoinMempools(r *Harness, t *testing.T) {
t.Fatalf("unable to generate pkscript to addr: %v", err) t.Fatalf("unable to generate pkscript to addr: %v", err)
} }
output := wire.NewTxOut(5e8, addrScript) 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 { if err != nil {
t.Fatalf("coinbase spend failed: %v", err) t.Fatalf("coinbase spend failed: %v", err)
} }
@ -340,7 +340,7 @@ func testGenerateAndSubmitBlock(r *Harness, t *testing.T) {
const numTxns = 5 const numTxns = 5
txns := make([]*btcutil.Tx, 0, numTxns) txns := make([]*btcutil.Tx, 0, numTxns)
for i := 0; i < numTxns; i++ { 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 { if err != nil {
t.Fatalf("unable to create tx: %v", err) t.Fatalf("unable to create tx: %v", err)
} }
@ -407,7 +407,7 @@ func testGenerateAndSubmitBlockWithCustomCoinbaseOutputs(r *Harness,
const numTxns = 5 const numTxns = 5
txns := make([]*btcutil.Tx, 0, numTxns) txns := make([]*btcutil.Tx, 0, numTxns)
for i := 0; i < numTxns; i++ { 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 { if err != nil {
t.Fatalf("unable to create tx: %v", err) 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) outputAmt := btcutil.Amount(50 * btcutil.SatoshiPerBitcoin)
output := wire.NewTxOut(int64(outputAmt), pkScript) 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 { if err != nil {
t.Fatalf("unable to create transaction: %v", err) t.Fatalf("unable to create transaction: %v", err)
} }