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

Fix/file-path #3691

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
10 changes: 10 additions & 0 deletions examples/gno.land/p/oxtekgrinder/ownable2step/errors.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ownable2step

import "errors"

var (
ErrNoPendingOwner = errors.New("ownable2step: no pending owner")
ErrUnauthorized = errors.New("ownable2step: caller is not owner")
ErrPendingUnauthorized = errors.New("ownable2step: caller is not pending owner")
ErrInvalidAddress = errors.New("ownable2step: new owner address is invalid")
)
1 change: 1 addition & 0 deletions examples/gno.land/p/oxtekgrinder/ownable2step/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gno.land/p/oxtekgrinder/ownable2step
98 changes: 98 additions & 0 deletions examples/gno.land/p/oxtekgrinder/ownable2step/ownable.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package ownable2step

import (
"std"
)

const OwnershipTransferEvent = "OwnershipTransfer"

// Ownable2Step is a two-step ownership transfer package
// It allows the current owner to set a new owner and the new owner will need to accept the ownership before it is transferred
type Ownable2Step struct {
owner std.Address
pendingOwner std.Address
}

func New() *Ownable2Step {
return &Ownable2Step{
owner: std.PrevRealm().Addr(),
pendingOwner: "",
}
}

func NewWithAddress(addr std.Address) *Ownable2Step {
return &Ownable2Step{
owner: addr,
pendingOwner: "",
}
}

// TransferOwnership initiate the transfer of the ownership to a new address by setting the PendingOwner
func (o *Ownable2Step) TransferOwnership(newOwner std.Address) error {
if !o.CallerIsOwner() {
return ErrUnauthorized
}
if !newOwner.IsValid() {
return ErrInvalidAddress
}

o.pendingOwner = newOwner
return nil
}

// AcceptOwnership accepts the pending ownership transfer
func (o *Ownable2Step) AcceptOwnership() error {
if o.pendingOwner.String() == "" {
return ErrNoPendingOwner
}
if std.PrevRealm().Addr() != o.pendingOwner {
return ErrPendingUnauthorized
}

o.owner = o.pendingOwner
o.pendingOwner = ""

return nil
}

// DropOwnership removes the owner, effectively disabling any owner-related actions
// Top-level usage: disables all only-owner actions/functions,
// Embedded usage: behaves like a burn functionality, removing the owner from the struct
func (o *Ownable2Step) DropOwnership() error {
if !o.CallerIsOwner() {
return ErrUnauthorized
}

prevOwner := o.owner
o.owner = ""

std.Emit(
OwnershipTransferEvent,
"from", prevOwner.String(),
"to", "",
)

return nil
}

// Owner returns the owner address from Ownable
func (o *Ownable2Step) Owner() std.Address {
return o.owner
}

// PendingOwner returns the pending owner address from Ownable2Step
func (o *Ownable2Step) PendingOwner() std.Address {
return o.pendingOwner
}

// CallerIsOwner checks if the caller of the function is the Realm's owner
func (o *Ownable2Step) CallerIsOwner() bool {
return std.PrevRealm().Addr() == o.owner
}

// AssertCallerIsOwner panics if the caller is not the owner
func (o *Ownable2Step) AssertCallerIsOwner() {
if std.PrevRealm().Addr() != o.owner {
panic(ErrUnauthorized)
}
}
156 changes: 156 additions & 0 deletions examples/gno.land/p/oxtekgrinder/ownable2step/ownable_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package ownable2step

import (
"std"
"testing"

"gno.land/p/demo/testutils"
"gno.land/p/demo/uassert"
"gno.land/p/demo/urequire"
)

var (
alice = testutils.TestAddress("alice")
bob = testutils.TestAddress("bob")
)

func TestNew(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(alice))
std.TestSetOrigCaller(alice)

o := New()
got := o.Owner()
pendingOwner := o.PendingOwner()

uassert.Equal(t, got, alice)
uassert.Equal(t, pendingOwner.String(), "")
}

func TestNewWithAddress(t *testing.T) {
o := NewWithAddress(alice)

got := o.Owner()
pendingOwner := o.PendingOwner()

uassert.Equal(t, got, alice)
uassert.Equal(t, pendingOwner.String(), "")
}

func TestInitiateTransferOwnership(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(alice))
std.TestSetOrigCaller(alice)

o := New()

err := o.TransferOwnership(bob)
urequire.NoError(t, err)

owner := o.Owner()
pendingOwner := o.PendingOwner()

uassert.Equal(t, owner, alice)
uassert.Equal(t, pendingOwner, bob)
}

func TestTransferOwnership(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(alice))
std.TestSetOrigCaller(alice)

o := New()

err := o.TransferOwnership(bob)
urequire.NoError(t, err)

owner := o.Owner()
pendingOwner := o.PendingOwner()

uassert.Equal(t, owner, alice)
uassert.Equal(t, pendingOwner, bob)

std.TestSetRealm(std.NewUserRealm(bob))
std.TestSetOrigCaller(bob)

err = o.AcceptOwnership()
urequire.NoError(t, err)

owner = o.Owner()
pendingOwner = o.PendingOwner()

uassert.Equal(t, owner, bob)
uassert.Equal(t, pendingOwner.String(), "")
}

func TestCallerIsOwner(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(alice))
std.TestSetOrigCaller(alice)

o := New()
unauthorizedCaller := bob

std.TestSetRealm(std.NewUserRealm(unauthorizedCaller))
std.TestSetOrigCaller(unauthorizedCaller)

uassert.False(t, o.CallerIsOwner())
}

func TestDropOwnership(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(alice))

o := New()

err := o.DropOwnership()
urequire.NoError(t, err, "DropOwnership failed")

owner := o.Owner()
uassert.Empty(t, owner, "owner should be empty")
}

// Errors

func TestErrUnauthorized(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(alice))
std.TestSetOrigCaller(alice)

o := New()

std.TestSetRealm(std.NewUserRealm(bob))
std.TestSetOrigCaller(bob)

uassert.ErrorContains(t, o.TransferOwnership(alice), ErrUnauthorized.Error())
uassert.ErrorContains(t, o.DropOwnership(), ErrUnauthorized.Error())
}

func TestErrInvalidAddress(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(alice))

o := New()

err := o.TransferOwnership("")
uassert.ErrorContains(t, err, ErrInvalidAddress.Error())

err = o.TransferOwnership("10000000001000000000100000000010000000001000000000")
uassert.ErrorContains(t, err, ErrInvalidAddress.Error())
}

func TestErrNoPendingOwner(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(alice))

o := New()

err := o.AcceptOwnership()
uassert.ErrorContains(t, err, ErrNoPendingOwner.Error())
}

func TestErrPendingUnauthorized(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(alice))

o := New()

err := o.TransferOwnership(bob)
urequire.NoError(t, err)

std.TestSetRealm(std.NewUserRealm(alice))

err = o.AcceptOwnership()
uassert.ErrorContains(t, err, ErrPendingUnauthorized.Error())
}
1 change: 1 addition & 0 deletions gnovm/memfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
type MemFile struct {
Name string `json:"name" yaml:"name"`
Body string `json:"body" yaml:"body"`
Path string `json:"path" yaml:"path"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's best if it's not in the MemFile directly, as MemFiles are part of the import paths. Instead, cmd/gno should have a mechanism to resolve import path + filename to a filename

}

// MemPackage represents the information and files of a package which will be
Expand Down
12 changes: 7 additions & 5 deletions gnovm/pkg/gnolang/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,16 @@ type Name string
// Acts as an identifier for nodes.

type Location struct {
PkgPath string
File string
Line int
Column int
PkgPath string
File string
Line int
Column int
FilePath string
}

func (loc Location) String() string {
return fmt.Sprintf("%s/%s:%d:%d",
loc.PkgPath,
loc.FilePath,
loc.File,
loc.Line,
loc.Column,
Expand Down Expand Up @@ -1327,6 +1328,7 @@ func ReadMemPackageFromList(list []string, pkgPath string) (*gnovm.MemPackage, e
}
memPkg.Files = append(memPkg.Files,
&gnovm.MemFile{
Path: fpath,
Name: fname,
Body: string(bz),
})
Expand Down
1 change: 1 addition & 0 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -5386,6 +5386,7 @@ func setNodeLocations(pkgPath string, fileName string, n Node) {
File: fileName,
Line: bn.GetLine(),
Column: bn.GetColumn(),
// TODO FilePath:
}
bn.SetLocation(loc)
}
Expand Down
Loading