github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/test/utxo_view/utxo_view_test.go (about) 1 package utxo_view 2 3 import ( 4 "os" 5 "testing" 6 7 "github.com/golang/protobuf/proto" 8 9 "github.com/bytom/bytom/database" 10 dbm "github.com/bytom/bytom/database/leveldb" 11 "github.com/bytom/bytom/database/storage" 12 "github.com/bytom/bytom/protocol/bc" 13 "github.com/bytom/bytom/protocol/bc/types" 14 "github.com/bytom/bytom/protocol/state" 15 "github.com/bytom/bytom/testutil" 16 ) 17 18 func TestAttachOrDetachBlocks(t *testing.T) { 19 cases := []struct { 20 desc string 21 before map[bc.Hash]*storage.UtxoEntry 22 want map[bc.Hash]*storage.UtxoEntry 23 attachBlock []*bc.Block 24 detachBlock []*bc.Block 25 }{ 26 { 27 desc: "coinbase tx", 28 before: make(map[bc.Hash]*storage.UtxoEntry), 29 want: map[bc.Hash]*storage.UtxoEntry{*newTx(mockBlocks[0].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[0].Block.Height, false)}, 30 attachBlock: []*bc.Block{ 31 types.MapBlock(&mockBlocks[0].Block), 32 }, 33 }, 34 { 35 desc: "Chain trading 3", 36 before: map[bc.Hash]*storage.UtxoEntry{ 37 newTx(mockBlocks[1].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height-1, false), 38 }, 39 want: map[bc.Hash]*storage.UtxoEntry{ 40 *newTx(mockBlocks[1].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[1].Height, false), 41 *newTx(mockBlocks[1].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false), 42 *newTx(mockBlocks[1].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false), 43 *newTx(mockBlocks[1].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false), 44 *newTx(mockBlocks[1].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false), 45 }, 46 attachBlock: []*bc.Block{ 47 types.MapBlock(&mockBlocks[1].Block), 48 }, 49 }, 50 { 51 desc: "detach 1 block, attach 2 block", 52 before: map[bc.Hash]*storage.UtxoEntry{ 53 *newTx(mockBlocks[2].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[2].Height, false), 54 *newTx(mockBlocks[2].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[2].Height, false), 55 *newTx(mockBlocks[2].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[2].Height, false), 56 }, 57 want: map[bc.Hash]*storage.UtxoEntry{ 58 *newTx(mockBlocks[3].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[3].Height, false), 59 *newTx(mockBlocks[3].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[3].Height, false), 60 61 *newTx(mockBlocks[4].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[4].Height, false), 62 *newTx(mockBlocks[4].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[4].Height, false), 63 *newTx(mockBlocks[4].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[4].Height, false), 64 }, 65 attachBlock: []*bc.Block{ 66 types.MapBlock(&mockBlocks[3].Block), 67 types.MapBlock(&mockBlocks[4].Block), 68 }, 69 detachBlock: []*bc.Block{ 70 types.MapBlock(&mockBlocks[2].Block), 71 }, 72 }, 73 { 74 desc: "detach block 5, attach block 2", 75 before: map[bc.Hash]*storage.UtxoEntry{ 76 *newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[5].Height, false), 77 *newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false), 78 *newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false), 79 80 *newTx(mockBlocks[6].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[6].Height, false), 81 *newTx(mockBlocks[6].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), 82 *newTx(mockBlocks[6].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), 83 *newTx(mockBlocks[6].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), 84 *newTx(mockBlocks[6].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), 85 *newTx(mockBlocks[6].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), 86 *newTx(mockBlocks[6].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), 87 *newTx(mockBlocks[6].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), 88 *newTx(mockBlocks[6].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), 89 90 *newTx(mockBlocks[7].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[7].Height, false), 91 *newTx(mockBlocks[7].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false), 92 *newTx(mockBlocks[7].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false), 93 *newTx(mockBlocks[7].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false), 94 *newTx(mockBlocks[7].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false), 95 96 *newTx(mockBlocks[8].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[8].Height, false), 97 *newTx(mockBlocks[8].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), 98 *newTx(mockBlocks[8].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), 99 *newTx(mockBlocks[8].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), 100 *newTx(mockBlocks[8].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), 101 *newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), 102 *newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), 103 *newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), 104 *newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), 105 106 *newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[9].Height, false), 107 *newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false), 108 *newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false), 109 }, 110 want: map[bc.Hash]*storage.UtxoEntry{ 111 *newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[10].Height, false), 112 *newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 113 *newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 114 *newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 115 *newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 116 *newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 117 *newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 118 *newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 119 *newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 120 *newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 121 *newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 122 *newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 123 *newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 124 *newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 125 *newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 126 *newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 127 *newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 128 *newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 129 *newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), 130 131 *newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[11].Height, false), 132 *newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), 133 *newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), 134 *newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), 135 *newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), 136 *newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), 137 *newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), 138 }, 139 attachBlock: []*bc.Block{ 140 types.MapBlock(&mockBlocks[10].Block), 141 types.MapBlock(&mockBlocks[11].Block), 142 }, 143 detachBlock: []*bc.Block{ 144 types.MapBlock(&mockBlocks[9].Block), 145 types.MapBlock(&mockBlocks[8].Block), 146 types.MapBlock(&mockBlocks[7].Block), 147 types.MapBlock(&mockBlocks[6].Block), 148 types.MapBlock(&mockBlocks[5].Block), 149 }, 150 }, 151 { 152 desc: "detach block 2, attach block 1. Chain trading", 153 before: map[bc.Hash]*storage.UtxoEntry{ 154 // coinbase tx 155 *newTx(mockBlocks[12].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[12].Height, false), 156 *newTx(mockBlocks[12].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false), 157 *newTx(mockBlocks[12].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false), 158 *newTx(mockBlocks[12].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false), 159 *newTx(mockBlocks[12].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false), 160 161 *newTx(mockBlocks[13].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[13].Height, false), 162 *newTx(mockBlocks[13].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false), 163 *newTx(mockBlocks[13].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false), 164 *newTx(mockBlocks[13].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false), 165 }, 166 want: map[bc.Hash]*storage.UtxoEntry{ 167 newTx(mockBlocks[12].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(storage.NormalUTXOType, 0, false), 168 *newTx(mockBlocks[14].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[14].Height, false), 169 }, 170 attachBlock: []*bc.Block{ 171 types.MapBlock(&mockBlocks[14].Block), 172 }, 173 detachBlock: []*bc.Block{ 174 types.MapBlock(&mockBlocks[13].Block), 175 types.MapBlock(&mockBlocks[12].Block), 176 }, 177 }, 178 } 179 mockBlockHeader := &mockBlocks[0].Block.BlockHeader 180 defer os.RemoveAll("temp") 181 182 for index, c := range cases { 183 testDB := dbm.NewDB("testdb", "leveldb", "temp") 184 store := database.NewStore(testDB) 185 186 utxoViewpoint := state.NewUtxoViewpoint() 187 for k, v := range c.before { 188 utxoViewpoint.Entries[k] = v 189 } 190 contractView := state.NewContractViewpoint() 191 if err := store.SaveChainStatus(mockBlockHeader, []*types.BlockHeader{mockBlockHeader}, utxoViewpoint, contractView, 0, &bc.Hash{}); err != nil { 192 t.Error(err) 193 } 194 195 utxoViewpoint = state.NewUtxoViewpoint() 196 for _, block := range c.detachBlock { 197 if err := store.GetTransactionsUtxo(utxoViewpoint, block.Transactions); err != nil { 198 t.Error(err) 199 } 200 if err := utxoViewpoint.DetachBlock(block); err != nil { 201 t.Error(err) 202 } 203 } 204 205 for _, block := range c.attachBlock { 206 if err := store.GetTransactionsUtxo(utxoViewpoint, block.Transactions); err != nil { 207 t.Error(err) 208 } 209 if err := utxoViewpoint.ApplyBlock(block); err != nil { 210 t.Error(err) 211 } 212 } 213 if err := store.SaveChainStatus(mockBlockHeader, []*types.BlockHeader{mockBlockHeader}, utxoViewpoint, contractView, 0, &bc.Hash{}); err != nil { 214 t.Error(err) 215 } 216 217 want := map[string]*storage.UtxoEntry{} 218 result := make(map[string]*storage.UtxoEntry) 219 220 for k, v := range c.want { 221 want[string(database.CalcUtxoKey(&k))] = v 222 } 223 224 iter := testDB.IteratorPrefix([]byte(database.UtxoKeyPrefix)) 225 defer iter.Release() 226 227 for iter.Next() { 228 utxoEntry := &storage.UtxoEntry{} 229 if err := proto.Unmarshal(iter.Value(), utxoEntry); err != nil { 230 t.Error(err) 231 } 232 key := string(iter.Key()) 233 result[key] = utxoEntry 234 } 235 236 if !testutil.DeepEqual(want, result) { 237 t.Errorf("case [%d] fail. want: %v, result: %v", index, want, result) 238 } 239 240 testDB.Close() 241 os.RemoveAll("temp") 242 } 243 }