func (cs *ConsensusSet) BlockByID(id types.BlockID) (block types.Block, height types.BlockHeight, exists bool) {
	_ = cs.db.View(func(tx *bolt.Tx) error {
		pb, err := getBlockMap(tx, id)
		if err != nil {
			return err
		}
		block = pb.Block
		height = pb.Height
		exists = true
		return nil
	})
	return block, height, exists
}
BlockByID returns the block for a given BlockID.
package consensus
import (
	"errors"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/persist"
	siasync "github.com/NebulousLabs/Sia/sync"
	"github.com/NebulousLabs/Sia/types"
	"github.com/NebulousLabs/demotemutex"
	"github.com/coreos/bbolt"
)
var (
	errNilGateway = errors.New("cannot have a nil gateway as input")
)
type marshaler interface {
	Marshal(interface{}) []byte
	Unmarshal([]byte, interface{}) error
}
type stdMarshaler struct{}
func (stdMarshaler) Marshal(v interface{}) []byte            { return encoding.Marshal(v) }
func (stdMarshaler) Unmarshal(b []byte, v interface{}) error { return encoding.Unmarshal(b, v) }
type ConsensusSet struct {
	gateway modules.Gateway
	blockRoot processedBlock
	subscribers []modules.ConsensusSetSubscriber
	dosBlocks map[types.BlockID]struct{}
	checkingConsistency bool
	synced bool
	marshaler       marshaler
	blockRuleHelper blockRuleHelper
	blockValidator  blockValidator
	db         *persist.BoltDatabase
	staticDeps modules.Dependencies
	log        *persist.Logger
	mu         demotemutex.DemoteMutex
	persistDir string
	tg         siasync.ThreadGroup
}
func New(gateway modules.Gateway, bootstrap bool, persistDir string) (*ConsensusSet, error) {
	return NewCustomConsensusSet(gateway, bootstrap, persistDir, modules.ProdDependencies)
}
func NewCustomConsensusSet(gateway modules.Gateway, bootstrap bool, persistDir string, deps modules.Dependencies) (*ConsensusSet, error) {
	if gateway == nil {
		return nil, errNilGateway
	}
	cs := &ConsensusSet{
		gateway: gateway,
		blockRoot: processedBlock{
			Block:       types.GenesisBlock,
			ChildTarget: types.RootTarget,
			Depth:       types.RootDepth,
			DiffsGenerated: true,
		},
		dosBlocks: make(map[types.BlockID]struct{}),
		marshaler:       stdMarshaler{},
		blockRuleHelper: stdBlockRuleHelper{},
		blockValidator:  NewBlockValidator(),
		staticDeps: deps,
		persistDir: persistDir,
	}
	for i, siafundOutput := range types.GenesisBlock.Transactions[0].SiafundOutputs {
		sfid := types.GenesisBlock.Transactions[0].SiafundOutputID(uint64(i))
		sfod := modules.SiafundOutputDiff{
			Direction:     modules.DiffApply,
			ID:            sfid,
			SiafundOutput: siafundOutput,
		}
		cs.blockRoot.SiafundOutputDiffs = append(cs.blockRoot.SiafundOutputDiffs, sfod)
	}
	err := cs.initPersist()
	if err != nil {
		return nil, err
	}
	go func() {
		if bootstrap {
			err = cs.threadedInitialBlockchainDownload()
			if err != nil {
				return
			}
		}
		err = cs.tg.Add()
		if err != nil {
			return
		}
		defer cs.tg.Done()
		gateway.RegisterRPC("SendBlocks", cs.rpcSendBlocks)
		gateway.RegisterRPC("RelayHeader", cs.threadedRPCRelayHeader)
		gateway.RegisterRPC("SendBlk", cs.rpcSendBlk)
		gateway.RegisterConnectCall("SendBlocks", cs.threadedReceiveBlocks)
		cs.tg.OnStop(func() {
			cs.gateway.UnregisterRPC("SendBlocks")
			cs.gateway.UnregisterRPC("RelayHeader")
			cs.gateway.UnregisterRPC("SendBlk")
			cs.gateway.UnregisterConnectCall("SendBlocks")
		})
		cs.mu.Lock()
		cs.synced = true
		cs.mu.Unlock()
	}()
	return cs, nil
}
func (cs *ConsensusSet) BlockAtHeight(height types.BlockHeight) (block types.Block, exists bool) {
	_ = cs.db.View(func(tx *bolt.Tx) error {
		id, err := getPath(tx, height)
		if err != nil {
			return err
		}
		pb, err := getBlockMap(tx, id)
		if err != nil {
			return err
		}
		block = pb.Block
		exists = true
		return nil
	})
	return block, exists
}