diff --git a/explorer/rest/rest/db/NemDatabase.py b/explorer/rest/rest/db/NemDatabase.py index 435f43f440..9245b39ae9 100644 --- a/explorer/rest/rest/db/NemDatabase.py +++ b/explorer/rest/rest/db/NemDatabase.py @@ -25,17 +25,30 @@ def __init__(self, db_config, network): self.network = network def _create_block_view(self, result): - harvest_public_key = PublicKey(_format_bytes(result[7])) + ( + height, + timestamp, + total_fee, + total_transactions, + difficulty, + block_hash, + beneficiary, + signer, + signature, + size + ) = result + return BlockView( - height=result[1], - timestamp=str(result[2]), - total_fees=_format_xem_relative(result[3]), - total_transactions=result[4], - difficulty=result[5], - block_hash=_format_bytes(result[6]), - signer=self.network.public_key_to_address(harvest_public_key), - signature=_format_bytes(result[8]), - size=result[9] + height=height, + timestamp=str(timestamp), + total_fees=_format_xem_relative(total_fee), + total_transactions=total_transactions, + difficulty=difficulty, + block_hash=_format_bytes(block_hash), + beneficiary=str(Address(beneficiary)), + signer=str(self.network.public_key_to_address(PublicKey(signer))), + signature=_format_bytes(signature), + size=size ) def _create_account_view(self, result): # pylint: disable=no-self-use,too-many-locals @@ -102,6 +115,27 @@ def _generate_account_query(self, where_condition): # pylint: disable=no-self-u WHERE {where_condition} ''' + def _generate_block_query(self, where_condition, order_condition='', limit_condition=''): # pylint: disable=no-self-use + """Base block query.""" + + return f''' + SELECT + height, + timestamp, + total_fee, + total_transactions, + difficulty, + hash, + beneficiary, + signer, + signature, + size + FROM blocks + {where_condition} + {order_condition} + {limit_condition} + ''' + def _get_account(self, where_clause, query_bytes): """Gets account by where clause.""" @@ -117,13 +151,13 @@ def _get_account(self, where_clause, query_bytes): def get_block(self, height): """Gets block by height in database.""" + where_condition = 'WHERE height = %s' + + sql = self._generate_block_query(where_condition) + with self.connection() as connection: cursor = connection.cursor() - cursor.execute(''' - SELECT * - FROM blocks - WHERE height = %s - ''', (height,)) + cursor.execute(sql, (height,)) result = cursor.fetchone() return self._create_block_view(result) if result else None @@ -131,15 +165,21 @@ def get_block(self, height): def get_blocks(self, limit, offset, min_height, sort): """Gets blocks pagination in database.""" + where_condition = ' WHERE height >= %s' + order_condition = f' ORDER BY id {sort}' + limit_condition = ' LIMIT %s OFFSET %s' + + sql = self._generate_block_query( + where_condition=where_condition, + order_condition=order_condition, + limit_condition=limit_condition + ) + + params = [min_height, limit, offset] + with self.connection() as connection: cursor = connection.cursor() - cursor.execute(f''' - SELECT * - FROM blocks - WHERE height >= %s - ORDER BY id {sort} - LIMIT %s OFFSET %s - ''', (min_height, limit, offset,)) + cursor.execute(sql, params) results = cursor.fetchall() return [self._create_block_view(result) for result in results] diff --git a/explorer/rest/rest/model/Block.py b/explorer/rest/rest/model/Block.py index b42ced2d43..2d9688e03c 100644 --- a/explorer/rest/rest/model/Block.py +++ b/explorer/rest/rest/model/Block.py @@ -1,5 +1,5 @@ class BlockView: # pylint: disable=too-many-instance-attributes - def __init__(self, height, timestamp, total_fees, total_transactions, difficulty, block_hash, signer, signature, size): + def __init__(self, height, timestamp, total_fees, total_transactions, difficulty, block_hash, beneficiary, signer, signature, size): """Create Block view.""" # pylint: disable=too-many-arguments,too-many-positional-arguments @@ -10,6 +10,7 @@ def __init__(self, height, timestamp, total_fees, total_transactions, difficulty self.total_transactions = total_transactions self.difficulty = difficulty self.block_hash = block_hash + self.beneficiary = beneficiary self.signer = signer self.signature = signature self.size = size @@ -22,6 +23,7 @@ def __eq__(self, other): self.total_transactions == other.total_transactions, self.difficulty == other.difficulty, self.block_hash == other.block_hash, + self.beneficiary == other.beneficiary, self.signer == other.signer, self.signature == other.signature, self.size == other.size @@ -32,12 +34,13 @@ def to_dict(self): return { 'height': self.height, - 'timestamp': str(self.timestamp), + 'timestamp': self.timestamp, 'totalFees': self.total_fees, 'totalTransactions': self.total_transactions, 'difficulty': self.difficulty, - 'hash': str(self.block_hash), - 'signer': str(self.signer), - 'signature': str(self.signature), + 'hash': self.block_hash, + 'beneficiary': self.beneficiary, + 'signer': self.signer, + 'signature': self.signature, 'size': self.size } diff --git a/explorer/rest/tests/model/test_Block.py b/explorer/rest/tests/model/test_Block.py index 047c7b7000..2c4e4f90a0 100644 --- a/explorer/rest/tests/model/test_Block.py +++ b/explorer/rest/tests/model/test_Block.py @@ -13,6 +13,7 @@ def _create_default_block_view(override=None): 1, 95000000000000, '9708256E8A8DFB76EED41DCFA2E47F4AF520B7B3286AFB7F60DCA02851F8A53E', + 'TCJLCZSOQ6RGWHTPSV2DW467WZSHK4NBSITND4OF', '45C1553FB1BE7F25B6F79278B9EDE1129BB9163F3B85883EA90F1C66F497E68B', ( '919AE66A34119B49812B335827B357F86884AB08B628029FD6E8DB3572FAEB4F' @@ -37,6 +38,7 @@ def test_can_create_block_view(self): self.assertEqual(1, block_view.total_transactions) self.assertEqual(95000000000000, block_view.difficulty) self.assertEqual('9708256E8A8DFB76EED41DCFA2E47F4AF520B7B3286AFB7F60DCA02851F8A53E', block_view.block_hash) + self.assertEqual('TCJLCZSOQ6RGWHTPSV2DW467WZSHK4NBSITND4OF', block_view.beneficiary) self.assertEqual('45C1553FB1BE7F25B6F79278B9EDE1129BB9163F3B85883EA90F1C66F497E68B', block_view.signer) self.assertEqual( '919AE66A34119B49812B335827B357F86884AB08B628029FD6E8DB3572FAEB4F' @@ -60,6 +62,7 @@ def test_can_convert_to_simple_dict(self): 'totalTransactions': 1, 'difficulty': 95000000000000, 'hash': '9708256E8A8DFB76EED41DCFA2E47F4AF520B7B3286AFB7F60DCA02851F8A53E', + 'beneficiary': 'TCJLCZSOQ6RGWHTPSV2DW467WZSHK4NBSITND4OF', 'signer': '45C1553FB1BE7F25B6F79278B9EDE1129BB9163F3B85883EA90F1C66F497E68B', 'signature': ( '919AE66A34119B49812B335827B357F86884AB08B628029FD6E8DB3572FAEB4F' @@ -82,6 +85,7 @@ def test_eq_is_supported(self): self.assertNotEqual(block_view, self._create_default_block_view(('total_transactions', 2))) self.assertNotEqual(block_view, self._create_default_block_view(('difficulty', 95000000000001))) self.assertNotEqual(block_view, self._create_default_block_view(('block_hash', 'random hash'))) + self.assertNotEqual(block_view, self._create_default_block_view(('beneficiary', 'random beneficiary'))) self.assertNotEqual(block_view, self._create_default_block_view(('signer', 'random signer'))) self.assertNotEqual(block_view, self._create_default_block_view(('signature', 'random signature'))) self.assertNotEqual(block_view, self._create_default_block_view(('size', 'random size'))) diff --git a/explorer/rest/tests/test/DatabaseTestUtils.py b/explorer/rest/tests/test/DatabaseTestUtils.py index 1c48481a13..4a6f1b8313 100644 --- a/explorer/rest/tests/test/DatabaseTestUtils.py +++ b/explorer/rest/tests/test/DatabaseTestUtils.py @@ -16,10 +16,11 @@ [ 'height', 'timestamp', - 'total_fees', + 'total_fee', 'total_transactions', 'difficulty', 'block_hash', + 'beneficiary', 'signer', 'signature', 'size' @@ -52,7 +53,8 @@ 5, 100000000000000, '438CF6375DAB5A0D32F9B7BF151D4539E00A590F7C022D5572C7D41815A24BE4', - '8D07F90FB4BBE7715FA327C926770166A11BE2E494A970605F2E12557F66C9B9', + Address('NANEMOABLAGR72AZ2RV3V4ZHDCXW25XQ73O7OBT5'), + PublicKey('8D07F90FB4BBE7715FA327C926770166A11BE2E494A970605F2E12557F66C9B9'), '2ABDD19AD3EFAB0413B42772A586FAA19DEDB16D35F665F90D598046A2132C4A' 'D1E71001545CEAA44E63C04345591E7AADBFD330AF82A0D8A1DA5643E791FF0F', 936), @@ -63,7 +65,8 @@ 3, 80000000000000, '1DD9D4D7B6AF603D29C082F9AA4E123F07D18154DDBCD7DDC6702491B854C5E4', - 'F9BD190DD0C364261F5C8A74870CC7F7374E631352293C62ECC437657E5DE2CD', + Address('NALICEPFLZQRZGPRIJTMJOCPWDNECXTNNG7QLSG3'), + PublicKey('F9BD190DD0C364261F5C8A74870CC7F7374E631352293C62ECC437657E5DE2CD'), '1B81379847241E45DA86B27911E5C9A9192EC04F644D98019657D32838B49C14' '3EAA4815A3028B80F9AFFDBF0B94CD620F7A925E02783DDA67B8627B69DDF70E', 752), @@ -87,8 +90,16 @@ ] BLOCK_VIEWS = [ - BlockView(*BLOCKS[0]._replace(total_fees=102.0, signer=Address('NANEMOABLAGR72AZ2RV3V4ZHDCXW25XQ73O7OBT5'))), - BlockView(*BLOCKS[1]._replace(total_fees=201.0, signer=Address('NALICEPFLZQRZGPRIJTMJOCPWDNECXTNNG7QLSG3'))) + BlockView(*BLOCKS[0]._replace( + total_fee=102.0, + beneficiary='NANEMOABLAGR72AZ2RV3V4ZHDCXW25XQ73O7OBT5', + signer='NANEMOABLAGR72AZ2RV3V4ZHDCXW25XQ73O7OBT5') + ), + BlockView(*BLOCKS[1]._replace( + total_fee=201.0, + beneficiary='NALICEPFLZQRZGPRIJTMJOCPWDNECXTNNG7QLSG3', + signer='NALICEPFLZQRZGPRIJTMJOCPWDNECXTNNG7QLSG3') + ) ] ACCOUNT_VIEWS = [ @@ -153,10 +164,11 @@ def initialize_database(db_config, network_name): id serial NOT NULL PRIMARY KEY, height bigint NOT NULL, timestamp timestamp NOT NULL, - total_fees bigint DEFAULT 0, + total_fee bigint DEFAULT 0, total_transactions int DEFAULT 0, difficulty bigInt NOT NULL, hash bytea NOT NULL, + beneficiary bytea NOT NULL, signer bytea NOT NULL, signature bytea NOT NULL, size bigint DEFAULT 0 @@ -167,16 +179,17 @@ def initialize_database(db_config, network_name): for block in BLOCKS: cursor.execute( ''' - INSERT INTO blocks (height, timestamp, total_fees, total_transactions, difficulty, hash, signer, signature, size) - VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) + INSERT INTO blocks (height, timestamp, total_fee, total_transactions, difficulty, hash, beneficiary, signer, signature, size) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) ''', ( block.height, block.timestamp, - block.total_fees, + block.total_fee, block.total_transactions, block.difficulty, unhexlify(block.block_hash), - unhexlify(block.signer), + block.beneficiary.bytes, + block.signer.bytes, unhexlify(block.signature), block.size )