Avoid calling getrawtransaction from signrawtransaction.
Replace all calls to getrawtransaction with gettxout. As btcd no longer enables the transaction index by default, getrawtransaction can no longer be depended on. gettxout is safe to use since it queries the utxo set. This also means that it will continue to work even when pruning is enabled. This should be further improved in the future to not look up previous output scripts over btcd rpc when they are already saved by the wallet. Fixes #410.
This commit is contained in:
parent
c82b8bae20
commit
a549b6908a
1 changed files with 12 additions and 40 deletions
|
@ -1622,13 +1622,6 @@ func SignMessage(icmd interface{}, w *wallet.Wallet) (interface{}, error) {
|
||||||
return base64.StdEncoding.EncodeToString(sigbytes), nil
|
return base64.StdEncoding.EncodeToString(sigbytes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// pendingTx is used for async fetching of transaction dependancies in
|
|
||||||
// SignRawTransaction.
|
|
||||||
type pendingTx struct {
|
|
||||||
resp btcrpcclient.FutureGetRawTransactionResult
|
|
||||||
inputs []uint32 // list of inputs that care about this tx.
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignRawTransaction handles the signrawtransaction command.
|
// SignRawTransaction handles the signrawtransaction command.
|
||||||
func SignRawTransaction(icmd interface{}, w *wallet.Wallet, chainClient *chain.RPCClient) (interface{}, error) {
|
func SignRawTransaction(icmd interface{}, w *wallet.Wallet, chainClient *chain.RPCClient) (interface{}, error) {
|
||||||
cmd := icmd.(*btcjson.SignRawTransactionCmd)
|
cmd := icmd.(*btcjson.SignRawTransactionCmd)
|
||||||
|
@ -1711,30 +1704,17 @@ func SignRawTransaction(icmd interface{}, w *wallet.Wallet, chainClient *chain.R
|
||||||
// querying btcd with getrawtransaction. We queue up a bunch of async
|
// querying btcd with getrawtransaction. We queue up a bunch of async
|
||||||
// requests and will wait for replies after we have checked the rest of
|
// requests and will wait for replies after we have checked the rest of
|
||||||
// the arguments.
|
// the arguments.
|
||||||
requested := make(map[wire.ShaHash]*pendingTx)
|
requested := make(map[wire.OutPoint]btcrpcclient.FutureGetTxOutResult)
|
||||||
for _, txIn := range tx.TxIn {
|
for _, txIn := range tx.TxIn {
|
||||||
// Did we get this txin from the arguments?
|
// Did we get this outpoint from the arguments?
|
||||||
if _, ok := inputs[txIn.PreviousOutPoint]; ok {
|
if _, ok := inputs[txIn.PreviousOutPoint]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are we already fetching this tx? If so mark us as interested
|
// Asynchronously request the output script.
|
||||||
// in this outpoint. (N.B. that any *sane* tx will only
|
requested[txIn.PreviousOutPoint] = chainClient.GetTxOutAsync(
|
||||||
// reference each outpoint once, since anything else is a double
|
&txIn.PreviousOutPoint.Hash, txIn.PreviousOutPoint.Index,
|
||||||
// spend. We don't check this ourselves to save having to scan
|
true)
|
||||||
// the array, it will fail later if so).
|
|
||||||
if ptx, ok := requested[txIn.PreviousOutPoint.Hash]; ok {
|
|
||||||
ptx.inputs = append(ptx.inputs,
|
|
||||||
txIn.PreviousOutPoint.Index)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Never heard of this one before, request it.
|
|
||||||
prevHash := &txIn.PreviousOutPoint.Hash
|
|
||||||
requested[txIn.PreviousOutPoint.Hash] = &pendingTx{
|
|
||||||
resp: chainClient.GetRawTransactionAsync(prevHash),
|
|
||||||
inputs: []uint32{txIn.PreviousOutPoint.Index},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse list of private keys, if present. If there are any keys here
|
// Parse list of private keys, if present. If there are any keys here
|
||||||
|
@ -1767,24 +1747,16 @@ func SignRawTransaction(icmd interface{}, w *wallet.Wallet, chainClient *chain.R
|
||||||
// We have checked the rest of the args. now we can collect the async
|
// We have checked the rest of the args. now we can collect the async
|
||||||
// txs. TODO: If we don't mind the possibility of wasting work we could
|
// txs. TODO: If we don't mind the possibility of wasting work we could
|
||||||
// move waiting to the following loop and be slightly more asynchronous.
|
// move waiting to the following loop and be slightly more asynchronous.
|
||||||
for txid, ptx := range requested {
|
for outPoint, resp := range requested {
|
||||||
tx, err := ptx.resp.Receive()
|
result, err := resp.Receive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
script, err := hex.DecodeString(result.ScriptPubKey.Hex)
|
||||||
for _, input := range ptx.inputs {
|
if err != nil {
|
||||||
if input >= uint32(len(tx.MsgTx().TxOut)) {
|
return nil, err
|
||||||
e := fmt.Errorf("input %s:%d is not in tx",
|
|
||||||
txid.String(), input)
|
|
||||||
return nil, InvalidParameterError{e}
|
|
||||||
}
|
|
||||||
|
|
||||||
inputs[wire.OutPoint{
|
|
||||||
Hash: txid,
|
|
||||||
Index: input,
|
|
||||||
}] = tx.MsgTx().TxOut[input].PkScript
|
|
||||||
}
|
}
|
||||||
|
inputs[outPoint] = script
|
||||||
}
|
}
|
||||||
|
|
||||||
// All args collected. Now we can sign all the inputs that we can.
|
// All args collected. Now we can sign all the inputs that we can.
|
||||||
|
|
Loading…
Reference in a new issue