4 "github.com/bytom/crypto/ed25519"
5 "github.com/bytom/errors"
6 "github.com/bytom/protocol/vm"
10 ErrBadValue = errors.New("bad value")
11 ErrMultisigFormat = errors.New("bad multisig program format")
14 func IsUnspendable(prog []byte) bool {
15 return len(prog) > 0 && prog[0] == byte(vm.OP_FAIL)
18 func ParseBlockMultiSigProgram(script []byte) ([]ed25519.PublicKey, int, error) {
19 pops, err := vm.ParseProgram(script)
24 return nil, 0, vm.ErrShortProgram
26 if pops[len(pops)-1].Op != vm.OP_CHECKMULTISIG {
27 return nil, 0, errors.Wrap(ErrMultisigFormat, "no OP_CHECKMULTISIG")
29 npubkeys, err := vm.AsInt64(pops[len(pops)-2].Data)
31 return nil, 0, errors.Wrap(ErrMultisigFormat, "parsing npubkeys")
33 if int(npubkeys) != len(pops)-4 {
34 return nil, 0, vm.ErrShortProgram
36 nrequired, err := vm.AsInt64(pops[len(pops)-3].Data)
38 return nil, 0, errors.Wrap(ErrMultisigFormat, "parsing nrequired")
40 err = checkMultiSigParams(nrequired, npubkeys)
45 firstPubkeyIndex := len(pops) - 3 - int(npubkeys)
47 pubkeys := make([]ed25519.PublicKey, 0, npubkeys)
48 for i := firstPubkeyIndex; i < firstPubkeyIndex+int(npubkeys); i++ {
49 if len(pops[i].Data) != ed25519.PublicKeySize {
52 pubkeys = append(pubkeys, ed25519.PublicKey(pops[i].Data))
54 return pubkeys, int(nrequired), nil
57 func P2SPMultiSigProgram(pubkeys []ed25519.PublicKey, nrequired int) ([]byte, error) {
58 err := checkMultiSigParams(int64(nrequired), int64(len(pubkeys)))
62 builder := NewBuilder()
63 // Expected stack: [... NARGS SIG SIG SIG PREDICATE]
64 // Number of sigs must match nrequired.
65 builder.AddOp(vm.OP_DUP).AddOp(vm.OP_TOALTSTACK) // stash a copy of the predicate
66 builder.AddOp(vm.OP_SHA3) // stack is now [... NARGS SIG SIG SIG PREDICATEHASH]
67 for _, p := range pubkeys {
70 builder.AddInt64(int64(nrequired)) // stack is now [... SIG SIG SIG PREDICATEHASH PUB PUB PUB M]
71 builder.AddInt64(int64(len(pubkeys))) // stack is now [... SIG SIG SIG PREDICATEHASH PUB PUB PUB M N]
72 builder.AddOp(vm.OP_CHECKMULTISIG).AddOp(vm.OP_VERIFY) // stack is now [... NARGS]
73 builder.AddOp(vm.OP_FROMALTSTACK) // stack is now [... NARGS PREDICATE]
74 builder.AddInt64(0).AddOp(vm.OP_CHECKPREDICATE)
75 return builder.Build()
78 func ParseP2SPMultiSigProgram(program []byte) ([]ed25519.PublicKey, int, error) {
79 pops, err := vm.ParseProgram(program)
84 return nil, 0, vm.ErrShortProgram
87 // Count all instructions backwards from the end in case there are
88 // extra instructions at the beginning of the program (like a
91 npubkeys, err := vm.AsInt64(pops[len(pops)-6].Data)
95 if int(npubkeys) > len(pops)-10 {
96 return nil, 0, vm.ErrShortProgram
98 nrequired, err := vm.AsInt64(pops[len(pops)-7].Data)
102 err = checkMultiSigParams(nrequired, npubkeys)
107 firstPubkeyIndex := len(pops) - 7 - int(npubkeys)
109 pubkeys := make([]ed25519.PublicKey, 0, npubkeys)
110 for i := firstPubkeyIndex; i < firstPubkeyIndex+int(npubkeys); i++ {
111 if len(pops[i].Data) != ed25519.PublicKeySize {
114 pubkeys = append(pubkeys, ed25519.PublicKey(pops[i].Data))
116 return pubkeys, int(nrequired), nil
119 func checkMultiSigParams(nrequired, npubkeys int64) error {
121 return errors.WithDetail(ErrBadValue, "negative quorum")
124 return errors.WithDetail(ErrBadValue, "negative pubkey count")
126 if nrequired > npubkeys {
127 return errors.WithDetail(ErrBadValue, "quorum too big")
129 if nrequired == 0 && npubkeys > 0 {
130 return errors.WithDetail(ErrBadValue, "quorum empty with non-empty pubkey list")