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"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
PrevShaMissing = errors.New("Previous sha missing from database")
|
|
|
|
TxShaMissing = errors.New("Requested Tx does not exist")
|
|
|
|
DuplicateSha = errors.New("Duplicate insert attempted")
|
|
|
|
DbDoesNotExist = errors.New("Non-existant database")
|
|
|
|
DbUnknownType = errors.New("Non-existant database type")
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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
|
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
|
// cache the underlying object if desired.
|
|
|
|
FetchBlockBySha(sha *btcwire.ShaHash) (blk *btcutil.Block, err error)
|
|
|
|
|
|
|
|
// FetchBlockShaByIdx returns a block sha based on its height in the
|
|
|
|
// blockchain.
|
|
|
|
FetchBlockShaByIdx(blkid int64) (sha *btcwire.ShaHash, err error)
|
|
|
|
|
|
|
|
// FetchIdxRange looks up a range of block by the start and ending ids.
|
|
|
|
// Fetch is inclusive of the start id and exclusive of the ending id. If
|
|
|
|
// the special id `AllShas' is provided as endid then FetchIdxRange will
|
|
|
|
// fetch all shas from startid until no more shas are present.
|
|
|
|
FetchIdxRange(startid, endid int64) (rshalist []btcwire.ShaHash, err error)
|
|
|
|
|
|
|
|
// FetchTxAllBySha returns several pieces of data regarding the given sha.
|
|
|
|
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
|
|
|
|
// for the transaction with the requested sha.
|
|
|
|
FetchTxBufBySha(txsha *btcwire.ShaHash) (txbuf []byte, rpver uint32, err error)
|
|
|
|
|
|
|
|
// FetchTxBySha returns some data for the given Tx Sha.
|
|
|
|
FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rpver uint32, blksha *btcwire.ShaHash, err error)
|
|
|
|
|
|
|
|
// FetchTxByShaList returns a TxListReply given an array of ShaHash, look up the transactions
|
|
|
|
// and return them in a TxListReply array.
|
|
|
|
FetchTxByShaList(txShaList []*btcwire.ShaHash) []*TxListReply
|
|
|
|
|
|
|
|
// FetchTxUsedBySha returns the used/spent buffer for a given transaction.
|
|
|
|
FetchTxUsedBySha(txsha *btcwire.ShaHash) (spentbuf []byte, err error)
|
|
|
|
|
|
|
|
// InsertBlock inserts the block data and transaction data from a block
|
|
|
|
// into the database.
|
|
|
|
InsertBlock(block *btcutil.Block) (blockid int64, err error)
|
|
|
|
|
2013-05-29 22:08:07 +02:00
|
|
|
// InsertBlockData stores a block hash and its associated data block with a
|
|
|
|
// previous sha of `prevSha' and a version of `pver'. This function is
|
|
|
|
// DEPRECATED and should not be used.
|
|
|
|
InsertBlockData(sha *btcwire.ShaHash, prevSha *btcwire.ShaHash, pver uint32, buf []byte) (blockid int64, err error)
|
|
|
|
|
2013-05-29 02:07:21 +02:00
|
|
|
// InsertTx inserts a tx hash and its associated data into the database
|
|
|
|
InsertTx(txsha *btcwire.ShaHash, blockidx int64, txoff int, txlen int, usedbuf []byte) (err error)
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
|
|
|
// NewestSha provides an interface to quickly look up the sha of
|
|
|
|
// the most recent (end) of the block chain.
|
|
|
|
NewestSha() (sha *btcwire.ShaHash, blkid int64, err error)
|
|
|
|
|
|
|
|
// RollbackClose discards the recent database changes to the previously
|
|
|
|
// saved data at last Sync and closes the database.
|
|
|
|
RollbackClose()
|
|
|
|
|
|
|
|
// SetDBInsertMode provides hints to the database to how the application
|
|
|
|
// is running. This allows the database to work in optimized modes when
|
|
|
|
// the database may be very busy.
|
|
|
|
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
|
|
|
|
// 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
|
|
|
|
}
|