OSDN Git Service

Handle the abnormal exit situation
[bytom/vapor.git] / protocol / bc / types / bytom / types / map.go
1 package types
2
3 import (
4         "github.com/vapor/consensus"
5         "github.com/vapor/protocol/bc"
6         "github.com/vapor/protocol/bc/types"
7         "github.com/vapor/protocol/bc/types/bytom"
8         "github.com/vapor/protocol/vm"
9         "github.com/vapor/protocol/vm/vmutil"
10 )
11
12 // MapTx converts a types TxData object into its entries-based
13 // representation.
14 func MapTx(oldTx *TxData) *bytom.Tx {
15         txID, txHeader, entries := mapTx(oldTx)
16         tx := &bytom.Tx{
17                 TxHeader: txHeader,
18                 ID:       txID,
19                 Entries:  entries,
20                 InputIDs: make([]bc.Hash, len(oldTx.Inputs)),
21         }
22
23         spentOutputIDs := make(map[bc.Hash]bool)
24         for id, e := range entries {
25                 var ord uint64
26                 switch e := e.(type) {
27                 case *bc.Issuance:
28                         ord = e.Ordinal
29
30                 case *bc.Spend:
31                         ord = e.Ordinal
32                         spentOutputIDs[*e.SpentOutputId] = true
33                         if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
34                                 tx.GasInputIDs = append(tx.GasInputIDs, id)
35                         }
36
37                 case *bc.Coinbase:
38                         ord = 0
39
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         )
69
70         muxSources := make([]*bc.ValueSource, len(tx.Inputs))
71         for i, input := range tx.Inputs {
72                 switch inp := input.TypedInput.(type) {
73                 case *types.IssuanceInput:
74                         nonceHash := inp.NonceHash()
75                         assetDefHash := inp.AssetDefinitionHash()
76                         value := input.AssetAmount()
77
78                         issuance := bc.NewIssuance(&nonceHash, &value, uint64(i))
79                         issuance.WitnessAssetDefinition = &bc.AssetDefinition{
80                                 Data: &assetDefHash,
81                                 IssuanceProgram: &bc.Program{
82                                         VmVersion: inp.VMVersion,
83                                         Code:      inp.IssuanceProgram,
84                                 },
85                         }
86                         issuance.WitnessArguments = inp.Arguments
87                         issuanceID := addEntry(issuance)
88
89                         muxSources[i] = &bc.ValueSource{
90                                 Ref:   &issuanceID,
91                                 Value: &value,
92                         }
93                         issuances = append(issuances, issuance)
94
95                 case *SpendInput:
96                         // create entry for prevout
97                         prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
98                         src := &bc.ValueSource{
99                                 Ref:      &inp.SourceID,
100                                 Value:    &inp.AssetAmount,
101                                 Position: inp.SourcePosition,
102                         }
103                         prevout := bc.NewOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
104                         prevoutID := addEntry(prevout)
105                         // create entry for spend
106                         spend := bc.NewSpend(&prevoutID, uint64(i))
107                         spend.WitnessArguments = inp.Arguments
108                         spendID := addEntry(spend)
109                         // setup mux
110                         muxSources[i] = &bc.ValueSource{
111                                 Ref:   &spendID,
112                                 Value: &inp.AssetAmount,
113                         }
114                         spends = append(spends, spend)
115
116                 case *CoinbaseInput:
117                         coinbase = bc.NewCoinbase(inp.Arbitrary)
118                         coinbaseID := addEntry(coinbase)
119
120                         out := tx.Outputs[0]
121                         muxSources[i] = &bc.ValueSource{
122                                 Ref:   &coinbaseID,
123                                 Value: &out.AssetAmount,
124                         }
125                 }
126         }
127
128         mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
129         muxID := addEntry(mux)
130
131         // connect the inputs to the mux
132         for _, spend := range spends {
133                 spentOutput := entryMap[*spend.SpentOutputId].(*bc.Output)
134                 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
135         }
136         for _, issuance := range issuances {
137                 issuance.SetDestination(&muxID, issuance.Value, issuance.Ordinal)
138         }
139
140         if coinbase != nil {
141                 coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0)
142         }
143
144         // convert types.outputs to the bytom.output
145         var resultIDs []*bc.Hash
146         for i, out := range tx.Outputs {
147                 src := &bc.ValueSource{
148                         Ref:      &muxID,
149                         Value:    &out.AssetAmount,
150                         Position: uint64(i),
151                 }
152                 var resultID bc.Hash
153                 if vmutil.IsUnspendable(out.ControlProgram) {
154                         // retirement
155                         r := bc.NewRetirement(src, uint64(i))
156                         resultID = addEntry(r)
157                 } else {
158                         // non-retirement
159                         prog := &bc.Program{out.VMVersion, out.ControlProgram}
160                         o := bc.NewOutput(src, prog, uint64(i))
161                         resultID = addEntry(o)
162                 }
163
164                 dest := &bc.ValueDestination{
165                         Value:    src.Value,
166                         Ref:      &resultID,
167                         Position: 0,
168                 }
169                 resultIDs = append(resultIDs, &resultID)
170                 mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
171         }
172
173         h := bc.NewTxHeader(tx.Version, tx.SerializedSize, &bc.Hash{}, tx.TimeRange, resultIDs, false)
174         return addEntry(h), h, entryMap
175 }
176
177 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BytomBlockHeader) {
178         bh := bc.NewBytomBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, old.Nonce, old.Bits)
179         return bc.EntryID(bh), bh
180 }
181
182 // MapBlock converts a types block to bc block
183 func MapBlock(old *Block) *bytom.Block {
184         if old == nil {
185                 return nil
186         }
187
188         b := new(bytom.Block)
189         b.ID, b.BytomBlockHeader = mapBlockHeader(&old.BlockHeader)
190         for _, oldTx := range old.Transactions {
191                 b.Transactions = append(b.Transactions, oldTx.Tx)
192         }
193         return b
194 }