Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions explorer/puller/puller/db/NemDatabase.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,6 @@ def create_tables(self):
timestamp timestamp NOT NULL,
deadline timestamp NOT NULL,
signature bytea,
amount bigint,
is_inner boolean DEFAULT false,
payload jsonb
)
Expand Down Expand Up @@ -493,11 +492,10 @@ def insert_transaction(cursor, transaction):
timestamp,
deadline,
signature,
amount,
is_inner,
payload
)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
RETURNING id
''',
(
Expand All @@ -511,7 +509,6 @@ def insert_transaction(cursor, transaction):
transaction.timestamp,
transaction.deadline,
unhexlify(transaction.signature) if transaction.signature else None,
transaction.amount,
transaction.is_inner,
json.dumps(transaction.payload) if transaction.payload else None
)
Expand Down
24 changes: 17 additions & 7 deletions explorer/puller/puller/facade/NemPuller.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from symbolchain.nem.Network import Address, Network
from symbollightapi.connector.NemConnector import NemConnector
from symbollightapi.model.Exceptions import NodeException
from symbollightapi.model.Transaction import Mosaic
from zenlog import log

from puller.db.NemDatabase import NemDatabase
Expand Down Expand Up @@ -71,7 +72,6 @@
'timestamp',
'deadline',
'signature',
'amount',
'transaction_type',
'is_inner',
'sender_address',
Expand Down Expand Up @@ -368,7 +368,6 @@ def _build_transaction_record(self, transaction, is_inner):

payload = None
recipient_address = None
amount = None
if transaction.transaction_type == TransactionType.TRANSFER.value:
payload = {
'message': {
Expand All @@ -377,7 +376,6 @@ def _build_transaction_record(self, transaction, is_inner):
} if transaction.message else None
}
recipient_address = transaction.recipient
amount = transaction.amount
elif transaction.transaction_type == TransactionType.ACCOUNT_KEY_LINK.value:
payload = {
'mode': transaction.mode,
Expand Down Expand Up @@ -451,7 +449,6 @@ def _build_transaction_record(self, transaction, is_inner):
fee=transaction.fee,
timestamp=self._convert_timestamp_to_datetime(transaction.timestamp),
deadline=self._convert_timestamp_to_datetime(transaction.deadline),
amount=amount,
signature=transaction.signature,
transaction_type=transaction.transaction_type,
is_inner=is_inner,
Expand All @@ -467,9 +464,22 @@ def _process_transaction(self, cursor, transaction, block_height, is_inner):
transaction_record = self._build_transaction_record(transaction, is_inner)
transaction_id = self.nem_db.insert_transaction(cursor, transaction_record)

if transaction.transaction_type == TransactionType.TRANSFER.value and transaction.mosaics:
for mosaic in transaction.mosaics:
self.nem_db.insert_transaction_mosaic(cursor, transaction_id, mosaic)
if transaction.transaction_type == TransactionType.TRANSFER.value:
if transaction.mosaics:
for mosaic in transaction.mosaics:
mosaic_amount = mosaic.quantity * transaction.amount // (10 ** 6)
self.nem_db.insert_transaction_mosaic(
cursor,
transaction_id,
Mosaic(mosaic.namespace_name, mosaic_amount)
)
else:
# handle v1 transfer transaction
self.nem_db.insert_transaction_mosaic(
cursor,
transaction_id,
Mosaic('nem.xem', transaction.amount)
)
elif transaction.transaction_type == TransactionType.NAMESPACE_REGISTRATION.value:
self._process_namespace(cursor, transaction, block_height)
elif transaction.transaction_type == TransactionType.MOSAIC_DEFINITION.value:
Expand Down
3 changes: 0 additions & 3 deletions explorer/puller/tests/db/test_NemDatabase.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@
fee=150000,
timestamp='2015-03-29 00:06:25+00:00',
deadline='2015-03-29 20:34:19+00:00',
amount=2000000,
signature=(
'1b81379847241e45da86b27911e5c9a9192ec04f644d98019657d32838b49c14'
'3eaa4815a3028b80f9affdbf0b94cd620f7a925e02783dda67b8627b69ddf70e'
Expand Down Expand Up @@ -688,7 +687,6 @@ def test_can_insert_transactions(self):
timestamp,
deadline,
encode(signature, 'hex'),
amount,
is_inner,
payload
FROM transactions
Expand All @@ -711,7 +709,6 @@ def test_can_insert_transactions(self):
datetime.datetime(2015, 3, 29, 0, 6, 25),
datetime.datetime(2015, 3, 29, 20, 34, 19),
TRANSACTIONS[0].signature,
2000000,
False,
'{}'
))
Expand Down
21 changes: 13 additions & 8 deletions explorer/puller/tests/facade/test_NemPuller.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ def test_can_process_mosaic_supply_change_increase(self, mock_update_mosaic_tota
expected_supply_change=500000
)

def _assert_transaction_record(self, transaction, payload, amount=None, recipient_address=None):
def _assert_transaction_record(self, transaction, payload, recipient_address=None):
# Act:
record = self.puller._build_transaction_record(transaction, False) # pylint: disable=protected-access

Expand All @@ -930,7 +930,6 @@ def _assert_transaction_record(self, transaction, payload, amount=None, recipien
fee=transaction.fee,
timestamp='2015-03-29 20:29:42+00:00',
deadline='2015-03-29 23:16:22+00:00',
amount=amount,
signature=transaction.signature,
transaction_type=transaction.transaction_type,
is_inner=False,
Expand All @@ -950,7 +949,6 @@ def test_can_build_transaction_record_transfer(self):
'is_plain': 1
}
},
amount=180000040000000,
recipient_address=transaction.recipient
)

Expand All @@ -963,7 +961,6 @@ def test_can_build_transaction_record_transfer_without_message(self):
self._assert_transaction_record(
transaction,
{'message': None},
amount=180000040000000,
recipient_address=transaction.recipient
)

Expand Down Expand Up @@ -1123,11 +1120,11 @@ def test_can_process_transaction_transfer(self, mock_insert_transaction_mosaic,
transfer.timestamp,
transfer.deadline,
transfer.signature,
transfer.amount,
1999999,
transfer.recipient,
transfer.message,
[
Mosaic('namespace.test', 1000000),
Mosaic('namespace.test', 20),
Mosaic('nem.xem', 8000000)
]
)
Expand All @@ -1141,7 +1138,11 @@ def test_can_process_transaction_transfer(self, mock_insert_transaction_mosaic,
mock_build_transaction_record.assert_called_once()
mock_insert_transaction.assert_called_once()
insert_transaction_mosaic_calls = mock_insert_transaction_mosaic.call_args_list
for index, mosaic in enumerate(transaction.mosaics):
expected_mosaics = [
Mosaic('namespace.test', 39),
Mosaic('nem.xem', 15999992)
]
for index, mosaic in enumerate(expected_mosaics):
self.assertEqual(insert_transaction_mosaic_calls[index][0], (
cursor,
1, # transaction_id from insert_transaction mock
Expand All @@ -1168,7 +1169,11 @@ def test_can_process_transaction_transfer_without_mosaic(
# Assert:
mock_build_transaction_record.assert_called_once()
mock_insert_transaction.assert_called_once()
mock_insert_transaction_mosaic.assert_not_called()
mock_insert_transaction_mosaic.assert_called_once_with(
cursor,
mock_insert_transaction.return_value,
Mosaic('nem.xem', transaction.amount)
)

@patch('puller.facade.NemPuller.NemPuller._build_transaction_record')
@patch('puller.facade.NemPuller.NemDatabase.insert_transaction')
Expand Down
76 changes: 76 additions & 0 deletions explorer/rest/rest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
from flask import Flask, abort, jsonify, request
from flask_cors import CORS
from symbolchain.CryptoTypes import PublicKey
from symbolchain.nc import TransactionType
from zenlog import log

from rest.facade.NemRestFacade import NemRestFacade
from rest.model.common import DatabaseConfig, Pagination, RestConfig, Sorting
from rest.model.Transaction import TransactionQuery


def create_app():
Expand Down Expand Up @@ -277,6 +279,80 @@ def api_get_nem_transaction_statistics_by_date_range(): # pylint: disable=inval

return jsonify(nem_api_facade.get_transaction_statistics_by_date_range(start_date, end_date, period_type))

@app.route('/api/nem/transactions')
def api_get_nem_transactions(): # pylint: disable=too-many-branches,too-many-statements
try:
limit = int(request.args.get('limit', 10))
offset = int(request.args.get('offset', 0))
sort = request.args.get('sort', 'DESC')
height = request.args.get('height', None)
transaction_types = request.args.get('transactionTypes', None)
address = request.args.get('address', None)
sender_address = request.args.get('senderAddress', None)
recipient_address = request.args.get('recipientAddress', None)
sender = request.args.get('senderPublicKey', None)
mosaic = request.args.get('mosaic', None)

if limit < 0 or offset < 0:
raise ValueError('Limit and offset must be greater than or equal to 0')

if sort.upper() not in ['ASC', 'DESC']:
raise ValueError('Sort must be either ASC or DESC')

if height is not None:
height = int(height)
if height < 1:
raise ValueError('Height must be greater than or equal to 1')

if address is not None:
if not nem_api_facade.nem_db.network.is_valid_address_string(address):
raise ValueError('Invalid address format')
else:
if sender_address is not None and sender is not None:
raise ValueError('Only one of senderAddress or senderPublicKey can be provided')

if sender_address is not None:
if not nem_api_facade.nem_db.network.is_valid_address_string(sender_address):
raise ValueError('Invalid sender address format')
else:
if sender is not None:
try:
PublicKey(sender)
except ValueError:
abort(400, 'Invalid sender public key format')

if recipient_address is not None:
if not nem_api_facade.nem_db.network.is_valid_address_string(recipient_address):
raise ValueError('Invalid recipient address format')

if transaction_types:
transaction_types = [tx_type.upper() for tx_type in transaction_types.split(',')]

for tx_type in transaction_types:
if tx_type not in TransactionType.__members__:
raise ValueError('Invalid transaction types')

transaction_types = [TransactionType[t].value for t in transaction_types]

except ValueError as error:
abort(400, error)

results = nem_api_facade.get_transactions(
pagination=Pagination(limit, offset),
sort=sort,
transaction_query=TransactionQuery(
height=height,
transaction_types=transaction_types,
sender=sender,
address=address,
sender_address=sender_address,
recipient_address=recipient_address,
mosaic=mosaic
)
)

return jsonify(results)


def setup_error_handlers(app):
@app.errorhandler(404)
Expand Down
Loading