lbry-sdk/lbry/blockchain/db.py
2020-04-08 19:03:01 -04:00

124 lines
2.9 KiB
Python

import os
import asyncio
from collections import namedtuple
import apsw
DDL = """
pragma journal_mode=WAL;
create table block (
block_hash bytes not null,
previous_hash bytes not null,
height int
);
create table tx (
block_hash integer not null,
position integer not null,
tx_hash bytes not null
);
create table txi (
block_hash bytes not null,
tx_hash bytes not null,
txo_hash bytes not null
);
create table claim (
txo_hash bytes not null,
claim_hash bytes not null,
claim_name text not null,
amount integer not null,
height integer
);
create table claim_history (
block_hash bytes not null,
tx_hash bytes not null,
tx_position integer not null,
txo_hash bytes not null,
claim_hash bytes not null,
claim_name text not null,
action integer not null,
amount integer not null,
height integer,
is_spent bool
);
create table support (
block_hash bytes not null,
tx_hash bytes not null,
txo_hash bytes not null,
claim_hash bytes not null,
amount integer not null
);
"""
class BlockchainDB:
__slots__ = 'db', 'directory'
def __init__(self, path: str):
self.db = None
self.directory = path
def open(self):
self.db = apsw.Connection(
os.path.join(self.directory, 'blockchain.db'),
flags=(
apsw.SQLITE_OPEN_READWRITE |
apsw.SQLITE_OPEN_CREATE |
apsw.SQLITE_OPEN_URI
)
)
def exec_factory(cursor, statement, bindings):
tpl = namedtuple('row', (d[0] for d in cursor.getdescription()))
cursor.setrowtrace(lambda cursor, row: tpl(*row))
return True
self.db.setexectrace(exec_factory)
self.execute(DDL)
self.execute(f"ATTACH {os.path.join(self._db_path, 'block_index.sqlite')} AS block_index")
def close(self):
if self.db is not None:
self.db.close()
def execute(self, *args):
return self.db.cursor().execute(*args)
def executemany(self, *args):
return self.db.cursor().executemany(*args)
def begin(self):
self.execute('begin;')
def commit(self):
self.execute('commit;')
def get_blocks(self):
pass
class AsyncBlockchainDB:
__slots__ = 'db',
def __init__(self, db: BlockchainDB):
self.db = db
@classmethod
def from_path(cls, path: str):
return cls(BlockchainDB(path))
@staticmethod
async def run_in_executor(func, *args):
return await asyncio.get_running_loop().run_in_executor(
None, func, *args
)
async def open(self):
return await self.run_in_executor(self.db.open)
async def close(self):
return await self.run_in_executor(self.db.close)
async def get_blocks(self):
return await self.run_in_executor(self.db.get_blocks)