diff --git a/db.go b/db.go index 06ea8e31f..b15c95b6b 100644 --- a/db.go +++ b/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 diff --git a/ldb/block.go b/ldb/block.go index c7471cb49..6423ac1c5 100644 --- a/ldb/block.go +++ b/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 diff --git a/ldb/dbcache.go b/ldb/dbcache.go index a96678467..0ac0506ec 100644 --- a/ldb/dbcache.go +++ b/ldb/dbcache.go @@ -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. diff --git a/ldb/insertremove_test.go b/ldb/insertremove_test.go index 26e9ad2b8..fadf4799d 100644 --- a/ldb/insertremove_test.go +++ b/ldb/insertremove_test.go @@ -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) diff --git a/ldb/leveldb.go b/ldb/leveldb.go index c1e773885..24f9b3a15 100644 --- a/ldb/leveldb.go +++ b/ldb/leveldb.go @@ -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 diff --git a/ldb/operational_test.go b/ldb/operational_test.go index 44d34bd38..0eab65e98 100644 --- a/ldb/operational_test.go +++ b/ldb/operational_test.go @@ -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 diff --git a/sqlite3/insertfail_test.go b/sqlite3/insertfail_test.go index d68380342..4c27e2c8b 100644 --- a/sqlite3/insertfail_test.go +++ b/sqlite3/insertfail_test.go @@ -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) } diff --git a/sqlite3/insertremove_test.go b/sqlite3/insertremove_test.go index ca8baf5b0..c49595c6d 100644 --- a/sqlite3/insertremove_test.go +++ b/sqlite3/insertremove_test.go @@ -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) diff --git a/sqlite3/operational_test.go b/sqlite3/operational_test.go index 58cb40bb6..b9eba8990 100644 --- a/sqlite3/operational_test.go +++ b/sqlite3/operational_test.go @@ -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) { diff --git a/sqlite3/sqlitedbcache.go b/sqlite3/sqlitedbcache.go index 97079cf67..daac3ec2e 100644 --- a/sqlite3/sqlitedbcache.go +++ b/sqlite3/sqlitedbcache.go @@ -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.