Skip to content

Commit

Permalink
Add delegation table, create delegation C-2293 (#5188)
Browse files Browse the repository at this point in the history
Co-authored-by: Nikki Kang <kangaroo233@gmail.com>
  • Loading branch information
nicoback2 and nicoback committed May 4, 2023
1 parent a90b483 commit c7fec30
Show file tree
Hide file tree
Showing 8 changed files with 540 additions and 11 deletions.
18 changes: 17 additions & 1 deletion discovery-provider/alembic/trigger_sql/ddl.sql
Expand Up @@ -122,7 +122,6 @@ begin;
);
commit;


-- 4/26/23: add AI columns
BEGIN;
DO $$ BEGIN
Expand Down Expand Up @@ -150,3 +149,20 @@ BEGIN;
WHERE is_current = true AND LENGTH(track_cid) = 47 AND track_cid LIKE 'Qm%';
COMMIT;

-- 5/4/23: create delegations table
BEGIN;
create table public.delegations (
shared_address varchar not null,
blockhash varchar references blocks(blockhash),
blocknumber integer references blocks(number),
delegate_address varchar not null,
user_id integer not null,
is_revoked boolean not null default false,
is_current boolean not null,
is_approved boolean not null default false,
updated_at timestamp not null,
created_at timestamp not null,
txhash varchar not null,
primary key (shared_address, is_current, txhash)
);
COMMIT;
@@ -0,0 +1,251 @@
from typing import List

from integration_tests.challenges.index_helpers import UpdateTask
from integration_tests.utils import populate_mock_db
from src.models.delegates.delegation import Delegation
from src.tasks.entity_manager.entity_manager import entity_manager_update
from src.tasks.entity_manager.utils import Action, EntityType
from src.utils.db_session import get_db
from web3 import Web3
from web3.datastructures import AttributeDict

new_delegations_data = [
{
"user_id": 1,
"shared_address": "0xDEA175F7C4c773DC54FC7C132eA85805936069BF",
"delegate_address": "user3wallet",
"is_user_delegation": True,
},
{
"user_id": 1,
"shared_address": "0x2aa4998ddf6A2C365323021061E0AE0F18F5a1DC",
"delegate_address": "0x3a388671bb4D6E1Ea08D79Ee191b40FB45A8F4C4",
"is_user_delegation": False,
},
{
"user_id": 1,
"shared_address": "0xaCa953E9197B79ca297A51315eA7FB467e062757",
"delegate_address": "0x04c9fc3784120f50932436f84c59aebebb12e0d",
"is_user_delegation": False,
},
]


def test_index_delegation(app, mocker):
"Tests delegation create action"

# setup db and mocked txs
with app.app_context():
db = get_db()
web3 = Web3()
update_task = UpdateTask(None, web3, None)

tx_receipts = {
"CreateDelegationTx1": [
{
"args": AttributeDict(
{
"_entityId": 0,
"_entityType": EntityType.DELEGATION,
"_userId": new_delegations_data[0]["user_id"],
"_metadata": f"""{{"shared_address": "{new_delegations_data[0]["shared_address"]}", "delegate_address": "{new_delegations_data[0]["delegate_address"]}"}}""",
"_action": Action.CREATE,
"_signer": "user1wallet",
}
)
},
],
"CreateDelegateTx2": [
{
"args": AttributeDict(
{
"_entityId": 0,
"_entityType": EntityType.DELEGATION,
"_userId": new_delegations_data[1]["user_id"],
"_metadata": f"""{{"shared_address": "{new_delegations_data[1]["shared_address"]}", "delegate_address": "{new_delegations_data[1]["delegate_address"]}"}}""",
"_action": Action.CREATE,
"_signer": "user1wallet",
}
)
},
],
"CreateDelegateTx3": [
{
"args": AttributeDict(
{
"_entityId": 0,
"_entityType": EntityType.DELEGATION,
"_userId": new_delegations_data[2]["user_id"],
"_metadata": f"""{{"shared_address": "{new_delegations_data[2]["shared_address"]}", "delegate_address": "{new_delegations_data[2]["delegate_address"]}"}}""",
"_action": Action.CREATE,
"_signer": "user1wallet",
}
)
},
],
}

entity_manager_txs = [
AttributeDict({"transactionHash": update_task.web3.toBytes(text=tx_receipt)})
for tx_receipt in tx_receipts
]

def get_events_side_effect(_, tx_receipt):
return tx_receipts[tx_receipt.transactionHash.decode("utf-8")]

mocker.patch(
"src.tasks.entity_manager.entity_manager.get_entity_manager_events_tx",
side_effect=get_events_side_effect,
autospec=True,
)

entities = {
"users": [
{"user_id": user_id, "wallet": f"user{user_id}wallet"}
for user_id in range(1, 6)
],
"app_delegates": [
{
"user_id": 5,
"name": "My App",
"address": "0x3a388671bb4D6E1Ea08D79Ee191b40FB45A8F4C4",
},
{
"user_id": 4,
"name": "My App",
"address": "0x04c9fc3784120f50932436f84c59aebebb12e0d",
},
],
"delegations": [
{
"user_id": 1,
"shared_address": "0xdB384D555480214632D08609848BbFB54CCeb76c",
"delegate_address": "0x04c9fc3784120f50932436f84c59aebebb12e0d",
}
],
}
populate_mock_db(db, entities)

with db.scoped_session() as session:
# index transactions
entity_manager_update(
None,
update_task,
session,
entity_manager_txs,
block_number=0,
block_timestamp=1000000000,
block_hash=0,
metadata={},
)

# validate db records
all_delegations: List[Delegation] = session.query(Delegation).all()
assert len(all_delegations) == 4

for expected_delegation in new_delegations_data:
found_matches = [
item
for item in all_delegations
if item.shared_address == expected_delegation["shared_address"].lower()
]
assert len(found_matches) == 1
res = found_matches[0]
assert res.user_id == expected_delegation["user_id"]
assert res.shared_address == expected_delegation["shared_address"].lower()
assert res.is_current == True
assert (
res.delegate_address == expected_delegation["delegate_address"].lower()
)
if expected_delegation["is_user_delegation"]:
assert res.is_approved == False
else:
assert res.is_approved == True
assert res.blocknumber == 0

# Test invalid create delegation txs
tx_receipts = {
"CreateDelegationInvalidTx1": [
{
# Incorrect signer
"args": AttributeDict(
{
"_entityId": 0,
"_entityType": EntityType.DELEGATION,
"_userId": 1,
"_metadata": '{"shared_address": "0x7899C15374cD5E332656BDDc6801c16af76a584B", "delegate_address": "0x04c9fc3784120f50932436f84c59aebebb12e0d"}',
"_action": Action.CREATE,
"_signer": "user2wallet",
}
)
},
],
"CreateDelegationInvalidTx2": [
{
# Duplicate address
"args": AttributeDict(
{
"_entityId": 0,
"_entityType": EntityType.DELEGATION,
"_userId": 1,
"_metadata": '{"shared_address": "0xdB384D555480214632D08609848BbFB54CCeb76c", "delegate_address": "0x04c9fc3784120f50932436f84c59aebebb12e0d"}',
"_action": Action.CREATE,
"_signer": "user1wallet",
}
)
},
],
"CreateDelegationInvalidTx3": [
{
# Delegate doesn't exist
"args": AttributeDict(
{
"_entityId": 0,
"_entityType": EntityType.DELEGATION,
"_userId": 2,
"_action": Action.CREATE,
"_metadata": '{"shared_address": "0xaB6Ac417265Ee2B8A1f1f460987CeF5Be71584b9", "delegate_address": "0xB131910795586228F0D11c1560771aea9DB382C8"}',
"_signer": "user2wallet",
}
)
},
],
"CreateDelegationInvalidTx4": [
{
# Missing metadata
"args": AttributeDict(
{
"_entityId": 0,
"_entityType": EntityType.DELEGATION,
"_userId": 2,
"_action": Action.CREATE,
"_metadata": '{"shared_address": "0x1843CaAa96a173e8e31FD43503f44c33e4471385"}',
"_signer": "user2wallet",
}
)
},
],
}

entity_manager_txs = [
AttributeDict({"transactionHash": update_task.web3.toBytes(text=tx_receipt)})
for tx_receipt in tx_receipts
]

with db.scoped_session() as session:
# index transactions
timestamp = 1000000001
entity_manager_update(
None,
update_task,
session,
entity_manager_txs,
block_number=0,
block_timestamp=timestamp,
block_hash=0,
metadata={},
)
# validate db records
all_delegations: List[Delegation] = session.query(Delegation).all()
# make sure no new rows were added
assert len(all_delegations) == 4
23 changes: 21 additions & 2 deletions discovery-provider/integration_tests/utils.py
@@ -1,6 +1,7 @@
from datetime import datetime

from src.models.delegates.app_delegate import AppDelegate
from src.models.delegates.delegation import Delegation
from src.models.indexing.block import Block
from src.models.indexing.indexing_checkpoints import IndexingCheckpoint
from src.models.indexing.ursm_content_node import UrsmContentNode
Expand Down Expand Up @@ -111,6 +112,7 @@ def populate_mock_db(db, entities, block_offset=None):
playlists = entities.get("playlists", [])
users = entities.get("users", [])
app_delegates = entities.get("app_delegates", [])
delegations = entities.get("delegations", [])
follows = entities.get("follows", [])
subscriptions = entities.get("subscriptions", [])
reposts = entities.get("reposts", [])
Expand Down Expand Up @@ -148,6 +150,7 @@ def populate_mock_db(db, entities, block_offset=None):
len(playlists),
len(users),
len(app_delegates),
len(delegations),
len(follows),
len(saves),
len(reposts),
Expand Down Expand Up @@ -207,7 +210,7 @@ def populate_mock_db(db, entities, block_offset=None):
premium_conditions=track_meta.get("premium_conditions", None),
is_playlist_upload=track_meta.get("is_playlist_upload", False),
track_cid=track_meta.get("track_cid", None),
ai_attribution_user_id=track_meta.get("ai_attribution_user_id", None)
ai_attribution_user_id=track_meta.get("ai_attribution_user_id", None),
)
session.add(track)
for i, playlist_meta in enumerate(playlists):
Expand Down Expand Up @@ -266,7 +269,6 @@ def populate_mock_db(db, entities, block_offset=None):
is_available=user_meta.get("is_available", True),
is_deactivated=user_meta.get("is_deactivated", False),
allow_ai_attribution=user_meta.get("allow_ai_attribution", False),

)
user_bank = UserBankAccount(
signature=f"0x{i}",
Expand All @@ -289,6 +291,23 @@ def populate_mock_db(db, entities, block_offset=None):
created_at=delegate_meta.get("created_at", datetime.now()),
)
session.add(delegate)

for i, delegation_meta in enumerate(delegations):
delegation = Delegation(
user_id=delegation_meta.get("user_id", i),
shared_address=delegation_meta.get("shared_address", str(i)),
delegate_address=delegation_meta.get("delegate_address", str(i)),
is_approved=delegation_meta.get("is_approved", False),
is_revoked=delegation_meta.get("is_revoked", False),
blockhash=hex(i + block_offset),
blocknumber=(i + block_offset),
is_current=True,
txhash=delegation_meta.get("txhash", str(i + block_offset)),
updated_at=delegation_meta.get("updated_at", datetime.now()),
created_at=delegation_meta.get("created_at", datetime.now()),
)
session.add(delegation)

for i, follow_meta in enumerate(follows):
follow = Follow(
blockhash=hex(i + block_offset),
Expand Down
1 change: 0 additions & 1 deletion discovery-provider/src/models/delegates/app_delegate.py
Expand Up @@ -13,7 +13,6 @@ class AppDelegate(Base, RepresentableMixin):
name = Column(String, nullable=False, index=False)
is_personal_access = Column(Boolean, nullable=False, server_default=text("false"))
is_revoked = Column(Boolean, nullable=False, server_default=text("false"))

created_at = Column(DateTime, nullable=False)
txhash = Column(
String,
Expand Down
27 changes: 27 additions & 0 deletions discovery-provider/src/models/delegates/delegation.py
@@ -0,0 +1,27 @@
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, text
from src.models.base import Base
from src.models.model_utils import RepresentableMixin


class Delegation(Base, RepresentableMixin):
__tablename__ = "delegations"

shared_address = Column(String, primary_key=True, nullable=False, index=True)
blockhash = Column(ForeignKey("blocks.blockhash")) # type: ignore
blocknumber = Column(ForeignKey("blocks.number")) # type: ignore
delegate_address = Column(String, nullable=False)
user_id = Column(Integer, nullable=False)
is_revoked = Column(Boolean, nullable=False, server_default=text("false"))
is_approved = Column(Boolean, nullable=False, server_default=text("false"))
is_current = Column(Boolean, primary_key=True, nullable=False)
created_at = Column(DateTime, nullable=False)
updated_at = Column(DateTime, nullable=False)
txhash = Column(
String,
primary_key=True,
nullable=False,
server_default=text("''::character varying"),
)

def get_attributes_dict(self):
return {col.name: getattr(self, col.name) for col in self.__table__.columns}

0 comments on commit c7fec30

Please sign in to comment.