Compare commits

..

6 Commits

160 changed files with 2070 additions and 4686 deletions

1
.gitignore vendored
View File

@@ -14,4 +14,3 @@ build/
**/.venv **/.venv
.idea .idea
**/.vim **/.vim
**/*secret.yaml

View File

@@ -1,43 +1,14 @@
include: include:
#- local: 'ci_templates/.cic-template.yml' #kaniko build templates - local: 'ci_templates/.cic-template.yml'
# these includes are app specific unit tests - local: 'apps/contract-migration/.gitlab-ci.yml'
- local: 'apps/cic-eth/.gitlab-ci.yml' - local: 'apps/cic-eth/.gitlab-ci.yml'
- local: 'apps/cic-ussd/.gitlab-ci.yml' - local: 'apps/cic-ussd/.gitlab-ci.yml'
- local: 'apps/cic-notify/.gitlab-ci.yml' - local: 'apps/cic-notify/.gitlab-ci.yml'
- local: 'apps/cic-meta/.gitlab-ci.yml' - local: 'apps/cic-meta/.gitlab-ci.yml'
- local: 'apps/cic-cache/.gitlab-ci.yml' - local: 'apps/cic-cache/.gitlab-ci.yml'
#- local: 'apps/contract-migration/.gitlab-ci.yml' - local: 'apps/data-seeding/.gitlab-ci.yml'
#- local: 'apps/data-seeding/.gitlab-ci.yml'
stages: stages:
- build - build
- test - test
- deploy - release
image: registry.gitlab.com/grassrootseconomics/cic-internal-integration/docker-with-compose:latest
variables:
DOCKER_BUILDKIT: "1"
COMPOSE_DOCKER_CLI_BUILD: "1"
CI_DEBUG_TRACE: "true"
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
# runs on protected branches and pushes to repo
build-push:
stage: build
tags:
- integration
#script:
# - TAG=$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA sh ./scripts/build-push.sh
script:
- TAG=latest sh ./scripts/build-push.sh
rules:
- if: $CI_COMMIT_REF_PROTECTED == "true"
when: always
deploy-dev:
stage: deploy
trigger: grassrootseconomics/devops
when: manual

View File

@@ -2,21 +2,25 @@
## Getting started ## Getting started
This repo uses docker-compose and docker buildkit. Set the following environment variables to get started: ## Make some keys
``` ```
export COMPOSE_DOCKER_CLI_BUILD=1 docker build -t bloxie . && docker run -v "$(pwd)/keys:/root/keys" --rm -it -t bloxie account new --chain /root/bloxberg.json --keys-path /root/keys
export DOCKER_BUILDKIT=1
``` ```
start services, database, redis and local ethereum node
```
docker-compose up -d
```
Run app/contract-migration to deploy contracts ### Prepare the repo
This is stuff we need to put in makefile but for now...
File mounts and permisssions need to be set
``` ```
RUN_MASK=3 docker-compose up contract-migration chmod -R 755 scripts/initdb apps/cic-meta/scripts/initdb
````
start cluster
```
docker-compose up
``` ```
stop cluster stop cluster
@@ -24,9 +28,9 @@ stop cluster
docker-compose down docker-compose down
``` ```
stop cluster and delete data delete data
``` ```
docker-compose down -v --remove-orphans docker-compose down -v
``` ```
rebuild an images rebuild an images
@@ -34,7 +38,5 @@ rebuild an images
docker-compose up --build <service_name> docker-compose up --build <service_name>
``` ```
to delete the buildkit cache Deployment variables are writtend to service-configs/.env after everthing is up.
```
docker builder prune --filter type=exec.cachemount
```

View File

@@ -0,0 +1,34 @@
# The solc image messes up the alpine environment, so we have to go all over again
FROM python:3.8.6-slim-buster
LABEL authors="Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746"
LABEL spdx-license-identifier="GPL-3.0-or-later"
LABEL description="Base layer for buiding development images for the cic component suite"
RUN apt-get update && \
apt-get install -y git gcc g++ libpq-dev && \
apt-get install -y vim gawk jq telnet openssl iputils-ping curl wget gnupg socat bash procps make python2 postgresql-client
RUN echo installing nodejs tooling
COPY ./dev/nvm.sh /root/
# Install nvm with node and npm
# https://stackoverflow.com/questions/25899912/how-to-install-nvm-in-docker
ENV NVM_DIR /root/.nvm
ENV NODE_VERSION 15.3.0
ENV BANCOR_NODE_VERSION 10.16.0
RUN wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash \
&& . $NVM_DIR/nvm.sh \
&& nvm install $NODE_VERSION \
&& nvm alias default $NODE_VERSION \
&& nvm use $NODE_VERSION \
# So many ridiculously stupid issues with node in docker that take oceans of absolutely wasted time to resolve
# owner of these files is "1001" by default - wtf
&& chown -R root:root "$NVM_DIR/versions/node/v$NODE_VERSION"
ENV NODE_PATH $NVM_DIR/versions/node//v$NODE_VERSION/lib/node_modules
ENV PATH $NVM_DIR/versions/node//v$NODE_VERSION/bin:$PATH

View File

@@ -0,0 +1 @@
## this is an example base image if we wanted one for all the other apps. Its just OS level things

View File

@@ -1,17 +1,52 @@
build-test-cic-cache: .cic_cache_variables:
stage: test variables:
tags: APP_NAME: cic-cache
- integration DOCKERFILE_PATH: docker/Dockerfile_ci
variables: CONTEXT: apps/$APP_NAME
APP_NAME: cic-cache
MR_IMAGE_TAG: mr-$APP_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA build-mr-cic-cache:
script: extends:
- cd apps/cic-cache - .py_build_merge_request
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile . - .cic_cache_variables
- docker run $MR_IMAGE_TAG sh docker/run_tests.sh rules:
allow_failure: true - if: $CI_PIPELINE_SOURCE == "merge_request_event"
rules: changes:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" - apps/cic-cache/**/*
changes: when: always
- apps/$APP_NAME/**/*
when: always test-mr-cic-cache:
stage: test
extends:
- .cic_cache_variables
cache:
key:
files:
- test_requirements.txt
paths:
- /root/.cache/pip
image: $MR_IMAGE_TAG
script:
- cd apps/$APP_NAME/
- >
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
-r test_requirements.txt
- export PYTHONPATH=. && pytest -x --cov=cic_cache --cov-fail-under=90 --cov-report term-missing tests
needs: ["build-mr-cic-cache"]
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/$APP_NAME/**/*
when: always
build-push-cic-cache:
extends:
- .py_build_push
- .cic_cache_variables
rules:
- if: $CI_COMMIT_BRANCH == "master"
changes:
- apps/cic-cache/**/*
when: always

View File

@@ -1 +0,0 @@
# CIC-CACHE

View File

@@ -27,11 +27,11 @@ class RPC:
@staticmethod @staticmethod
def from_config(config): def from_config(config):
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC')) chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
RPCConnection.register_location(config.get('RPC_PROVIDER'), chain_spec, 'default') RPCConnection.register_location(config.get('RPC_HTTP_PROVIDER'), chain_spec, 'default')
if config.get('SIGNER_PROVIDER'): if config.get('SIGNER_PROVIDER'):
RPCConnection.register_constructor(ConnType.UNIX, EthUnixSignerConnection, tag='signer') RPCConnection.register_constructor(ConnType.UNIX, EthUnixSignerConnection, tag='signer')
RPCConnection.register_location(config.get('SIGNER_PROVIDER'), chain_spec, 'signer') RPCConnection.register_location(config.get('SIGNER_PROVIDER'), chain_spec, 'signer')
rpc = RPC(chain_spec, config.get('RPC_PROVIDER'), signer_provider=config.get('SIGNER_PROVIDER')) rpc = RPC(chain_spec, config.get('RPC_HTTP_PROVIDER'), signer_provider=config.get('SIGNER_PROVIDER'))
logg.info('set up rpc: {}'.format(rpc)) logg.info('set up rpc: {}'.format(rpc))
return rpc return rpc

View File

@@ -5,7 +5,7 @@ version = (
0, 0,
2, 2,
1, 1,
'alpha.2', 'alpha.1',
) )
version_object = semver.VersionInfo( version_object = semver.VersionInfo(

View File

@@ -0,0 +1,38 @@
# syntax = docker/dockerfile:1.2
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
# RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2b9
COPY requirements.txt .
#RUN pip install $pip_extra_index_url_flag -r test_requirements.txt
#RUN pip install $pip_extra_index_url_flag .
#RUN pip install .[server]
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
ARG EXTRA_PIP_ARGS=""
RUN pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL $EXTRA_PIP_ARGS \
-r requirements.txt
COPY . .
RUN python setup.py install
# ini files in config directory defines the configurable parameters for the application
# they can all be overridden by environment variables
# to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
COPY config/ /usr/local/etc/cic-cache/
# for db migrations
RUN git clone https://github.com/vishnubob/wait-for-it.git /usr/local/bin/wait-for-it/
COPY cic_cache/db/migrations/ /usr/local/share/cic-cache/alembic/
COPY /docker/start_tracker.sh ./start_tracker.sh
COPY /docker/db.sh ./db.sh
RUN chmod 755 ./*.sh
# Tracker
# ENTRYPOINT ["/usr/local/bin/cic-cache-tracker", "-vv"]
# Server
# ENTRYPOINT [ "/usr/local/bin/uwsgi", "--wsgi-file", "/usr/local/lib/python3.8/site-packages/cic_cache/runnable/server.py", "--http", ":80", "--pyargv", "-vv" ]
ENTRYPOINT []

View File

@@ -1,10 +0,0 @@
#! /bin/bash
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 \
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
-r test_requirements.txt
export PYTHONPATH=. && pytest -x --cov=cic_cache --cov-fail-under=90 --cov-report term-missing tests

View File

@@ -8,7 +8,8 @@ semver==2.13.0
psycopg2==2.8.6 psycopg2==2.8.6
celery==4.4.7 celery==4.4.7
redis==3.5.3 redis==3.5.3
chainsyncer[sql]>=0.0.6a3,<0.1.0 chainsyncer[sql]>=0.0.6a1,<0.1.0
erc20-faucet>=0.3.2a2, <0.4.0 erc20-faucet>=0.3.2a1, <0.4.0
chainlib-eth>=0.0.9a14,<0.1.0 chainlib-eth>=0.0.9a3,<0.1.0
eth-address-index>=0.2.3a4,<0.3.0 chainlib>=0.0.9a2,<0.1.0
eth-address-index>=0.2.3a1,<0.3.0

View File

@@ -1,4 +1,5 @@
celery==4.4.7 celery==4.4.7
erc20-demurrage-token~=0.0.3a1 erc20-demurrage-token~=0.0.3a1
cic-eth-registry>=0.6.1a2,<0.7.0 cic-eth-registry~=0.5.8a1
cic-eth[services]~=0.12.4a8 chainlib~=0.0.7a1
cic_eth~=0.12.2a4

View File

@@ -1,16 +1,52 @@
build-test-cic-eth: .cic_eth_variables:
stage: test variables:
tags: APP_NAME: cic-eth
- integration DOCKERFILE_PATH: docker/Dockerfile_ci
variables: CONTEXT: apps/$APP_NAME
APP_NAME: cic-eth
MR_IMAGE_TAG: mr-$APP_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA build-mr-cic-eth:
script: extends:
- cd apps/cic-eth - .cic_eth_variables
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile . - .py_build_target_dev
- docker run $MR_IMAGE_TAG sh docker/run_tests.sh rules:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes: changes:
- apps/$APP_NAME/**/* - apps/cic-eth/**/*
when: always
test-mr-cic-eth:
stage: test
extends:
- .cic_eth_variables
cache:
key:
files:
- test_requirements.txt
paths:
- /root/.cache/pip
image: $MR_IMAGE_TAG
script:
- cd apps/$APP_NAME/
- >
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
-r admin_requirements.txt
-r services_requirements.txt
-r test_requirements.txt
- export PYTHONPATH=. && pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests
needs: ["build-mr-cic-eth"]
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/cic-eth/**/*
when: always
build-push-cic-eth:
extends:
- .py_build_push
- .cic_eth_variables
rules:
- if: $CI_COMMIT_BRANCH == "master"
changes:
- apps/cic-eth/**/*
when: always when: always

View File

@@ -1,5 +1,5 @@
SQLAlchemy==1.3.20 SQLAlchemy==1.3.20
cic-eth-registry>=0.6.1a5,<0.7.0 cic-eth-registry>=0.6.1a2,<0.7.0
hexathon~=0.0.1a8 hexathon~=0.0.1a8
chainqueue>=0.0.4a6,<0.1.0 chainqueue>=0.0.3a2,<0.1.0
eth-erc20>=0.1.2a2,<0.2.0 eth-erc20>=0.1.2a2,<0.2.0

View File

@@ -4,6 +4,7 @@ import logging
# external imports # external imports
import celery import celery
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from hexathon import ( from hexathon import (
add_0x, add_0x,
@@ -19,17 +20,18 @@ from cic_eth.task import (
CriticalSQLAlchemyTask, CriticalSQLAlchemyTask,
) )
from cic_eth.error import LockedError from cic_eth.error import LockedError
from cic_eth.encode import (
tx_normalize,
ZERO_ADDRESS_NORMAL,
)
celery_app = celery.current_app celery_app = celery.current_app
logg = logging.getLogger() logg = logging.getLogger()
def normalize_address(a):
if a == None:
return None
return add_0x(hex_uniform(strip_0x(a)))
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def lock(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, flags=LockEnum.ALL, tx_hash=None): def lock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.ALL, tx_hash=None):
"""Task wrapper to set arbitrary locks """Task wrapper to set arbitrary locks
:param chain_str: Chain spec string representation :param chain_str: Chain spec string representation
@@ -41,7 +43,7 @@ def lock(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, flags=Lock
:returns: New lock state for address :returns: New lock state for address
:rtype: number :rtype: number
""" """
address = tx_normalize.wallet_address(address) address = normalize_address(address)
chain_str = '::' chain_str = '::'
if chain_spec_dict != None: if chain_spec_dict != None:
chain_str = str(ChainSpec.from_dict(chain_spec_dict)) chain_str = str(ChainSpec.from_dict(chain_spec_dict))
@@ -51,7 +53,7 @@ def lock(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, flags=Lock
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def unlock(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, flags=LockEnum.ALL): def unlock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.ALL):
"""Task wrapper to reset arbitrary locks """Task wrapper to reset arbitrary locks
:param chain_str: Chain spec string representation :param chain_str: Chain spec string representation
@@ -63,7 +65,7 @@ def unlock(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, flags=Lo
:returns: New lock state for address :returns: New lock state for address
:rtype: number :rtype: number
""" """
address = tx_normalize.wallet_address(address) address = normalize_address(address)
chain_str = '::' chain_str = '::'
if chain_spec_dict != None: if chain_spec_dict != None:
chain_str = str(ChainSpec.from_dict(chain_spec_dict)) chain_str = str(ChainSpec.from_dict(chain_spec_dict))
@@ -73,7 +75,7 @@ def unlock(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, flags=Lo
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def lock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, tx_hash=None): def lock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS, tx_hash=None):
"""Task wrapper to set send lock """Task wrapper to set send lock
:param chain_str: Chain spec string representation :param chain_str: Chain spec string representation
@@ -83,7 +85,7 @@ def lock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, tx_ha
:returns: New lock state for address :returns: New lock state for address
:rtype: number :rtype: number
""" """
address = tx_normalize.wallet_address(address) address = normalize_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict)) chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.set(chain_str, LockEnum.SEND, address=address, tx_hash=tx_hash) r = Lock.set(chain_str, LockEnum.SEND, address=address, tx_hash=tx_hash)
logg.debug('Send locked for {}, flag now {}'.format(address, r)) logg.debug('Send locked for {}, flag now {}'.format(address, r))
@@ -91,7 +93,7 @@ def lock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, tx_ha
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def unlock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL): def unlock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
"""Task wrapper to reset send lock """Task wrapper to reset send lock
:param chain_str: Chain spec string representation :param chain_str: Chain spec string representation
@@ -101,7 +103,7 @@ def unlock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL):
:returns: New lock state for address :returns: New lock state for address
:rtype: number :rtype: number
""" """
address = tx_normalize.wallet_address(address) address = normalize_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict)) chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.reset(chain_str, LockEnum.SEND, address=address) r = Lock.reset(chain_str, LockEnum.SEND, address=address)
logg.debug('Send unlocked for {}, flag now {}'.format(address, r)) logg.debug('Send unlocked for {}, flag now {}'.format(address, r))
@@ -109,7 +111,7 @@ def unlock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def lock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, tx_hash=None): def lock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS, tx_hash=None):
"""Task wrapper to set queue direct lock """Task wrapper to set queue direct lock
:param chain_str: Chain spec string representation :param chain_str: Chain spec string representation
@@ -119,7 +121,7 @@ def lock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, tx_h
:returns: New lock state for address :returns: New lock state for address
:rtype: number :rtype: number
""" """
address = tx_normalize.wallet_address(address) address = normalize_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict)) chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.set(chain_str, LockEnum.QUEUE, address=address, tx_hash=tx_hash) r = Lock.set(chain_str, LockEnum.QUEUE, address=address, tx_hash=tx_hash)
logg.debug('Queue direct locked for {}, flag now {}'.format(address, r)) logg.debug('Queue direct locked for {}, flag now {}'.format(address, r))
@@ -127,7 +129,7 @@ def lock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, tx_h
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def unlock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL): def unlock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
"""Task wrapper to reset queue direct lock """Task wrapper to reset queue direct lock
:param chain_str: Chain spec string representation :param chain_str: Chain spec string representation
@@ -137,7 +139,7 @@ def unlock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL):
:returns: New lock state for address :returns: New lock state for address
:rtype: number :rtype: number
""" """
address = tx_normalize.wallet_address(address) address = normalize_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict)) chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.reset(chain_str, LockEnum.QUEUE, address=address) r = Lock.reset(chain_str, LockEnum.QUEUE, address=address)
logg.debug('Queue direct unlocked for {}, flag now {}'.format(address, r)) logg.debug('Queue direct unlocked for {}, flag now {}'.format(address, r))
@@ -146,13 +148,12 @@ def unlock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def check_lock(chained_input, chain_spec_dict, lock_flags, address=None): def check_lock(chained_input, chain_spec_dict, lock_flags, address=None):
if address != None: address = normalize_address(address)
address = tx_normalize.wallet_address(address)
chain_str = '::' chain_str = '::'
if chain_spec_dict != None: if chain_spec_dict != None:
chain_str = str(ChainSpec.from_dict(chain_spec_dict)) chain_str = str(ChainSpec.from_dict(chain_spec_dict))
session = SessionBase.create_session() session = SessionBase.create_session()
r = Lock.check(chain_str, lock_flags, address=ZERO_ADDRESS_NORMAL, session=session) r = Lock.check(chain_str, lock_flags, address=ZERO_ADDRESS, session=session)
if address != None: if address != None:
r |= Lock.check(chain_str, lock_flags, address=address, session=session) r |= Lock.check(chain_str, lock_flags, address=address, session=session)
if r > 0: if r > 0:

View File

@@ -33,7 +33,6 @@ from cic_eth.admin.ctrl import (
from cic_eth.queue.tx import queue_create from cic_eth.queue.tx import queue_create
from cic_eth.eth.gas import create_check_gas_task from cic_eth.eth.gas import create_check_gas_task
from cic_eth.task import BaseTask from cic_eth.task import BaseTask
from cic_eth.encode import tx_normalize
celery_app = celery.current_app celery_app = celery.current_app
logg = logging.getLogger() logg = logging.getLogger()
@@ -74,7 +73,7 @@ def shift_nonce(self, chainspec_dict, tx_hash_orig_hex, delta=1):
set_cancel(chain_spec, strip_0x(tx['hash']), manual=True, session=session) set_cancel(chain_spec, strip_0x(tx['hash']), manual=True, session=session)
query_address = tx_normalize.wallet_address(address) query_address = add_0x(hex_uniform(strip_0x(address))) # aaaaargh
q = session.query(Otx) q = session.query(Otx)
q = q.join(TxCache) q = q.join(TxCache)
q = q.filter(TxCache.sender==query_address) q = q.filter(TxCache.sender==query_address)

View File

@@ -1,2 +1,21 @@
# standard imports
import logging
# external imports
import celery
# local imports # local imports
from cic_eth.eth.erc20 import default_token from cic_eth.task import BaseTask
celery_app = celery.current_app
logg = logging.getLogger()
@celery_app.task(bind=True, base=BaseTask)
def default_token(self):
return {
'symbol': self.default_token_symbol,
'address': self.default_token_address,
'name': self.default_token_name,
'decimals': self.default_token_decimals,
}

View File

@@ -32,6 +32,7 @@ from chainqueue.db.enum import (
status_str, status_str,
) )
from chainqueue.error import TxStateChangeError from chainqueue.error import TxStateChangeError
from chainqueue.sql.query import get_tx
from eth_erc20 import ERC20 from eth_erc20 import ERC20
# local imports # local imports
@@ -39,7 +40,6 @@ from cic_eth.db.models.base import SessionBase
from cic_eth.db.models.role import AccountRole from cic_eth.db.models.role import AccountRole
from cic_eth.db.models.nonce import Nonce from cic_eth.db.models.nonce import Nonce
from cic_eth.error import InitializationError from cic_eth.error import InitializationError
from cic_eth.queue.query import get_tx_local
app = celery.current_app app = celery.current_app
@@ -284,7 +284,7 @@ class AdminApi:
tx_hash_hex = None tx_hash_hex = None
session = SessionBase.create_session() session = SessionBase.create_session()
for k in txs.keys(): for k in txs.keys():
tx_dict = get_tx_local(chain_spec, k, session=session) tx_dict = get_tx(chain_spec, k, session=session)
if tx_dict['nonce'] == nonce: if tx_dict['nonce'] == nonce:
tx_hash_hex = k tx_hash_hex = k
session.close() session.close()

View File

@@ -9,7 +9,6 @@ import logging
# external imports # external imports
import celery import celery
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from hexathon import strip_0x
# local imports # local imports
from cic_eth.api.base import ApiBase from cic_eth.api.base import ApiBase
@@ -17,50 +16,15 @@ from cic_eth.enum import LockEnum
app = celery.current_app app = celery.current_app
#logg = logging.getLogger(__name__) logg = logging.getLogger(__name__)
logg = logging.getLogger()
class Api(ApiBase): class Api(ApiBase):
@staticmethod
def to_v_list(v, n):
"""Translate an arbitrary number of string and/or list arguments to a list of list of string arguments
:param v: Arguments
:type v: str or list
:param n: Number of elements to generate arguments for
:type n: int
:rtype: list
:returns: list of assembled arguments
"""
if isinstance(v, str):
vv = v
v = []
for i in range(n):
v.append([vv])
elif not isinstance(v, list):
raise ValueError('argument must be single string, or list or strings or lists')
else:
if len(v) != n:
raise ValueError('v argument count must match integer n')
for i in range(n):
if isinstance(v[i], str):
v[i] = [v[i]]
elif not isinstance(v, list):
raise ValueError('proof argument must be single string, or list or strings or lists')
return v
def default_token(self): def default_token(self):
"""Retrieves the default fallback token of the custodial network.
:returns: uuid of root task
:rtype: celery.Task
"""
s_token = celery.signature( s_token = celery.signature(
'cic_eth.eth.erc20.default_token', 'cic_eth.admin.token.default_token',
[], [],
queue=self.queue, queue=self.queue,
) )
@@ -70,97 +34,6 @@ class Api(ApiBase):
return s_token.apply_async() return s_token.apply_async()
def token(self, token_symbol, proof=None):
"""Single-token alias for tokens method.
See tokens method for details.
:param token_symbol: Token symbol to look up
:type token_symbol: str
:param proof: Proofs to add to signature verification for the token
:type proof: str or list
:returns: uuid of root task
:rtype: celery.Task
"""
if not isinstance(token_symbol, str):
raise ValueError('token symbol must be string')
return self.tokens([token_symbol], proof=proof)
def tokens(self, token_symbols, proof=None):
"""Perform a token data lookup from the token index. The token index will enforce unique associations between token symbol and contract address.
Token symbols are always strings, and should be specified using uppercase letters.
If the proof argument is included, the network will be queried for trusted signatures on the given proof(s). There must exist at least one trusted signature for every given proof for every token. Trusted signatures for the custodial system are provided at service startup.
The proof argument may be specified in a number of ways:
- as None, in which case proof checks are skipped (although there may still be builtin proof checks being performed)
- as a single string, where the same proof is used for each token lookup
- as an array of strings, where the respective proof is used for the respective token. number of proofs must match the number of tokens.
- as an array of lists, where the respective proofs in each list is used for the respective token. number of lists of proofs must match the number of tokens.
The success callback provided at the Api object instantiation will receive individual calls for each token that passes the proof checks. Each token that does not pass is passed to the Api error callback.
This method is not intended to be used synchronously. Do so at your peril.
:param token_symbols: Token symbol strings to look up
:type token_symbol: list
:param proof: Proof(s) to verify tokens against
:type proof: None, str or list
:returns: uuid of root task
:rtype: celery.Task
"""
if not isinstance(token_symbols, list):
raise ValueError('token symbols argument must be list')
if proof == None:
logg.debug('looking up tokens without external proof check: {}'.format(','.join(token_symbols)))
proof = ''
logg.debug('proof is {}'.format(proof))
l = len(token_symbols)
if len(proof) == 0:
l = 0
proof = Api.to_v_list(proof, l)
chain_spec_dict = self.chain_spec.asdict()
s_token_resolve = celery.signature(
'cic_eth.eth.erc20.resolve_tokens_by_symbol',
[
token_symbols,
chain_spec_dict,
],
queue=self.queue,
)
s_token_info = celery.signature(
'cic_eth.eth.erc20.token_info',
[
chain_spec_dict,
proof,
],
queue=self.queue,
)
s_token_verify = celery.signature(
'cic_eth.eth.erc20.verify_token_info',
[
chain_spec_dict,
self.callback_success,
self.callback_error,
],
queue=self.queue,
)
s_token_info.link(s_token_verify)
s_token_resolve.link(s_token_info)
return s_token_resolve.apply_async()
# def convert_transfer(self, from_address, to_address, target_return, minimum_return, from_token_symbol, to_token_symbol): # def convert_transfer(self, from_address, to_address, target_return, minimum_return, from_token_symbol, to_token_symbol):
# """Executes a chain of celery tasks that performs conversion between two ERC20 tokens, and transfers to a specified receipient after convert has completed. # """Executes a chain of celery tasks that performs conversion between two ERC20 tokens, and transfers to a specified receipient after convert has completed.
# #
@@ -381,8 +254,6 @@ class Api(ApiBase):
:returns: uuid of root task :returns: uuid of root task
:rtype: celery.Task :rtype: celery.Task
""" """
#from_address = strip_0x(from_address)
#to_address = strip_0x(to_address)
s_check = celery.signature( s_check = celery.signature(
'cic_eth.admin.ctrl.check_lock', 'cic_eth.admin.ctrl.check_lock',
[ [

View File

@@ -1,10 +1,7 @@
import logging
import celery import celery
celery_app = celery.current_app celery_app = celery.current_app
#logg = celery_app.log.get_default_logger() logg = celery_app.log.get_default_logger()
logg = logging.getLogger()
@celery_app.task(bind=True) @celery_app.task(bind=True)

View File

@@ -35,14 +35,14 @@ class RPC:
def from_config(config, use_signer=False, default_label='default', signer_label='signer'): def from_config(config, use_signer=False, default_label='default', signer_label='signer'):
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC')) chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
RPCConnection.register_location(config.get('RPC_PROVIDER'), chain_spec, default_label) RPCConnection.register_location(config.get('RPC_HTTP_PROVIDER'), chain_spec, default_label)
if use_signer: if use_signer:
RPCConnection.register_constructor(ConnType.UNIX, EthUnixSignerConnection, signer_label) RPCConnection.register_constructor(ConnType.UNIX, EthUnixSignerConnection, signer_label)
RPCConnection.register_constructor(ConnType.HTTP, EthHTTPSignerConnection, signer_label) RPCConnection.register_constructor(ConnType.HTTP, EthHTTPSignerConnection, signer_label)
RPCConnection.register_constructor(ConnType.HTTP_SSL, EthHTTPSignerConnection, signer_label) RPCConnection.register_constructor(ConnType.HTTP_SSL, EthHTTPSignerConnection, signer_label)
RPCConnection.register_location(config.get('SIGNER_PROVIDER'), chain_spec, signer_label) RPCConnection.register_location(config.get('SIGNER_PROVIDER'), chain_spec, signer_label)
rpc = RPC(chain_spec, config.get('RPC_PROVIDER'), signer_provider=config.get('SIGNER_PROVIDER')) rpc = RPC(chain_spec, config.get('RPC_HTTP_PROVIDER'), signer_provider=config.get('SIGNER_PROVIDER'))
logg.info('set up rpc: {}'.format(rpc)) logg.info('set up rpc: {}'.format(rpc))
return rpc return rpc

View File

@@ -8,8 +8,8 @@ Create Date: 2021-04-02 18:41:20.864265
import datetime import datetime
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from chainlib.eth.constant import ZERO_ADDRESS
from cic_eth.db.enum import LockEnum from cic_eth.db.enum import LockEnum
from cic_eth.encode import ZERO_ADDRESS_NORMAL
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -30,7 +30,7 @@ def upgrade():
sa.Column("otx_id", sa.Integer, sa.ForeignKey('otx.id'), nullable=True), sa.Column("otx_id", sa.Integer, sa.ForeignKey('otx.id'), nullable=True),
) )
op.create_index('idx_chain_address', 'lock', ['blockchain', 'address'], unique=True) op.create_index('idx_chain_address', 'lock', ['blockchain', 'address'], unique=True)
op.execute("INSERT INTO lock (address, date_created, blockchain, flags) VALUES('{}', '{}', '::', {})".format(ZERO_ADDRESS_NORMAL, datetime.datetime.utcnow(), LockEnum.INIT | LockEnum.SEND | LockEnum.QUEUE)) op.execute("INSERT INTO lock (address, date_created, blockchain, flags) VALUES('{}', '{}', '::', {})".format(ZERO_ADDRESS, datetime.datetime.utcnow(), LockEnum.INIT | LockEnum.SEND | LockEnum.QUEUE))
def downgrade(): def downgrade():

View File

@@ -4,12 +4,12 @@ import logging
# third-party imports # third-party imports
from sqlalchemy import Column, String, Integer, DateTime, ForeignKey from sqlalchemy import Column, String, Integer, DateTime, ForeignKey
from chainlib.eth.constant import ZERO_ADDRESS
from chainqueue.db.models.tx import TxCache from chainqueue.db.models.tx import TxCache
from chainqueue.db.models.otx import Otx from chainqueue.db.models.otx import Otx
# local imports # local imports
from cic_eth.db.models.base import SessionBase from cic_eth.db.models.base import SessionBase
from cic_eth.encode import ZERO_ADDRESS_NORMAL
logg = logging.getLogger() logg = logging.getLogger()
@@ -37,7 +37,7 @@ class Lock(SessionBase):
@staticmethod @staticmethod
def set(chain_str, flags, address=ZERO_ADDRESS_NORMAL, session=None, tx_hash=None): def set(chain_str, flags, address=ZERO_ADDRESS, session=None, tx_hash=None):
"""Sets flags associated with the given address and chain. """Sets flags associated with the given address and chain.
If a flags entry does not exist it is created. If a flags entry does not exist it is created.
@@ -90,7 +90,7 @@ class Lock(SessionBase):
@staticmethod @staticmethod
def reset(chain_str, flags, address=ZERO_ADDRESS_NORMAL, session=None): def reset(chain_str, flags, address=ZERO_ADDRESS, session=None):
"""Resets flags associated with the given address and chain. """Resets flags associated with the given address and chain.
If the resulting flags entry value is 0, the entry will be deleted. If the resulting flags entry value is 0, the entry will be deleted.
@@ -134,7 +134,7 @@ class Lock(SessionBase):
@staticmethod @staticmethod
def check(chain_str, flags, address=ZERO_ADDRESS_NORMAL, session=None): def check(chain_str, flags, address=ZERO_ADDRESS, session=None):
"""Checks whether all given flags are set for given address and chain. """Checks whether all given flags are set for given address and chain.
Does not validate the address against any other tables or components. Does not validate the address against any other tables or components.

View File

@@ -1,16 +0,0 @@
# external imports
from chainlib.eth.constant import ZERO_ADDRESS
from chainqueue.encode import TxHexNormalizer
from chainlib.eth.tx import unpack
tx_normalize = TxHexNormalizer()
ZERO_ADDRESS_NORMAL = tx_normalize.wallet_address(ZERO_ADDRESS)
def unpack_normal(signed_tx_bytes, chain_spec):
tx = unpack(signed_tx_bytes, chain_spec)
tx['hash'] = tx_normalize.tx_hash(tx['hash'])
tx['from'] = tx_normalize.wallet_address(tx['from'])
tx['to'] = tx_normalize.wallet_address(tx['to'])
return tx

View File

@@ -48,6 +48,8 @@ class RoleMissingError(Exception):
pass pass
class IntegrityError(Exception): class IntegrityError(Exception):
"""Exception raised to signal irregularities with deduplication and ordering of tasks """Exception raised to signal irregularities with deduplication and ordering of tasks
@@ -83,8 +85,3 @@ class RoleAgencyError(SeppukuError):
class YouAreBrokeError(Exception): class YouAreBrokeError(Exception):
"""Exception raised when a value transfer is attempted without access to sufficient funds """Exception raised when a value transfer is attempted without access to sufficient funds
""" """
class TrustError(Exception):
"""Exception raised when required trust proofs are missing for a request
"""

View File

@@ -13,8 +13,11 @@ from chainlib.eth.sign import (
new_account, new_account,
sign_message, sign_message,
) )
from chainlib.eth.address import to_checksum_address, is_address from chainlib.eth.address import to_checksum_address
from chainlib.eth.tx import TxFormat from chainlib.eth.tx import (
TxFormat,
unpack,
)
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from chainlib.error import JSONRPCException from chainlib.error import JSONRPCException
from eth_accounts_index.registry import AccountRegistry from eth_accounts_index.registry import AccountRegistry
@@ -31,7 +34,6 @@ from cic_eth.eth.gas import (
from cic_eth.db.models.nonce import Nonce from cic_eth.db.models.nonce import Nonce
from cic_eth.db.models.base import SessionBase from cic_eth.db.models.base import SessionBase
from cic_eth.db.models.role import AccountRole from cic_eth.db.models.role import AccountRole
from cic_eth.encode import tx_normalize
from cic_eth.error import ( from cic_eth.error import (
RoleMissingError, RoleMissingError,
SignerError, SignerError,
@@ -47,11 +49,6 @@ from cic_eth.eth.nonce import (
from cic_eth.queue.tx import ( from cic_eth.queue.tx import (
register_tx, register_tx,
) )
from cic_eth.encode import (
unpack_normal,
ZERO_ADDRESS_NORMAL,
tx_normalize,
)
logg = logging.getLogger() logg = logging.getLogger()
celery_app = celery.current_app celery_app = celery.current_app
@@ -86,7 +83,7 @@ def create(self, password, chain_spec_dict):
# TODO: It seems infeasible that a can be None in any case, verify # TODO: It seems infeasible that a can be None in any case, verify
if a == None: if a == None:
raise SignerError('create account') raise SignerError('create account')
a = tx_normalize.wallet_address(a)
logg.debug('created account {}'.format(a)) logg.debug('created account {}'.format(a))
# Initialize nonce provider record for account # Initialize nonce provider record for account
@@ -177,9 +174,6 @@ def gift(self, account_address, chain_spec_dict):
""" """
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
if is_address(account_address):
account_address = tx_normalize.wallet_address(account_address)
logg.debug('gift account address {} to index'.format(account_address)) logg.debug('gift account address {} to index'.format(account_address))
queue = self.request.delivery_info.get('routing_key') queue = self.request.delivery_info.get('routing_key')
@@ -253,9 +247,8 @@ def have(self, account, chain_spec_dict):
@celery_app.task(bind=True, base=CriticalSQLAlchemyTask) @celery_app.task(bind=True, base=CriticalSQLAlchemyTask)
def set_role(self, tag, address, chain_spec_dict): def set_role(self, tag, address, chain_spec_dict):
if not is_address(address): if not to_checksum_address(address):
raise ValueError('invalid address {}'.format(address)) raise ValueError('invalid checksum address {}'.format(address))
address = tx_normalize.wallet_address(address)
session = SessionBase.create_session() session = SessionBase.create_session()
role = AccountRole.set(tag, address, session=session) role = AccountRole.set(tag, address, session=session)
session.add(role) session.add(role)
@@ -302,19 +295,17 @@ def cache_gift_data(
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex)) tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex))
tx = unpack_normal(tx_signed_raw_bytes, chain_spec) tx = unpack(tx_signed_raw_bytes, chain_spec)
tx_data = Faucet.parse_give_to_request(tx['data']) tx_data = Faucet.parse_give_to_request(tx['data'])
sender_address = tx_normalize.wallet_address(tx['from'])
recipient_address = tx_normalize.wallet_address(tx['to'])
session = self.create_session() session = self.create_session()
tx_dict = { tx_dict = {
'hash': tx['hash'], 'hash': tx_hash_hex,
'from': sender_address, 'from': tx['from'],
'to': recipient_address, 'to': tx['to'],
'source_token': ZERO_ADDRESS_NORMAL, 'source_token': ZERO_ADDRESS,
'destination_token': ZERO_ADDRESS_NORMAL, 'destination_token': ZERO_ADDRESS,
'from_value': 0, 'from_value': 0,
'to_value': 0, 'to_value': 0,
} }
@@ -343,19 +334,17 @@ def cache_account_data(
:rtype: tuple :rtype: tuple
""" """
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex)) tx_signed_raw_bytes = bytes.fromhex(tx_signed_raw_hex[2:])
tx = unpack_normal(tx_signed_raw_bytes, chain_spec) tx = unpack(tx_signed_raw_bytes, chain_spec)
tx_data = AccountsIndex.parse_add_request(tx['data']) tx_data = AccountsIndex.parse_add_request(tx['data'])
sender_address = tx_normalize.wallet_address(tx['from'])
recipient_address = tx_normalize.wallet_address(tx['to'])
session = SessionBase.create_session() session = SessionBase.create_session()
tx_dict = { tx_dict = {
'hash': tx['hash'], 'hash': tx_hash_hex,
'from': sender_address, 'from': tx['from'],
'to': recipient_address, 'to': tx['to'],
'source_token': ZERO_ADDRESS_NORMAL, 'source_token': ZERO_ADDRESS,
'destination_token': ZERO_ADDRESS_NORMAL, 'destination_token': ZERO_ADDRESS,
'from_value': 0, 'from_value': 0,
'to_value': 0, 'to_value': 0,
} }

View File

@@ -12,14 +12,10 @@ from chainlib.eth.tx import (
) )
from cic_eth_registry import CICRegistry from cic_eth_registry import CICRegistry
from cic_eth_registry.erc20 import ERC20Token from cic_eth_registry.erc20 import ERC20Token
from hexathon import ( from hexathon import strip_0x
strip_0x,
add_0x,
)
from chainqueue.error import NotLocalTxError from chainqueue.error import NotLocalTxError
from eth_erc20 import ERC20 from eth_erc20 import ERC20
from chainqueue.sql.tx import cache_tx_dict from chainqueue.sql.tx import cache_tx_dict
from okota.token_index import to_identifier
# local imports # local imports
from cic_eth.db.models.base import SessionBase from cic_eth.db.models.base import SessionBase
@@ -40,11 +36,8 @@ from cic_eth.task import (
CriticalSQLAlchemyTask, CriticalSQLAlchemyTask,
CriticalWeb3Task, CriticalWeb3Task,
CriticalSQLAlchemyAndSignerTask, CriticalSQLAlchemyAndSignerTask,
BaseTask,
) )
from cic_eth.eth.nonce import CustodialTaskNonceOracle from cic_eth.eth.nonce import CustodialTaskNonceOracle
from cic_eth.encode import tx_normalize
from cic_eth.eth.trust import verify_proofs
celery_app = celery.current_app celery_app = celery.current_app
logg = logging.getLogger() logg = logging.getLogger()
@@ -69,8 +62,7 @@ def balance(tokens, holder_address, chain_spec_dict):
for t in tokens: for t in tokens:
address = t['address'] address = t['address']
logg.debug('address {} {}'.format(address, holder_address)) token = ERC20Token(chain_spec, rpc, address)
token = ERC20Token(chain_spec, rpc, add_0x(address))
c = ERC20(chain_spec) c = ERC20(chain_spec)
o = c.balance_of(address, holder_address, sender_address=caller_address) o = c.balance_of(address, holder_address, sender_address=caller_address)
r = rpc.do(o) r = rpc.do(o)
@@ -379,15 +371,13 @@ def cache_transfer_data(
tx = unpack(tx_signed_raw_bytes, chain_spec) tx = unpack(tx_signed_raw_bytes, chain_spec)
tx_data = ERC20.parse_transfer_request(tx['data']) tx_data = ERC20.parse_transfer_request(tx['data'])
sender_address = tx_normalize.wallet_address(tx['from']) recipient_address = tx_data[0]
recipient_address = tx_normalize.wallet_address(tx_data[0])
token_value = tx_data[1] token_value = tx_data[1]
session = SessionBase.create_session() session = SessionBase.create_session()
tx_dict = { tx_dict = {
'hash': tx_hash_hex, 'hash': tx_hash_hex,
'from': sender_address, 'from': tx['from'],
'to': recipient_address, 'to': recipient_address,
'source_token': tx['to'], 'source_token': tx['to'],
'destination_token': tx['to'], 'destination_token': tx['to'],
@@ -458,14 +448,13 @@ def cache_approve_data(
tx = unpack(tx_signed_raw_bytes, chain_spec) tx = unpack(tx_signed_raw_bytes, chain_spec)
tx_data = ERC20.parse_approve_request(tx['data']) tx_data = ERC20.parse_approve_request(tx['data'])
sender_address = tx_normalize.wallet_address(tx['from']) recipient_address = tx_data[0]
recipient_address = tx_normalize.wallet_address(tx_data[0])
token_value = tx_data[1] token_value = tx_data[1]
session = SessionBase.create_session() session = SessionBase.create_session()
tx_dict = { tx_dict = {
'hash': tx_hash_hex, 'hash': tx_hash_hex,
'from': sender_address, 'from': tx['from'],
'to': recipient_address, 'to': recipient_address,
'source_token': tx['to'], 'source_token': tx['to'],
'destination_token': tx['to'], 'destination_token': tx['to'],
@@ -476,69 +465,3 @@ def cache_approve_data(
session.close() session.close()
return (tx_hash_hex, cache_id) return (tx_hash_hex, cache_id)
@celery_app.task(bind=True, base=BaseTask)
def token_info(self, tokens, chain_spec_dict, proofs=[]):
chain_spec = ChainSpec.from_dict(chain_spec_dict)
rpc = RPCConnection.connect(chain_spec, 'default')
i = 0
for token in tokens:
result_data = []
token_chain_object = ERC20Token(chain_spec, rpc, add_0x(token['address']))
token_chain_object.load(rpc)
token_symbol_proof_hex = to_identifier(token_chain_object.symbol)
token_proofs = [token_symbol_proof_hex]
if len(proofs) > 0:
token_proofs += proofs[i]
tokens[i] = {
'decimals': token_chain_object.decimals,
'name': token_chain_object.name,
'symbol': token_chain_object.symbol,
'address': tx_normalize.executable_address(token_chain_object.address),
'proofs': token_proofs,
'converters': tokens[i]['converters'],
}
i += 1
return tokens
@celery_app.task(bind=True, base=BaseTask)
def verify_token_info(self, tokens, chain_spec_dict, success_callback, error_callback):
queue = self.request.delivery_info.get('routing_key')
for token in tokens:
s = celery.signature(
'cic_eth.eth.trust.verify_proofs',
[
token,
token['address'],
token['proofs'],
chain_spec_dict,
success_callback,
error_callback,
],
queue=queue,
)
if success_callback != None:
s.link(success_callback)
if error_callback != None:
s.on_error(error_callback)
s.apply_async()
return tokens
@celery_app.task(bind=True, base=BaseTask)
def default_token(self):
return {
'symbol': self.default_token_symbol,
'address': self.default_token_address,
'name': self.default_token_name,
'decimals': self.default_token_decimals,
}

View File

@@ -3,17 +3,10 @@ import logging
# external imports # external imports
import celery import celery
from hexathon import ( from hexathon import strip_0x
strip_0x, from chainlib.eth.constant import ZERO_ADDRESS
add_0x,
)
#from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from chainlib.eth.address import ( from chainlib.eth.address import is_checksum_address
is_checksum_address,
to_checksum_address,
is_address
)
from chainlib.connection import RPCConnection from chainlib.connection import RPCConnection
from chainqueue.db.enum import StatusBits from chainqueue.db.enum import StatusBits
from chainqueue.sql.tx import cache_tx_dict from chainqueue.sql.tx import cache_tx_dict
@@ -28,6 +21,7 @@ from chainlib.eth.error import (
from chainlib.eth.tx import ( from chainlib.eth.tx import (
TxFactory, TxFactory,
TxFormat, TxFormat,
unpack,
) )
from chainlib.eth.contract import ( from chainlib.eth.contract import (
abi_decode_single, abi_decode_single,
@@ -51,7 +45,6 @@ from cic_eth.eth.nonce import CustodialTaskNonceOracle
from cic_eth.queue.tx import ( from cic_eth.queue.tx import (
queue_create, queue_create,
register_tx, register_tx,
unpack,
) )
from cic_eth.queue.query import get_tx from cic_eth.queue.query import get_tx
from cic_eth.task import ( from cic_eth.task import (
@@ -60,11 +53,6 @@ from cic_eth.task import (
CriticalSQLAlchemyAndSignerTask, CriticalSQLAlchemyAndSignerTask,
CriticalWeb3AndSignerTask, CriticalWeb3AndSignerTask,
) )
from cic_eth.encode import (
tx_normalize,
ZERO_ADDRESS_NORMAL,
unpack_normal,
)
celery_app = celery.current_app celery_app = celery.current_app
logg = logging.getLogger() logg = logging.getLogger()
@@ -142,16 +130,16 @@ def cache_gas_data(
""" """
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex)) tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex))
tx = unpack_normal(tx_signed_raw_bytes, chain_spec) tx = unpack(tx_signed_raw_bytes, chain_spec)
session = SessionBase.create_session() session = SessionBase.create_session()
tx_dict = { tx_dict = {
'hash': tx['hash'], 'hash': tx_hash_hex,
'from': tx['from'], 'from': tx['from'],
'to': tx['to'], 'to': tx['to'],
'source_token': ZERO_ADDRESS_NORMAL, 'source_token': ZERO_ADDRESS,
'destination_token': ZERO_ADDRESS_NORMAL, 'destination_token': ZERO_ADDRESS,
'from_value': tx['value'], 'from_value': tx['value'],
'to_value': tx['value'], 'to_value': tx['value'],
} }
@@ -162,7 +150,7 @@ def cache_gas_data(
@celery_app.task(bind=True, throws=(OutOfGasError), base=CriticalSQLAlchemyAndWeb3Task) @celery_app.task(bind=True, throws=(OutOfGasError), base=CriticalSQLAlchemyAndWeb3Task)
def check_gas(self, tx_hashes_hex, chain_spec_dict, txs_hex=[], address=None, gas_required=MAXIMUM_FEE_UNITS): def check_gas(self, tx_hashes, chain_spec_dict, txs=[], address=None, gas_required=MAXIMUM_FEE_UNITS):
"""Check the gas level of the sender address of a transaction. """Check the gas level of the sender address of a transaction.
If the account balance is not sufficient for the required gas, gas refill is requested and OutOfGasError raiser. If the account balance is not sufficient for the required gas, gas refill is requested and OutOfGasError raiser.
@@ -182,23 +170,8 @@ def check_gas(self, tx_hashes_hex, chain_spec_dict, txs_hex=[], address=None, ga
:return: Signed raw transaction data list :return: Signed raw transaction data list
:rtype: param txs, unchanged :rtype: param txs, unchanged
""" """
rpc_format_address = None
if address != None:
if not is_address(address):
raise ValueError('invalid address {}'.format(address))
address = tx_normalize.wallet_address(address)
address = add_0x(address)
tx_hashes = []
txs = []
for tx_hash in tx_hashes_hex:
tx_hash = tx_normalize.tx_hash(tx_hash)
tx_hashes.append(tx_hash)
for tx in txs_hex:
tx = tx_normalize.tx_wire(tx)
txs.append(tx)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
logg.debug('txs {} tx_hashes {}'.format(txs, tx_hashes))
addresspass = None addresspass = None
if len(txs) == 0: if len(txs) == 0:
@@ -214,7 +187,8 @@ def check_gas(self, tx_hashes_hex, chain_spec_dict, txs_hex=[], address=None, ga
raise ValueError('txs passed to check gas must all have same sender; had {} got {}'.format(address, tx['from'])) raise ValueError('txs passed to check gas must all have same sender; had {} got {}'.format(address, tx['from']))
addresspass.append(address) addresspass.append(address)
rpc_format_address = add_0x(to_checksum_address(address)) if not is_checksum_address(address):
raise ValueError('invalid address {}'.format(address))
queue = self.request.delivery_info.get('routing_key') queue = self.request.delivery_info.get('routing_key')
@@ -222,7 +196,7 @@ def check_gas(self, tx_hashes_hex, chain_spec_dict, txs_hex=[], address=None, ga
gas_balance = 0 gas_balance = 0
try: try:
o = balance(rpc_format_address) o = balance(address)
r = conn.do(o) r = conn.do(o)
conn.disconnect() conn.disconnect()
gas_balance = abi_decode_single(ABIContractType.UINT256, r) gas_balance = abi_decode_single(ABIContractType.UINT256, r)
@@ -330,7 +304,6 @@ def refill_gas(self, recipient_address, chain_spec_dict):
# Determine value of gas tokens to send # Determine value of gas tokens to send
# if an uncompleted gas refill for the same recipient already exists, we still need to spend the nonce # if an uncompleted gas refill for the same recipient already exists, we still need to spend the nonce
# however, we will perform a 0-value transaction instead # however, we will perform a 0-value transaction instead
recipient_address = tx_normalize.wallet_address(recipient_address)
zero_amount = False zero_amount = False
session = SessionBase.create_session() session = SessionBase.create_session()
status_filter = StatusBits.FINAL | StatusBits.NODE_ERROR | StatusBits.NETWORK_ERROR | StatusBits.UNKNOWN_ERROR status_filter = StatusBits.FINAL | StatusBits.NODE_ERROR | StatusBits.NETWORK_ERROR | StatusBits.UNKNOWN_ERROR
@@ -405,7 +378,6 @@ def resend_with_higher_gas(self, txold_hash_hex, chain_spec_dict, gas=None, defa
:returns: Transaction hash :returns: Transaction hash
:rtype: str, 0x-hex :rtype: str, 0x-hex
""" """
txold_hash_hex = tx_normalize.tx_hash(txold_hash_hex)
session = SessionBase.create_session() session = SessionBase.create_session()
otx = Otx.load(txold_hash_hex, session) otx = Otx.load(txold_hash_hex, session)

View File

@@ -2,9 +2,8 @@
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 from cic_eth_registry.erc20 import ERC20Token
from hexathon import add_0x
# local impor:ts # local imports
from cic_eth.ext.address import translate_address from cic_eth.ext.address import translate_address
@@ -45,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.chain_spec, self.rpc, add_0x(source)) st = ERC20Token(self.chain_spec, self.rpc, source)
dt = ERC20Token(self.chain_spec, self.rpc, add_0x(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

View File

@@ -3,12 +3,11 @@ import logging
# external imports # external imports
import celery import celery
from chainlib.eth.address import is_checksum_address, is_address, strip_0x from chainlib.eth.address import is_checksum_address
# local imports # local imports
from cic_eth.db.models.role import AccountRole from cic_eth.db.models.role import AccountRole
from cic_eth.db.models.base import SessionBase from cic_eth.db.models.base import SessionBase
from cic_eth.encode import tx_normalize
from cic_eth.task import CriticalSQLAlchemyTask from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.db.models.nonce import ( from cic_eth.db.models.nonce import (
Nonce, Nonce,
@@ -43,8 +42,7 @@ class CustodialTaskNonceOracle():
:returns: Nonce :returns: Nonce
:rtype: number :rtype: number
""" """
address = tx_normalize.wallet_address(self.address) r = NonceReservation.release(self.address, self.uuid, session=self.session)
r = NonceReservation.release(address, self.uuid, session=self.session)
return r[1] return r[1]
@@ -60,18 +58,17 @@ def reserve_nonce(self, chained_input, chain_spec_dict, signer_address=None):
address = chained_input address = chained_input
logg.debug('non-explicit address for reserve nonce, using arg head {}'.format(chained_input)) logg.debug('non-explicit address for reserve nonce, using arg head {}'.format(chained_input))
else: else:
if is_address(signer_address): if is_checksum_address(signer_address):
address = signer_address address = signer_address
logg.debug('explicit address for reserve nonce {}'.format(signer_address)) logg.debug('explicit address for reserve nonce {}'.format(signer_address))
else: else:
address = AccountRole.get_address(signer_address, session=session) address = AccountRole.get_address(signer_address, session=session)
logg.debug('role for reserve nonce {} -> {}'.format(signer_address, address)) logg.debug('role for reserve nonce {} -> {}'.format(signer_address, address))
if not is_address(address): if not is_checksum_address(address):
raise ValueError('invalid result when resolving address for nonce {}'.format(address)) raise ValueError('invalid result when resolving address for nonce {}'.format(address))
root_id = self.request.root_id root_id = self.request.root_id
address = tx_normalize.wallet_address(address)
r = NonceReservation.next(address, root_id, session=session) r = NonceReservation.next(address, root_id, session=session)
logg.debug('nonce {} reserved for address {} task {}'.format(r[1], address, r[0])) logg.debug('nonce {} reserved for address {} task {}'.format(r[1], address, r[0]))

View File

@@ -1,77 +0,0 @@
# standard imports
import logging
# external imports
import celery
from eth_address_declarator import Declarator
from chainlib.connection import RPCConnection
from chainlib.chain import ChainSpec
from cic_eth.db.models.role import AccountRole
from cic_eth_registry import CICRegistry
from hexathon import strip_0x
# local imports
from cic_eth.task import BaseTask
from cic_eth.error import TrustError
celery_app = celery.current_app
logg = logging.getLogger()
@celery_app.task(bind=True, base=BaseTask)
def verify_proof(self, chained_input, proof, subject, chain_spec_dict, success_callback, error_callback):
proof = strip_0x(proof)
proofs = []
logg.debug('proof count {}'.format(len(proofs)))
if len(proofs) == 0:
logg.debug('error {}'.format(len(proofs)))
raise TrustError('foo')
return (chained_input, (proof, proofs))
@celery_app.task(bind=True, base=BaseTask)
def verify_proofs(self, chained_input, subject, proofs, chain_spec_dict, success_callback, error_callback):
queue = self.request.delivery_info.get('routing_key')
chain_spec = ChainSpec.from_dict(chain_spec_dict)
rpc = RPCConnection.connect(chain_spec, 'default')
session = self.create_session()
sender_address = AccountRole.get_address('DEFAULT', session)
registry = CICRegistry(chain_spec, rpc)
declarator_address = registry.by_name('AddressDeclarator', sender_address=sender_address)
declarator = Declarator(chain_spec)
have_proofs = {}
for proof in proofs:
proof = strip_0x(proof)
have_proofs[proof] = []
for trusted_address in self.trusted_addresses:
o = declarator.declaration(declarator_address, trusted_address, subject, sender_address=sender_address)
r = rpc.do(o)
declarations = declarator.parse_declaration(r)
logg.debug('comparing proof {} with declarations for {} by {}: {}'.format(proof, subject, trusted_address, declarations))
for declaration in declarations:
declaration = strip_0x(declaration)
if declaration == proof:
logg.debug('have token proof {} match for trusted address {}'.format(declaration, trusted_address))
have_proofs[proof].append(trusted_address)
out_proofs = {}
for proof in have_proofs.keys():
if len(have_proofs[proof]) == 0:
logg.error('missing signer for proof {} subject {}'.format(proof, subject))
raise TrustError((subject, proof,))
out_proofs[proof] = have_proofs[proof]
return (chained_input, out_proofs)

View File

@@ -32,7 +32,6 @@ from potaahto.symbols import snake_and_camel
from cic_eth.queue.time import tx_times from cic_eth.queue.time import tx_times
from cic_eth.task import BaseTask from cic_eth.task import BaseTask
from cic_eth.db.models.base import SessionBase from cic_eth.db.models.base import SessionBase
from cic_eth.encode import tx_normalize
celery_app = celery.current_app celery_app = celery.current_app
logg = logging.getLogger() logg = logging.getLogger()
@@ -135,7 +134,7 @@ def list_tx_by_bloom(self, bloomspec, address, chain_spec_dict):
tx_address = transfer_data[0] tx_address = transfer_data[0]
tx_token_value = transfer_data[1] tx_token_value = transfer_data[1]
if tx_normalize.wallet_address(address) == tx_normalize.wallet_address(tx_address): if address == tx_address:
status = StatusEnum.SENT status = StatusEnum.SENT
try: try:
o = receipt(tx['hash']) o = receipt(tx['hash'])
@@ -153,8 +152,8 @@ def list_tx_by_bloom(self, bloomspec, address, chain_spec_dict):
times = tx_times(tx['hash'], chain_spec) times = tx_times(tx['hash'], chain_spec)
tx_r = { tx_r = {
'hash': tx['hash'], 'hash': tx['hash'],
'sender': tx_normalize.wallet_address(tx['from']), 'sender': tx['from'],
'recipient': tx_normalize.wallet_address(tx_address), 'recipient': tx_address,
'source_value': tx_token_value, 'source_value': tx_token_value,
'destination_value': tx_token_value, 'destination_value': tx_token_value,
'source_token': tx['to'], 'source_token': tx['to'],
@@ -165,12 +164,12 @@ def list_tx_by_bloom(self, bloomspec, address, chain_spec_dict):
tx_r['date_created'] = times['queue'] tx_r['date_created'] = times['queue']
else: else:
tx_r['date_created'] = times['network'] tx_r['date_created'] = times['network']
txs[strip_0x(tx['hash'])] = tx_r txs[tx['hash']] = tx_r
break break
return txs return txs
# TODO: Surely it must be possible to optimize this # TODO: Surely it must be possible to optimize this
# TODO: DRY this with callback filter in cic_eth/runnable/manager # TODO: DRY this with callback filter in cic_eth/runnable/manager
# TODO: Remove redundant fields from end representation (timestamp, tx_hash) # TODO: Remove redundant fields from end representation (timestamp, tx_hash)
@@ -231,8 +230,6 @@ def tx_collate(self, tx_batches, chain_spec_dict, offset, limit, newest_first=Tr
except UnknownContractError: except UnknownContractError:
logg.error('verify failed on tx {}, skipping'.format(tx['hash'])) logg.error('verify failed on tx {}, skipping'.format(tx['hash']))
continue continue
tx['recipient'] = tx_normalize.wallet_address(tx['recipient'])
tx['sender'] = tx_normalize.wallet_address(tx['sender'])
txs.append(tx) txs.append(tx)
return txs return txs

View File

@@ -4,21 +4,18 @@ import tempfile
import logging import logging
import shutil import shutil
# local imports # local impors
from cic_eth.task import BaseTask from cic_eth.task import BaseTask
#logg = logging.getLogger(__name__) #logg = logging.getLogger(__name__)
logg = logging.getLogger() logg = logging.getLogger()
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def init_celery_tasks( def init_celery_tasks(
contract_roles, contract_roles,
): ):
BaseTask.call_address = contract_roles['DEFAULT'] BaseTask.call_address = contract_roles['DEFAULT']
BaseTask.trusted_addresses = [
contract_roles['TRUSTED_DECLARATOR'],
contract_roles['CONTRACT_DEPLOYER'],
]
# celery fixtures # celery fixtures
@@ -41,7 +38,6 @@ def celery_includes():
'cic_eth.callbacks.noop', 'cic_eth.callbacks.noop',
'cic_eth.callbacks.http', 'cic_eth.callbacks.http',
'cic_eth.pytest.mock.filter', 'cic_eth.pytest.mock.filter',
'cic_eth.pytest.mock.callback',
] ]

View File

@@ -1,2 +1 @@
from .filter import * from .filter import *
from .callback import *

View File

@@ -1,38 +0,0 @@
# standard imports
import os
import logging
import mmap
# standard imports
import tempfile
# external imports
import celery
#logg = logging.getLogger(__name__)
logg = logging.getLogger()
celery_app = celery.current_app
class CallbackTask(celery.Task):
mmap_path = tempfile.mkdtemp()
@celery_app.task(bind=True, base=CallbackTask)
def test_callback(self, a, b, c):
s = 'ok'
if c > 0:
s = 'err'
fp = os.path.join(self.mmap_path, b)
f = open(fp, 'wb+')
f.write(b'\x00')
f.seek(0)
m = mmap.mmap(f.fileno(), length=1)
m.write(c.to_bytes(1, 'big'))
m.close()
f.close()
logg.debug('test callback ({}): {} {} {}'.format(s, a, b, c))

View File

@@ -15,7 +15,6 @@ from chainqueue.db.enum import (
# local imports # local imports
from cic_eth.db import SessionBase from cic_eth.db import SessionBase
from cic_eth.task import CriticalSQLAlchemyTask from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.encode import tx_normalize
celery_app = celery.current_app celery_app = celery.current_app
@@ -23,9 +22,6 @@ logg = logging.getLogger()
def __balance_outgoing_compatible(token_address, holder_address): def __balance_outgoing_compatible(token_address, holder_address):
token_address = tx_normalize.executable_address(token_address)
holder_address = tx_normalize.wallet_address(holder_address)
session = SessionBase.create_session() session = SessionBase.create_session()
q = session.query(TxCache.from_value) q = session.query(TxCache.from_value)
q = q.join(Otx) q = q.join(Otx)
@@ -62,9 +58,6 @@ def balance_outgoing(tokens, holder_address, chain_spec_dict):
def __balance_incoming_compatible(token_address, receiver_address): def __balance_incoming_compatible(token_address, receiver_address):
token_address = tx_normalize.executable_address(token_address)
receiver_address = tx_normalize.wallet_address(receiver_address)
session = SessionBase.create_session() session = SessionBase.create_session()
q = session.query(TxCache.to_value) q = session.query(TxCache.to_value)
q = q.join(Otx) q = q.join(Otx)
@@ -117,7 +110,7 @@ def assemble_balances(balances_collection):
logg.debug('received collection {}'.format(balances_collection)) logg.debug('received collection {}'.format(balances_collection))
for c in balances_collection: for c in balances_collection:
for b in c: for b in c:
address = tx_normalize.executable_address(b['address']) address = b['address']
if tokens.get(address) == None: if tokens.get(address) == None:
tokens[address] = { tokens[address] = {
'address': address, 'address': address,

View File

@@ -6,7 +6,6 @@ import celery
from cic_eth.task import CriticalSQLAlchemyTask from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.db import SessionBase from cic_eth.db import SessionBase
from cic_eth.db.models.lock import Lock from cic_eth.db.models.lock import Lock
from cic_eth.encode import tx_normalize
celery_app = celery.current_app celery_app = celery.current_app
@@ -22,9 +21,6 @@ def get_lock(address=None):
:returns: List of locks :returns: List of locks
:rtype: list of dicts :rtype: list of dicts
""" """
if address != None:
address = tx_normalize.wallet_address(address)
session = SessionBase.create_session() session = SessionBase.create_session()
q = session.query( q = session.query(
Lock.date_created, Lock.date_created,

View File

@@ -4,8 +4,8 @@ import datetime
# external imports # external imports
import celery import celery
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
import chainqueue.sql.query
from chainlib.eth.tx import unpack from chainlib.eth.tx import unpack
import chainqueue.sql.query
from chainqueue.db.enum import ( from chainqueue.db.enum import (
StatusEnum, StatusEnum,
is_alive, is_alive,
@@ -20,10 +20,6 @@ from cic_eth.db.enum import LockEnum
from cic_eth.task import CriticalSQLAlchemyTask from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.db.models.lock import Lock from cic_eth.db.models.lock import Lock
from cic_eth.db.models.base import SessionBase from cic_eth.db.models.base import SessionBase
from cic_eth.encode import (
tx_normalize,
unpack_normal,
)
celery_app = celery.current_app celery_app = celery.current_app
@@ -31,77 +27,49 @@ celery_app = celery.current_app
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def get_tx_cache(chain_spec_dict, tx_hash): def get_tx_cache(chain_spec_dict, tx_hash):
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
return get_tx_cache_local(chain_spec, tx_hash) session = SessionBase.create_session()
def get_tx_cache_local(chain_spec, tx_hash, session=None):
tx_hash = tx_normalize.tx_hash(tx_hash)
session = SessionBase.bind_session(session)
r = chainqueue.sql.query.get_tx_cache(chain_spec, tx_hash, session=session) r = chainqueue.sql.query.get_tx_cache(chain_spec, tx_hash, session=session)
SessionBase.release_session(session) session.close()
return r return r
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def get_tx(chain_spec_dict, tx_hash): def get_tx(chain_spec_dict, tx_hash):
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
return get_tx_local(chain_spec, tx_hash) session = SessionBase.create_session()
def get_tx_local(chain_spec, tx_hash, session=None):
tx_hash = tx_normalize.tx_hash(tx_hash)
session = SessionBase.bind_session(session)
r = chainqueue.sql.query.get_tx(chain_spec, tx_hash, session=session) r = chainqueue.sql.query.get_tx(chain_spec, tx_hash, session=session)
SessionBase.release_session(session) session.close()
return r return r
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def get_account_tx(chain_spec_dict, address, as_sender=True, as_recipient=True, counterpart=None): def get_account_tx(chain_spec_dict, address, as_sender=True, as_recipient=True, counterpart=None):
address = tx_normalize.wallet_address(address)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
return get_account_tx_local(chain_spec, address, as_sender=as_sender, as_recipient=as_recipient, counterpart=counterpart) session = SessionBase.create_session()
def get_account_tx_local(chain_spec, address, as_sender=True, as_recipient=True, counterpart=None, session=None):
address = tx_normalize.wallet_address(address)
session = SessionBase.bind_session(session)
r = chainqueue.sql.query.get_account_tx(chain_spec, address, as_sender=True, as_recipient=True, counterpart=None, session=session) r = chainqueue.sql.query.get_account_tx(chain_spec, address, as_sender=True, as_recipient=True, counterpart=None, session=session)
SessionBase.release_session(session) session.close()
return r return r
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def get_upcoming_tx_nolock(chain_spec_dict, status=StatusEnum.READYSEND, not_status=None, recipient=None, before=None, limit=0): def get_upcoming_tx_nolock(chain_spec_dict, status=StatusEnum.READYSEND, not_status=None, recipient=None, before=None, limit=0, session=None):
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
return get_upcoming_tx_nolock_local(chain_spec, status=status, not_status=not_status, recipient=recipient, before=before, limit=limit)
def get_upcoming_tx_nolock_local(chain_spec, status=StatusEnum.READYSEND, not_status=None, recipient=None, before=None, limit=0, session=None):
recipient = tx_normalize.wallet_address(recipient)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.query.get_upcoming_tx(chain_spec, status, not_status=not_status, recipient=recipient, before=before, limit=limit, session=session, decoder=unpack_normal) r = chainqueue.sql.query.get_upcoming_tx(chain_spec, status, not_status=not_status, recipient=recipient, before=before, limit=limit, session=session, decoder=unpack)
session.close() session.close()
return r return r
def get_status_tx(chain_spec, status, not_status=None, before=None, exact=False, limit=0, session=None): def get_status_tx(chain_spec, status, not_status=None, before=None, exact=False, limit=0, session=None):
return chainqueue.sql.query.get_status_tx_cache(chain_spec, status, not_status=not_status, before=before, exact=exact, limit=limit, session=session, decoder=unpack_normal) return chainqueue.sql.query.get_status_tx_cache(chain_spec, status, not_status=not_status, before=before, exact=exact, limit=limit, session=session, decoder=unpack)
def get_paused_tx(chain_spec, status=None, sender=None, session=None, decoder=None): def get_paused_tx(chain_spec, status=None, sender=None, session=None, decoder=None):
sender = tx_normalize.wallet_address(sender) return chainqueue.sql.query.get_paused_tx_cache(chain_spec, status=status, sender=sender, session=session, decoder=unpack)
return chainqueue.sql.query.get_paused_tx_cache(chain_spec, status=status, sender=sender, session=session, decoder=unpack_normal)
def get_nonce_tx(chain_spec, nonce, sender): def get_nonce_tx(chain_spec, nonce, sender):
sender = tx_normalize.wallet_address(sender) return get_nonce_tx_cache(chain_spec, nonce, sender, decoder=unpack)
return get_nonce_tx_local(chain_spec, nonce, sender)
def get_nonce_tx_local(chain_spec, nonce, sender, session=None):
sender = tx_normalize.wallet_address(sender)
return chainqueue.sql.query.get_nonce_tx_cache(chain_spec, nonce, sender, decoder=unpack_normal, session=session)
def get_upcoming_tx(chain_spec, status=StatusEnum.READYSEND, not_status=None, recipient=None, before=None, limit=0, session=None): def get_upcoming_tx(chain_spec, status=StatusEnum.READYSEND, not_status=None, recipient=None, before=None, limit=0, session=None):
@@ -123,8 +91,6 @@ def get_upcoming_tx(chain_spec, status=StatusEnum.READYSEND, not_status=None, re
:returns: Transactions :returns: Transactions
:rtype: dict, with transaction hash as key, signed raw transaction as value :rtype: dict, with transaction hash as key, signed raw transaction as value
""" """
if recipient != None:
recipient = tx_normalize.wallet_address(recipient)
session = SessionBase.bind_session(session) session = SessionBase.bind_session(session)
q_outer = session.query( q_outer = session.query(
TxCache.sender, TxCache.sender,

View File

@@ -6,14 +6,12 @@ import chainqueue.sql.state
import celery import celery
from cic_eth.task import CriticalSQLAlchemyTask from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.db.models.base import SessionBase from cic_eth.db.models.base import SessionBase
from cic_eth.encode import tx_normalize
celery_app = celery.current_app celery_app = celery.current_app
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def set_sent(chain_spec_dict, tx_hash, fail=False): def set_sent(chain_spec_dict, tx_hash, fail=False):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.set_sent(chain_spec, tx_hash, fail, session=session) r = chainqueue.sql.state.set_sent(chain_spec, tx_hash, fail, session=session)
@@ -23,7 +21,6 @@ def set_sent(chain_spec_dict, tx_hash, fail=False):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def set_final(chain_spec_dict, tx_hash, block=None, tx_index=None, fail=False): def set_final(chain_spec_dict, tx_hash, block=None, tx_index=None, fail=False):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.set_final(chain_spec, tx_hash, block=block, tx_index=tx_index, fail=fail, session=session) r = chainqueue.sql.state.set_final(chain_spec, tx_hash, block=block, tx_index=tx_index, fail=fail, session=session)
@@ -33,7 +30,6 @@ def set_final(chain_spec_dict, tx_hash, block=None, tx_index=None, fail=False):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def set_cancel(chain_spec_dict, tx_hash, manual=False): def set_cancel(chain_spec_dict, tx_hash, manual=False):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.set_cancel(chain_spec, tx_hash, manual, session=session) r = chainqueue.sql.state.set_cancel(chain_spec, tx_hash, manual, session=session)
@@ -43,7 +39,6 @@ def set_cancel(chain_spec_dict, tx_hash, manual=False):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def set_rejected(chain_spec_dict, tx_hash): def set_rejected(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.set_rejected(chain_spec, tx_hash, session=session) r = chainqueue.sql.state.set_rejected(chain_spec, tx_hash, session=session)
@@ -53,7 +48,6 @@ def set_rejected(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def set_fubar(chain_spec_dict, tx_hash): def set_fubar(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.set_fubar(chain_spec, tx_hash, session=session) r = chainqueue.sql.state.set_fubar(chain_spec, tx_hash, session=session)
@@ -63,7 +57,6 @@ def set_fubar(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def set_manual(chain_spec_dict, tx_hash): def set_manual(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.set_manual(chain_spec, tx_hash, session=session) r = chainqueue.sql.state.set_manual(chain_spec, tx_hash, session=session)
@@ -73,7 +66,6 @@ def set_manual(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def set_ready(chain_spec_dict, tx_hash): def set_ready(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.set_ready(chain_spec, tx_hash, session=session) r = chainqueue.sql.state.set_ready(chain_spec, tx_hash, session=session)
@@ -83,7 +75,6 @@ def set_ready(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def set_reserved(chain_spec_dict, tx_hash): def set_reserved(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.set_reserved(chain_spec, tx_hash, session=session) r = chainqueue.sql.state.set_reserved(chain_spec, tx_hash, session=session)
@@ -93,7 +84,6 @@ def set_reserved(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def set_waitforgas(chain_spec_dict, tx_hash): def set_waitforgas(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.set_waitforgas(chain_spec, tx_hash, session=session) r = chainqueue.sql.state.set_waitforgas(chain_spec, tx_hash, session=session)
@@ -103,7 +93,6 @@ def set_waitforgas(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def get_state_log(chain_spec_dict, tx_hash): def get_state_log(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.get_state_log(chain_spec, tx_hash, session=session) r = chainqueue.sql.state.get_state_log(chain_spec, tx_hash, session=session)
@@ -113,7 +102,6 @@ def get_state_log(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask) @celery_app.task(base=CriticalSQLAlchemyTask)
def obsolete(chain_spec_dict, tx_hash, final): def obsolete(chain_spec_dict, tx_hash, final):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict) chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session() session = SessionBase.create_session()
r = chainqueue.sql.state.obsolete_by_cache(chain_spec, tx_hash, final, session=session) r = chainqueue.sql.state.obsolete_by_cache(chain_spec, tx_hash, final, session=session)

View File

@@ -13,7 +13,6 @@ from chainqueue.error import NotLocalTxError
# local imports # local imports
from cic_eth.task import CriticalSQLAlchemyAndWeb3Task from cic_eth.task import CriticalSQLAlchemyAndWeb3Task
from cic_eth.db.models.base import SessionBase from cic_eth.db.models.base import SessionBase
from cic_eth.encode import tx_normalize
celery_app = celery.current_app celery_app = celery.current_app
@@ -21,7 +20,6 @@ logg = logging.getLogger()
def tx_times(tx_hash, chain_spec, session=None): def tx_times(tx_hash, chain_spec, session=None):
tx_hash = tx_normalize.tx_hash(tx_hash)
session = SessionBase.bind_session(session) session = SessionBase.bind_session(session)

View File

@@ -32,16 +32,12 @@ from cic_eth.db import SessionBase
from cic_eth.db.enum import LockEnum from cic_eth.db.enum import LockEnum
from cic_eth.task import CriticalSQLAlchemyTask from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.error import LockedError from cic_eth.error import LockedError
from cic_eth.encode import tx_normalize
celery_app = celery.current_app celery_app = celery.current_app
logg = logging.getLogger() logg = logging.getLogger()
def queue_create(chain_spec, nonce, holder_address, tx_hash, signed_tx, session=None): def queue_create(chain_spec, nonce, holder_address, tx_hash, signed_tx, session=None):
tx_hash = tx_normalize.tx_hash(tx_hash)
signed_tx = tx_normalize.tx_hash(signed_tx)
holder_address = tx_normalize.wallet_address(holder_address)
session = SessionBase.bind_session(session) session = SessionBase.bind_session(session)
lock = Lock.check_aggregate(str(chain_spec), LockEnum.QUEUE, holder_address, session=session) lock = Lock.check_aggregate(str(chain_spec), LockEnum.QUEUE, holder_address, session=session)
@@ -71,8 +67,6 @@ def register_tx(tx_hash_hex, tx_signed_raw_hex, chain_spec, queue, cache_task=No
:returns: Tuple; Transaction hash, signed raw transaction data :returns: Tuple; Transaction hash, signed raw transaction data
:rtype: tuple :rtype: tuple
""" """
tx_hash_hex = tx_normalize.tx_hash(tx_hash_hex)
tx_signed_raw_hex = tx_normalize.tx_hash(tx_signed_raw_hex)
logg.debug('adding queue tx {}:{} -> {}'.format(chain_spec, tx_hash_hex, tx_signed_raw_hex)) logg.debug('adding queue tx {}:{} -> {}'.format(chain_spec, tx_hash_hex, tx_signed_raw_hex))
tx_signed_raw = bytes.fromhex(strip_0x(tx_signed_raw_hex)) tx_signed_raw = bytes.fromhex(strip_0x(tx_signed_raw_hex))
tx = unpack(tx_signed_raw, chain_spec) tx = unpack(tx_signed_raw, chain_spec)

View File

@@ -21,7 +21,6 @@ from erc20_faucet import Faucet
# local imports # local imports
from .base import SyncFilter from .base import SyncFilter
from cic_eth.eth.meta import ExtendedTx from cic_eth.eth.meta import ExtendedTx
from cic_eth.encode import tx_normalize
logg = logging.getLogger().getChild(__name__) logg = logging.getLogger().getChild(__name__)
@@ -43,9 +42,9 @@ class CallbackFilter(SyncFilter):
return (None, None) return (None, None)
r = ERC20.parse_transfer_request(tx.payload) r = ERC20.parse_transfer_request(tx.payload)
transfer_data = {} transfer_data = {}
transfer_data['to'] = tx_normalize.wallet_address(r[0]) transfer_data['to'] = r[0]
transfer_data['value'] = r[1] transfer_data['value'] = r[1]
transfer_data['from'] = tx_normalize.wallet_address(tx.outputs[0]) transfer_data['from'] = tx.outputs[0]
transfer_data['token_address'] = tx.inputs[0] transfer_data['token_address'] = tx.inputs[0]
return ('transfer', transfer_data) return ('transfer', transfer_data)
@@ -55,8 +54,8 @@ class CallbackFilter(SyncFilter):
return (None, None) return (None, None)
r = ERC20.parse_transfer_from_request(tx.payload) r = ERC20.parse_transfer_from_request(tx.payload)
transfer_data = {} transfer_data = {}
transfer_data['from'] = tx_normalize.wallet_address(r[0]) transfer_data['from'] = r[0]
transfer_data['to'] = tx_normalize.wallet_address(r[1]) transfer_data['to'] = r[1]
transfer_data['value'] = r[2] transfer_data['value'] = r[2]
transfer_data['token_address'] = tx.inputs[0] transfer_data['token_address'] = tx.inputs[0]
return ('transferfrom', transfer_data) return ('transferfrom', transfer_data)
@@ -67,9 +66,9 @@ class CallbackFilter(SyncFilter):
return (None, None) return (None, None)
r = Faucet.parse_give_to_request(tx.payload) r = Faucet.parse_give_to_request(tx.payload)
transfer_data = {} transfer_data = {}
transfer_data['to'] = tx_normalize.wallet_address(r[0]) transfer_data['to'] = r[0]
transfer_data['value'] = tx.value transfer_data['value'] = tx.value
transfer_data['from'] = tx_normalize.wallet_address(tx.outputs[0]) transfer_data['from'] = tx.outputs[0]
#transfer_data['token_address'] = tx.inputs[0] #transfer_data['token_address'] = tx.inputs[0]
faucet_contract = tx.inputs[0] faucet_contract = tx.inputs[0]

View File

@@ -10,14 +10,15 @@ from chainlib.eth.tx import unpack
from chainqueue.db.enum import StatusBits from chainqueue.db.enum import StatusBits
from chainqueue.db.models.tx import TxCache from chainqueue.db.models.tx import TxCache
from chainqueue.db.models.otx import Otx from chainqueue.db.models.otx import Otx
from chainqueue.sql.query import get_paused_tx_cache as get_paused_tx
from chainlib.eth.address import to_checksum_address from chainlib.eth.address import to_checksum_address
# local imports # local imports
from cic_eth.db.models.base import SessionBase from cic_eth.db.models.base import SessionBase
from cic_eth.eth.gas import create_check_gas_task from cic_eth.eth.gas import create_check_gas_task
from cic_eth.queue.query import get_paused_tx
from .base import SyncFilter from .base import SyncFilter
#logg = logging.getLogger().getChild(__name__)
logg = logging.getLogger() logg = logging.getLogger()

View File

@@ -12,8 +12,7 @@ from hexathon import (
# local imports # local imports
from .base import SyncFilter from .base import SyncFilter
#logg = logging.getLogger(__name__) logg = logging.getLogger(__name__)
logg = logging.getLogger()
account_registry_add_log_hash = '0x9cc987676e7d63379f176ea50df0ae8d2d9d1141d1231d4ce15b5965f73c9430' account_registry_add_log_hash = '0x9cc987676e7d63379f176ea50df0ae8d2d9d1141d1231d4ce15b5965f73c9430'

View File

@@ -17,7 +17,6 @@ from cic_eth_registry import CICRegistry
from erc20_transfer_authorization import TransferAuthorization from erc20_transfer_authorization import TransferAuthorization
# local imports # local imports
from cic_eth.encode import tx_normalize
from .base import SyncFilter from .base import SyncFilter
@@ -53,9 +52,9 @@ class TransferAuthFilter(SyncFilter):
r = TransferAuthorization.parse_create_request_request(tx.payload) r = TransferAuthorization.parse_create_request_request(tx.payload)
sender = tx_normalize.wallet_address(r[0]) sender = r[0]
recipient = tx_normalize.wallet_address(r[1]) recipient = r[1]
token = tx_normalize.executable_address(r[2]) token = r[2]
value = r[3] value = r[3]
token_data = { token_data = {

View File

@@ -69,6 +69,7 @@ from cic_eth.registry import (
) )
from cic_eth.task import BaseTask from cic_eth.task import BaseTask
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()
@@ -206,11 +207,10 @@ def main():
BaseTask.default_token_symbol = config.get('CIC_DEFAULT_TOKEN_SYMBOL') BaseTask.default_token_symbol = config.get('CIC_DEFAULT_TOKEN_SYMBOL')
BaseTask.default_token_address = registry.by_name(BaseTask.default_token_symbol) BaseTask.default_token_address = registry.by_name(BaseTask.default_token_symbol)
default_token = ERC20Token(chain_spec, conn, add_0x(BaseTask.default_token_address)) default_token = ERC20Token(chain_spec, conn, BaseTask.default_token_address)
default_token.load(conn) default_token.load(conn)
BaseTask.default_token_decimals = default_token.decimals BaseTask.default_token_decimals = default_token.decimals
BaseTask.default_token_name = default_token.name BaseTask.default_token_name = default_token.name
BaseTask.trusted_addresses = trusted_addresses
BaseTask.run_dir = config.get('CIC_RUN_DIR') BaseTask.run_dir = config.get('CIC_RUN_DIR')
logg.info('default token set to {} {}'.format(BaseTask.default_token_symbol, BaseTask.default_token_address)) logg.info('default token set to {} {}'.format(BaseTask.default_token_symbol, BaseTask.default_token_address))

View File

@@ -13,6 +13,7 @@ from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.gas import RPCGasOracle from chainlib.eth.gas import RPCGasOracle
from cic_eth_registry import CICRegistry from cic_eth_registry import CICRegistry
from cic_eth_registry.error import UnknownContractError from cic_eth_registry.error import UnknownContractError
import liveness.linux
# local imports # local imports
from cic_eth.error import SeppukuError from cic_eth.error import SeppukuError
@@ -28,7 +29,6 @@ class BaseTask(celery.Task):
session_func = SessionBase.create_session session_func = SessionBase.create_session
call_address = ZERO_ADDRESS call_address = ZERO_ADDRESS
trusted_addresses = []
create_nonce_oracle = RPCNonceOracle create_nonce_oracle = RPCNonceOracle
create_gas_oracle = RPCGasOracle create_gas_oracle = RPCGasOracle
default_token_address = None default_token_address = None
@@ -48,7 +48,6 @@ class BaseTask(celery.Task):
def on_failure(self, exc, task_id, args, kwargs, einfo): def on_failure(self, exc, task_id, args, kwargs, einfo):
if isinstance(exc, SeppukuError): if isinstance(exc, SeppukuError):
import liveness.linux
liveness.linux.reset(rundir=self.run_dir) liveness.linux.reset(rundir=self.run_dir)
logg.critical(einfo) logg.critical(einfo)
msg = 'received critical exception {}, calling shutdown'.format(str(exc)) msg = 'received critical exception {}, calling shutdown'.format(str(exc))

View File

@@ -10,7 +10,7 @@ version = (
0, 0,
12, 12,
4, 4,
'alpha.11', 'alpha.4',
) )
version_object = semver.VersionInfo( version_object = semver.VersionInfo(

View File

@@ -1,6 +1,8 @@
@node cic-eth configuration @node cic-eth configuration
@section Configuration @section Configuration
(refer to @code{cic-base} for a general overview of the config pipeline)
Configuration parameters are grouped by configuration filename. Configuration parameters are grouped by configuration filename.
@@ -38,26 +40,7 @@ Boolean value. If set, the amount of available context for a task in the result
@subsection database @subsection database
@table @var See ref cic-base when ready
@item host
Database host
@item port
Database port
@item name
Database name
@item user
Database user
@item password
Database password
@item engine
The engine part of the dsn connection string (@code{postgresql} in @code{postgresql+psycopg2})
@item driver
The driver part of the dsn connection string (@code{psycopg2} in @code{postgresql+psycopg2})
@item pool_size
Connection pool size for database drivers that provide connection pooling
@item debug
Output actual sql queries to logs. Potentially very verbose
@end table
@subsection eth @subsection eth

View File

@@ -13,16 +13,7 @@ ARG EXTRA_PIP_ARGS=""
# pip install --index-url https://pypi.org/simple \ # pip install --index-url https://pypi.org/simple \
# --force-reinstall \ # --force-reinstall \
# --extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \ # --extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
# -r requirements.txt # -r requirements.txt
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL \
$EXTRA_PIP_ARGS \
cic-eth-aux-erc20-demurrage-token~=0.0.2a6
COPY *requirements.txt ./ COPY *requirements.txt ./
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \ RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url https://pypi.org/simple \ pip install --index-url https://pypi.org/simple \
@@ -31,21 +22,19 @@ RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
$EXTRA_PIP_ARGS \ $EXTRA_PIP_ARGS \
-r requirements.txt \ -r requirements.txt \
-r services_requirements.txt \ -r services_requirements.txt \
-r admin_requirements.txt -r admin_requirements.txt
# always install the latest signer
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL \
$EXTRA_PIP_ARGS \
crypto-dev-signer
COPY . . COPY . .
RUN python setup.py install RUN python setup.py install
ENV PYTHONPATH . ENV PYTHONPATH .
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL \
$EXTRA_PIP_ARGS \
cic-eth-aux-erc20-demurrage-token~=0.0.2a6
COPY docker/entrypoints/* ./ COPY docker/entrypoints/* ./
RUN chmod 755 *.sh RUN chmod 755 *.sh

View File

@@ -0,0 +1,71 @@
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
WORKDIR /usr/src/cic-eth
# Copy just the requirements and install....this _might_ give docker a hint on caching but we
# do load these all into setup.py later
# TODO can we take all the requirements out of setup.py and just do a pip install -r requirements.txt && python setup.py
#COPY cic-eth/requirements.txt .
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
ARG EXTRA_PIP_ARGS=""
#RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
# pip install --index-url https://pypi.org/simple \
# --force-reinstall \
# --extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
# -r requirements.txt
COPY *requirements.txt .
RUN pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL \
$EXTRA_PIP_ARGS \
-r requirements.txt \
-r services_requirements.txt \
-r admin_requirements.txt
COPY . .
RUN python setup.py install
COPY docker/entrypoints/* ./
RUN chmod 755 *.sh
# # ini files in config directory defines the configurable parameters for the application
# # they can all be overridden by environment variables
# # to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
COPY config/ /usr/local/etc/cic-eth/
COPY cic_eth/db/migrations/ /usr/local/share/cic-eth/alembic/
COPY crypto_dev_signer_config/ /usr/local/etc/crypto-dev-signer/
# TODO this kind of code sharing across projects should be discouraged...can we make util a library?
#COPY util/liveness/health.sh /usr/local/bin/health.sh
ENTRYPOINT []
# ------------------ PRODUCTION CONTAINER ----------------------
#FROM python:3.8.6-slim-buster as prod
#
#RUN apt-get update && \
# apt install -y gnupg libpq-dev procps
#
#WORKDIR /root
#
#COPY --from=dev /usr/local/bin/ /usr/local/bin/
#COPY --from=dev /usr/local/lib/python3.8/site-packages/ \
# /usr/local/lib/python3.8/site-packages/
#
#COPY docker/entrypoints/* ./
#RUN chmod 755 *.sh
#
## # ini files in config directory defines the configurable parameters for the application
## # they can all be overridden by environment variables
## # to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
#COPY config/ /usr/local/etc/cic-eth/
#COPY cic_eth/db/migrations/ /usr/local/share/cic-eth/alembic/
#COPY crypto_dev_signer_config/ /usr/local/etc/crypto-dev-signer/
#COPY scripts/ scripts/
#
## TODO this kind of code sharing across projects should be discouraged...can we make util a library?
##COPY util/liveness/health.sh /usr/local/bin/health.sh
#
#ENTRYPOINT []
#

View File

@@ -5,27 +5,27 @@ set -e
# set CONFINI_ENV_PREFIX to override the env prefix to override env vars # set CONFINI_ENV_PREFIX to override the env prefix to override env vars
#echo "!!! starting signer" echo "!!! starting signer"
#python /usr/local/bin/crypto-dev-daemon -c /usr/local/etc/crypto-dev-signer -vv 2> /tmp/signer.log & python /usr/local/bin/crypto-dev-daemon -c /usr/local/etc/crypto-dev-signer -vv 2> /tmp/signer.log &
echo "!!! starting taskerd" echo "!!! starting taskerd"
/usr/local/bin/cic-eth-taskerd $@ /usr/local/bin/cic-eth-taskerd $@
# thanks! https://docs.docker.com/config/containers/multi-service_container/ # thanks! https://docs.docker.com/config/containers/multi-service_container/
#sleep 1; sleep 1;
#echo "!!! entering monitor loop" echo "!!! entering monitor loop"
#while true; do while true; do
# ps aux | grep crypto-dev-daemon | grep -q -v grep ps aux | grep crypto-dev-daemon | grep -q -v grep
# PROCESS_1_STATUS=$? PROCESS_1_STATUS=$?
# ps aux | grep cic-eth-tasker |grep -q -v grep ps aux | grep cic-eth-tasker |grep -q -v grep
# PROCESS_2_STATUS=$? PROCESS_2_STATUS=$?
# # If the greps above find anything, they exit with 0 status # If the greps above find anything, they exit with 0 status
# # If they are not both 0, then something is wrong # If they are not both 0, then something is wrong
# if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
# echo "One of the processes has already exited." echo "One of the processes has already exited."
# exit 1 exit 1
# fi fi
# sleep 15; sleep 15;
#done done
#
set +e set +e

View File

@@ -1,11 +0,0 @@
#! /bin/bash
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 --extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
-r admin_requirements.txt \
-r services_requirements.txt \
-r test_requirements.txt
export PYTHONPATH=. && pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests

View File

@@ -1,4 +1,3 @@
celery==4.4.7 celery==4.4.7
chainlib-eth>=0.0.9rc4,<0.1.0 chainlib-eth>=0.0.9a3,<0.1.0
semver==2.13.0 semver==2.13.0
crypto-dev-signer>=0.4.15rc2,<0.5.0

View File

@@ -1,16 +1,15 @@
chainqueue>=0.0.5a1,<0.1.0 chainqueue>=0.0.3a2,<0.1.0
chainsyncer[sql]>=0.0.6a3,<0.1.0 chainsyncer[sql]>=0.0.6a1,<0.1.0
alembic==1.4.2 alembic==1.4.2
confini>=0.3.6rc4,<0.5.0 confini>=0.3.6rc4,<0.5.0
redis==3.5.3 redis==3.5.3
hexathon~=0.0.1a8 hexathon~=0.0.1a8
pycryptodome==3.10.1 pycryptodome==3.10.1
liveness~=0.0.1a7 liveness~=0.0.1a7
eth-address-index>=0.2.4a1,<0.3.0 eth-address-index>=0.2.3a4,<0.3.0
eth-accounts-index>=0.1.2a3,<0.2.0 eth-accounts-index>=0.1.2a3,<0.2.0
cic-eth-registry>=0.6.1a5,<0.7.0 cic-eth-registry>=0.6.1a2,<0.7.0
erc20-faucet>=0.3.2a2,<0.4.0 erc20-faucet>=0.3.2a2,<0.4.0
erc20-transfer-authorization>=0.3.5a2,<0.4.0 erc20-transfer-authorization>=0.3.5a2,<0.4.0
sarafu-faucet>=0.0.7a2,<0.1.0 sarafu-faucet>=0.0.7a2,<0.1.0
moolb~=0.1.1b2 moolb~=0.1.1b2
okota>=0.2.4a6,<0.3.0

View File

@@ -18,10 +18,7 @@ from eth_erc20 import ERC20
from sarafu_faucet import MinterFaucet from sarafu_faucet import MinterFaucet
from eth_accounts_index.registry import AccountRegistry from eth_accounts_index.registry import AccountRegistry
from potaahto.symbols import snake_and_camel from potaahto.symbols import snake_and_camel
from hexathon import ( from hexathon import add_0x
add_0x,
strip_0x,
)
# local imports # local imports
from cic_eth.runnable.daemons.filters.callback import CallbackFilter from cic_eth.runnable.daemons.filters.callback import CallbackFilter
@@ -163,7 +160,7 @@ def test_faucet_gift_to_tx(
assert transfer_data['token_address'] == foo_token assert transfer_data['token_address'] == foo_token
def test_callback_filter_filter( def test_callback_filter(
default_chain_spec, default_chain_spec,
init_database, init_database,
eth_rpc, eth_rpc,
@@ -216,7 +213,6 @@ def test_callback_filter_filter(
def call_back(self, transfer_type, result): def call_back(self, transfer_type, result):
self.results[transfer_type] = result self.results[transfer_type] = result
logg.debug('result {}'.format(result))
return self return self
mock = CallbackMock() mock = CallbackMock()
@@ -225,4 +221,4 @@ def test_callback_filter_filter(
fltr.filter(eth_rpc, mockblock, tx, init_database) fltr.filter(eth_rpc, mockblock, tx, init_database)
assert mock.results.get('transfer') != None assert mock.results.get('transfer') != None
assert mock.results['transfer']['destination_token'] == strip_0x(foo_token) assert mock.results['transfer']['destination_token'] == foo_token

View File

@@ -1,6 +1,7 @@
# external imports # external imports
from chainlib.connection import RPCConnection from chainlib.connection import RPCConnection
from chainlib.eth.nonce import OverrideNonceOracle from chainlib.eth.nonce import OverrideNonceOracle
from chainqueue.sql.tx import create as queue_create
from chainlib.eth.tx import ( from chainlib.eth.tx import (
TxFormat, TxFormat,
unpack, unpack,
@@ -25,8 +26,6 @@ from chainqueue.db.enum import StatusBits
# local imports # local imports
from cic_eth.runnable.daemons.filters.gas import GasFilter from cic_eth.runnable.daemons.filters.gas import GasFilter
from cic_eth.eth.gas import cache_gas_data from cic_eth.eth.gas import cache_gas_data
from cic_eth.encode import tx_normalize
from cic_eth.queue.tx import queue_create
def test_filter_gas( def test_filter_gas(

View File

@@ -17,18 +17,15 @@ from chainlib.eth.block import (
block_by_number, block_by_number,
Block, Block,
) )
from chainlib.eth.address import (
to_checksum_address,
)
from erc20_faucet import Faucet from erc20_faucet import Faucet
from hexathon import ( from hexathon import (
strip_0x, strip_0x,
add_0x, add_0x,
) )
from chainqueue.sql.query import get_account_tx
# local imports # local imports
from cic_eth.runnable.daemons.filters.register import RegistrationFilter from cic_eth.runnable.daemons.filters.register import RegistrationFilter
from cic_eth.queue.query import get_account_tx_local
logg = logging.getLogger() logg = logging.getLogger()
@@ -72,18 +69,17 @@ def test_register_filter(
tx = Tx(tx_src, block=block, rcpt=rcpt) tx = Tx(tx_src, block=block, rcpt=rcpt)
tx.apply_receipt(rcpt) tx.apply_receipt(rcpt)
fltr = RegistrationFilter(default_chain_spec, to_checksum_address(os.urandom(20).hex()), queue=None) fltr = RegistrationFilter(default_chain_spec, add_0x(os.urandom(20).hex()), queue=None)
t = fltr.filter(eth_rpc, block, tx, db_session=init_database) t = fltr.filter(eth_rpc, block, tx, db_session=init_database)
assert t == None assert t == None
fltr = RegistrationFilter(default_chain_spec, to_checksum_address(account_registry), queue=None) fltr = RegistrationFilter(default_chain_spec, account_registry, queue=None)
t = fltr.filter(eth_rpc, block, tx, db_session=init_database) t = fltr.filter(eth_rpc, block, tx, db_session=init_database)
logg.debug('t {}'.format(t))
t.get_leaf() t.get_leaf()
assert t.successful() assert t.successful()
gift_txs = get_account_tx_local(default_chain_spec, agent_roles['ALICE'], as_sender=True, session=init_database) gift_txs = get_account_tx(default_chain_spec.asdict(), agent_roles['ALICE'], as_sender=True, session=init_database)
ks = list(gift_txs.keys()) ks = list(gift_txs.keys())
assert len(ks) == 1 assert len(ks) == 1
@@ -92,4 +88,4 @@ def test_register_filter(
gift_tx = unpack(tx_raw_signed_bytes, default_chain_spec) gift_tx = unpack(tx_raw_signed_bytes, default_chain_spec)
gift = Faucet.parse_give_to_request(gift_tx['data']) gift = Faucet.parse_give_to_request(gift_tx['data'])
assert add_0x(gift[0]) == agent_roles['ALICE'] assert gift[0] == agent_roles['ALICE']

View File

@@ -19,7 +19,6 @@ from chainqueue.sql.query import get_account_tx
# local imports # local imports
from cic_eth.runnable.daemons.filters.transferauth import TransferAuthFilter from cic_eth.runnable.daemons.filters.transferauth import TransferAuthFilter
from cic_eth.encode import tx_normalize
def test_filter_transferauth( def test_filter_transferauth(
@@ -67,8 +66,7 @@ def test_filter_transferauth(
t.get_leaf() t.get_leaf()
assert t.successful() assert t.successful()
#approve_txs = get_account_tx(default_chain_spec.asdict(), agent_roles['ALICE'], as_sender=True, session=init_database) approve_txs = get_account_tx(default_chain_spec.asdict(), agent_roles['ALICE'], as_sender=True, session=init_database)
approve_txs = get_account_tx(default_chain_spec.asdict(), tx_normalize.wallet_address(agent_roles['ALICE']), as_sender=True, session=init_database)
ks = list(approve_txs.keys()) ks = list(approve_txs.keys())
assert len(ks) == 1 assert len(ks) == 1
@@ -78,4 +76,4 @@ def test_filter_transferauth(
c = ERC20(default_chain_spec) c = ERC20(default_chain_spec)
approve = c.parse_approve_request(approve_tx['data']) approve = c.parse_approve_request(approve_tx['data'])
assert approve[0] == strip_0x(agent_roles['BOB']) assert approve[0] == agent_roles['BOB']

View File

@@ -1,10 +0,0 @@
#! /bin/bash
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 --extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
-r admin_requirements.txt
-r services_requirements.txt
-r test_requirements.txt
export PYTHONPATH=. && pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests

View File

@@ -34,6 +34,10 @@ from chainqueue.sql.state import (
set_ready, set_ready,
set_reserved, set_reserved,
) )
from chainqueue.sql.query import (
get_tx,
get_nonce_tx_cache,
)
# local imports # local imports
from cic_eth.api.admin import AdminApi from cic_eth.api.admin import AdminApi
@@ -42,11 +46,6 @@ from cic_eth.db.enum import LockEnum
from cic_eth.error import InitializationError from cic_eth.error import InitializationError
from cic_eth.eth.gas import cache_gas_data from cic_eth.eth.gas import cache_gas_data
from cic_eth.queue.tx import queue_create from cic_eth.queue.tx import queue_create
from cic_eth.queue.query import (
get_tx,
get_nonce_tx_local,
)
from cic_eth.encode import tx_normalize
logg = logging.getLogger() logg = logging.getLogger()
@@ -110,8 +109,8 @@ def test_tag_account(
t = api.tag_account('bar', agent_roles['CAROL'], default_chain_spec) t = api.tag_account('bar', agent_roles['CAROL'], default_chain_spec)
t.get() t.get()
assert AccountRole.get_address('foo', init_database) == tx_normalize.wallet_address(agent_roles['ALICE']) assert AccountRole.get_address('foo', init_database) == agent_roles['ALICE']
assert AccountRole.get_address('bar', init_database) == tx_normalize.wallet_address(agent_roles['CAROL']) assert AccountRole.get_address('bar', init_database) == agent_roles['CAROL']
def test_tx( def test_tx(
@@ -287,15 +286,13 @@ def test_fix_nonce(
assert t.successful() assert t.successful()
init_database.commit() init_database.commit()
logg.debug('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!') txs = get_nonce_tx_cache(default_chain_spec, 3, agent_roles['ALICE'], session=init_database)
txs = get_nonce_tx_local(default_chain_spec, 3, agent_roles['ALICE'], session=init_database)
ks = txs.keys() ks = txs.keys()
assert len(ks) == 2 assert len(ks) == 2
for k in ks: for k in ks:
#hsh = add_0x(k) hsh = add_0x(k)
hsh = tx_normalize.tx_hash(k)
otx = Otx.load(hsh, session=init_database) otx = Otx.load(hsh, session=init_database)
init_database.refresh(otx) init_database.refresh(otx)
logg.debug('checking nonce {} tx {} status {}'.format(3, otx.tx_hash, otx.status)) logg.debug('checking nonce {} tx {} status {}'.format(3, otx.tx_hash, otx.status))

View File

@@ -30,6 +30,7 @@ from chainqueue.sql.state import (
) )
from chainqueue.db.models.otx import Otx from chainqueue.db.models.otx import Otx
from chainqueue.db.enum import StatusBits from chainqueue.db.enum import StatusBits
from chainqueue.sql.query import get_nonce_tx_cache
from eth_erc20 import ERC20 from eth_erc20 import ERC20
from cic_eth_registry import CICRegistry from cic_eth_registry import CICRegistry
@@ -37,7 +38,6 @@ from cic_eth_registry import CICRegistry
from cic_eth.api.admin import AdminApi from cic_eth.api.admin import AdminApi
from cic_eth.eth.gas import cache_gas_data from cic_eth.eth.gas import cache_gas_data
from cic_eth.eth.erc20 import cache_transfer_data from cic_eth.eth.erc20 import cache_transfer_data
from cic_eth.queue.query import get_nonce_tx_local
logg = logging.getLogger() logg = logging.getLogger()
@@ -312,7 +312,7 @@ def test_resend_inplace(
otx = Otx.load(tx_hash_hex, session=init_database) otx = Otx.load(tx_hash_hex, session=init_database)
assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE
txs = get_nonce_tx_local(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database) txs = get_nonce_tx_cache(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database)
assert len(txs) == 2 assert len(txs) == 2
@@ -363,10 +363,10 @@ def test_resend_clone(
assert otx.status & StatusBits.IN_NETWORK == StatusBits.IN_NETWORK assert otx.status & StatusBits.IN_NETWORK == StatusBits.IN_NETWORK
assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE
txs = get_nonce_tx_local(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database) txs = get_nonce_tx_cache(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database)
assert len(txs) == 1 assert len(txs) == 1
txs = get_nonce_tx_local(default_chain_spec, otx.nonce + 1, agent_roles['ALICE'], session=init_database) txs = get_nonce_tx_cache(default_chain_spec, otx.nonce + 1, agent_roles['ALICE'], session=init_database)
assert len(txs) == 1 assert len(txs) == 1
otx = Otx.load(txs[0], session=init_database) otx = Otx.load(txs[0], session=init_database)

View File

@@ -10,7 +10,6 @@ from cic_eth_registry.erc20 import ERC20Token
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from eth_accounts_index import AccountsIndex from eth_accounts_index import AccountsIndex
from chainlib.eth.tx import ( from chainlib.eth.tx import (
receipt,
transaction, transaction,
) )
from chainqueue.sql.state import ( from chainqueue.sql.state import (
@@ -30,7 +29,6 @@ def test_account_api(
init_database, init_database,
init_eth_rpc, init_eth_rpc,
account_registry, account_registry,
cic_registry,
custodial_roles, custodial_roles,
celery_session_worker, celery_session_worker,
): ):
@@ -51,7 +49,6 @@ def test_account_api_register(
eth_rpc, eth_rpc,
celery_session_worker, celery_session_worker,
): ):
api = Api(str(default_chain_spec), callback_param='accounts', callback_task='cic_eth.callbacks.noop.noop', queue=None) api = Api(str(default_chain_spec), callback_param='accounts', callback_task='cic_eth.callbacks.noop.noop', queue=None)
t = api.create_account('') t = api.create_account('')
register_tx_hash = t.get_leaf() register_tx_hash = t.get_leaf()
@@ -72,18 +69,12 @@ def test_account_api_register(
r = t.get_leaf() r = t.get_leaf()
assert t.successful() assert t.successful()
o = receipt(register_tx_hash)
r = eth_rpc.do(o)
assert r['status'] == 1
o = transaction(register_tx_hash) o = transaction(register_tx_hash)
tx_src = eth_rpc.do(o) tx_src = eth_rpc.do(o)
c = AccountsIndex(default_chain_spec) c = AccountsIndex(default_chain_spec)
address = c.parse_add_request(tx_src['data']) address = c.parse_add_request(tx_src['data'])
logg.debug('address {} '.format(address))
o = c.have(account_registry, address[0], sender_address=custodial_roles['CONTRACT_DEPLOYER']) o = c.have(account_registry, address[0], sender_address=custodial_roles['CONTRACT_DEPLOYER'])
logg.debug('o {}'.format(o))
r = eth_rpc.do(o) r = eth_rpc.do(o)
assert c.parse_have(r) assert c.parse_have(r)

View File

@@ -1,27 +1,6 @@
# standard imports
import logging
import os
import uuid
import time
import mmap
# external imports
import celery
import pytest
from hexathon import (
strip_0x,
uniform as hex_uniform,
)
# local imports # local imports
from cic_eth.api.api_task import Api from cic_eth.api.api_task import Api
from cic_eth.task import BaseTask from cic_eth.task import BaseTask
from cic_eth.error import TrustError
from cic_eth.encode import tx_normalize
from cic_eth.pytest.mock.callback import CallbackTask
logg = logging.getLogger()
def test_default_token( def test_default_token(
default_chain_spec, default_chain_spec,
@@ -38,175 +17,3 @@ def test_default_token(
t = api.default_token() t = api.default_token()
r = t.get_leaf() r = t.get_leaf()
assert r['address'] == foo_token assert r['address'] == foo_token
def test_to_v_list():
assert Api.to_v_list('', 0) == []
assert Api.to_v_list([], 0) == []
assert Api.to_v_list('foo', 1) == [['foo']]
assert Api.to_v_list(['foo'], 1) == [['foo']]
assert Api.to_v_list(['foo', 'bar'], 2) == [['foo'], ['bar']]
assert Api.to_v_list('foo', 3) == [['foo'], ['foo'], ['foo']]
assert Api.to_v_list([['foo'], ['bar']], 2) == [['foo'], ['bar']]
with pytest.raises(ValueError):
Api.to_v_list([['foo'], ['bar']], 3)
with pytest.raises(ValueError):
Api.to_v_list(['foo', 'bar'], 3)
with pytest.raises(ValueError):
Api.to_v_list([['foo'], ['bar'], ['baz']], 2)
assert Api.to_v_list([
['foo'],
'bar',
['inky', 'pinky', 'blinky', 'clyde'],
], 3) == [
['foo'],
['bar'],
['inky', 'pinky', 'blinky', 'clyde'],
]
def test_token_single(
default_chain_spec,
foo_token,
bar_token,
token_registry,
register_tokens,
register_lookups,
cic_registry,
init_database,
init_celery_tasks,
custodial_roles,
foo_token_declaration,
bar_token_declaration,
celery_session_worker,
):
api = Api(str(default_chain_spec), queue=None, callback_param='foo')
t = api.token('FOO', proof=None)
r = t.get()
logg.debug('rr {}'.format(r))
assert len(r) == 1
assert r[0]['address'] == strip_0x(foo_token)
t = api.token('FOO', proof=foo_token_declaration)
r = t.get()
assert len(r) == 1
assert r[0]['address'] == strip_0x(foo_token)
def test_tokens_noproof(
default_chain_spec,
foo_token,
bar_token,
token_registry,
register_tokens,
register_lookups,
cic_registry,
init_database,
init_celery_tasks,
custodial_roles,
foo_token_declaration,
bar_token_declaration,
celery_worker,
):
api = Api(str(default_chain_spec), queue=None, callback_param='foo')
t = api.tokens(['FOO'], proof=[])
r = t.get()
assert len(r) == 1
assert r[0]['address'] == strip_0x(foo_token)
t = api.tokens(['BAR'], proof='')
r = t.get()
assert len(r) == 1
assert r[0]['address'] == strip_0x(bar_token)
t = api.tokens(['FOO'], proof=None)
r = t.get()
assert len(r) == 1
assert r[0]['address'] == strip_0x(foo_token)
def test_tokens(
default_chain_spec,
foo_token,
bar_token,
token_registry,
register_tokens,
register_lookups,
cic_registry,
init_database,
init_celery_tasks,
custodial_roles,
foo_token_declaration,
bar_token_declaration,
celery_session_worker,
):
api = Api(str(default_chain_spec), queue=None, callback_param='foo')
t = api.tokens(['FOO'], proof=[[foo_token_declaration]])
r = t.get()
logg.debug('rr {}'.format(r))
assert len(r) == 1
assert r[0]['address'] == strip_0x(foo_token)
t = api.tokens(['BAR', 'FOO'], proof=[[bar_token_declaration], [foo_token_declaration]])
r = t.get()
logg.debug('results {}'.format(r))
assert len(r) == 2
assert r[1]['address'] == strip_0x(foo_token)
assert r[0]['address'] == strip_0x(bar_token)
celery_app = celery.current_app
results = []
targets = []
api_param = str(uuid.uuid4())
api = Api(str(default_chain_spec), queue=None, callback_param=api_param, callback_task='cic_eth.pytest.mock.callback.test_callback')
bogus_proof = os.urandom(32).hex()
t = api.tokens(['FOO'], proof=[[bogus_proof]])
r = t.get()
logg.debug('r {}'.format(r))
while True:
fp = os.path.join(CallbackTask.mmap_path, api_param)
try:
f = open(fp, 'rb')
except FileNotFoundError:
time.sleep(0.1)
logg.debug('look for {}'.format(fp))
continue
f = open(fp, 'rb')
m = mmap.mmap(f.fileno(), access=mmap.ACCESS_READ, length=1)
v = m.read(1)
m.close()
f.close()
assert v == b'\x01'
break
api_param = str(uuid.uuid4())
api = Api(str(default_chain_spec), queue=None, callback_param=api_param, callback_task='cic_eth.pytest.mock.callback.test_callback')
t = api.tokens(['BAR'], proof=[[bar_token_declaration]])
r = t.get()
logg.debug('rr {} {}'.format(r, t.children))
while True:
fp = os.path.join(CallbackTask.mmap_path, api_param)
try:
f = open(fp, 'rb')
except FileNotFoundError:
time.sleep(0.1)
continue
m = mmap.mmap(f.fileno(), access=mmap.ACCESS_READ, length=1)
v = m.read(1)
m.close()
f.close()
assert v == b'\x00'
break

View File

@@ -3,22 +3,18 @@ import os
import logging import logging
# external imports # external imports
import pytest
from chainlib.eth.address import to_checksum_address from chainlib.eth.address import to_checksum_address
from hexathon import add_0x
# local imports # local imports
from cic_eth.api.api_task import Api from cic_eth.api.api_task import Api
logg = logging.getLogger() logg = logging.getLogger()
def test_balance_simple_api( def test_balance_simple_api(
default_chain_spec, default_chain_spec,
init_database, init_database,
cic_registry, cic_registry,
foo_token, foo_token,
register_lookups,
register_tokens, register_tokens,
api, api,
celery_session_worker, celery_session_worker,
@@ -26,7 +22,7 @@ def test_balance_simple_api(
chain_str = str(default_chain_spec) chain_str = str(default_chain_spec)
a = add_0x(to_checksum_address(os.urandom(20).hex())) a = to_checksum_address('0x' + os.urandom(20).hex())
t = api.balance(a, 'FOO', include_pending=False) t = api.balance(a, 'FOO', include_pending=False)
r = t.get_leaf() r = t.get_leaf()
assert t.successful() assert t.successful()
@@ -40,7 +36,6 @@ def test_balance_complex_api(
init_database, init_database,
cic_registry, cic_registry,
foo_token, foo_token,
register_lookups,
register_tokens, register_tokens,
api, api,
celery_session_worker, celery_session_worker,
@@ -48,7 +43,7 @@ def test_balance_complex_api(
chain_str = str(default_chain_spec) chain_str = str(default_chain_spec)
a = add_0x(to_checksum_address(os.urandom(20).hex())) a = to_checksum_address('0x' + os.urandom(20).hex())
t = api.balance(a, 'FOO', include_pending=True) t = api.balance(a, 'FOO', include_pending=True)
r = t.get_leaf() r = t.get_leaf()
assert t.successful() assert t.successful()

View File

@@ -6,7 +6,6 @@ import pytest
from chainlib.eth.nonce import RPCNonceOracle from chainlib.eth.nonce import RPCNonceOracle
from eth_erc20 import ERC20 from eth_erc20 import ERC20
from chainlib.eth.tx import receipt from chainlib.eth.tx import receipt
from hexathon import strip_0x
# local imports # local imports
from cic_eth.api.api_task import Api from cic_eth.api.api_task import Api
@@ -24,6 +23,7 @@ from cic_eth.pytest.mock.filter import (
logg = logging.getLogger() logg = logging.getLogger()
@pytest.mark.xfail()
def test_list_tx( def test_list_tx(
default_chain_spec, default_chain_spec,
init_database, init_database,
@@ -34,10 +34,8 @@ def test_list_tx(
agent_roles, agent_roles,
foo_token, foo_token,
register_tokens, register_tokens,
register_lookups,
init_eth_tester, init_eth_tester,
celery_session_worker, celery_session_worker,
init_celery_tasks,
): ):
tx_hashes = [] tx_hashes = []
@@ -65,16 +63,13 @@ def test_list_tx(
o = receipt(tx_hash_hex) o = receipt(tx_hash_hex)
r = eth_rpc.do(o) r = eth_rpc.do(o)
assert r['status'] == 1 assert r['status'] == 1
a = r['block_number'] a = r['block_number']
ab = a.to_bytes(4, 'big') block_filter.add(a.to_bytes(4, 'big'))
block_filter.add(ab)
bb = r['transaction_index'].to_bytes(4, 'big') a = r['block_number'] + r['transaction_index']
cb = ab + bb tx_filter.add(a.to_bytes(4, 'big'))
tx_filter.add(cb)
tx_hashes.append(strip_0x(tx_hash_hex)) tx_hashes.append(tx_hash_hex)
# external tx two # external tx two
Nonce.next(agent_roles['ALICE'], 'foo', session=init_database) Nonce.next(agent_roles['ALICE'], 'foo', session=init_database)
@@ -88,29 +83,26 @@ def test_list_tx(
o = receipt(tx_hash_hex) o = receipt(tx_hash_hex)
r = eth_rpc.do(o) r = eth_rpc.do(o)
assert r['status'] == 1 assert r['status'] == 1
a = r['block_number'] a = r['block_number']
ab = a.to_bytes(4, 'big') block_filter.add(a.to_bytes(4, 'big'))
block_filter.add(ab)
bb = r['transaction_index'].to_bytes(4, 'big') a = r['block_number'] + r['transaction_index']
cb = ab + bb tx_filter.add(a.to_bytes(4, 'big'))
tx_filter.add(cb)
tx_hashes.append(strip_0x(tx_hash_hex)) tx_hashes.append(tx_hash_hex)
init_eth_tester.mine_blocks(28) init_eth_tester.mine_blocks(28)
# custodial tx 1 # custodial tx 1
api = Api(str(default_chain_spec), queue=None) api = Api(str(default_chain_spec), queue=None)
t = api.transfer(agent_roles['ALICE'], agent_roles['CAROL'], 64, 'FOO') t = api.transfer(agent_roles['ALICE'], agent_roles['CAROL'], 64, 'FOO') #, 'blinky')
r = t.get_leaf() r = t.get_leaf()
assert t.successful() assert t.successful()
tx_hashes.append(r) tx_hashes.append(r)
# custodial tx 2 # custodial tx 2
api = Api(str(default_chain_spec), queue=None) api = Api(str(default_chain_spec), queue=None)
t = api.transfer(agent_roles['ALICE'], agent_roles['DAVE'], 16, 'FOO') t = api.transfer(agent_roles['ALICE'], agent_roles['DAVE'], 16, 'FOO') #, 'blinky')
r = t.get_leaf() r = t.get_leaf()
assert t.successful() assert t.successful()
tx_hashes.append(r) tx_hashes.append(r)
@@ -125,8 +117,7 @@ def test_list_tx(
assert len(r) == 3 assert len(r) == 3
logg.debug('rrrr {}'.format(r)) logg.debug('rrrr {}'.format(r))
logg.debug('testing against hashes {}'.format(tx_hashes))
for tx in r: for tx in r:
logg.debug('have tx {}'.format(tx)) logg.debug('have tx {}'.format(tx))
tx_hashes.remove(strip_0x(tx['hash'])) tx_hashes.remove(tx['hash'])
assert len(tx_hashes) == 1 assert len(tx_hashes) == 1

View File

@@ -10,7 +10,6 @@ from chainlib.eth.tx import (
) )
from eth_erc20 import ERC20 from eth_erc20 import ERC20
from chainlib.eth.nonce import RPCNonceOracle from chainlib.eth.nonce import RPCNonceOracle
from hexathon import add_0x
# local imports # local imports
from cic_eth.db.models.nonce import ( from cic_eth.db.models.nonce import (
@@ -92,5 +91,5 @@ def test_filter_process(
assert len(r) == 2 assert len(r) == 2
for tx_hash in r.keys(): for tx_hash in r.keys():
tx_hashes.remove(add_0x(tx_hash)) tx_hashes.remove(tx_hash)
assert len(tx_hashes) == 0 assert len(tx_hashes) == 0

View File

@@ -21,6 +21,7 @@ from chainlib.eth.constant import (
MINIMUM_FEE_UNITS, MINIMUM_FEE_UNITS,
MINIMUM_FEE_PRICE, MINIMUM_FEE_PRICE,
) )
from chainqueue.sql.tx import create as queue_create
from chainqueue.sql.query import get_tx from chainqueue.sql.query import get_tx
from chainqueue.db.enum import StatusBits from chainqueue.db.enum import StatusBits
from chainqueue.sql.state import ( from chainqueue.sql.state import (
@@ -34,7 +35,6 @@ from hexathon import strip_0x
# local imports # local imports
from cic_eth.eth.gas import cache_gas_data from cic_eth.eth.gas import cache_gas_data
from cic_eth.error import OutOfGasError from cic_eth.error import OutOfGasError
from cic_eth.queue.tx import queue_create
logg = logging.getLogger() logg = logging.getLogger()
@@ -75,7 +75,7 @@ def test_task_check_gas_ok(
'cic_eth.eth.gas.check_gas', 'cic_eth.eth.gas.check_gas',
[ [
[ [
strip_0x(tx_hash_hex), tx_hash_hex,
], ],
default_chain_spec.asdict(), default_chain_spec.asdict(),
[], [],
@@ -283,3 +283,4 @@ def test_task_resend_explicit(
tx_after = unpack(bytes.fromhex(strip_0x(otx.signed_tx)), default_chain_spec) tx_after = unpack(bytes.fromhex(strip_0x(otx.signed_tx)), default_chain_spec)
logg.debug('gasprices before {} after {}'.format(tx_before['gasPrice'], tx_after['gasPrice'])) logg.debug('gasprices before {} after {}'.format(tx_before['gasPrice'], tx_after['gasPrice']))
assert tx_after['gasPrice'] > tx_before['gasPrice'] assert tx_after['gasPrice'] > tx_before['gasPrice']

View File

@@ -51,7 +51,6 @@ def test_ext_tx_collate(
tx_hash_hex, tx_hash_hex,
tx_signed_raw_hex, tx_signed_raw_hex,
) )
otx.block = 666
init_database.add(otx) init_database.add(otx)
init_database.commit() init_database.commit()

View File

@@ -10,7 +10,7 @@ def test_default_token(
): ):
s = celery.signature( s = celery.signature(
'cic_eth.eth.erc20.default_token', 'cic_eth.admin.token.default_token',
[], [],
queue=None, queue=None,
) )

View File

@@ -46,7 +46,6 @@ def test_set(
tx_hash_hex, tx_hash_hex,
tx_signed_raw_hex, tx_signed_raw_hex,
) )
otx.block = 666
init_database.add(otx) init_database.add(otx)
init_database.commit() init_database.commit()
@@ -75,6 +74,7 @@ def test_set(
assert (tx_stored.destination_token_address == ZERO_ADDRESS) assert (tx_stored.destination_token_address == ZERO_ADDRESS)
assert (tx_stored.from_value == tx['value']) assert (tx_stored.from_value == tx['value'])
assert (tx_stored.to_value == to_value) assert (tx_stored.to_value == to_value)
assert (tx_stored.block_number == 666)
assert (tx_stored.tx_index == 13) assert (tx_stored.tx_index == 13)

View File

@@ -13,7 +13,6 @@ from cic_eth.queue.balance import (
balance_incoming, balance_incoming,
assemble_balances, assemble_balances,
) )
from cic_eth.encode import tx_normalize
logg = logging.getLogger() logg = logging.getLogger()
@@ -52,8 +51,8 @@ def test_assemble():
r = assemble_balances(b) r = assemble_balances(b)
logg.debug('r {}'.format(r)) logg.debug('r {}'.format(r))
assert r[0]['address'] == tx_normalize.executable_address(token_foo) assert r[0]['address'] == token_foo
assert r[1]['address'] == tx_normalize.executable_address(token_bar) assert r[1]['address'] == token_bar
assert r[0].get('balance_foo') != None assert r[0].get('balance_foo') != None
assert r[0].get('balance_bar') != None assert r[0].get('balance_bar') != None
assert r[1].get('balance_baz') != None assert r[1].get('balance_baz') != None
@@ -75,11 +74,11 @@ def test_outgoing_balance(
token_address = '0x' + os.urandom(20).hex() token_address = '0x' + os.urandom(20).hex()
sender = '0x' + os.urandom(20).hex() sender = '0x' + os.urandom(20).hex()
txc = TxCache( txc = TxCache(
tx_normalize.tx_hash(tx_hash), tx_hash,
tx_normalize.wallet_address(sender), sender,
tx_normalize.wallet_address(recipient), recipient,
tx_normalize.executable_address(token_address), token_address,
tx_normalize.executable_address(token_address), token_address,
1000, 1000,
1000, 1000,
session=init_database, session=init_database,
@@ -126,11 +125,11 @@ def test_incoming_balance(
token_address = '0x' + os.urandom(20).hex() token_address = '0x' + os.urandom(20).hex()
sender = '0x' + os.urandom(20).hex() sender = '0x' + os.urandom(20).hex()
txc = TxCache( txc = TxCache(
tx_normalize.tx_hash(tx_hash), tx_hash,
tx_normalize.wallet_address(sender), sender,
tx_normalize.wallet_address(recipient), recipient,
tx_normalize.executable_address(token_address), token_address,
tx_normalize.executable_address(token_address), token_address,
1000, 1000,
1000, 1000,
session=init_database, session=init_database,

View File

@@ -21,7 +21,6 @@ from cic_eth.db.models.lock import Lock
from cic_eth.queue.query import get_upcoming_tx from cic_eth.queue.query import get_upcoming_tx
from cic_eth.queue.tx import register_tx from cic_eth.queue.tx import register_tx
from cic_eth.eth.gas import cache_gas_data from cic_eth.eth.gas import cache_gas_data
from cic_eth.encode import tx_normalize
# test imports # test imports
from tests.util.nonce import StaticNonceOracle from tests.util.nonce import StaticNonceOracle
@@ -40,8 +39,8 @@ def test_upcoming_with_lock(
gas_oracle = RPCGasOracle(eth_rpc) gas_oracle = RPCGasOracle(eth_rpc)
c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle) c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
alice_normal = tx_normalize.wallet_address(agent_roles['ALICE']) alice_normal = add_0x(hex_uniform(strip_0x(agent_roles['ALICE'])))
bob_normal = tx_normalize.wallet_address(agent_roles['BOB']) bob_normal = add_0x(hex_uniform(strip_0x(agent_roles['BOB'])))
(tx_hash_hex, tx_rpc) = c.create(alice_normal, bob_normal, 100 * (10 ** 6)) (tx_hash_hex, tx_rpc) = c.create(alice_normal, bob_normal, 100 * (10 ** 6))
tx_signed_raw_hex = tx_rpc['params'][0] tx_signed_raw_hex = tx_rpc['params'][0]

View File

@@ -9,7 +9,7 @@ from cic_eth.db.models.lock import Lock
from cic_eth.db.enum import LockEnum from cic_eth.db.enum import LockEnum
from cic_eth.error import LockedError from cic_eth.error import LockedError
from cic_eth.queue.tx import queue_create from cic_eth.queue.tx import queue_create
from cic_eth.encode import tx_normalize
def test_queue_lock( def test_queue_lock(
init_database, init_database,
@@ -21,8 +21,6 @@ def test_queue_lock(
address = '0x' + os.urandom(20).hex() address = '0x' + os.urandom(20).hex()
tx_hash = '0x' + os.urandom(32).hex() tx_hash = '0x' + os.urandom(32).hex()
tx_raw = '0x' + os.urandom(128).hex() tx_raw = '0x' + os.urandom(128).hex()
address_normal = tx_normalize.wallet_address(address)
tx_hash_normal = tx_normalize.tx_hash(tx_hash)
Lock.set(chain_str, LockEnum.QUEUE) Lock.set(chain_str, LockEnum.QUEUE)
with pytest.raises(LockedError): with pytest.raises(LockedError):
@@ -34,7 +32,7 @@ def test_queue_lock(
tx_raw, tx_raw,
) )
Lock.set(chain_str, LockEnum.QUEUE, address=address_normal) Lock.set(chain_str, LockEnum.QUEUE, address=address)
with pytest.raises(LockedError): with pytest.raises(LockedError):
queue_create( queue_create(
default_chain_spec, default_chain_spec,
@@ -54,7 +52,7 @@ def test_queue_lock(
tx_raw, tx_raw,
) )
Lock.set(chain_str, LockEnum.QUEUE, address=address_normal, tx_hash=tx_hash_normal) Lock.set(chain_str, LockEnum.QUEUE, address=address, tx_hash=tx_hash)
with pytest.raises(LockedError): with pytest.raises(LockedError):
queue_create( queue_create(
default_chain_spec, default_chain_spec,
@@ -63,3 +61,5 @@ def test_queue_lock(
tx_hash, tx_hash,
tx_raw, tx_raw,
) )

View File

@@ -1,6 +1,6 @@
crypto-dev-signer>=0.4.15rc2,<=0.4.15 crypto-dev-signer>=0.4.15a1,<=0.4.15
chainqueue>=0.0.5a1,<0.1.0 chainqueue>=0.0.3a1,<0.1.0
cic-eth-registry>=0.6.1a5,<0.7.0 cic-eth-registry>=0.6.1a2,<0.7.0
redis==3.5.3 redis==3.5.3
hexathon~=0.0.1a8 hexathon~=0.0.1a8
pycryptodome==3.10.1 pycryptodome==3.10.1

View File

@@ -1,16 +1,43 @@
build-test-cic-meta:
stage: test .cic_meta_variables:
tags: variables:
- integration APP_NAME: cic-meta
variables: DOCKERFILE_PATH: docker/Dockerfile_ci
APP_NAME: cic-meta CONTEXT: apps/$APP_NAME
MR_IMAGE_TAG: mr-$APP_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA
script: build-mr-cic-meta:
- cd apps/cic-meta extends:
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile . - .py_build_merge_request
- docker run --entrypoint=sh $MR_IMAGE_TAG docker/run_tests.sh - .cic_meta_variables
rules: rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes: changes:
- apps/$APP_NAME/**/* - apps/cic-meta/**/*
when: always
test-mr-cic-meta:
extends:
- .cic_meta_variables
stage: test
image: $MR_IMAGE_TAG
script:
- cd /root
- npm install --dev
- npm run test
- npm run test:coverage
needs: ["build-mr-cic-meta"]
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/cic-meta/**/*
when: always
build-push-cic-meta:
extends:
- .py_build_push
- .cic_meta_variables
rules:
- if: $CI_COMMIT_BRANCH == "master"
changes:
- apps/cic-meta/**/*
when: always when: always

View File

@@ -1 +0,0 @@
# CIC-Meta

View File

@@ -15,10 +15,11 @@ RUN --mount=type=cache,mode=0755,target=/root/.npm \
COPY webpack.config.js . COPY webpack.config.js .
COPY tsconfig.json . COPY tsconfig.json .
## required to build the cic-client-meta module ## required to build the cic-client-meta module
COPY . . COPY src/ src/
COPY scripts/ scripts/
COPY tests/ tests/
COPY tests/*.asc /root/pgp/ COPY tests/*.asc /root/pgp/
## copy runtime configs ## copy runtime configs
COPY .config/ /usr/local/etc/cic-meta/ COPY .config/ /usr/local/etc/cic-meta/
# #

View File

@@ -0,0 +1,32 @@
# syntax = docker/dockerfile:1.2
#FROM node:15.3.0-alpine3.10
FROM node:lts-alpine3.14
WORKDIR /root
RUN apk add --no-cache postgresql bash
# copy the dependencies
COPY package.json package-lock.json .
RUN npm set cache /root/.npm && \
npm ci
COPY webpack.config.js .
COPY tsconfig.json .
## required to build the cic-client-meta module
COPY src/ src/
COPY scripts/ scripts/
COPY tests/ tests/
COPY tests/*.asc /root/pgp/
## copy runtime configs
COPY .config/ /usr/local/etc/cic-meta/
#
## db migrations
COPY docker/db.sh ./db.sh
RUN chmod 755 ./db.sh
#
RUN alias tsc=node_modules/typescript/bin/tsc
COPY docker/start_server.sh ./start_server.sh
RUN chmod 755 ./start_server.sh
ENTRYPOINT ["sh", "./start_server.sh"]

View File

@@ -1,7 +0,0 @@
#! /bin/bash
set -e
npm install --dev
npm run test
npm run test:coverage

View File

@@ -1,17 +1,52 @@
build-test-cic-notify: .cic_notify_variables:
stage: test variables:
tags: APP_NAME: cic-notify
- integration DOCKERFILE_PATH: docker/Dockerfile_ci
variables: CONTEXT: apps/$APP_NAME
APP_NAME: cic-notify
MR_IMAGE_TAG: mr-$APP_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA build-mr-cic-notify:
script: extends:
- cd apps/cic-notify - .py_build_merge_request
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile . - .cic_notify_variables
- docker run $MR_IMAGE_TAG sh docker/run_tests.sh rules:
allow_failure: true - if: $CI_PIPELINE_SOURCE == "merge_request_event"
rules: changes:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" - apps/cic-notify/**/*
changes: when: always
- apps/$APP_NAME/**/*
when: always test-mr-cic-notify:
stage: test
extends:
- .cic_notify_variables
cache:
key:
files:
- test_requirements.txt
paths:
- /root/.cache/pip
image: $MR_IMAGE_TAG
script:
- cd apps/$APP_NAME/
- >
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
-r test_requirements.txt
- export PYTHONPATH=. && pytest -x --cov=cic_notify --cov-fail-under=90 --cov-report term-missing tests
needs: ["build-mr-cic-notify"]
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/$APP_NAME/**/*
when: always
build-push-cic-notify:
extends:
- .py_build_push
- .cic_notify_variables
rules:
- if: $CI_COMMIT_BRANCH == "master"
changes:
- apps/cic-notify/**/*
when: always

View File

@@ -11,12 +11,12 @@ celery_app = celery.current_app
@celery_app.task @celery_app.task
def persist_notification(message, recipient): def persist_notification(recipient, message):
""" """
:param message:
:type message:
:param recipient: :param recipient:
:type recipient: :type recipient:
:param message:
:type message:
:return: :return:
:rtype: :rtype:
""" """

View File

@@ -11,13 +11,12 @@ local_logg = logging.getLogger(__name__)
@celery_app.task @celery_app.task
def log(message, recipient): def log(recipient, message):
""" """
:param message:
:type message:
:param recipient: :param recipient:
:type recipient: :type recipient:
:param message:
:type message:
:return: :return:
:rtype: :rtype:
""" """

View File

@@ -0,0 +1,27 @@
# syntax = docker/dockerfile:1.2
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
#RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2a62
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
COPY requirements.txt .
RUN pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
-r requirements.txt
COPY . .
RUN python setup.py install
COPY docker/*.sh .
RUN chmod +x *.sh
# ini files in config directory defines the configurable parameters for the application
# they can all be overridden by environment variables
# to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
COPY .config/ /usr/local/etc/cic-notify/
COPY cic_notify/db/migrations/ /usr/local/share/cic-notify/alembic/
ENTRYPOINT []

View File

@@ -1,9 +0,0 @@
#! /bin/bash
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 \
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
-r test_requirements.txt
export PYTHONPATH=. && pytest -x --cov=cic_notify --cov-fail-under=90 --cov-report term-missing tests

View File

@@ -1,16 +1,52 @@
build-test-cic-ussd: .cic_ussd_variables:
stage: test variables:
tags: APP_NAME: cic-ussd
- integration DOCKERFILE_PATH: docker/Dockerfile_ci
variables: CONTEXT: apps/$APP_NAME
APP_NAME: cic-ussd
MR_IMAGE_TAG: mr-$APP_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA build-mr-cic-ussd:
script: extends:
- cd apps/cic-ussd - .py_build_merge_request
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile . - .cic_ussd_variables
- docker run $MR_IMAGE_TAG sh docker/run_tests.sh rules:
rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_PIPELINE_SOURCE == "merge_request_event" changes:
changes: - apps/cic-ussd/**/*
- apps/$APP_NAME/**/* when: always
when: always
test-mr-cic-ussd:
stage: test
extends:
- .cic_ussd_variables
cache:
key:
files:
- test_requirements.txt
paths:
- /root/.cache/pip
image: $MR_IMAGE_TAG
script:
- cd apps/$APP_NAME/
- >
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
-r test_requirements.txt
- export PYTHONPATH=. && pytest -x --cov=cic_ussd --cov-fail-under=90 --cov-report term-missing tests/cic_ussd
needs: ["build-mr-cic-ussd"]
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/$APP_NAME/**/*
when: always
build-push-cic-ussd:
extends:
- .py_build_push
- .cic_ussd_variables
rules:
- if: $CI_COMMIT_BRANCH == "master"
changes:
- apps/cic-ussd/**/*
when: always

View File

@@ -1,12 +1,10 @@
# standard imports # standard imports
import json import json
import logging import logging
from typing import Optional from typing import Optional
# third-party imports # third-party imports
from cic_eth.api import Api from cic_eth.api import Api
from cic_eth_aux.erc20_demurrage_token.api import Api as DemurrageApi
# local imports # local imports
from cic_ussd.account.transaction import from_wei from cic_ussd.account.transaction import from_wei
@@ -22,7 +20,7 @@ def get_balances(address: str,
asynchronous: bool = False, asynchronous: bool = False,
callback_param: any = None, callback_param: any = None,
callback_queue='cic-ussd', callback_queue='cic-ussd',
callback_task='cic_ussd.tasks.callback_handler.balances_callback') -> Optional[list]: callback_task='cic_ussd.tasks.callback_handler.process_balances_callback') -> Optional[list]:
"""This function queries cic-eth for an account's balances, It provides a means to receive the balance either """This function queries cic-eth for an account's balances, It provides a means to receive the balance either
asynchronously or synchronously.. It returns a dictionary containing the network, outgoing and incoming balances. asynchronously or synchronously.. It returns a dictionary containing the network, outgoing and incoming balances.
:param address: Ethereum address of an account. :param address: Ethereum address of an account.
@@ -75,24 +73,6 @@ def calculate_available_balance(balances: dict) -> float:
return from_wei(value=available_balance) return from_wei(value=available_balance)
def get_adjusted_balance(balance: int, chain_str: str, timestamp: int, token_symbol: str):
"""
:param balance:
:type balance:
:param chain_str:
:type chain_str:
:param timestamp:
:type timestamp:
:param token_symbol:
:type token_symbol:
:return:
:rtype:
"""
logg.debug(f'retrieving adjusted balance on chain: {chain_str}')
demurrage_api = DemurrageApi(chain_str=chain_str)
return demurrage_api.get_adjusted_balance(token_symbol, balance, timestamp).result
def get_cached_available_balance(blockchain_address: str) -> float: def get_cached_available_balance(blockchain_address: str) -> float:
"""This function attempts to retrieve balance data from the redis cache. """This function attempts to retrieve balance data from the redis cache.
:param blockchain_address: Ethereum address of an account. :param blockchain_address: Ethereum address of an account.
@@ -101,21 +81,10 @@ def get_cached_available_balance(blockchain_address: str) -> float:
:return: Operational balance of an account. :return: Operational balance of an account.
:rtype: float :rtype: float
""" """
identifier = bytes.fromhex(blockchain_address) identifier = bytes.fromhex(blockchain_address[2:])
key = cache_data_key(identifier, salt=':cic.balances') key = cache_data_key(identifier, salt=':cic.balances')
cached_balances = get_cached_data(key=key) cached_balances = get_cached_data(key=key)
if cached_balances: if cached_balances:
return calculate_available_balance(json.loads(cached_balances)) return calculate_available_balance(json.loads(cached_balances))
else: else:
raise CachedDataNotFoundError(f'No cached available balance for address: {blockchain_address}') raise CachedDataNotFoundError(f'No cached available balance for address: {blockchain_address}')
def get_cached_adjusted_balance(identifier: bytes):
"""
:param identifier:
:type identifier:
:return:
:rtype:
"""
key = cache_data_key(identifier, ':cic.adjusted_balance')
return get_cached_data(key)

View File

@@ -4,6 +4,7 @@ import logging
from typing import Optional from typing import Optional
# external imports # external imports
from chainlib.hash import strip_0x
from cic_types.models.person import Person from cic_types.models.person import Person
# local imports # local imports
@@ -19,7 +20,7 @@ def get_cached_preferred_language(blockchain_address: str) -> Optional[str]:
:return: Account's set preferred language | Fallback preferred language. :return: Account's set preferred language | Fallback preferred language.
:rtype: str :rtype: str
""" """
identifier = bytes.fromhex(blockchain_address) identifier = bytes.fromhex(strip_0x(blockchain_address))
preferences_metadata_handler = PreferencesMetadata(identifier) preferences_metadata_handler = PreferencesMetadata(identifier)
cached_preferences_metadata = preferences_metadata_handler.get_cached_metadata() cached_preferences_metadata = preferences_metadata_handler.get_cached_metadata()
if cached_preferences_metadata: if cached_preferences_metadata:

View File

@@ -86,7 +86,7 @@ def query_statement(blockchain_address: str, limit: int = 9):
:param limit: Number of transactions to be returned. :param limit: Number of transactions to be returned.
:type limit: int :type limit: int
""" """
logg.debug(f'retrieving statement for address: {blockchain_address}') logg.debug(f'retrieving balance for address: {blockchain_address}')
chain_str = Chain.spec.__str__() chain_str = Chain.spec.__str__()
cic_eth_api = Api( cic_eth_api = Api(
chain_str=chain_str, chain_str=chain_str,

View File

@@ -1,6 +1,5 @@
# standard import # standard import
import decimal import decimal
import json
import logging import logging
from typing import Dict, Tuple from typing import Dict, Tuple
@@ -9,8 +8,6 @@ from cic_eth.api import Api
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
# local import # local import
from cic_ussd.account.chain import Chain
from cic_ussd.account.tokens import get_cached_default_token
from cic_ussd.db.models.account import Account from cic_ussd.db.models.account import Account
from cic_ussd.db.models.base import SessionBase from cic_ussd.db.models.base import SessionBase
from cic_ussd.error import UnknownUssdRecipient from cic_ussd.error import UnknownUssdRecipient
@@ -62,9 +59,7 @@ def from_wei(value: int) -> float:
:return: SRF equivalent of value in Wei :return: SRF equivalent of value in Wei
:rtype: float :rtype: float
""" """
cached_token_data = json.loads(get_cached_default_token(Chain.spec.__str__())) value = float(value) / 1e+6
token_decimals: int = cached_token_data.get('decimals')
value = float(value) / (10**token_decimals)
return truncate(value=value, decimals=2) return truncate(value=value, decimals=2)
@@ -75,9 +70,7 @@ def to_wei(value: int) -> int:
:return: Wei equivalent of value in SRF :return: Wei equivalent of value in SRF
:rtype: int :rtype: int
""" """
cached_token_data = json.loads(get_cached_default_token(Chain.spec.__str__())) return int(value * 1e+6)
token_decimals: int = cached_token_data.get('decimals')
return int(value * (10**token_decimals))
def truncate(value: float, decimals: int): def truncate(value: float, decimals: int):
@@ -124,18 +117,18 @@ def transaction_actors(transaction: dict) -> Tuple[Dict, Dict]:
return recipient_transaction_data, sender_transaction_data return recipient_transaction_data, sender_transaction_data
def validate_transaction_account(blockchain_address: str, role: str, session: Session) -> Account: def validate_transaction_account(session: Session, transaction: dict) -> Account:
"""This function checks whether the blockchain address specified in a parsed transaction object resolves to an """This function checks whether the blockchain address specified in a parsed transaction object resolves to an
account object in the ussd system. account object in the ussd system.
:param blockchain_address: :param session: Database session object.
:type blockchain_address: :type session: Session
:param role: :param transaction: Parsed transaction data object.
:type role: :type transaction: dict
:param session:
:type session:
:return: :return:
:rtype: :rtype:
""" """
blockchain_address = transaction.get('blockchain_address')
role = transaction.get('role')
session = SessionBase.bind_session(session) session = SessionBase.bind_session(session)
account = session.query(Account).filter_by(blockchain_address=blockchain_address).first() account = session.query(Account).filter_by(blockchain_address=blockchain_address).first()
if not account: if not account:

View File

@@ -2,6 +2,7 @@
import json import json
# external imports # external imports
from chainlib.hash import strip_0x
from cic_eth.api import Api from cic_eth.api import Api
# local imports # local imports
@@ -100,7 +101,7 @@ class Account(SessionBase):
session.add(self) session.add(self)
session.flush() session.flush()
SessionBase.release_session(session=session) SessionBase.release_session(session=session)
return 'Pin reset successful.' return f'Pin reset successful.'
def standard_metadata_id(self) -> str: def standard_metadata_id(self) -> str:
"""This function creates an account's standard metadata identification information that contains an account owner's """This function creates an account's standard metadata identification information that contains an account owner's
@@ -108,7 +109,7 @@ class Account(SessionBase):
:return: Standard metadata identification information | e164 formatted phone number. :return: Standard metadata identification information | e164 formatted phone number.
:rtype: str :rtype: str
""" """
identifier = bytes.fromhex(self.blockchain_address) identifier = bytes.fromhex(strip_0x(self.blockchain_address))
key = cache_data_key(identifier, ':cic.person') key = cache_data_key(identifier, ':cic.person')
account_metadata = get_cached_data(key) account_metadata = get_cached_data(key)
if not account_metadata: if not account_metadata:

View File

@@ -44,7 +44,7 @@ class MetadataRequestsHandler(Metadata):
def create(self, data: Union[Dict, str]): def create(self, data: Union[Dict, str]):
"""""" """"""
data = json.dumps(data).encode('utf-8') data = json.dumps(data)
result = make_request(method='POST', url=self.url, data=data, headers=self.headers) result = make_request(method='POST', url=self.url, data=data, headers=self.headers)
error_handler(result=result) error_handler(result=result)

View File

@@ -1,17 +1,13 @@
# standard imports # standard imports
import json import json
import logging import logging
from datetime import datetime, timedelta
# external imports # external imports
import i18n.config import i18n.config
from sqlalchemy.orm.session import Session
# local imports # local imports
from cic_ussd.account.balance import (calculate_available_balance, from cic_ussd.account.balance import calculate_available_balance, get_balances, get_cached_available_balance
get_adjusted_balance,
get_balances,
get_cached_adjusted_balance,
get_cached_available_balance)
from cic_ussd.account.chain import Chain from cic_ussd.account.chain import Chain
from cic_ussd.account.metadata import get_cached_preferred_language from cic_ussd.account.metadata import get_cached_preferred_language
from cic_ussd.account.statement import ( from cic_ussd.account.statement import (
@@ -20,15 +16,14 @@ from cic_ussd.account.statement import (
query_statement, query_statement,
statement_transaction_set statement_transaction_set
) )
from cic_ussd.account.tokens import get_default_token_symbol
from cic_ussd.account.transaction import from_wei, to_wei from cic_ussd.account.transaction import from_wei, to_wei
from cic_ussd.account.tokens import get_default_token_symbol
from cic_ussd.cache import cache_data_key, cache_data from cic_ussd.cache import cache_data_key, cache_data
from cic_ussd.db.models.account import Account from cic_ussd.db.models.account import Account
from cic_ussd.metadata import PersonMetadata from cic_ussd.metadata import PersonMetadata
from cic_ussd.phone_number import Support from cic_ussd.phone_number import Support
from cic_ussd.processor.util import parse_person_metadata from cic_ussd.processor.util import latest_input, parse_person_metadata
from cic_ussd.translation import translation_for from cic_ussd.translation import translation_for
from sqlalchemy.orm.session import Session
logg = logging.getLogger(__name__) logg = logging.getLogger(__name__)
@@ -37,7 +32,7 @@ class MenuProcessor:
def __init__(self, account: Account, display_key: str, menu_name: str, session: Session, ussd_session: dict): def __init__(self, account: Account, display_key: str, menu_name: str, session: Session, ussd_session: dict):
self.account = account self.account = account
self.display_key = display_key self.display_key = display_key
self.identifier = bytes.fromhex(self.account.blockchain_address) self.identifier = bytes.fromhex(self.account.blockchain_address[2:])
self.menu_name = menu_name self.menu_name = menu_name
self.session = session self.session = session
self.ussd_session = ussd_session self.ussd_session = ussd_session
@@ -48,26 +43,21 @@ class MenuProcessor:
:rtype: :rtype:
""" """
available_balance = get_cached_available_balance(self.account.blockchain_address) available_balance = get_cached_available_balance(self.account.blockchain_address)
adjusted_balance = get_cached_adjusted_balance(self.identifier) logg.debug('Requires call to retrieve tax and bonus amounts')
tax = ''
bonus = ''
token_symbol = get_default_token_symbol() token_symbol = get_default_token_symbol()
preferred_language = get_cached_preferred_language(self.account.blockchain_address) preferred_language = get_cached_preferred_language(self.account.blockchain_address)
if not preferred_language: if not preferred_language:
preferred_language = i18n.config.get('fallback') preferred_language = i18n.config.get('fallback')
with_available_balance = f'{self.display_key}.available_balance' return translation_for(
with_fees = f'{self.display_key}.with_fees' key=self.display_key,
if not adjusted_balance: preferred_language=preferred_language,
return translation_for(key=with_available_balance, available_balance=available_balance,
preferred_language=preferred_language, tax=tax,
available_balance=available_balance, bonus=bonus,
token_symbol=token_symbol) token_symbol=token_symbol
adjusted_balance = json.loads(adjusted_balance) )
tax_wei = to_wei(int(available_balance)) - int(adjusted_balance)
tax = from_wei(int(tax_wei))
return translation_for(key=with_fees,
preferred_language=preferred_language,
available_balance=available_balance,
tax=tax,
token_symbol=token_symbol)
def account_statement(self) -> str: def account_statement(self) -> str:
""" """
@@ -77,7 +67,7 @@ class MenuProcessor:
cached_statement = get_cached_statement(self.account.blockchain_address) cached_statement = get_cached_statement(self.account.blockchain_address)
statement = json.loads(cached_statement) statement = json.loads(cached_statement)
statement_transactions = parse_statement_transactions(statement) statement_transactions = parse_statement_transactions(statement)
transaction_sets = [statement_transactions[tx:tx + 3] for tx in range(0, len(statement_transactions), 3)] transaction_sets = [statement_transactions[tx:tx+3] for tx in range(0, len(statement_transactions), 3)]
preferred_language = get_cached_preferred_language(self.account.blockchain_address) preferred_language = get_cached_preferred_language(self.account.blockchain_address)
if not preferred_language: if not preferred_language:
preferred_language = i18n.config.get('fallback') preferred_language = i18n.config.get('fallback')
@@ -159,22 +149,12 @@ class MenuProcessor:
:return: :return:
:rtype: :rtype:
""" """
chain_str = Chain.spec.__str__()
token_symbol = get_default_token_symbol() token_symbol = get_default_token_symbol()
blockchain_address = self.account.blockchain_address blockchain_address = self.account.blockchain_address
balances = get_balances(blockchain_address, chain_str, token_symbol, False)[0] balances = get_balances(blockchain_address, Chain.spec.__str__(), token_symbol, False)[0]
key = cache_data_key(self.identifier, ':cic.balances') key = cache_data_key(self.identifier, ':cic.balances')
cache_data(key, json.dumps(balances)) cache_data(key, json.dumps(balances))
available_balance = calculate_available_balance(balances) available_balance = calculate_available_balance(balances)
now = datetime.now()
if (now - self.account.created).days >= 30:
if available_balance <= 0:
logg.info(f'Not retrieving adjusted balance, available balance: {available_balance} is insufficient.')
else:
timestamp = int((now - timedelta(30)).timestamp())
adjusted_balance = get_adjusted_balance(to_wei(int(available_balance)), chain_str, timestamp, token_symbol)
key = cache_data_key(self.identifier, ':cic.adjusted_balance')
cache_data(key, json.dumps(adjusted_balance))
query_statement(blockchain_address) query_statement(blockchain_address)

View File

@@ -67,7 +67,6 @@ def resume_last_ussd_session(last_state: str) -> Document:
'exit', 'exit',
'exit_invalid_pin', 'exit_invalid_pin',
'exit_invalid_new_pin', 'exit_invalid_new_pin',
'exit_invalid_recipient',
'exit_invalid_request', 'exit_invalid_request',
'exit_pin_blocked', 'exit_pin_blocked',
'exit_pin_mismatch', 'exit_pin_mismatch',

View File

@@ -63,7 +63,7 @@ elif ssl == 0:
else: else:
ssl = True ssl = True
valid_service_codes = config.get('USSD_SERVICE_CODE').split(",")
def main(): def main():
# TODO: improve url building # TODO: improve url building
@@ -79,9 +79,9 @@ def main():
session = uuid.uuid4().hex session = uuid.uuid4().hex
data = { data = {
'sessionId': session, 'sessionId': session,
'serviceCode': valid_service_codes[0], 'serviceCode': config.get('APP_SERVICE_CODE'),
'phoneNumber': args.phone, 'phoneNumber': args.phone,
'text': "", 'text': config.get('APP_SERVICE_CODE'),
} }
state = "_BEGIN" state = "_BEGIN"

View File

@@ -146,7 +146,7 @@ def create_ussd_session(
) )
def update_ussd_session(ussd_session: DbUssdSession, def update_ussd_session(ussd_session: UssdSession,
user_input: str, user_input: str,
state: str, state: str,
data: Optional[dict] = None) -> UssdSession: data: Optional[dict] = None) -> UssdSession:

View File

@@ -154,14 +154,15 @@ def parse_person_metadata(account: Account, metadata: dict):
phone_number = account.phone_number phone_number = account.phone_number
date_registered = int(account.created.replace().timestamp()) date_registered = int(account.created.replace().timestamp())
blockchain_address = account.blockchain_address blockchain_address = account.blockchain_address
chain_str = Chain.spec.__str__() chain_spec = f'{Chain.spec.common_name()}:{Chain.spec.engine()}: {Chain.spec.chain_id()}'
if isinstance(metadata.get('identities'), dict): if isinstance(metadata.get('identities'), dict):
identities = metadata.get('identities') identities = metadata.get('identities')
else: else:
identities = manage_identity_data( identities = manage_identity_data(
blockchain_address=blockchain_address, blockchain_address=blockchain_address,
chain_str=chain_str blockchain_type=Chain.spec.engine(),
chain_spec=chain_spec
) )
return { return {

View File

@@ -4,7 +4,6 @@ from typing import Tuple
# third party imports # third party imports
import celery import celery
from phonenumbers.phonenumberutil import NumberParseException
# local imports # local imports
from cic_ussd.account.balance import get_cached_available_balance from cic_ussd.account.balance import get_cached_available_balance
@@ -22,21 +21,23 @@ logg = logging.getLogger(__file__)
def is_valid_recipient(state_machine_data: Tuple[str, dict, Account, Session]) -> bool: def is_valid_recipient(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:
"""This function checks that a phone number provided as the recipient of a transaction does not match the sending """This function checks that a user exists, is not the initiator of the transaction, has an active account status
party's own phone number. and is authorized to perform standard transactions.
:param state_machine_data: A tuple containing user input, a ussd session and user object. :param state_machine_data: A tuple containing user input, a ussd session and user object.
:type state_machine_data: tuple :type state_machine_data: tuple
:return: A recipient account's validity for a transaction :return: A user's validity
:rtype: bool :rtype: bool
""" """
user_input, ussd_session, account, session = state_machine_data user_input, ussd_session, account, session = state_machine_data
try: phone_number = process_phone_number(user_input, E164Format.region)
phone_number = process_phone_number(user_input, E164Format.region) session = SessionBase.bind_session(session=session)
except NumberParseException: recipient = Account.get_by_phone_number(phone_number=phone_number, session=session)
phone_number = None SessionBase.release_session(session=session)
is_not_initiator = phone_number != account.phone_number is_not_initiator = phone_number != account.phone_number
is_present = Account.get_by_phone_number(phone_number, session) is not None has_active_account_status = False
return phone_number is not None and phone_number.startswith('+') and is_present and is_not_initiator if recipient:
has_active_account_status = recipient.get_status(session) == AccountStatus.ACTIVE.name
return is_not_initiator and has_active_account_status and recipient is not None
def is_valid_transaction_amount(state_machine_data: Tuple[str, dict, Account, Session]) -> bool: def is_valid_transaction_amount(state_machine_data: Tuple[str, dict, Account, Session]) -> bool:

View File

@@ -5,6 +5,7 @@ from datetime import timedelta
# third-party imports # third-party imports
import celery import celery
from chainlib.hash import strip_0x
# local imports # local imports
from cic_ussd.account.balance import get_balances, calculate_available_balance from cic_ussd.account.balance import get_balances, calculate_available_balance
@@ -54,7 +55,6 @@ def account_creation_callback(self, result: str, url: str, status_code: int):
session.add(account) session.add(account)
session.commit() session.commit()
session.close() session.close()
logg.debug(f'recorded account with identifier: {result}')
queue = self.request.delivery_info.get('routing_key') queue = self.request.delivery_info.get('routing_key')
s_phone_pointer = celery.signature( s_phone_pointer = celery.signature(
@@ -86,7 +86,7 @@ def balances_callback(result: list, param: str, status_code: int):
raise ValueError(f'Unexpected status code: {status_code}.') raise ValueError(f'Unexpected status code: {status_code}.')
balances = result[0] balances = result[0]
identifier = bytes.fromhex(param) identifier = bytes.fromhex(strip_0x(param))
key = cache_data_key(identifier, ':cic.balances') key = cache_data_key(identifier, ':cic.balances')
cache_data(key, json.dumps(balances)) cache_data(key, json.dumps(balances))
@@ -113,10 +113,8 @@ def statement_callback(self, result, param: str, status_code: int):
for transaction in statement_transactions: for transaction in statement_transactions:
recipient_transaction, sender_transaction = transaction_actors(transaction) recipient_transaction, sender_transaction = transaction_actors(transaction)
if recipient_transaction.get('blockchain_address') == param: if recipient_transaction.get('blockchain_address') == param:
recipient_transaction['alt_blockchain_address'] = sender_transaction.get('blockchain_address')
generate(param, queue, recipient_transaction) generate(param, queue, recipient_transaction)
if sender_transaction.get('blockchain_address') == param: if sender_transaction.get('blockchain_address') == param:
sender_transaction['alt_blockchain_address'] = recipient_transaction.get('blockchain_address')
generate(param, queue, sender_transaction) generate(param, queue, sender_transaction)
@@ -140,14 +138,26 @@ def transaction_balances_callback(self, result: list, param: dict, status_code:
balances_data = result[0] balances_data = result[0]
available_balance = calculate_available_balance(balances_data) available_balance = calculate_available_balance(balances_data)
transaction = param transaction = param
blockchain_address = param.get('blockchain_address')
transaction['available_balance'] = available_balance transaction['available_balance'] = available_balance
queue = self.request.delivery_info.get('routing_key') queue = self.request.delivery_info.get('routing_key')
s_preferences_metadata = celery.signature(
'cic_ussd.tasks.metadata.query_preferences_metadata', [blockchain_address], queue=queue
)
s_process_account_metadata = celery.signature( s_process_account_metadata = celery.signature(
'cic_ussd.tasks.processor.parse_transaction', [transaction], queue=queue 'cic_ussd.tasks.processor.parse_transaction', [transaction], queue=queue
) )
s_notify_account = celery.signature('cic_ussd.tasks.notifications.transaction', queue=queue) s_notify_account = celery.signature('cic_ussd.tasks.notifications.transaction', queue=queue)
celery.chain(s_process_account_metadata, s_notify_account).apply_async()
if param.get('transaction_type') == 'transfer':
celery.chain(s_preferences_metadata, s_process_account_metadata, s_notify_account).apply_async()
if param.get('transaction_type') == 'tokengift':
s_process_account_metadata = celery.signature(
'cic_ussd.tasks.processor.parse_transaction', [{}, transaction], queue=queue
)
celery.chain(s_process_account_metadata, s_notify_account).apply_async()
@celery_app.task @celery_app.task
@@ -174,11 +184,10 @@ def transaction_callback(result: dict, param: str, status_code: int):
source_token_value = result.get('source_token_value') source_token_value = result.get('source_token_value')
recipient_metadata = { recipient_metadata = {
"alt_blockchain_address": sender_blockchain_address,
"blockchain_address": recipient_blockchain_address,
"role": "recipient",
"token_symbol": destination_token_symbol, "token_symbol": destination_token_symbol,
"token_value": destination_token_value, "token_value": destination_token_value,
"blockchain_address": recipient_blockchain_address,
"role": "recipient",
"transaction_type": param "transaction_type": param
} }
@@ -192,11 +201,10 @@ def transaction_callback(result: dict, param: str, status_code: int):
if param == 'transfer': if param == 'transfer':
sender_metadata = { sender_metadata = {
"alt_blockchain_address": recipient_blockchain_address,
"blockchain_address": sender_blockchain_address, "blockchain_address": sender_blockchain_address,
"role": "sender",
"token_symbol": source_token_symbol, "token_symbol": source_token_symbol,
"token_value": source_token_value, "token_value": source_token_value,
"role": "sender",
"transaction_type": param "transaction_type": param
} }

Some files were not shown because too many files have changed in this diff Show More