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: committee selection beacon slashing #65

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions core/application/networks/localnet-example/genesis.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ topology_target_k = 8
topology_min_nodes = 16
committee_selection_beacon_commit_phase_duration = 10
committee_selection_beacon_reveal_phase_duration = 10
committee_selection_beacon_non_reveal_slash_amount = 1000

[[node_info]]
owner = "0x959807B8D94B324A74117956731F09E2893aCd72"
Expand Down
4 changes: 4 additions & 0 deletions core/application/networks/testnet-stable/genesis.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ committee_selection_beacon_commit_phase_duration = 600
# and starting with a long duration for safety since non-revealing nodes will be slashed.
committee_selection_beacon_reveal_phase_duration = 12000

# Amount of stake to slash for non-revealing nodes.
# 1000 is 100% of the minimum stake.
committee_selection_beacon_non_reveal_slash_amount = 1000


[[node_info]]
owner = "0x2a8cf657769c264b0c7f88e3a716afdeaec1c318"
Expand Down
33 changes: 26 additions & 7 deletions core/application/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ impl ApplicationEnv {
let app = ApplicationState::executor(ctx);
let last_block_hash = app.get_block_hash();

let block_number = app.get_block_number() + 1;
let last_block_number = app.get_block_number();
let block_number = last_block_number + 1;

let committee_before_execution = app.get_current_committee();

// Create block response
let mut response = BlockExecutionResponse {
Expand Down Expand Up @@ -134,19 +137,28 @@ impl ApplicationEnv {
}

// Update node registry changes on the response if there were any for this block.
if let Some(committee) = app.get_current_committee() {
let committee = app.get_current_committee();
if let Some(committee) = &committee {
if let Some(changes) = committee.node_registry_changes.get(&block_number) {
response.node_registry_changes = changes.clone();
}
}

// If the committee changed, advance to the next epoch era.
let has_committee_members_changes =
committee_before_execution.map(|c| c.members) != committee.map(|c| c.members);
if has_committee_members_changes {
app.set_epoch_era(app.get_epoch_era() + 1);
}

// Set the last executed block hash and sub dag index
// if epoch changed a new committee starts and subdag starts back at 0
let (new_sub_dag_index, new_sub_dag_round) = if response.change_epoch {
(0, 0)
} else {
(block.sub_dag_index, block.sub_dag_round)
};
let (new_sub_dag_index, new_sub_dag_round) =
if response.change_epoch || has_committee_members_changes {
(0, 0)
} else {
(block.sub_dag_index, block.sub_dag_round)
};
app.set_last_block(response.block_hash, new_sub_dag_index, new_sub_dag_round);

// Set the new state root on the response.
Expand Down Expand Up @@ -334,6 +346,12 @@ impl ApplicationEnv {
genesis.committee_selection_beacon_reveal_phase_duration,
),
);
param_table.insert(
ProtocolParamKey::CommitteeSelectionBeaconNonRevealSlashAmount,
ProtocolParamValue::CommitteeSelectionBeaconNonRevealSlashAmount(
genesis.committee_selection_beacon_non_reveal_slash_amount,
),
);

let epoch_end: u64 = genesis.epoch_time + genesis.epoch_start;
let mut committee_members = Vec::with_capacity(4);
Expand Down Expand Up @@ -451,6 +469,7 @@ impl ApplicationEnv {
}

metadata_table.insert(Metadata::Epoch, Value::Epoch(0));
metadata_table.insert(Metadata::EpochEra, Value::EpochEra(0));

tracing::info!("Genesis block loaded into application state.");
Ok(true)
Expand Down
4 changes: 2 additions & 2 deletions core/application/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ mod tests {

#[test]
fn test_localnet_example_genesis() {
assert!(Network::LocalnetExample.genesis().is_ok());
Network::LocalnetExample.genesis().unwrap();
}

#[test]
fn test_testnet_stable_genesis() {
assert!(Network::TestnetStable.genesis().is_ok());
Network::TestnetStable.genesis().unwrap();
}
}
39 changes: 33 additions & 6 deletions core/application/src/state/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ impl<B: Backend> StateExecutor<B> {

// Increase the nodes stake by the amount being staked
node.stake.staked += amount.clone();
self.node_info.set(index, node);
self.node_info.set(index, node.clone());
},
None => {
// If the node doesn't Exist, create it. But check if they provided all the required
Expand Down Expand Up @@ -651,10 +651,10 @@ impl<B: Backend> StateExecutor<B> {
return TransactionResponse::Revert(ExecutionError::InsufficientNodeDetails);
}
},
}
};

// decrement the owners balance
owner.flk_balance -= amount;
owner.flk_balance -= amount.clone();

// Commit changes to the owner
self.account_info.set(sender, owner);
Expand Down Expand Up @@ -758,7 +758,7 @@ impl<B: Backend> StateExecutor<B> {
// current epoch + lock time todo(dalton): we should be storing unstaked tokens in a
// list so we can have multiple locked stakes with dif lock times
node.stake.staked -= amount.clone();
node.stake.locked += amount;
node.stake.locked += amount.clone();
node.stake.locked_until = current_epoch + lock_time;

// Save the changed node state.
Expand All @@ -769,7 +769,7 @@ impl<B: Backend> StateExecutor<B> {
// set as Participation::False on epoch change.
if !self.has_sufficient_unlocked_stake(&node_index) && self.is_participating(&node_index) {
node.participation = Participation::OptedOut;
self.node_info.set(node_index, node);
self.node_info.set(node_index, node.clone());
}

// Return success.
Expand Down Expand Up @@ -864,6 +864,7 @@ impl<B: Backend> StateExecutor<B> {
Some(mut node_info) => {
node_info.participation = Participation::OptedIn;
self.node_info.set(index, node_info);

TransactionResponse::Success(ExecutionData::None)
},
None => TransactionResponse::Revert(ExecutionError::NodeDoesNotExist),
Expand All @@ -879,6 +880,7 @@ impl<B: Backend> StateExecutor<B> {
Some(mut node_info) => {
node_info.participation = Participation::OptedOut;
self.node_info.set(index, node_info);

TransactionResponse::Success(ExecutionData::None)
},
None => TransactionResponse::Revert(ExecutionError::NodeDoesNotExist),
Expand Down Expand Up @@ -1591,7 +1593,7 @@ impl<B: Backend> StateExecutor<B> {
}
}

fn get_epoch(&self) -> u64 {
pub fn get_epoch(&self) -> u64 {
if let Some(Value::Epoch(epoch)) = self.metadata.get(&Metadata::Epoch) {
epoch
} else {
Expand All @@ -1600,6 +1602,14 @@ impl<B: Backend> StateExecutor<B> {
}
}

pub fn get_committee(&self, epoch: Epoch) -> Committee {
self.committee_info.get(&epoch).unwrap_or_default()
}

pub fn get_node_public_key(&self, node_index: &NodeIndex) -> NodePublicKey {
self.node_info.get(node_index).unwrap().public_key
}

fn clear_content_registry(&self, node_index: &NodeIndex) -> Result<(), ExecutionError> {
let uris = self.node_to_uri.get(node_index).unwrap_or_default();

Expand Down Expand Up @@ -1634,6 +1644,7 @@ impl<B: Backend> StateExecutor<B> {
}
}
}

/// Records a node registry change for the current epoch and block number.
fn record_node_registry_change(
&self,
Expand All @@ -1655,4 +1666,20 @@ impl<B: Backend> StateExecutor<B> {
pub fn get_current_committee(&self) -> Option<Committee> {
self.committee_info.get(&self.get_epoch())
}

pub fn get_node_index(&self, node_public_key: &NodePublicKey) -> Option<NodeIndex> {
self.pub_key_to_index.get(node_public_key)
}

pub fn get_epoch_era(&self) -> u64 {
if let Some(Value::EpochEra(era)) = self.metadata.get(&Metadata::EpochEra) {
era
} else {
0
}
}

pub fn set_epoch_era(&self, era: u64) {
self.metadata.set(Metadata::EpochEra, Value::EpochEra(era));
}
}
Loading