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 test outputs owned by aliases #797

Merged
merged 39 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
87e289c
...
Alex6323 Jun 24, 2024
9a1b4a4
add owned test outputs
Alex6323 Jun 24, 2024
52d270b
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jun 24, 2024
1d87cc6
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 8, 2024
f4d200c
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jun 26, 2024
83a4561
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 8, 2024
215dc59
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 8, 2024
64acc22
add test outputs owned by alias
Alex6323 Jun 27, 2024
bfc1121
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Jun 27, 2024
0875476
fix alias unlock
Alex6323 Jun 27, 2024
bcec772
randomized ownership dependency tree
Alex6323 Jun 28, 2024
10ddbef
clean up
Alex6323 Jun 28, 2024
3918c84
fix algo
Alex6323 Jul 1, 2024
ee91fdd
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 8, 2024
d1973e7
fix format
Alex6323 Jul 8, 2024
a5638e6
state controller uc
Alex6323 Jul 8, 2024
46c11c2
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 2, 2024
4973f3a
generate actual addresses
Alex6323 Jul 8, 2024
2615231
change mnemonic
Alex6323 Jul 2, 2024
fdbe054
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 2, 2024
7a8303b
min amount fix for foundries
Alex6323 Jul 2, 2024
9bb2d50
rm supply check
Alex6323 Jul 2, 2024
459ad60
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 2, 2024
c6a8199
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 8, 2024
7ae679f
align!
Alex6323 Jul 3, 2024
32be6b9
review
Alex6323 Jul 3, 2024
80566a2
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 3, 2024
d2170ce
fix compile
Alex6323 Jul 3, 2024
6b352ee
disable global snapshot verification for test data
Alex6323 Jul 3, 2024
4b20ce0
consistency
Alex6323 Jul 3, 2024
fce01f9
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 3, 2024
2d8859f
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 4, 2024
c87fa28
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 4, 2024
b5beb56
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 4, 2024
077fba4
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 5, 2024
506210d
bubble up
Alex6323 Jul 8, 2024
b6ac4e3
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 5, 2024
765bc63
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 8, 2024
88a449d
Merge branch 'develop' into dev-tools/test-data-alias-ownership
Alex6323 Jul 8, 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
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use iota_genesis_builder::stardust::{
};
use iota_types::gas_coin::TOTAL_SUPPLY_IOTA;

fn parse_snapshot<P: AsRef<Path>, const VERIFY: bool>(path: P) -> anyhow::Result<()> {
fn parse_snapshot<const VERIFY: bool>(path: impl AsRef<Path>) -> anyhow::Result<()> {
let file = File::open(path)?;
let mut parser = HornetSnapshotParser::new::<VERIFY>(file)?;

Expand Down Expand Up @@ -43,11 +43,11 @@ async fn main() -> anyhow::Result<()> {
new_path.push_str(&current_path);
}

parse_snapshot::<_, true>(&current_path)?;
parse_snapshot::<false>(&current_path)?;

add_snapshot_test_outputs::<_, true>(&current_path, &new_path).await?;
add_snapshot_test_outputs::<false>(&current_path, &new_path).await?;

parse_snapshot::<_, true>(&new_path)?;
parse_snapshot::<false>(&new_path)?;

Ok(())
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn create_bag_with_pt() {
.with_unlock_conditions([UnlockCondition::from(
ImmutableAliasAddressUnlockCondition::new(owner),
)])
.finish_with_params(supply)
.finish()
.unwrap();
let foundry_id = foundry.id();
let foundry_package_data = NativeTokenPackageData::new(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use std::collections::VecDeque;

use iota_sdk::{
client::secret::{mnemonic::MnemonicSecretManager, SecretManage},
types::block::{
address::{Address, AliasAddress},
output::{
feature::{Irc27Metadata, IssuerFeature, MetadataFeature},
unlock_condition::{
AddressUnlockCondition, GovernorAddressUnlockCondition,
ImmutableAliasAddressUnlockCondition, StateControllerAddressUnlockCondition,
},
AliasId, AliasOutput, AliasOutputBuilder, BasicOutput, BasicOutputBuilder, Feature,
FoundryOutput, FoundryOutputBuilder, NftId, NftOutput, NftOutputBuilder, Output,
SimpleTokenScheme, UnlockCondition, OUTPUT_INDEX_RANGE,
},
},
};
use rand::{rngs::StdRng, Rng, SeedableRng};

use crate::stardust::{
test_outputs::{MERGE_MILESTONE_INDEX, MERGE_TIMESTAMP_SECS},
types::{output_header::OutputHeader, output_index::OutputIndex},
};

const MNEMONIC: &str = "few hood high omit camp keep burger give happy iron evolve draft few dawn pulp jazz box dash load snake gown bag draft car";
const COIN_TYPE: u32 = 4218;
const OWNING_ALIAS_COUNT: u32 = 10;

pub(crate) async fn outputs() -> anyhow::Result<Vec<(OutputHeader, Output)>> {
let mut outputs = Vec::new();
let secret_manager = MnemonicSecretManager::try_from_mnemonic(MNEMONIC)?;

// create a randomized ownership dependency tree
let randomness_seed = rand::random();
let mut rng = StdRng::seed_from_u64(randomness_seed);
println!("alias_ownership randomness seed: {randomness_seed}");

let alias_owners = secret_manager
.generate_ed25519_addresses(COIN_TYPE, 0, 0..OWNING_ALIAS_COUNT, None)
.await?;

// create 10 different alias outputs with each owning various other assets
for alias_owner in alias_owners {
let alias_output_header = random_output_header(&mut rng);

let alias_output = AliasOutputBuilder::new_with_amount(
1_000_000,
(&alias_output_header.output_id()).into(),
)
.add_unlock_condition(GovernorAddressUnlockCondition::new(alias_owner))
.add_unlock_condition(StateControllerAddressUnlockCondition::new(alias_owner))
.finish()?;
let alias_address = AliasAddress::new(*alias_output.alias_id());

// let this alias own various other assets, that may themselves own other assets
let max_depth = rng.gen_range(1usize..5);
let mut owning_addresses: VecDeque<(usize, Address)> =
vec![(0, alias_address.into())].into();

while let Some((depth, owning_addr)) = owning_addresses.pop_front() {
if depth > max_depth {
continue;
}
let mut serial_number = 1;
// create a random number of random assets
for _ in 0usize..rng.gen_range(1..=5) {
match rng.gen_range(0..=3) {
0 => {
// alias
let (output_header, alias) = random_alias_output(&mut rng, owning_addr)?;
owning_addresses
.push_back((depth + 1, AliasAddress::new(*alias.alias_id()).into()));
outputs.push((output_header, alias.into()));
}
1 => {
// nft
let (output_header, nft) = random_nft_output(&mut rng, owning_addr)?;
owning_addresses.push_back((
depth + 1,
nft.nft_address(&output_header.output_id()).into(),
));
outputs.push((output_header, nft.into()));
}
2 => {
// basic
let (output_header, basic) = random_basic_output(&mut rng, owning_addr)?;
outputs.push((output_header, basic.into()));
}
3 => {
// foundry
if let Address::Alias(owning_addr) = owning_addr {
let (output_header, foundry) =
random_foundry_output(&mut rng, &mut serial_number, owning_addr)?;
outputs.push((output_header, foundry.into()));
}
}
_ => unreachable!(),
}
}
}
}
Ok(outputs)
}

fn random_basic_output(
rng: &mut StdRng,
owner: impl Into<Address>,
) -> anyhow::Result<(OutputHeader, BasicOutput)> {
let basic_output_header = random_output_header(rng);

let amount = rng.gen_range(1_000_000..10_000_000);
let basic_output = BasicOutputBuilder::new_with_amount(amount)
.add_unlock_condition(AddressUnlockCondition::new(owner))
.finish()?;

Ok((basic_output_header, basic_output))
}

fn random_nft_output(
rng: &mut StdRng,
owner: impl Into<Address>,
) -> anyhow::Result<(OutputHeader, NftOutput)> {
let owner = owner.into();
let nft_output_header = random_output_header(rng);
let nft_metadata = Irc27Metadata::new("image/png", "https://nft.org/nft.png".parse()?, "NFT")
.with_issuer_name("issuer_name")
.with_collection_name("collection_name")
.with_description("description");

let amount = rng.gen_range(1_000_000..10_000_000);
let nft_output = NftOutputBuilder::new_with_amount(amount, NftId::new(rng.gen()))
.add_unlock_condition(AddressUnlockCondition::new(owner.clone()))
.with_immutable_features(vec![
Feature::Metadata(MetadataFeature::new(serde_json::to_vec(&nft_metadata)?)?),
Feature::Issuer(IssuerFeature::new(owner)),
])
.finish()?;

Ok((nft_output_header, nft_output))
}

fn random_alias_output(
rng: &mut StdRng,
owner: impl Into<Address>,
) -> anyhow::Result<(OutputHeader, AliasOutput)> {
let owner = owner.into();
let alias_output_header = random_output_header(rng);

let amount = rng.gen_range(1_000_000..10_000_000);
let alias_output = AliasOutputBuilder::new_with_amount(amount, AliasId::new(rng.gen()))
.add_unlock_condition(GovernorAddressUnlockCondition::new(owner.clone()))
.add_unlock_condition(StateControllerAddressUnlockCondition::new(owner))
.finish()?;

Ok((alias_output_header, alias_output))
}

fn random_foundry_output(
rng: &mut StdRng,
serial_number: &mut u32,
owner: impl Into<AliasAddress>,
) -> anyhow::Result<(OutputHeader, FoundryOutput)> {
let foundry_output_header = random_output_header(rng);

let amount = rng.gen_range(1_000_000..10_000_000);
let supply = rng.gen_range(1_000_000..100_000_000);
let token_scheme = SimpleTokenScheme::new(supply, 0, supply)?;
let foundry_output =
FoundryOutputBuilder::new_with_amount(amount, *serial_number, token_scheme.into())
.with_unlock_conditions([UnlockCondition::from(
ImmutableAliasAddressUnlockCondition::new(owner),
)])
.finish()?;

*serial_number += 1;

Ok((foundry_output_header, foundry_output))
}

fn random_output_header(rng: &mut StdRng) -> OutputHeader {
OutputHeader::new_testing(
rng.gen(),
OutputIndex::new(rng.gen_range(OUTPUT_INDEX_RANGE))
.expect("range is guaranteed to be valid"),
rng.gen(),
MERGE_MILESTONE_INDEX,
MERGE_TIMESTAMP_SECS,
)
}
22 changes: 8 additions & 14 deletions crates/iota-genesis-builder/src/stardust/test_outputs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

mod alias_ownership;
mod stardust_mix;
mod vesting_schedule_entity;
mod vesting_schedule_iota_airdrop;

use std::{
fs::{File, OpenOptions},
io::BufWriter,
path::Path,
str::FromStr,
};
use std::{fs::File, io::BufWriter, path::Path, str::FromStr};

use iota_sdk::types::block::{
address::Ed25519Address,
Expand Down Expand Up @@ -65,23 +61,21 @@ pub(crate) fn new_vested_output(
}

/// Adds outputs to test specific and intricate scenario in the full snapshot.
pub async fn add_snapshot_test_outputs<P: AsRef<Path> + core::fmt::Debug, const VERIFY: bool>(
current_path: P,
new_path: P,
pub async fn add_snapshot_test_outputs<const VERIFY: bool>(
current_path: impl AsRef<Path> + core::fmt::Debug,
new_path: impl AsRef<Path> + core::fmt::Debug,
) -> anyhow::Result<()> {
let current_file = File::open(current_path)?;
let new_file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
Thoralf-M marked this conversation as resolved.
Show resolved Hide resolved
.open(new_path)?;
let new_file = File::create(new_path)?;

let mut writer = IoPacker::new(BufWriter::new(new_file));
let mut parser = HornetSnapshotParser::new::<VERIFY>(current_file)?;
let output_to_decrease_amount_from = OutputId::from_str(OUTPUT_TO_DECREASE_AMOUNT_FROM)?;
let mut new_header = parser.header.clone();
let mut vested_index = u32::MAX;

let new_outputs = [
alias_ownership::outputs().await?,
stardust_mix::outputs(&mut vested_index).await?,
vesting_schedule_entity::outputs(&mut vested_index).await?,
vesting_schedule_iota_airdrop::outputs(&mut vested_index).await?,
Expand Down
Loading