Compare commits

..

1 Commits

Author SHA1 Message Date
f3aa081510 docker: multi tag builds 2021-10-05 09:18:29 +03:00
71 changed files with 455 additions and 889 deletions

View File

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

View File

@@ -1,5 +1,4 @@
celery==4.4.7 celery==4.4.7
erc20-demurrage-token~=0.0.5a3 erc20-demurrage-token~=0.0.3a1
cic-eth-registry~=0.6.1a5 cic-eth-registry>=0.6.1a2,<0.7.0
chainlib~=0.0.9rc3 cic-eth[services]~=0.12.4a8
cic_eth~=0.12.4a9

View File

@@ -1,16 +1,33 @@
build-test-cic-eth: stages:
stage: test - build-push
tags: - test
- integration
variables: variables:
APP_NAME: cic-eth APP_NAME: cic-eth
MR_IMAGE_TAG: mr-$APP_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA
workflow:
rules:
- changes:
- apps/$APP_NAME/**/*
cic-eth:build-push:
stage: build-push
script: script:
- cd apps/cic-eth - cd apps/$APP_NAME
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile . - docker pull $REGISTRY/$APP_NAME:latest || true
- docker run $MR_IMAGE_TAG sh docker/run_tests.sh - docker build --cache-from $REGISTRY/$APP_NAME:latest -t $REGISTRY/$APP_NAME:$CI_COMMIT_SHORT_SHA -f docker/Dockerfile .
- docker push $REGISTRY/$APP_NAME --all-tags
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_REF_PROTECTED == "true"
cic-eth:test:
variables:
GIT_STRATEGY: none
stage: test
needs: ["cic-eth:build-push"]
variables:
allow_failure: true
script:
- docker run $REGISTRY/$APP_NAME:$CI_COMMIT_SHORT_SHA sh docker/run_tests.sh
rules: rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/$APP_NAME/**/*
when: always

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,11 +9,7 @@ from hexathon import (
) )
#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 +74,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,9 +179,8 @@ def check_gas(self, tx_hashes_hex, chain_spec_dict, txs_hex=[], address=None, ga
:return: Signed raw transaction data list :return: Signed raw transaction data list
:rtype: param txs, unchanged :rtype: param txs, unchanged
""" """
rpc_format_address = None
if address != None: if 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) address = add_0x(address)
@@ -199,6 +195,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 +211,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

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

View File

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

View File

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

View File

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

View File

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

View File

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

@@ -206,11 +206,10 @@ def main():
BaseTask.default_token_symbol = config.get('CIC_DEFAULT_TOKEN_SYMBOL') BaseTask.default_token_symbol = config.get('CIC_DEFAULT_TOKEN_SYMBOL')
BaseTask.default_token_address = registry.by_name(BaseTask.default_token_symbol) BaseTask.default_token_address = registry.by_name(BaseTask.default_token_symbol)
default_token = ERC20Token(chain_spec, conn, add_0x(BaseTask.default_token_address)) default_token = ERC20Token(chain_spec, conn, BaseTask.default_token_address)
default_token.load(conn) default_token.load(conn)
BaseTask.default_token_decimals = default_token.decimals BaseTask.default_token_decimals = default_token.decimals
BaseTask.default_token_name = default_token.name BaseTask.default_token_name = default_token.name
BaseTask.trusted_addresses = trusted_addresses
BaseTask.run_dir = config.get('CIC_RUN_DIR') BaseTask.run_dir = config.get('CIC_RUN_DIR')
logg.info('default token set to {} {}'.format(BaseTask.default_token_symbol, BaseTask.default_token_address)) logg.info('default token set to {} {}'.format(BaseTask.default_token_symbol, BaseTask.default_token_address))

View File

@@ -28,7 +28,6 @@ class BaseTask(celery.Task):
session_func = SessionBase.create_session session_func = SessionBase.create_session
call_address = ZERO_ADDRESS call_address = ZERO_ADDRESS
trusted_addresses = []
create_nonce_oracle = RPCNonceOracle create_nonce_oracle = RPCNonceOracle
create_gas_oracle = RPCGasOracle create_gas_oracle = RPCGasOracle
default_token_address = None default_token_address = None

View File

@@ -9,8 +9,8 @@ import semver
version = ( version = (
0, 0,
12, 12,
5, 4,
'alpha.1', 'alpha.8',
) )
version_object = semver.VersionInfo( version_object = semver.VersionInfo(

View File

@@ -1,3 +1,3 @@
celery==4.4.7 celery==4.4.7
chainlib>=0.0.10a3,<0.1.0 chainlib-eth>=0.0.9a14,<0.1.0
semver==2.13.0 semver==2.13.0

View File

@@ -6,12 +6,10 @@ redis==3.5.3
hexathon~=0.0.1a8 hexathon~=0.0.1a8
pycryptodome==3.10.1 pycryptodome==3.10.1
liveness~=0.0.1a7 liveness~=0.0.1a7
eth-address-index>=0.2.4a1,<0.3.0 eth-address-index>=0.2.3a4,<0.3.0
eth-accounts-index>=0.1.2a3,<0.2.0 eth-accounts-index>=0.1.2a3,<0.2.0
cic-eth-registry>=0.6.1a5,<0.7.0 cic-eth-registry>=0.6.1a2,<0.7.0
erc20-faucet>=0.3.2a2,<0.4.0 erc20-faucet>=0.3.2a2,<0.4.0
erc20-transfer-authorization>=0.3.5a2,<0.4.0 erc20-transfer-authorization>=0.3.5a2,<0.4.0
sarafu-faucet>=0.0.7a2,<0.1.0 sarafu-faucet>=0.0.7a2,<0.1.0
moolb~=0.1.1b2 moolb~=0.1.1b2
chainlib-eth>=0.0.10a2,<0.1.0
okota>=0.2.4a6,<0.3.0

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
chainqueue>=0.0.6a1,<0.1.0 crypto-dev-signer>=0.4.15a7,<=0.4.15
cic-eth-registry>=0.6.1a5,<0.7.0 chainqueue>=0.0.5a1,<0.1.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
pyxdg==0.27 pyxdg==0.27
chainlib-eth>=0.0.10a2,<0.1.0

View File

@@ -101,7 +101,7 @@ 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:

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

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

@@ -3,6 +3,7 @@
# external imports # external imports
# local imports # local imports
from .base import Metadata
from .custom import CustomMetadata from .custom import CustomMetadata
from .person import PersonMetadata from .person import PersonMetadata
from .phone import PhonePointerMetadata from .phone import PhonePointerMetadata

View File

@@ -1,30 +1,99 @@
# standard imports # standard imports
import json
import logging import logging
import os
from typing import Dict, Union
# external imports # third-part imports
from cic_types.condiments import MetadataPointer from cic_types.models.person import generate_metadata_pointer, Person
from cic_types.ext.metadata import MetadataRequestsHandler
from cic_types.processor import generate_metadata_pointer
# local imports # local imports
from cic_ussd.cache import cache_data, get_cached_data from cic_ussd.cache import cache_data, get_cached_data
from cic_ussd.http.requests import error_handler, make_request
from cic_ussd.metadata.signer import Signer
logg = logging.getLogger(__file__) logg = logging.getLogger(__file__)
class UssdMetadataHandler(MetadataRequestsHandler): class Metadata:
def __init__(self, cic_type: MetadataPointer, identifier: bytes): """
super().__init__(cic_type, identifier) :cvar base_url: The base url or the metadata server.
:type base_url: str
"""
def cache_metadata(self, data: str): base_url = None
"""
:param data:
:type data: class MetadataRequestsHandler(Metadata):
:return:
:rtype: def __init__(self, cic_type: str, identifier: bytes, engine: str = 'pgp'):
""" """"""
cache_data(self.metadata_pointer, data) self.cic_type = cic_type
logg.debug(f'caching: {data} with key: {self.metadata_pointer}') self.engine = engine
self.headers = {
'X-CIC-AUTOMERGE': 'server',
'Content-Type': 'application/json'
}
self.identifier = identifier
self.metadata_pointer = generate_metadata_pointer(
identifier=self.identifier,
cic_type=self.cic_type
)
if self.base_url:
self.url = os.path.join(self.base_url, self.metadata_pointer)
def create(self, data: Union[Dict, str]):
""""""
data = json.dumps(data).encode('utf-8')
result = make_request(method='POST', url=self.url, data=data, headers=self.headers)
error_handler(result=result)
metadata = result.json()
return self.edit(data=metadata)
def edit(self, data: Union[Dict, str]):
""""""
cic_meta_signer = Signer()
signature = cic_meta_signer.sign_digest(data=data)
algorithm = cic_meta_signer.get_operational_key().get('algo')
formatted_data = {
'm': json.dumps(data),
's': {
'engine': self.engine,
'algo': algorithm,
'data': signature,
'digest': data.get('digest'),
}
}
formatted_data = json.dumps(formatted_data)
result = make_request(method='PUT', url=self.url, data=formatted_data, headers=self.headers)
logg.info(f'signed metadata submission status: {result.status_code}.')
error_handler(result=result)
try:
decoded_identifier = self.identifier.decode("utf-8")
except UnicodeDecodeError:
decoded_identifier = self.identifier.hex()
logg.info(f'identifier: {decoded_identifier}. metadata pointer: {self.metadata_pointer} set to: {data}.')
return result
def query(self):
""""""
result = make_request(method='GET', url=self.url)
error_handler(result=result)
result_data = result.json()
if not isinstance(result_data, dict):
raise ValueError(f'Invalid result data object: {result_data}.')
if result.status_code == 200:
if self.cic_type == ':cic.person':
person = Person()
person_data = person.deserialize(person_data=result_data)
serialized_person_data = person_data.serialize()
data = json.dumps(serialized_person_data)
else:
data = json.dumps(result_data)
cache_data(key=self.metadata_pointer, data=data)
logg.debug(f'caching: {data} with key: {self.metadata_pointer}')
return result_data
def get_cached_metadata(self): def get_cached_metadata(self):
"""""" """"""

View File

@@ -1,13 +1,12 @@
# standard imports # standard imports
# external imports # external imports
from cic_types.condiments import MetadataPointer
# local imports # local imports
from .base import UssdMetadataHandler from .base import MetadataRequestsHandler
class CustomMetadata(UssdMetadataHandler): class CustomMetadata(MetadataRequestsHandler):
def __init__(self, identifier: bytes): def __init__(self, identifier: bytes):
super().__init__(cic_type=MetadataPointer.CUSTOM, identifier=identifier) super().__init__(cic_type=':cic.custom', identifier=identifier)

View File

@@ -1,13 +1,12 @@
# standard imports # standard imports
# external imports # external imports
from cic_types.condiments import MetadataPointer
# local imports # local imports
from .base import UssdMetadataHandler from .base import MetadataRequestsHandler
class PersonMetadata(UssdMetadataHandler): class PersonMetadata(MetadataRequestsHandler):
def __init__(self, identifier: bytes): def __init__(self, identifier: bytes):
super().__init__(cic_type=MetadataPointer.PERSON, identifier=identifier) super().__init__(cic_type=':cic.person', identifier=identifier)

View File

@@ -2,13 +2,12 @@
import logging import logging
# external imports # external imports
from cic_types.condiments import MetadataPointer
# local imports # local imports
from .base import UssdMetadataHandler from .base import MetadataRequestsHandler
class PhonePointerMetadata(UssdMetadataHandler): class PhonePointerMetadata(MetadataRequestsHandler):
def __init__(self, identifier: bytes): def __init__(self, identifier: bytes):
super().__init__(cic_type=MetadataPointer.PHONE, identifier=identifier) super().__init__(cic_type=':cic.phone', identifier=identifier)

View File

@@ -1,13 +1,13 @@
# standard imports # standard imports
# external imports # external imports
from cic_types.condiments import MetadataPointer import celery
# local imports # local imports
from .base import UssdMetadataHandler from .base import MetadataRequestsHandler
class PreferencesMetadata(UssdMetadataHandler): class PreferencesMetadata(MetadataRequestsHandler):
def __init__(self, identifier: bytes): def __init__(self, identifier: bytes):
super().__init__(cic_type=MetadataPointer.PREFERENCES, identifier=identifier) super().__init__(cic_type=':cic.preferences', identifier=identifier)

View File

@@ -0,0 +1,60 @@
# standard imports
import json
import logging
from typing import Optional
from urllib.request import Request, urlopen
# third-party imports
import gnupg
# local imports
logg = logging.getLogger()
class Signer:
"""
:cvar gpg_path:
:type gpg_path:
:cvar gpg_passphrase:
:type gpg_passphrase:
:cvar key_file_path:
:type key_file_path:
"""
gpg_path: str = None
gpg_passphrase: str = None
key_file_path: str = None
def __init__(self):
self.gpg = gnupg.GPG(gnupghome=self.gpg_path)
with open(self.key_file_path, 'r') as key_file:
self.key_data = key_file.read()
def get_operational_key(self):
"""
:return:
:rtype:
"""
# import key data into keyring
self.gpg.import_keys(key_data=self.key_data)
gpg_keys = self.gpg.list_keys()
key_algorithm = gpg_keys[0].get('algo')
key_id = gpg_keys[0].get("keyid")
logg.debug(f'using signing key: {key_id}, algorithm: {key_algorithm}')
return gpg_keys[0]
def sign_digest(self, data: dict):
"""
:param data:
:type data:
:return:
:rtype:
"""
digest = data['digest']
key_id = self.get_operational_key().get('keyid')
signature = self.gpg.sign(digest, passphrase=self.gpg_passphrase, keyid=key_id)
return str(signature)

View File

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

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)

View File

@@ -1,17 +1,16 @@
# standard imports # standard imports
import json
import logging import logging
# third-party imports # third-party imports
import celery import celery
from cic_types.models.person import Person 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
from cic_ussd.tasks.base import CriticalMetadataTask from cic_ussd.tasks.base import CriticalMetadataTask
celery_app = celery.current_app celery_app = celery.current_app
logg = logging.getLogger(__file__) logg = logging.getLogger().getChild(__name__)
@celery_app.task @celery_app.task
@@ -22,15 +21,9 @@ 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)
response = person_metadata_client.query() person_metadata_client.query()
data = response.json()
person = Person()
person_data = person.deserialize(person_data=data)
serialized_person_data = person_data.serialize()
data = json.dumps(serialized_person_data)
person_metadata_client.cache_metadata(data=data)
@celery_app.task @celery_app.task
@@ -43,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)
@@ -58,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)
@@ -83,10 +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}.')
preferences_metadata_client = PreferencesMetadata(identifier=identifier) person_metadata_client = PreferencesMetadata(identifier=identifier)
response = preferences_metadata_client.query() return person_metadata_client.query()
data = json.dumps(response.json())
preferences_metadata_client.cache_metadata(data)
return data

View File

@@ -5,6 +5,7 @@ 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.metadata import get_cached_preferred_language
@@ -23,13 +24,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,7 +53,7 @@ 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)

View File

@@ -4,10 +4,10 @@ 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 cffi==1.14.6
cic-eth[services]~=0.12.4a11 cic-eth[services]~=0.12.4a7
cic-notify~=0.4.0a10 cic-notify~=0.4.0a10
cic-types~=0.2.0a3 cic-types~=0.1.0a15
confini>=0.3.6rc4,<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
python-i18n[YAML]==0.3.9 python-i18n[YAML]==0.3.9

View File

@@ -28,6 +28,7 @@ def test_filter_statement_transactions(transactions_list):
def test_generate(activated_account, def test_generate(activated_account,
cache_default_token_data, cache_default_token_data,
cache_statement,
cache_preferences, cache_preferences,
celery_session_worker, celery_session_worker,
init_cache, init_cache,
@@ -36,22 +37,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):

View File

@@ -5,25 +5,24 @@ import os
# external imports # external imports
import requests_mock import requests_mock
from chainlib.hash import strip_0x from chainlib.hash import strip_0x
from cic_types.condiments import MetadataPointer
from cic_types.processor import generate_metadata_pointer from cic_types.processor import generate_metadata_pointer
# local imports # local imports
from cic_ussd.metadata.base import UssdMetadataHandler from cic_ussd.metadata.base import MetadataRequestsHandler
# external imports # external imports
def test_ussd_metadata_handler(activated_account, def test_metadata_requests_handler(activated_account,
init_cache, init_cache,
load_config, load_config,
person_metadata, person_metadata,
setup_metadata_request_handler, setup_metadata_request_handler,
setup_metadata_signer): setup_metadata_signer):
identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address)) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
cic_type = MetadataPointer.PERSON cic_type = ':cic.person'
metadata_client = UssdMetadataHandler(cic_type, identifier) metadata_client = MetadataRequestsHandler(cic_type, identifier)
assert metadata_client.cic_type == cic_type assert metadata_client.cic_type == cic_type
assert metadata_client.engine == 'pgp' assert metadata_client.engine == 'pgp'
assert metadata_client.identifier == identifier assert metadata_client.identifier == identifier
@@ -39,5 +38,7 @@ def test_ussd_metadata_handler(activated_account,
assert result.status_code == 200 assert result.status_code == 200
person_metadata.pop('digest') person_metadata.pop('digest')
request_mocker.register_uri('GET', metadata_client.url, status_code=200, reason='OK', json=person_metadata) request_mocker.register_uri('GET', metadata_client.url, status_code=200, reason='OK', json=person_metadata)
result = metadata_client.query().json() result = metadata_client.query()
assert result == person_metadata assert result == person_metadata
cached_metadata = metadata_client.get_cached_metadata()
assert json.loads(cached_metadata) == person_metadata

View File

@@ -1,7 +1,7 @@
# standard imports # standard imports
import os import os
# external imports # external imports
from cic_types.condiments import MetadataPointer from chainlib.hash import strip_0x
from cic_types.processor import generate_metadata_pointer from cic_types.processor import generate_metadata_pointer
# local imports # local imports
@@ -11,8 +11,8 @@ from cic_ussd.metadata import CustomMetadata
def test_custom_metadata(activated_account, load_config, setup_metadata_request_handler, setup_metadata_signer): def test_custom_metadata(activated_account, load_config, setup_metadata_request_handler, setup_metadata_signer):
cic_type = MetadataPointer.CUSTOM cic_type = ':cic.custom'
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
custom_metadata_client = CustomMetadata(identifier) custom_metadata_client = CustomMetadata(identifier)
assert custom_metadata_client.cic_type == cic_type assert custom_metadata_client.cic_type == cic_type
assert custom_metadata_client.engine == 'pgp' assert custom_metadata_client.engine == 'pgp'

View File

@@ -1,7 +1,7 @@
# standard imports # standard imports
import os import os
# external imports # external imports
from cic_types.condiments import MetadataPointer from chainlib.hash import strip_0x
from cic_types.processor import generate_metadata_pointer from cic_types.processor import generate_metadata_pointer
# local imports # local imports
@@ -11,8 +11,8 @@ from cic_ussd.metadata import PersonMetadata
def test_person_metadata(activated_account, load_config, setup_metadata_request_handler, setup_metadata_signer): def test_person_metadata(activated_account, load_config, setup_metadata_request_handler, setup_metadata_signer):
cic_type = MetadataPointer.PERSON cic_type = ':cic.person'
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
person_metadata_client = PersonMetadata(identifier) person_metadata_client = PersonMetadata(identifier)
assert person_metadata_client.cic_type == cic_type assert person_metadata_client.cic_type == cic_type
assert person_metadata_client.engine == 'pgp' assert person_metadata_client.engine == 'pgp'

View File

@@ -1,7 +1,7 @@
# standard imports # standard imports
import os import os
# external imports # external imports
from cic_types.condiments import MetadataPointer from chainlib.hash import strip_0x
from cic_types.processor import generate_metadata_pointer from cic_types.processor import generate_metadata_pointer
# local imports # local imports
@@ -12,8 +12,8 @@ from cic_ussd.metadata import PhonePointerMetadata
def test_phone_pointer_metadata(activated_account, load_config, setup_metadata_request_handler, setup_metadata_signer): def test_phone_pointer_metadata(activated_account, load_config, setup_metadata_request_handler, setup_metadata_signer):
cic_type = MetadataPointer.PHONE cic_type = ':cic.phone'
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
phone_pointer_metadata = PhonePointerMetadata(identifier) phone_pointer_metadata = PhonePointerMetadata(identifier)
assert phone_pointer_metadata.cic_type == cic_type assert phone_pointer_metadata.cic_type == cic_type
assert phone_pointer_metadata.engine == 'pgp' assert phone_pointer_metadata.engine == 'pgp'

View File

@@ -1,7 +1,7 @@
# standard imports # standard imports
import os import os
# external imports # external imports
from cic_types.condiments import MetadataPointer from chainlib.hash import strip_0x
from cic_types.processor import generate_metadata_pointer from cic_types.processor import generate_metadata_pointer
# local imports # local imports
@@ -11,8 +11,8 @@ from cic_ussd.metadata import PreferencesMetadata
def test_preferences_metadata(activated_account, load_config, setup_metadata_request_handler, setup_metadata_signer): def test_preferences_metadata(activated_account, load_config, setup_metadata_request_handler, setup_metadata_signer):
cic_type = MetadataPointer.PREFERENCES cic_type = ':cic.preferences'
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
preferences_metadata_client = PreferencesMetadata(identifier) preferences_metadata_client = PreferencesMetadata(identifier)
assert preferences_metadata_client.cic_type == cic_type assert preferences_metadata_client.cic_type == cic_type
assert preferences_metadata_client.engine == 'pgp' assert preferences_metadata_client.engine == 'pgp'

View File

@@ -0,0 +1,17 @@
# standard imports
import shutil
# third-party imports
# local imports
from cic_ussd.metadata.signer import Signer
def test_client(load_config, setup_metadata_signer, person_metadata):
signer = Signer()
gpg = signer.gpg
assert signer.key_data is not None
gpg.import_keys(key_data=signer.key_data)
gpg_keys = gpg.list_keys()
assert signer.get_operational_key() == gpg_keys[0]
shutil.rmtree(Signer.gpg_path)

View File

@@ -57,7 +57,7 @@ def test_menu_processor(activated_account,
available_balance=available_balance, available_balance=available_balance,
token_symbol=token_symbol) token_symbol=token_symbol)
identifier = bytes.fromhex(activated_account.blockchain_address) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
key = cache_data_key(identifier, ':cic.adjusted_balance') key = cache_data_key(identifier, ':cic.adjusted_balance')
adjusted_balance = 45931650.64654012 adjusted_balance = 45931650.64654012
cache_data(key, json.dumps(adjusted_balance)) cache_data(key, json.dumps(adjusted_balance))
@@ -108,7 +108,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)

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')

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

@@ -6,19 +6,33 @@ import tempfile
# external imports # external imports
import pytest import pytest
from chainlib.hash import strip_0x from chainlib.hash import strip_0x
from cic_types.condiments import MetadataPointer
from cic_types.processor import generate_metadata_pointer from cic_types.processor import generate_metadata_pointer
# local imports # local imports
from cic_ussd.metadata import PersonMetadata, PhonePointerMetadata, PreferencesMetadata from cic_ussd.metadata import Metadata, PersonMetadata, PhonePointerMetadata, PreferencesMetadata
from cic_ussd.metadata.signer import Signer
logg = logging.getLogger(__name__) logg = logging.getLogger(__name__)
@pytest.fixture(scope='function')
def setup_metadata_signer(load_config):
temp_dir = tempfile.mkdtemp(dir='/tmp')
logg.debug(f'Created temp dir: {temp_dir}')
Signer.gpg_path = temp_dir
Signer.gpg_passphrase = load_config.get('PGP_PASSPHRASE')
Signer.key_file_path = os.path.join(load_config.get('PGP_KEYS_PATH'), load_config.get('PGP_PRIVATE_KEYS'))
@pytest.fixture(scope='function')
def setup_metadata_request_handler(load_config):
Metadata.base_url = load_config.get('CIC_META_URL')
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def account_phone_pointer(activated_account): def account_phone_pointer(activated_account):
identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address)) identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
return generate_metadata_pointer(identifier, MetadataPointer.PERSON) return generate_metadata_pointer(identifier, ':cic.phone')
@pytest.fixture(scope='function') @pytest.fixture(scope='function')

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

@@ -1,14 +1,12 @@
cic-eth[tools]==0.12.4a11 cic-eth[tools]==0.12.4a8
chainlib-eth>=0.0.9rc4,<0.1.0 chainlib-eth>=0.0.9a14,<0.1.0
chainlib==0.0.9rc1,<0.1.0
eth-erc20>=0.1.2a3,<0.2.0 eth-erc20>=0.1.2a3,<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.4a1,<0.3.0 eth-address-index>=0.2.3a4,<0.3.0
cic-eth-registry>=0.6.1a5,<0.7.0 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 confini>=0.4.2rc3,<1.0.0
eth-token-index>=0.2.4a1,<=0.3.0 crypto-dev-signer>=0.4.15a7,<=0.4.15
okota>=0.2.4a5,<0.3.0

View File

@@ -65,25 +65,22 @@ 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" 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"
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 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 "deploy account index contract"
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`
>&2 echo "add deployer address as account index writer"
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
>&2 echo "deploy contract registry contract"
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`
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
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 # Deploy address declarator registry
>&2 echo "deploy address declarator contract" >&2 echo "deploy address declarator contract"
declarator_description=0x546869732069732074686520434943206e6574776f726b000000000000000000 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` DEV_DECLARATOR_ADDRESS=`eth-address-declarator-deploy -s -u -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -w -vv $declarator_description`
>&2 echo "deploy contract registry contract"
#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`
CIC_REGISTRY_ADDRESS=`okota-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 --address-declarator $DEV_DECLARATOR_ADDRESS -p $RPC_PROVIDER -vv -s -u -w`
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
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 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
>&2 echo "deploy account index contract"
#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`
DEV_ACCOUNT_INDEX_ADDRESS=`okota-accounts-index-deploy $fee_price_arg -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -y $WALLET_KEY_FILE -vv -s -u -w --address-declarator $DEV_DECLARATOR_ADDRESS --token-address $DEV_RESERVE_ADDRESS`
#>&2 echo "add deployer address as account index writer"
#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
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 transfer authorization contact # Deploy transfer authorization contact
>&2 echo "deploy transfer auth contract" >&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` DEV_TRANSFER_AUTHORIZATION_ADDRESS=`erc20-transfer-auth-deploy $gas_price_arg -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -w -vv`
@@ -91,8 +88,7 @@ eth-contract-registry-set $fee_price_arg -s -u -w -y $WALLET_KEY_FILE -e $CIC_RE
# Deploy token index contract # Deploy token index contract
>&2 echo "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` 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`
DEV_TOKEN_INDEX_ADDRESS=`okota-token-index-deploy -s -u $fee_price_arg -y $WALLET_KEY_FILE -i $CIC_CHAIN_SPEC -p $RPC_PROVIDER -w -vv --address-declarator $DEV_DECLARATOR_ADDRESS`
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 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" >&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 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

View File

@@ -46,7 +46,7 @@ cic-eth-tag -i $CHAIN_SPEC TRANSFER_AUTHORIZATION_OWNER $DEV_ETH_ACCOUNT_TRANSFE
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`
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 $WALLET_KEY_FILE -i $CHAIN_SPEC -p $RPC_PROVIDER -e $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
@@ -78,9 +78,9 @@ export DEV_ETH_SARAFU_TOKEN_ADDRESS=$DEV_ETH_RESERVE_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 $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}
# 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 -vv -i $CHAIN_SPEC unlock INIT cic-eth-ctl -i $CHAIN_SPEC unlock INIT
cic-eth-ctl -vv -i $CHAIN_SPEC unlock SEND cic-eth-ctl -i $CHAIN_SPEC unlock SEND
cic-eth-ctl -vv -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 #confini-dump --schema-module chainlib.eth.data.config --schema-module cic_eth.data.config --schema-dir ./config

View File

@@ -1,10 +1,10 @@
sarafu-faucet~=0.0.7a2 sarafu-faucet~=0.0.7a2
cic-eth[tools]~=0.12.5a1 cic-eth[tools]~=0.12.4a8
cic-types~=0.2.0a4 cic-types~=0.1.0a15
funga>=0.5.1a1,<0.6.0 crypto-dev-signer~=0.4.15a7
faker==4.17.1 faker==4.17.1
chainsyncer~=0.0.6a3 chainsyncer~=0.0.6a3
chainlib-eth~=0.0.10a2 chainlib-eth~=0.0.9a14
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