Compare commits
72 Commits
lash/impro
...
bvander/ci
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14850d06dd
|
||
|
|
1e602e1352
|
||
|
|
167ff0f5e4
|
||
|
|
e166a6737f
|
||
|
|
31d700efe3
|
||
| ffd989e7da | |||
| 991d13b9c2 | |||
| 480ed5b119 | |||
|
|
021c736707 | ||
|
|
e3028a5060 | ||
|
|
fdf7a3a503
|
||
|
|
e3079c3930
|
||
| e6fa450a2a | |||
| 9a7ccc3228 | |||
| 7fc99afe1b | |||
| 5a55d76faf | |||
| 74eb5df1bb | |||
| d9b25c1063 | |||
| 319e587f29 | |||
| 1bfc736513 | |||
| 80d7693532 | |||
| 2f36e3496e | |||
| de00762c2c | |||
| a71ef0a388 | |||
| 23cf75a4c9 | |||
| de36fe3fab | |||
| deeba250e4 | |||
| 5668ed1cf5 | |||
| 8b7a26abb9 | |||
|
|
5f6c57647f | ||
|
|
ed029a936c | ||
|
|
c559bb2fee | ||
|
|
9b79034ed3 | ||
| e40f15d106 | |||
| b94116a683 | |||
| 635ef775df | |||
| c35e230e9f | |||
| 0c842cf5d7 | |||
| e8f65dcd29 | |||
| d679a8441e | |||
| 58f3a90206 | |||
| 3256f23121 | |||
| 8cdd405122 | |||
| db4eb31de0 | |||
| 0fa7b99a15 | |||
| b3b051d3d5 | |||
| b86b57bcb7 | |||
| 4ecf4f1214 | |||
| e3da256e66 | |||
| c8e24c96c5 | |||
| ecc5d26666 | |||
| 304550c2ae | |||
| 93f0353808 | |||
| 2e6e80e134 | |||
| bc868fd2c8 | |||
| 0b3b1ef459 | |||
| f72d577b8c | |||
| 068d1112d2 | |||
| 460a7c223b | |||
| dd3ddfd41d | |||
| 8a6a2fd008 | |||
| 3fca9a6744 | |||
| b7d5c6799f | |||
| eef8bb2cf7 | |||
| cf96fee430 | |||
| 9740963431 | |||
|
|
a3c4932488 | ||
|
|
aa667951be | ||
|
|
c2459cfd65 | ||
|
|
e7102ff02d | ||
| a942c785f6 | |||
| 70704b09ec |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,3 +13,4 @@ build/
|
||||
**/coverage
|
||||
**/.venv
|
||||
.idea
|
||||
**/.vim
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
omit =
|
||||
.venv/*
|
||||
scripts/*
|
||||
cic_cache/db/postgres/*
|
||||
cic_cache/db/migrations/*
|
||||
cic_cache/version.py
|
||||
|
||||
4
apps/cic-cache/.dockerignore
Normal file
4
apps/cic-cache/.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
.git
|
||||
.cache
|
||||
.dot
|
||||
**/doc
|
||||
@@ -1,22 +1,52 @@
|
||||
.cic_cache_variables:
|
||||
variables:
|
||||
APP_NAME: cic-cache
|
||||
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
|
||||
|
||||
.cic_cache_changes_target:
|
||||
rules:
|
||||
- changes:
|
||||
- $CONTEXT/$APP_NAME/*
|
||||
DOCKERFILE_PATH: docker/Dockerfile_ci
|
||||
CONTEXT: apps/$APP_NAME
|
||||
|
||||
build-mr-cic-cache:
|
||||
extends:
|
||||
- .cic_cache_changes_target
|
||||
- .py_build_merge_request
|
||||
- .cic_cache_variables
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/cic-cache/**/*
|
||||
when: always
|
||||
|
||||
test-mr-cic-cache:
|
||||
stage: test
|
||||
extends:
|
||||
- .cic_cache_variables
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- test_requirements.txt
|
||||
paths:
|
||||
- /root/.cache/pip
|
||||
image: $MR_IMAGE_TAG
|
||||
script:
|
||||
- cd apps/$APP_NAME/
|
||||
- >
|
||||
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
|
||||
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
|
||||
-r test_requirements.txt
|
||||
- export PYTHONPATH=. && pytest -x --cov=cic_cache --cov-fail-under=90 --cov-report term-missing tests
|
||||
needs: ["build-mr-cic-cache"]
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/cic-eth/**/*
|
||||
when: always
|
||||
|
||||
build-push-cic-cache:
|
||||
extends:
|
||||
- .py_build_push
|
||||
- .cic_cache_variables
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "master"
|
||||
changes:
|
||||
- apps/cic-cache/**/*
|
||||
when: always
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ from cic_cache.db.list import (
|
||||
logg = logging.getLogger()
|
||||
|
||||
|
||||
DEFAULT_FILTER_SIZE = 8192 * 8
|
||||
|
||||
class Cache:
|
||||
|
||||
def __init__(self, session):
|
||||
@@ -25,7 +27,7 @@ class BloomCache(Cache):
|
||||
|
||||
@staticmethod
|
||||
def __get_filter_size(n):
|
||||
n = 8192 * 8
|
||||
n = DEFAULT_FILTER_SIZE
|
||||
logg.warning('filter size hardcoded to {}'.format(n))
|
||||
return n
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ import json
|
||||
import re
|
||||
import base64
|
||||
|
||||
# external imports
|
||||
from hexathon import add_0x
|
||||
|
||||
# local imports
|
||||
from cic_cache.cache import (
|
||||
BloomCache,
|
||||
@@ -11,10 +14,11 @@ from cic_cache.cache import (
|
||||
)
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
#logg = logging.getLogger()
|
||||
|
||||
re_transactions_all_bloom = r'/tx/(\d+)?/?(\d+)/?'
|
||||
re_transactions_account_bloom = r'/tx/user/((0x)?[a-fA-F0-9]+)/?(\d+)?/?(\d+)/?'
|
||||
re_transactions_all_data = r'/txa/(\d+)/(\d+)/?'
|
||||
re_transactions_account_bloom = r'/tx/user/((0x)?[a-fA-F0-9]+)(/(\d+)(/(\d+))?)?/?'
|
||||
re_transactions_all_data = r'/txa/(\d+)?/?(\d+)/?'
|
||||
|
||||
DEFAULT_LIMIT = 100
|
||||
|
||||
@@ -26,13 +30,13 @@ def process_transactions_account_bloom(session, env):
|
||||
|
||||
address = r[1]
|
||||
if r[2] == None:
|
||||
address = '0x' + address
|
||||
offset = DEFAULT_LIMIT
|
||||
address = add_0x(address)
|
||||
offset = 0
|
||||
if r.lastindex > 2:
|
||||
offset = r[3]
|
||||
limit = 0
|
||||
if r.lastindex > 3:
|
||||
limit = r[4]
|
||||
offset = r[4]
|
||||
limit = DEFAULT_LIMIT
|
||||
if r.lastindex > 4:
|
||||
limit = r[6]
|
||||
|
||||
c = BloomCache(session)
|
||||
(lowest_block, highest_block, bloom_filter_block, bloom_filter_tx) = c.load_transactions_account(address, offset, limit)
|
||||
|
||||
@@ -1,52 +1,38 @@
|
||||
FROM python:3.8.6-slim-buster
|
||||
# syntax = docker/dockerfile:1.2
|
||||
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
|
||||
|
||||
# RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2b9
|
||||
|
||||
#COPY --from=0 /usr/local/share/cic/solidity/ /usr/local/share/cic/solidity/
|
||||
COPY requirements.txt .
|
||||
#RUN pip install $pip_extra_index_url_flag -r test_requirements.txt
|
||||
#RUN pip install $pip_extra_index_url_flag .
|
||||
#RUN pip install .[server]
|
||||
|
||||
WORKDIR /usr/src/cic-cache
|
||||
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 --index-url https://pypi.org/simple \
|
||||
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
|
||||
-r requirements.txt
|
||||
|
||||
ARG pip_extra_index_url_flag='--index https://pypi.org/simple --extra-index-url https://pip.grassrootseconomics.net:8433'
|
||||
ARG root_requirement_file='requirements.txt'
|
||||
COPY . .
|
||||
|
||||
#RUN apk update && \
|
||||
# apk add gcc musl-dev gnupg libpq
|
||||
#RUN apk add postgresql-dev
|
||||
#RUN apk add linux-headers
|
||||
#RUN apk add libffi-dev
|
||||
RUN apt-get update && \
|
||||
apt install -y gcc gnupg libpq-dev wget make g++ gnupg bash procps git
|
||||
|
||||
# Copy shared requirements from top of mono-repo
|
||||
RUN echo "copying root req file ${root_requirement_file}"
|
||||
RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2b9
|
||||
|
||||
COPY cic-cache/requirements.txt ./
|
||||
COPY cic-cache/setup.cfg \
|
||||
cic-cache/setup.py \
|
||||
./
|
||||
COPY cic-cache/cic_cache/ ./cic_cache/
|
||||
COPY cic-cache/scripts/ ./scripts/
|
||||
COPY cic-cache/test_requirements.txt ./
|
||||
RUN pip install $pip_extra_index_url_flag -r test_requirements.txt
|
||||
RUN pip install $pip_extra_index_url_flag .
|
||||
RUN pip install .[server]
|
||||
|
||||
COPY cic-cache/tests/ ./tests/
|
||||
#COPY db/ cic-cache/db
|
||||
#RUN apk add postgresql-client
|
||||
RUN python setup.py install
|
||||
|
||||
# ini files in config directory defines the configurable parameters for the application
|
||||
# they can all be overridden by environment variables
|
||||
# to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
|
||||
COPY cic-cache/config/ /usr/local/etc/cic-cache/
|
||||
COPY config/ /usr/local/etc/cic-cache/
|
||||
|
||||
# for db migrations
|
||||
RUN git clone https://github.com/vishnubob/wait-for-it.git /usr/local/bin/wait-for-it/
|
||||
COPY cic-cache/cic_cache/db/migrations/ /usr/local/share/cic-cache/alembic/
|
||||
COPY cic_cache/db/migrations/ /usr/local/share/cic-cache/alembic/
|
||||
|
||||
COPY cic-cache/docker/start_tracker.sh ./start_tracker.sh
|
||||
COPY cic-cache/docker/db.sh ./db.sh
|
||||
COPY /docker/start_tracker.sh ./start_tracker.sh
|
||||
COPY /docker/db.sh ./db.sh
|
||||
RUN chmod 755 ./*.sh
|
||||
# Tracker
|
||||
# ENTRYPOINT ["/usr/local/bin/cic-cache-tracker", "-vv"]
|
||||
# Server
|
||||
# ENTRYPOINT [ "/usr/local/bin/uwsgi", "--wsgi-file", "/usr/local/lib/python3.8/site-packages/cic_cache/runnable/server.py", "--http", ":80", "--pyargv", "-vv" ]
|
||||
ENTRYPOINT []
|
||||
|
||||
37
apps/cic-cache/docker/Dockerfile_ci
Normal file
37
apps/cic-cache/docker/Dockerfile_ci
Normal file
@@ -0,0 +1,37 @@
|
||||
# syntax = docker/dockerfile:1.2
|
||||
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
|
||||
|
||||
# RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2b9
|
||||
|
||||
COPY requirements.txt .
|
||||
#RUN pip install $pip_extra_index_url_flag -r test_requirements.txt
|
||||
#RUN pip install $pip_extra_index_url_flag .
|
||||
#RUN pip install .[server]
|
||||
|
||||
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
|
||||
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
|
||||
RUN pip install --index-url https://pypi.org/simple \
|
||||
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
|
||||
-r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN python setup.py install
|
||||
|
||||
# ini files in config directory defines the configurable parameters for the application
|
||||
# they can all be overridden by environment variables
|
||||
# to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
|
||||
COPY config/ /usr/local/etc/cic-cache/
|
||||
|
||||
# for db migrations
|
||||
RUN git clone https://github.com/vishnubob/wait-for-it.git /usr/local/bin/wait-for-it/
|
||||
COPY cic_cache/db/migrations/ /usr/local/share/cic-cache/alembic/
|
||||
|
||||
COPY /docker/start_tracker.sh ./start_tracker.sh
|
||||
COPY /docker/db.sh ./db.sh
|
||||
RUN chmod 755 ./*.sh
|
||||
# Tracker
|
||||
# ENTRYPOINT ["/usr/local/bin/cic-cache-tracker", "-vv"]
|
||||
# Server
|
||||
# ENTRYPOINT [ "/usr/local/bin/uwsgi", "--wsgi-file", "/usr/local/lib/python3.8/site-packages/cic_cache/runnable/server.py", "--http", ":80", "--pyargv", "-vv" ]
|
||||
ENTRYPOINT []
|
||||
@@ -5,9 +5,12 @@ import datetime
|
||||
|
||||
# external imports
|
||||
import pytest
|
||||
import moolb
|
||||
|
||||
# local imports
|
||||
from cic_cache import db
|
||||
from cic_cache import BloomCache
|
||||
from cic_cache.cache import DEFAULT_FILTER_SIZE
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = os.path.dirname(script_dir)
|
||||
@@ -101,3 +104,7 @@ def tag_txs(
|
||||
|
||||
db.tag_transaction(init_database, txs[1], 'taag', domain='test')
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def zero_filter():
|
||||
return moolb.Bloom(DEFAULT_FILTER_SIZE, 3)
|
||||
|
||||
@@ -10,6 +10,7 @@ from sqlalchemy import text
|
||||
from chainlib.eth.tx import Tx
|
||||
from chainlib.eth.block import Block
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.eth.error import RequestMismatchException
|
||||
from hexathon import (
|
||||
strip_0x,
|
||||
add_0x,
|
||||
@@ -18,10 +19,21 @@ from hexathon import (
|
||||
# local imports
|
||||
from cic_cache.db import add_tag
|
||||
from cic_cache.runnable.daemons.filters.erc20 import ERC20TransferFilter
|
||||
from cic_cache.runnable.daemons.filters.base import TagSyncFilter
|
||||
|
||||
logg = logging.getLogger()
|
||||
|
||||
|
||||
def test_base_filter_str(
|
||||
init_database,
|
||||
):
|
||||
f = TagSyncFilter('foo')
|
||||
assert 'foo' == str(f)
|
||||
f = TagSyncFilter('foo', domain='bar')
|
||||
assert 'bar.foo' == str(f)
|
||||
|
||||
|
||||
|
||||
def test_erc20_filter(
|
||||
eth_rpc,
|
||||
foo_token,
|
||||
@@ -67,3 +79,95 @@ def test_erc20_filter(
|
||||
s = text("SELECT x.tx_hash FROM tag a INNER JOIN tag_tx_link l ON l.tag_id = a.id INNER JOIN tx x ON x.id = l.tx_id WHERE a.domain = :a AND a.value = :b")
|
||||
r = init_database.execute(s, {'a': fltr.tag_domain, 'b': fltr.tag_name}).fetchone()
|
||||
assert r[0] == tx.hash
|
||||
|
||||
|
||||
def test_erc20_filter_nocontract(
|
||||
eth_rpc,
|
||||
foo_token,
|
||||
init_database,
|
||||
list_defaults,
|
||||
list_actors,
|
||||
tags,
|
||||
):
|
||||
|
||||
chain_spec = ChainSpec('foo', 'bar', 42, 'baz')
|
||||
|
||||
fltr = ERC20TransferFilter(chain_spec)
|
||||
add_tag(init_database, fltr.tag_name, domain=fltr.tag_domain)
|
||||
|
||||
# incomplete args
|
||||
data = 'a9059cbb'
|
||||
data += strip_0x(list_actors['alice'])
|
||||
data += '1000'.ljust(64, '0')
|
||||
block = Block({
|
||||
'hash': os.urandom(32).hex(),
|
||||
'number': 42,
|
||||
'timestamp': datetime.datetime.utcnow().timestamp(),
|
||||
'transactions': [],
|
||||
})
|
||||
|
||||
tx = Tx({
|
||||
'to': os.urandom(20).hex(),
|
||||
'from': list_actors['bob'],
|
||||
'data': data,
|
||||
'value': 0,
|
||||
'hash': os.urandom(32).hex(),
|
||||
'nonce': 13,
|
||||
'gasPrice': 10000000,
|
||||
'gas': 123456,
|
||||
})
|
||||
block.txs.append(tx)
|
||||
tx.block = block
|
||||
|
||||
assert not fltr.filter(eth_rpc, block, tx, db_session=init_database)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'contract_method,contract_input,expected_exception',
|
||||
[
|
||||
('a9059cbb', os.urandom(32).hex(), ValueError), # not enough args
|
||||
('a9059cbb', os.urandom(31).hex(), ValueError), # wrong arg boundary
|
||||
('a9059cbc', os.urandom(64).hex(), RequestMismatchException), # wrong method
|
||||
],
|
||||
)
|
||||
def test_erc20_filter_bogus(
|
||||
eth_rpc,
|
||||
foo_token,
|
||||
init_database,
|
||||
list_defaults,
|
||||
list_actors,
|
||||
tags,
|
||||
contract_method,
|
||||
contract_input,
|
||||
expected_exception,
|
||||
):
|
||||
|
||||
chain_spec = ChainSpec('foo', 'bar', 42, 'baz')
|
||||
|
||||
fltr = ERC20TransferFilter(chain_spec)
|
||||
add_tag(init_database, fltr.tag_name, domain=fltr.tag_domain)
|
||||
|
||||
# incomplete args
|
||||
data = contract_method
|
||||
data += contract_input
|
||||
block = Block({
|
||||
'hash': os.urandom(32).hex(),
|
||||
'number': 42,
|
||||
'timestamp': datetime.datetime.utcnow().timestamp(),
|
||||
'transactions': [],
|
||||
})
|
||||
|
||||
tx = Tx({
|
||||
'to': foo_token,
|
||||
'from': list_actors['bob'],
|
||||
'data': data,
|
||||
'value': 0,
|
||||
'hash': os.urandom(32).hex(),
|
||||
'nonce': 13,
|
||||
'gasPrice': 10000000,
|
||||
'gas': 123456,
|
||||
})
|
||||
block.txs.append(tx)
|
||||
tx.block = block
|
||||
|
||||
assert not fltr.filter(eth_rpc, block, tx, db_session=init_database)
|
||||
|
||||
230
apps/cic-cache/tests/test_query.py
Normal file
230
apps/cic-cache/tests/test_query.py
Normal file
@@ -0,0 +1,230 @@
|
||||
# standard imports
|
||||
import logging
|
||||
import json
|
||||
import base64
|
||||
import copy
|
||||
import re
|
||||
|
||||
# external imports
|
||||
import pytest
|
||||
from hexathon import strip_0x
|
||||
|
||||
# local imports
|
||||
from cic_cache.runnable.daemons.query import *
|
||||
|
||||
logg = logging.getLogger()
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'query_path_prefix, query_role, query_address_index, query_offset, query_offset_index, query_limit, query_limit_index, match_re',
|
||||
[
|
||||
('/tx/user/', 'alice', 0, None, 3, None, 5, re_transactions_account_bloom),
|
||||
('/tx/user/', 'alice', 0, 42, 3, None, 5, re_transactions_account_bloom),
|
||||
('/tx/user/', 'alice', 0, 42, 3, 13, 5, re_transactions_account_bloom),
|
||||
('/tx/', None, 0, None, 3, None, 5, re_transactions_all_bloom),
|
||||
('/tx/', None, 0, 42, 3, None, 5, re_transactions_all_bloom),
|
||||
('/tx/', None, 0, 42, 3, 13, 5, re_transactions_all_bloom),
|
||||
('/txa/', None, 0, None, 3, None, 5, re_transactions_all_data),
|
||||
('/txa/', None, 0, 42, 3, None, 5, re_transactions_all_data),
|
||||
('/txa/', None, 0, 42, 3, 13, 5, re_transactions_all_data),
|
||||
],
|
||||
)
|
||||
def test_query_regex(
|
||||
list_actors,
|
||||
query_path_prefix,
|
||||
query_role,
|
||||
query_address_index,
|
||||
query_offset,
|
||||
query_offset_index,
|
||||
query_limit,
|
||||
query_limit_index,
|
||||
match_re,
|
||||
):
|
||||
|
||||
paths = []
|
||||
path = query_path_prefix
|
||||
query_address = None
|
||||
if query_role != None:
|
||||
query_address = strip_0x(list_actors[query_role])
|
||||
paths.append(path + '0x' + query_address)
|
||||
paths.append(path + query_address)
|
||||
if query_offset != None:
|
||||
if query_limit != None:
|
||||
for i in range(len(paths)-1):
|
||||
paths[i] += '/{}/{}'.format(query_offset, query_limit)
|
||||
else:
|
||||
for i in range(len(paths)-1):
|
||||
paths[i] += '/' + str(query_offset)
|
||||
|
||||
for i in range(len(paths)):
|
||||
paths.append(paths[i] + '/')
|
||||
|
||||
for p in paths:
|
||||
logg.debug('testing path {} against {}'.format(p, match_re))
|
||||
m = re.match(match_re, p)
|
||||
l = len(m.groups())
|
||||
logg.debug('laast index match {} groups {}'.format(m.lastindex, l))
|
||||
for i in range(l+1):
|
||||
logg.debug('group {} {}'.format(i, m[i]))
|
||||
if m.lastindex >= query_offset_index:
|
||||
assert query_offset == int(m[query_offset_index + 1])
|
||||
if m.lastindex >= query_limit_index:
|
||||
assert query_limit == int(m[query_limit_index + 1])
|
||||
if query_address_index != None:
|
||||
match_address = strip_0x(m[query_address_index + 1])
|
||||
assert query_address == match_address
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'role_name, query_offset, query_limit, query_match',
|
||||
[
|
||||
('alice', None, None, [(420000, 13), (419999, 42)]),
|
||||
('alice', None, 1, [(420000, 13)]),
|
||||
('alice', 1, None, [(419999, 42)]), # 420000 == list_defaults['block']
|
||||
('alice', 2, None, []), # 420000 == list_defaults['block']
|
||||
],
|
||||
)
|
||||
def test_query_process_txs_account(
|
||||
init_database,
|
||||
list_defaults,
|
||||
list_actors,
|
||||
list_tokens,
|
||||
txs,
|
||||
zero_filter,
|
||||
role_name,
|
||||
query_offset,
|
||||
query_limit,
|
||||
query_match,
|
||||
):
|
||||
|
||||
actor = None
|
||||
try:
|
||||
actor = list_actors[role_name]
|
||||
except KeyError:
|
||||
actor = os.urandom(20).hex()
|
||||
path_info = '/tx/user/0x' + strip_0x(actor)
|
||||
if query_offset != None:
|
||||
path_info += '/' + str(query_offset)
|
||||
if query_limit != None:
|
||||
if query_offset == None:
|
||||
path_info += '/0'
|
||||
path_info += '/' + str(query_limit)
|
||||
env = {
|
||||
'PATH_INFO': path_info,
|
||||
}
|
||||
logg.debug('using path {}'.format(path_info))
|
||||
r = process_transactions_account_bloom(init_database, env)
|
||||
assert r != None
|
||||
|
||||
o = json.loads(r[1])
|
||||
block_filter_data = base64.b64decode(o['block_filter'].encode('utf-8'))
|
||||
zero_filter_data = zero_filter.to_bytes()
|
||||
if len(query_match) == 0:
|
||||
assert block_filter_data == zero_filter_data
|
||||
return
|
||||
|
||||
assert block_filter_data != zero_filter_data
|
||||
block_filter = copy.copy(zero_filter)
|
||||
block_filter.merge(block_filter_data)
|
||||
block_filter_data = block_filter.to_bytes()
|
||||
assert block_filter_data != zero_filter_data
|
||||
|
||||
for (block, tx) in query_match:
|
||||
block = block.to_bytes(4, byteorder='big')
|
||||
assert block_filter.check(block)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'query_offset, query_limit, query_match',
|
||||
[
|
||||
(None, 2, [(420000, 13), (419999, 42)]),
|
||||
(0, 1, [(420000, 13)]),
|
||||
(1, 1, [(419999, 42)]),
|
||||
(2, 0, []),
|
||||
],
|
||||
)
|
||||
def test_query_process_txs_bloom(
|
||||
init_database,
|
||||
list_defaults,
|
||||
list_actors,
|
||||
list_tokens,
|
||||
txs,
|
||||
zero_filter,
|
||||
query_offset,
|
||||
query_limit,
|
||||
query_match,
|
||||
):
|
||||
|
||||
path_info = '/tx'
|
||||
if query_offset != None:
|
||||
path_info += '/' + str(query_offset)
|
||||
if query_limit != None:
|
||||
if query_offset == None:
|
||||
path_info += '/0'
|
||||
path_info += '/' + str(query_limit)
|
||||
env = {
|
||||
'PATH_INFO': path_info,
|
||||
}
|
||||
logg.debug('using path {}'.format(path_info))
|
||||
r = process_transactions_all_bloom(init_database, env)
|
||||
assert r != None
|
||||
|
||||
o = json.loads(r[1])
|
||||
block_filter_data = base64.b64decode(o['block_filter'].encode('utf-8'))
|
||||
zero_filter_data = zero_filter.to_bytes()
|
||||
if len(query_match) == 0:
|
||||
assert block_filter_data == zero_filter_data
|
||||
return
|
||||
|
||||
assert block_filter_data != zero_filter_data
|
||||
block_filter = copy.copy(zero_filter)
|
||||
block_filter.merge(block_filter_data)
|
||||
block_filter_data = block_filter.to_bytes()
|
||||
assert block_filter_data != zero_filter_data
|
||||
|
||||
for (block, tx) in query_match:
|
||||
block = block.to_bytes(4, byteorder='big')
|
||||
assert block_filter.check(block)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'query_block_start, query_block_end, query_match_count',
|
||||
[
|
||||
(None, 42, 0),
|
||||
(420000, 420001, 1),
|
||||
(419999, 419999, 1), # matches are inclusive
|
||||
(419999, 420000, 2),
|
||||
(419999, 420001, 2),
|
||||
],
|
||||
)
|
||||
def test_query_process_txs_data(
|
||||
init_database,
|
||||
list_defaults,
|
||||
list_actors,
|
||||
list_tokens,
|
||||
txs,
|
||||
zero_filter,
|
||||
query_block_start,
|
||||
query_block_end,
|
||||
query_match_count,
|
||||
):
|
||||
|
||||
path_info = '/txa'
|
||||
if query_block_start != None:
|
||||
path_info += '/' + str(query_block_start)
|
||||
if query_block_end != None:
|
||||
if query_block_start == None:
|
||||
path_info += '/0'
|
||||
path_info += '/' + str(query_block_end)
|
||||
env = {
|
||||
'PATH_INFO': path_info,
|
||||
'HTTP_X_CIC_CACHE_MODE': 'all',
|
||||
}
|
||||
logg.debug('using path {}'.format(path_info))
|
||||
r = process_transactions_all_data(init_database, env)
|
||||
assert r != None
|
||||
|
||||
o = json.loads(r[1])
|
||||
assert len(o['data']) == query_match_count
|
||||
1
apps/cic-eth-aux/erc20-demurrage-token/MANIFEST.in
Normal file
1
apps/cic-eth-aux/erc20-demurrage-token/MANIFEST.in
Normal file
@@ -0,0 +1 @@
|
||||
include *requirements.txt
|
||||
@@ -0,0 +1,53 @@
|
||||
# standard imports
|
||||
import logging
|
||||
|
||||
# external imports
|
||||
import celery
|
||||
from erc20_demurrage_token.demurrage import DemurrageCalculator
|
||||
from chainlib.connection import RPCConnection
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.eth.constant import ZERO_ADDRESS
|
||||
from cic_eth_registry import CICRegistry
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
celery_app = celery.current_app
|
||||
|
||||
|
||||
class NoopCalculator:
|
||||
|
||||
def amount_since(self, amount, timestamp):
|
||||
logg.debug('noopcalculator amount {} timestamp {}'.format(amount, timestamp))
|
||||
return amount
|
||||
|
||||
|
||||
class DemurrageCalculationTask(celery.Task):
|
||||
|
||||
demurrage_token_calcs = {}
|
||||
|
||||
@classmethod
|
||||
def register_token(cls, rpc, chain_spec, token_symbol, sender_address=ZERO_ADDRESS):
|
||||
registry = CICRegistry(chain_spec, rpc)
|
||||
token_address = registry.by_name(token_symbol, sender_address=sender_address)
|
||||
try:
|
||||
c = DemurrageCalculator.from_contract(rpc, chain_spec, token_address, sender_address=sender_address)
|
||||
logg.info('found demurrage calculator for ERC20 {} @ {}'.format(token_symbol, token_address))
|
||||
except:
|
||||
logg.warning('Token {} at address {} does not appear to be a demurrage contract. Calls to balance adjust for this token will always return the same amount'.format(token_symbol, token_address))
|
||||
c = NoopCalculator()
|
||||
|
||||
cls.demurrage_token_calcs[token_symbol] = c
|
||||
|
||||
|
||||
@celery_app.task(bind=True, base=DemurrageCalculationTask)
|
||||
def get_adjusted_balance(self, token_symbol, amount, timestamp):
|
||||
c = self.demurrage_token_calcs[token_symbol]
|
||||
return c.amount_since(amount, timestamp)
|
||||
|
||||
|
||||
def aux_setup(rpc, config, sender_address=ZERO_ADDRESS):
|
||||
chain_spec_str = config.get('CIC_CHAIN_SPEC')
|
||||
chain_spec = ChainSpec.from_chain_str(chain_spec_str)
|
||||
token_symbol = config.get('CIC_DEFAULT_TOKEN_SYMBOL')
|
||||
|
||||
DemurrageCalculationTask.register_token(rpc, chain_spec, token_symbol, sender_address=sender_address)
|
||||
@@ -0,0 +1,30 @@
|
||||
# standard imports
|
||||
import logging
|
||||
|
||||
# external imports
|
||||
import celery
|
||||
from cic_eth.api.base import ApiBase
|
||||
|
||||
app = celery.current_app
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Api(ApiBase):
|
||||
|
||||
def get_adjusted_balance(self, token_symbol, balance, timestamp):
|
||||
s = celery.signature(
|
||||
'cic_eth_aux.erc20_demurrage_token.get_adjusted_balance',
|
||||
[
|
||||
token_symbol,
|
||||
balance,
|
||||
timestamp,
|
||||
],
|
||||
queue=None,
|
||||
)
|
||||
if self.callback_param != None:
|
||||
s.link(self.callback_success)
|
||||
s.link.on_error(self.callback_error)
|
||||
|
||||
t = s.apply_async(queue=self.queue)
|
||||
return t
|
||||
5
apps/cic-eth-aux/erc20-demurrage-token/requirements.txt
Normal file
5
apps/cic-eth-aux/erc20-demurrage-token/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
celery==4.4.7
|
||||
erc20-demurrage-token~=0.0.2a3
|
||||
cic-eth-registry~=0.5.6a1
|
||||
chainlib~=0.0.5a1
|
||||
cic_eth~=0.12.0a2
|
||||
30
apps/cic-eth-aux/erc20-demurrage-token/setup.cfg
Normal file
30
apps/cic-eth-aux/erc20-demurrage-token/setup.cfg
Normal file
@@ -0,0 +1,30 @@
|
||||
[metadata]
|
||||
name = cic-eth-aux-erc20-demurrage-token
|
||||
version = 0.0.2a4
|
||||
description = cic-eth tasks supporting erc20 demurrage token
|
||||
author = Louis Holbrook
|
||||
author_email = dev@holbrook.no
|
||||
url = https://gitlab.com/ccicnet/erc20-demurrage-token
|
||||
keywords =
|
||||
ethereum
|
||||
blockchain
|
||||
cryptocurrency
|
||||
erc20
|
||||
classifiers =
|
||||
Programming Language :: Python :: 3
|
||||
Operating System :: OS Independent
|
||||
Development Status :: 3 - Alpha
|
||||
Environment :: No Input/Output (Daemon)
|
||||
Intended Audience :: Developers
|
||||
License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
||||
Topic :: Internet
|
||||
#Topic :: Blockchain :: EVM
|
||||
license = GPL3
|
||||
licence_files =
|
||||
LICENSE
|
||||
|
||||
[options]
|
||||
include_package_data = True
|
||||
python_requires = >= 3.6
|
||||
packages =
|
||||
cic_eth_aux.erc20_demurrage_token
|
||||
25
apps/cic-eth-aux/erc20-demurrage-token/setup.py
Normal file
25
apps/cic-eth-aux/erc20-demurrage-token/setup.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from setuptools import setup
|
||||
|
||||
requirements = []
|
||||
f = open('requirements.txt', 'r')
|
||||
while True:
|
||||
l = f.readline()
|
||||
if l == '':
|
||||
break
|
||||
requirements.append(l.rstrip())
|
||||
f.close()
|
||||
|
||||
test_requirements = []
|
||||
f = open('test_requirements.txt', 'r')
|
||||
while True:
|
||||
l = f.readline()
|
||||
if l == '':
|
||||
break
|
||||
test_requirements.append(l.rstrip())
|
||||
f.close()
|
||||
|
||||
|
||||
setup(
|
||||
install_requires=requirements,
|
||||
tests_require=test_requirements,
|
||||
)
|
||||
12
apps/cic-eth-aux/erc20-demurrage-token/test_requirements.txt
Normal file
12
apps/cic-eth-aux/erc20-demurrage-token/test_requirements.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
pytest==6.0.1
|
||||
pytest-celery==0.0.0a1
|
||||
pytest-mock==3.3.1
|
||||
pytest-cov==2.10.1
|
||||
eth-tester==0.5.0b3
|
||||
py-evm==0.3.0a20
|
||||
SQLAlchemy==1.3.20
|
||||
cic-eth~=0.12.0a1
|
||||
liveness~=0.0.1a7
|
||||
eth-accounts-index==0.0.12a1
|
||||
eth-contract-registry==0.5.6a1
|
||||
eth-address-index==0.1.2a1
|
||||
88
apps/cic-eth-aux/erc20-demurrage-token/tests/conftest.py
Normal file
88
apps/cic-eth-aux/erc20-demurrage-token/tests/conftest.py
Normal file
@@ -0,0 +1,88 @@
|
||||
# external imports
|
||||
import celery
|
||||
from chainlib.eth.pytest.fixtures_chain import *
|
||||
from chainlib.eth.pytest.fixtures_ethtester import *
|
||||
from cic_eth_registry.pytest.fixtures_contracts import *
|
||||
from cic_eth_registry.pytest.fixtures_tokens import *
|
||||
from erc20_demurrage_token.unittest.base import TestTokenDeploy
|
||||
from erc20_demurrage_token.token import DemurrageToken
|
||||
from eth_token_index.index import TokenUniqueSymbolIndex
|
||||
from eth_address_declarator.declarator import AddressDeclarator
|
||||
|
||||
# cic-eth imports
|
||||
from cic_eth.pytest.fixtures_celery import *
|
||||
from cic_eth.pytest.fixtures_token import *
|
||||
from cic_eth.pytest.fixtures_config import *
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def demurrage_token(
|
||||
default_chain_spec,
|
||||
eth_rpc,
|
||||
token_registry,
|
||||
contract_roles,
|
||||
eth_signer,
|
||||
):
|
||||
d = TestTokenDeploy(eth_rpc, token_symbol='BAR', token_name='Bar Token')
|
||||
nonce_oracle = RPCNonceOracle(contract_roles['CONTRACT_DEPLOYER'], conn=eth_rpc)
|
||||
c = DemurrageToken(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle)
|
||||
token_address = d.deploy(eth_rpc, contract_roles['CONTRACT_DEPLOYER'], c, 'SingleNocap')
|
||||
logg.debug('demurrage token contract "BAR" deployed to {}'.format(token_address))
|
||||
|
||||
return token_address
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def demurrage_token_symbol(
|
||||
default_chain_spec,
|
||||
eth_rpc,
|
||||
demurrage_token,
|
||||
contract_roles,
|
||||
):
|
||||
|
||||
c = DemurrageToken(default_chain_spec)
|
||||
o = c.symbol(demurrage_token, sender_address=contract_roles['CONTRACT_DEPLOYER'])
|
||||
r = eth_rpc.do(o)
|
||||
return c.parse_symbol(r)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def demurrage_token_declaration(
|
||||
foo_token_declaration,
|
||||
):
|
||||
return foo_token_declaration
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def register_demurrage_token(
|
||||
default_chain_spec,
|
||||
token_registry,
|
||||
eth_rpc,
|
||||
eth_signer,
|
||||
register_lookups,
|
||||
contract_roles,
|
||||
demurrage_token_declaration,
|
||||
demurrage_token,
|
||||
address_declarator,
|
||||
):
|
||||
|
||||
nonce_oracle = RPCNonceOracle(contract_roles['CONTRACT_DEPLOYER'], eth_rpc)
|
||||
|
||||
c = TokenUniqueSymbolIndex(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash_hex, o) = c.register(token_registry, contract_roles['CONTRACT_DEPLOYER'], demurrage_token)
|
||||
eth_rpc.do(o)
|
||||
o = receipt(tx_hash_hex)
|
||||
r = eth_rpc.do(o)
|
||||
assert r['status'] == 1
|
||||
|
||||
nonce_oracle = RPCNonceOracle(contract_roles['TRUSTED_DECLARATOR'], eth_rpc)
|
||||
c = AddressDeclarator(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle)
|
||||
(tx_hash_hex, o) = c.add_declaration(address_declarator, contract_roles['TRUSTED_DECLARATOR'], demurrage_token, demurrage_token_declaration)
|
||||
|
||||
eth_rpc.do(o)
|
||||
o = receipt(tx_hash_hex)
|
||||
r = eth_rpc.do(o)
|
||||
assert r['status'] == 1
|
||||
|
||||
return token_registry
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# standard imports
|
||||
import logging
|
||||
import copy
|
||||
import datetime
|
||||
|
||||
# external imports
|
||||
import celery
|
||||
|
||||
# cic-eth imports
|
||||
from cic_eth_aux.erc20_demurrage_token import (
|
||||
DemurrageCalculationTask,
|
||||
aux_setup,
|
||||
)
|
||||
from cic_eth_aux.erc20_demurrage_token.api import Api as AuxApi
|
||||
|
||||
logg = logging.getLogger()
|
||||
|
||||
|
||||
def test_demurrage_calulate_task(
|
||||
default_chain_spec,
|
||||
eth_rpc,
|
||||
cic_registry,
|
||||
celery_session_worker,
|
||||
register_demurrage_token,
|
||||
demurrage_token_symbol,
|
||||
contract_roles,
|
||||
load_config,
|
||||
):
|
||||
|
||||
config = copy.copy(load_config)
|
||||
config.add(str(default_chain_spec), 'CIC_CHAIN_SPEC', exists_ok=True)
|
||||
config.add(demurrage_token_symbol, 'CIC_DEFAULT_TOKEN_SYMBOL', exists_ok=True)
|
||||
aux_setup(eth_rpc, load_config, sender_address=contract_roles['CONTRACT_DEPLOYER'])
|
||||
|
||||
since = datetime.datetime.utcnow() - datetime.timedelta(minutes=1)
|
||||
s = celery.signature(
|
||||
'cic_eth_aux.erc20_demurrage_token.get_adjusted_balance',
|
||||
[
|
||||
demurrage_token_symbol,
|
||||
1000,
|
||||
since.timestamp(),
|
||||
],
|
||||
queue=None,
|
||||
)
|
||||
t = s.apply_async()
|
||||
r = t.get_leaf()
|
||||
assert t.successful()
|
||||
assert r == 980
|
||||
|
||||
|
||||
|
||||
def test_demurrage_calculate_api(
|
||||
default_chain_spec,
|
||||
eth_rpc,
|
||||
cic_registry,
|
||||
celery_session_worker,
|
||||
register_demurrage_token,
|
||||
demurrage_token_symbol,
|
||||
contract_roles,
|
||||
load_config,
|
||||
):
|
||||
|
||||
api = AuxApi(str(default_chain_spec), queue=None)
|
||||
since = datetime.datetime.utcnow() - datetime.timedelta(minutes=1)
|
||||
t = api.get_adjusted_balance(demurrage_token_symbol, 1000, since.timestamp())
|
||||
r = t.get_leaf()
|
||||
assert t.successful()
|
||||
assert r == 980
|
||||
|
||||
6
apps/cic-eth/.dockerignore
Normal file
6
apps/cic-eth/.dockerignore
Normal file
@@ -0,0 +1,6 @@
|
||||
.git
|
||||
.cache
|
||||
.dot
|
||||
**/doc
|
||||
**/.venv
|
||||
**/venv
|
||||
@@ -1,33 +1,52 @@
|
||||
.cic_eth_variables:
|
||||
variables:
|
||||
APP_NAME: cic-eth
|
||||
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
|
||||
|
||||
.cic_eth_changes_target:
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
#changes:
|
||||
#- $CONTEXT/$APP_NAME/**/*
|
||||
when: always
|
||||
DOCKERFILE_PATH: docker/Dockerfile_ci
|
||||
CONTEXT: apps/$APP_NAME
|
||||
|
||||
build-mr-cic-eth:
|
||||
extends:
|
||||
- .cic_eth_variables
|
||||
- .cic_eth_changes_target
|
||||
- .py_build_target_test
|
||||
- .py_build_target_dev
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/cic-eth/**/*
|
||||
when: always
|
||||
|
||||
test-mr-cic-eth:
|
||||
stage: test
|
||||
extends:
|
||||
- .cic_eth_variables
|
||||
- .cic_eth_changes_target
|
||||
stage: test
|
||||
image: $CI_REGISTRY_IMAGE/$APP_NAME-test:latest
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- test_requirements.txt
|
||||
paths:
|
||||
- /root/.cache/pip
|
||||
image: $MR_IMAGE_TAG
|
||||
script:
|
||||
- cd apps/$APP_NAME/
|
||||
- pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests
|
||||
- >
|
||||
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
|
||||
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
|
||||
-r admin_requirements.txt
|
||||
-r services_requirements.txt
|
||||
-r test_requirements.txt
|
||||
- export PYTHONPATH=. && pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests
|
||||
needs: ["build-mr-cic-eth"]
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/cic-eth/**/*
|
||||
when: always
|
||||
|
||||
build-push-cic-eth:
|
||||
extends:
|
||||
- .py_build_push
|
||||
- .cic_eth_variables
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "master"
|
||||
changes:
|
||||
- apps/cic-eth/**/*
|
||||
when: always
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
include *requirements.txt
|
||||
include *requirements.txt config/test/*
|
||||
|
||||
|
||||
5
apps/cic-eth/admin_requirements.txt
Normal file
5
apps/cic-eth/admin_requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
SQLAlchemy==1.3.20
|
||||
cic-eth-registry~=0.5.6a1
|
||||
hexathon~=0.0.1a7
|
||||
chainqueue~=0.0.2b5
|
||||
eth-erc20==0.0.10a2
|
||||
@@ -5,4 +5,3 @@
|
||||
"""
|
||||
|
||||
from .api_task import Api
|
||||
from .api_admin import AdminApi
|
||||
|
||||
@@ -8,59 +8,19 @@ import logging
|
||||
|
||||
# external imports
|
||||
import celery
|
||||
from cic_eth_registry import CICRegistry
|
||||
from chainlib.chain import ChainSpec
|
||||
|
||||
# local imports
|
||||
from cic_eth.db.enum import LockEnum
|
||||
from cic_eth.api.base import ApiBase
|
||||
from cic_eth.enum import LockEnum
|
||||
|
||||
app = celery.current_app
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Api:
|
||||
"""Creates task chains to perform well-known CIC operations.
|
||||
|
||||
Each method that sends tasks returns details about the root task. The root task uuid can be provided in the callback, to enable to caller to correlate the result with individual calls. It can also be used to independently poll the completion of a task chain.
|
||||
|
||||
:param callback_param: Static value to pass to callback
|
||||
:type callback_param: str
|
||||
:param callback_task: Callback task that executes callback_param call. (Must be included by the celery worker)
|
||||
:type callback_task: string
|
||||
:param queue: Name of worker queue to submit tasks to
|
||||
:type queue: str
|
||||
"""
|
||||
def __init__(self, chain_str, queue='cic-eth', callback_param=None, callback_task='cic_eth.callbacks.noop.noop', callback_queue=None):
|
||||
self.chain_str = chain_str
|
||||
self.chain_spec = ChainSpec.from_chain_str(chain_str)
|
||||
self.callback_param = callback_param
|
||||
self.callback_task = callback_task
|
||||
self.queue = queue
|
||||
logg.debug('api using queue {}'.format(self.queue))
|
||||
self.callback_success = None
|
||||
self.callback_error = None
|
||||
if callback_queue == None:
|
||||
callback_queue=self.queue
|
||||
|
||||
if callback_param != None:
|
||||
self.callback_success = celery.signature(
|
||||
callback_task,
|
||||
[
|
||||
callback_param,
|
||||
0,
|
||||
],
|
||||
queue=callback_queue,
|
||||
)
|
||||
self.callback_error = celery.signature(
|
||||
callback_task,
|
||||
[
|
||||
callback_param,
|
||||
1,
|
||||
],
|
||||
queue=callback_queue,
|
||||
)
|
||||
|
||||
class Api(ApiBase):
|
||||
|
||||
|
||||
def default_token(self):
|
||||
s_token = celery.signature(
|
||||
|
||||
52
apps/cic-eth/cic_eth/api/base.py
Normal file
52
apps/cic-eth/cic_eth/api/base.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# standard imports
|
||||
import logging
|
||||
|
||||
# external imports
|
||||
import celery
|
||||
from chainlib.chain import ChainSpec
|
||||
|
||||
logg = logging.getLogger(__name__)
|
||||
|
||||
class ApiBase:
|
||||
"""Creates task chains to perform well-known CIC operations.
|
||||
|
||||
Each method that sends tasks returns details about the root task. The root task uuid can be provided in the callback, to enable to caller to correlate the result with individual calls. It can also be used to independently poll the completion of a task chain.
|
||||
|
||||
:param callback_param: Static value to pass to callback
|
||||
:type callback_param: str
|
||||
:param callback_task: Callback task that executes callback_param call. (Must be included by the celery worker)
|
||||
:type callback_task: string
|
||||
:param queue: Name of worker queue to submit tasks to
|
||||
:type queue: str
|
||||
"""
|
||||
def __init__(self, chain_str, queue='cic-eth', callback_param=None, callback_task='cic_eth.callbacks.noop.noop', callback_queue=None):
|
||||
self.chain_str = chain_str
|
||||
self.chain_spec = ChainSpec.from_chain_str(chain_str)
|
||||
self.callback_param = callback_param
|
||||
self.callback_task = callback_task
|
||||
self.queue = queue
|
||||
logg.debug('api using queue {}'.format(self.queue))
|
||||
self.callback_success = None
|
||||
self.callback_error = None
|
||||
if callback_queue == None:
|
||||
callback_queue=self.queue
|
||||
|
||||
if callback_param != None:
|
||||
self.callback_success = celery.signature(
|
||||
callback_task,
|
||||
[
|
||||
callback_param,
|
||||
0,
|
||||
],
|
||||
queue=callback_queue,
|
||||
)
|
||||
self.callback_error = celery.signature(
|
||||
callback_task,
|
||||
[
|
||||
callback_param,
|
||||
1,
|
||||
],
|
||||
queue=callback_queue,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,158 +1 @@
|
||||
# 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)
|
||||
from cic_eth.enum import *
|
||||
|
||||
158
apps/cic-eth/cic_eth/enum.py
Normal file
158
apps/cic-eth/cic_eth/enum.py
Normal file
@@ -0,0 +1,158 @@
|
||||
# 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)
|
||||
@@ -37,7 +37,7 @@ def celery_includes():
|
||||
'cic_eth.eth.account',
|
||||
'cic_eth.callbacks.noop',
|
||||
'cic_eth.callbacks.http',
|
||||
'tests.mock.filter',
|
||||
'cic_eth.pytest.mock.filter',
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@ logg = logging.getLogger(__name__)
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def load_config():
|
||||
config_dir = os.path.join(root_dir, 'config/test')
|
||||
config_dir = os.environ.get('CONFINI_DIR')
|
||||
if config_dir == None:
|
||||
config_dir = os.path.join(root_dir, 'config/test')
|
||||
conf = confini.Config(config_dir, 'CICTEST')
|
||||
conf.process()
|
||||
logg.debug('config {}'.format(conf))
|
||||
|
||||
19
apps/cic-eth/cic_eth/pytest/fixtures_token.py
Normal file
19
apps/cic-eth/cic_eth/pytest/fixtures_token.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# external imports
|
||||
import pytest
|
||||
from eth_erc20 import ERC20
|
||||
|
||||
# TODO: missing dep fixture includes
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def foo_token_symbol(
|
||||
default_chain_spec,
|
||||
foo_token,
|
||||
eth_rpc,
|
||||
contract_roles,
|
||||
):
|
||||
|
||||
c = ERC20(default_chain_spec)
|
||||
o = c.symbol(foo_token, sender_address=contract_roles['CONTRACT_DEPLOYER'])
|
||||
r = eth_rpc.do(o)
|
||||
return c.parse_symbol(r)
|
||||
@@ -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 import AdminApi
|
||||
from cic_eth.api.admin import AdminApi
|
||||
from cic_eth.db.enum import LockEnum
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
@@ -7,6 +7,8 @@ import tempfile
|
||||
import re
|
||||
import urllib
|
||||
import websocket
|
||||
import stat
|
||||
import importlib
|
||||
|
||||
# external imports
|
||||
import celery
|
||||
@@ -68,6 +70,8 @@ from cic_eth.task import BaseTask
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
config_dir = os.path.join('/usr/local/etc/cic-eth')
|
||||
|
||||
argparser = argparse.ArgumentParser()
|
||||
@@ -79,6 +83,8 @@ argparser.add_argument('--default-token-symbol', dest='default_token_symbol', ty
|
||||
argparser.add_argument('--trace-queue-status', default=None, dest='trace_queue_status', action='store_true', help='set to perist all queue entry status changes to storage')
|
||||
argparser.add_argument('-i', '--chain-spec', dest='i', type=str, help='chain spec')
|
||||
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('--aux-all', action='store_true', help='include tasks from all submodules from the aux module path')
|
||||
argparser.add_argument('--aux', action='append', type=str, default=[], help='add single submodule from the aux module path')
|
||||
argparser.add_argument('-v', action='store_true', help='be verbose')
|
||||
argparser.add_argument('-vv', action='store_true', help='be more verbose')
|
||||
args = argparser.parse_args()
|
||||
@@ -109,6 +115,8 @@ if len(health_modules) != 0:
|
||||
health_modules = health_modules.split(',')
|
||||
logg.debug('health mods {}'.format(health_modules))
|
||||
|
||||
|
||||
|
||||
# connect to database
|
||||
dsn = dsn_from_config(config)
|
||||
SessionBase.connect(dsn, pool_size=int(config.get('DATABASE_POOL_SIZE')), debug=config.true('DATABASE_DEBUG'))
|
||||
@@ -167,6 +175,84 @@ Otx.tracing = config.true('TASKS_TRACE_QUEUE_STATUS')
|
||||
# raise RuntimeError()
|
||||
liveness.linux.load(health_modules, rundir=config.get('CIC_RUN_DIR'), config=config, unit='cic-eth-tasker')
|
||||
|
||||
rpc = RPCConnection.connect(chain_spec, 'default')
|
||||
try:
|
||||
registry = connect_registry(rpc, chain_spec, config.get('CIC_REGISTRY_ADDRESS'))
|
||||
except UnknownContractError as e:
|
||||
logg.exception('Registry contract connection failed for {}: {}'.format(config.get('CIC_REGISTRY_ADDRESS'), e))
|
||||
sys.exit(1)
|
||||
logg.info('connected contract registry {}'.format(config.get('CIC_REGISTRY_ADDRESS')))
|
||||
|
||||
trusted_addresses_src = config.get('CIC_TRUST_ADDRESS')
|
||||
if trusted_addresses_src == None:
|
||||
logg.critical('At least one trusted address must be declared in CIC_TRUST_ADDRESS')
|
||||
sys.exit(1)
|
||||
trusted_addresses = trusted_addresses_src.split(',')
|
||||
for address in trusted_addresses:
|
||||
logg.info('using trusted address {}'.format(address))
|
||||
|
||||
connect_declarator(rpc, chain_spec, trusted_addresses)
|
||||
connect_token_registry(rpc, chain_spec)
|
||||
|
||||
# detect aux
|
||||
# TODO: move to separate file
|
||||
#aux_dir = os.path.join(script_dir, '..', '..', 'aux')
|
||||
aux = []
|
||||
if args.aux_all:
|
||||
if len(args.aux) > 0:
|
||||
logg.warning('--aux-all is set so --aux will have no effect')
|
||||
for p in sys.path:
|
||||
logg.debug('checking for aux modules in {}'.format(p))
|
||||
aux_dir = os.path.join(p, 'cic_eth_aux')
|
||||
try:
|
||||
d = os.listdir(aux_dir)
|
||||
except FileNotFoundError:
|
||||
logg.debug('no aux module found in {}'.format(aux_dir))
|
||||
continue
|
||||
for v in d:
|
||||
if v[:1] == '.':
|
||||
logg.debug('dotfile, skip {}'.format(v))
|
||||
continue
|
||||
aux_mod_path = os.path.join(aux_dir, v)
|
||||
st = os.stat(aux_mod_path)
|
||||
if not stat.S_ISDIR(st.st_mode):
|
||||
logg.debug('not a dir, skip {}'.format(v))
|
||||
continue
|
||||
aux_mod_file = os.path.join(aux_dir, v,'__init__.py')
|
||||
try:
|
||||
st = os.stat(aux_mod_file)
|
||||
except FileNotFoundError:
|
||||
logg.debug('__init__.py not found, skip {}'.format(v))
|
||||
continue
|
||||
aux.append(v)
|
||||
logg.debug('found module {} in {}'.format(v, aux_dir))
|
||||
|
||||
elif len(args.aux) > 0:
|
||||
for p in sys.path:
|
||||
v_found = None
|
||||
for v in args.aux:
|
||||
aux_dir = os.path.join(p, 'cic_eth_aux')
|
||||
aux_mod_file = os.path.join(aux_dir, v, '__init__.py')
|
||||
try:
|
||||
st = os.stat(aux_mod_file)
|
||||
v_found = v
|
||||
except FileNotFoundError:
|
||||
logg.debug('cannot find explicity requested aux module {} in path {}'.format(v, aux_dir))
|
||||
continue
|
||||
if v_found == None:
|
||||
logg.critical('excplicity requested aux module {} not found in any path'.format(v))
|
||||
sys.exit(1)
|
||||
|
||||
logg.info('aux module {} found in path {}'.format(v, aux_dir))
|
||||
aux.append(v)
|
||||
|
||||
for v in aux:
|
||||
mname = 'cic_eth_aux.' + v
|
||||
mod = importlib.import_module(mname)
|
||||
mod.aux_setup(rpc, config)
|
||||
logg.info('loaded aux module {}'.format(mname))
|
||||
|
||||
|
||||
def main():
|
||||
argv = ['worker']
|
||||
if args.vv:
|
||||
@@ -189,24 +275,6 @@ def main():
|
||||
|
||||
rpc = RPCConnection.connect(chain_spec, 'default')
|
||||
|
||||
try:
|
||||
registry = connect_registry(rpc, chain_spec, config.get('CIC_REGISTRY_ADDRESS'))
|
||||
except UnknownContractError as e:
|
||||
logg.exception('Registry contract connection failed for {}: {}'.format(config.get('CIC_REGISTRY_ADDRESS'), e))
|
||||
sys.exit(1)
|
||||
logg.info('connected contract registry {}'.format(config.get('CIC_REGISTRY_ADDRESS')))
|
||||
|
||||
trusted_addresses_src = config.get('CIC_TRUST_ADDRESS')
|
||||
if trusted_addresses_src == None:
|
||||
logg.critical('At least one trusted address must be declared in CIC_TRUST_ADDRESS')
|
||||
sys.exit(1)
|
||||
trusted_addresses = trusted_addresses_src.split(',')
|
||||
for address in trusted_addresses:
|
||||
logg.info('using trusted address {}'.format(address))
|
||||
|
||||
connect_declarator(rpc, chain_spec, trusted_addresses)
|
||||
connect_token_registry(rpc, chain_spec)
|
||||
|
||||
BaseTask.default_token_symbol = config.get('CIC_DEFAULT_TOKEN_SYMBOL')
|
||||
BaseTask.default_token_address = registry.by_name(BaseTask.default_token_symbol)
|
||||
default_token = ERC20Token(chain_spec, rpc, BaseTask.default_token_address)
|
||||
|
||||
@@ -12,10 +12,8 @@ import confini
|
||||
import celery
|
||||
|
||||
# local imports
|
||||
from cic_eth.api import (
|
||||
Api,
|
||||
AdminApi,
|
||||
)
|
||||
from cic_eth.api import Api
|
||||
from cic_eth.api.admin import AdminApi
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
@@ -11,7 +11,7 @@ from chainlib.chain import ChainSpec
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
|
||||
# local imports
|
||||
from cic_eth.api.api_admin import AdminApi
|
||||
from cic_eth.api.admin import AdminApi
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
|
||||
@@ -12,7 +12,7 @@ from chainlib.chain import ChainSpec
|
||||
from xdg.BaseDirectory import xdg_config_home
|
||||
|
||||
# local imports
|
||||
from cic_eth.api import AdminApi
|
||||
from cic_eth.api.admin import AdminApi
|
||||
from cic_eth.db import dsn_from_config
|
||||
from cic_eth.db.models.base import SessionBase
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ from chainlib.eth.connection import EthHTTPConnection
|
||||
from hexathon import add_0x
|
||||
|
||||
# local imports
|
||||
from cic_eth.api import AdminApi
|
||||
from cic_eth.api.admin import AdminApi
|
||||
from cic_eth.db.enum import (
|
||||
StatusEnum,
|
||||
status_str,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# import
|
||||
import time
|
||||
import requests
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
@@ -76,7 +75,7 @@ class CriticalSQLAlchemyTask(CriticalTask):
|
||||
|
||||
class CriticalWeb3Task(CriticalTask):
|
||||
autoretry_for = (
|
||||
requests.exceptions.ConnectionError,
|
||||
ConnectionError,
|
||||
)
|
||||
safe_gas_threshold_amount = 2000000000 * 60000 * 3
|
||||
safe_gas_refill_amount = safe_gas_threshold_amount * 5
|
||||
@@ -86,7 +85,7 @@ class CriticalSQLAlchemyAndWeb3Task(CriticalTask):
|
||||
autoretry_for = (
|
||||
sqlalchemy.exc.DatabaseError,
|
||||
sqlalchemy.exc.TimeoutError,
|
||||
requests.exceptions.ConnectionError,
|
||||
ConnectionError,
|
||||
sqlalchemy.exc.ResourceClosedError,
|
||||
)
|
||||
safe_gas_threshold_amount = 2000000000 * 60000 * 3
|
||||
@@ -102,7 +101,7 @@ class CriticalSQLAlchemyAndSignerTask(CriticalTask):
|
||||
|
||||
class CriticalWeb3AndSignerTask(CriticalTask):
|
||||
autoretry_for = (
|
||||
requests.exceptions.ConnectionError,
|
||||
ConnectionError,
|
||||
)
|
||||
safe_gas_threshold_amount = 2000000000 * 60000 * 3
|
||||
safe_gas_refill_amount = safe_gas_threshold_amount * 5
|
||||
|
||||
@@ -8,9 +8,9 @@ import semver
|
||||
|
||||
version = (
|
||||
0,
|
||||
11,
|
||||
1,
|
||||
'alpha.3',
|
||||
12,
|
||||
0,
|
||||
'alpha.2',
|
||||
)
|
||||
|
||||
version_object = semver.VersionInfo(
|
||||
|
||||
@@ -1,45 +1,39 @@
|
||||
FROM python:3.8.6-slim-buster as compile
|
||||
# syntax = docker/dockerfile:1.2
|
||||
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
|
||||
|
||||
WORKDIR /usr/src/cic-eth
|
||||
# Copy just the requirements and install....this _might_ give docker a hint on caching but we
|
||||
# do load these all into setup.py later
|
||||
# TODO can we take all the requirements out of setup.py and just do a pip install -r requirements.txt && python setup.py
|
||||
#COPY cic-eth/requirements.txt .
|
||||
|
||||
RUN apt-get update && \
|
||||
apt install -y gcc gnupg libpq-dev wget make g++ gnupg bash procps git
|
||||
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 --index-url https://pypi.org/simple \
|
||||
# --force-reinstall \
|
||||
# --extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
|
||||
# -r requirements.txt
|
||||
|
||||
#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'
|
||||
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 $pip_extra_index_url_flag .
|
||||
|
||||
# --- TEST IMAGE ---
|
||||
FROM python:3.8.6-slim-buster as test
|
||||
|
||||
RUN apt-get update && \
|
||||
apt install -y gcc gnupg libpq-dev wget make g++ gnupg bash procps git
|
||||
|
||||
WORKDIR /usr/src/cic-eth
|
||||
|
||||
RUN /usr/local/bin/python -m pip install --upgrade pip
|
||||
|
||||
COPY --from=compile /usr/local/bin/ /usr/local/bin/
|
||||
COPY --from=compile /usr/local/lib/python3.8/site-packages/ \
|
||||
/usr/local/lib/python3.8/site-packages/
|
||||
# TODO we could use venv inside container to isolate the system and app deps further
|
||||
# COPY --from=compile /usr/src/cic-eth/ .
|
||||
# RUN . venv/bin/activate
|
||||
|
||||
COPY cic-eth/test_requirements.txt .
|
||||
RUN pip install $pip_extra_index_url_flag -r test_requirements.txt
|
||||
|
||||
COPY cic-eth .
|
||||
COPY . .
|
||||
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
|
||||
pip install --index-url https://pypi.org/simple \
|
||||
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL .
|
||||
|
||||
ENV PYTHONPATH .
|
||||
|
||||
ENTRYPOINT ["pytest"]
|
||||
COPY docker/entrypoints/* ./
|
||||
RUN chmod 755 *.sh
|
||||
|
||||
# # ini files in config directory defines the configurable parameters for the application
|
||||
# # they can all be overridden by environment variables
|
||||
# # to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
|
||||
COPY config/ /usr/local/etc/cic-eth/
|
||||
COPY cic_eth/db/migrations/ /usr/local/share/cic-eth/alembic/
|
||||
COPY crypto_dev_signer_config/ /usr/local/etc/crypto-dev-signer/
|
||||
|
||||
# TODO this kind of code sharing across projects should be discouraged...can we make util a library?
|
||||
#COPY util/liveness/health.sh /usr/local/bin/health.sh
|
||||
ENTRYPOINT []
|
||||
|
||||
# --- RUNTIME ---
|
||||
FROM python:3.8.6-slim-buster as runtime
|
||||
@@ -49,20 +43,22 @@ RUN apt-get update && \
|
||||
|
||||
WORKDIR /usr/src/cic-eth
|
||||
|
||||
COPY --from=compile /usr/local/bin/ /usr/local/bin/
|
||||
COPY --from=compile /usr/local/lib/python3.8/site-packages/ \
|
||||
COPY --from=dev /usr/local/bin/ /usr/local/bin/
|
||||
COPY --from=dev /usr/local/lib/python3.8/site-packages/ \
|
||||
/usr/local/lib/python3.8/site-packages/
|
||||
|
||||
COPY cic-eth/docker/* ./
|
||||
COPY docker/entrypoints/* ./
|
||||
RUN chmod 755 *.sh
|
||||
|
||||
COPY cic-eth/scripts/ scripts/
|
||||
# # ini files in config directory defines the configurable parameters for the application
|
||||
# # they can all be overridden by environment variables
|
||||
# # to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
|
||||
COPY cic-eth/config/ /usr/local/etc/cic-eth/
|
||||
COPY cic-eth/cic_eth/db/migrations/ /usr/local/share/cic-eth/alembic/
|
||||
COPY cic-eth/crypto_dev_signer_config/ /usr/local/etc/crypto-dev-signer/
|
||||
COPY config/ /usr/local/etc/cic-eth/
|
||||
COPY cic_eth/db/migrations/ /usr/local/share/cic-eth/alembic/
|
||||
COPY crypto_dev_signer_config/ /usr/local/etc/crypto-dev-signer/
|
||||
|
||||
COPY util/liveness/health.sh /usr/local/bin/health.sh
|
||||
# TODO this kind of code sharing across projects should be discouraged...can we make util a library?
|
||||
#COPY util/liveness/health.sh /usr/local/bin/health.sh
|
||||
|
||||
ENTRYPOINT []
|
||||
|
||||
|
||||
62
apps/cic-eth/docker/Dockerfile_ci
Normal file
62
apps/cic-eth/docker/Dockerfile_ci
Normal file
@@ -0,0 +1,62 @@
|
||||
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
|
||||
|
||||
WORKDIR /usr/src/cic-eth
|
||||
|
||||
# Copy just the requirements and install....this _might_ give docker a hint on caching but we
|
||||
# do load these all into setup.py later
|
||||
# TODO can we take all the requirements out of setup.py and just do a pip install -r requirements.txt && python setup.py
|
||||
#COPY cic-eth/requirements.txt .
|
||||
|
||||
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
|
||||
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
|
||||
#RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
|
||||
# pip install --index-url https://pypi.org/simple \
|
||||
# --force-reinstall \
|
||||
# --extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
|
||||
# -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
RUN pip install --index-url https://pypi.org/simple \
|
||||
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL .
|
||||
|
||||
COPY docker/entrypoints/* ./
|
||||
RUN chmod 755 *.sh
|
||||
|
||||
# # ini files in config directory defines the configurable parameters for the application
|
||||
# # they can all be overridden by environment variables
|
||||
# # to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
|
||||
COPY config/ /usr/local/etc/cic-eth/
|
||||
COPY cic_eth/db/migrations/ /usr/local/share/cic-eth/alembic/
|
||||
COPY crypto_dev_signer_config/ /usr/local/etc/crypto-dev-signer/
|
||||
|
||||
# TODO this kind of code sharing across projects should be discouraged...can we make util a library?
|
||||
#COPY util/liveness/health.sh /usr/local/bin/health.sh
|
||||
ENTRYPOINT []
|
||||
|
||||
# --- RUNTIME ---
|
||||
FROM python:3.8.6-slim-buster as runtime
|
||||
|
||||
RUN apt-get update && \
|
||||
apt install -y gnupg libpq-dev procps
|
||||
|
||||
WORKDIR /usr/src/cic-eth
|
||||
|
||||
COPY --from=dev /usr/local/bin/ /usr/local/bin/
|
||||
COPY --from=dev /usr/local/lib/python3.8/site-packages/ \
|
||||
/usr/local/lib/python3.8/site-packages/
|
||||
|
||||
COPY docker/entrypoints/* ./
|
||||
RUN chmod 755 *.sh
|
||||
|
||||
# # ini files in config directory defines the configurable parameters for the application
|
||||
# # they can all be overridden by environment variables
|
||||
# # to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
|
||||
COPY config/ /usr/local/etc/cic-eth/
|
||||
COPY cic_eth/db/migrations/ /usr/local/share/cic-eth/alembic/
|
||||
COPY crypto_dev_signer_config/ /usr/local/etc/crypto-dev-signer/
|
||||
|
||||
# TODO this kind of code sharing across projects should be discouraged...can we make util a library?
|
||||
#COPY util/liveness/health.sh /usr/local/bin/health.sh
|
||||
|
||||
ENTRYPOINT []
|
||||
|
||||
@@ -8,7 +8,7 @@ set -e
|
||||
echo "!!! starting signer"
|
||||
python /usr/local/bin/crypto-dev-daemon -c /usr/local/etc/crypto-dev-signer -vv 2> /tmp/signer.log &
|
||||
|
||||
echo "!!! starting tracker"
|
||||
echo "!!! starting taskerd"
|
||||
/usr/local/bin/cic-eth-taskerd $@
|
||||
|
||||
# thanks! https://docs.docker.com/config/containers/multi-service_container/
|
||||
@@ -1,25 +1,3 @@
|
||||
cic-base==0.1.3a3+build.984b5cff
|
||||
celery==4.4.7
|
||||
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
|
||||
chainlib~=0.0.5a1
|
||||
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
|
||||
|
||||
15
apps/cic-eth/services_requirements.txt
Normal file
15
apps/cic-eth/services_requirements.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
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
|
||||
liveness~=0.0.1a7
|
||||
eth-address-index~=0.1.2a1
|
||||
eth-accounts-index~=0.0.12a1
|
||||
cic-eth-registry~=0.5.6a1
|
||||
erc20-faucet~=0.2.2a1
|
||||
erc20-transfer-authorization~=0.3.2a1
|
||||
sarafu-faucet~=0.0.4a1
|
||||
moolb~=0.1.1b2
|
||||
@@ -39,22 +39,25 @@ packages =
|
||||
cic_eth.callbacks
|
||||
cic_eth.sync
|
||||
cic_eth.check
|
||||
# should be concealed behind extras "test" if possible (but its not unfortunately)
|
||||
cic_eth.pytest
|
||||
cic_eth.pytest.mock
|
||||
scripts =
|
||||
./scripts/migrate.py
|
||||
|
||||
[options.entry_points]
|
||||
console_scripts =
|
||||
# daemons
|
||||
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
|
||||
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]
|
||||
# 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
|
||||
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]
|
||||
# TODO: Merge this with ctl when subcmds sorted to submodules
|
||||
cic-eth-tag = cic_eth.runnable.tag:main
|
||||
cic-eth-resend = cic_eth.runnable.resend:main
|
||||
cic-eth-transfer = cic_eth.runnable.transfer:main
|
||||
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]
|
||||
|
||||
@@ -11,6 +11,41 @@ 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
|
||||
)
|
||||
install_requires=requirements,
|
||||
extras_require = {
|
||||
'tools': tools_requirements,
|
||||
'admin_api': admin_requirements,
|
||||
'services': services_requirements,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -2,5 +2,8 @@ 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
|
||||
|
||||
@@ -5,6 +5,7 @@ import logging
|
||||
import uuid
|
||||
|
||||
# external imports
|
||||
import pytest
|
||||
from eth_erc20 import ERC20
|
||||
import redis
|
||||
|
||||
@@ -22,6 +23,7 @@ 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 cic_eth.pytest.fixtures_token import *
|
||||
from chainlib.eth.pytest import *
|
||||
from eth_contract_registry.pytest import *
|
||||
from cic_eth_registry.pytest.fixtures_contracts import *
|
||||
@@ -37,20 +39,6 @@ def api(
|
||||
return Api(chain_str, queue=None, callback_param='foo')
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def foo_token_symbol(
|
||||
default_chain_spec,
|
||||
foo_token,
|
||||
eth_rpc,
|
||||
contract_roles,
|
||||
):
|
||||
|
||||
c = ERC20(default_chain_spec)
|
||||
o = c.symbol(foo_token, sender_address=contract_roles['CONTRACT_DEPLOYER'])
|
||||
r = eth_rpc.do(o)
|
||||
return c.parse_symbol(r)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def default_token(
|
||||
foo_token,
|
||||
|
||||
@@ -40,7 +40,7 @@ from chainqueue.sql.query import (
|
||||
)
|
||||
|
||||
# local imports
|
||||
from cic_eth.api import AdminApi
|
||||
from cic_eth.api.admin import AdminApi
|
||||
from cic_eth.db.models.role import AccountRole
|
||||
from cic_eth.db.enum import LockEnum
|
||||
from cic_eth.error import InitializationError
|
||||
|
||||
@@ -35,7 +35,7 @@ from eth_erc20 import ERC20
|
||||
from cic_eth_registry import CICRegistry
|
||||
|
||||
# local imports
|
||||
from cic_eth.api.api_admin import AdminApi
|
||||
from cic_eth.api.admin import AdminApi
|
||||
from cic_eth.eth.gas import cache_gas_data
|
||||
from cic_eth.eth.erc20 import cache_transfer_data
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ from cic_eth.db.models.nonce import (
|
||||
)
|
||||
|
||||
# test imports
|
||||
from tests.mock.filter import (
|
||||
from cic_eth.pytest.mock.filter import (
|
||||
block_filter,
|
||||
tx_filter,
|
||||
)
|
||||
@@ -110,7 +110,7 @@ def test_list_tx(
|
||||
logg.debug('r {}'.format(r))
|
||||
|
||||
# test the api
|
||||
t = api.list(agent_roles['ALICE'], external_task='tests.mock.filter.filter')
|
||||
t = api.list(agent_roles['ALICE'], external_task='cic_eth.pytest.mock.filter.filter')
|
||||
r = t.get_leaf()
|
||||
assert t.successful()
|
||||
|
||||
|
||||
8
apps/cic-eth/tools_requirements.txt
Normal file
8
apps/cic-eth/tools_requirements.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
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
|
||||
4
apps/cic-meta/.dockerignore
Normal file
4
apps/cic-meta/.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
.git
|
||||
.cache
|
||||
.dot
|
||||
**/doc
|
||||
@@ -3,42 +3,41 @@
|
||||
variables:
|
||||
APP_NAME: cic-meta
|
||||
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
|
||||
IMAGE_TAG: $CI_REGISTRY_IMAGE/$APP_NAME:unittest-$CI_COMMIT_SHORT_SHA
|
||||
CONTEXT: apps
|
||||
|
||||
.cic_meta_changes_target:
|
||||
build-mr-cic-meta:
|
||||
extends:
|
||||
- .py_build_merge_request
|
||||
- .cic_meta_variables
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
# - changes:
|
||||
# - $CONTEXT/$APP_NAME/*
|
||||
- when: always
|
||||
|
||||
cic-meta-build-mr:
|
||||
stage: build
|
||||
extends:
|
||||
- .cic_meta_variables
|
||||
- .cic_meta_changes_target
|
||||
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 --destination $IMAGE_TAG
|
||||
- /kaniko/executor --context $CONTEXT --dockerfile $DOCKERFILE_PATH $KANIKO_CACHE_ARGS --destination $IMAGE_TAG
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/cic-meta/**/*
|
||||
when: always
|
||||
|
||||
test-mr-cic-meta:
|
||||
extends:
|
||||
- .cic_meta_variables
|
||||
- .cic_meta_changes_target
|
||||
stage: test
|
||||
image: $IMAGE_TAG
|
||||
image: $MR_IMAGE_TAG
|
||||
script:
|
||||
- cd /tmp/src/cic-meta
|
||||
- npm install --dev
|
||||
- npm run test
|
||||
- npm run test:coverage
|
||||
needs: ["cic-meta-build-mr"]
|
||||
needs: ["build-mr-cic-meta"]
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/cic-meta/**/*
|
||||
when: always
|
||||
|
||||
build-push-cic-meta:
|
||||
extends:
|
||||
- .py_build_push
|
||||
- .cic_meta_variables
|
||||
|
||||
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "master"
|
||||
changes:
|
||||
- apps/cic-meta/**/*
|
||||
when: always
|
||||
|
||||
@@ -1,22 +1,52 @@
|
||||
.cic_notify_variables:
|
||||
variables:
|
||||
APP_NAME: cic-notify
|
||||
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
|
||||
|
||||
.cic_notify_changes_target:
|
||||
rules:
|
||||
- changes:
|
||||
- $CONTEXT/$APP_NAME/*
|
||||
DOCKERFILE_PATH: docker/Dockerfile_ci
|
||||
CONTEXT: apps/$APP_NAME
|
||||
|
||||
build-mr-cic-notify:
|
||||
extends:
|
||||
- .cic_notify_changes_target
|
||||
- .py_build_merge_request
|
||||
- .cic_notify_variables
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/cic-notify/**/*
|
||||
when: always
|
||||
|
||||
test-mr-cic-notify:
|
||||
stage: test
|
||||
extends:
|
||||
- .cic_notify_variables
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- test_requirements.txt
|
||||
paths:
|
||||
- /root/.cache/pip
|
||||
image: $MR_IMAGE_TAG
|
||||
script:
|
||||
- cd apps/$APP_NAME/
|
||||
- >
|
||||
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
|
||||
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
|
||||
-r test_requirements.txt
|
||||
- export PYTHONPATH=. && pytest -x --cov=cic_notify --cov-fail-under=90 --cov-report term-missing tests
|
||||
needs: ["build-mr-cic-notify"]
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/cic-eth/**/*
|
||||
when: always
|
||||
|
||||
build-push-cic-notify:
|
||||
extends:
|
||||
- .py_build_push
|
||||
- .cic_notify_variables
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "master"
|
||||
changes:
|
||||
- apps/cic-notify/**/*
|
||||
when: always
|
||||
|
||||
|
||||
|
||||
@@ -1,38 +1,30 @@
|
||||
FROM python:3.8.6-slim-buster
|
||||
# syntax = docker/dockerfile:1.2
|
||||
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
|
||||
|
||||
RUN apt-get update && \
|
||||
apt install -y gcc gnupg libpq-dev wget make g++ gnupg bash procps
|
||||
#RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2a62
|
||||
|
||||
WORKDIR /usr/src/cic-notify
|
||||
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
|
||||
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
|
||||
COPY requirements.txt .
|
||||
|
||||
ARG pip_extra_index_url_flag='--index https://pypi.org/simple --extra-index-url https://pip.grassrootseconomics.net:8433'
|
||||
RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2a62
|
||||
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
|
||||
pip install --index-url https://pypi.org/simple \
|
||||
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
|
||||
-r requirements.txt
|
||||
|
||||
COPY cic-notify/setup.cfg \
|
||||
cic-notify/setup.py \
|
||||
./
|
||||
COPY . .
|
||||
|
||||
COPY cic-notify/cic_notify/ ./cic_notify/
|
||||
RUN python setup.py install
|
||||
|
||||
COPY cic-notify/requirements.txt \
|
||||
cic-notify/test_requirements.txt \
|
||||
./
|
||||
|
||||
COPY cic-notify/scripts/ scripts/
|
||||
# TODO please review..can this go into requirements?
|
||||
RUN pip install $pip_extra_index_url_flag .[africastalking,notifylog]
|
||||
|
||||
COPY cic-notify/tests/ tests/
|
||||
COPY cic-notify/docker/db.sh \
|
||||
cic-notify/docker/start_tasker.sh \
|
||||
/root/
|
||||
|
||||
#RUN apk add postgresql-client
|
||||
#RUN apk add bash
|
||||
COPY docker/*.sh .
|
||||
|
||||
# ini files in config directory defines the configurable parameters for the application
|
||||
# they can all be overridden by environment variables
|
||||
# to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
|
||||
COPY cic-notify/.config/ /usr/local/etc/cic-notify/
|
||||
COPY cic-notify/cic_notify/db/migrations/ /usr/local/share/cic-notify/alembic/
|
||||
COPY .config/ /usr/local/etc/cic-notify/
|
||||
COPY cic_notify/db/migrations/ /usr/local/share/cic-notify/alembic/
|
||||
|
||||
WORKDIR /root
|
||||
ENTRYPOINT []
|
||||
|
||||
29
apps/cic-notify/docker/Dockerfile_ci
Normal file
29
apps/cic-notify/docker/Dockerfile_ci
Normal file
@@ -0,0 +1,29 @@
|
||||
# syntax = docker/dockerfile:1.2
|
||||
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
|
||||
|
||||
#RUN pip install $pip_extra_index_url_flag cic-base[full_graph]==0.1.2a62
|
||||
|
||||
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
|
||||
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
|
||||
COPY requirements.txt .
|
||||
|
||||
RUN pip install --index-url https://pypi.org/simple \
|
||||
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
|
||||
-r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN python setup.py install
|
||||
|
||||
# TODO please review..can this go into requirements?
|
||||
RUN pip install $pip_extra_index_url_flag .[africastalking,notifylog]
|
||||
|
||||
COPY docker/*.sh .
|
||||
|
||||
# ini files in config directory defines the configurable parameters for the application
|
||||
# they can all be overridden by environment variables
|
||||
# to generate a list of environment variables from configuration, use: confini-dump -z <dir> (executable provided by confini package)
|
||||
COPY .config/ /usr/local/etc/cic-notify/
|
||||
COPY cic_notify/db/migrations/ /usr/local/share/cic-notify/alembic/
|
||||
|
||||
ENTRYPOINT []
|
||||
4
apps/cic-ussd/.dockerignore
Normal file
4
apps/cic-ussd/.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
.git
|
||||
.cache
|
||||
.dot
|
||||
**/doc
|
||||
@@ -1,22 +1,52 @@
|
||||
.cic_ussd_variables:
|
||||
variables:
|
||||
APP_NAME: cic-ussd
|
||||
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
|
||||
|
||||
.cic_ussd_changes_target:
|
||||
rules:
|
||||
- changes:
|
||||
- $CONTEXT/$APP_NAME/*
|
||||
DOCKERFILE_PATH: docker/Dockerfile_ci
|
||||
CONTEXT: apps/$APP_NAME
|
||||
|
||||
build-mr-cic-ussd:
|
||||
extends:
|
||||
- .cic_ussd_changes_target
|
||||
- .py_build_merge_request
|
||||
- .cic_ussd_variables
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/cic-ussd/**/*
|
||||
when: always
|
||||
|
||||
test-mr-cic-ussd:
|
||||
stage: test
|
||||
extends:
|
||||
- .cic_ussd_variables
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- test_requirements.txt
|
||||
paths:
|
||||
- /root/.cache/pip
|
||||
image: $MR_IMAGE_TAG
|
||||
script:
|
||||
- cd apps/$APP_NAME/
|
||||
- >
|
||||
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
|
||||
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
|
||||
-r test_requirements.txt
|
||||
- export PYTHONPATH=. && pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests
|
||||
needs: ["build-mr-cic-ussd"]
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/cic-eth/**/*
|
||||
when: always
|
||||
|
||||
build-push-cic-ussd:
|
||||
extends:
|
||||
- .py_build_push
|
||||
- .cic_ussd_variables
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "master"
|
||||
changes:
|
||||
- apps/cic-ussd/**/*
|
||||
when: always
|
||||
|
||||
|
||||
|
||||
@@ -127,6 +127,8 @@ 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)
|
||||
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
# FROM python:3.8.5-alpine
|
||||
FROM python:3.8.6-slim-buster
|
||||
|
||||
# set working directory
|
||||
WORKDIR /usr/src
|
||||
|
||||
# add args for installing from self-hosted packages
|
||||
ARG pip_extra_index_url_flag='--extra-index-url https://pip.grassrootseconomics.net:8433'
|
||||
|
||||
RUN apt-get update && \
|
||||
apt install -y gcc gnupg libpq-dev wget make g++ gnupg bash procps git
|
||||
# syntax = docker/dockerfile:1.2
|
||||
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
|
||||
|
||||
# create secrets directory
|
||||
RUN mkdir -vp pgp/keys
|
||||
@@ -17,39 +8,25 @@ RUN mkdir -vp pgp/keys
|
||||
RUN mkdir -vp cic-ussd
|
||||
RUN mkdir -vp data
|
||||
|
||||
COPY cic-ussd/setup.cfg \
|
||||
cic-ussd/setup.py \
|
||||
cic-ussd/
|
||||
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
|
||||
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
|
||||
COPY requirements.txt .
|
||||
|
||||
COPY cic-ussd/requirements.txt \
|
||||
cic-ussd/test_requirements.txt \
|
||||
cic-ussd/
|
||||
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
|
||||
pip install --index-url https://pypi.org/simple \
|
||||
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
|
||||
-r requirements.txt
|
||||
|
||||
# install requirements
|
||||
RUN cd cic-ussd && \
|
||||
pip install -r requirements.txt $pip_extra_index_url_flag
|
||||
COPY . .
|
||||
RUN python setup.py install
|
||||
|
||||
# copy all necessary files
|
||||
COPY cic-ussd/cic_ussd/ cic-ussd/cic_ussd/
|
||||
COPY cic-ussd/cic_ussd/db/ussd_menu.json data/
|
||||
COPY cic-ussd/scripts/ cic-ussd/scripts/
|
||||
COPY cic-ussd/states/ cic-ussd/states/
|
||||
COPY cic-ussd/transitions/ cic-ussd/transitions/
|
||||
COPY cic-ussd/var/ cic-ussd/var/
|
||||
|
||||
COPY cic-ussd/docker/db.sh \
|
||||
cic-ussd/docker/start_cic_user_tasker.sh \
|
||||
cic-ussd/docker/start_cic_user_ussd_server.sh\
|
||||
cic-ussd/docker/start_cic_user_server.sh\
|
||||
/root/
|
||||
COPY cic_ussd/db/ussd_menu.json data/
|
||||
|
||||
COPY docker/*.sh .
|
||||
RUN chmod +x /root/*.sh
|
||||
RUN cd cic-ussd && \
|
||||
pip install $pip_extra_index_url_flag .
|
||||
|
||||
|
||||
# copy config and migration files to definitive file so they can be referenced in path definitions for running scripts
|
||||
COPY cic-ussd/.config/ /usr/local/etc/cic-ussd/
|
||||
COPY cic-ussd/cic_ussd/db/migrations/ /usr/local/share/cic-ussd/alembic
|
||||
COPY .config/ /usr/local/etc/cic-ussd/
|
||||
COPY cic_ussd/db/migrations/ /usr/local/share/cic-ussd/alembic
|
||||
|
||||
WORKDIR /root
|
||||
ENTRYPOINT []
|
||||
|
||||
32
apps/cic-ussd/docker/Dockerfile_ci
Normal file
32
apps/cic-ussd/docker/Dockerfile_ci
Normal file
@@ -0,0 +1,32 @@
|
||||
# syntax = docker/dockerfile:1.2
|
||||
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e as dev
|
||||
|
||||
|
||||
# create secrets directory
|
||||
RUN mkdir -vp pgp/keys
|
||||
|
||||
# create application directory
|
||||
RUN mkdir -vp cic-ussd
|
||||
RUN mkdir -vp data
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
|
||||
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
|
||||
RUN pip install --index-url https://pypi.org/simple \
|
||||
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
|
||||
-r requirements.txt
|
||||
|
||||
COPY . .
|
||||
RUN python setup.py install
|
||||
|
||||
COPY cic_ussd/db/ussd_menu.json data/
|
||||
|
||||
COPY docker/*.sh .
|
||||
RUN chmod +x /root/*.sh
|
||||
|
||||
# copy config and migration files to definitive file so they can be referenced in path definitions for running scripts
|
||||
COPY .config/ /usr/local/etc/cic-ussd/
|
||||
COPY cic_ussd/db/migrations/ /usr/local/share/cic-ussd/alembic
|
||||
|
||||
ENTRYPOINT []
|
||||
@@ -1,4 +1,4 @@
|
||||
cic_base[full_graph]==0.1.3a3+build.984b5cff
|
||||
cic-eth~=0.11.1a3
|
||||
cic-eth~=0.12.0a1
|
||||
cic-notify~=0.4.0a7
|
||||
cic-types~=0.1.0a11
|
||||
|
||||
4
apps/contract-migration/.dockerignore
Normal file
4
apps/contract-migration/.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
.git
|
||||
.cache
|
||||
.dot
|
||||
**/doc
|
||||
@@ -1,20 +1,25 @@
|
||||
.contract_migration_variables:
|
||||
variables:
|
||||
APP_NAME: contract-migration
|
||||
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
|
||||
|
||||
.contract_migration_changes_target:
|
||||
rules:
|
||||
- changes:
|
||||
- $CONTEXT/$APP_NAME/*
|
||||
DOCKERFILE_PATH: docker/Dockerfile_ci
|
||||
CONTEXT: apps/$APP_NAME
|
||||
|
||||
build-mr-contract-migration:
|
||||
extends:
|
||||
- .contract_migration_changes_target
|
||||
- .py_build_merge_request
|
||||
- .contract_migration_variables
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/contract-migration/**/*
|
||||
when: always
|
||||
|
||||
build-push-contract-migration:
|
||||
extends:
|
||||
- .py_build_push
|
||||
- .contract_migration_variables
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "master"
|
||||
changes:
|
||||
- apps/contract-migration/**/*
|
||||
when: always
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
# 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-55da5f4e
|
||||
|
||||
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
|
||||
WORKDIR /root
|
||||
|
||||
RUN touch /etc/apt/sources.list.d/ethereum.list
|
||||
RUN echo 'deb http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic main' > /etc/apt/sources.list.d/ethereum.list
|
||||
RUN echo 'deb-src http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic main' >> /etc/apt/sources.list.d/ethereum.list
|
||||
|
||||
RUN cat etc/apt/sources.list.d/ethereum.list
|
||||
RUN cat /etc/apt/sources.list.d/ethereum.list
|
||||
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 2A518C819BE37D2C2031944D1C52189C923F6CA9
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install solc
|
||||
RUN pip install --upgrade pip
|
||||
#RUN apt-get install solc
|
||||
|
||||
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=35c69ba75f00c8147150acf325565d5391cf25bf
|
||||
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 && \
|
||||
@@ -31,70 +25,18 @@ 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
|
||||
COPY requirements.txt .
|
||||
|
||||
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 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
|
||||
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
|
||||
|
||||
# -------------- 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 [ ]
|
||||
COPY . .
|
||||
RUN chmod +x *.sh
|
||||
|
||||
41
apps/contract-migration/docker/Dockerfile_ci
Normal file
41
apps/contract-migration/docker/Dockerfile_ci
Normal file
@@ -0,0 +1,41 @@
|
||||
# syntax = docker/dockerfile:1.2
|
||||
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55da5f4e
|
||||
|
||||
WORKDIR /root
|
||||
|
||||
RUN touch /etc/apt/sources.list.d/ethereum.list
|
||||
RUN echo 'deb http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic main' > /etc/apt/sources.list.d/ethereum.list
|
||||
RUN echo 'deb-src http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic main' >> /etc/apt/sources.list.d/ethereum.list
|
||||
RUN cat /etc/apt/sources.list.d/ethereum.list
|
||||
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 2A518C819BE37D2C2031944D1C52189C923F6CA9
|
||||
|
||||
#RUN apt-get install solc
|
||||
|
||||
RUN mkdir -vp /usr/local/etc/cic
|
||||
|
||||
ENV CONFINI_DIR /usr/local/etc/cic/
|
||||
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 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 . .
|
||||
RUN chmod +x *.sh
|
||||
3
apps/contract-migration/override_requirements.txt
Normal file
3
apps/contract-migration/override_requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
#eth-contract-registry==0.5.5a3
|
||||
#erc20-demurrage-token==0.0.2a3
|
||||
#eth-address-index==0.1.1a12
|
||||
@@ -1,4 +1,5 @@
|
||||
cic-base[full_graph]==0.1.2b15
|
||||
sarafu-faucet==0.0.3a3
|
||||
sarafu-token==0.0.1a8
|
||||
cic-eth==0.11.0b16
|
||||
cic_base[full]==0.1.3a4+build.ce68c833
|
||||
sarafu-faucet~=0.0.4a1
|
||||
cic-eth[tools]==0.12.0a2
|
||||
eth-erc20~=0.0.10a3
|
||||
erc20-demurrage-token==0.0.2a3
|
||||
|
||||
@@ -2,8 +2,28 @@
|
||||
|
||||
set -a
|
||||
|
||||
CIC_CHAIN_SPEC=${CIC_CHAIN_SPEC:-evm:bloxberg:8995}
|
||||
default_token=giftable_erc20_token
|
||||
CIC_DEFAULT_TOKEN_SYMBOL=${CIC_DEFAULT_TOKEN_SYMBOL:-GFT}
|
||||
TOKEN_SYMBOL=${CIC_DEFAULT_TOKEN_SYMBOL}
|
||||
TOKEN_NAME=${TOKEN_NAME:-$TOKEN_SYMBOL}
|
||||
TOKEN_TYPE=${TOKEN_TYPE:-$default_token}
|
||||
if [ $TOKEN_TYPE == 'default' ]; then
|
||||
>&2 echo resolving "default" token to $default_token
|
||||
TOKEN_TYPE=$default_token
|
||||
fi
|
||||
cat <<EOF
|
||||
external token settings:
|
||||
token_type: $TOKEN_TYPE
|
||||
token_symbol: $TOKEN_SYMBOL
|
||||
token_name: $TOKEN_NAME
|
||||
token_decimals: $TOKEN_DECIMALS
|
||||
token_demurrage: $TOKEN_DEMURRAGE_LEVEL
|
||||
token_redistribution_period: $TOKEN_REDISTRIBUTION_PERIOD
|
||||
token_supply_limit: $TOKEN_SUPPLY_LIMIT
|
||||
EOF
|
||||
|
||||
CIC_CHAIN_SPEC=${CIC_CHAIN_SPEC:-evm:bloxberg:8995}
|
||||
TOKEN_SYMBOL=${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}
|
||||
@@ -19,11 +39,6 @@ if [ ! -z $DEV_ETH_GAS_PRICE ]; then
|
||||
>&2 echo using static gas price $DEV_ETH_GAS_PRICE
|
||||
fi
|
||||
|
||||
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
|
||||
|
||||
echo "environment:"
|
||||
printenv
|
||||
echo \n
|
||||
@@ -60,17 +75,23 @@ if [[ -n "${ETH_PROVIDER}" ]]; then
|
||||
./wait-for-it.sh "${ETH_PROVIDER_HOST}:${ETH_PROVIDER_PORT}"
|
||||
fi
|
||||
|
||||
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 -w --name "Giftable Token" --symbol "GFT" --decimals 6 -vv`
|
||||
if [ $TOKEN_TYPE == $default_token ]; then
|
||||
>&2 echo deploying default token $TOKEN_TYPE
|
||||
DEV_RESERVE_ADDRESS=`giftable-token-deploy $gas_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -vv -ww --name $TOKEN_NAME --symbol $TOKEN_SYMBOL --decimals 6 -vv`
|
||||
elif [ $TOKEN_TYPE == 'erc20_demurrage_token' ]; then
|
||||
>&2 echo deploying token $TOKEN_TYPE
|
||||
if [ -z $TOKEN_SINK_ADDRESS ]; then
|
||||
if [ ! -z $TOKEN_REDISTRIBUTION_PERIOD ]; then
|
||||
>&2 echo -e "\033[;93mtoken sink address not set, so redistribution will be BURNED\033[;39m"
|
||||
fi
|
||||
fi
|
||||
DEV_RESERVE_ADDRESS=`erc20-demurrage-token-deploy $gas_price_arg -p $ETH_PROVIDER -y $DEV_ETH_KEYSTORE_FILE -i $CIC_CHAIN_SPEC -vv -ww`
|
||||
else
|
||||
>&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`
|
||||
>&2 echo unknown token type $TOKEN_TYPE
|
||||
exit 1
|
||||
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"
|
||||
|
||||
@@ -2,13 +2,22 @@
|
||||
|
||||
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
|
||||
exit 1;
|
||||
>&2 echo -e "\033[;31mFAILED\033[;39m RUN_MASK 1 - contract deployment"
|
||||
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
|
||||
|
||||
@@ -14,6 +14,7 @@ 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
|
||||
@@ -98,8 +99,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 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}
|
||||
>&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}
|
||||
|
||||
#echo -n 0 > $init_level_file
|
||||
|
||||
|
||||
4
apps/data-seeding/.dockerignore
Normal file
4
apps/data-seeding/.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
.git
|
||||
.cache
|
||||
.dot
|
||||
**/doc
|
||||
@@ -1,21 +1,26 @@
|
||||
.data_seeding_variables:
|
||||
variables:
|
||||
APP_NAME: data-seeding
|
||||
DOCKERFILE_PATH: $APP_NAME/docker/Dockerfile
|
||||
|
||||
.data_seeding_changes_target:
|
||||
rules:
|
||||
- changes:
|
||||
- $CONTEXT/$APP_NAME/*
|
||||
DOCKERFILE_PATH: docker/Dockerfile_ci
|
||||
CONTEXT: apps/$APP_NAME
|
||||
|
||||
build-mr-data-seeding:
|
||||
extends:
|
||||
- .data_seeding_changes_target
|
||||
- .py_build_merge_request
|
||||
- .data_seeding_variables
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
- apps/data-seeding/**/*
|
||||
when: always
|
||||
|
||||
build-push-data-seeding:
|
||||
extends:
|
||||
- .py_build_push
|
||||
- .data_seeding_variables
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "master"
|
||||
changes:
|
||||
- apps/data-seeding/**/*
|
||||
when: always
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import redis
|
||||
import celery
|
||||
from cic_eth_registry.registry import CICRegistry
|
||||
from chainsyncer.backend.memory import MemBackend
|
||||
from chainsyncer.driver import HeadSyncer
|
||||
from chainsyncer.driver.head import HeadSyncer
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
from chainlib.chain import ChainSpec
|
||||
from chainlib.eth.gas import RPCGasOracle
|
||||
@@ -24,6 +24,7 @@ from cic_base import (
|
||||
rpc,
|
||||
signer as signer_funcs,
|
||||
)
|
||||
from cic_base.eth.syncer import chain_interface
|
||||
|
||||
# local imports
|
||||
#import common
|
||||
@@ -120,7 +121,7 @@ def main():
|
||||
'api_queue': config.get('_CELERY_QUEUE'),
|
||||
}
|
||||
|
||||
syncer = HeadSyncer(syncer_backend, block_callback=handler.refresh)
|
||||
syncer = HeadSyncer(syncer_backend, chain_interface, block_callback=handler.refresh)
|
||||
syncer.add_filter(handler)
|
||||
syncer.loop(1, conn)
|
||||
|
||||
|
||||
@@ -93,9 +93,9 @@ function importMeta(keystore) {
|
||||
let files;
|
||||
|
||||
try {
|
||||
err, files = fs.readdirSync(workDir);
|
||||
} catch {
|
||||
console.error('source directory not yet ready', workDir);
|
||||
files = fs.readdirSync(workDir);
|
||||
} catch (err) {
|
||||
console.error('source directory not yet ready', workDir, 'reason: ', err);
|
||||
setTimeout(importMeta, batchDelay, keystore);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
# standard imports
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import argparse
|
||||
import hashlib
|
||||
import redis
|
||||
import celery
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
|
||||
# external imports
|
||||
import celery
|
||||
import confini
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
import redis
|
||||
from chainlib.chain import ChainSpec
|
||||
from hexathon import (
|
||||
strip_0x,
|
||||
add_0x,
|
||||
)
|
||||
from chainlib.eth.address import to_checksum_address
|
||||
from chainlib.eth.connection import EthHTTPConnection
|
||||
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_util import BalanceProcessor
|
||||
from import_task import *
|
||||
from import_task import ImportTask, MetadataTask
|
||||
from import_util import BalanceProcessor, get_celery_worker_status
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
@@ -41,37 +35,41 @@ 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='SRF', type=str, dest='token_symbol', help='Token symbol to use for trnsactions')
|
||||
argparser.add_argument('--token-symbol', default='GFT', type=str, dest='token_symbol',
|
||||
help='Token symbol to use for transactions')
|
||||
argparser.add_argument('--head', action='store_true', help='start at current block height (overrides --offset)')
|
||||
argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration')
|
||||
argparser.add_argument('-q', type=str, default='cic-eth', 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-import-ussd', help='celery queue to submit transaction tasks to')
|
||||
argparser.add_argument('--offset', type=int, default=0, help='block offset to start syncer from')
|
||||
argparser.add_argument('-v', help='be verbose', action='store_true')
|
||||
argparser.add_argument('-vv', help='be more verbose', action='store_true')
|
||||
argparser.add_argument('user_dir', default='out', type=str, help='user export directory')
|
||||
args = argparser.parse_args(sys.argv[1:])
|
||||
|
||||
if args.v == True:
|
||||
if args.v:
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
elif args.vv == True:
|
||||
|
||||
elif args.vv:
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
|
||||
config_dir = os.path.join(args.c)
|
||||
os.makedirs(config_dir, 0o777, True)
|
||||
config = confini.Config(config_dir, args.env_prefix)
|
||||
config.process()
|
||||
|
||||
# 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')
|
||||
@@ -81,14 +79,19 @@ 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)
|
||||
celery_app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL'))
|
||||
|
||||
# create celery apps
|
||||
celery_app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL'))
|
||||
status = get_celery_worker_status(celery_app=celery_app)
|
||||
|
||||
signer_address = None
|
||||
keystore = DictKeystore()
|
||||
if args.y != None:
|
||||
if args.y is not 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
|
||||
@@ -103,7 +106,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
|
||||
|
||||
@@ -111,20 +114,22 @@ 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 == None:
|
||||
if l is None:
|
||||
break
|
||||
r = l.split(',')
|
||||
try:
|
||||
@@ -143,15 +148,23 @@ def main():
|
||||
ImportTask.import_dir = user_dir
|
||||
|
||||
s = celery.signature(
|
||||
'import_task.send_txs',
|
||||
[
|
||||
MetadataTask.balance_processor.nonce_offset,
|
||||
],
|
||||
queue='cic-import-ussd',
|
||||
)
|
||||
'import_task.send_txs',
|
||||
[
|
||||
MetadataTask.balance_processor.nonce_offset,
|
||||
],
|
||||
queue=queue,
|
||||
)
|
||||
s.apply_async()
|
||||
|
||||
argv = ['worker', '-Q', 'cic-import-ussd', '--loglevel=DEBUG']
|
||||
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)
|
||||
celery_app.worker_main(argv)
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import celery
|
||||
import confini
|
||||
|
||||
# local imports
|
||||
from import_task import *
|
||||
from import_util import get_celery_worker_status
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logg = logging.getLogger()
|
||||
@@ -39,9 +39,12 @@ 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'),
|
||||
@@ -61,7 +64,8 @@ def main():
|
||||
(db_configs, phone_to_pins),
|
||||
queue=args.q
|
||||
)
|
||||
s_import_pins.apply_async()
|
||||
result = s_import_pins.apply_async()
|
||||
logg.debug(f'TASK: {result.id}, STATUS: {result.status}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,36 +1,33 @@
|
||||
# standard imports
|
||||
import os
|
||||
import logging
|
||||
import random
|
||||
import urllib.parse
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
# 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.processor import generate_metadata_pointer
|
||||
unpack,
|
||||
raw,
|
||||
)
|
||||
from cic_types.models.person import Person
|
||||
from cic_types.processor import generate_metadata_pointer
|
||||
from hexathon import (
|
||||
strip_0x,
|
||||
add_0x,
|
||||
)
|
||||
|
||||
#logg = logging.getLogger().getChild(__name__)
|
||||
logg = logging.getLogger()
|
||||
|
||||
celery_app = celery.current_app
|
||||
|
||||
|
||||
class ImportTask(celery.Task):
|
||||
|
||||
balances = None
|
||||
import_dir = 'out'
|
||||
count = 0
|
||||
@@ -38,16 +35,16 @@ class ImportTask(celery.Task):
|
||||
balance_processor = None
|
||||
max_retries = None
|
||||
|
||||
class MetadataTask(ImportTask):
|
||||
|
||||
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
|
||||
@@ -64,12 +61,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()
|
||||
@@ -97,11 +94,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)
|
||||
@@ -116,12 +113,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()
|
||||
@@ -131,10 +128,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
|
||||
@@ -180,10 +177,8 @@ 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)
|
||||
|
||||
|
||||
k = to_checksum_address(strip_0x(old_address))
|
||||
balance = self.balances[k]
|
||||
logg.debug('found balance {} for address {} phone {}'.format(balance, old_address, phone))
|
||||
@@ -196,39 +191,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()
|
||||
@@ -238,21 +233,20 @@ 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
|
||||
|
||||
|
||||
@@ -310,4 +304,3 @@ def set_ussd_data(config: dict, ussd_data: dict):
|
||||
# close connections
|
||||
db_cursor.close()
|
||||
db_conn.close()
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ 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()
|
||||
|
||||
@@ -28,11 +31,14 @@ 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')
|
||||
@@ -49,13 +55,16 @@ 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')
|
||||
@@ -65,22 +74,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)
|
||||
os.makedirs(user_new_dir, exist_ok=True)
|
||||
|
||||
ussd_data_dir = os.path.join(args.user_dir, 'ussd')
|
||||
os.makedirs(ussd_data_dir)
|
||||
os.makedirs(ussd_data_dir, exist_ok=True)
|
||||
|
||||
preferences_dir = os.path.join(args.user_dir, 'preferences')
|
||||
os.makedirs(os.path.join(preferences_dir, 'meta'))
|
||||
os.makedirs(os.path.join(preferences_dir, 'meta'), exist_ok=True)
|
||||
|
||||
meta_dir = os.path.join(args.user_dir, 'meta')
|
||||
os.makedirs(meta_dir)
|
||||
os.makedirs(meta_dir, exist_ok=True)
|
||||
|
||||
user_old_dir = os.path.join(args.user_dir, 'old')
|
||||
os.stat(user_old_dir)
|
||||
|
||||
txs_dir = os.path.join(args.user_dir, 'txs')
|
||||
os.makedirs(txs_dir)
|
||||
os.makedirs(txs_dir, exist_ok=True)
|
||||
|
||||
chain_spec = ChainSpec.from_chain_str(config.get('CIC_CHAIN_SPEC'))
|
||||
chain_str = str(chain_spec)
|
||||
@@ -95,6 +104,7 @@ 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:
|
||||
@@ -109,13 +119,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')
|
||||
@@ -150,7 +160,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)
|
||||
@@ -164,35 +174,35 @@ if __name__ == '__main__':
|
||||
f.close()
|
||||
u = Person.deserialize(o)
|
||||
|
||||
new_address = register_ussd(i, u)
|
||||
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)
|
||||
@@ -206,4 +216,3 @@ if __name__ == '__main__':
|
||||
if j == batch_size:
|
||||
time.sleep(batch_delay)
|
||||
j = 0
|
||||
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
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 eth_erc20 import ERC20
|
||||
from chainlib.eth.tx import (
|
||||
count,
|
||||
TxFormat,
|
||||
)
|
||||
count,
|
||||
TxFormat,
|
||||
)
|
||||
from celery import Celery
|
||||
from eth_contract_registry import Registry
|
||||
from eth_erc20 import ERC20
|
||||
from eth_token_index import TokenUniqueSymbolIndex
|
||||
|
||||
logg = logging.getLogger().getChild(__name__)
|
||||
|
||||
@@ -18,10 +19,9 @@ 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,7 +35,6 @@ class BalanceProcessor:
|
||||
self.gas_oracle = OverrideGasOracle(conn=conn, limit=8000000)
|
||||
|
||||
self.value_multiplier = 1
|
||||
|
||||
|
||||
def init(self, token_symbol):
|
||||
# Get Token registry address
|
||||
@@ -57,16 +56,25 @@ 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[pgp]
|
||||
exports_dir = ../contract-migration/testdata/pgp
|
||||
exports_dir = testdata/pgp
|
||||
private_key_file = privatekeys_meta.asc
|
||||
public_key_file = publickeys_meta.asc
|
||||
passphrase = merman
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
# 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 \
|
||||
COPY package.json \
|
||||
package-lock.json \
|
||||
.
|
||||
|
||||
RUN npm install
|
||||
RUN --mount=type=cache,mode=0755,target=/root/node_modules npm install
|
||||
|
||||
COPY data-seeding/requirements.txt .
|
||||
COPY requirements.txt .
|
||||
|
||||
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
|
||||
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
|
||||
RUN pip install --extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL -r requirements.txt
|
||||
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
|
||||
|
||||
COPY data-seeding/ .
|
||||
COPY . .
|
||||
|
||||
ENTRYPOINT [ ]
|
||||
|
||||
24
apps/data-seeding/docker/Dockerfile_ci
Normal file
24
apps/data-seeding/docker/Dockerfile_ci
Normal file
@@ -0,0 +1,24 @@
|
||||
# syntax = docker/dockerfile:1.2
|
||||
FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-5ab8bf45
|
||||
|
||||
WORKDIR /root
|
||||
|
||||
RUN mkdir -vp /usr/local/etc/cic
|
||||
|
||||
COPY package.json \
|
||||
package-lock.json \
|
||||
.
|
||||
|
||||
RUN npm install
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
|
||||
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
|
||||
RUN pip install \
|
||||
--extra-index-url $GITLAB_PYTHON_REGISTRY \
|
||||
--extra-index-url $EXTRA_INDEX_URL -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
ENTRYPOINT [ ]
|
||||
@@ -1,5 +1,4 @@
|
||||
cic_base[full_graph]==0.1.3a3+build.984b5cff
|
||||
sarafu-faucet==0.0.4a1
|
||||
cic-eth==0.11.1a1
|
||||
cic-eth[tools]==0.12.0a1
|
||||
cic-types==0.1.0a13
|
||||
crypto-dev-signer==0.4.14b6
|
||||
|
||||
83
apps/data-seeding/testdata/pgp/alice.priv.asc
vendored
Normal file
83
apps/data-seeding/testdata/pgp/alice.priv.asc
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
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
|
||||
=zMNq
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
41
apps/data-seeding/testdata/pgp/alice.pub.asc
vendored
Normal file
41
apps/data-seeding/testdata/pgp/alice.pub.asc
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
xgjhMwawpFV3APdc0dOIvUdZAFQ=
|
||||
=BKz+
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
83
apps/data-seeding/testdata/pgp/bob.priv.asc
vendored
Normal file
83
apps/data-seeding/testdata/pgp/bob.priv.asc
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
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
|
||||
=qmcx
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
41
apps/data-seeding/testdata/pgp/bob.pub.asc
vendored
Normal file
41
apps/data-seeding/testdata/pgp/bob.pub.asc
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
n0OSM7kpK5v6VPdtByaN6w==
|
||||
=EmWr
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
83
apps/data-seeding/testdata/pgp/ge.priv.asc
vendored
Normal file
83
apps/data-seeding/testdata/pgp/ge.priv.asc
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
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
|
||||
=B12U
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user