Compare commits

..

11 Commits

77 changed files with 523 additions and 1949 deletions

View File

@@ -1,4 +1,4 @@
cic-base==0.1.3a3+build.984b5cff
cic-base==0.1.3a3+build.4aa03607
alembic==1.4.2
confini~=0.3.6rc3
uwsgi==2.0.19.1

View File

@@ -6,5 +6,5 @@ sqlparse==0.4.1
pytest-celery==0.0.0a1
eth_tester==0.5.0b3
py-evm==0.3.0a20
cic_base[full]==0.1.3a3+build.984b5cff
cic_base[full]==0.1.3a3+build.4aa03607
sarafu-faucet~=0.0.4a1

View File

@@ -3,29 +3,31 @@
APP_NAME: cic-eth
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
.cic_eth_mr_changes_target:
.cic_eth_changes_target:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- $CONTEXT/$APP_NAME/**/*
#changes:
#- $CONTEXT/$APP_NAME/**/*
when: always
build-mr-cic-eth:
extends:
- .cic_eth_variables
- .cic_eth_mr_changes_target
- .cic_eth_changes_target
- .py_build_target_test
test-mr-cic-eth:
extends:
- .cic_eth_variables
- .cic_eth_mr_changes_target
- .cic_eth_changes_target
stage: test
image: $IMAGE_TAG_BASE
image: $CI_REGISTRY_IMAGE/$APP_NAME-test:latest
script:
- cd apps/$APP_NAME/
- pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests
needs: ["build-mr-cic-eth"]
build-push-cic-eth:
extends:
- .py_build_push
- .cic_eth_variables

View File

@@ -1,5 +0,0 @@
SQLAlchemy==1.3.20
cic-eth-registry~=0.5.6a1
hexathon~=0.0.1a7
chainqueue~=0.0.2b5
eth-erc20==0.0.10a2

View File

@@ -5,3 +5,4 @@
"""
from .api_task import Api
from .api_admin import AdminApi

View File

@@ -8,10 +8,11 @@ import logging
# external imports
import celery
from cic_eth_registry import CICRegistry
from chainlib.chain import ChainSpec
# local imports
from cic_eth.enum import LockEnum
from cic_eth.db.enum import LockEnum
app = celery.current_app
@@ -203,82 +204,6 @@ class Api:
# return t
def transfer_from(self, from_address, to_address, value, token_symbol, spender_address):
"""Executes a chain of celery tasks that performs a transfer of ERC20 tokens by one address on behalf of another address to a third party.
:param from_address: Ethereum address of sender
:type from_address: str, 0x-hex
:param to_address: Ethereum address of recipient
:type to_address: str, 0x-hex
:param value: Estimated return from conversion
:type value: int
:param token_symbol: ERC20 token symbol of token to send
:type token_symbol: str
:param spender_address: Ethereum address of recipient
:type spender_address: str, 0x-hex
:returns: uuid of root task
:rtype: celery.Task
"""
s_check = celery.signature(
'cic_eth.admin.ctrl.check_lock',
[
[token_symbol],
self.chain_spec.asdict(),
LockEnum.QUEUE,
from_address,
],
queue=self.queue,
)
s_nonce = celery.signature(
'cic_eth.eth.nonce.reserve_nonce',
[
self.chain_spec.asdict(),
from_address,
],
queue=self.queue,
)
s_tokens = celery.signature(
'cic_eth.eth.erc20.resolve_tokens_by_symbol',
[
self.chain_spec.asdict(),
],
queue=self.queue,
)
s_allow = celery.signature(
'cic_eth.eth.erc20.check_allowance',
[
from_address,
value,
self.chain_spec.asdict(),
spender_address,
],
queue=self.queue,
)
s_transfer = celery.signature(
'cic_eth.eth.erc20.transfer_from',
[
from_address,
to_address,
value,
self.chain_spec.asdict(),
spender_address,
],
queue=self.queue,
)
s_tokens.link(s_allow)
s_nonce.link(s_tokens)
s_check.link(s_nonce)
if self.callback_param != None:
s_transfer.link(self.callback_success)
s_allow.link(s_transfer).on_error(self.callback_error)
else:
s_allow.link(s_transfer)
t = s_check.apply_async(queue=self.queue)
return t
def transfer(self, from_address, to_address, value, token_symbol):
"""Executes a chain of celery tasks that performs a transfer of ERC20 tokens from one address to another.

View File

@@ -1 +1,158 @@
from cic_eth.enum import *
# standard imports
import enum
@enum.unique
class StatusBits(enum.IntEnum):
"""Individual bit flags that are combined to define the state and legacy of a queued transaction
"""
QUEUED = 0x01 # transaction should be sent to network
IN_NETWORK = 0x08 # transaction is in network
DEFERRED = 0x10 # an attempt to send the transaction to network has failed
GAS_ISSUES = 0x20 # transaction is pending sender account gas funding
LOCAL_ERROR = 0x100 # errors that originate internally from the component
NODE_ERROR = 0x200 # errors originating in the node (invalid RLP input...)
NETWORK_ERROR = 0x400 # errors that originate from the network (REVERT)
UNKNOWN_ERROR = 0x800 # unclassified errors (the should not occur)
FINAL = 0x1000 # transaction processing has completed
OBSOLETE = 0x2000 # transaction has been replaced by a different transaction with higher fee
MANUAL = 0x8000 # transaction processing has been manually overridden
@enum.unique
class StatusEnum(enum.IntEnum):
"""
- Inactive, not finalized. (<0)
* PENDING: The initial state of a newly added transaction record. No action has been performed on this transaction yet.
* SENDFAIL: The transaction was not received by the node.
* RETRY: The transaction is queued for a new send attempt after previously failing.
* READYSEND: The transaction is queued for its first send attempt
* OBSOLETED: A new transaction with the same nonce and higher gas has been sent to network.
* WAITFORGAS: The transaction is on hold pending gas funding.
- Active state: (==0)
* SENT: The transaction has been sent to the mempool.
- Inactive, finalized. (>0)
* FUBAR: Unknown error occurred and transaction is abandoned. Manual intervention needed.
* CANCELLED: The transaction was sent, but was not mined and has disappered from the mempool. This usually follows a transaction being obsoleted.
* OVERRIDDEN: Transaction has been manually overriden.
* REJECTED: The transaction was rejected by the node.
* REVERTED: The transaction was mined, but exception occurred during EVM execution. (Block number will be set)
* SUCCESS: THe transaction was successfully mined. (Block number will be set)
"""
PENDING = 0
SENDFAIL = StatusBits.DEFERRED | StatusBits.LOCAL_ERROR
RETRY = StatusBits.QUEUED | StatusBits.DEFERRED
READYSEND = StatusBits.QUEUED
OBSOLETED = StatusBits.OBSOLETE | StatusBits.IN_NETWORK
WAITFORGAS = StatusBits.GAS_ISSUES
SENT = StatusBits.IN_NETWORK
FUBAR = StatusBits.FINAL | StatusBits.UNKNOWN_ERROR
CANCELLED = StatusBits.IN_NETWORK | StatusBits.FINAL | StatusBits.OBSOLETE
OVERRIDDEN = StatusBits.FINAL | StatusBits.OBSOLETE | StatusBits.MANUAL
REJECTED = StatusBits.NODE_ERROR | StatusBits.FINAL
REVERTED = StatusBits.IN_NETWORK | StatusBits.FINAL | StatusBits.NETWORK_ERROR
SUCCESS = StatusBits.IN_NETWORK | StatusBits.FINAL
@enum.unique
class LockEnum(enum.IntEnum):
"""
STICKY: When set, reset is not possible
CREATE: Disable creation of accounts
SEND: Disable sending to network
QUEUE: Disable queueing new or modified transactions
"""
STICKY=1
INIT=2
CREATE=4
SEND=8
QUEUE=16
QUERY=32
ALL=int(0xfffffffffffffffe)
def status_str(v, bits_only=False):
"""Render a human-readable string describing the status
If the bit field exactly matches a StatusEnum value, the StatusEnum label will be returned.
If a StatusEnum cannot be matched, the string will be postfixed with "*", unless explicitly instructed to return bit field labels only.
:param v: Status bit field
:type v: number
:param bits_only: Only render individual bit labels.
:type bits_only: bool
:returns: Status string
:rtype: str
"""
s = ''
if not bits_only:
try:
s = StatusEnum(v).name
return s
except ValueError:
pass
if v == 0:
return 'NONE'
for i in range(16):
b = (1 << i)
if (b & 0xffff) & v:
n = StatusBits(b).name
if len(s) > 0:
s += ','
s += n
if not bits_only:
s += '*'
return s
def all_errors():
"""Bit mask of all error states
:returns: Error flags
:rtype: number
"""
return StatusBits.LOCAL_ERROR | StatusBits.NODE_ERROR | StatusBits.NETWORK_ERROR | StatusBits.UNKNOWN_ERROR
def is_error_status(v):
"""Check if value is an error state
:param v: Status bit field
:type v: number
:returns: True if error
:rtype: bool
"""
return bool(v & all_errors())
def dead():
"""Bit mask defining whether a transaction is still likely to be processed on the network.
:returns: Bit mask
:rtype: number
"""
return StatusBits.FINAL | StatusBits.OBSOLETE
def is_alive(v):
"""Check if transaction is still likely to be processed on the network.
The contingency of "likely" refers to the case a transaction has been obsoleted after sent to the network, but the network still confirms the obsoleted transaction. The return value of this method will not change as a result of this, BUT the state itself will (as the FINAL bit will be set).
:returns:
"""
return bool(v & dead() == 0)

View File

@@ -1,158 +0,0 @@
# standard imports
import enum
@enum.unique
class StatusBits(enum.IntEnum):
"""Individual bit flags that are combined to define the state and legacy of a queued transaction
"""
QUEUED = 0x01 # transaction should be sent to network
IN_NETWORK = 0x08 # transaction is in network
DEFERRED = 0x10 # an attempt to send the transaction to network has failed
GAS_ISSUES = 0x20 # transaction is pending sender account gas funding
LOCAL_ERROR = 0x100 # errors that originate internally from the component
NODE_ERROR = 0x200 # errors originating in the node (invalid RLP input...)
NETWORK_ERROR = 0x400 # errors that originate from the network (REVERT)
UNKNOWN_ERROR = 0x800 # unclassified errors (the should not occur)
FINAL = 0x1000 # transaction processing has completed
OBSOLETE = 0x2000 # transaction has been replaced by a different transaction with higher fee
MANUAL = 0x8000 # transaction processing has been manually overridden
@enum.unique
class StatusEnum(enum.IntEnum):
"""
- Inactive, not finalized. (<0)
* PENDING: The initial state of a newly added transaction record. No action has been performed on this transaction yet.
* SENDFAIL: The transaction was not received by the node.
* RETRY: The transaction is queued for a new send attempt after previously failing.
* READYSEND: The transaction is queued for its first send attempt
* OBSOLETED: A new transaction with the same nonce and higher gas has been sent to network.
* WAITFORGAS: The transaction is on hold pending gas funding.
- Active state: (==0)
* SENT: The transaction has been sent to the mempool.
- Inactive, finalized. (>0)
* FUBAR: Unknown error occurred and transaction is abandoned. Manual intervention needed.
* CANCELLED: The transaction was sent, but was not mined and has disappered from the mempool. This usually follows a transaction being obsoleted.
* OVERRIDDEN: Transaction has been manually overriden.
* REJECTED: The transaction was rejected by the node.
* REVERTED: The transaction was mined, but exception occurred during EVM execution. (Block number will be set)
* SUCCESS: THe transaction was successfully mined. (Block number will be set)
"""
PENDING = 0
SENDFAIL = StatusBits.DEFERRED | StatusBits.LOCAL_ERROR
RETRY = StatusBits.QUEUED | StatusBits.DEFERRED
READYSEND = StatusBits.QUEUED
OBSOLETED = StatusBits.OBSOLETE | StatusBits.IN_NETWORK
WAITFORGAS = StatusBits.GAS_ISSUES
SENT = StatusBits.IN_NETWORK
FUBAR = StatusBits.FINAL | StatusBits.UNKNOWN_ERROR
CANCELLED = StatusBits.IN_NETWORK | StatusBits.FINAL | StatusBits.OBSOLETE
OVERRIDDEN = StatusBits.FINAL | StatusBits.OBSOLETE | StatusBits.MANUAL
REJECTED = StatusBits.NODE_ERROR | StatusBits.FINAL
REVERTED = StatusBits.IN_NETWORK | StatusBits.FINAL | StatusBits.NETWORK_ERROR
SUCCESS = StatusBits.IN_NETWORK | StatusBits.FINAL
@enum.unique
class LockEnum(enum.IntEnum):
"""
STICKY: When set, reset is not possible
CREATE: Disable creation of accounts
SEND: Disable sending to network
QUEUE: Disable queueing new or modified transactions
"""
STICKY=1
INIT=2
CREATE=4
SEND=8
QUEUE=16
QUERY=32
ALL=int(0xfffffffffffffffe)
def status_str(v, bits_only=False):
"""Render a human-readable string describing the status
If the bit field exactly matches a StatusEnum value, the StatusEnum label will be returned.
If a StatusEnum cannot be matched, the string will be postfixed with "*", unless explicitly instructed to return bit field labels only.
:param v: Status bit field
:type v: number
:param bits_only: Only render individual bit labels.
:type bits_only: bool
:returns: Status string
:rtype: str
"""
s = ''
if not bits_only:
try:
s = StatusEnum(v).name
return s
except ValueError:
pass
if v == 0:
return 'NONE'
for i in range(16):
b = (1 << i)
if (b & 0xffff) & v:
n = StatusBits(b).name
if len(s) > 0:
s += ','
s += n
if not bits_only:
s += '*'
return s
def all_errors():
"""Bit mask of all error states
:returns: Error flags
:rtype: number
"""
return StatusBits.LOCAL_ERROR | StatusBits.NODE_ERROR | StatusBits.NETWORK_ERROR | StatusBits.UNKNOWN_ERROR
def is_error_status(v):
"""Check if value is an error state
:param v: Status bit field
:type v: number
:returns: True if error
:rtype: bool
"""
return bool(v & all_errors())
def dead():
"""Bit mask defining whether a transaction is still likely to be processed on the network.
:returns: Bit mask
:rtype: number
"""
return StatusBits.FINAL | StatusBits.OBSOLETE
def is_alive(v):
"""Check if transaction is still likely to be processed on the network.
The contingency of "likely" refers to the case a transaction has been obsoleted after sent to the network, but the network still confirms the obsoleted transaction. The return value of this method will not change as a result of this, BUT the state itself will (as the FINAL bit will be set).
:returns:
"""
return bool(v & dead() == 0)

View File

@@ -80,8 +80,3 @@ class SignerError(SeppukuError):
class RoleAgencyError(SeppukuError):
"""Exception raise when a role cannot perform its function. This is a critical exception
"""
class YouAreBrokeError(Exception):
"""Exception raised when a value transfer is attempted without access to sufficient funds
"""

View File

@@ -24,7 +24,6 @@ from cic_eth.error import (
TokenCountError,
PermanentTxError,
OutOfGasError,
YouAreBrokeError,
)
from cic_eth.queue.tx import register_tx
from cic_eth.eth.gas import (
@@ -72,117 +71,6 @@ def balance(tokens, holder_address, chain_spec_dict):
return tokens
@celery_app.task(bind=True)
def check_allowance(self, tokens, holder_address, value, chain_spec_dict, spender_address):
"""Best-effort verification that the allowance for a transfer from spend is sufficient.
:raises YouAreBrokeError: If allowance is insufficient
:param tokens: Token addresses
:type tokens: list of str, 0x-hex
:param holder_address: Token holder address
:type holder_address: str, 0x-hex
:param value: Amount of token, in 'wei'
:type value: int
:param chain_str: Chain spec string representation
:type chain_str: str
:param spender_address: Address of account spending on behalf of holder
:type spender_address: str, 0x-hex
:return: Token list as passed to task
:rtype: dict
"""
logg.debug('tokens {}'.format(tokens))
if len(tokens) != 1:
raise TokenCountError
t = tokens[0]
chain_spec = ChainSpec.from_dict(chain_spec_dict)
rpc = RPCConnection.connect(chain_spec, 'default')
caller_address = ERC20Token.caller_address
c = ERC20(chain_spec)
o = c.allowance(t['address'], holder_address, spender_address, sender_address=caller_address)
r = rpc.do(o)
allowance = c.parse_allowance(r)
if allowance < value:
errstr = 'allowance {} insufficent to transfer {} {} by {} on behalf of {}'.format(allowance, value, t['symbol'], spender_address, holder_address)
logg.error(errstr)
raise YouAreBrokeError(errstr)
return tokens
@celery_app.task(bind=True, base=CriticalSQLAlchemyAndSignerTask)
def transfer_from(self, tokens, holder_address, receiver_address, value, chain_spec_dict, spender_address):
"""Transfer ERC20 tokens between addresses
First argument is a list of tokens, to enable the task to be chained to the symbol to token address resolver function. However, it accepts only one token as argument.
:param tokens: Token addresses
:type tokens: list of str, 0x-hex
:param holder_address: Token holder address
:type holder_address: str, 0x-hex
:param receiver_address: Token receiver address
:type receiver_address: str, 0x-hex
:param value: Amount of token, in 'wei'
:type value: int
:param chain_str: Chain spec string representation
:type chain_str: str
:param spender_address: Address of account spending on behalf of holder
:type spender_address: str, 0x-hex
:raises TokenCountError: Either none or more then one tokens have been passed as tokens argument
:return: Transaction hash for tranfer operation
:rtype: str, 0x-hex
"""
# we only allow one token, one transfer
logg.debug('tokens {}'.format(tokens))
if len(tokens) != 1:
raise TokenCountError
t = tokens[0]
chain_spec = ChainSpec.from_dict(chain_spec_dict)
queue = self.request.delivery_info.get('routing_key')
rpc = RPCConnection.connect(chain_spec, 'default')
rpc_signer = RPCConnection.connect(chain_spec, 'signer')
session = self.create_session()
nonce_oracle = CustodialTaskNonceOracle(holder_address, self.request.root_id, session=session)
gas_oracle = self.create_gas_oracle(rpc, MaxGasOracle.gas)
c = ERC20(chain_spec, signer=rpc_signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle)
try:
(tx_hash_hex, tx_signed_raw_hex) = c.transfer_from(t['address'], spender_address, holder_address, receiver_address, value, tx_format=TxFormat.RLP_SIGNED)
except FileNotFoundError as e:
raise SignerError(e)
except ConnectionError as e:
raise SignerError(e)
rpc_signer.disconnect()
rpc.disconnect()
cache_task = 'cic_eth.eth.erc20.cache_transfer_from_data'
register_tx(tx_hash_hex, tx_signed_raw_hex, chain_spec, queue, cache_task=cache_task, session=session)
session.commit()
session.close()
gas_pair = gas_oracle.get_gas(tx_signed_raw_hex)
gas_budget = gas_pair[0] * gas_pair[1]
logg.debug('transfer tx {} {} {}'.format(tx_hash_hex, queue, gas_budget))
s = create_check_gas_task(
[tx_signed_raw_hex],
chain_spec,
holder_address,
gas_budget,
[tx_hash_hex],
queue,
)
s.apply_async()
return tx_hash_hex
@celery_app.task(bind=True, base=CriticalSQLAlchemyAndSignerTask)
def transfer(self, tokens, holder_address, receiver_address, value, chain_spec_dict):
"""Transfer ERC20 tokens between addresses
@@ -344,7 +232,6 @@ def resolve_tokens_by_symbol(self, token_symbols, chain_spec_dict):
logg.debug('token {}'.format(token_address))
tokens.append({
'address': token_address,
'symbol': token_symbol,
'converters': [],
})
rpc.disconnect()
@@ -392,48 +279,6 @@ def cache_transfer_data(
return (tx_hash_hex, cache_id)
@celery_app.task(base=CriticalSQLAlchemyTask)
def cache_transfer_from_data(
tx_hash_hex,
tx_signed_raw_hex,
chain_spec_dict,
):
"""Helper function for otx_cache_transfer_from
:param tx_hash_hex: Transaction hash
:type tx_hash_hex: str, 0x-hex
:param tx: Signed raw transaction
:type tx: str, 0x-hex
:returns: Transaction hash and id of cache element in storage backend, respectively
:rtype: tuple
"""
chain_spec = ChainSpec.from_dict(chain_spec_dict)
tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex))
tx = unpack(tx_signed_raw_bytes, chain_spec)
tx_data = ERC20.parse_transfer_from_request(tx['data'])
spender_address = tx_data[0]
recipient_address = tx_data[1]
token_value = tx_data[2]
session = SessionBase.create_session()
tx_cache = TxCache(
tx_hash_hex,
tx['from'],
recipient_address,
tx['to'],
tx['to'],
token_value,
token_value,
session=session,
)
session.add(tx_cache)
session.commit()
cache_id = tx_cache.id
session.close()
return (tx_hash_hex, cache_id)
@celery_app.task(base=CriticalSQLAlchemyTask)
def cache_approve_data(
tx_hash_hex,

View File

@@ -12,7 +12,7 @@ from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.eth.address import is_checksum_address
# local imports
from cic_eth.api.admin import AdminApi
from cic_eth.api import AdminApi
from cic_eth.db.enum import LockEnum
logging.basicConfig(level=logging.WARNING)

View File

@@ -12,8 +12,10 @@ import confini
import celery
# local imports
from cic_eth.api import Api
from cic_eth.api.admin import AdminApi
from cic_eth.api import (
Api,
AdminApi,
)
logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger()

View File

@@ -11,7 +11,7 @@ from chainlib.chain import ChainSpec
from chainlib.eth.connection import EthHTTPConnection
# local imports
from cic_eth.api.admin import AdminApi
from cic_eth.api.api_admin import AdminApi
logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger()

View File

@@ -12,7 +12,7 @@ from chainlib.chain import ChainSpec
from xdg.BaseDirectory import xdg_config_home
# local imports
from cic_eth.api.admin import AdminApi
from cic_eth.api import AdminApi
from cic_eth.db import dsn_from_config
from cic_eth.db.models.base import SessionBase

View File

@@ -19,7 +19,7 @@ from chainlib.eth.connection import EthHTTPConnection
from hexathon import add_0x
# local imports
from cic_eth.api.admin import AdminApi
from cic_eth.api import AdminApi
from cic_eth.db.enum import (
StatusEnum,
status_str,

View File

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

View File

@@ -8,14 +8,12 @@ RUN apt-get update && \
#RUN python -m venv venv && . venv/bin/activate
ARG pip_extra_index_url_flag='--index https://pypi.org/simple --extra-index-url https://pip.grassrootseconomics.net:8433'
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
RUN /usr/local/bin/python -m pip install --upgrade pip
RUN pip install semver
# TODO use a packaging style that lets us copy requirments only ie. pip-tools
COPY cic-eth/ .
RUN pip install --extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL .
RUN pip install $pip_extra_index_url_flag .
# --- TEST IMAGE ---
FROM python:3.8.6-slim-buster as test
@@ -34,12 +32,8 @@ COPY --from=compile /usr/local/lib/python3.8/site-packages/ \
# COPY --from=compile /usr/src/cic-eth/ .
# RUN . venv/bin/activate
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
COPY cic-eth/test_requirements.txt .
RUN pip install --extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL -r test_requirements.txt
RUN pip install $pip_extra_index_url_flag -r test_requirements.txt
COPY cic-eth .

View File

@@ -1,3 +1,25 @@
cic-base==0.1.3a3+build.4aa03607
celery==4.4.7
chainlib~=0.0.5a1
crypto-dev-signer~=0.4.14b6
confini~=0.3.6rc3
cic-eth-registry~=0.5.6a1
redis==3.5.3
alembic==1.4.2
websockets==8.1
requests~=2.24.0
eth_accounts_index~=0.0.12a1
erc20-transfer-authorization~=0.3.2a1
uWSGI==2.0.19.1
semver==2.13.0
websocket-client==0.57.0
moolb~=0.1.1b2
eth-address-index~=0.1.2a1
chainlib-eth~=0.0.5a1
hexathon~=0.0.1a7
chainsyncer[sql]~=0.0.3a3
chainqueue~=0.0.2b5
sarafu-faucet~=0.0.4a1
erc20-faucet~=0.2.2a1
coincurve==15.0.0
potaahto~=0.0.1a2
pycryptodome==3.10.1

View File

@@ -1,7 +0,0 @@
chainsyncer[sql]~=0.0.3a3
chainqueue~=0.0.2b5
alembic==1.4.2
confini~=0.3.6rc4
redis==3.5.3
hexathon~=0.0.1a7
pycryptodome==3.10.1

View File

@@ -45,16 +45,16 @@ scripts =
[options.entry_points]
console_scripts =
# daemons
cic-eth-taskerd = cic_eth.runnable.daemons.tasker:main [services]
cic-eth-trackerd = cic_eth.runnable.daemons.tracker:main [services]
cic-eth-dispatcherd = cic_eth.runnable.daemons.dispatcher:main [services]
cic-eth-retrierd = cic_eth.runnable.daemons.retry:main [services]
cic-eth-taskerd = cic_eth.runnable.daemons.tasker:main
cic-eth-trackerd = cic_eth.runnable.daemons.tracker:main
cic-eth-dispatcherd = cic_eth.runnable.daemons.dispatcher:main
cic-eth-retrierd = cic_eth.runnable.daemons.retry:main
# tools
cic-eth-create = cic_eth.runnable.create:main [tools]
cic-eth-inspect = cic_eth.runnable.view:main [tools]
cic-eth-ctl = cic_eth.runnable.ctrl:main [tools]
cic-eth-info = cic_eth.runnable.info:main [tools]
cic-eth-create = cic_eth.runnable.create:main
cic-eth-inspect = cic_eth.runnable.view:main
cic-eth-ctl = cic_eth.runnable.ctrl:main
cic-eth-info = cic_eth.runnable.info:main
# TODO: Merge this with ctl when subcmds sorted to submodules
cic-eth-tag = cic_eth.runnable.tag:main [tools]
cic-eth-resend = cic_eth.runnable.resend:main [tools]
cic-eth-transfer = cic_eth.runnable.transfer:main [tools]
cic-eth-tag = cic_eth.runnable.tag:main
cic-eth-resend = cic_eth.runnable.resend:main
cic-eth-transfer = cic_eth.runnable.transfer:main

View File

@@ -11,41 +11,6 @@ while True:
requirements.append(l.rstrip())
f.close()
admin_requirements = []
f = open('admin_requirements.txt', 'r')
while True:
l = f.readline()
if l == '':
break
admin_requirements.append(l.rstrip())
f.close()
tools_requirements = []
f = open('tools_requirements.txt', 'r')
while True:
l = f.readline()
if l == '':
break
tools_requirements.append(l.rstrip())
f.close()
services_requirements = []
f = open('services_requirements.txt', 'r')
while True:
l = f.readline()
if l == '':
break
services_requirements.append(l.rstrip())
f.close()
setup(
install_requires=requirements,
extras_require = {
'tools': tools_requirements,
'admin_api': admin_requirements,
'services': services_requirements,
}
install_requires=requirements
)

View File

@@ -2,8 +2,5 @@ pytest==6.0.1
pytest-celery==0.0.0a1
pytest-mock==3.3.1
pytest-cov==2.10.1
pytest-redis==2.0.0
redis==3.5.3
eth-tester==0.5.0b3
py-evm==0.3.0a20
eth-erc20~=0.0.10a2

View File

@@ -17,11 +17,11 @@ root_dir = os.path.dirname(script_dir)
sys.path.insert(0, root_dir)
# assemble fixtures
from cic_eth.pytest.fixtures_config import *
from cic_eth.pytest.fixtures_celery import *
from cic_eth.pytest.fixtures_database import *
from cic_eth.pytest.fixtures_role import *
from cic_eth.pytest.fixtures_contract import *
from tests.fixtures_config import *
from tests.fixtures_database import *
from tests.fixtures_celery import *
from tests.fixtures_role import *
from tests.fixtures_contract import *
from chainlib.eth.pytest import *
from eth_contract_registry.pytest import *
from cic_eth_registry.pytest.fixtures_contracts import *

View File

@@ -2,13 +2,13 @@
import os
import logging
# external imports
# third-party imports
import pytest
import confini
script_dir = os.path.dirname(os.path.realpath(__file__))
root_dir = os.path.dirname(os.path.dirname(script_dir))
logg = logging.getLogger(__name__)
root_dir = os.path.dirname(script_dir)
logg = logging.getLogger(__file__)
@pytest.fixture(scope='session')

View File

@@ -37,8 +37,7 @@ def init_database(
database_engine,
):
script_dir = os.path.dirname(os.path.realpath(__file__))
rootdir = os.path.dirname(os.path.dirname(script_dir))
rootdir = os.path.dirname(os.path.dirname(__file__))
dbdir = os.path.join(rootdir, 'cic_eth', 'db')
migrationsdir = os.path.join(dbdir, 'migrations', load_config.get('DATABASE_ENGINE'))
if not os.path.isdir(migrationsdir):

View File

@@ -40,7 +40,7 @@ from chainqueue.sql.query import (
)
# local imports
from cic_eth.api.admin import AdminApi
from cic_eth.api import AdminApi
from cic_eth.db.models.role import AccountRole
from cic_eth.db.enum import LockEnum
from cic_eth.error import InitializationError

View File

@@ -35,7 +35,7 @@ from eth_erc20 import ERC20
from cic_eth_registry import CICRegistry
# local imports
from cic_eth.api.admin import AdminApi
from cic_eth.api.api_admin import AdminApi
from cic_eth.eth.gas import cache_gas_data
from cic_eth.eth.erc20 import cache_transfer_data

View File

@@ -1 +1 @@
from cic_eth.pytest.fixtures_celery import *
from tests.fixtures_celery import *

View File

@@ -13,7 +13,6 @@ from chainlib.eth.tx import (
# local imports
from cic_eth.queue.tx import register_tx
from cic_eth.error import YouAreBrokeError
logg = logging.getLogger()
@@ -168,101 +167,3 @@ def test_erc20_approve_task(
r = t.get_leaf()
logg.debug('result {}'.format(r))
def test_erc20_transfer_from_task(
default_chain_spec,
foo_token,
agent_roles,
custodial_roles,
eth_signer,
eth_rpc,
init_database,
celery_session_worker,
token_roles,
):
token_object = {
'address': foo_token,
}
transfer_value = 100 * (10 ** 6)
nonce_oracle = RPCNonceOracle(token_roles['FOO_TOKEN_OWNER'], conn=eth_rpc)
c = ERC20(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.approve(foo_token, token_roles['FOO_TOKEN_OWNER'], agent_roles['ALICE'], transfer_value)
r = eth_rpc.do(o)
o = receipt(tx_hash)
r = eth_rpc.do(o)
assert r['status'] == 1
s_nonce = celery.signature(
'cic_eth.eth.nonce.reserve_nonce',
[
[token_object],
default_chain_spec.asdict(),
custodial_roles['FOO_TOKEN_GIFTER'],
],
queue=None,
)
s_transfer = celery.signature(
'cic_eth.eth.erc20.transfer_from',
[
custodial_roles['FOO_TOKEN_GIFTER'],
agent_roles['BOB'],
transfer_value,
default_chain_spec.asdict(),
agent_roles['ALICE'],
],
queue=None,
)
s_nonce.link(s_transfer)
t = s_nonce.apply_async()
r = t.get_leaf()
logg.debug('result {}'.format(r))
def test_erc20_allowance_check_task(
default_chain_spec,
foo_token,
agent_roles,
custodial_roles,
eth_signer,
eth_rpc,
init_database,
celery_session_worker,
token_roles,
):
token_object = {
'address': foo_token,
'symbol': 'FOO',
}
transfer_value = 100 * (10 ** 6)
s_check = celery.signature(
'cic_eth.eth.erc20.check_allowance',
[
[token_object],
custodial_roles['FOO_TOKEN_GIFTER'],
transfer_value,
default_chain_spec.asdict(),
agent_roles['ALICE']
],
queue=None,
)
t = s_check.apply_async()
with pytest.raises(YouAreBrokeError):
t.get()
nonce_oracle = RPCNonceOracle(token_roles['FOO_TOKEN_OWNER'], conn=eth_rpc)
c = ERC20(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle)
(tx_hash, o) = c.approve(foo_token, token_roles['FOO_TOKEN_OWNER'], agent_roles['ALICE'], transfer_value)
r = eth_rpc.do(o)
o = receipt(tx_hash)
r = eth_rpc.do(o)
assert r['status'] == 1
t = s_check.apply_async()
t.get()
assert t.successful()

View File

@@ -1,8 +0,0 @@
crypto-dev-signer~=0.4.14b6
chainqueue~=0.0.2b5
confini~=0.3.6rc4
cic-eth-registry~=0.5.6a1
redis==3.5.3
hexathon~=0.0.1a7
pycryptodome==3.10.1
pyxdg==0.27

View File

@@ -9,7 +9,7 @@ import semver
logg = logging.getLogger()
version = (0, 4, 0, 'alpha.7')
version = (0, 4, 0, 'alpha.6')
version_object = semver.VersionInfo(
major=version[0],

View File

@@ -1 +1 @@
cic_base[full_graph]==0.1.3a3+build.984b5cff
cic_base[full_graph]==0.1.3a3+build.4aa03607

View File

@@ -127,8 +127,6 @@ def main():
argv.append('--loglevel=INFO')
argv.append('-Q')
argv.append(args.q)
argv.append('-n')
argv.append(args.q)
current_app.worker_main(argv)

View File

@@ -1,4 +1,4 @@
cic_base[full_graph]==0.1.3a3+build.984b5cff
cic-eth~=0.12.0a1
cic-notify~=0.4.0a7
cic_base[full_graph]==0.1.3a3+build.4aa03607
cic-eth~=0.11.1a2
cic-notify~=0.4.0a6
cic-types~=0.1.0a11

View File

@@ -1,7 +1,7 @@
.contract_migration_variables:
variables:
APP_NAME: contract-migration
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile_ci
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
.contract_migration_changes_target:
rules:

View File

@@ -1,22 +1,28 @@
# syntax = docker/dockerfile:1.2
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e
FROM python:3.8.6-slim-buster as compile-image
WORKDIR /root
RUN apt-get update
RUN apt-get install -y --no-install-recommends git gcc g++ libpq-dev gawk jq telnet wget openssl iputils-ping gnupg socat bash procps make python2 cargo
RUN touch /etc/apt/sources.list.d/ethereum.list
RUN echo 'deb http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic main' > /etc/apt/sources.list.d/ethereum.list
RUN echo 'deb-src http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic main' >> /etc/apt/sources.list.d/ethereum.list
RUN cat /etc/apt/sources.list.d/ethereum.list
RUN cat etc/apt/sources.list.d/ethereum.list
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 2A518C819BE37D2C2031944D1C52189C923F6CA9
#RUN apt-get install solc
RUN apt-get update
RUN apt-get install solc
RUN pip install --upgrade pip
WORKDIR /root
RUN mkdir -vp /usr/local/etc/cic
COPY contract-migration/nvm.sh .
ENV CONFINI_DIR /usr/local/etc/cic/
RUN mkdir -vp $CONFINI_DIR
ARG cic_config_commit=0abe0867f18077907c7023bf0ef5e466a3984dd8
ARG cic_config_commit=35c69ba75f00c8147150acf325565d5391cf25bf
ARG cic_config_url=https://gitlab.com/grassrootseconomics/cic-config.git/
RUN echo Install confini schema files && \
git clone --depth 1 $cic_config_url cic-config && \
@@ -25,18 +31,70 @@ RUN echo Install confini schema files && \
git checkout $cic_config_commit && \
cp -v *.ini $CONFINI_DIR
# Install nvm with node and npm
# https://stackoverflow.com/questions/25899912/how-to-install-nvm-in-docker
ENV NVM_DIR /root/.nvm
ENV NODE_VERSION 15.3.0
ENV BANCOR_NODE_VERSION 10.16.0
RUN wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash \
&& . $NVM_DIR/nvm.sh \
&& nvm install $NODE_VERSION \
&& nvm alias default $NODE_VERSION \
&& nvm use $NODE_VERSION
# && chown -R root:root "$NVM_DIR/versions/node/v$NODE_VERSION"
ENV NODE_PATH $NVM_DIR/versions/node//v$NODE_VERSION/lib/node_modules
ENV PATH $NVM_DIR/versions/node//v$NODE_VERSION/bin:$PATH
#RUN useradd --create-home grassroots
# WORKDIR /home/grassroots
# USER grassroots
COPY contract-migration/requirements.txt .
ARG pip_extra_args=""
ARG pip_index_url=https://pypi.org/simple
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
ARG pip_trusted_host=pypi.org
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url https://pypi.org/simple \
--force-reinstall \
--trusted-host $pip_trusted_host \
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
-r requirements.txt
ARG pip_extra_index_url=https://pip.grassrootseconomics.net:8433
RUN pip install --index-url https://pypi.org/simple \
--extra-index-url $pip_extra_index_url -r requirements.txt
COPY contract-migration/ .
RUN chmod +x *.sh
# -------------- begin runtime container ----------------
FROM python:3.8.6-slim-buster as runtime-image
RUN apt-get update
RUN apt-get install -y --no-install-recommends gnupg libpq-dev
RUN apt-get install -y jq bash iputils-ping socat
COPY --from=compile-image /usr/local/bin/ /usr/local/bin/
COPY --from=compile-image /usr/local/etc/cic/ /usr/local/etc/cic/
COPY --from=compile-image /usr/local/lib/python3.8/site-packages/ \
/usr/local/lib/python3.8/site-packages/
ENV EXTRA_INDEX_URL https://pip.grassrootseconomics.net:8433
# RUN useradd -u 1001 --create-home grassroots
# RUN adduser grassroots sudo && \
# echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
# WORKDIR /home/grassroots
COPY contract-migration/testdata/pgp testdata/pgp
COPY contract-migration/sarafu_declaration.json sarafu_declaration.json
COPY contract-migration/keystore keystore
COPY contract-migration/envlist .
# A shared output dir for environment configs
RUN mkdir -p /tmp/cic/config
# RUN chown grassroots:grassroots /tmp/cic/config
RUN chmod a+rwx /tmp/cic/config
COPY contract-migration/*.sh ./
# RUN chown grassroots:grassroots -R .
RUN chmod gu+x *.sh
# we copied these from the root build container.
# this is dumb though...I guess the compile image should have the same user
# RUN chown grassroots:grassroots -R /usr/local/lib/python3.8/site-packages/
# USER grassroots
ENTRYPOINT [ ]

View File

@@ -1,42 +0,0 @@
# syntax = docker/dockerfile:1.2
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e
WORKDIR /root
# solc install which we needed for bancor. Leaving as an artfact of HOW to do it.
#RUN touch /etc/apt/sources.list.d/ethereum.list
#RUN echo 'deb http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic main' > /etc/apt/sources.list.d/ethereum.list
#RUN echo 'deb-src http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic main' >> /etc/apt/sources.list.d/ethereum.list
#RUN cat /etc/apt/sources.list.d/ethereum.list
#RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 2A518C819BE37D2C2031944D1C52189C923F6CA9
#RUN apt-get install solc
RUN mkdir -vp /usr/local/etc/cic
ENV CONFINI_DIR /usr/local/etc/cic/
RUN mkdir -vp $CONFINI_DIR
ARG cic_config_commit=0abe0867f18077907c7023bf0ef5e466a3984dd8
ARG cic_config_url=https://gitlab.com/grassrootseconomics/cic-config.git/
RUN echo Install confini schema files && \
git clone --depth 1 $cic_config_url cic-config && \
cd cic-config && \
git fetch --depth 1 origin $cic_config_commit && \
git checkout $cic_config_commit && \
cp -v *.ini $CONFINI_DIR
COPY contract-migration/requirements.txt .
ARG pip_index_url=https://pypi.org/simple
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
ARG pip_trusted_host=pypi.org
RUN pip install --index-url https://pypi.org/simple \
--force-reinstall \
--trusted-host $pip_trusted_host \
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
-r requirements.txt
COPY contract-migration/ .
RUN chmod +x *.sh

View File

@@ -1,3 +0,0 @@
#eth-contract-registry==0.5.5a3
#erc20-demurrage-token==0.0.1b4
#eth-address-index==0.1.1a12

View File

@@ -1,4 +1,4 @@
cic_base[full]==0.1.3a3+build.984b5cff
sarafu-faucet~=0.0.4a1
cic-eth~=0.11.1a2
erc20-demurrage-token==0.0.2a1
cic-base[full_graph]==0.1.2b15
sarafu-faucet==0.0.3a3
sarafu-token==0.0.1a8
cic-eth==0.11.0b16

View File

@@ -2,20 +2,8 @@
set -a
CIC_DEFAULT_TOKEN_SYMBOL=${CIC_DEFAULT_TOKEN_SYMBOL:-GFT}
TOKEN_SYMBOL=${CIC_DEFAULT_TOKEN_SYMBOL}
cat <<EOF
external token settings:
token_symbol: $TOKEN_SYMBOL
token_name: $TOKEN_NAME
token_decimals: $TOKEN_DECIMALS
token_demurrage: $TOKEN_DEMURRAGE_LEVEL
token_redistribution_period: $TOKEN_REDISTRIBUTION_PERIOD
token_supply_limit: $TOKEN_SUPPLY_LIMIT
EOF
CIC_CHAIN_SPEC=${CIC_CHAIN_SPEC:-evm:bloxberg:8995}
TOKEN_SYMBOL=${TOKEN_SYMBOL:-GFT}
CIC_DEFAULT_TOKEN_SYMBOL=${CIC_DEFAULT_TOKEN_SYMBOL:-GFT}
DEV_ETH_ACCOUNT_RESERVE_MINTER=${DEV_ETH_ACCOUNT_RESERVE_MINTER:-$DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER}
DEV_ETH_ACCOUNT_ACCOUNTS_INDEX_WRITER=${DEV_ETH_ACCOUNT_RESERVE_MINTER:-$DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER}
DEV_RESERVE_AMOUNT=${DEV_ETH_RESERVE_AMOUNT:-""10000000000000000000000000000000000}
@@ -31,8 +19,8 @@ if [ ! -z $DEV_ETH_GAS_PRICE ]; then
>&2 echo using static gas price $DEV_ETH_GAS_PRICE
fi
if [[ $TOKEN_SYMBOL != 'GFT' && $TOKEN_SYMBOL != 'SRF' ]]; then
>&2 echo TOKEN_SYMBOL must be one of [GFT,SRF], but was $TOKEN_SYMBOL
if [[ $CIC_DEFAULT_TOKEN_SYMBOL != 'GFT' && $CIC_DEFAULT_TOKEN_SYMBOL != 'SRF' ]]; then
>&2 echo CIC_DEFAULT_TOKEN_SYMBOL must be one of [GFT,SRF], but was $CIC_DEFAULT_TOKEN_SYMBOL
exit 1
fi
@@ -72,18 +60,17 @@ if [[ -n "${ETH_PROVIDER}" ]]; then
./wait-for-it.sh "${ETH_PROVIDER_HOST}:${ETH_PROVIDER_PORT}"
fi
if [ $TOKEN_SYMBOL == 'GFT' ]; then
if [ $CIC_DEFAULT_TOKEN_SYMBOL == 'GFT' ]; then
>&2 echo "deploying 'giftable token'"
DEV_RESERVE_ADDRESS=`giftable-token-deploy $gas_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -vv -ww --name "Giftable Token" --symbol "GFT" --decimals 6 -vv`
DEV_RESERVE_ADDRESS=`giftable-token-deploy $gas_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -vv -w --name "Giftable Token" --symbol "GFT" --decimals 6 -vv`
else
>&2 echo "deploying 'redistributed demurrage token'"
if [ -z $TOKEN_SINK_ADDRESS && ! -z $TOKEN_REDISTRIBUTION_PERIOD ]; then
>&2 echo -e "\033[;93mtoken sink address not set, so redistribution will be BURNED\033[;39m"
fi
DEV_RESERVE_ADDRESS=`erc20-demurrage-token-deploy $gas_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -vv -ww`
>&2 echo "deploying 'sarafu' token'"
DEV_RESERVE_ADDRESS=`sarafu-token-deploy $gas_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -vv -w --name "Sarafu" --decimals 6 -vv SRF $DEV_SARAFU_DEMURRAGE_LEVEL`
fi
giftable-token-gift $gas_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -vv -w -a $DEV_RESERVE_ADDRESS $DEV_RESERVE_AMOUNT
#BANCOR_REGISTRY_ADDRESS=`cic-bancor-deploy $gas_price_arg --bancor-dir /usr/local/share/cic/bancor -z $DEV_ETH_RESERVE_ADDRESS -p $ETH_PROVIDER -o $DEV_ETH_ACCOUNT_CONTRACT_DEPLOYER`
>&2 echo "deploy account index contract"
DEV_ACCOUNT_INDEX_ADDRESS=`eth-accounts-index-deploy $gas_price_arg -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -vv -w`
>&2 echo "add deployer address as account index writer"

View File

@@ -2,22 +2,13 @@
if [[ $((RUN_MASK & 1)) -eq 1 ]]
then
>&2 echo -e "\033[;96mRUNNING\033[;39m RUN_MASK 1 - contract deployment"
./reset.sh
if [ $? -ne "0" ]; then
>&2 echo -e "\033[;31mFAILED\033[;39m RUN_MASK 1 - contract deployment"
exit 1;
exit 1;
fi
>&2 echo -e "\033[;32mSUCCEEDED\033[;39m RUN_MASK 1 - contract deployment"
fi
if [[ $((RUN_MASK & 2)) -eq 2 ]]
then
>&2 echo -e "\033[;96mRUNNING\033[;39m RUN_MASK 2 - custodial service initialization"
./seed_cic_eth.sh
if [ $? -ne "0" ]; then
>&2 echo -e "\033[;31mFAILED\033[;39m RUN_MASK 2 - custodial service initialization"
exit 1;
fi
>&2 echo -e "\033[;32mSUCCEEDED\033[;39m RUN_MASK 2 - custodial service initialization"
fi

View File

@@ -14,7 +14,6 @@ DEV_DATABASE_NAME_CIC_ETH=${DEV_DATABASE_NAME_CIC_ETH:-"cic-eth"}
CIC_DATA_DIR=${CIC_DATA_DIR:-/tmp/cic}
ETH_PASSPHRASE=''
CIC_DEFAULT_TOKEN_SYMBOL=${CIC_DEFAULT_TOKEN_SYMBOL:-GFT}
TOKEN_SYMBOL=$CIC_DEFAULT_TOKEN_SYMBOL
if [[ $CIC_DEFAULT_TOKEN_SYMBOL != 'GFT' && $CIC_DEFAULT_TOKEN_SYMBOL != 'SRF' ]]; then
>&2 echo CIC_DEFAULT_TOKEN_SYMBOL must be one of [GFT,SRF], but was $CIC_DEFAULT_TOKEN_SYMBOL
exit 1
@@ -99,8 +98,8 @@ echo DEV_ETH_SARAFU_TOKEN_ADDRESS=$DEV_ETH_RESERVE_ADDRESS >> $env_out_file
export DEV_ETH_SARAFU_TOKEN_ADDRESS=$DEV_ETH_RESERVE_ADDRESS
# Transfer tokens to gifter address
>&2 echo "transfer tokens to token gifter address"
>&2 erc20-transfer -y $keystore_file -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER --gas-limit 100000 --token-address $DEV_RESERVE_ADDRESS -w $debug $DEV_ETH_ACCOUNT_SARAFU_GIFTER ${token_amount:0:-1}
>&2 echo "transfer sarafu tokens to token gifter address"
>&2 erc20-transfer -y $keystore_file -i $CIC_CHAIN_SPEC -p $ETH_PROVIDER --token-address $DEV_RESERVE_ADDRESS -w $debug $DEV_ETH_ACCOUNT_SARAFU_GIFTER ${token_amount:0:-1}
#echo -n 0 > $init_level_file

View File

@@ -1,7 +1,7 @@
.data_seeding_variables:
variables:
APP_NAME: data-seeding
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile_ci
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
.data_seeding_changes_target:
rules:

View File

@@ -10,7 +10,7 @@ import redis
import celery
from cic_eth_registry.registry import CICRegistry
from chainsyncer.backend.memory import MemBackend
from chainsyncer.driver.head import HeadSyncer
from chainsyncer.driver import HeadSyncer
from chainlib.eth.connection import EthHTTPConnection
from chainlib.chain import ChainSpec
from chainlib.eth.gas import RPCGasOracle
@@ -24,7 +24,6 @@ from cic_base import (
rpc,
signer as signer_funcs,
)
from cic_base.eth.syncer import chain_interface
# local imports
#import common
@@ -121,7 +120,7 @@ def main():
'api_queue': config.get('_CELERY_QUEUE'),
}
syncer = HeadSyncer(syncer_backend, chain_interface, block_callback=handler.refresh)
syncer = HeadSyncer(syncer_backend, block_callback=handler.refresh)
syncer.add_filter(handler)
syncer.loop(1, conn)

View File

@@ -93,9 +93,9 @@ function importMeta(keystore) {
let files;
try {
files = fs.readdirSync(workDir);
} catch (err) {
console.error('source directory not yet ready', workDir, 'reason: ', err);
err, files = fs.readdirSync(workDir);
} catch {
console.error('source directory not yet ready', workDir);
setTimeout(importMeta, batchDelay, keystore);
return;
}

View File

@@ -1,22 +1,28 @@
# standard imports
import argparse
import logging
import sys
import os
import sys
import logging
import argparse
import hashlib
import redis
import celery
# external imports
import celery
import confini
import redis
from chainlib.chain import ChainSpec
from chainlib.eth.address import to_checksum_address
from chainlib.eth.connection import EthHTTPConnection
from chainlib.chain import ChainSpec
from hexathon import (
strip_0x,
add_0x,
)
from chainlib.eth.address import to_checksum_address
from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer
from crypto_dev_signer.keystore.dict import DictKeystore
from cic_types.models.person import Person
# local imports
from import_task import ImportTask, MetadataTask
from import_util import BalanceProcessor, get_celery_worker_status
from import_util import BalanceProcessor
from import_task import *
logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger()
@@ -35,41 +41,37 @@ argparser.add_argument('--meta-port', dest='meta_port', type=int, help='metadata
argparser.add_argument('--redis-host', dest='redis_host', type=str, help='redis host to use for task submission')
argparser.add_argument('--redis-port', dest='redis_port', type=int, help='redis host to use for task submission')
argparser.add_argument('--redis-db', dest='redis_db', type=int, help='redis db to use for task submission and callback')
argparser.add_argument('--token-symbol', default='GFT', type=str, dest='token_symbol',
help='Token symbol to use for transactions')
argparser.add_argument('--token-symbol', default='SRF', type=str, dest='token_symbol', help='Token symbol to use for trnsactions')
argparser.add_argument('--head', action='store_true', help='start at current block height (overrides --offset)')
argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str,
help='environment prefix for variables to overwrite configuration')
argparser.add_argument('-q', type=str, default='cic-import-ussd', help='celery queue to submit transaction tasks to')
argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration')
argparser.add_argument('-q', type=str, default='cic-eth', help='celery queue to submit transaction tasks to')
argparser.add_argument('--offset', type=int, default=0, help='block offset to start syncer from')
argparser.add_argument('-v', help='be verbose', action='store_true')
argparser.add_argument('-vv', help='be more verbose', action='store_true')
argparser.add_argument('user_dir', default='out', type=str, help='user export directory')
args = argparser.parse_args(sys.argv[1:])
if args.v:
if args.v == True:
logging.getLogger().setLevel(logging.INFO)
elif args.vv:
elif args.vv == True:
logging.getLogger().setLevel(logging.DEBUG)
config_dir = os.path.join(args.c)
os.makedirs(config_dir, 0o777, True)
config = confini.Config(config_dir, args.env_prefix)
config.process()
# override args
args_override = {
'CIC_CHAIN_SPEC': getattr(args, 'i'),
'ETH_PROVIDER': getattr(args, 'p'),
'CIC_REGISTRY_ADDRESS': getattr(args, 'r'),
'REDIS_HOST': getattr(args, 'redis_host'),
'REDIS_PORT': getattr(args, 'redis_port'),
'REDIS_DB': getattr(args, 'redis_db'),
'META_HOST': getattr(args, 'meta_host'),
'META_PORT': getattr(args, 'meta_port'),
'KEYSTORE_FILE_PATH': getattr(args, 'y')
}
'CIC_CHAIN_SPEC': getattr(args, 'i'),
'ETH_PROVIDER': getattr(args, 'p'),
'CIC_REGISTRY_ADDRESS': getattr(args, 'r'),
'REDIS_HOST': getattr(args, 'redis_host'),
'REDIS_PORT': getattr(args, 'redis_port'),
'REDIS_DB': getattr(args, 'redis_db'),
'META_HOST': getattr(args, 'meta_host'),
'META_PORT': getattr(args, 'meta_port'),
'KEYSTORE_FILE_PATH': getattr(args, 'y')
}
config.dict_override(args_override, 'cli flag')
config.censor('PASSWORD', 'DATABASE')
config.censor('PASSWORD', 'SSL')
@@ -79,19 +81,14 @@ redis_host = config.get('REDIS_HOST')
redis_port = config.get('REDIS_PORT')
redis_db = config.get('REDIS_DB')
r = redis.Redis(redis_host, redis_port, redis_db)
# create celery apps
celery_app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL'))
status = get_celery_worker_status(celery_app=celery_app)
celery_app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL'))
signer_address = None
keystore = DictKeystore()
if args.y is not None:
if args.y != None:
logg.debug('loading keystore file {}'.format(args.y))
signer_address = keystore.import_keystore_file(args.y)
logg.debug('now have key for signer address {}'.format(signer_address))
# define signer
signer = EIP155Signer(keystore)
queue = args.q
@@ -106,7 +103,7 @@ chain_spec = ChainSpec.from_chain_str(chain_str)
old_chain_spec_str = args.old_chain_spec
old_chain_spec = ChainSpec.from_chain_str(old_chain_spec_str)
user_dir = args.user_dir # user_out_dir from import_users.py
user_dir = args.user_dir # user_out_dir from import_users.py
token_symbol = args.token_symbol
@@ -114,22 +111,20 @@ MetadataTask.meta_host = config.get('META_HOST')
MetadataTask.meta_port = config.get('META_PORT')
ImportTask.chain_spec = chain_spec
def main():
conn = EthHTTPConnection(config.get('ETH_PROVIDER'))
ImportTask.balance_processor = BalanceProcessor(conn, chain_spec, config.get('CIC_REGISTRY_ADDRESS'),
signer_address, signer)
ImportTask.balance_processor = BalanceProcessor(conn, chain_spec, config.get('CIC_REGISTRY_ADDRESS'), signer_address, signer)
ImportTask.balance_processor.init(token_symbol)
# TODO get decimals from token
balances = {}
f = open('{}/balances.csv'.format(user_dir, 'r'))
remove_zeros = 10 ** 6
remove_zeros = 10**6
i = 0
while True:
l = f.readline()
if l is None:
if l == None:
break
r = l.split(',')
try:
@@ -148,23 +143,15 @@ def main():
ImportTask.import_dir = user_dir
s = celery.signature(
'import_task.send_txs',
[
MetadataTask.balance_processor.nonce_offset,
],
queue=queue,
)
'import_task.send_txs',
[
MetadataTask.balance_processor.nonce_offset,
],
queue='cic-import-ussd',
)
s.apply_async()
argv = ['worker']
if args.vv:
argv.append('--loglevel=DEBUG')
elif args.v:
argv.append('--loglevel=INFO')
argv.append('-Q')
argv.append(args.q)
argv.append('-n')
argv.append(args.q)
argv = ['worker', '-Q', 'cic-import-ussd', '--loglevel=DEBUG']
celery_app.worker_main(argv)

View File

@@ -9,7 +9,7 @@ import celery
import confini
# local imports
from import_util import get_celery_worker_status
from import_task import *
logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger()
@@ -39,12 +39,9 @@ elif args.vv:
config_dir = args.c
config = confini.Config(config_dir, os.environ.get('CONFINI_ENV_PREFIX'))
config.process()
config.censor('PASSWORD', 'DATABASE')
logg.debug('config loaded from {}:\n{}'.format(args.c, config))
celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL'))
status = get_celery_worker_status(celery_app=celery_app)
db_configs = {
'database': config.get('DATABASE_NAME'),
@@ -64,8 +61,7 @@ def main():
(db_configs, phone_to_pins),
queue=args.q
)
result = s_import_pins.apply_async()
logg.debug(f'TASK: {result.id}, STATUS: {result.status}')
s_import_pins.apply_async()
if __name__ == '__main__':

View File

@@ -1,33 +1,36 @@
# standard imports
import json
import logging
import os
import logging
import random
import urllib.error
import urllib.parse
import urllib.error
import urllib.request
import json
# external imports
import celery
import psycopg2
from psycopg2 import extras
from hexathon import (
strip_0x,
add_0x,
)
from chainlib.eth.address import to_checksum_address
from chainlib.eth.tx import (
unpack,
raw,
)
from cic_types.models.person import Person
unpack,
raw,
)
from cic_types.processor import generate_metadata_pointer
from hexathon import (
strip_0x,
add_0x,
)
from cic_types.models.person import Person
#logg = logging.getLogger().getChild(__name__)
logg = logging.getLogger()
celery_app = celery.current_app
class ImportTask(celery.Task):
balances = None
import_dir = 'out'
count = 0
@@ -35,16 +38,16 @@ class ImportTask(celery.Task):
balance_processor = None
max_retries = None
class MetadataTask(ImportTask):
meta_host = None
meta_port = None
meta_path = ''
meta_ssl = False
autoretry_for = (
urllib.error.HTTPError,
OSError,
)
urllib.error.HTTPError,
OSError,
)
retry_jitter = True
retry_backoff = True
retry_backoff_max = 60
@@ -61,12 +64,12 @@ class MetadataTask(ImportTask):
def old_address_from_phone(base_path, phone):
pidx = generate_metadata_pointer(phone.encode('utf-8'), ':cic.phone')
phone_idx_path = os.path.join('{}/phone/{}/{}/{}'.format(
base_path,
pidx[:2],
pidx[2:4],
pidx,
)
)
base_path,
pidx[:2],
pidx[2:4],
pidx,
)
)
f = open(phone_idx_path, 'r')
old_address = f.read()
f.close()
@@ -94,11 +97,11 @@ def generate_metadata(self, address, phone):
logg.debug('address {}'.format(address))
old_address_upper = strip_0x(old_address).upper()
metadata_path = '{}/old/{}/{}/{}.json'.format(
self.import_dir,
old_address_upper[:2],
old_address_upper[2:4],
old_address_upper,
)
self.import_dir,
old_address_upper[:2],
old_address_upper[2:4],
old_address_upper,
)
f = open(metadata_path, 'r')
o = json.load(f)
@@ -113,12 +116,12 @@ def generate_metadata(self, address, phone):
new_address_clean = strip_0x(address)
filepath = os.path.join(
self.import_dir,
'new',
new_address_clean[:2].upper(),
new_address_clean[2:4].upper(),
new_address_clean.upper() + '.json',
)
self.import_dir,
'new',
new_address_clean[:2].upper(),
new_address_clean[2:4].upper(),
new_address_clean.upper() + '.json',
)
os.makedirs(os.path.dirname(filepath), exist_ok=True)
o = u.serialize()
@@ -128,10 +131,10 @@ def generate_metadata(self, address, phone):
meta_key = generate_metadata_pointer(bytes.fromhex(new_address_clean), ':cic.person')
meta_filepath = os.path.join(
self.import_dir,
'meta',
'{}.json'.format(new_address_clean.upper()),
)
self.import_dir,
'meta',
'{}.json'.format(new_address_clean.upper()),
)
os.symlink(os.path.realpath(filepath), meta_filepath)
# write ussd data
@@ -177,8 +180,10 @@ def generate_metadata(self, address, phone):
@celery_app.task(bind=True, base=MetadataTask)
def opening_balance_tx(self, address, phone, serial):
old_address = old_address_from_phone(self.import_dir, phone)
old_address = old_address_from_phone(self.import_dir, phone)
k = to_checksum_address(strip_0x(old_address))
balance = self.balances[k]
logg.debug('found balance {} for address {} phone {}'.format(balance, old_address, phone))
@@ -191,39 +196,39 @@ def opening_balance_tx(self, address, phone, serial):
logg.debug('generated tx token value {} to {} tx hash {}'.format(decimal_balance, address, tx_hash_hex))
tx_path = os.path.join(
self.import_dir,
'txs',
strip_0x(tx_hash_hex),
)
self.import_dir,
'txs',
strip_0x(tx_hash_hex),
)
f = open(tx_path, 'w')
f.write(strip_0x(o))
f.close()
tx_nonce_path = os.path.join(
self.import_dir,
'txs',
'.' + str(tx['nonce']),
)
self.import_dir,
'txs',
'.' + str(tx['nonce']),
)
os.symlink(os.path.realpath(tx_path), tx_nonce_path)
return tx['hash']
@celery_app.task(bind=True, base=ImportTask, autoretry_for=(FileNotFoundError,), max_retries=None,
default_retry_delay=0.1)
@celery_app.task(bind=True, base=ImportTask, autoretry_for=(FileNotFoundError,), max_retries=None, default_retry_delay=0.1)
def send_txs(self, nonce):
if nonce == self.count + self.balance_processor.nonce_offset:
logg.info('reached nonce {} (offset {} + count {}) exiting'.format(nonce, self.balance_processor.nonce_offset,
self.count))
logg.info('reached nonce {} (offset {} + count {}) exiting'.format(nonce, self.balance_processor.nonce_offset, self.count))
return
logg.debug('attempt to open symlink for nonce {}'.format(nonce))
tx_nonce_path = os.path.join(
self.import_dir,
'txs',
'.' + str(nonce),
)
self.import_dir,
'txs',
'.' + str(nonce),
)
f = open(tx_nonce_path, 'r')
tx_signed_raw_hex = f.read()
f.close()
@@ -233,20 +238,21 @@ def send_txs(self, nonce):
o = raw(add_0x(tx_signed_raw_hex))
tx_hash_hex = self.balance_processor.conn.do(o)
logg.info('sent nonce {} tx hash {}'.format(nonce, tx_hash_hex)) # tx_signed_raw_hex))
logg.info('sent nonce {} tx hash {}'.format(nonce, tx_hash_hex)) #tx_signed_raw_hex))
nonce += 1
queue = self.request.delivery_info.get('routing_key')
s = celery.signature(
'import_task.send_txs',
[
nonce,
],
queue=queue,
)
'import_task.send_txs',
[
nonce,
],
queue=queue,
)
s.apply_async()
return nonce
@@ -304,3 +310,4 @@ def set_ussd_data(config: dict, ussd_data: dict):
# close connections
db_cursor.close()
db_conn.close()

View File

@@ -17,9 +17,6 @@ import redis
from chainlib.chain import ChainSpec
from cic_types.models.person import Person
# local imports
from import_util import get_celery_worker_status
logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger()
@@ -31,14 +28,11 @@ argparser.add_argument('-i', '--chain-spec', dest='i', type=str, help='Chain spe
argparser.add_argument('--redis-host', dest='redis_host', type=str, help='redis host to use for task submission')
argparser.add_argument('--redis-port', dest='redis_port', type=int, help='redis host to use for task submission')
argparser.add_argument('--redis-db', dest='redis_db', type=int, help='redis db to use for task submission and callback')
argparser.add_argument('--batch-size', dest='batch_size', default=100, type=int,
help='burst size of sending transactions to node') # batch size should be slightly below cumulative gas limit worth, eg 80000 gas txs with 8000000 limit is a bit less than 100 batch size
argparser.add_argument('--batch-size', dest='batch_size', default=100, type=int, help='burst size of sending transactions to node') # batch size should be slightly below cumulative gas limit worth, eg 80000 gas txs with 8000000 limit is a bit less than 100 batch size
argparser.add_argument('--batch-delay', dest='batch_delay', default=3, type=int, help='seconds delay between batches')
argparser.add_argument('--timeout', default=60.0, type=float, help='Callback timeout')
argparser.add_argument('--ussd-host', dest='ussd_host', type=str,
help="host to ussd app responsible for processing ussd requests.")
argparser.add_argument('--ussd-port', dest='ussd_port', type=str,
help="port to ussd app responsible for processing ussd requests.")
argparser.add_argument('--ussd-host', dest='ussd_host', type=str, help="host to ussd app responsible for processing ussd requests.")
argparser.add_argument('--ussd-port', dest='ussd_port', type=str, help="port to ussd app responsible for processing ussd requests.")
argparser.add_argument('--ussd-no-ssl', dest='ussd_no_ssl', help='do not use ssl (careful)', action='store_true')
argparser.add_argument('-q', type=str, default='cic-eth', help='Task queue')
argparser.add_argument('-v', action='store_true', help='Be verbose')
@@ -55,16 +49,13 @@ config_dir = args.c
config = confini.Config(config_dir, os.environ.get('CONFINI_ENV_PREFIX'))
config.process()
args_override = {
'CIC_CHAIN_SPEC': getattr(args, 'i'),
'REDIS_HOST': getattr(args, 'redis_host'),
'REDIS_PORT': getattr(args, 'redis_port'),
'REDIS_DB': getattr(args, 'redis_db'),
}
'CIC_CHAIN_SPEC': getattr(args, 'i'),
'REDIS_HOST': getattr(args, 'redis_host'),
'REDIS_PORT': getattr(args, 'redis_port'),
'REDIS_DB': getattr(args, 'redis_db'),
}
config.dict_override(args_override, 'cli')
logg.debug('config loaded from {}:\n{}'.format(args.c, config))
celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL'))
get_celery_worker_status(celery_app=celery_app)
redis_host = config.get('REDIS_HOST')
redis_port = config.get('REDIS_PORT')
@@ -74,22 +65,22 @@ r = redis.Redis(redis_host, redis_port, redis_db)
ps = r.pubsub()
user_new_dir = os.path.join(args.user_dir, 'new')
os.makedirs(user_new_dir, exist_ok=True)
os.makedirs(user_new_dir)
ussd_data_dir = os.path.join(args.user_dir, 'ussd')
os.makedirs(ussd_data_dir, exist_ok=True)
os.makedirs(ussd_data_dir)
preferences_dir = os.path.join(args.user_dir, 'preferences')
os.makedirs(os.path.join(preferences_dir, 'meta'), exist_ok=True)
os.makedirs(os.path.join(preferences_dir, 'meta'))
meta_dir = os.path.join(args.user_dir, 'meta')
os.makedirs(meta_dir, exist_ok=True)
os.makedirs(meta_dir)
user_old_dir = os.path.join(args.user_dir, 'old')
os.stat(user_old_dir)
txs_dir = os.path.join(args.user_dir, 'txs')
os.makedirs(txs_dir, exist_ok=True)
os.makedirs(txs_dir)
chain_spec = ChainSpec.from_chain_str(config.get('CIC_CHAIN_SPEC'))
chain_str = str(chain_spec)
@@ -104,7 +95,6 @@ if ussd_no_ssl is True:
else:
ussd_ssl = True
def build_ussd_request(phone, host, port, service_code, username, password, ssl=False):
url = 'http'
if ssl:
@@ -119,13 +109,13 @@ def build_ussd_request(phone, host, port, service_code, username, password, ssl=
session = uuid.uuid4().hex
data = {
'sessionId': session,
'serviceCode': service_code,
'phoneNumber': phone,
'text': service_code,
}
'sessionId': session,
'serviceCode': service_code,
'phoneNumber': phone,
'text': service_code,
}
req = urllib.request.Request(url)
req.method = 'POST'
req.method=('POST')
data_str = urlencode(data)
data_bytes = data_str.encode('utf-8')
req.add_header('Content-Type', 'application/x-www-form-urlencoded')
@@ -160,7 +150,7 @@ if __name__ == '__main__':
j = 0
for x in os.walk(user_old_dir):
for y in x[2]:
if y[len(y) - 5:] != '.json':
if y[len(y)-5:] != '.json':
continue
# handle json containing person object
filepath = os.path.join(x[0], y)
@@ -174,35 +164,35 @@ if __name__ == '__main__':
f.close()
u = Person.deserialize(o)
register_ussd(i, u)
new_address = register_ussd(i, u)
phone_object = phonenumbers.parse(u.tel)
phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164)
s_phone = celery.signature(
'import_task.resolve_phone',
[
phone,
],
queue='cic-import-ussd',
)
'import_task.resolve_phone',
[
phone,
],
queue='cic-import-ussd',
)
s_meta = celery.signature(
'import_task.generate_metadata',
[
phone,
],
queue='cic-import-ussd',
)
'import_task.generate_metadata',
[
phone,
],
queue='cic-import-ussd',
)
s_balance = celery.signature(
'import_task.opening_balance_tx',
[
phone,
i,
],
queue='cic-import-ussd',
)
'import_task.opening_balance_tx',
[
phone,
i,
],
queue='cic-import-ussd',
)
s_meta.link(s_balance)
s_phone.link(s_meta)
@@ -216,3 +206,4 @@ if __name__ == '__main__':
if j == batch_size:
time.sleep(batch_delay)
j = 0

View File

@@ -2,16 +2,15 @@
import logging
# external imports
from eth_contract_registry import Registry
from eth_token_index import TokenUniqueSymbolIndex
from chainlib.eth.gas import OverrideGasOracle
from chainlib.eth.nonce import OverrideNonceOracle
from chainlib.eth.tx import (
count,
TxFormat,
)
from celery import Celery
from eth_contract_registry import Registry
from eth_erc20 import ERC20
from eth_token_index import TokenUniqueSymbolIndex
from chainlib.eth.tx import (
count,
TxFormat,
)
logg = logging.getLogger().getChild(__name__)
@@ -19,9 +18,10 @@ logg = logging.getLogger().getChild(__name__)
class BalanceProcessor:
def __init__(self, conn, chain_spec, registry_address, signer_address, signer):
self.chain_spec = chain_spec
self.conn = conn
# self.signer_address = signer_address
#self.signer_address = signer_address
self.registry_address = registry_address
self.token_index_address = None
@@ -35,6 +35,7 @@ class BalanceProcessor:
self.gas_oracle = OverrideGasOracle(conn=conn, limit=8000000)
self.value_multiplier = 1
def init(self, token_symbol):
# Get Token registry address
@@ -56,25 +57,16 @@ class BalanceProcessor:
n = tx_factory.parse_decimals(r)
self.value_multiplier = 10 ** n
def get_rpc_tx(self, recipient, value, i):
logg.debug('initiating nonce offset {} for recipient {}'.format(self.nonce_offset + i, recipient))
nonce_oracle = OverrideNonceOracle(self.signer_address, self.nonce_offset + i)
tx_factory = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=self.gas_oracle)
return tx_factory.transfer(self.token_address, self.signer_address, recipient, value,
tx_format=TxFormat.RLP_SIGNED)
# (tx_hash_hex, o) = tx_factory.transfer(self.token_address, self.signer_address, recipient, value)
# self.conn.do(o)
# return tx_hash_hex
return tx_factory.transfer(self.token_address, self.signer_address, recipient, value, tx_format=TxFormat.RLP_SIGNED)
#(tx_hash_hex, o) = tx_factory.transfer(self.token_address, self.signer_address, recipient, value)
#self.conn.do(o)
#return tx_hash_hex
def get_decimal_amount(self, value):
return value * self.value_multiplier
def get_celery_worker_status(celery_app: Celery):
inspector = celery_app.control.inspect()
availability = inspector.ping()
status = {
'availability': availability,
}
logg.debug(f'RUNNING WITH STATUS: {status}')
return status

View File

@@ -1,5 +1,5 @@
[pgp]
exports_dir = testdata/pgp
exports_dir = ../contract-migration/testdata/pgp
private_key_file = privatekeys_meta.asc
public_key_file = publickeys_meta.asc
passphrase = merman

View File

@@ -1,23 +1,20 @@
# syntax = docker/dockerfile:1.2
#FROM python:3.8.6-slim-buster as compile-image
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-5ab8bf45
WORKDIR /root
RUN mkdir -vp /usr/local/etc/cic
COPY data-seeding/package.json \
data-seeding/package-lock.json \
.
RUN --mount=type=cache,mode=0755,target=/root/node_modules npm install
RUN npm install
COPY data-seeding/requirements.txt .
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip pip install \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL -r requirements.txt
RUN pip install --extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL -r requirements.txt
COPY data-seeding/ .

View File

@@ -1,24 +0,0 @@
# syntax = docker/dockerfile:1.2
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-5ab8bf45
WORKDIR /root
RUN mkdir -vp /usr/local/etc/cic
COPY data-seeding/package.json \
data-seeding/package-lock.json \
.
RUN npm install
COPY data-seeding/requirements.txt .
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
RUN pip install \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL -r requirements.txt
COPY data-seeding/ .
ENTRYPOINT [ ]

View File

@@ -1,4 +1,5 @@
cic_base[full_graph]==0.1.3a3+build.4aa03607
sarafu-faucet==0.0.4a1
cic-eth[tools]==0.12.0a1
cic-eth==0.11.1a1
cic-types==0.1.0a13
crypto-dev-signer==0.4.14b6

View File

@@ -1,83 +0,0 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
=zMNq
-----END PGP PRIVATE KEY BLOCK-----

View File

@@ -1,41 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQGNBF/A0RkBDADH1+1rOKYVEdvrboR739wpNyj4QWIyrrhyFlT3fv+j2VlzD2xT
/AemWYA4MjhWAadCbvQyzNUZBPlp4yDQXQZkgmcrP2HupObDSfvU4kHTNYlWdB3z
I/PHkBEqBYpD4hV/MioF7ObYRUeq073527uyUQkPTGQO7870mQJm3ifAHk3Pa4rH
OobtOHzhCiUns5gNtmV8x8I+PaPiMaEGNQu1xhYLdcWUv7qAhDC18gSRKNIbUk+3
1mN6Hy6s/Mm+RBnrxUOMBcOAXFkEscZq3jZwAckeBEU4aVsOXWZWCCVEquzMKpAX
jxwW1L7sAqq4hHyNE5c/1nJIlnyoLFDnEO/XLtCX8rZ5kkrJUKhb/sysmzLMYu24
GtI9N6T1H+KvyrKq880xb86K32LjuVFd8/E25zjJaTDej47cjpjmIRagZVTCCsZX
iERpohgmmciEy7NxnkwTFGJnCnugcc8kQFTNdYADr+UjUrnDZXXHumlNAMEyAjqn
hpuFsWf/PaH5IzEAEQEAAbQcQWxpY2UgQ3J5cHQgPGFsaWNlQGFjbWUub3JnPokB
1AQTAQgAPhYhBLLKqKgQVuEZFX6ueErrhB1qaGknBQJfwNEZAhsDBQkDwmcABQsJ
CAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEErrhB1qaGkncPIMAKoIcZmltZpG1wL0
DtER3yo0G9xVmy93yRRwSpK/R0JdMSd9IgT336qh6cCsx02jCstR9Bz5coGOZYtz
r27YLceGHDlsS7RAiiMiQsq22A9aN4il7PIggudg251I+FMkGSUfYvBpcgFSJxgj
sMu71L65l5dT4AfFyHJ50N+6ilGzeo04ZF+pWNmXOn4G8M3xfeL+47eYuB1OL4J3
utvKsjfng8Z0wjtj647bdsMqiWGgmonShK+pJ2I84RbPwsoNR5HOqaJpfUNBJ3To
VyOennaFum/NgE6yGH1Y8NBejI1FMYkZwC0nBkUavq667FkQDIaa5yJwNTuiMoMk
R62Tx9iq3juNDfVrbG/FBZPCS2E+MXCFuyuCISZ392fVaf0Nx1sXIWEr9pmpNyUH
Hs0RDhEOKVZpOJsymXkfNncHF5NIym8BfN+S/slHXzqBxo3i/dLWuVA8NkRneuwk
qe1o8ImU/4NcQMyDyUZ6xvugPqhjpMaiRSjGlju6h6YDRB+bw7kBjQRfwNEZAQwA
3s/c1BI5CwbrHFs2lgaHaXrZsyqEvrXLLceMs8krn16Qxo7Y1xXV/I9v7AUcrQdY
ixtDs65/ptdgwFVJIQuMMKQK4EekaK4dmDXfb1p6/93mTx1JscDVCRVz6aq6ycFy
qcnh0a7tXQMbcz7AnbQPpo4oRuMhzCAWvXbhf/09njjl9BdeEYyke+j9M295xmzb
J0EFZhcKSob39YZHiHwphNIt78sC2rdOay+IbdHqM16IhGBesdOBoTdqOAJXndz4
vvVXveh7PhkQCi8zDJRZXoQGpgaaZKG67Qh/Z5fbzDKoB61Feaaat0neyEZAYFi8
aVGqzEhLwmb4iJg+FY9FwexGdZTzOFk3n4KKsZ6EYKjxMEokkTw4lgkjI/01DE+Z
KRCbw5XiZTvT15FQC+RVzkBom4NZhT5qorE15nWd6BbDCuZ1aiqxS6Sj7+Y7b/96
2Yjlw3vFPM2sRmeGVvRccEdEJyxV1bwJHJxV7g/z3Sgb+xracfByvRGKUzqTh9fH
ABEBAAGJAbwEGAEIACYWIQSyyqioEFbhGRV+rnhK64QdamhpJwUCX8DRGQIbDAUJ
A8JnAAAKCRBK64QdamhpJxjTC/9zUmjShP25NFuajn+99S9rav6IO4w/zBeb6HAL
x1XKaewhcuxl09t5PStaZRRqvYuQ8YO9bI+/nMzKrxhyUXf3wJe8h4USwkJ4/3Bu
fNdLAbGIlaBmXilaWz/d3E/9+One2HxJSU6OCMc4qwFYDo4pKq/aL/O63zKnXUrJ
O6En6HZWDJpX9cdQRhxk9QMkze7Rf3qU9ZPM+PXk6tR9PrjYiHDWcUDvRK/cNa3/
AT/lX2+67NoCDgwxd4i07lReiWA5Hms/IoJ93t3nNnMsHvc/tcq2dkA9iyBd4uR6
ZIkM6LQZ3OLzo70nzxK7R0InaPqFGjFL76Flx+OelFZIeFaLEbcmo6wqWChJAA1c
PN+QLoFN33sPHw/xdLnpLTzxUVes5iv2sGk3yDCK9rAvd1K+DLHhGwQ0O6p+zkHT
W7v26nTQpKoqfYpsEeBRmcHPq73+05rVUGP7DyCebARGxORbjiSr/ZbupN/B1dPe
xgjhMwawpFV3APdc0dOIvUdZAFQ=
=BKz+
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,83 +0,0 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
=qmcx
-----END PGP PRIVATE KEY BLOCK-----

View File

@@ -1,41 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
n0OSM7kpK5v6VPdtByaN6w==
=EmWr
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,83 +0,0 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
=B12U
-----END PGP PRIVATE KEY BLOCK-----

View File

@@ -1,41 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
32d1dwRCBUARSk9jwmwsycaIC9eupit1mLY=
=vg+T
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,241 +0,0 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
1VrzRbOS5ymseDJcjejtMxuCOuSTN9R5KuQ=
=VqO+
-----END PGP PRIVATE KEY BLOCK-----

View File

@@ -1,114 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
7qTmw0n71OJB0zWJVnQd8yPzx5ARKgWKQ+IVfzIqBezm2EVHqtO9+du7slEJD0xk
Du/O9JkCZt4nwB5Nz2uKxzqG7Th84QolJ7OYDbZlfMfCPj2j4jGhBjULtcYWC3XF
lL+6gIQwtfIEkSjSG1JPt9Zjeh8urPzJvkQZ68VDjAXDgFxZBLHGat42cAHJHgRF
OGlbDl1mVgglRKrszCqQF48cFtS+7AKquIR8jROXP9ZySJZ8qCxQ5xDv1y7Ql/K2
eZJKyVCoW/7MrJsyzGLtuBrSPTek9R/ir8qyqvPNMW/Oit9i47lRXfPxNuc4yWkw
3o+O3I6Y5iEWoGVUwgrGV4hEaaIYJpnIhMuzcZ5MExRiZwp7oHHPJEBUzXWAA6/l
I1K5w2V1x7ppTQDBMgI6p4abhbFn/z2h+SMxABEBAAG0HEFsaWNlIENyeXB0IDxh
bGljZUBhY21lLm9yZz6JAdQEEwEIAD4WIQSyyqioEFbhGRV+rnhK64QdamhpJwUC
X8DRGQIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRBK64Qdamhp
J3DyDACqCHGZpbWaRtcC9A7REd8qNBvcVZsvd8kUcEqSv0dCXTEnfSIE99+qoenA
rMdNowrLUfQc+XKBjmWLc69u2C3Hhhw5bEu0QIojIkLKttgPWjeIpezyIILnYNud
SPhTJBklH2LwaXIBUicYI7DLu9S+uZeXU+AHxchyedDfuopRs3qNOGRfqVjZlzp+
BvDN8X3i/uO3mLgdTi+Cd7rbyrI354PGdMI7Y+uO23bDKolhoJqJ0oSvqSdiPOEW
z8LKDUeRzqmiaX1DQSd06Fcjnp52hbpvzYBOshh9WPDQXoyNRTGJGcAtJwZFGr6u
uuxZEAyGmucicDU7ojKDJEetk8fYqt47jQ31a2xvxQWTwkthPjFwhbsrgiEmd/dn
1Wn9DcdbFyFhK/aZqTclBx7NEQ4RDilWaTibMpl5HzZ3BxeTSMpvAXzfkv7JR186
gcaN4v3S1rlQPDZEZ3rsJKntaPCJlP+DXEDMg8lGesb7oD6oY6TGokUoxpY7uoem
A0Qfm8O5AY0EX8DRGQEMAN7P3NQSOQsG6xxbNpYGh2l62bMqhL61yy3HjLPJK59e
kMaO2NcV1fyPb+wFHK0HWIsbQ7Ouf6bXYMBVSSELjDCkCuBHpGiuHZg1329aev/d
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
wmwsycaIC9eupit1mLY=
=1aEW
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,151 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
KuNFGWsKI1qTd1aEMRQzT4s+JJM=
=8257
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,29 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIE4DCCAsgCAQMwDQYJKoZIhvcNAQELBQAwgaExCzAJBgNVBAYTAktZMQ8wDQYD
VQQIDAZLaWxpZmkxEDAOBgNVBAcMB01uYXJhbmkxHTAbBgNVBAoMFEdyYXNzcm9v
dHMgRWNvbm9taWNzMQswCQYDVQQLDAJIUTEgMB4GA1UEAwwXZ3Jhc3Nyb290c2Vj
b25vbWljcy5vcmcxITAfBgkqhkiG9w0BCQEWEndpbGxAZ3Jhc3NlY29uLm9yZzAe
Fw0yMDAzMjgwMDE3MzRaFw0yMjEyMjQwMDE3MzRaMIHJMQswCQYDVQQGEwJNTjEU
MBIGA1UECgwLVGhlIE1vbmdvbHMxGzAZBgNVBAMMEnd3dy51bGFhbmJhYXRhci5t
bjEVMBMGA1UEKQwMS2h1YmxhaSBLaGFuMR8wHQYJKoZIhvcNAQkBFhBmb29Ac2Vj
aG9zdC5pbmZvMRAwDgYDVQQqDAdLaHVibGFpMQ0wCwYDVQQEDARLaGFuMRQwEgYD
VQQHDAtVbGFhbmJhYXRhcjEYMBYGA1UECAwPVGhlIFdob2xlIFdvcmxkMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtT1IP3Ls0ha5cX5RiMnyjPzjGjvS
GrWhDU579+qQ4T4k9ONq8fxNv95ZdxkccUyXZVR24pq+ALxmV65soCAGNJHb00lE
XWY3mQ9Jd10pC8UQPqfQ4Ez/J0Q+oIwpTdUCQStIe8QHz6sh8AVmPrTKWphjD5Up
PuWjFz4qs6h46hzNDoc90HPr4rqnxzBIo4Phs4a8/46FWvphufybKgorz+B5uWeB
Uzi3fOOKNAk8UmZK8fWB8DMIm8NFcOZV7METJmMBH1v5sY6zQWNBOHJmin02VkCW
rie16Ll+vfWp1jQEh442qgBFk0NiZBoGWJamYa7RmwH5d4LPGLiDUVgsnwIDAQAB
MA0GCSqGSIb3DQEBCwUAA4ICAQBy0DIHBXVDPy4dTrmjcr78ytxy26p+8kjlzTQF
w9a9F+CPsRNV4KAmXJKUlyBTPiVocVhhSmj2Mz9OtI9FFWkSleKzxUtWlDEjIwGj
PRqWKhj/Y8LJsgdcUGCBtraBMCD5D1xyNx3n+zwhNp+HNB4ThVlV0iGCoOOq7XZu
4QHwkuy0ILcXt3NU6tWNXXsP544BxsCFHgyu+Ks+JkJzSFzGe+ybEMblXyHJZtOC
uyCLQN2Uo44Mtdo728p00mRGSFlouFfQWMu/7lQPNYouQ7XiLXy+mNeNN0CYUjpg
a7wfPExMljJEkgYyWT4JMuTB5RTsjQqw41aGtfy021L7yCZnVR2GG3pmeRQtqe4r
+V+WHV3YOkW5vObd5RE3ykntFkbrZNodBzxp6qKF4qsfqQH6WJFVXh0b36VmOdSa
qWxidz+SeCI379nemy93bcusQxRDXc+j5hbpW2pTtz2uxN5Y86DWEdSjpmiu6ExT
eBUyoK/5Zes/oZ3R9vj0V9jhpGN1/FahkXfkjZcuwXXFXuwk8rODU9DKGOEqFPKI
P/MZSVkfNvkBhiNozBXx1X/vJ2QoQKqE9zPfXlmvZkLiUaMjqd+h3qRe0vqXlQU+
ZH8NrKTi5xS/2VGtz4ksGlQp7GMZ0XFWL23BGhUfQVRLKMPCqta+GTuJUo3r5HVL
YiI4dw==
-----END CERTIFICATE-----

View File

@@ -1,30 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,A748148F1C16F6129F04A346A324170A
k5K2EMTBDsaa9LqsnWnDV2Ocd14fZ6lXsNBoPZR1axrOV+zNZtDDIQwFP0FHmTN6
KrxDuDvPjkhoebMiLkRyWc6d4fslWQnr3vASi8gONYGT3pXKbuPNEMSXJeRfxvzC
CAcSh9rItcVxKv7m8+vuUWUy8m6TGBLRpDwiYf/9KTjGaPO2fnDBLHPlBuHVEmQW
xa0MOknleWnMucGMAtNdsiOVULgyljnoexgbES0VAosegnCKaRA5mRt47V0XUFDl
cFxXsHlZ4Wo4R9BowkWhpxX+IBVBmr1Rbmhkl8Z/k3SWfmAd2PNqHckl4oZsG0NN
kfi/x5RvMFXGwfW0q5XK/4oK1KbxV7UTn/lozkyvixSWDrN+2jETNCJyL//oXUcS
ZTr1+qic92fAAonx1JkX1QwQlNTb0ogmgpJzvAKqGqlNpSL3D0xySNTsSM0fEeZV
1qEnWTp1WpoyxG1CeiV0MDN9wkh9aV+KYm0FFo8PEqG6L1jsVNJKMtySeCXmWETK
S6iUBwiNf8atQwERfWx0wqSwHtJs9+zqUasskqYWJcO9T3TGqdc8UBaeVGAGdWFF
soGsBqrVyU8TEAuK6UReJyFQtHqXbm7kFIJ8J6fgc/QG4Dhy4laBKpR5Lg1W3fCa
g+o4OvkWr0Mvu0/y528qL0cqb3JoxvAtsZ8cHiiy1g3AiSr9ehlvtVboyg1ViP5d
cZZyU0NaeEUYOIULeBap4LNUBPQUSN5lw15C7N/reI8uuTNp8u8/6ITXKH3tknJr
n6Jhd6uFuYNImRhHgQ5rKgai5+Nhc6RqdO5K05fVMt8wIng5RkShQzQEZtaynWyg
3VbmJrKXjYesMxYFuKYP4efEVH/9tUeHiqlgVBF2N2Ntd4vKYied3mllthAo8BVC
0S0A+cZ2K65MKSoh/FHxxqfXo3AF6dL58DC+9jnzhKNgErVSTti0/Ps6pxrloNuN
ILUVeUQNhVlZu7KpJHININCnicohj8wAJDVZo7bb3iZfRGDIAFfgKuEALk+CRd0H
D6PukualFGd9w+KDLmUVdpkUTq9+UaZcJMXqGAN1ihIz44Xvk4QgFRN+9Szz4HbL
j5rTNqRmXjWjPahk90D/cOQuuE81GsVdiLnFzEacAlDGoGgV+Wcr/lQ06H099Hz1
v9hSwXoI+EbeQTjoqenQV62V7wuOiAKg3SpekGsYAsuuPElCBwYGTzWvotf9BBFe
LxhfVTCXD1cOQo3pgC8nHBwQSJ6TEXMrR52lgIkOZq/EPhPAYyO5A6ab2tKD1Zah
7qlkDDov7f4eTJrXfPnOu/tl3voN+VOxVbxFqsJuMPRCDc/DI18mOi+4yeUFK22W
pOCa+Etv7tGa3KlOuU/VWQfGTsICC8ejCIBgwmcbJ5HndEtzrPQv0ESziIcy/ybr
zkmlKJ7n7MZLNx/if5Ly9rxg+Y1al5JkOWpIqGKIhP075M2H9Kcg08TqHY6YoG5w
eJuudcyosGggxo/oTCCPrHNnPSvaauaZRynF02AQ1hle83V7T1Sy0jbtoGRXM7Hq
7AyQDLAcCregAkUuCMF/pktcJLQ2rY738RzNyaR3OiaTgKjko553QkciLP28qwZh
-----END RSA PRIVATE KEY-----

View File

@@ -1,35 +0,0 @@
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----

View File

@@ -254,10 +254,6 @@ class Verifier:
if len(k) > 7 and k[:7] == 'verify_':
logg.debug('verifier has verify method {}'.format(k))
verifymethods.append(k[7:])
o = self.faucet_tx_factory.token_amount(self.faucet_address, sender_address=ZERO_ADDRESS)
r = self.conn.do(o)
self.faucet_amount = self.faucet_tx_factory.parse_token_amount(r)
logg.info('faucet amount set to {} at verify initialization time'.format(self.faucet_amount))
self.state = VerifierState(verifymethods, active_tests=active_tests)
@@ -288,7 +284,6 @@ class Verifier:
except ValueError:
actual_balance = int(r)
balance = int(balance / 1000000) * 1000000
balance += self.faucet_amount
logg.debug('balance for {}: {}'.format(address, balance))
if balance != actual_balance:
raise VerifierError((actual_balance, balance), 'balance')

View File

@@ -1 +1 @@
cic-base==0.1.3a3+build.984b5cff
cic-base==0.1.3a3+build.4aa03607

View File

@@ -9,18 +9,13 @@ fi
t=$(mktemp)
>&2 echo using tmp $t
repos=(../../cic-cache ../../cic-eth ../../cic-ussd ../../data-seeding ../../cic-notify ../../contract-migration)
repos=(../../cic-cache ../../cic-eth ../../cic-ussd ../../data-seeding ../../cic-notify)
for r in ${repos[@]}; do
f="$r/requirements.txt"
>&2 echo updating $f
pyreq-update $f base_requirement.txt -v > $t
cp $t $f
f="$r/test_requirements.txt"
if [ -f $f ]; then
>&2 echo updating $f
pyreq-update $f base_requirement.txt -v > $t
cp $t $f
fi
>&2 echo updating $f
pyreq-update $f base_requirement.txt > $t
cp $t $f
done

View File

@@ -21,12 +21,14 @@ variables:
.py_build_target_test:
stage: build
variables:
IMAGE_TAG_BASE: $CI_REGISTRY_IMAGE/$APP_NAME:mr-unittest-$CI_COMMIT_SHORT_SHA
CI_DEBUG_TRACE: "true"
script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > "/kaniko/.docker/config.json"
- /kaniko/executor --context $CONTEXT --dockerfile $DOCKERFILE_PATH $KANIKO_CACHE_ARGS --cache-repo $CI_REGISTRY_IMAGE --target test --destination $IMAGE_TAG_BASE
- /kaniko/executor --context $CONTEXT --dockerfile $DOCKERFILE_PATH $KANIKO_CACHE_ARGS --cache-repo $CI_REGISTRY_IMAGE --target test --tarPath $APP_NAME-test-image.tar --destination $CI_REGISTRY_IMAGE/$APP_NAME-test:latest
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: always
.py_build_push:
stage: build

View File

@@ -72,11 +72,11 @@ services:
contract-migration:
build:
dockerfile: contract-migration/docker/Dockerfile
args:
pip_index_url: ${PIP_DEFAULT_INDEX_URL:-https://pypi.org/simple}
pip_extra_args: $PIP_EXTRA_ARGS
context: apps/
dockerfile: contract-migration/docker/Dockerfile
# image: registry.gitlab.com/grassrootseconomics/cic-internal-integration/contract-migration:latest
environment:
# ETH_PROVIDER should be broken out into host/port but cic-eth expects this
@@ -101,16 +101,9 @@ services:
DEV_PIP_EXTRA_INDEX_URL: ${DEV_PIP_EXTRA_INDEX_URL:-https://pip.grassrootseconomics.net:8433}
RUN_MASK: ${RUN_MASK:-0} # bit flags; 1: contract migrations 2: seed data
DEV_FAUCET_AMOUNT: ${DEV_FAUCET_AMOUNT:-0}
#DEV_SARAFU_DEMURRAGE_LEVEL: ${DEV_SARAFU_DEMURRAGE_LEVEL:-196454828847045000000000000000000}
DEV_ETH_GAS_PRICE: ${DEV_ETH_GAS_PRICE:-1}
CIC_DEFAULT_TOKEN_SYMBOL: ${CIC_DEFAULT_TOKEN_SYMBOL:-GFT}
TOKEN_NAME: $TOKEN_NAME
TOKEN_DECIMALS: $TOKEN_DECIMALS
TOKEN_REDISTRIBUTION_PERIOD: $TOKEN_REDISTRIBUTION_PERIOD
TOKEN_SUPPLY_LIMIT: $TOKEN_SUPPLY_LIMIT
TOKEN_DEMURRAGE_LEVEL: ${TOKEN_DEMURRAGE_LEVEL:-196454828847045000000000000000000}
TOKEN_SINK_ADDRESS: $TOKEN_SINK_ADDRESS
#CONFINI_DIR: ${CONFINI_DIR:-/tmp/cic/config}
DEV_SARAFU_DEMURRAGE_LEVEL: ${DEV_SARAFU_DEMURRAGE_LEVEL:-196454828847045000000000000000000}
DEV_ETH_GAS_PRICE: ${DEV_ETH_GAS_PRICE:-1}
command: ["./run_job.sh"]
#command: ["./reset.sh"]
depends_on: