6 "github.com/bytom/bytom/consensus/bcrp"
7 "github.com/bytom/bytom/errors"
8 "github.com/bytom/bytom/protocol/vm"
13 ErrBadValue = errors.New("bad value")
14 ErrMultisigFormat = errors.New("bad multisig program format")
17 // IsUnspendable checks if a contorl program is absolute failed
18 func IsUnspendable(prog []byte) bool {
19 return len(prog) > 0 && prog[0] == byte(vm.OP_FAIL)
22 func (b *Builder) addP2SPMultiSig(pubkeys []ed25519.PublicKey, nrequired int) error {
23 if err := checkMultiSigParams(int64(nrequired), int64(len(pubkeys))); err != nil {
27 b.AddOp(vm.OP_TXSIGHASH) // stack is now [... NARGS SIG SIG SIG PREDICATEHASH]
28 for _, p := range pubkeys {
31 b.AddInt64(int64(nrequired)) // stack is now [... SIG SIG SIG PREDICATEHASH PUB PUB PUB M]
32 b.AddInt64(int64(len(pubkeys))) // stack is now [... SIG SIG SIG PREDICATEHASH PUB PUB PUB M N]
33 b.AddOp(vm.OP_CHECKMULTISIG) // stack is now [... NARGS]
37 // DefaultCoinbaseProgram generates the script for contorl coinbase output
38 func DefaultCoinbaseProgram() ([]byte, error) {
39 builder := NewBuilder()
40 builder.AddOp(vm.OP_TRUE)
41 return builder.Build()
44 // P2WPKHProgram return the segwit pay to public key hash
45 func P2WPKHProgram(hash []byte) ([]byte, error) {
46 builder := NewBuilder()
49 return builder.Build()
52 // P2WSHProgram return the segwit pay to script hash
53 func P2WSHProgram(hash []byte) ([]byte, error) {
54 builder := NewBuilder()
57 return builder.Build()
60 // RetireProgram generates the script for retire output
61 func RetireProgram(comment []byte) ([]byte, error) {
62 builder := NewBuilder()
63 builder.AddOp(vm.OP_FAIL)
64 if len(comment) != 0 {
65 builder.AddData(comment)
67 return builder.Build()
70 // RegisterProgram generates the script for register contract output
71 // follow BCRP(bytom contract register protocol)
72 func RegisterProgram(contract []byte) ([]byte, error) {
73 builder := NewBuilder()
74 builder.AddOp(vm.OP_FAIL)
75 builder.AddOp(vm.OP_PUSHDATA1)
76 builder.AddData([]byte(bcrp.BCRP))
77 builder.AddOp(vm.OP_PUSHDATA1)
78 builder.AddData([]byte{byte(bcrp.Version)})
79 builder.AddOp(vm.OP_PUSHDATA1)
80 builder.AddData(contract)
81 return builder.Build()
84 // CallContractProgram generates the script for control contract output
85 // follow BCRP(bytom contract register protocol)
86 func CallContractProgram(contractID []byte) ([]byte, error) {
87 builder := NewBuilder()
88 builder.AddOp(vm.OP_1)
89 builder.AddOp(vm.OP_PUSHDATA1)
90 builder.AddData(contractID)
91 return builder.Build()
94 // P2PKHSigProgram generates the script for control with pubkey hash
95 func P2PKHSigProgram(pubkeyHash []byte) ([]byte, error) {
96 builder := NewBuilder()
97 builder.AddOp(vm.OP_DUP)
98 builder.AddOp(vm.OP_HASH160)
99 builder.AddData(pubkeyHash)
100 builder.AddOp(vm.OP_EQUALVERIFY)
101 builder.AddOp(vm.OP_TXSIGHASH)
102 builder.AddOp(vm.OP_SWAP)
103 builder.AddOp(vm.OP_CHECKSIG)
104 return builder.Build()
107 // P2SHProgram generates the script for control with script hash
108 func P2SHProgram(scriptHash []byte) ([]byte, error) {
109 builder := NewBuilder()
110 builder.AddOp(vm.OP_DUP)
111 builder.AddOp(vm.OP_SHA3)
112 builder.AddData(scriptHash)
113 builder.AddOp(vm.OP_EQUALVERIFY)
115 builder.AddOp(vm.OP_SWAP)
117 builder.AddOp(vm.OP_CHECKPREDICATE)
118 return builder.Build()
121 // P2SPMultiSigProgram generates the script for control transaction output
122 func P2SPMultiSigProgram(pubkeys []ed25519.PublicKey, nrequired int) ([]byte, error) {
123 builder := NewBuilder()
124 if err := builder.addP2SPMultiSig(pubkeys, nrequired); err != nil {
127 return builder.Build()
130 // P2SPMultiSigProgramWithHeight generates the script with block height for control transaction output
131 func P2SPMultiSigProgramWithHeight(pubkeys []ed25519.PublicKey, nrequired int, blockHeight int64) ([]byte, error) {
132 builder := NewBuilder()
134 builder.AddInt64(blockHeight)
135 builder.AddOp(vm.OP_BLOCKHEIGHT)
136 builder.AddOp(vm.OP_GREATERTHAN)
137 builder.AddOp(vm.OP_VERIFY)
138 } else if blockHeight < 0 {
139 return nil, errors.WithDetail(ErrBadValue, "negative blockHeight")
141 if err := builder.addP2SPMultiSig(pubkeys, nrequired); err != nil {
144 return builder.Build()
147 func checkMultiSigParams(nrequired, npubkeys int64) error {
149 return errors.WithDetail(ErrBadValue, "negative quorum")
152 return errors.WithDetail(ErrBadValue, "negative pubkey count")
154 if nrequired > npubkeys {
155 return errors.WithDetail(ErrBadValue, "quorum too big")
157 if nrequired == 0 && npubkeys > 0 {
158 return errors.WithDetail(ErrBadValue, "quorum empty with non-empty pubkey list")
163 // GetIssuanceProgramRestrictHeight return issuance program restrict height
164 // if height invalid return 0
165 func GetIssuanceProgramRestrictHeight(program []byte) uint64 {
166 insts, err := vm.ParseProgram(program)
171 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 {
172 heightInt, err := vm.AsBigInt(insts[0].Data)
177 height, overflow := heightInt.Uint64WithOverflow()