OSDN Git Service

21cc0d4b4307a0fbd08b366f922ffd92ea05e797
[bytom/vapor.git] / protocol / vm / vmutil / script.go
1 package vmutil
2
3 import (
4         "github.com/bytom/vapor/crypto/ed25519"
5         "github.com/bytom/vapor/errors"
6         "github.com/bytom/vapor/protocol/bc"
7         "github.com/bytom/vapor/protocol/vm"
8 )
9
10 // pre-define errors
11 var (
12         ErrBadValue       = errors.New("bad value")
13         ErrMultisigFormat = errors.New("bad multisig program format")
14 )
15
16 // MagneticContractArgs is a struct for magnetic contract arguments
17 type MagneticContractArgs struct {
18         RequestedAsset   bc.AssetID
19         RatioNumerator   int64
20         RatioDenominator int64
21         SellerProgram    []byte
22         SellerKey        []byte
23 }
24
25 // IsUnspendable checks if a contorl program is absolute failed
26 func IsUnspendable(prog []byte) bool {
27         return len(prog) > 0 && prog[0] == byte(vm.OP_FAIL)
28 }
29
30 func (b *Builder) addP2SPMultiSig(pubkeys []ed25519.PublicKey, nrequired int) error {
31         if err := checkMultiSigParams(int64(nrequired), int64(len(pubkeys))); err != nil {
32                 return err
33         }
34
35         b.AddOp(vm.OP_TXSIGHASH) // stack is now [... NARGS SIG SIG SIG PREDICATEHASH]
36         for _, p := range pubkeys {
37                 b.AddData(p)
38         }
39         b.AddInt64(int64(nrequired))    // stack is now [... SIG SIG SIG PREDICATEHASH PUB PUB PUB M]
40         b.AddInt64(int64(len(pubkeys))) // stack is now [... SIG SIG SIG PREDICATEHASH PUB PUB PUB M N]
41         b.AddOp(vm.OP_CHECKMULTISIG)    // stack is now [... NARGS]
42         return nil
43 }
44
45 // DefaultCoinbaseProgram generates the script for contorl coinbase output
46 func DefaultCoinbaseProgram() ([]byte, error) {
47         builder := NewBuilder()
48         builder.AddOp(vm.OP_TRUE)
49         return builder.Build()
50 }
51
52 // P2WPKHProgram return the segwit pay to public key hash
53 func P2WPKHProgram(hash []byte) ([]byte, error) {
54         builder := NewBuilder()
55         builder.AddInt64(0)
56         builder.AddData(hash)
57         return builder.Build()
58 }
59
60 // P2WSHProgram return the segwit pay to script hash
61 func P2WSHProgram(hash []byte) ([]byte, error) {
62         builder := NewBuilder()
63         builder.AddInt64(0)
64         builder.AddData(hash)
65         return builder.Build()
66 }
67
68 // RetireProgram generates the script for retire output
69 func RetireProgram(comment []byte) ([]byte, error) {
70         builder := NewBuilder()
71         builder.AddOp(vm.OP_FAIL)
72         if len(comment) != 0 {
73                 builder.AddData(comment)
74         }
75         return builder.Build()
76 }
77
78 // P2PKHSigProgram generates the script for control with pubkey hash
79 func P2PKHSigProgram(pubkeyHash []byte) ([]byte, error) {
80         builder := NewBuilder()
81         builder.AddOp(vm.OP_DUP)
82         builder.AddOp(vm.OP_HASH160)
83         builder.AddData(pubkeyHash)
84         builder.AddOp(vm.OP_EQUALVERIFY)
85         builder.AddOp(vm.OP_TXSIGHASH)
86         builder.AddOp(vm.OP_SWAP)
87         builder.AddOp(vm.OP_CHECKSIG)
88         return builder.Build()
89 }
90
91 // P2SHProgram generates the script for control with script hash
92 func P2SHProgram(scriptHash []byte) ([]byte, error) {
93         builder := NewBuilder()
94         builder.AddOp(vm.OP_DUP)
95         builder.AddOp(vm.OP_SHA3)
96         builder.AddData(scriptHash)
97         builder.AddOp(vm.OP_EQUALVERIFY)
98         builder.AddInt64(-1)
99         builder.AddOp(vm.OP_SWAP)
100         builder.AddInt64(0)
101         builder.AddOp(vm.OP_CHECKPREDICATE)
102         return builder.Build()
103 }
104
105 // P2SPMultiSigProgram generates the script for control transaction output
106 func P2SPMultiSigProgram(pubkeys []ed25519.PublicKey, nrequired int) ([]byte, error) {
107         builder := NewBuilder()
108         if err := builder.addP2SPMultiSig(pubkeys, nrequired); err != nil {
109                 return nil, err
110         }
111         return builder.Build()
112 }
113
114 // P2SPMultiSigProgramWithHeight generates the script with block height for control transaction output
115 func P2SPMultiSigProgramWithHeight(pubkeys []ed25519.PublicKey, nrequired int, blockHeight int64) ([]byte, error) {
116         builder := NewBuilder()
117         if blockHeight > 0 {
118                 builder.AddInt64(blockHeight)
119                 builder.AddOp(vm.OP_BLOCKHEIGHT)
120                 builder.AddOp(vm.OP_GREATERTHAN)
121                 builder.AddOp(vm.OP_VERIFY)
122         } else if blockHeight < 0 {
123                 return nil, errors.WithDetail(ErrBadValue, "negative blockHeight")
124         }
125         if err := builder.addP2SPMultiSig(pubkeys, nrequired); err != nil {
126                 return nil, err
127         }
128         return builder.Build()
129 }
130
131 func checkMultiSigParams(nrequired, npubkeys int64) error {
132         if nrequired < 0 {
133                 return errors.WithDetail(ErrBadValue, "negative quorum")
134         }
135         if npubkeys < 0 {
136                 return errors.WithDetail(ErrBadValue, "negative pubkey count")
137         }
138         if nrequired > npubkeys {
139                 return errors.WithDetail(ErrBadValue, "quorum too big")
140         }
141         if nrequired == 0 && npubkeys > 0 {
142                 return errors.WithDetail(ErrBadValue, "quorum empty with non-empty pubkey list")
143         }
144         return nil
145 }
146
147 // P2WMCProgram return the segwit pay to magnetic contract
148 func P2WMCProgram(magneticContractArgs MagneticContractArgs) ([]byte, error) {
149         builder := NewBuilder()
150         builder.AddInt64(0)
151         builder.AddData(magneticContractArgs.RequestedAsset.Bytes())
152         builder.AddInt64(magneticContractArgs.RatioNumerator)
153         builder.AddInt64(magneticContractArgs.RatioDenominator)
154         builder.AddData(magneticContractArgs.SellerProgram)
155         builder.AddData(magneticContractArgs.SellerKey)
156         return builder.Build()
157 }
158
159 // P2MCProgram generates the script for control with magnetic contract
160 //
161 // MagneticContract source code:
162 // contract MagneticContract(requestedAsset: Asset,
163 //                           ratioNumerator: Integer,
164 //                           ratioDenominator: Integer,
165 //                           sellerProgram: Program,
166 //                           standardProgram: Program,
167 //                           sellerKey: PublicKey) locks valueAmount of valueAsset {
168 //  clause partialTrade(exchangeAmount: Amount) {
169 //   define actualAmount: Integer = exchangeAmount * ratioDenominator / ratioNumerator
170 //   verify actualAmount > 0 && actualAmount < valueAmount
171 //   define receiveAmount: Integer = exchangeAmount * 999 / 1000
172 //   lock receiveAmount of requestedAsset with sellerProgram
173 //   lock valueAmount-actualAmount of valueAsset with standardProgram
174 //   unlock actualAmount of valueAsset
175 //  }
176 //  clause fullTrade() {
177 //   define requestedAmount: Integer = valueAmount * ratioNumerator / ratioDenominator
178 //   define requestedAmount: Integer = requestedAmount * 999 / 1000
179 //   verify requestedAmount > 0
180 //   lock requestedAmount of requestedAsset with sellerProgram
181 //   unlock valueAmount of valueAsset
182 //  }
183 //  clause cancel(sellerSig: Signature) {
184 //   verify checkTxSig(sellerKey, sellerSig)
185 //   unlock valueAmount of valueAsset
186 //  }
187 // }
188 //
189 // contract stack flow:
190 // 7                        [... <position> <clause selector> sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset 7]
191 // ROLL                     [... <clause selector> sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <position>]
192 // TOALTSTACK               [... <clause selector> sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
193 // 6                        [... <clause selector> sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset 6]
194 // ROLL                     [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector>]
195 // DUP                      [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector> <clause selector>]
196 // 2                        [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector> <clause selector> 2]
197 // NUMEQUAL                 [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector> (<clause selector> == 2)]
198 // JUMPIF:$cancel           [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector>]
199 // JUMPIF:$fullTrade        [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
200 // $partialTrade            [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
201 // 6                        [... exchangeAmount sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset 6]
202 // PICK                     [... exchangeAmount sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset exchangeAmount]
203 // 3                        [... exchangeAmount sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset exchangeAmount 3]
204 // ROLL                     [... exchangeAmount sellerKey standardProgram sellerProgram ratioNumerator requestedAsset exchangeAmount ratioDenominator]
205 // 3                        [... exchangeAmount sellerKey standardProgram sellerProgram ratioNumerator requestedAsset exchangeAmount ratioDenominator 3]
206 // ROLL                     [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset exchangeAmount ratioDenominator ratioNumerator]
207 // MULFRACTION              [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount]
208 // AMOUNT                   [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount]
209 // OVER                     [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount actualAmount]
210 // 0                        [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount actualAmount 0]
211 // GREATERTHAN              [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0)]
212 // 2                        [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0) 2]
213 // PICK                     [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0) actualAmount]
214 // 2                        [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0) actualAmount 2]
215 // ROLL                     [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount (actualAmount > 0) actualAmount valueAmount]
216 // LESSTHAN                 [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount (actualAmount > 0) (actualAmount < valueAmount)]
217 // BOOLAND                  [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount ((actualAmount > 0) && (actualAmount < valueAmount))]
218 // VERIFY                   [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount]
219 // FROMALTSTACK             [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount <position>]
220 // DUP                      [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> <position>]
221 // TOALTSTACK               [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount <position>]
222 // 6                        [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> 6]
223 // ROLL                     [... sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> exchangeAmount]
224 // 999                      [... sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> exchangeAmount 999]
225 // 1000                     [... sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> exchangeAmount 1000]
226 // MULFRACTION              [... sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> receiveAmount]
227 // 3                        [... sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> receiveAmount 3]
228 // ROLL                     [... sellerKey standardProgram sellerProgram actualAmount <position> receiveAmount requestedAsset]
229 // 1                        [... sellerKey standardProgram sellerProgram actualAmount <position> receiveAmount requestedAsset 1]
230 // 5                        [... sellerKey standardProgram sellerProgram actualAmount <position> receiveAmount requestedAsset 1 5]
231 // ROLL                     [... sellerKey standardProgram actualAmount <position> receiveAmount requestedAsset 1 sellerProgram]
232 // CHECKOUTPUT              [... sellerKey standardProgram actualAmount checkOutput(receiveAmount, requestedAsset, sellerProgram)]
233 // VERIFY                   [... sellerKey standardProgram actualAmount]
234 // FROMALTSTACK             [... sellerKey standardProgram actualAmount <position>]
235 // 1                        [... sellerKey standardProgram actualAmount <position> 1]
236 // ADD                      [... sellerKey standardProgram actualAmount (<position> + 1)]
237 // AMOUNT                   [... sellerKey standardProgram actualAmount (<position> + 1) valueAmount]
238 // 2                        [... sellerKey standardProgram actualAmount (<position> + 1) valueAmount 2]
239 // ROLL                     [... sellerKey standardProgram (<position> + 1) valueAmount actualAmount]
240 // SUB                      [... sellerKey standardProgram (<position> + 1) (valueAmount - actualAmount)]
241 // ASSET                    [... sellerKey standardProgram (<position> + 1) (valueAmount - actualAmount) valueAsset]
242 // 1                        [... sellerKey standardProgram (<position> + 1) (valueAmount - actualAmount) valueAsset 1]
243 // 4                        [... sellerKey standardProgram (<position> + 1) (valueAmount - actualAmount) valueAsset 1 4]
244 // ROLL                     [... sellerKey (<position> + 1) (valueAmount - actualAmount) valueAsset 1 standardProgram]
245 // CHECKOUTPUT              [... sellerKey checkOutput((valueAmount - actualAmount), valueAsset, standardProgram)]
246 // JUMP:$_end               [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
247 // $fullTrade               [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
248 // AMOUNT                   [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset valueAmount]
249 // 2                        [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset valueAmount 2]
250 // ROLL                     [... sellerKey standardProgram sellerProgram ratioDenominator requestedAsset valueAmount ratioNumerator]
251 // 3                        [... sellerKey standardProgram sellerProgram ratioDenominator requestedAsset valueAmount ratioNumerator 3]
252 // ROLL                     [... sellerKey standardProgram sellerProgram requestedAsset valueAmount ratioNumerator ratioDenominator]
253 // MULFRACTION              [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount]
254 // 999                      [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount 999]
255 // 1000                     [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount 999 1000]
256 // MULFRACTION              [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount]
257 // DUP                      [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount requestedAmount]
258 // 0                        [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount requestedAmount 0]
259 // GREATERTHAN              [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount (requestedAmount > 0)]
260 // VERIFY                   [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount]
261 // FROMALTSTACK             [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount <position>]
262 // SWAP                     [... sellerKey standardProgram sellerProgram requestedAsset <position> requestedAmount]
263 // 2                        [... sellerKey standardProgram sellerProgram requestedAsset <position> requestedAmount 2]
264 // ROLL                     [... sellerKey standardProgram sellerProgram <position> requestedAmount requestedAsset]
265 // 1                        [... sellerKey standardProgram sellerProgram <position> requestedAmount requestedAsset 1]
266 // 4                        [... sellerKey standardProgram sellerProgram <position> requestedAmount requestedAsset 1 4]
267 // ROLL                     [... sellerKey standardProgram <position> requestedAmount requestedAsset 1 sellerProgram]
268 // CHECKOUTPUT              [... sellerKey standardProgram checkOutput(requestedAmount, requestedAsset, sellerProgram)]
269 // JUMP:$_end               [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
270 // $cancel                  [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector>]
271 // DROP                     [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
272 // 6                        [... sellerSig sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset 6]
273 // ROLL                     [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset sellerSig]
274 // 6                        [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset sellerSig 6]
275 // ROLL                     [... standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset sellerSig sellerKey]
276 // TXSIGHASH SWAP CHECKSIG  [... standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset checkTxSig(sellerKey, sellerSig)]
277 // $_end                    [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
278 func P2MCProgram(magneticContractArgs MagneticContractArgs) ([]byte, error) {
279         standardProgram, err := P2WMCProgram(magneticContractArgs)
280         if err != nil {
281                 return nil, err
282         }
283
284         builder := NewBuilder()
285         // contract arguments
286         builder.AddData(magneticContractArgs.SellerKey)
287         builder.AddData(standardProgram)
288         builder.AddData(magneticContractArgs.SellerProgram)
289         builder.AddInt64(magneticContractArgs.RatioDenominator)
290         builder.AddInt64(magneticContractArgs.RatioNumerator)
291         builder.AddData(magneticContractArgs.RequestedAsset.Bytes())
292
293         // contract instructions
294         builder.AddOp(vm.OP_7)
295         builder.AddOp(vm.OP_ROLL)
296         builder.AddOp(vm.OP_TOALTSTACK)
297         builder.AddOp(vm.OP_6)
298         builder.AddOp(vm.OP_ROLL)
299         builder.AddOp(vm.OP_DUP)
300         builder.AddOp(vm.OP_2)
301         builder.AddOp(vm.OP_NUMEQUAL)
302         builder.AddJumpIf(0)
303         builder.AddJumpIf(1)
304         builder.AddOp(vm.OP_6)
305         builder.AddOp(vm.OP_PICK)
306         builder.AddOp(vm.OP_3)
307         builder.AddOp(vm.OP_ROLL)
308         builder.AddOp(vm.OP_3)
309         builder.AddOp(vm.OP_ROLL)
310         builder.AddOp(vm.OP_MULFRACTION)
311         builder.AddOp(vm.OP_AMOUNT)
312         builder.AddOp(vm.OP_OVER)
313         builder.AddOp(vm.OP_0)
314         builder.AddOp(vm.OP_GREATERTHAN)
315         builder.AddOp(vm.OP_2)
316         builder.AddOp(vm.OP_PICK)
317         builder.AddOp(vm.OP_ROT)
318         builder.AddOp(vm.OP_LESSTHAN)
319         builder.AddOp(vm.OP_BOOLAND)
320         builder.AddOp(vm.OP_VERIFY)
321         builder.AddOp(vm.OP_FROMALTSTACK)
322         builder.AddOp(vm.OP_DUP)
323         builder.AddOp(vm.OP_TOALTSTACK)
324         builder.AddOp(vm.OP_6)
325         builder.AddOp(vm.OP_ROLL)
326         builder.AddInt64(999)
327         builder.AddInt64(1000)
328         builder.AddOp(vm.OP_MULFRACTION)
329         builder.AddOp(vm.OP_3)
330         builder.AddOp(vm.OP_ROLL)
331         builder.AddOp(vm.OP_1)
332         builder.AddOp(vm.OP_5)
333         builder.AddOp(vm.OP_ROLL)
334         builder.AddOp(vm.OP_CHECKOUTPUT)
335         builder.AddOp(vm.OP_VERIFY)
336         builder.AddOp(vm.OP_FROMALTSTACK)
337         builder.AddOp(vm.OP_1)
338         builder.AddOp(vm.OP_ADD)
339         builder.AddOp(vm.OP_AMOUNT)
340         builder.AddOp(vm.OP_ROT)
341         builder.AddOp(vm.OP_SUB)
342         builder.AddOp(vm.OP_ASSET)
343         builder.AddOp(vm.OP_1)
344         builder.AddOp(vm.OP_4)
345         builder.AddOp(vm.OP_ROLL)
346         builder.AddOp(vm.OP_CHECKOUTPUT)
347         builder.AddJump(2)
348         builder.SetJumpTarget(1)
349         builder.AddOp(vm.OP_AMOUNT)
350         builder.AddOp(vm.OP_ROT)
351         builder.AddOp(vm.OP_3)
352         builder.AddOp(vm.OP_ROLL)
353         builder.AddOp(vm.OP_MULFRACTION)
354         builder.AddInt64(999)
355         builder.AddInt64(1000)
356         builder.AddOp(vm.OP_MULFRACTION)
357         builder.AddOp(vm.OP_DUP)
358         builder.AddOp(vm.OP_0)
359         builder.AddOp(vm.OP_GREATERTHAN)
360         builder.AddOp(vm.OP_VERIFY)
361         builder.AddOp(vm.OP_FROMALTSTACK)
362         builder.AddOp(vm.OP_SWAP)
363         builder.AddOp(vm.OP_ROT)
364         builder.AddOp(vm.OP_1)
365         builder.AddOp(vm.OP_4)
366         builder.AddOp(vm.OP_ROLL)
367         builder.AddOp(vm.OP_CHECKOUTPUT)
368         builder.AddJump(3)
369         builder.SetJumpTarget(0)
370         builder.AddOp(vm.OP_DROP)
371         builder.AddOp(vm.OP_6)
372         builder.AddOp(vm.OP_ROLL)
373         builder.AddOp(vm.OP_6)
374         builder.AddOp(vm.OP_ROLL)
375         builder.AddOp(vm.OP_TXSIGHASH)
376         builder.AddOp(vm.OP_SWAP)
377         builder.AddOp(vm.OP_CHECKSIG)
378         builder.SetJumpTarget(2)
379         builder.SetJumpTarget(3)
380         return builder.Build()
381 }