eth-monitor

Monitor and cache ethereum transactions with match filters
git clone git://git.defalsify.org/eth-monitor.git
Log | Files | Refs | README | LICENSE

commit c4e2dc37f36c99de0da3d985d3251162aa8d1b76
parent 4dfe6be170daf805459b5e72ce08b11516786adb
Author: lash <dev@holbrook.no>
Date:   Tue,  5 Apr 2022 11:44:15 +0000

add data filter

Diffstat:
MCHANGELOG | 4++++
Meth_monitor/filters/out.py | 19++++++++++++++++++-
Meth_monitor/rules.py | 49++++++++++++++++++++++++++++++++++++++++---------
Meth_monitor/runnable/sync.py | 24++++++++++++++++++++++--
Msetup.cfg | 2+-
5 files changed, 85 insertions(+), 13 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,3 +1,7 @@ +- 0.3.1 + * Add data filter +- 0.3.0 + * Reimplement on shep/chainsyncer 0.3.0 - 0.2.1 * Implement --keep-alive flag - 0.2.0 diff --git a/eth_monitor/filters/out.py b/eth_monitor/filters/out.py @@ -1,6 +1,12 @@ # standard imports import sys import logging +import datetime + +# external imports +from hexathon import ( + strip_0x, + ) # local imports from .base import RuledFilter @@ -61,7 +67,18 @@ class OutFilter(RuledFilter): data = data[:8] + '...' if len(data) > 0: data = 'data {}'.format(data) - s = '{} {} {} {}'.format(self.c, block, tx, data) + #s = '{} {} {} {}'.format(self.c, block, tx, data) + tx_count = len(block.txs) + s = '{} {} block {} {} tx {}/{} {} {}'.format( + self.c, + datetime.datetime.fromtimestamp(block.timestamp), + block.number, + strip_0x(block.hash), + tx.index, + tx_count, + strip_0x(tx.hash), + data, + ) self.w.write(s + '\n') self.c += 1 diff --git a/eth_monitor/rules.py b/eth_monitor/rules.py @@ -8,6 +8,36 @@ from chainlib.eth.address import is_same_address logg = logging.getLogger() +class RuleMethod: + + def __init__(self, methods, description=None): + self.methods = methods + self.description = description + if self.description == None: + self.description = str(uuid.uuid4()) + + + def check(self, sender, recipient, data, tx_hash): + if len(self.methods) == 0: + return False + + for method in self.methods: + l = len(method) + if len(method) > len(data): + continue + if data[:l] == method: + logg.debug('tx {} rule {} match in DATA {}'.format(tx_hash, self.description, method)) + return True + + return False + + + def __str__(self): + return 'Method ' + self.description + ' {}'.format( + self.methods, + ) + + class RuleSimple: def __init__(self, outputs, inputs, executables, description=None): @@ -19,18 +49,18 @@ class RuleSimple: self.executables = executables - def check(self, sender, recipient, tx_hash): + def check(self, sender, recipient, data, tx_hash): for rule in self.outputs: if rule != None and is_same_address(sender, rule): - logg.debug('tx {} rule INCLUDE match in SENDER {}'.format(tx_hash, sender)) + logg.debug('tx {} rule {} match in SENDER {}'.format(tx_hash, self.description, sender)) return True for rule in self.inputs: if rule != None and is_same_address(recipient, rule): - logg.debug('tx {} rule INCLUDE match in RECIPIENT {}'.format(tx_hash, recipient)) + logg.debug('tx {} rule {} match in RECIPIENT {}'.format(tx_hash, self.description, recipient)) return True for rule in self.executables: if rule != None and is_same_address(recipient, rule): - logg.debug('tx {} rule INCLUDE match in ExECUTABLE {}'.format(tx_hash, recipient)) + logg.debug('tx {} rule {} match in EXECUTABLE {}'.format(tx_hash, self.description, recipient)) return True @@ -57,24 +87,25 @@ class AddressRules: def include(self, rule): self.includes.append(rule) - logg.info('cache filter added EXCLUDE rule {}'.format(rule)) + logg.info('cache filter added INCLUDE rule {}'.format(rule)) def apply_rules(self, tx): - return self.apply_rules_addresses(tx.outputs[0], tx.inputs[0], tx.hash) + return self.apply_rules_addresses(tx.outputs[0], tx.inputs[0], tx.payload, tx.hash) - def apply_rules_addresses(self, sender, recipient, tx_hash): + # TODO: rename + def apply_rules_addresses(self, sender, recipient, data, tx_hash): v = self.include_by_default for rule in self.includes: - if rule.check(sender, recipient, tx_hash): + if rule.check(sender, recipient, data, tx_hash): v = True logg.info('match in includes rule: {}'.format(rule)) break for rule in self.excludes: - if rule.check(sender, recipient, tx_hash): + if rule.check(sender, recipient, data, tx_hash): v = False logg.info('match in excludes rule: {}'.format(rule)) break diff --git a/eth_monitor/runnable/sync.py b/eth_monitor/runnable/sync.py @@ -30,6 +30,7 @@ from eth_monitor.filters.cache import Filter as CacheFilter from eth_monitor.rules import ( AddressRules, RuleSimple, + RuleMethod, ) from eth_monitor.filters import RuledFilter from eth_monitor.filters.out import OutFilter @@ -61,6 +62,8 @@ argparser.add_argument('--keep-alive', action='store_true', dest='keep_alive', h argparser.add_argument('--input', default=[], action='append', type=str, help='Add input (recipient) addresses to includes list') argparser.add_argument('--output', default=[], action='append', type=str, help='Add output (sender) addresses to includes list') argparser.add_argument('--exec', default=[], action='append', type=str, help='Add exec (contract) addresses to includes list') +argparser.add_argument('--data', default=[], action='append', type=str, help='Add data strings to include list') +argparser.add_argument('--x-data', default=[], action='append', dest='xdata', type=str, help='Add data strings to exclude list') argparser.add_argument('--address', default=[], action='append', type=str, help='Add addresses as input, output and exec to includes list') argparser.add_argument('--x-input', default=[], action='append', type=str, dest='xinput', help='Add input (recipient) addresses to excludes list') argparser.add_argument('--x-output', default=[], action='append', type=str, dest='xoutput', help='Add output (sender) addresses to excludes list') @@ -155,10 +158,23 @@ def setup_address_arg_rules(rules, args): exclude_outputs.append(address) exclude_exec.append(address) - includes = RuleSimple(include_outputs, include_inputs, include_exec) + includes = RuleSimple(include_outputs, include_inputs, include_exec, description='INCLUDE') rules.include(includes) - excludes = RuleSimple(exclude_outputs, exclude_inputs, exclude_exec) + excludes = RuleSimple(exclude_outputs, exclude_inputs, exclude_exec, description='EXCLUDE') + rules.exclude(excludes) + + return rules + + +def setup_data_arg_rules(rules, args): + include_data = args.data + exclude_data = args.xdata + + includes = RuleMethod(include_data, description='INCLUDE') + rules.include(includes) + + excludes = RuleMethod(exclude_data, description='EXCLUDE') rules.exclude(excludes) return rules @@ -301,6 +317,10 @@ def main(): block_limit = block_offset address_rules = AddressRules(include_by_default=args.include_default) + address_rules = setup_data_arg_rules( + address_rules, + args, + ) address_rules = setup_address_file_rules( address_rules, includes_file=args.includes_file, diff --git a/setup.cfg b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = eth-monitor -version = 0.3.0 +version = 0.3.1 description = Monitor and cache transactions using match filters author = Louis Holbrook author_email = dev@holbrook.no