package utxo_view import ( "os" "testing" "github.com/vapor/testutil" "github.com/golang/protobuf/proto" "github.com/vapor/database" dbm "github.com/vapor/database/leveldb" "github.com/vapor/database/storage" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" "github.com/vapor/protocol/state" ) func TestAttachOrDetachBlocks(t *testing.T) { cases := []struct { desc string before map[bc.Hash]*storage.UtxoEntry want map[bc.Hash]*storage.UtxoEntry attachBlock []*bc.Block detachBlock []*bc.Block attachTxStatus []*bc.TransactionStatus detachTxStatus []*bc.TransactionStatus }{ { desc: "coinbase tx", before: make(map[bc.Hash]*storage.UtxoEntry), want: map[bc.Hash]*storage.UtxoEntry{*newTx(mockBlocks[0].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[0].Block.Height, false)}, attachBlock: []*bc.Block{ types.MapBlock(&mockBlocks[0].Block), }, attachTxStatus: []*bc.TransactionStatus{ &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, }}, }, }, { desc: "Chain trading 3", before: map[bc.Hash]*storage.UtxoEntry{ newTx(mockBlocks[1].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height-1, false), }, want: map[bc.Hash]*storage.UtxoEntry{ *newTx(mockBlocks[1].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[1].Height, false), *newTx(mockBlocks[1].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false), *newTx(mockBlocks[1].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false), *newTx(mockBlocks[1].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false), *newTx(mockBlocks[1].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false), }, attachBlock: []*bc.Block{ types.MapBlock(&mockBlocks[1].Block), }, attachTxStatus: []*bc.TransactionStatus{ &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, }, }, { desc: "detach 1 block, attach 2 block", before: map[bc.Hash]*storage.UtxoEntry{ *newTx(mockBlocks[2].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[2].Height, false), *newTx(mockBlocks[2].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[2].Height, false), *newTx(mockBlocks[2].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[2].Height, false), }, want: map[bc.Hash]*storage.UtxoEntry{ *newTx(mockBlocks[3].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[3].Height, false), *newTx(mockBlocks[3].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[3].Height, false), *newTx(mockBlocks[4].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[4].Height, false), *newTx(mockBlocks[4].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[4].Height, false), *newTx(mockBlocks[4].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[4].Height, false), }, attachBlock: []*bc.Block{ types.MapBlock(&mockBlocks[3].Block), types.MapBlock(&mockBlocks[4].Block), }, detachBlock: []*bc.Block{ types.MapBlock(&mockBlocks[2].Block), }, attachTxStatus: []*bc.TransactionStatus{ &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, }, detachTxStatus: []*bc.TransactionStatus{ &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, }, }, { desc: "detach block 5, attach block 2", before: map[bc.Hash]*storage.UtxoEntry{ *newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[5].Height, false), *newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false), *newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false), *newTx(mockBlocks[6].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[7].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[7].Height, false), *newTx(mockBlocks[7].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false), *newTx(mockBlocks[7].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false), *newTx(mockBlocks[7].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false), *newTx(mockBlocks[7].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false), *newTx(mockBlocks[8].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[9].Height, false), *newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false), *newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false), }, want: map[bc.Hash]*storage.UtxoEntry{ *newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), }, attachBlock: []*bc.Block{ types.MapBlock(&mockBlocks[10].Block), types.MapBlock(&mockBlocks[11].Block), }, detachBlock: []*bc.Block{ types.MapBlock(&mockBlocks[9].Block), types.MapBlock(&mockBlocks[8].Block), types.MapBlock(&mockBlocks[7].Block), types.MapBlock(&mockBlocks[6].Block), types.MapBlock(&mockBlocks[5].Block), }, attachTxStatus: []*bc.TransactionStatus{ &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, }, detachTxStatus: []*bc.TransactionStatus{ &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, }, }, { desc: "detach block 5, attach block 2. Other asset deals failed.", before: map[bc.Hash]*storage.UtxoEntry{ *newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[5].Height, false), *newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false), *newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false), *newTx(mockBlocks[6].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), newTx(mockBlocks[6].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height-1, false), *newTx(mockBlocks[6].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), *newTx(mockBlocks[6].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false), newTx(mockBlocks[6].Transactions[2]).getSpentOutputID(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height-1, false), *newTx(mockBlocks[7].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[7].Height, false), *newTx(mockBlocks[7].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false), *newTx(mockBlocks[7].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false), newTx(mockBlocks[7].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height-1, false), *newTx(mockBlocks[8].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), newTx(mockBlocks[8].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height-1, false), *newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false), *newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[9].Height, false), *newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false), *newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false), }, want: map[bc.Hash]*storage.UtxoEntry{ *newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false), *newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), *newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false), }, attachBlock: []*bc.Block{ types.MapBlock(&mockBlocks[10].Block), types.MapBlock(&mockBlocks[11].Block), }, detachBlock: []*bc.Block{ types.MapBlock(&mockBlocks[9].Block), types.MapBlock(&mockBlocks[8].Block), types.MapBlock(&mockBlocks[7].Block), types.MapBlock(&mockBlocks[6].Block), types.MapBlock(&mockBlocks[5].Block), }, attachTxStatus: []*bc.TransactionStatus{ &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, }, detachTxStatus: []*bc.TransactionStatus{ &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: true}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: true}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: true}, &bc.TxVerifyResult{StatusFail: true}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, }, }, { desc: "detach block 2, attach block 1. Chain trading", before: map[bc.Hash]*storage.UtxoEntry{ // coinbase tx *newTx(mockBlocks[12].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[12].Height, false), *newTx(mockBlocks[12].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false), *newTx(mockBlocks[12].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false), *newTx(mockBlocks[12].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false), *newTx(mockBlocks[12].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false), *newTx(mockBlocks[13].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[13].Height, false), *newTx(mockBlocks[13].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false), *newTx(mockBlocks[13].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false), *newTx(mockBlocks[13].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false), }, want: map[bc.Hash]*storage.UtxoEntry{ newTx(mockBlocks[12].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(storage.NormalUTXOType, 0, false), *newTx(mockBlocks[14].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[14].Height, false), }, attachBlock: []*bc.Block{ types.MapBlock(&mockBlocks[14].Block), }, detachBlock: []*bc.Block{ types.MapBlock(&mockBlocks[13].Block), types.MapBlock(&mockBlocks[12].Block), }, attachTxStatus: []*bc.TransactionStatus{ &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, }, detachTxStatus: []*bc.TransactionStatus{ &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{ &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, &bc.TxVerifyResult{StatusFail: false}, }}, }, }, } mockBlockHeader := &mockBlocks[0].Block.BlockHeader defer os.RemoveAll("temp") for index, c := range cases { testDB := dbm.NewDB("testdb", "leveldb", "temp") store := database.NewStore(testDB) utxoViewpoint := state.NewUtxoViewpoint() for k, v := range c.before { utxoViewpoint.Entries[k] = v } if err := store.SaveChainStatus(mockBlockHeader, mockBlockHeader, []*types.BlockHeader{mockBlockHeader}, utxoViewpoint, []*state.VoteResult{}); err != nil { t.Error(err) } utxoViewpoint = state.NewUtxoViewpoint() for index, block := range c.detachBlock { if err := store.GetTransactionsUtxo(utxoViewpoint, block.Transactions); err != nil { t.Error(err) } if err := utxoViewpoint.DetachBlock(block, c.detachTxStatus[index]); err != nil { t.Error(err) } } for index, block := range c.attachBlock { if err := store.GetTransactionsUtxo(utxoViewpoint, block.Transactions); err != nil { t.Error(err) } if err := utxoViewpoint.ApplyBlock(block, c.attachTxStatus[index]); err != nil { t.Error(err) } } if err := store.SaveChainStatus(mockBlockHeader, mockBlockHeader, []*types.BlockHeader{mockBlockHeader}, utxoViewpoint, []*state.VoteResult{}); err != nil { t.Error(err) } want := map[string]*storage.UtxoEntry{} result := make(map[string]*storage.UtxoEntry) for k, v := range c.want { want[string(calcUtxoKey(&k))] = v } iter := testDB.IteratorPrefix([]byte(utxoPreFix)) defer iter.Release() for iter.Next() { utxoEntry := &storage.UtxoEntry{} if err := proto.Unmarshal(iter.Value(), utxoEntry); err != nil { t.Error(err) } key := string(iter.Key()) result[key] = utxoEntry } if !testutil.DeepEqual(want, result) { t.Errorf("case [%d] fail. want: %v, result: %v", index, want, result) } testDB.Close() os.RemoveAll("temp") } }