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(iota-genesis-builder): Add configurable delegator to genesis CLI #4346

Open
wants to merge 29 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b6fc756
feat(iota-genesis-builder): add delegator as cli arg for genesis
nonast Dec 4, 2024
c44b0b3
add bail when delegator missing
nonast Dec 4, 2024
232f688
fix genesis tests
nonast Dec 4, 2024
7e90668
feat(genesis): add delegator map type to genesis builder
nonast Dec 6, 2024
19e1efa
refactor(iota-genesis-builder): add comments and restructure resolve_…
miker83z Dec 6, 2024
0d90ad1
refactor(iota-genesis-builder): genesis cli arg to IotaAddress and ad…
nonast Dec 9, 2024
ab907ad
feat(genesis-ceremony): add InitDelegatorMap command
nonast Dec 9, 2024
6d6199e
refactor(iota-genesis-builder): renaming structs and replace fold() u…
nonast Dec 10, 2024
b77f93a
feat(iota-genesis-builder): add GenesisDelegation enum
nonast Dec 10, 2024
4b20406
chore(iota): correct bail messages to start with lower case
nonast Dec 10, 2024
25ec11f
refactor(iota-genesis-builder): rename schedule_without_migration to …
nonast Dec 10, 2024
4066d42
feat(iota-genesis-builder): create a token allocation to pay validato…
miker83z Dec 10, 2024
22fdd90
feat(iota-genesis-builder): optimize timelock and gas objects picks
miker83z Dec 10, 2024
8042a2e
fix format
miker83z Dec 10, 2024
4a35f0c
fix: add hardcoded delegator arg to docker config
nonast Dec 11, 2024
3ac99ea
fix(iota-genesis-builder): fix csv read and write functions
nonast Dec 11, 2024
a255e9f
chore: fix clippy warnings
nonast Dec 11, 2024
a6783fa
fix pick_objects_for_allocation logic
miker83z Dec 11, 2024
9b88238
Merge branch 'develop' into sc-platform/custom-genesis-delegator
miker83z Dec 13, 2024
dd0ebee
minor improvements
DaughterOfMars Dec 13, 2024
1211f0a
fix: add delegator to start cmd and partially revert minor improvement
nonast Dec 16, 2024
d850a38
refactor: add comments and adjust example argument
nonast Dec 17, 2024
1304b0e
fix fmt
miker83z Dec 17, 2024
3331460
fix clippy issue
nonast Dec 17, 2024
ab802af
Merge branch 'develop' into sc-platform/custom-genesis-delegator
nonast Dec 18, 2024
c42f614
chore: fix typos in comments
nonast Dec 19, 2024
59145c7
fix(iota-genesis-builder): comments and names to make it clearer
miker83z Dec 20, 2024
1ef83d2
refactor(iota-genesis-builder): use the destroy verb instead of burn
miker83z Dec 20, 2024
dea22ae
Merge branch 'develop' into sc-platform/custom-genesis-delegator
miker83z Dec 20, 2024
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
133 changes: 126 additions & 7 deletions crates/iota-config/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ impl TokenDistributionSchedule {
for allocation in &self.allocations {
total_nanos = total_nanos
.checked_add(allocation.amount_nanos)
.expect("TokenDistributionSchedule allocates more than the maximum supply which equals u64::MAX", );
.expect("TokenDistributionSchedule allocates more than the maximum supply which equals u64::MAX");
}
}

Expand Down Expand Up @@ -516,12 +516,7 @@ impl TokenDistributionSchedule {
/// Helper to read a TokenDistributionSchedule from a csv file.
///
/// The file is encoded such that the final entry in the CSV file is used to
/// denote the allocation to the stake subsidy fund. It must be in the
/// following format:
/// `0x0000000000000000000000000000000000000000000000000000000000000000,
/// <pre>minted supply</pre>,`
///
/// All entries in a token distribution schedule must add up to 10B Iota.
/// denote the allocation to the stake subsidy fund.
pub fn from_csv<R: std::io::Read>(reader: R) -> Result<Self> {
let mut reader = csv::Reader::from_reader(reader);
let mut allocations: Vec<TokenAllocation> =
Expand Down Expand Up @@ -568,7 +563,17 @@ impl TokenDistributionSchedule {
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct TokenAllocation {
/// Indicates the address that owns the tokens. It means that this
/// `TokenAllocation` can serve to stake some funds to the
/// `staked_with_validator` during genesis, but it's the `recipient_address`
/// which will receive the associated StakedIota (or TimelockedStakedIota)
/// object.
pub recipient_address: IotaAddress,
/// Indicates an amount of nanos that is:
/// - minted for the `recipient_address` and staked to a validator, only in
/// the case `staked_with_validator` is Some
/// - minted for the `recipient_address` and transferred that address,
/// otherwise.
pub amount_nanos: u64,

/// Indicates if this allocation should be staked at genesis and with which
Expand Down Expand Up @@ -628,3 +633,117 @@ impl TokenDistributionScheduleBuilder {
schedule
}
}

/// Represents the allocation of stake and gas payment to a validator.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct ValidatorAllocation {
miker83z marked this conversation as resolved.
Show resolved Hide resolved
/// The validator address receiving the stake and/or gas payment
pub validator: IotaAddress,
/// The amount of nanos to stake to the validator
pub amount_nanos_to_stake: u64,
/// The amount of nanos to transfer as gas payment to the validator
pub amount_nanos_to_pay_gas: u64,
kodemartin marked this conversation as resolved.
Show resolved Hide resolved
}

/// Represents a delegation of stake and gas payment to a validator,
/// coming from a delegator. This struct is used to serialize and deserialize
/// delegations to and from a csv file.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Delegation {
/// The address from which to take the nanos for staking/gas
pub delegator: IotaAddress,
/// The allocation to a validator receiving a stake and/or a gas payment
#[serde(flatten)]
pub validator_allocation: ValidatorAllocation,
}

/// Represents genesis delegations to validators.
///
/// This struct maps a delegator address to a list of validators and their
/// stake and gas allocations. Each ValidatorAllocation contains the address of
/// a validator that will receive an amount of nanos to stake and an amount as
/// gas payment.
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Delegations {
pub allocations: HashMap<IotaAddress, Vec<ValidatorAllocation>>,
}

impl Delegations {
pub fn new_for_validators_with_default_allocation(
validators: impl IntoIterator<Item = IotaAddress>,
delegator: IotaAddress,
) -> Self {
let validator_allocations = validators
.into_iter()
.map(|address| ValidatorAllocation {
validator: address,
amount_nanos_to_stake: iota_types::governance::MIN_VALIDATOR_JOINING_STAKE_NANOS,
amount_nanos_to_pay_gas: 0,
})
.collect();

let mut allocations = HashMap::new();
allocations.insert(delegator, validator_allocations);

Self { allocations }
}

/// Helper to read a Delegations struct from a csv file.
///
/// The file is encoded such that the final entry in the CSV file is used to
/// denote the allocation coming from a delegator. It must be in the
/// following format:
/// `delegator,validator,amount-nanos-to-stake,amount-nanos-to-pay-gas
/// <delegator1-address>,<validator-1-address>,2000000000000000,5000000000
/// <delegator1-address>,<validator-2-address>,3000000000000000,5000000000
/// <delegator2-address>,<validator-3-address>,4500000000000000,5000000000`
pub fn from_csv<R: std::io::Read>(reader: R) -> Result<Self> {
let mut reader = csv::Reader::from_reader(reader);

let mut delegations = Self::default();
for delegation in reader.deserialize::<Delegation>() {
let delegation = delegation?;
delegations
.allocations
.entry(delegation.delegator)
.or_default()
.push(delegation.validator_allocation);
}

Ok(delegations)
}

/// Helper to write a Delegations struct into a csv file.
///
/// It writes in the following format:
/// `delegator,validator,amount-nanos-to-stake,amount-nanos-to-pay-gas
/// <delegator1-address>,<validator-1-address>,2000000000000000,5000000000
/// <delegator1-address>,<validator-2-address>,3000000000000000,5000000000
/// <delegator2-address>,<validator-3-address>,4500000000000000,5000000000`
pub fn to_csv<W: std::io::Write>(&self, writer: W) -> Result<()> {
let mut writer = csv::Writer::from_writer(writer);

writer.write_record([
"delegator",
"validator",
"amount-nanos-to-stake",
"amount-nanos-to-pay-gas",
])?;

for (&delegator, validator_allocations) in &self.allocations {
for validator_allocation in validator_allocations {
writer.write_record(&[
delegator.to_string(),
validator_allocation.validator.to_string(),
validator_allocation.amount_nanos_to_stake.to_string(),
validator_allocation.amount_nanos_to_pay_gas.to_string(),
])?;
}
}

Ok(())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@
use std::{fs::File, path::Path};

use clap::{Parser, Subcommand};
use iota_genesis_builder::{
IF_STARDUST_ADDRESS,
stardust::{
parse::HornetSnapshotParser,
test_outputs::{add_snapshot_test_outputs, to_nanos},
},
use iota_genesis_builder::stardust::{
parse::HornetSnapshotParser,
test_outputs::{add_snapshot_test_outputs, to_nanos},
};
use iota_sdk::types::block::address::Ed25519Address;
use iota_types::{
base_types::IotaAddress, gas_coin::STARDUST_TOTAL_SUPPLY_IOTA, stardust::coin_type::CoinType,
};
use iota_sdk::types::block::address::Address;
use iota_types::{gas_coin::STARDUST_TOTAL_SUPPLY_IOTA, stardust::coin_type::CoinType};

const WITH_SAMPLING: bool = false;

Expand All @@ -32,6 +31,8 @@ enum Snapshot {
Iota {
#[clap(long, help = "Path to the Iota Hornet full-snapshot file")]
snapshot_path: String,
#[clap(long, help = "Specify the delegator address")]
delegator: IotaAddress,
},
}

Expand Down Expand Up @@ -62,8 +63,11 @@ fn parse_snapshot<const VERIFY: bool>(
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
let (current_path, coin_type) = match cli.snapshot {
Snapshot::Iota { snapshot_path } => (snapshot_path, CoinType::Iota),
let (current_path, delegator, coin_type) = match cli.snapshot {
Snapshot::Iota {
snapshot_path,
delegator,
} => (snapshot_path, delegator, CoinType::Iota),
};
let mut new_path = String::from("test-");
// prepend "test-" before the file name
Expand All @@ -80,7 +84,7 @@ async fn main() -> anyhow::Result<()> {
let (randomness_seed, delegator_address) = match coin_type {
CoinType::Iota => {
// IOTA coin type values
(0, IF_STARDUST_ADDRESS)
(0, delegator)
}
};

Expand All @@ -89,7 +93,7 @@ async fn main() -> anyhow::Result<()> {
&new_path,
coin_type,
randomness_seed,
*Address::try_from_bech32(delegator_address)?.as_ed25519(),
Ed25519Address::from(delegator_address.to_inner()),
WITH_SAMPLING,
)
.await?;
Expand Down
Loading
Loading