Compare commits

..

23 Commits

Author SHA1 Message Date
4131bfea7c replace deploy image 2021-08-28 16:05:11 -07:00
8f83066082 try a kustomize build 2021-08-28 15:42:08 -07:00
01c6f06b4b Merge remote-tracking branch 'origin/master' into bvander/deploy-to-k8s-dev 2021-08-28 09:28:36 -07:00
415d64a4bd Merge branch 'master' into bvander/deploy-to-k8s-dev 2021-08-25 08:57:39 -07:00
79d29689f9 Merge branch 'master' into bvander/deploy-to-k8s-dev 2021-08-24 16:00:34 -07:00
83f1161772 peppa pig 2021-08-24 14:53:22 -07:00
93cedcc3dd remove flux stuff 2021-08-24 14:27:00 -07:00
293c8d4b57 remove af secrets 2021-08-24 14:24:35 -07:00
01fef92166 fix user proxy deployment 2021-08-24 12:39:45 -07:00
41a7f483cc update the deploy script part 2021-08-24 12:22:34 -07:00
aaa91dab63 Merge branch 'master' into bvander/deploy-to-k8s-dev 2021-08-24 12:04:08 -07:00
c0e0836a08 Merge remote-tracking branch 'origin/master' into bvander/deploy-to-k8s-dev 2021-08-24 09:48:56 -07:00
434805c914 progress 2021-08-24 09:48:38 -07:00
6f7000f234 run contract migration to completion 2021-08-23 14:23:34 -07:00
183bb1e50b fix images and remove last script 2021-08-23 14:05:51 -07:00
8240a79b0e fix paths 2021-08-23 13:52:41 -07:00
ea6ce88dab try and launch some k8s 2021-08-23 13:46:17 -07:00
70ce759564 more debugging 2021-08-23 12:16:59 -07:00
bca5d4d09f maybe just a typo 2021-08-23 11:58:16 -07:00
a3c0539114 added secrets can we read 2021-08-23 10:40:32 -07:00
a2fbdd8338 ci debug 2021-08-23 09:55:52 -07:00
3f850913ed move the kaniko image to no be default 2021-08-23 09:54:05 -07:00
6e97c41b78 try adding a k8s job 2021-08-23 09:50:05 -07:00
148 changed files with 4978 additions and 3636 deletions

View File

@@ -20,24 +20,48 @@ variables:
DOCKER_BUILDKIT: "1" DOCKER_BUILDKIT: "1"
COMPOSE_DOCKER_CLI_BUILD: "1" COMPOSE_DOCKER_CLI_BUILD: "1"
CI_DEBUG_TRACE: "true" CI_DEBUG_TRACE: "true"
TAG: $CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
# runs on protected branches and pushes to repo # runs on protected branches and pushes to repo
build-push: build-push:
stage: build stage: build
tags: tags:
- integration - integration
#script: before_script:
# - TAG=$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA sh ./scripts/build-push.sh - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
script: script:
- TAG=latest sh ./scripts/build-push.sh - TAG=$TAG sh ./scripts/build-push.sh
rules: rules:
- if: $CI_COMMIT_REF_PROTECTED == "true" - if: $CI_COMMIT_REF_PROTECTED == "true"
when: always when: always
deploy-dev: deploy-k8s-dev:
stage: deploy stage: deploy
trigger: grassrootseconomics/devops image: line/kubectl-kustomize
when: manual variables:
CI_DEBUG_TRACE: "true"
script:
- kubectl config set-cluster k8s --server="${K8S_DEV_SERVER?dev server missing}"
- kubectl config set clusters.k8s.certificate-authority-data ${K8S_DEV_CERTIFICATE_AUTHORITY_DATA}
- kubectl config set-credentials gitlab --token="${K8S_DEV_USER_TOKEN}"
- kubectl config set-context grassroots --cluster=k8s --user=gitlab --namespace grassroots
- kubectl config use-context grassroots
#- sed -i "s/<VERSION>/${CI_COMMIT_SHORT_SHA}/g" deployment.yaml
#- kubectl apply -f deployment.yaml
- echo "Wiping state..."
- kubectl delete jobs.batch --all
- kubectl delete hr postgresql && kubectl delete pvc -l 'app.kubernetes.io/name=postgresql'
- kubectl delete sts,pvc -l 'app=bloxberg-validator'
- kubectl delete hr redis && kubectl delete pvc -l 'app=redis'
- kubectl apply -f kubernetes/eth-node/ -f kubernetes/postgresql/ -f kubernetes/redis/
- echo "deploy and run database migrations..."
# set image based on deploy tag
- bash ./scripts/set-image.sh
- kubectl apply -f .
- echo "run contract migrations..."
- kubectl apply -f kubernetes/contract-migration/contract-migration-job.yaml
rules:
- if: $CI_COMMIT_REF_PROTECTED == "true"
when: always

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

@@ -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

@@ -9,6 +9,7 @@ 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.6a3,<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.9a7,<0.1.0
eth-address-index>=0.2.3a4,<0.3.0 chainlib>=0.0.9a3,<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

@@ -9,8 +9,8 @@ build-test-cic-eth:
- cd apps/cic-eth - cd apps/cic-eth
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile . - docker build -t $MR_IMAGE_TAG -f docker/Dockerfile .
- docker run $MR_IMAGE_TAG sh docker/run_tests.sh - 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/$APP_NAME/**/*
when: always # when: always

View File

@@ -1,5 +1,5 @@
SQLAlchemy==1.3.20 SQLAlchemy==1.3.20
cic-eth-registry>=0.6.1a3,<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.4a6,<0.1.0
eth-erc20>=0.1.2a2,<0.2.0 eth-erc20>=0.1.2a2,<0.2.0

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
@@ -255,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

@@ -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

@@ -13,7 +13,7 @@ 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
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from chainlib.error import JSONRPCException from chainlib.error import JSONRPCException
@@ -31,7 +31,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,
@@ -50,7 +49,6 @@ from cic_eth.queue.tx import (
from cic_eth.encode import ( from cic_eth.encode import (
unpack_normal, unpack_normal,
ZERO_ADDRESS_NORMAL, ZERO_ADDRESS_NORMAL,
tx_normalize,
) )
logg = logging.getLogger() logg = logging.getLogger()
@@ -86,7 +84,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 +175,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 +248,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)
@@ -304,15 +298,13 @@ def cache_gift_data(
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_normal(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'],
'from': sender_address, 'from': tx['from'],
'to': recipient_address, 'to': tx['to'],
'source_token': ZERO_ADDRESS_NORMAL, 'source_token': ZERO_ADDRESS_NORMAL,
'destination_token': ZERO_ADDRESS_NORMAL, 'destination_token': ZERO_ADDRESS_NORMAL,
'from_value': 0, 'from_value': 0,
@@ -346,14 +338,12 @@ def cache_account_data(
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_normal(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'],
'from': sender_address, 'from': tx['from'],
'to': recipient_address, 'to': tx['to'],
'source_token': ZERO_ADDRESS_NORMAL, 'source_token': ZERO_ADDRESS_NORMAL,
'destination_token': ZERO_ADDRESS_NORMAL, 'destination_token': ZERO_ADDRESS_NORMAL,
'from_value': 0, 'from_value': 0,

View File

@@ -12,10 +12,7 @@ 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
@@ -41,7 +38,6 @@ from cic_eth.task import (
CriticalSQLAlchemyAndSignerTask, CriticalSQLAlchemyAndSignerTask,
) )
from cic_eth.eth.nonce import CustodialTaskNonceOracle from cic_eth.eth.nonce import CustodialTaskNonceOracle
from cic_eth.encode import tx_normalize
celery_app = celery.current_app celery_app = celery.current_app
logg = logging.getLogger() logg = logging.getLogger()
@@ -66,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)
@@ -376,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'],
@@ -455,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'],

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,
add_0x,
)
#from chainlib.eth.constant import ZERO_ADDRESS #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
@@ -78,6 +71,7 @@ class MaxGasOracle:
return MAXIMUM_FEE_UNITS return MAXIMUM_FEE_UNITS
#def create_check_gas_task(tx_signed_raws_hex, chain_spec, holder_address, gas=None, tx_hashes_hex=None, queue=None):
def create_check_gas_task(tx_signed_raws_hex, chain_spec, holder_address, gas=None, tx_hashes_hex=None, queue=None): def create_check_gas_task(tx_signed_raws_hex, chain_spec, holder_address, gas=None, tx_hashes_hex=None, queue=None):
"""Creates a celery task signature for a check_gas task that adds the task to the outgoing queue to be processed by the dispatcher. """Creates a celery task signature for a check_gas task that adds the task to the outgoing queue to be processed by the dispatcher.
@@ -182,12 +176,10 @@ 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 address != None:
if not is_address(address): if not is_checksum_address(address):
raise ValueError('invalid address {}'.format(address)) raise ValueError('invalid address {}'.format(address))
address = tx_normalize.wallet_address(address) address = tx_normalize.wallet_address(address)
address = add_0x(address)
tx_hashes = [] tx_hashes = []
txs = [] txs = []
@@ -199,6 +191,7 @@ def check_gas(self, tx_hashes_hex, chain_spec_dict, txs_hex=[], address=None, ga
txs.append(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,15 +207,13 @@ 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))
queue = self.request.delivery_info.get('routing_key') queue = self.request.delivery_info.get('routing_key')
conn = RPCConnection.connect(chain_spec) conn = RPCConnection.connect(chain_spec)
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)

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

@@ -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

@@ -58,7 +58,6 @@ def get_tx_local(chain_spec, tx_hash, session=None):
@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) return get_account_tx_local(chain_spec, address, as_sender=as_sender, as_recipient=as_recipient, counterpart=counterpart)

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

@@ -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,7 +207,7 @@ 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

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
@@ -47,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.8', 'alpha.7',
) )
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

@@ -14,15 +14,6 @@ ARG EXTRA_PIP_ARGS=""
# --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 \
@@ -33,19 +24,17 @@ RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
-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

@@ -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,4 +1,3 @@
celery==4.4.7 celery==4.4.7
chainlib-eth>=0.0.9rc2,<0.1.0 chainlib-eth>=0.0.9a7,<0.1.0
semver==2.13.0 semver==2.13.0
crypto-dev-signer>=0.4.15rc2,<0.5.0

View File

@@ -8,7 +8,7 @@ pycryptodome==3.10.1
liveness~=0.0.1a7 liveness~=0.0.1a7
eth-address-index>=0.2.3a4,<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.1a3,<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

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

@@ -17,9 +17,6 @@ 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,
@@ -28,6 +25,7 @@ from hexathon import (
# 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.encode import tx_normalize
from cic_eth.queue.query import get_account_tx_local from cic_eth.queue.query import get_account_tx_local
logg = logging.getLogger() logg = logging.getLogger()
@@ -72,13 +70,12 @@ 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()
@@ -92,4 +89,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

@@ -110,8 +110,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(

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

@@ -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

@@ -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

@@ -1,6 +1,6 @@
crypto-dev-signer>=0.4.15a7,<=0.4.15 crypto-dev-signer>=0.4.15a1,<=0.4.15
chainqueue>=0.0.5a1,<0.1.0 chainqueue>=0.0.5a1,<0.1.0
cic-eth-registry>=0.6.1a3,<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

@@ -9,8 +9,8 @@ build-test-cic-meta:
- cd apps/cic-meta - cd apps/cic-meta
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile . - docker build -t $MR_IMAGE_TAG -f docker/Dockerfile .
- docker run --entrypoint=sh $MR_IMAGE_TAG docker/run_tests.sh - docker run --entrypoint=sh $MR_IMAGE_TAG 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/$APP_NAME/**/*
when: always # when: always

View File

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

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

@@ -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
@@ -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):

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

@@ -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

@@ -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 = transaction.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 transaction.get('transaction_type') == 'transfer':
celery.chain(s_preferences_metadata, s_process_account_metadata, s_notify_account).apply_async()
if transaction.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

View File

@@ -3,6 +3,7 @@ import logging
# third-party imports # third-party imports
import celery import celery
from hexathon import strip_0x
# local imports # local imports
from cic_ussd.metadata import CustomMetadata, PersonMetadata, PhonePointerMetadata, PreferencesMetadata from cic_ussd.metadata import CustomMetadata, PersonMetadata, PhonePointerMetadata, PreferencesMetadata
@@ -20,7 +21,7 @@ def query_person_metadata(blockchain_address: str):
:return: :return:
:rtype: :rtype:
""" """
identifier = bytes.fromhex(blockchain_address) identifier = bytes.fromhex(strip_0x(blockchain_address))
person_metadata_client = PersonMetadata(identifier=identifier) person_metadata_client = PersonMetadata(identifier=identifier)
person_metadata_client.query() person_metadata_client.query()
@@ -35,14 +36,14 @@ def create_person_metadata(blockchain_address: str, data: dict):
:return: :return:
:rtype: :rtype:
""" """
identifier = bytes.fromhex(blockchain_address) identifier = bytes.fromhex(strip_0x(blockchain_address))
person_metadata_client = PersonMetadata(identifier=identifier) person_metadata_client = PersonMetadata(identifier=identifier)
person_metadata_client.create(data=data) person_metadata_client.create(data=data)
@celery_app.task @celery_app.task
def edit_person_metadata(blockchain_address: str, data: dict): def edit_person_metadata(blockchain_address: str, data: dict):
identifier = bytes.fromhex(blockchain_address) identifier = bytes.fromhex(strip_0x(blockchain_address))
person_metadata_client = PersonMetadata(identifier=identifier) person_metadata_client = PersonMetadata(identifier=identifier)
person_metadata_client.edit(data=data) person_metadata_client.edit(data=data)
@@ -50,21 +51,21 @@ def edit_person_metadata(blockchain_address: str, data: dict):
@celery_app.task(bind=True, base=CriticalMetadataTask) @celery_app.task(bind=True, base=CriticalMetadataTask)
def add_phone_pointer(self, blockchain_address: str, phone_number: str): def add_phone_pointer(self, blockchain_address: str, phone_number: str):
identifier = phone_number.encode('utf-8') identifier = phone_number.encode('utf-8')
stripped_address = blockchain_address stripped_address = strip_0x(blockchain_address)
phone_metadata_client = PhonePointerMetadata(identifier=identifier) phone_metadata_client = PhonePointerMetadata(identifier=identifier)
phone_metadata_client.create(data=stripped_address) phone_metadata_client.create(data=stripped_address)
@celery_app.task() @celery_app.task()
def add_custom_metadata(blockchain_address: str, data: dict): def add_custom_metadata(blockchain_address: str, data: dict):
identifier = bytes.fromhex(blockchain_address) identifier = bytes.fromhex(strip_0x(blockchain_address))
custom_metadata_client = CustomMetadata(identifier=identifier) custom_metadata_client = CustomMetadata(identifier=identifier)
custom_metadata_client.create(data=data) custom_metadata_client.create(data=data)
@celery_app.task() @celery_app.task()
def add_preferences_metadata(blockchain_address: str, data: dict): def add_preferences_metadata(blockchain_address: str, data: dict):
identifier = bytes.fromhex(blockchain_address) identifier = bytes.fromhex(strip_0x(blockchain_address))
preferences_metadata_client = PreferencesMetadata(identifier=identifier) preferences_metadata_client = PreferencesMetadata(identifier=identifier)
preferences_metadata_client.create(data=data) preferences_metadata_client.create(data=data)
@@ -75,7 +76,7 @@ def query_preferences_metadata(blockchain_address: str):
:param blockchain_address: Blockchain address of an account. :param blockchain_address: Blockchain address of an account.
:type blockchain_address: str | Ox-hex :type blockchain_address: str | Ox-hex
""" """
identifier = bytes.fromhex(blockchain_address) identifier = bytes.fromhex(strip_0x(blockchain_address))
logg.debug(f'Retrieving preferences metadata for address: {blockchain_address}.') logg.debug(f'Retrieving preferences metadata for address: {blockchain_address}.')
person_metadata_client = PreferencesMetadata(identifier=identifier) person_metadata_client = PreferencesMetadata(identifier=identifier)
return person_metadata_client.query() return person_metadata_client.query()

View File

@@ -24,8 +24,7 @@ def transaction(notification_data: dict):
:rtype: :rtype:
""" """
role = notification_data.get('role') role = notification_data.get('role')
token_value = notification_data.get('token_value') amount = from_wei(notification_data.get('token_value'))
amount = token_value if token_value == 0 else from_wei(token_value)
balance = notification_data.get('available_balance') balance = notification_data.get('available_balance')
phone_number = notification_data.get('phone_number') phone_number = notification_data.get('phone_number')
preferred_language = notification_data.get('preferred_language') preferred_language = notification_data.get('preferred_language')

View File

@@ -5,9 +5,9 @@ import logging
# third-party imports # third-party imports
import celery import celery
import i18n import i18n
from chainlib.hash import strip_0x
# local imports # local imports
from cic_ussd.account.metadata import get_cached_preferred_language
from cic_ussd.account.statement import get_cached_statement from cic_ussd.account.statement import get_cached_statement
from cic_ussd.account.transaction import aux_transaction_data, validate_transaction_account from cic_ussd.account.transaction import aux_transaction_data, validate_transaction_account
from cic_ussd.cache import cache_data, cache_data_key from cic_ussd.cache import cache_data, cache_data_key
@@ -23,13 +23,17 @@ logg = logging.getLogger(__file__)
def generate_statement(self, querying_party: str, transaction: dict): def generate_statement(self, querying_party: str, transaction: dict):
"""""" """"""
queue = self.request.delivery_info.get('routing_key') queue = self.request.delivery_info.get('routing_key')
s_preferences = celery.signature(
'cic_ussd.tasks.metadata.query_preferences_metadata', [querying_party], queue=queue
)
s_parse_transaction = celery.signature( s_parse_transaction = celery.signature(
'cic_ussd.tasks.processor.parse_transaction', [transaction], queue=queue 'cic_ussd.tasks.processor.parse_transaction', [transaction], queue=queue
) )
s_cache_statement = celery.signature( s_cache_statement = celery.signature(
'cic_ussd.tasks.processor.cache_statement', [querying_party], queue=queue 'cic_ussd.tasks.processor.cache_statement', [querying_party], queue=queue
) )
celery.chain(s_parse_transaction, s_cache_statement).apply_async() celery.chain(s_preferences, s_parse_transaction, s_cache_statement).apply_async()
@celery_app.task @celery_app.task
@@ -48,23 +52,25 @@ def cache_statement(parsed_transaction: dict, querying_party: str):
statement_transactions = json.loads(cached_statement) statement_transactions = json.loads(cached_statement)
statement_transactions.append(parsed_transaction) statement_transactions.append(parsed_transaction)
data = json.dumps(statement_transactions) data = json.dumps(statement_transactions)
identifier = bytes.fromhex(querying_party) identifier = bytes.fromhex(strip_0x(querying_party))
key = cache_data_key(identifier, ':cic.statement') key = cache_data_key(identifier, ':cic.statement')
cache_data(key, data) cache_data(key, data)
@celery_app.task @celery_app.task
def parse_transaction(transaction: dict) -> dict: def parse_transaction(preferences: dict, transaction: dict) -> dict:
"""This function parses transaction objects and collates all relevant data for system use i.e: """This function parses transaction objects and collates all relevant data for system use i.e:
- An account's set preferred language. - An account's set preferred language.
- Account identifier that facilitates notification. - Account identifier that facilitates notification.
- Contextual tags i.e action and direction tags. - Contextual tags i.e action and direction tags.
:param preferences: An account's set preferences.
:type preferences: dict
:param transaction: Transaction object. :param transaction: Transaction object.
:type transaction: dict :type transaction: dict
:return: Transaction object with contextual data for use in the system. :return: Transaction object with contextual data for use in the system.
:rtype: dict :rtype: dict
""" """
preferred_language = get_cached_preferred_language(transaction.get('blockchain_address')) preferred_language = preferences.get('preferred_language')
if not preferred_language: if not preferred_language:
preferred_language = i18n.config.get('fallback') preferred_language = i18n.config.get('fallback')
transaction['preferred_language'] = preferred_language transaction['preferred_language'] = preferred_language
@@ -77,8 +83,6 @@ def parse_transaction(transaction: dict) -> dict:
alt_account = session.query(Account).filter_by(blockchain_address=alt_blockchain_address).first() alt_account = session.query(Account).filter_by(blockchain_address=alt_blockchain_address).first()
if alt_account: if alt_account:
transaction['alt_metadata_id'] = alt_account.standard_metadata_id() transaction['alt_metadata_id'] = alt_account.standard_metadata_id()
else:
transaction['alt_metadata_id'] = 'GRASSROOTS ECONOMICS'
transaction['metadata_id'] = account.standard_metadata_id() transaction['metadata_id'] = account.standard_metadata_id()
transaction['phone_number'] = account.phone_number transaction['phone_number'] = account.phone_number
session.close() session.close()

View File

@@ -1,7 +1,7 @@
# standard imports # standard imports
import semver import semver
version = (0, 3, 1, 'alpha.5') version = (0, 3, 1, 'alpha.4')
version_object = semver.VersionInfo( version_object = semver.VersionInfo(
major=version[0], major=version[0],

View File

@@ -0,0 +1,2 @@
[app]
service_code = *483*46#

View File

@@ -1,4 +1,3 @@
[ussd] [ussd]
service_code = *483*46#
user = user =
pass = pass =

View File

@@ -10,13 +10,6 @@ RUN mkdir -vp data
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433" ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple" ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
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 \
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 \

View File

@@ -1,12 +1,9 @@
alembic==1.4.2 alembic==1.4.2
attrs==21.2.0
billiard==3.6.4.0
bcrypt==3.2.0 bcrypt==3.2.0
celery==4.4.7 celery==4.4.7
cffi==1.14.6
cic-eth[services]~=0.12.4a7 cic-eth[services]~=0.12.4a7
cic-notify~=0.4.0a10 cic-notify~=0.4.0a10
cic-types~=0.1.0a15 cic-types~=0.1.0a14
confini>=0.4.1a1,<0.5.0 confini>=0.4.1a1,<0.5.0
phonenumbers==8.12.12 phonenumbers==8.12.12
psycopg2==2.8.6 psycopg2==2.8.6

View File

@@ -43,13 +43,10 @@ def test_sync_get_balances(activated_account,
(5000000, 89000000, 67000000, 27.00) (5000000, 89000000, 67000000, 27.00)
]) ])
def test_calculate_available_balance(activated_account, def test_calculate_available_balance(activated_account,
available_balance,
balance_incoming, balance_incoming,
balance_network, balance_network,
balance_outgoing, balance_outgoing,
cache_balances, available_balance):
cache_default_token_data,
load_chain_spec):
balances = { balances = {
'address': activated_account.blockchain_address, 'address': activated_account.blockchain_address,
'converters': [], 'converters': [],
@@ -60,11 +57,7 @@ def test_calculate_available_balance(activated_account,
assert calculate_available_balance(balances) == available_balance assert calculate_available_balance(balances) == available_balance
def test_get_cached_available_balance(activated_account, def test_get_cached_available_balance(activated_account, cache_balances, balances):
balances,
cache_balances,
cache_default_token_data,
load_chain_spec):
cached_available_balance = get_cached_available_balance(activated_account.blockchain_address) cached_available_balance = get_cached_available_balance(activated_account.blockchain_address)
available_balance = calculate_available_balance(balances[0]) available_balance = calculate_available_balance(balances[0])
assert cached_available_balance == available_balance assert cached_available_balance == available_balance

View File

@@ -27,7 +27,6 @@ def test_filter_statement_transactions(transactions_list):
def test_generate(activated_account, def test_generate(activated_account,
cache_default_token_data,
cache_preferences, cache_preferences,
celery_session_worker, celery_session_worker,
init_cache, init_cache,
@@ -36,22 +35,22 @@ def test_generate(activated_account,
preferences, preferences,
preferences_metadata_url, preferences_metadata_url,
transactions_list): transactions_list):
statement_transactions = filter_statement_transactions(transactions_list) with requests_mock.Mocker(real_http=False) as request_mocker:
for transaction in statement_transactions: request_mocker.register_uri('GET', preferences_metadata_url, status_code=200, reason='OK', json=preferences)
querying_party = activated_account.blockchain_address statement_transactions = filter_statement_transactions(transactions_list)
recipient_transaction, sender_transaction = transaction_actors(transaction) for transaction in statement_transactions:
if recipient_transaction.get('blockchain_address') == querying_party: querying_party = activated_account.blockchain_address
recipient_transaction['alt_blockchain_address'] = sender_transaction.get('blockchain_address') recipient_transaction, sender_transaction = transaction_actors(transaction)
generate(querying_party, None, recipient_transaction) if recipient_transaction.get('blockchain_address') == querying_party:
if sender_transaction.get('blockchain_address') == querying_party: generate(querying_party, None, recipient_transaction)
sender_transaction['alt_blockchain_address'] = recipient_transaction.get('blockchain_address') if sender_transaction.get('blockchain_address') == querying_party:
generate(querying_party, None, sender_transaction) generate(querying_party, None, sender_transaction)
time.sleep(2) time.sleep(2)
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
key = cache_data_key(identifier, ':cic.statement') key = cache_data_key(identifier, ':cic.statement')
statement = get_cached_data(key) statement = get_cached_data(key)
statement = json.loads(statement) statement = json.loads(statement)
assert len(statement) == 1 assert len(statement) == 1
def test_get_cached_statement(activated_account, cache_statement, statement): def test_get_cached_statement(activated_account, cache_statement, statement):
@@ -61,7 +60,7 @@ def test_get_cached_statement(activated_account, cache_statement, statement):
assert cached_statement[0].get('blockchain_address') == statement[0].get('blockchain_address') assert cached_statement[0].get('blockchain_address') == statement[0].get('blockchain_address')
def test_parse_statement_transactions(cache_default_token_data, statement): def test_parse_statement_transactions(statement):
parsed_transactions = parse_statement_transactions(statement) parsed_transactions = parse_statement_transactions(statement)
parsed_transaction = parsed_transactions[0] parsed_transaction = parsed_transactions[0]
parsed_transaction.startswith('Sent') parsed_transaction.startswith('Sent')
@@ -77,7 +76,7 @@ def test_query_statement(blockchain_address, limit, load_chain_spec, activated_a
assert mock_transaction_list_query.get('limit') == limit assert mock_transaction_list_query.get('limit') == limit
def test_statement_transaction_set(cache_default_token_data, load_chain_spec, preferences, set_locale_files, statement): def test_statement_transaction_set(preferences, set_locale_files, statement):
parsed_transactions = parse_statement_transactions(statement) parsed_transactions = parse_statement_transactions(statement)
preferred_language = preferences.get('preferred_language') preferred_language = preferences.get('preferred_language')
transaction_set = statement_transaction_set(preferred_language, parsed_transactions) transaction_set = statement_transaction_set(preferred_language, parsed_transactions)

View File

@@ -36,19 +36,19 @@ def test_aux_transaction_data(preferences, set_locale_files, transactions_list):
check_aux_data('helpers.sent', 'helpers.to', preferred_language, sender_tx_aux_data) check_aux_data('helpers.sent', 'helpers.to', preferred_language, sender_tx_aux_data)
@pytest.mark.parametrize("value, expected_result", [ @pytest.mark.parametrize("wei, expected_result", [
(50000000, Decimal('50.00')), (50000000, Decimal('50.00')),
(100000, Decimal('0.10')) (100000, Decimal('0.10'))
]) ])
def test_from_wei(cache_default_token_data, expected_result, value): def test_from_wei(wei, expected_result):
assert from_wei(value) == expected_result assert from_wei(wei) == expected_result
@pytest.mark.parametrize("value, expected_result", [ @pytest.mark.parametrize("value, expected_result", [
(50, 50000000), (50, 50000000),
(0.10, 100000) (0.10, 100000)
]) ])
def test_to_wei(cache_default_token_data, expected_result, value): def test_to_wei(value, expected_result):
assert to_wei(value) == expected_result assert to_wei(value) == expected_result
@@ -96,7 +96,6 @@ def test_validate_transaction_account(activated_account, init_database, transact
@pytest.mark.parametrize("amount", [50, 0.10]) @pytest.mark.parametrize("amount", [50, 0.10])
def test_outgoing_transaction_processor(activated_account, def test_outgoing_transaction_processor(activated_account,
amount, amount,
cache_default_token_data,
celery_session_worker, celery_session_worker,
load_config, load_config,
load_chain_spec, load_chain_spec,

View File

@@ -1,6 +1,5 @@
# standard imports # standard imports
import json import json
import datetime
# external imports # external imports
from chainlib.hash import strip_0x from chainlib.hash import strip_0x
@@ -15,7 +14,6 @@ from cic_ussd.account.statement import (
) )
from cic_ussd.account.tokens import get_default_token_symbol 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.cache import cache_data, cache_data_key
from cic_ussd.menu.ussd_menu import UssdMenu from cic_ussd.menu.ussd_menu import UssdMenu
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
@@ -40,34 +38,24 @@ def test_menu_processor(activated_account,
load_chain_spec, load_chain_spec,
load_support_phone, load_support_phone,
load_ussd_menu, load_ussd_menu,
mock_get_adjusted_balance,
mock_sync_balance_api_query, mock_sync_balance_api_query,
mock_transaction_list_query, mock_transaction_list_query,
valid_recipient): valid_recipient):
preferred_language = get_cached_preferred_language(activated_account.blockchain_address) preferred_language = get_cached_preferred_language(activated_account.blockchain_address)
available_balance = get_cached_available_balance(activated_account.blockchain_address) available_balance = get_cached_available_balance(activated_account.blockchain_address)
token_symbol = get_default_token_symbol() token_symbol = get_default_token_symbol()
with_available_balance = 'ussd.kenya.account_balances.available_balance'
with_fees = 'ussd.kenya.account_balances.with_fees' tax = ''
bonus = ''
display_key = 'ussd.kenya.account_balances'
ussd_menu = UssdMenu.find_by_name('account_balances') ussd_menu = UssdMenu.find_by_name('account_balances')
name = ussd_menu.get('name') name = ussd_menu.get('name')
resp = response(activated_account, 'ussd.kenya.account_balances', name, init_database, generic_ussd_session) resp = response(activated_account, display_key, name, init_database, generic_ussd_session)
assert resp == translation_for(with_available_balance, assert resp == translation_for(display_key,
preferred_language, preferred_language,
available_balance=available_balance, available_balance=available_balance,
token_symbol=token_symbol)
identifier = bytes.fromhex(activated_account.blockchain_address)
key = cache_data_key(identifier, ':cic.adjusted_balance')
adjusted_balance = 45931650.64654012
cache_data(key, json.dumps(adjusted_balance))
resp = response(activated_account, 'ussd.kenya.account_balances', name, init_database, generic_ussd_session)
tax_wei = to_wei(int(available_balance)) - int(adjusted_balance)
tax = from_wei(int(tax_wei))
assert resp == translation_for(key=with_fees,
preferred_language=preferred_language,
available_balance=available_balance,
tax=tax, tax=tax,
bonus=bonus,
token_symbol=token_symbol) token_symbol=token_symbol)
cached_statement = get_cached_statement(activated_account.blockchain_address) cached_statement = get_cached_statement(activated_account.blockchain_address)
@@ -108,7 +96,7 @@ def test_menu_processor(activated_account,
display_key = 'ussd.kenya.display_user_metadata' display_key = 'ussd.kenya.display_user_metadata'
ussd_menu = UssdMenu.find_by_name('display_user_metadata') ussd_menu = UssdMenu.find_by_name('display_user_metadata')
name = ussd_menu.get('name') name = ussd_menu.get('name')
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
person_metadata = PersonMetadata(identifier) person_metadata = PersonMetadata(identifier)
cached_person_metadata = person_metadata.get_cached_metadata() cached_person_metadata = person_metadata.get_cached_metadata()
resp = response(activated_account, display_key, name, init_database, generic_ussd_session) resp = response(activated_account, display_key, name, init_database, generic_ussd_session)
@@ -135,15 +123,6 @@ def test_menu_processor(activated_account,
account_balance=available_balance, account_balance=available_balance,
account_token_name=token_symbol) account_token_name=token_symbol)
display_key = 'ussd.kenya.start'
ussd_menu = UssdMenu.find_by_name('start')
name = ussd_menu.get('name')
older_timestamp = (activated_account.created - datetime.timedelta(days=35))
activated_account.created = older_timestamp
init_database.flush()
response(activated_account, display_key, name, init_database, generic_ussd_session)
assert mock_get_adjusted_balance['timestamp'] == int((datetime.datetime.now() - datetime.timedelta(days=30)).timestamp())
display_key = 'ussd.kenya.transaction_pin_authorization' display_key = 'ussd.kenya.transaction_pin_authorization'
ussd_menu = UssdMenu.find_by_name('transaction_pin_authorization') ussd_menu = UssdMenu.find_by_name('transaction_pin_authorization')
name = ussd_menu.get('name') name = ussd_menu.get('name')

View File

@@ -49,7 +49,6 @@ def test_is_valid_transaction_amount(activated_account, amount, expected_result,
]) ])
def test_has_sufficient_balance(activated_account, def test_has_sufficient_balance(activated_account,
cache_balances, cache_balances,
cache_default_token_data,
expected_result, expected_result,
generic_ussd_session, generic_ussd_session,
init_database, init_database,

View File

@@ -114,7 +114,6 @@ def test_statement_callback(activated_account, mocker, transactions_list):
s_statement_callback.apply_async().get() s_statement_callback.apply_async().get()
statement_transactions = filter_statement_transactions(transactions_list) statement_transactions = filter_statement_transactions(transactions_list)
recipient_transaction, sender_transaction = transaction_actors(statement_transactions[0]) recipient_transaction, sender_transaction = transaction_actors(statement_transactions[0])
sender_transaction['alt_blockchain_address'] = recipient_transaction.get('blockchain_address')
mock_statement_generate.assert_called_with( mock_statement_generate.assert_called_with(
(activated_account.blockchain_address, sender_transaction), {}, queue='cic-ussd') (activated_account.blockchain_address, sender_transaction), {}, queue='cic-ussd')
@@ -122,7 +121,6 @@ def test_statement_callback(activated_account, mocker, transactions_list):
def test_transaction_balances_callback(activated_account, def test_transaction_balances_callback(activated_account,
balances, balances,
cache_balances, cache_balances,
cache_default_token_data,
cache_person_metadata, cache_person_metadata,
cache_preferences, cache_preferences,
load_chain_spec, load_chain_spec,

View File

@@ -13,8 +13,7 @@ from cic_ussd.translation import translation_for
# tests imports # tests imports
def test_transaction(cache_default_token_data, def test_transaction(celery_session_worker,
celery_session_worker,
load_support_phone, load_support_phone,
mock_notifier_api, mock_notifier_api,
notification_data, notification_data,

View File

@@ -30,11 +30,10 @@ def test_generate_statement(activated_account,
def test_cache_statement(activated_account, def test_cache_statement(activated_account,
cache_default_token_data,
cache_person_metadata, cache_person_metadata,
cache_preferences,
celery_session_worker, celery_session_worker,
init_database, init_database,
preferences,
transaction_result): transaction_result):
recipient_transaction, sender_transaction = transaction_actors(transaction_result) recipient_transaction, sender_transaction = transaction_actors(transaction_result)
identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address)) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
@@ -42,7 +41,7 @@ def test_cache_statement(activated_account,
cached_statement = get_cached_data(key) cached_statement = get_cached_data(key)
assert cached_statement is None assert cached_statement is None
s_parse_transaction = celery.signature( s_parse_transaction = celery.signature(
'cic_ussd.tasks.processor.parse_transaction', [sender_transaction]) 'cic_ussd.tasks.processor.parse_transaction', [preferences, sender_transaction])
result = s_parse_transaction.apply_async().get() result = s_parse_transaction.apply_async().get()
s_cache_statement = celery.signature( s_cache_statement = celery.signature(
'cic_ussd.tasks.processor.cache_statement', [result, activated_account.blockchain_address] 'cic_ussd.tasks.processor.cache_statement', [result, activated_account.blockchain_address]
@@ -62,15 +61,15 @@ def test_cache_statement(activated_account,
def test_parse_transaction(activated_account, def test_parse_transaction(activated_account,
cache_person_metadata, cache_person_metadata,
cache_preferences,
celery_session_worker, celery_session_worker,
init_database, init_database,
preferences,
transaction_result): transaction_result):
recipient_transaction, sender_transaction = transaction_actors(transaction_result) recipient_transaction, sender_transaction = transaction_actors(transaction_result)
assert sender_transaction.get('metadata_id') is None assert sender_transaction.get('metadata_id') is None
assert sender_transaction.get('phone_number') is None assert sender_transaction.get('phone_number') is None
s_parse_transaction = celery.signature( s_parse_transaction = celery.signature(
'cic_ussd.tasks.processor.parse_transaction', [sender_transaction]) 'cic_ussd.tasks.processor.parse_transaction', [preferences, sender_transaction])
result = s_parse_transaction.apply_async().get() result = s_parse_transaction.apply_async().get()
assert result.get('metadata_id') == activated_account.standard_metadata_id() assert result.get('metadata_id') == activated_account.standard_metadata_id()
assert result.get('phone_number') == activated_account.phone_number assert result.get('phone_number') == activated_account.phone_number

View File

@@ -54,7 +54,7 @@ def cache_account_creation_data(init_cache, account_creation_data):
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def cache_balances(activated_account, balances, init_cache): def cache_balances(activated_account, balances, init_cache):
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
balances = json.dumps(balances[0]) balances = json.dumps(balances[0])
key = cache_data_key(identifier, ':cic.balances') key = cache_data_key(identifier, ':cic.balances')
cache_data(key, balances) cache_data(key, balances)
@@ -70,7 +70,7 @@ def cache_default_token_data(default_token_data, init_cache, load_chain_spec):
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def cache_person_metadata(activated_account, init_cache, person_metadata): def cache_person_metadata(activated_account, init_cache, person_metadata):
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
person = json.dumps(person_metadata) person = json.dumps(person_metadata)
key = cache_data_key(identifier, ':cic.person') key = cache_data_key(identifier, ':cic.person')
cache_data(key, person) cache_data(key, person)
@@ -78,7 +78,7 @@ def cache_person_metadata(activated_account, init_cache, person_metadata):
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def cache_preferences(activated_account, init_cache, preferences): def cache_preferences(activated_account, init_cache, preferences):
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
preferences = json.dumps(preferences) preferences = json.dumps(preferences)
key = cache_data_key(identifier, ':cic.preferences') key = cache_data_key(identifier, ':cic.preferences')
cache_data(key, preferences) cache_data(key, preferences)
@@ -86,10 +86,10 @@ def cache_preferences(activated_account, init_cache, preferences):
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def cache_statement(activated_account, init_cache, statement): def cache_statement(activated_account, init_cache, statement):
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
statement = json.dumps(statement) preferences = json.dumps(statement)
key = cache_data_key(identifier, ':cic.statement') key = cache_data_key(identifier, ':cic.statement')
cache_data(key, statement) cache_data(key, preferences)
@pytest.fixture(scope='function') @pytest.fixture(scope='function')

View File

@@ -41,22 +41,6 @@ def mock_async_balance_api_query(mocker):
return query_args return query_args
@pytest.fixture(scope='function')
def mock_get_adjusted_balance(mocker, task_uuid):
query_args = {}
def get_adjusted_balance(self, token_symbol, balance, timestamp):
sync_res = mocker.patch('celery.result.AsyncResult')
sync_res.id = task_uuid
sync_res.result = 45931650.64654012
query_args['balance'] = balance
query_args['timestamp'] = timestamp
query_args['token_symbol'] = token_symbol
return sync_res
mocker.patch('cic_eth_aux.erc20_demurrage_token.api.Api.get_adjusted_balance', get_adjusted_balance)
return query_args
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def mock_notifier_api(mocker): def mock_notifier_api(mocker):
sms = {} sms = {}

View File

@@ -7,7 +7,6 @@ import pytest
# local import # local import
from cic_ussd.account.balance import get_cached_available_balance from cic_ussd.account.balance import get_cached_available_balance
# tests imports # tests imports
@@ -104,8 +103,8 @@ def transactions_list(activated_account, valid_recipient):
'destination_token': '0x0000000000000000000000000000000000000000', 'destination_token': '0x0000000000000000000000000000000000000000',
'block_number': 80, 'block_number': 80,
'tx_index': 0, 'tx_index': 0,
'sender': '367cB0F65137b0A845c1DB4B7Ca47D3DEF32dDe8', 'sender': '0x367cB0F65137b0A845c1DB4B7Ca47D3DEF32dDe8',
'recipient': '103d1ed6e370dBa6267045c70d4999384c18a04A', 'recipient': '0x103d1ed6e370dBa6267045c70d4999384c18a04A',
'from_value': 0, 'from_value': 0,
'to_value': 0, 'to_value': 0,
'date_created': '2021-07-14T14:13:46.036198', 'date_created': '2021-07-14T14:13:46.036198',
@@ -123,8 +122,8 @@ def transactions_list(activated_account, valid_recipient):
'destination_token': '0x0000000000000000000000000000000000000000', 'destination_token': '0x0000000000000000000000000000000000000000',
'block_number': 78, 'block_number': 78,
'tx_index': 0, 'tx_index': 0,
'sender': 'b41BfEE260693A473254D62b81aE1ADCC9E51AFb', 'sender': '0xb41BfEE260693A473254D62b81aE1ADCC9E51AFb',
'recipient': '367cB0F65137b0A845c1DB4B7Ca47D3DEF32dDe8', 'recipient': '0x367cB0F65137b0A845c1DB4B7Ca47D3DEF32dDe8',
'from_value': 1800000000000000, 'from_value': 1800000000000000,
'to_value': 1800000000000000, 'to_value': 1800000000000000,
'date_created': '2021-07-14T14:13:35.839638', 'date_created': '2021-07-14T14:13:35.839638',
@@ -143,8 +142,8 @@ def transactions_list(activated_account, valid_recipient):
'destination_token': '0x0000000000000000000000000000000000000000', 'destination_token': '0x0000000000000000000000000000000000000000',
'block_number': 79, 'block_number': 79,
'tx_index': 0, 'tx_index': 0,
'sender': '367cB0F65137b0A845c1DB4B7Ca47D3DEF32dDe8', 'sender': '0x367cB0F65137b0A845c1DB4B7Ca47D3DEF32dDe8',
'recipient': '103d1ed6e370dBa6267045c70d4999384c18a04A', 'recipient': '0x103d1ed6e370dBa6267045c70d4999384c18a04A',
'from_value': 0, 'from_value': 0,
'to_value': 0, 'to_value': 0,
'date_created': '2021-07-14T14:13:35.638355', 'date_created': '2021-07-14T14:13:35.638355',
@@ -153,3 +152,4 @@ def transactions_list(activated_account, valid_recipient):
'timestamp': 1626272015, 'timestamp': 1626272015,
'hash': '0x32ca3dd3bef06463b452f4d32f5f563d083cb4759219eed90f3d2a9c1791c5fc'} 'hash': '0x32ca3dd3bef06463b452f4d32f5f563d083cb4759219eed90f3d2a9c1791c5fc'}
] ]

View File

@@ -4,6 +4,7 @@ import random
import uuid import uuid
# external imports # external imports
from chainlib.eth.address import to_checksum_address
from faker import Faker from faker import Faker
from faker_e164.providers import E164Provider from faker_e164.providers import E164Provider
@@ -20,7 +21,7 @@ def phone_number() -> str:
def blockchain_address() -> str: def blockchain_address() -> str:
return os.urandom(20).hex().lower() return to_checksum_address('0x' + os.urandom(20).hex())
def session_id() -> str: def session_id() -> str:

View File

@@ -141,22 +141,12 @@ en:
0. Back 0. Back
retry: |- retry: |-
%{retry_pin_entry} %{retry_pin_entry}
account_balances: account_balances: |-
available_balance: |- CON Your balances are as follows:
CON Your balances are as follows: balance: %{available_balance} %{token_symbol}
balance: %{available_balance} %{token_symbol} fees: %{tax} %{token_symbol}
0. Back rewards: %{bonus} %{token_symbol}
with_fees: |- 0. Back
CON Your balances are as follows:
balances: %{available_balance} %{token_symbol}
fees: %{tax} %{token_symbol}
0. Back
with_rewards: |-
CON Your balances are as follows:
balance: %{available_balance} %{token_symbol}
fees: %{tax} %{token_symbol}
rewards: %{bonus} %{token_symbol}
0. Back
first_transaction_set: |- first_transaction_set: |-
CON %{first_transaction_set} CON %{first_transaction_set}
1. Next 1. Next

View File

@@ -140,22 +140,12 @@ sw:
0. Nyuma 0. Nyuma
retry: |- retry: |-
%{retry_pin_entry} %{retry_pin_entry}
account_balances: account_balances: |-
available_balance: |- CON Salio zako ni zifuatazo:
CON Salio zako ni zifuatazo: salio: %{available_balance} %{token_symbol}
salio: %{available_balance} %{token_symbol} ushuru: %{tax} %{token_symbol}
0. Nyuma tuzo: %{bonus} %{token_symbol}
with_fees: |- 0. Nyuma
CON Salio zako ni zifuatazo:
salio: %{available_balance} %{token_symbol}
ushuru: %{tax} %{token_symbol}
0. Nyuma
with_rewards: |-
CON Salio zako ni zifuatazo:
salio: %{available_balance} %{token_symbol}
ushuru: %{tax} %{token_symbol}
tuzo: %{bonus} %{token_symbol}
0. Nyuma
first_transaction_set: |- first_transaction_set: |-
CON %{first_transaction_set} CON %{first_transaction_set}
1. Mbele 1. Mbele

View File

@@ -1,46 +0,0 @@
#!/bin/bash
set -a
if [ -z $DEV_DATA_DIR ]; then
export DEV_DATA_DIR=`mktemp -d`
else
mkdir -p $DEV_DATA_DIR
fi
if [ -z $DEV_CONFIG_RESET ]; then
if [ -f ${DEV_DATA_DIR}/env_reset ]; then
>&2 echo "importing existing configuration values from ${DEV_DATA_DIR}/env_reset"
. ${DEV_DATA_DIR}/env_reset
fi
fi
# Handle wallet
export WALLET_KEY_FILE=${WALLET_KEY_FILE:-`realpath ./keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c`}
if [ ! -f $WALLET_KEY_FILE ]; then
>&2 echo "wallet path '$WALLET_KEY_FILE' does not point to a file"
exit 1
fi
export DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER=`eth-checksum $(cat $WALLET_KEY_FILE | jq -r .address)`
# Wallet dependent variable defaults
export DEV_ETH_ACCOUNT_RESERVE_MINTER=${DEV_ETH_ACCOUNT_RESERVE_MINTER:-$DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER}
export DEV_ETH_ACCOUNT_ACCOUNTS_INDEX_WRITER=${DEV_ETH_ACCOUNT_RESERVE_MINTER:-$DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER}
export CIC_TRUST_ADDRESS=${CIC_TRUST_ADDRESS:-$DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER}
export CIC_DEFAULT_TOKEN_SYMBOL=$TOKEN_SYMBOL
export TOKEN_SINK_ADDRESS=${TOKEN_SINK_ADDRESS:-$DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER}
# Legacy variable defaults
# Migration variable processing
confini-dump --schema-dir ./config --prefix export > ${DEV_DATA_DIR}/env_reset
echo "export CIC_TRUST_ADDRESS=$CIC_TRUST_ADDRESS
export CIC_DEFAULT_TOKEN_SYMBOL=$CIC_DEFAULT_TOKEN_SYMBOL
export WALLET_KEY_FILE=$WALLET_KEY_FILE
" >> ${DEV_DATA_DIR}/env_reset
cat ${DEV_DATA_DIR}/env_reset
set +a

View File

@@ -1,13 +0,0 @@
[dev]
eth_account_contract_deployer =
eth_account_reserve_minter =
eth_account_accounts_index_writer =
reserve_amount = 10000000000000000000000000000000000
faucet_amount = 0
gas_amount = 100000000000000000000000
token_amount = 100000000000000000000000
eth_gas_price =
data_dir =
pip_extra_index_url =
eth_provider_host =
eth_provider_port =

View File

@@ -0,0 +1,44 @@
# syntax = docker/dockerfile:1.2
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e
WORKDIR /root
RUN touch /etc/apt/sources.list.d/ethereum.list
RUN echo 'deb http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic main' > /etc/apt/sources.list.d/ethereum.list
RUN echo 'deb-src http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic main' >> /etc/apt/sources.list.d/ethereum.list
RUN cat /etc/apt/sources.list.d/ethereum.list
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 2A518C819BE37D2C2031944D1C52189C923F6CA9
#RUN apt-get install solc
RUN mkdir -vp /usr/local/etc/cic
ENV CONFINI_DIR /usr/local/etc/cic/
COPY config_template/ /usr/local/etc/cic/
COPY requirements.txt .
COPY override_requirements.txt .
ARG pip_index_url=https://pypi.org/simple
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG EXTRA_PIP_ARGS=""
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
ARG pip_trusted_host=pypi.org
RUN pip install --index-url https://pypi.org/simple \
pip install --index-url https://pypi.org/simple \
--pre \
--force-reinstall \
--trusted-host $pip_trusted_host \
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL $EXTRA_PIP_ARGS \
-r requirements.txt
RUN pip install --index-url https://pypi.org/simple \
--force-reinstall \
--pre \
--trusted-host $pip_trusted_host \
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL $EXTRA_PIP_ARGS \
-r override_requirements.txt
COPY . .
RUN chmod +x *.sh

View File

@@ -56,7 +56,6 @@ ETH_PROVIDER
ETH_ABI_DIR ETH_ABI_DIR
SIGNER_SOCKET_PATH SIGNER_SOCKET_PATH
SIGNER_SECRET SIGNER_SECRET
SIGNER_PROVIDER
CELERY_BROKER_URL CELERY_BROKER_URL
CELERY_RESULT_URL CELERY_RESULT_URL
META_PROVIDER META_PROVIDER

View File

@@ -1,6 +1,6 @@
cic-eth[tools]==0.12.4a8 cic-eth[tools]==0.12.4a4
chainlib-eth>=0.0.9a14,<0.1.0 chainlib-eth>=0.0.9a7,<0.1.0
eth-erc20>=0.1.2a3,<0.2.0 eth-erc20>=0.1.2a2,<0.2.0
erc20-demurrage-token>=0.0.5a2,<0.1.0 erc20-demurrage-token>=0.0.5a2,<0.1.0
eth-accounts-index>=0.1.2a2,<0.2.0 eth-accounts-index>=0.1.2a2,<0.2.0
eth-address-index>=0.2.3a4,<0.3.0 eth-address-index>=0.2.3a4,<0.3.0
@@ -8,5 +8,3 @@ cic-eth-registry>=0.6.1a2,<0.7.0
erc20-transfer-authorization>=0.3.5a2,<0.4.0 erc20-transfer-authorization>=0.3.5a2,<0.4.0
erc20-faucet>=0.3.2a2,<0.4.0 erc20-faucet>=0.3.2a2,<0.4.0
sarafu-faucet>=0.0.7a2,<0.1.0 sarafu-faucet>=0.0.7a2,<0.1.0
confini>=0.4.2rc3,<1.0.0
crypto-dev-signer>=0.4.15a7,<=0.4.15

View File

@@ -2,122 +2,179 @@
set -a set -a
. ${DEV_DATA_DIR}/env_reset default_token=giftable_erc20_token
TOKEN_SYMBOL=${CIC_DEFAULT_TOKEN_SYMBOL}
TOKEN_NAME=${TOKEN_NAME}
TOKEN_TYPE=${TOKEN_TYPE:-$default_token}
cat <<EOF
external token settings:
token_type: $TOKEN_TYPE
token_symbol: $TOKEN_SYMBOL
token_name: $TOKEN_NAME
token_decimals: $TOKEN_DECIMALS
token_demurrage: $TOKEN_DEMURRAGE_LEVEL
token_redistribution_period: $TOKEN_REDISTRIBUTION_PERIOD
token_supply_limit: $TOKEN_SUPPLY_LIMIT
EOF
WAIT_FOR_TIMEOUT=${WAIT_FOR_TIMEOUT:-60} CHAIN_SPEC=${CHAIN_SPEC:-$CIC_CHAIN_SPEC}
RPC_HTTP_PROVIDER=${RPC_HTTP_PROVIDER:-$ETH_PROVIDER}
DEV_ETH_ACCOUNT_RESERVE_MINTER=${DEV_ETH_ACCOUNT_RESERVE_MINTER:-$DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER}
DEV_ETH_ACCOUNT_ACCOUNTS_INDEX_WRITER=${DEV_ETH_ACCOUNT_RESERVE_MINTER:-$DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER}
DEV_RESERVE_AMOUNT=${DEV_ETH_RESERVE_AMOUNT:-""10000000000000000000000000000000000}
DEV_FAUCET_AMOUNT=${DEV_FAUCET_AMOUNT:-0}
DEV_ETH_KEYSTORE_FILE=${DEV_ETH_KEYSTORE_FILE:-`realpath ./keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c`}
set -e set -e
DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER=`eth-checksum $(cat $DEV_ETH_KEYSTORE_FILE | jq -r .address)`
if [ ! -z $DEV_ETH_GAS_PRICE ]; then if [ ! -z $DEV_ETH_GAS_PRICE ]; then
gas_price_arg="--gas-price $DEV_ETH_GAS_PRICE" gas_price_arg="--gas-price $DEV_ETH_GAS_PRICE"
fee_price_arg="--fee-price $DEV_ETH_GAS_PRICE" fee_price_arg="--fee-price $DEV_ETH_GAS_PRICE"
>&2 echo using static gas price $DEV_ETH_GAS_PRICE
fi fi
echo "environment:"
printenv
echo \n
echo "using wallet address '$DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER' from keystore file $DEV_ETH_KEYSTORE_FILE"
# This is a grassroots team convention for building the Bancor contracts using the bancor protocol repository truffle setup
# Running this in docker-internal dev container (built from Docker folder in this repo) will write a
# source-able env file to CIC_DATA_DIR. Services dependent on these contracts can mount this file OR
# define these parameters at runtime
# pushd /usr/src
if [ -z $CIC_DATA_DIR ]; then
CIC_DATA_DIR=`mktemp -d`
fi
>&2 echo using data dir $CIC_DATA_DIR
init_level_file=${CIC_DATA_DIR}/.init
if [ ! -f ${CIC_DATA_DIR}/.init ]; then
echo "Creating .init file..."
mkdir -p $CIC_DATA_DIR
touch $CIC_DATA_DIR/.init
# touch $init_level_file
fi
echo -n 1 > $init_level_file
# Abort on any error (including if wait-for-it fails).
# Wait for the backend to be up, if we know where it is. # Wait for the backend to be up, if we know where it is.
if [ -z "${RPC_PROVIDER}" ]; then if [[ -n "${ETH_PROVIDER}" ]]; then
echo "\$RPC_PROVIDER not set!"
exit 1
fi
unset CONFINI_DIR export CONFINI_DIR=$_CONFINI_DIR
unset CONFINI_DIR
if [ ! -z "$DEV_USE_DOCKER_WAIT_SCRIPT" ]; then if [ ! -z "$DEV_USE_DOCKER_WAIT_SCRIPT" ]; then
IFS=: read -a p <<< "$RPC_PROVIDER" echo "waiting for ${ETH_PROVIDER}..."
read -i "/" rpc_provider_port <<< "${p[2]}" ./wait-for-it.sh "${ETH_PROVIDER_HOST}:${ETH_PROVIDER_PORT}"
rpc_provider_host=${p[1]:2}
echo "waiting for provider host $rpc_provider_host port $rpc_provider_port..."
./wait-for-it.sh "$rpc_provider_host:$rpc_provider_port" -t $WAIT_FOR_TIMEOUT
fi
if [ "$TOKEN_TYPE" == "giftable_erc20_token" ]; then
if [ -z "$TOKEN_SYMBOL" ]; then
>&2 echo token symbol not set, setting defaults for type $TOKEN_TYPE
TOKEN_SYMBOL="GFT"
TOKEN_NAME="Giftable Token"
elif [ -z "$TOKEN_NAME" ]; then
>&2 echo token name not set, setting same as symbol for type $TOKEN_TYPE
TOKEN_NAME=$TOKEN_SYMBOL
fi fi
>&2 echo deploying default token $TOKEN_TYPE
echo giftable-token-deploy $fee_price_arg -p $RPC_PROVIDER -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -vv -s -ww --name "$TOKEN_NAME" --symbol $TOKEN_SYMBOL --decimals 6 -vv if [ "$TOKEN_TYPE" == "$default_token" ]; then
DEV_RESERVE_ADDRESS=`giftable-token-deploy $fee_price_arg -p $RPC_PROVIDER -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -vv -s -ww --name "$TOKEN_NAME" --symbol $TOKEN_SYMBOL --decimals 6 -vv` if [ -z "$TOKEN_SYMBOL" ]; then
elif [ "$TOKEN_TYPE" == "erc20_demurrage_token" ]; then >&2 echo token symbol not set, setting defaults for type $TOKEN_TYPE
if [ -z "$TOKEN_SYMBOL" ]; then TOKEN_SYMBOL="GFT"
>&2 echo token symbol not set, setting defaults for type $TOKEN_TYPE TOKEN_NAME="Giftable Token"
TOKEN_SYMBOL="DET" elif [ -z "$TOKEN_NAME" ]; then
TOKEN_NAME="Demurrage Token" >&2 echo token name not set, setting same as symbol for type $TOKEN_TYPE
elif [ -z "$TOKEN_NAME" ]; then TOKEN_NAME=$TOKEN_SYMBOL
>&2 echo token name not set, setting same as symbol for type $TOKEN_TYPE
TOKEN_NAME=$TOKEN_SYMBOL
fi
>&2 echo deploying token $TOKEN_TYPE
if [ -z $TOKEN_SINK_ADDRESS ]; then
if [ ! -z $TOKEN_REDISTRIBUTION_PERIOD ]; then
>&2 echo -e "\033[;93mtoken sink address not set, so redistribution will be BURNED\033[;39m"
fi fi
>&2 echo deploying default token $TOKEN_TYPE
echo giftable-token-deploy $fee_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -vv -s -ww --name "$TOKEN_NAME" --symbol $TOKEN_SYMBOL --decimals 6 -vv
DEV_RESERVE_ADDRESS=`giftable-token-deploy $fee_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -vv -s -ww --name "$TOKEN_NAME" --symbol $TOKEN_SYMBOL --decimals 6 -vv`
elif [ "$TOKEN_TYPE" == "erc20_demurrage_token" ]; then
if [ -z "$TOKEN_SYMBOL" ]; then
>&2 echo token symbol not set, setting defaults for type $TOKEN_TYPE
TOKEN_SYMBOL="SARAFU"
TOKEN_NAME="Sarafu Token"
elif [ -z "$TOKEN_NAME" ]; then
>&2 echo token name not set, setting same as symbol for type $TOKEN_TYPE
TOKEN_NAME=$TOKEN_SYMBOL
fi
>&2 echo deploying token $TOKEN_TYPE
if [ -z $TOKEN_SINK_ADDRESS ]; then
if [ ! -z $TOKEN_REDISTRIBUTION_PERIOD ]; then
>&2 echo -e "\033[;93mtoken sink address not set, so redistribution will be BURNED\033[;39m"
fi
fi
DEV_RESERVE_ADDRESS=`erc20-demurrage-token-deploy $fee_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC --name "$TOKEN_NAME" --symbol $TOKEN_SYMBOL -vv -ww -s`
else
>&2 echo unknown token type $TOKEN_TYPE
exit 1
fi fi
DEV_RESERVE_ADDRESS=`erc20-demurrage-token-deploy $fee_price_arg -p $RPC_PROVIDER -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC --name "$TOKEN_NAME" --symbol $TOKEN_SYMBOL -vv -ww -s`
echo "giftable-token-gift $fee_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -vv -w -e $DEV_RESERVE_ADDRESS $DEV_RESERVE_AMOUNT"
giftable-token-gift $fee_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -u -vv -s -w -e $DEV_RESERVE_ADDRESS $DEV_RESERVE_AMOUNT
>&2 echo "deploy account index contract"
DEV_ACCOUNT_INDEX_ADDRESS=`eth-accounts-index-deploy $fee_price_arg -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -vv -s -u -w`
>&2 echo "add deployer address as account index writer"
eth-accounts-index-writer $fee_price_arg -s -u -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -e $DEV_ACCOUNT_INDEX_ADDRESS -ww -vv $debug $DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER
>&2 echo "deploy contract registry contract"
CIC_REGISTRY_ADDRESS=`eth-contract-registry-deploy $fee_price_arg -i $CIC_CHAIN_SPEC -y $DEV_ETH_KEYSTORE_FILE --identifier AccountRegistry --identifier TokenRegistry --identifier AddressDeclarator --identifier Faucet --identifier TransferAuthorization --identifier ContractRegistry -p $ETH_PROVIDER -vv -s -u -w`
eth-contract-registry-set $fee_price_arg -s -u -w -y $DEV_ETH_KEYSTORE_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -vv --identifier ContractRegistry $CIC_REGISTRY_ADDRESS
eth-contract-registry-set $fee_price_arg -s -u -w -y $DEV_ETH_KEYSTORE_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -vv --identifier AccountRegistry $DEV_ACCOUNT_INDEX_ADDRESS
# Deploy address declarator registry
>&2 echo "deploy address declarator contract"
declarator_description=0x546869732069732074686520434943206e6574776f726b000000000000000000
DEV_DECLARATOR_ADDRESS=`eth-address-declarator-deploy -s -u -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -w -vv $declarator_description`
eth-contract-registry-set $fee_price_arg -s -u -w -y $DEV_ETH_KEYSTORE_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -vv --identifier AddressDeclarator $DEV_DECLARATOR_ADDRESS
# Deploy transfer authorization contact
>&2 echo "deploy transfer auth contract"
DEV_TRANSFER_AUTHORIZATION_ADDRESS=`erc20-transfer-auth-deploy $gas_price_arg -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -w -vv`
eth-contract-registry-set $fee_price_arg -s -u -w -y $DEV_ETH_KEYSTORE_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -vv --identifier TransferAuthorization $DEV_TRANSFER_AUTHORIZATION_ADDRESS
# Deploy token index contract
>&2 echo "deploy token index contract"
DEV_TOKEN_INDEX_ADDRESS=`eth-token-index-deploy -s -u $fee_price_arg -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -w -vv`
eth-contract-registry-set $fee_price_arg -s -u -w -y $DEV_ETH_KEYSTORE_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -vv --identifier TokenRegistry $DEV_TOKEN_INDEX_ADDRESS
>&2 echo "add reserve token to token index"
eth-token-index-add $fee_price_arg -s -u -w -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -vv -e $DEV_TOKEN_INDEX_ADDRESS $DEV_RESERVE_ADDRESS
# Sarafu faucet contract
>&2 echo "deploy token faucet contract"
DEV_FAUCET_ADDRESS=`sarafu-faucet-deploy $fee_price_arg -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -w -vv --account-index-address $DEV_ACCOUNT_INDEX_ADDRESS $DEV_RESERVE_ADDRESS -s`
>&2 echo "set token faucet amount"
sarafu-faucet-set $fee_price_arg -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -e $DEV_FAUCET_ADDRESS -vv -s --fee-limit 100000 $DEV_FAUCET_AMOUNT
>&2 echo "register faucet in registry"
eth-contract-registry-set -s -u $fee_price_arg -w -y $DEV_ETH_KEYSTORE_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -vv --identifier Faucet $DEV_FAUCET_ADDRESS
>&2 echo "set faucet as token minter"
giftable-token-minter -s -u $fee_price_arg -w -y $DEV_ETH_KEYSTORE_FILE -e $DEV_RESERVE_ADDRESS -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -vv $DEV_FAUCET_ADDRESS
export CONFINI_DIR=$_CONFINI_DIR
else else
>&2 echo unknown token type $TOKEN_TYPE echo "\$ETH_PROVIDER not set!"
exit 1 exit 1
fi fi
echo "giftable-token-gift $fee_price_arg -p $RPC_PROVIDER -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -vv -w -e $DEV_RESERVE_ADDRESS $DEV_RESERVE_AMOUNT" mkdir -p $CIC_DATA_DIR
giftable-token-gift $fee_price_arg -p $RPC_PROVIDER -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -u -vv -s -w -e $DEV_RESERVE_ADDRESS $DEV_RESERVE_AMOUNT >&2 echo using data dir $CIC_DATA_DIR for environment variable dump
>&2 echo "deploy account index contract" # this is consumed in downstream services to set environment variables
DEV_ACCOUNT_INDEX_ADDRESS=`eth-accounts-index-deploy $fee_price_arg -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -y $WALLET_KEY_FILE -vv -s -u -w` cat << EOF > $CIC_DATA_DIR/.env
>&2 echo "add deployer address as account index writer" export CIC_REGISTRY_ADDRESS=$CIC_REGISTRY_ADDRESS
eth-accounts-index-writer $fee_price_arg -s -u -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -e $DEV_ACCOUNT_INDEX_ADDRESS -ww -vv $debug $DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER export CIC_TRUST_ADDRESS=$DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER
export CIC_DECLARATOR_ADDRESS=$CIC_DECLARATOR_ADDRESS
EOF
>&2 echo "deploy contract registry contract" cat ./envlist | bash from_env.sh > $CIC_DATA_DIR/.env_all
CIC_REGISTRY_ADDRESS=`eth-contract-registry-deploy $fee_price_arg -i $CIC_CHAIN_SPEC -y $WALLET_KEY_FILE --identifier AccountRegistry --identifier TokenRegistry --identifier AddressDeclarator --identifier Faucet --identifier TransferAuthorization --identifier ContractRegistry -p $RPC_PROVIDER -vv -s -u -w` cat ./envlist
eth-contract-registry-set $fee_price_arg -s -u -w -y $WALLET_KEY_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -vv --identifier ContractRegistry $CIC_REGISTRY_ADDRESS # popd
eth-contract-registry-set $fee_price_arg -s -u -w -y $WALLET_KEY_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -vv --identifier AccountRegistry $DEV_ACCOUNT_INDEX_ADDRESS
# Deploy address declarator registry
>&2 echo "deploy address declarator contract"
declarator_description=0x546869732069732074686520434943206e6574776f726b000000000000000000
DEV_DECLARATOR_ADDRESS=`eth-address-declarator-deploy -s -u -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -w -vv $declarator_description`
eth-contract-registry-set $fee_price_arg -s -u -w -y $WALLET_KEY_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -vv --identifier AddressDeclarator $DEV_DECLARATOR_ADDRESS
# Deploy transfer authorization contact
>&2 echo "deploy transfer auth contract"
DEV_TRANSFER_AUTHORIZATION_ADDRESS=`erc20-transfer-auth-deploy $gas_price_arg -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -w -vv`
eth-contract-registry-set $fee_price_arg -s -u -w -y $WALLET_KEY_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -vv --identifier TransferAuthorization $DEV_TRANSFER_AUTHORIZATION_ADDRESS
# Deploy token index contract
>&2 echo "deploy token index contract"
DEV_TOKEN_INDEX_ADDRESS=`eth-token-index-deploy -s -u $fee_price_arg -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -w -vv`
eth-contract-registry-set $fee_price_arg -s -u -w -y $WALLET_KEY_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -vv --identifier TokenRegistry $DEV_TOKEN_INDEX_ADDRESS
>&2 echo "add reserve token to token index"
eth-token-index-add $fee_price_arg -s -u -w -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -vv -e $DEV_TOKEN_INDEX_ADDRESS $DEV_RESERVE_ADDRESS
# Sarafu faucet contract
>&2 echo "deploy token faucet contract"
DEV_FAUCET_ADDRESS=`sarafu-faucet-deploy $fee_price_arg -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -w -vv --account-index-address $DEV_ACCOUNT_INDEX_ADDRESS $DEV_RESERVE_ADDRESS -s`
>&2 echo "set token faucet amount"
sarafu-faucet-set $fee_price_arg -w -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -e $DEV_FAUCET_ADDRESS -vv -s --fee-limit 100000 $DEV_FAUCET_AMOUNT
>&2 echo "register faucet in registry"
eth-contract-registry-set -s -u $fee_price_arg -w -y $WALLET_KEY_FILE -e $CIC_REGISTRY_ADDRESS -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -vv --identifier Faucet $DEV_FAUCET_ADDRESS
>&2 echo "set faucet as token minter"
giftable-token-minter -s -u $fee_price_arg -w -y $WALLET_KEY_FILE -e $DEV_RESERVE_ADDRESS -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -vv $DEV_FAUCET_ADDRESS
#echo "export CIC_DEFAULT_TOKEN_SYMBOL=$TOKEN_SYMBOL" >> ${DEV_DATA_DIR}/env_reset
export CIC_DEFAULT_TOKEN_SYMBOL=$TOKEN_SYMBOL
echo "Writing env_reset file ..."
echo "export CIC_REGISTRY_ADDRESS=$CIC_REGISTRY_ADDRESS
export CIC_DEFAULT_TOKEN_SYMBOL=$CIC_DEFAULT_TOKEN_SYMBOL
export TOKEN_NAME=$TOKEN_NAME
" >> "${DEV_DATA_DIR}"/env_reset
set +a set +a
set +e set +e
echo -n 2 > $init_level_file
exec "$@" exec "$@"

View File

@@ -1,13 +1,5 @@
#! /bin/bash #! /bin/bash
>&2 echo -e "\033[;96mRUNNING\033[;39m configurations"
./config.sh
if [ $? -ne "0" ]; then
>&2 echo -e "\033[;31mFAILED\033[;39m configurations"
exit 1;
fi
>&2 echo -e "\033[;32mSUCCEEDED\033[;39m configurations"
if [[ $((RUN_MASK & 1)) -eq 1 ]] if [[ $((RUN_MASK & 1)) -eq 1 ]]
then then
>&2 echo -e "\033[;96mRUNNING\033[;39m RUN_MASK 1 - contract deployment" >&2 echo -e "\033[;96mRUNNING\033[;39m RUN_MASK 1 - contract deployment"

View File

@@ -1,40 +1,68 @@
#!/bin/bash #!/bin/bash
# defaults # defaults
source ${DEV_DATA_DIR}/env_reset #initlevel=`cat ${CIC_DATA_DIR}/.init`
cat ${DEV_DATA_DIR}/env_reset #echo $inilevel
#if [ $initlevel -lt 2 ]; then
# >&2 echo "initlevel too low $initlevel"
# exit 1
#fi
source ${CIC_DATA_DIR}/.env
source ${CIC_DATA_DIR}/.env_all
DEV_PIP_EXTRA_INDEX_URL=${DEV_PIP_EXTRA_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
DEV_DATABASE_NAME_CIC_ETH=${DEV_DATABASE_NAME_CIC_ETH:-"cic-eth"}
CIC_DATA_DIR=${CIC_DATA_DIR:-/tmp/cic}
ETH_PASSPHRASE=''
CIC_DEFAULT_TOKEN_SYMBOL=${CIC_DEFAULT_TOKEN_SYMBOL:-GFT}
TOKEN_SYMBOL=$CIC_DEFAULT_TOKEN_SYMBOL
CHAIN_SPEC=${CHAIN_SPEC:-$CIC_CHAIN_SPEC}
RPC_HTTP_PROVIDER=${RPC_HTTP_PROVIDER:-$ETH_PROVIDER}
# Debug flag # Debug flag
DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER=0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C
keystore_file=./keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c
debug='-vv' debug='-vv'
gas_amount=100000000000000000000000
token_amount=${gas_amount}
env_out_file=${CIC_DATA_DIR}/.env_seed
init_level_file=${CIC_DATA_DIR}/.init
empty_config_dir=$CONFINI_DIR/empty empty_config_dir=$CONFINI_DIR/empty
truncate $env_out_file -s 0
set -e set -e
set -a set -a
#pip install --extra-index-url $DEV_PIP_EXTRA_INDEX_URL eth-address-index==0.1.1a7
export CONFINI_DIR=$_CONFINI_DIR
unset CONFINI_DIR unset CONFINI_DIR
# get required addresses from registries # get required addresses from registries
token_index_address=`eth-contract-registry-list -u -i $CHAIN_SPEC -p $RPC_PROVIDER -e $CIC_REGISTRY_ADDRESS -vv --raw TokenRegistry` DEV_TOKEN_INDEX_ADDRESS=`eth-contract-registry-list -u -i $CHAIN_SPEC -p $ETH_PROVIDER -e $CIC_REGISTRY_ADDRESS -vv --raw TokenRegistry`
account_index_address=`eth-contract-registry-list -u -i $CHAIN_SPEC -p $RPC_PROVIDER -e $CIC_REGISTRY_ADDRESS -vv --raw AccountRegistry` DEV_ACCOUNT_INDEX_ADDRESS=`eth-contract-registry-list -u -i $CHAIN_SPEC -p $ETH_PROVIDER -e $CIC_REGISTRY_ADDRESS -vv --raw AccountRegistry`
reserve_address=`eth-token-index-list -i $CHAIN_SPEC -u -p $RPC_PROVIDER -e $token_index_address -vv --raw $CIC_DEFAULT_TOKEN_SYMBOL` DEV_RESERVE_ADDRESS=`eth-token-index-list -i $CHAIN_SPEC -u -p $ETH_PROVIDER -e $DEV_TOKEN_INDEX_ADDRESS -vv --raw $CIC_DEFAULT_TOKEN_SYMBOL`
cat <<EOF
>&2 echo "Token registry: $token_index_address" Token registry: $DEV_TOKEN_INDEX_ADDRESS
>&2 echo "Account registry: $account_index_address" Account reigstry: $DEV_ACCOUNT_INDEX_ADDRESS
>&2 echo "Reserve address: $reserve_address ($TOKEN_SYMBOL)" Reserve address: $DEV_RESERVE_ADDRESS ($CIC_DEFAULT_TOKEN_SYMBOL)
EOF
>&2 echo "create account for gas gifter" >&2 echo "create account for gas gifter"
old_gas_provider=$DEV_ETH_ACCOUNT_GAS_PROVIDER old_gas_provider=$DEV_ETH_ACCOUNT_GAS_PROVIDER
#DEV_ETH_ACCOUNT_GAS_GIFTER=`CONFINI_DIR=$empty_config_dir cic-eth-create --redis-timeout 120 $debug --redis-host $REDIS_HOST --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register` DEV_ETH_ACCOUNT_GAS_GIFTER=`CONFINI_DIR=$empty_config_dir cic-eth-create --redis-timeout 120 $debug --redis-host $REDIS_HOST --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register`
DEV_ETH_ACCOUNT_GAS_GIFTER=`cic-eth-create --redis-timeout 120 $debug --redis-host $REDIS_HOST --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register` echo DEV_ETH_ACCOUNT_GAS_GIFTER=$DEV_ETH_ACCOUNT_GAS_GIFTER >> $env_out_file
cic-eth-tag -i $CHAIN_SPEC GAS_GIFTER $DEV_ETH_ACCOUNT_GAS_GIFTER cic-eth-tag -i $CHAIN_SPEC GAS_GIFTER $DEV_ETH_ACCOUNT_GAS_GIFTER
>&2 echo "create account for sarafu gifter" >&2 echo "create account for sarafu gifter"
DEV_ETH_ACCOUNT_SARAFU_GIFTER=`CONFINI_DIR=$empty_config_dir cic-eth-create $debug --redis-host $REDIS_HOST --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register` DEV_ETH_ACCOUNT_SARAFU_GIFTER=`CONFINI_DIR=$empty_config_dir cic-eth-create $debug --redis-host $REDIS_HOST --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register`
echo DEV_ETH_ACCOUNT_SARAFU_GIFTER=$DEV_ETH_ACCOUNT_SARAFU_GIFTER >> $env_out_file
cic-eth-tag -i $CHAIN_SPEC SARAFU_GIFTER $DEV_ETH_ACCOUNT_SARAFU_GIFTER cic-eth-tag -i $CHAIN_SPEC SARAFU_GIFTER $DEV_ETH_ACCOUNT_SARAFU_GIFTER
>&2 echo "create account for approval escrow owner" >&2 echo "create account for approval escrow owner"
DEV_ETH_ACCOUNT_TRANSFER_AUTHORIZATION_OWNER=`CONFINI_DIR=$empty_config_dir cic-eth-create $debug --redis-host $REDIS_HOST --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register` DEV_ETH_ACCOUNT_TRANSFER_AUTHORIZATION_OWNER=`CONFINI_DIR=$empty_config_dir cic-eth-create $debug --redis-host $REDIS_HOST --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register`
echo DEV_ETH_ACCOUNT_TRANSFER_AUTHORIZATION_OWNER=$DEV_ETH_ACCOUNT_TRANSFER_AUTHORIZATION_OWNER >> $env_out_file
cic-eth-tag -i $CHAIN_SPEC TRANSFER_AUTHORIZATION_OWNER $DEV_ETH_ACCOUNT_TRANSFER_AUTHORIZATION_OWNER cic-eth-tag -i $CHAIN_SPEC TRANSFER_AUTHORIZATION_OWNER $DEV_ETH_ACCOUNT_TRANSFER_AUTHORIZATION_OWNER
#>&2 echo "create account for faucet owner" #>&2 echo "create account for faucet owner"
@@ -44,45 +72,50 @@ cic-eth-tag -i $CHAIN_SPEC TRANSFER_AUTHORIZATION_OWNER $DEV_ETH_ACCOUNT_TRANSFE
>&2 echo "create account for accounts index writer" >&2 echo "create account for accounts index writer"
DEV_ETH_ACCOUNT_ACCOUNT_REGISTRY_WRITER=`CONFINI_DIR=$empty_config_dir cic-eth-create $debug --redis-host $REDIS_HOST --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register` DEV_ETH_ACCOUNT_ACCOUNT_REGISTRY_WRITER=`CONFINI_DIR=$empty_config_dir cic-eth-create $debug --redis-host $REDIS_HOST --redis-host-callback=$REDIS_HOST --redis-port-callback=$REDIS_PORT --no-register`
echo DEV_ETH_ACCOUNT_ACCOUNT_REGISTRY_WRITER=$DEV_ETH_ACCOUNT_ACCOUNT_REGISTRY_WRITER >> $env_out_file
cic-eth-tag -i $CHAIN_SPEC ACCOUNT_REGISTRY_WRITER $DEV_ETH_ACCOUNT_ACCOUNT_REGISTRY_WRITER cic-eth-tag -i $CHAIN_SPEC ACCOUNT_REGISTRY_WRITER $DEV_ETH_ACCOUNT_ACCOUNT_REGISTRY_WRITER
>&2 echo "add acccounts index writer account as writer on contract" >&2 echo "add acccounts index writer account as writer on contract"
eth-accounts-index-writer -s -u -y $WALLET_KEY_FILE -i $CHAIN_SPEC -p $RPC_PROVIDER -e $account_index_address -ww $debug $DEV_ETH_ACCOUNT_ACCOUNT_REGISTRY_WRITER eth-accounts-index-writer -s -u -y $keystore_file -i $CHAIN_SPEC -p $ETH_PROVIDER -e $DEV_ACCOUNT_INDEX_ADDRESS -ww $debug $DEV_ETH_ACCOUNT_ACCOUNT_REGISTRY_WRITER
# Transfer gas to custodial gas provider adddress # Transfer gas to custodial gas provider adddress
_CONFINI_DIR=$CONFINI_DIR _CONFINI_DIR=$CONFINI_DIR
unset CONFINI_DIR unset CONFINI_DIR
>&2 echo gift gas to gas gifter >&2 echo gift gas to gas gifter
>&2 eth-gas -s -u -y $WALLET_KEY_FILE -i $CHAIN_SPEC -p $RPC_PROVIDER -w $debug -a $DEV_ETH_ACCOUNT_GAS_GIFTER $DEV_GAS_AMOUNT >&2 eth-gas -s -u -y $keystore_file -i $CHAIN_SPEC -p $ETH_PROVIDER -w $debug -a $DEV_ETH_ACCOUNT_GAS_GIFTER $gas_amount
>&2 echo gift gas to sarafu token owner >&2 echo gift gas to sarafu token owner
>&2 eth-gas -s -u -y $WALLET_KEY_FILE -i $CHAIN_SPEC -p $RPC_PROVIDER -w $debug -a $DEV_ETH_ACCOUNT_SARAFU_GIFTER $DEV_GAS_AMOUNT >&2 eth-gas -s -u -y $keystore_file -i $CHAIN_SPEC -p $ETH_PROVIDER -w $debug -a $DEV_ETH_ACCOUNT_SARAFU_GIFTER $gas_amount
>&2 echo gift gas to account index owner >&2 echo gift gas to account index owner
>&2 eth-gas -s -u -y $WALLET_KEY_FILE -i $CHAIN_SPEC -p $RPC_PROVIDER -w $debug -a $DEV_ETH_ACCOUNT_ACCOUNT_REGISTRY_WRITER $DEV_GAS_AMOUNT >&2 eth-gas -s -u -y $keystore_file -i $CHAIN_SPEC -p $ETH_PROVIDER -w $debug -a $DEV_ETH_ACCOUNT_ACCOUNT_REGISTRY_WRITER $gas_amount
# Send token to token creator # Send token to token creator
>&2 echo "gift tokens to sarafu owner" >&2 echo "gift tokens to sarafu owner"
echo "giftable-token-gift -s -u -y $WALLET_KEY_FILE -i $CHAIN_SPEC -p $RPC_PROVIDER -e $reserve_address -a $DEV_ETH_ACCOUNT_SARAFU_GIFTER -w $debug $DEV_TOKEN_AMOUNT" echo "giftable-token-gift -s -u -y $keystore_file -i $CHAIN_SPEC -p $ETH_PROVIDER -e $DEV_RESERVE_ADDRESS -a $DEV_ETH_ACCOUNT_SARAFU_GIFTER -w $debug $token_amount"
>&2 giftable-token-gift -s -u -y $WALLET_KEY_FILE -i $CHAIN_SPEC -p $RPC_PROVIDER -e $reserve_address -a $DEV_ETH_ACCOUNT_SARAFU_GIFTER -w $debug $DEV_TOKEN_AMOUNT >&2 giftable-token-gift -s -u -y $keystore_file -i $CHAIN_SPEC -p $ETH_PROVIDER -e $DEV_RESERVE_ADDRESS -a $DEV_ETH_ACCOUNT_SARAFU_GIFTER -w $debug $token_amount
# Send token to token gifter # Send token to token gifter
>&2 echo "gift tokens to keystore address" >&2 echo "gift tokens to keystore address"
>&2 giftable-token-gift -s -u -y $WALLET_KEY_FILE -i $CHAIN_SPEC -p $RPC_PROVIDER -e $reserve_address -a $DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER -w $debug $DEV_TOKEN_AMOUNT >&2 giftable-token-gift -s -u -y $keystore_file -i $CHAIN_SPEC -p $ETH_PROVIDER -e $DEV_RESERVE_ADDRESS -a $DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER -w $debug $token_amount
>&2 echo "set sarafu token to reserve token (temporarily while bancor contracts are not connected)" >&2 echo "set sarafu token to reserve token (temporarily while bancor contracts are not connected)"
echo DEV_ETH_SARAFU_TOKEN_ADDRESS=$DEV_ETH_RESERVE_ADDRESS >> $env_out_file
export DEV_ETH_SARAFU_TOKEN_ADDRESS=$DEV_ETH_RESERVE_ADDRESS export DEV_ETH_SARAFU_TOKEN_ADDRESS=$DEV_ETH_RESERVE_ADDRESS
# Transfer tokens to gifter address # Transfer tokens to gifter address
>&2 echo "transfer tokens to token gifter address" >&2 echo "transfer tokens to token gifter address"
>&2 erc20-transfer -s -u -y $WALLET_KEY_FILE -i $CHAIN_SPEC -p $RPC_PROVIDER --fee-limit 100000 -e $reserve_address -w $debug -a $DEV_ETH_ACCOUNT_SARAFU_GIFTER ${DEV_TOKEN_AMOUNT:0:-1} >&2 erc20-transfer -s -u -y $keystore_file -i $CHAIN_SPEC -p $ETH_PROVIDER --fee-limit 100000 -e $DEV_RESERVE_ADDRESS -w $debug -a $DEV_ETH_ACCOUNT_SARAFU_GIFTER ${token_amount:0:-1}
#echo -n 0 > $init_level_file
#CONFINI_DIR=$_CONFINI_DIR
# Remove the SEND (8), QUEUE (16) and INIT (2) locks (or'ed), set by default at migration # Remove the SEND (8), QUEUE (16) and INIT (2) locks (or'ed), set by default at migration
cic-eth-ctl -i $CHAIN_SPEC unlock INIT cic-eth-ctl -i $CHAIN_SPEC unlock INIT
cic-eth-ctl -i $CHAIN_SPEC unlock SEND cic-eth-ctl -i $CHAIN_SPEC unlock SEND
cic-eth-ctl -i $CHAIN_SPEC unlock QUEUE cic-eth-ctl -i $CHAIN_SPEC unlock QUEUE
#confini-dump --schema-module chainlib.eth.data.config --schema-module cic_eth.data.config --schema-dir ./config export CONFINI_DIR=$_CONFINI_DIR
set +a set +a
set +e set +e

View File

@@ -2,7 +2,7 @@
.cache .cache
.dot .dot
**/doc **/doc
node_modules/ **/node_modules
**/venv **/venv
**/.venv **/.venv

View File

@@ -1,61 +1,64 @@
# standard imports
import argparse import argparse
import logging import logging
import os
import sys import sys
import os
# external imports # external imports
import celery import celery
import confini
import redis
from chainlib.chain import ChainSpec from chainlib.chain import ChainSpec
from chainlib.eth.address import to_checksum_address from chainlib.eth.address import to_checksum_address
from chainlib.eth.connection import EthHTTPConnection from chainlib.eth.connection import EthHTTPConnection
from confini import Config
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
from crypto_dev_signer.keystore.dict import DictKeystore from crypto_dev_signer.keystore.dict import DictKeystore
# local imports # local imports
from import_util import BalanceProcessor, get_celery_worker_status
from import_task import ImportTask, MetadataTask from import_task import ImportTask, MetadataTask
from import_util import BalanceProcessor, get_celery_worker_status
default_config_dir = '/usr/local/etc/data-seeding/' logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()
arg_parser = argparse.ArgumentParser(description='Daemon worker that handles data seeding tasks.') config_dir = './config'
arg_parser.add_argument('-c', type=str, default=default_config_dir, help='config root to use.')
arg_parser.add_argument('--env-prefix',
default=os.environ.get('CONFINI_ENV_PREFIX'),
dest='env_prefix',
type=str,
help='environment prefix for variables to overwrite configuration.')
arg_parser.add_argument('--head', action='store_true', help='start at current block height (overrides --offset)')
arg_parser.add_argument('-i', '--chain-spec', type=str, dest='i', help='chain spec')
arg_parser.add_argument('--include-balances', dest='include_balances', help='include opening balance transactions',
action='store_true')
arg_parser.add_argument('--meta-host', dest='meta_host', type=str, help='metadata server host')
arg_parser.add_argument('--meta-port', dest='meta_port', type=int, help='metadata server host')
arg_parser.add_argument('-p', '--provider', dest='p', type=str, help='chain rpc provider address')
arg_parser.add_argument('-q', type=str, default='cic-import-ussd', help='celery queue to submit data seeding tasks to.')
arg_parser.add_argument('-r', '--registry-address', type=str, dest='r', help='CIC Registry address')
arg_parser.add_argument('--redis-db', dest='redis_db', type=int, help='redis db to use for task submission and callback')
arg_parser.add_argument('--redis-host', dest='redis_host', type=str, help='redis host to use for task submission')
arg_parser.add_argument('--redis-port', dest='redis_port', type=int, help='redis host to use for task submission')
arg_parser.add_argument('--token-symbol', default='GFT', type=str, dest='token_symbol',
help='Token symbol to use for transactions')
arg_parser.add_argument('-v', help='be verbose', action='store_true')
arg_parser.add_argument('-vv', help='be more verbose', action='store_true')
arg_parser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing')
arg_parser.add_argument('--offset', type=int, default=0, help='block offset to start syncer from')
arg_parser.add_argument('--old-chain-spec', type=str, dest='old_chain_spec', default='evm:oldchain:1',
help='chain spec')
arg_parser.add_argument('import_dir', default='out', type=str, help='user export directory')
args = arg_parser.parse_args()
if args.vv: argparser = argparse.ArgumentParser(description='daemon that monitors transactions in new blocks')
logging.getLogger().setLevel(logging.DEBUG) argparser.add_argument('-p', '--provider', dest='p', type=str, help='chain rpc provider address')
elif args.v: argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing')
argparser.add_argument('-c', type=str, default=config_dir, help='config root to use')
argparser.add_argument('--old-chain-spec', type=str, dest='old_chain_spec', default='evm:oldchain:1', help='chain spec')
argparser.add_argument('-i', '--chain-spec', type=str, dest='i', help='chain spec')
argparser.add_argument('-r', '--registry-address', type=str, dest='r', help='CIC Registry address')
argparser.add_argument('--meta-host', dest='meta_host', type=str, help='metadata server host')
argparser.add_argument('--meta-port', dest='meta_port', type=int, help='metadata server host')
argparser.add_argument('--redis-host', dest='redis_host', type=str, help='redis host to use for task submission')
argparser.add_argument('--redis-port', dest='redis_port', type=int, help='redis host to use for task submission')
argparser.add_argument('--redis-db', dest='redis_db', type=int, help='redis db to use for task submission and callback')
argparser.add_argument('--token-symbol', default='GFT', type=str, dest='token_symbol',
help='Token symbol to use for transactions')
argparser.add_argument('--head', action='store_true', help='start at current block height (overrides --offset)')
argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str,
help='environment prefix for variables to overwrite configuration')
argparser.add_argument('-q', type=str, default='cic-import-ussd', help='celery queue to submit transaction tasks to')
argparser.add_argument('--offset', type=int, default=0, help='block offset to start syncer from')
argparser.add_argument('-v', help='be verbose', action='store_true')
argparser.add_argument('-vv', help='be more verbose', action='store_true')
argparser.add_argument('user_dir', default='out', type=str, help='user export directory')
args = argparser.parse_args(sys.argv[1:])
if args.v:
logging.getLogger().setLevel(logging.INFO) logging.getLogger().setLevel(logging.INFO)
config = Config(args.c, args.env_prefix) elif args.vv:
logging.getLogger().setLevel(logging.DEBUG)
config_dir = os.path.join(args.c)
os.makedirs(config_dir, 0o777, True)
config = confini.Config(config_dir, args.env_prefix)
config.process() config.process()
# override args
args_override = { args_override = {
'CIC_CHAIN_SPEC': getattr(args, 'i'), 'CIC_CHAIN_SPEC': getattr(args, 'i'),
'ETH_PROVIDER': getattr(args, 'p'), 'ETH_PROVIDER': getattr(args, 'p'),
@@ -70,76 +73,88 @@ args_override = {
config.dict_override(args_override, 'cli flag') config.dict_override(args_override, 'cli flag')
config.censor('PASSWORD', 'DATABASE') config.censor('PASSWORD', 'DATABASE')
config.censor('PASSWORD', 'SSL') config.censor('PASSWORD', 'SSL')
logg.debug(f'config loaded from {args.c}:\n{config}') logg.debug('config loaded from {}:\n{}'.format(config_dir, config))
db_config = { redis_host = config.get('REDIS_HOST')
'database': config.get('DATABASE_NAME'), redis_port = config.get('REDIS_PORT')
'host': config.get('DATABASE_HOST'), redis_db = config.get('REDIS_DB')
'port': config.get('DATABASE_PORT'), r = redis.Redis(redis_host, redis_port, redis_db)
'user': config.get('DATABASE_USER'),
'password': config.get('DATABASE_PASSWORD')
}
ImportTask.db_config = db_config
# create celery apps
celery_app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL'))
status = get_celery_worker_status(celery_app=celery_app)
signer_address = None
keystore = DictKeystore() keystore = DictKeystore()
os.path.isfile(args.y) if args.y is not None:
logg.debug(f'loading keystore file {args.y}') logg.debug('loading keystore file {}'.format(args.y))
signer_address = keystore.import_keystore_file(args.y) signer_address = keystore.import_keystore_file(args.y)
logg.debug(f'now have key for signer address {signer_address}') logg.debug('now have key for signer address {}'.format(signer_address))
# define signer
signer = EIP155Signer(keystore) signer = EIP155Signer(keystore)
block_offset = -1 if args.head else args.offset queue = args.q
chain_str = config.get('CIC_CHAIN_SPEC') chain_str = config.get('CIC_CHAIN_SPEC')
block_offset = 0
if args.head:
block_offset = -1
else:
block_offset = args.offset
chain_spec = ChainSpec.from_chain_str(chain_str) chain_spec = ChainSpec.from_chain_str(chain_str)
ImportTask.chain_spec = chain_spec
old_chain_spec_str = args.old_chain_spec old_chain_spec_str = args.old_chain_spec
old_chain_spec = ChainSpec.from_chain_str(old_chain_spec_str) old_chain_spec = ChainSpec.from_chain_str(old_chain_spec_str)
user_dir = args.user_dir # user_out_dir from import_users.py
token_symbol = args.token_symbol
MetadataTask.meta_host = config.get('META_HOST') MetadataTask.meta_host = config.get('META_HOST')
MetadataTask.meta_port = config.get('META_PORT') MetadataTask.meta_port = config.get('META_PORT')
ImportTask.chain_spec = chain_spec
txs_dir = os.path.join(args.import_dir, 'txs')
os.makedirs(txs_dir, exist_ok=True)
sys.stdout.write(f'created txs dir: {txs_dir}')
celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL'))
get_celery_worker_status(celery_app)
def main(): def main():
conn = EthHTTPConnection(config.get('ETH_PROVIDER')) conn = EthHTTPConnection(config.get('ETH_PROVIDER'))
ImportTask.balance_processor = BalanceProcessor(conn,
chain_spec, ImportTask.balance_processor = BalanceProcessor(conn, chain_spec, config.get('CIC_REGISTRY_ADDRESS'),
config.get('CIC_REGISTRY_ADDRESS'), signer_address, signer)
signer_address, ImportTask.balance_processor.init(token_symbol)
signer)
ImportTask.balance_processor.init(args.token_symbol) # TODO get decimals from token
balances = {} balances = {}
accuracy = 10 ** 6 f = open('{}/balances.csv'.format(user_dir, 'r'))
count = 0 remove_zeros = 10 ** 6
with open(f'{args.import_dir}/balances.csv', 'r') as balances_file: i = 0
while True: while True:
line = balances_file.readline() l = f.readline()
if line is None: if l is None:
break break
balance_data = line.split(',') r = l.split(',')
try: try:
blockchain_address = to_checksum_address(balance_data[0]) address = to_checksum_address(r[0])
logg.info( sys.stdout.write('loading balance {} {} {}'.format(i, address, r[1]).ljust(200) + "\r")
'loading balance: {} {} {}'.format(count, blockchain_address, balance_data[1].ljust(200) + "\r")) except ValueError:
except ValueError: break
break balance = int(int(r[1].rstrip()) / remove_zeros)
balance = int(int(balance_data[1].rstrip()) / accuracy) balances[address] = balance
balances[blockchain_address] = balance i += 1
count += 1
f.close()
ImportTask.balances = balances ImportTask.balances = balances
ImportTask.count = count ImportTask.count = i
ImportTask.include_balances = args.include_balances is True ImportTask.import_dir = user_dir
ImportTask.import_dir = args.import_dir
s_send_txs = celery.signature( s = celery.signature(
'import_task.send_txs', [ImportTask.balance_processor.nonce_offset], queue=args.q) 'import_task.send_txs',
s_send_txs.apply_async() [
MetadataTask.balance_processor.nonce_offset,
],
queue=queue,
)
s.apply_async()
argv = ['worker'] argv = ['worker']
if args.vv: if args.vv:
@@ -150,7 +165,6 @@ def main():
argv.append(args.q) argv.append(args.q)
argv.append('-n') argv.append('-n')
argv.append(args.q) argv.append(args.q)
argv.append(f'--pidfile={args.q}.pid')
celery_app.worker_main(argv) celery_app.worker_main(argv)

View File

@@ -1,63 +1,71 @@
# standard imports # standard import
import argparse import argparse
import csv import csv
import logging import logging
import os import os
import psycopg2
# external imports # third-party imports
from confini import Config import celery
import confini
# local imports # local imports
from import_util import get_celery_worker_status
default_config_dir = './config'
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()
arg_parser = argparse.ArgumentParser(description='Pins import script.') default_config_dir = './config'
arg_parser.add_argument('-c', type=str, default=default_config_dir, help='config root to use.')
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('-c', type=str, default=default_config_dir, help='config root to use')
arg_parser.add_argument('--env-prefix', arg_parser.add_argument('--env-prefix',
default=os.environ.get('CONFINI_ENV_PREFIX'), default=os.environ.get('CONFINI_ENV_PREFIX'),
dest='env_prefix', dest='env_prefix',
type=str, type=str,
help='environment prefix for variables to overwrite configuration.') help='environment prefix for variables to overwrite configuration')
arg_parser.add_argument('import_dir', default='out', type=str, help='user export directory') arg_parser.add_argument('-q', type=str, default='cic-import-ussd', help='celery queue to submit transaction tasks to')
arg_parser.add_argument('-v', help='be verbose', action='store_true') arg_parser.add_argument('-v', help='be verbose', action='store_true')
arg_parser.add_argument('-vv', help='be more verbose', action='store_true') arg_parser.add_argument('-vv', help='be more verbose', action='store_true')
arg_parser.add_argument('pins_dir', default='out', type=str, help='user export directory')
args = arg_parser.parse_args() args = arg_parser.parse_args()
if args.vv: # set log levels
logging.getLogger().setLevel(logging.DEBUG) if args.v:
elif args.v: logg.setLevel(logging.INFO)
logging.getLogger().setLevel(logging.INFO) elif args.vv:
logg.setLevel(logging.DEBUG)
config = Config(args.c, args.env_prefix) # process configs
config_dir = args.c
config = confini.Config(config_dir, os.environ.get('CONFINI_ENV_PREFIX'))
config.process() config.process()
config.censor('PASSWORD', 'DATABASE') config.censor('PASSWORD', 'DATABASE')
logg.debug(f'config loaded from {args.c}:\n{config}') logg.debug('config loaded from {}:\n{}'.format(args.c, config))
celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL'))
status = get_celery_worker_status(celery_app=celery_app)
db_configs = {
'database': config.get('DATABASE_NAME'),
'host': config.get('DATABASE_HOST'),
'port': config.get('DATABASE_PORT'),
'user': config.get('DATABASE_USER'),
'password': config.get('DATABASE_PASSWORD')
}
def main(): def main():
with open(f'{args.import_dir}/pins.csv') as pins_file: with open(f'{args.pins_dir}/pins.csv') as pins_file:
phone_to_pins = [tuple(row) for row in csv.reader(pins_file)] phone_to_pins = [tuple(row) for row in csv.reader(pins_file)]
db_conn = psycopg2.connect( s_import_pins = celery.signature(
database=config.get('DATABASE_NAME'), 'import_task.set_pins',
host=config.get('DATABASE_HOST'), (db_configs, phone_to_pins),
port=config.get('DATABASE_PORT'), queue=args.q
user=config.get('DATABASE_USER'),
password=config.get('DATABASE_PASSWORD')
) )
db_cursor = db_conn.cursor() result = s_import_pins.apply_async()
sql = 'UPDATE account SET password_hash = %s WHERE phone_number = %s' logg.debug(f'TASK: {result.id}, STATUS: {result.status}')
for element in phone_to_pins:
db_cursor.execute(sql, (element[1], element[0]))
logg.debug(f'Updating account: {element[0]} with: {element[1]}')
db_conn.commit()
db_cursor.close()
db_conn.close()
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -1,37 +1,38 @@
# standard imports # standard imports
import csv
import json import json
import logging import logging
import os import os
import random import random
import uuid import urllib.error
from urllib import error, parse, request import urllib.parse
import urllib.request
# external imports # external imports
import celery import celery
import psycopg2 import psycopg2
from celery import Task
from chainlib.chain import ChainSpec
from chainlib.eth.address import to_checksum_address from chainlib.eth.address import to_checksum_address
from chainlib.eth.tx import raw, unpack from chainlib.eth.tx import (
from cic_types.models.person import Person, generate_metadata_pointer unpack,
from hexathon import add_0x, strip_0x raw,
)
from cic_types.models.person import Person
from cic_types.processor import generate_metadata_pointer
from hexathon import (
strip_0x,
add_0x,
)
# local imports
celery_app = celery.current_app
logg = logging.getLogger() logg = logging.getLogger()
celery_app = celery.current_app
class ImportTask(Task):
class ImportTask(celery.Task):
balances = None balances = None
balance_processor = None import_dir = 'out'
chain_spec: ChainSpec = None
count = 0 count = 0
db_config: dict = None chain_spec = None
import_dir = '' balance_processor = None
include_balances = False
max_retries = None max_retries = None
@@ -40,70 +41,121 @@ class MetadataTask(ImportTask):
meta_port = None meta_port = None
meta_path = '' meta_path = ''
meta_ssl = False meta_ssl = False
autoretry_for = (error.HTTPError, OSError,) autoretry_for = (
urllib.error.HTTPError,
OSError,
)
retry_jitter = True retry_jitter = True
retry_backoff = True retry_backoff = True
retry_backoff_max = 60 retry_backoff_max = 60
@classmethod @classmethod
def meta_url(cls): def meta_url(self):
scheme = 'http' scheme = 'http'
if cls.meta_ssl: if self.meta_ssl:
scheme += 's' scheme += 's'
url = parse.urlparse(f'{scheme}://{cls.meta_host}:{cls.meta_port}/{cls.meta_path}') url = urllib.parse.urlparse('{}://{}:{}/{}'.format(scheme, self.meta_host, self.meta_port, self.meta_path))
return parse.urlunparse(url) return urllib.parse.urlunparse(url)
def old_address_from_phone(base_path: str, phone_number: str): def old_address_from_phone(base_path, phone):
pid_x = generate_metadata_pointer(phone_number.encode('utf-8'), ':cic.phone') pidx = generate_metadata_pointer(phone.encode('utf-8'), ':cic.phone')
phone_idx_path = os.path.join(f'{base_path}/phone/{pid_x[:2]}/{pid_x[2:4]}/{pid_x}') phone_idx_path = os.path.join('{}/phone/{}/{}/{}'.format(
with open(phone_idx_path, 'r') as f: base_path,
old_address = f.read() pidx[:2],
pidx[2:4],
pidx,
)
)
f = open(phone_idx_path, 'r')
old_address = f.read()
f.close()
return old_address return old_address
@celery_app.task(bind=True, base=MetadataTask) @celery_app.task(bind=True, base=MetadataTask)
def generate_person_metadata(self, blockchain_address: str, phone_number: str): def resolve_phone(self, phone):
logg.debug(f'blockchain address: {blockchain_address}') identifier = generate_metadata_pointer(phone.encode('utf-8'), ':cic.phone')
old_blockchain_address = old_address_from_phone(self.import_dir, phone_number) url = urllib.parse.urljoin(self.meta_url(), identifier)
old_address_upper = strip_0x(old_blockchain_address).upper() logg.debug('attempt getting phone pointer at {} for phone {}'.format(url, phone))
metadata_path = f'{self.import_dir}/old/{old_address_upper[:2]}/{old_address_upper[2:4]}/{old_address_upper}.json' r = urllib.request.urlopen(url)
with open(metadata_path, 'r') as metadata_file: address = json.load(r)
person_metadata = json.load(metadata_file) address = address.replace('"', '')
person = Person.deserialize(person_metadata) logg.debug('address {} for phone {}'.format(address, phone))
if not person.identities.get('evm'):
person.identities['evm'] = {} return address
sub_chain_str = f'{self.chain_spec.common_name()}:{self.chain_spec.network_id()}'
person.identities['evm'][sub_chain_str] = [add_0x(blockchain_address)]
blockchain_address = strip_0x(blockchain_address)
file_path = os.path.join(
self.import_dir,
'new',
blockchain_address[:2].upper(),
blockchain_address[2:4].upper(),
blockchain_address.upper() + '.json'
)
os.makedirs(os.path.dirname(file_path), exist_ok=True)
serialized_person_metadata = person.serialize()
with open(file_path, 'w') as metadata_file:
metadata_file.write(json.dumps(serialized_person_metadata))
logg.debug(f'written person metadata for address: {blockchain_address}')
meta_filepath = os.path.join(
self.import_dir,
'meta',
'{}.json'.format(blockchain_address.upper()),
)
os.symlink(os.path.realpath(file_path), meta_filepath)
return blockchain_address
@celery_app.task(bind=True, base=MetadataTask) @celery_app.task(bind=True, base=MetadataTask)
def generate_preferences_data(self, data: tuple): def generate_metadata(self, address, phone):
blockchain_address: str = data[0] old_address = old_address_from_phone(self.import_dir, phone)
preferences = data[1]
logg.debug('address {}'.format(address))
old_address_upper = strip_0x(old_address).upper()
metadata_path = '{}/old/{}/{}/{}.json'.format(
self.import_dir,
old_address_upper[:2],
old_address_upper[2:4],
old_address_upper,
)
f = open(metadata_path, 'r')
o = json.load(f)
f.close()
u = Person.deserialize(o)
if u.identities.get('evm') == None:
u.identities['evm'] = {}
sub_chain_str = '{}:{}'.format(self.chain_spec.common_name(), self.chain_spec.network_id())
u.identities['evm'][sub_chain_str] = [add_0x(address)]
new_address_clean = strip_0x(address)
filepath = os.path.join(
self.import_dir,
'new',
new_address_clean[:2].upper(),
new_address_clean[2:4].upper(),
new_address_clean.upper() + '.json',
)
os.makedirs(os.path.dirname(filepath), exist_ok=True)
o = u.serialize()
f = open(filepath, 'w')
f.write(json.dumps(o))
f.close()
meta_key = generate_metadata_pointer(bytes.fromhex(new_address_clean), ':cic.person')
meta_filepath = os.path.join(
self.import_dir,
'meta',
'{}.json'.format(new_address_clean.upper()),
)
os.symlink(os.path.realpath(filepath), meta_filepath)
# write ussd data
ussd_data = {
'phone': phone,
'is_activated': 1,
'preferred_language': random.sample(['en', 'sw'], 1)[0],
'is_disabled': False
}
ussd_data_dir = os.path.join(self.import_dir, 'ussd')
ussd_data_file_path = os.path.join(ussd_data_dir, f'{old_address}.json')
f = open(ussd_data_file_path, 'w')
f.write(json.dumps(ussd_data))
f.close()
# write preferences data
preferences_dir = os.path.join(self.import_dir, 'preferences') preferences_dir = os.path.join(self.import_dir, 'preferences')
preferences_key = generate_metadata_pointer(bytes.fromhex(strip_0x(blockchain_address)), ':cic.preferences') preferences_data = {
'preferred_language': ussd_data['preferred_language']
}
preferences_key = generate_metadata_pointer(bytes.fromhex(new_address_clean[2:]), ':cic.preferences')
preferences_filepath = os.path.join(preferences_dir, 'meta', preferences_key) preferences_filepath = os.path.join(preferences_dir, 'meta', preferences_key)
filepath = os.path.join( filepath = os.path.join(
preferences_dir, preferences_dir,
'new', 'new',
@@ -112,95 +164,95 @@ def generate_preferences_data(self, data: tuple):
preferences_key.upper() + '.json' preferences_key.upper() + '.json'
) )
os.makedirs(os.path.dirname(filepath), exist_ok=True) os.makedirs(os.path.dirname(filepath), exist_ok=True)
with open(filepath, 'w') as preferences_file:
preferences_file.write(json.dumps(preferences)) f = open(filepath, 'w')
logg.debug(f'written preferences metadata: {preferences} for address: {blockchain_address}') f.write(json.dumps(preferences_data))
f.close()
os.symlink(os.path.realpath(filepath), preferences_filepath) os.symlink(os.path.realpath(filepath), preferences_filepath)
return blockchain_address
logg.debug('found metadata {} for phone {}'.format(o, phone))
@celery_app.task(bind=True, base=MetadataTask)
def generate_pins_data(self, blockchain_address: str, phone_number: str):
pins_file = f'{self.import_dir}/pins.csv'
file_op = 'a' if os.path.exists(pins_file) else 'w'
with open(pins_file, file_op) as pins_file:
password_hash = uuid.uuid4().hex
pins_file.write(f'{phone_number},{password_hash}\n')
logg.debug(f'written pin data for address: {blockchain_address}')
return blockchain_address
@celery_app.task(bind=True, base=MetadataTask)
def generate_ussd_data(self, blockchain_address: str, phone_number: str):
ussd_data_file = f'{self.import_dir}/ussd_data.csv'
file_op = 'a' if os.path.exists(ussd_data_file) else 'w'
preferred_language = random.sample(["en", "sw"], 1)[0]
preferences = {'preferred_language': preferred_language}
with open(ussd_data_file, file_op) as ussd_data_file:
ussd_data_file.write(f'{phone_number}, { 1}, {preferred_language}, {False}\n')
logg.debug(f'written ussd data for address: {blockchain_address}')
return blockchain_address, preferences
@celery_app.task(bind=True, base=MetadataTask)
def opening_balance_tx(self, blockchain_address: str, phone_number: str, serial: str):
old_blockchain_address = old_address_from_phone(self.import_dir, phone_number)
address = to_checksum_address(strip_0x(old_blockchain_address))
balance = self.balances[address]
logg.debug(f'found balance: {balance} for address: {address} phone: {phone_number}')
decimal_balance = self.balance_processor.get_decimal_amount(int(balance))
tx_hash_hex, o = self.balance_processor.get_rpc_tx(blockchain_address, decimal_balance, serial)
tx = unpack(bytes.fromhex(strip_0x(o)), self.chain_spec)
logg.debug(f'generated tx token value: {decimal_balance}: {blockchain_address} tx hash {tx_hash_hex}')
tx_path = os.path.join(self.import_dir, 'txs', strip_0x(tx_hash_hex))
with open(tx_path, 'w') as tx_file:
tx_file.write(strip_0x(o))
logg.debug(f'written tx with tx hash: {tx["hash"]} for address: {blockchain_address}')
tx_nonce_path = os.path.join(self.import_dir, 'txs', '.' + str(tx['nonce']))
os.symlink(os.path.realpath(tx_path), tx_nonce_path)
return tx['hash']
@celery_app.task(bind=True, base=MetadataTask)
def resolve_phone(self, phone_number: str):
identifier = generate_metadata_pointer(phone_number.encode('utf-8'), ':cic.phone')
url = parse.urljoin(self.meta_url(), identifier)
logg.debug(f'attempt getting phone pointer at: {url} for phone: {phone_number}')
r = request.urlopen(url)
address = json.load(r)
address = address.replace('"', '')
logg.debug(f'address: {address} for phone: {phone_number}')
return address return address
@celery_app.task(autoretry_for=(FileNotFoundError,), @celery_app.task(bind=True, base=MetadataTask)
bind=True, def opening_balance_tx(self, address, phone, serial):
base=ImportTask, old_address = old_address_from_phone(self.import_dir, phone)
max_retries=None,
k = to_checksum_address(strip_0x(old_address))
balance = self.balances[k]
logg.debug('found balance {} for address {} phone {}'.format(balance, old_address, phone))
decimal_balance = self.balance_processor.get_decimal_amount(int(balance))
(tx_hash_hex, o) = self.balance_processor.get_rpc_tx(address, decimal_balance, serial)
tx = unpack(bytes.fromhex(strip_0x(o)), self.chain_spec)
logg.debug('generated tx token value {} to {} tx hash {}'.format(decimal_balance, address, tx_hash_hex))
tx_path = os.path.join(
self.import_dir,
'txs',
strip_0x(tx_hash_hex),
)
f = open(tx_path, 'w')
f.write(strip_0x(o))
f.close()
tx_nonce_path = os.path.join(
self.import_dir,
'txs',
'.' + str(tx['nonce']),
)
os.symlink(os.path.realpath(tx_path), tx_nonce_path)
return tx['hash']
@celery_app.task(bind=True, base=ImportTask, autoretry_for=(FileNotFoundError,), max_retries=None,
default_retry_delay=0.1) default_retry_delay=0.1)
def send_txs(self, nonce): def send_txs(self, nonce):
queue = self.request.delivery_info.get('routing_key')
if nonce == self.count + self.balance_processor.nonce_offset: if nonce == self.count + self.balance_processor.nonce_offset:
logg.info(f'reached nonce {nonce} (offset {self.balance_processor.nonce_offset} + count {self.count}).') logg.info('reached nonce {} (offset {} + count {}) exiting'.format(nonce, self.balance_processor.nonce_offset,
celery_app.control.broadcast('shutdown', destination=[f'celery@{queue}']) self.count))
return
logg.debug('attempt to open symlink for nonce {}'.format(nonce))
tx_nonce_path = os.path.join(
self.import_dir,
'txs',
'.' + str(nonce),
)
f = open(tx_nonce_path, 'r')
tx_signed_raw_hex = f.read()
f.close()
logg.debug(f'attempt to open symlink for nonce {nonce}')
tx_nonce_path = os.path.join(self.import_dir, 'txs', '.' + str(nonce))
with open(tx_nonce_path, 'r') as tx_nonce_file:
tx_signed_raw_hex = tx_nonce_file.read()
os.unlink(tx_nonce_path) os.unlink(tx_nonce_path)
o = raw(add_0x(tx_signed_raw_hex)) o = raw(add_0x(tx_signed_raw_hex))
if self.include_balances: tx_hash_hex = self.balance_processor.conn.do(o)
tx_hash_hex = self.balance_processor.conn.do(o)
logg.info(f'sent nonce {nonce} tx hash {tx_hash_hex}') logg.info('sent nonce {} tx hash {}'.format(nonce, tx_hash_hex)) # tx_signed_raw_hex))
nonce += 1 nonce += 1
s = celery.signature('import_task.send_txs', [nonce], queue=queue)
queue = self.request.delivery_info.get('routing_key')
s = celery.signature(
'import_task.send_txs',
[
nonce,
],
queue=queue,
)
s.apply_async() s.apply_async()
return nonce return nonce
@celery_app.task() @celery_app.task
def set_pin_data(config: dict, phone_to_pins: list): def set_pins(config: dict, phone_to_pins: list):
# define db connection
db_conn = psycopg2.connect( db_conn = psycopg2.connect(
database=config.get('database'), database=config.get('database'),
host=config.get('host'), host=config.get('host'),
@@ -209,17 +261,24 @@ def set_pin_data(config: dict, phone_to_pins: list):
password=config.get('password') password=config.get('password')
) )
db_cursor = db_conn.cursor() db_cursor = db_conn.cursor()
sql = 'UPDATE account SET password_hash = %s WHERE phone_number = %s'
# update db
for element in phone_to_pins: for element in phone_to_pins:
sql = 'UPDATE account SET password_hash = %s WHERE phone_number = %s'
db_cursor.execute(sql, (element[1], element[0])) db_cursor.execute(sql, (element[1], element[0]))
logg.debug(f'Updating: {element[0]} with: {element[1]}') logg.debug(f'Updating: {element[0]} with: {element[1]}')
# commit changes
db_conn.commit() db_conn.commit()
# close connections
db_cursor.close() db_cursor.close()
db_conn.close() db_conn.close()
@celery_app.task @celery_app.task
def set_ussd_data(config: dict, ussd_data: list): def set_ussd_data(config: dict, ussd_data: dict):
# define db connection
db_conn = psycopg2.connect( db_conn = psycopg2.connect(
database=config.get('database'), database=config.get('database'),
host=config.get('host'), host=config.get('host'),
@@ -228,12 +287,20 @@ def set_ussd_data(config: dict, ussd_data: list):
password=config.get('password') password=config.get('password')
) )
db_cursor = db_conn.cursor() db_cursor = db_conn.cursor()
# process ussd_data
account_status = 1
if ussd_data['is_activated'] == 1:
account_status = 2
preferred_language = ussd_data['preferred_language']
phone_number = ussd_data['phone']
sql = 'UPDATE account SET status = %s, preferred_language = %s WHERE phone_number = %s' sql = 'UPDATE account SET status = %s, preferred_language = %s WHERE phone_number = %s'
for element in ussd_data: db_cursor.execute(sql, (account_status, preferred_language, phone_number))
status = 2 if int(element[1]) == 1 else 1
preferred_language = element[2] # commit changes
phone_number = element[0]
db_cursor.execute(sql, (status, preferred_language, phone_number))
db_conn.commit() db_conn.commit()
# close connections
db_cursor.close() db_cursor.close()
db_conn.close() db_conn.close()

View File

@@ -3,61 +3,56 @@ import argparse
import json import json
import logging import logging
import os import os
import redis
import sys import sys
import time import time
import urllib.request
import uuid import uuid
from urllib import request
from urllib.parse import urlencode from urllib.parse import urlencode
# external imports # external imports
import celery import celery
import confini
import phonenumbers import phonenumbers
import redis
from chainlib.chain import ChainSpec
from cic_types.models.person import Person from cic_types.models.person import Person
from confini import Config
# local imports # local imports
from import_util import get_celery_worker_status from import_util import get_celery_worker_status
default_config_dir = './config'
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()
arg_parser = argparse.ArgumentParser(description='Daemon worker that handles data seeding tasks.') default_config_dir = '/usr/local/etc/cic'
# batch size should be slightly below cumulative gas limit worth, eg 80000 gas txs with 8000000 limit is a bit less than 100 batch size
arg_parser.add_argument('--batch-size',
dest='batch_size',
default=100,
type=int,
help='burst size of sending transactions to node')
arg_parser.add_argument('--batch-delay', dest='batch_delay', default=3, type=int, help='seconds delay between batches')
arg_parser.add_argument('-c', type=str, default=default_config_dir, help='config root to use.')
arg_parser.add_argument('--env-prefix',
default=os.environ.get('CONFINI_ENV_PREFIX'),
dest='env_prefix',
type=str,
help='environment prefix for variables to overwrite configuration.')
arg_parser.add_argument('-i', '--chain-spec', type=str, dest='i', help='chain spec')
arg_parser.add_argument('-q', type=str, default='cic-import-ussd', help='celery queue to submit data seeding tasks to.')
arg_parser.add_argument('--redis-db', dest='redis_db', type=int, help='redis db to use for task submission and callback')
arg_parser.add_argument('--redis-host', dest='redis_host', type=str, help='redis host to use for task submission')
arg_parser.add_argument('--redis-port', dest='redis_port', type=int, help='redis host to use for task submission')
arg_parser.add_argument('--ussd-host', dest='ussd_host', type=str,
help="host to ussd app responsible for processing ussd requests.")
arg_parser.add_argument('--ussd-no-ssl', dest='ussd_no_ssl', help='do not use ssl (careful)', action='store_true')
arg_parser.add_argument('--ussd-port', dest='ussd_port', type=str,
help="port to ussd app responsible for processing ussd requests.")
arg_parser.add_argument('-v', help='be verbose', action='store_true')
arg_parser.add_argument('-vv', help='be more verbose', action='store_true')
arg_parser.add_argument('import_dir', default='out', type=str, help='user export directory')
args = arg_parser.parse_args()
if args.vv: argparser = argparse.ArgumentParser()
logging.getLogger().setLevel(logging.DEBUG) argparser.add_argument('-c', type=str, default=default_config_dir, help='config file')
elif args.v: argparser.add_argument('-i', '--chain-spec', dest='i', type=str, help='Chain specification string')
logging.getLogger().setLevel(logging.INFO) argparser.add_argument('--redis-host', dest='redis_host', type=str, help='redis host to use for task submission')
argparser.add_argument('--redis-port', dest='redis_port', type=int, help='redis host to use for task submission')
argparser.add_argument('--redis-db', dest='redis_db', type=int, help='redis db to use for task submission and callback')
argparser.add_argument('--batch-size', dest='batch_size', default=100, type=int,
help='burst size of sending transactions to node') # batch size should be slightly below cumulative gas limit worth, eg 80000 gas txs with 8000000 limit is a bit less than 100 batch size
argparser.add_argument('--batch-delay', dest='batch_delay', default=3, type=int, help='seconds delay between batches')
argparser.add_argument('--timeout', default=60.0, type=float, help='Callback timeout')
argparser.add_argument('--ussd-host', dest='ussd_host', type=str,
help="host to ussd app responsible for processing ussd requests.")
argparser.add_argument('--ussd-port', dest='ussd_port', type=str,
help="port to ussd app responsible for processing ussd requests.")
argparser.add_argument('--ussd-no-ssl', dest='ussd_no_ssl', help='do not use ssl (careful)', action='store_true')
argparser.add_argument('-q', type=str, default='cic-eth', help='Task queue')
argparser.add_argument('-v', action='store_true', help='Be verbose')
argparser.add_argument('-vv', action='store_true', help='Be more verbose')
argparser.add_argument('user_dir', type=str, help='path to users export dir tree')
args = argparser.parse_args()
config = Config(args.c, args.env_prefix) if args.v:
logg.setLevel(logging.INFO)
elif args.vv:
logg.setLevel(logging.DEBUG)
config_dir = args.c
config = confini.Config(config_dir, os.environ.get('CONFINI_ENV_PREFIX'))
config.process() config.process()
args_override = { args_override = {
'CIC_CHAIN_SPEC': getattr(args, 'i'), 'CIC_CHAIN_SPEC': getattr(args, 'i'),
@@ -65,29 +60,44 @@ args_override = {
'REDIS_PORT': getattr(args, 'redis_port'), 'REDIS_PORT': getattr(args, 'redis_port'),
'REDIS_DB': getattr(args, 'redis_db'), 'REDIS_DB': getattr(args, 'redis_db'),
} }
config.dict_override(args_override, 'cli flag') config.dict_override(args_override, 'cli')
config.censor('PASSWORD', 'DATABASE') logg.debug('config loaded from {}:\n{}'.format(args.c, config))
config.censor('PASSWORD', 'SSL')
logg.debug(f'config loaded from {args.c}:\n{config}')
old_account_dir = os.path.join(args.import_dir, 'old') celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL'))
os.stat(old_account_dir) get_celery_worker_status(celery_app=celery_app)
logg.debug(f'created old system data dir: {old_account_dir}')
new_account_dir = os.path.join(args.import_dir, 'new') redis_host = config.get('REDIS_HOST')
os.makedirs(new_account_dir, exist_ok=True) redis_port = config.get('REDIS_PORT')
logg.debug(f'created new system data dir: {new_account_dir}') redis_db = config.get('REDIS_DB')
r = redis.Redis(redis_host, redis_port, redis_db)
person_metadata_dir = os.path.join(args.import_dir, 'meta') ps = r.pubsub()
os.makedirs(person_metadata_dir, exist_ok=True)
logg.debug(f'created person metadata dir: {person_metadata_dir}')
preferences_dir = os.path.join(args.import_dir, 'preferences') user_new_dir = os.path.join(args.user_dir, 'new')
os.makedirs(user_new_dir, exist_ok=True)
ussd_data_dir = os.path.join(args.user_dir, 'ussd')
os.makedirs(ussd_data_dir, exist_ok=True)
preferences_dir = os.path.join(args.user_dir, 'preferences')
os.makedirs(os.path.join(preferences_dir, 'meta'), exist_ok=True) os.makedirs(os.path.join(preferences_dir, 'meta'), exist_ok=True)
logg.debug(f'created preferences metadata dir: {preferences_dir}')
valid_service_codes = config.get('USSD_SERVICE_CODE').split(",") meta_dir = os.path.join(args.user_dir, 'meta')
os.makedirs(meta_dir, exist_ok=True)
user_old_dir = os.path.join(args.user_dir, 'old')
os.stat(user_old_dir)
txs_dir = os.path.join(args.user_dir, 'txs')
os.makedirs(txs_dir, exist_ok=True)
chain_spec = ChainSpec.from_chain_str(config.get('CIC_CHAIN_SPEC'))
chain_str = str(chain_spec)
batch_size = args.batch_size
batch_delay = args.batch_delay
ussd_port = args.ussd_port
ussd_host = args.ussd_host
ussd_no_ssl = args.ussd_no_ssl ussd_no_ssl = args.ussd_no_ssl
if ussd_no_ssl is True: if ussd_no_ssl is True:
ussd_ssl = False ussd_ssl = False
@@ -95,17 +105,7 @@ else:
ussd_ssl = True ussd_ssl = True
celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL')) def build_ussd_request(phone, host, port, service_code, username, password, ssl=False):
get_celery_worker_status(celery_app)
def build_ussd_request(host: str,
password: str,
phone_number: str,
port: str,
service_code: str,
username: str,
ssl: bool = False):
url = 'http' url = 'http'
if ssl: if ssl:
url += 's' url += 's'
@@ -115,16 +115,16 @@ def build_ussd_request(host: str,
url += '/?username={}&password={}'.format(username, password) url += '/?username={}&password={}'.format(username, password)
logg.info('ussd service url {}'.format(url)) logg.info('ussd service url {}'.format(url))
logg.info('ussd phone {}'.format(phone_number)) logg.info('ussd phone {}'.format(phone))
session = uuid.uuid4().hex session = uuid.uuid4().hex
data = { data = {
'sessionId': session, 'sessionId': session,
'serviceCode': service_code, 'serviceCode': service_code,
'phoneNumber': phone_number, 'phoneNumber': phone,
'text': service_code, 'text': service_code,
} }
req = request.Request(url) req = urllib.request.Request(url)
req.method = 'POST' req.method = 'POST'
data_str = urlencode(data) data_str = urlencode(data)
data_bytes = data_str.encode('utf-8') data_bytes = data_str.encode('utf-8')
@@ -134,77 +134,85 @@ def build_ussd_request(host: str,
return req return req
def e164_phone_number(phone_number: str): def register_ussd(i, u):
phone_object = phonenumbers.parse(phone_number) phone_object = phonenumbers.parse(u.tel)
return phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164) phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164)
logg.debug('tel {} {}'.format(u.tel, phone))
req = build_ussd_request(
def register_account(person: Person): phone,
phone_number = e164_phone_number(person.tel) ussd_host,
logg.debug(f'tel: {phone_number}') ussd_port,
req = build_ussd_request(args.ussd_host, config.get('APP_SERVICE_CODE'),
'', '',
phone_number, '',
args.ussd_port, ussd_ssl
valid_service_codes[0], )
'', response = urllib.request.urlopen(req)
ussd_ssl)
response = request.urlopen(req)
response_data = response.read().decode('utf-8') response_data = response.read().decode('utf-8')
logg.debug(f'ussd response: {response_data[4:]}') state = response_data[:3]
out = response_data[4:]
logg.debug('ussd reponse: {}'.format(out))
if __name__ == '__main__': if __name__ == '__main__':
i = 0 i = 0
j = 0 j = 0
for x in os.walk(old_account_dir): for x in os.walk(user_old_dir):
for y in x[2]: for y in x[2]:
if y[len(y) - 5:] != '.json': if y[len(y) - 5:] != '.json':
continue continue
# handle json containing person object
filepath = os.path.join(x[0], y)
f = open(filepath, 'r')
try:
o = json.load(f)
except json.decoder.JSONDecodeError as e:
f.close()
logg.error('load error for {}: {}'.format(y, e))
continue
f.close()
u = Person.deserialize(o)
file_path = os.path.join(x[0], y) register_ussd(i, u)
with open(file_path, 'r') as account_file:
try: phone_object = phonenumbers.parse(u.tel)
account_data = json.load(account_file) phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164)
except json.decoder.JSONDecodeError as e:
logg.error('load error for {}: {}'.format(y, e)) s_phone = celery.signature(
continue 'import_task.resolve_phone',
person = Person.deserialize(account_data) [
register_account(person) phone,
phone_number = e164_phone_number(person.tel) ],
s_resolve_phone = celery.signature( queue='cic-import-ussd',
'import_task.resolve_phone', [phone_number], queue=args.q
) )
s_person_metadata = celery.signature( s_meta = celery.signature(
'import_task.generate_person_metadata', [phone_number], queue=args.q 'import_task.generate_metadata',
[
phone,
],
queue='cic-import-ussd',
) )
s_ussd_data = celery.signature( s_balance = celery.signature(
'import_task.generate_ussd_data', [phone_number], queue=args.q 'import_task.opening_balance_tx',
[
phone,
i,
],
queue='cic-import-ussd',
) )
s_preferences_metadata = celery.signature( s_meta.link(s_balance)
'import_task.generate_preferences_data', [], queue=args.q s_phone.link(s_meta)
) # block time plus a bit of time for ussd processing
s_phone.apply_async(countdown=7)
s_pins_data = celery.signature(
'import_task.generate_pins_data', [phone_number], queue=args.q
)
s_opening_balance = celery.signature(
'import_task.opening_balance_tx', [phone_number, i], queue=args.q
)
celery.chain(s_resolve_phone,
s_person_metadata,
s_ussd_data,
s_preferences_metadata,
s_pins_data,
s_opening_balance).apply_async(countdown=7)
i += 1 i += 1
sys.stdout.write('imported: {} {}'.format(i, person).ljust(200) + "\r\n") sys.stdout.write('imported {} {}'.format(i, u).ljust(200) + "\r")
j += 1 j += 1
if j == args.batch_size: if j == batch_size:
time.sleep(args.batch_delay) time.sleep(batch_delay)
j = 0 j = 0

View File

@@ -1,67 +1,67 @@
# standard imports # standard imports
import argparse import argparse
import csv import json
import logging import logging
import os import os
import psycopg2
# external imports # external imports
import celery
from confini import Config from confini import Config
# local imports # local imports
default_config_dir = './config'
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()
arg_parser = argparse.ArgumentParser(description='Pins import script.') default_config_dir = '/usr/local/etc/cic'
arg_parser.add_argument('-c', type=str, default=default_config_dir, help='config root to use.')
arg_parser.add_argument('--env-prefix',
default=os.environ.get('CONFINI_ENV_PREFIX'),
dest='env_prefix',
type=str,
help='environment prefix for variables to overwrite configuration.')
arg_parser.add_argument('import_dir', default='out', type=str, help='user export directory')
arg_parser.add_argument('-v', help='be verbose', action='store_true')
arg_parser.add_argument('-vv', help='be more verbose', action='store_true')
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('-c', type=str, default=default_config_dir, help='config file')
arg_parser.add_argument('-q', type=str, default='cic-import-ussd', help='Task queue')
arg_parser.add_argument('-v', action='store_true', help='Be verbose')
arg_parser.add_argument('-vv', action='store_true', help='Be more verbose')
arg_parser.add_argument('user_dir', type=str, help='path to users export dir tree')
args = arg_parser.parse_args() args = arg_parser.parse_args()
if args.vv: if args.v:
logging.getLogger().setLevel(logging.DEBUG) logg.setLevel(logging.INFO)
elif args.v: elif args.vv:
logging.getLogger().setLevel(logging.INFO) logg.setLevel(logging.DEBUG)
config = Config(args.c, args.env_prefix) config_dir = args.c
config = Config(config_dir, os.environ.get('CONFINI_ENV_PREFIX'))
config.process() config.process()
config.censor('PASSWORD', 'DATABASE') logg.debug('config loaded from {}:\n{}'.format(args.c, config))
logg.debug(f'config loaded from {args.c}:\n{config}')
ussd_data_dir = os.path.join(args.user_dir, 'ussd')
def main(): db_configs = {
with open(f'{args.import_dir}/ussd_data.csv') as ussd_data_file: 'database': config.get('DATABASE_NAME'),
ussd_data = [tuple(row) for row in csv.reader(ussd_data_file)] 'host': config.get('DATABASE_HOST'),
'port': config.get('DATABASE_PORT'),
db_conn = psycopg2.connect( 'user': config.get('DATABASE_USER'),
database=config.get('DATABASE_NAME'), 'password': config.get('DATABASE_PASSWORD')
host=config.get('DATABASE_HOST'), }
port=config.get('DATABASE_PORT'), celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL'))
user=config.get('DATABASE_USER'),
password=config.get('DATABASE_PASSWORD')
)
db_cursor = db_conn.cursor()
sql = 'UPDATE account SET status = %s, preferred_language = %s WHERE phone_number = %s'
for element in ussd_data:
status = 2 if int(element[1]) == 1 else 1
preferred_language = element[2]
phone_number = element[0]
db_cursor.execute(sql, (status, preferred_language, phone_number))
logg.debug(f'Updating account:{phone_number} with: preferred language: {preferred_language} status: {status}.')
db_conn.commit()
db_cursor.close()
db_conn.close()
if __name__ == '__main__': if __name__ == '__main__':
main() for x in os.walk(ussd_data_dir):
for y in x[2]:
if y[len(y) - 5:] == '.json':
filepath = os.path.join(x[0], y)
f = open(filepath, 'r')
try:
ussd_data = json.load(f)
logg.debug(f'LOADING USSD DATA: {ussd_data}')
except json.decoder.JSONDecodeError as e:
f.close()
logg.error('load error for {}: {}'.format(y, e))
continue
f.close()
s_set_ussd_data = celery.signature(
'import_task.set_ussd_data',
[db_configs, ussd_data]
)
s_set_ussd_data.apply_async(queue='cic-import-ussd')

View File

@@ -1,4 +1,27 @@
[app] [app]
allowed_ip=0.0.0.0/0 ALLOWED_IP=0.0.0.0/0
max_body_length=1024 LOCALE_FALLBACK=en
password_pepper= LOCALE_PATH=/usr/src/cic-ussd/var/lib/locale/
MAX_BODY_LENGTH=1024
PASSWORD_PEPPER=QYbzKff6NhiQzY3ygl2BkiKOpER8RE/Upqs/5aZWW+I=
SERVICE_CODE=*483*46#
[phone_number]
REGION=KE
[ussd]
MENU_FILE=/usr/src/data/ussd_menu.json
user =
pass =
[statemachine]
STATES=/usr/src/cic-ussd/states/
TRANSITIONS=/usr/src/cic-ussd/transitions/
[client]
host =
port =
ssl =
[keystore]
file_path = keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c

View File

@@ -1,10 +1,11 @@
[cic] [cic]
registry_address = registry_address = 0x32E860c2A0645d1B7B005273696905F5D6DC5D05
token_index_address = token_index_address =
accounts_index_address = accounts_index_address =
declarator_address = declarator_address =
approval_escrow_address = approval_escrow_address =
chain_spec = chain_spec = evm:bloxberg:8996
tx_retry_delay = tx_retry_delay =
trust_address = trust_address = 0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C
user_ussd_svc_service_port = user_ussd_svc_service_port =

View File

@@ -1,10 +1,10 @@
[database] [database]
name=cic_ussd NAME=sempo
user=postgres USER=postgres
password= PASSWORD=
host=localhost HOST=localhost
port=5432 PORT=5432
engine=postgresql ENGINE=postgresql
driver=psycopg2 DRIVER=psycopg2
debug=0 DEBUG=0
pool_size=1 POOL_SIZE=1

View File

@@ -1,5 +0,0 @@
[ussd]
menu_file=data/ussd_menu.json
service_code=*483*46#,*483*061#,*384*96#
user =
pass =

View File

@@ -0,0 +1,91 @@
# standard imports
import argparse
import json
import logging
import os
import uuid
# third-party imports
import bcrypt
import celery
import confini
import phonenumbers
import random
from cic_types.models.person import Person
from cryptography.fernet import Fernet
# local imports
logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger()
script_dir = os.path.realpath(os.path.dirname(__file__))
default_config_dir = os.environ.get('CONFINI_DIR', os.path.join(script_dir, 'config'))
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('-c', type=str, default=default_config_dir, help='Config dir')
arg_parser.add_argument('-v', action='store_true', help='Be verbose')
arg_parser.add_argument('-vv', action='store_true', help='Be more verbose')
arg_parser.add_argument('--userdir', type=str, help='path to users export dir tree')
arg_parser.add_argument('pins_dir', type=str, help='path to pin export dir tree')
args = arg_parser.parse_args()
if args.v:
logg.setLevel(logging.INFO)
elif args.vv:
logg.setLevel(logging.DEBUG)
config = confini.Config(args.c, os.environ.get('CONFINI_ENV_PREFIX'))
config.process()
logg.info('loaded config\n{}'.format(config))
celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL'))
user_dir = args.userdir
pins_dir = args.pins_dir
def generate_password_hash():
key = Fernet.generate_key()
fnt = Fernet(key)
pin = str(random.randint(1000, 9999))
return fnt.encrypt(bcrypt.hashpw(pin.encode('utf-8'), bcrypt.gensalt())).decode()
user_old_dir = os.path.join(user_dir, 'old')
logg.debug(f'reading user data from: {user_old_dir}')
pins_file = open(f'{pins_dir}/pins.csv', 'w')
if __name__ == '__main__':
for x in os.walk(user_old_dir):
for y in x[2]:
# skip non-json files
if y[len(y) - 5:] != '.json':
continue
# define file path for
filepath = None
if y[:15] != '_ussd_data.json':
filepath = os.path.join(x[0], y)
f = open(filepath, 'r')
try:
o = json.load(f)
except json.decoder.JSONDecodeError as e:
f.close()
logg.error('load error for {}: {}'.format(y, e))
continue
f.close()
u = Person.deserialize(o)
phone_object = phonenumbers.parse(u.tel)
phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164)
password_hash = uuid.uuid4().hex
pins_file.write(f'{phone},{password_hash}\n')
logg.info(f'Writing phone: {phone}, password_hash: {password_hash}')
pins_file.close()

View File

@@ -28,11 +28,12 @@ logg = logging.getLogger()
fake = Faker(['sl', 'en_US', 'no', 'de', 'ro']) fake = Faker(['sl', 'en_US', 'no', 'de', 'ro'])
default_config_dir = './config' script_dir = os.path.realpath(os.path.dirname(__file__))
# config_dir = os.environ.get('CONFINI_DIR', '/usr/local/etc/cic')
config_dir = os.environ.get('CONFINI_DIR', os.path.join(script_dir, 'config'))
argparser = argparse.ArgumentParser() argparser = argparse.ArgumentParser()
argparser.add_argument('-c', type=str, default=default_config_dir, help='Config dir') argparser.add_argument('-c', type=str, default=config_dir, help='Config dir')
argparser.add_argument('--tag', type=str, action='append', argparser.add_argument('--tag', type=str, action='append',
help='Tags to add to record') help='Tags to add to record')
argparser.add_argument('--gift-threshold', type=int, argparser.add_argument('--gift-threshold', type=int,
@@ -52,7 +53,7 @@ elif args.vv:
config = confini.Config(args.c, os.environ.get('CONFINI_ENV_PREFIX')) config = confini.Config(args.c, os.environ.get('CONFINI_ENV_PREFIX'))
config.process() config.process()
logg.debug('loaded config\n{}'.format(config)) logg.info('loaded config\n{}'.format(config))
dt_now = datetime.datetime.utcnow() dt_now = datetime.datetime.utcnow()

View File

@@ -9,12 +9,9 @@ COPY package.json \
package-lock.json \ package-lock.json \
. .
RUN --mount=type=cache,mode=0755,target=/root/node_modules npm install
RUN npm ci --production
#RUN --mount=type=cache,mode=0755,target=/root/node_modules npm install
COPY requirements.txt . COPY requirements.txt .
COPY config/ /usr/local/etc/data-seeding
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433" ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple" ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"

View File

@@ -0,0 +1,24 @@
# syntax = docker/dockerfile:1.2
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-5ab8bf45
WORKDIR /root
RUN mkdir -vp /usr/local/etc/cic
COPY package.json \
package-lock.json \
.
RUN npm install
COPY 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"
RUN pip install \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL -r requirements.txt
COPY . .
ENTRYPOINT [ ]

View File

@@ -1,94 +0,0 @@
#!/bin/bash
if [[ -d "$OUT_DIR" ]]
then
echo "found existing IMPORT DIR cleaning up..."
rm -rf "$OUT_DIR"
mkdir -p "$OUT_DIR"
else
echo "IMPORT DIR does not exist creating it."
mkdir -p "$OUT_DIR"
fi
# using timeout because the timeout flag for celery inspect does not work
timeout 5 celery inspect ping -b "$CELERY_BROKER_URL"
if [[ $? -eq 124 ]]
then
>&2 echo "Celery workers not available. Is the CELERY_BROKER_URL ($CELERY_BROKER_URL) correct?"
exit 1
fi
echo "Creating seed data..."
python create_import_users.py -vv -c "$CONFIG" --dir "$OUT_DIR" "$NUMBER_OF_USERS"
wait $!
echo "Check for running celery workers ..."
if [ -f ./cic-ussd-import.pid ];
then
echo "Found a running worker. Killing ..."
kill -9 $(<cic-ussd-import.pid)
fi
echo "Purge tasks from celery worker"
celery -A cic_ussd.import_task purge -Q "$CELERY_QUEUE" --broker redis://"$REDIS_HOST":"$REDIS_PORT" -f
echo "Start celery work and import balance job"
if [ "$INCLUDE_BALANCES" != "y" ]
then
echo "Running worker without opening balance transactions"
TARGET_TX_COUNT=$NUMBER_OF_USERS
nohup python cic_ussd/import_balance.py -vv -c "$CONFIG" -p "$ETH_PROVIDER" -r "$CIC_REGISTRY_ADDRESS" --token-symbol "$TOKEN_SYMBOL" -y "$KEYSTORE_PATH" "$OUT_DIR" > nohup.out 2> nohup.err < /dev/null &
else
echo "Running worker with opening balance transactions"
TARGET_TX_COUNT=$((NUMBER_OF_USERS*2))
nohup python cic_ussd/import_balance.py -vv -c "$CONFIG" -p "$ETH_PROVIDER" -r "$CIC_REGISTRY_ADDRESS" --include-balances --token-symbol "$TOKEN_SYMBOL" -y "$KEYSTORE_PATH" "$OUT_DIR" &
fi
echo "Target count set to ${TARGET_TX_COUNT}"
until [ -f ./cic-import-ussd.pid ]
do
echo "Polling for celery worker pid file..."
sleep 1
done
IMPORT_BALANCE_JOB=$(<cic-import-ussd.pid)
echo "Start import users job"
if [ "$USSD_SSL" == "y" ]
then
echo "Targeting secure ussd-user server"
python cic_ussd/import_users.py -vv -c "$CONFIG" --ussd-host "$USSD_HOST" --ussd-port "$USSD_PORT" "$OUT_DIR"
else
python cic_ussd/import_users.py -vv -c "$CONFIG" --ussd-host "$USSD_HOST" --ussd-port "$USSD_PORT" --ussd-no-ssl "$OUT_DIR"
fi
echo "Waiting for import balance job to complete ..."
tail --pid="$IMPORT_BALANCE_JOB" -f /dev/null
set -e
echo "Importing pins"
python cic_ussd/import_pins.py -c "$CONFIG" -vv "$OUT_DIR"
set +e
wait $!
set -e
echo "Importing ussd data"
python cic_ussd/import_ussd_data.py -c "$CONFIG" -vv "$OUT_DIR"
set +e
wait $!
echo "Importing person metadata"
node cic_meta/import_meta.js "$OUT_DIR" "$NUMBER_OF_USERS"
echo "Import preferences metadata"
node cic_meta/import_meta_preferences.js "$OUT_DIR" "$NUMBER_OF_USERS"
CIC_NOTIFY_DATABASE=postgres://$DATABASE_USER:$DATABASE_PASSWORD@$DATABASE_HOST:$DATABASE_PORT/$NOTIFY_DATABASE_NAME
NOTIFICATION_COUNT=$(psql -qtA "$CIC_NOTIFY_DATABASE" -c 'SELECT COUNT(message) FROM notification WHERE message IS NOT NULL')
while [[ "$NOTIFICATION_COUNT" < "$TARGET_TX_COUNT" ]]
do
NOTIFICATION_COUNT=$(psql -qtA "$CIC_NOTIFY_DATABASE" -c 'SELECT COUNT(message) FROM notification WHERE message IS NOT NULL')
sleep 5
echo "Notification count is: ${NOTIFICATION_COUNT} of ${TARGET_TX_COUNT}. Checking after 5 ..."
done
echo "Running verify script."
python verify.py -c "$CONFIG" -v -p "$ETH_PROVIDER" -r "$CIC_REGISTRY_ADDRESS" --exclude "$EXCLUSIONS" --meta-provider "$META_URL" --token-symbol "$TOKEN_SYMBOL" --ussd-provider "$USSD_PROVIDER" "$OUT_DIR"

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,13 @@
sarafu-faucet~=0.0.7a2 sarafu-faucet~=0.0.7a1
cic-eth[tools]~=0.12.4a8 cic-eth[tools]~=0.12.4a7
cic-types~=0.1.0a15 cic-types~=0.1.0a14
crypto-dev-signer~=0.4.15a7 crypto-dev-signer>=0.4.15a1,<=0.4.15
faker==4.17.1 faker==4.17.1
chainsyncer~=0.0.6a3 chainsyncer~=0.0.6a3
chainlib-eth~=0.0.9a14 chainlib-eth~=0.0.9a7
eth-address-index~=0.2.3a4 eth-address-index~=0.2.3a4
eth-contract-registry~=0.6.3a3 eth-contract-registry~=0.6.3a3
eth-accounts-index~=0.1.2a3 eth-accounts-index~=0.1.2a3
eth-erc20~=0.1.2a3 eth-erc20~=0.1.2a2
erc20-faucet~=0.3.2a2 erc20-faucet~=0.3.2a2
psycopg2==2.8.6 psycopg2==2.8.6
liveness~=0.0.1a7

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