OSDN Git Service

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