4 "github.com/vapor/protocol/vm"
5 "github.com/vapor/protocol/vm/vmutil"
8 // Signature programs constrain how the signed inputs of a transaction
9 // in a template may be used, especially if the transaction is not yet
12 // For example, suppose Alice wants to send Bob 80 EUR but only if Bob
13 // pays her 100 USD, and only if payment is made before next
14 // Tuesday. Alice constructs a partial transaction that includes her
15 // 80 EUR as one input, a payment to Bob as one output, _and_ a
16 // payment to Alice (of 100 USD) as one more output. She then
17 // constructs a program testing that the transaction includes all
18 // those components (and that the maxtime of the transaction is before
19 // next Tuesday) and signs a hash of that in order to unlock her 80
20 // EUR. She then passes the partial transaction template to Bob, who
21 // supplies his 100 USD input. Because of the signature program, Bob
22 // (or an eavesdropper) cannot use the signed 80-EUR input in any
23 // transaction other than one that pays 100 USD to Alice before
26 // This works because of Chain's convention for formatting of account
27 // control programs. The 80 EUR prevout being spent by Alice was paid
29 // DUP TOALTSTACK SHA3 <pubkey1> <pubkey2> ... <pubkeyN> <quorum> <N> CHECKMULTISIG VERIFY FROMALTSTACK 0 CHECKPREDICATE
30 // which means that any attempt to spend it must be accompanied by a
31 // signed program that evaluates to true. The default program (for a
32 // complete transaction to which no other entries may be added) is
33 // <txsighash> TXSIGHASH EQUAL
34 // which commits to the transaction as-is.
36 func buildSigProgram(tpl *Template, index uint32) ([]byte, error) {
37 if !tpl.AllowAdditional {
39 builder := vmutil.NewBuilder()
40 builder.AddData(h.Bytes())
41 builder.AddOp(vm.OP_TXSIGHASH).AddOp(vm.OP_EQUAL)
43 return builder.Build()
45 constraints := make([]constraint, 0, 3+len(tpl.Transaction.Outputs))
46 id := tpl.Transaction.Tx.InputIDs[index]
47 if sp, err := tpl.Transaction.Tx.Spend(id); err == nil {
48 constraints = append(constraints, outputIDConstraint(*sp.SpentOutputId))
51 for i, out := range tpl.Transaction.Outputs {
54 AssetAmount: out.AssetAmount,
55 Program: out.ControlProgram,
57 constraints = append(constraints, c)
60 for i, c := range constraints {
61 program = append(program, c.code()...)
62 if i < len(constraints)-1 { // leave the final bool on top of the stack
63 program = append(program, byte(vm.OP_VERIFY))