11 "github.com/golang/protobuf/proto"
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"
28 type storeItem struct {
33 type serialFun func(obj interface{}) ([]byte, error)
34 type deserialFun func(data []byte) (interface{}, error)
36 func getSerialFun(item interface{}) (serialFun, error) {
38 case *protocol.BlockStoreState:
39 return json.Marshal, nil
41 return func(obj interface{}) ([]byte, error) {
42 block := obj.(*types.Block)
43 return block.MarshalText()
45 case types.BlockHeader:
46 return func(obj interface{}) ([]byte, error) {
47 bh := obj.(types.BlockHeader)
48 return bh.MarshalText()
50 case *bc.TransactionStatus:
51 return func(obj interface{}) ([]byte, error) {
52 status := obj.(*bc.TransactionStatus)
53 return proto.Marshal(status)
55 case *storage.UtxoEntry:
56 return func(obj interface{}) ([]byte, error) {
57 utxo := obj.(*storage.UtxoEntry)
58 return proto.Marshal(utxo)
61 typ := reflect.TypeOf(item)
62 return nil, fmt.Errorf("can not found any serialization function for type:%s", typ.Name())
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
72 string(database.TxStatusPrefix): func(data []byte) (interface{}, error) {
73 status := &bc.TransactionStatus{}
74 err := proto.Unmarshal(data, status)
77 string(database.BlockPrefix): func(data []byte) (interface{}, error) {
78 block := &types.Block{}
79 err := block.UnmarshalText(data)
80 sortSpendOutputID(block)
83 string(database.BlockHeaderPrefix): func(data []byte) (interface{}, error) {
84 bh := types.BlockHeader{}
85 err := bh.UnmarshalText(data)
88 database.UtxoPreFix: func(data []byte) (interface{}, error) {
89 utxo := &storage.UtxoEntry{}
90 err := proto.Unmarshal(data, utxo)
95 for prefix, converter := range funMap {
96 if strings.HasPrefix(string(key), prefix) {
100 return nil, fmt.Errorf("can not found any deserialization function for key:%s", string(key))
103 type storeItems []*storeItem
105 func (s1 storeItems) equals(s2 storeItems) bool {
110 itemMap1 := make(map[string]interface{}, len(s1))
111 for _, item := range s1 {
112 itemMap1[string(item.key)] = item.val
115 itemMap2 := make(map[string]interface{}, len(s2))
116 for _, item := range s2 {
117 itemMap2[string(item.key)] = item.val
120 return testutil.DeepEqual(itemMap1, itemMap2)
123 type processBlockTestCase struct {
125 initStore []*storeItem
126 wantStore []*storeItem
127 wantBlockIndex *state.BlockIndex
128 initOrphanManage *protocol.OrphanManage
129 wantOrphanManage *protocol.OrphanManage
132 newBlock *types.Block
135 func (p *processBlockTestCase) Run() error {
136 defer os.RemoveAll(dbDir)
137 if p.initStore == nil {
138 p.initStore = make([]*storeItem, 0)
140 store, db, err := initStore(p)
145 orphanManage := p.initOrphanManage
146 if orphanManage == nil {
147 orphanManage = protocol.NewOrphanManage()
150 txPool := protocol.NewTxPool(store, event.NewDispatcher())
151 chain, err := protocol.NewChainWithOrphanManage(store, txPool, orphanManage)
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)
161 if isOrphan != p.wantIsOrphan {
162 return fmt.Errorf("#case(%s) want orphan:%t, got orphan:%t", p.desc, p.wantIsOrphan, isOrphan)
165 if p.wantStore != nil {
166 gotStoreItems, err := loadStoreItems(db)
171 if !storeItems(gotStoreItems).equals(p.wantStore) {
172 return fmt.Errorf("#case(%s) want store:%v, got store:%v", p.desc, p.wantStore, gotStoreItems)
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)
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)
191 func loadStoreItems(db dbm.DB) ([]*storeItem, error) {
192 iter := db.Iterator()
195 var items []*storeItem
197 item := &storeItem{key: iter.Key()}
198 fun, err := getDeserialFun(iter.Key())
203 val, err := fun(iter.Value())
209 items = append(items, item)
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)
223 bytes, err := fun(item.val)
228 batch.Set(item.key, bytes)
231 return database.NewStore(testDB), testDB, nil
234 func sortSpendOutputID(block *types.Block) {
235 for _, tx := range block.Transactions {
236 sort.Sort(HashSlice(tx.SpentOutputIDs))
240 type HashSlice []bc.Hash
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] }