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(sui-genesis-builder): migrate Alias Outputs #163

Merged
merged 36 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1385342
feat(sui-genesis-builder): store TypeOrigin of native tokens
kodemartin May 1, 2024
bf229ca
refactor(sui-genesis-builder): split stardust::types module
kodemartin May 1, 2024
28246e8
feat(sui-genesis-builder): add unlock types
kodemartin May 1, 2024
073ed9a
feat(sui-genesis-builder): add BasicOutput type
kodemartin May 1, 2024
87337aa
refactor(sui-genesis-builder): use OutputHeader while creating outputs
kodemartin May 1, 2024
3c1e1de
feat(sui-genesis-builder): implement stardust::migration::Executor::c…
kodemartin May 1, 2024
091f125
fixup! feat(sui-genesis-builder): implement stardust::migration::Exec…
kodemartin May 9, 2024
4b0a400
fixup! fixup! feat(sui-genesis-builder): implement stardust::migratio…
kodemartin May 10, 2024
d7776ad
feat(sui-genesis-builder): fix native-token object ids during migration
kodemartin May 10, 2024
c9aa74b
fixup! fixup! fixup! feat(sui-genesis-builder): implement stardust::m…
kodemartin May 10, 2024
fbe3f6b
Merge remote-tracking branch 'origin/develop' into 112-migrate-basic-…
kodemartin May 10, 2024
f22acfe
fix(sui-genesis-builder): correct BasicOutput::type_ module and name
kodemartin May 13, 2024
c55f70c
fix(sui-genesis-builder): load packages and input objects correctly
kodemartin May 13, 2024
85de8d6
fix(sui-genesis-builder): dummy transfer Bag object
kodemartin May 13, 2024
3a366b1
Implement move data model in Rust
PhilippGackstatter May 3, 2024
822b02e
Execute alias creation transaction
PhilippGackstatter May 6, 2024
8f38ec7
Fix dependencies during PTB execution
PhilippGackstatter May 6, 2024
9c2594c
Fix alias tags, extend test
PhilippGackstatter May 7, 2024
c4a13fb
Add TODO for dynamic object field
PhilippGackstatter May 8, 2024
b7b1b5e
Expose `attach_alias` function
PhilippGackstatter May 14, 2024
a9285f6
Fix outstanding alias migration TODOs
PhilippGackstatter May 14, 2024
e60e613
Prettify alias migration test
PhilippGackstatter May 14, 2024
c72792e
`cargo fmt` the genesis builder
PhilippGackstatter May 14, 2024
6c4611b
Make state controller non-optional
PhilippGackstatter May 14, 2024
f5457a5
Merge remote-tracking branch 'origin/develop' into 154-migrate-alias-…
PhilippGackstatter May 15, 2024
bf5134a
Move alias migration test to separate file
PhilippGackstatter May 15, 2024
ec92dc6
Cleanup alias migration test
PhilippGackstatter May 15, 2024
c846e3a
Add zeroized check and simplify match statement
PhilippGackstatter May 15, 2024
71ea94d
Merge remote-tracking branch 'origin/develop' into 154-migrate-alias-…
PhilippGackstatter May 15, 2024
c87dd6b
Add non-zeroed alias id test
PhilippGackstatter May 15, 2024
436601b
Use to_genesis_object approach
PhilippGackstatter May 16, 2024
7799f2d
Use fresh_id as the alias output ID
PhilippGackstatter May 16, 2024
2fd0d93
Merge remote-tracking branch 'origin/develop' into 154-migrate-alias-…
PhilippGackstatter May 16, 2024
56db801
Compute version of aliases via `lamport_timestamp`
PhilippGackstatter May 16, 2024
9820678
Merge remote-tracking branch 'origin/develop' into 154-migrate-alias-…
PhilippGackstatter May 16, 2024
01a4ed8
Move crate-level migration test to module
PhilippGackstatter May 16, 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
6 changes: 3 additions & 3 deletions crates/sui-framework/docs/stardust/alias.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ have to be received via this object once extracted from <code>AliasOutput</code>
This is the AliasID from Stardust.
</dd>
<dt>
<code>legacy_state_controller: <a href="../move-stdlib/option.md#0x1_option_Option">option::Option</a>&lt;<b>address</b>&gt;</code>
<code>legacy_state_controller: <b>address</b></code>
</dt>
<dd>
The last State Controller address assigned before the migration.
Expand Down Expand Up @@ -138,7 +138,7 @@ Destroy the <code><a href="alias.md#0x107a_alias_Alias">Alias</a></code> object,
Get the Alias's <code>legacy_state_controller</code>.


<pre><code><b>public</b> <b>fun</b> <a href="alias.md#0x107a_alias_legacy_state_controller">legacy_state_controller</a>(self: &<a href="alias.md#0x107a_alias_Alias">alias::Alias</a>): &<a href="../move-stdlib/option.md#0x1_option_Option">option::Option</a>&lt;<b>address</b>&gt;
<pre><code><b>public</b> <b>fun</b> <a href="alias.md#0x107a_alias_legacy_state_controller">legacy_state_controller</a>(self: &<a href="alias.md#0x107a_alias_Alias">alias::Alias</a>): &<b>address</b>
</code></pre>


Expand All @@ -147,7 +147,7 @@ Get the Alias's <code>legacy_state_controller</code>.
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="alias.md#0x107a_alias_legacy_state_controller">legacy_state_controller</a>(self: &<a href="alias.md#0x107a_alias_Alias">Alias</a>): &Option&lt;<b>address</b>&gt; {
<pre><code><b>public</b> <b>fun</b> <a href="alias.md#0x107a_alias_legacy_state_controller">legacy_state_controller</a>(self: &<a href="alias.md#0x107a_alias_Alias">Alias</a>): &<b>address</b> {
&self.legacy_state_controller
}
</code></pre>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module stardust::alias {
id: UID,

/// The last State Controller address assigned before the migration.
legacy_state_controller: Option<address>,
legacy_state_controller: address,
/// A counter increased by 1 every time the alias was state transitioned.
state_index: u32,
/// State metadata that can be used to store additional information.
Expand Down Expand Up @@ -47,7 +47,7 @@ module stardust::alias {
// === Public-Mutative Functions ===

/// Get the Alias's `legacy_state_controller`.
public fun legacy_state_controller(self: &Alias): &Option<address> {
public fun legacy_state_controller(self: &Alias): &address {
&self.legacy_state_controller
}

Expand Down Expand Up @@ -92,7 +92,7 @@ module stardust::alias {

#[test_only]
public fun create_for_testing(
legacy_state_controller: Option<address>,
legacy_state_controller: address,
state_index: u32,
state_metadata: Option<vector<u8>>,
sender: Option<address>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ module stardust::alias_tests {

let alias = alias::create_for_testing(
// legacy state controller
option::some(owner),
owner,
// state index
0,
// state metadata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ module stardust::address_unlock_condition_tests {

let alias = alias::create_for_testing(
// legacy state controller
option::some(owner),
owner,
// state index
0,
// state metadata
Expand Down
77 changes: 70 additions & 7 deletions crates/sui-genesis-builder/src/stardust/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use sui_types::{
use anyhow::Result;
use fastcrypto::hash::HashFunction;
use iota_sdk::types::block::output::{
AliasOutput, BasicOutput, FoundryOutput, NativeTokens, NftOutput, Output, TokenId,
TreasuryOutput,
AliasOutput as StardustAlias, BasicOutput, FoundryOutput, NativeTokens, NftOutput, Output,
TokenId, TreasuryOutput,
};
use move_vm_runtime_v2::move_vm::MoveVM;
use sui_adapter_v2::{
Expand Down Expand Up @@ -46,7 +46,7 @@ use sui_types::{
MOVE_STDLIB_PACKAGE_ID, STARDUST_PACKAGE_ID, SUI_FRAMEWORK_PACKAGE_ID, SUI_SYSTEM_PACKAGE_ID,
};

use super::types::snapshot::OutputHeader;
use super::types::{snapshot::OutputHeader, stardust_to_sui_address_owner, Alias, AliasOutput};
use crate::process_package;
use crate::stardust::native_token::package_builder;
use crate::stardust::native_token::package_data::NativeTokenPackageData;
Expand Down Expand Up @@ -121,7 +121,7 @@ impl Migration {
outputs.sort_by_key(|(header, _)| (header.ms_timestamp(), header.output_id()));
for (header, output) in outputs {
match output {
Output::Alias(alias) => self.executor.create_alias_objects(alias)?,
Output::Alias(alias) => self.executor.create_alias_objects(header, alias)?,
Output::Basic(basic) => self.executor.create_basic_objects(header, basic)?,
Output::Nft(nft) => self.executor.create_nft_objects(nft)?,
Output::Treasury(treasury) => self.executor.create_treasury_objects(treasury)?,
Expand Down Expand Up @@ -213,6 +213,7 @@ impl Executor {
)?;
}
let move_vm = Arc::new(new_move_vm(all_natives(silent), &protocol_config, None)?);

Ok(Self {
protocol_config,
tx_context,
Expand Down Expand Up @@ -341,8 +342,69 @@ impl Executor {
Ok(())
}

fn create_alias_objects(&mut self, _alias: AliasOutput) -> Result<()> {
todo!();
fn create_alias_objects(&mut self, header: OutputHeader, alias: StardustAlias) -> Result<()> {
// Take the Alias ID set in the output or, if its zeroized, compute it from the Output ID.
let alias_id = ObjectID::new(*alias.alias_id().or_from_output_id(&header.output_id()));
let move_alias = Alias::try_from_stardust(alias_id, &alias)?;

// TODO: We should ensure that no circular ownership exists.
let alias_output_owner = stardust_to_sui_address_owner(alias.governor_address())?;

let package_deps = InputObjects::new(self.load_packages(PACKAGE_DEPS).collect());
let version = package_deps.lamport_timestamp(&[]);
let move_alias_object = move_alias.to_genesis_object(
alias_output_owner,
&self.protocol_config,
&self.tx_context,
version,
)?;

let move_alias_object_ref = move_alias_object.compute_object_reference();
self.store.insert_object(move_alias_object);

let (bag, version) = self.create_bag(alias.native_tokens())?;
let move_alias_output =
AliasOutput::try_from_stardust(self.tx_context.fresh_id(), &alias, bag)?;

// The bag will be wrapped into the alias output object, so
// by equating their versions we emulate a ptb.
let move_alias_output_object = move_alias_output.to_genesis_object(
alias_output_owner,
&self.protocol_config,
&self.tx_context,
version,
)?;
let move_alias_output_object_ref = move_alias_output_object.compute_object_reference();
self.store.insert_object(move_alias_output_object);

// Attach the Alias to the Alias Output as a dynamic object field via the attach_alias convenience method.
let pt = {
let mut builder = ProgrammableTransactionBuilder::new();

let alias_output_arg =
builder.obj(ObjectArg::ImmOrOwnedObject(move_alias_output_object_ref))?;
let alias_arg = builder.obj(ObjectArg::ImmOrOwnedObject(move_alias_object_ref))?;
builder.programmable_move_call(
STARDUST_PACKAGE_ID,
ident_str!("alias_output").into(),
ident_str!("attach_alias").into(),
vec![],
vec![alias_output_arg, alias_arg],
);

builder.finish()
};

let input_objects = CheckedInputObjects::new_for_genesis(
self.load_input_objects([move_alias_object_ref, move_alias_output_object_ref])
.chain(self.load_packages(PACKAGE_DEPS))
.collect(),
);

let InnerTemporaryStore { written, .. } = self.execute_pt_unmetered(input_objects, pt)?;
self.store.finish(written);

Ok(())
}

/// Create a [`Bag`] of balances of native tokens.
Expand Down Expand Up @@ -510,7 +572,8 @@ impl Executor {

/// Verify the ledger state represented by the objects in [`InMemoryStorage`].
fn verify_ledger_state(_store: &InMemoryStorage) -> Result<()> {
todo!();
// TODO: Implementation. Returns Ok for now so the migration can be tested.
Ok(())
}

/// Serialize the objects stored in [`InMemoryStorage`] into a file using
Expand Down
125 changes: 125 additions & 0 deletions crates/sui-genesis-builder/src/stardust/migration_tests.rs
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);
}
2 changes: 2 additions & 0 deletions crates/sui-genesis-builder/src/stardust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ pub mod migration;
pub mod native_token;
pub mod parse;
pub mod types;
#[cfg(test)]
mod migration_tests;
26 changes: 26 additions & 0 deletions crates/sui-genesis-builder/src/stardust/types/address.rs
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,
)?)),
}
}
Loading
Loading