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

feat: tests for csm build report #516

Merged
merged 11 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
46 changes: 29 additions & 17 deletions src/modules/csm/csm.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from src.modules.csm.types import ReportData, Shares
from src.modules.submodules.consensus import ConsensusModule
from src.modules.submodules.oracle_module import BaseModule, ModuleExecuteDelay
from src.modules.submodules.types import ZERO_HASH
from src.providers.execution.contracts.cs_fee_oracle import CSFeeOracleContract
from src.providers.execution.exceptions import InconsistentData
from src.providers.ipfs import CID
Expand Down Expand Up @@ -95,33 +96,42 @@ def execute_module(self, last_finalized_blockstamp: BlockStamp) -> ModuleExecute
def build_report(self, blockstamp: ReferenceBlockStamp) -> tuple:
self.validate_state(blockstamp)

distributed, shares, log = self.calculate_distribution(blockstamp)
if not distributed:
logger.info({"msg": "No shares distributed in the current frame"})

# Load the previous tree if any.
prev_root = self.w3.csm.get_csm_tree_root(blockstamp)
prev_cid = self.w3.csm.get_csm_tree_cid(blockstamp)

if prev_cid:
if bool(prev_cid) != (prev_root != ZERO_HASH):
raise InconsistentData(f"Got inconsistent previous tree data: {prev_root=} {prev_cid=}")

distributed, shares, log = self.calculate_distribution(blockstamp)

log_cid = self.publish_log(log)

if not distributed:
logger.info({"msg": "No shares distributed in the current frame"})
return ReportData(
self.report_contract.get_consensus_version(blockstamp.block_hash),
blockstamp.ref_slot,
tree_root=prev_root,
tree_cid=prev_cid or "",
log_cid=log_cid,
distributed=0,
).as_tuple()

if prev_cid and prev_root != ZERO_HASH:
# Update cumulative amount of shares for all operators.
for no_id, acc_shares in self.get_accumulated_shares(prev_cid, prev_root):
shares[no_id] += acc_shares
else:
logger.info({"msg": "No previous CID available"})
logger.info({"msg": "No previous distribution. Nothing to accumulate"})

tree = self.make_tree(shares)
tree_cid: CID | None = None

log_cid = self.publish_log(log)
if tree:
tree_cid = self.publish_tree(tree)
tree_cid = self.publish_tree(tree)

return ReportData(
self.report_contract.get_consensus_version(blockstamp.block_hash),
blockstamp.ref_slot,
tree_root=tree.root if tree else prev_root,
tree_cid=tree_cid or prev_cid or "",
tree_root=tree.root,
tree_cid=tree_cid,
log_cid=log_cid,
distributed=distributed,
).as_tuple()
Expand Down Expand Up @@ -169,7 +179,9 @@ def collect_data(self, blockstamp: BlockStamp) -> bool:
report_blockstamp = self.get_blockstamp_for_report(blockstamp)
if report_blockstamp and report_blockstamp.ref_epoch != r_epoch:
logger.warning(
{"msg": f"Frame has been changed, but the change is not yet observed on finalized epoch {finalized_epoch}"}
{
"msg": f"Frame has been changed, but the change is not yet observed on finalized epoch {finalized_epoch}"
}
)
return False

Expand Down Expand Up @@ -296,9 +308,9 @@ def stuck_operators(self, blockstamp: ReferenceBlockStamp) -> set[NodeOperatorId
)
return stuck

def make_tree(self, shares: dict[NodeOperatorId, Shares]) -> Tree | None:
def make_tree(self, shares: dict[NodeOperatorId, Shares]) -> Tree:
if not shares:
return None
raise ValueError("No shares to build a tree")

# XXX: We put a stone here to make sure, that even with only 1 node operator in the tree, it's still possible to
# claim rewards. The CSModule contract skips pulling rewards if the proof's length is zero, which is the case
Expand Down
2 changes: 1 addition & 1 deletion src/modules/csm/types.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from dataclasses import dataclass
from typing import Literal, TypeAlias
from typing import TypeAlias, Literal

from hexbytes import HexBytes

Expand Down
2 changes: 1 addition & 1 deletion src/web3py/extensions/csm.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def get_csm_tree_root(self, blockstamp: BlockStamp) -> HexBytes:

def get_csm_tree_cid(self, blockstamp: BlockStamp) -> CID | None:
result = self.fee_distributor.tree_cid(blockstamp.block_hash)
if not result:
if result == "":
return None
madlabman marked this conversation as resolved.
Show resolved Hide resolved
return CIDv0(result) if is_cid_v0(result) else CIDv1(result)

Expand Down
Loading
Loading