github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/test/integration/block_integration_util.go (about)

     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/bytom/database"
    14  	dbm "github.com/bytom/bytom/database/leveldb"
    15  	"github.com/bytom/bytom/database/storage"
    16  	"github.com/bytom/bytom/event"
    17  	"github.com/bytom/bytom/protocol"
    18  	"github.com/bytom/bytom/protocol/bc"
    19  	"github.com/bytom/bytom/protocol/bc/types"
    20  	"github.com/bytom/bytom/protocol/state"
    21  	"github.com/bytom/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] }