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

View File

@ -1,3 +1,4 @@
import re
import sys import sys
import warnings import warnings
from .address import address from .address import address
@ -113,6 +114,13 @@ class PaymentManager(object):
return fetch(self.account_idx, PaymentFilter(**filterparams)) 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): class _ByHeight(object):
"""A helper class used as key in sorting of payments by height. """A helper class used as key in sorting of payments by height.
Mempool goes on top, blockchain payments are ordered with descending block numbers. 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.unconfirmed = filterparams.pop('unconfirmed', False)
self.confirmed = filterparams.pop('confirmed', True) self.confirmed = filterparams.pop('confirmed', True)
_local_address = filterparams.pop('local_address', None) _local_address = filterparams.pop('local_address', None)
_tx_id = filterparams.pop('tx_id', None)
_payment_id = filterparams.pop('payment_id', None) _payment_id = filterparams.pop('payment_id', None)
if len(filterparams) > 0: if len(filterparams) > 0:
raise ValueError("Excessive arguments for payment query: {}".format(filterparams)) raise ValueError("Excessive arguments for payment query: {}".format(filterparams))
@ -179,6 +188,18 @@ class PaymentFilter(object):
except TypeError: except TypeError:
local_addresses = [_local_address] local_addresses = [_local_address]
self.local_addresses = list(map(address, local_addresses)) 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: if _payment_id is None:
self.payment_ids = [] self.payment_ids = []
else: else:
@ -209,6 +230,8 @@ class PaymentFilter(object):
return False return False
if self.payment_ids and payment.payment_id not in self.payment_ids: if self.payment_ids and payment.payment_id not in self.payment_ids:
return False 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: if self.local_addresses and payment.local_address not in self.local_addresses:
return False return False
return True return True

View File

@ -0,0 +1,26 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"subaddress_accounts": [
{
"account_index": 0,
"balance": 119141601989972,
"base_address": "56cXYWG13YKaT9z1aEy2hb9TZNnxrW3zE9S4nTQVDux5Qq7UYsmjuux3Zstxkorj9HAufyWLU3FwHW4uERQF6tkeUVogGN3",
"label": "Primary account",
"tag": "",
"unlocked_balance": 119141601989972
},
{
"account_index": 1,
"balance": 1000000000000,
"base_address": "79kTZg96pMf2Dt9rLEWnLzTUB8XC1wMhxaJyxa79hJu6bK9CfFnfbSL1GJNZbqhv9xPqJhRj2Yfb7QUWa2zeEw56H4KiUfN",
"label": "Untitled account",
"tag": "",
"unlocked_balance": 1000000000000
}
],
"total_balance": 120141601989972,
"total_unlocked_balance": 120141601989972
}
}

View File

@ -0,0 +1,58 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"transfer": {
"address": "7AEBRUmNcjhUjiqdVpeKKYiAVZ216AYdhBFx8UUfjPhWdKujoosnsUtHCohLcYWUXFdNiqnBsMmCFCyDkSmat3Ys4H4yHUp",
"amount": 4000000000000,
"confirmations": 1,
"double_spend_seen": false,
"fee": 195890000,
"height": 409450,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 0,
"minor": 232
},
"subaddr_indices": [
{
"major": 0,
"minor": 232
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568408341,
"txid": "55e758d7d259bb316551ddcdd4808711de99c30b8b5c52de3e95e563fd92d156",
"type": "in",
"unlock_time": 0
},
"transfers": [
{
"address": "7AEBRUmNcjhUjiqdVpeKKYiAVZ216AYdhBFx8UUfjPhWdKujoosnsUtHCohLcYWUXFdNiqnBsMmCFCyDkSmat3Ys4H4yHUp",
"amount": 4000000000000,
"confirmations": 1,
"double_spend_seen": false,
"fee": 195890000,
"height": 409450,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 0,
"minor": 232
},
"subaddr_indices": [
{
"major": 0,
"minor": 232
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568408341,
"txid": "55e758d7d259bb316551ddcdd4808711de99c30b8b5c52de3e95e563fd92d156",
"type": "in",
"unlock_time": 0
}
]
}
}

View File

@ -0,0 +1,58 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"transfer": {
"address": "7AwMU2kQkqseHgdVWPaD6J8QvUbomAR3ThBkyaBH3dFTTwT2CcQaZyrSetwq2TXtweHFpprTN1SmEKM2wG64oFdZQ5mqkLe",
"amount": 6000000000000,
"confirmations": 0,
"double_spend_seen": false,
"fee": 195990000,
"height": 0,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 0,
"minor": 233
},
"subaddr_indices": [
{
"major": 0,
"minor": 233
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568409539,
"txid": "31b527fb9c27e759d56892fef93136df1057186c5cf4e3c93c5298b70160f562",
"type": "pool",
"unlock_time": 0
},
"transfers": [
{
"address": "7AwMU2kQkqseHgdVWPaD6J8QvUbomAR3ThBkyaBH3dFTTwT2CcQaZyrSetwq2TXtweHFpprTN1SmEKM2wG64oFdZQ5mqkLe",
"amount": 6000000000000,
"confirmations": 0,
"double_spend_seen": false,
"fee": 195990000,
"height": 0,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 0,
"minor": 233
},
"subaddr_indices": [
{
"major": 0,
"minor": 233
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568409539,
"txid": "31b527fb9c27e759d56892fef93136df1057186c5cf4e3c93c5298b70160f562",
"type": "pool",
"unlock_time": 0
}
]
}
}

View File

@ -0,0 +1,58 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"transfer": {
"address": "7AEBRUmNcjhUjiqdVpeKKYiAVZ216AYdhBFx8UUfjPhWdKujoosnsUtHCohLcYWUXFdNiqnBsMmCFCyDkSmat3Ys4H4yHUp",
"amount": 4000000000000,
"confirmations": 1,
"double_spend_seen": false,
"fee": 195890000,
"height": 409450,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 0,
"minor": 232
},
"subaddr_indices": [
{
"major": 0,
"minor": 232
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568408341,
"txid": "55e758d7d259bb316551ddcdd4808711de99c30b8b5c52de3e95e563fd92d156",
"type": "in",
"unlock_time": 0
},
"transfers": [
{
"address": "7AEBRUmNcjhUjiqdVpeKKYiAVZ216AYdhBFx8UUfjPhWdKujoosnsUtHCohLcYWUXFdNiqnBsMmCFCyDkSmat3Ys4H4yHUp",
"amount": 4000000000000,
"confirmations": 1,
"double_spend_seen": false,
"fee": 195890000,
"height": 409450,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 0,
"minor": 232
},
"subaddr_indices": [
{
"major": 0,
"minor": 232
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568408341,
"txid": "55e758d7d259bb316551ddcdd4808711de99c30b8b5c52de3e95e563fd92d156",
"type": "in",
"unlock_time": 0
}
]
}
}

View File

@ -0,0 +1,108 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"transfer": {
"address": "76SJ4sPWzgQKE3fBbAoRTC7HtewGAo37VEgMpmHPEfPMRssYQgdeVyfJt5rcEcHw9dJJ4cLSkZ9c5fPTnKFHKh43UKmJs25",
"amount": 1000000000000,
"confirmations": 208,
"double_spend_seen": false,
"fee": 292510000,
"height": 409227,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 0,
"minor": 8
},
"subaddr_indices": [
{
"major": 0,
"minor": 8
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568388430,
"txid": "7ab84fe2fb34467c590cde2f7d6ba7de5928a2db6c84c6ccfff8962eca0ad99c",
"type": "in",
"unlock_time": 0
},
"transfers": [
{
"address": "76SJ4sPWzgQKE3fBbAoRTC7HtewGAo37VEgMpmHPEfPMRssYQgdeVyfJt5rcEcHw9dJJ4cLSkZ9c5fPTnKFHKh43UKmJs25",
"amount": 1000000000000,
"confirmations": 208,
"double_spend_seen": false,
"fee": 292510000,
"height": 409227,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 0,
"minor": 8
},
"subaddr_indices": [
{
"major": 0,
"minor": 8
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568388430,
"txid": "7ab84fe2fb34467c590cde2f7d6ba7de5928a2db6c84c6ccfff8962eca0ad99c",
"type": "in",
"unlock_time": 0
},
{
"address": "75LwnK3zfQS5mEzxgEdyep8SSwnvGSKcMLnCpzUqCF4CMFHDNrSnCojfoTRV9EWy2Y3ejeFLMPH9tAjagMAim8F8EKWjHos",
"amount": 1000000000000,
"confirmations": 208,
"double_spend_seen": false,
"fee": 292510000,
"height": 409227,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 0,
"minor": 19
},
"subaddr_indices": [
{
"major": 0,
"minor": 19
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568388430,
"txid": "7ab84fe2fb34467c590cde2f7d6ba7de5928a2db6c84c6ccfff8962eca0ad99c",
"type": "in",
"unlock_time": 0
},
{
"address": "74sZRQ2sHs4YLh8PnW8fseUoUoM4bXQ3wQ6bfCr6YyxmK5QRawKLytF9CfRbuv581LEnXBj27Dwg6eNC4fhhrH9kUvpbWQ5",
"amount": 2000000000000,
"confirmations": 208,
"double_spend_seen": false,
"fee": 292510000,
"height": 409227,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 0,
"minor": 29
},
"subaddr_indices": [
{
"major": 0,
"minor": 29
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568388430,
"txid": "7ab84fe2fb34467c590cde2f7d6ba7de5928a2db6c84c6ccfff8962eca0ad99c",
"type": "in",
"unlock_time": 0
}
]
}
}

View File

@ -0,0 +1,8 @@
{
"error": {
"code": -8,
"message": "Transaction not found."
},
"id": 0,
"jsonrpc": "2.0"
}

View File

@ -0,0 +1,26 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"subaddress_accounts": [
{
"account_index": 0,
"balance": 130141601989972,
"base_address": "56cXYWG13YKaT9z1aEy2hb9TZNnxrW3zE9S4nTQVDux5Qq7UYsmjuux3Zstxkorj9HAufyWLU3FwHW4uERQF6tkeUVogGN3",
"label": "Primary account",
"tag": "",
"unlocked_balance": 123141601989972
},
{
"account_index": 1,
"balance": 458323130000,
"base_address": "79kTZg96pMf2Dt9rLEWnLzTUB8XC1wMhxaJyxa79hJu6bK9CfFnfbSL1GJNZbqhv9xPqJhRj2Yfb7QUWa2zeEw56H4KiUfN",
"label": "Untitled account",
"tag": "",
"unlocked_balance": 458323130000
}
],
"total_balance": 130599925119972,
"total_unlocked_balance": 123599925119972
}
}

View File

@ -0,0 +1,78 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"transfer": {
"address": "79kTZg96pMf2Dt9rLEWnLzTUB8XC1wMhxaJyxa79hJu6bK9CfFnfbSL1GJNZbqhv9xPqJhRj2Yfb7QUWa2zeEw56H4KiUfN",
"amount": 520000000000,
"confirmations": 23,
"destinations": [
{
"address": "77yjHxBeLNq4mf4dhEB7ksD6WDaAEEguqHHvuFYyiLiMWwSrvYHftzT5c1HRS9iWa2UBn4MQLuz8jEiE6sPDfMzB81UMHaK",
"amount": 220000000000
},
{
"address": "787CXWuevtt2SdD9x6rB7hCk73pYVv7HYgAUAPsYQJ9zAmQN7Ksxr5KieQFXuEL6ZSMqMDNbbaUze365iF2DbkjB9bcL82t",
"amount": 300000000000
}
],
"double_spend_seen": false,
"fee": 280650000,
"height": 409449,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 1,
"minor": 0
},
"subaddr_indices": [
{
"major": 1,
"minor": 1
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568408151,
"txid": "362c3a4e601d5847b3882c3debfd28a0ee31654e433c38498539677199c304c2",
"type": "out",
"unlock_time": 0
},
"transfers": [
{
"address": "79kTZg96pMf2Dt9rLEWnLzTUB8XC1wMhxaJyxa79hJu6bK9CfFnfbSL1GJNZbqhv9xPqJhRj2Yfb7QUWa2zeEw56H4KiUfN",
"amount": 520000000000,
"confirmations": 23,
"destinations": [
{
"address": "77yjHxBeLNq4mf4dhEB7ksD6WDaAEEguqHHvuFYyiLiMWwSrvYHftzT5c1HRS9iWa2UBn4MQLuz8jEiE6sPDfMzB81UMHaK",
"amount": 220000000000
},
{
"address": "787CXWuevtt2SdD9x6rB7hCk73pYVv7HYgAUAPsYQJ9zAmQN7Ksxr5KieQFXuEL6ZSMqMDNbbaUze365iF2DbkjB9bcL82t",
"amount": 300000000000
}
],
"double_spend_seen": false,
"fee": 280650000,
"height": 409449,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 1,
"minor": 0
},
"subaddr_indices": [
{
"major": 1,
"minor": 1
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568408151,
"txid": "362c3a4e601d5847b3882c3debfd28a0ee31654e433c38498539677199c304c2",
"type": "out",
"unlock_time": 0
}
]
}
}

View File

@ -0,0 +1,70 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"transfer": {
"address": "79kTZg96pMf2Dt9rLEWnLzTUB8XC1wMhxaJyxa79hJu6bK9CfFnfbSL1GJNZbqhv9xPqJhRj2Yfb7QUWa2zeEw56H4KiUfN",
"amount": 40000000000,
"confirmations": 0,
"destinations": [
{
"address": "72nfCSqpigFWaMeKyZYjKMQRvYFxWvJaf8Nnb1KxVndeTuL7avqoCF5NME4WGMqwmK58i8BnKxCz543mFoZhuUMpGhN1dcm",
"amount": 40000000000
}
],
"double_spend_seen": false,
"fee": 979320000,
"height": 0,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 1,
"minor": 0
},
"subaddr_indices": [
{
"major": 1,
"minor": 0
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568413596,
"txid": "afaf04e5e40c6b60fc7cc928a88843fc96031ec2b567c310ee61abf3d00020da",
"type": "pending",
"unlock_time": 0
},
"transfers": [
{
"address": "79kTZg96pMf2Dt9rLEWnLzTUB8XC1wMhxaJyxa79hJu6bK9CfFnfbSL1GJNZbqhv9xPqJhRj2Yfb7QUWa2zeEw56H4KiUfN",
"amount": 40000000000,
"confirmations": 0,
"destinations": [
{
"address": "72nfCSqpigFWaMeKyZYjKMQRvYFxWvJaf8Nnb1KxVndeTuL7avqoCF5NME4WGMqwmK58i8BnKxCz543mFoZhuUMpGhN1dcm",
"amount": 40000000000
}
],
"double_spend_seen": false,
"fee": 979320000,
"height": 0,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 1,
"minor": 0
},
"subaddr_indices": [
{
"major": 1,
"minor": 0
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568413596,
"txid": "afaf04e5e40c6b60fc7cc928a88843fc96031ec2b567c310ee61abf3d00020da",
"type": "pending",
"unlock_time": 0
}
]
}
}

View File

@ -0,0 +1,70 @@
{
"id": 0,
"jsonrpc": "2.0",
"result": {
"transfer": {
"address": "79kTZg96pMf2Dt9rLEWnLzTUB8XC1wMhxaJyxa79hJu6bK9CfFnfbSL1GJNZbqhv9xPqJhRj2Yfb7QUWa2zeEw56H4KiUfN",
"amount": 21200000000,
"confirmations": 23,
"destinations": [
{
"address": "72quvHYJ8QzivQyV4NMZ9h1gyZXyJZvsWZTwgVFRCw9b1eJ4yibHEnU3CVCCXJ7evqXhSEKJL2rjzCMV3LpXirR5B8EnkaE",
"amount": 21200000000
}
],
"double_spend_seen": false,
"fee": 196220000,
"height": 409449,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 1,
"minor": 0
},
"subaddr_indices": [
{
"major": 1,
"minor": 2
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568408151,
"txid": "eda891adf76993f9066abd56a8a5aa5c51a7618298cab59ec37739f1c960596d",
"type": "out",
"unlock_time": 0
},
"transfers": [
{
"address": "79kTZg96pMf2Dt9rLEWnLzTUB8XC1wMhxaJyxa79hJu6bK9CfFnfbSL1GJNZbqhv9xPqJhRj2Yfb7QUWa2zeEw56H4KiUfN",
"amount": 21200000000,
"confirmations": 23,
"destinations": [
{
"address": "72quvHYJ8QzivQyV4NMZ9h1gyZXyJZvsWZTwgVFRCw9b1eJ4yibHEnU3CVCCXJ7evqXhSEKJL2rjzCMV3LpXirR5B8EnkaE",
"amount": 21200000000
}
],
"double_spend_seen": false,
"fee": 196220000,
"height": 409449,
"note": "",
"payment_id": "0000000000000000",
"subaddr_index": {
"major": 1,
"minor": 0
},
"subaddr_indices": [
{
"major": 1,
"minor": 2
}
],
"suggested_confirmations_threshold": 1,
"timestamp": 1568408151,
"txid": "eda891adf76993f9066abd56a8a5aa5c51a7618298cab59ec37739f1c960596d",
"type": "out",
"unlock_time": 0
}
]
}
}

View File

@ -462,6 +462,7 @@ class JSONRPCWalletTestCase(JSONTestCase):
self.assertIsInstance(pmt.transaction.fee, Decimal) self.assertIsInstance(pmt.transaction.fee, Decimal)
self.assertIsInstance(pmt.transaction.height, (int, type(None))) self.assertIsInstance(pmt.transaction.height, (int, type(None)))
@patch('monero.backends.jsonrpc.requests.post') @patch('monero.backends.jsonrpc.requests.post')
def test_incoming_unconfirmed(self, mock_post): def test_incoming_unconfirmed(self, mock_post):
mock_post.return_value.status_code = 200 mock_post.return_value.status_code = 200
@ -505,6 +506,165 @@ class JSONRPCWalletTestCase(JSONTestCase):
self.assertIsInstance(pmt.transaction.fee, Decimal) self.assertIsInstance(pmt.transaction.fee, Decimal)
self.assertIs(pmt.transaction.height, None) self.assertIs(pmt.transaction.height, None)
@responses.activate
def test_incoming_by_tx_id(self):
# 3 payments in one transaction
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-00-get_accounts.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-7ab84-get_transfer_by_txid.json'),
status=200)
self.wallet = Wallet(JSONRPCWallet())
pmts = self.wallet.incoming(tx_id='7ab84fe2fb34467c590cde2f7d6ba7de5928a2db6c84c6ccfff8962eca0ad99c')
self.assertEqual(len(pmts), 3)
self.assertEqual(pmts[0].amount, Decimal(1))
self.assertEqual(pmts[1].amount, Decimal(1))
self.assertEqual(pmts[2].amount, Decimal(2))
@responses.activate
def test_incoming_by_tx_id__with_min_height(self):
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-00-get_accounts.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-7ab84-get_transfer_by_txid.json'),
status=200)
self.wallet = Wallet(JSONRPCWallet())
pmts = self.wallet.incoming(min_height=409223,
tx_id='7ab84fe2fb34467c590cde2f7d6ba7de5928a2db6c84c6ccfff8962eca0ad99c')
self.assertEqual(len(pmts), 3)
self.assertEqual(pmts[0].amount, Decimal(1))
self.assertEqual(pmts[1].amount, Decimal(1))
self.assertEqual(pmts[2].amount, Decimal(2))
@responses.activate
def test_incoming_by_tx_id__with_max_height(self):
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-00-get_accounts.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-7ab84-get_transfer_by_txid.json'),
status=200)
self.wallet = Wallet(JSONRPCWallet())
pmts = self.wallet.incoming(max_height=409223,
tx_id='7ab84fe2fb34467c590cde2f7d6ba7de5928a2db6c84c6ccfff8962eca0ad99c')
self.assertEqual(len(pmts), 0)
@responses.activate
def test_incoming_by_tx_id__not_found(self):
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-00-get_accounts.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-e0b15-get_transfer_by_txid.json'),
status=200)
self.wallet = Wallet(JSONRPCWallet())
pmts = self.wallet.incoming(tx_id='e0b15ac819c94ed9ba81edb955a98c696f3216335960ccf90018d76a8dcb0e7e')
self.assertEqual(len(pmts), 0)
@responses.activate
def test_incoming_by_tx_id__multiple_ids(self):
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-00-get_accounts.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-7ab84-get_transfer_by_txid.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-55e75-get_transfer_by_txid.json'),
status=200)
self.wallet = Wallet(JSONRPCWallet())
pmts = self.wallet.incoming(tx_id=[
'7ab84fe2fb34467c590cde2f7d6ba7de5928a2db6c84c6ccfff8962eca0ad99c',
'55e758d7d259bb316551ddcdd4808711de99c30b8b5c52de3e95e563fd92d156'])
self.assertEqual(len(pmts), 4)
self.assertEqual(pmts[0].amount, Decimal(4))
self.assertEqual(pmts[1].amount, Decimal(1))
self.assertEqual(pmts[2].amount, Decimal(1))
self.assertEqual(pmts[3].amount, Decimal(2))
@responses.activate
def test_incoming_by_tx_id__mempool(self):
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-00-get_accounts.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-31b52-get_transfer_by_txid.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-31b52-get_transfer_by_txid.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_incoming_by_tx_id-31b52-get_transfer_by_txid.json'),
status=200)
self.wallet = Wallet(JSONRPCWallet())
pmts = self.wallet.incoming(
tx_id='31b527fb9c27e759d56892fef93136df1057186c5cf4e3c93c5298b70160f562')
self.assertEqual(len(pmts), 0)
pmts = self.wallet.incoming(
tx_id='31b527fb9c27e759d56892fef93136df1057186c5cf4e3c93c5298b70160f562',
unconfirmed=True)
self.assertEqual(len(pmts), 1)
pmts = self.wallet.incoming(
tx_id='31b527fb9c27e759d56892fef93136df1057186c5cf4e3c93c5298b70160f562',
confirmed=False)
self.assertEqual(len(pmts), 0)
@responses.activate
def test_outgoing_by_tx_id(self):
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_outgoing_by_tx_id-00-get_accounts.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_outgoing_by_tx_id-362c3-get_transfer_by_txid.json'),
status=200)
self.wallet = Wallet(JSONRPCWallet())
acc = self.wallet.accounts[1]
pmts = acc.outgoing(tx_id='362c3a4e601d5847b3882c3debfd28a0ee31654e433c38498539677199c304c2')
self.assertEqual(len(pmts), 1)
self.assertEqual(pmts[0].amount, Decimal('0.52'))
@responses.activate
def test_outgoing_by_tx_id__mempool(self):
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_outgoing_by_tx_id-00-get_accounts.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_outgoing_by_tx_id-afaf0-get_transfer_by_txid.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_outgoing_by_tx_id-afaf0-get_transfer_by_txid.json'),
status=200)
self.wallet = Wallet(JSONRPCWallet())
acc = self.wallet.accounts[1]
pmts = acc.outgoing(tx_id='afaf04e5e40c6b60fc7cc928a88843fc96031ec2b567c310ee61abf3d00020da')
self.assertEqual(len(pmts), 0)
pmts = acc.outgoing(
tx_id='afaf04e5e40c6b60fc7cc928a88843fc96031ec2b567c310ee61abf3d00020da',
unconfirmed=True)
self.assertEqual(len(pmts), 1)
@responses.activate
def test_outgoing_by_tx_id__multiple_ids(self):
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_outgoing_by_tx_id-00-get_accounts.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_outgoing_by_tx_id-362c3-get_transfer_by_txid.json'),
status=200)
responses.add(responses.POST, self.jsonrpc_url,
json=self._read('test_outgoing_by_tx_id-eda89-get_transfer_by_txid.json'),
status=200)
self.wallet = Wallet(JSONRPCWallet())
acc = self.wallet.accounts[1]
pmts = acc.outgoing(tx_id=[
'362c3a4e601d5847b3882c3debfd28a0ee31654e433c38498539677199c304c2',
'eda891adf76993f9066abd56a8a5aa5c51a7618298cab59ec37739f1c960596d'])
self.assertEqual(len(pmts), 2)
self.assertEqual(pmts[0].amount, Decimal('0.52'))
self.assertEqual(pmts[1].amount, Decimal('0.0212'))
@patch('monero.backends.jsonrpc.requests.post') @patch('monero.backends.jsonrpc.requests.post')
def test_incoming_by_payment_ids(self, mock_post): def test_incoming_by_payment_ids(self, mock_post):
# These queries will use get_bulk_payments RPC method instead of get_transfers # These queries will use get_bulk_payments RPC method instead of get_transfers