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