OSDN Git Service

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