mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-06 06:06:49 +00:00
[NOD-333] Make ExtractScriptPubKeyAddrs return single address (#415)
* [NOD-333] Make ExtractScriptPubKeyAddrs return single address * [NOD-333] Remove reference to required signatures from ExtractScriptPubKeyAddrs
This commit is contained in:
parent
1064b5009d
commit
7371120481
@ -626,31 +626,29 @@ type writeIndexData map[[addrKeySize]byte][]int
|
||||
func (idx *AddrIndex) indexScriptPubKey(data writeIndexData, scriptPubKey []byte, txIdx int) {
|
||||
// Nothing to index if the script is non-standard or otherwise doesn't
|
||||
// contain any addresses.
|
||||
_, addrs, _, err := txscript.ExtractScriptPubKeyAddrs(scriptPubKey,
|
||||
_, addr, err := txscript.ExtractScriptPubKeyAddress(scriptPubKey,
|
||||
idx.dagParams)
|
||||
if err != nil || len(addrs) == 0 {
|
||||
if err != nil || addr == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
addrKey, err := addrToKey(addr)
|
||||
if err != nil {
|
||||
// Ignore unsupported address types.
|
||||
continue
|
||||
}
|
||||
|
||||
// Avoid inserting the transaction more than once. Since the
|
||||
// transactions are indexed serially any duplicates will be
|
||||
// indexed in a row, so checking the most recent entry for the
|
||||
// address is enough to detect duplicates.
|
||||
indexedTxns := data[addrKey]
|
||||
numTxns := len(indexedTxns)
|
||||
if numTxns > 0 && indexedTxns[numTxns-1] == txIdx {
|
||||
continue
|
||||
}
|
||||
indexedTxns = append(indexedTxns, txIdx)
|
||||
data[addrKey] = indexedTxns
|
||||
addrKey, err := addrToKey(addr)
|
||||
if err != nil {
|
||||
// Ignore unsupported address types.
|
||||
return
|
||||
}
|
||||
|
||||
// Avoid inserting the transaction more than once. Since the
|
||||
// transactions are indexed serially any duplicates will be
|
||||
// indexed in a row, so checking the most recent entry for the
|
||||
// address is enough to detect duplicates.
|
||||
indexedTxns := data[addrKey]
|
||||
numTxns := len(indexedTxns)
|
||||
if numTxns > 0 && indexedTxns[numTxns-1] == txIdx {
|
||||
return
|
||||
}
|
||||
indexedTxns = append(indexedTxns, txIdx)
|
||||
data[addrKey] = indexedTxns
|
||||
}
|
||||
|
||||
// indexBlock extract all of the standard addresses from all of the transactions
|
||||
@ -791,33 +789,31 @@ func (idx *AddrIndex) indexUnconfirmedAddresses(scriptPubKey []byte, tx *util.Tx
|
||||
// The error is ignored here since the only reason it can fail is if the
|
||||
// script fails to parse and it was already validated before being
|
||||
// admitted to the mempool.
|
||||
_, addresses, _, _ := txscript.ExtractScriptPubKeyAddrs(scriptPubKey,
|
||||
_, addr, _ := txscript.ExtractScriptPubKeyAddress(scriptPubKey,
|
||||
idx.dagParams)
|
||||
for _, addr := range addresses {
|
||||
// Ignore unsupported address types.
|
||||
addrKey, err := addrToKey(addr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Add a mapping from the address to the transaction.
|
||||
idx.unconfirmedLock.Lock()
|
||||
addrIndexEntry := idx.txnsByAddr[addrKey]
|
||||
if addrIndexEntry == nil {
|
||||
addrIndexEntry = make(map[daghash.TxID]*util.Tx)
|
||||
idx.txnsByAddr[addrKey] = addrIndexEntry
|
||||
}
|
||||
addrIndexEntry[*tx.ID()] = tx
|
||||
|
||||
// Add a mapping from the transaction to the address.
|
||||
addrsByTxEntry := idx.addrsByTx[*tx.ID()]
|
||||
if addrsByTxEntry == nil {
|
||||
addrsByTxEntry = make(map[[addrKeySize]byte]struct{})
|
||||
idx.addrsByTx[*tx.ID()] = addrsByTxEntry
|
||||
}
|
||||
addrsByTxEntry[addrKey] = struct{}{}
|
||||
idx.unconfirmedLock.Unlock()
|
||||
// Ignore unsupported address types.
|
||||
addrKey, err := addrToKey(addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Add a mapping from the address to the transaction.
|
||||
idx.unconfirmedLock.Lock()
|
||||
addrIndexEntry := idx.txnsByAddr[addrKey]
|
||||
if addrIndexEntry == nil {
|
||||
addrIndexEntry = make(map[daghash.TxID]*util.Tx)
|
||||
idx.txnsByAddr[addrKey] = addrIndexEntry
|
||||
}
|
||||
addrIndexEntry[*tx.ID()] = tx
|
||||
|
||||
// Add a mapping from the transaction to the address.
|
||||
addrsByTxEntry := idx.addrsByTx[*tx.ID()]
|
||||
if addrsByTxEntry == nil {
|
||||
addrsByTxEntry = make(map[[addrKeySize]byte]struct{})
|
||||
idx.addrsByTx[*tx.ID()] = addrsByTxEntry
|
||||
}
|
||||
addrsByTxEntry[addrKey] = struct{}{}
|
||||
idx.unconfirmedLock.Unlock()
|
||||
}
|
||||
|
||||
// AddUnconfirmedTx adds all addresses related to the transaction to the
|
||||
|
@ -56,11 +56,10 @@ type CreateMultiSigResult struct {
|
||||
|
||||
// DecodeScriptResult models the data returned from the decodescript command.
|
||||
type DecodeScriptResult struct {
|
||||
Asm string `json:"asm"`
|
||||
Type string `json:"type"`
|
||||
ReqSigs int32 `json:"reqSigs,omitempty"`
|
||||
Addresses []string `json:"addresses,omitempty"`
|
||||
P2sh string `json:"p2sh,omitempty"`
|
||||
Asm string `json:"asm"`
|
||||
Type string `json:"type"`
|
||||
Address *string `json:"address,omitempty"`
|
||||
P2sh string `json:"p2sh,omitempty"`
|
||||
}
|
||||
|
||||
// GetManualNodeInfoResultAddr models the data of the addresses portion of the
|
||||
@ -268,11 +267,10 @@ type GetRawMempoolVerboseResult struct {
|
||||
// ScriptPubKeyResult models the scriptPubKey data of a tx script. It is
|
||||
// defined separately since it is used by multiple commands.
|
||||
type ScriptPubKeyResult struct {
|
||||
Asm string `json:"asm"`
|
||||
Hex string `json:"hex,omitempty"`
|
||||
Type string `json:"type"`
|
||||
ReqSigs int32 `json:"reqSigs,omitempty"`
|
||||
Addresses []string `json:"addresses,omitempty"`
|
||||
Asm string `json:"asm"`
|
||||
Hex string `json:"hex,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Address *string `json:"address,omitempty"`
|
||||
}
|
||||
|
||||
// GetSubnetworkResult models the data from the getSubnetwork command.
|
||||
@ -350,8 +348,8 @@ func (v *Vin) MarshalJSON() ([]byte, error) {
|
||||
|
||||
// PrevOut represents previous output for an input Vin.
|
||||
type PrevOut struct {
|
||||
Addresses []string `json:"addresses,omitempty"`
|
||||
Value float64 `json:"value"`
|
||||
Address *string `json:"address,omitempty"`
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
// VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction
|
||||
|
@ -61,12 +61,12 @@ func TestDAGSvrCustomResults(t *testing.T) {
|
||||
Hex: "00",
|
||||
},
|
||||
PrevOut: &btcjson.PrevOut{
|
||||
Addresses: []string{"addr1"},
|
||||
Value: 0,
|
||||
Address: btcjson.String("addr1"),
|
||||
Value: 0,
|
||||
},
|
||||
Sequence: 4294967295,
|
||||
},
|
||||
expected: `{"txId":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0},"sequence":4294967295}`,
|
||||
expected: `{"txId":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"address":"addr1","value":0},"sequence":4294967295}`,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -642,23 +642,19 @@ func createVoutList(mtx *wire.MsgTx, chainParams *dagconfig.Params, filterAddrMa
|
||||
// Ignore the error here since an error means the script
|
||||
// couldn't parse and there is no additional information about
|
||||
// it anyways.
|
||||
scriptClass, addrs, reqSigs, _ := txscript.ExtractScriptPubKeyAddrs(
|
||||
scriptClass, addr, _ := txscript.ExtractScriptPubKeyAddress(
|
||||
v.ScriptPubKey, chainParams)
|
||||
|
||||
// Encode the addresses while checking if the address passes the
|
||||
// filter when needed.
|
||||
passesFilter := len(filterAddrMap) == 0
|
||||
encodedAddrs := make([]string, len(addrs))
|
||||
for j, addr := range addrs {
|
||||
encodedAddr := addr.EncodeAddress()
|
||||
encodedAddrs[j] = encodedAddr
|
||||
var encodedAddr *string
|
||||
if addr != nil {
|
||||
encodedAddr = btcjson.String(addr.EncodeAddress())
|
||||
|
||||
// No need to check the map again if the filter already
|
||||
// passes.
|
||||
if passesFilter {
|
||||
continue
|
||||
}
|
||||
if _, exists := filterAddrMap[encodedAddr]; exists {
|
||||
// If the filter doesn't already pass, make it pass if
|
||||
// the address exists in the filter.
|
||||
if _, exists := filterAddrMap[*encodedAddr]; exists {
|
||||
passesFilter = true
|
||||
}
|
||||
}
|
||||
@ -670,11 +666,10 @@ func createVoutList(mtx *wire.MsgTx, chainParams *dagconfig.Params, filterAddrMa
|
||||
var vout btcjson.Vout
|
||||
vout.N = uint32(i)
|
||||
vout.Value = util.Amount(v.Value).ToBTC()
|
||||
vout.ScriptPubKey.Addresses = encodedAddrs
|
||||
vout.ScriptPubKey.Address = encodedAddr
|
||||
vout.ScriptPubKey.Asm = disbuf
|
||||
vout.ScriptPubKey.Hex = hex.EncodeToString(v.ScriptPubKey)
|
||||
vout.ScriptPubKey.Type = scriptClass.String()
|
||||
vout.ScriptPubKey.ReqSigs = int32(reqSigs)
|
||||
|
||||
voutList = append(voutList, vout)
|
||||
}
|
||||
@ -783,11 +778,11 @@ func handleDecodeScript(s *Server, cmd interface{}, closeChan <-chan struct{}) (
|
||||
// Get information about the script.
|
||||
// Ignore the error here since an error means the script couldn't parse
|
||||
// and there is no additinal information about it anyways.
|
||||
scriptClass, addrs, reqSigs, _ := txscript.ExtractScriptPubKeyAddrs(script,
|
||||
scriptClass, addr, _ := txscript.ExtractScriptPubKeyAddress(script,
|
||||
s.cfg.DAGParams)
|
||||
addresses := make([]string, len(addrs))
|
||||
for i, addr := range addrs {
|
||||
addresses[i] = addr.EncodeAddress()
|
||||
var address *string
|
||||
if addr != nil {
|
||||
address = btcjson.String(addr.EncodeAddress())
|
||||
}
|
||||
|
||||
// Convert the script itself to a pay-to-script-hash address.
|
||||
@ -799,10 +794,9 @@ func handleDecodeScript(s *Server, cmd interface{}, closeChan <-chan struct{}) (
|
||||
|
||||
// Generate and return the reply.
|
||||
reply := btcjson.DecodeScriptResult{
|
||||
Asm: disbuf,
|
||||
ReqSigs: int32(reqSigs),
|
||||
Type: scriptClass.String(),
|
||||
Addresses: addresses,
|
||||
Asm: disbuf,
|
||||
Type: scriptClass.String(),
|
||||
Address: address,
|
||||
}
|
||||
if scriptClass != txscript.ScriptHashTy {
|
||||
reply.P2sh = p2sh.EncodeAddress()
|
||||
@ -2823,11 +2817,11 @@ func handleGetTxOut(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
|
||||
// Get further info about the script.
|
||||
// Ignore the error here since an error means the script couldn't parse
|
||||
// and there is no additional information about it anyways.
|
||||
scriptClass, addrs, reqSigs, _ := txscript.ExtractScriptPubKeyAddrs(scriptPubKey,
|
||||
scriptClass, addr, _ := txscript.ExtractScriptPubKeyAddress(scriptPubKey,
|
||||
s.cfg.DAGParams)
|
||||
addresses := make([]string, len(addrs))
|
||||
for i, addr := range addrs {
|
||||
addresses[i] = addr.EncodeAddress()
|
||||
var address *string
|
||||
if addr != nil {
|
||||
address = btcjson.String(addr.EncodeAddress())
|
||||
}
|
||||
|
||||
txOutReply := &btcjson.GetTxOutResult{
|
||||
@ -2836,11 +2830,10 @@ func handleGetTxOut(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
|
||||
IsInMempool: isInMempool,
|
||||
Value: util.Amount(value).ToBTC(),
|
||||
ScriptPubKey: btcjson.ScriptPubKeyResult{
|
||||
Asm: disbuf,
|
||||
Hex: hex.EncodeToString(scriptPubKey),
|
||||
ReqSigs: int32(reqSigs),
|
||||
Type: scriptClass.String(),
|
||||
Addresses: addresses,
|
||||
Asm: disbuf,
|
||||
Hex: hex.EncodeToString(scriptPubKey),
|
||||
Type: scriptClass.String(),
|
||||
Address: address,
|
||||
},
|
||||
Coinbase: isCoinbase,
|
||||
}
|
||||
@ -3061,22 +3054,18 @@ func createVinListPrevOut(s *Server, mtx *wire.MsgTx, chainParams *dagconfig.Par
|
||||
// Ignore the error here since an error means the script
|
||||
// couldn't parse and there is no additional information about
|
||||
// it anyways.
|
||||
_, addrs, _, _ := txscript.ExtractScriptPubKeyAddrs(
|
||||
_, addr, _ := txscript.ExtractScriptPubKeyAddress(
|
||||
originTxOut.ScriptPubKey, chainParams)
|
||||
|
||||
// Encode the addresses while checking if the address passes the
|
||||
// filter when needed.
|
||||
encodedAddrs := make([]string, len(addrs))
|
||||
for j, addr := range addrs {
|
||||
encodedAddr := addr.EncodeAddress()
|
||||
encodedAddrs[j] = encodedAddr
|
||||
var encodedAddr *string
|
||||
if addr != nil {
|
||||
// Encode the address while checking if the address passes the
|
||||
// filter when needed.
|
||||
encodedAddr = btcjson.String(addr.EncodeAddress())
|
||||
|
||||
// No need to check the map again if the filter already
|
||||
// passes.
|
||||
if passesFilter {
|
||||
continue
|
||||
}
|
||||
if _, exists := filterAddrMap[encodedAddr]; exists {
|
||||
// If the filter doesn't already pass, make it pass if
|
||||
// the address exists in the filter.
|
||||
if _, exists := filterAddrMap[*encodedAddr]; exists {
|
||||
passesFilter = true
|
||||
}
|
||||
}
|
||||
@ -3096,8 +3085,8 @@ func createVinListPrevOut(s *Server, mtx *wire.MsgTx, chainParams *dagconfig.Par
|
||||
if vinExtra {
|
||||
vinListEntry := &vinList[len(vinList)-1]
|
||||
vinListEntry.PrevOut = &btcjson.PrevOut{
|
||||
Addresses: encodedAddrs,
|
||||
Value: util.Amount(originTxOut.Value).ToBTC(),
|
||||
Address: encodedAddr,
|
||||
Value: util.Amount(originTxOut.Value).ToBTC(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,8 +60,8 @@ var helpDescsEnUS = map[string]string{
|
||||
"scriptSig-hex": "Hex-encoded bytes of the script",
|
||||
|
||||
// PrevOut help.
|
||||
"prevOut-addresses": "previous output addresses",
|
||||
"prevOut-value": "previous output value",
|
||||
"prevOut-address": "previous output address (if any)",
|
||||
"prevOut-value": "previous output value",
|
||||
|
||||
// VinPrevOut help.
|
||||
"vinPrevOut-coinbase": "The hex-encoded bytes of the signature script (coinbase txns only)",
|
||||
@ -79,11 +79,10 @@ var helpDescsEnUS = map[string]string{
|
||||
"vin-sequence": "The script sequence number",
|
||||
|
||||
// ScriptPubKeyResult help.
|
||||
"scriptPubKeyResult-asm": "Disassembly of the script",
|
||||
"scriptPubKeyResult-hex": "Hex-encoded bytes of the script",
|
||||
"scriptPubKeyResult-type": "The type of the script (e.g. 'pubkeyhash')",
|
||||
"scriptPubKeyResult-reqSigs": "The number of required signatures",
|
||||
"scriptPubKeyResult-addresses": "The bitcoin addresses associated with this script",
|
||||
"scriptPubKeyResult-asm": "Disassembly of the script",
|
||||
"scriptPubKeyResult-hex": "Hex-encoded bytes of the script",
|
||||
"scriptPubKeyResult-type": "The type of the script (e.g. 'pubkeyhash')",
|
||||
"scriptPubKeyResult-address": "The bitcoin address (if any) associated with this script",
|
||||
|
||||
// Vout help.
|
||||
"vout-value": "The amount in BTC",
|
||||
@ -110,11 +109,11 @@ var helpDescsEnUS = map[string]string{
|
||||
"decodeRawTransaction-hexTx": "Serialized, hex-encoded transaction",
|
||||
|
||||
// DecodeScriptResult help.
|
||||
"decodeScriptResult-asm": "Disassembly of the script",
|
||||
"decodeScriptResult-type": "The type of the script (e.g. 'pubkeyhash')",
|
||||
"decodeScriptResult-reqSigs": "The number of required signatures",
|
||||
"decodeScriptResult-addresses": "The bitcoin addresses associated with this script",
|
||||
"decodeScriptResult-p2sh": "The script hash for use in pay-to-script-hash transactions (only present if the provided redeem script is not already a pay-to-script-hash script)",
|
||||
"decodeScriptResult-asm": "Disassembly of the script",
|
||||
"decodeScriptResult-type": "The type of the script (e.g. 'pubkeyhash')",
|
||||
"decodeScriptResult-reqSigs": "The number of required signatures",
|
||||
"decodeScriptResult-address": "The bitcoin address (if any) associated with this script",
|
||||
"decodeScriptResult-p2sh": "The script hash for use in pay-to-script-hash transactions (only present if the provided redeem script is not already a pay-to-script-hash script)",
|
||||
|
||||
// DecodeScriptCmd help.
|
||||
"decodeScript--synopsis": "Returns a JSON object with information about the provided hex-encoded script.",
|
||||
|
@ -622,9 +622,9 @@ func (m *wsNotificationManager) subscribedClients(tx *util.Tx,
|
||||
}
|
||||
|
||||
for i, output := range msgTx.TxOut {
|
||||
_, addrs, _, err := txscript.ExtractScriptPubKeyAddrs(
|
||||
_, addr, err := txscript.ExtractScriptPubKeyAddress(
|
||||
output.ScriptPubKey, m.server.cfg.DAGParams)
|
||||
if err != nil {
|
||||
if err != nil || addr == nil {
|
||||
// Clients are not able to subscribe to
|
||||
// nonstandard or non-address outputs.
|
||||
continue
|
||||
@ -637,15 +637,13 @@ func (m *wsNotificationManager) subscribedClients(tx *util.Tx,
|
||||
continue
|
||||
}
|
||||
filter.mu.Lock()
|
||||
for _, a := range addrs {
|
||||
if filter.existsAddress(a) {
|
||||
subscribed[quitChan] = struct{}{}
|
||||
op := wire.Outpoint{
|
||||
TxID: *tx.ID(),
|
||||
Index: uint32(i),
|
||||
}
|
||||
filter.addUnspentOutpoint(&op)
|
||||
if filter.existsAddress(addr) {
|
||||
subscribed[quitChan] = struct{}{}
|
||||
op := wire.Outpoint{
|
||||
TxID: *tx.ID(),
|
||||
Index: uint32(i),
|
||||
}
|
||||
filter.addUnspentOutpoint(&op)
|
||||
}
|
||||
filter.mu.Unlock()
|
||||
}
|
||||
@ -1604,13 +1602,13 @@ func rescanBlockFilter(filter *wsClientFilter, block *util.Block, params *dagcon
|
||||
|
||||
// Scan outputs.
|
||||
for i, output := range msgTx.TxOut {
|
||||
_, addrs, _, err := txscript.ExtractScriptPubKeyAddrs(
|
||||
_, addr, err := txscript.ExtractScriptPubKeyAddress(
|
||||
output.ScriptPubKey, params)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, a := range addrs {
|
||||
if !filter.existsAddress(a) {
|
||||
if addr != nil {
|
||||
if !filter.existsAddress(addr) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ func ExamplePayToAddrScript() {
|
||||
|
||||
// This example demonstrates extracting information from a standard public key
|
||||
// script.
|
||||
func ExampleExtractScriptPubKeyAddrs() {
|
||||
func ExampleExtractScriptPubKeyAddress() {
|
||||
// Start with a standard pay-to-pubkey-hash script.
|
||||
scriptHex := "76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac"
|
||||
script, err := hex.DecodeString(scriptHex)
|
||||
@ -60,18 +60,16 @@ func ExampleExtractScriptPubKeyAddrs() {
|
||||
}
|
||||
|
||||
// Extract and print details from the script.
|
||||
scriptClass, addresses, reqSigs, err := txscript.ExtractScriptPubKeyAddrs(
|
||||
scriptClass, address, err := txscript.ExtractScriptPubKeyAddress(
|
||||
script, &dagconfig.MainNetParams)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Script Class:", scriptClass)
|
||||
fmt.Println("Addresses:", addresses)
|
||||
fmt.Println("Required Signatures:", reqSigs)
|
||||
fmt.Println("Address:", address)
|
||||
|
||||
// Output:
|
||||
// Script Class: pubkeyhash
|
||||
// Addresses: [dagcoin:qqfgqp8l9l90zwetj84k2jcac2m8falvvy9uastr55]
|
||||
// Required Signatures: 1
|
||||
// Address: dagcoin:qqfgqp8l9l90zwetj84k2jcac2m8falvvy9uastr55
|
||||
}
|
||||
|
@ -58,39 +58,38 @@ func SignatureScript(tx *wire.MsgTx, idx int, script []byte, hashType SigHashTyp
|
||||
|
||||
func sign(chainParams *dagconfig.Params, tx *wire.MsgTx, idx int,
|
||||
script []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB) ([]byte,
|
||||
ScriptClass, []util.Address, int, error) {
|
||||
ScriptClass, util.Address, error) {
|
||||
|
||||
class, addresses, nrequired, err := ExtractScriptPubKeyAddrs(script,
|
||||
class, address, err := ExtractScriptPubKeyAddress(script,
|
||||
chainParams)
|
||||
if err != nil {
|
||||
return nil, NonStandardTy, nil, 0, err
|
||||
return nil, NonStandardTy, nil, err
|
||||
}
|
||||
|
||||
switch class {
|
||||
case PubKeyHashTy:
|
||||
// look up key for address
|
||||
key, compressed, err := kdb.GetKey(addresses[0])
|
||||
key, compressed, err := kdb.GetKey(address)
|
||||
if err != nil {
|
||||
return nil, class, nil, 0, err
|
||||
return nil, class, nil, err
|
||||
}
|
||||
|
||||
signedScript, err := SignatureScript(tx, idx, script, hashType,
|
||||
key, compressed)
|
||||
if err != nil {
|
||||
return nil, class, nil, 0, err
|
||||
return nil, class, nil, err
|
||||
}
|
||||
|
||||
return signedScript, class, addresses, nrequired, nil
|
||||
return signedScript, class, address, nil
|
||||
case ScriptHashTy:
|
||||
script, err := sdb.GetScript(addresses[0])
|
||||
script, err := sdb.GetScript(address)
|
||||
if err != nil {
|
||||
return nil, class, nil, 0, err
|
||||
return nil, class, nil, err
|
||||
}
|
||||
|
||||
return script, class, addresses, nrequired, nil
|
||||
return script, class, address, nil
|
||||
default:
|
||||
return nil, class, nil, 0,
|
||||
errors.New("can't sign unknown transactions")
|
||||
return nil, class, nil, errors.New("can't sign unknown transactions")
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,8 +100,7 @@ func sign(chainParams *dagconfig.Params, tx *wire.MsgTx, idx int,
|
||||
// function with addresses, class and nrequired that do not match scriptPubKey is
|
||||
// an error and results in undefined behaviour.
|
||||
func mergeScripts(chainParams *dagconfig.Params, tx *wire.MsgTx, idx int,
|
||||
scriptPubKey []byte, class ScriptClass, addresses []util.Address,
|
||||
nRequired int, sigScript, prevScript []byte) ([]byte, error) {
|
||||
class ScriptClass, sigScript, prevScript []byte) ([]byte, error) {
|
||||
|
||||
// TODO: the scripthash and multisig paths here are overly
|
||||
// inefficient in that they will recompute already known data.
|
||||
@ -126,16 +124,15 @@ func mergeScripts(chainParams *dagconfig.Params, tx *wire.MsgTx, idx int,
|
||||
script := sigPops[len(sigPops)-1].data
|
||||
|
||||
// We already know this information somewhere up the stack.
|
||||
class, addresses, nrequired, _ :=
|
||||
ExtractScriptPubKeyAddrs(script, chainParams)
|
||||
class, _, _ :=
|
||||
ExtractScriptPubKeyAddress(script, chainParams)
|
||||
|
||||
// regenerate scripts.
|
||||
sigScript, _ := unparseScript(sigPops)
|
||||
prevScript, _ := unparseScript(prevPops)
|
||||
|
||||
// Merge
|
||||
mergedScript, err := mergeScripts(chainParams, tx, idx, script,
|
||||
class, addresses, nrequired, sigScript, prevScript)
|
||||
mergedScript, err := mergeScripts(chainParams, tx, idx, class, sigScript, prevScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -200,7 +197,7 @@ func SignTxOutput(chainParams *dagconfig.Params, tx *wire.MsgTx, idx int,
|
||||
scriptPubKey []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB,
|
||||
previousScript []byte) ([]byte, error) {
|
||||
|
||||
sigScript, class, addresses, nrequired, err := sign(chainParams, tx,
|
||||
sigScript, class, _, err := sign(chainParams, tx,
|
||||
idx, scriptPubKey, hashType, kdb, sdb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -208,7 +205,7 @@ func SignTxOutput(chainParams *dagconfig.Params, tx *wire.MsgTx, idx int,
|
||||
|
||||
if class == ScriptHashTy {
|
||||
// TODO keep the sub addressed and pass down to merge.
|
||||
realSigScript, _, _, _, err := sign(chainParams, tx, idx,
|
||||
realSigScript, _, _, err := sign(chainParams, tx, idx,
|
||||
sigScript, hashType, kdb, sdb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -224,6 +221,5 @@ func SignTxOutput(chainParams *dagconfig.Params, tx *wire.MsgTx, idx int,
|
||||
}
|
||||
|
||||
// Merge scripts. with any previous data, if any.
|
||||
return mergeScripts(chainParams, tx, idx, scriptPubKey, class,
|
||||
addresses, nrequired, sigScript, previousScript)
|
||||
return mergeScripts(chainParams, tx, idx, class, sigScript, previousScript)
|
||||
}
|
||||
|
@ -271,19 +271,14 @@ func PushedData(script []byte) ([][]byte, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// ExtractScriptPubKeyAddrs returns the type of script, addresses and required
|
||||
// signatures associated with the passed ScriptPubKey. Note that it only works for
|
||||
// 'standard' transaction script types. Any data such as public keys which are
|
||||
// invalid are omitted from the results.
|
||||
func ExtractScriptPubKeyAddrs(scriptPubKey []byte, chainParams *dagconfig.Params) (ScriptClass, []util.Address, int, error) {
|
||||
var addrs []util.Address
|
||||
var requiredSigs int
|
||||
|
||||
// No valid addresses or required signatures if the script doesn't
|
||||
// parse.
|
||||
// ExtractScriptPubKeyAddress returns the type of script and its addresses.
|
||||
// Note that it only works for 'standard' transaction script types. Any data such
|
||||
// as public keys which are invalid will return a nil address.
|
||||
func ExtractScriptPubKeyAddress(scriptPubKey []byte, chainParams *dagconfig.Params) (ScriptClass, util.Address, error) {
|
||||
// No valid address if the script doesn't parse.
|
||||
pops, err := parseScript(scriptPubKey)
|
||||
if err != nil {
|
||||
return NonStandardTy, nil, 0, err
|
||||
return NonStandardTy, nil, err
|
||||
}
|
||||
|
||||
scriptClass := typeOfScript(pops)
|
||||
@ -292,32 +287,33 @@ func ExtractScriptPubKeyAddrs(scriptPubKey []byte, chainParams *dagconfig.Params
|
||||
// A pay-to-pubkey-hash script is of the form:
|
||||
// OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG
|
||||
// Therefore the pubkey hash is the 3rd item on the stack.
|
||||
// Skip the pubkey hash if it's invalid for some reason.
|
||||
requiredSigs = 1
|
||||
// If the pubkey hash is invalid for some reason, return a nil address.
|
||||
addr, err := util.NewAddressPubKeyHash(pops[2].data,
|
||||
chainParams.Prefix)
|
||||
if err == nil {
|
||||
addrs = append(addrs, addr)
|
||||
if err != nil {
|
||||
return scriptClass, nil, nil
|
||||
}
|
||||
return scriptClass, addr, nil
|
||||
|
||||
case ScriptHashTy:
|
||||
// A pay-to-script-hash script is of the form:
|
||||
// OP_HASH160 <scripthash> OP_EQUAL
|
||||
// Therefore the script hash is the 2nd item on the stack.
|
||||
// Skip the script hash if it's invalid for some reason.
|
||||
requiredSigs = 1
|
||||
// If the script hash ss invalid for some reason, return a nil address.
|
||||
addr, err := util.NewAddressScriptHashFromHash(pops[1].data,
|
||||
chainParams.Prefix)
|
||||
if err == nil {
|
||||
addrs = append(addrs, addr)
|
||||
if err != nil {
|
||||
return scriptClass, nil, nil
|
||||
}
|
||||
return scriptClass, addr, nil
|
||||
|
||||
case NonStandardTy:
|
||||
// Don't attempt to extract addresses or required signatures for
|
||||
// nonstandard transactions.
|
||||
return NonStandardTy, nil, nil
|
||||
}
|
||||
|
||||
return scriptClass, addrs, requiredSigs, nil
|
||||
return NonStandardTy, nil, fmt.Errorf("Cannot handle script class %s", scriptClass)
|
||||
}
|
||||
|
||||
// AtomicSwapDataPushes houses the data pushes found in atomic swap contracts.
|
||||
|
@ -60,33 +60,26 @@ func TestExtractScriptPubKeyAddrs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
script []byte
|
||||
addrs []util.Address
|
||||
reqSigs int
|
||||
class ScriptClass
|
||||
name string
|
||||
script []byte
|
||||
addr util.Address
|
||||
class ScriptClass
|
||||
}{
|
||||
{
|
||||
name: "standard p2pkh",
|
||||
script: hexToBytes("76a914ad06dd6ddee55cbca9a9e3713bd" +
|
||||
"7587509a3056488ac"),
|
||||
addrs: []util.Address{
|
||||
newAddressPubKeyHash(hexToBytes("ad06dd6ddee5" +
|
||||
"5cbca9a9e3713bd7587509a30564")),
|
||||
},
|
||||
reqSigs: 1,
|
||||
class: PubKeyHashTy,
|
||||
addr: newAddressPubKeyHash(hexToBytes("ad06dd6ddee5" +
|
||||
"5cbca9a9e3713bd7587509a30564")),
|
||||
class: PubKeyHashTy,
|
||||
},
|
||||
{
|
||||
name: "standard p2sh",
|
||||
script: hexToBytes("a91463bcc565f9e68ee0189dd5cc67f1b" +
|
||||
"0e5f02f45cb87"),
|
||||
addrs: []util.Address{
|
||||
newAddressScriptHash(hexToBytes("63bcc565f9e6" +
|
||||
"8ee0189dd5cc67f1b0e5f02f45cb")),
|
||||
},
|
||||
reqSigs: 1,
|
||||
class: ScriptHashTy,
|
||||
addr: newAddressScriptHash(hexToBytes("63bcc565f9e6" +
|
||||
"8ee0189dd5cc67f1b0e5f02f45cb")),
|
||||
class: ScriptHashTy,
|
||||
},
|
||||
|
||||
// The below are nonstandard script due to things such as
|
||||
@ -99,9 +92,8 @@ func TestExtractScriptPubKeyAddrs(t *testing.T) {
|
||||
"c1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddf" +
|
||||
"b84ccf9744464f82e160bfa9b8b64f9d4c03f999b864" +
|
||||
"3f656b412a3"),
|
||||
addrs: nil,
|
||||
reqSigs: 0,
|
||||
class: NonStandardTy,
|
||||
addr: nil,
|
||||
class: NonStandardTy,
|
||||
},
|
||||
{
|
||||
name: "valid signature from a sigscript - no addresses",
|
||||
@ -109,9 +101,8 @@ func TestExtractScriptPubKeyAddrs(t *testing.T) {
|
||||
"3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41022" +
|
||||
"0181522ec8eca07de4860a4acdd12909d831cc56cbba" +
|
||||
"c4622082221a8768d1d0901"),
|
||||
addrs: nil,
|
||||
reqSigs: 0,
|
||||
class: NonStandardTy,
|
||||
addr: nil,
|
||||
class: NonStandardTy,
|
||||
},
|
||||
// Note the technically the pubkey is the second item on the
|
||||
// stack, but since the address extraction intentionally only
|
||||
@ -126,49 +117,39 @@ func TestExtractScriptPubKeyAddrs(t *testing.T) {
|
||||
"523b6f9cb9f5bed06de1ba37e96a1bbd13745fcf9d11" +
|
||||
"c25b1dff9a519675d198804ba9962d3eca2d5937d58e" +
|
||||
"5a75a71042d40388a4d307f887d"),
|
||||
addrs: nil,
|
||||
reqSigs: 0,
|
||||
class: NonStandardTy,
|
||||
addr: nil,
|
||||
class: NonStandardTy,
|
||||
},
|
||||
{
|
||||
name: "empty script",
|
||||
script: []byte{},
|
||||
addrs: nil,
|
||||
reqSigs: 0,
|
||||
class: NonStandardTy,
|
||||
name: "empty script",
|
||||
script: []byte{},
|
||||
addr: nil,
|
||||
class: NonStandardTy,
|
||||
},
|
||||
{
|
||||
name: "script that does not parse",
|
||||
script: []byte{OpData45},
|
||||
addrs: nil,
|
||||
reqSigs: 0,
|
||||
class: NonStandardTy,
|
||||
name: "script that does not parse",
|
||||
script: []byte{OpData45},
|
||||
addr: nil,
|
||||
class: NonStandardTy,
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests.", len(tests))
|
||||
for i, test := range tests {
|
||||
class, addrs, reqSigs, err := ExtractScriptPubKeyAddrs(
|
||||
class, addr, err := ExtractScriptPubKeyAddress(
|
||||
test.script, &dagconfig.MainNetParams)
|
||||
if err != nil {
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(addrs, test.addrs) {
|
||||
t.Errorf("ExtractScriptPubKeyAddrs #%d (%s) unexpected "+
|
||||
"addresses\ngot %v\nwant %v", i, test.name,
|
||||
addrs, test.addrs)
|
||||
continue
|
||||
}
|
||||
|
||||
if reqSigs != test.reqSigs {
|
||||
t.Errorf("ExtractScriptPubKeyAddrs #%d (%s) unexpected "+
|
||||
"number of required signatures - got %d, "+
|
||||
"want %d", i, test.name, reqSigs, test.reqSigs)
|
||||
if !reflect.DeepEqual(addr, test.addr) {
|
||||
t.Errorf("ExtractScriptPubKeyAddress #%d (%s) unexpected "+
|
||||
"address\ngot %v\nwant %v", i, test.name,
|
||||
addr, test.addr)
|
||||
continue
|
||||
}
|
||||
|
||||
if class != test.class {
|
||||
t.Errorf("ExtractScriptPubKeyAddrs #%d (%s) unexpected "+
|
||||
t.Errorf("ExtractScriptPubKeyAddress #%d (%s) unexpected "+
|
||||
"script type - got %s, want %s", i, test.name,
|
||||
class, test.class)
|
||||
continue
|
||||
|
Loading…
x
Reference in New Issue
Block a user