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
54 changes: 54 additions & 0 deletions src/attestation/inclusion_tracker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//! Attestation inclusion-delay accounting.
//!
//! Inclusion delay is measured in wall-clock slots: the difference between the
//! slot an attestation was assigned to and the slot of the beacon block that
//! includes it. Skipped slots still count toward this delay even though no block
//! exists for those slots.

/// Consensus slot number.
pub type Slot = u64;

/// Minimum valid attestation inclusion delay, in slots.
pub const MIN_ATTESTATION_INCLUSION_DELAY: u64 = 1;

/// Delay at which the inclusion-delay reward reaches zero.
pub const MAX_ATTESTATION_INCLUSION_DELAY: u64 = 32;

/// Return the number of wall-clock slots from `start` to `end`.
///
/// This intentionally does not inspect produced blocks. A skipped slot advances
/// wall-clock time and therefore increases attestation inclusion delay.
pub fn wall_slots_between(start: Slot, end: Slot) -> u64 {
end.saturating_sub(start)
}

/// Compute the inclusion delay for an attestation assigned to
/// `attestation_slot` and included in a block at `block_slot`.
pub fn compute_inclusion_delay(attestation_slot: Slot, block_slot: Slot) -> u64 {
wall_slots_between(attestation_slot, block_slot)
}

/// Compute the inclusion-delay reward for `delay` from `max_reward`.
///
/// Rewards are maximal at delay 1 and linearly decrease to zero at delay 32.
pub fn update_delay_rewards(delay: u64, max_reward: u64) -> u64 {
if delay < MIN_ATTESTATION_INCLUSION_DELAY {
return 0;
}

if delay >= MAX_ATTESTATION_INCLUSION_DELAY {
return 0;
}

let remaining = MAX_ATTESTATION_INCLUSION_DELAY - delay;
let reward_span = MAX_ATTESTATION_INCLUSION_DELAY - MIN_ATTESTATION_INCLUSION_DELAY;
max_reward.saturating_mul(remaining) / reward_span
}

/// Convenience helper for callers that have attestation and inclusion slots.
pub fn delay_reward(attestation_slot: Slot, block_slot: Slot, max_reward: u64) -> u64 {
update_delay_rewards(
compute_inclusion_delay(attestation_slot, block_slot),
max_reward,
)
}
1 change: 1 addition & 0 deletions src/attestation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

pub mod bitfield;
pub mod bls_aggregator;
pub mod inclusion_tracker;
pub mod key_registry;
pub mod verifier;
31 changes: 31 additions & 0 deletions src/consensus/fork_choice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//! Fork-choice branch weighting.

use crate::attestation::inclusion_tracker::{delay_reward, Slot};

/// Attestation data needed to weight a branch.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct IncludedAttestation {
/// Slot the attestation was assigned to.
pub attestation_slot: Slot,
/// Slot of the block that included the attestation.
pub inclusion_slot: Slot,
/// Validator or aggregate vote weight before inclusion-delay adjustment.
pub validator_weight: u64,
}

/// Compute a branch's total attestation weight after inclusion-delay rewards.
///
/// The calculation depends only on wall-clock attestation/inclusion slots, so
/// skipped-slot placement between them cannot make a branch appear heavier.
pub fn branch_weighting(attestations: &[IncludedAttestation], max_delay_reward: u64) -> u64 {
attestations
.iter()
.map(|attestation| {
attestation.validator_weight.saturating_add(delay_reward(
attestation.attestation_slot,
attestation.inclusion_slot,
max_delay_reward,
))
})
.sum()
}
3 changes: 3 additions & 0 deletions src/consensus/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Consensus helpers.

pub mod fork_choice;
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod slashing_core;
// signatures cannot be replayed across consensus domains.
pub mod attestation;
pub mod crypto;
pub mod consensus;

// Validator lifecycle and state transition.
// `validator` provides a deterministic exit queue ordered strictly by
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
{
"generators": {
"address": 2,
"nonce": 0
},
"auth": [
[]
],
"ledger": {
"protocol_version": 21,
"sequence_number": 0,
"timestamp": 0,
"network_id": "0000000000000000000000000000000000000000000000000000000000000000",
"base_reserve": 0,
"min_persistent_entry_ttl": 4096,
"min_temp_entry_ttl": 16,
"max_entry_ttl": 6312000,
"ledger_entries": [
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": "ledger_key_contract_instance",
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": "ledger_key_contract_instance",
"durability": "persistent",
"val": {
"contract_instance": {
"executable": {
"wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"storage": [
{
"key": {
"vec": [
{
"symbol": "Event"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4"
},
{
"u64": 1
}
]
},
"val": {
"map": [
{
"key": {
"symbol": "created_at"
},
"val": {
"u64": 100
}
},
{
"key": {
"symbol": "node_id"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4"
}
},
{
"key": {
"symbol": "penalty_amount"
},
"val": {
"i128": {
"hi": 0,
"lo": 1000
}
}
},
{
"key": {
"symbol": "reasons"
},
"val": {
"vec": [
{
"vec": [
{
"symbol": "DoubleSigning"
}
]
}
]
}
},
{
"key": {
"symbol": "scan_epoch"
},
"val": {
"u64": 1
}
},
{
"key": {
"symbol": "status"
},
"val": {
"vec": [
{
"symbol": "Pending"
}
]
}
}
]
}
}
]
}
}
}
},
"ext": "v0"
},
4095
]
],
[
{
"contract_code": {
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_code": {
"ext": "v0",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"code": ""
}
},
"ext": "v0"
},
4095
]
]
]
},
"events": []
}
Loading
Loading