Update for recent btcscript API changes.

This commit changes all code which deals with extracting addresses from
scripts to use the btcscript API ExtractPkScriptAddrs which in turn makes
use of the new btcutil.Address interface.

This provides much cleaner code for dealing with arbitrary script
destinations which is extensible without having to churn the APIs if new
destination types are added.
This commit is contained in:
Dave Collins 2014-01-07 20:30:01 -06:00
parent 96ded50f6b
commit 462bc5a031
2 changed files with 128 additions and 142 deletions

View File

@ -630,26 +630,18 @@ func createVoutList(mtx *btcwire.MsgTx, net btcwire.BitcoinNet) ([]btcjson.Vout,
voutList[i].ScriptPubKey.Asm = disbuf voutList[i].ScriptPubKey.Asm = disbuf
voutList[i].ScriptPubKey.Hex = hex.EncodeToString(v.PkScript) voutList[i].ScriptPubKey.Hex = hex.EncodeToString(v.PkScript)
scriptType, reqSigs, hashes := btcscript.CalcPkScriptAddrHashes(v.PkScript) // Ignore the error here since an error means the script
voutList[i].ScriptPubKey.Type = scriptType.String() // couldn't parse and there is no additional information about
// it anyways.
scriptClass, addrs, reqSigs, _ := btcscript.ExtractPkScriptAddrs(v.PkScript, net)
voutList[i].ScriptPubKey.Type = scriptClass.String()
voutList[i].ScriptPubKey.ReqSigs = reqSigs voutList[i].ScriptPubKey.ReqSigs = reqSigs
if hashes == nil { if addrs == nil {
voutList[i].ScriptPubKey.Addresses = nil voutList[i].ScriptPubKey.Addresses = nil
} else { } else {
voutList[i].ScriptPubKey.Addresses = make([]string, len(hashes)) voutList[i].ScriptPubKey.Addresses = make([]string, len(addrs))
for j := 0; j < len(hashes); j++ { for j, addr := range addrs {
var addr btcutil.Address
if scriptType == btcscript.ScriptHashTy {
addr, err = btcutil.NewAddressScriptHash(hashes[j], net)
} else {
addr, err = btcutil.NewAddressPubKeyHash(hashes[j], net)
}
if err != nil {
// hash will always be 20 bytes, so the only
// possible error is from an invalid network.
return nil, errors.New("Cannot create address with invalid network.")
}
voutList[i].ScriptPubKey.Addresses[j] = addr.EncodeAddress() voutList[i].ScriptPubKey.Addresses[j] = addr.EncodeAddress()
} }
} }
@ -724,22 +716,14 @@ func handleDecodeScript(s *rpcServer, cmd btcjson.Cmd) (interface{}, error) {
disbuf, _ := btcscript.DisasmString(script) disbuf, _ := btcscript.DisasmString(script)
// Get information about the script. // Get information about the script.
// TODO(davec): The btcscript CalcPkScriptAddrHashes function should // Ignore the error here since an error means the script couldn't parse
// be changed to return btcutil.Address. // and there is no additinal information about it anyways.
net := s.server.btcnet net := s.server.btcnet
scriptType, reqSigs, hashes := btcscript.CalcPkScriptAddrHashes(script) scriptClass, addrs, reqSigs, _ := btcscript.ExtractPkScriptAddrs(script, net)
addresses := make([]string, len(hashes)) addresses := make([]string, len(addrs))
for i, hash := range hashes { for i, addr := range addrs {
var addr btcutil.Address
if scriptType == btcscript.ScriptHashTy {
addr, err = btcutil.NewAddressScriptHash(hash, net)
} else {
addr, err = btcutil.NewAddressPubKeyHash(hash, net)
}
if err == nil {
addresses[i] = addr.EncodeAddress() addresses[i] = addr.EncodeAddress()
} }
}
// Convert the script itself to a pay-to-script-hash address. // Convert the script itself to a pay-to-script-hash address.
p2sh, err := btcutil.NewAddressScriptHash(script, net) p2sh, err := btcutil.NewAddressScriptHash(script, net)
@ -754,7 +738,7 @@ func handleDecodeScript(s *rpcServer, cmd btcjson.Cmd) (interface{}, error) {
reply := btcjson.DecodeScriptResult{ reply := btcjson.DecodeScriptResult{
Asm: disbuf, Asm: disbuf,
ReqSigs: reqSigs, ReqSigs: reqSigs,
Type: scriptType.String(), Type: scriptClass.String(),
Addresses: addresses, Addresses: addresses,
P2sh: p2sh.EncodeAddress(), P2sh: p2sh.EncodeAddress(),
} }

View File

@ -65,7 +65,7 @@ type notificationCtx struct {
} }
// AddTxRequest adds the request context for new transaction notifications. // AddTxRequest adds the request context for new transaction notifications.
func (r *wsContext) AddTxRequest(walletNotification chan []byte, rc *requestContexts, addrhash string, id interface{}) { func (r *wsContext) AddTxRequest(walletNotification chan []byte, rc *requestContexts, addr string, id interface{}) {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
@ -75,19 +75,19 @@ func (r *wsContext) AddTxRequest(walletNotification chan []byte, rc *requestCont
rc: rc, rc: rc,
} }
clist, ok := r.txNotifications[addrhash] clist, ok := r.txNotifications[addr]
if !ok { if !ok {
clist = list.New() clist = list.New()
r.txNotifications[addrhash] = clist r.txNotifications[addr] = clist
} }
clist.PushBack(nc) clist.PushBack(nc)
rc.txRequests[addrhash] = id rc.txRequests[addr] = id
} }
func (r *wsContext) removeGlobalTxRequest(walletNotification chan []byte, addrhash string) { func (r *wsContext) removeGlobalTxRequest(walletNotification chan []byte, addr string) {
clist := r.txNotifications[addrhash] clist := r.txNotifications[addr]
var enext *list.Element var enext *list.Element
for e := clist.Front(); e != nil; e = enext { for e := clist.Front(); e != nil; e = enext {
enext = e.Next() enext = e.Next()
@ -99,7 +99,7 @@ func (r *wsContext) removeGlobalTxRequest(walletNotification chan []byte, addrha
} }
if clist.Len() == 0 { if clist.Len() == 0 {
delete(r.txNotifications, addrhash) delete(r.txNotifications, addr)
} }
} }
@ -351,8 +351,8 @@ func handleNotifyNewTXs(s *rpcServer, cmd btcjson.Cmd,
return fmt.Errorf("address is not P2PKH: %v", addr.EncodeAddress()) return fmt.Errorf("address is not P2PKH: %v", addr.EncodeAddress())
} }
s.ws.AddTxRequest(walletNotification, rc, s.ws.AddTxRequest(walletNotification, rc, addr.EncodeAddress(),
string(addr.ScriptAddress()), cmd.Id()) cmd.Id())
} }
mreply, _ := json.Marshal(reply) mreply, _ := json.Marshal(reply)
@ -419,24 +419,22 @@ func handleRescan(s *rpcServer, cmd btcjson.Cmd,
for i := range blkshalist { for i := range blkshalist {
blk, err := s.server.db.FetchBlockBySha(&blkshalist[i]) blk, err := s.server.db.FetchBlockBySha(&blkshalist[i])
if err != nil { if err != nil {
rpcsLog.Errorf("Error looking up block sha: %v", err) rpcsLog.Errorf("Error looking up block sha: %v",
err)
return err return err
} }
txs := blk.Transactions() for _, tx := range blk.Transactions() {
for _, tx := range txs {
var txReply *btcdb.TxListReply var txReply *btcdb.TxListReply
for txOutIdx, txout := range tx.MsgTx().TxOut { for txOutIdx, txout := range tx.MsgTx().TxOut {
st, txaddrhash, err := btcscript.ScriptToAddrHash(txout.PkScript) _, addrs, _, err := btcscript.ExtractPkScriptAddrs(
if st != btcscript.ScriptAddr || err != nil { txout.PkScript, s.server.btcnet)
if err != nil {
continue continue
} }
txaddr, err := btcutil.NewAddressPubKeyHash(txaddrhash, s.server.btcnet)
if err != nil {
rpcsLog.Errorf("Error creating address: %v", err)
return err
}
if _, ok := rescanCmd.Addresses[txaddr.EncodeAddress()]; ok { for i, addr := range addrs {
encodedAddr := addr.EncodeAddress()
if _, ok := rescanCmd.Addresses[encodedAddr]; ok {
// TODO(jrick): This lookup is expensive and can be avoided // TODO(jrick): This lookup is expensive and can be avoided
// if the wallet is sent the previous outpoints for all inputs // if the wallet is sent the previous outpoints for all inputs
// of the tx, so any can removed from the utxo set (since // of the tx, so any can removed from the utxo set (since
@ -467,7 +465,7 @@ func handleRescan(s *rpcServer, cmd btcjson.Cmd,
PkScript string `json:"pkscript"` PkScript string `json:"pkscript"`
Spent bool `json:"spent"` Spent bool `json:"spent"`
}{ }{
Receiver: txaddr.EncodeAddress(), Receiver: encodedAddr,
Height: blk.Height(), Height: blk.Height(),
BlockHash: blkshalist[i].String(), BlockHash: blkshalist[i].String(),
BlockIndex: tx.Index(), BlockIndex: tx.Index(),
@ -484,6 +482,7 @@ func handleRescan(s *rpcServer, cmd btcjson.Cmd,
} }
} }
} }
}
if maxblock-minblock > int64(len(blkshalist)) { if maxblock-minblock > int64(len(blkshalist)) {
minblock += int64(len(blkshalist)) minblock += int64(len(blkshalist))
@ -782,21 +781,23 @@ func (s *rpcServer) newBlockNotifyCheckTxIn(tx *btcutil.Tx) {
// additional block information is passed with the notifications. // additional block information is passed with the notifications.
func (s *rpcServer) NotifyForTxOuts(tx *btcutil.Tx, block *btcutil.Block) { func (s *rpcServer) NotifyForTxOuts(tx *btcutil.Tx, block *btcutil.Block) {
for i, txout := range tx.MsgTx().TxOut { for i, txout := range tx.MsgTx().TxOut {
stype, txaddrhash, err := btcscript.ScriptToAddrHash(txout.PkScript) _, addrs, _, err := btcscript.ExtractPkScriptAddrs(
if stype != btcscript.ScriptAddr || err != nil { txout.PkScript, s.server.btcnet)
// Only support pay-to-pubkey-hash right now. if err != nil {
continue continue
} }
if idlist, ok := s.ws.txNotifications[string(txaddrhash)]; ok {
for _, addr := range addrs {
// Only support pay-to-pubkey-hash right now.
if _, ok := addr.(*btcutil.AddressPubKeyHash); !ok {
continue
}
encodedAddr := addr.EncodeAddress()
if idlist, ok := s.ws.txNotifications[encodedAddr]; ok {
for e := idlist.Front(); e != nil; e = e.Next() { for e := idlist.Front(); e != nil; e = e.Next() {
ctx := e.Value.(*notificationCtx) ctx := e.Value.(*notificationCtx)
txaddr, err := btcutil.NewAddressPubKeyHash(txaddrhash, s.server.btcnet)
if err != nil {
rpcsLog.Debugf("Error creating address; dropping Tx notification.")
break
}
// TODO(jrick): shove this in btcws // TODO(jrick): shove this in btcws
result := struct { result := struct {
Receiver string `json:"receiver"` Receiver string `json:"receiver"`
@ -809,7 +810,7 @@ func (s *rpcServer) NotifyForTxOuts(tx *btcutil.Tx, block *btcutil.Block) {
Amount int64 `json:"amount"` Amount int64 `json:"amount"`
PkScript string `json:"pkscript"` PkScript string `json:"pkscript"`
}{ }{
Receiver: txaddr.EncodeAddress(), Receiver: encodedAddr,
TxID: tx.Sha().String(), TxID: tx.Sha().String(),
TxOutIndex: uint32(i), TxOutIndex: uint32(i),
Amount: txout.Value, Amount: txout.Value,
@ -845,4 +846,5 @@ func (s *rpcServer) NotifyForTxOuts(tx *btcutil.Tx, block *btcutil.Block) {
} }
} }
} }
}
} }