OSDN Git Service

888c9420ed45acb7d25a51a47e20d1ee98ef6093
[bytom/vapor.git] / protocol / bc / types / txinput.go
1 package types
2
3 import (
4         "fmt"
5         "io"
6
7         "github.com/vapor/encoding/blockchain"
8         "github.com/vapor/errors"
9         "github.com/vapor/protocol/bc"
10 )
11
12 // serflag variables for input types.
13 const (
14         CrossChainInputType uint8 = iota
15         SpendInputType
16         CoinbaseInputType
17         VetoInputType
18 )
19
20 type (
21         // TxInput is the top level struct of tx input.
22         TxInput struct {
23                 AssetVersion uint64
24                 TypedInput
25                 CommitmentSuffix []byte
26                 WitnessSuffix    []byte
27         }
28
29         // TypedInput return the txinput type.
30         TypedInput interface {
31                 InputType() uint8
32         }
33 )
34
35 var errBadAssetID = errors.New("asset ID does not match other issuance parameters")
36
37 // AssetAmount return the asset id and amount of the txinput.
38 func (t *TxInput) AssetAmount() bc.AssetAmount {
39         switch inp := t.TypedInput.(type) {
40         case *SpendInput:
41                 return inp.AssetAmount
42
43         case *CrossChainInput:
44                 return inp.AssetAmount
45
46         case *VetoInput:
47                 return inp.AssetAmount
48         }
49
50         return bc.AssetAmount{}
51 }
52
53 // AssetID return the assetID of the txinput
54 func (t *TxInput) AssetID() bc.AssetID {
55         switch inp := t.TypedInput.(type) {
56         case *SpendInput:
57                 return *inp.AssetId
58
59         case *CrossChainInput:
60                 return *inp.AssetAmount.AssetId
61
62         case *VetoInput:
63                 return *inp.AssetId
64
65         }
66         return bc.AssetID{}
67 }
68
69 // Amount return the asset amount of the txinput
70 func (t *TxInput) Amount() uint64 {
71         switch inp := t.TypedInput.(type) {
72         case *SpendInput:
73                 return inp.Amount
74
75         case *CrossChainInput:
76                 return inp.AssetAmount.Amount
77
78         case *VetoInput:
79                 return inp.Amount
80
81         }
82         return 0
83 }
84
85 // ControlProgram return the control program of the spend input
86 func (t *TxInput) ControlProgram() []byte {
87         switch inp := t.TypedInput.(type) {
88         case *SpendInput:
89                 return inp.ControlProgram
90
91         case *CrossChainInput:
92                 return inp.ControlProgram
93
94         case *VetoInput:
95                 return inp.ControlProgram
96
97         }
98
99         return nil
100 }
101
102 // Arguments get the args for the input
103 func (t *TxInput) Arguments() [][]byte {
104         switch inp := t.TypedInput.(type) {
105         case *SpendInput:
106                 return inp.Arguments
107
108         case *CrossChainInput:
109                 return inp.Arguments
110
111         case *VetoInput:
112                 return inp.Arguments
113         }
114         return nil
115 }
116
117 // SetArguments set the args for the input
118 func (t *TxInput) SetArguments(args [][]byte) {
119         switch inp := t.TypedInput.(type) {
120         case *SpendInput:
121                 inp.Arguments = args
122
123         case *CrossChainInput:
124                 inp.Arguments = args
125
126         case *VetoInput:
127                 inp.Arguments = args
128         }
129 }
130
131 // SpentOutputID calculate the hash of spended output
132 func (t *TxInput) SpentOutputID() (o bc.Hash, err error) {
133         switch inp := t.TypedInput.(type) {
134         case *SpendInput:
135                 o, err = ComputeOutputID(&inp.SpendCommitment, SpendInputType, nil)
136
137         case *VetoInput:
138                 o, err = ComputeOutputID(&inp.SpendCommitment, VetoInputType, inp.Vote)
139         }
140
141         return o, err
142 }
143
144 func (t *TxInput) readFrom(r *blockchain.Reader) (err error) {
145         if t.AssetVersion, err = blockchain.ReadVarint63(r); err != nil {
146                 return err
147         }
148
149         t.CommitmentSuffix, err = blockchain.ReadExtensibleString(r, func(r *blockchain.Reader) error {
150                 if t.AssetVersion != 1 {
151                         return nil
152                 }
153                 var icType [1]byte
154                 if _, err = io.ReadFull(r, icType[:]); err != nil {
155                         return errors.Wrap(err, "reading input commitment type")
156                 }
157
158                 switch icType[0] {
159                 case SpendInputType:
160                         si := new(SpendInput)
161                         t.TypedInput = si
162                         if si.SpendCommitmentSuffix, err = si.SpendCommitment.readFrom(r, 1); err != nil {
163                                 return err
164                         }
165
166                 case CoinbaseInputType:
167                         ci := new(CoinbaseInput)
168                         t.TypedInput = ci
169                         if ci.Arbitrary, err = blockchain.ReadVarstr31(r); err != nil {
170                                 return err
171                         }
172
173                 case CrossChainInputType:
174                         ci := new(CrossChainInput)
175                         t.TypedInput = ci
176                         if ci.SpendCommitmentSuffix, err = ci.SpendCommitment.readFrom(r, 1); err != nil {
177                                 return err
178                         }
179
180                 case VetoInputType:
181                         ui := new(VetoInput)
182                         t.TypedInput = ui
183                         if ui.VetoCommitmentSuffix, err = ui.SpendCommitment.readFrom(r, 1); err != nil {
184
185                                 return err
186                         }
187
188                 default:
189                         return fmt.Errorf("unsupported input type %d", icType[0])
190                 }
191                 return nil
192         })
193         if err != nil {
194                 return err
195         }
196
197         t.WitnessSuffix, err = blockchain.ReadExtensibleString(r, func(r *blockchain.Reader) error {
198                 if t.AssetVersion != 1 {
199                         return nil
200                 }
201
202                 switch inp := t.TypedInput.(type) {
203                 case *SpendInput:
204                         if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil {
205                                 return err
206                         }
207
208                 case *CrossChainInput:
209                         if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil {
210                                 return err
211                         }
212
213                         if inp.VMVersion, err = blockchain.ReadVarint63(r); err != nil {
214                                 return err
215                         }
216
217                         if inp.AssetDefinition, err = blockchain.ReadVarstr31(r); err != nil {
218                                 return err
219                         }
220
221                         if inp.IssuanceProgram, err = blockchain.ReadVarstr31(r); err != nil {
222                                 return err
223                         }
224
225                 case *VetoInput:
226                         if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil {
227                                 return err
228                         }
229                         if inp.Vote, err = blockchain.ReadVarstr31(r); err != nil {
230                                 return err
231                         }
232
233                 }
234                 return nil
235         })
236         if err != nil {
237                 return err
238         }
239
240         return nil
241 }
242
243 func (t *TxInput) writeTo(w io.Writer) error {
244         if _, err := blockchain.WriteVarint63(w, t.AssetVersion); err != nil {
245                 return errors.Wrap(err, "writing asset version")
246         }
247
248         if _, err := blockchain.WriteExtensibleString(w, t.CommitmentSuffix, t.writeInputCommitment); err != nil {
249                 return errors.Wrap(err, "writing input commitment")
250         }
251
252         if _, err := blockchain.WriteExtensibleString(w, t.WitnessSuffix, t.writeInputWitness); err != nil {
253                 return errors.Wrap(err, "writing input witness")
254         }
255
256         return nil
257 }
258
259 func (t *TxInput) writeInputCommitment(w io.Writer) (err error) {
260         if t.AssetVersion != 1 {
261                 return nil
262         }
263
264         switch inp := t.TypedInput.(type) {
265         case *SpendInput:
266                 if _, err = w.Write([]byte{SpendInputType}); err != nil {
267                         return err
268                 }
269                 return inp.SpendCommitment.writeExtensibleString(w, inp.SpendCommitmentSuffix, t.AssetVersion)
270
271         case *CrossChainInput:
272                 if _, err = w.Write([]byte{CrossChainInputType}); err != nil {
273                         return err
274                 }
275                 return inp.SpendCommitment.writeExtensibleString(w, inp.SpendCommitmentSuffix, t.AssetVersion)
276
277         case *CoinbaseInput:
278                 if _, err = w.Write([]byte{CoinbaseInputType}); err != nil {
279                         return err
280                 }
281                 if _, err = blockchain.WriteVarstr31(w, inp.Arbitrary); err != nil {
282                         return errors.Wrap(err, "writing coinbase arbitrary")
283                 }
284
285         case *VetoInput:
286                 if _, err = w.Write([]byte{VetoInputType}); err != nil {
287                         return err
288                 }
289                 return inp.SpendCommitment.writeExtensibleString(w, inp.VetoCommitmentSuffix, t.AssetVersion)
290         }
291         return nil
292 }
293
294 func (t *TxInput) writeInputWitness(w io.Writer) error {
295         if t.AssetVersion != 1 {
296                 return nil
297         }
298
299         switch inp := t.TypedInput.(type) {
300         case *SpendInput:
301                 _, err := blockchain.WriteVarstrList(w, inp.Arguments)
302                 return err
303
304         case *CrossChainInput:
305                 if _, err := blockchain.WriteVarstrList(w, inp.Arguments); err != nil {
306                         return err
307                 }
308
309                 if _, err := blockchain.WriteVarint63(w, inp.VMVersion); err != nil {
310                         return err
311                 }
312
313                 if _, err := blockchain.WriteVarstr31(w, inp.AssetDefinition); err != nil {
314                         return err
315                 }
316
317                 _, err := blockchain.WriteVarstr31(w, inp.IssuanceProgram)
318
319                 return err
320         case *VetoInput:
321                 if _, err := blockchain.WriteVarstrList(w, inp.Arguments); err != nil {
322                         return err
323                 }
324                 _, err := blockchain.WriteVarstr31(w, inp.Vote)
325                 return err
326         }
327         return nil
328 }