dcrd/blockchain/example_test.go
Dave Collins f140d33745
multi: Decouple orphan handling from blockchain.
This decouples and removes the orphan handling from blockchain in favor
of implementing it in the block manager as part of the overall effort to
decouple the connection code from the download logic.

The change might not make a ton of sense in isolation, since there is no
major functional change, however, decoupling the orphan handling
independently helps make the review process easier and alleviates what
would otherwise result in additional intermediate code to handle cases
that ultimately will no longer exist.

The following is a high level overview of the changes:

- Introduce blockchain function to more easily determine if an error is
  a rule error with a given error code
- Move core orphan handling code from blockchain to block manager
  - Move data structures used to cache and track orphan blocks
  - Move all functions releated to orphans
    - BlockChain.IsKnownOrphan -> blockManager.isKnownOrphan
    - BlockChain.GetOrphanRoot -> blockManager.orphanRoot
    - BlockChain.removeOrphanBlock -> blockManager.removeOrphanBlock
    - BlockChain.addOrphanBlock -> blockManager.addOrphanBlock
- Implement orphan handling in block manager
  - Rework to use the moved functions and data structs
  - Add check for known orphans in addition HaveBlock calls to retain
    the same behavior
  - Modify the semantics of the process block func exposed by the block
    manager so that it no longer stores orphans since all consumers of
    it ultimately reject orphans anyway
- Remove remaining orphan related code from blockchain
  - Update ProcessBlock to return an error when called with an orphan
  - Remove additional orphan processing from ProcessBlock
  - Remove orphan cache check from HaveBlock
  - Adjust example to account for the removed parameter
  - Change chaingen harness tests to detect orphans via returned error
  - Modify fullblock tests to detect orphans via returned error
  - Adapt process order logic tests to cope with lack of orphan
    processing
  - Update all other tests accordingly
  - Update various comments and the README.md and doc.go to properly
    reflect the removal of orphan handling
2019-12-05 21:38:29 -06:00

79 lines
2.9 KiB
Go

// Copyright (c) 2014-2016 The btcsuite developers
// Copyright (c) 2015-2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain_test
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/decred/dcrd/blockchain/v3"
"github.com/decred/dcrd/chaincfg/v2"
"github.com/decred/dcrd/database/v2"
_ "github.com/decred/dcrd/database/v2/ffldb"
"github.com/decred/dcrd/dcrutil/v3"
)
// This example demonstrates how to create a new chain instance and use
// ProcessBlock to attempt to add a block to the chain. As the package
// overview documentation describes, this includes all of the Decred consensus
// rules. This example intentionally attempts to insert a duplicate genesis
// block to illustrate how an invalid block is handled.
func ExampleBlockChain_ProcessBlock() {
// Create a new database to store the accepted blocks into. Typically
// this would be opening an existing database and would not be deleting
// and creating a new database like this, but it is done here so this is
// a complete working example and does not leave temporary files laying
// around.
mainNetParams := chaincfg.MainNetParams()
dbPath := filepath.Join(os.TempDir(), "exampleprocessblock")
_ = os.RemoveAll(dbPath)
db, err := database.Create("ffldb", dbPath, mainNetParams.Net)
if err != nil {
fmt.Printf("Failed to create database: %v\n", err)
return
}
defer os.RemoveAll(dbPath)
defer db.Close()
// Create a new BlockChain instance using the underlying database for
// the main bitcoin network. This example does not demonstrate some
// of the other available configuration options such as specifying a
// notification callback and signature cache. Also, the caller would
// ordinarily keep a reference to the median time source and add time
// values obtained from other peers on the network so the local time is
// adjusted to be in agreement with other peers.
chain, err := blockchain.New(context.Background(),
&blockchain.Config{
DB: db,
ChainParams: mainNetParams,
TimeSource: blockchain.NewMedianTime(),
})
if err != nil {
fmt.Printf("Failed to create chain instance: %v\n", err)
return
}
// Process a block. For this example, we are going to intentionally
// cause an error by trying to process the genesis block which already
// exists.
genesisBlock := dcrutil.NewBlock(mainNetParams.GenesisBlock)
forkLen, err := chain.ProcessBlock(genesisBlock,
blockchain.BFNone)
if err != nil {
fmt.Printf("Failed to create chain instance: %v\n", err)
return
}
isMainChain := forkLen == 0
fmt.Printf("Block accepted. Is it on the main chain?: %v", isMainChain)
// This output is dependent on the genesis block, and needs to be
// updated if the mainnet genesis block is updated.
// Output:
// Failed to process block: already have block 267a53b5ee86c24a48ec37aee4f4e7c0c4004892b7259e695e9f5b321f1ab9d2
}