vm: implement ParseMultisigContract()

When creating witness for a multisig contract, it is
needed to extract the order of public keys from it.
This commit is contained in:
Evgenii Stratonikov 2020-03-05 09:41:35 +03:00
parent acea3867b2
commit 8819d4f970

View file

@ -31,49 +31,58 @@ func getNumOfThingsFromInstr(instr opcode.Opcode, param []byte) (int, bool) {
// IsMultiSigContract checks whether the passed script is a multi-signature // IsMultiSigContract checks whether the passed script is a multi-signature
// contract. // contract.
func IsMultiSigContract(script []byte) bool { func IsMultiSigContract(script []byte) bool {
_, ok := ParseMultiSigContract(script)
return ok
}
// ParseMultiSigContract returns list of public keys from the verification
// script of the contract.
func ParseMultiSigContract(script []byte) ([][]byte, bool) {
var nsigs, nkeys int var nsigs, nkeys int
ctx := NewContext(script) ctx := NewContext(script)
instr, param, err := ctx.Next() instr, param, err := ctx.Next()
if err != nil { if err != nil {
return false return nil, false
} }
nsigs, ok := getNumOfThingsFromInstr(instr, param) nsigs, ok := getNumOfThingsFromInstr(instr, param)
if !ok { if !ok {
return false return nil, false
} }
var pubs [][]byte
for { for {
instr, param, err = ctx.Next() instr, param, err = ctx.Next()
if err != nil { if err != nil {
return false return nil, false
} }
if instr != opcode.PUSHBYTES33 { if instr != opcode.PUSHBYTES33 {
break break
} }
pubs = append(pubs, param)
nkeys++ nkeys++
if nkeys > MaxArraySize { if nkeys > MaxArraySize {
return false return nil, false
} }
} }
if nkeys < nsigs { if nkeys < nsigs {
return false return nil, false
} }
nkeys2, ok := getNumOfThingsFromInstr(instr, param) nkeys2, ok := getNumOfThingsFromInstr(instr, param)
if !ok { if !ok {
return false return nil, false
} }
if nkeys2 != nkeys { if nkeys2 != nkeys {
return false return nil, false
} }
instr, _, err = ctx.Next() instr, _, err = ctx.Next()
if err != nil || instr != opcode.CHECKMULTISIG { if err != nil || instr != opcode.CHECKMULTISIG {
return false return nil, false
} }
instr, _, err = ctx.Next() instr, _, err = ctx.Next()
if err != nil || instr != opcode.RET || ctx.ip != len(script) { if err != nil || instr != opcode.RET || ctx.ip != len(script) {
return false return nil, false
} }
return true return pubs, true
} }
// IsSignatureContract checks whether the passed script is a signature check // IsSignatureContract checks whether the passed script is a signature check