346 lines
14 KiB
Python
346 lines
14 KiB
Python
# standard imports
|
||
import logging
|
||
import datetime
|
||
|
||
# external imports
|
||
from cic_cache.db.models.base import SessionBase
|
||
from sqlalchemy import text
|
||
|
||
logg = logging.getLogger()
|
||
|
||
|
||
def list_transactions_mined(
|
||
session,
|
||
offset,
|
||
limit,
|
||
block_offset,
|
||
block_limit,
|
||
oldest=False,
|
||
):
|
||
"""Executes db query to return all confirmed transactions according to the specified offset and limit.
|
||
|
||
:param offset: Offset in data set to return transactions from
|
||
:type offset: int
|
||
:param limit: Max number of transactions to retrieve
|
||
:type limit: int
|
||
:result: Result set
|
||
:rtype: SQLAlchemy.ResultProxy
|
||
"""
|
||
order_by = 'DESC'
|
||
if oldest:
|
||
order_by = 'ASC'
|
||
|
||
if block_offset:
|
||
if block_limit:
|
||
s = "SELECT block_number, tx_index FROM tx WHERE block_number >= {} and block_number <= {} ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, block_limit, order_by, order_by, limit, offset)
|
||
else:
|
||
s = "SELECT block_number, tx_index FROM tx WHERE block_number >= {} ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, order_by, order_by, limit, offset)
|
||
else:
|
||
s = "SELECT block_number, tx_index FROM tx ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(order_by, order_by, limit, offset)
|
||
r = session.execute(s)
|
||
return r
|
||
|
||
|
||
def list_transactions_mined_with_data(
|
||
session,
|
||
offset,
|
||
limit,
|
||
block_offset,
|
||
block_limit,
|
||
oldest=False,
|
||
):
|
||
"""Executes db query to return all confirmed transactions according to the specified offset and limit.
|
||
|
||
:param block_offset: First block to include in search
|
||
:type block_offset: int
|
||
:param block_limit: Last block to include in search
|
||
:type block_limit: int
|
||
:result: Result set
|
||
:rtype: SQLAlchemy.ResultProxy
|
||
"""
|
||
order_by = 'DESC'
|
||
if oldest:
|
||
order_by = 'ASC'
|
||
|
||
if block_offset:
|
||
if block_limit:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id WHERE block_number >= {} AND block_number <= {} ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, block_limit, order_by, order_by, limit, offset)
|
||
else:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id WHERE block_number >= {} ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, order_by, order_by, limit, offset)
|
||
else:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(order_by, order_by, limit, offset)
|
||
|
||
|
||
r = session.execute(s)
|
||
return r
|
||
|
||
|
||
def list_transactions_mined_with_data_index(
|
||
session,
|
||
offset,
|
||
end,
|
||
block_offset,
|
||
block_limit,
|
||
oldest=False,
|
||
):
|
||
"""Executes db query to return all confirmed transactions according to the specified offset and limit.
|
||
|
||
:param offset: Offset in data set to return transactions from
|
||
:type offset: int
|
||
:param limit: Max number of transactions to retrieve
|
||
:type limit: int
|
||
:result: Result set
|
||
:rtype: SQLAlchemy.ResultProxy
|
||
"""
|
||
|
||
order_by = 'DESC'
|
||
if oldest:
|
||
order_by = 'ASC'
|
||
|
||
if block_offset:
|
||
if block_limit:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id WHERE block_number >= {} and block_number <= {} ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, block_limit, order_by, order_by, offset, end)
|
||
else:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id WHERE block_number >= {} ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, order_by, order_by, offset, end)
|
||
else:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(order_by, order_by, offset, end)
|
||
|
||
r = session.execute(s)
|
||
return r
|
||
|
||
|
||
def list_transactions_account_mined_with_data_index(
|
||
session,
|
||
address,
|
||
offset,
|
||
limit,
|
||
block_offset,
|
||
block_limit,
|
||
oldest=False,
|
||
):
|
||
"""Executes db query to return all confirmed transactions according to the specified offset and limit, filtered by address
|
||
|
||
:param offset: Offset in data set to return transactions from
|
||
:type offset: int
|
||
:param limit: Max number of transactions to retrieve
|
||
:type limit: int
|
||
:result: Result set
|
||
:rtype: SQLAlchemy.ResultProxy
|
||
"""
|
||
|
||
order_by = 'DESC'
|
||
if oldest:
|
||
order_by = 'ASC'
|
||
|
||
if block_offset:
|
||
if block_limit:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id WHERE block_number >= {} AND block_number <= {} AND (sender = '{}' OR recipient = '{}') ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, block_limit, address, address, order_by, order_by, limit, offset)
|
||
else:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id WHERE block_number >= {} AND (sender = '{}' OR recipient = '{}') ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, address, address, order_by, order_by, limit, offset)
|
||
else:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id WHERE sender = '{}' OR recipient = '{}' ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(address, address, order_by, order_by, limit, offset)
|
||
|
||
r = session.execute(s)
|
||
return r
|
||
|
||
def list_transactions_account_mined_with_data(
|
||
session,
|
||
address,
|
||
offset,
|
||
limit,
|
||
block_offset,
|
||
block_limit,
|
||
oldest=False,
|
||
):
|
||
"""Executes db query to return all confirmed transactions according to the specified offset and limit.
|
||
|
||
:param block_offset: First block to include in search
|
||
:type block_offset: int
|
||
:param block_limit: Last block to include in search
|
||
:type block_limit: int
|
||
:result: Result set
|
||
:rtype: SQLAlchemy.ResultProxy
|
||
"""
|
||
|
||
order_by = 'DESC'
|
||
if oldest:
|
||
order_by = 'ASC'
|
||
|
||
if block_offset:
|
||
if block_limit:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id WHERE block_number >= {} AND block_number <= {} AND (sender = '{}' OR recipient = '{}') ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, block_limit, address, address, order_by, order_by, limit, offset)
|
||
else:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id WHERE block_number >= {} AND (sender = '{}' OR recipient = '{}') ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, address, address, order_by, order_by, limit, offset)
|
||
else:
|
||
s = "SELECT tx_hash, block_number, date_block, sender, recipient, from_value, to_value, source_token, destination_token, success, domain, value FROM tx LEFT JOIN tag_tx_link ON tx.id = tag_tx_link.tx_id LEFT JOIN tag ON tag_tx_link.tag_id = tag.id WHERE sender = '{}' OR recipient = '{}' ORDER BY block_number , tx_index {} LIMIT {} OFFSET {}".format(address, address, order_by, order_by, limit, offset)
|
||
|
||
r = session.execute(s)
|
||
return r
|
||
|
||
|
||
def list_transactions_account_mined(
|
||
session,
|
||
address,
|
||
offset,
|
||
limit,
|
||
block_offset,
|
||
block_limit,
|
||
oldest=False,
|
||
):
|
||
"""Same as list_transactions_mined(...), but only retrieves transaction where the specified account address is sender or recipient.
|
||
|
||
:param address: Address to retrieve transactions for.
|
||
:type address: str, 0x-hex
|
||
:param offset: Offset in data set to return transactions from
|
||
:type offset: int
|
||
:param limit: Max number of transactions to retrieve
|
||
:type limit: int
|
||
:result: Result set
|
||
:rtype: SQLAlchemy.ResultProxy
|
||
"""
|
||
|
||
order_by = 'DESC'
|
||
if oldest:
|
||
order_by = 'ASC'
|
||
|
||
if block_offset:
|
||
if block_limit:
|
||
s = "SELECT block_number, tx_index FROM tx WHERE block_number >= {} AND block_number <= {} AND (sender = '{}' OR recipient = '{}') ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, block_limit, address, address, order_by, order_by, limit, offset)
|
||
else:
|
||
s = "SELECT block_number, tx_index FROM tx WHERE block_number >= {} AND (sender = '{}' OR recipient = '{}') ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(block_offset, address, address, order_by, order_by, limit, offset)
|
||
|
||
else:
|
||
s = "SELECT block_number, tx_index FROM tx WHERE sender = '{}' OR recipient = '{}' ORDER BY block_number {}, tx_index {} LIMIT {} OFFSET {}".format(address, address, order_by, order_by, limit, offset)
|
||
|
||
r = session.execute(s)
|
||
return r
|
||
|
||
|
||
def add_transaction(
|
||
session,
|
||
tx_hash,
|
||
block_number,
|
||
tx_index,
|
||
sender,
|
||
receiver,
|
||
source_token,
|
||
destination_token,
|
||
from_value,
|
||
to_value,
|
||
success,
|
||
timestamp,
|
||
):
|
||
"""Adds a single transaction to the cache persistent storage. Sensible interpretation of all fields is the responsibility of the caller.
|
||
|
||
:param session: Persistent storage session object
|
||
:type session: SQLAlchemy session
|
||
:param tx_hash: Transaction hash
|
||
:type tx_hash: str, 0x-hex
|
||
:param block_number: Block number
|
||
:type block_number: int
|
||
:param tx_index: Transaction index in block
|
||
:type tx_index: int
|
||
:param sender: Ethereum address of effective sender
|
||
:type sender: str, 0x-hex
|
||
:param receiver: Ethereum address of effective recipient
|
||
:type receiver: str, 0x-hex
|
||
:param source_token: Ethereum address of token used by sender
|
||
:type source_token: str, 0x-hex
|
||
:param destination_token: Ethereum address of token received by recipient
|
||
:type destination_token: str, 0x-hex
|
||
:param from_value: Source token value spent in transaction
|
||
:type from_value: int
|
||
:param to_value: Destination token value received in transaction
|
||
:type to_value: int
|
||
:param success: True if code execution on network was successful
|
||
:type success: bool
|
||
:param date_block: Block timestamp
|
||
:type date_block: datetime
|
||
"""
|
||
date_block = datetime.datetime.fromtimestamp(timestamp)
|
||
s = "INSERT INTO tx (tx_hash, block_number, tx_index, sender, recipient, source_token, destination_token, from_value, to_value, success, date_block) VALUES ('{}', {}, {}, '{}', '{}', '{}', '{}', {}, {}, {}, '{}')".format(
|
||
tx_hash,
|
||
block_number,
|
||
tx_index,
|
||
sender,
|
||
receiver,
|
||
source_token,
|
||
destination_token,
|
||
from_value,
|
||
to_value,
|
||
success,
|
||
date_block,
|
||
)
|
||
session.execute(s)
|
||
|
||
|
||
|
||
def tag_transaction(
|
||
session,
|
||
tx_hash,
|
||
name,
|
||
domain=None,
|
||
):
|
||
"""Tag a single transaction with a single tag.
|
||
|
||
Tag must already exist in storage.
|
||
|
||
:param session: Persistent storage session object
|
||
:type session: SQLAlchemy session
|
||
:param tx_hash: Transaction hash
|
||
:type tx_hash: str, 0x-hex
|
||
:param name: Tag value
|
||
:type name: str
|
||
:param domain: Tag domain
|
||
:type domain: str
|
||
:raises ValueError: Unknown tag or transaction hash
|
||
|
||
"""
|
||
|
||
s = text("SELECT id from tx where tx_hash = :a")
|
||
r = session.execute(s, {'a': tx_hash}).fetchall()
|
||
tx_id = r[0].values()[0]
|
||
|
||
if tx_id == None:
|
||
raise ValueError('unknown tx hash {}'.format(tx_hash))
|
||
|
||
#s = text("SELECT id from tag where value = :a and domain = :b")
|
||
if domain == None:
|
||
s = text("SELECT id from tag where value = :a")
|
||
else:
|
||
s = text("SELECT id from tag where value = :a and domain = :b")
|
||
r = session.execute(s, {'a': name, 'b': domain}).fetchall()
|
||
tag_id = r[0].values()[0]
|
||
|
||
logg.debug('type {} {}'.format(type(tag_id), type(tx_id)))
|
||
|
||
if tag_id == None:
|
||
raise ValueError('unknown tag name {} domain {}'.format(name, domain))
|
||
|
||
s = text("INSERT INTO tag_tx_link (tag_id, tx_id) VALUES (:a, :b)")
|
||
r = session.execute(s, {'a': int(tag_id), 'b': int(tx_id)})
|
||
|
||
|
||
def add_tag(
|
||
session,
|
||
name,
|
||
domain=None,
|
||
):
|
||
"""Add a single tag to storage.
|
||
|
||
:param session: Persistent storage session object
|
||
:type session: SQLAlchemy session
|
||
:param name: Tag value
|
||
:type name: str
|
||
:param domain: Tag domain
|
||
:type domain: str
|
||
:raises sqlalchemy.exc.IntegrityError: Tag already exists
|
||
"""
|
||
|
||
s = None
|
||
if domain == None:
|
||
s = text("INSERT INTO tag (value) VALUES (:b)")
|
||
else:
|
||
s = text("INSERT INTO tag (domain, value) VALUES (:a, :b)")
|
||
session.execute(s, {'a': domain, 'b': name})
|