OSDN Git Service

modify chain tx fee (#1793)
[bytom/bytom.git] / test / integration / block_integration_util.go
1 package integration
2
3 import (
4         "encoding/json"
5         "fmt"
6         "os"
7         "reflect"
8         "strings"
9         "sort"
10
11         "github.com/golang/protobuf/proto"
12
13         "github.com/bytom/database"
14         dbm "github.com/bytom/database/leveldb"
15         "github.com/bytom/database/storage"
16         "github.com/bytom/event"
17         "github.com/bytom/protocol"
18         "github.com/bytom/protocol/bc"
19         "github.com/bytom/protocol/bc/types"
20         "github.com/bytom/protocol/state"
21         "github.com/bytom/testutil"
22 )
23
24 const (
25         dbDir = "temp"
26 )
27
28 type storeItem struct {
29         key []byte
30         val interface{}
31 }
32
33 type serialFun func(obj interface{}) ([]byte, error)
34 type deserialFun func(data []byte) (interface{}, error)
35
36 func getSerialFun(item interface{}) (serialFun, error) {
37         switch item.(type) {
38         case *protocol.BlockStoreState:
39                 return json.Marshal, nil
40         case *types.Block:
41                 return func(obj interface{}) ([]byte, error) {
42                         block := obj.(*types.Block)
43                         return block.MarshalText()
44                 }, nil
45         case types.BlockHeader:
46                 return func(obj interface{}) ([]byte, error) {
47                         bh := obj.(types.BlockHeader)
48                         return bh.MarshalText()
49                 }, nil
50         case *bc.TransactionStatus:
51                 return func(obj interface{}) ([]byte, error) {
52                         status := obj.(*bc.TransactionStatus)
53                         return proto.Marshal(status)
54                 }, nil
55         case *storage.UtxoEntry:
56                 return func(obj interface{}) ([]byte, error) {
57                         utxo := obj.(*storage.UtxoEntry)
58                         return proto.Marshal(utxo)
59                 }, nil
60         }
61         typ := reflect.TypeOf(item)
62         return nil, fmt.Errorf("can not found any serialization function for type:%s", typ.Name())
63 }
64
65 func getDeserialFun(key []byte) (deserialFun, error) {
66         funMap := map[string]deserialFun{
67                 string(database.BlockStoreKey): func(data []byte) (interface{}, error) {
68                         storeState := &protocol.BlockStoreState{}
69                         err := json.Unmarshal(data, storeState)
70                         return storeState, err
71                 },
72                 string(database.TxStatusPrefix): func(data []byte) (interface{}, error) {
73                         status := &bc.TransactionStatus{}
74                         err := proto.Unmarshal(data, status)
75                         return status, err
76                 },
77                 string(database.BlockPrefix): func(data []byte) (interface{}, error) {
78                         block := &types.Block{}
79                         err := block.UnmarshalText(data)
80                         sortSpendOutputID(block)
81                         return block, err
82                 },
83                 string(database.BlockHeaderPrefix): func(data []byte) (interface{}, error) {
84                         bh := types.BlockHeader{}
85                         err := bh.UnmarshalText(data)
86                         return bh, err
87                 },
88                 database.UtxoPreFix: func(data []byte) (interface{}, error) {
89                         utxo := &storage.UtxoEntry{}
90                         err := proto.Unmarshal(data, utxo)
91                         return utxo, err
92                 },
93         }
94
95         for prefix, converter := range funMap {
96                 if strings.HasPrefix(string(key), prefix) {
97                         return converter, nil
98                 }
99         }
100         return nil, fmt.Errorf("can not found any deserialization function for key:%s", string(key))
101 }
102
103 type storeItems []*storeItem
104
105 func (s1 storeItems) equals(s2 storeItems) bool {
106         if s2 == nil {
107                 return false
108         }
109
110         itemMap1 := make(map[string]interface{}, len(s1))
111         for _, item := range s1 {
112                 itemMap1[string(item.key)] = item.val
113         }
114
115         itemMap2 := make(map[string]interface{}, len(s2))
116         for _, item := range s2 {
117                 itemMap2[string(item.key)] = item.val
118         }
119
120         return testutil.DeepEqual(itemMap1, itemMap2)
121 }
122
123 type processBlockTestCase struct {
124         desc             string
125         initStore        []*storeItem
126         wantStore        []*storeItem
127         wantBlockIndex   *state.BlockIndex
128         initOrphanManage *protocol.OrphanManage
129         wantOrphanManage *protocol.OrphanManage
130         wantIsOrphan     bool
131         wantError        bool
132         newBlock         *types.Block
133 }
134
135 func (p *processBlockTestCase) Run() error {
136         defer os.RemoveAll(dbDir)
137         if p.initStore == nil {
138                 p.initStore = make([]*storeItem, 0)
139         }
140         store, db, err := initStore(p)
141         if err != nil {
142                 return err
143         }
144
145         orphanManage := p.initOrphanManage
146         if orphanManage == nil {
147                 orphanManage = protocol.NewOrphanManage()
148         }
149
150         txPool := protocol.NewTxPool(store, event.NewDispatcher())
151         chain, err := protocol.NewChainWithOrphanManage(store, txPool, orphanManage)
152         if err != nil {
153                 return err
154         }
155
156         isOrphan, err := chain.ProcessBlock(p.newBlock)
157         if p.wantError != (err != nil) {
158                 return fmt.Errorf("#case(%s) want error:%t, got error:%t", p.desc, p.wantError, err != nil)
159         }
160
161         if isOrphan != p.wantIsOrphan {
162                 return fmt.Errorf("#case(%s) want orphan:%t, got orphan:%t", p.desc, p.wantIsOrphan, isOrphan)
163         }
164
165         if p.wantStore != nil {
166                 gotStoreItems, err := loadStoreItems(db)
167                 if err != nil {
168                         return err
169                 }
170
171                 if !storeItems(gotStoreItems).equals(p.wantStore) {
172                         return fmt.Errorf("#case(%s) want store:%v, got store:%v", p.desc, p.wantStore, gotStoreItems)
173                 }
174         }
175
176         if p.wantBlockIndex != nil {
177                 blockIndex := chain.GetBlockIndex()
178                 if !blockIndex.Equals(p.wantBlockIndex) {
179                         return fmt.Errorf("#case(%s) want block index:%v, got block index:%v", p.desc, *p.wantBlockIndex, *blockIndex)
180                 }
181         }
182
183         if p.wantOrphanManage != nil {
184                 if !orphanManage.Equals(p.wantOrphanManage) {
185                         return fmt.Errorf("#case(%s) want orphan manage:%v, got orphan manage:%v", p.desc, *p.wantOrphanManage, *orphanManage)
186                 }
187         }
188         return nil
189 }
190
191 func loadStoreItems(db dbm.DB) ([]*storeItem, error) {
192         iter := db.Iterator()
193         defer iter.Release()
194
195         var items []*storeItem
196         for iter.Next() {
197                 item := &storeItem{key: iter.Key()}
198                 fun, err := getDeserialFun(iter.Key())
199                 if err != nil {
200                         return nil, err
201                 }
202
203                 val, err := fun(iter.Value())
204                 if err != nil {
205                         return nil, err
206                 }
207
208                 item.val = val
209                 items = append(items, item)
210         }
211         return items, nil
212 }
213
214 func initStore(c *processBlockTestCase) (protocol.Store, dbm.DB, error) {
215         testDB := dbm.NewDB("testdb", "leveldb", dbDir)
216         batch := testDB.NewBatch()
217         for _, item := range c.initStore {
218                 fun, err := getSerialFun(item.val)
219                 if err != nil {
220                         return nil, nil, err
221                 }
222
223                 bytes, err := fun(item.val)
224                 if err != nil {
225                         return nil, nil, err
226                 }
227
228                 batch.Set(item.key, bytes)
229         }
230         batch.Write()
231         return database.NewStore(testDB), testDB, nil
232 }
233
234 func sortSpendOutputID(block *types.Block) {
235         for _, tx := range block.Transactions {
236                 sort.Sort(HashSlice(tx.SpentOutputIDs))
237         }
238 }
239
240 type HashSlice []bc.Hash
241
242 func (p HashSlice) Len() int           { return len(p) }
243 func (p HashSlice) Less(i, j int) bool { return p[i].String() < p[j].String() }
244 func (p HashSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }