OSDN Git Service

merge node_p2p and chain.
[bytom/bytom-spv.git] / protocol / bc / legacy / spend.go
1 package legacy
2
3 import (
4         "fmt"
5         "io"
6
7         "github.com/blockchain/crypto/sha3pool"
8         "github.com/blockchain/encoding/blockchain"
9         "github.com/blockchain/errors"
10         "github.com/blockchain/protocol/bc"
11 )
12
13 // SpendInput satisfies the TypedInput interface and represents a spend transaction.
14 type SpendInput struct {
15         // Commitment
16         SpendCommitment
17
18         // The unconsumed suffix of the output commitment
19         SpendCommitmentSuffix []byte
20
21         // Witness
22         Arguments [][]byte
23 }
24
25 func (si *SpendInput) IsIssuance() bool { return false }
26
27 func NewSpendInput(arguments [][]byte, sourceID bc.Hash, assetID bc.AssetID, amount uint64, sourcePos uint64, controlProgram []byte, outRefDataHash bc.Hash, referenceData []byte) *TxInput {
28         const (
29                 vmver    = 1
30                 assetver = 1
31         )
32         sc := SpendCommitment{
33                 AssetAmount: bc.AssetAmount{
34                         AssetId: &assetID,
35                         Amount:  amount,
36                 },
37                 SourceID:       sourceID,
38                 SourcePosition: sourcePos,
39                 VMVersion:      vmver,
40                 ControlProgram: controlProgram,
41                 RefDataHash:    outRefDataHash,
42         }
43         return &TxInput{
44                 AssetVersion:  assetver,
45                 ReferenceData: referenceData,
46                 TypedInput: &SpendInput{
47                         SpendCommitment: sc,
48                         Arguments:       arguments,
49                 },
50         }
51 }
52
53 // SpendCommitment contains the commitment data for a transaction
54 // output (which also appears in the spend input of that output).
55 type SpendCommitment struct {
56         bc.AssetAmount
57         SourceID       bc.Hash
58         SourcePosition uint64
59         VMVersion      uint64
60         ControlProgram []byte
61         RefDataHash    bc.Hash
62 }
63
64 func (sc *SpendCommitment) writeExtensibleString(w io.Writer, suffix []byte, assetVersion uint64) error {
65         _, err := blockchain.WriteExtensibleString(w, suffix, func(w io.Writer) error {
66                 return sc.writeContents(w, suffix, assetVersion)
67         })
68         return err
69 }
70
71 func (sc *SpendCommitment) writeContents(w io.Writer, suffix []byte, assetVersion uint64) (err error) {
72         if assetVersion == 1 {
73                 _, err = sc.SourceID.WriteTo(w)
74                 if err != nil {
75                         return errors.Wrap(err, "writing source id")
76                 }
77                 _, err = sc.AssetAmount.WriteTo(w)
78                 if err != nil {
79                         return errors.Wrap(err, "writing asset amount")
80                 }
81                 _, err = blockchain.WriteVarint63(w, sc.SourcePosition)
82                 if err != nil {
83                         return errors.Wrap(err, "writing source position")
84                 }
85                 _, err = blockchain.WriteVarint63(w, sc.VMVersion)
86                 if err != nil {
87                         return errors.Wrap(err, "writing vm version")
88                 }
89                 _, err = blockchain.WriteVarstr31(w, sc.ControlProgram)
90                 if err != nil {
91                         return errors.Wrap(err, "writing control program")
92                 }
93                 _, err = sc.RefDataHash.WriteTo(w)
94                 if err != nil {
95                         return errors.Wrap(err, "writing reference data hash")
96                 }
97         }
98         if len(suffix) > 0 {
99                 _, err = w.Write(suffix)
100                 if err != nil {
101                         return errors.Wrap(err, "writing suffix")
102                 }
103         }
104         return nil
105 }
106
107 func (sc *SpendCommitment) readFrom(r *blockchain.Reader, assetVersion uint64) (suffix []byte, err error) {
108         return blockchain.ReadExtensibleString(r, func(r *blockchain.Reader) error {
109                 if assetVersion == 1 {
110                         _, err := sc.SourceID.ReadFrom(r)
111                         if err != nil {
112                                 return errors.Wrap(err, "reading source id")
113                         }
114                         err = sc.AssetAmount.ReadFrom(r)
115                         if err != nil {
116                                 return errors.Wrap(err, "reading asset+amount")
117                         }
118                         sc.SourcePosition, err = blockchain.ReadVarint63(r)
119                         if err != nil {
120                                 return errors.Wrap(err, "reading source position")
121                         }
122                         sc.VMVersion, err = blockchain.ReadVarint63(r)
123                         if err != nil {
124                                 return errors.Wrap(err, "reading VM version")
125                         }
126                         if sc.VMVersion != 1 {
127                                 return fmt.Errorf("unrecognized VM version %d for asset version 1", sc.VMVersion)
128                         }
129                         sc.ControlProgram, err = blockchain.ReadVarstr31(r)
130                         if err != nil {
131                                 return errors.Wrap(err, "reading control program")
132                         }
133                         _, err = sc.RefDataHash.ReadFrom(r)
134                         if err != nil {
135                                 return errors.Wrap(err, "reading reference data hash")
136                         }
137                         return nil
138                 }
139                 return nil
140         })
141 }
142
143 func (sc *SpendCommitment) Hash(suffix []byte, assetVersion uint64) (spendhash bc.Hash) {
144         h := sha3pool.Get256()
145         defer sha3pool.Put256(h)
146         sc.writeExtensibleString(h, suffix, assetVersion) // TODO(oleg): get rid of this assetVersion parameter to actually write all the bytes
147         spendhash.ReadFrom(h)
148         return spendhash
149 }