Simplify txToPairs function signature.
This moves the non-error return values for txToPairs into a new struct, createdTx, and adds an additional value for the payment address string.
This commit is contained in:
parent
3c390364d7
commit
851a9d6e41
3 changed files with 46 additions and 33 deletions
26
cmdmgr.go
26
cmdmgr.go
|
@ -360,7 +360,7 @@ func SendFrom(reply chan []byte, msg *btcjson.Message) {
|
||||||
pairs := map[string]uint64{
|
pairs := map[string]uint64{
|
||||||
toaddr58: uint64(amt),
|
toaddr58: uint64(amt),
|
||||||
}
|
}
|
||||||
rawtx, inputs, changeUtxo, err := w.txToPairs(pairs, uint64(fee), int(minconf))
|
createdTx, err := w.txToPairs(pairs, uint64(fee), int(minconf))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := btcjson.ErrInternal
|
e := btcjson.ErrInternal
|
||||||
e.Message = err.Error()
|
e.Message = err.Error()
|
||||||
|
@ -372,7 +372,7 @@ func SendFrom(reply chan []byte, msg *btcjson.Message) {
|
||||||
n := <-NewJSONID
|
n := <-NewJSONID
|
||||||
var id interface{} = fmt.Sprintf("btcwallet(%v)", n)
|
var id interface{} = fmt.Sprintf("btcwallet(%v)", n)
|
||||||
m, err := btcjson.CreateMessageWithId("sendrawtransaction", id,
|
m, err := btcjson.CreateMessageWithId("sendrawtransaction", id,
|
||||||
hex.EncodeToString(rawtx))
|
hex.EncodeToString(createdTx.rawTx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := btcjson.ErrInternal
|
e := btcjson.ErrInternal
|
||||||
e.Message = err.Error()
|
e.Message = err.Error()
|
||||||
|
@ -394,12 +394,12 @@ func SendFrom(reply chan []byte, msg *btcjson.Message) {
|
||||||
|
|
||||||
// Remove previous unspent outputs now spent by the tx.
|
// Remove previous unspent outputs now spent by the tx.
|
||||||
w.UtxoStore.Lock()
|
w.UtxoStore.Lock()
|
||||||
modified := w.UtxoStore.s.Remove(inputs)
|
modified := w.UtxoStore.s.Remove(createdTx.inputs)
|
||||||
|
|
||||||
// Add unconfirmed change utxo (if any) to UtxoStore.
|
// Add unconfirmed change utxo (if any) to UtxoStore.
|
||||||
if changeUtxo != nil {
|
if createdTx.changeUtxo != nil {
|
||||||
w.UtxoStore.s = append(w.UtxoStore.s, changeUtxo)
|
w.UtxoStore.s = append(w.UtxoStore.s, createdTx.changeUtxo)
|
||||||
w.ReqSpentUtxoNtfn(changeUtxo)
|
w.ReqSpentUtxoNtfn(createdTx.changeUtxo)
|
||||||
modified = true
|
modified = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,7 +515,7 @@ func SendMany(reply chan []byte, msg *btcjson.Message) {
|
||||||
TxFee.Lock()
|
TxFee.Lock()
|
||||||
fee := TxFee.i
|
fee := TxFee.i
|
||||||
TxFee.Unlock()
|
TxFee.Unlock()
|
||||||
rawtx, inputs, changeUtxo, err := w.txToPairs(pairs, uint64(fee), int(minconf))
|
createdTx, err := w.txToPairs(pairs, uint64(fee), int(minconf))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := btcjson.ErrInternal
|
e := btcjson.ErrInternal
|
||||||
e.Message = err.Error()
|
e.Message = err.Error()
|
||||||
|
@ -527,7 +527,7 @@ func SendMany(reply chan []byte, msg *btcjson.Message) {
|
||||||
n := <-NewJSONID
|
n := <-NewJSONID
|
||||||
var id interface{} = fmt.Sprintf("btcwallet(%v)", n)
|
var id interface{} = fmt.Sprintf("btcwallet(%v)", n)
|
||||||
m, err := btcjson.CreateMessageWithId("sendrawtransaction", id,
|
m, err := btcjson.CreateMessageWithId("sendrawtransaction", id,
|
||||||
hex.EncodeToString(rawtx))
|
hex.EncodeToString(createdTx.rawTx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := btcjson.ErrInternal
|
e := btcjson.ErrInternal
|
||||||
e.Message = err.Error()
|
e.Message = err.Error()
|
||||||
|
@ -549,12 +549,12 @@ func SendMany(reply chan []byte, msg *btcjson.Message) {
|
||||||
|
|
||||||
// Remove previous unspent outputs now spent by the tx.
|
// Remove previous unspent outputs now spent by the tx.
|
||||||
w.UtxoStore.Lock()
|
w.UtxoStore.Lock()
|
||||||
modified := w.UtxoStore.s.Remove(inputs)
|
modified := w.UtxoStore.s.Remove(createdTx.inputs)
|
||||||
|
|
||||||
// Add unconfirmed change utxo (if any) to UtxoStore.
|
// Add unconfirmed change utxo (if any) to UtxoStore.
|
||||||
if changeUtxo != nil {
|
if createdTx.changeUtxo != nil {
|
||||||
w.UtxoStore.s = append(w.UtxoStore.s, changeUtxo)
|
w.UtxoStore.s = append(w.UtxoStore.s, createdTx.changeUtxo)
|
||||||
w.ReqSpentUtxoNtfn(changeUtxo)
|
w.ReqSpentUtxoNtfn(createdTx.changeUtxo)
|
||||||
modified = true
|
modified = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,7 +577,7 @@ func SendMany(reply chan []byte, msg *btcjson.Message) {
|
||||||
// Add hex string of raw tx to sent tx pool. If future blocks
|
// Add hex string of raw tx to sent tx pool. If future blocks
|
||||||
// do not contain a tx, a resend is attempted.
|
// do not contain a tx, a resend is attempted.
|
||||||
UnminedTxs.Lock()
|
UnminedTxs.Lock()
|
||||||
UnminedTxs.m[result.(string)] = hex.EncodeToString(rawtx)
|
UnminedTxs.m[result.(string)] = hex.EncodeToString(createdTx.rawTx)
|
||||||
UnminedTxs.Unlock()
|
UnminedTxs.Unlock()
|
||||||
|
|
||||||
ReplySuccess(reply, msg.Id, result)
|
ReplySuccess(reply, msg.Id, result)
|
||||||
|
|
49
createtx.go
49
createtx.go
|
@ -108,6 +108,16 @@ func selectInputs(s tx.UtxoStore, amt uint64, minconf int) (inputs []*tx.Utxo, b
|
||||||
return inputs, btcout, nil
|
return inputs, btcout, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createdTx is a type holding information regarding a newly-created
|
||||||
|
// transaction, including the raw bytes, inputs, and a address and UTXO
|
||||||
|
// for change.
|
||||||
|
type createdTx struct {
|
||||||
|
rawTx []byte
|
||||||
|
inputs []*tx.Utxo
|
||||||
|
changeAddr string
|
||||||
|
changeUtxo *tx.Utxo
|
||||||
|
}
|
||||||
|
|
||||||
// txToPairs creates a raw transaction sending the amounts for each
|
// txToPairs creates a raw transaction sending the amounts for each
|
||||||
// address/amount pair and fee to each address and the miner. minconf
|
// address/amount pair and fee to each address and the miner. minconf
|
||||||
// specifies the minimum number of confirmations required before an
|
// specifies the minimum number of confirmations required before an
|
||||||
|
@ -117,7 +127,7 @@ func selectInputs(s tx.UtxoStore, amt uint64, minconf int) (inputs []*tx.Utxo, b
|
||||||
// address, changeUtxo will point to a unconfirmed (height = -1, zeroed
|
// address, changeUtxo will point to a unconfirmed (height = -1, zeroed
|
||||||
// block hash) Utxo. ErrInsufficientFunds is returned if there are not
|
// block hash) Utxo. ErrInsufficientFunds is returned if there are not
|
||||||
// enough eligible unspent outputs to create the transaction.
|
// enough eligible unspent outputs to create the transaction.
|
||||||
func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int) (rawtx []byte, inputs []*tx.Utxo, changeUtxo *tx.Utxo, err error) {
|
func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int) (*createdTx, error) {
|
||||||
// Recorded unspent transactions should not be modified until this
|
// Recorded unspent transactions should not be modified until this
|
||||||
// finishes.
|
// finishes.
|
||||||
w.UtxoStore.RLock()
|
w.UtxoStore.RLock()
|
||||||
|
@ -135,20 +145,20 @@ func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int)
|
||||||
// Select unspent outputs to be used in transaction.
|
// Select unspent outputs to be used in transaction.
|
||||||
inputs, btcout, err := selectInputs(w.UtxoStore.s, amt+fee, minconf)
|
inputs, btcout, err := selectInputs(w.UtxoStore.s, amt+fee, minconf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add outputs to new tx.
|
// Add outputs to new tx.
|
||||||
for addr, amt := range pairs {
|
for addr, amt := range pairs {
|
||||||
addr160, _, err := btcutil.DecodeAddress(addr)
|
addr160, _, err := btcutil.DecodeAddress(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("cannot decode address: %s", err)
|
return nil, fmt.Errorf("cannot decode address: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spend amt to addr160
|
// Spend amt to addr160
|
||||||
pkScript, err := btcscript.PayToPubKeyHashScript(addr160)
|
pkScript, err := btcscript.PayToPubKeyHashScript(addr160)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("cannot create txout script: %s", err)
|
return nil, fmt.Errorf("cannot create txout script: %s", err)
|
||||||
}
|
}
|
||||||
txout := btcwire.NewTxOut(int64(amt), pkScript)
|
txout := btcwire.NewTxOut(int64(amt), pkScript)
|
||||||
msgtx.AddTxOut(txout)
|
msgtx.AddTxOut(txout)
|
||||||
|
@ -156,23 +166,26 @@ func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int)
|
||||||
|
|
||||||
// Check if there are leftover unspent outputs, and return coins back to
|
// Check if there are leftover unspent outputs, and return coins back to
|
||||||
// a new address we own.
|
// a new address we own.
|
||||||
|
var changeUtxo *tx.Utxo
|
||||||
|
var changeAddr string
|
||||||
if btcout > amt+fee {
|
if btcout > amt+fee {
|
||||||
// Create a new address to spend leftover outputs to.
|
// Create a new address to spend leftover outputs to.
|
||||||
// TODO(jrick): use the next chained address, not the next unused.
|
// TODO(jrick): use the next chained address, not the next unused.
|
||||||
newaddr, err := w.NextUnusedAddress()
|
var err error
|
||||||
|
changeAddr, err = w.NextUnusedAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("failed to get next unused address: %s", err)
|
return nil, fmt.Errorf("failed to get next unused address: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spend change
|
// Spend change
|
||||||
change := btcout - (amt + fee)
|
change := btcout - (amt + fee)
|
||||||
newaddr160, _, err := btcutil.DecodeAddress(newaddr)
|
changeAddrHash, _, err := btcutil.DecodeAddress(changeAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("cannot decode new address: %s", err)
|
return nil, fmt.Errorf("cannot decode new address: %s", err)
|
||||||
}
|
}
|
||||||
pkScript, err := btcscript.PayToPubKeyHashScript(newaddr160)
|
pkScript, err := btcscript.PayToPubKeyHashScript(changeAddrHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("cannot create txout script: %s", err)
|
return nil, fmt.Errorf("cannot create txout script: %s", err)
|
||||||
}
|
}
|
||||||
msgtx.AddTxOut(btcwire.NewTxOut(int64(change), pkScript))
|
msgtx.AddTxOut(btcwire.NewTxOut(int64(change), pkScript))
|
||||||
|
|
||||||
|
@ -187,7 +200,7 @@ func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int)
|
||||||
Height: -1,
|
Height: -1,
|
||||||
Subscript: pkScript,
|
Subscript: pkScript,
|
||||||
}
|
}
|
||||||
copy(changeUtxo.AddrHash[:], newaddr160)
|
copy(changeUtxo.AddrHash[:], changeAddrHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Selected unspent outputs become new transaction's inputs.
|
// Selected unspent outputs become new transaction's inputs.
|
||||||
|
@ -197,11 +210,11 @@ func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int)
|
||||||
for i, ip := range inputs {
|
for i, ip := range inputs {
|
||||||
addrstr, err := btcutil.EncodeAddress(ip.AddrHash[:], w.Wallet.Net())
|
addrstr, err := btcutil.EncodeAddress(ip.AddrHash[:], w.Wallet.Net())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
privkey, err := w.GetAddressKey(addrstr)
|
privkey, err := w.GetAddressKey(addrstr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("cannot get address key: %v", err)
|
return nil, fmt.Errorf("cannot get address key: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jrick): we want compressed pubkeys. Switch wallet to
|
// TODO(jrick): we want compressed pubkeys. Switch wallet to
|
||||||
|
@ -210,7 +223,7 @@ func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int)
|
||||||
sigscript, err := btcscript.SignatureScript(msgtx, i,
|
sigscript, err := btcscript.SignatureScript(msgtx, i,
|
||||||
ip.Subscript, btcscript.SigHashAll, privkey, false)
|
ip.Subscript, btcscript.SigHashAll, privkey, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("cannot create sigscript: %s", err)
|
return nil, fmt.Errorf("cannot create sigscript: %s", err)
|
||||||
}
|
}
|
||||||
msgtx.TxIn[i].SignatureScript = sigscript
|
msgtx.TxIn[i].SignatureScript = sigscript
|
||||||
}
|
}
|
||||||
|
@ -225,10 +238,10 @@ func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int)
|
||||||
engine, err := btcscript.NewScript(txin.SignatureScript, inputs[i].Subscript, i,
|
engine, err := btcscript.NewScript(txin.SignatureScript, inputs[i].Subscript, i,
|
||||||
msgtx, flags)
|
msgtx, flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("cannot create script engine: %s", err)
|
return nil, fmt.Errorf("cannot create script engine: %s", err)
|
||||||
}
|
}
|
||||||
if err = engine.Execute(); err != nil {
|
if err = engine.Execute(); err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("cannot validate transaction: %s", err)
|
return nil, fmt.Errorf("cannot validate transaction: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,12 +249,12 @@ func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int)
|
||||||
if changeUtxo != nil {
|
if changeUtxo != nil {
|
||||||
txHash, err := msgtx.TxSha()
|
txHash, err := msgtx.TxSha()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("cannot create transaction hash: %s", err)
|
return nil, fmt.Errorf("cannot create transaction hash: %s", err)
|
||||||
}
|
}
|
||||||
copy(changeUtxo.Out.Hash[:], txHash[:])
|
copy(changeUtxo.Out.Hash[:], txHash[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
msgtx.BtcEncode(buf, btcwire.ProtocolVersion)
|
msgtx.BtcEncode(buf, btcwire.ProtocolVersion)
|
||||||
return buf.Bytes(), inputs, changeUtxo, nil
|
return &createdTx{buf.Bytes(), inputs, changeAddr, changeUtxo}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ func TestFakeTxs(t *testing.T) {
|
||||||
pairs := map[string]uint64{
|
pairs := map[string]uint64{
|
||||||
"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": 5000,
|
"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": 5000,
|
||||||
}
|
}
|
||||||
rawtx, _, _, err := btcw.txToPairs(pairs, 100, 0)
|
createdTx, err := btcw.txToPairs(pairs, 100, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Tx creation failed: %s", err)
|
t.Errorf("Tx creation failed: %s", err)
|
||||||
return
|
return
|
||||||
|
@ -75,7 +75,7 @@ func TestFakeTxs(t *testing.T) {
|
||||||
Id: "test",
|
Id: "test",
|
||||||
Method: "sendrawtransaction",
|
Method: "sendrawtransaction",
|
||||||
Params: []interface{}{
|
Params: []interface{}{
|
||||||
hex.EncodeToString(rawtx),
|
hex.EncodeToString(createdTx.rawTx),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
m, _ := json.Marshal(msg)
|
m, _ := json.Marshal(msg)
|
||||||
|
|
Loading…
Reference in a new issue