OSDN Git Service

Dev utxo unit test (#1606)
authorwz <mars@bytom.io>
Sat, 2 Mar 2019 03:23:31 +0000 (11:23 +0800)
committerPaladz <yzhu101@uottawa.ca>
Sat, 2 Mar 2019 03:23:31 +0000 (11:23 +0800)
* add a unit test for attacBlocks of utxoview

* modify  unit test for attacBlocks of utxoview

* recovery test file

* delete code

* Add attach block list

* add init transaction and block

* modify code format

* add error deal

test/utxo_view/utxo_view_test.go [new file with mode: 0644]
test/utxo_view/utxo_view_test_util.go [new file with mode: 0644]

diff --git a/test/utxo_view/utxo_view_test.go b/test/utxo_view/utxo_view_test.go
new file mode 100644 (file)
index 0000000..6bd9a20
--- /dev/null
@@ -0,0 +1,128 @@
+package utxo_view
+
+import (
+       "os"
+       "testing"
+
+       "github.com/bytom/testutil"
+
+       "github.com/golang/protobuf/proto"
+       dbm "github.com/tendermint/tmlibs/db"
+
+       "github.com/bytom/database/leveldb"
+       "github.com/bytom/database/storage"
+       "github.com/bytom/protocol/bc"
+       "github.com/bytom/protocol/bc/types"
+       "github.com/bytom/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(true, 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(): storage.NewUtxoEntry(false, mockBlocks[1].Height-1, false),
+                       },
+                       want: map[bc.Hash]*storage.UtxoEntry{
+                               *newTx(mockBlocks[1].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[1].Height, false),
+                               *newTx(mockBlocks[1].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
+                               *newTx(mockBlocks[1].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
+                               *newTx(mockBlocks[1].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
+                               *newTx(mockBlocks[1].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, 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},
+                               }},
+                       },
+               },
+       }
+       node := blockNode(types.MapBlock(&mockBlocks[0].Block).BlockHeader)
+       defer os.RemoveAll("temp")
+       for index, c := range cases {
+               testDB := dbm.NewDB("testdb", "leveldb", "temp")
+               store := leveldb.NewStore(testDB)
+
+               utxoViewpoint := state.NewUtxoViewpoint()
+               for k, v := range c.before {
+                       utxoViewpoint.Entries[k] = v
+               }
+               if err := store.SaveChainStatus(node, utxoViewpoint); 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(node, utxoViewpoint); 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")
+       }
+}
diff --git a/test/utxo_view/utxo_view_test_util.go b/test/utxo_view/utxo_view_test_util.go
new file mode 100644 (file)
index 0000000..f2089de
--- /dev/null
@@ -0,0 +1,172 @@
+package utxo_view
+
+import (
+       "encoding/hex"
+
+       "github.com/bytom/consensus"
+       "github.com/bytom/consensus/difficulty"
+       "github.com/bytom/protocol/bc"
+       "github.com/bytom/protocol/bc/types"
+       "github.com/bytom/protocol/state"
+       "github.com/bytom/testutil"
+)
+
+const utxoPreFix = "UT:"
+
+func calcUtxoKey(hash *bc.Hash) []byte {
+       return []byte(utxoPreFix + hash.String())
+}
+
+type tx struct {
+       Tx *types.Tx
+}
+
+func newTx(t *types.Tx) *tx {
+       return &tx{
+               Tx: t,
+       }
+}
+
+func (t *tx) getSourceID(outIndex int) *bc.Hash {
+       output := t.Tx.Entries[*t.Tx.OutputID(outIndex)].(*bc.Output)
+       return output.Source.Ref
+}
+
+func (t *tx) getAmount(outIndex int) uint64 {
+       output := t.Tx.Entries[*t.Tx.OutputID(outIndex)].(*bc.Output)
+       return output.Source.Value.Amount
+}
+
+func (t *tx) getSpentOutputID() bc.Hash {
+       return t.Tx.SpentOutputIDs[0]
+}
+
+func (t *tx) OutputHash(outIndex int) *bc.Hash {
+       return t.Tx.ResultIds[outIndex]
+}
+
+func blockNode(header *bc.BlockHeader) *state.BlockNode {
+       h := types.BlockHeader{
+               Version:           header.Version,
+               Height:            header.Height,
+               PreviousBlockHash: *header.PreviousBlockId,
+               Timestamp:         header.Timestamp,
+               Bits:              header.Bits,
+               Nonce:             header.Nonce,
+       }
+       return &state.BlockNode{
+               Parent:    nil,
+               Hash:      h.Hash(),
+               WorkSum:   difficulty.CalcWork(h.Bits),
+               Version:   h.Version,
+               Height:    h.Height,
+               Timestamp: h.Timestamp,
+               Nonce:     h.Nonce,
+               Bits:      h.Bits,
+       }
+}
+
+func mustDecodeHex(str string) []byte {
+       data, err := hex.DecodeString(str)
+       if err != nil {
+               panic(err)
+       }
+       return data
+}
+
+func coinBaseTx(amount uint64, arbitrary string) *types.Tx {
+       return types.NewTx(types.TxData{
+               Inputs: []*types.TxInput{
+                       types.NewCoinbaseInput([]byte(arbitrary)),
+               },
+               Outputs: []*types.TxOutput{
+                       types.NewTxOutput(*consensus.BTMAssetID, amount, mustDecodeHex("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
+               },
+       })
+}
+
+var mockTransaction = []*tx{}
+var mockBlocks = []*block{}
+
+func toHash(hash string) bc.Hash {
+       sourceID := bc.Hash{}
+       sourceID.UnmarshalText([]byte(hash))
+       return sourceID
+}
+
+type block struct {
+       types.Block
+}
+
+func init() {
+       t := &tx{
+               Tx: types.NewTx(types.TxData{
+                       Inputs: []*types.TxInput{
+                               types.NewSpendInput(nil, toHash("ca9b179e549406aa583869e124e39817414d4500a8ce5476e95b6018d182b966"), *consensus.BTMAssetID, 41250000000, 0, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
+                       },
+                       Outputs: []*types.TxOutput{
+                               types.NewTxOutput(*consensus.BTMAssetID, 100000000, []byte("00148c704747e94387fa0b8712b053ed2132d84820ac")),
+                               types.NewTxOutput(*consensus.BTMAssetID, 41150000000, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
+                       },
+               }),
+       }
+       mockTransaction = append(mockTransaction, t)
+
+       t = &tx{
+               Tx: types.NewTx(types.TxData{
+                       Inputs: []*types.TxInput{
+                               types.NewSpendInput(nil, *mockTransaction[0].getSourceID(1), *consensus.BTMAssetID, 41150000000, 1, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
+                       },
+                       Outputs: []*types.TxOutput{
+                               types.NewTxOutput(*consensus.BTMAssetID, 100000000, []byte("00148c704747e94387fa0b8712b053ed2132d84820ac")),
+                               types.NewTxOutput(*consensus.BTMAssetID, 41050000000, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
+                       },
+               }),
+       }
+       mockTransaction = append(mockTransaction, t)
+
+       t = &tx{
+               Tx: types.NewTx(types.TxData{
+                       Inputs: []*types.TxInput{
+                               types.NewSpendInput(nil, *mockTransaction[1].getSourceID(1), *consensus.BTMAssetID, 41050000000, 1, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
+                       },
+                       Outputs: []*types.TxOutput{
+                               types.NewTxOutput(*consensus.BTMAssetID, 100000000, []byte("00148c704747e94387fa0b8712b053ed2132d84820ac")),
+                               types.NewTxOutput(*consensus.BTMAssetID, 40950000000, []byte("00144431c4278632c6e35dd2870faa1a4b8e0a275cbc")),
+                       },
+               }),
+       }
+       mockTransaction = append(mockTransaction, t)
+
+       mockBlocks = []*block{
+               // coinbase tx
+               &block{Block: types.Block{
+                       BlockHeader: types.BlockHeader{
+                               Height:            100,
+                               PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
+                               Timestamp:         1522908275,
+                               Nonce:             0,
+                       },
+                       Transactions: []*types.Tx{
+                               coinBaseTx(41250000000, "arbitrary block0"),
+                       },
+               }},
+
+               // Chain trading 3
+               &block{Block: types.Block{
+                       BlockHeader: types.BlockHeader{
+                               Height:            101,
+                               PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"),
+                               Timestamp:         1522908275,
+                               Nonce:             0,
+                       },
+                       Transactions: []*types.Tx{
+                               coinBaseTx(41250000000, "arbitrary block1"),
+                               mockTransaction[0].Tx,
+                               mockTransaction[1].Tx,
+                               mockTransaction[2].Tx,
+                       },
+               }},
+       }
+
+}