Introduce an API change for btcdb
FetchTxBySha changes what it returns, it can now return a TxListReply and and error if none are found. FetchTxByShaList is renamed to FetchUnSpentTxByShaList to indicate that it will (likey/eventually) only return Tx that have some unspent TxOuts. Tx which are fully spent may not be (reliably) looked up using this API.
This commit is contained in:
parent
07d634c76a
commit
cda0b10082
10 changed files with 84 additions and 59 deletions
5
db.go
5
db.go
|
@ -75,11 +75,11 @@ type Db interface {
|
|||
|
||||
// FetchTxBySha returns some data for the given transaction hash. The
|
||||
// implementation may cache the underlying data if desired.
|
||||
FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rpver uint32, blksha *btcwire.ShaHash, err error)
|
||||
FetchTxBySha(txsha *btcwire.ShaHash) ([]*TxListReply, error)
|
||||
|
||||
// FetchTxByShaList returns a TxListReply given an array of transaction
|
||||
// hashes. The implementation may cache the underlying data if desired.
|
||||
FetchTxByShaList(txShaList []*btcwire.ShaHash) []*TxListReply
|
||||
FetchUnSpentTxByShaList(txShaList []*btcwire.ShaHash) ([]*TxListReply)
|
||||
|
||||
// InsertBlock inserts raw block and transaction data from a block
|
||||
// into the database. The first block inserted into the database
|
||||
|
@ -145,6 +145,7 @@ type DriverDB struct {
|
|||
type TxListReply struct {
|
||||
Sha *btcwire.ShaHash
|
||||
Tx *btcwire.MsgTx
|
||||
BlkSha *btcwire.ShaHash
|
||||
Height int64
|
||||
TxSpent []bool
|
||||
Err error
|
||||
|
|
13
ldb/block.go
13
ldb/block.go
|
@ -12,15 +12,6 @@ import (
|
|||
"github.com/conformal/btcwire"
|
||||
)
|
||||
|
||||
// InsertBlockData stores a block hash and its associated data block with a
|
||||
// previous sha of `prevSha' and a version of `pver'.
|
||||
func (db *LevelDb) InsertBlockData(sha *btcwire.ShaHash, prevSha *btcwire.ShaHash, pver uint32, buf []byte) (blockid int64, err error) {
|
||||
db.dbLock.Lock()
|
||||
defer db.dbLock.Unlock()
|
||||
|
||||
return db.insertBlockData(sha, prevSha, buf)
|
||||
}
|
||||
|
||||
func (db *LevelDb) getBlkLoc(sha *btcwire.ShaHash) (int64, error) {
|
||||
var blkHeight int64
|
||||
|
||||
|
@ -107,7 +98,7 @@ func (db *LevelDb) setBlk(sha *btcwire.ShaHash, blkHeight int64, buf []byte) err
|
|||
}
|
||||
|
||||
// insertSha stores a block hash and its associated data block with a
|
||||
// previous sha of `prevSha' and a version of `pver'.
|
||||
// previous sha of `prevSha'.
|
||||
// insertSha shall be called with db lock held
|
||||
func (db *LevelDb) insertBlockData(sha *btcwire.ShaHash, prevSha *btcwire.ShaHash, buf []byte) (blockid int64, err error) {
|
||||
|
||||
|
@ -144,7 +135,7 @@ func (db *LevelDb) insertBlockData(sha *btcwire.ShaHash, prevSha *btcwire.ShaHas
|
|||
return blkHeight, nil
|
||||
}
|
||||
|
||||
// fetchSha returns the datablock and pver for the given ShaHash.
|
||||
// fetchSha returns the datablock for the given ShaHash.
|
||||
func (db *LevelDb) fetchSha(sha *btcwire.ShaHash) (rbuf []byte,
|
||||
rblkHeight int64, err error) {
|
||||
var blkHeight int64
|
||||
|
|
|
@ -36,15 +36,15 @@ func (db *LevelDb) fetchBlockBySha(sha *btcwire.ShaHash) (blk *btcutil.Block, er
|
|||
return
|
||||
}
|
||||
|
||||
// FetchTxByShaList given a array of ShaHash, look up the transactions
|
||||
// FetchUnSpentTxByShaList given a array of ShaHash, look up the transactions
|
||||
// and return them in a TxListReply array.
|
||||
func (db *LevelDb) FetchTxByShaList(txShaList []*btcwire.ShaHash) []*btcdb.TxListReply {
|
||||
func (db *LevelDb) FetchUnSpentTxByShaList(txShaList []*btcwire.ShaHash) []*btcdb.TxListReply {
|
||||
db.dbLock.Lock()
|
||||
defer db.dbLock.Unlock()
|
||||
|
||||
replies := make([]*btcdb.TxListReply, len(txShaList))
|
||||
for i, txsha := range txShaList {
|
||||
tx, _, _, _, height, txspent, err := db.fetchTxDataBySha(txsha)
|
||||
tx, blockSha, height, txspent, err := db.fetchTxDataBySha(txsha)
|
||||
btxspent := []bool{}
|
||||
if err == nil {
|
||||
btxspent = make([]bool, len(tx.TxOut), len(tx.TxOut))
|
||||
|
@ -54,15 +54,14 @@ func (db *LevelDb) FetchTxByShaList(txShaList []*btcwire.ShaHash) []*btcdb.TxLis
|
|||
btxspent[idx] = (txspent[byteidx] & (byte(1) << byteoff)) != 0
|
||||
}
|
||||
}
|
||||
txlre := btcdb.TxListReply{Sha: txsha, Tx: tx, Height: height, TxSpent: btxspent, Err: err}
|
||||
txlre := btcdb.TxListReply{Sha: txsha, Tx: tx, BlkSha: blockSha, Height: height, TxSpent: btxspent, Err: err}
|
||||
replies[i] = &txlre
|
||||
}
|
||||
return replies
|
||||
}
|
||||
|
||||
// fetchTxDataBySha returns several pieces of data regarding the given sha.
|
||||
func (db *LevelDb) fetchTxDataBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rtxbuf []byte, rpver uint32, rblksha *btcwire.ShaHash, rheight int64, rtxspent []byte, err error) {
|
||||
var pver uint32
|
||||
func (db *LevelDb) fetchTxDataBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rblksha *btcwire.ShaHash, rheight int64, rtxspent []byte, err error) {
|
||||
var blksha *btcwire.ShaHash
|
||||
var blkHeight int64
|
||||
var txspent []byte
|
||||
|
@ -83,9 +82,7 @@ func (db *LevelDb) fetchTxDataBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx,
|
|||
//log.Trace("transaction %v is at block %v %v txoff %v, txlen %v\n",
|
||||
// txsha, blksha, blkHeight, txOff, txLen)
|
||||
|
||||
txbuf := make([]byte, txLen)
|
||||
copy(txbuf[:], blkbuf[txOff:txOff+txLen])
|
||||
rbuf := bytes.NewBuffer(txbuf)
|
||||
rbuf := bytes.NewBuffer(blkbuf[txOff:txOff+txLen])
|
||||
|
||||
var tx btcwire.MsgTx
|
||||
err = tx.Deserialize(rbuf)
|
||||
|
@ -95,13 +92,28 @@ func (db *LevelDb) fetchTxDataBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx,
|
|||
return
|
||||
}
|
||||
|
||||
return &tx, txbuf, pver, blksha, blkHeight, txspent, nil
|
||||
return &tx, blksha, blkHeight, txspent, nil
|
||||
}
|
||||
|
||||
// FetchTxBySha returns some data for the given Tx Sha.
|
||||
func (db *LevelDb) FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rpver uint32, blksha *btcwire.ShaHash, err error) {
|
||||
rtx, _, rpver, blksha, _, _, err = db.fetchTxDataBySha(txsha)
|
||||
return
|
||||
func (db *LevelDb) FetchTxBySha(txsha *btcwire.ShaHash) ([]*btcdb.TxListReply, error) {
|
||||
tx, blksha, height, txspent, err := db.fetchTxDataBySha(txsha)
|
||||
if err != nil {
|
||||
return []*btcdb.TxListReply{}, err
|
||||
}
|
||||
|
||||
replies := make ([]*btcdb.TxListReply, 1)
|
||||
|
||||
btxspent := make([]bool, len(tx.TxOut), len(tx.TxOut))
|
||||
for idx := range tx.TxOut {
|
||||
byteidx := idx / 8
|
||||
byteoff := uint(idx % 8)
|
||||
btxspent[idx] = (txspent[byteidx] & (byte(1) << byteoff)) != 0
|
||||
}
|
||||
|
||||
txlre := btcdb.TxListReply{Sha: txsha, Tx: tx, BlkSha: blksha, Height: height, TxSpent: btxspent, Err: err}
|
||||
replies[0] = &txlre
|
||||
return replies, nil
|
||||
}
|
||||
|
||||
// InvalidateTxCache clear/release all cached transactions.
|
||||
|
|
|
@ -104,7 +104,7 @@ endtest:
|
|||
}
|
||||
|
||||
txneededmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||
txlist := db.FetchTxByShaList(txneededList)
|
||||
txlist := db.FetchUnSpentTxByShaList(txneededList)
|
||||
for _, txe := range txlist {
|
||||
if txe.Err != nil {
|
||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||
|
@ -130,7 +130,7 @@ endtest:
|
|||
}
|
||||
|
||||
txlookupmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||
txlist = db.FetchTxByShaList(txlookupList)
|
||||
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||
for _, txe := range txlist {
|
||||
if txe.Err != nil {
|
||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||
|
@ -166,7 +166,7 @@ endtest:
|
|||
}
|
||||
|
||||
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||
txlist = db.FetchTxByShaList(txlookupList)
|
||||
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||
for _, txe := range txlist {
|
||||
if txe.Err != nil {
|
||||
if _, ok := txneededmap[*txe.Sha]; ok {
|
||||
|
@ -188,7 +188,7 @@ endtest:
|
|||
break endtest
|
||||
}
|
||||
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||
txlist = db.FetchTxByShaList(txlookupList)
|
||||
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||
for _, txe := range txlist {
|
||||
if txe.Err != nil {
|
||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||
|
|
|
@ -27,11 +27,6 @@ const (
|
|||
|
||||
var log seelog.LoggerInterface = seelog.Disabled
|
||||
|
||||
type tBlockInsertData struct {
|
||||
sha btcwire.ShaHash
|
||||
pver uint32
|
||||
buf []byte
|
||||
}
|
||||
type tTxInsertData struct {
|
||||
txsha *btcwire.ShaHash
|
||||
blockid int64
|
||||
|
|
|
@ -93,13 +93,13 @@ out:
|
|||
t.Errorf("referenced tx not found %v ", origintxsha)
|
||||
}
|
||||
|
||||
_, _, _, err = db.FetchTxBySha(origintxsha)
|
||||
_, err = db.FetchTxBySha(origintxsha)
|
||||
if err != nil {
|
||||
t.Errorf("referenced tx not found %v err %v ", origintxsha, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
txlist := db.FetchTxByShaList(txneededList)
|
||||
txlist := db.FetchUnSpentTxByShaList(txneededList)
|
||||
for _, txe := range txlist {
|
||||
if txe.Err != nil {
|
||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||
|
@ -260,7 +260,7 @@ func testBackout(t *testing.T, mode int) {
|
|||
t.Errorf("tx %v not located db\n", txsha)
|
||||
}
|
||||
|
||||
_, _, _, err = db.FetchTxBySha(&txsha)
|
||||
_, err = db.FetchTxBySha(&txsha)
|
||||
if err != nil {
|
||||
t.Errorf("tx %v not located db\n", txsha)
|
||||
return
|
||||
|
|
|
@ -84,7 +84,7 @@ out:
|
|||
txin := tx.TxIn[0]
|
||||
origintxsha := &txin.PreviousOutpoint.Hash
|
||||
sqlite3.KillTx(db, origintxsha)
|
||||
_, _, _, err = db.FetchTxBySha(origintxsha)
|
||||
_, err = db.FetchTxBySha(origintxsha)
|
||||
if err == nil {
|
||||
t.Errorf("deleted tx found %v", origintxsha)
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ out:
|
|||
if height == 248 {
|
||||
for _, tx := range mblock.Transactions {
|
||||
txsha, err := tx.TxSha()
|
||||
_, _, _, err = db.FetchTxBySha(&txsha)
|
||||
_, err = db.FetchTxBySha(&txsha)
|
||||
if err == nil {
|
||||
t.Errorf("referenced tx found, should not have been %v, ", txsha)
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ endtest:
|
|||
}
|
||||
|
||||
txneededmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||
txlist := db.FetchTxByShaList(txneededList)
|
||||
txlist := db.FetchUnSpentTxByShaList(txneededList)
|
||||
for _, txe := range txlist {
|
||||
if txe.Err != nil {
|
||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||
|
@ -133,7 +133,7 @@ endtest:
|
|||
}
|
||||
|
||||
txlookupmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||
txlist = db.FetchTxByShaList(txlookupList)
|
||||
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||
for _, txe := range txlist {
|
||||
if txe.Err != nil {
|
||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||
|
@ -169,7 +169,7 @@ endtest:
|
|||
}
|
||||
|
||||
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||
txlist = db.FetchTxByShaList(txlookupList)
|
||||
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||
for _, txe := range txlist {
|
||||
if txe.Err != nil {
|
||||
if _, ok := txneededmap[*txe.Sha]; ok {
|
||||
|
@ -191,7 +191,7 @@ endtest:
|
|||
break endtest
|
||||
}
|
||||
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||
txlist = db.FetchTxByShaList(txlookupList)
|
||||
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||
for _, txe := range txlist {
|
||||
if txe.Err != nil {
|
||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||
|
|
|
@ -99,13 +99,13 @@ out:
|
|||
t.Errorf("referenced tx not found %v ", origintxsha)
|
||||
}
|
||||
|
||||
_, _, _, err = db.FetchTxBySha(origintxsha)
|
||||
_, err = db.FetchTxBySha(origintxsha)
|
||||
if err != nil {
|
||||
t.Errorf("referenced tx not found %v err %v ", origintxsha, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
txlist := db.FetchTxByShaList(txneededList)
|
||||
txlist := db.FetchUnSpentTxByShaList(txneededList)
|
||||
for _, txe := range txlist {
|
||||
if txe.Err != nil {
|
||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||
|
@ -270,8 +270,8 @@ func testBackout(t *testing.T, mode int) {
|
|||
t.Errorf("tx %v exists in db, failure expected", txsha)
|
||||
}
|
||||
|
||||
_, _, _, err = db.FetchTxBySha(&txsha)
|
||||
_, _, _, err = db.FetchTxBySha(&txsha)
|
||||
_, err = db.FetchTxBySha(&txsha)
|
||||
_, err = db.FetchTxBySha(&txsha)
|
||||
}
|
||||
|
||||
func loadBlocks(t *testing.T, file string) (blocks []*btcutil.Block, err error) {
|
||||
|
|
|
@ -131,9 +131,9 @@ func (db *SqliteDb) insertBlockCache(sha *btcwire.ShaHash, blk *btcutil.Block) {
|
|||
bc.blockMap[blkObj.sha] = &blkObj
|
||||
}
|
||||
|
||||
// FetchTxByShaList given a array of ShaHash, look up the transactions
|
||||
// FetchUnSpentTxByShaList given a array of ShaHash, look up the transactions
|
||||
// and return them in a TxListReply array.
|
||||
func (db *SqliteDb) FetchTxByShaList(txShaList []*btcwire.ShaHash) []*btcdb.TxListReply {
|
||||
func (db *SqliteDb) FetchUnSpentTxByShaList(txShaList []*btcwire.ShaHash) []*btcdb.TxListReply {
|
||||
db.dbLock.Lock()
|
||||
defer db.dbLock.Unlock()
|
||||
|
||||
|
@ -229,30 +229,44 @@ func (db *SqliteDb) fetchTxDataBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx
|
|||
}
|
||||
|
||||
// FetchTxBySha returns several pieces of data regarding the given sha.
|
||||
func (db *SqliteDb) FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rpver uint32, rblksha *btcwire.ShaHash, err error) {
|
||||
func (db *SqliteDb) FetchTxBySha(txsha *btcwire.ShaHash) ([]*btcdb.TxListReply, error) {
|
||||
var pver uint32
|
||||
var blksha *btcwire.ShaHash
|
||||
var height int64
|
||||
var toff int
|
||||
var tlen int
|
||||
var txspent []byte
|
||||
var blk *btcutil.Block
|
||||
var blkbuf []byte
|
||||
var err error
|
||||
|
||||
// Check Tx cache
|
||||
if txc, ok := db.fetchTxCache(txsha); ok {
|
||||
return txc.tx, txc.pver, &txc.blksha, nil
|
||||
replies := make ([]*btcdb.TxListReply, 1)
|
||||
|
||||
tx := txc.tx
|
||||
btxspent := make([]bool, len(tx.TxOut), len(tx.TxOut))
|
||||
for idx := range tx.TxOut {
|
||||
byteidx := idx / 8
|
||||
byteoff := uint(idx % 8)
|
||||
btxspent[idx] = (txc.spent[byteidx] & (byte(1) << byteoff)) != 0
|
||||
}
|
||||
|
||||
txlre := btcdb.TxListReply{Sha: txsha, Tx: tx, BlkSha: &txc.blksha, Height: txc.height, TxSpent: btxspent, Err: nil}
|
||||
replies[0] = &txlre
|
||||
return replies, nil
|
||||
}
|
||||
|
||||
// If not cached load it
|
||||
height, toff, tlen, err = db.FetchLocationBySha(txsha)
|
||||
height, toff, tlen, txspent, err = db.fetchLocationUsedBySha(txsha)
|
||||
if err != nil {
|
||||
return
|
||||
return []*btcdb.TxListReply{}, err
|
||||
}
|
||||
|
||||
blksha, err = db.FetchBlockShaByHeight(height)
|
||||
if err != nil {
|
||||
log.Warnf("block idx lookup %v to %v", height, err)
|
||||
return
|
||||
return []*btcdb.TxListReply{}, err
|
||||
}
|
||||
log.Tracef("transaction %v is at block %v %v tx %v",
|
||||
txsha, blksha, height, toff)
|
||||
|
@ -261,13 +275,13 @@ func (db *SqliteDb) FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rp
|
|||
if err != nil {
|
||||
log.Warnf("unable to fetch block %v %v ",
|
||||
height, &blksha)
|
||||
return
|
||||
return []*btcdb.TxListReply{}, err
|
||||
}
|
||||
|
||||
blkbuf, err = blk.Bytes()
|
||||
if err != nil {
|
||||
log.Warnf("unable to decode block %v %v", height, &blksha)
|
||||
return
|
||||
return []*btcdb.TxListReply{}, err
|
||||
}
|
||||
|
||||
txbuf := make([]byte, tlen)
|
||||
|
@ -279,7 +293,7 @@ func (db *SqliteDb) FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rp
|
|||
if err != nil {
|
||||
log.Warnf("unable to decode tx block %v %v txoff %v txlen %v",
|
||||
height, &blksha, toff, tlen)
|
||||
return
|
||||
return []*btcdb.TxListReply{}, err
|
||||
}
|
||||
|
||||
// Shove data into TxCache
|
||||
|
@ -290,10 +304,22 @@ func (db *SqliteDb) FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rp
|
|||
txc.txbuf = txbuf
|
||||
txc.pver = pver
|
||||
txc.height = height
|
||||
txc.spent = txspent
|
||||
txc.blksha = *blksha
|
||||
db.insertTxCache(&txc)
|
||||
|
||||
return &tx, pver, blksha, nil
|
||||
|
||||
btxspent := make([]bool, len(tx.TxOut), len(tx.TxOut))
|
||||
for idx := range tx.TxOut {
|
||||
byteidx := idx / 8
|
||||
byteoff := uint(idx % 8)
|
||||
btxspent[idx] = (txspent[byteidx] & (byte(1) << byteoff)) != 0
|
||||
}
|
||||
|
||||
replies := make ([]*btcdb.TxListReply, 1)
|
||||
txlre := btcdb.TxListReply{Sha: txsha, Tx: &tx, BlkSha: blksha, Height: height, TxSpent: btxspent, Err: err}
|
||||
replies[0] = &txlre
|
||||
return replies, nil
|
||||
}
|
||||
|
||||
// fetchTxCache look up the given transaction in the Tx cache.
|
||||
|
|
Loading…
Reference in a new issue