github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/equity/compiler/compile.go (about) 1 package compiler 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "io/ioutil" 8 9 chainjson "github.com/bytom/bytom/encoding/json" 10 "github.com/bytom/bytom/errors" 11 "github.com/bytom/bytom/protocol/vm" 12 "github.com/bytom/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 = typeCheckClause(contract, clause, env) 346 if err != nil { 347 return err 348 } 349 err = requireAllParamsUsedInClause(clause.Params, clause) 350 if err != nil { 351 return err 352 } 353 354 return nil 355 } 356 357 func compileStatement(b *builder, stk stack, contract *Contract, env *environ, clause *Clause, counts map[string]int, stat statement, sequence *int) (stack, error) { 358 var err error 359 switch stmt := stat.(type) { 360 case *ifStatement: 361 // sequence add 1 when the statement is ifStatement 362 *sequence++ 363 strSequence := fmt.Sprintf("%d", *sequence) 364 365 // compile condition expression 366 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.condition) 367 if err != nil { 368 return stk, errors.Wrapf(err, "in check condition of ifStatement in clause \"%s\"", clause.Name) 369 } 370 371 // jump to falseBody when condition is false, while the JUMPIF instruction will be run success when 372 // the value of dataStack is true, therefore add this negation 373 conditionExpr := stk.str 374 stk = b.addNot(stk, fmt.Sprintf("!%s", conditionExpr)) 375 376 // add nop instruction to differ with clause selector for JUMPIF instruction 377 stk = b.addNop(stk) 378 379 // add label 380 var label string 381 if len(stmt.body.falseBody) != 0 { 382 label = "else_" + strSequence 383 } else { 384 label = "endif_" + strSequence 385 } 386 stk = b.addJumpIf(stk, label) 387 b.addJumpTarget(stk, "if_"+strSequence) 388 389 // temporary store stack and counts for falseBody 390 condStk := stk 391 elseCounts := make(map[string]int) 392 for k, v := range counts { 393 elseCounts[k] = v 394 } 395 396 // compile trueBody statements 397 if len(stmt.body.trueBody) != 0 { 398 for _, st := range stmt.body.trueBody { 399 st.countVarRefs(counts) 400 } 401 402 for _, st := range stmt.body.trueBody { 403 if stk, err = compileStatement(b, stk, contract, env, clause, counts, st, sequence); err != nil { 404 return stk, err 405 } 406 } 407 } 408 409 // compile falseBody statements 410 if len(stmt.body.falseBody) != 0 { 411 counts := make(map[string]int) 412 for k, v := range elseCounts { 413 counts[k] = v 414 } 415 416 for _, st := range stmt.body.falseBody { 417 st.countVarRefs(counts) 418 } 419 420 stk = condStk 421 b.addJump(stk, "endif_"+strSequence) 422 b.addJumpTarget(stk, "else_"+strSequence) 423 424 for _, st := range stmt.body.falseBody { 425 if stk, err = compileStatement(b, stk, contract, env, clause, counts, st, sequence); err != nil { 426 return stk, err 427 } 428 } 429 } 430 b.addJumpTarget(stk, "endif_"+strSequence) 431 432 case *defineStatement: 433 // add environ for define variable 434 if err = env.add(stmt.variable.Name, stmt.variable.Type, roleClauseVariable); err != nil { 435 return stk, err 436 } 437 438 // check whether the variable is used or not 439 if counts[stmt.variable.Name] == 0 { 440 return stk, fmt.Errorf("the defined variable \"%s\" is unused in clause \"%s\"", stmt.variable.Name, clause.Name) 441 } 442 443 if stmt.expr != nil { 444 // variable 445 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.expr) 446 if err != nil { 447 return stk, errors.Wrapf(err, "in define statement in clause \"%s\"", clause.Name) 448 } 449 450 // modify stack name 451 stk.str = stmt.variable.Name 452 } 453 454 case *assignStatement: 455 // find variable from environ with roleClauseVariable 456 if entry := env.lookup(string(stmt.variable.Name)); entry != nil { 457 if entry.r != roleClauseVariable { 458 return stk, fmt.Errorf("the type of variable is not roleClauseVariable in assign statement in clause \"%s\"", clause.Name) 459 } 460 stmt.variable.Type = entry.t 461 } else { 462 return stk, fmt.Errorf("the variable \"%s\" is not defined before the assign statement in clause \"%s\"", stmt.variable.Name, clause.Name) 463 } 464 465 // temporary store the counts of defined variable 466 varCount := counts[stmt.variable.Name] 467 468 // calculate the counts of variable for assign statement 469 tmpCounts := make(map[string]int) 470 stmt.countVarRefs(tmpCounts) 471 472 // modify the map counts of defined variable to 1 and minus the number of defined variable 473 // when the assign expression contains the defined variable 474 if tmpCounts[stmt.variable.Name] > 0 { 475 counts[stmt.variable.Name] = 1 476 varCount -= tmpCounts[stmt.variable.Name] 477 } else { 478 depth := stk.find(stmt.variable.Name) 479 switch depth { 480 case 0: 481 break 482 case 1: 483 stk = b.addSwap(stk) 484 default: 485 stk = b.addRoll(stk, depth) 486 } 487 stk = b.addDrop(stk) 488 } 489 490 // variable 491 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.expr) 492 if err != nil { 493 return stk, errors.Wrapf(err, "in define statement in clause \"%s\"", clause.Name) 494 } 495 496 // restore the defined variable counts 497 if tmpCounts[stmt.variable.Name] > 0 { 498 counts[stmt.variable.Name] = varCount 499 } 500 501 // modify stack name 502 stk.str = stmt.variable.Name 503 504 case *verifyStatement: 505 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.expr) 506 if err != nil { 507 return stk, errors.Wrapf(err, "in verify statement in clause \"%s\"", clause.Name) 508 } 509 stk = b.addVerify(stk) 510 511 // special-case reporting of certain function calls 512 if c, ok := stmt.expr.(*callExpr); ok && len(c.args) == 1 { 513 if b := referencedBuiltin(c.fn); b != nil { 514 switch b.name { 515 case "below": 516 clause.BlockHeight = append(clause.BlockHeight, c.args[0].String()) 517 case "above": 518 clause.BlockHeight = append(clause.BlockHeight, c.args[0].String()) 519 } 520 } 521 } 522 523 case *lockStatement: 524 // index 525 stk = b.addInt64(stk, stmt.index) 526 527 // TODO: permit more complex expressions for locked, 528 // like "lock x+y with foo" (?) 529 530 if stmt.lockedAmount.String() == contract.Value.Amount && stmt.lockedAsset.String() == contract.Value.Asset { 531 stk = b.addAmount(stk, contract.Value.Amount) 532 stk = b.addAsset(stk, contract.Value.Asset) 533 } else { 534 // calculate the counts of variable for lockStatement 535 lockCounts := make(map[string]int) 536 stmt.countVarRefs(lockCounts) 537 538 // amount 539 switch { 540 case stmt.lockedAmount.String() == contract.Value.Amount: 541 stk = b.addAmount(stk, contract.Value.Amount) 542 case stmt.lockedAmount.String() != contract.Value.Amount && lockCounts[contract.Value.Amount] > 0: 543 counts[contract.Value.Amount] = lockCounts[contract.Value.Amount] 544 stk = b.addAmount(stk, contract.Value.Amount) 545 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAmount) 546 if err != nil { 547 return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name) 548 } 549 default: 550 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAmount) 551 if err != nil { 552 return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name) 553 } 554 } 555 556 // asset 557 switch { 558 case stmt.lockedAsset.String() == contract.Value.Asset: 559 stk = b.addAsset(stk, contract.Value.Asset) 560 case stmt.lockedAsset.String() != contract.Value.Asset && lockCounts[contract.Value.Asset] > 0: 561 counts[contract.Value.Asset] = lockCounts[contract.Value.Asset] 562 stk = b.addAsset(stk, contract.Value.Asset) 563 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAsset) 564 if err != nil { 565 return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name) 566 } 567 default: 568 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAsset) 569 if err != nil { 570 return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name) 571 } 572 } 573 } 574 575 // version 576 stk = b.addInt64(stk, 1) 577 578 // prog 579 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.program) 580 if err != nil { 581 return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name) 582 } 583 584 stk = b.addCheckOutput(stk, fmt.Sprintf("checkOutput(%s, %s, %s)", 585 stmt.lockedAmount.String(), stmt.lockedAsset.String(), stmt.program)) 586 stk = b.addVerify(stk) 587 588 case *unlockStatement: 589 if len(clause.statements) == 1 { 590 // This is the only statement in the clause, make sure TRUE is 591 // on the stack. 592 stk = b.addBoolean(stk, true) 593 } 594 } 595 596 return stk, nil 597 } 598 599 func compileExpr(b *builder, stk stack, contract *Contract, clause *Clause, env *environ, counts map[string]int, expr expression) (stack, error) { 600 var err error 601 602 switch e := expr.(type) { 603 case *binaryExpr: 604 // Do typechecking after compiling subexpressions (because other 605 // compilation errors are more interesting than type mismatch 606 // errors). 607 608 stk, err = compileExpr(b, stk, contract, clause, env, counts, e.left) 609 if err != nil { 610 return stk, errors.Wrapf(err, "in left operand of \"%s\" expression", e.op.op) 611 } 612 stk, err = compileExpr(b, stk, contract, clause, env, counts, e.right) 613 if err != nil { 614 return stk, errors.Wrapf(err, "in right operand of \"%s\" expression", e.op.op) 615 } 616 617 lType := e.left.typ(env) 618 if e.op.left != "" && ((e.op.left == intType && !(lType == amountType || lType == intType)) || 619 (e.op.left == boolType && !(lType == boolType))) { 620 return stk, fmt.Errorf("in \"%s\", left operand has type \"%s\", must be \"%s\"", e, lType, e.op.left) 621 } 622 623 rType := e.right.typ(env) 624 if e.op.right != "" && ((e.op.right == intType && !(rType == amountType || rType == intType)) || 625 (e.op.right == boolType && !(rType == boolType))) { 626 return stk, fmt.Errorf("in \"%s\", right operand has type \"%s\", must be \"%s\"", e, rType, e.op.right) 627 } 628 629 switch e.op.op { 630 case "==", "!=": 631 if lType != rType { 632 // Maybe one is Hash and the other is (more-specific-Hash subtype). 633 // TODO(bobg): generalize this mechanism 634 if lType == hashType && isHashSubtype(rType) { 635 propagateType(contract, clause, env, rType, e.left) 636 } else if rType == hashType && isHashSubtype(lType) { 637 propagateType(contract, clause, env, lType, e.right) 638 } else { 639 return stk, fmt.Errorf("type mismatch in \"%s\": left operand has type \"%s\", right operand has type \"%s\"", e, lType, rType) 640 } 641 } 642 if lType == "Boolean" { 643 return stk, fmt.Errorf("in \"%s\": using \"%s\" on Boolean values not allowed", e, e.op.op) 644 } 645 } 646 647 stk = b.addOps(stk.dropN(2), e.op.opcodes, e.String()) 648 649 case *unaryExpr: 650 // Do typechecking after compiling subexpression (because other 651 // compilation errors are more interesting than type mismatch 652 // errors). 653 654 var err error 655 stk, err = compileExpr(b, stk, contract, clause, env, counts, e.expr) 656 if err != nil { 657 return stk, errors.Wrapf(err, "in \"%s\" expression", e.op.op) 658 } 659 660 if e.op.operand != "" && e.expr.typ(env) != e.op.operand { 661 return stk, fmt.Errorf("in \"%s\", operand has type \"%s\", must be \"%s\"", e, e.expr.typ(env), e.op.operand) 662 } 663 b.addOps(stk.drop(), e.op.opcodes, e.String()) 664 665 case *callExpr: 666 bi := referencedBuiltin(e.fn) 667 if bi == nil { 668 if v, ok := e.fn.(varRef); ok { 669 if entry := env.lookup(string(v)); entry != nil && entry.t == contractType { 670 clause.Contracts = append(clause.Contracts, entry.c.Name) 671 672 partialName := fmt.Sprintf("%s(...)", v) 673 stk = b.addData(stk, nil) 674 675 if len(e.args) != len(entry.c.Params) { 676 return stk, fmt.Errorf("contract \"%s\" expects %d argument(s), got %d", entry.c.Name, len(entry.c.Params), len(e.args)) 677 } 678 679 for i := len(e.args) - 1; i >= 0; i-- { 680 arg := e.args[i] 681 if entry.c.Params[i].Type != "" && arg.typ(env) != entry.c.Params[i].Type && 682 !(arg.typ(env) == intType && entry.c.Params[i].Type == amountType) { 683 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) 684 } 685 stk, err = compileExpr(b, stk, contract, clause, env, counts, arg) 686 if err != nil { 687 return stk, err 688 } 689 stk = b.addCatPushdata(stk, partialName) 690 } 691 692 switch { 693 case entry.c == contract: 694 // Recursive call - cannot use entry.c.Body 695 // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE 696 stk, err = compileRef(b, stk, counts, varRef(contract.Name)) 697 if err != nil { 698 return stk, errors.Wrap(err, "compiling contract call") 699 } 700 stk = b.addCatPushdata(stk, partialName) 701 stk = b.addData(stk, []byte{byte(vm.OP_DEPTH), byte(vm.OP_OVER)}) 702 stk = b.addCat(stk, partialName) 703 704 case entry.c.Recursive: 705 // Non-recursive call to a (different) recursive contract 706 // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE 707 if len(entry.c.Body) == 0 { 708 // TODO(bobg): sort input contracts topologically to permit forward calling 709 return stk, fmt.Errorf("contract \"%s\" not defined", entry.c.Name) 710 } 711 stk = b.addData(stk, entry.c.Body) 712 stk = b.addCatPushdata(stk, partialName) 713 stk = b.addData(stk, []byte{byte(vm.OP_DEPTH), byte(vm.OP_OVER)}) 714 stk = b.addCat(stk, partialName) 715 716 default: 717 // Non-recursive call to non-recursive contract 718 // <argN> <argN-1> ... <arg1> DEPTH <body> 0 CHECKPREDICATE 719 stk = b.addData(stk, []byte{byte(vm.OP_DEPTH)}) 720 stk = b.addCat(stk, partialName) 721 if len(entry.c.Body) == 0 { 722 // TODO(bobg): sort input contracts topologically to permit forward calling 723 return stk, fmt.Errorf("contract \"%s\" not defined", entry.c.Name) 724 } 725 stk = b.addData(stk, entry.c.Body) 726 stk = b.addCatPushdata(stk, partialName) 727 } 728 stk = b.addData(stk, vm.Int64Bytes(0)) 729 stk = b.addCatPushdata(stk, partialName) 730 stk = b.addData(stk, []byte{byte(vm.OP_CHECKPREDICATE)}) 731 stk = b.addCat(stk, e.String()) 732 733 return stk, nil 734 } 735 } 736 return stk, fmt.Errorf("unknown function \"%s\"", e.fn) 737 } 738 739 if len(e.args) != len(bi.args) { 740 return stk, fmt.Errorf("wrong number of args for \"%s\": have %d, want %d", bi.name, len(e.args), len(bi.args)) 741 } 742 743 // WARNING WARNING WOOP WOOP 744 // special-case hack 745 // WARNING WARNING WOOP WOOP 746 if bi.name == "checkTxMultiSig" { 747 if _, ok := e.args[0].(listExpr); !ok { 748 return stk, fmt.Errorf("checkTxMultiSig expects list literals, got %T for argument 0", e.args[0]) 749 } 750 if _, ok := e.args[1].(listExpr); !ok { 751 return stk, fmt.Errorf("checkTxMultiSig expects list literals, got %T for argument 1", e.args[1]) 752 } 753 754 var k1, k2 int 755 756 stk, k1, err = compileArg(b, stk, contract, clause, env, counts, e.args[1]) 757 if err != nil { 758 return stk, err 759 } 760 761 // stack: [... sigM ... sig1 M] 762 763 var altEntry string 764 stk, altEntry = b.addToAltStack(stk) // stack: [... sigM ... sig1] 765 stk = b.addTxSigHash(stk) // stack: [... sigM ... sig1 txsighash] 766 767 stk, k2, err = compileArg(b, stk, contract, clause, env, counts, e.args[0]) 768 if err != nil { 769 return stk, err 770 } 771 772 // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 N] 773 774 stk = b.addFromAltStack(stk, altEntry) // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 N M] 775 stk = b.addSwap(stk) // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 M N] 776 stk = b.addCheckMultisig(stk, k1+k2, e.String()) 777 778 return stk, nil 779 } 780 781 var k int 782 783 for i := len(e.args) - 1; i >= 0; i-- { 784 a := e.args[i] 785 var k2 int 786 var err error 787 stk, k2, err = compileArg(b, stk, contract, clause, env, counts, a) 788 if err != nil { 789 return stk, errors.Wrapf(err, "compiling argument %d in call expression", i) 790 } 791 k += k2 792 } 793 794 // Do typechecking after compiling subexpressions (because other 795 // compilation errors are more interesting than type mismatch 796 // errors). 797 for i, actual := range e.args { 798 if bi.args[i] != "" && actual.typ(env) != bi.args[i] { 799 return stk, fmt.Errorf("argument %d to \"%s\" has type \"%s\", must be \"%s\"", i, bi.name, actual.typ(env), bi.args[i]) 800 } 801 } 802 803 stk = b.addOps(stk.dropN(k), bi.opcodes, e.String()) 804 805 // special-case reporting 806 switch bi.name { 807 case "sha3", "sha256": 808 clause.HashCalls = append(clause.HashCalls, HashCall{bi.name, e.args[0].String(), string(e.args[0].typ(env))}) 809 } 810 811 case varRef: 812 return compileRef(b, stk, counts, e) 813 814 case integerLiteral: 815 stk = b.addInt64(stk, int64(e)) 816 817 case bytesLiteral: 818 stk = b.addData(stk, []byte(e)) 819 820 case booleanLiteral: 821 stk = b.addBoolean(stk, bool(e)) 822 823 case listExpr: 824 // Lists are excluded here because they disobey the invariant of 825 // this function: namely, that it increases the stack size by 826 // exactly one. (A list pushes its items and its length on the 827 // stack.) But they're OK as function-call arguments because the 828 // function (presumably) consumes all the stack items added. 829 return stk, fmt.Errorf("encountered list outside of function-call context") 830 } 831 return stk, nil 832 } 833 834 func compileArg(b *builder, stk stack, contract *Contract, clause *Clause, env *environ, counts map[string]int, expr expression) (stack, int, error) { 835 var n int 836 if list, ok := expr.(listExpr); ok { 837 for i := 0; i < len(list); i++ { 838 elt := list[len(list)-i-1] 839 var err error 840 stk, err = compileExpr(b, stk, contract, clause, env, counts, elt) 841 if err != nil { 842 return stk, 0, err 843 } 844 n++ 845 } 846 stk = b.addInt64(stk, int64(len(list))) 847 n++ 848 return stk, n, nil 849 } 850 var err error 851 stk, err = compileExpr(b, stk, contract, clause, env, counts, expr) 852 return stk, 1, err 853 } 854 855 func compileRef(b *builder, stk stack, counts map[string]int, ref varRef) (stack, error) { 856 depth := stk.find(string(ref)) 857 if depth < 0 { 858 return stk, fmt.Errorf("undefined reference: \"%s\"", ref) 859 } 860 861 var isFinal bool 862 if count, ok := counts[string(ref)]; ok && count > 0 { 863 count-- 864 counts[string(ref)] = count 865 isFinal = count == 0 866 } 867 868 switch depth { 869 case 0: 870 if !isFinal { 871 stk = b.addDup(stk) 872 } 873 case 1: 874 if isFinal { 875 stk = b.addSwap(stk) 876 } else { 877 stk = b.addOver(stk) 878 } 879 default: 880 if isFinal { 881 stk = b.addRoll(stk, depth) 882 } else { 883 stk = b.addPick(stk, depth) 884 } 885 } 886 return stk, nil 887 } 888 889 func (a *ContractArg) UnmarshalJSON(b []byte) error { 890 var m map[string]json.RawMessage 891 err := json.Unmarshal(b, &m) 892 if err != nil { 893 return err 894 } 895 if r, ok := m["boolean"]; ok { 896 var bval bool 897 err = json.Unmarshal(r, &bval) 898 if err != nil { 899 return err 900 } 901 a.B = &bval 902 return nil 903 } 904 if r, ok := m["integer"]; ok { 905 var ival int64 906 err = json.Unmarshal(r, &ival) 907 if err != nil { 908 return err 909 } 910 a.I = &ival 911 return nil 912 } 913 r, ok := m["string"] 914 if !ok { 915 return fmt.Errorf("contract arg must define one of boolean, integer, string") 916 } 917 var sval chainjson.HexBytes 918 err = json.Unmarshal(r, &sval) 919 if err != nil { 920 return err 921 } 922 a.S = &sval 923 return nil 924 }