OSDN Git Service

add assgin statement and modify defined statement to support declaration (#9)
[bytom/equity.git] / compiler / compile.go
1 package compiler
2
3 import (
4         "encoding/json"
5         "fmt"
6         "io"
7         "io/ioutil"
8         "strings"
9
10         chainjson "github.com/bytom/encoding/json"
11         "github.com/bytom/errors"
12         "github.com/bytom/protocol/vm"
13         "github.com/bytom/protocol/vm/vmutil"
14 )
15
16 // ValueInfo describes how a blockchain value is used in a contract
17 // clause.
18 type ValueInfo struct {
19         // Name is the clause's name for this value.
20         Name string `json:"name"`
21
22         // Program is the program expression used to the lock the value, if
23         // the value is locked with "lock." If it's unlocked with "unlock"
24         // instead, this is empty.
25         Program string `json:"program,omitempty"`
26
27         // Asset is the expression describing the asset type the value must
28         // have, as it appears in a clause's "requires" section. If this is
29         // the contract value instead, this is empty.
30         Asset string `json:"asset,omitempty"`
31
32         // Amount is the expression describing the amount the value must
33         // have, as it appears in a clause's "requires" section. If this is
34         // the contract value instead, this is empty.
35         Amount string `json:"amount,omitempty"`
36 }
37
38 // ContractArg is an argument with which to instantiate a contract as
39 // a program. Exactly one of B, I, and S should be supplied.
40 type ContractArg struct {
41         B *bool               `json:"boolean,omitempty"`
42         I *int64              `json:"integer,omitempty"`
43         S *chainjson.HexBytes `json:"string,omitempty"`
44 }
45
46 // Compile parses a sequence of Equity contracts from the supplied reader
47 // and produces Contract objects containing the compiled bytecode and
48 // other analysis. If argMap is non-nil, it maps contract names to
49 // lists of arguments with which to instantiate them as programs, with
50 // the results placed in the contract's Program field. A contract
51 // named in argMap but not found in the input is silently ignored.
52 func Compile(r io.Reader) ([]*Contract, error) {
53         inp, err := ioutil.ReadAll(r)
54         if err != nil {
55                 return nil, errors.Wrap(err, "reading input")
56         }
57         contracts, err := parse(inp)
58         if err != nil {
59                 return nil, errors.Wrap(err, "parse error")
60         }
61
62         globalEnv := newEnviron(nil)
63         for _, k := range keywords {
64                 globalEnv.add(k, nilType, roleKeyword)
65         }
66         for _, b := range builtins {
67                 globalEnv.add(b.name, nilType, roleBuiltin)
68         }
69
70         // All contracts must be checked for recursiveness before any are
71         // compiled.
72         for _, contract := range contracts {
73                 contract.Recursive = checkRecursive(contract)
74         }
75
76         for _, contract := range contracts {
77                 err = globalEnv.addContract(contract)
78                 if err != nil {
79                         return nil, err
80                 }
81         }
82
83         for _, contract := range contracts {
84                 err = compileContract(contract, globalEnv)
85                 if err != nil {
86                         return nil, errors.Wrap(err, "compiling contract")
87                 }
88                 for _, clause := range contract.Clauses {
89                         for _, stmt := range clause.statements {
90                                 switch s := stmt.(type) {
91                                 case *lockStatement:
92                                         valueInfo := ValueInfo{
93                                                 Amount:  s.lockedAmount.String(),
94                                                 Asset:   s.lockedAsset.String(),
95                                                 Program: s.program.String(),
96                                         }
97
98                                         clause.Values = append(clause.Values, valueInfo)
99                                 case *unlockStatement:
100                                         valueInfo := ValueInfo{
101                                                 Amount: contract.Value.Amount,
102                                                 Asset:  contract.Value.Asset,
103                                         }
104                                         clause.Values = append(clause.Values, valueInfo)
105                                 }
106                         }
107                 }
108         }
109
110         return contracts, nil
111 }
112
113 func Instantiate(body []byte, params []*Param, recursive bool, args []ContractArg) ([]byte, error) {
114         if len(args) != len(params) {
115                 return nil, fmt.Errorf("got %d argument(s), want %d", len(args), len(params))
116         }
117
118         // typecheck args against param types
119         for i, param := range params {
120                 arg := args[i]
121                 switch param.Type {
122                 case amountType, intType:
123                         if arg.I == nil {
124                                 return nil, fmt.Errorf("type mismatch in arg %d (want integer)", i)
125                         }
126                 case assetType, hashType, progType, pubkeyType, sigType, strType:
127                         if arg.S == nil {
128                                 return nil, fmt.Errorf("type mismatch in arg %d (want string)", i)
129                         }
130                 case boolType:
131                         if arg.B == nil {
132                                 return nil, fmt.Errorf("type mismatch in arg %d (want boolean)", i)
133                         }
134                 }
135         }
136
137         b := vmutil.NewBuilder()
138
139         for i := len(args) - 1; i >= 0; i-- {
140                 a := args[i]
141                 switch {
142                 case a.B != nil:
143                         var n int64
144                         if *a.B {
145                                 n = 1
146                         }
147                         b.AddInt64(n)
148                 case a.I != nil:
149                         b.AddInt64(*a.I)
150                 case a.S != nil:
151                         b.AddData(*a.S)
152                 }
153         }
154
155         if recursive {
156                 // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE
157                 b.AddData(body)
158                 b.AddOp(vm.OP_DEPTH).AddOp(vm.OP_OVER)
159         } else {
160                 // <argN> <argN-1> ... <arg1> DEPTH <body> 0 CHECKPREDICATE
161                 b.AddOp(vm.OP_DEPTH)
162                 b.AddData(body)
163         }
164         b.AddInt64(0)
165         b.AddOp(vm.OP_CHECKPREDICATE)
166         return b.Build()
167 }
168
169 func compileContract(contract *Contract, globalEnv *environ) error {
170         var err error
171
172         if len(contract.Clauses) == 0 {
173                 return fmt.Errorf("empty contract")
174         }
175         env := newEnviron(globalEnv)
176         for _, p := range contract.Params {
177                 err = env.add(p.Name, p.Type, roleContractParam)
178                 if err != nil {
179                         return err
180                 }
181         }
182
183         // value is spilt with valueAmount and valueAsset
184         if err = env.add(contract.Value.Amount, amountType, roleContractValue); err != nil {
185                 return err
186         }
187         if err = env.add(contract.Value.Asset, assetType, roleContractValue); err != nil {
188                 return err
189         }
190
191         for _, c := range contract.Clauses {
192                 err = env.add(c.Name, nilType, roleClause)
193                 if err != nil {
194                         return err
195                 }
196         }
197
198         err = prohibitSigParams(contract)
199         if err != nil {
200                 return err
201         }
202         err = requireAllParamsUsedInClauses(contract.Params, contract.Clauses)
203         if err != nil {
204                 return err
205         }
206
207         var stk stack
208
209         if len(contract.Clauses) > 1 {
210                 stk = stk.add("<clause selector>")
211         }
212
213         for i := len(contract.Params) - 1; i >= 0; i-- {
214                 p := contract.Params[i]
215                 stk = stk.add(p.Name)
216         }
217
218         if contract.Recursive {
219                 stk = stk.add(contract.Name)
220         }
221
222         b := &builder{}
223         sequence := 0 // sequence is used to count the number of ifStatements
224
225         if len(contract.Clauses) == 1 {
226                 err = compileClause(b, stk, contract, env, contract.Clauses[0], &sequence)
227                 if err != nil {
228                         return err
229                 }
230         } else {
231                 if len(contract.Params) > 0 {
232                         // A clause selector is at the bottom of the stack. Roll it to the
233                         // top.
234                         n := len(contract.Params)
235                         if contract.Recursive {
236                                 n++
237                         }
238                         stk = b.addRoll(stk, n) // stack: [<clause params> <contract params> [<maybe contract body>] <clause selector>]
239                 }
240
241                 var stk2 stack
242
243                 // clauses 2..N-1
244                 for i := len(contract.Clauses) - 1; i >= 2; i-- {
245                         stk = b.addDup(stk)                                                   // stack: [... <clause selector> <clause selector>]
246                         stk = b.addInt64(stk, int64(i))                                       // stack: [... <clause selector> <clause selector> <i>]
247                         stk = b.addNumEqual(stk, fmt.Sprintf("(<clause selector> == %d)", i)) // stack: [... <clause selector> <i == clause selector>]
248                         stk = b.addJumpIf(stk, contract.Clauses[i].Name)                      // stack: [... <clause selector>]
249                         stk2 = stk                                                            // stack starts here for clauses 2 through N-1
250                 }
251
252                 // clause 1
253                 stk = b.addJumpIf(stk, contract.Clauses[1].Name) // consumes the clause selector
254
255                 // no jump needed for clause 0
256
257                 for i, clause := range contract.Clauses {
258                         if i > 1 {
259                                 // Clauses 0 and 1 have no clause selector on top of the
260                                 // stack. Clauses 2 and later do.
261                                 stk = stk2
262                         }
263
264                         b.addJumpTarget(stk, clause.Name)
265
266                         if i > 1 {
267                                 stk = b.addDrop(stk)
268                         }
269
270                         err = compileClause(b, stk, contract, env, clause, &sequence)
271                         if err != nil {
272                                 return errors.Wrapf(err, "compiling clause \"%s\"", clause.Name)
273                         }
274                         b.forgetPendingVerify()
275                         if i < len(contract.Clauses)-1 {
276                                 b.addJump(stk, "_end")
277                         }
278                 }
279                 b.addJumpTarget(stk, "_end")
280         }
281
282         opcodes := optimize(b.opcodes())
283         prog, err := vm.Assemble(opcodes)
284         if err != nil {
285                 return err
286         }
287
288         contract.Body = prog
289         contract.Opcodes = opcodes
290
291         contract.Steps = b.steps()
292
293         return nil
294 }
295
296 func compileClause(b *builder, contractStk stack, contract *Contract, env *environ, clause *Clause, sequence *int) error {
297         var err error
298
299         // copy env to leave outerEnv unchanged
300         env = newEnviron(env)
301         for _, p := range clause.Params {
302                 err = env.add(p.Name, p.Type, roleClauseParam)
303                 if err != nil {
304                         return err
305                 }
306         }
307
308         if err = assignIndexes(clause); err != nil {
309                 return err
310         }
311
312         var stk stack
313         for _, p := range clause.Params {
314                 // NOTE: the order of clause params is not reversed, unlike
315                 // contract params (and also unlike the arguments to Equity
316                 // function-calls).
317                 stk = stk.add(p.Name)
318         }
319         stk = stk.addFromStack(contractStk)
320
321         // a count of the number of times each variable is referenced
322         counts := make(map[string]int)
323         for _, s := range clause.statements {
324                 if stmt, ok := s.(*defineStatement); ok && stmt.expr == nil {
325                         continue
326                 }
327
328                 s.countVarRefs(counts)
329                 if stmt, ok := s.(*ifStatement); ok {
330                         for _, trueStmt := range stmt.body.trueBody {
331                                 trueStmt.countVarRefs(counts)
332                         }
333
334                         for _, falseStmt := range stmt.body.falseBody {
335                                 falseStmt.countVarRefs(counts)
336                         }
337                 }
338         }
339
340         for _, stat := range clause.statements {
341                 if stk, err = compileStatement(b, stk, contract, env, clause, counts, stat, sequence); err != nil {
342                         return err
343                 }
344         }
345
346         err = requireAllValuesDisposedOnce(contract, clause)
347         if err != nil {
348                 return err
349         }
350         err = typeCheckClause(contract, clause, env)
351         if err != nil {
352                 return err
353         }
354         err = requireAllParamsUsedInClause(clause.Params, clause)
355         if err != nil {
356                 return err
357         }
358
359         return nil
360 }
361
362 func compileStatement(b *builder, stk stack, contract *Contract, env *environ, clause *Clause, counts map[string]int, stat statement, sequence *int) (stack, error) {
363         var err error
364         switch stmt := stat.(type) {
365         case *ifStatement:
366                 // sequence add 1 when the statement is ifStatement
367                 *sequence++
368                 strSequence := fmt.Sprintf("%d", *sequence)
369
370                 // compile condition expression
371                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.condition)
372                 if err != nil {
373                         return stk, errors.Wrapf(err, "in check condition of ifStatement in clause \"%s\"", clause.Name)
374                 }
375
376                 // jump to falseBody when condition is false, while the JUMPIF instruction will be run success when
377                 // the value of dataStack is true, therefore add this check
378                 conditionExpr := stk.str
379                 stk = b.addBoolean(stk, false)
380                 stk = b.addEqual(stk, fmt.Sprintf("(%s == false)", conditionExpr)) // stack: [... <condition_result == false>]
381
382                 // add label
383                 var label string
384                 if len(stmt.body.falseBody) != 0 {
385                         label = "else_" + strSequence
386                 } else {
387                         label = "endif_" + strSequence
388                 }
389                 stk = b.addJumpIf(stk, label)
390                 b.addJumpTarget(stk, "if_"+strSequence)
391
392                 // temporary store stack and counts for falseBody
393                 condStk := stk
394                 elseCounts := make(map[string]int)
395                 for k, v := range counts {
396                         elseCounts[k] = v
397                 }
398
399                 // compile trueBody statements
400                 if len(stmt.body.trueBody) != 0 {
401                         for _, st := range stmt.body.trueBody {
402                                 st.countVarRefs(counts)
403                         }
404
405                         // modify value amount because of using only once
406                         if counts[contract.Value.Amount] > 1 {
407                                 counts[contract.Value.Amount] = 1
408                         }
409
410                         // modify value asset because of using only once
411                         if counts[contract.Value.Asset] > 1 {
412                                 counts[contract.Value.Asset] = 1
413                         }
414
415                         for _, st := range stmt.body.trueBody {
416                                 if stk, err = compileStatement(b, stk, contract, env, clause, counts, st, sequence); err != nil {
417                                         return stk, err
418                                 }
419                         }
420                 }
421
422                 // compile falseBody statements
423                 if len(stmt.body.falseBody) != 0 {
424                         counts := make(map[string]int)
425                         for k, v := range elseCounts {
426                                 counts[k] = v
427                         }
428
429                         for _, st := range stmt.body.falseBody {
430                                 st.countVarRefs(counts)
431                         }
432
433                         // modify value amount because of using only once
434                         if counts[contract.Value.Amount] > 1 {
435                                 counts[contract.Value.Amount] = 1
436                         }
437
438                         // modify value asset because of using only once
439                         if counts[contract.Value.Asset] > 1 {
440                                 counts[contract.Value.Asset] = 1
441                         }
442
443                         stk = condStk
444                         b.addJump(stk, "endif_"+strSequence)
445                         b.addJumpTarget(stk, "else_"+strSequence)
446
447                         for _, st := range stmt.body.falseBody {
448                                 if stk, err = compileStatement(b, stk, contract, env, clause, counts, st, sequence); err != nil {
449                                         return stk, err
450                                 }
451                         }
452                 }
453                 b.addJumpTarget(stk, "endif_"+strSequence)
454
455         case *defineStatement:
456                 // add environ for define variable
457                 if err = env.add(stmt.variable.Name, stmt.variable.Type, roleClauseVariable); err != nil {
458                         return stk, err
459                 }
460
461                 // check whether the variable is used or not
462                 if counts[stmt.variable.Name] == 0 {
463                         return stk, fmt.Errorf("the defined variable \"%s\" is unused in clause \"%s\"", stmt.variable.Name, clause.Name)
464                 }
465
466                 if stmt.expr != nil {
467                         // variable
468                         stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.expr)
469                         if err != nil {
470                                 return stk, errors.Wrapf(err, "in define statement in clause \"%s\"", clause.Name)
471                         }
472
473                         // modify stack name
474                         stk.str = stmt.variable.Name
475                 }
476
477         case *assignStatement:
478                 // find variable from environ with roleClauseVariable
479                 if entry := env.lookup(string(stmt.variable.Name)); entry != nil {
480                         if entry.r != roleClauseVariable {
481                                 return stk, fmt.Errorf("the type of variable is not roleClauseVariable in assign statement in clause \"%s\"", clause.Name)
482                         }
483                         stmt.variable.Type = entry.t
484                 } else {
485                         return stk, fmt.Errorf("the variable \"%s\" is not defined before the assign statement in clause \"%s\"", stmt.variable.Name, clause.Name)
486                 }
487
488                 // temporary store the counts of defined variable
489                 varCount := counts[stmt.variable.Name]
490
491                 // calculate the counts of variable for assign statement
492                 tmpCounts := make(map[string]int)
493                 stmt.countVarRefs(tmpCounts)
494
495                 // modify the map counts of defined variable to 1 and minus the number of defined variable
496                 // when the assign expression contains the defined variable
497                 if tmpCounts[stmt.variable.Name] > 0 {
498                         counts[stmt.variable.Name] = 1
499                         varCount -= tmpCounts[stmt.variable.Name]
500                 } else {
501                         depth := stk.find(stmt.variable.Name)
502                         switch depth {
503                         case 0:
504                                 break
505                         case 1:
506                                 stk = b.addSwap(stk)
507                         default:
508                                 stk = b.addRoll(stk, depth)
509                         }
510                         stk = b.addDrop(stk)
511                 }
512
513                 // variable
514                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.expr)
515                 if err != nil {
516                         return stk, errors.Wrapf(err, "in define statement in clause \"%s\"", clause.Name)
517                 }
518
519                 // restore the defined variable counts
520                 counts[stmt.variable.Name] = varCount
521
522                 // modify stack name
523                 stk.str = stmt.variable.Name
524
525         case *verifyStatement:
526                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.expr)
527                 if err != nil {
528                         return stk, errors.Wrapf(err, "in verify statement in clause \"%s\"", clause.Name)
529                 }
530                 stk = b.addVerify(stk)
531
532                 // special-case reporting of certain function calls
533                 if c, ok := stmt.expr.(*callExpr); ok && len(c.args) == 1 {
534                         if b := referencedBuiltin(c.fn); b != nil {
535                                 switch b.name {
536                                 case "below":
537                                         clause.BlockHeight = append(clause.BlockHeight, c.args[0].String())
538                                 case "above":
539                                         clause.BlockHeight = append(clause.BlockHeight, c.args[0].String())
540                                 }
541                         }
542                 }
543
544         case *lockStatement:
545                 // index
546                 stk = b.addInt64(stk, stmt.index)
547
548                 // TODO: permit more complex expressions for locked,
549                 // like "lock x+y with foo" (?)
550
551                 if stmt.lockedAmount.String() == contract.Value.Amount && stmt.lockedAsset.String() == contract.Value.Asset {
552                         stk = b.addAmount(stk, contract.Value.Amount)
553                         stk = b.addAsset(stk, contract.Value.Asset)
554                 } else {
555                         // amount
556                         if stmt.lockedAmount.String() == contract.Value.Amount {
557                                 stk = b.addAmount(stk, contract.Value.Amount)
558                         } else if strings.Contains(stmt.lockedAmount.String(), contract.Value.Amount) {
559                                 stk = b.addAmount(stk, contract.Value.Amount)
560                                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAmount)
561                                 if err != nil {
562                                         return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
563                                 }
564                         } else {
565                                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAmount)
566                                 if err != nil {
567                                         return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
568                                 }
569                         }
570
571                         // asset
572                         if stmt.lockedAsset.String() == contract.Value.Asset {
573                                 stk = b.addAsset(stk, contract.Value.Asset)
574                         } else if strings.Contains(stmt.lockedAsset.String(), contract.Value.Asset) {
575                                 stk = b.addAsset(stk, contract.Value.Asset)
576                                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAsset)
577                                 if err != nil {
578                                         return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
579                                 }
580                         } else {
581                                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAsset)
582                                 if err != nil {
583                                         return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
584                                 }
585                         }
586                 }
587
588                 // version
589                 stk = b.addInt64(stk, 1)
590
591                 // prog
592                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.program)
593                 if err != nil {
594                         return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
595                 }
596
597                 stk = b.addCheckOutput(stk, fmt.Sprintf("checkOutput(%s, %s, %s)",
598                         stmt.lockedAmount.String(), stmt.lockedAsset.String(), stmt.program))
599                 stk = b.addVerify(stk)
600
601         case *unlockStatement:
602                 if len(clause.statements) == 1 {
603                         // This is the only statement in the clause, make sure TRUE is
604                         // on the stack.
605                         stk = b.addBoolean(stk, true)
606                 }
607         }
608
609         return stk, nil
610 }
611
612 func compileExpr(b *builder, stk stack, contract *Contract, clause *Clause, env *environ, counts map[string]int, expr expression) (stack, error) {
613         var err error
614
615         switch e := expr.(type) {
616         case *binaryExpr:
617                 // Do typechecking after compiling subexpressions (because other
618                 // compilation errors are more interesting than type mismatch
619                 // errors).
620
621                 stk, err = compileExpr(b, stk, contract, clause, env, counts, e.left)
622                 if err != nil {
623                         return stk, errors.Wrapf(err, "in left operand of \"%s\" expression", e.op.op)
624                 }
625                 stk, err = compileExpr(b, stk, contract, clause, env, counts, e.right)
626                 if err != nil {
627                         return stk, errors.Wrapf(err, "in right operand of \"%s\" expression", e.op.op)
628                 }
629
630                 lType := e.left.typ(env)
631                 if e.op.left != "" && !(lType == e.op.left || lType == amountType) {
632                         return stk, fmt.Errorf("in \"%s\", left operand has type \"%s\", must be \"%s\"", e, lType, e.op.left)
633                 }
634
635                 rType := e.right.typ(env)
636                 if e.op.right != "" && !(rType == e.op.right || rType == amountType) {
637                         return stk, fmt.Errorf("in \"%s\", right operand has type \"%s\", must be \"%s\"", e, rType, e.op.right)
638                 }
639
640                 switch e.op.op {
641                 case "==", "!=":
642                         if lType != rType {
643                                 // Maybe one is Hash and the other is (more-specific-Hash subtype).
644                                 // TODO(bobg): generalize this mechanism
645                                 if lType == hashType && isHashSubtype(rType) {
646                                         propagateType(contract, clause, env, rType, e.left)
647                                 } else if rType == hashType && isHashSubtype(lType) {
648                                         propagateType(contract, clause, env, lType, e.right)
649                                 } else {
650                                         return stk, fmt.Errorf("type mismatch in \"%s\": left operand has type \"%s\", right operand has type \"%s\"", e, lType, rType)
651                                 }
652                         }
653                         if lType == "Boolean" {
654                                 return stk, fmt.Errorf("in \"%s\": using \"%s\" on Boolean values not allowed", e, e.op.op)
655                         }
656                 }
657
658                 stk = b.addOps(stk.dropN(2), e.op.opcodes, e.String())
659
660         case *unaryExpr:
661                 // Do typechecking after compiling subexpression (because other
662                 // compilation errors are more interesting than type mismatch
663                 // errors).
664
665                 var err error
666                 stk, err = compileExpr(b, stk, contract, clause, env, counts, e.expr)
667                 if err != nil {
668                         return stk, errors.Wrapf(err, "in \"%s\" expression", e.op.op)
669                 }
670
671                 if e.op.operand != "" && e.expr.typ(env) != e.op.operand {
672                         return stk, fmt.Errorf("in \"%s\", operand has type \"%s\", must be \"%s\"", e, e.expr.typ(env), e.op.operand)
673                 }
674                 b.addOps(stk.drop(), e.op.opcodes, e.String())
675
676         case *callExpr:
677                 bi := referencedBuiltin(e.fn)
678                 if bi == nil {
679                         if v, ok := e.fn.(varRef); ok {
680                                 if entry := env.lookup(string(v)); entry != nil && entry.t == contractType {
681                                         clause.Contracts = append(clause.Contracts, entry.c.Name)
682
683                                         partialName := fmt.Sprintf("%s(...)", v)
684                                         stk = b.addData(stk, nil)
685
686                                         if len(e.args) != len(entry.c.Params) {
687                                                 return stk, fmt.Errorf("contract \"%s\" expects %d argument(s), got %d", entry.c.Name, len(entry.c.Params), len(e.args))
688                                         }
689
690                                         for i := len(e.args) - 1; i >= 0; i-- {
691                                                 arg := e.args[i]
692                                                 if entry.c.Params[i].Type != "" && arg.typ(env) != entry.c.Params[i].Type {
693                                                         return stk, fmt.Errorf("argument %d to contract \"%s\" has type \"%s\", must be \"%s\"", i, entry.c.Name, arg.typ(env), entry.c.Params[i].Type)
694                                                 }
695                                                 stk, err = compileExpr(b, stk, contract, clause, env, counts, arg)
696                                                 if err != nil {
697                                                         return stk, err
698                                                 }
699                                                 stk = b.addCatPushdata(stk, partialName)
700                                         }
701
702                                         switch {
703                                         case entry.c == contract:
704                                                 // Recursive call - cannot use entry.c.Body
705                                                 // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE
706                                                 stk, err = compileRef(b, stk, counts, varRef(contract.Name))
707                                                 if err != nil {
708                                                         return stk, errors.Wrap(err, "compiling contract call")
709                                                 }
710                                                 stk = b.addCatPushdata(stk, partialName)
711                                                 stk = b.addData(stk, []byte{byte(vm.OP_DEPTH), byte(vm.OP_OVER)})
712                                                 stk = b.addCat(stk, partialName)
713
714                                         case entry.c.Recursive:
715                                                 // Non-recursive call to a (different) recursive contract
716                                                 // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE
717                                                 if len(entry.c.Body) == 0 {
718                                                         // TODO(bobg): sort input contracts topologically to permit forward calling
719                                                         return stk, fmt.Errorf("contract \"%s\" not defined", entry.c.Name)
720                                                 }
721                                                 stk = b.addData(stk, entry.c.Body)
722                                                 stk = b.addCatPushdata(stk, partialName)
723                                                 stk = b.addData(stk, []byte{byte(vm.OP_DEPTH), byte(vm.OP_OVER)})
724                                                 stk = b.addCat(stk, partialName)
725
726                                         default:
727                                                 // Non-recursive call to non-recursive contract
728                                                 // <argN> <argN-1> ... <arg1> DEPTH <body> 0 CHECKPREDICATE
729                                                 stk = b.addData(stk, []byte{byte(vm.OP_DEPTH)})
730                                                 stk = b.addCat(stk, partialName)
731                                                 if len(entry.c.Body) == 0 {
732                                                         // TODO(bobg): sort input contracts topologically to permit forward calling
733                                                         return stk, fmt.Errorf("contract \"%s\" not defined", entry.c.Name)
734                                                 }
735                                                 stk = b.addData(stk, entry.c.Body)
736                                                 stk = b.addCatPushdata(stk, partialName)
737                                         }
738                                         stk = b.addData(stk, vm.Int64Bytes(0))
739                                         stk = b.addCatPushdata(stk, partialName)
740                                         stk = b.addData(stk, []byte{byte(vm.OP_CHECKPREDICATE)})
741                                         stk = b.addCat(stk, e.String())
742
743                                         return stk, nil
744                                 }
745                         }
746                         return stk, fmt.Errorf("unknown function \"%s\"", e.fn)
747                 }
748
749                 if len(e.args) != len(bi.args) {
750                         return stk, fmt.Errorf("wrong number of args for \"%s\": have %d, want %d", bi.name, len(e.args), len(bi.args))
751                 }
752
753                 // WARNING WARNING WOOP WOOP
754                 // special-case hack
755                 // WARNING WARNING WOOP WOOP
756                 if bi.name == "checkTxMultiSig" {
757                         if _, ok := e.args[0].(listExpr); !ok {
758                                 return stk, fmt.Errorf("checkTxMultiSig expects list literals, got %T for argument 0", e.args[0])
759                         }
760                         if _, ok := e.args[1].(listExpr); !ok {
761                                 return stk, fmt.Errorf("checkTxMultiSig expects list literals, got %T for argument 1", e.args[1])
762                         }
763
764                         var k1, k2 int
765
766                         stk, k1, err = compileArg(b, stk, contract, clause, env, counts, e.args[1])
767                         if err != nil {
768                                 return stk, err
769                         }
770
771                         // stack: [... sigM ... sig1 M]
772
773                         var altEntry string
774                         stk, altEntry = b.addToAltStack(stk) // stack: [... sigM ... sig1]
775                         stk = b.addTxSigHash(stk)            // stack: [... sigM ... sig1 txsighash]
776
777                         stk, k2, err = compileArg(b, stk, contract, clause, env, counts, e.args[0])
778                         if err != nil {
779                                 return stk, err
780                         }
781
782                         // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 N]
783
784                         stk = b.addFromAltStack(stk, altEntry) // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 N M]
785                         stk = b.addSwap(stk)                   // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 M N]
786                         stk = b.addCheckMultisig(stk, k1+k2, e.String())
787
788                         return stk, nil
789                 }
790
791                 var k int
792
793                 for i := len(e.args) - 1; i >= 0; i-- {
794                         a := e.args[i]
795                         var k2 int
796                         var err error
797                         stk, k2, err = compileArg(b, stk, contract, clause, env, counts, a)
798                         if err != nil {
799                                 return stk, errors.Wrapf(err, "compiling argument %d in call expression", i)
800                         }
801                         k += k2
802                 }
803
804                 // Do typechecking after compiling subexpressions (because other
805                 // compilation errors are more interesting than type mismatch
806                 // errors).
807                 for i, actual := range e.args {
808                         if bi.args[i] != "" && actual.typ(env) != bi.args[i] {
809                                 return stk, fmt.Errorf("argument %d to \"%s\" has type \"%s\", must be \"%s\"", i, bi.name, actual.typ(env), bi.args[i])
810                         }
811                 }
812
813                 stk = b.addOps(stk.dropN(k), bi.opcodes, e.String())
814
815                 // special-case reporting
816                 switch bi.name {
817                 case "sha3", "sha256":
818                         clause.HashCalls = append(clause.HashCalls, HashCall{bi.name, e.args[0].String(), string(e.args[0].typ(env))})
819                 }
820
821         case varRef:
822                 return compileRef(b, stk, counts, e)
823
824         case integerLiteral:
825                 stk = b.addInt64(stk, int64(e))
826
827         case bytesLiteral:
828                 stk = b.addData(stk, []byte(e))
829
830         case booleanLiteral:
831                 stk = b.addBoolean(stk, bool(e))
832
833         case listExpr:
834                 // Lists are excluded here because they disobey the invariant of
835                 // this function: namely, that it increases the stack size by
836                 // exactly one. (A list pushes its items and its length on the
837                 // stack.) But they're OK as function-call arguments because the
838                 // function (presumably) consumes all the stack items added.
839                 return stk, fmt.Errorf("encountered list outside of function-call context")
840         }
841         return stk, nil
842 }
843
844 func compileArg(b *builder, stk stack, contract *Contract, clause *Clause, env *environ, counts map[string]int, expr expression) (stack, int, error) {
845         var n int
846         if list, ok := expr.(listExpr); ok {
847                 for i := 0; i < len(list); i++ {
848                         elt := list[len(list)-i-1]
849                         var err error
850                         stk, err = compileExpr(b, stk, contract, clause, env, counts, elt)
851                         if err != nil {
852                                 return stk, 0, err
853                         }
854                         n++
855                 }
856                 stk = b.addInt64(stk, int64(len(list)))
857                 n++
858                 return stk, n, nil
859         }
860         var err error
861         stk, err = compileExpr(b, stk, contract, clause, env, counts, expr)
862         return stk, 1, err
863 }
864
865 func compileRef(b *builder, stk stack, counts map[string]int, ref varRef) (stack, error) {
866         depth := stk.find(string(ref))
867         if depth < 0 {
868                 return stk, fmt.Errorf("undefined reference: \"%s\"", ref)
869         }
870
871         var isFinal bool
872         if count, ok := counts[string(ref)]; ok && count > 0 {
873                 count--
874                 counts[string(ref)] = count
875                 isFinal = count == 0
876         }
877
878         switch depth {
879         case 0:
880                 if !isFinal {
881                         stk = b.addDup(stk)
882                 }
883         case 1:
884                 if isFinal {
885                         stk = b.addSwap(stk)
886                 } else {
887                         stk = b.addOver(stk)
888                 }
889         default:
890                 if isFinal {
891                         stk = b.addRoll(stk, depth)
892                 } else {
893                         stk = b.addPick(stk, depth)
894                 }
895         }
896         return stk, nil
897 }
898
899 func (a *ContractArg) UnmarshalJSON(b []byte) error {
900         var m map[string]json.RawMessage
901         err := json.Unmarshal(b, &m)
902         if err != nil {
903                 return err
904         }
905         if r, ok := m["boolean"]; ok {
906                 var bval bool
907                 err = json.Unmarshal(r, &bval)
908                 if err != nil {
909                         return err
910                 }
911                 a.B = &bval
912                 return nil
913         }
914         if r, ok := m["integer"]; ok {
915                 var ival int64
916                 err = json.Unmarshal(r, &ival)
917                 if err != nil {
918                         return err
919                 }
920                 a.I = &ival
921                 return nil
922         }
923         r, ok := m["string"]
924         if !ok {
925                 return fmt.Errorf("contract arg must define one of boolean, integer, string")
926         }
927         var sval chainjson.HexBytes
928         err = json.Unmarshal(r, &sval)
929         if err != nil {
930                 return err
931         }
932         a.S = &sval
933         return nil
934 }