OSDN Git Service

99be15336109b8f595bc811b9e9ee0c2a49b2180
[bytom/vapor.git] / protocol / bc / types / map.go
1 package types
2
3 import (
4         "github.com/vapor/consensus"
5         "github.com/vapor/crypto/sha3pool"
6         "github.com/vapor/protocol/bc"
7         "github.com/vapor/protocol/vm"
8         "github.com/vapor/protocol/vm/vmutil"
9 )
10
11 // MapTx converts a types TxData object into its entries-based
12 // representation.
13 func MapTx(oldTx *TxData) *bc.Tx {
14         txID, txHeader, entries := mapTx(oldTx)
15         tx := &bc.Tx{
16                 TxHeader: txHeader,
17                 ID:       txID,
18                 Entries:  entries,
19                 InputIDs: make([]bc.Hash, len(oldTx.Inputs)),
20         }
21
22         spentOutputIDs := make(map[bc.Hash]bool)
23         for id, e := range entries {
24                 var ord uint64
25                 switch e := e.(type) {
26                 case *bc.Issuance:
27                         ord = e.Ordinal
28
29                 case *bc.Spend:
30                         ord = e.Ordinal
31                         spentOutputIDs[*e.SpentOutputId] = true
32                         if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
33                                 tx.GasInputIDs = append(tx.GasInputIDs, id)
34                         }
35
36                 case *bc.Coinbase:
37                         ord = 0
38                 case *bc.Claim:
39                         ord = 0
40                 default:
41                         continue
42                 }
43
44                 if ord >= uint64(len(oldTx.Inputs)) {
45                         continue
46                 }
47                 tx.InputIDs[ord] = id
48         }
49
50         for id := range spentOutputIDs {
51                 tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
52         }
53         return tx
54 }
55
56 func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) {
57         entryMap = make(map[bc.Hash]bc.Entry)
58         addEntry := func(e bc.Entry) bc.Hash {
59                 id := bc.EntryID(e)
60                 entryMap[id] = e
61                 return id
62         }
63
64         var (
65                 spends    []*bc.Spend
66                 issuances []*bc.Issuance
67                 coinbase  *bc.Coinbase
68                 claim     *bc.Claim
69         )
70
71         muxSources := make([]*bc.ValueSource, len(tx.Inputs))
72         for i, input := range tx.Inputs {
73                 switch inp := input.TypedInput.(type) {
74                 case *IssuanceInput:
75                         nonceHash := inp.NonceHash()
76                         assetDefHash := inp.AssetDefinitionHash()
77                         value := input.AssetAmount()
78
79                         issuance := bc.NewIssuance(&nonceHash, &value, uint64(i))
80                         issuance.WitnessAssetDefinition = &bc.AssetDefinition{
81                                 Data: &assetDefHash,
82                                 IssuanceProgram: &bc.Program{
83                                         VmVersion: inp.VMVersion,
84                                         Code:      inp.IssuanceProgram,
85                                 },
86                         }
87                         issuance.WitnessArguments = inp.Arguments
88                         issuanceID := addEntry(issuance)
89
90                         muxSources[i] = &bc.ValueSource{
91                                 Ref:   &issuanceID,
92                                 Value: &value,
93                         }
94                         issuances = append(issuances, issuance)
95
96                 case *SpendInput:
97                         // create entry for prevout
98                         prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
99                         src := &bc.ValueSource{
100                                 Ref:      &inp.SourceID,
101                                 Value:    &inp.AssetAmount,
102                                 Position: inp.SourcePosition,
103                         }
104                         prevout := bc.NewOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
105                         prevoutID := addEntry(prevout)
106                         // create entry for spend
107                         spend := bc.NewSpend(&prevoutID, uint64(i))
108                         spend.WitnessArguments = inp.Arguments
109                         spendID := addEntry(spend)
110                         // setup mux
111                         muxSources[i] = &bc.ValueSource{
112                                 Ref:   &spendID,
113                                 Value: &inp.AssetAmount,
114                         }
115                         spends = append(spends, spend)
116
117                 case *CoinbaseInput:
118                         coinbase = bc.NewCoinbase(inp.Arbitrary)
119                         coinbaseID := addEntry(coinbase)
120
121                         out := tx.Outputs[0]
122                         muxSources[i] = &bc.ValueSource{
123                                 Ref:   &coinbaseID,
124                                 Value: &out.AssetAmount,
125                         }
126                 case *ClaimInput:
127                         // create entry for prevout
128                         prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
129                         src := &bc.ValueSource{
130                                 Ref:      &inp.SourceID,
131                                 Value:    &inp.AssetAmount,
132                                 Position: inp.SourcePosition,
133                         }
134                         prevout := bc.NewOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
135                         prevoutID := addEntry(prevout)
136
137                         claim = bc.NewClaim(&prevoutID, uint64(i), input.Peginwitness)
138                         claim.WitnessArguments = inp.Arguments
139                         claimID := addEntry(claim)
140                         muxSources[i] = &bc.ValueSource{
141                                 Ref:   &claimID,
142                                 Value: &inp.AssetAmount,
143                         }
144                 }
145         }
146
147         mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
148         muxID := addEntry(mux)
149
150         // connect the inputs to the mux
151         for _, spend := range spends {
152                 spentOutput := entryMap[*spend.SpentOutputId].(*bc.Output)
153                 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
154         }
155         for _, issuance := range issuances {
156                 issuance.SetDestination(&muxID, issuance.Value, issuance.Ordinal)
157         }
158
159         if coinbase != nil {
160                 coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0)
161         }
162
163         if claim != nil {
164                 claim.SetDestination(&muxID, mux.Sources[0].Value, 0)
165         }
166
167         // convert types.outputs to the bc.output
168         var resultIDs []*bc.Hash
169         for i, out := range tx.Outputs {
170                 src := &bc.ValueSource{
171                         Ref:      &muxID,
172                         Value:    &out.AssetAmount,
173                         Position: uint64(i),
174                 }
175                 var resultID bc.Hash
176                 if vmutil.IsUnspendable(out.ControlProgram) {
177                         // retirement
178                         r := bc.NewRetirement(src, uint64(i))
179                         resultID = addEntry(r)
180                 } else {
181                         // non-retirement
182                         prog := &bc.Program{out.VMVersion, out.ControlProgram}
183                         o := bc.NewOutput(src, prog, uint64(i))
184                         resultID = addEntry(o)
185                 }
186
187                 dest := &bc.ValueDestination{
188                         Value:    src.Value,
189                         Ref:      &resultID,
190                         Position: 0,
191                 }
192                 resultIDs = append(resultIDs, &resultID)
193                 mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
194         }
195         refdatahash := hashData(tx.ReferenceData)
196         h := bc.NewTxHeader(tx.Version, tx.SerializedSize, &refdatahash, tx.TimeRange, resultIDs, true)
197         return addEntry(h), h, entryMap
198 }
199
200 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
201         bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash)
202         return bc.EntryID(bh), bh
203 }
204
205 // MapBlock converts a types block to bc block
206 func MapBlock(old *Block) *bc.Block {
207         if old == nil {
208                 return nil
209         }
210
211         b := new(bc.Block)
212         b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
213         for _, oldTx := range old.Transactions {
214                 b.Transactions = append(b.Transactions, oldTx.Tx)
215         }
216         return b
217 }
218
219 func hashData(data []byte) bc.Hash {
220         var b32 [32]byte
221         sha3pool.Sum256(b32[:], data)
222         return bc.NewHash(b32)
223 }