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 }