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
|
// FetchTxBySha returns some data for the given transaction hash. The
|
||||||
// implementation may cache the underlying data if desired.
|
// 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
|
// FetchTxByShaList returns a TxListReply given an array of transaction
|
||||||
// hashes. The implementation may cache the underlying data if desired.
|
// 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
|
// InsertBlock inserts raw block and transaction data from a block
|
||||||
// into the database. The first block inserted into the database
|
// into the database. The first block inserted into the database
|
||||||
|
@ -145,6 +145,7 @@ type DriverDB struct {
|
||||||
type TxListReply struct {
|
type TxListReply struct {
|
||||||
Sha *btcwire.ShaHash
|
Sha *btcwire.ShaHash
|
||||||
Tx *btcwire.MsgTx
|
Tx *btcwire.MsgTx
|
||||||
|
BlkSha *btcwire.ShaHash
|
||||||
Height int64
|
Height int64
|
||||||
TxSpent []bool
|
TxSpent []bool
|
||||||
Err error
|
Err error
|
||||||
|
|
13
ldb/block.go
13
ldb/block.go
|
@ -12,15 +12,6 @@ import (
|
||||||
"github.com/conformal/btcwire"
|
"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) {
|
func (db *LevelDb) getBlkLoc(sha *btcwire.ShaHash) (int64, error) {
|
||||||
var blkHeight int64
|
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
|
// 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
|
// insertSha shall be called with db lock held
|
||||||
func (db *LevelDb) insertBlockData(sha *btcwire.ShaHash, prevSha *btcwire.ShaHash, buf []byte) (blockid int64, err error) {
|
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
|
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,
|
func (db *LevelDb) fetchSha(sha *btcwire.ShaHash) (rbuf []byte,
|
||||||
rblkHeight int64, err error) {
|
rblkHeight int64, err error) {
|
||||||
var blkHeight int64
|
var blkHeight int64
|
||||||
|
|
|
@ -36,15 +36,15 @@ func (db *LevelDb) fetchBlockBySha(sha *btcwire.ShaHash) (blk *btcutil.Block, er
|
||||||
return
|
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.
|
// 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()
|
db.dbLock.Lock()
|
||||||
defer db.dbLock.Unlock()
|
defer db.dbLock.Unlock()
|
||||||
|
|
||||||
replies := make([]*btcdb.TxListReply, len(txShaList))
|
replies := make([]*btcdb.TxListReply, len(txShaList))
|
||||||
for i, txsha := range txShaList {
|
for i, txsha := range txShaList {
|
||||||
tx, _, _, _, height, txspent, err := db.fetchTxDataBySha(txsha)
|
tx, blockSha, height, txspent, err := db.fetchTxDataBySha(txsha)
|
||||||
btxspent := []bool{}
|
btxspent := []bool{}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
btxspent = make([]bool, len(tx.TxOut), len(tx.TxOut))
|
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
|
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
|
replies[i] = &txlre
|
||||||
}
|
}
|
||||||
return replies
|
return replies
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchTxDataBySha returns several pieces of data regarding the given sha.
|
// 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) {
|
func (db *LevelDb) fetchTxDataBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rblksha *btcwire.ShaHash, rheight int64, rtxspent []byte, err error) {
|
||||||
var pver uint32
|
|
||||||
var blksha *btcwire.ShaHash
|
var blksha *btcwire.ShaHash
|
||||||
var blkHeight int64
|
var blkHeight int64
|
||||||
var txspent []byte
|
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",
|
//log.Trace("transaction %v is at block %v %v txoff %v, txlen %v\n",
|
||||||
// txsha, blksha, blkHeight, txOff, txLen)
|
// txsha, blksha, blkHeight, txOff, txLen)
|
||||||
|
|
||||||
txbuf := make([]byte, txLen)
|
rbuf := bytes.NewBuffer(blkbuf[txOff:txOff+txLen])
|
||||||
copy(txbuf[:], blkbuf[txOff:txOff+txLen])
|
|
||||||
rbuf := bytes.NewBuffer(txbuf)
|
|
||||||
|
|
||||||
var tx btcwire.MsgTx
|
var tx btcwire.MsgTx
|
||||||
err = tx.Deserialize(rbuf)
|
err = tx.Deserialize(rbuf)
|
||||||
|
@ -95,13 +92,28 @@ func (db *LevelDb) fetchTxDataBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return &tx, txbuf, pver, blksha, blkHeight, txspent, nil
|
return &tx, blksha, blkHeight, txspent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchTxBySha returns some data for the given Tx Sha.
|
// 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) {
|
func (db *LevelDb) FetchTxBySha(txsha *btcwire.ShaHash) ([]*btcdb.TxListReply, error) {
|
||||||
rtx, _, rpver, blksha, _, _, err = db.fetchTxDataBySha(txsha)
|
tx, blksha, height, txspent, err := db.fetchTxDataBySha(txsha)
|
||||||
return
|
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.
|
// InvalidateTxCache clear/release all cached transactions.
|
||||||
|
|
|
@ -104,7 +104,7 @@ endtest:
|
||||||
}
|
}
|
||||||
|
|
||||||
txneededmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
txneededmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||||
txlist := db.FetchTxByShaList(txneededList)
|
txlist := db.FetchUnSpentTxByShaList(txneededList)
|
||||||
for _, txe := range txlist {
|
for _, txe := range txlist {
|
||||||
if txe.Err != nil {
|
if txe.Err != nil {
|
||||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||||
|
@ -130,7 +130,7 @@ endtest:
|
||||||
}
|
}
|
||||||
|
|
||||||
txlookupmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
txlookupmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||||
txlist = db.FetchTxByShaList(txlookupList)
|
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||||
for _, txe := range txlist {
|
for _, txe := range txlist {
|
||||||
if txe.Err != nil {
|
if txe.Err != nil {
|
||||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||||
|
@ -166,7 +166,7 @@ endtest:
|
||||||
}
|
}
|
||||||
|
|
||||||
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||||
txlist = db.FetchTxByShaList(txlookupList)
|
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||||
for _, txe := range txlist {
|
for _, txe := range txlist {
|
||||||
if txe.Err != nil {
|
if txe.Err != nil {
|
||||||
if _, ok := txneededmap[*txe.Sha]; ok {
|
if _, ok := txneededmap[*txe.Sha]; ok {
|
||||||
|
@ -188,7 +188,7 @@ endtest:
|
||||||
break endtest
|
break endtest
|
||||||
}
|
}
|
||||||
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||||
txlist = db.FetchTxByShaList(txlookupList)
|
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||||
for _, txe := range txlist {
|
for _, txe := range txlist {
|
||||||
if txe.Err != nil {
|
if txe.Err != nil {
|
||||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||||
|
|
|
@ -27,11 +27,6 @@ const (
|
||||||
|
|
||||||
var log seelog.LoggerInterface = seelog.Disabled
|
var log seelog.LoggerInterface = seelog.Disabled
|
||||||
|
|
||||||
type tBlockInsertData struct {
|
|
||||||
sha btcwire.ShaHash
|
|
||||||
pver uint32
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
type tTxInsertData struct {
|
type tTxInsertData struct {
|
||||||
txsha *btcwire.ShaHash
|
txsha *btcwire.ShaHash
|
||||||
blockid int64
|
blockid int64
|
||||||
|
|
|
@ -93,13 +93,13 @@ out:
|
||||||
t.Errorf("referenced tx not found %v ", origintxsha)
|
t.Errorf("referenced tx not found %v ", origintxsha)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, err = db.FetchTxBySha(origintxsha)
|
_, err = db.FetchTxBySha(origintxsha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("referenced tx not found %v err %v ", origintxsha, err)
|
t.Errorf("referenced tx not found %v err %v ", origintxsha, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
txlist := db.FetchTxByShaList(txneededList)
|
txlist := db.FetchUnSpentTxByShaList(txneededList)
|
||||||
for _, txe := range txlist {
|
for _, txe := range txlist {
|
||||||
if txe.Err != nil {
|
if txe.Err != nil {
|
||||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
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)
|
t.Errorf("tx %v not located db\n", txsha)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, err = db.FetchTxBySha(&txsha)
|
_, err = db.FetchTxBySha(&txsha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("tx %v not located db\n", txsha)
|
t.Errorf("tx %v not located db\n", txsha)
|
||||||
return
|
return
|
||||||
|
|
|
@ -84,7 +84,7 @@ out:
|
||||||
txin := tx.TxIn[0]
|
txin := tx.TxIn[0]
|
||||||
origintxsha := &txin.PreviousOutpoint.Hash
|
origintxsha := &txin.PreviousOutpoint.Hash
|
||||||
sqlite3.KillTx(db, origintxsha)
|
sqlite3.KillTx(db, origintxsha)
|
||||||
_, _, _, err = db.FetchTxBySha(origintxsha)
|
_, err = db.FetchTxBySha(origintxsha)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("deleted tx found %v", origintxsha)
|
t.Errorf("deleted tx found %v", origintxsha)
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ out:
|
||||||
if height == 248 {
|
if height == 248 {
|
||||||
for _, tx := range mblock.Transactions {
|
for _, tx := range mblock.Transactions {
|
||||||
txsha, err := tx.TxSha()
|
txsha, err := tx.TxSha()
|
||||||
_, _, _, err = db.FetchTxBySha(&txsha)
|
_, err = db.FetchTxBySha(&txsha)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("referenced tx found, should not have been %v, ", txsha)
|
t.Errorf("referenced tx found, should not have been %v, ", txsha)
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ endtest:
|
||||||
}
|
}
|
||||||
|
|
||||||
txneededmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
txneededmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||||
txlist := db.FetchTxByShaList(txneededList)
|
txlist := db.FetchUnSpentTxByShaList(txneededList)
|
||||||
for _, txe := range txlist {
|
for _, txe := range txlist {
|
||||||
if txe.Err != nil {
|
if txe.Err != nil {
|
||||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||||
|
@ -133,7 +133,7 @@ endtest:
|
||||||
}
|
}
|
||||||
|
|
||||||
txlookupmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
txlookupmap := map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||||
txlist = db.FetchTxByShaList(txlookupList)
|
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||||
for _, txe := range txlist {
|
for _, txe := range txlist {
|
||||||
if txe.Err != nil {
|
if txe.Err != nil {
|
||||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
||||||
|
@ -169,7 +169,7 @@ endtest:
|
||||||
}
|
}
|
||||||
|
|
||||||
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||||
txlist = db.FetchTxByShaList(txlookupList)
|
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||||
for _, txe := range txlist {
|
for _, txe := range txlist {
|
||||||
if txe.Err != nil {
|
if txe.Err != nil {
|
||||||
if _, ok := txneededmap[*txe.Sha]; ok {
|
if _, ok := txneededmap[*txe.Sha]; ok {
|
||||||
|
@ -191,7 +191,7 @@ endtest:
|
||||||
break endtest
|
break endtest
|
||||||
}
|
}
|
||||||
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
txlookupmap = map[btcwire.ShaHash]*btcdb.TxListReply{}
|
||||||
txlist = db.FetchTxByShaList(txlookupList)
|
txlist = db.FetchUnSpentTxByShaList(txlookupList)
|
||||||
for _, txe := range txlist {
|
for _, txe := range txlist {
|
||||||
if txe.Err != nil {
|
if txe.Err != nil {
|
||||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
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)
|
t.Errorf("referenced tx not found %v ", origintxsha)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, err = db.FetchTxBySha(origintxsha)
|
_, err = db.FetchTxBySha(origintxsha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("referenced tx not found %v err %v ", origintxsha, err)
|
t.Errorf("referenced tx not found %v err %v ", origintxsha, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
txlist := db.FetchTxByShaList(txneededList)
|
txlist := db.FetchUnSpentTxByShaList(txneededList)
|
||||||
for _, txe := range txlist {
|
for _, txe := range txlist {
|
||||||
if txe.Err != nil {
|
if txe.Err != nil {
|
||||||
t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err)
|
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)
|
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) {
|
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
|
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.
|
// 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()
|
db.dbLock.Lock()
|
||||||
defer db.dbLock.Unlock()
|
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.
|
// 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 pver uint32
|
||||||
var blksha *btcwire.ShaHash
|
var blksha *btcwire.ShaHash
|
||||||
var height int64
|
var height int64
|
||||||
var toff int
|
var toff int
|
||||||
var tlen int
|
var tlen int
|
||||||
|
var txspent []byte
|
||||||
var blk *btcutil.Block
|
var blk *btcutil.Block
|
||||||
var blkbuf []byte
|
var blkbuf []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
// Check Tx cache
|
// Check Tx cache
|
||||||
if txc, ok := db.fetchTxCache(txsha); ok {
|
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
|
// If not cached load it
|
||||||
height, toff, tlen, err = db.FetchLocationBySha(txsha)
|
height, toff, tlen, txspent, err = db.fetchLocationUsedBySha(txsha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return []*btcdb.TxListReply{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
blksha, err = db.FetchBlockShaByHeight(height)
|
blksha, err = db.FetchBlockShaByHeight(height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("block idx lookup %v to %v", height, err)
|
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",
|
log.Tracef("transaction %v is at block %v %v tx %v",
|
||||||
txsha, blksha, height, toff)
|
txsha, blksha, height, toff)
|
||||||
|
@ -261,13 +275,13 @@ func (db *SqliteDb) FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rp
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("unable to fetch block %v %v ",
|
log.Warnf("unable to fetch block %v %v ",
|
||||||
height, &blksha)
|
height, &blksha)
|
||||||
return
|
return []*btcdb.TxListReply{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
blkbuf, err = blk.Bytes()
|
blkbuf, err = blk.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("unable to decode block %v %v", height, &blksha)
|
log.Warnf("unable to decode block %v %v", height, &blksha)
|
||||||
return
|
return []*btcdb.TxListReply{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txbuf := make([]byte, tlen)
|
txbuf := make([]byte, tlen)
|
||||||
|
@ -279,7 +293,7 @@ func (db *SqliteDb) FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rp
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("unable to decode tx block %v %v txoff %v txlen %v",
|
log.Warnf("unable to decode tx block %v %v txoff %v txlen %v",
|
||||||
height, &blksha, toff, tlen)
|
height, &blksha, toff, tlen)
|
||||||
return
|
return []*btcdb.TxListReply{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shove data into TxCache
|
// Shove data into TxCache
|
||||||
|
@ -290,10 +304,22 @@ func (db *SqliteDb) FetchTxBySha(txsha *btcwire.ShaHash) (rtx *btcwire.MsgTx, rp
|
||||||
txc.txbuf = txbuf
|
txc.txbuf = txbuf
|
||||||
txc.pver = pver
|
txc.pver = pver
|
||||||
txc.height = height
|
txc.height = height
|
||||||
|
txc.spent = txspent
|
||||||
txc.blksha = *blksha
|
txc.blksha = *blksha
|
||||||
db.insertTxCache(&txc)
|
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.
|
// fetchTxCache look up the given transaction in the Tx cache.
|
||||||
|
|
Loading…
Reference in a new issue