OSDN Git Service

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