OSDN Git Service

init for remove issue (#63)
[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         IssuanceInputType uint8 = iota
15         SpendInputType
16         CoinbaseInputType
17 )
18
19 type (
20         // TxInput is the top level struct of tx input.
21         TxInput struct {
22                 AssetVersion uint64
23                 TypedInput
24                 CommitmentSuffix []byte
25                 WitnessSuffix    []byte
26         }
27
28         // TypedInput return the txinput type.
29         TypedInput interface {
30                 InputType() uint8
31         }
32 )
33
34 var errBadAssetID = errors.New("asset ID does not match other issuance parameters")
35
36 // AssetAmount return the asset id and amount of the txinput.
37 func (t *TxInput) AssetAmount() bc.AssetAmount {
38         switch inp := t.TypedInput.(type) {
39         case *SpendInput:
40                 return inp.AssetAmount
41         }
42         return bc.AssetAmount{}
43 }
44
45 // AssetID return the assetID of the txinput
46 func (t *TxInput) AssetID() bc.AssetID {
47         switch inp := t.TypedInput.(type) {
48         case *SpendInput:
49                 return *inp.AssetId
50
51         }
52         return bc.AssetID{}
53 }
54
55 // Amount return the asset amount of the txinput
56 func (t *TxInput) Amount() uint64 {
57         switch inp := t.TypedInput.(type) {
58         case *SpendInput:
59                 return inp.Amount
60         }
61         return 0
62 }
63
64 // ControlProgram return the control program of the spend input
65 func (t *TxInput) ControlProgram() []byte {
66         if si, ok := t.TypedInput.(*SpendInput); ok {
67                 return si.ControlProgram
68         }
69         return nil
70 }
71
72 // Arguments get the args for the input
73 func (t *TxInput) Arguments() [][]byte {
74         switch inp := t.TypedInput.(type) {
75         case *SpendInput:
76                 return inp.Arguments
77         }
78         return nil
79 }
80
81 // SetArguments set the args for the input
82 func (t *TxInput) SetArguments(args [][]byte) {
83         switch inp := t.TypedInput.(type) {
84         case *SpendInput:
85                 inp.Arguments = args
86         }
87 }
88
89 // SpentOutputID calculate the hash of spended output
90 func (t *TxInput) SpentOutputID() (o bc.Hash, err error) {
91         if si, ok := t.TypedInput.(*SpendInput); ok {
92                 o, err = ComputeOutputID(&si.SpendCommitment)
93         }
94         return o, err
95 }
96
97 func (t *TxInput) readFrom(r *blockchain.Reader) (err error) {
98         if t.AssetVersion, err = blockchain.ReadVarint63(r); err != nil {
99                 return err
100         }
101
102         t.CommitmentSuffix, err = blockchain.ReadExtensibleString(r, func(r *blockchain.Reader) error {
103                 if t.AssetVersion != 1 {
104                         return nil
105                 }
106                 var icType [1]byte
107                 if _, err = io.ReadFull(r, icType[:]); err != nil {
108                         return errors.Wrap(err, "reading input commitment type")
109                 }
110                 switch icType[0] {
111                 case SpendInputType:
112                         si := new(SpendInput)
113                         t.TypedInput = si
114                         if si.SpendCommitmentSuffix, err = si.SpendCommitment.readFrom(r, 1); err != nil {
115                                 return err
116                         }
117
118                 case CoinbaseInputType:
119                         ci := new(CoinbaseInput)
120                         t.TypedInput = ci
121                         if ci.Arbitrary, err = blockchain.ReadVarstr31(r); err != nil {
122                                 return err
123                         }
124
125                 default:
126                         return fmt.Errorf("unsupported input type %d", icType[0])
127                 }
128                 return nil
129         })
130         if err != nil {
131                 return err
132         }
133
134         t.WitnessSuffix, err = blockchain.ReadExtensibleString(r, func(r *blockchain.Reader) error {
135                 if t.AssetVersion != 1 {
136                         return nil
137                 }
138
139                 switch inp := t.TypedInput.(type) {
140                 case *SpendInput:
141                         if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil {
142                                 return err
143                         }
144                 }
145                 return nil
146         })
147
148         return err
149 }
150
151 func (t *TxInput) writeTo(w io.Writer) error {
152         if _, err := blockchain.WriteVarint63(w, t.AssetVersion); err != nil {
153                 return errors.Wrap(err, "writing asset version")
154         }
155
156         if _, err := blockchain.WriteExtensibleString(w, t.CommitmentSuffix, t.writeInputCommitment); err != nil {
157                 return errors.Wrap(err, "writing input commitment")
158         }
159
160         _, err := blockchain.WriteExtensibleString(w, t.WitnessSuffix, t.writeInputWitness)
161         return errors.Wrap(err, "writing input witness")
162 }
163
164 func (t *TxInput) writeInputCommitment(w io.Writer) (err error) {
165         if t.AssetVersion != 1 {
166                 return nil
167         }
168
169         switch inp := t.TypedInput.(type) {
170         case *SpendInput:
171                 if _, err = w.Write([]byte{SpendInputType}); err != nil {
172                         return err
173                 }
174                 return inp.SpendCommitment.writeExtensibleString(w, inp.SpendCommitmentSuffix, t.AssetVersion)
175
176         case *CoinbaseInput:
177                 if _, err = w.Write([]byte{CoinbaseInputType}); err != nil {
178                         return err
179                 }
180                 if _, err = blockchain.WriteVarstr31(w, inp.Arbitrary); err != nil {
181                         return errors.Wrap(err, "writing coinbase arbitrary")
182                 }
183         }
184         return nil
185 }
186
187 func (t *TxInput) writeInputWitness(w io.Writer) error {
188         if t.AssetVersion != 1 {
189                 return nil
190         }
191
192         switch inp := t.TypedInput.(type) {
193         case *SpendInput:
194                 _, err := blockchain.WriteVarstrList(w, inp.Arguments)
195                 return err
196         }
197         return nil
198 }