Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Network / Contracts models + CRUD endpoints + Celery Orchestration #44

Merged
merged 26 commits into from
Mar 16, 2021

Conversation

frisitano
Copy link
Member

@frisitano frisitano commented Mar 1, 2021

This PR introduces database tables for both chains and contracts and associated CRUD endpoints to interact with these tables. This will allow the user to activate / deactivate chains and contracts, and also allows them to add / delete contracts.

When a chain / contract is activated / deactivated / create / deleted, all celery collector tasks are terminated and new collector tasks are executed to reflect the updated chain statuses.

closes #21
supports paralink-network/paralink-ui#10

@frisitano frisitano mentioned this pull request Mar 1, 2021
Copy link
Member

@jbargu jbargu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of questions:

  1. Would it be possible to terminate only the workers that have changed in the request?
  2. I would at least test the client <-> DB interaction in this PR.
  3. Have you thought about how could we perform integration tests with celery? It does not need to be in this PR but it should be somehow included as it is the critical functionality of the node.

src/__init__.py Outdated
@@ -36,7 +40,9 @@ def create_app(args: dict = {}) -> Sanic: # noqa: C901
if app.config["ENABLE_BACKGROUND_WORKER"]:
from src.process.collector import start_collecting

asyncio.get_event_loop().run_until_complete(start_collecting(chains))
@app.listener("after_server_start")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move this below to have all the hooks on the same place?

except ActiveChainFailed as e:
raise NotFound(e)

await restart_collectors(processor, chains, request.app.db)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I tried curl -X PUT -H "Content-Type: application/json" -d '{"active":true}' localhost:7424/api/chains/eth.mainnet without the celery worker running this part would fail but the chain status would be updated. Also any other problems would result in the same behaviour. We should either wrap the DB update into transaction or return appropriate message if the collector restart failed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My proposal would be to check if the celery worker is enabled app.config["ENABLE_DATABASE"] == True. If the celery worker is enabled then we would restart the appropriate celery chain collector. If not then we would do nothing. This will allow the user to configure the desired chain / contract statuses whilst the celery worker is disabled.

@@ -15,8 +15,7 @@
"src.process.collector.*": {"queue": "collect"},
"src.process.executor.*": {"queue": "execute"},
},
task_serializer="pickle",
accept_content=["json", "pickle"],
accept_content=["json"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

"""
data = request.json
await Contract.create_contract(
request.app.db, data["id"], data["active"], data["chain"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Data should be validated:

  • is the given address of a correct format depending on the chain?


__tablename__ = "contracts"

id = sa.Column(sa.String, primary_key=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contract model requires an address field. With this setup now we cannot have 2 contracts with the same address on 2 different chains (e.g. ETH, BSC). A contract can therefore be uniquely identifiable by a (address, chain) tuple.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the address field. I have not had time to change the interfaces to use a (address, chain) as a primary key for the contracts. They are currently using the id field which is an auto-incrementing integer. I can change this tomorrow.

@frisitano
Copy link
Member Author

A couple of questions:

  1. Would it be possible to terminate only the workers that have changed in the request?
  2. I would at least test the client <-> DB interaction in this PR.
  3. Have you thought about how could we perform integration tests with celery? It does not need to be in this PR but it should be somehow included as it is the critical functionality of the node.
  1. Yes it will be possible to terminate only the worker that has changed, I'll update the PR to do this.
  2. Good point, I will get some tests written.
  3. Yes we could run our tests using the docker-compose stack. We could probably reuse the paralink_node docker image and just execute a test command (you could also execute examples in a similar. Viable solution for Missing integration tests #41? ):
    command: /wait-for-it.sh -t 0 rabbitmq:5672 -- pipenv run pytest
    We would need to take care and run tests synchronously when testing the dynamics of the tasks on the workers (restarting chains)

@frisitano frisitano requested a review from jbargu March 16, 2021 00:08
Copy link
Member

@jbargu jbargu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, thank you. I made a couple of tests locally, it seems to work alright. I had hoped you will include the integration tests: client -> API endpoints -> DB as this is what we care from the FE side but I guess this is fine.

RUN mkdir /home/worker/paralink-node
RUN mkdir /home/worker/paralink-node/data
RUN mkdir -p /home/worker/paralink-node
RUN mkdir -p /home/worker/paralink-node/data
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this does not exposes the system for any vulnerabilities.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will resolve this shortly. I was thinking we can provide a build flag to indicate if the root user should be used. We can then toggle root on for github builds and turn it off for operation. What do you think?

@@ -5,4 +5,6 @@
from src.network.chains import Chains

chain_config = Path(config.DATA_FOLDER).joinpath("chain_config.json")
chains = Chains.read_from_json(str(chain_config.absolute()))
chains = Chains.from_list(
json.load(open(Path(config.DATA_FOLDER).joinpath("chain_config.json")))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why this cannot use the above chain_config variable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason... just me being blind 😄

@pytest.fixture()
async def tables(engine):
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to migrate or use schema + migrate to spot any issues regarding the migrations. I guess this will do for now. The tables are persisted though, since you do not call drop_all anywhere. Not a major issue, if we are using a new DB every time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performing the migration sounds like a sensible thing to do. I will see about changing this.

@jbargu jbargu merged commit 3a56b92 into paralink-network:master Mar 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add PostgreSQL network, tracked contracts table
2 participants