diff --git a/db.go b/db.go index 13d61d8..03863fc 100644 --- a/db.go +++ b/db.go @@ -14,7 +14,7 @@ import ( // Errors that the various database functions may return. var ( - ErrAddrIndexDoesNotExist = errors.New("Address index hasn't been built up yet.") + ErrAddrIndexDoesNotExist = errors.New("address index hasn't been built up yet") ErrUnsupportedAddressType = errors.New("address type is not supported " + "by the address-index") ErrPrevShaMissing = errors.New("previous sha missing from database") @@ -125,14 +125,14 @@ type Db interface { // Addresses are indexed by the raw bytes of their base58 decoded // hash160. UpdateAddrIndexForBlock(blkSha *btcwire.ShaHash, height int64, - addrIndex *BlockAddrIndex) error - - // FetchBlockBySha looks up and returns all transactions which either - // spend from a previously created output of the passed address, or - // create a new output locked to the passed address. The, `limit` parameter - // should be the max number of transactions to be returned. Additionally, if the - // caller wishes to seek forward in the results some amount, the 'seek' - // represents how many results to skip. + addrIndex BlockAddrIndex) error + + // FetchTxsForAddr looks up and returns all transactions which either + // spend a previously created output of the passed address, or create + // a new output locked to the passed address. The, `limit` parameter + // should be the max number of transactions to be returned. + // Additionally, if the caller wishes to skip forward in the results + // some amount, the 'seek' represents how many results to skip. FetchTxsForAddr(addr btcutil.Address, skip int, limit int) ([]*TxListReply, error) // DeleteAddrIndex deletes the entire addrindex stored within the DB. @@ -166,10 +166,13 @@ type TxListReply struct { Err error } +// AddrIndexKeySize is the number of bytes used by keys into the BlockAddrIndex. +const AddrIndexKeySize = ripemd160.Size + // BlockAddrIndex represents the indexing structure for addresses. // It maps a hash160 to a list of transaction locations within a block that // either pays to or spends from the passed UTXO for the hash160. -type BlockAddrIndex map[[ripemd160.Size]byte][]*btcwire.TxLoc +type BlockAddrIndex map[[AddrIndexKeySize]byte][]*btcwire.TxLoc // driverList holds all of the registered database backends. var driverList []DriverDB diff --git a/ldb/internal_test.go b/ldb/internal_test.go index d3fcf0a..d0fc00b 100644 --- a/ldb/internal_test.go +++ b/ldb/internal_test.go @@ -9,7 +9,7 @@ import ( "testing" - "github.com/conformal/btcutil" + "github.com/btcsuite/btcutil" "golang.org/x/crypto/ripemd160" ) @@ -59,6 +59,6 @@ func TestBytesPrefix(t *testing.T) { if !bytes.Equal(prefixRange.Limit, []byte("b")) { t.Errorf("Wrong prefix end, got %d, expected %d", prefixRange.Limit, - []byte("a")) + []byte("b")) } } diff --git a/ldb/operational_test.go b/ldb/operational_test.go index 37d0174..a8ae7a3 100644 --- a/ldb/operational_test.go +++ b/ldb/operational_test.go @@ -25,7 +25,18 @@ import ( var network = btcwire.MainNet -func setUpTestDb(t *testing.T) (btcdb.Db, []*btcutil.Block, string, string, error) { +// testDb is used to store db related context for a running test. +// the `cleanUpFunc` *must* be called after each test to maintain db +// consistency across tests. +type testDb struct { + db btcdb.Db + blocks []*btcutil.Block + dbName string + dbNameVer string + cleanUpFunc func() +} + +func setUpTestDb(t *testing.T) (*testDb, error) { // Ignore db remove errors since it means we didn't have an old one. dbname := fmt.Sprintf("tstdbop1") dbnamever := dbname + ".ver" @@ -33,16 +44,28 @@ func setUpTestDb(t *testing.T) (btcdb.Db, []*btcutil.Block, string, string, erro _ = os.RemoveAll(dbnamever) db, err := btcdb.CreateDB("leveldb", dbname) if err != nil { - return nil, nil, "", "", err + return nil, err } testdatafile := filepath.Join("..", "testdata", "blocks1-256.bz2") blocks, err := loadBlocks(t, testdatafile) if err != nil { - return nil, nil, "", "", err + return nil, err + } + + cleanUp := func() { + db.Close() + os.RemoveAll(dbname) + os.RemoveAll(dbnamever) } - return db, blocks, dbname, dbnamever, nil + return &testDb{ + db: db, + blocks: blocks, + dbName: dbname, + dbNameVer: dbnamever, + cleanUpFunc: cleanUp, + }, nil } func TestOperational(t *testing.T) { @@ -55,36 +78,31 @@ func testAddrIndexOperations(t *testing.T, db btcdb.Db, newestBlock *btcutil.Blo // Metadata about the current addr index state should be unset. sha, height, err := db.FetchAddrIndexTip() if err != btcdb.ErrAddrIndexDoesNotExist { - t.Errorf("Address index metadata shouldn't be in db, hasn't" + - " be built up yet.") - return + t.Fatalf("Address index metadata shouldn't be in db, hasn't been built up yet.") } var zeroHash btcwire.ShaHash if !sha.IsEqual(&zeroHash) { - t.Errorf("AddrIndexTip wrong hash got: %s, want %s", sha, &zeroHash) - return + t.Fatalf("AddrIndexTip wrong hash got: %s, want %s", sha, &zeroHash) } if height != -1 { - t.Errorf("Addrindex not built up, yet a block index tip has been set to: %d.", height) - return + t.Fatalf("Addrindex not built up, yet a block index tip has been set to: %d.", height) } // Simple test to index outputs(s) of the first tx. testIndex := make(btcdb.BlockAddrIndex) testTx, err := newestBlock.Tx(0) if err != nil { - t.Errorf("Block has no transactions, unable to test addr "+"indexing, err %v", err) - return + t.Fatalf("Block has no transactions, unable to test addr "+ + "indexing, err %v", err) } // Extract the dest addr from the tx. _, testAddrs, _, err := btcscript.ExtractPkScriptAddrs(testTx.MsgTx().TxOut[0].PkScript, &btcnet.MainNetParams) if err != nil { - t.Errorf("Unable to decode tx output, err %v", err) - return + t.Fatalf("Unable to decode tx output, err %v", err) } // Extract the hash160 from the output script. @@ -97,12 +115,11 @@ func testAddrIndexOperations(t *testing.T, db btcdb.Db, newestBlock *btcutil.Blo testIndex[hash160Bytes] = []*btcwire.TxLoc{&blktxLoc[0]} // Insert our test addr index into the DB. - err = db.UpdateAddrIndexForBlock(newestSha, newestBlockIdx, &testIndex) + err = db.UpdateAddrIndexForBlock(newestSha, newestBlockIdx, testIndex) if err != nil { - t.Errorf("UpdateAddrIndexForBlock: failed to index"+ + t.Fatalf("UpdateAddrIndexForBlock: failed to index"+ " addrs for block #%d (%s) "+ "err %v", newestBlockIdx, newestSha, err) - return } // Chain Tip of address should've been updated. @@ -111,22 +128,19 @@ func testAddrIndexOperations(t *testing.T, db btcdb.Db, newestBlock *btcutil.Blo // Check index retrieval. txReplies, err := db.FetchTxsForAddr(testAddrs[0], 0, 1000) if err != nil { - t.Errorf("FetchTxsForAddr failed to correctly fetch txs for an "+ + t.Fatalf("FetchTxsForAddr failed to correctly fetch txs for an "+ "address, err %v", err) - return } // Should have one reply. - if len(txReplies) == 0 { - t.Errorf("Failed to properly index tx by address.") - return + if len(txReplies) != 1 { + t.Fatalf("Failed to properly index tx by address.") } // Our test tx and indexed tx should have the same sha. indexedTx := txReplies[0] if !bytes.Equal(indexedTx.Sha.Bytes(), testTx.Sha().Bytes()) { - t.Errorf("Failed to fetch proper indexed tx. Expected sha %v, "+ - "fetched %v", indexedTx.Sha, testTx.Sha()) - return + t.Fatalf("Failed to fetch proper indexed tx. Expected sha %v, "+ + "fetched %v", testTx.Sha(), indexedTx.Sha) } // Shut down DB. @@ -136,30 +150,30 @@ func testAddrIndexOperations(t *testing.T, db btcdb.Db, newestBlock *btcutil.Blo // Re-Open, tip still should be updated to current height and sha. db, err = btcdb.OpenDB("leveldb", "tstdbop1") if err != nil { - t.Errorf("Unable to re-open created db, err %v", err) - return + t.Fatalf("Unable to re-open created db, err %v", err) } assertAddrIndexTipIsUpdated(db, t, newestSha, newestBlockIdx) // Delete the entire index. err = db.DeleteAddrIndex() if err != nil { - t.Errorf("Couldn't delete address index, err %v", err) - return + t.Fatalf("Couldn't delete address index, err %v", err) } // Former index should no longer exist. txReplies, err = db.FetchTxsForAddr(testAddrs[0], 0, 1000) + if err != nil { + t.Fatalf("Unable to fetch transactions for address: %v", err) + } if len(txReplies) != 0 { - t.Errorf("Address index was not successfully deleted. "+ + t.Fatalf("Address index was not successfully deleted. "+ "Should have 0 tx's indexed, %v were returned.", len(txReplies)) - return } // Tip should be blanked out. if _, _, err := db.FetchAddrIndexTip(); err != btcdb.ErrAddrIndexDoesNotExist { - t.Errorf("Address index was not fully deleted.") + t.Fatalf("Address index was not fully deleted.") } } @@ -168,14 +182,12 @@ func assertAddrIndexTipIsUpdated(db btcdb.Db, t *testing.T, newestSha *btcwire.S // Safe to ignore error, since height will be < 0 in "error" case. sha, height, _ := db.FetchAddrIndexTip() if newestBlockIdx != height { - t.Errorf("Height of address index tip failed to update, "+ + t.Fatalf("Height of address index tip failed to update, "+ "expected %v, got %v", newestBlockIdx, height) - return } if !bytes.Equal(newestSha.Bytes(), sha.Bytes()) { - t.Errorf("Sha of address index tip failed to update, "+ + t.Fatalf("Sha of address index tip failed to update, "+ "expected %v, got %v", newestSha, sha) - return } } @@ -185,19 +197,16 @@ func testOperationalMode(t *testing.T) { // 2) look up all txin (except coinbase in db) // 3) insert block // 4) exercise the optional addridex - db, blocks, dbname, dbnamever, err := setUpTestDb(t) + testDb, err := setUpTestDb(t) + defer testDb.cleanUpFunc() if err != nil { t.Errorf("Unable to load blocks from test data: %v", err) return } - // Tear down. - defer db.Close() - defer os.RemoveAll(dbname) - defer os.RemoveAll(dbnamever) err = nil out: - for height := int64(0); height < int64(len(blocks)); height++ { - block := blocks[height] + for height := int64(0); height < int64(len(testDb.blocks)); height++ { + block := testDb.blocks[height] mblock := block.MsgBlock() var txneededList []*btcwire.ShaHash for _, tx := range mblock.Transactions { @@ -208,7 +217,7 @@ out: origintxsha := &txin.PreviousOutPoint.Hash txneededList = append(txneededList, origintxsha) - exists, err := db.ExistsTxSha(origintxsha) + exists, err := testDb.db.ExistsTxSha(origintxsha) if err != nil { t.Errorf("ExistsTxSha: unexpected error %v ", err) } @@ -216,13 +225,13 @@ out: t.Errorf("referenced tx not found %v ", origintxsha) } - _, err = db.FetchTxBySha(origintxsha) + _, err = testDb.db.FetchTxBySha(origintxsha) if err != nil { t.Errorf("referenced tx not found %v err %v ", origintxsha, err) } } } - txlist := db.FetchUnSpentTxByShaList(txneededList) + txlist := testDb.db.FetchUnSpentTxByShaList(txneededList) for _, txe := range txlist { if txe.Err != nil { t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err) @@ -230,7 +239,7 @@ out: } } - newheight, err := db.InsertBlock(block) + newheight, err := testDb.db.InsertBlock(block) if err != nil { t.Errorf("failed to insert block %v err %v", height, err) break out @@ -240,7 +249,7 @@ out: break out } - newSha, blkid, err := db.NewestSha() + newSha, blkid, err := testDb.db.NewestSha() if err != nil { t.Errorf("failed to obtain latest sha %v %v", height, err) } @@ -256,12 +265,12 @@ out: } // now that the db is populated, do some additional tests - testFetchHeightRange(t, db, blocks) + testFetchHeightRange(t, testDb.db, testDb.blocks) // Ensure all operations dealing with the optional address index behave // correctly. - newSha, blkid, err := db.NewestSha() - testAddrIndexOperations(t, db, blocks[len(blocks)-1], newSha, blkid) + newSha, blkid, err := testDb.db.NewestSha() + testAddrIndexOperations(t, testDb.db, testDb.blocks[len(testDb.blocks)-1], newSha, blkid) } func TestBackout(t *testing.T) { @@ -274,38 +283,35 @@ func testBackout(t *testing.T) { // 2) look up all txin (except coinbase in db) // 3) insert block - db, blocks, dbname, dbnamever, err := setUpTestDb(t) - // Tear down. - defer db.Close() - defer os.RemoveAll(dbname) - defer os.RemoveAll(dbnamever) + testDb, err := setUpTestDb(t) + defer testDb.cleanUpFunc() if err != nil { t.Errorf("Failed to open test database %v", err) return } - if len(blocks) < 120 { + if len(testDb.blocks) < 120 { t.Errorf("test data too small") return } err = nil - for height := int64(0); height < int64(len(blocks)); height++ { + for height := int64(0); height < int64(len(testDb.blocks)); height++ { if height == 100 { t.Logf("Syncing at block height 100") - db.Sync() + testDb.db.Sync() } if height == 120 { t.Logf("Simulating unexpected application quit") // Simulate unexpected application quit - db.RollbackClose() + testDb.db.RollbackClose() break } - block := blocks[height] + block := testDb.blocks[height] - newheight, err := db.InsertBlock(block) + newheight, err := testDb.db.InsertBlock(block) if err != nil { t.Errorf("failed to insert block %v err %v", height, err) return @@ -319,49 +325,49 @@ func testBackout(t *testing.T) { // db was closed at height 120, so no cleanup is possible. // reopen db - db, err = btcdb.OpenDB("leveldb", dbname) + testDb.db, err = btcdb.OpenDB("leveldb", testDb.dbName) if err != nil { t.Errorf("Failed to open test database %v", err) return } defer func() { - if err := db.Close(); err != nil { + if err := testDb.db.Close(); err != nil { t.Errorf("Close: unexpected error: %v", err) } }() - sha, err := blocks[99].Sha() + sha, err := testDb.blocks[99].Sha() if err != nil { t.Errorf("failed to get block 99 sha err %v", err) return } - if _, err := db.ExistsSha(sha); err != nil { + if _, err := testDb.db.ExistsSha(sha); err != nil { t.Errorf("ExistsSha: unexpected error: %v", err) } - _, err = db.FetchBlockBySha(sha) + _, err = testDb.db.FetchBlockBySha(sha) if err != nil { t.Errorf("failed to load block 99 from db %v", err) return } - sha, err = blocks[119].Sha() + sha, err = testDb.blocks[119].Sha() if err != nil { t.Errorf("failed to get block 110 sha err %v", err) return } - if _, err := db.ExistsSha(sha); err != nil { + if _, err := testDb.db.ExistsSha(sha); err != nil { t.Errorf("ExistsSha: unexpected error: %v", err) } - _, err = db.FetchBlockBySha(sha) + _, err = testDb.db.FetchBlockBySha(sha) if err != nil { t.Errorf("loaded block 119 from db") return } - block := blocks[119] + block := testDb.blocks[119] mblock := block.MsgBlock() txsha, err := mblock.Transactions[0].TxSha() - exists, err := db.ExistsTxSha(&txsha) + exists, err := testDb.db.ExistsTxSha(&txsha) if err != nil { t.Errorf("ExistsTxSha: unexpected error %v ", err) } @@ -369,7 +375,7 @@ func testBackout(t *testing.T) { t.Errorf("tx %v not located db\n", txsha) } - _, err = db.FetchTxBySha(&txsha) + _, err = testDb.db.FetchTxBySha(&txsha) if err != nil { t.Errorf("tx %v not located db\n", txsha) return @@ -498,22 +504,19 @@ func testFetchHeightRange(t *testing.T, db btcdb.Db, blocks []*btcutil.Block) { } func TestLimitAndSkipFetchTxsForAddr(t *testing.T) { - db, _, dbname, dbnamever, err := setUpTestDb(t) - // Tear down. - defer db.Close() - defer os.RemoveAll(dbname) - defer os.RemoveAll(dbnamever) + testDb, err := setUpTestDb(t) + defer testDb.cleanUpFunc() // Insert a block with some fake test transactions. The block will have // 10 copies of a fake transaction involving same address. addrString := "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa" targetAddr, err := btcutil.DecodeAddress(addrString, &btcnet.MainNetParams) if err != nil { - t.Errorf("Unable to decode test address: %v", err) + t.Fatalf("Unable to decode test address: %v", err) } outputScript, err := btcscript.PayToAddrScript(targetAddr) if err != nil { - t.Errorf("Unable make test pkScript %v", err) + t.Fatalf("Unable make test pkScript %v", err) } fakeTxOut := btcwire.NewTxOut(10, outputScript) var emptyHash btcwire.ShaHash @@ -527,9 +530,9 @@ func TestLimitAndSkipFetchTxsForAddr(t *testing.T) { // Insert the test block into the DB. testBlock := btcutil.NewBlock(msgBlock) - newheight, err := db.InsertBlock(testBlock) + newheight, err := testDb.db.InsertBlock(testBlock) if err != nil { - t.Errorf("Unable to insert block into db: %v", err) + t.Fatalf("Unable to insert block into db: %v", err) } // Create and insert an address index for out test addr. @@ -542,32 +545,41 @@ func TestLimitAndSkipFetchTxsForAddr(t *testing.T) { index[hash160] = append(index[hash160], &txLoc[i]) } blkSha, _ := testBlock.Sha() - err = db.UpdateAddrIndexForBlock(blkSha, newheight, &index) + err = testDb.db.UpdateAddrIndexForBlock(blkSha, newheight, index) if err != nil { - t.Errorf("UpdateAddrIndexForBlock: failed to index"+ + t.Fatalf("UpdateAddrIndexForBlock: failed to index"+ " addrs for block #%d (%s) "+ "err %v", newheight, blkSha, err) return } // Try skipping the first 4 results, should get 6 in return. - txReply, err := db.FetchTxsForAddr(targetAddr, 4, 100000) - if err != nil && len(txReply) != 6 { - t.Errorf("Did not correctly skip forward in txs for address reply"+ - "got %v txs, expected %v", len(txReply), 6) + txReply, err := testDb.db.FetchTxsForAddr(targetAddr, 4, 100000) + if err != nil { + t.Fatalf("Unable to fetch transactions for address: %v", err) + } + if len(txReply) != 6 { + t.Fatalf("Did not correctly skip forward in txs for address reply"+ + " got %v txs, expected %v", len(txReply), 6) } // Limit the number of results to 3. - txReply, err = db.FetchTxsForAddr(targetAddr, 0, 3) - if err != nil && len(txReply) != 3 { - t.Errorf("Did not correctly limit in txs for address reply"+ - "got %v txs, expected %v", len(txReply), 3) + txReply, err = testDb.db.FetchTxsForAddr(targetAddr, 0, 3) + if err != nil { + t.Fatalf("Unable to fetch transactions for address: %v", err) + } + if len(txReply) != 3 { + t.Fatalf("Did not correctly limit in txs for address reply"+ + " got %v txs, expected %v", len(txReply), 3) } // Skip 1, limit 5. - txReply, err = db.FetchTxsForAddr(targetAddr, 1, 5) - if err != nil && len(txReply) != 5 { - t.Errorf("Did not correctly limit in txs for address reply"+ - "got %v txs, expected %v", len(txReply), 5) + txReply, err = testDb.db.FetchTxsForAddr(targetAddr, 1, 5) + if err != nil { + t.Fatalf("Unable to fetch transactions for address: %v", err) + } + if len(txReply) != 5 { + t.Fatalf("Did not correctly limit in txs for address reply"+ + " got %v txs, expected %v", len(txReply), 5) } } diff --git a/ldb/tx.go b/ldb/tx.go index d065f42..1541493 100644 --- a/ldb/tx.go +++ b/ldb/tx.go @@ -18,13 +18,13 @@ import ( ) const ( - // Each address index is 38 bytes: + // Each address index is 34 bytes: // -------------------------------------------------------- // | Prefix | Hash160 | BlkHeight | Tx Offset | Tx Size | // -------------------------------------------------------- - // | 2 bytes | 20 bytes | 8 bytes | 4 bytes | 4 bytes | + // | 2 bytes | 20 bytes | 4 bytes | 4 bytes | 4 bytes | // -------------------------------------------------------- - addrIndexKeyLength = 2 + ripemd160.Size + 8 + 4 + 4 + addrIndexKeyLength = 2 + ripemd160.Size + 4 + 4 + 4 batchDeleteThreshold = 10000 ) @@ -377,24 +377,15 @@ func (db *LevelDb) FetchTxBySha(txsha *btcwire.ShaHash) ([]*btcdb.TxListReply, e } // addrIndexToKey serializes the passed txAddrIndex for storage within the DB. -// Transactions indexed by address are stored with the following format: -// * prefix || hash160 || blockHeight || txoffset || txlen -// Indexes are stored purely in the key, with blank data for the actual value -// in order to facilitate ease of iteration by their shared prefix and -// also to allow limiting the number of returned transactions (RPC). -// Alternatively, indexes for each address could be stored as an -// append-only list for the stored value. However, this add unnecessary -// overhead when storing and retrieving since the *entire* list must -// be fetched each time. func addrIndexToKey(index *txAddrIndex) []byte { record := make([]byte, addrIndexKeyLength, addrIndexKeyLength) copy(record[:2], addrIndexKeyPrefix) copy(record[2:22], index.hash160[:]) // The index itself. - binary.LittleEndian.PutUint64(record[22:30], uint64(index.blkHeight)) - binary.LittleEndian.PutUint32(record[30:34], uint32(index.txoffset)) - binary.LittleEndian.PutUint32(record[34:38], uint32(index.txlen)) + binary.LittleEndian.PutUint32(record[22:26], uint32(index.blkHeight)) + binary.LittleEndian.PutUint32(record[26:30], uint32(index.txoffset)) + binary.LittleEndian.PutUint32(record[30:34], uint32(index.txlen)) return record } @@ -402,9 +393,9 @@ func addrIndexToKey(index *txAddrIndex) []byte { // unpackTxIndex deserializes the raw bytes of a address tx index. func unpackTxIndex(rawIndex []byte) *txAddrIndex { return &txAddrIndex{ - blkHeight: int64(binary.LittleEndian.Uint64(rawIndex[0:8])), - txoffset: int(binary.LittleEndian.Uint32(rawIndex[8:12])), - txlen: int(binary.LittleEndian.Uint32(rawIndex[12:16])), + blkHeight: int64(binary.LittleEndian.Uint32(rawIndex[0:4])), + txoffset: int(binary.LittleEndian.Uint32(rawIndex[4:8])), + txlen: int(binary.LittleEndian.Uint32(rawIndex[8:12])), } } @@ -452,7 +443,7 @@ func (db *LevelDb) FetchTxsForAddr(addr btcutil.Address, skip int, addrPrefix := make([]byte, 22, 22) copy(addrPrefix[:2], addrIndexKeyPrefix) - copy(addrPrefix[2:], addrKey[:]) + copy(addrPrefix[2:], addrKey) var replies []*btcdb.TxListReply iter := db.lDb.NewIterator(bytesPrefix(addrPrefix), nil) @@ -491,12 +482,16 @@ func (db *LevelDb) FetchTxsForAddr(addr btcutil.Address, skip int, // will update the stored meta-data related to the curent tip of the // addr index. These two operations are performed in an atomic // transaction which is commited before the function returns. -// Addresses are indexed by the raw bytes of their base58 decoded -// hash160. -// NOTE: See comment for addrIndexToKey for information pertaining to -// how the address index is currently represented and stored within the -// db. -func (db *LevelDb) UpdateAddrIndexForBlock(blkSha *btcwire.ShaHash, blkHeight int64, addrIndex *btcdb.BlockAddrIndex) error { +// Transactions indexed by address are stored with the following format: +// * prefix || hash160 || blockHeight || txoffset || txlen +// Indexes are stored purely in the key, with blank data for the actual value +// in order to facilitate ease of iteration by their shared prefix and +// also to allow limiting the number of returned transactions (RPC). +// Alternatively, indexes for each address could be stored as an +// append-only list for the stored value. However, this add unnecessary +// overhead when storing and retrieving since the entire list must +// be fetched each time. +func (db *LevelDb) UpdateAddrIndexForBlock(blkSha *btcwire.ShaHash, blkHeight int64, addrIndex btcdb.BlockAddrIndex) error { db.dbLock.Lock() defer db.dbLock.Unlock() @@ -506,7 +501,7 @@ func (db *LevelDb) UpdateAddrIndexForBlock(blkSha *btcwire.ShaHash, blkHeight in // Write all data for the new address indexes in a single batch // transaction. - for addrKey, indexes := range *addrIndex { + for addrKey, indexes := range addrIndex { for _, txLoc := range indexes { index := &txAddrIndex{ hash160: addrKey, @@ -558,12 +553,12 @@ func (db *LevelDb) DeleteAddrIndex() error { if numInBatch >= batchDeleteThreshold { if err := db.lDb.Write(batch, db.wo); err != nil { return err - } else { - batch.Reset() - numInBatch = 0 } + batch.Reset() + numInBatch = 0 } } + iter.Release() batch.Delete(addrIndexMetaDataKey) if err := db.lDb.Write(batch, db.wo); err != nil { diff --git a/memdb/memdb.go b/memdb/memdb.go index 01420f4..bacb9be 100644 --- a/memdb/memdb.go +++ b/memdb/memdb.go @@ -707,7 +707,7 @@ func (db *MemDb) FetchAddrIndexTip() (*btcwire.ShaHash, int64, error) { // UpdateAddrIndexForBlock isn't currently implemented. This is a part of the // btcdb.Db interface implementation. func (db *MemDb) UpdateAddrIndexForBlock(*btcwire.ShaHash, int64, - *btcdb.BlockAddrIndex) error { + btcdb.BlockAddrIndex) error { return btcdb.ErrNotImplemented }