github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/protocol/state/utxo_view_test.go (about) 1 package state 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/bytom/bytom/consensus" 8 "github.com/bytom/bytom/database/storage" 9 "github.com/bytom/bytom/protocol/bc" 10 "github.com/bytom/bytom/testutil" 11 ) 12 13 var defaultEntry = map[bc.Hash]bc.Entry{ 14 bc.Hash{V0: 0}: &bc.OriginalOutput{ 15 Source: &bc.ValueSource{ 16 Value: &bc.AssetAmount{ 17 AssetId: &bc.AssetID{V0: 0}, 18 Amount: 1, 19 }, 20 }, 21 }, 22 } 23 24 var gasOnlyTxEntry = map[bc.Hash]bc.Entry{ 25 bc.Hash{V1: 0}: &bc.OriginalOutput{ 26 Source: &bc.ValueSource{ 27 Value: &bc.AssetAmount{ 28 AssetId: consensus.BTMAssetID, 29 Amount: 1, 30 }, 31 }, 32 }, 33 bc.Hash{V1: 1}: &bc.OriginalOutput{ 34 Source: &bc.ValueSource{ 35 Value: &bc.AssetAmount{ 36 AssetId: &bc.AssetID{V0: 999}, 37 Amount: 1, 38 }, 39 }, 40 }, 41 } 42 43 func TestApplyBlock(t *testing.T) { 44 cases := []struct { 45 block *bc.Block 46 inputView *UtxoViewpoint 47 fetchView *UtxoViewpoint 48 gasOnlyTx bool 49 err bool 50 }{ 51 { 52 // can't find prevout in tx entries 53 block: &bc.Block{ 54 BlockHeader: &bc.BlockHeader{}, 55 Transactions: []*bc.Tx{ 56 &bc.Tx{ 57 SpentOutputIDs: []bc.Hash{ 58 bc.Hash{V0: 1}, 59 }, 60 Entries: defaultEntry, 61 }, 62 }, 63 }, 64 inputView: &UtxoViewpoint{ 65 Entries: map[bc.Hash]*storage.UtxoEntry{ 66 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false), 67 }, 68 }, 69 fetchView: NewUtxoViewpoint(), 70 err: true, 71 }, 72 { 73 block: &bc.Block{ 74 BlockHeader: &bc.BlockHeader{}, 75 Transactions: []*bc.Tx{ 76 &bc.Tx{ 77 SpentOutputIDs: []bc.Hash{ 78 bc.Hash{V0: 0}, 79 }, 80 Entries: defaultEntry, 81 }, 82 }, 83 }, 84 inputView: NewUtxoViewpoint(), 85 fetchView: NewUtxoViewpoint(), 86 err: true, 87 }, 88 { 89 block: &bc.Block{ 90 BlockHeader: &bc.BlockHeader{}, 91 Transactions: []*bc.Tx{ 92 &bc.Tx{ 93 SpentOutputIDs: []bc.Hash{ 94 bc.Hash{V0: 0}, 95 }, 96 Entries: defaultEntry, 97 }, 98 }, 99 }, 100 inputView: &UtxoViewpoint{ 101 Entries: map[bc.Hash]*storage.UtxoEntry{ 102 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true), 103 }, 104 }, 105 err: true, 106 }, 107 { 108 block: &bc.Block{ 109 BlockHeader: &bc.BlockHeader{}, 110 Transactions: []*bc.Tx{ 111 &bc.Tx{ 112 TxHeader: &bc.TxHeader{ 113 ResultIds: []*bc.Hash{}, 114 }, 115 SpentOutputIDs: []bc.Hash{ 116 bc.Hash{V0: 0}, 117 }, 118 Entries: defaultEntry, 119 }, 120 }, 121 }, 122 inputView: &UtxoViewpoint{ 123 Entries: map[bc.Hash]*storage.UtxoEntry{ 124 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false), 125 }, 126 }, 127 fetchView: &UtxoViewpoint{ 128 Entries: map[bc.Hash]*storage.UtxoEntry{ 129 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true), 130 }, 131 }, 132 err: false, 133 }, 134 { 135 block: &bc.Block{ 136 BlockHeader: &bc.BlockHeader{ 137 Height: 101, 138 }, 139 Transactions: []*bc.Tx{ 140 &bc.Tx{ 141 TxHeader: &bc.TxHeader{ 142 ResultIds: []*bc.Hash{}, 143 }, 144 SpentOutputIDs: []bc.Hash{ 145 bc.Hash{V0: 0}, 146 }, 147 Entries: defaultEntry, 148 }, 149 }, 150 }, 151 inputView: &UtxoViewpoint{ 152 Entries: map[bc.Hash]*storage.UtxoEntry{ 153 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false), 154 }, 155 }, 156 fetchView: &UtxoViewpoint{ 157 Entries: map[bc.Hash]*storage.UtxoEntry{ 158 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, true), 159 }, 160 }, 161 err: false, 162 }, 163 { 164 block: &bc.Block{ 165 BlockHeader: &bc.BlockHeader{ 166 Height: 0, 167 }, 168 Transactions: []*bc.Tx{ 169 &bc.Tx{ 170 TxHeader: &bc.TxHeader{ 171 ResultIds: []*bc.Hash{}, 172 }, 173 SpentOutputIDs: []bc.Hash{ 174 bc.Hash{V0: 0}, 175 }, 176 Entries: defaultEntry, 177 }, 178 }, 179 }, 180 inputView: &UtxoViewpoint{ 181 Entries: map[bc.Hash]*storage.UtxoEntry{ 182 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false), 183 }, 184 }, 185 fetchView: &UtxoViewpoint{ 186 Entries: map[bc.Hash]*storage.UtxoEntry{ 187 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, true), 188 }, 189 }, 190 err: true, 191 }, 192 { 193 // output will be store 194 block: &bc.Block{ 195 BlockHeader: &bc.BlockHeader{}, 196 Transactions: []*bc.Tx{ 197 &bc.Tx{ 198 TxHeader: &bc.TxHeader{ 199 ResultIds: []*bc.Hash{ 200 &bc.Hash{V0: 0}, 201 }, 202 }, 203 SpentOutputIDs: []bc.Hash{}, 204 Entries: defaultEntry, 205 }, 206 }, 207 }, 208 inputView: NewUtxoViewpoint(), 209 fetchView: &UtxoViewpoint{ 210 Entries: map[bc.Hash]*storage.UtxoEntry{ 211 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false), 212 }, 213 }, 214 err: false, 215 }, 216 { 217 // non-btm asset spent input will be spent 218 block: &bc.Block{ 219 BlockHeader: &bc.BlockHeader{}, 220 Transactions: []*bc.Tx{ 221 &bc.Tx{ 222 TxHeader: &bc.TxHeader{ 223 ResultIds: []*bc.Hash{}, 224 }, 225 SpentOutputIDs: []bc.Hash{ 226 bc.Hash{V1: 0}, 227 bc.Hash{V1: 1}, 228 }, 229 Entries: gasOnlyTxEntry, 230 }, 231 }, 232 }, 233 inputView: &UtxoViewpoint{ 234 Entries: map[bc.Hash]*storage.UtxoEntry{ 235 bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false), 236 bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false), 237 }, 238 }, 239 fetchView: &UtxoViewpoint{ 240 Entries: map[bc.Hash]*storage.UtxoEntry{ 241 bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true), 242 bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true), 243 }, 244 }, 245 err: false, 246 }, 247 { 248 // apply gas only tx, non-btm asset spent output will not be store 249 block: &bc.Block{ 250 BlockHeader: &bc.BlockHeader{}, 251 Transactions: []*bc.Tx{ 252 &bc.Tx{ 253 TxHeader: &bc.TxHeader{ 254 ResultIds: []*bc.Hash{ 255 &bc.Hash{V1: 0}, 256 &bc.Hash{V1: 1}, 257 }, 258 }, 259 SpentOutputIDs: []bc.Hash{}, 260 Entries: gasOnlyTxEntry, 261 }, 262 }, 263 }, 264 inputView: NewUtxoViewpoint(), 265 fetchView: &UtxoViewpoint{ 266 Entries: map[bc.Hash]*storage.UtxoEntry{ 267 bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false), 268 bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false), 269 }, 270 }, 271 err: false, 272 }, 273 } 274 275 for i, c := range cases { 276 if err := c.inputView.ApplyBlock(c.block); c.err != (err != nil) { 277 t.Errorf("case #%d want err = %v, get err = %v", i, c.err, err) 278 } 279 if c.err { 280 continue 281 } 282 if !testutil.DeepEqual(c.inputView, c.fetchView) { 283 t.Errorf("test case %d, want %v, get %v", i, c.fetchView, c.inputView) 284 } 285 } 286 } 287 288 func TestDetachBlock(t *testing.T) { 289 cases := []struct { 290 block *bc.Block 291 inputView *UtxoViewpoint 292 fetchView *UtxoViewpoint 293 gasOnlyTx bool 294 err bool 295 }{ 296 { 297 block: &bc.Block{ 298 BlockHeader: &bc.BlockHeader{}, 299 Transactions: []*bc.Tx{ 300 &bc.Tx{ 301 TxHeader: &bc.TxHeader{ 302 ResultIds: []*bc.Hash{}, 303 }, 304 SpentOutputIDs: []bc.Hash{ 305 bc.Hash{V0: 0}, 306 }, 307 Entries: defaultEntry, 308 }, 309 }, 310 }, 311 inputView: NewUtxoViewpoint(), 312 fetchView: &UtxoViewpoint{ 313 Entries: map[bc.Hash]*storage.UtxoEntry{ 314 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false), 315 }, 316 }, 317 err: false, 318 }, 319 { 320 block: &bc.Block{ 321 BlockHeader: &bc.BlockHeader{}, 322 Transactions: []*bc.Tx{ 323 &bc.Tx{ 324 TxHeader: &bc.TxHeader{ 325 ResultIds: []*bc.Hash{ 326 &bc.Hash{V0: 0}, 327 }, 328 }, 329 SpentOutputIDs: []bc.Hash{}, 330 Entries: defaultEntry, 331 }, 332 }, 333 }, 334 inputView: NewUtxoViewpoint(), 335 fetchView: &UtxoViewpoint{ 336 Entries: map[bc.Hash]*storage.UtxoEntry{ 337 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true), 338 }, 339 }, 340 err: false, 341 }, 342 { 343 block: &bc.Block{ 344 BlockHeader: &bc.BlockHeader{}, 345 Transactions: []*bc.Tx{ 346 &bc.Tx{ 347 TxHeader: &bc.TxHeader{ 348 ResultIds: []*bc.Hash{}, 349 }, 350 SpentOutputIDs: []bc.Hash{ 351 bc.Hash{V0: 0}, 352 }, 353 Entries: defaultEntry, 354 }, 355 }, 356 }, 357 inputView: &UtxoViewpoint{ 358 Entries: map[bc.Hash]*storage.UtxoEntry{ 359 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false), 360 }, 361 }, 362 err: true, 363 }, 364 { 365 block: &bc.Block{ 366 BlockHeader: &bc.BlockHeader{}, 367 Transactions: []*bc.Tx{ 368 &bc.Tx{ 369 TxHeader: &bc.TxHeader{ 370 ResultIds: []*bc.Hash{}, 371 }, 372 SpentOutputIDs: []bc.Hash{ 373 bc.Hash{V0: 0}, 374 }, 375 Entries: defaultEntry, 376 }, 377 }, 378 }, 379 inputView: &UtxoViewpoint{ 380 Entries: map[bc.Hash]*storage.UtxoEntry{ 381 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true), 382 }, 383 }, 384 fetchView: &UtxoViewpoint{ 385 Entries: map[bc.Hash]*storage.UtxoEntry{ 386 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false), 387 }, 388 }, 389 err: false, 390 }, 391 } 392 393 for i, c := range cases { 394 if err := c.inputView.DetachBlock(c.block); c.err != (err != nil) { 395 t.Errorf("case %d want err = %v, get err = %v", i, c.err, err) 396 } 397 if c.err { 398 continue 399 } 400 if !testutil.DeepEqual(c.inputView, c.fetchView) { 401 for hash, entry := range c.inputView.Entries { 402 fmt.Println(hash.String(), ":", entry.String()) 403 } 404 405 for hash, entry := range c.fetchView.Entries { 406 fmt.Println(hash.String(), ":", entry.String()) 407 } 408 409 t.Errorf("test case %d, want %v, get %v", i, c.fetchView, c.inputView) 410 } 411 } 412 }