OSDN Git Service

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