Add retrieval of transaction from daemon
This commit is contained in:
parent
df9dd7152b
commit
44d87be2e6
|
@ -71,6 +71,22 @@ class JSONRPCDaemon(object):
|
||||||
return res['headers']
|
return res['headers']
|
||||||
raise exceptions.BackendException(res['status'])
|
raise exceptions.BackendException(res['status'])
|
||||||
|
|
||||||
|
def transactions(self, hashes):
|
||||||
|
res = self.raw_request('/get_transactions', {
|
||||||
|
'txs_hashes': hashes,
|
||||||
|
'decode_as_json': True})
|
||||||
|
if res['status'] != 'OK':
|
||||||
|
raise exceptions.BackendException(res['status'])
|
||||||
|
txs = []
|
||||||
|
for tx in res.get('txs', []):
|
||||||
|
txs.append(Transaction(
|
||||||
|
hash=tx['tx_hash'],
|
||||||
|
height=None if tx['in_pool'] else tx['block_height'],
|
||||||
|
timestamp=datetime.fromtimestamp(tx['block_timestamp']) if 'block_timestamp' in tx else None,
|
||||||
|
blob=tx['as_hex'],
|
||||||
|
json=json.loads(tx['as_json'])))
|
||||||
|
return txs
|
||||||
|
|
||||||
def raw_request(self, path, data):
|
def raw_request(self, path, data):
|
||||||
hdr = {'Content-Type': 'application/json'}
|
hdr = {'Content-Type': 'application/json'}
|
||||||
_log.debug(u"Request: {path}\nData: {data}".format(
|
_log.debug(u"Request: {path}\nData: {data}".format(
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import six
|
||||||
|
|
||||||
class Daemon(object):
|
class Daemon(object):
|
||||||
"""Monero daemon.
|
"""Monero daemon.
|
||||||
|
|
||||||
|
@ -51,3 +53,13 @@ class Daemon(object):
|
||||||
:rtype: list of dict
|
:rtype: list of dict
|
||||||
"""
|
"""
|
||||||
return self._backend.headers(start_height, end_height)
|
return self._backend.headers(start_height, end_height)
|
||||||
|
|
||||||
|
def transactions(self, hashes):
|
||||||
|
"""
|
||||||
|
Returns transactions matching given hashes. Accepts single hash or a sequence.
|
||||||
|
|
||||||
|
:hashes: str or list of str
|
||||||
|
"""
|
||||||
|
if isinstance(hashes, six.string_types):
|
||||||
|
hashes = [hashes]
|
||||||
|
return self._backend.transactions(hashes)
|
||||||
|
|
|
@ -72,8 +72,13 @@ class Transaction(object):
|
||||||
timestamp = None
|
timestamp = None
|
||||||
key = None
|
key = None
|
||||||
blob = None
|
blob = None
|
||||||
|
json = None
|
||||||
confirmations = None
|
confirmations = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size(self):
|
||||||
|
return len(self.blob)//2
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.hash = kwargs.get('hash', self.hash)
|
self.hash = kwargs.get('hash', self.hash)
|
||||||
self.fee = kwargs.get('fee', self.fee)
|
self.fee = kwargs.get('fee', self.fee)
|
||||||
|
@ -81,6 +86,7 @@ class Transaction(object):
|
||||||
self.timestamp = kwargs.get('timestamp', self.timestamp)
|
self.timestamp = kwargs.get('timestamp', self.timestamp)
|
||||||
self.key = kwargs.get('key', self.key)
|
self.key = kwargs.get('key', self.key)
|
||||||
self.blob = kwargs.get('blob', self.blob)
|
self.blob = kwargs.get('blob', self.blob)
|
||||||
|
self.json = kwargs.get('json', self.json)
|
||||||
self.confirmations = kwargs.get('confirmations', self.confirmations)
|
self.confirmations = kwargs.get('confirmations', self.confirmations)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -10,6 +10,7 @@ from .base import JSONTestCase
|
||||||
class JSONRPCDaemonTestCase(JSONTestCase):
|
class JSONRPCDaemonTestCase(JSONTestCase):
|
||||||
jsonrpc_url = 'http://127.0.0.1:18081/json_rpc'
|
jsonrpc_url = 'http://127.0.0.1:18081/json_rpc'
|
||||||
mempool_url = 'http://127.0.0.1:18081/get_transaction_pool'
|
mempool_url = 'http://127.0.0.1:18081/get_transaction_pool'
|
||||||
|
transactions_url = 'http://127.0.0.1:18081/get_transactions'
|
||||||
data_subdir = 'test_jsonrpcdaemon'
|
data_subdir = 'test_jsonrpcdaemon'
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -37,3 +38,33 @@ class JSONRPCDaemonTestCase(JSONTestCase):
|
||||||
self.assertEqual(txs[1].confirmations, 0)
|
self.assertEqual(txs[1].confirmations, 0)
|
||||||
self.assertGreater(txs[0].fee, 0)
|
self.assertGreater(txs[0].fee, 0)
|
||||||
self.assertGreater(txs[1].fee, 0)
|
self.assertGreater(txs[1].fee, 0)
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
def test_transactions(self):
|
||||||
|
responses.add(responses.POST, self.transactions_url,
|
||||||
|
json=self._read('test_transactions.json'),
|
||||||
|
status=200)
|
||||||
|
txs = self.daemon.transactions([
|
||||||
|
"050679bd5717cd4c3d0ed1db7dac4aa7e8a222ffc7661b249e5a595a3af37d3c", # @471570
|
||||||
|
"e3a3b8361777c8f4f1fd423b86655b5c775de0230b44aa5b82f506135a96c53a", # @451993
|
||||||
|
"e2871c4203e29433257219bc20fa58c68dc12efed8f05a86d59921969a2b97cc", # @472279
|
||||||
|
"035a1cfadd2f80124998f5af8c7bb6703743a4f322d0a20b7f7b502956ada59d", # mempool
|
||||||
|
"feed00000000000face00000000000bad00000000000beef00000000000acab0", # doesn't exist
|
||||||
|
])
|
||||||
|
self.assertEqual(len(txs), 4)
|
||||||
|
self.assertEqual(txs[0].hash,
|
||||||
|
"050679bd5717cd4c3d0ed1db7dac4aa7e8a222ffc7661b249e5a595a3af37d3c")
|
||||||
|
self.assertEqual(txs[0].height, 471570)
|
||||||
|
self.assertEqual(txs[0].size, 2826)
|
||||||
|
self.assertEqual(txs[1].hash,
|
||||||
|
"e3a3b8361777c8f4f1fd423b86655b5c775de0230b44aa5b82f506135a96c53a")
|
||||||
|
self.assertEqual(txs[1].height, 451993)
|
||||||
|
self.assertEqual(txs[1].size, 2596)
|
||||||
|
self.assertEqual(txs[2].hash,
|
||||||
|
"e2871c4203e29433257219bc20fa58c68dc12efed8f05a86d59921969a2b97cc")
|
||||||
|
self.assertEqual(txs[2].height, 472279)
|
||||||
|
self.assertEqual(txs[2].size, 2796)
|
||||||
|
self.assertEqual(txs[3].hash,
|
||||||
|
"035a1cfadd2f80124998f5af8c7bb6703743a4f322d0a20b7f7b502956ada59d")
|
||||||
|
self.assertIsNone(txs[3].height)
|
||||||
|
self.assertEqual(txs[3].size, 2724)
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import operator
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from monero.backends.jsonrpc import JSONRPCDaemon
|
||||||
|
from monero.daemon import Daemon
|
||||||
|
|
||||||
|
|
||||||
|
def url_data(url):
|
||||||
|
gs = re.compile(r"^(?P<host>[^:\s]+)(?::(?P<port>[0-9]+))?$").match(url).groupdict()
|
||||||
|
return dict(filter(operator.itemgetter(1), gs.items()))
|
||||||
|
|
||||||
|
|
||||||
|
argsparser = argparse.ArgumentParser(
|
||||||
|
description="Retrieve transaction(s) from daemon and print them"
|
||||||
|
)
|
||||||
|
argsparser.add_argument("tx_id", nargs="+", type=str, help="Transaction id (hash)")
|
||||||
|
argsparser.add_argument(
|
||||||
|
"-d",
|
||||||
|
dest="daemon_rpc_url",
|
||||||
|
type=url_data,
|
||||||
|
default="127.0.0.1:18081",
|
||||||
|
help="Daemon RPC URL [host[:port]]",
|
||||||
|
)
|
||||||
|
argsparser.add_argument(
|
||||||
|
"-t", dest="timeout", type=int, default=30, help="Request timeout"
|
||||||
|
)
|
||||||
|
argsparser.add_argument(
|
||||||
|
"-v",
|
||||||
|
dest="verbosity",
|
||||||
|
action="count",
|
||||||
|
default=0,
|
||||||
|
help="Verbosity (repeat to increase; -v for INFO, -vv for DEBUG",
|
||||||
|
)
|
||||||
|
args = argsparser.parse_args()
|
||||||
|
level = logging.WARNING
|
||||||
|
if args.verbosity == 1:
|
||||||
|
level = logging.INFO
|
||||||
|
elif args.verbosity > 1:
|
||||||
|
level = logging.DEBUG
|
||||||
|
logging.basicConfig(level=level, format="%(asctime)-15s %(message)s")
|
||||||
|
|
||||||
|
d = Daemon(JSONRPCDaemon(timeout=args.timeout, **args.daemon_rpc_url))
|
||||||
|
|
||||||
|
txs = list(d.transactions(args.tx_id))
|
||||||
|
print("Found {:d} transaction(s)".format(len(txs)))
|
||||||
|
if len(txs) > 0:
|
||||||
|
print("-" * 79)
|
||||||
|
for tx in txs:
|
||||||
|
print("id: {:s}".format(tx.hash))
|
||||||
|
print(
|
||||||
|
"height: {:s}".format("None" if tx.height is None else "{:d}".format(tx.height))
|
||||||
|
)
|
||||||
|
print("size: {:d}".format(tx.size))
|
||||||
|
print("JSON:")
|
||||||
|
print(json.dumps(tx.json, indent=2))
|
||||||
|
print("-" * 79)
|
Loading…
Reference in New Issue