This commit is contained in:
Lex Berezhny 2020-04-12 11:06:05 -04:00
parent 74e3471bd9
commit 10c262a095
4 changed files with 72 additions and 51 deletions

View file

@ -39,6 +39,16 @@ jobs:
db: db:
- postgres - postgres
- sqlite - sqlite
services:
postgres:
image: postgres:12
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1

View file

@ -21,7 +21,13 @@ from lbry.wallet import PubKey
from lbry.wallet.transaction import Transaction, Output, OutputScript, TXRefImmutable from lbry.wallet.transaction import Transaction, Output, OutputScript, TXRefImmutable
from lbry.wallet.constants import TXO_TYPES, CLAIM_TYPES from lbry.wallet.constants import TXO_TYPES, CLAIM_TYPES
from .tables import metadata, Version, TX, TXI, TXO, PubkeyAddress, AccountAddress from .tables import (
metadata, Version,
PubkeyAddress, AccountAddress,
TX,
TXO, txo_join_account,
TXI, txi_join_account,
)
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -229,8 +235,8 @@ class Database:
def sync_create(self, name): def sync_create(self, name):
engine = sqlalchemy.create_engine(self.url) engine = sqlalchemy.create_engine(self.url)
db = engine.connect() db = engine.connect()
db.execute('commit') db.execute(text('commit'))
db.execute(f'create database {name}') db.execute(text(f'create database {name}'))
async def create(self, name): async def create(self, name):
await asyncio.get_event_loop().run_in_executor( await asyncio.get_event_loop().run_in_executor(
@ -240,8 +246,8 @@ class Database:
def sync_drop(self, name): def sync_drop(self, name):
engine = sqlalchemy.create_engine(self.url) engine = sqlalchemy.create_engine(self.url)
db = engine.connect() db = engine.connect()
db.execute('commit') db.execute(text('commit'))
db.execute(f'drop database if exists {name}') db.execute(text(f'drop database if exists {name}'))
async def drop(self, name): async def drop(self, name):
await asyncio.get_event_loop().run_in_executor( await asyncio.get_event_loop().run_in_executor(
@ -366,8 +372,8 @@ class Database:
assert accounts, "'accounts' argument required when no 'tx_hash' constraint is present" assert accounts, "'accounts' argument required when no 'tx_hash' constraint is present"
where = in_account(accounts) where = in_account(accounts)
tx_hashes = union( tx_hashes = union(
select(TXO.c.tx_hash).select_from(TXO.join(AccountAddress)).where(where), select(TXO.c.tx_hash).select_from(txo_join_account).where(where),
select(TXI.c.tx_hash).select_from(TXI.join(AccountAddress)).where(where) select(TXI.c.tx_hash).select_from(txi_join_account).where(where)
) )
s = s.where(TX.c.tx_hash.in_(tx_hashes)) s = s.where(TX.c.tx_hash.in_(tx_hashes))
return await self.execute_fetchall(query2([TX], s, **constraints)) return await self.execute_fetchall(query2([TX], s, **constraints))
@ -753,7 +759,7 @@ class Database:
if not {'purchased_claim_hash', 'purchased_claim_hash__in'}.intersection(constraints): if not {'purchased_claim_hash', 'purchased_claim_hash__in'}.intersection(constraints):
constraints['purchased_claim_hash__is_not_null'] = True constraints['purchased_claim_hash__is_not_null'] = True
constraints['tx_hash__in'] = ( constraints['tx_hash__in'] = (
select(TXI.c.tx_hash).select_from(TXI.join(AccountAddress)).where(in_account(accounts)) select(TXI.c.tx_hash).select_from(txi_join_account).where(in_account(accounts))
) )
async def get_purchases(self, **constraints): async def get_purchases(self, **constraints):

View file

@ -2,7 +2,7 @@
from sqlalchemy import ( from sqlalchemy import (
MetaData, Table, Column, ForeignKey, MetaData, Table, Column, ForeignKey,
BINARY, TEXT, SMALLINT, INTEGER, BOOLEAN LargeBinary, Text, SmallInteger, Integer, Boolean
) )
@ -11,74 +11,78 @@ metadata = MetaData()
Version = Table( Version = Table(
'version', metadata, 'version', metadata,
Column('version', TEXT, primary_key=True), Column('version', Text, primary_key=True),
) )
PubkeyAddress = Table( PubkeyAddress = Table(
'pubkey_address', metadata, 'pubkey_address', metadata,
Column('address', TEXT, primary_key=True), Column('address', Text, primary_key=True),
Column('history', TEXT, nullable=True), Column('history', Text, nullable=True),
Column('used_times', INTEGER, server_default='0'), Column('used_times', Integer, server_default='0'),
) )
AccountAddress = Table( AccountAddress = Table(
'account_address', metadata, 'account_address', metadata,
Column('account', TEXT, primary_key=True), Column('account', Text, primary_key=True),
Column('address', TEXT, ForeignKey(PubkeyAddress.columns.address), primary_key=True), Column('address', Text, ForeignKey(PubkeyAddress.columns.address), primary_key=True),
Column('chain', INTEGER), Column('chain', Integer),
Column('pubkey', BINARY), Column('pubkey', LargeBinary),
Column('chain_code', BINARY), Column('chain_code', LargeBinary),
Column('n', INTEGER), Column('n', Integer),
Column('depth', INTEGER), Column('depth', Integer),
) )
Block = Table( Block = Table(
'block', metadata, 'block', metadata,
Column('block_hash', BINARY, primary_key=True), Column('block_hash', LargeBinary, primary_key=True),
Column('previous_hash', BINARY), Column('previous_hash', LargeBinary),
Column('file_number', SMALLINT), Column('file_number', SmallInteger),
Column('height', INTEGER), Column('height', Integer),
) )
TX = Table( TX = Table(
'tx', metadata, 'tx', metadata,
Column('block_hash', BINARY, nullable=True), Column('block_hash', LargeBinary, nullable=True),
Column('tx_hash', BINARY, primary_key=True), Column('tx_hash', LargeBinary, primary_key=True),
Column('raw', BINARY), Column('raw', LargeBinary),
Column('height', INTEGER), Column('height', Integer),
Column('position', SMALLINT), Column('position', SmallInteger),
Column('is_verified', BOOLEAN, server_default='FALSE'), Column('is_verified', Boolean, server_default='FALSE'),
Column('purchased_claim_hash', BINARY, nullable=True), Column('purchased_claim_hash', LargeBinary, nullable=True),
Column('day', INTEGER, nullable=True), Column('day', Integer, nullable=True),
) )
TXO = Table( TXO = Table(
'txo', metadata, 'txo', metadata,
Column('tx_hash', BINARY, ForeignKey(TX.columns.tx_hash)), Column('tx_hash', LargeBinary, ForeignKey(TX.columns.tx_hash)),
Column('txo_hash', BINARY, primary_key=True), Column('txo_hash', LargeBinary, primary_key=True),
Column('address', TEXT, ForeignKey(AccountAddress.columns.address)), Column('address', Text),
Column('position', INTEGER), Column('position', Integer),
Column('amount', INTEGER), Column('amount', Integer),
Column('script', BINARY), Column('script', LargeBinary),
Column('is_reserved', BOOLEAN, server_default='0'), Column('is_reserved', Boolean, server_default='0'),
Column('txo_type', INTEGER, server_default='0'), Column('txo_type', Integer, server_default='0'),
Column('claim_id', TEXT, nullable=True), Column('claim_id', Text, nullable=True),
Column('claim_hash', BINARY, nullable=True), Column('claim_hash', LargeBinary, nullable=True),
Column('claim_name', TEXT, nullable=True), Column('claim_name', Text, nullable=True),
Column('channel_hash', BINARY, nullable=True), Column('channel_hash', LargeBinary, nullable=True),
Column('reposted_claim_hash', BINARY, nullable=True), Column('reposted_claim_hash', LargeBinary, nullable=True),
) )
txo_join_account = TXO.join(AccountAddress, TXO.columns.address == AccountAddress.columns.address)
TXI = Table( TXI = Table(
'txi', metadata, 'txi', metadata,
Column('tx_hash', BINARY, ForeignKey(TX.columns.tx_hash)), Column('tx_hash', LargeBinary, ForeignKey(TX.columns.tx_hash)),
Column('txo_hash', BINARY, ForeignKey(TXO.columns.txo_hash), primary_key=True), Column('txo_hash', LargeBinary, ForeignKey(TXO.columns.txo_hash), primary_key=True),
Column('address', TEXT, ForeignKey(AccountAddress.columns.address)), Column('address', Text),
Column('position', INTEGER), Column('position', Integer),
) )
txi_join_account = TXI.join(AccountAddress, TXI.columns.address == AccountAddress.columns.address)

View file

@ -130,11 +130,12 @@ class WalletNode:
if db_driver == 'sqlite': if db_driver == 'sqlite':
db = 'sqlite:///'+os.path.join(self.data_path, self.ledger_class.get_id(), 'blockchain.db') db = 'sqlite:///'+os.path.join(self.data_path, self.ledger_class.get_id(), 'blockchain.db')
elif db_driver == 'postgres': elif db_driver == 'postgres':
db_connection = 'postgres:postgres@localhost:5432'
db_name = f'lbry_test_{self.port}' db_name = f'lbry_test_{self.port}'
meta_db = Database(f'postgresql+psycopg2:///postgres') meta_db = Database(f'postgresql+psycopg2://{db_connection}/postgres')
await meta_db.drop(db_name) await meta_db.drop(db_name)
await meta_db.create(db_name) await meta_db.create(db_name)
db = f'postgresql+psycopg2:///{db_name}' db = f'postgresql+psycopg2://{db_connection}/{db_name}'
else: else:
raise RuntimeError(f"Unsupported database driver: {db_driver}") raise RuntimeError(f"Unsupported database driver: {db_driver}")
self.manager = self.manager_class.from_config({ self.manager = self.manager_class.from_config({