OSDN Git Service

8c83936c9d7fc3c676c315d2bb6a827b556938d0
[bytom/vapor.git] / blockchain / txbuilder / actions.go
1 package txbuilder
2
3 import (
4         "context"
5         stdjson "encoding/json"
6         "errors"
7
8         "github.com/vapor/config"
9
10         "github.com/vapor/common"
11         "github.com/vapor/consensus"
12         "github.com/vapor/encoding/json"
13         "github.com/vapor/protocol/bc"
14         "github.com/vapor/protocol/bc/types"
15         "github.com/vapor/protocol/vm/vmutil"
16 )
17
18 // DecodeControlAddressAction convert input data to action struct
19 func DecodeControlAddressAction(data []byte) (Action, error) {
20         a := new(controlAddressAction)
21         err := stdjson.Unmarshal(data, a)
22         return a, err
23 }
24
25 type controlAddressAction struct {
26         bc.AssetAmount
27         Address string `json:"address"`
28 }
29
30 func (a *controlAddressAction) Build(ctx context.Context, b *TemplateBuilder) error {
31         var missing []string
32         if a.Address == "" {
33                 missing = append(missing, "address")
34         }
35         if a.AssetId.IsZero() {
36                 missing = append(missing, "asset_id")
37         }
38         if a.Amount == 0 {
39                 missing = append(missing, "amount")
40         }
41         if len(missing) > 0 {
42                 return MissingFieldsError(missing...)
43         }
44
45         address, err := common.DecodeAddress(a.Address, &consensus.ActiveNetParams)
46         if err != nil {
47                 return err
48         }
49
50         redeemContract := address.ScriptAddress()
51         program := []byte{}
52         switch address.(type) {
53         case *common.AddressWitnessPubKeyHash:
54                 program, err = vmutil.P2WPKHProgram(redeemContract)
55         case *common.AddressWitnessScriptHash:
56                 program, err = vmutil.P2WSHProgram(redeemContract)
57         default:
58                 return errors.New("unsupport address type")
59         }
60         if err != nil {
61                 return err
62         }
63
64         out := types.NewIntraChainOutput(*a.AssetId, a.Amount, program)
65         return b.AddOutput(out)
66 }
67
68 func (a *controlAddressAction) ActionType() string {
69         return "control_address"
70 }
71
72 // DecodeControlProgramAction convert input data to action struct
73 func DecodeControlProgramAction(data []byte) (Action, error) {
74         a := new(controlProgramAction)
75         err := stdjson.Unmarshal(data, a)
76         return a, err
77 }
78
79 type controlProgramAction struct {
80         bc.AssetAmount
81         Program json.HexBytes `json:"control_program"`
82 }
83
84 func (a *controlProgramAction) Build(ctx context.Context, b *TemplateBuilder) error {
85         var missing []string
86         if len(a.Program) == 0 {
87                 missing = append(missing, "control_program")
88         }
89         if a.AssetId.IsZero() {
90                 missing = append(missing, "asset_id")
91         }
92         if a.Amount == 0 {
93                 missing = append(missing, "amount")
94         }
95         if len(missing) > 0 {
96                 return MissingFieldsError(missing...)
97         }
98
99         out := types.NewIntraChainOutput(*a.AssetId, a.Amount, a.Program)
100         return b.AddOutput(out)
101 }
102
103 func (a *controlProgramAction) ActionType() string {
104         return "control_program"
105 }
106
107 // DecodeRetireAction convert input data to action struct
108 func DecodeRetireAction(data []byte) (Action, error) {
109         a := new(retireAction)
110         err := stdjson.Unmarshal(data, a)
111         return a, err
112 }
113
114 type retireAction struct {
115         bc.AssetAmount
116         Arbitrary json.HexBytes `json:"arbitrary"`
117 }
118
119 func (a *retireAction) Build(ctx context.Context, b *TemplateBuilder) error {
120         var missing []string
121         if a.AssetId.IsZero() {
122                 missing = append(missing, "asset_id")
123         }
124         if a.Amount == 0 {
125                 missing = append(missing, "amount")
126         }
127         if len(missing) > 0 {
128                 return MissingFieldsError(missing...)
129         }
130
131         program, err := vmutil.RetireProgram(a.Arbitrary)
132         if err != nil {
133                 return err
134         }
135         out := types.NewIntraChainOutput(*a.AssetId, a.Amount, program)
136         return b.AddOutput(out)
137 }
138
139 func (a *retireAction) ActionType() string {
140         return "retire"
141 }
142
143 // DecodeCrossOutAction convert input data to action struct
144 func DecodeCrossOutAction(data []byte) (Action, error) {
145         a := new(crossOutAction)
146         err := stdjson.Unmarshal(data, a)
147         return a, err
148 }
149
150 type crossOutAction struct {
151         bc.AssetAmount
152         Address string `json:"address"`
153 }
154
155 func (a *crossOutAction) Build(ctx context.Context, b *TemplateBuilder) error {
156         var missing []string
157         if a.Address == "" {
158                 missing = append(missing, "address")
159         }
160         if a.AssetId.IsZero() {
161                 missing = append(missing, "asset_id")
162         }
163         if a.Amount == 0 {
164                 missing = append(missing, "amount")
165         }
166         if len(missing) > 0 {
167                 return MissingFieldsError(missing...)
168         }
169
170         address, err := common.DecodeAddress(a.Address, &consensus.MainNetParams)
171         if err != nil {
172                 return err
173         }
174
175         redeemContract := address.ScriptAddress()
176         program := []byte{}
177         switch address.(type) {
178         case *common.AddressWitnessPubKeyHash:
179                 program, err = vmutil.P2WPKHProgram(redeemContract)
180         case *common.AddressWitnessScriptHash:
181                 program, err = vmutil.P2WSHProgram(redeemContract)
182         default:
183                 return errors.New("unsupport address type")
184         }
185         if err != nil {
186                 return err
187         }
188
189         out := types.NewCrossChainOutput(*a.AssetId, a.Amount, program)
190         return b.AddOutput(out)
191 }
192
193 func (a *crossOutAction) ActionType() string {
194         return "cross_chain_out"
195 }
196
197 // DecodeVoteOutputAction convert input data to action struct
198 func DecodeVoteOutputAction(data []byte) (Action, error) {
199         a := new(voteOutputAction)
200         err := stdjson.Unmarshal(data, a)
201         return a, err
202 }
203
204 type voteOutputAction struct {
205         bc.AssetAmount
206         Address string        `json:"address"`
207         Vote    json.HexBytes `json:"vote"`
208 }
209
210 func (a *voteOutputAction) Build(ctx context.Context, b *TemplateBuilder) error {
211         var missing []string
212         if a.Address == "" {
213                 missing = append(missing, "address")
214         }
215         if a.AssetId.IsZero() {
216                 missing = append(missing, "asset_id")
217         }
218         if a.Amount == 0 {
219                 missing = append(missing, "amount")
220         }
221         if len(a.Vote) == 0 {
222                 missing = append(missing, "vote")
223         }
224         if len(missing) > 0 {
225                 return MissingFieldsError(missing...)
226         }
227
228         address, err := common.DecodeAddress(a.Address, &consensus.ActiveNetParams)
229         if err != nil {
230                 return err
231         }
232
233         redeemContract := address.ScriptAddress()
234         program := []byte{}
235         switch address.(type) {
236         case *common.AddressWitnessPubKeyHash:
237                 program, err = vmutil.P2WPKHProgram(redeemContract)
238         case *common.AddressWitnessScriptHash:
239                 program, err = vmutil.P2WSHProgram(redeemContract)
240         default:
241                 return errors.New("unsupport address type")
242         }
243         if err != nil {
244                 return err
245         }
246
247         out := types.NewVoteOutput(*a.AssetId, a.Amount, program, a.Vote)
248         return b.AddOutput(out)
249 }
250
251 func (a *voteOutputAction) ActionType() string {
252         return "vote_output"
253 }
254
255 // DecodeCrossInAction convert input data to action struct
256 func DecodeCrossInAction(data []byte) (Action, error) {
257         a := new(crossInAction)
258         err := stdjson.Unmarshal(data, a)
259         return a, err
260 }
261
262 type crossInAction struct {
263         bc.AssetAmount
264         SourceID  bc.Hash `json:"source_id"`
265         SourcePos uint64  `json:"source_pos"`
266         bc.CrossChainAssetDefinition
267 }
268
269 func (a *crossInAction) Build(ctx context.Context, builder *TemplateBuilder) error {
270         var missing []string
271         if a.SourceID.IsZero() {
272                 missing = append(missing, "source_id")
273         }
274         if a.AssetId.IsZero() {
275                 missing = append(missing, "asset_id")
276         }
277         if a.Amount == 0 {
278                 missing = append(missing, "amount")
279         }
280         if len(missing) > 0 {
281                 return MissingFieldsError(missing...)
282         }
283
284         if err := a.checkAssetID(); err != nil {
285                 return err
286         }
287
288         // arguments will be set when materializeWitnesses
289         fedProg := config.FederationProgrom(config.CommonConfig)
290         txin := types.NewCrossChainInput(nil, a.SourceID, *a.AssetId, a.Amount, a.SourcePos, fedProg, a.CrossChainAssetDefinition)
291         tplIn := &SigningInstruction{}
292         fed := config.CommonConfig.Federation
293         tplIn.AddRawWitnessKeys(fed.Xpubs, nil, fed.Quorum)
294         return builder.AddInput(txin, tplIn)
295 }
296
297 func (a *crossInAction) ActionType() string {
298         return "cross_chain_in"
299 }
300
301 func (c *crossInAction) checkAssetID() error {
302         if *c.AssetId == *consensus.BTMAssetID {
303                 return nil
304         }
305
306         assetID := c.CrossChainAssetDefinition.ComputeAssetID()
307
308         if assetID != *c.AssetAmount.AssetId {
309                 return errors.New("incorrect asset_idincorrect asset_id")
310         }
311
312         return nil
313 }