-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sui-genesis-builder): migrate Alias Outputs (#163)
* feat(sui-genesis-builder): store TypeOrigin of native tokens While creating foundries now maps the `(ObjectID, TypeOrigin)` to the `TokenId`. * refactor(sui-genesis-builder): split stardust::types module * feat(sui-genesis-builder): add unlock types * feat(sui-genesis-builder): add BasicOutput type * refactor(sui-genesis-builder): use OutputHeader while creating outputs * feat(sui-genesis-builder): implement stardust::migration::Executor::create_basic_objects * fixup! feat(sui-genesis-builder): implement stardust::migration::Executor::create_basic_objects * fixup! fixup! feat(sui-genesis-builder): implement stardust::migration::Executor::create_basic_objects * feat(sui-genesis-builder): fix native-token object ids during migration * fixup! fixup! fixup! feat(sui-genesis-builder): implement stardust::migration::Executor::create_basic_objects * fix(sui-genesis-builder): correct BasicOutput::type_ module and name Co-authored-by: Philipp Gackstatter <[email protected]> * fix(sui-genesis-builder): load packages and input objects correctly * fix(sui-genesis-builder): dummy transfer Bag object * Implement move data model in Rust * Execute alias creation transaction * Fix dependencies during PTB execution * Fix alias tags, extend test * Add TODO for dynamic object field * Expose `attach_alias` function * Fix outstanding alias migration TODOs * Prettify alias migration test * `cargo fmt` the genesis builder * Make state controller non-optional * Move alias migration test to separate file * Cleanup alias migration test * Add zeroized check and simplify match statement * Add non-zeroed alias id test * Use to_genesis_object approach * Use fresh_id as the alias output ID * Compute version of aliases via `lamport_timestamp` * Move crate-level migration test to module --------- Co-authored-by: Konstantinos Demartinos <[email protected]>
- Loading branch information
1 parent
775f8a3
commit 54b588c
Showing
11 changed files
with
452 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
crates/sui-genesis-builder/src/stardust/migration_tests.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
use iota_sdk::types::block::{ | ||
address::Ed25519Address, | ||
output::{ | ||
feature::{IssuerFeature, MetadataFeature, SenderFeature}, | ||
unlock_condition::{GovernorAddressUnlockCondition, StateControllerAddressUnlockCondition}, | ||
AliasId, AliasOutput as StardustAlias, AliasOutputBuilder, Feature, | ||
}, | ||
}; | ||
use crate::stardust::{ | ||
migration::Migration, | ||
types::{snapshot::OutputHeader, Alias, AliasOutput}, | ||
}; | ||
use sui_types::{base_types::ObjectID, object::Object}; | ||
|
||
fn migrate_alias( | ||
header: OutputHeader, | ||
stardust_alias: StardustAlias, | ||
) -> (ObjectID, Alias, AliasOutput) { | ||
let alias_id: AliasId = stardust_alias | ||
.alias_id() | ||
.or_from_output_id(&header.output_id()) | ||
.to_owned(); | ||
let mut snapshot_buffer = Vec::new(); | ||
Migration::new() | ||
.unwrap() | ||
.run( | ||
[].into_iter(), | ||
[(header, stardust_alias.into())].into_iter(), | ||
&mut snapshot_buffer, | ||
) | ||
.unwrap(); | ||
|
||
let migrated_objects: Vec<Object> = bcs::from_bytes(&snapshot_buffer).unwrap(); | ||
|
||
// Ensure the migrated objects exist under the expected identifiers. | ||
let alias_object_id = ObjectID::new(*alias_id); | ||
let alias_object = migrated_objects | ||
.iter() | ||
.find(|obj| obj.id() == alias_object_id) | ||
.expect("alias object should be present in the migrated snapshot"); | ||
assert_eq!(alias_object.struct_tag().unwrap(), Alias::tag(),); | ||
let alias_output_object = migrated_objects | ||
.iter() | ||
.find(|obj| match obj.struct_tag() { | ||
Some(tag) => tag == AliasOutput::tag(), | ||
None => false, | ||
}) | ||
.expect("alias object should be present in the migrated snapshot"); | ||
|
||
// Version is set to 1 when the alias is created based on the computed lamport timestamp. | ||
// When the alias is attached to the alias output, the version should be incremented. | ||
assert!( | ||
alias_object.version().value() > 1, | ||
"alias object version should have been incremented" | ||
); | ||
assert!( | ||
alias_output_object.version().value() > 1, | ||
"alias output object version should have been incremented" | ||
); | ||
|
||
let alias_output: AliasOutput = | ||
bcs::from_bytes(alias_output_object.data.try_as_move().unwrap().contents()).unwrap(); | ||
let alias: Alias = | ||
bcs::from_bytes(alias_object.data.try_as_move().unwrap().contents()).unwrap(); | ||
|
||
(alias_object_id, alias, alias_output) | ||
} | ||
|
||
/// Test that the migrated alias objects in the snapshot contain the expected data. | ||
#[test] | ||
fn test_alias_migration() { | ||
let alias_id = AliasId::new(rand::random()); | ||
let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); | ||
let header = OutputHeader::new_testing( | ||
rand::random(), | ||
rand::random(), | ||
rand::random(), | ||
rand::random(), | ||
); | ||
|
||
let stardust_alias = AliasOutputBuilder::new_with_amount(1_000_000, alias_id) | ||
.add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) | ||
.add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) | ||
.with_state_metadata([0xff; 1]) | ||
.with_features(vec![ | ||
Feature::Metadata(MetadataFeature::new([0xdd; 1]).unwrap()), | ||
Feature::Sender(SenderFeature::new(random_address)), | ||
]) | ||
.with_immutable_features(vec![ | ||
Feature::Metadata(MetadataFeature::new([0xaa; 1]).unwrap()), | ||
Feature::Issuer(IssuerFeature::new(random_address)), | ||
]) | ||
.with_state_index(3) | ||
.finish() | ||
.unwrap(); | ||
|
||
let (alias_object_id, alias, alias_output) = migrate_alias(header, stardust_alias.clone()); | ||
let expected_alias = Alias::try_from_stardust(alias_object_id, &stardust_alias).unwrap(); | ||
|
||
// Compare only the balance. The ID is newly generated and the bag is tested separately. | ||
assert_eq!(stardust_alias.amount(), alias_output.iota.value()); | ||
|
||
assert_eq!(expected_alias, alias); | ||
} | ||
|
||
#[test] | ||
fn test_alias_migration_with_zeroed_id() { | ||
let random_address = Ed25519Address::from(rand::random::<[u8; Ed25519Address::LENGTH]>()); | ||
let header = OutputHeader::new_testing( | ||
rand::random(), | ||
rand::random(), | ||
rand::random(), | ||
rand::random(), | ||
); | ||
|
||
let stardust_alias = AliasOutputBuilder::new_with_amount(1_000_000, AliasId::null()) | ||
.add_unlock_condition(StateControllerAddressUnlockCondition::new(random_address)) | ||
.add_unlock_condition(GovernorAddressUnlockCondition::new(random_address)) | ||
.finish() | ||
.unwrap(); | ||
|
||
// If this function does not panic, then the created aliases | ||
// were found at the correct non-zeroed Alias ID. | ||
migrate_alias(header, stardust_alias); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,5 @@ pub mod migration; | |
pub mod native_token; | ||
pub mod parse; | ||
pub mod types; | ||
#[cfg(test)] | ||
mod migration_tests; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use iota_sdk::types::block::address::Address; | ||
use sui_types::{base_types::SuiAddress, object::Owner}; | ||
|
||
/// Converts a ["Stardust" `Address`](Address) to a [`SuiAddress`]. | ||
/// | ||
/// This is intended as the only conversion function to go from Stardust to Sui addresses, so there is only | ||
/// one place to potentially update it if we decide to change it later. | ||
pub fn stardust_to_sui_address(stardust_address: impl Into<Address>) -> anyhow::Result<SuiAddress> { | ||
stardust_address.into().to_string().parse() | ||
} | ||
|
||
/// Converts a ["Stardust" `Address`](Address) to a [`SuiAddress`] and then wraps it into an [`Owner`] | ||
/// which is either address- or object-owned depending on the stardust address. | ||
pub fn stardust_to_sui_address_owner( | ||
stardust_address: impl Into<Address>, | ||
) -> anyhow::Result<Owner> { | ||
let stardust_address = stardust_address.into(); | ||
match &stardust_address { | ||
Address::Ed25519(_) => Ok(Owner::AddressOwner(stardust_to_sui_address( | ||
stardust_address, | ||
)?)), | ||
Address::Alias(_) | Address::Nft(_) => Ok(Owner::ObjectOwner(stardust_to_sui_address( | ||
stardust_address, | ||
)?)), | ||
} | ||
} |
Oops, something went wrong.