lbcd/database/db.go

222 lines
9 KiB
Go
Raw Normal View History

2014-01-09 06:54:52 +01:00
// Copyright (c) 2013-2014 Conformal Systems LLC.
2013-05-29 02:07:21 +02:00
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package database
2013-05-29 02:07:21 +02:00
import (
"errors"
2014-07-03 02:47:24 +02:00
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwire"
"golang.org/x/crypto/ripemd160"
2013-05-29 02:07:21 +02:00
)
// Errors that the various database functions may return.
2013-05-29 02:07:21 +02:00
var (
ErrAddrIndexDoesNotExist = errors.New("address index hasn't been built up yet")
ErrUnsupportedAddressType = errors.New("address type is not supported " +
"by the address-index")
ErrPrevShaMissing = errors.New("previous sha missing from database")
ErrTxShaMissing = errors.New("requested transaction does not exist")
ErrBlockShaMissing = errors.New("requested block does not exist")
ErrDuplicateSha = errors.New("duplicate insert attempted")
ErrDbDoesNotExist = errors.New("non-existent database")
ErrDbUnknownType = errors.New("non-existent database type")
ErrNotImplemented = errors.New("method has not yet been implemented")
2013-05-29 02:07:21 +02:00
)
// AllShas is a special value that can be used as the final sha when requesting
// a range of shas by height to request them all.
const AllShas = int64(^uint64(0) >> 1)
2013-05-31 22:12:20 +02:00
// Db defines a generic interface that is used to request and insert data into
// the bitcoin block chain. This interface is intended to be agnostic to actual
// mechanism used for backend data storage. The AddDBDriver function can be
// used to add a new backend data storage method.
2013-05-29 02:07:21 +02:00
type Db interface {
// Close cleanly shuts down the database and syncs all data.
Close() (err error)
2013-05-29 02:07:21 +02:00
// DropAfterBlockBySha will remove any blocks from the database after
// the given block. It terminates any existing transaction and performs
// its operations in an atomic transaction which is commited before
// the function returns.
DropAfterBlockBySha(*btcwire.ShaHash) (err error)
2013-05-29 02:07:21 +02:00
// ExistsSha returns whether or not the given block hash is present in
// the database.
ExistsSha(sha *btcwire.ShaHash) (exists bool, err error)
2013-05-29 02:07:21 +02:00
// FetchBlockBySha returns a btcutil Block. The implementation may
// cache the underlying data if desired.
2013-05-29 02:07:21 +02:00
FetchBlockBySha(sha *btcwire.ShaHash) (blk *btcutil.Block, err error)
// FetchBlockHeightBySha returns the block height for the given hash.
FetchBlockHeightBySha(sha *btcwire.ShaHash) (height int64, err error)
// FetchBlockHeaderBySha returns a btcwire.BlockHeader for the given
// sha. The implementation may cache the underlying data if desired.
FetchBlockHeaderBySha(sha *btcwire.ShaHash) (bh *btcwire.BlockHeader, err error)
// FetchBlockShaByHeight returns a block hash based on its height in the
// block chain.
FetchBlockShaByHeight(height int64) (sha *btcwire.ShaHash, err error)
2013-05-29 02:07:21 +02:00
// FetchHeightRange looks up a range of blocks by the start and ending
// heights. Fetch is inclusive of the start height and exclusive of the
// ending height. To fetch all hashes from the start height until no
// more are present, use the special id `AllShas'.
FetchHeightRange(startHeight, endHeight int64) (rshalist []btcwire.ShaHash, err error)
2013-05-29 02:07:21 +02:00
// ExistsTxSha returns whether or not the given tx hash is present in
// the database
ExistsTxSha(sha *btcwire.ShaHash) (exists bool, err error)
// FetchTxBySha returns some data for the given transaction hash. The
// implementation may cache the underlying data if desired.
FetchTxBySha(txsha *btcwire.ShaHash) ([]*TxListReply, error)
2013-05-29 02:07:21 +02:00
// FetchTxByShaList returns a TxListReply given an array of transaction
// hashes. The implementation may cache the underlying data if desired.
// This differs from FetchUnSpentTxByShaList in that it will return
// the most recent known Tx, if it is fully spent or not.
//
// NOTE: This function does not return an error directly since it MUST
// return at least one TxListReply instance for each requested
// transaction. Each TxListReply instance then contains an Err field
// which can be used to detect errors.
FetchTxByShaList(txShaList []*btcwire.ShaHash) []*TxListReply
// FetchUnSpentTxByShaList returns a TxListReply given an array of
// transaction hashes. The implementation may cache the underlying
// data if desired. Fully spent transactions will not normally not
// be returned in this operation.
//
// NOTE: This function does not return an error directly since it MUST
// return at least one TxListReply instance for each requested
// transaction. Each TxListReply instance then contains an Err field
// which can be used to detect errors.
FetchUnSpentTxByShaList(txShaList []*btcwire.ShaHash) []*TxListReply
2013-05-29 02:07:21 +02:00
// InsertBlock inserts raw block and transaction data from a block
// into the database. The first block inserted into the database
// will be treated as the genesis block. Every subsequent block insert
// requires the referenced parent block to already exist.
InsertBlock(block *btcutil.Block) (height int64, err error)
2013-05-29 02:07:21 +02:00
// NewestSha returns the hash and block height of the most recent (end)
// block of the block chain. It will return the zero hash, -1 for
// the block height, and no error (nil) if there are not any blocks in
// the database yet.
NewestSha() (sha *btcwire.ShaHash, height int64, err error)
2013-05-29 02:07:21 +02:00
// FetchAddrIndexTip returns the hash and block height of the most recent
// block which has had its address index populated. It will return
// ErrAddrIndexDoesNotExist along with a zero hash, and -1 if the
// addrindex hasn't yet been built up.
FetchAddrIndexTip() (sha *btcwire.ShaHash, height int64, err error)
// UpdateAddrIndexForBlock updates the stored addrindex with passed
// index information for a particular block height. Additionally, it
// will update the stored meta-data related to the curent tip of the
// addr index. These two operations are performed in an atomic
// transaction which is commited before the function returns.
// Addresses are indexed by the raw bytes of their base58 decoded
// hash160.
UpdateAddrIndexForBlock(blkSha *btcwire.ShaHash, height int64,
addrIndex BlockAddrIndex) error
// FetchTxsForAddr looks up and returns all transactions which either
// spend a previously created output of the passed address, or create
// a new output locked to the passed address. The, `limit` parameter
// should be the max number of transactions to be returned.
// Additionally, if the caller wishes to skip forward in the results
// some amount, the 'seek' represents how many results to skip.
// NOTE: Values for both `seek` and `limit` MUST be positive.
FetchTxsForAddr(addr btcutil.Address, skip int, limit int) ([]*TxListReply, error)
// DeleteAddrIndex deletes the entire addrindex stored within the DB.
DeleteAddrIndex() error
2013-05-29 02:07:21 +02:00
// RollbackClose discards the recent database changes to the previously
// saved data at last Sync and closes the database.
RollbackClose() (err error)
2013-05-29 02:07:21 +02:00
// Sync verifies that the database is coherent on disk and no
// outstanding transactions are in flight.
Sync() (err error)
2013-05-29 02:07:21 +02:00
}
// DriverDB defines a structure for backend drivers to use when they registered
// themselves as a backend which implements the Db interface.
2013-05-29 02:07:21 +02:00
type DriverDB struct {
DbType string
CreateDB func(args ...interface{}) (pbdb Db, err error)
OpenDB func(args ...interface{}) (pbdb Db, err error)
2013-05-29 02:07:21 +02:00
}
// TxListReply is used to return individual transaction information when
// data about multiple transactions is requested in a single call.
2013-05-29 02:07:21 +02:00
type TxListReply struct {
Sha *btcwire.ShaHash
Tx *btcwire.MsgTx
BlkSha *btcwire.ShaHash
Height int64
TxSpent []bool
Err error
2013-05-29 02:07:21 +02:00
}
// AddrIndexKeySize is the number of bytes used by keys into the BlockAddrIndex.
const AddrIndexKeySize = ripemd160.Size
// BlockAddrIndex represents the indexing structure for addresses.
// It maps a hash160 to a list of transaction locations within a block that
// either pays to or spends from the passed UTXO for the hash160.
type BlockAddrIndex map[[AddrIndexKeySize]byte][]*btcwire.TxLoc
2013-05-29 02:07:21 +02:00
// driverList holds all of the registered database backends.
var driverList []DriverDB
// AddDBDriver adds a back end database driver to available interfaces.
func AddDBDriver(instance DriverDB) {
// TODO(drahn) Does this really need to check for duplicate names ?
for _, drv := range driverList {
// TODO(drahn) should duplicates be an error?
if drv.DbType == instance.DbType {
return
}
}
driverList = append(driverList, instance)
}
// CreateDB intializes and opens a database.
func CreateDB(dbtype string, args ...interface{}) (pbdb Db, err error) {
2013-05-29 02:07:21 +02:00
for _, drv := range driverList {
if drv.DbType == dbtype {
return drv.CreateDB(args...)
2013-05-29 02:07:21 +02:00
}
}
return nil, ErrDbUnknownType
2013-05-29 02:07:21 +02:00
}
// OpenDB opens an existing database.
func OpenDB(dbtype string, args ...interface{}) (pbdb Db, err error) {
2013-05-29 02:07:21 +02:00
for _, drv := range driverList {
if drv.DbType == dbtype {
return drv.OpenDB(args...)
2013-05-29 02:07:21 +02:00
}
}
return nil, ErrDbUnknownType
2013-05-29 02:07:21 +02:00
}
// SupportedDBs returns a slice of strings that represent the database drivers
// that have been registered and are therefore supported.
func SupportedDBs() []string {
var supportedDBs []string
for _, drv := range driverList {
supportedDBs = append(supportedDBs, drv.DbType)
}
return supportedDBs
}