Skip to content
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
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ GENVM_SOURCE_MODE=""
GENVM_TAG="" # Exact release tag, e.g. v0.6.0-rc0. Mutually exclusive with GENVM_REF.
GENVM_REF="" # Source git ref/SHA; set mode=source, or use <branch>:<commit> for auto source mode.
GENVM_EXECUTOR_VERSION_NAME="" # Optional source-build executor label, e.g. v0.3.0-e2e-dev.
NIX_NETRC_FILE="/dev/null" # Netrc with a nix cache pull token; must exist, empty one just means no cache hits.
NIX_NETRC_FILE="./docker/empty.netrc" # Netrc with a nix cache pull token; must exist, empty one just means no cache hits.
GENVM_LLM_DEBUG="0"
GENVM_WEB_DEBUG="0"

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/genvm-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ jobs:
# Contracts pinned to runners newer than the released linter's bundled
# SDK cannot be loaded by genvm-linter (<= 0.11.0): the genvm-main
# runner (1zr6nqk...) fails with "No module named 'genlayer.py'", and
# the v0.3.0-rc7 runner (bq43ya7v...) fails with
# "filename 'runners/py-genlayer/bq/43ya....zip' not found". Skip both
# the v0.3 runners (5jycge4q... and babwp9t3...) fail because their
# archives are not bundled. Skip them
# until a linter release bundles them (genvm-linter dxp-694), then
# drop this filter.
- name: Lint example contracts
run: |
failed=0
for f in examples/contracts/*.py; do
echo "::group::$f"
if grep -qE "py-genlayer:(1zr6nqk597d97kg0dyxg0shhrykx5v02zjgnyrajapy4wlqvfvwh|5jycge4q8k23462jtb0b9fyey1s9qz928sz2nbrd9mg4sxqg2qng)" "$f"; then
if grep -qE "py-genlayer:(1zr6nqk597d97kg0dyxg0shhrykx5v02zjgnyrajapy4wlqvfvwh|5jycge4q8k23462jtb0b9fyey1s9qz928sz2nbrd9mg4sxqg2qng|babwp9t37jw9g4j2bccgn14g6x7x9s1f7dsmh7emvz735pz4zxa0)" "$f"; then
echo "SKIP: pinned to a runner unsupported by released genvm-linter"
elif ! genvm-lint check "$f"; then
failed=1
Expand All @@ -59,7 +59,7 @@ jobs:
for f in tests/load/contracts/*.py tests/direct/contracts/*.py; do
[ -f "$f" ] || continue
echo "::group::$f"
if grep -qE "py-genlayer:(1zr6nqk597d97kg0dyxg0shhrykx5v02zjgnyrajapy4wlqvfvwh|5jycge4q8k23462jtb0b9fyey1s9qz928sz2nbrd9mg4sxqg2qng)" "$f"; then
if grep -qE "py-genlayer:(1zr6nqk597d97kg0dyxg0shhrykx5v02zjgnyrajapy4wlqvfvwh|5jycge4q8k23462jtb0b9fyey1s9qz928sz2nbrd9mg4sxqg2qng|babwp9t37jw9g4j2bccgn14g6x7x9s1f7dsmh7emvz735pz4zxa0)" "$f"; then
echo "SKIP: pinned to a runner unsupported by released genvm-linter"
elif ! genvm-lint check "$f"; then
failed=1
Expand Down
25 changes: 23 additions & 2 deletions backend/consensus/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
runtime_rotations_for_round,
stamp_receipt_execution_policy,
unwind_reveal_message_fees,
uses_unmetered_message_fee_pool,
validate_receipt_admission_caps,
)
from backend.rollup.consensus_service import ConsensusService
Expand Down Expand Up @@ -4145,7 +4146,15 @@ def _attach_child_fee_accounting(
pending_transaction: PendingTransaction,
data: dict,
) -> None:
if int(message_payload.get("declaredBudget", 0) or 0) <= 0:
if (
int(message_payload.get("declaredBudget", 0) or 0) <= 0
and not pending_transaction.use_balance
and not parent_fee_accounting.get("message_allocations_from_grant")
):
return
if not pending_transaction.use_balance and uses_unmetered_message_fee_pool(
Comment thread
kp2pml30 marked this conversation as resolved.
parent_fee_accounting
):
return

try:
Expand All @@ -4160,9 +4169,21 @@ def _attach_child_fee_accounting(
sender=(
context.transaction.to_address
if pending_transaction.use_balance
else context.transaction.origin_address
else next(
(
contribution["depositor"]
for contribution in parent_fee_accounting.get("contributions")
or []
if contribution.get("depositor")
),
parent_fee_accounting.get("sender"),
)
or context.transaction.origin_address
or context.transaction.from_address
),
message_allocations_from_grant=bool(
parent_fee_accounting.get("message_allocations_from_grant")
),
policy=execution_policy_for_accounting(
parent_fee_accounting,
StudioFeePolicy.from_env(),
Expand Down
13 changes: 10 additions & 3 deletions backend/node/genvm/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,13 @@ def _emission_int(emission: dict, name: str) -> int:
return int(_emission_value(emission, name) or 0)


def _emission_declared_budget(emission: dict) -> int:
value = _emission_value(emission, "messageFee")
if value is None:
value = _emission_value(emission, "declaredBudget")
return int(value or 0)


def _emission_on(emission: dict) -> typing.Literal["accepted", "finalized"]:
"""GenVM calls the pre-finalization lifecycle `decided`; Studio calls it `accepted`.

Expand Down Expand Up @@ -634,7 +641,7 @@ def provide_result(
value=emission["value"],
on=_emission_on(emission),
fee_params=_emission_internal_fee_params(emission),
declared_budget=_emission_int(emission, "declaredBudget"),
declared_budget=_emission_declared_budget(emission),
call_key=_emission_hex(emission, "callKey"),
allocation_subtree=_emission_allocation_subtree(emission),
use_balance=bool(
Expand All @@ -652,7 +659,7 @@ def provide_result(
value=emission["value"],
on=_emission_on(emission),
fee_params=_emission_internal_fee_params(emission),
declared_budget=_emission_int(emission, "declaredBudget"),
declared_budget=_emission_declared_budget(emission),
call_key=_emission_hex(emission, "callKey"),
allocation_subtree=_emission_allocation_subtree(emission),
use_balance=bool(
Expand All @@ -671,7 +678,7 @@ def provide_result(
on="finalized",
is_eth_send=True,
fee_params=_emission_external_fee_params(emission),
declared_budget=_emission_int(emission, "declaredBudget"),
declared_budget=_emission_declared_budget(emission),
call_key=_emission_hex(emission, "callKey"),
allocation_subtree=_emission_allocation_subtree(emission),
gas_used=_emission_int(emission, "gasUsed"),
Expand Down
10 changes: 6 additions & 4 deletions backend/node/genvm/origin/base_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,17 +127,19 @@ class UnsafeOverrides:
Request overrides that reach boundaries production traffic cannot.

Each member states the `debug_mode` the manager requires before it applies:
`reroute_to` from `safe`, `initial_recursion` from `unsafe`. With debugging
`reroute_to` from `safe`, other overrides from `unsafe`. With debugging
disabled none of them take effect.
"""

reroute_to: str = ""
initial_recursion: int | None = None
allow_two_workers: bool | None = None

def as_request_field(self) -> dict[str, typing.Any]:
return {
"reroute_to": self.reroute_to,
"initial_recursion": self.initial_recursion,
"allow_two_workers": self.allow_two_workers,
}


Expand Down Expand Up @@ -685,9 +687,9 @@ def __init__(self, message: str, *, genvm_id: int):
super().__init__(message)


# Transient manager refusals worth retrying. The manager reports these with the
# generic `Errors.INTERNAL` code (no dedicated variant yet), so the message is
# the only discriminator -- kept here so callers never have to string-match.
# Transient manager refusals worth retrying. They arrive as a `failed_to_start`
# error string, so the message is the only discriminator -- kept here so callers
# never have to string-match.
_RETRYABLE_RUN_REFUSAL_MARKERS: typing.Final = (
"modules are required but not running",
"modules are required but not all are running",
Expand Down
16 changes: 16 additions & 0 deletions backend/node/genvm/origin/fees.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ class MessageAllocationNode(typing.TypedDict):
subtree: bytes


UNMATCHED_EXTERNAL_GUARD_ALLOC: MessageAllocationNode = {
"recipient": None,
"call_key": None,
"budget": 0,
"on": "finalized",
"fee_params": {
"External": {
"gas_limit": 1,
"max_gas_price": 2**256 - 1,
},
},
"children_budget": 0,
"subtree": b"",
}


DEFAULT_EXTERNAL_MESSAGE_ALLOC: MessageAllocationNode = {
"budget": 2**200,
"recipient": None,
Expand Down
22 changes: 18 additions & 4 deletions backend/node/genvm/origin/public_abi.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,15 +277,25 @@ def external() -> "VmError":
return VmError("fee no_matching_allocation # external")


class _VmErrorFeeDescendantGrant:
@staticmethod
def budget() -> "VmError":
return VmError("fee descendant_grant budget")

@staticmethod
def tree() -> "VmError":
return VmError("fee descendant_grant tree")

@staticmethod
def external() -> "VmError":
return VmError("fee descendant_grant external")


class _VmErrorFee:
@staticmethod
def below_minimum() -> "VmError":
return VmError("fee below_minimum")

@staticmethod
def phase_timeout_out_of_bounds() -> "VmError":
return VmError("fee phase_timeout_out_of_bounds")

@staticmethod
def too_many_rounds() -> "VmError":
return VmError("fee too_many_rounds")
Expand All @@ -294,6 +304,10 @@ def too_many_rounds() -> "VmError":
def no_matching_allocation() -> "_VmErrorFeeNoMatchingAllocation":
return _VmErrorFeeNoMatchingAllocation()

@staticmethod
def descendant_grant() -> "_VmErrorFeeDescendantGrant":
return _VmErrorFeeDescendantGrant()


class _VmErrorEvm:
@staticmethod
Expand Down
Loading
Loading