Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable trigger message. #71

Draft
wants to merge 1 commit into
base: monaparty-develop
Choose a base branch
from
Draft
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
112 changes: 67 additions & 45 deletions counterpartylib/lib/messages/trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,41 @@
LENGTH = 32
ID = 120

receivers = [
asset_metadata.asset_metadata_receiver,
]
_INITIALISER_RECEIVERS = []
_PARSER_RECEIVERS = {}

class NoTargetTableNameError(Exception):
pass
class DuplicateTargetTableNameError(Exception):
pass

def trigger_initiailser():
def wrapper(func):
global _INITIALISER_RECEIVERS
_INITIALISER_RECEIVERS += func
return func
return wrapper

def trigger_parser(trigger_id = 0, target_table_name = None):
def wrapper(func):
global _PARSER_RECEIVERS

def _wrapper(*args, **kwargs):
return func(*args, **kwargs)

if target_table_name is None:
raise NoTargetTableNameError
if 'target_table_name' in _PARSER_RECEIVERS:
raise DuplicateTargetTableNameError
_PARSER_RECEIVERS += {
trigger_id: {
'target_table_name': target_table_name,
'func': func
}
}
return _wrapper
return wrapper


def initialise (db):
cursor = db.cursor()
Expand All @@ -42,37 +74,26 @@ def initialise (db):
source_idx ON triggers (source)
''')

for receiver in receivers:
receiver.initialise(db)
for init in _INITIALISER_RECEIVERS:
init()

def validate (db, source, target_hash, payload_bytes):
problems = []
targets = []
target_type = None
target_table_name = None

cursor = db.cursor()
receiver_instance = None
for receiver in receivers:
sql = 'SELECT tx_hash FROM ' + receiver.target_table_name() + ' WHERE tx_hash = ?'
cursor.execute(sql, (target_hash,))
for receiver in _PARSER_RECEIVERS:
sql = 'SELECT tx_hash FROM ' + receiver.target_table_name + ' WHERE tx_hash = ? AND status = ?'
cursor.execute(sql, (target_hash,'valid'))
targets = cursor.fetchall()
if targets:
assert receiver_instance is None
assert len(targets) == 1
receiver_instance = receiver(db, source, target_hash, payload_bytes)
problems += receiver_instance.validate()

if receiver_instance is None:
problems.append('no trigger target with that hash')
assert len(targets) <= 1
if len(targets) == 1:
target_table_name = receiver.target_table_name

fee = int(0.001 * config.UNIT)
cursor.execute('''SELECT * FROM balances
WHERE (address = ? AND asset = ?)''', (source, config.XCP))
balances = cursor.fetchall()
if not balances or balances[0]['quantity'] < fee:
problems.append('insufficient funds')
if target_table_name is None:
problems.append('no valid trigger target')

return receiver_instance, fee, problems
return target_table_name, problems

def compose (db, source, target_hash, payload, payload_is_hex):
# convert memo to memo_bytes based on memo_is_hex setting
Expand All @@ -85,12 +106,14 @@ def compose (db, source, target_hash, payload, payload_is_hex):
raise exceptions.ComposeError(['failed to convert the payload'])

else:
payload_bytes = struct.pack(">{}s".format(len(payload)),
payload_bytes = struct.pack(
">{}s".format(len(payload)),
payload.encode('utf-8'))

# Check that target exists.
_, _, problems = validate(db, source, target_hash, payload_bytes)
if problems: raise exceptions.ComposeError(problems)
_, problems = validate(db, source, target_hash, payload_bytes)
if problems:
raise exceptions.ComposeError(problems)

target_hash_bytes = binascii.unhexlify(bytes(target_hash, 'utf-8'))

Expand Down Expand Up @@ -122,17 +145,16 @@ def parse (db, tx, message):
status = 'invalid: could not unpack'

if status == 'valid':
receiver, fee, problems = validate(db, tx['source'], target_hash, payload_bytes)
if problems:
status = 'invalid: ' + '; '.join(problems)
target_table_name, problems = validate(db, tx['source'], target_hash, payload_bytes)

if status == 'valid':
try:
problems += receiver.execute(tx)
if problems:
status = 'invalid: ' + '; '.join(problems)
problems += _PARSER_RECEIVERS[target_table_name](db, tx, payload_bytes)
except:
status = 'invalid: execution failed'
problems += [ 'invalid: trigger execution failed' ]

if status == 'valid' and problems:
status = 'invalid: ' + '; '.join(problems)

# Add parsed transaction to message-type–specific table.
bindings = {
Expand All @@ -144,14 +166,14 @@ def parse (db, tx, message):
'payload': payload_bytes,
'status': status,
}
if "integer overflow" not in status:
sql='INSERT INTO triggers VALUES (:tx_index, :tx_hash, :block_index, :source, :target_hash, :payload, :status)'
cursor.execute(sql, bindings)
else:
logger.warn("Not storing [trigger] tx [%s]: %s", tx['tx_hash'], status)
logger.debug("Bindings: %s", json.dumps(bindings))

if status == 'valid':
util.debit(db, tx['source'], config.XCP, fee, action="trigger fee", event=tx['tx_hash'])
sql = '''INSERT INTO triggers VALUES (
:tx_index,
:tx_hash,
:block_index,
:source,
:target_hash,
:payload,
:status)'''
cursor.execute(sql, bindings)

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4