Skip to content

Commit 9dfc103

Browse files
committed
Add P2SH32
1 parent 7fcf552 commit 9dfc103

8 files changed

Lines changed: 96 additions & 9 deletions

File tree

bchrpc/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1017,7 +1017,7 @@ func (s *GrpcServer) GetAddressUnspentOutputs(ctx context.Context, req *pb.GetAd
10171017
matchAddr := ""
10181018

10191019
switch typedAddr := addrs[0].(type) {
1020-
case *bchutil.AddressPubKeyHash, *bchutil.AddressScriptHash:
1020+
case *bchutil.AddressPubKeyHash, *bchutil.AddressScriptHash, *bchutil.AddressScriptHash32:
10211021
matchAddr = addrs[0].EncodeAddress()
10221022

10231023
case *bchutil.AddressPubKey:

blockchain/compress.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,20 @@ func isScriptHash(script []byte) (bool, []byte) {
201201
return false, nil
202202
}
203203

204+
// isScriptHash32 returns whether or not the passed public key script is a
205+
// standard pay-to-script-hash script along with the script hash it is paying to
206+
// if it is.
207+
func isScriptHash32(script []byte) (bool, []byte) {
208+
if len(script) == 35 && script[0] == txscript.OP_HASH256 &&
209+
script[1] == txscript.OP_DATA_32 &&
210+
script[22] == txscript.OP_EQUAL {
211+
212+
return true, script[2:34]
213+
}
214+
215+
return false, nil
216+
}
217+
204218
// isPubKey returns whether or not the passed public key script is a standard
205219
// pay-to-pubkey script that pays to a valid compressed or uncompressed public
206220
// key along with the serialized pubkey it is paying to if it is.

blockchain/fullblocktests/generate.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,19 @@ func payToScriptHashScript(redeemScript []byte) []byte {
230230
return script
231231
}
232232

233+
// payToScriptHashScript32 returns a standard pay-to-script-hash for the provided
234+
// redeem script.
235+
func payToScriptHashScript32(redeemScript []byte) []byte {
236+
redeemScriptHash := bchutil.Hash256(redeemScript)
237+
script, err := txscript.NewScriptBuilder().
238+
AddOp(txscript.OP_HASH256).AddData(redeemScriptHash).
239+
AddOp(txscript.OP_EQUAL).Script()
240+
if err != nil {
241+
panic(err)
242+
}
243+
return script
244+
}
245+
233246
// pushDataScript returns a script with the provided items individually pushed
234247
// to the stack.
235248
func pushDataScript(items ...[]byte) []byte {

blockchain/indexers/addrindex.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@ const (
3030

3131
// addrKeySize is the number of bytes an address key consumes in the
3232
// index. It consists of 1 byte address type + 20 bytes hash160.
33-
addrKeySize = 1 + 20
33+
//addrKeySize = 1 + 20
34+
35+
// addrKeySize is the number of bytes an address key consumes in the
36+
// index. It consists of 1 byte address type + 32 bytes hash256.
37+
// TODO: Since we updated the size, please note that we need to either:
38+
// a) detect old indexes and force them to be rebuilt
39+
// b) write a migration of the existing index
40+
addrKeySize = 1 + 32
3441

3542
// levelKeySize is the number of bytes a level key in the address index
3643
// consumes. It consists of the address key + 1 byte for the level.
@@ -529,6 +536,11 @@ func addrToKey(addr bchutil.Address) ([addrKeySize]byte, error) {
529536
copy(result[1:], addr.Hash160()[:])
530537
return result, nil
531538

539+
case *bchutil.AddressScriptHash32:
540+
var result [addrKeySize]byte
541+
result[0] = addrKeyTypeScriptHash
542+
copy(result[1:], addr.Hash256()[:])
543+
return result, nil
532544
case *bchutil.AddressPubKey:
533545
var result [addrKeySize]byte
534546
result[0] = addrKeyTypePubKeyHash

rpcserver.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeNotifier <-c
580580
switch addr.(type) {
581581
case *bchutil.AddressPubKeyHash:
582582
case *bchutil.AddressScriptHash:
583+
case *bchutil.AddressScriptHash32:
583584
default:
584585
return nil, &btcjson.RPCError{
585586
Code: btcjson.ErrRPCInvalidAddressOrKey,

txscript/pkscript.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ func (s PkScript) String() string {
139139
// ComputePkScript computes the pkScript of an transaction output by looking at
140140
// the transaction input's signature script.
141141
//
142-
// NOTE: Only P2PKH, and P2SH redeem scripts are supported.
142+
// NOTE: Only P2PKH, P2SH and P2SH32 redeem scripts are supported.
143143
func ComputePkScript(sigScript []byte) (PkScript, error) {
144144
var pkScript PkScript
145145

txscript/script.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ func isScriptHash(pops []parsedOpcode) bool {
6464
pops[2].opcode.value == OP_EQUAL
6565
}
6666

67+
// isScriptHash32 returns true if the script passed is a pay-to-script-hash-32
68+
// transaction, false otherwise.
69+
func isScriptHash32(pops []parsedOpcode) bool {
70+
return len(pops) == 3 &&
71+
pops[0].opcode.value == OP_HASH256 &&
72+
pops[1].opcode.value == OP_DATA_32 &&
73+
pops[2].opcode.value == OP_EQUAL
74+
}
75+
6776
// IsPayToScriptHash returns true if the script is in the standard
6877
// pay-to-script-hash (P2SH) format, false otherwise.
6978
func IsPayToScriptHash(script []byte) bool {
@@ -74,6 +83,16 @@ func IsPayToScriptHash(script []byte) bool {
7483
return isScriptHash(pops)
7584
}
7685

86+
// IsPayToScriptHash32 returns true if the script is in the standard
87+
// pay-to-script-hash-32 (P2SH) format, false otherwise.
88+
func IsPayToScriptHash32(script []byte) bool {
89+
pops, err := parseScript(script)
90+
if err != nil {
91+
return false
92+
}
93+
return isScriptHash32(pops)
94+
}
95+
7796
// isPushOnly returns true if the script only pushes data, false otherwise.
7897
func isPushOnly(pops []parsedOpcode) bool {
7998
// NOTE: This function does NOT verify opcodes directly since it is

txscript/standard.go

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,13 @@ type ScriptClass byte
5555

5656
// Classes of script payment known about in the blockchain.
5757
const (
58-
NonStandardTy ScriptClass = iota // None of the recognized forms.
59-
PubKeyTy // Pay pubkey.
60-
PubKeyHashTy // Pay pubkey hash.
61-
ScriptHashTy // Pay to script hash.
62-
MultiSigTy // Multi signature.
63-
NullDataTy // Empty data-only (provably prunable).
58+
NonStandardTy ScriptClass = iota // None of the recognized forms.
59+
PubKeyTy // Pay pubkey.
60+
PubKeyHashTy // Pay pubkey hash.
61+
ScriptHashTy // Pay to script hash.
62+
ScriptHash32Ty // Pay to script hash 32
63+
MultiSigTy // Multi signature.
64+
NullDataTy // Empty data-only (provably prunable).
6465
)
6566

6667
// scriptClassToName houses the human-readable strings which describe each
@@ -186,6 +187,8 @@ func typeOfScript(pops []parsedOpcode) ScriptClass {
186187
return PubKeyHashTy
187188
} else if isScriptHash(pops) {
188189
return ScriptHashTy
190+
} else if isScriptHash32(pops) {
191+
return ScriptHash32Ty
189192
} else if isMultiSig(pops) {
190193
return MultiSigTy
191194
} else if isNullData(pops) {
@@ -355,6 +358,13 @@ func payToScriptHashScript(scriptHash []byte) ([]byte, error) {
355358
AddOp(OP_EQUAL).Script()
356359
}
357360

361+
// payToScriptHashScript creates a new script to pay a transaction output to a
362+
// script hash. It is expected that the input is a valid hash.
363+
func payToScriptHashScript32(scriptHash []byte) ([]byte, error) {
364+
return NewScriptBuilder().AddOp(OP_HASH256).AddData(scriptHash).
365+
AddOp(OP_EQUAL).Script()
366+
}
367+
358368
// payToPubkeyScript creates a new script to pay a transaction output to a
359369
// public key. It is expected that the input is a valid pubkey.
360370
func payToPubKeyScript(serializedPubKey []byte) ([]byte, error) {
@@ -392,6 +402,12 @@ func PayToAddrScript(addr bchutil.Address) ([]byte, error) {
392402
nilAddrErrStr)
393403
}
394404
return payToScriptHashScript(addr.ScriptAddress())
405+
case *bchutil.AddressScriptHash32:
406+
if addr == nil {
407+
return nil, scriptError(ErrUnsupportedAddress,
408+
nilAddrErrStr)
409+
}
410+
return payToScriptHashScript32(addr.ScriptAddress())
395411
case *bchutil.AddressPubKey:
396412
if addr == nil {
397413
return nil, scriptError(ErrUnsupportedAddress,
@@ -512,6 +528,18 @@ func ExtractPkScriptAddrs(pkScript []byte, chainParams *chaincfg.Params) (Script
512528
addrs = append(addrs, addr)
513529
}
514530

531+
case ScriptHash32Ty:
532+
// A pay-to-script-hash32 script is of the form:
533+
// OP_HASH256 <scripthash> OP_EQUAL
534+
// Therefore the script hash is the 2nd item on the stack.
535+
// Skip the script hash if it's invalid for some reason.
536+
requiredSigs = 1
537+
addr, err := bchutil.NewAddressScriptHash32FromHash(pops[1].data,
538+
chainParams)
539+
if err == nil {
540+
addrs = append(addrs, addr)
541+
}
542+
515543
case MultiSigTy:
516544
// A multi-signature script is of the form:
517545
// <numsigs> <pubkey> <pubkey> <pubkey>... <numpubkeys> OP_CHECKMULTISIG

0 commit comments

Comments
 (0)