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 btcdb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2014-07-03 02:47:24 +02:00
|
|
|
|
2013-05-29 02:07:21 +02:00
|
|
|
"github.com/conformal/btcutil"
|
|
|
|
"github.com/conformal/btcwire"
|
|
|
|
)
|
|
|
|
|
2013-05-31 21:07:48 +02:00
|
|
|
// Errors that the various database functions may return.
|
2013-05-29 02:07:21 +02:00
|
|
|
var (
|
|
|
|
PrevShaMissing = errors.New("Previous sha missing from database")
|
2013-05-31 21:07:48 +02:00
|
|
|
TxShaMissing = errors.New("Requested transaction does not exist")
|
2013-05-29 02:07:21 +02:00
|
|
|
DuplicateSha = errors.New("Duplicate insert attempted")
|
2013-05-31 21:02:47 +02:00
|
|
|
DbDoesNotExist = errors.New("Non-existent database")
|
|
|
|
DbUnknownType = errors.New("Non-existent database type")
|
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()
|
|
|
|
|
|
|
|
// 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.
|
2013-06-25 17:15:58 +02:00
|
|
|
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)
|
|
|
|
|
|
|
|
// FetchBlockBySha returns a btcutil Block. The implementation may
|
2013-05-31 20:40:38 +02:00
|
|
|
// cache the underlying data if desired.
|
2013-05-29 02:07:21 +02:00
|
|
|
FetchBlockBySha(sha *btcwire.ShaHash) (blk *btcutil.Block, err error)
|
|
|
|
|
2014-01-19 03:59:53 +01:00
|
|
|
// 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)
|
|
|
|
|
2013-05-31 00:27:39 +02:00
|
|
|
// 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
|
|
|
|
2013-05-31 00:27:39 +02:00
|
|
|
// FetchHeightRange looks up a range of blocks by the start and ending
|
2013-05-31 00:18:13 +02:00
|
|
|
// 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'.
|
2013-05-31 00:27:39 +02:00
|
|
|
FetchHeightRange(startHeight, endHeight int64) (rshalist []btcwire.ShaHash, err error)
|
2013-05-29 02:07:21 +02:00
|
|
|
|
2013-07-10 01:11:02 +02:00
|
|
|
// ExistsTxSha returns whether or not the given tx hash is present in
|
|
|
|
// the database
|
|
|
|
ExistsTxSha(sha *btcwire.ShaHash) (exists bool)
|
|
|
|
|
2013-05-31 20:40:38 +02:00
|
|
|
// FetchTxBySha returns some data for the given transaction hash. The
|
|
|
|
// implementation may cache the underlying data if desired.
|
2013-10-03 21:21:45 +02:00
|
|
|
FetchTxBySha(txsha *btcwire.ShaHash) ([]*TxListReply, error)
|
2013-05-29 02:07:21 +02:00
|
|
|
|
2013-05-31 00:18:13 +02:00
|
|
|
// FetchTxByShaList returns a TxListReply given an array of transaction
|
2013-05-31 20:40:38 +02:00
|
|
|
// hashes. The implementation may cache the underlying data if desired.
|
2013-10-13 17:08:21 +02:00
|
|
|
// This differs from FetchUnSpentTxByShaList in that it will return
|
|
|
|
// the most recent known Tx, if it is fully spent or not.
|
|
|
|
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.
|
|
|
|
FetchUnSpentTxByShaList(txShaList []*btcwire.ShaHash) []*TxListReply
|
2013-05-29 02:07:21 +02:00
|
|
|
|
2013-05-31 00:18:13 +02:00
|
|
|
// InsertBlock inserts raw block and transaction data from a block
|
2013-07-25 23:44:18 +02:00
|
|
|
// 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.
|
2013-05-31 00:27:39 +02:00
|
|
|
InsertBlock(block *btcutil.Block) (height int64, err error)
|
2013-05-29 02:07:21 +02:00
|
|
|
|
2013-07-25 23:44:18 +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.
|
2013-05-31 00:27:39 +02:00
|
|
|
NewestSha() (sha *btcwire.ShaHash, height int64, err 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()
|
|
|
|
|
|
|
|
// Sync verifies that the database is coherent on disk and no
|
|
|
|
// outstanding transactions are in flight.
|
|
|
|
Sync()
|
|
|
|
}
|
|
|
|
|
2013-05-31 22:19:34 +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 {
|
2014-01-20 03:01:31 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-05-31 22:19:34 +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 {
|
2013-07-11 22:35:50 +02:00
|
|
|
Sha *btcwire.ShaHash
|
|
|
|
Tx *btcwire.MsgTx
|
2013-10-13 17:08:21 +02:00
|
|
|
BlkSha *btcwire.ShaHash
|
2013-07-11 22:35:50 +02:00
|
|
|
Height int64
|
|
|
|
TxSpent []bool
|
|
|
|
Err error
|
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.
|
2014-01-20 03:01:31 +01:00
|
|
|
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 {
|
2014-01-20 03:01:31 +01:00
|
|
|
return drv.CreateDB(args...)
|
2013-05-29 02:07:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, DbUnknownType
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpenDB opens an existing database.
|
2014-01-20 03:01:31 +01:00
|
|
|
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 {
|
2014-01-20 03:01:31 +01:00
|
|
|
return drv.OpenDB(args...)
|
2013-05-29 02:07:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, DbUnknownType
|
|
|
|
}
|
2013-09-15 22:18:46 +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
|
|
|
|
}
|