Module model.parts.ethereum

Ethereum System

Policy Functions and State Update Functions shared between the Eth1 and Eth2 systems.

Expand source code
"""
# Ethereum System

Policy Functions and State Update Functions shared between the Eth1 and Eth2 systems.
"""

import typing

import model.constants as constants
from model.types import ETH, USD_per_ETH, Gwei, Stage


def policy_network_issuance(
    params, substep, state_history, previous_state
) -> typing.Dict[str, ETH]:
    # Parameters
    dt = params["dt"]
    daily_pow_issuance = params["daily_pow_issuance"]

    # State Variables
    stage = previous_state["stage"]
    amount_slashed = previous_state["amount_slashed"]
    total_basefee = previous_state["total_basefee"]
    total_priority_fee_to_validators = previous_state["total_priority_fee_to_validators"]
    total_online_validator_rewards = previous_state["total_online_validator_rewards"]

    # Calculate network issuance in ETH
    network_issuance = (
        # Remove tips to validators which is not issuance (ETH transferred rather than minted)
        (total_online_validator_rewards - total_priority_fee_to_validators)
        - amount_slashed
        - total_basefee
    ) / constants.gwei

    # Calculate Proof of Work issuance
    pow_issuance = (
        daily_pow_issuance / constants.epochs_per_day
        if Stage(stage) in [Stage.BEACON_CHAIN, Stage.EIP1559]
        else 0
    )
    network_issuance += pow_issuance * dt

    return {
        "network_issuance": network_issuance,
        "pow_issuance": pow_issuance,
    }


def policy_eip1559_transaction_pricing(
    params, substep, state_history, previous_state
) -> typing.Dict[str, Gwei]:
    """EIP1559 Transaction Pricing Mechanism
    A transaction pricing mechanism that includes fixed-per-block network fee
    that is burned and dynamically expands/contracts block sizes to deal with transient congestion.

    See:
    * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md
    * https://eips.ethereum.org/EIPS/eip-1559
    """

    stage = Stage(previous_state["stage"])
    if not stage in [Stage.EIP1559, Stage.PROOF_OF_STAKE]:
        return {
            "basefee": 0,
            "total_basefee": 0,
            "total_tips_to_miners": 0,
            "total_priority_fee_to_validators": 0,
        }

    # Parameters
    dt = params["dt"]
    gas_target = params["gas_target"]  # Gas
    ELASTICITY_MULTIPLIER = params["ELASTICITY_MULTIPLIER"]
    BASE_FEE_MAX_CHANGE_DENOMINATOR = params["BASE_FEE_MAX_CHANGE_DENOMINATOR"]
    eip1559_basefee_process = params["eip1559_basefee_process"]
    eip1559_tip_process = params["eip1559_tip_process"]
    daily_transactions_process = params["daily_transactions_process"]
    transaction_average_gas = params["transaction_average_gas"]

    # State Variables
    run = previous_state["run"]
    timestep = previous_state["timestep"]
    previous_basefee = previous_state["basefee"]

    # Get samples for current run and timestep from basefee, tip, and transaction processes
    basefee = eip1559_basefee_process(run, timestep * dt)  # Gwei per Gas

    # Ensure basefee changes by no more than 1 / BASE_FEE_MAX_CHANGE_DENOMINATOR %
    # assert (
    #     abs(basefee - previous_basefee) / previous_basefee
    #     <= constants.slots_per_epoch / BASE_FEE_MAX_CHANGE_DENOMINATOR
    #     if timestep > 1
    #     else True
    # ), "basefee changed by more than 1 / BASE_FEE_MAX_CHANGE_DENOMINATOR %"

    avg_tip_amount = eip1559_tip_process(run, timestep * dt)  # Gwei per Gas
    transactions_per_day = daily_transactions_process(
        run, timestep * dt
    )  # Transactions per day
    transactions_per_epoch = (
        transactions_per_day / constants.epochs_per_day
    )  # Transactions per epoch

    # Calculate total basefee and tips to validators
    gas_used = transactions_per_epoch * transaction_average_gas  # Gas
    total_basefee = gas_used * basefee  # Gwei
    total_tips = gas_used * avg_tip_amount  # Gwei

    if stage in [Stage.PROOF_OF_STAKE]:
        total_tips_to_miners = 0
        total_priority_fee_to_validators = total_tips
    else:
        total_tips_to_miners = total_tips
        total_priority_fee_to_validators = 0

    # Check if the block used too much gas
    assert (
        gas_used <= gas_target * ELASTICITY_MULTIPLIER * constants.slots_per_epoch
    ), "invalid block: too much gas used"

    return {
        "basefee": basefee,
        "total_basefee": total_basefee * dt,
        "total_tips_to_miners": total_tips_to_miners * dt,
        "total_priority_fee_to_validators": total_priority_fee_to_validators * dt,
    }


def update_eth_price(
    params, substep, state_history, previous_state, policy_input
) -> typing.Tuple[str, USD_per_ETH]:
    # Parameters
    dt = params["dt"]
    eth_price_process = params["eth_price_process"]

    # State Variables
    run = previous_state["run"]
    timestep = previous_state["timestep"]

    # Get the ETH price sample for the current run and timestep
    eth_price_sample = eth_price_process(run, timestep * dt)

    return "eth_price", eth_price_sample


def update_eth_supply(
    params, substep, state_history, previous_state, policy_input
) -> typing.Tuple[str, ETH]:
    # Policy Inputs
    network_issuance = policy_input["network_issuance"]

    # State variables
    eth_supply = previous_state["eth_supply"]

    return "eth_supply", eth_supply + network_issuance

Functions

def policy_eip1559_transaction_pricing(params, substep, state_history, previous_state) ‑> Dict[str, float]

EIP1559 Transaction Pricing Mechanism A transaction pricing mechanism that includes fixed-per-block network fee that is burned and dynamically expands/contracts block sizes to deal with transient congestion.

See: * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md * https://eips.ethereum.org/EIPS/eip-1559

Expand source code
def policy_eip1559_transaction_pricing(
    params, substep, state_history, previous_state
) -> typing.Dict[str, Gwei]:
    """EIP1559 Transaction Pricing Mechanism
    A transaction pricing mechanism that includes fixed-per-block network fee
    that is burned and dynamically expands/contracts block sizes to deal with transient congestion.

    See:
    * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md
    * https://eips.ethereum.org/EIPS/eip-1559
    """

    stage = Stage(previous_state["stage"])
    if not stage in [Stage.EIP1559, Stage.PROOF_OF_STAKE]:
        return {
            "basefee": 0,
            "total_basefee": 0,
            "total_tips_to_miners": 0,
            "total_priority_fee_to_validators": 0,
        }

    # Parameters
    dt = params["dt"]
    gas_target = params["gas_target"]  # Gas
    ELASTICITY_MULTIPLIER = params["ELASTICITY_MULTIPLIER"]
    BASE_FEE_MAX_CHANGE_DENOMINATOR = params["BASE_FEE_MAX_CHANGE_DENOMINATOR"]
    eip1559_basefee_process = params["eip1559_basefee_process"]
    eip1559_tip_process = params["eip1559_tip_process"]
    daily_transactions_process = params["daily_transactions_process"]
    transaction_average_gas = params["transaction_average_gas"]

    # State Variables
    run = previous_state["run"]
    timestep = previous_state["timestep"]
    previous_basefee = previous_state["basefee"]

    # Get samples for current run and timestep from basefee, tip, and transaction processes
    basefee = eip1559_basefee_process(run, timestep * dt)  # Gwei per Gas

    # Ensure basefee changes by no more than 1 / BASE_FEE_MAX_CHANGE_DENOMINATOR %
    # assert (
    #     abs(basefee - previous_basefee) / previous_basefee
    #     <= constants.slots_per_epoch / BASE_FEE_MAX_CHANGE_DENOMINATOR
    #     if timestep > 1
    #     else True
    # ), "basefee changed by more than 1 / BASE_FEE_MAX_CHANGE_DENOMINATOR %"

    avg_tip_amount = eip1559_tip_process(run, timestep * dt)  # Gwei per Gas
    transactions_per_day = daily_transactions_process(
        run, timestep * dt
    )  # Transactions per day
    transactions_per_epoch = (
        transactions_per_day / constants.epochs_per_day
    )  # Transactions per epoch

    # Calculate total basefee and tips to validators
    gas_used = transactions_per_epoch * transaction_average_gas  # Gas
    total_basefee = gas_used * basefee  # Gwei
    total_tips = gas_used * avg_tip_amount  # Gwei

    if stage in [Stage.PROOF_OF_STAKE]:
        total_tips_to_miners = 0
        total_priority_fee_to_validators = total_tips
    else:
        total_tips_to_miners = total_tips
        total_priority_fee_to_validators = 0

    # Check if the block used too much gas
    assert (
        gas_used <= gas_target * ELASTICITY_MULTIPLIER * constants.slots_per_epoch
    ), "invalid block: too much gas used"

    return {
        "basefee": basefee,
        "total_basefee": total_basefee * dt,
        "total_tips_to_miners": total_tips_to_miners * dt,
        "total_priority_fee_to_validators": total_priority_fee_to_validators * dt,
    }
def policy_network_issuance(params, substep, state_history, previous_state) ‑> Dict[str, float]
Expand source code
def policy_network_issuance(
    params, substep, state_history, previous_state
) -> typing.Dict[str, ETH]:
    # Parameters
    dt = params["dt"]
    daily_pow_issuance = params["daily_pow_issuance"]

    # State Variables
    stage = previous_state["stage"]
    amount_slashed = previous_state["amount_slashed"]
    total_basefee = previous_state["total_basefee"]
    total_priority_fee_to_validators = previous_state["total_priority_fee_to_validators"]
    total_online_validator_rewards = previous_state["total_online_validator_rewards"]

    # Calculate network issuance in ETH
    network_issuance = (
        # Remove tips to validators which is not issuance (ETH transferred rather than minted)
        (total_online_validator_rewards - total_priority_fee_to_validators)
        - amount_slashed
        - total_basefee
    ) / constants.gwei

    # Calculate Proof of Work issuance
    pow_issuance = (
        daily_pow_issuance / constants.epochs_per_day
        if Stage(stage) in [Stage.BEACON_CHAIN, Stage.EIP1559]
        else 0
    )
    network_issuance += pow_issuance * dt

    return {
        "network_issuance": network_issuance,
        "pow_issuance": pow_issuance,
    }
def update_eth_price(params, substep, state_history, previous_state, policy_input) ‑> Tuple[str, float]
Expand source code
def update_eth_price(
    params, substep, state_history, previous_state, policy_input
) -> typing.Tuple[str, USD_per_ETH]:
    # Parameters
    dt = params["dt"]
    eth_price_process = params["eth_price_process"]

    # State Variables
    run = previous_state["run"]
    timestep = previous_state["timestep"]

    # Get the ETH price sample for the current run and timestep
    eth_price_sample = eth_price_process(run, timestep * dt)

    return "eth_price", eth_price_sample
def update_eth_supply(params, substep, state_history, previous_state, policy_input) ‑> Tuple[str, float]
Expand source code
def update_eth_supply(
    params, substep, state_history, previous_state, policy_input
) -> typing.Tuple[str, ETH]:
    # Policy Inputs
    network_issuance = policy_input["network_issuance"]

    # State variables
    eth_supply = previous_state["eth_supply"]

    return "eth_supply", eth_supply + network_issuance