Package Metadata #36
miker83z
started this conversation in
Featured Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Proposal
Abstract
PackageMetadatais an immutable on-chain object that provides trusted metadata about Move packages during execution. BecausePackageMetadataobjects are created exclusively by the protocol during publish and upgrade operations, Move code can read this metadata with full confidence in its authenticity. This enables on-chain verification of package properties without relying on user-provided claims. This mechanism allows Move modules to introspect package capabilities, verify function signatures, and make decisions based on protocol-attested information.Motivation
Move execution might require knowledge about external packages or the same package being used: What functions does a package expose? What capabilities does it claim? Is a given function a valid authenticator?
Traditionally, answering these questions required either:
PackageMetadatasolves this by providing protocol-attested package introspection. Because only the protocol can createPackageMetadataobjects (during publish/upgrade), and because these objects are immutable, Move code can trust their contents completely. This enables:Possible use cases exploiting
PackageMetadatacould be:PackageMetadatato verify that a function is a valid authenticator and to obtain the account type it authenticates. This enables theaccountmodule to createAuthenticatorInfoV1instances that reference verified authenticator functions.Specification
In this section, we present the technical specification for implementing an Package Metadata model version 1 within the IOTA protocol. The specification begins by outlining a set of functional requirements the model must satisfy, followed by a high-level overview of the proposed architectural approach. Finally, the main set of Move type interfaces will be provided as standard for the first version of this model.
Requirements
The proposed Package Metadata model must adhere to the following constraints:
PackageMetadataobjects can only be created by the protocol during publish or upgrade execution. There is no public constructor or creation function exposed to Move code. This guarantees that:PackageMetadatacontent is derived from verified bytecodePackageMetadataobjects are frozen immediately upon creation.PackageMetadatais created only when meaningful metadata exists, e.g., at least one recognized attribute must be present in a module of the package. Packages without attributes have noPackageMetadataobject.PackageMetadataid derivation: Given any package id, the correspondingPackageMetadataobject id can be computed using the derived object mechanism (same as dynamic fields id derivation). See https://docs.sui.io/guides/developer/objects/derived-objects. Move code can compute this derivation on-chain.High-Level Overview
To support
PackageMetadata, we propose to modify part of the Move compilation, part of the publish/upgrade execution and the addition of a new module to the iota-framework.In the following, we are going to use the usage of Package Metadata within the IOTA Account Abstraction model (see #35), because that is a concrete use of the standard.
Compilation and building phase
The process begins on the developer's machine during package compilation. When the Move compiler encounters a function annotated with a recognized attribute (such as
#[authenticator]), it records this information in the function's metadata. The compiler performs initial syntax validation, ensuring the attribute is well-formed and applied to an appropriate element, but does not verify semantic correctness (e.g., whether the function signature actually satisfies authenticator requirements).During the build phase, the collected attribute information is serialized into a
RuntimeModuleMetadatastructure and embedded directly into the module's bytecode. Once all attributes for a module are collected, theRuntimeModuleMetadataV1is wrapped in aRuntimeModuleMetadataWrapper(which includes a version number) and serialized to BCS bytes. These bytes are then pushed into the module's bytecode metadata vector using a dedicated key.The
IOTA_METADATA_KEYis a protocol-defined constant that acts as a reserved namespace. While the bytecode format allows arbitrary metadata entries, the protocol's verifier enforces strict rules:IOTA_METADATA_KEYRuntimeModuleMetadataWrapperFinally, the metadata will travels with the bytecode through the publish transaction, ensuring the protocol has access to the original annotations.
Publish/Upgrade phase
When a publish or upgrade transaction is executed, the protocol takes over. This phase is critical because it establishes the trust boundary: everything that happens here is performed by the protocol itself, not by user code.
Verification
During publish or upgrade, the protocol extracts
RuntimeModuleMetadatafrom each module's bytecode using this theIOTA_METADATA_KEY, deserializes it, and verifies each attribute. For every attribute found, the protocol invokes the corresponding verifier. For authenticator attributes, for instance, this means callingverify_authenticate_func_v1(), which checks that the function has the correct visibility, parameter types, and return type (see #35).If any verification fails, the entire publish or upgrade transaction fails. User code cannot write to the
IOTA_METADATA_KEYslot in a way that would bypass verification, because the verifier runs before execution completes, and any invalid metadata causes the transaction to fail.Object creation
Once all attributes are verified, the protocol constructs the
PackageMetadataV1object. For each module containing verified attributes, it creates aModuleMetadataV1entry. For authenticator attributes specifically, it extracts the first parameter's type from the verified function signature, this becomes theaccount_typefield, representing which object type this authenticator can authenticate.Finally, the protocol creates the
PackageMetadataV1object and immediately freezes it, making it immutable. The object is stored on-chain with no owner (immutable objects have no owner), ensuring it cannot be modified or deleted.Object id derivation
During the creation, the protocol derives the metadata object's ID deterministically from the package's storage ID, reusing the dynamic field address derivation logic:
Where:
package_storage_id- The object ID of the package (treated as the "parent")<0x2::derived_object::DerivedObjectKey<0x2::package_metadata::PackageMetadataKey>>- The full type tag wrapping the key type, i.e.,<0x2::package_metadata::PackageMetadataKey>, (which can be arbitrary for the derived object mechanism) in the<0x2::derived_object::DerivedObjectKey<T>>type (which is hardcoded in this mechanism).{/* dummy bool */}- The key bytes, which in the case of PackageMetadataKey contains only a dummy bool field.bcs()- The BCS serialization of a key type.Blake2b256()- The hashing function used for the ID derivationHashingIntentScope::ChildObjectId- The flag used to avoid hash collisions. Hardcoded value of 240 (or 0xF0).||- ConcatenationThis derivation ensures that given any package ID, the corresponding metadata ID can always be computed without an on-chain lookup.
Runtime phase
After a successful publish/upgrade, any Move code can read the
PackageMetadataobject by borrowing it as an immutable reference. For example, when the Account Abstraction framework needs to create anAuthenticatorFunctionRefV1for an account, it reads the relevantPackageMetadataV1object, looks up the authenticator by module and function name, and extracts theaccount_type. This type information is trustworthy because it was extracted from verified bytecode by the protocol, i.e., not provided by user input or claimed by the package developer.Move Types and Methods Specification
Main Types:
Key Accessor Functions:
Rationale
When the protocol creates metadata, it does so by extracting information from verified bytecode, not from user claims or developer assertions. This means Move code reading
PackageMetadatacan trust its contents implicitly: if the metadata says a function is a valid authenticator with a specific account type, that fact has been verified by the protocol during publish.PackageMetadatais frozen immediately upon creation because the information it represents, i.e., a package metadata, is itself immutable. Once a package is published, its bytecode cannot change, so metadata derived from that bytecode should not change either. If a package is upgraded, then a newPackageMetadataobject dedicated to the new version is created. Moreover,PackageMetadataobjects are only created when a package contains at least one recognized attribute.Computing metadata IDs deterministically from package IDs means that any code, on-chain Move or off-chain tooling, can calculate a package metadata ID without performing a lookup. This eliminates the need to store the mapping explicitly and ensures the relationship between package and metadata is inherent rather than recorded.
Backwards Compatibility
PackageMetadataintroduction no metadata object exists and these packages continue to function normally.PackageMetadatafor that version, but old metadata objects remain always valid and accessible. package_version distinguishes between versions and runtime_id links all versions to the original package.IotaAttributeenum or a field toModuleMetadataand increase thePackageMetadataversion, i.e.,PackageMetadataV2,V3, etc. Existing metadata continues to work.Test Cases
Reference Implementation
Main PR against the develop branch: iotaledger/iota#9586. See #35
Questions and Open Issues
Future Work
Planned Attributes
Tooling
iota package metadata <package-id>Copyright
Copyright and related rights waived via CC0.
Discussion
The discussion should continue to look for improvements for this proposal.
CC @lzpap @iotaledger/vm-language
Beta Was this translation helpful? Give feedback.
All reactions