-
Notifications
You must be signed in to change notification settings - Fork 397
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
chore(demo): upgradable realm demo #3147
Changes from all commits
31dbc62
33ac66f
3929646
0da5ee7
4ed558c
e0c2424
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package admin | ||
|
||
import ( | ||
"std" | ||
) | ||
|
||
var ReadCounter func() uint64 = nil | ||
var UpdateCounter func() = nil | ||
var DebugPrevRealm func() string = nil | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
func DebugAdminPrevRealm() string { | ||
return std.PrevRealm().Addr().String() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module gno.land/r/x/manfred_upgrade_patterns/upgrade_g/admin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package admin | ||
|
||
import ( | ||
"std" | ||
) | ||
|
||
type Logic interface { | ||
ReadCounter() uint64 | ||
UpdateCounter() | ||
|
||
DebugPrevRealm() string | ||
} | ||
|
||
func RegisterLogic(l Logic, setStore func(Store)) { | ||
ReadCounter = l.ReadCounter | ||
UpdateCounter = l.UpdateCounter | ||
DebugPrevRealm = l.DebugPrevRealm | ||
|
||
newStore := store() | ||
setStore(newStore) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package admin | ||
|
||
type Store interface { | ||
GetCounter() uint64 | ||
SetCounter(value uint64) | ||
} | ||
|
||
var store func() Store = nil | ||
|
||
func RegisterStore(newStore func() Store) { | ||
if store != nil { | ||
panic("Store already registered") | ||
} | ||
store = newStore | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package v1 | ||
|
||
import ( | ||
"std" | ||
|
||
"gno.land/r/x/manfred_upgrade_patterns/upgrade_g/admin" | ||
) | ||
|
||
var store admin.Store = nil | ||
|
||
func Init() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this uppercase on purpose? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It needs to be lowercase if this is supposed to be a realm constructor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a constructor, meant to be called by the testing code as an emulated deployment |
||
admin.RegisterLogic(&logic{}, func(_store admin.Store) { store = _store }) | ||
} | ||
|
||
var _ admin.Logic = &logic{} | ||
|
||
type logic struct {} | ||
|
||
func (l *logic) ReadCounter() uint64 { | ||
return store.GetCounter() | ||
} | ||
|
||
func (l *logic) UpdateCounter() { | ||
store.SetCounter(store.GetCounter() + 1) | ||
} | ||
|
||
func (l *logic) DebugPrevRealm() string { | ||
return std.PrevRealm().Addr().String() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module gno.land/r/x/manfred_upgrade_patterns/upgrade_g/logic/v1 | ||
|
||
require gno.land/r/x/manfred_upgrade_patterns/upgrade_g/admin v0.0.0-latest |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package v2 | ||
|
||
import ( | ||
"std" | ||
|
||
"gno.land/r/x/manfred_upgrade_patterns/upgrade_g/admin" | ||
) | ||
|
||
var store admin.Store = nil | ||
|
||
func Init() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question, why uppercase? |
||
admin.RegisterLogic(&logic{}, func(_store admin.Store) { store = _store }) | ||
} | ||
|
||
var _ admin.Logic = &logic{} | ||
|
||
type logic struct {} | ||
|
||
func (l *logic) ReadCounter() uint64 { | ||
return store.GetCounter() | ||
} | ||
|
||
func (l *logic) UpdateCounter() { | ||
store.SetCounter(store.GetCounter() + 2) | ||
} | ||
|
||
func (l *logic) DebugPrevRealm() string { | ||
return std.PrevRealm().Addr().String() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module gno.land/r/x/manfred_upgrade_patterns/upgrade_g/logic/v2 | ||
|
||
require gno.land/r/x/manfred_upgrade_patterns/upgrade_g/admin v0.0.0-latest |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module gno.land/r/x/manfred_upgrade_patterns/upgrade_g/store | ||
|
||
require gno.land/r/x/manfred_upgrade_patterns/upgrade_g/admin v0.0.0-latest |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package store | ||
|
||
import ( | ||
"std" | ||
"fmt" | ||
|
||
"gno.land/r/x/manfred_upgrade_patterns/upgrade_g/admin" | ||
) | ||
|
||
var counterValue uint64 | ||
|
||
var _ admin.Store = &store{} | ||
|
||
var currentStore *store | ||
|
||
type store struct {} | ||
|
||
func (s *store) GetCounter() uint64 { | ||
if s != currentStore { | ||
panic("Revoked store") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When is this possible? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The user tries to call the public function in a old version logics without going through the admin interface. In this case, any outer-world call would fail because the prevRealm will return the logic's address, not the admin's. However, the old logics still holds the store reference, thus need to be deprecated when a new store struct is instantiated. |
||
} | ||
|
||
return counterValue | ||
} | ||
|
||
func (s *store) SetCounter(value uint64) { | ||
if s != currentStore { | ||
panic("Revoked store") | ||
} | ||
|
||
counterValue = value | ||
} | ||
|
||
func newStore() admin.Store { | ||
currentStore = &store{} | ||
|
||
return currentStore | ||
} | ||
|
||
func Init() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👀 |
||
admin.RegisterStore(newStore) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module gno.land/r/x/manfred_upgrade_patterns/upgrade_g/upgradable_testing | ||
|
||
require ( | ||
gno.land/p/demo/testutils v0.0.0-latest | ||
gno.land/p/demo/urequire v0.0.0-latest | ||
gno.land/r/x/manfred_upgrade_patterns/upgrade_g/admin v0.0.0-latest | ||
gno.land/r/x/manfred_upgrade_patterns/upgrade_g/logic/v1 v0.0.0-latest | ||
gno.land/r/x/manfred_upgrade_patterns/upgrade_g/logic/v2 v0.0.0-latest | ||
gno.land/r/x/manfred_upgrade_patterns/upgrade_g/store v0.0.0-latest | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package upgradable_testing |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package upgradable_testing | ||
|
||
import ( | ||
"std" | ||
"testing" | ||
|
||
"gno.land/p/demo/testutils" | ||
"gno.land/p/demo/urequire" | ||
|
||
"gno.land/r/x/manfred_upgrade_patterns/upgrade_g/admin" | ||
"gno.land/r/x/manfred_upgrade_patterns/upgrade_g/logic/v1" | ||
"gno.land/r/x/manfred_upgrade_patterns/upgrade_g/logic/v2" | ||
"gno.land/r/x/manfred_upgrade_patterns/upgrade_g/store" | ||
|
||
) | ||
|
||
func TestPackage(t *testing.T) { | ||
alice := testutils.TestAddress("alice") | ||
std.TestSetRealm(std.NewUserRealm(alice)) | ||
std.TestSetOrigCaller(alice) // XXX: should not need this | ||
|
||
store.Init() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand now, you want to manually trigger the init :) |
||
|
||
v1.Init() | ||
urequire.Equal(t, uint64(0), admin.ReadCounter()) | ||
admin.UpdateCounter() | ||
urequire.Equal(t, uint64(1), admin.ReadCounter()) | ||
|
||
v2.Init() | ||
urequire.Equal(t, uint64(1), admin.ReadCounter()) | ||
admin.UpdateCounter() | ||
urequire.Equal(t, uint64(3), admin.ReadCounter()) | ||
|
||
urequire.Equal(t, admin.DebugPrevRealm(), admin.DebugAdminPrevRealm()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does
store
need to be the global, and not an instance oflogic
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main question is why doesn't this
store
instance live in thelogic
instance?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
logic
is simply a set of functions to be registered to the admin. It is a workaround withinterface
s as they are not able to cross the realm boundary. Store, in this case, needs to be accessed by any functions in the realm, entrypoint or not. By having store as a top level variable it could have the similar coding style with having state variables.