mirror of
https://git.wownero.com/lza_menace/wownero-python.git
synced 2024-08-15 03:25:25 +00:00
Add Block class and handling
This commit is contained in:
parent
ccf5066739
commit
1b503fd0ab
6 changed files with 250 additions and 0 deletions
|
@ -9,6 +9,7 @@ import requests
|
|||
from .. import exceptions
|
||||
from ..account import Account
|
||||
from ..address import address, Address, SubAddress
|
||||
from ..block import Block
|
||||
from ..const import NET_MAIN, NET_TEST, NET_STAGE
|
||||
from ..numbers import from_atomic, to_atomic, PaymentID
|
||||
from ..seed import Seed
|
||||
|
@ -94,6 +95,33 @@ class JSONRPCDaemon(object):
|
|||
return res['headers']
|
||||
raise exceptions.BackendException(res['status'])
|
||||
|
||||
def block(self, bhash=None, height=None):
|
||||
data = {}
|
||||
if bhash:
|
||||
data['hash'] = bhash
|
||||
if height:
|
||||
data['height'] = height
|
||||
res = self.raw_jsonrpc_request('get_block', data)
|
||||
if res['status'] == 'OK':
|
||||
bhdr = res['block_header']
|
||||
sub_json = json.loads(res['json'])
|
||||
data = {
|
||||
'blob': res['blob'],
|
||||
'hash': bhdr['hash'],
|
||||
'height': bhdr['height'],
|
||||
'timestamp': datetime.fromtimestamp(bhdr['timestamp']),
|
||||
'version': (bhdr['major_version'], bhdr['minor_version']),
|
||||
'difficulty': bhdr['difficulty'],
|
||||
'nonce': bhdr['nonce'],
|
||||
'orphan': bhdr['orphan_status'],
|
||||
'prev_hash': bhdr['prev_hash'],
|
||||
'reward': bhdr['reward'],
|
||||
'transactions': self.transactions(
|
||||
[bhdr['miner_tx_hash']] + sub_json['tx_hashes']),
|
||||
}
|
||||
return Block(**data)
|
||||
raise exceptions.BackendException(res['status'])
|
||||
|
||||
def transactions(self, hashes):
|
||||
res = self.raw_request('/get_transactions', {
|
||||
'txs_hashes': hashes,
|
||||
|
|
42
monero/block.py
Normal file
42
monero/block.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
import operator
|
||||
import six
|
||||
from .transaction import Transaction
|
||||
|
||||
|
||||
class Block(object):
|
||||
"""
|
||||
A Monero block. Identified by `hash` (optionaly by `height`).
|
||||
|
||||
This class is not intended to be turned into objects by the user,
|
||||
it is used by backends.
|
||||
"""
|
||||
hash = None
|
||||
height = None
|
||||
timestamp = None
|
||||
version = None
|
||||
difficulty = None
|
||||
nonce = None
|
||||
orphan = False
|
||||
prev_hash = None
|
||||
reward = None
|
||||
blob = None
|
||||
|
||||
transactions = None
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
for k in ('hash', 'height', 'timestamp', 'version', 'difficulty', 'nonce', 'prev_hash', 'reward'):
|
||||
setattr(self, k, kwargs[k])
|
||||
self.orphan = kwargs['orphan']
|
||||
self.transactions = kwargs['transactions']
|
||||
self.blob = kwargs.get('blob', None)
|
||||
|
||||
def __contains__(self, tx):
|
||||
if isinstance(tx, six.string_types):
|
||||
txid = tx
|
||||
elif isinstance(tx, Transaction):
|
||||
txid = tx.hash
|
||||
else:
|
||||
raise ValueError(
|
||||
"Only Transaction or hash strings may be used to test existence in Blocks, "
|
||||
"got '{:s}'".format(tx))
|
||||
return txid in map(operator.attrgetter('hash'), self.transactions)
|
|
@ -58,6 +58,19 @@ class Daemon(object):
|
|||
"""
|
||||
return self._backend.headers(start_height, end_height)
|
||||
|
||||
def block(self, bhash=None, height=None):
|
||||
"""
|
||||
Returns a block of specified height or hash.
|
||||
|
||||
:param str bhash: block hash, or
|
||||
:param int height: block height
|
||||
|
||||
:rtype: :class:`Block <monero.block.Block>`
|
||||
"""
|
||||
if not height and not bhash:
|
||||
raise ValueError("Height or hash must be specified")
|
||||
return self._backend.block(bhash=bhash, height=height)
|
||||
|
||||
def transactions(self, hashes):
|
||||
"""
|
||||
Returns transactions matching given hashes. Accepts single hash or a sequence.
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"id": 0,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"blob": "0b0cd6e0afee0551f6816891b6a7adedd0f1ad57a846eada1baac476421aa9d32d0630ce3dce413af2580802d4cb1b01ff98cb1b01d6a9ddfc9bbe0302e351068aea8f05e9e30f876c3f203a89d09e7e07786979d79df6c7f8cbb75ff12101aaa20f9b81d64636002de35a6a4914ac4fb36145da0ba0f9d670e6c2b6a11c8000047e5fea8470c5771315bab4b3c77493d2ff534f5201c7c6b2bab069cb7d21ce7b3a2f859dea9d2ad5ecec167719302d4e14e21beef9b74f9583183d8e965d9106bde2b5344b63cbe58ce1a724d0a2276aaa4266be5235d5e5fde969446c3e8de124fb42f9f324082658524b29b4cf946a9f5fcfa82194070e2f17c1875e15d5d0",
|
||||
"block_header": {
|
||||
"block_size": 9632,
|
||||
"block_weight": 9632,
|
||||
"cumulative_difficulty": 11915811790,
|
||||
"cumulative_difficulty_top64": 0,
|
||||
"depth": 49003,
|
||||
"difficulty": 3590,
|
||||
"difficulty_top64": 0,
|
||||
"hash": "423cd4d170c53729cf25b4243ea576d1e901d86e26c06d6a7f79815f3fcb9a89",
|
||||
"height": 451992,
|
||||
"long_term_weight": 9632,
|
||||
"major_version": 11,
|
||||
"miner_tx_hash": "f2bd4cb3dafd5c096be7e1ec908f98bf34903f5a013faa65a0d0c8998154c583",
|
||||
"minor_version": 12,
|
||||
"nonce": 140046906,
|
||||
"num_txes": 4,
|
||||
"orphan_status": false,
|
||||
"pow_hash": "",
|
||||
"prev_hash": "51f6816891b6a7adedd0f1ad57a846eada1baac476421aa9d32d0630ce3dce41",
|
||||
"reward": 15331952645334,
|
||||
"timestamp": 1573646422,
|
||||
"wide_cumulative_difficulty": "0x2c63cdbce",
|
||||
"wide_difficulty": "0xe06"
|
||||
},
|
||||
"credits": 0,
|
||||
"json": "{\n \"major_version\": 11, \n \"minor_version\": 12, \n \"timestamp\": 1573646422, \n \"prev_id\": \"51f6816891b6a7adedd0f1ad57a846eada1baac476421aa9d32d0630ce3dce41\", \n \"nonce\": 140046906, \n \"miner_tx\": {\n \"version\": 2, \n \"unlock_time\": 452052, \n \"vin\": [ {\n \"gen\": {\n \"height\": 451992\n }\n }\n ], \n \"vout\": [ {\n \"amount\": 15331952645334, \n \"target\": {\n \"key\": \"e351068aea8f05e9e30f876c3f203a89d09e7e07786979d79df6c7f8cbb75ff1\"\n }\n }\n ], \n \"extra\": [ 1, 170, 162, 15, 155, 129, 214, 70, 54, 0, 45, 227, 90, 106, 73, 20, 172, 79, 179, 97, 69, 218, 11, 160, 249, 214, 112, 230, 194, 182, 161, 28, 128\n ], \n \"rct_signatures\": {\n \"type\": 0\n }\n }, \n \"tx_hashes\": [ \"7e5fea8470c5771315bab4b3c77493d2ff534f5201c7c6b2bab069cb7d21ce7b\", \"3a2f859dea9d2ad5ecec167719302d4e14e21beef9b74f9583183d8e965d9106\", \"bde2b5344b63cbe58ce1a724d0a2276aaa4266be5235d5e5fde969446c3e8de1\", \"24fb42f9f324082658524b29b4cf946a9f5fcfa82194070e2f17c1875e15d5d0\"\n ]\n}",
|
||||
"miner_tx_hash": "",
|
||||
"status": "OK",
|
||||
"top_hash": "",
|
||||
"tx_hashes": [
|
||||
"7e5fea8470c5771315bab4b3c77493d2ff534f5201c7c6b2bab069cb7d21ce7b",
|
||||
"3a2f859dea9d2ad5ecec167719302d4e14e21beef9b74f9583183d8e965d9106",
|
||||
"bde2b5344b63cbe58ce1a724d0a2276aaa4266be5235d5e5fde969446c3e8de1",
|
||||
"24fb42f9f324082658524b29b4cf946a9f5fcfa82194070e2f17c1875e15d5d0"
|
||||
],
|
||||
"untrusted": false
|
||||
}
|
||||
}
|
|
@ -56,6 +56,29 @@ class JSONRPCDaemonTestCase(JSONTestCase):
|
|||
self.assertGreater(txs[0].fee, 0)
|
||||
self.assertGreater(txs[1].fee, 0)
|
||||
|
||||
@responses.activate
|
||||
def test_block(self):
|
||||
responses.add(responses.POST, self.jsonrpc_url,
|
||||
json=self._read("test_block-423cd4d170c53729cf25b4243ea576d1e901d86e26c06d6a7f79815f3fcb9a89.json"),
|
||||
status=200)
|
||||
responses.add(responses.POST, self.transactions_url,
|
||||
json=self._read("test_block-423cd4d170c53729cf25b4243ea576d1e901d86e26c06d6a7f79815f3fcb9a89-txns.json"),
|
||||
status=200)
|
||||
blk = self.daemon.block("423cd4d170c53729cf25b4243ea576d1e901d86e26c06d6a7f79815f3fcb9a89")
|
||||
self.assertEqual(
|
||||
blk.hash,
|
||||
"423cd4d170c53729cf25b4243ea576d1e901d86e26c06d6a7f79815f3fcb9a89")
|
||||
self.assertEqual(blk.height, 451992)
|
||||
|
||||
self.assertIn("24fb42f9f324082658524b29b4cf946a9f5fcfa82194070e2f17c1875e15d5d0", blk)
|
||||
for tx in blk.transactions:
|
||||
self.assertIn(tx, blk)
|
||||
|
||||
# tx not in block
|
||||
self.assertNotIn("e3a3b8361777c8f4f1fd423b86655b5c775de0230b44aa5b82f506135a96c53a", blk)
|
||||
# wrong arg type
|
||||
self.assertRaises(ValueError, lambda txid: txid in blk, 1245)
|
||||
|
||||
@responses.activate
|
||||
def test_transactions(self):
|
||||
responses.add(responses.POST, self.transactions_url,
|
||||
|
|
Loading…
Reference in a new issue