github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/test/integration/block_integration_util.go (about)

     1  package integration
     2  
     3  import (
     4  	"encoding/hex"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  	"reflect"
     9  	"sort"
    10  	"strings"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  
    14  	"github.com/bytom/bytom/database"
    15  	dbm "github.com/bytom/bytom/database/leveldb"
    16  	"github.com/bytom/bytom/database/storage"
    17  	"github.com/bytom/bytom/event"
    18  	"github.com/bytom/bytom/protocol"
    19  	"github.com/bytom/bytom/protocol/bc"
    20  	"github.com/bytom/bytom/protocol/bc/types"
    21  	"github.com/bytom/bytom/protocol/state"
    22  	"github.com/bytom/bytom/testutil"
    23  )
    24  
    25  const (
    26  	dbDir = "temp"
    27  )
    28  
    29  type storeItem struct {
    30  	key []byte
    31  	val interface{}
    32  }
    33  
    34  type storeItems []*storeItem
    35  
    36  type processBlockTestCase struct {
    37  	desc             string
    38  	initStore        []storeEntry
    39  	wantStore        []storeEntry
    40  	initOrphanManage *protocol.OrphanManage
    41  	wantOrphanManage *protocol.OrphanManage
    42  	wantIsOrphan     bool
    43  	wantError        bool
    44  	newBlock         *types.Block
    45  }
    46  
    47  func (p *processBlockTestCase) Run() error {
    48  	defer os.RemoveAll(dbDir)
    49  	if p.initStore == nil {
    50  		p.initStore = make([]storeEntry, 0)
    51  	}
    52  	store, db, err := initStore(p)
    53  	if err != nil {
    54  		return err
    55  	}
    56  
    57  	orphanManage := p.initOrphanManage
    58  	if orphanManage == nil {
    59  		orphanManage = protocol.NewOrphanManage()
    60  	}
    61  
    62  	txPool := protocol.NewTxPool(store, event.NewDispatcher())
    63  	chain, err := protocol.NewChainWithOrphanManage(store, txPool, orphanManage, nil)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	isOrphan, err := chain.ProcessBlock(p.newBlock)
    69  	if p.wantError != (err != nil) {
    70  		return fmt.Errorf("#case(%s) want error:%t, got error:%t", p.desc, p.wantError, err != nil)
    71  	}
    72  
    73  	if isOrphan != p.wantIsOrphan {
    74  		return fmt.Errorf("#case(%s) want orphan:%t, got orphan:%t", p.desc, p.wantIsOrphan, isOrphan)
    75  	}
    76  
    77  	if p.wantStore != nil {
    78  		gotStoreEntries := loadStoreEntries(db)
    79  		if !equalsStoreEntries(p.wantStore, gotStoreEntries) {
    80  			gotMap := make(map[string]string)
    81  			for _, entry := range gotStoreEntries {
    82  				gotMap[hex.EncodeToString(entry.key)] = hex.EncodeToString(entry.val)
    83  			}
    84  
    85  			wantMap := make(map[string]string)
    86  			for _, entry := range p.wantStore {
    87  				wantMap[hex.EncodeToString(entry.key)] = hex.EncodeToString(entry.val)
    88  			}
    89  			return fmt.Errorf("#case(%s) want store:%v, got store:%v", p.desc, p.wantStore, gotStoreEntries)
    90  		}
    91  	}
    92  
    93  	if p.wantOrphanManage != nil {
    94  		if !orphanManage.Equals(p.wantOrphanManage) {
    95  			return fmt.Errorf("#case(%s) want orphan manage:%v, got orphan manage:%v", p.desc, *p.wantOrphanManage, *orphanManage)
    96  		}
    97  	}
    98  	return nil
    99  }
   100  
   101  func initStore(c *processBlockTestCase) (state.Store, dbm.DB, error) {
   102  	testDB := dbm.NewDB("testdb", "leveldb", dbDir)
   103  	batch := testDB.NewBatch()
   104  	for _, entry := range c.initStore {
   105  		batch.Set(entry.key, entry.val)
   106  	}
   107  	batch.Write()
   108  	return database.NewStore(testDB), testDB, nil
   109  }
   110  
   111  func sortSpendOutputID(block *types.Block) {
   112  	for _, tx := range block.Transactions {
   113  		sort.Sort(HashSlice(tx.SpentOutputIDs))
   114  	}
   115  }
   116  
   117  type HashSlice []bc.Hash
   118  
   119  func (p HashSlice) Len() int           { return len(p) }
   120  func (p HashSlice) Less(i, j int) bool { return p[i].String() < p[j].String() }
   121  func (p HashSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
   122  
   123  type storeEntry struct {
   124  	key []byte
   125  	val []byte
   126  }
   127  
   128  func serialItem(item *storeItem) ([]storeEntry, error) {
   129  	var storeEntrys []storeEntry
   130  	switch item.val.(type) {
   131  	case *state.BlockStoreState:
   132  		bytes, err := json.Marshal(item.val)
   133  		if err != nil {
   134  			return nil, err
   135  		}
   136  
   137  		storeEntrys = append(storeEntrys, storeEntry{key: item.key, val: bytes})
   138  	case *types.Block:
   139  		block := item.val.(*types.Block)
   140  		hash := block.Hash()
   141  		binaryBlockHeader, err := block.MarshalTextForBlockHeader()
   142  		if err != nil {
   143  			return nil, err
   144  		}
   145  
   146  		storeEntrys = append(storeEntrys, storeEntry{key: database.CalcBlockHeaderKey(&hash), val: binaryBlockHeader})
   147  		binaryBlockTxs, err := block.MarshalTextForTransactions()
   148  		if err != nil {
   149  			return nil, err
   150  		}
   151  
   152  		storeEntrys = append(storeEntrys, storeEntry{key: database.CalcBlockTransactionsKey(&hash), val: binaryBlockTxs})
   153  	case types.BlockHeader:
   154  		bh := item.val.(types.BlockHeader)
   155  		bytes, err := bh.MarshalText()
   156  		if err != nil {
   157  			return nil, err
   158  		}
   159  
   160  		storeEntrys = append(storeEntrys, storeEntry{key: item.key, val: bytes})
   161  	case *storage.UtxoEntry:
   162  		utxo := item.val.(*storage.UtxoEntry)
   163  		bytes, err := proto.Marshal(utxo)
   164  		if err != nil {
   165  			return nil, err
   166  		}
   167  
   168  		storeEntrys = append(storeEntrys, storeEntry{key: item.key, val: bytes})
   169  	default:
   170  		typ := reflect.TypeOf(item.val)
   171  		return nil, fmt.Errorf("can not found any serialization function for type:%s", typ.Name())
   172  	}
   173  
   174  	return storeEntrys, nil
   175  }
   176  
   177  func equalsStoreEntries(s1, s2 []storeEntry) bool {
   178  	itemMap1 := make(map[string]interface{}, len(s1))
   179  	for _, item := range s1 {
   180  		itemMap1[string(item.key)] = item.val
   181  	}
   182  
   183  	itemMap2 := make(map[string]interface{}, len(s2))
   184  	for _, item := range s2 {
   185  		itemMap2[string(item.key)] = item.val
   186  	}
   187  
   188  	return testutil.DeepEqual(itemMap1, itemMap2)
   189  }
   190  
   191  func loadStoreEntries(db dbm.DB) []storeEntry {
   192  	var entries []storeEntry
   193  	iter := db.Iterator()
   194  	defer iter.Release()
   195  	for iter.Next() {
   196  		if strings.HasPrefix(string(iter.Key()), string(database.BlockHashesKeyPrefix)) {
   197  			continue
   198  		}
   199  
   200  		item := storeEntry{key: iter.Key(), val: iter.Value()}
   201  		entries = append(entries, item)
   202  	}
   203  	return entries
   204  }