taint

Crypto forensics for private use
git clone git://git.defalsify.org/taint.git
Log | Files | Refs | LICENSE

commit 59aea60d87769e5c6a5495b1feb55dfb6ac62e7c
parent 15b4aa9c5af40c50f9aa71878362a17d1325f0dd
Author: nolash <dev@holbrook.no>
Date:   Fri, 16 Apr 2021 16:05:17 +0200

Add tag pool results backend, move filter to interface wrapper

Diffstat:
Mtaint/account.py | 8++++++++
Mtaint/cache.py | 29+++--------------------------
Ataint/result.py | 21+++++++++++++++++++++
Mtaint/tag.py | 22+++++++++++++++++++++-
Ataint/taint.py | 36++++++++++++++++++++++++++++++++++++
Mtests/eth/test_syncer.py | 18++++++++++++------
Mtests/test_cache.py | 14+++++++-------
7 files changed, 108 insertions(+), 40 deletions(-)

diff --git a/taint/account.py b/taint/account.py @@ -25,6 +25,14 @@ class Account(Salter): self.tags.create(tag) + def tag(self, value): + self.tags.create(value) + + + def sum(self): + return self.tags.get() + + def connect(self, account): if not isinstance(account, Account): raise TypeError('account must be type crypto_account_cache.account.Account') diff --git a/taint/cache.py b/taint/cache.py @@ -4,11 +4,9 @@ import logging # external imports from moolb import Bloom -from hexathon import strip_0x # local imports from .name import for_label -from .store import FileStore from .crypto import Salter from .account import Account @@ -129,10 +127,9 @@ class CacheBloom: class Cache(Salter): - def __init__(self, chain_spec, bits_size, store=None, cache_bloom=None): + def __init__(self, chain_spec, bits_size, cache_bloom=None): super(Cache, self).__init__(chain_spec) self.bits_size = bits_size - self.store = store self.chain_spec = chain_spec if cache_bloom == None: @@ -172,12 +169,6 @@ class Cache(Salter): return c - def set_store(self, store): - self.store = store - if not store.initd and self.cache_bloom: - self.store.save(self.cache_bloom.serialize()) - - def divide(self, accounts): subjects = [] objects = [] @@ -214,7 +205,7 @@ class Cache(Salter): match = self.cache_bloom.register(accounts, block_height, tx_index) if not match: - return False + return None if self.first_block_height == -1: self.first_block_height = block_height @@ -234,22 +225,8 @@ class Cache(Salter): continue subject.connect(other_subject) - return True + return (subjects, objects) def have(self, block_height, tx_index): return self.cache_bloom.have_index(block_height, tx_index) - - - def filter(self, conn, block, tx, storer): - for output in tx.outputs: - for inpt in tx.inputs: - sender = bytes.fromhex(strip_0x(output)) - recipient = bytes.fromhex(strip_0x(inpt)) - print('tx {} '.format(tx.index)) - self.add_tx( - self.sprinkle(sender), - self.sprinkle(recipient), - block.number, - tx.index, - ) diff --git a/taint/result.py b/taint/result.py @@ -0,0 +1,21 @@ +# standard imports +import logging + +logg = logging.getLogger().getChild(__name__) + + +class Result: + + def __init__(self): + self.handler = [] + + + def add_handler(self, result_handler): + self.handlers.append(result_handler) + logg.debug('added handler {}'.format(str(result_handler))) + + + def register(self, account): + for h in self.handlers: + r = h(account) + logg.debug('processed handler {} -> {}'.format(str(h), r)) diff --git a/taint/tag.py b/taint/tag.py @@ -5,6 +5,26 @@ import logging logg = logging.getLogger().getChild(__name__) + +class TagPool: + + def __init__(self): + self.pool = {} + + + def register(self, account): + z = account.sum() + if self.pool.get(z) == None: + self.pool[z] = [] + + self.pool[z].append(account) + + logg.debug('pool register account {} to tag sum {}'.format(account, z.hex())) + + + return True + + class Tag: def __init__(self): @@ -43,7 +63,7 @@ class Tag: def merge(self, tags): if not isinstance(tags, Tag): - raise TypeError('tags must be type crypto_account_type.tag.Tag') + raise TypeError('tags must be type taint.tag.Tag') for tag in tags.tags: self.add(tag) self.tag_values[tag] = tags.tag_values[tag] diff --git a/taint/taint.py b/taint/taint.py @@ -0,0 +1,36 @@ +# external imports +from hexathon import strip_0x + +# local imports +from .cache import Cache + + +class Tainter(Cache): + + def __init__(self, chain_spec, bits_size, result_handler=None, store_handler=None, cache_bloom=None): + super(Tainter, self).__init__(chain_spec, bits_size, cache_bloom=cache_bloom) + self.store_handler = store_handler + self.result_handler = result_handler + + + def set_store(self, store): + self.store = store + if not store.initd and self.cache_bloom: + self.store.save(self.cache_bloom.serialize()) + + + def filter(self, conn, block, tx, storer): + for output in tx.outputs: + for inpt in tx.inputs: + sender = bytes.fromhex(strip_0x(output)) + recipient = bytes.fromhex(strip_0x(inpt)) + (subjects, objects) = self.add_tx( + self.sprinkle(sender), + self.sprinkle(recipient), + block.number, + tx.index, + ) + + if self.result_handler != None: + for account in subjects: + self.result_handler.register(account) diff --git a/tests/eth/test_syncer.py b/tests/eth/test_syncer.py @@ -13,8 +13,9 @@ from chainsyncer.backend.memory import MemBackend from hexathon import strip_0x # local imports -from taint.cache import Cache +from taint.taint import Tainter from taint.account import Account +from taint.tag import TagPool class TestSyncer(EthTesterCase): @@ -26,12 +27,17 @@ class TestSyncer(EthTesterCase): self.alice_account = bytes.fromhex(strip_0x(self.accounts[0])) self.alice = Account(self.chain_spec, self.alice_account, label='alice') + self.alice.tag(b'foo') + self.alice.tag(b'bar') + self.filter_bits_size = 1024 - self.cache = Cache(self.chain_spec, self.filter_bits_size) - self.cache.add_subject(self.alice) + self.result_handler = TagPool() + self.frontend = Tainter(self.chain_spec, self.filter_bits_size, result_handler=self.result_handler) + self.frontend.add_subject(self.alice) + - self.syncer.add_filter(self.cache) + self.syncer.add_filter(self.frontend) def test_sync_single(self): @@ -43,11 +49,11 @@ class TestSyncer(EthTesterCase): self.rpc.do(o) self.backend.mine_blocks(3) - self.assertFalse(self.cache.have(4, 0)) + self.assertFalse(self.frontend.have(4, 0)) self.syncer.loop(0.001, self.rpc) - self.assertTrue(self.cache.have(4, 0)) + self.assertTrue(self.frontend.have(4, 0)) if __name__ == '__main__': diff --git a/tests/test_cache.py b/tests/test_cache.py @@ -73,7 +73,7 @@ class TestBasic(TestBase): self.assertNotEqual(self.alice.tags.get(), self.bob.tags.get()) match = cache.add_tx(self.alice.account, self.bob.account, block_height, tx_index) - self.assertTrue(match) + self.assertNotEqual(match, None) self.assertEqual(self.alice.tags.get(), self.bob.tags.get()) @@ -87,11 +87,11 @@ class TestBasic(TestBase): first_block_height = 42 first_tx_index = 13 - match = cache.add_tx(self.alice.account, self.bob.account, first_block_height, first_tx_index) + cache.add_tx(self.alice.account, self.bob.account, first_block_height, first_tx_index) new_block_height = 666 new_tx_index = 1337 - match = cache.add_tx(self.alice.account, self.eve.account, new_block_height, new_tx_index) + cache.add_tx(self.alice.account, self.eve.account, new_block_height, new_tx_index) cache.first_block_height == first_block_height cache.first_tx_index == first_tx_index @@ -108,11 +108,11 @@ class TestBasic(TestBase): first_block_height = 42 first_tx_index = 13 - match = cache.add_tx(self.alice.account, self.bob.account, first_block_height, first_tx_index) + cache.add_tx(self.alice.account, self.bob.account, first_block_height, first_tx_index) new_block_height = 666 new_tx_index = 1337 - match = cache.add_tx(self.alice.account, self.eve.account, new_block_height, new_tx_index) + cache.add_tx(self.alice.account, self.eve.account, new_block_height, new_tx_index) self.assertTrue(cache.have(first_block_height, first_tx_index)) self.assertTrue(cache.have(new_block_height, new_tx_index)) @@ -131,11 +131,11 @@ class TestBasic(TestBase): first_block_height = 42 first_tx_index = 13 - match = cache.add_tx(self.alice.account, self.bob.account, first_block_height, first_tx_index) + cache.add_tx(self.alice.account, self.bob.account, first_block_height, first_tx_index) new_block_height = 666 new_tx_index = 1337 - match = cache.add_tx(self.alice.account, self.eve.account, new_block_height, new_tx_index) + cache.add_tx(self.alice.account, self.eve.account, new_block_height, new_tx_index) b = cache.serialize() cache_recovered = cache.from_serialized(self.chain_spec, b)