2014-01-09 06:54:52 +01:00
|
|
|
// Copyright (c) 2013-2014 Conformal Systems LLC.
|
2013-08-03 17:20:05 +02:00
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package ldb_test
|
|
|
|
|
|
|
|
import (
|
2013-08-22 17:40:59 +02:00
|
|
|
"fmt"
|
2014-07-03 02:47:24 +02:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"testing"
|
|
|
|
|
2015-01-27 18:45:10 +01:00
|
|
|
"github.com/btcsuite/btcd/database"
|
|
|
|
_ "github.com/btcsuite/btcd/database/ldb"
|
2015-02-05 22:16:39 +01:00
|
|
|
"github.com/btcsuite/btcd/wire"
|
2015-01-15 17:33:06 +01:00
|
|
|
"github.com/btcsuite/btcutil"
|
2013-08-03 17:20:05 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var tstBlocks []*btcutil.Block
|
|
|
|
|
|
|
|
func loadblocks(t *testing.T) []*btcutil.Block {
|
|
|
|
if len(tstBlocks) != 0 {
|
|
|
|
return tstBlocks
|
|
|
|
}
|
|
|
|
|
2013-10-12 08:48:27 +02:00
|
|
|
testdatafile := filepath.Join("..", "testdata", "blocks1-256.bz2")
|
2013-08-03 17:20:05 +02:00
|
|
|
blocks, err := loadBlocks(t, testdatafile)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Unable to load blocks from test data: %v", err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
tstBlocks = blocks
|
|
|
|
return blocks
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUnspentInsert(t *testing.T) {
|
2014-01-20 00:34:54 +01:00
|
|
|
testUnspentInsert(t)
|
2013-08-03 17:20:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// insert every block in the test chain
|
|
|
|
// after each insert, fetch all the tx affected by the latest
|
|
|
|
// block and verify that the the tx is spent/unspent
|
|
|
|
// new tx should be fully unspent, referenced tx should have
|
|
|
|
// the associated txout set to spent.
|
2014-01-20 00:34:54 +01:00
|
|
|
func testUnspentInsert(t *testing.T) {
|
2013-08-03 17:20:05 +02:00
|
|
|
// Ignore db remove errors since it means we didn't have an old one.
|
2014-01-20 00:34:54 +01:00
|
|
|
dbname := fmt.Sprintf("tstdbuspnt1")
|
2013-09-25 22:18:35 +02:00
|
|
|
dbnamever := dbname + ".ver"
|
2013-08-03 17:20:05 +02:00
|
|
|
_ = os.RemoveAll(dbname)
|
2013-09-25 22:18:35 +02:00
|
|
|
_ = os.RemoveAll(dbnamever)
|
2015-01-27 18:45:10 +01:00
|
|
|
db, err := database.CreateDB("leveldb", dbname)
|
2013-08-03 17:20:05 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Failed to open test database %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(dbname)
|
2013-09-25 22:18:35 +02:00
|
|
|
defer os.RemoveAll(dbnamever)
|
2014-07-07 16:50:50 +02:00
|
|
|
defer func() {
|
|
|
|
if err := db.Close(); err != nil {
|
|
|
|
t.Errorf("Close: unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
}()
|
2013-08-03 17:20:05 +02:00
|
|
|
|
|
|
|
blocks := loadblocks(t)
|
|
|
|
endtest:
|
|
|
|
for height := int64(0); height < int64(len(blocks)); height++ {
|
|
|
|
|
|
|
|
block := blocks[height]
|
2014-12-25 00:55:14 +01:00
|
|
|
// look up inputs to this tx
|
2013-08-03 17:20:05 +02:00
|
|
|
mblock := block.MsgBlock()
|
2015-02-05 22:16:39 +01:00
|
|
|
var txneededList []*wire.ShaHash
|
|
|
|
var txlookupList []*wire.ShaHash
|
|
|
|
var txOutList []*wire.ShaHash
|
|
|
|
var txInList []*wire.OutPoint
|
2013-08-03 17:20:05 +02:00
|
|
|
for _, tx := range mblock.Transactions {
|
|
|
|
for _, txin := range tx.TxIn {
|
2014-10-01 14:52:19 +02:00
|
|
|
if txin.PreviousOutPoint.Index == uint32(4294967295) {
|
2013-08-03 17:20:05 +02:00
|
|
|
continue
|
|
|
|
}
|
2014-10-01 14:52:19 +02:00
|
|
|
origintxsha := &txin.PreviousOutPoint.Hash
|
2013-08-03 17:20:05 +02:00
|
|
|
|
2014-10-01 14:52:19 +02:00
|
|
|
txInList = append(txInList, &txin.PreviousOutPoint)
|
2013-08-03 17:20:05 +02:00
|
|
|
txneededList = append(txneededList, origintxsha)
|
|
|
|
txlookupList = append(txlookupList, origintxsha)
|
|
|
|
|
2014-07-07 16:50:50 +02:00
|
|
|
exists, err := db.ExistsTxSha(origintxsha)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("ExistsTxSha: unexpected error %v ", err)
|
|
|
|
}
|
|
|
|
if !exists {
|
2013-08-03 17:20:05 +02:00
|
|
|
t.Errorf("referenced tx not found %v ", origintxsha)
|
|
|
|
}
|
|
|
|
}
|
2015-04-17 08:09:21 +02:00
|
|
|
txshaname := tx.TxSha()
|
2013-08-03 17:20:05 +02:00
|
|
|
txlookupList = append(txlookupList, &txshaname)
|
|
|
|
txOutList = append(txOutList, &txshaname)
|
|
|
|
}
|
|
|
|
|
2015-02-05 22:16:39 +01:00
|
|
|
txneededmap := map[wire.ShaHash]*database.TxListReply{}
|
2013-10-03 21:21:45 +02:00
|
|
|
txlist := db.FetchUnSpentTxByShaList(txneededList)
|
2013-08-03 17:20:05 +02:00
|
|
|
for _, txe := range txlist {
|
|
|
|
if txe.Err != nil {
|
|
|
|
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
|
|
|
break endtest
|
|
|
|
}
|
|
|
|
txneededmap[*txe.Sha] = txe
|
|
|
|
}
|
|
|
|
for _, spend := range txInList {
|
|
|
|
itxe := txneededmap[spend.Hash]
|
|
|
|
if itxe.TxSpent[spend.Index] == true {
|
|
|
|
t.Errorf("txin %v:%v is already spent", spend.Hash, spend.Index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
newheight, err := db.InsertBlock(block)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to insert block %v err %v", height, err)
|
|
|
|
break endtest
|
|
|
|
}
|
|
|
|
if newheight != height {
|
|
|
|
t.Errorf("height mismatch expect %v returned %v", height, newheight)
|
|
|
|
break endtest
|
|
|
|
}
|
|
|
|
|
2015-02-05 22:16:39 +01:00
|
|
|
txlookupmap := map[wire.ShaHash]*database.TxListReply{}
|
2013-09-30 23:44:26 +02:00
|
|
|
txlist = db.FetchTxByShaList(txlookupList)
|
2013-08-03 17:20:05 +02:00
|
|
|
for _, txe := range txlist {
|
|
|
|
if txe.Err != nil {
|
|
|
|
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
|
|
|
break endtest
|
|
|
|
}
|
|
|
|
txlookupmap[*txe.Sha] = txe
|
|
|
|
}
|
|
|
|
for _, spend := range txInList {
|
|
|
|
itxe := txlookupmap[spend.Hash]
|
|
|
|
if itxe.TxSpent[spend.Index] == false {
|
|
|
|
t.Errorf("txin %v:%v is unspent %v", spend.Hash, spend.Index, itxe.TxSpent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, txo := range txOutList {
|
|
|
|
itxe := txlookupmap[*txo]
|
|
|
|
for i, spent := range itxe.TxSpent {
|
|
|
|
if spent == true {
|
|
|
|
t.Errorf("freshly inserted tx %v already spent %v", txo, i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if len(txInList) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
dropblock := blocks[height-1]
|
|
|
|
|
2015-04-17 07:58:45 +02:00
|
|
|
err = db.DropAfterBlockBySha(dropblock.Sha())
|
2013-08-03 17:20:05 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to drop block %v err %v", height, err)
|
|
|
|
break endtest
|
|
|
|
}
|
|
|
|
|
2015-02-05 22:16:39 +01:00
|
|
|
txlookupmap = map[wire.ShaHash]*database.TxListReply{}
|
2013-10-03 21:21:45 +02:00
|
|
|
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
2013-08-03 17:20:05 +02:00
|
|
|
for _, txe := range txlist {
|
|
|
|
if txe.Err != nil {
|
|
|
|
if _, ok := txneededmap[*txe.Sha]; ok {
|
|
|
|
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
|
|
|
break endtest
|
|
|
|
}
|
|
|
|
}
|
|
|
|
txlookupmap[*txe.Sha] = txe
|
|
|
|
}
|
|
|
|
for _, spend := range txInList {
|
|
|
|
itxe := txlookupmap[spend.Hash]
|
|
|
|
if itxe.TxSpent[spend.Index] == true {
|
|
|
|
t.Errorf("txin %v:%v is unspent %v", spend.Hash, spend.Index, itxe.TxSpent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
newheight, err = db.InsertBlock(block)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("failed to insert block %v err %v", height, err)
|
|
|
|
break endtest
|
|
|
|
}
|
2015-02-05 22:16:39 +01:00
|
|
|
txlookupmap = map[wire.ShaHash]*database.TxListReply{}
|
2013-09-30 23:44:26 +02:00
|
|
|
txlist = db.FetchTxByShaList(txlookupList)
|
2013-08-03 17:20:05 +02:00
|
|
|
for _, txe := range txlist {
|
|
|
|
if txe.Err != nil {
|
|
|
|
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
|
|
|
break endtest
|
|
|
|
}
|
|
|
|
txlookupmap[*txe.Sha] = txe
|
|
|
|
}
|
|
|
|
for _, spend := range txInList {
|
|
|
|
itxe := txlookupmap[spend.Hash]
|
|
|
|
if itxe.TxSpent[spend.Index] == false {
|
|
|
|
t.Errorf("txin %v:%v is unspent %v", spend.Hash, spend.Index, itxe.TxSpent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|