Skip to content

Commit

Permalink
rpc: address instead of deprecated addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
lindlof committed Apr 24, 2023
1 parent 7975168 commit faae231
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 60 deletions.
18 changes: 8 additions & 10 deletions btcjson/chainsvrresults.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,10 @@ type CreateMultiSigResult struct {

// DecodeScriptResult models the data returned from the decodescript command.
type DecodeScriptResult struct {
Asm string `json:"asm"`
ReqSigs int32 `json:"reqSigs,omitempty"`
Type string `json:"type"`
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"`
}

// GetAddedNodeInfoResultAddr models the data of the addresses portion of the
Expand Down Expand Up @@ -427,11 +426,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"`
ReqSigs int32 `json:"reqSigs,omitempty"`
Type string `json:"type"`
Addresses []string `json:"addresses,omitempty"`
Asm string `json:"asm"`
Hex string `json:"hex,omitempty"`
Type string `json:"type"`
Address string `json:"address,omitempty"`
}

// GetTxOutResult models the data from the gettxout command.
Expand Down
66 changes: 26 additions & 40 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -704,39 +704,30 @@ func createVoutList(mtx *wire.MsgTx, chainParams *chaincfg.Params, filterAddrMap
// 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.ExtractPkScriptAddrs(
scriptClass, addr, _ := txscript.ExtractPkScriptAddr(
v.PkScript, 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 = addr.EncodeAddress()

// No need to check the map again if the filter already
// passes.
if passesFilter {
continue
}
if _, exists := filterAddrMap[encodedAddr]; exists {
passesFilter = true
// Checking if the address passes the filter.
if len(filterAddrMap) > 0 {
if _, exists := filterAddrMap[encodedAddr]; !exists {
continue
}
}
}

if !passesFilter {
continue
}

var vout btcjson.Vout
vout.N = uint32(i)
vout.Value = btcutil.Amount(v.Value).ToBTC()
vout.ScriptPubKey.Addresses = encodedAddrs
if len(encodedAddr) > 0 {
vout.ScriptPubKey.Address = encodedAddr
}
vout.ScriptPubKey.Asm = disbuf
vout.ScriptPubKey.Hex = hex.EncodeToString(v.PkScript)
vout.ScriptPubKey.Type = scriptClass.String()
vout.ScriptPubKey.ReqSigs = int32(reqSigs)

voutList = append(voutList, vout)
}
Expand Down Expand Up @@ -833,12 +824,8 @@ func handleDecodeScript(s *rpcServer, 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.ExtractPkScriptAddrs(script,
scriptClass, addr, _ := txscript.ExtractPkScriptAddr(script,
s.cfg.ChainParams)
addresses := make([]string, len(addrs))
for i, addr := range addrs {
addresses[i] = addr.EncodeAddress()
}

// Convert the script itself to a pay-to-script-hash address.
p2sh, err := btcutil.NewAddressScriptHash(script, s.cfg.ChainParams)
Expand All @@ -849,14 +836,15 @@ func handleDecodeScript(s *rpcServer, 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(),
}
if scriptClass != txscript.ScriptHashTy {
reply.P2sh = p2sh.EncodeAddress()
}
if addr != nil {
reply.Address = addr.EncodeAddress()
}
return reply, nil
}

Expand Down Expand Up @@ -2791,26 +2779,24 @@ func handleGetTxOut(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i
// 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.ExtractPkScriptAddrs(pkScript,
scriptClass, addr, _ := txscript.ExtractPkScriptAddr(pkScript,
s.cfg.ChainParams)
addresses := make([]string, len(addrs))
for i, addr := range addrs {
addresses[i] = addr.EncodeAddress()
}

txOutReply := &btcjson.GetTxOutResult{
BestBlock: bestBlockHash,
Confirmations: int64(confirmations),
Value: btcutil.Amount(value).ToBTC(),
ScriptPubKey: btcjson.ScriptPubKeyResult{
Asm: disbuf,
Hex: hex.EncodeToString(pkScript),
ReqSigs: int32(reqSigs),
Type: scriptClass.String(),
Addresses: addresses,
Asm: disbuf,
Hex: hex.EncodeToString(pkScript),
Type: scriptClass.String(),
},
Coinbase: isCoinbase,
}
if addr != nil {
txOutReply.ScriptPubKey.Address = addr.EncodeAddress()
}

return txOutReply, nil
}

Expand Down
18 changes: 8 additions & 10 deletions rpcserverhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,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-reqSigs": "The number of required signatures",
"scriptpubkeyresult-type": "The type of the script (e.g. 'pubkeyhash')",
"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 associated with this script",

// Vout help.
"vout-value": "The amount in BTC",
Expand All @@ -105,11 +104,10 @@ var helpDescsEnUS = map[string]string{
"decoderawtransaction-hextx": "Serialized, hex-encoded transaction",

// DecodeScriptResult help.
"decodescriptresult-asm": "Disassembly of the script",
"decodescriptresult-reqSigs": "The number of required signatures",
"decodescriptresult-type": "The type of the script (e.g. 'pubkeyhash')",
"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-address": "The bitcoin address 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.",
Expand Down
20 changes: 20 additions & 0 deletions txscript/standard.go
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,26 @@ func ExtractPkScriptAddrs(pkScript []byte,
return NonStandardTy, nil, 0, nil
}

// ExtractPkScriptAddr returns the type of script and address
// associated with the passed PkScript. Address is returned for scripts that
// are only concerned of a single address. 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 ExtractPkScriptAddr(pkScript []byte,
chainParams *chaincfg.Params) (ScriptClass, btcutil.Address, error) {
class, addresses, nrequired, err := ExtractPkScriptAddrs(pkScript, chainParams)

switch class {
case MultiSigTy:
return class, nil, err
}

if len(addresses) == 1 && nrequired == 1 {
return class, addresses[0], err
}
return class, nil, err
}

// AtomicSwapDataPushes houses the data pushes found in atomic swap contracts.
type AtomicSwapDataPushes struct {
RecipientHash160 [20]byte
Expand Down
69 changes: 69 additions & 0 deletions txscript/standard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,75 @@ func TestExtractPkScriptAddrs(t *testing.T) {
}
}

// TestExtractPkScriptAddr ensures that ExtractPkScriptAddr returns
// the type and address received from ExtractPkScriptAddrs as intended.
func TestExtractPkScriptAddr(t *testing.T) {
t.Parallel()

tests := []struct {
name string
script []byte
addr btcutil.Address
class ScriptClass
}{
// single address returned
{
name: "standard p2pk with compressed pubkey (0x02)",
script: hexToBytes("2102192d74d0cb94344c9569c2e779015" +
"73d8d7903c3ebec3a957724895dca52c6b4ac"),
addr: newAddressPubKey(hexToBytes("02192d74d0cb9434" +
"4c9569c2e77901573d8d7903c3ebec3a9577" +
"24895dca52c6b4")),
class: PubKeyTy,
},
// multisig address not returned
{
name: "standard 1 of 2 multisig",
script: hexToBytes("514104cc71eb30d653c0c3163990c47b9" +
"76f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a47" +
"3e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d1" +
"1fcdd0d348ac4410461cbdcc5409fb4b4d42b51d3338" +
"1354d80e550078cb532a34bfa2fcfdeb7d76519aecc6" +
"2770f5b0e4ef8551946d8a540911abe3e7854a26f39f" +
"58b25c15342af52ae"),
addr: nil,
class: MultiSigTy,
},
// address not returned because of nonstandard script
{
name: "p2pk with uncompressed pk missing OP_CHECKSIG",
script: hexToBytes("410411db93e1dcdb8a016b49840f8c53b" +
"c1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddf" +
"b84ccf9744464f82e160bfa9b8b64f9d4c03f999b864" +
"3f656b412a3"),
addr: nil,
class: NonStandardTy,
},
}

t.Logf("Running %d tests.", len(tests))
for i, test := range tests {
class, addr, err := ExtractPkScriptAddr(
test.script, &chaincfg.MainNetParams)
if err != nil {
}

if !reflect.DeepEqual(addr, test.addr) {
t.Errorf("ExtractPkScriptAddr #%d (%s) unexpected "+
"address\ngot %v\nwant %v", i, test.name,
addr, test.addr)
continue
}

if class != test.class {
t.Errorf("ExtractPkScriptAddrs #%d (%s) unexpected "+
"script type - got %s, want %s", i, test.name,
class, test.class)
continue
}
}
}

// TestCalcScriptInfo ensures the CalcScriptInfo provides the expected results
// for various valid and invalid script pairs.
func TestCalcScriptInfo(t *testing.T) {
Expand Down

0 comments on commit faae231

Please sign in to comment.