OSDN Git Service

fix bug and add address for contract
[bytom/vapor.git] / equity / pegin_contract / pegin_contract.go
1 package pegin_contract
2
3 import (
4         "crypto/hmac"
5         "crypto/sha256"
6         "errors"
7         "fmt"
8         "strings"
9
10         "github.com/vapor/consensus"
11         "github.com/vapor/crypto/ed25519"
12         "github.com/vapor/crypto/ed25519/chainkd"
13         chainjson "github.com/vapor/encoding/json"
14         "github.com/vapor/equity/compiler"
15 )
16
17 var lockWith2of3KeysFmt = `
18 contract LockWith2of3Keys(%s) locks amount of asset {
19   clause unlockWith2Sigs(%s) {
20     verify checkTxMultiSig(%s)
21     unlock amount of asset
22   }
23 }
24 `
25
26 func GetPeginContractPrograms(claimScript []byte) ([]byte, error) {
27
28         pubkeys := getNewXpub(consensus.ActiveNetParams.FedpegXPubs, claimScript)
29         num := len(pubkeys)
30         if num == 0 {
31                 return nil, errors.New("Fedpeg's XPubs is empty")
32         }
33         params := ""
34         unlockParams := ""
35         checkParams := "["
36
37         for index := 0; index < num; index++ {
38                 param := fmt.Sprintf("pubkey%d", index+1)
39                 params += param
40                 checkParams += param
41                 if (index + 1) < num {
42                         params += ","
43                         checkParams += ","
44                 }
45         }
46         params += ": PublicKey"
47         checkParams += "],["
48
49         signNum := getNumberOfSignaturesRequired(pubkeys)
50         for index := 0; index < signNum; index++ {
51                 param := fmt.Sprintf("sig%d", index+1)
52                 unlockParams += param
53                 checkParams += param
54                 if index+1 < signNum {
55                         unlockParams += ","
56                         checkParams += ","
57                 }
58         }
59
60         unlockParams += ": Signature"
61         checkParams += "]"
62
63         lockWith2of3Keys := fmt.Sprintf(lockWith2of3KeysFmt, params, unlockParams, checkParams)
64         r := strings.NewReader(lockWith2of3Keys)
65         compiled, err := compiler.Compile(r)
66         if err != nil {
67                 return nil, errors.New("Compile contract failed")
68         }
69
70         contract := compiled[len(compiled)-1]
71
72         if num < len(contract.Params) {
73                 return nil, errors.New("Compile contract failed")
74         }
75
76         contractArgs, err := convertArguments(contract, pubkeys)
77         if err != nil {
78                 fmt.Println("Convert arguments into contract parameters error:", err)
79                 return nil, errors.New("Convert arguments into contract parameters error")
80         }
81
82         instantProg, err := instantiateContract(contract, contractArgs)
83         if err != nil {
84                 fmt.Println("Instantiate contract error:", err)
85                 return nil, errors.New("Instantiate contract error")
86         }
87
88         return instantProg, nil
89 }
90
91 func getNewXpub(federationRedeemXPub []chainkd.XPub, claimScript []byte) []ed25519.PublicKey {
92
93         var pubkeys []ed25519.PublicKey
94         for _, xpub := range federationRedeemXPub {
95                 // pub + scriptPubKey 生成一个随机数A
96                 var tmp [32]byte
97                 h := hmac.New(sha256.New, xpub[:])
98                 h.Write(claimScript)
99                 tweak := h.Sum(tmp[:])
100                 // pub +  A 生成一个新的公钥pub_new
101                 chaildXPub := xpub.Child(tweak)
102                 pubkeys = append(pubkeys, chaildXPub.PublicKey())
103         }
104         return pubkeys
105 }
106
107 func getNumberOfSignaturesRequired(pubkeys []ed25519.PublicKey) int {
108         return len(pubkeys)/2 + 1
109 }
110
111 // InstantiateContract instantiate contract parameters
112 func instantiateContract(contract *compiler.Contract, args []compiler.ContractArg) ([]byte, error) {
113         program, err := compiler.Instantiate(contract.Body, contract.Params, contract.Recursive, args)
114         if err != nil {
115                 return nil, err
116         }
117
118         return program, nil
119 }
120
121 func convertArguments(contract *compiler.Contract, args []ed25519.PublicKey) ([]compiler.ContractArg, error) {
122         var contractArgs []compiler.ContractArg
123         for i, p := range contract.Params {
124                 var argument compiler.ContractArg
125                 switch p.Type {
126                 case "PublicKey":
127                         argument.S = (*chainjson.HexBytes)(&args[i])
128                 default:
129                         return nil, errors.New("Contract parameter type error")
130                 }
131                 contractArgs = append(contractArgs, argument)
132         }
133
134         return contractArgs, nil
135 }