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

OCT-1351 move allocate to new architecture #86

Merged
merged 18 commits into from
Mar 27, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions backend/app/legacy/controllers/allocations.py
Original file line number Diff line number Diff line change
@@ -15,7 +15,6 @@
deserialize_payload,
verify_allocations,
add_allocations_to_db,
revoke_previous_allocation,
store_allocation_request,
)
from app.legacy.core.common import AccountFunds
@@ -74,16 +73,6 @@ def get_all_by_proposal_and_epoch(
]


@deprecated("ALLOCATIONS REWORK")
def revoke_previous_user_allocation(user_address: str):
pending_epoch = epochs.get_pending_epoch()

if pending_epoch is None:
raise exceptions.NotInDecisionWindow

revoke_previous_allocation(user_address, pending_epoch)


def _make_allocation(
payload: Dict,
user_address: str,
4 changes: 2 additions & 2 deletions backend/app/legacy/controllers/user.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

from app.exceptions import InvalidSignature, UserNotFound, NotInDecisionWindow
from app.extensions import db
from app.legacy.controllers import allocations as allocations_controller
from app.modules.user.allocations import controller as allocations_controller
from app.legacy.core.user import patron_mode as patron_mode_core
from app.legacy.core.user.tos import (
has_user_agreed_to_terms_of_service,
@@ -37,7 +37,7 @@ def toggle_patron_mode(user_address: str, signature: str) -> bool:
patron_mode_status = patron_mode_core.toggle_patron_mode(user_address)

try:
allocations_controller.revoke_previous_user_allocation(user_address)
allocations_controller.revoke_previous_allocation(user_address)
except NotInDecisionWindow:
app.logger.info(
f"Not in allocation period. Skipped revoking previous allocation for user {user_address}"
2 changes: 2 additions & 0 deletions backend/app/legacy/core/allocations.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing_extensions import deprecated
from dataclasses import dataclass
from typing import List, Dict, Tuple, Optional

@@ -115,6 +116,7 @@ def verify_allocations(
raise exceptions.RewardsBudgetExceeded


@deprecated("ALLOCATIONS REWORK")
def revoke_previous_allocation(user_address: str, epoch: int):
user = database.user.get_by_address(user_address)
if user is None:
6 changes: 6 additions & 0 deletions backend/app/modules/modules_factory/protocols.py
Original file line number Diff line number Diff line change
@@ -63,6 +63,12 @@ def get_last_user_allocation(
...


@runtime_checkable
class AllocationManipulationProtocol(Protocol):
def revoke_previous_allocation(self, context: Context, user_address: str):
...


@runtime_checkable
class SimulateAllocation(Protocol):
def simulate_allocation(
20 changes: 19 additions & 1 deletion backend/app/modules/user/allocations/controller.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,11 @@

from app.context.epoch_state import EpochState
from app.context.manager import epoch_context, state_context
from app.exceptions import NotImplementedForGivenEpochState
from app.exceptions import (
NotImplementedForGivenEpochState,
InvalidEpoch,
NotInDecisionWindow,
)
from app.modules.dto import AccountFundsDTO, AllocationDTO, ProposalDonationDTO
from app.modules.registry import get_services
from app.modules.user.allocations.service.pending import PendingUserAllocations
@@ -59,6 +63,20 @@ def simulate_allocation(
return leverage, threshold, matched


def revoke_previous_allocation(user_address: str):
context = None

try:
context = state_context(EpochState.PENDING)
except InvalidEpoch:
raise NotInDecisionWindow

service: PendingUserAllocations = get_services(
context.epoch_state
).user_allocations_service
service.revoke_previous_allocation(context, user_address)


def _deserialize_payload(payload: Dict) -> List[AllocationDTO]:
return [
AllocationDTO.from_dict(allocation_data)
14 changes: 14 additions & 0 deletions backend/app/modules/user/allocations/service/pending.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from typing import List, Tuple, Protocol, runtime_checkable

from app import exceptions
from app.context.manager import Context
from app.context.epoch_state import EpochState
from app.engine.projects.rewards import ProjectRewardDTO
from app.infrastructure import database
from app.modules.dto import AllocationDTO
@@ -38,3 +40,15 @@ def simulate_allocation(
projects,
matched_rewards,
)

def revoke_previous_allocation(self, context: Context, user_address: str):
if context.epoch_state is not EpochState.PENDING:
raise exceptions.NotInDecisionWindow

user = database.user.get_by_address(user_address)
if user is None:
raise exceptions.UserNotFound

database.allocations.soft_delete_all_by_epoch_and_user_id(
context.epoch_details.epoch_num, user.id
)
8 changes: 8 additions & 0 deletions backend/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -665,6 +665,14 @@ def mock_staking_proceeds():
return staking_proceeds_service_mock


@pytest.fixture(scope="function")
def mock_user_nonce():
user_nonce_service_mock = Mock()
user_nonce_service_mock.get_next_user_nonce.return_value = 0

return user_nonce_service_mock


@pytest.fixture(scope="function")
def mock_events_generator():
events = [
8 changes: 5 additions & 3 deletions backend/tests/legacy/test_user.py
Original file line number Diff line number Diff line change
@@ -97,7 +97,9 @@ def test_patron_mode_toggle_fails_when_use_sig_to_disable_for_enable(user_accoun
toggle_patron_mode(user_accounts[0].address, toggle_true_sig)


def test_patron_mode_revokes_allocations_for_the_epoch(alice, make_allocations):
def test_patron_mode_revokes_allocations_for_the_epoch(
alice, make_allocations, mock_pending_epoch_snapshot_db
):
toggle_true_sig = "52d249ca8ac8f40c01613635dac8a9b01eb50230ad1467451a058170726650b92223e80032a4bff4d25c3554e9d1347043c53b4c2dc9f1ba3f071bd3a1c8b9121b"
make_allocations(alice, MOCKED_PENDING_EPOCH_NO)
assert len(allocations_controller.get_all_by_user_and_epoch(alice.address)) == 3
@@ -111,7 +113,7 @@ def test_patron_mode_revokes_allocations_for_the_epoch(alice, make_allocations):


def test_when_patron_mode_changes_revoked_allocations_are_not_restored(
alice, make_allocations
alice, make_allocations, mock_pending_epoch_snapshot_db
):
toggle_true_sig = "52d249ca8ac8f40c01613635dac8a9b01eb50230ad1467451a058170726650b92223e80032a4bff4d25c3554e9d1347043c53b4c2dc9f1ba3f071bd3a1c8b9121b"
toggle_false_sig = "979b997cb2b990f104ed4d342a364207a019649eda00497780033d154ee07c44141a6be33cecdde879b1b4238c1622660e70baddb745def53d6733e4aacaeb181b"
@@ -127,7 +129,7 @@ def test_when_patron_mode_changes_revoked_allocations_are_not_restored(


def test_patron_mode_does_not_revoke_allocations_from_previous_epochs(
alice, make_allocations
alice, make_allocations, mock_pending_epoch_snapshot_db
):
toggle_true_sig = "52d249ca8ac8f40c01613635dac8a9b01eb50230ad1467451a058170726650b92223e80032a4bff4d25c3554e9d1347043c53b4c2dc9f1ba3f071bd3a1c8b9121b"
make_allocations(alice, MOCKED_PENDING_EPOCH_NO - 1)
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import pytest

from app import exceptions
from app.engine.projects.rewards import ProjectRewardDTO
from app.infrastructure import database
from app.context.epoch_state import EpochState
from app.modules.dto import AllocationDTO
from app.modules.user.allocations.service.history import UserAllocationsHistory
from app.modules.user.allocations.service.pending import PendingUserAllocations
from tests.helpers.constants import MATCHED_REWARDS
from tests.helpers.context import get_context
@@ -13,7 +16,16 @@ def before(app):
pass


def test_simulate_allocation(mock_users_db, mock_octant_rewards):
@pytest.fixture()
def service(mock_octant_rewards, mock_patron_mode, mock_user_budgets):
return PendingUserAllocations(
octant_rewards=mock_octant_rewards,
user_budgets=mock_user_budgets,
patrons_mode=mock_patron_mode,
user_nonce=UserAllocationsHistory(),
)

def test_simulate_allocation(service, mock_users_db):
user1, _, _ = mock_users_db
context = get_context()
projects = context.projects_details.projects
@@ -26,8 +38,6 @@ def test_simulate_allocation(mock_users_db, mock_octant_rewards):
AllocationDTO(projects[1], 200_000000000),
]

service = PendingUserAllocations(octant_rewards=mock_octant_rewards)

leverage, threshold, rewards = service.simulate_allocation(
context, next_allocations, user1.address
)
@@ -47,3 +57,26 @@ def test_simulate_allocation(mock_users_db, mock_octant_rewards):
ProjectRewardDTO(sorted_projects[8], 0, 0),
ProjectRewardDTO(sorted_projects[9], 0, 0),
]


def test_revoke_previous_allocation(service, mock_users_db):
user1, _, _ = mock_users_db
context = get_context(epoch_state=EpochState.PENDING)

projects = context.projects_details.projects
prev_allocation = [
AllocationDTO(projects[0], 100_000000000),
]
database.allocations.add_all(1, user1.id, 0, prev_allocation)

assert service.get_user_allocation_sum(context, user1.address) == 100_000000000
service.revoke_previous_allocation(context, user1.address)
assert service.get_user_allocation_sum(context, user1.address) == 0

def test_revoke_previous_allocation_fails_outside_decision_window(service, mock_users_db):
user1, _, _ = mock_users_db

for state in [EpochState.FUTURE, EpochState.CURRENT, EpochState.PRE_PENDING, EpochState.FINALIZING, EpochState.FINALIZED]:
context = get_context(epoch_state=state)
with pytest.raises(exceptions.NotInDecisionWindow):
service.revoke_previous_allocation(context, user1.address)