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}
// 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
}

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
// 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 <sig> OP_DATA_33 <pubkey>
@ -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
}

View file

@ -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

View file

@ -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)
}