From 017ff2d564f0cf1a4b1b0df99abeb2c7e2a32777 Mon Sep 17 00:00:00 2001 From: lash Date: Thu, 4 Jul 2024 19:12:06 +0100 Subject: [PATCH] Add tx hash selector flag for rules matching --- CHANGELOG | 5 +++++ eth_monitor/cache.py | 33 +++++++++++++++++++++++++++++ eth_monitor/cli/arg.py | 2 ++ eth_monitor/cli/config.py | 3 ++- eth_monitor/cli/rules.py | 4 ++++ eth_monitor/data/config/monitor.ini | 2 ++ eth_monitor/rules.py | 30 ++++++++++++++++++++++++-- eth_monitor/settings.py | 25 ++++++++++++++++++++++ man/build/eth-monitor-sync.1 | 10 +++++++++ man/build/eth-monitor.1 | 10 +++++++++ man/eth-monitor.overrides | 2 ++ 11 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 eth_monitor/cache.py diff --git a/CHANGELOG b/CHANGELOG index 9a6b4f1..ec8ab3f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +- 0.8.10 + * Add tx hash filter to rules + * Add cache spec flag to allow other cache backends +- 0.8.9 + * Fix pysha dependency - 0.8.8 * Skip rules filter processing for cache when deactivated * Add match-all flag to rule processing diff --git a/eth_monitor/cache.py b/eth_monitor/cache.py new file mode 100644 index 0000000..e6dbca4 --- /dev/null +++ b/eth_monitor/cache.py @@ -0,0 +1,33 @@ +# standard imports +import logging +from urllib.parse import urlparse + +logg = logging.getLogger(__name__) + + +def from_cache_spec(chain_spec, s): + o = urlparse(s) + path = '.' + scheme = None + if o.scheme == '': + scheme = 'file' + else: + scheme = o.scheme + + if o.path != '': + if o.path[0] != '/': + path = os.path.join(path, o.path) + else: + path = o.path + + logg.debug('parsed scheme {} from cache spec'.format(scheme)) + + if scheme == 'file': + from eth_cache.store.fs import FileStore + return FsStore(chain_spec, cache_root=path) + + if scheme == 'lmdb': + from eth_cache.store.lmdb import LmdbStore + return LmdbStore(chain_spec, cache_root=path) + + return None diff --git a/eth_monitor/cli/arg.py b/eth_monitor/cli/arg.py index 4a00ed9..ce47139 100644 --- a/eth_monitor/cli/arg.py +++ b/eth_monitor/cli/arg.py @@ -10,6 +10,7 @@ def process_args(argparser, args, flags): argparser.add_argument('--input', action='append', type=str, help='Add input (recipient) addresses to includes list') argparser.add_argument('--output', action='append', type=str, help='Add output (sender) addresses to includes list') argparser.add_argument('--exec', action='append', type=str, help='Add exec (contract) addresses to includes list') + argparser.add_argument('--txhash', action='append', type=str, help='Add tx hash part to includes list') argparser.add_argument('--data', action='append', type=str, help='Add data prefix strings to include list') argparser.add_argument('--data-in', action='append', dest='data_in', type=str, help='Add data contain strings to include list') argparser.add_argument('--x-data', action='append', dest='x_data', type=str, help='Add data prefix string to exclude list') @@ -18,6 +19,7 @@ def process_args(argparser, args, flags): argparser.add_argument('--x-input', action='append', type=str, dest='x_input', help='Add input (recipient) addresses to excludes list') argparser.add_argument('--x-output', action='append', type=str, dest='x_output', help='Add output (sender) addresses to excludes list') argparser.add_argument('--x-exec', action='append', type=str, dest='x_exec', help='Add exec (contract) addresses to excludes list') + argparser.add_argument('--x-txhash', action='append', type=str, help='Add tx hash part to excludes list') argparser.add_argument('--x-address', action='append', type=str, dest='x_address', help='Add addresses as input, output and exec to excludes list') argparser.add_argument('--includes-file', type=str, dest='includes_file', help='Load include rules from file') argparser.add_argument('--excludes-file', type=str, dest='excludes_file', help='Load exclude rules from file') diff --git a/eth_monitor/cli/config.py b/eth_monitor/cli/config.py index 458aff6..f65973f 100644 --- a/eth_monitor/cli/config.py +++ b/eth_monitor/cli/config.py @@ -2,13 +2,14 @@ from .rules import ( rules_address_args, rules_data_args, + rules_txhash_args, to_config_names, ) def process_config(config, arg, args, flags): arg_override = {} - rules_args = rules_address_args + rules_data_args + rules_args = rules_address_args + rules_data_args + rules_txhash_args for rules_arg in rules_args: (vy, vn) = to_config_names(rules_arg) diff --git a/eth_monitor/cli/rules.py b/eth_monitor/cli/rules.py index 74232f2..8276719 100644 --- a/eth_monitor/cli/rules.py +++ b/eth_monitor/cli/rules.py @@ -10,6 +10,10 @@ rules_data_args = [ 'data_in', ] +rules_txhash_args = [ + 'txhash', + ] + def to_config_names(v): v = v.upper() diff --git a/eth_monitor/data/config/monitor.ini b/eth_monitor/data/config/monitor.ini index e3d3fcc..5b365ec 100644 --- a/eth_monitor/data/config/monitor.ini +++ b/eth_monitor/data/config/monitor.ini @@ -11,6 +11,8 @@ data = x_data = data_in = x_data_in = +txhash = +x_txhash = includes_file = excludes_file = renderer = diff --git a/eth_monitor/rules.py b/eth_monitor/rules.py index b4dfaa8..ea19fe3 100644 --- a/eth_monitor/rules.py +++ b/eth_monitor/rules.py @@ -4,6 +4,9 @@ import uuid # external imports from chainlib.eth.address import is_same_address +from hexathon import same as same_hex + +# local imports from .error import RuleFail logg = logging.getLogger() @@ -150,6 +153,29 @@ class RuleSimple: ) +class RuleHash: + + def __init__(self, hashes, description=None): + self.hashes = hashes + self.description = description + if self.description == None: + self.description = str(uuid.uuid4()) + + + def check(self, sender, recipient, data, tx_hash): + for h in self.hashes: + if len(tx_hash) >= len(h): + if same_hex(tx_hash[:len(h)], h): + return True + return False + + + def __str__(self): + return 'Hash ' + self.description + ' hashes {}'.format( + self.hashes, + ) + + class AddressRules: def __init__(self, include_by_default=False, match_all=False): @@ -170,10 +196,10 @@ class AddressRules: def apply_rules(self, tx): - return self.apply_rules_addresses(tx.outputs[0], tx.inputs[0], tx.payload, tx.hash) + return self.apply_rules_detail(tx.outputs[0], tx.inputs[0], tx.payload, tx.hash) - def apply_rules_addresses(self, sender, recipient, data, tx_hash): + def apply_rules_detail(self, sender, recipient, data, tx_hash): v = self.include_by_default have_fail = False have_match = False diff --git a/eth_monitor/settings.py b/eth_monitor/settings.py index a5f42e8..3261110 100644 --- a/eth_monitor/settings.py +++ b/eth_monitor/settings.py @@ -22,6 +22,7 @@ from eth_monitor.rules import ( RuleSimple, RuleMethod, RuleData, + RuleHash, ) from eth_monitor.cli.rules import to_config_names from eth_monitor.callback import ( @@ -137,6 +138,10 @@ def process_address_arg_rules(settings, config): 'i': [], 'x': [], }, + 'hash': { + 'i': [], + 'x': [], + }, } for rules_arg in [ 'input', @@ -205,6 +210,25 @@ def process_data_arg_rules(settings, config): return settings +def process_tx_hash_rules(settings, config): + rules = settings.get('RULES') + + include_tx = [] + for v in config.get('ETHMONITOR_TXHASH'): + include_tx.append(v.lower()) + exclude_tx = [] + for v in config.get('ETHMONITOR_X_TXHASH'): + exclude_tx.append(v.lower()) + + includes = RuleHash(include_tx, description='INCLUDE') + rules.include(includes) + + excludes = RuleHash(exclude_tx, description='EXCLUDE') + rules.exclude(excludes) + + return settings + + def process_address_file_rules(settings, config): #rules, includes_file=None, excludes_file=None, include_default=False, include_block_default=False): rules = settings.get('RULES') includes_file = config.get('ETHMONITOR_INCLUDES_FILE') @@ -277,6 +301,7 @@ def process_arg_rules(settings, config): settings = process_address_arg_rules(settings, config) settings = process_data_arg_rules(settings, config) settings = process_address_file_rules(settings, config) + settings = process_tx_hash_rules(settings, config) return settings diff --git a/man/build/eth-monitor-sync.1 b/man/build/eth-monitor-sync.1 index a24b9fb..952a5ad 100644 --- a/man/build/eth-monitor-sync.1 +++ b/man/build/eth-monitor-sync.1 @@ -140,6 +140,11 @@ Store block data in cache for matching transactions. Requires \fB--cache-dir\fP. \fP\fP Store transaction data in cache for matching transactions. Requires \fB--cache-dir\fP. +.TP +\fB--txhash \fI\fIhash +\fP\fP +Add a tx hash of interest to match + .TP \fB-u\fP, \fB--unsafe\fP Allow addresses that do not pass checksum. @@ -172,6 +177,11 @@ Add an address of disinterest to inputs (recipients) array. \fP\fP Add an address of disinterest to outputs (sender) array. +.TP +\fB--x-txhash \fI\fIhash +\fP\fP +Add a tx hash of disinterest to match + .SH CONFIGURATION All configuration settings may be overriden both by environment variables, or by overriding settings with the contents of ini-files in the directory defined by the \fB-c\fP option. diff --git a/man/build/eth-monitor.1 b/man/build/eth-monitor.1 index a24b9fb..952a5ad 100644 --- a/man/build/eth-monitor.1 +++ b/man/build/eth-monitor.1 @@ -140,6 +140,11 @@ Store block data in cache for matching transactions. Requires \fB--cache-dir\fP. \fP\fP Store transaction data in cache for matching transactions. Requires \fB--cache-dir\fP. +.TP +\fB--txhash \fI\fIhash +\fP\fP +Add a tx hash of interest to match + .TP \fB-u\fP, \fB--unsafe\fP Allow addresses that do not pass checksum. @@ -172,6 +177,11 @@ Add an address of disinterest to inputs (recipients) array. \fP\fP Add an address of disinterest to outputs (sender) array. +.TP +\fB--x-txhash \fI\fIhash +\fP\fP +Add a tx hash of disinterest to match + .SH CONFIGURATION All configuration settings may be overriden both by environment variables, or by overriding settings with the contents of ini-files in the directory defined by the \fB-c\fP option. diff --git a/man/eth-monitor.overrides b/man/eth-monitor.overrides index 75a82f4..2276e5a 100644 --- a/man/eth-monitor.overrides +++ b/man/eth-monitor.overrides @@ -2,10 +2,12 @@ input Add an address of interest to inputs (recipients) array. Complements \fB-- output Add an address of interest to outputs (sender) array. Complements \fB--address-file\fP. --output address exec Add an address of interest to executable address array. Complements \fB--address-file\fP. --exec address address Add an address of interest to match any role. Complements \fB--address-file\fP. --address address +txhash Add a tx hash of interest to match --txhash hash xinput Add an address of disinterest to inputs (recipients) array. --x-input address xoutput Add an address of disinterest to outputs (sender) array. --x-output address xexec Add an address of disinterest to executable address array. --x-exec address xaddress Add an address of interest to match any role. --x-address address +xtxhash Add a tx hash of disinterest to match --x-txhash hash includedefault Match all addresses by default. Addresses may be excluded using --excludes-file. If this is set, --input, --output, --exec and --includes-file will have no effect. --include-default includesfile Load address include matching rules from file. See \fBMATCHING ADDRESSES\fP. --includes-file file excludesfile Load address exclude matching rules from file. See \fBMATCHING ADDRESSES\fP. --excludes-file file