transaction_list produces same output as old version

This commit is contained in:
Lex Berezhny 2018-09-25 22:40:52 -04:00
parent 1c2849235c
commit b16c36b55f
4 changed files with 117 additions and 20 deletions

View file

@ -16,6 +16,7 @@ from twisted.internet.task import LoopingCall
from twisted.python.failure import Failure from twisted.python.failure import Failure
from torba.constants import COIN from torba.constants import COIN
from torba.baseaccount import SingleKey, HierarchicalDeterministic
from lbryschema.claim import ClaimDict from lbryschema.claim import ClaimDict
from lbryschema.uri import parse_lbry_uri from lbryschema.uri import parse_lbry_uri
@ -46,7 +47,7 @@ from lbrynet.core.Peer import Peer
from lbrynet.core.SinglePeerDownloader import SinglePeerDownloader from lbrynet.core.SinglePeerDownloader import SinglePeerDownloader
from lbrynet.core.client.StandaloneBlobDownloader import StandaloneBlobDownloader from lbrynet.core.client.StandaloneBlobDownloader import StandaloneBlobDownloader
from lbrynet.wallet.account import Account as LBCAccount from lbrynet.wallet.account import Account as LBCAccount
from torba.baseaccount import SingleKey, HierarchicalDeterministic from lbrynet.wallet.manager import LbryWalletManager
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
requires = AuthJSONRPCServer.requires requires = AuthJSONRPCServer.requires
@ -226,7 +227,7 @@ class Daemon(AuthJSONRPCServer):
# TODO: delete these, get the components where needed # TODO: delete these, get the components where needed
self.storage = None self.storage = None
self.dht_node = None self.dht_node = None
self.wallet_manager = None self.wallet_manager: LbryWalletManager = None
self.sd_identifier = None self.sd_identifier = None
self.file_manager = None self.file_manager = None
self.exchange_rate_manager = None self.exchange_rate_manager = None

View file

@ -64,7 +64,7 @@ class WalletDatabase(BaseDatabase):
SELECT tx.txid, txo.position, txo.claim_id SELECT tx.txid, txo.position, txo.claim_id
FROM txo JOIN tx ON tx.txid=txo.txid FROM txo JOIN tx ON tx.txid=txo.txid
WHERE {} AND (is_claim OR is_update) WHERE {} AND (is_claim OR is_update)
GROUP BY txo.claim_id ORDER BY tx.height DESC; GROUP BY txo.claim_id ORDER BY tx.height DESC, tx.position ASC;
""".format(filter_sql), (filter_value,) """.format(filter_sql), (filter_value,)
) )
@ -89,23 +89,30 @@ class WalletDatabase(BaseDatabase):
filter_sql = "claim_id=?" filter_sql = "claim_id=?"
filter_value = (claim_id,) filter_value = (claim_id,)
else: else:
filter_sql = "txo.txid=? AND position=?" filter_sql = "txo.txid=? AND txo.position=?"
filter_value = (txid, nout) filter_value = (txid, nout)
utxos = yield self.db.runQuery( utxos = yield self.db.runQuery(
""" """
SELECT amount, script, txo.txid, position SELECT amount, script, txo.txid, txo.position, account
FROM txo JOIN tx ON tx.txid=txo.txid FROM txo
WHERE {} AND (is_claim OR is_update) AND txoid NOT IN (SELECT txoid FROM txi) JOIN tx ON tx.txid=txo.txid
ORDER BY tx.height DESC LIMIT 1; JOIN pubkey_address ON pubkey_address.address=txo.address
WHERE {}
AND (is_claim OR is_update)
AND txoid NOT IN (SELECT txoid FROM txi)
ORDER BY tx.height DESC, tx.position ASC LIMIT 1;
""".format(filter_sql), filter_value """.format(filter_sql), filter_value
) )
output_class = account.ledger.transaction_class.output_class output_class = account.ledger.transaction_class.output_class
account_id = account.public_key.address
return [ return [
output_class( output_class(
values[0], values[0],
output_class.script_class(values[1]), output_class.script_class(values[1]),
TXRefImmutable.from_id(values[2]), TXRefImmutable.from_id(values[2]),
position=values[3] position=values[3],
is_change=False,
is_my_account=values[4] == account_id
) for values in utxos ) for values in utxos
] ]
@ -113,11 +120,15 @@ class WalletDatabase(BaseDatabase):
def get_claims(self, account): def get_claims(self, account):
utxos = yield self.db.runQuery( utxos = yield self.db.runQuery(
""" """
SELECT amount, script, txo.txid, position SELECT amount, script, txo.txid, txo.position
FROM txo JOIN tx ON tx.txid=txo.txid FROM txo
WHERE (is_claim OR is_update) AND txoid NOT IN (SELECT txoid FROM txi) JOIN tx ON tx.txid=txo.txid
ORDER BY tx.height DESC; JOIN pubkey_address ON pubkey_address.address=txo.address
""" WHERE (is_claim OR is_update)
AND txoid NOT IN (SELECT txoid FROM txi)
AND account = :account
ORDER BY tx.height DESC, tx.position ASC;
""", {'account': account.public_key.address}
) )
output_class = account.ledger.transaction_class.output_class output_class = account.ledger.transaction_class.output_class
return [ return [
@ -125,6 +136,8 @@ class WalletDatabase(BaseDatabase):
values[0], values[0],
output_class.script_class(values[1]), output_class.script_class(values[1]),
TXRefImmutable.from_id(values[2]), TXRefImmutable.from_id(values[2]),
position=values[3] position=values[3],
is_change=False,
is_my_account=True
) for values in utxos ) for values in utxos
] ]

View file

@ -1,6 +1,9 @@
import os import os
import json import json
import logging import logging
from datetime import datetime
from typing import List
from twisted.internet import defer from twisted.internet import defer
from torba.basemanager import BaseWalletManager from torba.basemanager import BaseWalletManager
@ -8,7 +11,7 @@ from torba.basemanager import BaseWalletManager
from lbryschema.claim import ClaimDict from lbryschema.claim import ClaimDict
from .ledger import MainNetLedger from .ledger import MainNetLedger
from .account import generate_certificate from .account import BaseAccount, generate_certificate
from .transaction import Transaction from .transaction import Transaction
from .database import WalletDatabase from .database import WalletDatabase
@ -227,13 +230,62 @@ class LbryWalletManager(BaseWalletManager):
return True return True
return False return False
def get_transaction(self, txid): def get_transaction(self, txid: str):
return self.default_account.ledger.get_transaction(txid) return self.default_account.ledger.get_transaction(txid)
def get_history(self, account): @staticmethod
return account.get_transactions() @defer.inlineCallbacks
def get_history(account: BaseAccount):
headers = account.ledger.headers
txs: List[Transaction] = (yield account.get_transactions())
history = []
for tx in txs:
ts = headers[tx.height]['timestamp']
history.append({
'txid': tx.id,
'timestamp': ts,
'value': tx.net_account_balance,
'fee': tx.fee,
'date': datetime.fromtimestamp(ts).isoformat(' ')[:-3],
'confirmations': headers.height - tx.height,
'claim_info': [{
'address': txo.get_address(account.ledger),
'balance_delta': -txo.amount,
'amount': txo.amount,
'claim_id': txo.claim_id,
'claim_name': txo.claim_name,
'nout': txo.position
} for txo in tx.my_claim_outputs],
'update_info': [{
'address': txo.get_address(account.ledger),
'balance_delta': -txo.amount,
'amount': txo.amount,
'claim_id': txo.claim_id,
'claim_name': txo.claim_name,
'nout': txo.position
} for txo in tx.my_update_outputs],
'support_info': [{
'address': txo.get_address(account.ledger),
'balance_delta': -txo.amount,
'amount': txo.amount,
'claim_id': txo.claim_id,
'claim_name': txo.claim_name,
'is_tip': False, # TODO: need to add lookup
'nout': txo.position
} for txo in tx.my_support_outputs],
'abandon_info': [{
'address': txo.get_address(account.ledger),
'balance_delta': txo.amount,
'amount': txo.amount,
'claim_id': txo.claim_id,
'claim_name': txo.claim_name,
'nout': txo.position
} for txo in tx.my_abandon_outputs],
})
return history
def get_utxos(self, account): @staticmethod
def get_utxos(account: BaseAccount):
return account.get_unspent_outputs() return account.get_unspent_outputs()
@defer.inlineCallbacks @defer.inlineCallbacks

View file

@ -123,3 +123,34 @@ class Transaction(BaseTransaction):
@classmethod @classmethod
def abandon(cls, claims: Iterable[Output], funding_accounts: Iterable[Account], change_account: Account): def abandon(cls, claims: Iterable[Output], funding_accounts: Iterable[Account], change_account: Account):
return cls.create([Input.spend(txo) for txo in claims], [], funding_accounts, change_account) return cls.create([Input.spend(txo) for txo in claims], [], funding_accounts, change_account)
def _filter_my_outputs(self, f):
for txo in self.outputs:
if txo.is_my_account and f(txo.script):
yield txo
@property
def my_claim_outputs(self):
return self._filter_my_outputs(lambda s: s.is_claim_name)
@property
def my_update_outputs(self):
return self._filter_my_outputs(lambda s: s.is_update_claim)
@property
def my_support_outputs(self):
return self._filter_my_outputs(lambda s: s.is_support_claim)
@property
def my_abandon_outputs(self):
for txi in self.inputs:
abandon = txi.txo_ref.txo
if abandon is not None and abandon.is_my_account and abandon.script.is_claim_involved:
is_update = False
if abandon.script.is_claim_name or abandon.script.is_update_claim:
for update in self.my_update_outputs:
if abandon.claim_id == update.claim_id:
is_update = True
break
if not is_update:
yield abandon