1// Package version_manager provides a runtime version management system for dynamic2// implementation switching without data migration. It implements the Strategy Pattern3// combined with Plugin Architecture to enable hot-swapping between different versioned4// implementations of the same domain.5//6// ## Overview7//8// Version Manager enables seamless upgrades by allowing multiple versioned implementations9// (v1, v2, v3) to coexist and share a unified storage layer. The domain10// (proxy) realm owns that storage; the manager records version initializers and11// swaps the active implementation reference without granting implementation12// realms direct write permission.13//14// Key components of this package include:15//16// 1. **VersionManager Interface**: Defines the contract for managing multiple versioned17// implementations of a domain.18// 2. **versionManager Implementation**: Concrete implementation that manages version19// registration and active implementation switching.20// 3. **Realm-Threaded Validation**: Validates live realm tokens and restricts21// registration to packages under the configured domain path.22// 4. **Domain-Scoped Security**: Ensures only authorized packages within the domain23// path can register implementations.24//25// ## Key Features26//27// - **Zero-Downtime Upgrades**: Switch implementations at runtime without service28// interruption or data migration.29// - **Unified Storage**: All versions share a single KVStore owned by the30// domain (proxy) realm, eliminating migration overhead.31// - **Hot-Swapping**: Instant version switching through dynamic strategy replacement32// with explicit realm validation.33// - **Domain-Scoped Security**: Only packages under the authorized domain path can34// register implementations, preventing unauthorized access.35// - **Backward Compatibility**: Previous versions remain registered for36// gradual migration and rollback support.37// - **Strategy Pattern**: Enables runtime algorithm swapping without code changes.38//39// ## Architecture Pattern40//41// The package implements two complementary design patterns:42//43// - **Strategy Pattern**: Enables runtime selection of implementation strategies44// - **Plugin Architecture**: Supports explicit registration of version packages45//46// ## Workflow47//48// Typical usage of the version_manager package includes the following steps:49//50// 1. **Initialization**: Create a version manager for the domain using NewVersionManager.51// 2. **Version Registration**: Each version (v1, v2, v3) calls RegisterInitializer during52// its init(cur realm) function to register its implementation.53// 3. **Active Implementation**: The first registered version becomes the active implementation;54// subsequent versions are retained for later switching.55// 4. **Version Switching**: Use ChangeImplementation to hot-swap to a different version56// while storage ownership stays with the domain KVStore.57//58// ## Example Usage59//60// ### Step 1: Define Domain Interface61//62// ```gno63// // protocol_fee/types.gno64// package protocol_fee65//66// type ProtocolFee interface {67// SetFeeRatio(ratio uint64) error68// GetFeeRatio() uint6469// }70//71// ```72//73// ### Step 2: Create Version Manager74//75// ```gno76// // protocol_fee/protocol_fee.gno77// package protocol_fee78//79// import (80//81// "gno.land/p/gnoswap/version_manager/v1"82// "gno.land/p/gnoswap/store/v1"83//84// )85//86// var manager version_manager.VersionManager87//88// func init(cur realm) {89// kvStore := store.NewKVStore(cur.Address())90//91// manager = version_manager.NewVersionManager(92// cur.PkgPath(),93// kvStore,94// func(_ int, rlm realm, kv store.KVStore) any {95// return NewProtocolFeeStore(kv)96// },97// )98// }99//100// func GetManager() version_manager.VersionManager {101// return manager102// }103//104// ```105//106// ### Step 3: Implement Version 1107//108// ```gno109// // protocol_fee/v1/v1.gno110// package v1111//112// import "gno.land/r/gnoswap/protocol_fee"113//114// type protocolFeeV1 struct {115//116// store any117//118// }119//120// func init(cur realm) {121// // Register this version during package initialization.122// protocol_fee.RegisterInitializer(cross(cur), func(_ int, rlm realm, store any) any {123// return &protocolFeeV1{store: store}124// })125// }126//127// func (pf *protocolFeeV1) SetFeeRatio(ratio uint64) error {128// // v1 implementation129// return nil130// }131//132// func (pf *protocolFeeV1) GetFeeRatio() uint64 {133// // v1 implementation134// return 0135// }136//137// ```138//139// ### Step 4: Implement Version 2140//141// ```gno142// // protocol_fee/v2/v2.gno143// package v2144//145// import "gno.land/r/gnoswap/protocol_fee"146//147// type protocolFeeV2 struct {148//149// store any150//151// }152//153// func init(cur realm) {154// // Register v2 - inactive until explicitly activated.155// protocol_fee.RegisterInitializer(cross(cur), func(_ int, rlm realm, store any) any {156// return &protocolFeeV2{store: store}157// })158// }159//160// func (pf *protocolFeeV2) SetFeeRatio(ratio uint64) error {161// // v2 improved implementation162// return nil163// }164//165// func (pf *protocolFeeV2) GetFeeRatio() uint64 {166// // v2 improved implementation167// return 0168// }169//170// ```171//172// ### Step 5: Use Active Implementation173//174// ```gno175// // client code176// import "gno.land/r/gnoswap/protocol_fee"177//178// func UseFee() {179// manager := protocol_fee.GetManager()180// impl := manager.GetCurrentImplementation().(protocol_fee.ProtocolFee)181//182// ratio := impl.GetFeeRatio()183// // Use the active version's implementation184// }185//186// ```187//188// ### Step 6: Switch Versions at Runtime189//190// ```gno191// // governance or admin function192//193// func UpgradeToV2(cur realm) {194// // Hot-swap to v2 - zero downtime.195// protocol_fee.UpgradeImpl(cross(cur), "gno.land/r/gnoswap/protocol_fee/v2")196// }197//198// ```199//200// ## Registration Flow201//202// The version registration process follows this sequence:203//204// 1. Domain package initializes version manager with KVStore205// ↓206// 2. v1 package calls the domain registration wrapper during init(cur realm)207// → Becomes the active implementation208// ↓209// 3. v2 package calls the domain registration wrapper during init(cur realm)210// → Registered for later activation211// ↓212// 4. v3 package calls the domain registration wrapper during init(cur realm)213// → Registered for later activation214//215// ## Version Switching Flow216//217// When switching versions, the following steps occur:218//219// 1. Admin/governance calls the domain upgrade wrapper220// ↓221// 2. The domain wrapper enforces authorization and calls ChangeImplementation(0, cur, ...)222// ↓223// 3. Version Manager validates the live realm token and retrieves v2's initializer224// ↓225// 4. Executes v2 initializer with the shared KVStore226// ↓227// 5. Updates currentPackagePath and currentImplementation228//229// ## Storage Access Model230//231// The version manager keeps storage ownership with the domain (proxy) realm:232//233// - **Domain Ownership**: The domain realm owns the KVStore and drives writes.234// - **No Direct Grants**: Implementation realms do not receive direct storage235// permissions from version_manager.236// - **Explicit Realm Threading**: Registration and switching calls validate the237// live realm token with `rlm.IsCurrent()` and identify the caller with238// `rlm.Previous()`.239// - **Domain Isolation**: Registration is scoped to packages under the domain path.240//241// ## Security242//243// Domain-scoped security ensures that only authorized packages can register:244//245// - **Path Validation**: Caller's package path must start with the domain path + "/"246// - **Realm Verification**: Only realm (contract) code can register, not user calls247// - **Example**: For domain "gno.land/r/gnoswap/protocol_fee":248// - Valid: "gno.land/r/gnoswap/protocol_fee/v1", "gno.land/r/gnoswap/protocol_fee/v2"249// - Invalid: "gno.land/r/gnoswap/other", "gno.land/r/attacker/malicious"250//251// ## Error Handling252//253// The package returns errors for:254//255// - Unauthorized caller attempting to register (not in domain path)256// - Duplicate registration of the same package path257// - Attempting to switch to an unregistered version258// - A nil initializer in the registered map (an internal invalid state).259// The initializer function signature is checked at compile time by the typed API.260//261// ## Best Practices262//263// 1. **Version Registration**: All versions should register during init(cur realm) to ensure264// they're available before any runtime operations.265// 2. **Interface Compliance**: Ensure all versions implement the same domain interface266// for seamless switching.267// 3. **Storage Compatibility**: Design storage schema to be forward and backward268// compatible across versions to prevent data corruption.269// 4. **Testing**: Thoroughly test version switching in a staging environment before270// production use.271// 5. **Rollback Support**: Keep previous versions registered to enable quick rollback272// if issues are detected in new versions.273// 6. **Type Assertions**: Always check type assertions when retrieving the current274// implementation to prevent runtime panics.275//276// ## Use Cases277//278// ### Protocol Upgrades279//280// Upgrade DeFi protocol logic without disrupting active users. The target281// version package must already be deployed/loaded and must have registered its282// initializer during package initialization:283//284// manager.ChangeImplementation(0, cur, "gno.land/r/gnoswap/protocol_fee/v2")285//286// ### A/B Testing287//288// Test new implementations before full rollout. Switch only to paths whose289// version packages have already registered initializers:290//291// // Switch to a registered experimental version292// manager.ChangeImplementation(0, cur, "gno.land/r/gnoswap/protocol_fee/experimental")293//294// // Rollback to another registered version295// manager.ChangeImplementation(0, cur, "gno.land/r/gnoswap/protocol_fee/v1")296//297// ### Emergency Response298//299// Quickly switch to a patched version during security incidents. Deploy/load300// the hotfix package and register its initializer before activation:301//302// manager.ChangeImplementation(0, cur, "gno.land/r/gnoswap/protocol_fee/v1_hotfix")303//304// ## Limitations and Considerations305//306// - **Type Safety**: Requires runtime type assertion to domain interface. No compile-time307// type checking for implementation compatibility.308// - **Atomic Switching**: Initializer side effects during ChangeImplementation are not309// transactionally rolled back on partial failure. Manual recovery may be required.310// - **Storage Schema**: Requires careful schema design for cross-version compatibility.311// Breaking schema changes require migration or careful version ordering.312// - **Registration Order**: The first registered version automatically becomes the313// active implementation. Plan your deployment order carefully.314// - **No Unregistration**: Once registered, a version cannot be unregistered. Plan315// version lifecycles accordingly.316//317// ## Related Packages318//319// - gno.land/p/gnoswap/store/v1: Provides KVStore with permission-based access control320//321// Package version_manager is intended for use in Gno smart contracts requiring322// dynamic, upgradeable implementations with zero-downtime version switching.323package version_manager324Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.