bdb (bcoin-org) - LevelDB Backend
bdb is an embedded, low-level key-value database library specifically designed as a LevelDB backend for the bcoin full node Bitcoin implementation. It is built on top of `leveldown` (or compatible LevelDB bindings) to provide persistent storage. The package, currently at version 1.6.2, is part of the broader `bcoin-org` ecosystem, which appears to be under active maintenance, though `bdb` itself sees less frequent, direct updates. Its primary differentiator is the `bdb.key` utility, offering structured key encoding and decoding for managing complex data types common in blockchain applications, such as cryptographic hashes and integers, enabling efficient storage and retrieval. Unlike general-purpose LevelDB wrappers, `bdb` is tailored for the specific data structures and performance requirements of a Bitcoin node. It operates as a local, embedded database without a server component, similar to other NoSQL key-value stores. Release cadence is tied to the needs of the `bcoin` project, rather than independent frequent updates.
Common errors
-
TypeError: bdb is not a function
cause Attempting to call the `bdb` module itself as a function, often due to a misunderstanding of how the module's API is exposed.fixThe main `bdb` export is an object. To create a database instance, use `bdb.create()`. For key utilities, use `bdb.key()`. -
Error: IO error: While open a file for appending: /path/to/my.db/LOG: Permission denied
cause The application lacks write permissions to the specified database directory.fixEnsure the Node.js process has read and write permissions for the database directory path provided to `bdb.create()`. Check directory ownership and permissions. -
ERR_REQUIRE_ESM: require() of ES Module ... not supported. Instead change the require of index.js in ... to a dynamic import() which is available in all CommonJS modules.
cause You are attempting to use `require()` in an ES module environment where it's not directly compatible, or trying to `import` a CommonJS module incorrectly.fixbdb is CommonJS. If your project is ESM, you might need to use dynamic `import('bdb')` or convert the surrounding code to CommonJS, or use a build tool to handle the interoperability.
Warnings
- gotcha bdb is a CommonJS module and does not natively support ES module `import` syntax. Attempting to `import bdb from 'bdb'` directly will result in runtime errors in an ESM context.
- gotcha Key encoding/decoding is central to bdb's design. Incorrectly defining `bdb.key` formats or attempting to read keys with a mismatched format will lead to data corruption or incorrect parsing, returning unexpected values or errors.
- gotcha Not closing database instances (`db.close()`) or iterators (`iter.end()`) can lead to file descriptor leaks, corrupted databases, or resource exhaustion, especially in long-running applications.
Install
-
npm install bdb -
yarn add bdb -
pnpm add bdb
Imports
- bdb
import bdb from 'bdb';
const bdb = require('bdb'); - bdb.create
const bdb = require('bdb'); const db = bdb.create('/path/to/my.db'); - bdb.key
const bdb = require('bdb'); const myKey = bdb.key('prefix', ['type1', 'type2']);
Quickstart
const bdb = require('bdb');
const path = require('path');
const os = require('os');
const fs = require('fs/promises');
async function runDbExample() {
const dbPath = path.join(os.tmpdir(), `bdb-example-${Date.now()}`);
await fs.mkdir(dbPath, { recursive: true });
const db = bdb.create(dbPath);
try {
await db.open();
console.log('Database opened at:', dbPath);
const myPrefix = bdb.key('r');
const myKey = bdb.key('t', ['hash160', 'uint32']);
const bucket = db.bucket(myPrefix.encode());
const batch = bucket.batch();
const hash = Buffer.alloc(20, 0x11); // Example 20-byte hash
// Write `foo` to `rt[11...11][00000000]`
batch.put(myKey.encode(hash, 0), Buffer.from('foo'));
batch.put(myKey.encode(Buffer.alloc(20, 0x22), 1), Buffer.from('bar'));
await batch.write();
console.log('Batch write complete.');
// Iterate:
const iter = bucket.iterator({
gte: myKey.min(),
lte: myKey.max(),
values: true
});
console.log('\nIterating through records:');
await iter.each((key, value) => {
const [decodedHash, index] = myKey.decode(key);
console.log(' Key:', key.toString('hex'), '-> Hash:', decodedHash.toString('hex'), 'Index:', index, 'Value:', value.toString());
});
await iter.end(); // Important to close iterator resources
// Using async iterator:
console.log('\nIterating with async iterator:');
const asyncIter = bucket.iterator({
gte: myKey.min(),
lte: myKey.max(),
values: true
});
for await (const {key, value} of asyncIter) {
const [decodedHash, index] = myKey.decode(key);
console.log(' Key:', key.toString('hex'), '-> Hash:', decodedHash.toString('hex'), 'Index:', index, 'Value:', value.toString());
}
await db.close();
console.log('\nDatabase closed.');
} catch (error) {
console.error('Database operation failed:', error);
} finally {
await fs.rm(dbPath, { recursive: true, force: true });
console.log('Cleaned up database directory:', dbPath);
}
}
runDbExample();