Merge branch 'onetimeout' of https://github.com/jeffro256/monero-python into jeffro256-onetimeout

pull/93/head
Michał Sałaban 3 years ago
commit 646ae2ba2e

@ -163,6 +163,7 @@ class JSONRPCDaemon(object):
timestamp=datetime.fromtimestamp(
tx['block_timestamp']) if 'block_timestamp' in tx else None,
blob=binascii.unhexlify(tx['as_hex']) or None,
output_indices=None if tx['in_pool'] else tx['output_indices'],
json=as_json))
return txs

@ -2,7 +2,7 @@ import re
import six
import warnings
from .address import address
from .numbers import PaymentID
from .numbers import from_atomic, PaymentID
from . import exceptions
class Payment(object):
@ -73,8 +73,9 @@ class Transaction(object):
timestamp = None
key = None
blob = None
json = None
confirmations = None
output_indices = None
json = None
@property
def size(self):
@ -84,6 +85,22 @@ class Transaction(object):
"Perhaps the backend prunes transaction data?")
return len(self.blob)
@property
def outputs(self):
if not self.json:
raise ValueError('.json attribute not set')
outs = []
for i, vout in enumerate(self.json['vout']):
outs.append(OneTimeOutput(
pubkey=vout['target']['key'],
amount=from_atomic(vout['amount']),
index=self.output_indices[i] if self.output_indices else None,
height=self.height,
txid=self.hash))
return outs
def __init__(self, **kwargs):
self.hash = kwargs.get('hash', self.hash)
self.fee = kwargs.get('fee', self.fee)
@ -91,13 +108,60 @@ class Transaction(object):
self.timestamp = kwargs.get('timestamp', self.timestamp)
self.key = kwargs.get('key', self.key)
self.blob = kwargs.get('blob', self.blob)
self.json = kwargs.get('json', self.json)
self.confirmations = kwargs.get('confirmations', self.confirmations)
self.output_indices = kwargs.get('output_indices', self.output_indices)
self.json = kwargs.get('json', self.json)
def __repr__(self):
return self.hash
class OneTimeOutput(object):
"""
A Monero one-time public output (A.K.A stealth address). Identified by `pubkey`, or `index` and `amount`
together, it can contain differing levels of information on an output.
This class is not intended to be turned into objects by the user,
it is used by backends.
"""
pubkey = None
amount = None
index = None
height = None
mask = None
txid = None
unlocked = None
def __init__(self, **kwargs):
self.pubkey = kwargs.get('pubkey', self.pubkey)
self.amount = kwargs.get('amount', self.amount)
self.index = kwargs.get('index', self.index)
self.height = kwargs.get('height', self.height)
self.mask = kwargs.get('mask', self.mask)
self.txid = kwargs.get('txid', self.txid)
self.unlocked = kwargs.get('unlocked', self.unlocked)
def __repr__(self):
# Try to represent output as (index, amount) pair if applicable because there is no RPC
# daemon command to lookup outputs by their pubkey ;(
if self.pubkey:
return self.pubkey
else:
return '(index={},amount={})'.format(self.index, self.amount)
def __eq__(self, other):
# Try to compare pubkeys, then try to compare (index,amount) pairs, else raise error
if self.pubkey and other.pubkey:
return self.pubkey == other.pubkey
elif None not in (self.index, other.index, self.amount, other.amount):
return self.index == other.index and self.amount == other.amount
else:
raise TypeError('one-time outputs are not comparable')
def __ne__(self, other):
return not(self == other)
class PaymentManager(object):
"""
A payment query manager, handling either incoming or outgoing payments of

@ -6,7 +6,7 @@ import unittest
from monero.address import address
from monero.numbers import PaymentID
from monero.transaction import IncomingPayment, Transaction, _ByHeight
from monero.transaction import IncomingPayment, Transaction, OneTimeOutput, _ByHeight
class FiltersTestCase(unittest.TestCase):
def setUp(self):
@ -21,6 +21,23 @@ class FiltersTestCase(unittest.TestCase):
payment_id=PaymentID('0166d8da6c0045c51273dd65d6f63734beb8a84e0545a185b2cfd053fced9f5d'),
transaction=self.tx1)
# setup for one-time output tests
self.json1 = { # Actual as_json response from TX ee5bcb6430c39757ff27f8d607287572f3956a0ee16bb1d2378891f93746c8f9
'version': 2, 'unlock_time': 0, 'vin': [{'key': {'amount': 0, 'key_offsets':
[25471133, 261981, 36602, 18967, 13096, 16260, 54279, 3105, 5403, 786, 555],
'k_image': '4b48346e954a74be9a334b03cadf8aa020542d201fb6ae7416246d19fd04fdb7'}}],
'vout': [{'amount': 0, 'target': {'key': 'c55e793b4d673dcf73587e5141b777ef24e255d48826c75ce110ffc23ff762b9'}},
{'amount': 0, 'target': {'key': '93b263454cd3cc349245ad60c9c248332b885a1f2d7b5792cfc24fd87434d62a'}}],
'extra': [1, 209, 170, 43, 245, 190, 68, 82, 131, 116, 79, 134, 175, 104, 216, 127, 99, 49, 127, 141, 255, 65, 204, 101,
81, 244, 111, 253, 155, 75, 111, 14, 159, 2, 9, 1, 24, 56, 108, 94, 20, 88, 150, 94], 'rct_signatures': {'type': 5,
'txnFee': 58560000, 'ecdhInfo': [{'amount': '6c13cf459cb9ed96'}, {'amount': '373bc40c7f600bf4'}], 'outPk':
['80521a77ebe954a5daa6f14b13cc74337f999bc68177a58e76f768c18f2fa421',
'5997e64b90d59f7f810ddbc801f747c4fa43e2de593e4ea48531e16d776c00fd']}}
self.outind1 = [25884175, 25884176]
self.tx2 = Transaction(json=self.json1, output_indices=self.outind1)
self.oto1 = OneTimeOutput(index=25973289, amount=Decimal('0.000000000000'))
self.oto2 = OneTimeOutput(pubkey='0faff18f7149a0db5aa0dc3c9116887740ccbb5dc4d1eeff87895288e55e5052')
def test_hash(self):
self.assertIn(
'a0b876ebcf7c1d499712d84cedec836f9d50b608bb22d6cb49fd2feae3ffed14',
@ -29,6 +46,18 @@ class FiltersTestCase(unittest.TestCase):
'a0b876ebcf7c1d499712d84cedec836f9d50b608bb22d6cb49fd2feae3ffed14',
repr(self.pm1))
def test_outputs(self):
out1, out2 = self.tx2.outputs
self.assertIn(self.json1['vout'][0]['target']['key'], repr(out1))
self.assertFalse(out2 != OneTimeOutput(pubkey=self.json1['vout'][1]['target']['key']))
self.assertIn('(index=25973289,amount=0E-12)', repr(self.oto1))
self.assertEqual(self.oto1, OneTimeOutput(index=25973289, amount=Decimal('0.000000000000')))
with self.assertRaises(ValueError):
failed_outs = self.tx1.outputs
with self.assertRaises(TypeError):
self.oto1 == self.oto2
class SortingTestCase(unittest.TestCase):
def test_sorting(self):

Loading…
Cancel
Save