You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
4.1 KiB
169 lines
4.1 KiB
// Copyright (c) 2015 The btcsuite developers |
|
// Use of this source code is governed by an ISC |
|
// license that can be found in the LICENSE file. |
|
|
|
package database_test |
|
|
|
import ( |
|
"compress/bzip2" |
|
"encoding/binary" |
|
"io" |
|
"os" |
|
"path/filepath" |
|
"strings" |
|
"testing" |
|
|
|
"github.com/btcsuite/btcd/wire" |
|
"github.com/btcsuite/btcutil" |
|
) |
|
|
|
// testReorganization performs reorganization tests for the passed DB type. |
|
// Much of the setup is copied from the blockchain package, but the test looks |
|
// to see if each TX in each block in the best chain can be fetched using |
|
// FetchTxBySha. If not, then there's a bug. |
|
func testReorganization(t *testing.T, dbType string) { |
|
db, teardown, err := createDB(dbType, "reorganization", true) |
|
if err != nil { |
|
t.Fatalf("Failed to create test database (%s) %v", dbType, err) |
|
} |
|
defer teardown() |
|
|
|
blocks, err := loadReorgBlocks("reorgblocks.bz2") |
|
if err != nil { |
|
t.Fatalf("Error loading file: %v", err) |
|
} |
|
|
|
for i := int64(0); i <= 2; i++ { |
|
_, err = db.InsertBlock(blocks[i]) |
|
if err != nil { |
|
t.Fatalf("Error inserting block %d (%v): %v", i, |
|
blocks[i].Sha(), err) |
|
} |
|
var txIDs []string |
|
for _, tx := range blocks[i].Transactions() { |
|
txIDs = append(txIDs, tx.Sha().String()) |
|
} |
|
} |
|
|
|
for i := int64(1); i >= 0; i-- { |
|
blkHash := blocks[i].Sha() |
|
err = db.DropAfterBlockBySha(blkHash) |
|
if err != nil { |
|
t.Fatalf("Error removing block %d for reorganization: %v", i, err) |
|
} |
|
// Exercise NewestSha() to make sure DropAfterBlockBySha() updates the |
|
// info correctly |
|
maxHash, blkHeight, err := db.NewestSha() |
|
if err != nil { |
|
t.Fatalf("Error getting newest block info") |
|
} |
|
if !maxHash.IsEqual(blkHash) || blkHeight != i { |
|
t.Fatalf("NewestSha returned %v (%v), expected %v (%v)", blkHeight, |
|
maxHash, i, blkHash) |
|
} |
|
} |
|
|
|
for i := int64(3); i < int64(len(blocks)); i++ { |
|
blkHash := blocks[i].Sha() |
|
if err != nil { |
|
t.Fatalf("Error getting SHA for block %dA: %v", i-2, err) |
|
} |
|
_, err = db.InsertBlock(blocks[i]) |
|
if err != nil { |
|
t.Fatalf("Error inserting block %dA (%v): %v", i-2, blkHash, err) |
|
} |
|
} |
|
|
|
_, maxHeight, err := db.NewestSha() |
|
if err != nil { |
|
t.Fatalf("Error getting newest block info") |
|
} |
|
|
|
for i := int64(0); i <= maxHeight; i++ { |
|
blkHash, err := db.FetchBlockShaByHeight(i) |
|
if err != nil { |
|
t.Fatalf("Error fetching SHA for block %d: %v", i, err) |
|
} |
|
block, err := db.FetchBlockBySha(blkHash) |
|
if err != nil { |
|
t.Fatalf("Error fetching block %d (%v): %v", i, blkHash, err) |
|
} |
|
for _, tx := range block.Transactions() { |
|
_, err := db.FetchTxBySha(tx.Sha()) |
|
if err != nil { |
|
t.Fatalf("Error fetching transaction %v: %v", tx.Sha(), err) |
|
} |
|
} |
|
} |
|
} |
|
|
|
// loadReorgBlocks reads files containing bitcoin block data (bzipped but |
|
// otherwise in the format bitcoind writes) from disk and returns them as an |
|
// array of btcutil.Block. This is copied from the blockchain package, which |
|
// itself largely borrowed it from the test code in this package. |
|
func loadReorgBlocks(filename string) ([]*btcutil.Block, error) { |
|
filename = filepath.Join("testdata/", filename) |
|
|
|
var blocks []*btcutil.Block |
|
var err error |
|
|
|
var network = wire.SimNet |
|
var dr io.Reader |
|
var fi io.ReadCloser |
|
|
|
fi, err = os.Open(filename) |
|
if err != nil { |
|
return blocks, err |
|
} |
|
|
|
if strings.HasSuffix(filename, ".bz2") { |
|
dr = bzip2.NewReader(fi) |
|
} else { |
|
dr = fi |
|
} |
|
defer fi.Close() |
|
|
|
var block *btcutil.Block |
|
|
|
err = nil |
|
for height := int64(1); err == nil; height++ { |
|
var rintbuf uint32 |
|
err = binary.Read(dr, binary.LittleEndian, &rintbuf) |
|
if err == io.EOF { |
|
// hit end of file at expected offset: no warning |
|
height-- |
|
err = nil |
|
break |
|
} |
|
if err != nil { |
|
break |
|
} |
|
if rintbuf != uint32(network) { |
|
break |
|
} |
|
err = binary.Read(dr, binary.LittleEndian, &rintbuf) |
|
if err != nil { |
|
return blocks, err |
|
} |
|
blocklen := rintbuf |
|
|
|
rbytes := make([]byte, blocklen) |
|
|
|
// read block |
|
numbytes, err := dr.Read(rbytes) |
|
if err != nil { |
|
return blocks, err |
|
} |
|
if uint32(numbytes) != blocklen { |
|
return blocks, io.ErrUnexpectedEOF |
|
} |
|
|
|
block, err = btcutil.NewBlockFromBytes(rbytes) |
|
if err != nil { |
|
return blocks, err |
|
} |
|
blocks = append(blocks, block) |
|
} |
|
|
|
return blocks, nil |
|
}
|
|
|