OSDN Git Service

add dpos consensus
[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                 case *bc.Claim:
38                         ord = 0
39                 case *bc.Dpos:
40                         ord = e.Ordinal
41                         //spentOutputIDs[*e.SpentOutputId] = true
42                         /*
43                                 if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
44                                         tx.GasInputIDs = append(tx.GasInputIDs, id)
45                                 }
46                         */
47                         continue
48                 default:
49                         continue
50                 }
51
52                 if ord >= uint64(len(oldTx.Inputs)) {
53                         continue
54                 }
55                 tx.InputIDs[ord] = id
56         }
57
58         for id := range spentOutputIDs {
59                 tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
60         }
61         return tx
62 }
63
64 func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) {
65         entryMap = make(map[bc.Hash]bc.Entry)
66         addEntry := func(e bc.Entry) bc.Hash {
67                 id := bc.EntryID(e)
68                 entryMap[id] = e
69                 return id
70         }
71
72         var (
73                 spends    []*bc.Spend
74                 dposs     []*bc.Dpos
75                 issuances []*bc.Issuance
76                 coinbase  *bc.Coinbase
77                 claim     *bc.Claim
78         )
79
80         muxSources := make([]*bc.ValueSource, len(tx.Inputs))
81         for i, input := range tx.Inputs {
82                 switch inp := input.TypedInput.(type) {
83                 case *IssuanceInput:
84                         nonceHash := inp.NonceHash()
85                         assetDefHash := inp.AssetDefinitionHash()
86                         value := input.AssetAmount()
87
88                         issuance := bc.NewIssuance(&nonceHash, &value, uint64(i))
89                         issuance.WitnessAssetDefinition = &bc.AssetDefinition{
90                                 Data: &assetDefHash,
91                                 IssuanceProgram: &bc.Program{
92                                         VmVersion: inp.VMVersion,
93                                         Code:      inp.IssuanceProgram,
94                                 },
95                         }
96                         issuance.WitnessArguments = inp.Arguments
97                         issuanceID := addEntry(issuance)
98
99                         muxSources[i] = &bc.ValueSource{
100                                 Ref:   &issuanceID,
101                                 Value: &value,
102                         }
103                         issuances = append(issuances, issuance)
104
105                 case *SpendInput:
106                         // create entry for prevout
107                         prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
108                         src := &bc.ValueSource{
109                                 Ref:      &inp.SourceID,
110                                 Value:    &inp.AssetAmount,
111                                 Position: inp.SourcePosition,
112                         }
113                         prevout := bc.NewOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
114                         prevoutID := addEntry(prevout)
115                         // create entry for spend
116                         spend := bc.NewSpend(&prevoutID, uint64(i))
117                         spend.WitnessArguments = inp.Arguments
118                         spendID := addEntry(spend)
119                         // setup mux
120                         muxSources[i] = &bc.ValueSource{
121                                 Ref:   &spendID,
122                                 Value: &inp.AssetAmount,
123                         }
124                         spends = append(spends, spend)
125
126                 case *CoinbaseInput:
127                         coinbase = bc.NewCoinbase(inp.Arbitrary)
128                         coinbaseID := addEntry(coinbase)
129
130                         out := tx.Outputs[0]
131                         muxSources[i] = &bc.ValueSource{
132                                 Ref:   &coinbaseID,
133                                 Value: &out.AssetAmount,
134                         }
135                 case *ClaimInput:
136                         // create entry for prevout
137                         prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
138                         src := &bc.ValueSource{
139                                 Ref:      &inp.SourceID,
140                                 Value:    &inp.AssetAmount,
141                                 Position: inp.SourcePosition,
142                         }
143                         prevout := bc.NewOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
144                         prevoutID := addEntry(prevout)
145
146                         claim = bc.NewClaim(&prevoutID, uint64(i), input.Peginwitness)
147                         claim.WitnessArguments = inp.Arguments
148                         claimID := addEntry(claim)
149                         muxSources[i] = &bc.ValueSource{
150                                 Ref:   &claimID,
151                                 Value: &inp.AssetAmount,
152                         }
153                 case *DposTx:
154                         // create entry for prevout
155                         prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram}
156                         src := &bc.ValueSource{
157                                 Ref:      &inp.SourceID,
158                                 Value:    &inp.AssetAmount,
159                                 Position: inp.SourcePosition,
160                         }
161                         prevout := bc.NewOutput(src, prog, 0) // ordinal doesn't matter for prevouts, only for result outputs
162                         prevoutID := addEntry(prevout)
163                         // create entry for dpos
164                         dpos := bc.NewDpos(&prevoutID, uint64(i), uint32(inp.Type), inp.Stake, inp.From, inp.To, inp.Info)
165                         dpos.WitnessArguments = inp.Arguments
166                         dposID := addEntry(dpos)
167                         // setup mux
168                         muxSources[i] = &bc.ValueSource{
169                                 Ref:   &dposID,
170                                 Value: &inp.AssetAmount,
171                         }
172                         dposs = append(dposs, dpos)
173                 }
174         }
175
176         mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
177         muxID := addEntry(mux)
178
179         // connect the inputs to the mux
180         for _, spend := range spends {
181                 spentOutput := entryMap[*spend.SpentOutputId].(*bc.Output)
182                 spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal)
183         }
184         for _, issuance := range issuances {
185                 issuance.SetDestination(&muxID, issuance.Value, issuance.Ordinal)
186         }
187
188         // connect the inputs to the mux
189         for _, dpos := range dposs {
190                 spentOutput := entryMap[*dpos.SpentOutputId].(*bc.Output)
191                 dpos.SetDestination(&muxID, spentOutput.Source.Value, dpos.Ordinal)
192         }
193
194         if coinbase != nil {
195                 coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0)
196         }
197
198         if claim != nil {
199                 claim.SetDestination(&muxID, mux.Sources[0].Value, 0)
200         }
201
202         // convert types.outputs to the bc.output
203         var resultIDs []*bc.Hash
204         for i, out := range tx.Outputs {
205                 src := &bc.ValueSource{
206                         Ref:      &muxID,
207                         Value:    &out.AssetAmount,
208                         Position: uint64(i),
209                 }
210                 var resultID bc.Hash
211                 if vmutil.IsUnspendable(out.ControlProgram) {
212                         // retirement
213                         r := bc.NewRetirement(src, uint64(i))
214                         resultID = addEntry(r)
215                 } else {
216
217                         // non-retirement
218                         prog := &bc.Program{out.VMVersion, out.ControlProgram}
219                         o := bc.NewOutput(src, prog, uint64(i))
220                         resultID = addEntry(o)
221                 }
222
223                 dest := &bc.ValueDestination{
224                         Value:    src.Value,
225                         Ref:      &resultID,
226                         Position: 0,
227                 }
228                 resultIDs = append(resultIDs, &resultID)
229                 mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
230         }
231         h := bc.NewTxHeader(tx.Version, tx.SerializedSize, tx.TimeRange, resultIDs)
232         return addEntry(h), h, entryMap
233 }
234
235 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
236         proof := &bc.Proof{Sign: old.Proof.Sign, ControlProgram: old.Proof.ControlProgram}
237         bh := bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.Timestamp, &old.TransactionsMerkleRoot, &old.TransactionStatusHash, proof, old.Extra, old.Coinbase)
238         return bc.EntryID(bh), bh
239 }
240
241 // MapBlock converts a types block to bc block
242 func MapBlock(old *Block) *bc.Block {
243         if old == nil {
244                 return nil
245         }
246
247         b := new(bc.Block)
248         b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
249         for _, oldTx := range old.Transactions {
250                 b.Transactions = append(b.Transactions, oldTx.Tx)
251         }
252         return b
253 }