OSDN Git Service

remove the timerange check
[bytom/bytom.git] / protocol / bc / legacy / map.go
1 package legacy
2
3 import (
4         "github.com/bytom/crypto/sha3pool"
5         "github.com/bytom/protocol/bc"
6         "github.com/bytom/protocol/vm"
7         "github.com/bytom/protocol/vm/vmutil"
8 )
9
10 // MapTx converts a legacy TxData object into its entries-based
11 // representation.
12 func MapTx(oldTx *TxData) *bc.Tx {
13         txid, header, entries := mapTx(oldTx)
14
15         tx := &bc.Tx{
16                 TxHeader: header,
17                 ID:       txid,
18                 Entries:  entries,
19                 InputIDs: make([]bc.Hash, len(oldTx.Inputs)),
20         }
21
22         var (
23                 nonceIDs       = make(map[bc.Hash]bool)
24                 spentOutputIDs = make(map[bc.Hash]bool)
25         )
26         for id, e := range entries {
27                 var ord uint64
28                 switch e := e.(type) {
29                 case *bc.Issuance:
30                         anchor, ok := entries[*e.AnchorId]
31                         if !ok {
32                                 // this tx will be invalid because this issuance is
33                                 // missing an anchor
34                                 continue
35                         }
36                         if _, ok := anchor.(*bc.Nonce); ok {
37                                 nonceIDs[*e.AnchorId] = true
38                         }
39                         ord = e.Ordinal
40                         // resume below after the switch
41
42                 case *bc.Spend:
43                         spentOutputIDs[*e.SpentOutputId] = true
44                         ord = e.Ordinal
45                         // resume below after the switch
46
47                 default:
48                         continue
49                 }
50                 if ord >= uint64(len(oldTx.Inputs)) {
51                         continue // poorly-formed transaction
52                 }
53                 tx.InputIDs[ord] = id
54         }
55
56         for id := range nonceIDs {
57                 tx.NonceIDs = append(tx.NonceIDs, id)
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
68         addEntry := func(e bc.Entry) bc.Hash {
69                 id := bc.EntryID(e)
70                 entryMap[id] = e
71                 return id
72         }
73
74         // Loop twice over tx.Inputs, once for spends and once for
75         // issuances.  Do spends first so the entry ID of the first spend is
76         // available in case an issuance needs it for its anchor.
77
78         var (
79                 firstSpend   *bc.Spend
80                 firstSpendID bc.Hash
81                 spends       []*bc.Spend
82                 issuances    []*bc.Issuance
83                 muxSources   = make([]*bc.ValueSource, len(tx.Inputs))
84         )
85
86         for i, inp := range tx.Inputs {
87                 if oldSp, ok := inp.TypedInput.(*SpendInput); ok {
88                         prog := &bc.Program{VmVersion: oldSp.VMVersion, Code: oldSp.ControlProgram}
89                         src := &bc.ValueSource{
90                                 Ref:      &oldSp.SourceID,
91                                 Value:    &oldSp.AssetAmount,
92                                 Position: oldSp.SourcePosition,
93                         }
94                         out := bc.NewOutput(src, prog, &oldSp.RefDataHash, 0) // ordinal doesn't matter for prevouts, only for result outputs
95                         prevoutID := addEntry(out)
96                         refdatahash := hashData(inp.ReferenceData)
97                         sp := bc.NewSpend(&prevoutID, &refdatahash, uint64(i))
98                         sp.WitnessArguments = oldSp.Arguments
99                         id := addEntry(sp)
100                         muxSources[i] = &bc.ValueSource{
101                                 Ref:   &id,
102                                 Value: &oldSp.AssetAmount,
103                         }
104                         if firstSpend == nil {
105                                 firstSpend = sp
106                                 firstSpendID = id
107                         }
108                         spends = append(spends, sp)
109                 }
110         }
111
112         for i, inp := range tx.Inputs {
113                 if oldIss, ok := inp.TypedInput.(*IssuanceInput); ok {
114                         // Note: asset definitions, initial block ids, and issuance
115                         // programs are omitted here because they do not contribute to
116                         // the body hash of an issuance.
117
118                         var (
119                                 anchorID    bc.Hash
120                                 setAnchored = func(*bc.Hash) {}
121                         )
122
123                         if len(oldIss.Nonce) > 0 {
124                                 assetID := oldIss.AssetID()
125
126                                 builder := vmutil.NewBuilder()
127                                 builder.AddData(oldIss.Nonce).AddOp(vm.OP_DROP)
128                                 builder.AddOp(vm.OP_ASSET).AddData(assetID.Bytes()).AddOp(vm.OP_EQUAL)
129                                 prog, _ := builder.Build() // error is impossible
130
131                                 nonce := bc.NewNonce(&bc.Program{VmVersion: 1, Code: prog})
132                                 anchorID = addEntry(nonce)
133                                 setAnchored = nonce.SetAnchored
134                         } else if firstSpend != nil {
135                                 anchorID = firstSpendID
136                                 setAnchored = firstSpend.SetAnchored
137                         }
138
139                         val := inp.AssetAmount()
140
141                         refdatahash := hashData(inp.ReferenceData)
142                         assetdefhash := hashData(oldIss.AssetDefinition)
143                         iss := bc.NewIssuance(&anchorID, &val, &refdatahash, uint64(i))
144                         iss.WitnessAssetDefinition = &bc.AssetDefinition{
145                                 InitialBlockId: &oldIss.InitialBlock,
146                                 Data:           &assetdefhash,
147                                 IssuanceProgram: &bc.Program{
148                                         VmVersion: oldIss.VMVersion,
149                                         Code:      oldIss.IssuanceProgram,
150                                 },
151                         }
152                         iss.WitnessArguments = oldIss.Arguments
153                         issID := addEntry(iss)
154                         setAnchored(&issID)
155
156                         muxSources[i] = &bc.ValueSource{
157                                 Ref:   &issID,
158                                 Value: &val,
159                         }
160                         issuances = append(issuances, iss)
161                 }
162         }
163
164         mux := bc.NewMux(muxSources, &bc.Program{VmVersion: 1, Code: []byte{byte(vm.OP_TRUE)}})
165         muxID := addEntry(mux)
166
167         for _, sp := range spends {
168                 spentOutput := entryMap[*sp.SpentOutputId].(*bc.Output)
169                 sp.SetDestination(&muxID, spentOutput.Source.Value, sp.Ordinal)
170         }
171         for _, iss := range issuances {
172                 iss.SetDestination(&muxID, iss.Value, iss.Ordinal)
173         }
174
175         var resultIDs []*bc.Hash
176
177         for i, out := range tx.Outputs {
178                 src := &bc.ValueSource{
179                         Ref:      &muxID,
180                         Value:    &out.AssetAmount,
181                         Position: uint64(i),
182                 }
183                 var dest *bc.ValueDestination
184                 if vmutil.IsUnspendable(out.ControlProgram) {
185                         // retirement
186                         refdatahash := hashData(out.ReferenceData)
187                         r := bc.NewRetirement(src, &refdatahash, uint64(i))
188                         rID := addEntry(r)
189                         resultIDs = append(resultIDs, &rID)
190                         dest = &bc.ValueDestination{
191                                 Ref:      &rID,
192                                 Position: 0,
193                         }
194                 } else {
195                         // non-retirement
196                         prog := &bc.Program{out.VMVersion, out.ControlProgram}
197                         refdatahash := hashData(out.ReferenceData)
198                         o := bc.NewOutput(src, prog, &refdatahash, uint64(i))
199                         oID := addEntry(o)
200                         resultIDs = append(resultIDs, &oID)
201                         dest = &bc.ValueDestination{
202                                 Ref:      &oID,
203                                 Position: 0,
204                         }
205                 }
206                 dest.Value = src.Value
207                 mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
208         }
209
210         refdatahash := hashData(tx.ReferenceData)
211         h := bc.NewTxHeader(tx.Version, resultIDs, &refdatahash, tx.MinTime, tx.MaxTime)
212         headerID = addEntry(h)
213
214         return headerID, h, entryMap
215 }
216
217 func mapBlockHeader(old *BlockHeader) (bhID bc.Hash, bh *bc.BlockHeader) {
218         bh = bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, old.TimestampMS, &old.TransactionsMerkleRoot, &old.AssetsMerkleRoot, old.Nonce, old.Bits)
219         bhID = bc.EntryID(bh)
220         return
221 }
222
223 func MapBlock(old *Block) *bc.Block {
224         if old == nil {
225                 return nil // if old is nil, so should new be
226         }
227         b := new(bc.Block)
228         b.ID, b.BlockHeader = mapBlockHeader(&old.BlockHeader)
229         for _, oldTx := range old.Transactions {
230                 b.Transactions = append(b.Transactions, oldTx.Tx)
231         }
232         return b
233 }
234
235 func hashData(data []byte) bc.Hash {
236         var b32 [32]byte
237         sha3pool.Sum256(b32[:], data)
238         return bc.NewHash(b32)
239 }