-
Notifications
You must be signed in to change notification settings - Fork 373
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: small improvements for #1702 #2276
Changes from all commits
7289a9a
1d4ef92
c63ba9d
2b2212f
593db9a
4930964
eed932e
d7134db
395e263
e454cf4
d20ff79
b8e6373
23208e1
e16edff
2f5589f
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 |
---|---|---|
|
@@ -30,3 +30,7 @@ pbbindings.go | |
# Test coverage leftovers | ||
cover.out | ||
coverage.out | ||
|
||
*.swp | ||
*.swo | ||
*.bak |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,42 +5,41 @@ | |
"path/filepath" | ||
|
||
gno "github.com/gnolang/gno/gnovm/pkg/gnolang" | ||
"github.com/gnolang/gno/gnovm/stdlibs" | ||
"github.com/gnolang/gno/tm2/pkg/crypto" | ||
osm "github.com/gnolang/gno/tm2/pkg/os" | ||
"github.com/gnolang/gno/tm2/pkg/sdk" | ||
"github.com/gnolang/gno/tm2/pkg/std" | ||
) | ||
|
||
func (vm *VMKeeper) initBuiltinPackagesAndTypes(store gno.Store) { | ||
// NOTE: native functions/methods added here must be quick operations, | ||
// or account for gas before operation. | ||
// TODO: define criteria for inclusion, and solve gas calculations. | ||
getPackage := func(pkgPath string, newStore gno.Store) (pn *gno.PackageNode, pv *gno.PackageValue) { | ||
// otherwise, built-in package value. | ||
// first, load from filepath. | ||
stdlibPath := filepath.Join(vm.stdlibsDir, pkgPath) | ||
if !osm.DirExists(stdlibPath) { | ||
// does not exist. | ||
return nil, nil | ||
} | ||
memPkg := gno.ReadMemPackage(stdlibPath, pkgPath) | ||
if memPkg.IsEmpty() { | ||
// no gno files are present, skip this package | ||
return nil, nil | ||
} | ||
|
||
m2 := gno.NewMachineWithOptions(gno.MachineOptions{ | ||
PkgPath: "gno.land/r/stdlibs/" + pkgPath, | ||
// PkgPath: pkgPath, | ||
Output: os.Stdout, | ||
Store: newStore, | ||
}) | ||
defer m2.Release() | ||
return m2.RunMemPackage(memPkg, true) | ||
// NOTE: this function may add loaded dependencies to store if they don't | ||
// already exist, including mem packages. If this happens during a transaction | ||
// with the tx context store, the transaction caller will pay for operations. | ||
// NOTE: native functions/methods added here must be quick operations, or | ||
// account for gas before operation. | ||
// TODO: define criteria for inclusion, and solve gas calculations(???). | ||
func (vm *VMKeeper) getPackage(pkgPath string, store gno.Store) (pn *gno.PackageNode, pv *gno.PackageValue) { | ||
// otherwise, built-in package value. | ||
// first, load from filepath. | ||
stdlibPath := filepath.Join(vm.stdlibsDir, pkgPath) | ||
if !osm.DirExists(stdlibPath) { | ||
// does not exist. | ||
return nil, nil | ||
} | ||
memPkg := gno.ReadMemPackage(stdlibPath, pkgPath) | ||
if memPkg.IsEmpty() { | ||
// no gno files are present, skip this package | ||
return nil, nil | ||
} | ||
store.SetPackageGetter(getPackage) | ||
store.SetNativeStore(stdlibs.NativeStore) | ||
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. diff artifact, not actually removed from the original code block. |
||
|
||
m2 := gno.NewMachineWithOptions(gno.MachineOptions{ | ||
PkgPath: "gno.land/r/stdlibs/" + pkgPath, | ||
// PkgPath: pkgPath, | ||
Output: os.Stdout, | ||
Store: store, | ||
}) | ||
defer m2.Release() | ||
pn, pv = m2.RunMemPackage(memPkg, true) | ||
return | ||
} | ||
|
||
// ---------------------------------------- | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,16 +9,21 @@ import ( | |
"strings" | ||
|
||
"github.com/gnolang/gno/tm2/pkg/amino" | ||
"github.com/gnolang/gno/tm2/pkg/colors" | ||
"github.com/gnolang/gno/tm2/pkg/std" | ||
"github.com/gnolang/gno/tm2/pkg/store" | ||
"github.com/gnolang/gno/tm2/pkg/store/types" | ||
"github.com/gnolang/gno/tm2/pkg/store/utils" | ||
stringz "github.com/gnolang/gno/tm2/pkg/strings" | ||
) | ||
|
||
// PackageGetter specifies how the store may retrieve packages which are not | ||
// already in its cache. PackageGetter should return nil when the requested | ||
// package does not exist. store should be used to run the machine, or otherwise | ||
// call any methods which may call store.GetPackage; avoid using any "global" | ||
// store as the one passed to the PackageGetter may be a fork of that (ie. | ||
// the original is not meant to be written to). | ||
// the original is not meant to be written to). Loading dependencies may | ||
// cause writes to happen to the store, such as MemPackages to iavlstore. | ||
type PackageGetter func(pkgPath string, store Store) (*PackageNode, *PackageValue) | ||
|
||
// inject natives into a new or loaded package (value and node) | ||
|
@@ -68,6 +73,8 @@ type Store interface { | |
LogSwitchRealm(rlmpath string) // to mark change of realm boundaries | ||
ClearCache() | ||
Print() | ||
Write() | ||
Flush() | ||
} | ||
|
||
// Used to keep track of in-mem objects during tx. | ||
|
@@ -86,7 +93,7 @@ type defaultStore struct { | |
|
||
// transient | ||
opslog []StoreOp // for debugging and testing. | ||
current []string | ||
current []string // for detecting import cycles. | ||
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's still detecting import cycles. |
||
} | ||
|
||
func NewStore(alloc *Allocator, baseStore, iavlStore store.Store) *defaultStore { | ||
|
@@ -115,6 +122,7 @@ func (ds *defaultStore) SetPackageGetter(pg PackageGetter) { | |
|
||
// Gets package from cache, or loads it from baseStore, or gets it from package getter. | ||
func (ds *defaultStore) GetPackage(pkgPath string, isImport bool) *PackageValue { | ||
// helper to detect circular imports | ||
if isImport { | ||
if slices.Contains(ds.current, pkgPath) { | ||
panic(fmt.Sprintf("import cycle detected: %q (through %v)", pkgPath, ds.current)) | ||
|
@@ -672,8 +680,16 @@ func (ds *defaultStore) GetNative(pkgPath string, name Name) func(m *Machine) { | |
return nil | ||
} | ||
|
||
// Writes one level of cache to store. | ||
func (ds *defaultStore) Write() { | ||
ds.baseStore.(types.Writer).Write() | ||
ds.iavlStore.(types.Writer).Write() | ||
} | ||
|
||
// Flush cached writes to disk. | ||
func (ds *defaultStore) Flush() { | ||
// XXX | ||
ds.baseStore.(types.Flusher).Flush() | ||
ds.iavlStore.(types.Flusher).Flush() | ||
} | ||
|
||
// ---------------------------------------- | ||
|
@@ -755,22 +771,25 @@ func (ds *defaultStore) ClearCache() { | |
|
||
// for debugging | ||
func (ds *defaultStore) Print() { | ||
fmt.Println("//----------------------------------------") | ||
fmt.Println("defaultStore:baseStore...") | ||
store.Print(ds.baseStore) | ||
fmt.Println("//----------------------------------------") | ||
fmt.Println("defaultStore:iavlStore...") | ||
store.Print(ds.iavlStore) | ||
fmt.Println("//----------------------------------------") | ||
fmt.Println("defaultStore:cacheTypes...") | ||
fmt.Println(colors.Yellow("//----------------------------------------")) | ||
fmt.Println(colors.Green("defaultStore:baseStore...")) | ||
utils.Print(ds.baseStore) | ||
fmt.Println(colors.Yellow("//----------------------------------------")) | ||
fmt.Println(colors.Green("defaultStore:iavlStore...")) | ||
utils.Print(ds.iavlStore) | ||
fmt.Println(colors.Yellow("//----------------------------------------")) | ||
fmt.Println(colors.Green("defaultStore:cacheTypes...")) | ||
for tid, typ := range ds.cacheTypes { | ||
fmt.Printf("- %v: %v\n", tid, typ) | ||
fmt.Printf("- %v: %v\n", tid, | ||
stringz.TrimN(fmt.Sprintf("%v", typ), 50)) | ||
} | ||
fmt.Println("//----------------------------------------") | ||
fmt.Println("defaultStore:cacheNodes...") | ||
fmt.Println(colors.Yellow("//----------------------------------------")) | ||
fmt.Println(colors.Green("defaultStore:cacheNodes...")) | ||
for loc, bn := range ds.cacheNodes { | ||
fmt.Printf("- %v: %v\n", loc, bn) | ||
fmt.Printf("- %v: %v\n", loc, | ||
stringz.TrimN(fmt.Sprintf("%v", bn), 50)) | ||
} | ||
fmt.Println(colors.Red("//----------------------------------------")) | ||
} | ||
|
||
// ---------------------------------------- | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,8 +61,8 @@ const ( | |
) | ||
|
||
// NOTE: this isn't safe, should only be used for testing. | ||
func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Writer, mode importMode) (store gno.Store) { | ||
getPackage := func(pkgPath string, newStore gno.Store) (pn *gno.PackageNode, pv *gno.PackageValue) { | ||
func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Writer, mode importMode) (resStore gno.Store) { | ||
getPackage := func(pkgPath string, store gno.Store) (pn *gno.PackageNode, pv *gno.PackageValue) { | ||
if pkgPath == "" { | ||
panic(fmt.Sprintf("invalid zero package path in testStore().pkgGetter")) | ||
} | ||
|
@@ -83,7 +83,7 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri | |
m2 := gno.NewMachineWithOptions(gno.MachineOptions{ | ||
PkgPath: "test", | ||
Output: stdout, | ||
Store: newStore, | ||
Store: store, | ||
Context: ctx, | ||
}) | ||
// pkg := gno.NewPackageNode(gno.Name(memPkg.Name), memPkg.Path, nil) | ||
|
@@ -96,7 +96,7 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri | |
// if stdlibs package is preferred , try to load it first. | ||
if mode == ImportModeStdlibsOnly || | ||
mode == ImportModeStdlibsPreferred { | ||
pn, pv = loadStdlib(rootDir, pkgPath, newStore, stdout) | ||
pn, pv = loadStdlib(rootDir, pkgPath, store, stdout) | ||
if pn != nil { | ||
return | ||
} | ||
|
@@ -375,7 +375,7 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri | |
|
||
// if native package is preferred, try to load stdlibs/* as backup. | ||
if mode == ImportModeNativePreferred { | ||
pn, pv = loadStdlib(rootDir, pkgPath, newStore, stdout) | ||
pn, pv = loadStdlib(rootDir, pkgPath, store, stdout) | ||
if pn != nil { | ||
return | ||
} | ||
|
@@ -394,23 +394,23 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri | |
m2 := gno.NewMachineWithOptions(gno.MachineOptions{ | ||
PkgPath: "test", | ||
Output: stdout, | ||
Store: newStore, | ||
Store: store, | ||
Context: ctx, | ||
}) | ||
pn, pv = m2.RunMemPackage(memPkg, true) | ||
return | ||
} | ||
return nil, nil | ||
} | ||
// NOTE: store is also used in closure above. | ||
db := memdb.NewMemDB() | ||
baseStore := dbadapter.StoreConstructor(db, stypes.StoreOptions{}) | ||
iavlStore := iavl.StoreConstructor(db, stypes.StoreOptions{}) | ||
store = gno.NewStore(nil, baseStore, iavlStore) | ||
store.SetPackageGetter(getPackage) | ||
store.SetNativeStore(teststdlibs.NativeStore) | ||
store.SetPackageInjector(testPackageInjector) | ||
store.SetStrictGo2GnoMapping(false) | ||
// make a new store | ||
resStore = gno.NewStore(nil, baseStore, iavlStore) | ||
resStore.SetPackageGetter(getPackage) | ||
resStore.SetNativeStore(teststdlibs.NativeStore) | ||
resStore.SetPackageInjector(testPackageInjector) | ||
resStore.SetStrictGo2GnoMapping(false) | ||
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. they're both new stores, so name neither "newStore" :) |
||
return | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,14 +96,80 @@ func Gray(args ...interface{}) string { | |
return treatAll(ANSIFgGray, args...) | ||
} | ||
|
||
func ColoredBytes(data []byte, textColor, bytesColor func(...interface{}) string) string { | ||
// result may be 4 ASNSII chars longer than they should be to denote the | ||
// elipses (...), and one for a trailing hex nibble in case the last byte is | ||
// non-ascii. | ||
// NOTE: it is annoying to try make this perfect and always fit within n, so we | ||
// don't do this yet, but left as an exercise. :) | ||
func ColoredBytesN(data []byte, n int, textColor, bytesColor func(...interface{}) string) string { | ||
_n := 0 | ||
s := "" | ||
for _, b := range data { | ||
buf := "" // buffer | ||
bufIsText := true // is buf text or hex | ||
for i, b := range data { | ||
RESTART: | ||
if 0x21 <= b && b < 0x7F { | ||
s += textColor(string(b)) | ||
if !bufIsText { | ||
s += bytesColor(buf) | ||
buf = "" | ||
bufIsText = true | ||
goto RESTART | ||
} | ||
buf += string(b) | ||
_n += 1 | ||
if n != 0 && _n >= n { | ||
if i == len(data)-1 { | ||
// done | ||
s += textColor(buf) | ||
buf = "" | ||
} else { | ||
s += textColor(buf) + "..." | ||
buf = "" | ||
} | ||
break | ||
} | ||
} else { | ||
if bufIsText { | ||
s += textColor(buf) | ||
buf = "" | ||
bufIsText = false | ||
goto RESTART | ||
} | ||
buf += fmt.Sprintf("%02X", b) | ||
_n += 2 | ||
if n != 0 && _n >= n { | ||
if i == len(data)-1 { | ||
// done | ||
s += bytesColor(buf) | ||
buf = "" | ||
} else { | ||
s += bytesColor(buf) + "..." | ||
buf = "" | ||
} | ||
break | ||
} | ||
} | ||
} | ||
if buf != "" { | ||
if bufIsText { | ||
s += textColor(buf) | ||
buf = "" | ||
} else { | ||
s += bytesColor(fmt.Sprintf("%02X", b)) | ||
s += bytesColor(buf) | ||
buf = "" | ||
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. If somebody can write a perfect n len-capped implementation that is simpler than this, I'd be impressed. But it's also probably unnecessary. |
||
} | ||
} | ||
return s | ||
} | ||
|
||
func DefaultColoredBytesN(data []byte, n int) string { | ||
return ColoredBytesN(data, n, Blue, Green) | ||
} | ||
|
||
func ColoredBytes(data []byte, textColor, bytesColor func(...interface{}) string) string { | ||
return ColoredBytesN(data, 0, textColor, bytesColor) | ||
} | ||
|
||
func DefaultColoredBytes(data []byte) string { | ||
return ColoredBytes(data, Blue, Green) | ||
} |
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.
I think it was always requried, but its absence (of MultiWrite) being masked by the fact that later transactions would commit the same side effect, e.g. populate the mem package for dependencies like "time" or "strconv". But i'm not sure. If that's true, then loadpkg in genesis would have no effect for our integration tests?
Can somebody look into it?