2013-05-29 02:07:21 +02:00
|
|
|
// Copyright (c) 2013 Conformal Systems LLC.
|
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package btcdb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"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)
|
|
|
|
|
|
|
|
// InsertMode represents a hint to the database about how much data the
|
|
|
|
// application is expecting to send to the database in a short period of time.
|
|
|
|
// This in turn provides the database with the opportunity to work in optimized
|
|
|
|
// modes when it will be very busy such as during the initial block chain
|
|
|
|
// download.
|
|
|
|
type InsertMode int
|
|
|
|
|
|
|
|
// Constants used to indicate the database insert mode hint. See InsertMode.
|
|
|
|
const (
|
|
|
|
InsertNormal InsertMode = iota
|
|
|
|
InsertFast
|
|
|
|
InsertValidatedInput
|
|
|
|
)
|
|
|
|
|
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.
|
|
|
|
DropAfterBlockBySha(btcwire.ShaHash) (err error)
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
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-05-31 00:21:15 +02:00
|
|
|
// FetchTxAllBySha returns several pieces of data for a given
|
2013-05-31 20:40:38 +02:00
|
|
|
// transaction hash. The implementation may cache the underlying data
|
|
|
|
// if desired.
|
2013-05-29 02:07:21 +02:00
|
|
|
FetchTxAllBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rtxbuf []byte, rpver uint32, rblksha *btcwire.ShaHash, err error)
|
|
|
|
|
|
|
|
// FetchTxBufBySha returns the raw bytes and associated protocol version
|
2013-05-31 20:40:38 +02:00
|
|
|
// for the transaction with the requested hash. The implementation may
|
|
|
|
// cache the underlying data if desired.
|
2013-05-29 02:07:21 +02:00
|
|
|
FetchTxBufBySha(txsha *btcwire.ShaHash) (txbuf []byte, rpver uint32, err error)
|
|
|
|
|
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-05-29 02:07:21 +02:00
|
|
|
FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rpver uint32, blksha *btcwire.ShaHash, err error)
|
|
|
|
|
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-05-29 02:07:21 +02:00
|
|
|
FetchTxByShaList(txShaList []*btcwire.ShaHash) []*TxListReply
|
|
|
|
|
2013-05-31 00:18:13 +02:00
|
|
|
// FetchTxUsedBySha returns the used/spent buffer for a given
|
|
|
|
// transaction hash.
|
2013-05-29 02:07:21 +02:00
|
|
|
FetchTxUsedBySha(txsha *btcwire.ShaHash) (spentbuf []byte, err error)
|
|
|
|
|
2013-05-31 00:18:13 +02:00
|
|
|
// InsertBlock inserts raw block and transaction data from a block
|
2013-05-29 02:07:21 +02:00
|
|
|
// into the database.
|
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-05-31 00:18:13 +02:00
|
|
|
// InsertBlockData stores a block hash and its associated data block
|
|
|
|
// with the given previous hash and protocol version into the database.
|
2013-05-29 22:08:07 +02:00
|
|
|
InsertBlockData(sha *btcwire.ShaHash, prevSha *btcwire.ShaHash, pver uint32, buf []byte) (blockid int64, err error)
|
|
|
|
|
2013-05-31 00:18:13 +02:00
|
|
|
// InsertTx stores a transaction hash and its associated data into the
|
|
|
|
// database.
|
2013-05-31 00:27:39 +02:00
|
|
|
InsertTx(txsha *btcwire.ShaHash, blockHeight int64, txoff int, txlen int, usedbuf []byte) (err error)
|
2013-05-29 02:07:21 +02:00
|
|
|
|
|
|
|
// InvalidateBlockCache releases all cached blocks.
|
|
|
|
InvalidateBlockCache()
|
|
|
|
|
|
|
|
// InvalidateCache releases all cached blocks and transactions.
|
|
|
|
InvalidateCache()
|
|
|
|
|
|
|
|
// InvalidateTxCache releases all cached transactions.
|
|
|
|
InvalidateTxCache()
|
|
|
|
|
|
|
|
// NewIterateBlocks returns an iterator for all blocks in database.
|
|
|
|
NewIterateBlocks() (pbi BlockIterator, err error)
|
|
|
|
|
2013-05-31 00:18:13 +02:00
|
|
|
// NewestSha provides an interface to quickly look up the hash of
|
|
|
|
// the most recent (end) block of the block chain.
|
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()
|
|
|
|
|
2013-05-31 00:18:13 +02:00
|
|
|
// SetDBInsertMode provides hints to the database about how the
|
|
|
|
// application is running. This allows the database to work in
|
|
|
|
// optimized modes when the database may be very busy.
|
2013-05-29 02:07:21 +02:00
|
|
|
SetDBInsertMode(InsertMode)
|
|
|
|
|
|
|
|
// Sync verifies that the database is coherent on disk and no
|
|
|
|
// outstanding transactions are in flight.
|
|
|
|
Sync()
|
|
|
|
}
|
|
|
|
|
|
|
|
type BlockIterator interface {
|
|
|
|
// Close shuts down the iterator when done walking blocks in the database.
|
|
|
|
Close()
|
|
|
|
|
|
|
|
// NextRow iterates thru all blocks in database.
|
|
|
|
NextRow() bool
|
2013-05-31 20:40:38 +02:00
|
|
|
|
2013-05-29 02:07:21 +02:00
|
|
|
// Row returns row data for block iterator.
|
|
|
|
Row() (key *btcwire.ShaHash, pver uint32, buf []byte, err error)
|
|
|
|
}
|
|
|
|
|
|
|
|
type DriverDB struct {
|
|
|
|
DbType string
|
|
|
|
Create func(argstr string) (pbdb Db, err error)
|
|
|
|
Open func(filepath string) (pbdb Db, err error)
|
|
|
|
}
|
|
|
|
|
|
|
|
type TxListReply struct {
|
|
|
|
Sha *btcwire.ShaHash
|
|
|
|
Tx *btcwire.MsgTx
|
|
|
|
Err error
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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, argstr string) (pbdb Db, err error) {
|
|
|
|
for _, drv := range driverList {
|
|
|
|
if drv.DbType == dbtype {
|
|
|
|
return drv.Create(argstr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, DbUnknownType
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpenDB opens an existing database.
|
|
|
|
func OpenDB(dbtype string, argstr string) (pbdb Db, err error) {
|
|
|
|
for _, drv := range driverList {
|
|
|
|
if drv.DbType == dbtype {
|
|
|
|
return drv.Open(argstr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, DbUnknownType
|
|
|
|
}
|