4 "github.com/vapor/crypto/ed25519"
5 "github.com/vapor/errors"
6 "github.com/vapor/protocol/vm"
11 ErrBadValue = errors.New("bad value")
12 ErrMultisigFormat = errors.New("bad multisig program format")
15 // IsUnspendable checks if a contorl program is absolute failed
16 func IsUnspendable(prog []byte) bool {
17 return len(prog) > 0 && prog[0] == byte(vm.OP_FAIL)
20 func (b *Builder) addP2SPMultiSig(pubkeys []ed25519.PublicKey, nrequired int) error {
21 if err := checkMultiSigParams(int64(nrequired), int64(len(pubkeys))); err != nil {
25 b.AddOp(vm.OP_TXSIGHASH) // stack is now [... NARGS SIG SIG SIG PREDICATEHASH]
26 for _, p := range pubkeys {
29 b.AddInt64(int64(nrequired)) // stack is now [... SIG SIG SIG PREDICATEHASH PUB PUB PUB M]
30 b.AddInt64(int64(len(pubkeys))) // stack is now [... SIG SIG SIG PREDICATEHASH PUB PUB PUB M N]
31 b.AddOp(vm.OP_CHECKMULTISIG) // stack is now [... NARGS]
35 // DefaultCoinbaseProgram generates the script for contorl coinbase output
36 func DefaultCoinbaseProgram() ([]byte, error) {
37 builder := NewBuilder()
38 builder.AddOp(vm.OP_TRUE)
39 return builder.Build()
42 // P2WPKHProgram return the segwit pay to public key hash
43 func P2WPKHProgram(hash []byte) ([]byte, error) {
44 builder := NewBuilder()
47 return builder.Build()
50 // P2WSHProgram return the segwit pay to script hash
51 func P2WSHProgram(hash []byte) ([]byte, error) {
52 builder := NewBuilder()
55 return builder.Build()
58 // RetireProgram generates the script for retire output
59 func RetireProgram(comment []byte) ([]byte, error) {
60 builder := NewBuilder()
61 builder.AddOp(vm.OP_FAIL)
62 if len(comment) != 0 {
63 builder.AddData(comment)
65 return builder.Build()
68 // P2PKHSigProgram generates the script for control with pubkey hash
69 func P2PKHSigProgram(pubkeyHash []byte) ([]byte, error) {
70 builder := NewBuilder()
71 builder.AddOp(vm.OP_DUP)
72 builder.AddOp(vm.OP_HASH160)
73 builder.AddData(pubkeyHash)
74 builder.AddOp(vm.OP_EQUALVERIFY)
75 builder.AddOp(vm.OP_TXSIGHASH)
76 builder.AddOp(vm.OP_SWAP)
77 builder.AddOp(vm.OP_CHECKSIG)
78 return builder.Build()
81 // P2SHProgram generates the script for control with script hash
82 func P2SHProgram(scriptHash []byte) ([]byte, error) {
83 builder := NewBuilder()
84 builder.AddOp(vm.OP_DUP)
85 builder.AddOp(vm.OP_SHA3)
86 builder.AddData(scriptHash)
87 builder.AddOp(vm.OP_EQUALVERIFY)
89 builder.AddOp(vm.OP_SWAP)
91 builder.AddOp(vm.OP_CHECKPREDICATE)
92 return builder.Build()
95 // P2SPMultiSigProgram generates the script for control transaction output
96 func P2SPMultiSigProgram(pubkeys []ed25519.PublicKey, nrequired int) ([]byte, error) {
97 builder := NewBuilder()
98 if err := builder.addP2SPMultiSig(pubkeys, nrequired); err != nil {
101 return builder.Build()
104 // P2SPMultiSigProgramWithHeight generates the script with block height for control transaction output
105 func P2SPMultiSigProgramWithHeight(pubkeys []ed25519.PublicKey, nrequired int, blockHeight int64) ([]byte, error) {
106 builder := NewBuilder()
108 builder.AddInt64(blockHeight)
109 builder.AddOp(vm.OP_BLOCKHEIGHT)
110 builder.AddOp(vm.OP_GREATERTHAN)
111 builder.AddOp(vm.OP_VERIFY)
112 } else if blockHeight < 0 {
113 return nil, errors.WithDetail(ErrBadValue, "negative blockHeight")
115 if err := builder.addP2SPMultiSig(pubkeys, nrequired); err != nil {
118 return builder.Build()
121 func checkMultiSigParams(nrequired, npubkeys int64) error {
123 return errors.WithDetail(ErrBadValue, "negative quorum")
126 return errors.WithDetail(ErrBadValue, "negative pubkey count")
128 if nrequired > npubkeys {
129 return errors.WithDetail(ErrBadValue, "quorum too big")
131 if nrequired == 0 && npubkeys > 0 {
132 return errors.WithDetail(ErrBadValue, "quorum empty with non-empty pubkey list")
137 // GetIssuanceProgramRestrictHeight return issuance program restrict height
138 // if height invalid return 0
139 func GetIssuanceProgramRestrictHeight(program []byte) int64 {
140 insts, err := vm.ParseProgram(program)
145 if len(insts) >= 4 && insts[0].IsPushdata() && insts[1].Op == vm.OP_BLOCKHEIGHT && insts[2].Op == vm.OP_GREATERTHAN && insts[3].Op == vm.OP_VERIFY {
146 height, err := vm.AsInt64(insts[0].Data)