// processBlock potentially imports the block into the database. It first
// deserializes the raw block while checking for errors. Already known blocks
// are skipped and orphan blocks are considered errors. Finally, it runs the
// block through the chain rules to ensure it follows all rules and matches
// up to the known checkpoint. Returns whether the block was imported along
// with any potential errors.
func (bi *blockImporter) processBlock(serializedBlock []byte) (bool, error) {
// Deserialize the block which includes checks for malformed blocks.
block, err := dcrutil.NewBlockFromBytes(serializedBlock)
if err != nil {
return false, err
}
// update progress statistics
bi.lastBlockTime = block.MsgBlock().Header.Timestamp
bi.receivedLogTx += int64(len(block.MsgBlock().Transactions))
// Skip blocks that already exist.
blockSha := block.Sha()
exists, err := bi.db.ExistsSha(blockSha)
if err != nil {
return false, err
}
if exists {
return false, nil
}
// Don't bother trying to process orphans.
prevHash := &block.MsgBlock().Header.PrevBlock
if !prevHash.IsEqual(&zeroHash) {
exists, err := bi.db.ExistsSha(prevHash)
if err != nil {
return false, err
}
if !exists {
return false, fmt.Errorf("import file contains block "+
"%v which does not link to the available "+
"block chain", prevHash)
}
}
// Ensure the blocks follows all of the chain rules and match up to the
// known checkpoints.
_, isOrphan, err := bi.chain.ProcessBlock(block, bi.medianTime,
blockchain.BFFastAdd)
if err != nil {
return false, err
}
if isOrphan {
return false, fmt.Errorf("import file contains an orphan "+
"block: %v", blockSha)
}
return true, nil
}
开发者ID:ironbits,项目名称:dcrd,代码行数:55,代码来源:import.go
示例4: fetchBlockBySha
// fetchBlockBySha - return a dcrutil Block
// Must be called with db lock held.
func (db *LevelDb) fetchBlockBySha(sha *chainhash.Hash) (blk *dcrutil.Block, err error) {
buf, height, err := db.fetchSha(sha)
if err != nil {
return
}
blk, err = dcrutil.NewBlockFromBytes(buf)
if err != nil {
return
}
blk.SetHeight(height)
return
}
// loadBlocks loads the blocks contained in the testdata directory and returns
// a slice of them.
func loadBlocks(t *testing.T, dataFile string, network wire.CurrencyNet) ([]*dcrutil.Block, error) {
// Open the file that contains the blocks for reading.
fi, err := os.Open(dataFile)
if err != nil {
t.Errorf("failed to open file %v, err %v", dataFile, err)
return nil, err
}
defer func() {
if err := fi.Close(); err != nil {
t.Errorf("failed to close file %v %v", dataFile,
err)
}
}()
bcStream := bzip2.NewReader(fi)
// Create a buffer of the read file.
bcBuf := new(bytes.Buffer)
bcBuf.ReadFrom(bcStream)
// Create decoder from the buffer and a map to store the data.
bcDecoder := gob.NewDecoder(bcBuf)
blockChain := make(map[int64][]byte)
// Decode the blockchain into the map.
if err := bcDecoder.Decode(&blockChain); err != nil {
t.Errorf("error decoding test blockchain: %v", err.Error())
}
// Fetch blocks 1 to 168 and perform various tests.
blocks := make([]*dcrutil.Block, 169)
for i := 0; i <= 168; i++ {
bl, err := dcrutil.NewBlockFromBytes(blockChain[int64(i)])
if err != nil {
t.Errorf("NewBlockFromBytes error: %v", err.Error())
}
bl.SetHeight(int64(i))
blocks[i] = bl
}
return blocks, nil
}
// loadReorgBlocks reads files containing decred block data (bzipped but
// otherwise in the format bitcoind writes) from disk and returns them as an
// array of dcrutil.Block. This is copied from the blockchain package, which
// itself largely borrowed it from the test code in this package.
func loadReorgBlocks(filename string) ([]*dcrutil.Block, error) {
filename = filepath.Join("../blockchain/testdata/", filename)
fi, err := os.Open(filename)
if err != nil {
return nil, err
}
bcStream := bzip2.NewReader(fi)
defer fi.Close()
// Create a buffer of the read file
bcBuf := new(bytes.Buffer)
bcBuf.ReadFrom(bcStream)
// Create decoder from the buffer and a map to store the data
bcDecoder := gob.NewDecoder(bcBuf)
blockchain := make(map[int64][]byte)
// Decode the blockchain into the map
if err := bcDecoder.Decode(&blockchain); err != nil {
return nil, err
}
var block *dcrutil.Block
blocks := make([]*dcrutil.Block, 0, len(blockchain))
for height := int64(0); height < int64(len(blockchain)); height++ {
block, err = dcrutil.NewBlockFromBytes(blockchain[height])
if err != nil {
return blocks, err
}
block.SetHeight(height)
blocks = append(blocks, block)
}
return blocks, nil
}
func TestTicketDB(t *testing.T) {
// Declare some useful variables
testBCHeight := int64(168)
// Set up a DB
database, err := database.CreateDB("leveldb", "ticketdb_test")
if err != nil {
t.Errorf("Db create error: %v", err.Error())
}
// Make a new tmdb to fill with dummy live and used tickets
var tmdb stake.TicketDB
tmdb.Initialize(simNetParams, database)
filename := filepath.Join("..", "/../blockchain/testdata", "blocks0to168.bz2")
fi, err := os.Open(filename)
bcStream := bzip2.NewReader(fi)
defer fi.Close()
// Create a buffer of the read file
bcBuf := new(bytes.Buffer)
bcBuf.ReadFrom(bcStream)
// Create decoder from the buffer and a map to store the data
bcDecoder := gob.NewDecoder(bcBuf)
blockchain := make(map[int64][]byte)
// Decode the blockchain into the map
if err := bcDecoder.Decode(&blockchain); err != nil {
t.Errorf("error decoding test blockchain")
}
var CopyOfMapsAtBlock50, CopyOfMapsAtBlock168 stake.TicketMaps
var ticketsToSpendIn167 []chainhash.Hash
var sortedTickets167 []*stake.TicketData
for i := int64(0); i <= testBCHeight; i++ {
block, err := dcrutil.NewBlockFromBytes(blockchain[i])
if err != nil {
t.Errorf("block deserialization error on block %v", i)
}
block.SetHeight(i)
database.InsertBlock(block)
tmdb.InsertBlock(block)
if i == 50 {
// Create snapshot of tmdb at block 50
CopyOfMapsAtBlock50, err = cloneTicketDB(&tmdb)
if err != nil {
t.Errorf("db cloning at block 50 failure! %v", err)
}
}
// Test to make sure that ticket selection is working correctly.
if i == 167 {
// Sort the entire list of tickets lexicographically by sorting
// each bucket and then appending it to the list. Then store it
// to use in the next block.
totalTickets := 0
sortedSlice := make([]*stake.TicketData, 0)
for i := 0; i < stake.BucketsSize; i++ {
tix, err := tmdb.DumpLiveTickets(uint8(i))
if err != nil {
t.Errorf("error dumping live tickets")
}
mapLen := len(tix)
totalTickets += mapLen
tempTdSlice := stake.NewTicketDataSlice(mapLen)
itr := 0 // Iterator
for _, td := range tix {
tempTdSlice[itr] = td
itr++
}
sort.Sort(tempTdSlice)
sortedSlice = append(sortedSlice, tempTdSlice...)
}
sortedTickets167 = sortedSlice
}
if i == 168 {
parentBlock, err := dcrutil.NewBlockFromBytes(blockchain[i-1])
if err != nil {
t.Errorf("block deserialization error on block %v", i-1)
}
pbhB, err := parentBlock.MsgBlock().Header.Bytes()
if err != nil {
t.Errorf("block header serialization error")
}
prng := stake.NewHash256PRNG(pbhB)
ts, err := stake.FindTicketIdxs(int64(len(sortedTickets167)),
int(simNetParams.TicketsPerBlock), prng)
if err != nil {
t.Errorf("failure on FindTicketIdxs")
}
for _, idx := range ts {
ticketsToSpendIn167 =
append(ticketsToSpendIn167, sortedTickets167[idx].SStxHash)
}
// Make sure that the tickets that were supposed to be spent or
//.........这里部分代码省略.........
// TestReorganization loads a set of test blocks which force a chain
// reorganization to test the block chain handling code.
func TestReorganization(t *testing.T) {
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("reorgunittest",
simNetParams)
if err != nil {
t.Errorf("Failed to setup chain instance: %v", err)
return
}
defer teardownFunc()
err = chain.GenerateInitialIndex()
if err != nil {
t.Errorf("GenerateInitialIndex: %v", err)
}
// The genesis block should fail to connect since it's already
// inserted.
genesisBlock := simNetParams.GenesisBlock
err = chain.CheckConnectBlock(dcrutil.NewBlock(genesisBlock))
if err == nil {
t.Errorf("CheckConnectBlock: Did not receive expected error")
}
// Load up the rest of the blocks up to HEAD.
filename := filepath.Join("testdata/", "reorgto179.bz2")
fi, err := os.Open(filename)
bcStream := bzip2.NewReader(fi)
defer fi.Close()
// Create a buffer of the read file
bcBuf := new(bytes.Buffer)
bcBuf.ReadFrom(bcStream)
// Create decoder from the buffer and a map to store the data
bcDecoder := gob.NewDecoder(bcBuf)
blockChain := make(map[int64][]byte)
// Decode the blockchain into the map
if err := bcDecoder.Decode(&blockChain); err != nil {
t.Errorf("error decoding test blockchain: %v", err.Error())
}
// Load up the short chain
timeSource := blockchain.NewMedianTime()
finalIdx1 := 179
for i := 1; i < finalIdx1+1; i++ {
bl, err := dcrutil.NewBlockFromBytes(blockChain[int64(i)])
if err != nil {
t.Errorf("NewBlockFromBytes error: %v", err.Error())
}
bl.SetHeight(int64(i))
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
if err != nil {
t.Errorf("ProcessBlock error: %v", err.Error())
}
}
// Load the long chain and begin loading blocks from that too,
// forcing a reorganization
// Load up the rest of the blocks up to HEAD.
filename = filepath.Join("testdata/", "reorgto180.bz2")
fi, err = os.Open(filename)
bcStream = bzip2.NewReader(fi)
defer fi.Close()
// Create a buffer of the read file
bcBuf = new(bytes.Buffer)
bcBuf.ReadFrom(bcStream)
// Create decoder from the buffer and a map to store the data
bcDecoder = gob.NewDecoder(bcBuf)
blockChain = make(map[int64][]byte)
// Decode the blockchain into the map
if err := bcDecoder.Decode(&blockChain); err != nil {
t.Errorf("error decoding test blockchain: %v", err.Error())
}
forkPoint := 131
finalIdx2 := 180
for i := forkPoint; i < finalIdx2+1; i++ {
bl, err := dcrutil.NewBlockFromBytes(blockChain[int64(i)])
if err != nil {
t.Errorf("NewBlockFromBytes error: %v", err.Error())
}
bl.SetHeight(int64(i))
_, _, err = chain.ProcessBlock(bl, timeSource, blockchain.BFNone)
if err != nil {
t.Errorf("ProcessBlock error: %v", err.Error())
}
}
// Ensure our blockchain is at the correct best tip
topBlock, _ := chain.GetTopBlock()
tipHash := topBlock.Sha()
expected, _ := chainhash.NewHashFromStr("5ab969d0afd8295b6cd1506f2a310d" +
//.........这里部分代码省略.........
// reorgTestsForced tests a forced reorganization of a single block at HEAD.
func reorgTestForced(t *testing.T) {
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("reorgunittest",
simNetParams)
if err != nil {
t.Errorf("Failed to setup chain instance: %v", err)
return
}
defer teardownFunc()
// The genesis block should fail to connect since it's already
// inserted.
genesisBlock := simNetParams.GenesisBlock
err = chain.CheckConnectBlock(dcrutil.NewBlock(genesisBlock))
if err == nil {
t.Errorf("CheckConnectBlock: Did not receive expected error")
}
// Load up the rest of the blocks up to HEAD.
filename := filepath.Join("testdata/", "reorgto179.bz2")
fi, err := os.Open(filename)
bcStream := bzip2.NewReader(fi)
defer fi.Close()
// Create a buffer of the read file
bcBuf := new(bytes.Buffer)
bcBuf.ReadFrom(bcStream)
// Create decoder from the buffer and a map to store the data
bcDecoder := gob.NewDecoder(bcBuf)
blockChain := make(map[int64][]byte)
// Decode the blockchain into the map
if err := bcDecoder.Decode(&blockChain); err != nil {
t.Errorf("error decoding test blockchain: %v", err.Error())
}
// Load up the short chain
finalIdx1 := 131
var oldBestHash *chainhash.Hash
for i := 1; i < finalIdx1+1; i++ {
bl, err := dcrutil.NewBlockFromBytes(blockChain[int64(i)])
if err != nil {
t.Fatalf("NewBlockFromBytes error: %v", err.Error())
}
bl.SetHeight(int64(i))
if i == finalIdx1 {
oldBestHash = bl.Sha()
}
_, _, err = chain.ProcessBlock(bl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error at height %v: %v", i, err.Error())
}
}
// Load the long chain and begin loading blocks from that too,
// forcing a reorganization
// Load up the rest of the blocks up to HEAD.
filename = filepath.Join("testdata/", "reorgto180.bz2")
fi, err = os.Open(filename)
bcStream = bzip2.NewReader(fi)
defer fi.Close()
// Create a buffer of the read file
bcBuf = new(bytes.Buffer)
bcBuf.ReadFrom(bcStream)
// Create decoder from the buffer and a map to store the data
bcDecoder = gob.NewDecoder(bcBuf)
blockChain = make(map[int64][]byte)
// Decode the blockchain into the map
if err := bcDecoder.Decode(&blockChain); err != nil {
t.Errorf("error decoding test blockchain: %v", err.Error())
}
forkPoint := int64(131)
forkBl, err := dcrutil.NewBlockFromBytes(blockChain[forkPoint])
if err != nil {
t.Fatalf("NewBlockFromBytes error: %v", err.Error())
}
forkBl.SetHeight(forkPoint)
_, _, err = chain.ProcessBlock(forkBl, blockchain.BFNone)
if err != nil {
t.Fatalf("ProcessBlock error: %v", err.Error())
}
newBestHash := forkBl.Sha()
err = chain.ForceHeadReorganization(*oldBestHash, *newBestHash)
if err != nil {
t.Fatalf("failed forced reorganization: %v", err.Error())
}
// Ensure our blockchain is at the correct best tip for our forced
// reorganization
topBlock, _ := chain.GetTopBlock()
tipHash := topBlock.Sha()
//.........这里部分代码省略.........
请发表评论