OSDN Git Service

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