eip | title | status | type | category | author | discussions-to | created |
---|---|---|---|---|---|---|---|
1011 |
Hybrid Casper FFG |
Stagnant |
Standards Track |
Core |
Danny Ryan (@djrtwo), Chih-Cheng Liang (@ChihChengLiang) |
2018-04-20 |
Specification of the first step to transition Ethereum main net from Proof of Work (PoW) to Proof of Stake (PoS). The resulting consensus model is a PoW/PoS hybrid.
This EIP specifies a hybrid PoW/PoS consensus model for Ethereum main net. Existing PoW mechanics are used for new block creation, and a novel PoS mechanism called Casper the Friendly Finality Gadget (FFG) is layered on top using a smart contract.
Through the use of Ether deposits, slashing conditions, and a modified fork choice, FFG allows the underlying PoW blockchain to be finalized. As network security is greatly shifted from PoW to PoS, PoW block rewards are reduced.
This EIP does not contain safety and liveness proofs or validator implementation details, but these can be found in the Casper FFG paper and Validator Implementation Guide respectively.
- epoch: The span of blocks between checkpoints. Epochs are numbered starting at the hybrid casper fork, incrementing by one at the start of each epoch.
- finality: The point at which a block has been decided upon by a client to never revert. Proof of Work does not have the concept of finality, only of further deep block confirmations.
- checkpoint: The block/hash under consideration for finality for a given epoch. This block is the last block of the previous epoch. Rather than dealing with every block, Casper FFG only considers checkpoints for finalization. When a checkpoint is explicitly finalized, all ancestor blocks of the checkpoint are implicitly finalized.
- validator: A participant in the Casper FFG consensus that has deposited ether in the casper contract and has the responsibility to vote and finalize checkpoints.
- validator set: The set of validators in the casper contract at any given time.
- dynasty: The number of finalized checkpoints in the chain from root to the parent of a block. The dynasty is used to define when a validator starts and ends validating. The current dynasty only increments when a checkpoint is finalized as opposed to epoch numbers that increment regardless of finality.
- slash: The burning of some amount of a validator's deposit along with an immediate logout from the validator set. Slashing occurs when a validator signs two conflicting
vote
messages that violate a slashing condition. For an in-depth discussion of slashing conditions, see the Casper FFG Paper.
Transitioning the Ethereum network from PoW to PoS has been on the roadmap and in the Yellow Paper since the launch of the protocol. Although effective in coming to a decentralized consensus, PoW consumes an incredible amount of energy, has no economic finality, and has no effective strategy in resisting cartels. Excessive energy consumption, issues with equal access to mining hardware, mining pool centralization, and an emerging market of ASICs each provide a distinct motivation to make the transition as soon as possible.
Until recently, the proper way to make this transition was still an open area of research. In October of 2017 Casper the Friendly Finality Gadget was published, solving open questions of economic finality through validator deposits and crypto-economic incentives. For a detailed discussion and proofs of "accountable safety" and "plausible liveness", see the Casper FFG paper.
The Casper FFG contract can be layered on top of any block proposal mechanism, providing finality to the underlying chain. This EIP proposes layering FFG on top of the existing PoW block proposal mechanism as a conservative step-wise approach in the transition to full PoS. The new FFG staking mechanism requires minimal changes to the protocol, allowing the Ethereum network to fully test and evaluate Casper FFG on top of PoW before moving to a validator based block proposal mechanism.
HYBRID_CASPER_FORK_BLKNUM
: TBDCASPER_ADDR
: TBDCASPER_CODE
: see belowCASPER_BALANCE
: 1.25e24 wei (1,250,000 ETH)MSG_HASHER_ADDR
: TBDMSG_HASHER_CODE
: see belowPURITY_CHECKER_ADDR
: TBDPURITY_CHECKER_CODE
: see belowNULL_SENDER
:2**160 - 1
NEW_BLOCK_REWARD
: 6e17 wei (0.6 ETH)REWARD_STEPDOWN_BLOCK_COUNT
: 5.5e5 blocks (~3 months)CASPER_INIT_DATA
: TBDVOTE_BYTES
:0xe9dc0614
INITIALIZE_EPOCH_BYTES
:0x5dcffc17
NON_REVERT_MIN_DEPOSIT
: amount in wei configurable by client
EPOCH_LENGTH
: 50 blocksWARM_UP_PERIOD
: 1.8e5 blocks (~1 month)WITHDRAWAL_DELAY
: 1.5e4 epochsDYNASTY_LOGOUT_DELAY
: 700 dynastiesBASE_INTEREST_FACTOR
: 7e-3BASE_PENALTY_FACTOR
: 2e-7MIN_DEPOSIT_SIZE
: 1.5e21 wei (1500 ETH)
If block.number == HYBRID_CASPER_FORK_BLKNUM
, then when processing the block before processing any transactions:
- set the code of
MSG_HASHER_ADDR
toMSG_HASHER_CODE
- set the code of
PURITY_CHECKER_ADDR
toPURITY_CHECKER_CODE
- set the code of
CASPER_ADDR
toCASPER_CODE
- set balance of
CASPER_ADDR
toCASPER_BALANCE
Then execute a CALL
with the following parameters before executing any normal block transactions:
SENDER
:NULL_SENDER
GAS
: 3141592TO
:CASPER_ADDR
VALUE
: 0NONCE
: 0GASPRICE
: 0DATA
:CASPER_INIT_DATA
This CALL
utilizes no gas and does not increment the nonce of NULL_SENDER
If block.number >= (HYBRID_CASPER_FORK_BLKNUM + WARM_UP_PERIOD)
and block.number % EPOCH_LENGTH == 0
, execute a CALL
with the following parameters before executing any normal block transactions:
SENDER
:NULL_SENDER
GAS
: 3141592TO
:CASPER_ADDR
VALUE
: 0NONCE
: 0GASPRICE
: 0DATA
:INITIALIZE_EPOCH_BYTES
followed by the 32-byte encoding offloor(block.number / EPOCH_LENGTH)
This CALL
utilizes no gas and does not increment the nonce of NULL_SENDER
A vote
transaction is defined as a transaction with the following parameters:
TO
:CASPER_ADDR
DATA
: Begins withVOTE_BYTES
If block.number >= HYBRID_CASPER_FORK_BLKNUM
, then:
- A valid
vote
transaction toCASPER_ADDR
must satisfy each of the following:- Must have the following signature
(CHAIN_ID, 0, 0)
(ie.r = s = 0, v = CHAIN_ID
) - Must have
value == nonce == gasprice == 0
- Must have the following signature
- When producing and validating a block, when handling
vote
transactions toCASPER_ADDR
:- Only include "valid"
vote
transactions as defined above - Place all
vote
transactions at the end of the block - Track cumulative gas used by votes separately from cumulative gas used by normal transactions via
vote_gas_used
- Total
vote_gas_used
ofvote
transactions cannot exceed theblock_gas_limit
, independent of gas used by normal block transactions
- Only include "valid"
- When applying
vote
transactions toCASPER_ADDR
to vm state:- Set sender to
NULL_SENDER
- Count gas of
vote
towardvote_gas_used
- Do not count gas of
vote
toward the normalgas_used
. For allvote
transaction receipts, cumulative gas used is equal to last non-vote
transaction receipt - Do not increment the nonce of
NULL_SENDER
- Set sender to
- All unsuccessful
vote
transactions toCASPER_ADDR
are invalid and must not be included in the block
If block.number >= HYBRID_CASPER_FORK_BLKNUM
, the fork choice rule is the logic represented by the following pseudocode. Note that options --casper-fork-choice
and --exclude
are discussed below in "Client Settings".
def handle_block(new_block):
if not is_new_head(new_block):
return
set_head(new_block)
if --casper-fork-choice is on:
check_and_finalize_new_checkpoint(new_block)
def is_new_head(new_block):
if --casper-fork-choice is off
# old pure PoW chain scoring rule
return new_block.total_difficuty > current_head.total_difficulty
if new_block is in --exclude list or one of its descendants
return false
# don't revert finalized blocks
if db.last_finalized_block is not in new_block.ancestors:
return false
# new casper chain scoring rule
return highest_justified_epoch(new_block) * 10**40 + new_block.total_difficuty >
highest_justified_epoch(current_head) * 10**40 + current_head.total_difficulty
def highest_justified_epoch(block):
casper = block.post_state.casper_contract
return casper.highest_justified_epoch(NON_REVERT_MIN_DEPOSITS)
def check_and_finalize_new_checkpoint(new_block):
casper = new_block.post_state.casper_contract
# If no finalized blocks, db.last_finalized_epoch initialized to -1
finalized_epoch = casper.highest_finalized_epoch(NON_REVERT_MIN_DEPOSITS)
if finalized_epoch > db.last_finalized_epoch:
finalized_hash = casper.checkpoint_hashes(finalized_epoch)
# ensure not trivially finalized
if finalized_hash == b'\x00' * 32:
return
db.last_finalized_epoch = finalized_epoch
db.last_finalized_block = finalized_hash
The new chain scoring rule queries the casper contract to find the highest justified epoch that meets the client's minimum deposit requirement (NON_REVERT_MIN_DEPOSITS
). The 10**40
multiplier ensures that the justified epoch takes precedence over block mining difficulty. total_difficulty
only serves as a tie breaker if the two blocks in question have an equivalent highest_justified_epoch
.
Note: If the client has no justified checkpoints, the contract returns highest_justified_epoch
as 0
essentially reverting the fork choice rule to pure PoW.
When assessing a new block as the chain's head, clients must never revert finalized blocks as seen by the code commented as "don't revert finalized blocks".
When a new block is added as the chain's head, clients then check for a new finalized block. This is handled by the check_and_finalized_new_checkpoint(new_block)
method above. If the highest finalized epoch in the casper contract is greater than the previous finalized epoch, then the client finalizes the block with the hash casper.checkpoint_hashes(finalized_epoch)
, storing this block and the related epoch number in the client database as finalized.
Clients only consider checkpoints justified or finalized if deposits were greater than NON_REVERT_MIN_DEPOSIT
during the epoch in question. This logic is encapsulated in casper.highest_justified_epoch(NON_REVERT_MIN_DEPOSIT)
and casper.highest_finalized_epoch(NON_REVERT_MIN_DEPOSIT)
, respectively.
If block.number >= HYBRID_CASPER_FORK_BLKNUM
, then block_reward
is defined by the following logic and utilizes the same formulas for ommer rewards but with the updated block_reward
.
if block.number < HYBRID_CASPER_FORK_BLKNUM + REWARD_STEPDOWN_BLOCK_COUNT:
block_reward = 5 * NEW_BLOCK_REWARD
elif block.number < HYBRID_CASPER_FORK_BLKNUM + 2*REWARD_STEPDOWN_BLOCK_COUNT:
block_reward = 4 * NEW_BLOCK_REWARD
elif block.number < HYBRID_CASPER_FORK_BLKNUM + 3*REWARD_STEPDOWN_BLOCK_COUNT:
block_reward = 3 * NEW_BLOCK_REWARD
elif block.number < HYBRID_CASPER_FORK_BLKNUM + 4*REWARD_STEPDOWN_BLOCK_COUNT:
block_reward = 2 * NEW_BLOCK_REWARD
else:
block_reward = NEW_BLOCK_REWARD
The mechanics and responsibilities of validators are not specified in this EIP because they rely upon network transactions to the contract at CASPER_ADDR
rather than on protocol level implementation and changes.
See the Validator Implementation Guide for validator details.
The source code for MSG_HASHER_CODE
is located here.
The source is to be migrated to Vyper LLL before the bytecode is finalized for this EIP.
The EVM init code is:
TBD
The EVM bytecode that the contract should be set to is:
TBD
The source code for PURITY_CHECKER_CODE
is located here.
The source is to be migrated to Vyper LLL before the bytecode is finalized for this EIP.
The EVM init code is:
TBD
The EVM bytecode that the contract should be set to is:
TBD
The source code for CASPER_CODE
is located at
here.
The contract is to be formally verified and further tested before the bytecode is finalized for this EIP.
The EVM init code with the above specified params is:
TBD
The EVM bytecode that the contract should be set to is:
TBD
Clients should be implemented with the following configurable settings:
The ability to enable/disable the Casper Fork Choice. A suggested implementation is --casper-fork-choice
.
This setting should ship as default disabled in client versions during the initial casper fork. This setting should ship as default enabled in subsequent client versions.
The minimum size of total deposits that the client must observe in the FFG contract for the state of the contract to affect the client's fork choice. A suggested implementation is --non-revert-min-deposit WEI_VALUE
.
The suggested default value that clients should ship with is at least 2e23 wei (200K ETH).
See "Fork Choice" more details.
The ability to exclude a specified blockhash and all of its descendants from a client's fork choice. A suggested implementation is --exclude BLOCKHASHES
, where BLOCK_HASHES
is a comma delimited list of blockhashes to exclude.
Note: this can by design override a client's forkchoice and revert finalized blocks.
The ability to manually join a fork specified by a blockhash. A suggested implementation is --join-fork BLOCKHASH
where the client automatically sets the head to the block defined byBLOCKHASH
and locally finalizes it.
Note: this can by design override a client's forkchoice and revert finalized blocks.
The ability to monitor incoming vote
transactions for slashing conditions and submit proof to the casper contract for a finder's fee if found. A suggested implementation is --monitor-votes
.
The setting should default to disabled.
The following pseudocode defines when two vote
messages violate a slashing condition. A vote
message is the singular argument included in a vote
transaction.
def decode_rlp_list(vote_msg):
# [validator_index, target_hash, target_epoch, source_epoch, signature]
return RLPList(vote_msg, [int, bytes, int, int, bytes])
def same_target_epoch(vote_msg_1, vote_msg_2):
decoded_values_1 = decode_rlp_msg(vote_msg_1)
target_epoch_1 = decoded_values_1[2]
decoded_values_2 = decode_rlp_msg(vote_msg_2)
target_epoch_2 = decoded_values_2[2]
return target_epoch_1 == target_epoch_2
def surrounds(vote_msg_1, vote_msg_2):
decoded_values_1 = decode_rlp_msg(vote_msg_1)
target_epoch_1 = decoded_values_1[2]
source_epoch_1 = decoded_values_1[3]
decoded_values_2 = decode_rlp_msg(vote_msg_2)
target_epoch_2 = decoded_values_2[2]
source_epoch_1 = decoded_values_1[3]
vote_1_surrounds_vote_2 = target_epoch_1 > target_epoch_2 and source_epoch_1 < source_epoch_2
vote_2_surrounds_vote_1 = target_epoch_2 > target_epoch_1 and source_epoch_2 < source_epoch_1
return vote_1_surrounds_vote_2 or vote_2_surrounds_vote_1
def violates_slashing_condition(vote_msg_1, vote_msg_2):
return same_target_epoch(vote_msg_1, vote_msg_2) or surrounds(vote_msg_1, vote_msg_2)
The casper contract also provides a helper method slashable(vote_msg_1, vote_msg_2)
to check if two votes violate a slashing condition. Clients should use the above pseudocode in combination with casper.slashable()
as a final check when deciding whether to submit a slash
to the contract.
The --monitor-votes
setting is to be used for clients that wish to monitor vote transactions for slashing conditions. If a slashing condition is found, the client creates and sends a transaction to slash
on the casper contract. The first transaction to include the slashing condition proof slashes the validator in question and sends a 4% finder's fee to the transaction sender.
Naive PoS specifications and implementations have existed since early blockchain days, but most are vulnerable to serious attacks and do not hold up under crypto-economic analysis. Casper FFG solves problems such as "Nothing at Stake" and "Long Range Attacks" through requiring validators to post slashable deposits and through defining economic finality.
The finality gadget is designed to minimize changes across clients. For this reason, FFG is implemented within the EVM, so that the contract byte code encapsulates most of the complexity of the fork.
Most other decisions were made to minimize changes across clients. For example, it would be possible to allow CASPER_ADDR
to mint Ether each time it paid rewards (as compared to creating the contract with CASPER_BALANCE
), but this would be more invasive and error-prone than relying on existing EVM mechanics.
The MSG_HASHER_CODE
and PURITY_CHECKER_CODE
both do not require any initialization so the EVM bytecode can simply be placed at MSG_HASHER_ADDR
and PURITY_CHECKER_ADDR
. On the other hand, the casper contract does require passing in parameters and initialization of state. This initialization would normally occur by the EVM init code interacting with the CREATE opcode. Due to the nature of this contract being deployed outside of normal block transactions and to a particular address, the EVM init code/CREATE method requires client specific "hacks" to make it work. For simplicity of specifying across clients, the EVM bytecode -- CASPER_CODE
-- is placed at CASPER_ADDR
followed by an explicit CALL
to a one-time init
method on the casper contract. init
handles all of the logic that a constructor normally would, accepting contract parameters as arguments and setting initial variable values, and can only be run once.
CASPER_INIT_DATA
is composed of the byte signature of the init
method of the casper contract concatenated with the 32-byte encodings of the following variables in the following order:
EPOCH_LENGTH
WITHDRAWAL_DELAY
DYNASTY_LOGOUT_DELAY
MSG_HASHER_ADDR
PURITY_CHECKER_ADDR
BASE_INTEREST_FACTOR
BASE_PENALTY_FACTOR
MIN_DEPOSIT_SIZE
The entirety of this data is provided as a bytestring -- CASPER_INIT_DATA
-- to reduce the chance of encoding errors across clients, especially regarding fixed decimal types which are new in vyper and not yet supported by all clients.
EPOCH_LENGTH
is set to 50 blocks as a balance between time to finality and message overhead.
WARM_UP_PERIOD
is set to 1.8e5 blocks to provide validators with an approximate 1 month period to make initial deposits before full contract functionality and voting begin. This helps prevent degenerate cases such as having very few or even just one validator in the initial dynasty. This 1 month period also gives the network time to observe on the order of how many validators will initially be participating in consensus. If for some reason there is an unexpectedly low turnout, the community might choose to delay validation and consider design alternatives.
WITHDRAWAL_DELAY
is set to 15000 epochs to freeze a validator's funds for approximately 4 months after logout. This allows for at least a 4 month window to identify and slash a validator for attempting to finalize two conflicting checkpoints. This also defines the window of time with which a client must log on to sync the network due to weak subjectivity.
DYNASTY_LOGOUT_DELAY
is set to 700 dynasties to prevent immediate logout in the event of an attack from being a viable strategy.
BASE_INTEREST_FACTOR
is set to 7e-3 such that if there are ~10M ETH in total deposits, then validators earn approximately 5% per year in ETH rewards under optimal FFG conditions.
BASE_PENALTY_FACTOR
is set to 2e-7 such that if 50% of deposits go offline, then offline validators lose half of their deposits in approximately 3 weeks, at which the online portion of validators becomes a 2/3 majority and can begin finalizing checkpoints again.
MIN_DEPOSIT_SIZE
is set to 1500 ETH to form a natural upper bound on the total number of validators, bounding the overhead due to vote
messages. Using formulas found here under "From validator count to minimum staking ETH", we estimate that with 1500 ETH minimum deposit at an assumed ~10M in total deposits there will be approximately 900 validators at any given time. vote
s are only sent after the first quarter of an epoch so 900 votes have to fit into 37 blocks or ~24 vote
s per block. We have experimented with more dynamic models for MIN_DEPOSIT_SIZE
, but these tend to introduce significant complexities and without data from a live network seem to be premature optimizations.
The call to the method at INITIALIZE_EPOCH_BYTES
at CASPER_ADDR
at the start of each epoch is a call to the initialize_epoch
method in the casper contract. This method can only be called once per epoch and is guaranteed by the protocol to be called at the start block of each epoch by NULL_SENDER
. This method performs a number of bookkeeping tasks around incrementing variables, updating rewards, etc.
Any call to this method fails prior to the end of the WARM_UP_PERIOD
. Thus the protocol does not begin executing initialize_epoch
calls until block.number >= HYBRID_CASPER_FORK_BLKNUM + WARM_UP_PERIOD
.
A fixed amount of 1.25M ETH was chosen as CASPER_BALANCE
to fund the casper contract. This gives the contract enough runway to operate for approximately 2 years (assuming ~10M ETH in validator deposits). Acting similarly to the "difficulty bomb", this "funding crunch" forces the network to hardfork in the relative near future to further fund the contract. This future hardfork is an opportunity to upgrade the contract and transition to full PoS.
The PoW block reward is reduced from 3.0 to 0.6 ETH/block over the course of approximately one year because the security of the chain is greatly shifted from PoW difficulty to PoS finality and because rewards are now issued to both validators and miners. Rewards are stepped down by 0.6 ETH/block every 3 months (REWARD_STEPDOWN_BLOCK_COUNT
) to provide for a conservative transition period from full PoW to hybrid PoS/PoW. This gives validators time to become familiar with the new technology and begin logging on and also provides the network with more leeway in case of any unforeseen issues. If any major issues do arise, the Ethereum network will still have substantial PoW security to rely upon while decisions are made and/or patches are deployed. See here for further analysis of the current PoW security and of the effect of PoW block reward reduction in the context of Hybrid Casper FFG.
In addition to block rewards, miners now receive an issuance reward for including successful vote
transactions into the block on time. This reward is equal to 1/8th that of the reward the validator receives for a successful vote
transaction. Under optimal FFG conditions after group validator reward adjustments are made, miners receive approximately 1/5th of the total ETH issued by the Casper contract.
Below is a table of deposit sizes with associated annual interest rate and approximate time until funding crunch:
Deposit Size | Annual Validator Interest | Funding Crunch |
---|---|---|
2.5M ETH | 10.12% | ~4 years |
10M ETH | 5.00% | ~2 years |
20M ETH | 3.52% | ~1.4 years |
40M ETH | 2.48% | ~1 year |
Normal block transactions cannot affect casper vote
validation results, but casper vote
validation results can affect normal block transaction execution. Due to this asymmetrical relationship, vote
transactions can be processed in parallel with normal block transactions if vote
transactions are placed after all normal block transactions. Because vote
transactions can be processed in parallel to normal block transactions, vote
transactions cost 0 gas for validators, ensuring that validators can submit votes even in highly congested or high gas-price periods.
vote_gas_used
is introduced to ensure that vote
transactions do not put an undue burden on block processing. The additional overhead from vote
transactions is capped at the same limit as normal block transactions so that, when run in parallel, neither sets of transactions exceed the overhead defined by the block_gas_limit
.
The call to initialize_epoch
at the beginning of each epoch requires 0 gas so that this protocol state transition does not take any gas allowance away from normal transactions.
This EIP implements a limited version of account abstraction for validators' vote
transactions. The general design was borrowed from EIP-86. Rather than relying upon native transaction signatures, each validator specifies a signature contract when sending their deposit
to CASPER_ADDR
. When casting a vote
, the validator bundles and signs the parameters of their vote
according to the requirements of their signature contract. The vote
method of the casper contract checks the signature of the parameters against the validator's signature contract, exiting the transaction as unsuccessful if the signature is not successfully verified.
This allows validators to customize their own signing scheme for votes. Use cases include:
- quantum-secure signature schemes
- multisig wallets
- threshold schemes
For more details on validator account abstraction, see the Validator Implementation Guide.
Releasing client versions with the casper fork choice as initially default disabled allows for a more conservative transition to hybrid Casper FFG. Under normal operating conditions there are no disparities between the PoW fork choice and the hybrid Casper FFG fork choice. The two fork choice rules can only diverge if either 51% of miners or 51% of validators are faulty.
Validators will begin to log on, vote, and finalize the FFG contract before the majority of the network begins explicitly relying upon the new finality mechanism. Once a significant number of validators have logged on and the finality mechanism has been tested on the live network, new client software versions that change the default to enabled will be released.
NON_REVERT_MIN_DEPOSIT
is defined and configurable locally by each client. Clients are in charge of deciding upon the minimum deposits (security) at which they will accept the chain as finalized. In the general case, differing values in the choice of this local constant will not create any fork inconsistencies because clients with very strict finalization requirements will revert to follow the longest PoW chain.
Arguments have been made to hardcode a value into clients or the contract, but we cannot reasonably define security required for all clients especially in the context of massive fluctuations in the value of ETH.
This setting is useful in coordinating minority forks in cases of majority collusion.
This setting is to be used by new clients that are syncing the network for the first time. Due to weak subjectivity, a blockhash should be supplied to successfully sync the network when initially starting a node.
This setting is also useful for coordinating minority forks in cases of majority collusion.
Monitoring the network for slashing conditions is key to Casper FFG's "accountable safety" as submitting proof of nefarious activity burns a validator's deposit.
This setting is suggested default disabled because the block producer will almost certainly frontrun anyone else submitting a slash
transaction. To prevent every client on the network from submitting a slash
transaction in the event of a slashing condition, this setting should only be enabled by block producers and those clients who explicitly choose to monitor votes.
This EIP is not forward compatible and introduces backwards incompatibilities in the state, fork choice rule, block reward, transaction validity, and gas calculations on certain transactions. Therefore, all changes should be included in a scheduled hardfork at HYBRID_CASPER_FORK_BLKNUM
.
Copyright and related rights waived via CC0.