Add payment filtering by tx_id

This commit is contained in:
Michał Sałaban 2019-09-13 23:12:25 +02:00
parent f76311d03e
commit d44d4fd2ac
13 changed files with 781 additions and 17 deletions

View file

@ -183,6 +183,8 @@ class JSONRPCWallet(object):
def transfers_in(self, account, pmtfilter):
params = {'account_index': account, 'pending': False}
method = 'get_transfers'
if pmtfilter.tx_ids:
method = 'get_transfer_by_txid'
if pmtfilter.unconfirmed:
params['in'] = pmtfilter.confirmed
params['out'] = False
@ -196,7 +198,6 @@ class JSONRPCWallet(object):
params['out'] = False
params['pool'] = False
if method == 'get_transfers':
arg = 'in'
if pmtfilter.min_height:
# NOTE: the API uses (min, max] range which is confusing
params['min_height'] = pmtfilter.min_height - 1
@ -204,29 +205,48 @@ class JSONRPCWallet(object):
if pmtfilter.max_height:
params['max_height'] = pmtfilter.max_height
params['filter_by_height'] = True
# PR#3235 makes the following obsolete
# CRYPTONOTE_MAX_BLOCK_NUMBER = 500000000
params['max_height'] = params.get('max_height', 500000000)
_pmts = self.raw_request(method, params)
pmts = _pmts.get('in', [])
elif method == 'get_transfer_by_txid':
pmts = []
for txid in pmtfilter.tx_ids:
params['txid'] = txid
try:
_pmts = self.raw_request(method, params, squelch_error_logging=True)
except exceptions.TransactionNotFound:
continue
pmts.extend(_pmts['transfers'])
else:
arg = 'payments'
# NOTE: the API uses (min, max] range which is confusing
params['min_block_height'] = (pmtfilter.min_height or 1) - 1
_pmts = self.raw_request(method, params)
pmts = _pmts.get(arg, [])
_pmts = self.raw_request(method, params)
pmts = _pmts.get('payments', [])
if pmtfilter.unconfirmed:
pmts.extend(_pmts.get('pool', []))
return list(pmtfilter.filter(map(self._inpayment, pmts)))
def transfers_out(self, account, pmtfilter):
_pmts = self.raw_request('get_transfers', {
'account_index': account,
'in': False,
'out': pmtfilter.confirmed,
'pool': False,
'pending': pmtfilter.unconfirmed})
pmts = _pmts.get('out', [])
if pmtfilter.unconfirmed:
pmts.extend(_pmts.get('pending', []))
if pmtfilter.tx_ids:
pmts = []
for txid in pmtfilter.tx_ids:
try:
_pmts = self.raw_request(
'get_transfer_by_txid',
{'account_index': account, 'txid': txid},
squelch_error_logging=True)
except exceptions.TransactionNotFound:
continue
pmts.extend(_pmts['transfers'])
else:
_pmts = self.raw_request('get_transfers', {
'account_index': account,
'in': False,
'out': pmtfilter.confirmed,
'pool': False,
'pending': pmtfilter.unconfirmed})
pmts = _pmts.get('out', [])
if pmtfilter.unconfirmed:
pmts.extend(_pmts.get('pending', []))
return list(pmtfilter.filter(map(self._outpayment, pmts)))
def _paymentdict(self, data):
@ -363,7 +383,8 @@ class JSONRPCWallet(object):
if 'error' in result:
err = result['error']
_log.error(u"JSON RPC error:\n{result}".format(result=_ppresult))
if not squelch_error_logging:
_log.error(u"JSON RPC error:\n{result}".format(result=_ppresult))
if err['code'] in _err2exc:
raise _err2exc[err['code']](err['message'])
else:

View file

@ -1,3 +1,4 @@
import re
import sys
import warnings
from .address import address
@ -113,6 +114,13 @@ class PaymentManager(object):
return fetch(self.account_idx, PaymentFilter(**filterparams))
def _validate_tx_id(txid):
if not bool(re.compile('^[0-9a-f]{64}$').match(txid)):
raise ValueError("Transaction ID must be a 64-character hexadecimal string, not "
"'{}'".format(txid))
return txid
class _ByHeight(object):
"""A helper class used as key in sorting of payments by height.
Mempool goes on top, blockchain payments are ordered with descending block numbers.
@ -158,6 +166,7 @@ class PaymentFilter(object):
self.unconfirmed = filterparams.pop('unconfirmed', False)
self.confirmed = filterparams.pop('confirmed', True)
_local_address = filterparams.pop('local_address', None)
_tx_id = filterparams.pop('tx_id', None)
_payment_id = filterparams.pop('payment_id', None)
if len(filterparams) > 0:
raise ValueError("Excessive arguments for payment query: {}".format(filterparams))
@ -179,6 +188,18 @@ class PaymentFilter(object):
except TypeError:
local_addresses = [_local_address]
self.local_addresses = list(map(address, local_addresses))
if _tx_id is None:
self.tx_ids = []
else:
if isinstance(_tx_id, _str_types):
tx_ids = [_tx_id]
else:
try:
iter(_tx_id)
tx_ids = _tx_id
except TypeError:
tx_ids = [_tx_id]
self.tx_ids = list(map(_validate_tx_id, tx_ids))
if _payment_id is None:
self.payment_ids = []
else:
@ -209,6 +230,8 @@ class PaymentFilter(object):
return False
if self.payment_ids and payment.payment_id not in self.payment_ids:
return False
if self.tx_ids and payment.transaction.hash not in self.tx_ids:
return False
if self.local_addresses and payment.local_address not in self.local_addresses:
return False
return True