From cd2fc78d5b8c88a017ef6b85bcf8aafbbdc27b2b Mon Sep 17 00:00:00 2001 From: nolash Date: Sun, 2 May 2021 12:12:04 +0200 Subject: [PATCH] Add faucet filter with tests --- .../runnable/daemons/filters/__init__.py | 1 + .../runnable/daemons/filters/faucet.py | 70 ++++++++++++++++++ .../cic_cache/runnable/daemons/tracker.py | 3 + apps/cic-cache/requirements.txt | 4 +- apps/cic-cache/tests/filters/test_erc20.py | 2 +- apps/cic-cache/tests/filters/test_faucet.py | 71 +++++++++++++++++++ 6 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 apps/cic-cache/cic_cache/runnable/daemons/filters/faucet.py create mode 100644 apps/cic-cache/tests/filters/test_faucet.py diff --git a/apps/cic-cache/cic_cache/runnable/daemons/filters/__init__.py b/apps/cic-cache/cic_cache/runnable/daemons/filters/__init__.py index e8c9c530..af3eac98 100644 --- a/apps/cic-cache/cic_cache/runnable/daemons/filters/__init__.py +++ b/apps/cic-cache/cic_cache/runnable/daemons/filters/__init__.py @@ -1 +1,2 @@ from .erc20 import * +from .faucet import * diff --git a/apps/cic-cache/cic_cache/runnable/daemons/filters/faucet.py b/apps/cic-cache/cic_cache/runnable/daemons/filters/faucet.py new file mode 100644 index 00000000..b4488e0e --- /dev/null +++ b/apps/cic-cache/cic_cache/runnable/daemons/filters/faucet.py @@ -0,0 +1,70 @@ +# standard imports +import logging + +# external imports +from erc20_faucet import Faucet +from chainlib.eth.address import to_checksum_address +from chainlib.eth.constant import ZERO_ADDRESS +from chainlib.status import Status +from hexathon import strip_0x + +# local imports +import cic_cache.db as cic_cache_db +from .base import TagSyncFilter + +#logg = logging.getLogger().getChild(__name__) +logg = logging.getLogger() + + +class FaucetFilter(TagSyncFilter): + + def __init__(self, chain_spec, sender_address=ZERO_ADDRESS): + super(FaucetFilter, self).__init__('give_to', domain='faucet') + self.chain_spec = chain_spec + self.sender_address = sender_address + + + def filter(self, conn, block, tx, db_session=None): + data = strip_0x(tx.payload) + logg.debug('data {}'.format(data)) + if Faucet.method_for(data[:8]) == None: + return False + + token_sender = tx.inputs[0] + token_recipient = data[64+8-40:] + logg.debug('token recipient {}'.format(token_recipient)) + + f = Faucet(self.chain_spec) + o = f.token(token_sender, sender_address=self.sender_address) + r = conn.do(o) + token = f.parse_token(r) + + f = Faucet(self.chain_spec) + o = f.token_amount(token_sender, sender_address=self.sender_address) + r = conn.do(o) + token_value = f.parse_token_amount(r) + + cic_cache_db.add_transaction( + db_session, + tx.hash, + block.number, + tx.index, + to_checksum_address(token_sender), + to_checksum_address(token_recipient), + token, + token, + token_value, + token_value, + tx.status == Status.SUCCESS, + block.timestamp, + ) + db_session.flush() + cic_cache_db.tag_transaction( + db_session, + tx.hash, + self.tag_name, + domain=self.tag_domain, + ) + db_session.commit() + + return True diff --git a/apps/cic-cache/cic_cache/runnable/daemons/tracker.py b/apps/cic-cache/cic_cache/runnable/daemons/tracker.py index ceac150b..785c8479 100644 --- a/apps/cic-cache/cic_cache/runnable/daemons/tracker.py +++ b/apps/cic-cache/cic_cache/runnable/daemons/tracker.py @@ -41,6 +41,7 @@ from cic_cache.db import ( ) from cic_cache.runnable.daemons.filters import ( ERC20TransferFilter, + FaucetFilter, ) script_dir = os.path.realpath(os.path.dirname(__file__)) @@ -112,9 +113,11 @@ def main(): logg.info('using trusted address {}'.format(address)) erc20_transfer_filter = ERC20TransferFilter(chain_spec) + faucet_filter = FaucetFilter(chain_spec) filters = [ erc20_transfer_filter, + faucet_filter, ] session = SessionBase.create_session() diff --git a/apps/cic-cache/requirements.txt b/apps/cic-cache/requirements.txt index 82eb421a..0d0b55d0 100644 --- a/apps/cic-cache/requirements.txt +++ b/apps/cic-cache/requirements.txt @@ -1,9 +1,9 @@ -cic-base~=0.1.2b6 +cic-base~=0.1.2b7 alembic==1.4.2 confini~=0.3.6rc3 uwsgi==2.0.19.1 moolb~=0.1.0 -cic-eth-registry~=0.5.5a1 +cic-eth-registry~=0.5.5a4 SQLAlchemy==1.3.20 semver==2.13.0 psycopg2==2.8.6 diff --git a/apps/cic-cache/tests/filters/test_erc20.py b/apps/cic-cache/tests/filters/test_erc20.py index d7582ed1..fb44e29a 100644 --- a/apps/cic-cache/tests/filters/test_erc20.py +++ b/apps/cic-cache/tests/filters/test_erc20.py @@ -22,7 +22,7 @@ from cic_cache.runnable.daemons.filters.erc20 import ERC20TransferFilter logg = logging.getLogger() -def test_cache( +def test_erc20_filter( eth_rpc, foo_token, init_database, diff --git a/apps/cic-cache/tests/filters/test_faucet.py b/apps/cic-cache/tests/filters/test_faucet.py new file mode 100644 index 00000000..c1f0dc10 --- /dev/null +++ b/apps/cic-cache/tests/filters/test_faucet.py @@ -0,0 +1,71 @@ +# standard imports +import logging + +# external imports +from chainlib.chain import ChainSpec +from chainlib.eth.nonce import RPCNonceOracle +from chainlib.eth.block import ( + block_by_hash, + Block, + ) +from chainlib.eth.tx import ( + receipt, + unpack, + transaction, + Tx, + ) +from hexathon import strip_0x +from erc20_faucet.faucet import SingleShotFaucet +from sqlalchemy import text + +# local imports +from cic_cache.db import add_tag +from cic_cache.runnable.daemons.filters.faucet import FaucetFilter + +logg = logging.getLogger() + + +def test_filter_faucet( + eth_rpc, + eth_signer, + foo_token, + faucet_noregistry, + init_database, + list_defaults, + contract_roles, + agent_roles, + tags, + ): + + chain_spec = ChainSpec('foo', 'bar', 42, 'baz') + + fltr = FaucetFilter(chain_spec, contract_roles['CONTRACT_DEPLOYER']) + + add_tag(init_database, fltr.tag_name, domain=fltr.tag_domain) + + nonce_oracle = RPCNonceOracle(agent_roles['ALICE'], eth_rpc) + c = SingleShotFaucet(chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = c.give_to(faucet_noregistry, agent_roles['ALICE'], agent_roles['ALICE']) + r = eth_rpc.do(o) + + tx_src = unpack(bytes.fromhex(strip_0x(o['params'][0])), chain_spec) + + o = receipt(r) + r = eth_rpc.do(o) + rcpt = Tx.src_normalize(r) + + assert r['status'] == 1 + + o = block_by_hash(r['block_hash']) + r = eth_rpc.do(o) + block_object = Block(r) + + tx = Tx(tx_src, block_object) + tx.apply_receipt(rcpt) + + r = fltr.filter(eth_rpc, block_object, tx, init_database) + assert r + + s = text("SELECT x.tx_hash FROM tag a INNER JOIN tag_tx_link l ON l.tag_id = a.id INNER JOIN tx x ON x.id = l.tx_id WHERE a.domain = :a AND a.value = :b") + r = init_database.execute(s, {'a': fltr.tag_domain, 'b': fltr.tag_name}).fetchone() + assert r[0] == tx.hash