Skip to content

Commit

Permalink
Support XMPIP-0015
Browse files Browse the repository at this point in the history
  • Loading branch information
cryptcoin-junkey committed Feb 12, 2022
1 parent f0ab224 commit 21d17a4
Showing 1 changed file with 67 additions and 45 deletions.
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

0 comments on commit 21d17a4

Please sign in to comment.