Philip/fix filter callbacks

This commit is contained in:
Philip Wafula 2021-04-16 20:24:07 +00:00
parent 01454c9ac0
commit f410e8b7e3
20 changed files with 388 additions and 130 deletions

View File

@ -17,7 +17,7 @@ RUN apt-get update && \
# Copy shared requirements from top of mono-repo # Copy shared requirements from top of mono-repo
RUN echo "copying root req file ${root_requirement_file}" RUN echo "copying root req file ${root_requirement_file}"
RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2a58 RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2a76
COPY cic-cache/requirements.txt ./ COPY cic-cache/requirements.txt ./
COPY cic-cache/setup.cfg \ COPY cic-cache/setup.cfg \

View File

@ -1,6 +1,10 @@
# extended imports # external imports
from chainlib.eth.constant import ZERO_ADDRESS from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.status import Status as TxStatus from chainlib.status import Status as TxStatus
from cic_eth_registry.erc20 import ERC20Token
# local imports
from cic_eth.ext.address import translate_address
class ExtendedTx: class ExtendedTx:
@ -27,12 +31,12 @@ class ExtendedTx:
self.status_code = TxStatus.PENDING.value self.status_code = TxStatus.PENDING.value
def set_actors(self, sender, recipient, trusted_declarator_addresses=None): def set_actors(self, sender, recipient, trusted_declarator_addresses=None, caller_address=ZERO_ADDRESS):
self.sender = sender self.sender = sender
self.recipient = recipient self.recipient = recipient
if trusted_declarator_addresses != None: if trusted_declarator_addresses != None:
self.sender_label = translate_address(sender, trusted_declarator_addresses, self.chain_spec) self.sender_label = translate_address(sender, trusted_declarator_addresses, self.chain_spec, sender_address=caller_address)
self.recipient_label = translate_address(recipient, trusted_declarator_addresses, self.chain_spec) self.recipient_label = translate_address(recipient, trusted_declarator_addresses, self.chain_spec, sender_address=caller_address)
def set_tokens(self, source, source_value, destination=None, destination_value=None): def set_tokens(self, source, source_value, destination=None, destination_value=None):
@ -40,8 +44,8 @@ class ExtendedTx:
destination = source destination = source
if destination_value == None: if destination_value == None:
destination_value = source_value destination_value = source_value
st = ERC20Token(self.rpc, source) st = ERC20Token(self.chain_spec, self.rpc, source)
dt = ERC20Token(self.rpc, destination) dt = ERC20Token(self.chain_spec, self.rpc, destination)
self.source_token = source self.source_token = source
self.source_token_symbol = st.symbol self.source_token_symbol = st.symbol
self.source_token_name = st.name self.source_token_name = st.name
@ -62,10 +66,10 @@ class ExtendedTx:
self.status_code = n self.status_code = n
def to_dict(self): def asdict(self):
o = {} o = {}
for attr in dir(self): for attr in dir(self):
if attr[0] == '_' or attr in ['set_actors', 'set_tokens', 'set_status', 'to_dict']: if attr[0] == '_' or attr in ['set_actors', 'set_tokens', 'set_status', 'asdict', 'rpc']:
continue continue
o[attr] = getattr(self, attr) o[attr] = getattr(self, attr)
return o return o

View File

@ -1,7 +1,7 @@
# standard imports # standard imports
import logging import logging
# third-party imports # external imports
import celery import celery
from cic_eth_registry.error import UnknownContractError from cic_eth_registry.error import UnknownContractError
from chainlib.status import Status as TxStatus from chainlib.status import Status as TxStatus
@ -9,7 +9,13 @@ from chainlib.eth.address import to_checksum_address
from chainlib.eth.error import RequestMismatchException from chainlib.eth.error import RequestMismatchException
from chainlib.eth.constant import ZERO_ADDRESS from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.eth.erc20 import ERC20 from chainlib.eth.erc20 import ERC20
from hexathon import strip_0x from hexathon import (
strip_0x,
add_0x,
)
# TODO: use sarafu_Faucet for both when inheritance has been implemented
from erc20_single_shot_faucet import SingleShotFaucet
from sarafu_faucet import MinterFaucet as Faucet
# local imports # local imports
from .base import SyncFilter from .base import SyncFilter
@ -18,65 +24,73 @@ from cic_eth.eth.meta import ExtendedTx
logg = logging.getLogger().getChild(__name__) logg = logging.getLogger().getChild(__name__)
def parse_transfer(tx):
r = ERC20.parse_transfer_request(tx.payload)
transfer_data = {}
transfer_data['to'] = r[0]
transfer_data['value'] = r[1]
transfer_data['from'] = tx['from']
transfer_data['token_address'] = tx['to']
return ('transfer', transfer_data)
def parse_transferfrom(tx):
r = ERC20.parse_transfer_request(tx.payload)
transfer_data = unpack_transferfrom(tx.payload)
transfer_data['from'] = r[0]
transfer_data['to'] = r[1]
transfer_data['value'] = r[2]
transfer_data['token_address'] = tx['to']
return ('transferfrom', transfer_data)
def parse_giftto(tx):
# TODO: broken
logg.error('broken')
return
transfer_data = unpack_gift(tx.payload)
transfer_data['from'] = tx.inputs[0]
transfer_data['value'] = 0
transfer_data['token_address'] = ZERO_ADDRESS
# TODO: would be better to query the gift amount from the block state
for l in tx.logs:
topics = l['topics']
logg.debug('topixx {}'.format(topics))
if strip_0x(topics[0]) == '45c201a59ac545000ead84f30b2db67da23353aa1d58ac522c48505412143ffa':
#transfer_data['value'] = web3.Web3.toInt(hexstr=strip_0x(l['data']))
transfer_data['value'] = int.from_bytes(bytes.fromhex(strip_0x(l_data)))
#token_address_bytes = topics[2][32-20:]
token_address = strip_0x(topics[2])[64-40:]
transfer_data['token_address'] = to_checksum_address(token_address)
return ('tokengift', transfer_data)
class CallbackFilter(SyncFilter): class CallbackFilter(SyncFilter):
trusted_addresses = [] trusted_addresses = []
def __init__(self, chain_spec, method, queue): def __init__(self, chain_spec, method, queue, caller_address=ZERO_ADDRESS):
self.queue = queue self.queue = queue
self.method = method self.method = method
self.chain_spec = chain_spec self.chain_spec = chain_spec
self.caller_address = caller_address
def parse_transfer(self, tx, conn):
if not tx.payload:
return (None, None)
r = ERC20.parse_transfer_request(tx.payload)
transfer_data = {}
transfer_data['to'] = r[0]
transfer_data['value'] = r[1]
transfer_data['from'] = tx.outputs[0]
transfer_data['token_address'] = tx.inputs[0]
return ('transfer', transfer_data)
def parse_transferfrom(self, tx, conn):
if not tx.payload:
return (None, None)
r = ERC20.parse_transfer_from_request(tx.payload)
transfer_data = {}
transfer_data['from'] = r[0]
transfer_data['to'] = r[1]
transfer_data['value'] = r[2]
transfer_data['token_address'] = tx.inputs[0]
return ('transferfrom', transfer_data)
def parse_giftto(self, tx, conn):
if not tx.payload:
return (None, None)
r = Faucet.parse_give_to_request(tx.payload)
transfer_data = {}
transfer_data['to'] = r[0]
transfer_data['value'] = tx.value
transfer_data['from'] = tx.outputs[0]
#transfer_data['token_address'] = tx.inputs[0]
faucet_contract = tx.inputs[0]
c = SingleShotFaucet(self.chain_spec)
o = c.token(faucet_contract, sender_address=self.caller_address)
r = conn.do(o)
transfer_data['token_address'] = add_0x(c.parse_token(r))
o = c.amount(faucet_contract, sender_address=self.caller_address)
r = conn.do(o)
transfer_data['value'] = c.parse_amount(r)
return ('tokengift', transfer_data)
def call_back(self, transfer_type, result): def call_back(self, transfer_type, result):
logg.debug('result {}'.format(result)) result['chain_spec'] = result['chain_spec'].asdict()
s = celery.signature( s = celery.signature(
self.method, self.method,
[ [
result, result,
transfer_type, transfer_type,
int(result['status_code'] == 0), int(result['status_code'] != 0),
], ],
queue=self.queue, queue=self.queue,
) )
@ -92,26 +106,29 @@ class CallbackFilter(SyncFilter):
# s_translate.link(s) # s_translate.link(s)
# s_translate.apply_async() # s_translate.apply_async()
t = s.apply_async() t = s.apply_async()
return s return t
def parse_data(self, tx): def parse_data(self, tx, conn):
transfer_type = None transfer_type = None
transfer_data = None transfer_data = None
# TODO: what's with the mix of attributes and dict keys # TODO: what's with the mix of attributes and dict keys
logg.debug('have payload {}'.format(tx.payload)) logg.debug('have payload {}'.format(tx.payload))
method_signature = tx.payload[:8]
logg.debug('tx status {}'.format(tx.status)) logg.debug('tx status {}'.format(tx.status))
for parser in [ for parser in [
parse_transfer, self.parse_transfer,
parse_transferfrom, self.parse_transferfrom,
parse_giftto, self.parse_giftto,
]: ]:
try: try:
(transfer_type, transfer_data) = parser(tx) if tx:
break (transfer_type, transfer_data) = parser(tx, conn)
if transfer_type == None:
continue
else:
pass
except RequestMismatchException: except RequestMismatchException:
continue continue
@ -128,7 +145,7 @@ class CallbackFilter(SyncFilter):
transfer_data = None transfer_data = None
transfer_type = None transfer_type = None
try: try:
(transfer_type, transfer_data) = self.parse_data(tx) (transfer_type, transfer_data) = self.parse_data(tx, conn)
except TypeError: except TypeError:
logg.debug('invalid method data length for tx {}'.format(tx.hash)) logg.debug('invalid method data length for tx {}'.format(tx.hash))
return return
@ -144,16 +161,17 @@ class CallbackFilter(SyncFilter):
result = None result = None
try: try:
tokentx = ExtendedTx(conn, tx.hash, self.chain_spec) tokentx = ExtendedTx(conn, tx.hash, self.chain_spec)
tokentx.set_actors(transfer_data['from'], transfer_data['to'], self.trusted_addresses) tokentx.set_actors(transfer_data['from'], transfer_data['to'], self.trusted_addresses, caller_address=self.caller_address)
tokentx.set_tokens(transfer_data['token_address'], transfer_data['value']) tokentx.set_tokens(transfer_data['token_address'], transfer_data['value'])
if transfer_data['status'] == 0: if transfer_data['status'] == 0:
tokentx.set_status(1) tokentx.set_status(1)
else: else:
tokentx.set_status(0) tokentx.set_status(0)
t = self.call_back(transfer_type, tokentx.to_dict()) result = tokentx.asdict()
logg.info('callback success task id {} tx {}'.format(t, tx.hash)) t = self.call_back(transfer_type, result)
logg.info('callback success task id {} tx {} queue {}'.format(t, tx.hash, t.queue))
except UnknownContractError: except UnknownContractError:
logg.debug('callback filter {}:{} skipping "transfer" method on unknown contract {} tx {}'.format(tc.queue, tc.method, transfer_data['to'], tx.hash)) logg.debug('callback filter {}:{} skipping "transfer" method on unknown contract {} tx {}'.format(tx.queue, tx.method, transfer_data['to'], tx.hash))
def __str__(self): def __str__(self):

View File

@ -39,6 +39,7 @@ from cic_eth.queue import (
from cic_eth.callbacks import ( from cic_eth.callbacks import (
Callback, Callback,
http, http,
noop,
#tcp, #tcp,
redis, redis,
) )

View File

@ -15,7 +15,6 @@ import cic_base.config
import cic_base.log import cic_base.log
import cic_base.argparse import cic_base.argparse
import cic_base.rpc import cic_base.rpc
from cic_eth_registry import CICRegistry
from cic_eth_registry.error import UnknownContractError from cic_eth_registry.error import UnknownContractError
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from chainlib.eth.constant import ZERO_ADDRESS from chainlib.eth.constant import ZERO_ADDRESS
@ -43,6 +42,12 @@ from cic_eth.runnable.daemons.filters import (
TransferAuthFilter, TransferAuthFilter,
) )
from cic_eth.stat import init_chain_stat from cic_eth.stat import init_chain_stat
from cic_eth.registry import (
connect as connect_registry,
connect_declarator,
connect_token_registry,
)
script_dir = os.path.realpath(os.path.dirname(__file__)) script_dir = os.path.realpath(os.path.dirname(__file__))
@ -109,6 +114,8 @@ def main():
logg.info('Initializing HEAD syncer on backend {}'.format(syncer_backend)) logg.info('Initializing HEAD syncer on backend {}'.format(syncer_backend))
syncers.append(HeadSyncer(syncer_backend)) syncers.append(HeadSyncer(syncer_backend))
connect_registry(rpc, chain_spec, config.get('CIC_REGISTRY_ADDRESS'))
trusted_addresses_src = config.get('CIC_TRUST_ADDRESS') trusted_addresses_src = config.get('CIC_TRUST_ADDRESS')
if trusted_addresses_src == None: if trusted_addresses_src == None:
logg.critical('At least one trusted address must be declared in CIC_TRUST_ADDRESS') logg.critical('At least one trusted address must be declared in CIC_TRUST_ADDRESS')
@ -116,6 +123,8 @@ def main():
trusted_addresses = trusted_addresses_src.split(',') trusted_addresses = trusted_addresses_src.split(',')
for address in trusted_addresses: for address in trusted_addresses:
logg.info('using trusted address {}'.format(address)) logg.info('using trusted address {}'.format(address))
connect_declarator(rpc, chain_spec, trusted_addresses)
connect_token_registry(rpc, chain_spec)
CallbackFilter.trusted_addresses = trusted_addresses CallbackFilter.trusted_addresses = trusted_addresses
callback_filters = [] callback_filters = []

View File

@ -10,7 +10,7 @@ version = (
0, 0,
11, 11,
0, 0,
'beta.3', 'beta.6',
) )
version_object = semver.VersionInfo( version_object = semver.VersionInfo(

View File

@ -29,8 +29,7 @@ RUN /usr/local/bin/python -m pip install --upgrade pip
# python merge_requirements.py | tee merged_requirements.txt # python merge_requirements.py | tee merged_requirements.txt
#RUN cd cic-base && \ #RUN cd cic-base && \
# pip install $pip_extra_index_url_flag -r ./merged_requirements.txt # pip install $pip_extra_index_url_flag -r ./merged_requirements.txt
RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2a76 RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2a77
RUN pip install $pip_extra_index_url_flag chainsyncer~=0.0.2a2
COPY cic-eth/scripts/ scripts/ COPY cic-eth/scripts/ scripts/
COPY cic-eth/setup.cfg cic-eth/setup.py ./ COPY cic-eth/setup.cfg cic-eth/setup.py ./

View File

@ -1,25 +1,25 @@
cic-base~=0.1.2a67 cic-base~=0.1.2a76
celery==4.4.7 celery==4.4.7
crypto-dev-signer~=0.4.14a17 crypto-dev-signer~=0.4.14b2
confini~=0.3.6rc3 confini~=0.3.6rc3
cic-eth-registry~=0.5.4a13 cic-eth-registry~=0.5.4a16
#cic-bancor~=0.0.6 #cic-bancor~=0.0.6
redis==3.5.3 redis==3.5.3
alembic==1.4.2 alembic==1.4.2
websockets==8.1 websockets==8.1
requests~=2.24.0 requests~=2.24.0
eth_accounts_index~=0.0.11a7 eth_accounts_index~=0.0.11a9
erc20-transfer-authorization~=0.3.1a3 erc20-transfer-authorization~=0.3.1a5
#simple-rlp==0.1.2
uWSGI==2.0.19.1 uWSGI==2.0.19.1
semver==2.13.0 semver==2.13.0
websocket-client==0.57.0 websocket-client==0.57.0
moolb~=0.1.1b2 moolb~=0.1.1b2
eth-address-index~=0.1.1a7 eth-address-index~=0.1.1a9
chainlib~=0.0.2a5 chainlib~=0.0.2a13
hexathon~=0.0.1a7 hexathon~=0.0.1a7
chainsyncer[sql]~=0.0.2a2 chainsyncer[sql]~=0.0.2a2
chainqueue~=0.0.1a7 chainqueue~=0.0.1a7
pysha3==1.0.2 pysha3==1.0.2
coincurve==15.0.0 coincurve==15.0.0
sarafu-faucet~=0.0.2a19 sarafu-faucet==0.0.2a28
potaahto~=0.0.1a1

View File

@ -4,4 +4,4 @@ pytest-mock==3.3.1
pytest-cov==2.10.1 pytest-cov==2.10.1
eth-tester==0.5.0b3 eth-tester==0.5.0b3
py-evm==0.3.0a20 py-evm==0.3.0a20
giftable-erc20-token==0.0.8a4 giftable-erc20-token==0.0.8a9

View File

@ -0,0 +1,223 @@
# standard import
import logging
import datetime
import os
# external imports
import pytest
from chainlib.connection import RPCConnection
from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.gas import OverrideGasOracle
from chainlib.eth.tx import (
receipt,
transaction,
Tx,
)
from chainlib.eth.block import Block
from chainlib.eth.erc20 import ERC20
from sarafu_faucet import MinterFaucet
from eth_accounts_index import AccountRegistry
from potaahto.symbols import snake_and_camel
from hexathon import add_0x
# local imports
from cic_eth.runnable.daemons.filters.callback import CallbackFilter
logg = logging.getLogger()
@pytest.mark.skip()
def test_transfer_tx(
default_chain_spec,
init_database,
eth_rpc,
eth_signer,
foo_token,
agent_roles,
token_roles,
contract_roles,
celery_session_worker,
):
rpc = RPCConnection.connect(default_chain_spec, 'default')
nonce_oracle = RPCNonceOracle(token_roles['FOO_TOKEN_OWNER'], rpc)
gas_oracle = OverrideGasOracle(conn=rpc, limit=200000)
txf = ERC20(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, o) = txf.transfer(foo_token, token_roles['FOO_TOKEN_OWNER'], agent_roles['ALICE'], 1024)
r = rpc.do(o)
o = transaction(tx_hash_hex)
r = rpc.do(o)
logg.debug(r)
tx_src = snake_and_camel(r)
tx = Tx(tx_src)
o = receipt(tx_hash_hex)
r = rpc.do(o)
assert r['status'] == 1
rcpt = snake_and_camel(r)
tx.apply_receipt(rcpt)
fltr = CallbackFilter(default_chain_spec, None, None, caller_address=contract_roles['CONTRACT_DEPLOYER'])
(transfer_type, transfer_data) = fltr.parse_transfer(tx, eth_rpc)
assert transfer_type == 'transfer'
@pytest.mark.skip()
def test_transfer_from_tx(
default_chain_spec,
init_database,
eth_rpc,
eth_signer,
foo_token,
agent_roles,
token_roles,
contract_roles,
celery_session_worker,
):
rpc = RPCConnection.connect(default_chain_spec, 'default')
nonce_oracle = RPCNonceOracle(token_roles['FOO_TOKEN_OWNER'], rpc)
gas_oracle = OverrideGasOracle(conn=rpc, limit=200000)
txf = ERC20(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, o) = txf.approve(foo_token, token_roles['FOO_TOKEN_OWNER'], agent_roles['ALICE'], 1024)
r = rpc.do(o)
o = receipt(tx_hash_hex)
r = rpc.do(o)
assert r['status'] == 1
nonce_oracle = RPCNonceOracle(agent_roles['ALICE'], rpc)
txf = ERC20(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, o) = txf.transfer_from(foo_token, agent_roles['ALICE'], token_roles['FOO_TOKEN_OWNER'], agent_roles['BOB'], 1024)
r = rpc.do(o)
o = transaction(tx_hash_hex)
r = rpc.do(o)
tx_src = snake_and_camel(r)
tx = Tx(tx_src)
o = receipt(tx_hash_hex)
r = rpc.do(o)
assert r['status'] == 1
rcpt = snake_and_camel(r)
tx.apply_receipt(rcpt)
fltr = CallbackFilter(default_chain_spec, None, None, caller_address=contract_roles['CONTRACT_DEPLOYER'])
(transfer_type, transfer_data) = fltr.parse_transferfrom(tx, eth_rpc)
assert transfer_type == 'transferfrom'
def test_faucet_gift_to_tx(
default_chain_spec,
init_database,
eth_rpc,
eth_signer,
foo_token,
agent_roles,
contract_roles,
faucet,
account_registry,
celery_session_worker,
):
rpc = RPCConnection.connect(default_chain_spec, 'default')
gas_oracle = OverrideGasOracle(conn=rpc, limit=800000)
nonce_oracle = RPCNonceOracle(contract_roles['ACCOUNT_REGISTRY_WRITER'], rpc)
txf = AccountRegistry(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, o) = txf.add(account_registry, contract_roles['ACCOUNT_REGISTRY_WRITER'], agent_roles['ALICE'])
r = rpc.do(o)
o = receipt(tx_hash_hex)
r = rpc.do(o)
assert r['status'] == 1
nonce_oracle = RPCNonceOracle(agent_roles['ALICE'], rpc)
txf = MinterFaucet(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, o) = txf.give_to(faucet, agent_roles['ALICE'], agent_roles['ALICE'])
r = rpc.do(o)
o = transaction(tx_hash_hex)
r = rpc.do(o)
tx_src = snake_and_camel(r)
tx = Tx(tx_src)
o = receipt(tx_hash_hex)
r = rpc.do(o)
assert r['status'] == 1
rcpt = snake_and_camel(r)
tx.apply_receipt(rcpt)
fltr = CallbackFilter(default_chain_spec, None, None, caller_address=contract_roles['CONTRACT_DEPLOYER'])
(transfer_type, transfer_data) = fltr.parse_giftto(tx, eth_rpc)
assert transfer_type == 'tokengift'
assert transfer_data['token_address'] == foo_token
def test_callback_filter(
default_chain_spec,
init_database,
eth_rpc,
eth_signer,
foo_token,
token_roles,
agent_roles,
contract_roles,
register_lookups,
):
rpc = RPCConnection.connect(default_chain_spec, 'default')
nonce_oracle = RPCNonceOracle(token_roles['FOO_TOKEN_OWNER'], rpc)
gas_oracle = OverrideGasOracle(conn=rpc, limit=200000)
txf = ERC20(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, o) = txf.transfer(foo_token, token_roles['FOO_TOKEN_OWNER'], agent_roles['ALICE'], 1024)
r = rpc.do(o)
o = transaction(tx_hash_hex)
r = rpc.do(o)
logg.debug(r)
mockblock_src = {
'hash': add_0x(os.urandom(32).hex()),
'number': '0x2a',
'transactions': [tx_hash_hex],
'timestamp': datetime.datetime.utcnow().timestamp(),
}
mockblock = Block(mockblock_src)
tx_src = snake_and_camel(r)
tx = Tx(tx_src, block=mockblock)
o = receipt(tx_hash_hex)
r = rpc.do(o)
assert r['status'] == 1
rcpt = snake_and_camel(r)
tx.apply_receipt(rcpt)
fltr = CallbackFilter(default_chain_spec, None, None, caller_address=contract_roles['CONTRACT_DEPLOYER'])
class CallbackMock:
def __init__(self):
self.results = {}
def call_back(self, transfer_type, result):
self.results[transfer_type] = result
mock = CallbackMock()
fltr.call_back = mock.call_back
fltr.filter(eth_rpc, mockblock, tx, init_database)
assert mock.results.get('transfer') != None
assert mock.results['transfer']['destination_token'] == foo_token

View File

@ -33,7 +33,9 @@ elif args.v:
config = confini.Config(args.c, args.env_prefix) config = confini.Config(args.c, args.env_prefix)
config.process() config.process()
config.add(args.q, '_CELERY_QUEUE', True)
config.censor('PASSWORD', 'DATABASE') config.censor('PASSWORD', 'DATABASE')
logg.debug('config loaded from {}:\n{}'.format(args.c, config))
# connect to database # connect to database
dsn = dsn_from_config(config) dsn = dsn_from_config(config)

View File

@ -6,11 +6,10 @@ import time
import semver import semver
# local imports # local imports
from cic_notify.error import PleaseCommitFirstError
logg = logging.getLogger() logg = logging.getLogger()
version = (0, 4, 0, 'alpha.3') version = (0, 4, 0, 'alpha.4')
version_object = semver.VersionInfo( version_object = semver.VersionInfo(
major=version[0], major=version[0],
@ -18,27 +17,4 @@ version_object = semver.VersionInfo(
patch=version[2], patch=version[2],
prerelease=version[3], prerelease=version[3],
) )
version_string = str(version_object) version_string = str(version_object)
def git_hash():
import subprocess
git_hash = subprocess.run(['git', 'rev-parse', 'HEAD'], capture_output=True)
git_hash_brief = git_hash.stdout.decode('utf-8')[:8]
return git_hash_brief
try:
version_git = git_hash()
version_string += '+build.{}'.format(version_git)
except FileNotFoundError:
time_string_pair = str(time.time()).split('.')
version_string += '+build.{}{:<09d}'.format(
time_string_pair[0],
int(time_string_pair[1]),
)
logg.info(f'Final version string will be {version_string}')
__version_string__ = version_string

View File

@ -1,6 +1,5 @@
[metadata] [metadata]
name = cic-notify name = cic-notify
version= 0.4.0a3
description = CIC notifications service description = CIC notifications service
author = Louis Holbrook author = Louis Holbrook
author_email = dev@holbrook.no author_email = dev@holbrook.no

View File

@ -1,9 +1,31 @@
# standard imports # standard imports
import logging
import subprocess
import time
from setuptools import setup from setuptools import setup
# third-party imports
# local imports # local imports
from cic_notify.version import version_string
logg = logging.getLogger()
def git_hash():
git_hash = subprocess.run(['git', 'rev-parse', 'HEAD'], capture_output=True)
git_hash_brief = git_hash.stdout.decode('utf-8')[:8]
return git_hash_brief
try:
version_git = git_hash()
version_string += '+build.{}'.format(version_git)
except FileNotFoundError:
time_string_pair = str(time.time()).split('.')
version_string += '+build.{}{:<09d}'.format(
time_string_pair[0],
int(time_string_pair[1]),
)
logg.info(f'Final version string will be {version_string}')
requirements = [] requirements = []
@ -25,6 +47,6 @@ while True:
test_requirements_file.close() test_requirements_file.close()
setup( setup(
version=version_string,
install_requires=requirements, install_requires=requirements,
tests_require=test_requirements, tests_require=test_requirements)
)

View File

@ -1,6 +1,6 @@
[celery] [celery]
BROKER_URL=redis://redis:6379 BROKER_URL=redis://
RESULT_URL=redis://redis:6379 RESULT_URL=redis://
[redis] [redis]
HOSTNAME=redis HOSTNAME=redis

View File

@ -57,19 +57,17 @@ arg_parser.add_argument('--env-prefix',
help='environment prefix for variables to overwrite configuration') help='environment prefix for variables to overwrite configuration')
args = arg_parser.parse_args() args = arg_parser.parse_args()
# parse config
config = Config(config_dir=args.c, env_prefix=args.env_prefix)
config.process()
config.censor('PASSWORD', 'DATABASE')
# define log levels # define log levels
if args.vv: if args.vv:
logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG)
elif args.v: elif args.v:
logging.getLogger().setLevel(logging.INFO) logging.getLogger().setLevel(logging.INFO)
# log config vars # parse config
logg.debug(config) config = Config(config_dir=args.c, env_prefix=args.env_prefix)
config.process()
config.censor('PASSWORD', 'DATABASE')
logg.debug('config loaded from {}:\n{}'.format(args.c, config))
# initialize elements # initialize elements
# set up translations # set up translations

View File

@ -6,6 +6,7 @@ import tempfile
# third party imports # third party imports
import celery import celery
import i18n
import redis import redis
from confini import Config from confini import Config
@ -33,18 +34,18 @@ arg_parser.add_argument('-vv', action='store_true', help='be more verbose')
arg_parser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration') arg_parser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration')
args = arg_parser.parse_args() args = arg_parser.parse_args()
# parse config
config = Config(config_dir=args.c, env_prefix=args.env_prefix)
config.process()
config.censor('PASSWORD', 'DATABASE')
# define log levels # define log levels
if args.vv: if args.vv:
logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG)
elif args.v: elif args.v:
logging.getLogger().setLevel(logging.INFO) logging.getLogger().setLevel(logging.INFO)
logg.debug(config) # parse config
config = Config(args.c, args.env_prefix)
config.process()
config.add(args.q, '_CELERY_QUEUE', True)
config.censor('PASSWORD', 'DATABASE')
logg.debug('config loaded from {}:\n{}'.format(args.c, config))
# connect to database # connect to database
data_source_name = dsn_from_config(config) data_source_name = dsn_from_config(config)
@ -77,6 +78,10 @@ if key_file_path:
validate_presence(path=key_file_path) validate_presence(path=key_file_path)
Signer.key_file_path = key_file_path Signer.key_file_path = key_file_path
# set up translations
i18n.load_path.append(config.get('APP_LOCALE_PATH'))
i18n.set('fallback', config.get('APP_LOCALE_FALLBACK'))
# set up celery # set up celery
current_app = celery.Celery(__name__) current_app = celery.Celery(__name__)

View File

@ -83,8 +83,8 @@ def process_incoming_transfer_callback(result: dict, param: str, status_code: in
# collect result data # collect result data
recipient_blockchain_address = result.get('recipient') recipient_blockchain_address = result.get('recipient')
sender_blockchain_address = result.get('sender') sender_blockchain_address = result.get('sender')
token_symbol = result.get('token_symbol') token_symbol = result.get('destination_token_symbol')
value = result.get('destination_value') value = result.get('destination_token_value')
# try to find users in system # try to find users in system
recipient_user = session.query(User).filter_by(blockchain_address=recipient_blockchain_address).first() recipient_user = session.query(User).filter_by(blockchain_address=recipient_blockchain_address).first()

View File

@ -1,4 +1,4 @@
cic_base[full_graph]~=0.1.2a68 cic_base[full_graph]~=0.1.2a68
cic-eth~=0.11.0b3 cic-eth~=0.11.0b3
cic-notify~=0.4.0a3 cic-notify~=0.4.0a4
cic-types~=0.1.0a10 cic-types~=0.1.0a10

View File

@ -446,7 +446,7 @@ services:
deploy: deploy:
restart_policy: restart_policy:
condition: on-failure condition: on-failure
command: "/root/start_tasker.sh -q cic-notify" command: "/root/start_tasker.sh -q cic-notify -vv"
cic-meta-server: cic-meta-server:
@ -494,6 +494,8 @@ services:
DATABASE_NAME: cic_ussd DATABASE_NAME: cic_ussd
DATABASE_ENGINE: postgresql DATABASE_ENGINE: postgresql
DATABASE_DRIVER: psycopg2 DATABASE_DRIVER: psycopg2
CELERY_BROKER_URL: ${CELERY_BROKER_URL:-redis://redis}
CELERY_RESULT_URL: ${CELERY_BROKER_URL:-redis://redis}
PGP_PASSPHRASE: merman PGP_PASSPHRASE: merman
SERVER_PORT: 9000 SERVER_PORT: 9000
CIC_META_URL: ${CIC_META_URL:-http://meta:8000} CIC_META_URL: ${CIC_META_URL:-http://meta:8000}