From 663edac6246046f6cac0af912b0c38722f5eaa66 Mon Sep 17 00:00:00 2001 From: 6h057 <15034695+omarsy@users.noreply.github.com> Date: Mon, 13 Jan 2025 12:11:33 +0100 Subject: [PATCH 01/13] feat(gnovm): add software floating point package (#3185) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes: #312 The idea to use softfloat and work originates from this PR: https://github.com/gnolang/gno/pull/2863
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
--------- Co-authored-by: Morgan Bazalgette Co-authored-by: Miloš Živković --- gno.land/pkg/sdk/vm/convert.go | 5 +- gnovm/pkg/gnolang/frame.go | 5 +- gnovm/pkg/gnolang/gonative.go | 19 +- gnovm/pkg/gnolang/internal/softfloat/copy.sh | 32 + .../internal/softfloat/runtime_softfloat64.go | 631 ++++++++++++++++++ .../softfloat/runtime_softfloat64_test.go | 204 ++++++ .../gnolang/internal/softfloat/softfloat.go | 134 ++++ gnovm/pkg/gnolang/op_binary.go | 46 +- gnovm/pkg/gnolang/op_inc_dec.go | 9 +- gnovm/pkg/gnolang/op_unary.go | 5 +- gnovm/pkg/gnolang/values.go | 21 +- gnovm/pkg/gnolang/values_conversions.go | 258 +++---- gnovm/pkg/gnolang/values_conversions_test.go | 3 +- gnovm/pkg/gnolang/values_string.go | 9 +- gnovm/tests/files/float8.gno | 166 +++++ 15 files changed, 1360 insertions(+), 187 deletions(-) create mode 100644 gnovm/pkg/gnolang/internal/softfloat/copy.sh create mode 100644 gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64.go create mode 100644 gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64_test.go create mode 100644 gnovm/pkg/gnolang/internal/softfloat/softfloat.go create mode 100644 gnovm/tests/files/float8.gno diff --git a/gno.land/pkg/sdk/vm/convert.go b/gno.land/pkg/sdk/vm/convert.go index cafb6cad67f..dbaabcfbc4b 100644 --- a/gno.land/pkg/sdk/vm/convert.go +++ b/gno.land/pkg/sdk/vm/convert.go @@ -3,6 +3,7 @@ package vm import ( "encoding/base64" "fmt" + "math" "strconv" "strings" @@ -143,11 +144,11 @@ func convertArgToGno(arg string, argT gno.Type) (tv gno.TypedValue) { return case gno.Float32Type: value := convertFloat(arg, 32) - tv.SetFloat32(float32(value)) + tv.SetFloat32(math.Float32bits(float32(value))) return case gno.Float64Type: value := convertFloat(arg, 64) - tv.SetFloat64(value) + tv.SetFloat64(math.Float64bits(value)) return default: panic(fmt.Sprintf("unexpected primitive type %s", bt.String())) diff --git a/gnovm/pkg/gnolang/frame.go b/gnovm/pkg/gnolang/frame.go index 2ac1027eb32..60f19979b7a 100644 --- a/gnovm/pkg/gnolang/frame.go +++ b/gnovm/pkg/gnolang/frame.go @@ -2,6 +2,7 @@ package gnolang import ( "fmt" + "math" "strings" ) @@ -207,9 +208,9 @@ func toConstExpTrace(cte *ConstExpr) string { case Uint64Type: return fmt.Sprintf("%d", tv.GetUint64()) case Float32Type: - return fmt.Sprintf("%v", tv.GetFloat32()) + return fmt.Sprintf("%v", math.Float32frombits(tv.GetFloat32())) case Float64Type: - return fmt.Sprintf("%v", tv.GetFloat64()) + return fmt.Sprintf("%v", math.Float64frombits(tv.GetFloat64())) } } diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index 5a39c76b5e1..85fc8b70051 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -2,7 +2,10 @@ package gnolang import ( "fmt" + "math" "reflect" + + "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" ) // NOTE @@ -329,9 +332,9 @@ func go2GnoValue(alloc *Allocator, rv reflect.Value) (tv TypedValue) { case reflect.Uint64: tv.SetUint64(rv.Uint()) case reflect.Float32: - tv.SetFloat32(float32(rv.Float())) + tv.SetFloat32(softfloat.F64to32(math.Float64bits(rv.Float()))) case reflect.Float64: - tv.SetFloat64(rv.Float()) + tv.SetFloat64(math.Float64bits(rv.Float())) case reflect.Array: tv.V = alloc.NewNative(rv) case reflect.Slice: @@ -428,11 +431,11 @@ func go2GnoValueUpdate(alloc *Allocator, rlm *Realm, lvl int, tv *TypedValue, rv } case Float32Kind: if lvl != 0 { - tv.SetFloat32(float32(rv.Float())) + tv.SetFloat32(softfloat.F64to32(math.Float64bits(rv.Float()))) } case Float64Kind: if lvl != 0 { - tv.SetFloat64(rv.Float()) + tv.SetFloat64(math.Float64bits(rv.Float())) } case BigintKind: panic("not yet implemented") @@ -644,9 +647,9 @@ func go2GnoValue2(alloc *Allocator, store Store, rv reflect.Value, recursive boo case reflect.Uint64: tv.SetUint64(rv.Uint()) case reflect.Float32: - tv.SetFloat32(float32(rv.Float())) + tv.SetFloat32(softfloat.F64to32(math.Float64bits(rv.Float()))) case reflect.Float64: - tv.SetFloat64(rv.Float()) + tv.SetFloat64(math.Float64bits(rv.Float())) case reflect.Array: rvl := rv.Len() if rv.Type().Elem().Kind() == reflect.Uint8 { @@ -1049,9 +1052,9 @@ func gno2GoValue(tv *TypedValue, rv reflect.Value) (ret reflect.Value) { case Uint64Type: rv.SetUint(tv.GetUint64()) case Float32Type: - rv.SetFloat(float64(tv.GetFloat32())) + rv.SetFloat(math.Float64frombits(softfloat.F32to64(tv.GetFloat32()))) case Float64Type: - rv.SetFloat(tv.GetFloat64()) + rv.SetFloat(math.Float64frombits(tv.GetFloat64())) default: panic(fmt.Sprintf( "unexpected type %s", diff --git a/gnovm/pkg/gnolang/internal/softfloat/copy.sh b/gnovm/pkg/gnolang/internal/softfloat/copy.sh new file mode 100644 index 00000000000..6d2a8f80462 --- /dev/null +++ b/gnovm/pkg/gnolang/internal/softfloat/copy.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# softfloat64.go: +# - add header +# - change package name +cat > runtime_softfloat64.go << EOF +// Code generated by copy.sh. DO NOT EDIT. +// This file is copied from \$GOROOT/src/runtime/softfloat64.go. +// It is the software floating point implementation used by the Go runtime. + +EOF +cat "$GOROOT/src/runtime/softfloat64.go" >> ./runtime_softfloat64.go +sed -i 's/^package runtime$/package softfloat/' runtime_softfloat64.go + +# softfloat64_test.go: +# - add header +# - change package name +# - change import to right package +# - change GOARCH to runtime.GOARCH, and import the "runtime" package +cat > runtime_softfloat64_test.go << EOF +// Code generated by copy.sh. DO NOT EDIT. +// This file is copied from \$GOROOT/src/runtime/softfloat64_test.go. +// It is the tests for the software floating point implementation +// used by the Go runtime. + +EOF +cat "$GOROOT/src/runtime/softfloat64_test.go" >> ./runtime_softfloat64_test.go +sed -i 's/^package runtime_test$/package softfloat_test/ +s#^\t\. "runtime"$#\t. "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat"# +s/GOARCH/runtime.GOARCH/g +16a\ + "runtime"' runtime_softfloat64_test.go \ No newline at end of file diff --git a/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64.go b/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64.go new file mode 100644 index 00000000000..cf2ad5afd8a --- /dev/null +++ b/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64.go @@ -0,0 +1,631 @@ +// Code generated by copy.sh. DO NOT EDIT. +// This file is copied from $GOROOT/src/runtime/softfloat64.go. +// It is the software floating point implementation used by the Go runtime. + +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Software IEEE754 64-bit floating point. +// Only referred to (and thus linked in) by softfloat targets +// and by tests in this directory. + +package softfloat + +const ( + mantbits64 uint = 52 + expbits64 uint = 11 + bias64 = -1<<(expbits64-1) + 1 + + nan64 uint64 = (1<>mantbits64) & (1<>mantbits32) & (1<= 4<>= 1 + exp++ + } + if mant >= 2<= 4<>= 1 + exp++ + } + } + mant >>= 1 + exp++ + } + if exp >= 1<>= 1 + exp++ + } + if mant&1 != 0 && (trunc != 0 || mant&2 != 0) { + mant++ + } + mant >>= 1 + exp++ + if mant < 1<= 4<>= 1 + exp++ + } + if mant >= 2<= 4<>= 1 + exp++ + } + } + mant >>= 1 + exp++ + } + if exp >= 1<>= 1 + exp++ + } + if mant&1 != 0 && (trunc != 0 || mant&2 != 0) { + mant++ + } + mant >>= 1 + exp++ + if mant < 1<>= shift + if fs == gs { + fm += gm + } else { + fm -= gm + if trunc != 0 { + fm-- + } + } + if fm == 0 { + fs = 0 + } + return fpack64(fs, fm, fe-2, trunc) +} + +func fsub64(f, g uint64) uint64 { + return fadd64(f, fneg64(g)) +} + +func fneg64(f uint64) uint64 { + return f ^ (1 << (mantbits64 + expbits64)) +} + +func fmul64(f, g uint64) uint64 { + fs, fm, fe, fi, fn := funpack64(f) + gs, gm, ge, gi, gn := funpack64(g) + + // Special cases. + switch { + case fn || gn: // NaN * g or f * NaN = NaN + return nan64 + + case fi && gi: // Inf * Inf = Inf (with sign adjusted) + return f ^ gs + + case fi && gm == 0, fm == 0 && gi: // 0 * Inf = Inf * 0 = NaN + return nan64 + + case fm == 0: // 0 * x = 0 (with sign adjusted) + return f ^ gs + + case gm == 0: // x * 0 = 0 (with sign adjusted) + return g ^ fs + } + + // 53-bit * 53-bit = 107- or 108-bit + lo, hi := mullu(fm, gm) + shift := mantbits64 - 1 + trunc := lo & (1<>shift + return fpack64(fs^gs, mant, fe+ge-1, trunc) +} + +func fdiv64(f, g uint64) uint64 { + fs, fm, fe, fi, fn := funpack64(f) + gs, gm, ge, gi, gn := funpack64(g) + + // Special cases. + switch { + case fn || gn: // NaN / g = f / NaN = NaN + return nan64 + + case fi && gi: // ±Inf / ±Inf = NaN + return nan64 + + case !fi && !gi && fm == 0 && gm == 0: // 0 / 0 = NaN + return nan64 + + case fi, !gi && gm == 0: // Inf / g = f / 0 = Inf + return fs ^ gs ^ inf64 + + case gi, fm == 0: // f / Inf = 0 / g = Inf + return fs ^ gs ^ 0 + } + _, _, _, _ = fi, fn, gi, gn + + // 53-bit<<54 / 53-bit = 53- or 54-bit. + shift := mantbits64 + 2 + q, r := divlu(fm>>(64-shift), fm<> 32) + if fi { + return fs32 ^ inf32 + } + const d = mantbits64 - mantbits32 - 1 + return fpack32(fs32, uint32(fm>>d), fe-1, uint32(fm&(1< gs: // f < 0, g > 0 + return -1, false + + case fs < gs: // f > 0, g < 0 + return +1, false + + // Same sign, not NaN. + // Can compare encodings directly now. + // Reverse for sign. + case fs == 0 && f < g, fs != 0 && f > g: + return -1, false + + case fs == 0 && f > g, fs != 0 && f < g: + return +1, false + } + + // f == g + return 0, false +} + +func f64toint(f uint64) (val int64, ok bool) { + fs, fm, fe, fi, fn := funpack64(f) + + switch { + case fi, fn: // NaN + return 0, false + + case fe < -1: // f < 0.5 + return 0, false + + case fe > 63: // f >= 2^63 + if fs != 0 && fm == 0 { // f == -2^63 + return -1 << 63, true + } + if fs != 0 { + return 0, false + } + return 0, false + } + + for fe > int(mantbits64) { + fe-- + fm <<= 1 + } + for fe < int(mantbits64) { + fe++ + fm >>= 1 + } + val = int64(fm) + if fs != 0 { + val = -val + } + return val, true +} + +func fintto64(val int64) (f uint64) { + fs := uint64(val) & (1 << 63) + mant := uint64(val) + if fs != 0 { + mant = -mant + } + return fpack64(fs, mant, int(mantbits64), 0) +} +func fintto32(val int64) (f uint32) { + fs := uint64(val) & (1 << 63) + mant := uint64(val) + if fs != 0 { + mant = -mant + } + // Reduce mantissa size until it fits into a uint32. + // Keep track of the bits we throw away, and if any are + // nonzero or them into the lowest bit. + exp := int(mantbits32) + var trunc uint32 + for mant >= 1<<32 { + trunc |= uint32(mant) & 1 + mant >>= 1 + exp++ + } + + return fpack32(uint32(fs>>32), uint32(mant), exp, trunc) +} + +// 64x64 -> 128 multiply. +// adapted from hacker's delight. +func mullu(u, v uint64) (lo, hi uint64) { + const ( + s = 32 + mask = 1<> s + v0 := v & mask + v1 := v >> s + w0 := u0 * v0 + t := u1*v0 + w0>>s + w1 := t & mask + w2 := t >> s + w1 += u0 * v1 + return u * v, u1*v1 + w2 + w1>>s +} + +// 128/64 -> 64 quotient, 64 remainder. +// adapted from hacker's delight +func divlu(u1, u0, v uint64) (q, r uint64) { + const b = 1 << 32 + + if u1 >= v { + return 1<<64 - 1, 1<<64 - 1 + } + + // s = nlz(v); v <<= s + s := uint(0) + for v&(1<<63) == 0 { + s++ + v <<= 1 + } + + vn1 := v >> 32 + vn0 := v & (1<<32 - 1) + un32 := u1<>(64-s) + un10 := u0 << s + un1 := un10 >> 32 + un0 := un10 & (1<<32 - 1) + q1 := un32 / vn1 + rhat := un32 - q1*vn1 + +again1: + if q1 >= b || q1*vn0 > b*rhat+un1 { + q1-- + rhat += vn1 + if rhat < b { + goto again1 + } + } + + un21 := un32*b + un1 - q1*v + q0 := un21 / vn1 + rhat = un21 - q0*vn1 + +again2: + if q0 >= b || q0*vn0 > b*rhat+un0 { + q0-- + rhat += vn1 + if rhat < b { + goto again2 + } + } + + return q1*b + q0, (un21*b + un0 - q0*v) >> s +} + +func fadd32(x, y uint32) uint32 { + return f64to32(fadd64(f32to64(x), f32to64(y))) +} + +func fmul32(x, y uint32) uint32 { + return f64to32(fmul64(f32to64(x), f32to64(y))) +} + +func fdiv32(x, y uint32) uint32 { + // TODO: are there double-rounding problems here? See issue 48807. + return f64to32(fdiv64(f32to64(x), f32to64(y))) +} + +func feq32(x, y uint32) bool { + cmp, nan := fcmp64(f32to64(x), f32to64(y)) + return cmp == 0 && !nan +} + +func fgt32(x, y uint32) bool { + cmp, nan := fcmp64(f32to64(x), f32to64(y)) + return cmp >= 1 && !nan +} + +func fge32(x, y uint32) bool { + cmp, nan := fcmp64(f32to64(x), f32to64(y)) + return cmp >= 0 && !nan +} + +func feq64(x, y uint64) bool { + cmp, nan := fcmp64(x, y) + return cmp == 0 && !nan +} + +func fgt64(x, y uint64) bool { + cmp, nan := fcmp64(x, y) + return cmp >= 1 && !nan +} + +func fge64(x, y uint64) bool { + cmp, nan := fcmp64(x, y) + return cmp >= 0 && !nan +} + +func fint32to32(x int32) uint32 { + return fintto32(int64(x)) +} + +func fint32to64(x int32) uint64 { + return fintto64(int64(x)) +} + +func fint64to32(x int64) uint32 { + return fintto32(x) +} + +func fint64to64(x int64) uint64 { + return fintto64(x) +} + +func f32toint32(x uint32) int32 { + val, _ := f64toint(f32to64(x)) + return int32(val) +} + +func f32toint64(x uint32) int64 { + val, _ := f64toint(f32to64(x)) + return val +} + +func f64toint32(x uint64) int32 { + val, _ := f64toint(x) + return int32(val) +} + +func f64toint64(x uint64) int64 { + val, _ := f64toint(x) + return val +} + +func f64touint64(x uint64) uint64 { + var m uint64 = 0x43e0000000000000 // float64 1<<63 + if fgt64(m, x) { + return uint64(f64toint64(x)) + } + y := fadd64(x, -m) + z := uint64(f64toint64(y)) + return z | (1 << 63) +} + +func f32touint64(x uint32) uint64 { + var m uint32 = 0x5f000000 // float32 1<<63 + if fgt32(m, x) { + return uint64(f32toint64(x)) + } + y := fadd32(x, -m) + z := uint64(f32toint64(y)) + return z | (1 << 63) +} + +func fuint64to64(x uint64) uint64 { + if int64(x) >= 0 { + return fint64to64(int64(x)) + } + // See ../cmd/compile/internal/ssagen/ssa.go:uint64Tofloat + y := x & 1 + z := x >> 1 + z = z | y + r := fint64to64(int64(z)) + return fadd64(r, r) +} + +func fuint64to32(x uint64) uint32 { + if int64(x) >= 0 { + return fint64to32(int64(x)) + } + // See ../cmd/compile/internal/ssagen/ssa.go:uint64Tofloat + y := x & 1 + z := x >> 1 + z = z | y + r := fint64to32(int64(z)) + return fadd32(r, r) +} diff --git a/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64_test.go b/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64_test.go new file mode 100644 index 00000000000..c57fe08b0ef --- /dev/null +++ b/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64_test.go @@ -0,0 +1,204 @@ +// Code generated by copy.sh. DO NOT EDIT. +// This file is copied from $GOROOT/src/runtime/softfloat64_test.go. +// It is the tests for the software floating point implementation +// used by the Go runtime. + +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package softfloat_test + +import ( + "math" + "math/rand" + . "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" + "testing" + "runtime" +) + +// turn uint64 op into float64 op +func fop(f func(x, y uint64) uint64) func(x, y float64) float64 { + return func(x, y float64) float64 { + bx := math.Float64bits(x) + by := math.Float64bits(y) + return math.Float64frombits(f(bx, by)) + } +} + +func add(x, y float64) float64 { return x + y } +func sub(x, y float64) float64 { return x - y } +func mul(x, y float64) float64 { return x * y } +func div(x, y float64) float64 { return x / y } + +func TestFloat64(t *testing.T) { + base := []float64{ + 0, + math.Copysign(0, -1), + -1, + 1, + math.NaN(), + math.Inf(+1), + math.Inf(-1), + 0.1, + 1.5, + 1.9999999999999998, // all 1s mantissa + 1.3333333333333333, // 1.010101010101... + 1.1428571428571428, // 1.001001001001... + 1.112536929253601e-308, // first normal + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 3, + 12, + 1234, + 123456, + -0.1, + -1.5, + -1.9999999999999998, + -1.3333333333333333, + -1.1428571428571428, + -2, + -3, + 1e-200, + 1e-300, + 1e-310, + 5e-324, + 1e-105, + 1e-305, + 1e+200, + 1e+306, + 1e+307, + 1e+308, + } + all := make([]float64, 200) + copy(all, base) + for i := len(base); i < len(all); i++ { + all[i] = rand.NormFloat64() + } + + test(t, "+", add, fop(Fadd64), all) + test(t, "-", sub, fop(Fsub64), all) + if runtime.GOARCH != "386" { // 386 is not precise! + test(t, "*", mul, fop(Fmul64), all) + test(t, "/", div, fop(Fdiv64), all) + } +} + +// 64 -hw-> 32 -hw-> 64 +func trunc32(f float64) float64 { + return float64(float32(f)) +} + +// 64 -sw->32 -hw-> 64 +func to32sw(f float64) float64 { + return float64(math.Float32frombits(F64to32(math.Float64bits(f)))) +} + +// 64 -hw->32 -sw-> 64 +func to64sw(f float64) float64 { + return math.Float64frombits(F32to64(math.Float32bits(float32(f)))) +} + +// float64 -hw-> int64 -hw-> float64 +func hwint64(f float64) float64 { + return float64(int64(f)) +} + +// float64 -hw-> int32 -hw-> float64 +func hwint32(f float64) float64 { + return float64(int32(f)) +} + +// float64 -sw-> int64 -hw-> float64 +func toint64sw(f float64) float64 { + i, ok := F64toint(math.Float64bits(f)) + if !ok { + // There's no right answer for out of range. + // Match the hardware to pass the test. + i = int64(f) + } + return float64(i) +} + +// float64 -hw-> int64 -sw-> float64 +func fromint64sw(f float64) float64 { + return math.Float64frombits(Fintto64(int64(f))) +} + +var nerr int + +func err(t *testing.T, format string, args ...any) { + t.Errorf(format, args...) + + // cut errors off after a while. + // otherwise we spend all our time + // allocating memory to hold the + // formatted output. + if nerr++; nerr >= 10 { + t.Fatal("too many errors") + } +} + +func test(t *testing.T, op string, hw, sw func(float64, float64) float64, all []float64) { + for _, f := range all { + for _, g := range all { + h := hw(f, g) + s := sw(f, g) + if !same(h, s) { + err(t, "%g %s %g = sw %g, hw %g\n", f, op, g, s, h) + } + testu(t, "to32", trunc32, to32sw, h) + testu(t, "to64", trunc32, to64sw, h) + testu(t, "toint64", hwint64, toint64sw, h) + testu(t, "fromint64", hwint64, fromint64sw, h) + testcmp(t, f, h) + testcmp(t, h, f) + testcmp(t, g, h) + testcmp(t, h, g) + } + } +} + +func testu(t *testing.T, op string, hw, sw func(float64) float64, v float64) { + h := hw(v) + s := sw(v) + if !same(h, s) { + err(t, "%s %g = sw %g, hw %g\n", op, v, s, h) + } +} + +func hwcmp(f, g float64) (cmp int, isnan bool) { + switch { + case f < g: + return -1, false + case f > g: + return +1, false + case f == g: + return 0, false + } + return 0, true // must be NaN +} + +func testcmp(t *testing.T, f, g float64) { + hcmp, hisnan := hwcmp(f, g) + scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g)) + if int32(hcmp) != scmp || hisnan != sisnan { + err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan) + } +} + +func same(f, g float64) bool { + if math.IsNaN(f) && math.IsNaN(g) { + return true + } + if math.Copysign(1, f) != math.Copysign(1, g) { + return false + } + return f == g +} diff --git a/gnovm/pkg/gnolang/internal/softfloat/softfloat.go b/gnovm/pkg/gnolang/internal/softfloat/softfloat.go new file mode 100644 index 00000000000..30f66dff620 --- /dev/null +++ b/gnovm/pkg/gnolang/internal/softfloat/softfloat.go @@ -0,0 +1,134 @@ +// Package softfloat is a copy of the Go runtime's softfloat64.go file. +// It is a pure software floating point implementation. It can be used to +// perform determinstic, hardware-independent floating point computations. +// +// This package uses shortnames to refer to its different operations. Here is a +// quick reference: +// +// add f + g +// sub f - g +// mul f * g +// div f / g +// neg (- f) +// eq f == g +// gt f > g +// ge f >= g +package softfloat + +// This file mostly exports the functions from runtime_softfloat64.go + +//go:generate sh copy.sh + +const ( + mask = 0x7FF + shift = 64 - 11 - 1 + bias = 1023 +) + +func Fadd64(f, g uint64) uint64 { return fadd64(f, g) } +func Fsub64(f, g uint64) uint64 { return fsub64(f, g) } +func Fmul64(f, g uint64) uint64 { return fmul64(f, g) } +func Fdiv64(f, g uint64) uint64 { return fdiv64(f, g) } +func Fneg64(f uint64) uint64 { return fneg64(f) } +func Feq64(f, g uint64) bool { return feq64(f, g) } +func Fgt64(f, g uint64) bool { return fgt64(f, g) } +func Fge64(f, g uint64) bool { return fge64(f, g) } + +func Fadd32(f, g uint32) uint32 { return fadd32(f, g) } +func Fsub32(f, g uint32) uint32 { return fadd32(f, Fneg32(g)) } +func Fmul32(f, g uint32) uint32 { return fmul32(f, g) } +func Fdiv32(f, g uint32) uint32 { return fdiv32(f, g) } +func Feq32(f, g uint32) bool { return feq32(f, g) } +func Fgt32(f, g uint32) bool { return fgt32(f, g) } +func Fge32(f, g uint32) bool { return fge32(f, g) } +func Flt32(f, g uint32) bool { + cmp, nan := fcmp64(f32to64(f), f32to64(g)) + return cmp <= -1 && !nan +} + +func Fle32(f, g uint32) bool { + cmp, nan := fcmp64(f32to64(f), f32to64(g)) + return cmp <= 0 && !nan +} + +func Flt64(f, g uint64) bool { + cmp, nan := fcmp64(f, g) + return cmp <= -1 && !nan +} + +func Fle64(f, g uint64) bool { + cmp, nan := fcmp64(f, g) + return cmp <= 0 && !nan +} + +func Fcmp64(f, g uint64) (cmp int32, isnan bool) { return fcmp64(f, g) } + +func Fneg32(f uint32) uint32 { + // Not defined in runtime - this is a copy similar to fneg64. + return f ^ (1 << (mantbits32 + expbits32)) +} + +// Conversions + +func Fintto64(val int64) (f uint64) { return fintto64(val) } +func Fintto32(val int64) (f uint32) { return fintto32(val) } + +func F32to64(f uint32) uint64 { return f32to64(f) } +func F32toint32(x uint32) int32 { return f32toint32(x) } +func F32toint64(x uint32) int64 { return f32toint64(x) } +func F32touint64(x uint32) uint64 { return f32touint64(x) } +func F64to32(f uint64) uint32 { return f64to32(f) } +func F64toint(f uint64) (val int64, ok bool) { return f64toint(f) } +func F64toint32(x uint64) int32 { return f64toint32(x) } +func F64toint64(x uint64) int64 { return f64toint64(x) } +func F64touint64(x uint64) uint64 { return f64touint64(x) } +func Fint32to32(x int32) uint32 { return fint32to32(x) } +func Fint32to64(x int32) uint64 { return fint32to64(x) } +func Fint64to32(x int64) uint32 { return fint64to32(x) } +func Fint64to64(x int64) uint64 { return fint64to64(x) } +func Fuint64to32(x uint64) uint32 { return fuint64to32(x) } +func Fuint64to64(x uint64) uint64 { return fuint64to64(x) } + +// unpack64 unpacks the float64 f into sign, exp, mantissa, isInf, isNaN. + +func Funpack32(f uint32) (sign, mant uint32, exp int, inf, nan bool) { return funpack32(f) } +func Funpack64(f uint64) (sign, mant uint64, exp int, inf, nan bool) { return funpack64(f) } + +// Trunc + +func Ftrunc64(f uint64) uint64 { return trunc(f) } +func Ftrunc32(f uint32) uint32 { return f64to32(trunc(f32to64(f))) } + +func trunc(x uint64) uint64 { + cmp, _ := Fcmp64(x, Fintto64(0)) + if _, _, _, isInf, IsNaN := Funpack64(x); cmp == 0 || isInf || IsNaN { + return x + } + + d, _ := modf(x) + return d +} + +func modf(u uint64) (it uint64, frac uint64) { + if Flt64(u, fint64to64(1)) { + switch { + case Flt64(u, fint64to64(0)): + it, frac = modf(Fneg64(u)) + return -it, -frac + case feq64(u, fint64to64(0)): + return u, u // Return -0, -0 when f == -0 + } + return 0, u + } + + it = u + e := uint(it>>shift)&mask - bias + + // Keep the top 12+e bits, the integer part; clear the rest. + if e < 64-12 { + it &^= 1<<(64-12-e) - 1 + } + + frac = fsub64(u, it) + return +} diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index 0f66da5e685..765f3ccbfbd 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -6,6 +6,7 @@ import ( "math/big" "github.com/cockroachdb/apd/v3" + "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" "github.com/gnolang/gno/tm2/pkg/overflow" ) @@ -394,9 +395,9 @@ func isEql(store Store, lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() == rv.GetUint64()) case Float32Kind: - return (lv.GetFloat32() == rv.GetFloat32()) // XXX determinism? + return softfloat.Feq32(lv.GetFloat32(), rv.GetFloat32()) case Float64Kind: - return (lv.GetFloat64() == rv.GetFloat64()) // XXX determinism? + return softfloat.Feq64(lv.GetFloat64(), rv.GetFloat64()) case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -535,9 +536,9 @@ func isLss(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() < rv.GetUint64()) case Float32Kind: - return (lv.GetFloat32() < rv.GetFloat32()) // XXX determinism? + return softfloat.Flt32(lv.GetFloat32(), rv.GetFloat32()) case Float64Kind: - return (lv.GetFloat64() < rv.GetFloat64()) // XXX determinism? + return softfloat.Flt64(lv.GetFloat64(), rv.GetFloat64()) case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -579,9 +580,9 @@ func isLeq(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() <= rv.GetUint64()) case Float32Kind: - return (lv.GetFloat32() <= rv.GetFloat32()) // XXX determinism? + return softfloat.Fle32(lv.GetFloat32(), rv.GetFloat32()) case Float64Kind: - return (lv.GetFloat64() <= rv.GetFloat64()) // XXX determinism? + return softfloat.Fle64(lv.GetFloat64(), rv.GetFloat64()) case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -623,9 +624,9 @@ func isGtr(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() > rv.GetUint64()) case Float32Kind: - return (lv.GetFloat32() > rv.GetFloat32()) // XXX determinism? + return softfloat.Fgt32(lv.GetFloat32(), rv.GetFloat32()) case Float64Kind: - return (lv.GetFloat64() > rv.GetFloat64()) // XXX determinism? + return softfloat.Fgt64(lv.GetFloat64(), rv.GetFloat64()) case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -667,9 +668,9 @@ func isGeq(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() >= rv.GetUint64()) case Float32Kind: - return (lv.GetFloat32() >= rv.GetFloat32()) // XXX determinism? + return softfloat.Fge32(lv.GetFloat32(), rv.GetFloat32()) case Float64Kind: - return (lv.GetFloat64() >= rv.GetFloat64()) // XXX determinism? + return softfloat.Fge64(lv.GetFloat64(), rv.GetFloat64()) case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -732,10 +733,10 @@ func addAssign(alloc *Allocator, lv, rv *TypedValue) *Exception { lv.SetUint64(lv.GetUint64() + rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat32(lv.GetFloat32() + rv.GetFloat32()) // XXX determinism? + lv.SetFloat32(softfloat.Fadd32(lv.GetFloat32(), rv.GetFloat32())) case Float64Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat64(lv.GetFloat64() + rv.GetFloat64()) // XXX determinism? + lv.SetFloat64(softfloat.Fadd64(lv.GetFloat64(), rv.GetFloat64())) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Add(lb, rv.GetBigInt()) @@ -807,10 +808,10 @@ func subAssign(lv, rv *TypedValue) *Exception { lv.SetUint64(lv.GetUint64() - rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat32(lv.GetFloat32() - rv.GetFloat32()) // XXX determinism? + lv.SetFloat32(softfloat.Fsub32(lv.GetFloat32(), rv.GetFloat32())) case Float64Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat64(lv.GetFloat64() - rv.GetFloat64()) // XXX determinism? + lv.SetFloat64(softfloat.Fsub64(lv.GetFloat64(), rv.GetFloat64())) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Sub(lb, rv.GetBigInt()) @@ -879,10 +880,10 @@ func mulAssign(lv, rv *TypedValue) *Exception { lv.SetUint64(lv.GetUint64() * rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat32(lv.GetFloat32() * rv.GetFloat32()) // XXX determinism? + lv.SetFloat32(softfloat.Fmul32(lv.GetFloat32(), rv.GetFloat32())) case Float64Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat64(lv.GetFloat64() * rv.GetFloat64()) // XXX determinism? + lv.SetFloat64(softfloat.Fmul64(lv.GetFloat64(), rv.GetFloat64())) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Mul(lb, rv.GetBigInt()) @@ -975,20 +976,17 @@ func quoAssign(lv, rv *TypedValue) *Exception { // XXX Handling float overflows is more complex. case Float32Type: // NOTE: gno doesn't fuse *+. - y := rv.GetFloat32() - ok = y != 0 + ok = !softfloat.Feq32(rv.GetFloat32(), softfloat.Fintto32(0)) + if ok { - lv.SetFloat32(lv.GetFloat32() / y) + lv.SetFloat32(softfloat.Fdiv32(lv.GetFloat32(), rv.GetFloat32())) } - // XXX FOR DETERMINISM, PANIC IF NAN. case Float64Type: // NOTE: gno doesn't fuse *+. - y := rv.GetFloat64() - ok = y != 0 + ok = !softfloat.Feq64(rv.GetFloat64(), softfloat.Fintto64(0)) if ok { - lv.SetFloat64(lv.GetFloat64() / y) + lv.SetFloat64(softfloat.Fdiv64(lv.GetFloat64(), rv.GetFloat64())) } - // XXX FOR DETERMINISM, PANIC IF NAN. case BigintType, UntypedBigintType: if rv.GetBigInt().Sign() == 0 { ok = false diff --git a/gnovm/pkg/gnolang/op_inc_dec.go b/gnovm/pkg/gnolang/op_inc_dec.go index 1e68e195596..c67a4be6ed5 100644 --- a/gnovm/pkg/gnolang/op_inc_dec.go +++ b/gnovm/pkg/gnolang/op_inc_dec.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/cockroachdb/apd/v3" + "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" "github.com/gnolang/gno/tm2/pkg/overflow" ) @@ -57,9 +58,9 @@ func (m *Machine) doOpInc() { case Uint64Type: lv.SetUint64(lv.GetUint64() + 1) case Float32Type: - lv.SetFloat32(lv.GetFloat32() + 1) + lv.SetFloat32(softfloat.Fadd32(lv.GetFloat32(), softfloat.Fintto32(1))) case Float64Type: - lv.SetFloat64(lv.GetFloat64() + 1) + lv.SetFloat64(softfloat.Fadd64(lv.GetFloat64(), softfloat.Fintto64(1))) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Add(lb, big.NewInt(1)) @@ -129,9 +130,9 @@ func (m *Machine) doOpDec() { case Uint64Type: lv.SetUint64(lv.GetUint64() - 1) case Float32Type: - lv.SetFloat32(lv.GetFloat32() - 1) + lv.SetFloat32(softfloat.Fsub32(lv.GetFloat32(), softfloat.Fintto32(1))) case Float64Type: - lv.SetFloat64(lv.GetFloat64() - 1) + lv.SetFloat64(softfloat.Fsub64(lv.GetFloat64(), softfloat.Fintto64(1))) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Sub(lb, big.NewInt(1)) diff --git a/gnovm/pkg/gnolang/op_unary.go b/gnovm/pkg/gnolang/op_unary.go index 9c330c7f8f1..469c80b8dac 100644 --- a/gnovm/pkg/gnolang/op_unary.go +++ b/gnovm/pkg/gnolang/op_unary.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/cockroachdb/apd/v3" + "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" ) func (m *Machine) doOpUpos() { @@ -46,9 +47,9 @@ func (m *Machine) doOpUneg() { case Uint64Type: xv.SetUint64(-xv.GetUint64()) case Float32Type: - xv.SetFloat32(-xv.GetFloat32()) + xv.SetFloat32(softfloat.Fneg32(xv.GetFloat32())) case Float64Type: - xv.SetFloat64(-xv.GetFloat64()) + xv.SetFloat64(softfloat.Fneg64(xv.GetFloat64())) case UntypedBigintType, BigintType: bv := xv.V.(BigintValue) xv.V = BigintValue{V: new(big.Int).Neg(bv.V)} diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 4c2e2835f95..da887764c8e 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -3,7 +3,6 @@ package gnolang import ( "encoding/binary" "fmt" - "math" "math/big" "reflect" "strconv" @@ -1121,13 +1120,13 @@ func (tv *TypedValue) PrimitiveBytes() (data []byte) { return data case Float32Type: data = make([]byte, 4) - u32 := math.Float32bits(tv.GetFloat32()) + u32 := tv.GetFloat32() binary.LittleEndian.PutUint32( data, u32) return data case Float64Type: data = make([]byte, 8) - u64 := math.Float64bits(tv.GetFloat64()) + u64 := tv.GetFloat64() binary.LittleEndian.PutUint64( data, u64) return data @@ -1450,7 +1449,7 @@ func (tv *TypedValue) GetUint64() uint64 { return *(*uint64)(unsafe.Pointer(&tv.N)) } -func (tv *TypedValue) SetFloat32(n float32) { +func (tv *TypedValue) SetFloat32(n uint32) { if debug { if tv.T.Kind() != Float32Kind || isNative(tv.T) { panic(fmt.Sprintf( @@ -1458,10 +1457,10 @@ func (tv *TypedValue) SetFloat32(n float32) { tv.T.String())) } } - *(*float32)(unsafe.Pointer(&tv.N)) = n + *(*uint32)(unsafe.Pointer(&tv.N)) = n } -func (tv *TypedValue) GetFloat32() float32 { +func (tv *TypedValue) GetFloat32() uint32 { if debug { if tv.T != nil && tv.T.Kind() != Float32Kind { panic(fmt.Sprintf( @@ -1469,10 +1468,10 @@ func (tv *TypedValue) GetFloat32() float32 { tv.T.String())) } } - return *(*float32)(unsafe.Pointer(&tv.N)) + return *(*uint32)(unsafe.Pointer(&tv.N)) } -func (tv *TypedValue) SetFloat64(n float64) { +func (tv *TypedValue) SetFloat64(n uint64) { if debug { if tv.T.Kind() != Float64Kind || isNative(tv.T) { panic(fmt.Sprintf( @@ -1480,10 +1479,10 @@ func (tv *TypedValue) SetFloat64(n float64) { tv.T.String())) } } - *(*float64)(unsafe.Pointer(&tv.N)) = n + *(*uint64)(unsafe.Pointer(&tv.N)) = n } -func (tv *TypedValue) GetFloat64() float64 { +func (tv *TypedValue) GetFloat64() uint64 { if debug { if tv.T != nil && tv.T.Kind() != Float64Kind { panic(fmt.Sprintf( @@ -1491,7 +1490,7 @@ func (tv *TypedValue) GetFloat64() float64 { tv.T.String())) } } - return *(*float64)(unsafe.Pointer(&tv.N)) + return *(*uint64)(unsafe.Pointer(&tv.N)) } func (tv *TypedValue) GetBigInt() *big.Int { diff --git a/gnovm/pkg/gnolang/values_conversions.go b/gnovm/pkg/gnolang/values_conversions.go index baeded76c1a..e1c9378fe67 100644 --- a/gnovm/pkg/gnolang/values_conversions.go +++ b/gnovm/pkg/gnolang/values_conversions.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/cockroachdb/apd/v3" + "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" ) // t cannot be nil or untyped or DataByteType. @@ -163,11 +164,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetInt()) // XXX determinism? + x := softfloat.Fintto32(int64(tv.GetInt())) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetInt()) // XXX determinism? + x := softfloat.Fintto64(int64(tv.GetInt())) tv.T = t tv.SetFloat64(x) case StringKind: @@ -233,11 +234,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetInt8()) // XXX determinism? + x := softfloat.Fint32to32(int32(tv.GetInt8())) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetInt8()) // XXX determinism? + x := softfloat.Fint32to64(int32(tv.GetInt8())) tv.T = t tv.SetFloat64(x) case StringKind: @@ -304,11 +305,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetInt16()) // XXX determinism? + x := softfloat.Fint32to32(int32(tv.GetInt16())) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetInt16()) // XXX determinism? + x := softfloat.Fint32to64(int32(tv.GetInt16())) tv.T = t tv.SetFloat64(x) case StringKind: @@ -379,11 +380,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetInt32()) // XXX determinism? + x := softfloat.Fint32to32(tv.GetInt32()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetInt32()) // XXX determinism? + x := softfloat.Fint32to64(tv.GetInt32()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -456,11 +457,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetInt64()) // XXX determinism? + x := softfloat.Fint64to32(tv.GetInt64()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetInt64()) // XXX determinism? + x := softfloat.Fint64to64(tv.GetInt64()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -533,11 +534,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetUint()) // XXX determinism? + x := softfloat.Fuint64to32(uint64(tv.GetUint())) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetUint()) // XXX determinism? + x := softfloat.Fuint64to64(uint64(tv.GetUint())) tv.T = t tv.SetFloat64(x) case StringKind: @@ -602,11 +603,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetUint8()) // XXX determinism? + x := softfloat.Fuint64to32(uint64(tv.GetUint8())) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetUint8()) // XXX determinism? + x := softfloat.Fuint64to64(uint64(tv.GetUint8())) tv.T = t tv.SetFloat64(x) case StringKind: @@ -673,11 +674,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetUint16()) // XXX determinism? + x := softfloat.Fuint64to32(uint64(tv.GetUint16())) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetUint16()) // XXX determinism? + x := softfloat.Fuint64to64(uint64(tv.GetUint16())) tv.T = t tv.SetFloat64(x) case StringKind: @@ -746,11 +747,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetUint32()) // XXX determinism? + x := softfloat.Fuint64to32(uint64(tv.GetUint32())) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetUint32()) // XXX determinism? + x := softfloat.Fuint64to64(uint64(tv.GetUint32())) tv.T = t tv.SetFloat64(x) case StringKind: @@ -825,11 +826,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetUint64()) // XXX determinism? + x := softfloat.Fuint64to32(tv.GetUint64()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetUint64()) // XXX determinism? + x := softfloat.Fuint64to64(tv.GetUint64()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -847,156 +848,155 @@ GNO_CASE: switch k { case IntKind: validate(Float32Kind, IntKind, func() bool { - val := float64(tv.GetFloat32()) - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc32(tv.GetFloat32()) - if val != trunc { + if !softfloat.Feq32(trunc, tv.GetFloat32()) { return false } - return int64(trunc) >= math.MinInt && int64(trunc) <= math.MaxInt + truncInt64 := softfloat.F32toint64(trunc) + return truncInt64 >= math.MinInt && truncInt64 <= math.MaxInt }) - x := int(tv.GetFloat32()) // XXX determinism? + x := int(softfloat.F32toint64(tv.GetFloat32())) tv.T = t tv.SetInt(x) case Int8Kind: validate(Float32Kind, Int8Kind, func() bool { - val := float64(tv.GetFloat32()) - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc32(tv.GetFloat32()) - if val != trunc { + if !softfloat.Feq32(trunc, tv.GetFloat32()) { return false } - return int64(trunc) >= math.MinInt8 && int64(trunc) <= math.MaxInt8 + truncInt64 := softfloat.F32toint64(trunc) + return truncInt64 >= math.MinInt8 && truncInt64 <= math.MaxInt8 }) - x := int8(tv.GetFloat32()) // XXX determinism? + x := int8(softfloat.F32toint32(tv.GetFloat32())) tv.T = t tv.SetInt8(x) case Int16Kind: validate(Float32Kind, Int16Kind, func() bool { - val := float64(tv.GetFloat32()) - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc32(tv.GetFloat32()) - if val != trunc { + if !softfloat.Feq32(trunc, tv.GetFloat32()) { return false } - return int64(trunc) >= math.MinInt16 && int64(trunc) <= math.MaxInt16 + truncInt64 := softfloat.F32toint64(trunc) + return truncInt64 >= math.MinInt16 && truncInt64 <= math.MaxInt16 }) - x := int16(tv.GetFloat32()) // XXX determinism? + x := int16(softfloat.F32toint32(tv.GetFloat32())) tv.T = t tv.SetInt16(x) case Int32Kind: validate(Float32Kind, Int32Kind, func() bool { - val := float64(tv.GetFloat32()) - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc32(tv.GetFloat32()) - if val != trunc { + if !softfloat.Feq32(trunc, tv.GetFloat32()) { return false } - return int64(trunc) >= math.MinInt32 && int64(trunc) <= math.MaxInt32 + truncInt64 := softfloat.F32toint64(trunc) + return truncInt64 >= math.MinInt32 && truncInt64 <= math.MaxInt32 }) - x := int32(tv.GetFloat32()) // XXX determinism? + x := softfloat.F32toint32(tv.GetFloat32()) tv.T = t tv.SetInt32(x) case Int64Kind: validate(Float32Kind, Int64Kind, func() bool { - val := float64(tv.GetFloat32()) - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc32(tv.GetFloat32()) - return val == trunc + return softfloat.Feq32(trunc, tv.GetFloat32()) }) - x := int64(tv.GetFloat32()) // XXX determinism? + x := softfloat.F32toint64(tv.GetFloat32()) tv.T = t tv.SetInt64(x) case UintKind: validate(Float32Kind, UintKind, func() bool { - val := float64(tv.GetFloat32()) - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc32(tv.GetFloat32()) - if val != trunc { + if !softfloat.Feq32(trunc, tv.GetFloat32()) { return false } - return trunc >= 0 && trunc <= math.MaxUint + truncUint64 := softfloat.F32touint64(trunc) + return truncUint64 >= 0 && truncUint64 <= math.MaxUint }) - x := uint(tv.GetFloat32()) // XXX determinism? + x := uint(softfloat.F32touint64(tv.GetFloat32())) tv.T = t tv.SetUint(x) case Uint8Kind: validate(Float32Kind, Uint8Kind, func() bool { - val := float64(tv.GetFloat32()) - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc32(tv.GetFloat32()) - if val != trunc { + if !softfloat.Feq32(trunc, tv.GetFloat32()) { return false } - return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint8 + truncUint64 := softfloat.F32touint64(trunc) + return truncUint64 >= 0 && truncUint64 <= math.MaxUint8 }) - x := uint8(tv.GetFloat32()) // XXX determinism? + x := uint8(softfloat.F32touint64(tv.GetFloat32())) tv.T = t tv.SetUint8(x) case Uint16Kind: validate(Float32Kind, Uint16Kind, func() bool { - val := float64(tv.GetFloat32()) - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc32(tv.GetFloat32()) - if val != trunc { + if !softfloat.Feq32(trunc, tv.GetFloat32()) { return false } - return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint16 + truncUint64 := softfloat.F32touint64(trunc) + return truncUint64 >= 0 && truncUint64 <= math.MaxUint16 }) - x := uint16(tv.GetFloat32()) // XXX determinism? + x := uint16(softfloat.F32touint64(tv.GetFloat32())) tv.T = t tv.SetUint16(x) case Uint32Kind: validate(Float32Kind, Uint32Kind, func() bool { - val := float64(tv.GetFloat32()) - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc32(tv.GetFloat32()) - if val != trunc { + if !softfloat.Feq32(trunc, tv.GetFloat32()) { return false } - return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint32 + truncUint64 := softfloat.F32touint64(trunc) + return truncUint64 >= 0 && truncUint64 <= math.MaxUint32 }) - x := uint32(tv.GetFloat32()) // XXX determinism? + x := uint32(softfloat.F32touint64(tv.GetFloat32())) tv.T = t tv.SetUint32(x) case Uint64Kind: validate(Float32Kind, Uint64Kind, func() bool { - val := float64(tv.GetFloat32()) - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc32(tv.GetFloat32()) - if val != trunc { + if !softfloat.Feq32(trunc, tv.GetFloat32()) { return false } - return trunc >= 0 && trunc <= math.MaxUint + truncUint64 := softfloat.F32touint64(trunc) + return truncUint64 >= 0 && truncUint64 <= math.MaxUint }) - x := uint64(tv.GetFloat32()) // XXX determinism? + x := softfloat.F32touint64(tv.GetFloat32()) tv.T = t tv.SetUint64(x) case Float32Kind: - x := tv.GetFloat32() // XXX determinism? + x := tv.GetFloat32() // ??? tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetFloat32()) // XXX determinism? + x := softfloat.F32to64(tv.GetFloat32()) tv.T = t tv.SetFloat64(x) default: @@ -1008,160 +1008,160 @@ GNO_CASE: switch k { case IntKind: validate(Float64Kind, IntKind, func() bool { - val := tv.GetFloat64() - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc64(tv.GetFloat64()) - if val != trunc { + if !softfloat.Feq64(trunc, tv.GetFloat64()) { return false } - return int64(trunc) >= math.MinInt && int64(trunc) <= math.MaxInt + truncInt64 := softfloat.F64toint64(trunc) + return truncInt64 >= math.MinInt && truncInt64 <= math.MaxInt }) - x := int(tv.GetFloat64()) // XXX determinism? + xp, _ := softfloat.F64toint(tv.GetFloat64()) + x := int(xp) tv.T = t tv.SetInt(x) case Int8Kind: validate(Float64Kind, Int8Kind, func() bool { - val := tv.GetFloat64() - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc64(tv.GetFloat64()) - if val != trunc { + if !softfloat.Feq64(trunc, tv.GetFloat64()) { return false } - return int64(trunc) >= math.MinInt8 && int64(trunc) <= math.MaxInt8 + truncInt64 := softfloat.F64toint64(trunc) + return truncInt64 >= math.MinInt8 && truncInt64 <= math.MaxInt8 }) - x := int8(tv.GetFloat64()) // XXX determinism? + x := int8(softfloat.F64toint32(tv.GetFloat64())) tv.T = t tv.SetInt8(x) case Int16Kind: validate(Float64Kind, Int16Kind, func() bool { - val := tv.GetFloat64() - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc64(tv.GetFloat64()) - if val != trunc { + if !softfloat.Feq64(trunc, tv.GetFloat64()) { return false } - return int64(trunc) >= math.MinInt16 && int64(trunc) <= math.MaxInt16 + truncInt64 := softfloat.F64toint64(trunc) + return truncInt64 >= math.MinInt16 && truncInt64 <= math.MaxInt16 }) - x := int16(tv.GetFloat64()) // XXX determinism? + x := int16(softfloat.F64toint32(tv.GetFloat64())) tv.T = t tv.SetInt16(x) case Int32Kind: validate(Float64Kind, Int32Kind, func() bool { - val := tv.GetFloat64() - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc64(tv.GetFloat64()) - if val != trunc { + if !softfloat.Feq64(trunc, tv.GetFloat64()) { return false } - return int64(trunc) >= math.MinInt32 && int64(trunc) <= math.MaxInt32 + truncInt64 := softfloat.F64toint64(trunc) + return truncInt64 >= math.MinInt32 && truncInt64 <= math.MaxInt32 }) - x := int32(tv.GetFloat64()) // XXX determinism? + x := softfloat.F64toint32(tv.GetFloat64()) tv.T = t tv.SetInt32(x) case Int64Kind: validate(Float64Kind, Int64Kind, func() bool { - val := tv.GetFloat64() - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc64(tv.GetFloat64()) - return val == trunc + return softfloat.Feq64(trunc, tv.GetFloat64()) }) - x := int64(tv.GetFloat64()) // XXX determinism? + x := softfloat.F64toint64(tv.GetFloat64()) tv.T = t tv.SetInt64(x) case UintKind: validate(Float64Kind, UintKind, func() bool { - val := tv.GetFloat64() - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc64(tv.GetFloat64()) - if val != trunc { + if !softfloat.Feq64(trunc, tv.GetFloat64()) { return false } - return trunc >= 0 && trunc <= math.MaxUint + truncUint64 := softfloat.F64touint64(trunc) + + return truncUint64 >= 0 && truncUint64 <= math.MaxUint }) - x := uint(tv.GetFloat64()) // XXX determinism? + x := uint(softfloat.F64touint64(tv.GetFloat64())) tv.T = t tv.SetUint(x) case Uint8Kind: validate(Float64Kind, Uint8Kind, func() bool { - val := tv.GetFloat64() - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc64(tv.GetFloat64()) - if val != trunc { + if !softfloat.Feq64(trunc, tv.GetFloat64()) { return false } - return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint8 + truncUint64 := softfloat.F64touint64(trunc) + return truncUint64 >= 0 && truncUint64 <= math.MaxUint8 }) - x := uint8(tv.GetFloat64()) // XXX determinism? + x := uint8(softfloat.F64touint64(tv.GetFloat64())) tv.T = t tv.SetUint8(x) case Uint16Kind: validate(Float64Kind, Uint16Kind, func() bool { - val := tv.GetFloat64() - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc64(tv.GetFloat64()) - if val != trunc { + if !softfloat.Feq64(trunc, tv.GetFloat64()) { return false } - return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint16 + truncUint64 := softfloat.F64touint64(trunc) + return truncUint64 >= 0 && truncUint64 <= math.MaxUint16 }) - x := uint16(tv.GetFloat64()) // XXX determinism? + x := uint16(softfloat.F64touint64(tv.GetFloat64())) tv.T = t tv.SetUint16(x) case Uint32Kind: validate(Float64Kind, Uint32Kind, func() bool { - val := tv.GetFloat64() - trunc := math.Trunc(val) - - if val != trunc { + trunc := softfloat.Ftrunc64(tv.GetFloat64()) + if !softfloat.Feq64(trunc, tv.GetFloat64()) { return false } - return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint32 + truncUint64 := softfloat.F64touint64(trunc) + return truncUint64 >= 0 && truncUint64 <= math.MaxUint32 }) - x := uint32(tv.GetFloat64()) // XXX determinism? + x := uint32(softfloat.F64touint64(tv.GetFloat64())) tv.T = t tv.SetUint32(x) case Uint64Kind: validate(Float64Kind, Uint64Kind, func() bool { - val := tv.GetFloat64() - trunc := math.Trunc(val) + trunc := softfloat.Ftrunc64(tv.GetFloat64()) - if val != trunc { + if !softfloat.Feq64(tv.GetFloat64(), trunc) { return false } - return trunc >= 0 && trunc <= math.MaxUint64 + truncUint64 := softfloat.F64touint64(trunc) + return truncUint64 >= 0 && truncUint64 <= math.MaxUint64 }) - x := uint64(tv.GetFloat64()) // XXX determinism? + x := softfloat.F64touint64(tv.GetFloat64()) tv.T = t tv.SetUint64(x) case Float32Kind: validate(Float64Kind, Float32Kind, func() bool { - return tv.GetFloat64() <= math.MaxFloat32 + return softfloat.Fle64(tv.GetFloat64(), math.Float64bits(float64(math.MaxFloat32))) }) - x := float32(tv.GetFloat64()) // XXX determinism? + x := softfloat.F64to32(tv.GetFloat64()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := tv.GetFloat64() // XXX determinism? + x := tv.GetFloat64() // ??? tv.T = t tv.SetFloat64(x) default: @@ -1481,7 +1481,7 @@ func ConvertUntypedBigintTo(dst *TypedValue, bv BigintValue, t Type) { if f32 == 0 && (acc == big.Below || acc == big.Above) { panic("bigint underflows float32 (too close to zero)") } - dst.SetFloat32(f32) + dst.SetFloat32(math.Float32bits(f32)) return // done case Float64Kind: dst.T = t @@ -1495,7 +1495,7 @@ func ConvertUntypedBigintTo(dst *TypedValue, bv BigintValue, t Type) { if f64 == 0 && (acc == big.Below || acc == big.Above) { panic("bigint underflows float64 (too close to zero)") } - dst.SetFloat64(f64) + dst.SetFloat64(math.Float64bits(f64)) return // done case BigdecKind: dst.T = t @@ -1610,7 +1610,7 @@ func ConvertUntypedBigdecTo(dst *TypedValue, bv BigdecValue, t Type) { dst.T = Float64Type dst.V = nil f, _ := bd.Float64() - dst.SetFloat64(f) + dst.SetFloat64(math.Float64bits(f)) return case IntKind, Int8Kind, Int16Kind, Int32Kind, Int64Kind: fallthrough @@ -1636,7 +1636,7 @@ func ConvertUntypedBigdecTo(dst *TypedValue, bv BigdecValue, t Type) { if math.IsInf(float64(f32), 0) { panic("cannot convert untyped bigdec to float32 -- too close to +-Inf") } - dst.SetFloat32(f32) + dst.SetFloat32(math.Float32bits(f32)) return case Float64Kind: dst.T = t @@ -1648,7 +1648,7 @@ func ConvertUntypedBigdecTo(dst *TypedValue, bv BigdecValue, t Type) { if math.IsInf(f64, 0) { panic("cannot convert untyped bigdec to float64 -- too close to +-Inf") } - dst.SetFloat64(f64) + dst.SetFloat64(math.Float64bits(f64)) return default: panic(fmt.Sprintf( diff --git a/gnovm/pkg/gnolang/values_conversions_test.go b/gnovm/pkg/gnolang/values_conversions_test.go index 7ffa3e98c71..5538e973bdc 100644 --- a/gnovm/pkg/gnolang/values_conversions_test.go +++ b/gnovm/pkg/gnolang/values_conversions_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/cockroachdb/apd/v3" + "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" "github.com/stretchr/testify/require" ) @@ -24,7 +25,7 @@ func TestConvertUntypedBigdecToFloat(t *testing.T) { ConvertUntypedBigdecTo(dst, bd, typ) - require.Equal(t, float64(0), dst.GetFloat64()) + require.True(t, softfloat.Feq64(dst.GetFloat64(), 0)) } func TestBitShiftingOverflow(t *testing.T) { diff --git a/gnovm/pkg/gnolang/values_string.go b/gnovm/pkg/gnolang/values_string.go index a414f440e4e..fdf0c8f55de 100644 --- a/gnovm/pkg/gnolang/values_string.go +++ b/gnovm/pkg/gnolang/values_string.go @@ -2,6 +2,7 @@ package gnolang import ( "fmt" + "math" "reflect" "strconv" "strings" @@ -339,9 +340,9 @@ func (tv *TypedValue) ProtectedSprint(seen *seenValues, considerDeclaredType boo case Uint64Type: return fmt.Sprintf("%d", tv.GetUint64()) case Float32Type: - return fmt.Sprintf("%v", tv.GetFloat32()) + return fmt.Sprintf("%v", math.Float32frombits(tv.GetFloat32())) case Float64Type: - return fmt.Sprintf("%v", tv.GetFloat64()) + return fmt.Sprintf("%v", math.Float64frombits(tv.GetFloat64())) case UntypedBigintType, BigintType: return tv.V.(BigintValue).V.String() case UntypedBigdecType, BigdecType: @@ -447,9 +448,9 @@ func (tv TypedValue) ProtectedString(seen *seenValues) string { case Uint64Type: vs = fmt.Sprintf("%d", tv.GetUint64()) case Float32Type: - vs = fmt.Sprintf("%v", tv.GetFloat32()) + vs = fmt.Sprintf("%v", math.Float32frombits(tv.GetFloat32())) case Float64Type: - vs = fmt.Sprintf("%v", tv.GetFloat64()) + vs = fmt.Sprintf("%v", math.Float64frombits(tv.GetFloat64())) // Complex types that require recusion protection. default: vs = nilStr diff --git a/gnovm/tests/files/float8.gno b/gnovm/tests/files/float8.gno new file mode 100644 index 00000000000..989d1b4fd61 --- /dev/null +++ b/gnovm/tests/files/float8.gno @@ -0,0 +1,166 @@ +package main + +import "math" + +func main() { + asVars() + asConsts() +} + +func asVars() { + var i8 int8 = 127 + var i16 int16 = 32767 + var i32 int32 = 2147483647 + var i64 int64 = 9223372036854775807 + var i int = 9223372036854775807 + var u8 uint8 = 255 + var u16 uint16 = 65535 + var u32 uint32 = 4294967295 + var u64 uint64 = 18446744073709551615 + var f32Max float32 = math.MaxFloat32 + var f64Max float64 = math.MaxFloat64 + var f64Min float64 = math.SmallestNonzeroFloat64 + var f32Min float32 = math.SmallestNonzeroFloat32 + println(f32Max / 2) + println(f64Max / 2) + println((f32Max - 1) + 1) + println((f64Max - 1) + 1) + println((f32Max / 2) * 2) + println((f64Max / 2) * 2) + println(f32Max - 1) + println(f64Max - 1) + println(f64Min / 2) + println(f32Min / 2) + println(float32(i8)) + println(float64(i8)) + println(float32(i16)) + println(float64(i16)) + println(float32(i32)) + println(float64(i32)) + println(float32(i64)) + println(float64(i64)) + println(float32(i)) + println(float64(i)) + println(float32(u8)) + println(float64(u8)) + println(float32(u16)) + println(float64(u16)) + println(float32(u32)) + println(float64(u32)) + println(float32(u64)) + println(float64(u64)) + println(float32(f32Max)) + println(float64(f32Max)) + println(float64(f64Max)) +} + +func asConsts() { + const i8 int8 = 127 + const i16 int16 = 32767 + const i32 int32 = 2147483647 + const i64 int64 = 9223372036854775807 + const i int = 9223372036854775807 + const u8 uint8 = 255 + const u16 uint16 = 65535 + const u32 uint32 = 4294967295 + const u64 uint64 = 18446744073709551615 + const f32Max float32 = math.MaxFloat32 + const f64Max float64 = math.MaxFloat64 + const f64Min float64 = math.SmallestNonzeroFloat64 + const f32Min float32 = math.SmallestNonzeroFloat32 + println(f32Max / 2) + println(f64Max / 2) + println((f32Max - 1) + 1) + println((f64Max - 1) + 1) + println((f32Max / 2) * 2) + println((f64Max / 2) * 2) + println(f32Max - 1) + println(f64Max - 1) + println(f64Min / 2) + println(f32Min / 2) + println(float32(i8)) + println(float64(i8)) + println(float32(i16)) + println(float64(i16)) + println(float32(i32)) + println(float64(i32)) + println(float32(i64)) + println(float64(i64)) + println(float32(i)) + println(float64(i)) + println(float32(u8)) + println(float64(u8)) + println(float32(u16)) + println(float64(u16)) + println(float32(u32)) + println(float64(u32)) + println(float32(u64)) + println(float64(u64)) + println(float32(f32Max)) + println(float64(f32Max)) + println(float64(f64Max)) +} + +// Output: +// 1.7014117e+38 +// 8.988465674311579e+307 +// 3.4028235e+38 +// 1.7976931348623157e+308 +// 3.4028235e+38 +// 1.7976931348623157e+308 +// 3.4028235e+38 +// 1.7976931348623157e+308 +// 0 +// 0 +// 127 +// 127 +// 32767 +// 32767 +// 2.1474836e+09 +// 2.147483647e+09 +// 9.223372e+18 +// 9.223372036854776e+18 +// 9.223372e+18 +// 9.223372036854776e+18 +// 255 +// 255 +// 65535 +// 65535 +// 4.2949673e+09 +// 4.294967295e+09 +// 1.8446744e+19 +// 1.8446744073709552e+19 +// 3.4028235e+38 +// 3.4028234663852886e+38 +// 1.7976931348623157e+308 +// 1.7014117e+38 +// 8.988465674311579e+307 +// 3.4028235e+38 +// 1.7976931348623157e+308 +// 3.4028235e+38 +// 1.7976931348623157e+308 +// 3.4028235e+38 +// 1.7976931348623157e+308 +// 0 +// 0 +// 127 +// 127 +// 32767 +// 32767 +// 2.1474836e+09 +// 2.147483647e+09 +// 9.223372e+18 +// 9.223372036854776e+18 +// 9.223372e+18 +// 9.223372036854776e+18 +// 255 +// 255 +// 65535 +// 65535 +// 4.2949673e+09 +// 4.294967295e+09 +// 1.8446744e+19 +// 1.8446744073709552e+19 +// 3.4028235e+38 +// 3.4028234663852886e+38 +// 1.7976931348623157e+308 From ee8dcc6f2180fea94c17da38c9bcaf519a45dd7b Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 13 Jan 2025 13:02:43 +0100 Subject: [PATCH 02/13] feat(github-bot): config improvements (#3466) - change the "docs" merge requirements to allow also for a third-party contribution approved by both core+devrel - disallow merging on all prs with the "don't merge" label - don't require additional information on dependabot PRs --- contribs/github-bot/internal/config/config.go | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/contribs/github-bot/internal/config/config.go b/contribs/github-bot/internal/config/config.go index 86acc6cfa83..f80fc86cb11 100644 --- a/contribs/github-bot/internal/config/config.go +++ b/contribs/github-bot/internal/config/config.go @@ -38,17 +38,22 @@ func Config(gh *client.GitHub) ([]AutomaticCheck, []ManualCheck) { { Description: "Changes to 'docs' folder must be reviewed/authored by at least one devrel and one tech-staff", If: c.FileChanged(gh, "^docs/"), - Then: r.Or( - r.And( - r.AuthorInTeam(gh, "devrels"), + Then: r.And( + r.Or( + r.AuthorInTeam(gh, "tech-staff"), r.ReviewByTeamMembers(gh, "tech-staff", 1), ), - r.And( - r.AuthorInTeam(gh, "tech-staff"), + r.Or( + r.AuthorInTeam(gh, "devrels"), r.ReviewByTeamMembers(gh, "devrels", 1), ), ), }, + { + Description: "Must not contain the \"don't merge\" label", + If: c.Label("don't merge"), + Then: r.Never(), + }, } manual := []ManualCheck{ @@ -59,8 +64,11 @@ func Config(gh *client.GitHub) ([]AutomaticCheck, []ManualCheck) { }, { Description: "The pull request description provides enough details", - If: c.Not(c.AuthorInTeam(gh, "core-contributors")), - Teams: Teams{"core-contributors"}, + If: c.And( + c.Not(c.AuthorInTeam(gh, "core-contributors")), + c.Not(c.Author("dependabot[bot]")), + ), + Teams: Teams{"core-contributors"}, }, { Description: "Determine if infra needs to be updated before merging", From cc5cb36fe65fb3d4f2d8cb0df2dc40f686fb55d3 Mon Sep 17 00:00:00 2001 From: Miguel Victoria Villaquiran Date: Mon, 13 Jan 2025 13:31:45 +0100 Subject: [PATCH 03/13] feat(stdlibs): add package crypto/bech32 (#3375) Related to #1475 --------- Co-authored-by: Nathan Toups <612924+n2p5@users.noreply.github.com> --- .../gno.land/p/demo/testutils/crypto_test.gno | 12 + .../r/demo/keystore/keystore_test.gno | 6 +- .../r/demo/microblog/microblog_test.gno | 2 +- .../testdata/assertorigincall.txtar | 2 +- .../testdata/grc20_invalid_address.txtar | 2 +- .../integration/testdata/grc20_registry.txtar | 4 +- .../integration/testdata/grc721_emit.txtar | 10 +- .../pkg/integration/testdata/issue_1786.txtar | 8 +- .../pkg/integration/testdata/prevrealm.txtar | 2 +- .../pkg/integration/testdata/wugnot.txtar | 14 +- gnovm/stdlibs/crypto/bech32/bech32.gno | 445 +++++++++++ gnovm/stdlibs/crypto/bech32/bech32_test.gno | 691 ++++++++++++++++++ gnovm/stdlibs/crypto/bech32/error.gno | 83 +++ gnovm/stdlibs/crypto/bech32/version.gno | 43 ++ gnovm/stdlibs/generated.go | 101 +-- gnovm/stdlibs/std/crypto.gno | 67 ++ gnovm/stdlibs/std/crypto_test.gno | 19 + gnovm/stdlibs/std/native.gno | 15 - gnovm/stdlibs/std/native.go | 21 - gnovm/tests/files/std5.gno | 2 +- gnovm/tests/files/std8.gno | 2 +- gnovm/tests/files/zrealm_natbind0.gno | 2 +- 22 files changed, 1391 insertions(+), 162 deletions(-) create mode 100644 examples/gno.land/p/demo/testutils/crypto_test.gno create mode 100644 gnovm/stdlibs/crypto/bech32/bech32.gno create mode 100644 gnovm/stdlibs/crypto/bech32/bech32_test.gno create mode 100644 gnovm/stdlibs/crypto/bech32/error.gno create mode 100644 gnovm/stdlibs/crypto/bech32/version.gno diff --git a/examples/gno.land/p/demo/testutils/crypto_test.gno b/examples/gno.land/p/demo/testutils/crypto_test.gno new file mode 100644 index 00000000000..ac77b76dadf --- /dev/null +++ b/examples/gno.land/p/demo/testutils/crypto_test.gno @@ -0,0 +1,12 @@ +package testutils + +import ( + "testing" + + "gno.land/p/demo/uassert" +) + +func TestTestAddress(t *testing.T) { + testAddr := TestAddress("author1") + uassert.Equal(t, "g1v96hg6r0wgc47h6lta047h6lta047h6lm33tq6", string(testAddr)) +} diff --git a/examples/gno.land/r/demo/keystore/keystore_test.gno b/examples/gno.land/r/demo/keystore/keystore_test.gno index ffd8e60936f..41597016ea3 100644 --- a/examples/gno.land/r/demo/keystore/keystore_test.gno +++ b/examples/gno.land/r/demo/keystore/keystore_test.gno @@ -11,7 +11,11 @@ import ( ) func TestRender(t *testing.T) { - const ( + // https://github.com/gnolang/gno/pull/3375 changed const -> var : + // For some reason non native functions fails on constants with + // constant overflows (code=2), this does not happens when using a variable + // TODO: check this issue after and if this PR is merged + var ( author1 std.Address = testutils.TestAddress("author1") author2 std.Address = testutils.TestAddress("author2") ) diff --git a/examples/gno.land/r/demo/microblog/microblog_test.gno b/examples/gno.land/r/demo/microblog/microblog_test.gno index a3c8f04ee7f..9ad98d3cbfe 100644 --- a/examples/gno.land/r/demo/microblog/microblog_test.gno +++ b/examples/gno.land/r/demo/microblog/microblog_test.gno @@ -10,7 +10,7 @@ import ( ) func TestMicroblog(t *testing.T) { - const ( + var ( author1 std.Address = testutils.TestAddress("author1") author2 std.Address = testutils.TestAddress("author2") ) diff --git a/gno.land/pkg/integration/testdata/assertorigincall.txtar b/gno.land/pkg/integration/testdata/assertorigincall.txtar index 2c4a27f9d06..2c5da25c0aa 100644 --- a/gno.land/pkg/integration/testdata/assertorigincall.txtar +++ b/gno.land/pkg/integration/testdata/assertorigincall.txtar @@ -43,7 +43,7 @@ gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-w stdout 'OK!' ## 3. MsgCall -> myrlm.C: PASS -gnokey maketx call -pkgpath gno.land/r/myrlm -func C -gas-fee 100000ugnot -gas-wanted 700000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/myrlm -func C -gas-fee 100000ugnot -gas-wanted 1500000 -broadcast -chainid tendermint_test test1 stdout 'OK!' ## 4. MsgCall -> r/foo.A -> myrlm.A: PANIC diff --git a/gno.land/pkg/integration/testdata/grc20_invalid_address.txtar b/gno.land/pkg/integration/testdata/grc20_invalid_address.txtar index d3dcc86725c..0068384903e 100644 --- a/gno.land/pkg/integration/testdata/grc20_invalid_address.txtar +++ b/gno.land/pkg/integration/testdata/grc20_invalid_address.txtar @@ -4,7 +4,7 @@ loadpkg gno.land/r/demo/foo20 gnoland start # execute Faucet -gnokey maketx call -pkgpath gno.land/r/demo/foo20 -func Faucet -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/foo20 -func Faucet -gas-fee 10000000ugnot -gas-wanted 40000000 -broadcast -chainid=tendermint_test test1 stdout 'OK!' # execute Transfer for invalid address diff --git a/gno.land/pkg/integration/testdata/grc20_registry.txtar b/gno.land/pkg/integration/testdata/grc20_registry.txtar index df11e92f8db..4377e10a575 100644 --- a/gno.land/pkg/integration/testdata/grc20_registry.txtar +++ b/gno.land/pkg/integration/testdata/grc20_registry.txtar @@ -6,7 +6,7 @@ loadpkg gno.land/r/registry $WORK/registry gnoland start # we call Transfer with foo20, before it's registered -gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 150000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 1500000 -broadcast -chainid=tendermint_test test1 stdout 'not found' # add foo20, and foo20wrapper @@ -14,7 +14,7 @@ gnokey maketx addpkg -pkgdir $WORK/foo20 -pkgpath gno.land/r/foo20 -gas-fee 1000 gnokey maketx addpkg -pkgdir $WORK/foo20wrapper -pkgpath gno.land/r/foo20wrapper -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1 # we call Transfer with foo20, after it's registered -gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 800000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 8000000 -broadcast -chainid=tendermint_test test1 stdout 'same address, success!' -- registry/registry.gno -- diff --git a/gno.land/pkg/integration/testdata/grc721_emit.txtar b/gno.land/pkg/integration/testdata/grc721_emit.txtar index 6b4770e37c6..45101b74634 100644 --- a/gno.land/pkg/integration/testdata/grc721_emit.txtar +++ b/gno.land/pkg/integration/testdata/grc721_emit.txtar @@ -6,23 +6,23 @@ loadpkg gno.land/r/foo721 $WORK/foo721 gnoland start # Mint -gnokey maketx call -pkgpath gno.land/r/foo721 -func Mint -args g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 -args 1 -gas-fee 1000000ugnot -gas-wanted 3500000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo721 -func Mint -args g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 -args 1 -gas-fee 1000000ugnot -gas-wanted 35000000 -broadcast -chainid=tendermint_test test1 stdout '\[{\"type\":\"Mint\",\"attrs\":\[{\"key\":\"to\",\"value\":\"g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\"},{\"key\":\"tokenId\",\"value\":\"1\"}],\"pkg_path\":\"gno.land\/r\/foo721\",\"func\":\"mint\"}\]' # Approve -gnokey maketx call -pkgpath gno.land/r/foo721 -func Approve -args g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj -args 1 -gas-fee 1000000ugnot -gas-wanted 3500000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo721 -func Approve -args g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj -args 1 -gas-fee 1000000ugnot -gas-wanted 35000000 -broadcast -chainid=tendermint_test test1 stdout '\[{\"type\":\"Approval\",\"attrs\":\[{\"key\":\"owner\",\"value\":\"g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\"},{\"key\":\"to\",\"value\":\"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj\"},{\"key\":\"tokenId\",\"value\":\"1\"}],\"pkg_path\":\"gno.land\/r\/foo721\",\"func\":\"Approve\"}\]' # SetApprovalForAll -gnokey maketx call -pkgpath gno.land/r/foo721 -func SetApprovalForAll -args g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj -args false -gas-fee 1000000ugnot -gas-wanted 3500000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo721 -func SetApprovalForAll -args g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj -args false -gas-fee 1000000ugnot -gas-wanted 35000000 -broadcast -chainid=tendermint_test test1 stdout '\[{\"type\":\"ApprovalForAll\",\"attrs\":\[{\"key\":\"owner\",\"value\":\"g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\"},{\"key\":\"to\",\"value\":\"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj\"},{\"key\":\"approved\",\"value\":\"false\"}],\"pkg_path\":\"gno\.land/r/foo721\",\"func\":\"setApprovalForAll\"}\]' # TransferFrom -gnokey maketx call -pkgpath gno.land/r/foo721 -func TransferFrom -args g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 -args g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj -args 1 -gas-fee 1000000ugnot -gas-wanted 3500000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo721 -func TransferFrom -args g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 -args g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj -args 1 -gas-fee 1000000ugnot -gas-wanted 35000000 -broadcast -chainid=tendermint_test test1 stdout '\[{\"type\":\"Transfer\",\"attrs\":\[{\"key\":\"from\",\"value\":\"g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\"},{\"key\":\"to\",\"value\":\"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj\"},{\"key\":\"tokenId\",\"value\":\"1\"}],\"pkg_path\":\"gno\.land/r/foo721\",\"func\":\"transfer\"}\]' # Burn -gnokey maketx call -pkgpath gno.land/r/foo721 -func Burn -args 1 -gas-fee 1000000ugnot -gas-wanted 3500000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo721 -func Burn -args 1 -gas-fee 1000000ugnot -gas-wanted 35000000 -broadcast -chainid=tendermint_test test1 stdout '\[{\"type\":\"Burn\",\"attrs\":\[{\"key\":\"from\",\"value\":\"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj\"},{\"key\":\"tokenId\",\"value\":\"1\"}],\"pkg_path\":\"gno\.land/r/foo721\",\"func\":\"Burn\"}\]' diff --git a/gno.land/pkg/integration/testdata/issue_1786.txtar b/gno.land/pkg/integration/testdata/issue_1786.txtar index 0e66a882a6d..1cbaf2c6643 100644 --- a/gno.land/pkg/integration/testdata/issue_1786.txtar +++ b/gno.land/pkg/integration/testdata/issue_1786.txtar @@ -9,20 +9,20 @@ gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/proxywugnot -gas-fee stdout OK! # approve wugnot to `proxywugnot ≈ g1fndyg0we60rdfchyy5dwxzkfmhl5u34j932rg3` -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Approve -args "g1fndyg0we60rdfchyy5dwxzkfmhl5u34j932rg3" -args 10000 -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Approve -args "g1fndyg0we60rdfchyy5dwxzkfmhl5u34j932rg3" -args 10000 -gas-fee 1000000ugnot -gas-wanted 40000000 -broadcast -chainid=tendermint_test test1 stdout OK! # send 10000ugnot to `proxywugnot` to wrap it -gnokey maketx call -pkgpath gno.land/r/demo/proxywugnot --send "10000ugnot" -func ProxyWrap -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/proxywugnot --send "10000ugnot" -func ProxyWrap -gas-fee 1000000ugnot -gas-wanted 40000000 -broadcast -chainid=tendermint_test test1 stdout OK! # check user's wugnot balance -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func BalanceOf -args "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func BalanceOf -args "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" -gas-fee 1000000ugnot -gas-wanted 40000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '10000 uint64' # unwrap 500 wugnot -gnokey maketx call -pkgpath gno.land/r/demo/proxywugnot -func ProxyUnwrap -args 500 -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/proxywugnot -func ProxyUnwrap -args 500 -gas-fee 1000000ugnot -gas-wanted 40000000 -broadcast -chainid=tendermint_test test1 # XXX without patching anything it will panic # panic msg: insufficient coins error diff --git a/gno.land/pkg/integration/testdata/prevrealm.txtar b/gno.land/pkg/integration/testdata/prevrealm.txtar index 4bbe16c3205..31f0ca336ba 100644 --- a/gno.land/pkg/integration/testdata/prevrealm.txtar +++ b/gno.land/pkg/integration/testdata/prevrealm.txtar @@ -34,7 +34,7 @@ env RFOO_USER_ADDR=g1evezrh92xaucffmtgsaa3rvmz5s8kedffsg469 # Test cases ## 1. MsgCall -> myrlm.A: user address -gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 700000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 1500000 -broadcast -chainid tendermint_test test1 stdout ${test1_user_addr} ## 2. MsgCall -> myrealm.B -> myrlm.A: user address diff --git a/gno.land/pkg/integration/testdata/wugnot.txtar b/gno.land/pkg/integration/testdata/wugnot.txtar index 5fa7dab2945..5a63e0148e2 100644 --- a/gno.land/pkg/integration/testdata/wugnot.txtar +++ b/gno.land/pkg/integration/testdata/wugnot.txtar @@ -2,14 +2,14 @@ loadpkg gno.land/r/demo/wugnot gnoland start -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 5000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 10000000ugnot -gas-wanted 5000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '# wrapped GNOT \(\$wugnot\)' stdout 'Decimals..: 0' stdout 'Total supply..: 0' stdout 'Known accounts..: 0' stdout 'OK!' -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Deposit -send 12345678ugnot -gas-fee 1000000ugnot -gas-wanted 5000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Deposit -send 12345678ugnot -gas-fee 1000000ugnot -gas-wanted 50000000 -broadcast -chainid=tendermint_test test1 stdout 'OK!' gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 5000000 -args '' -broadcast -chainid=tendermint_test test1 @@ -18,7 +18,7 @@ stdout 'Known accounts..: 1' stdout 'OK!' # XXX: use test2 instead (depends on https://github.com/gnolang/gno/issues/1269#issuecomment-1806386069) -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Deposit -send 12345678ugnot -gas-fee 1000000ugnot -gas-wanted 5000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Deposit -send 12345678ugnot -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test test1 stdout 'OK!' gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 5000000 -args '' -broadcast -chainid=tendermint_test test1 @@ -27,19 +27,19 @@ stdout 'Known accounts..: 1' # should be 2 once we can use test2 stdout 'OK!' # XXX: replace hardcoded address with test3 -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Transfer -gas-fee 1000000ugnot -gas-wanted 5000000 -args 'g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq' -args '10000000' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Transfer -gas-fee 1000000ugnot -gas-wanted 100000000 -args 'g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq' -args '10000000' -broadcast -chainid=tendermint_test test1 stdout 'OK!' -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 5000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 50000000 -args '' -broadcast -chainid=tendermint_test test1 stdout 'Total supply..: 24691356' stdout 'Known accounts..: 2' # should be 3 once we can use test2 stdout 'OK!' # XXX: use test3 instead (depends on https://github.com/gnolang/gno/issues/1269#issuecomment-1806386069) -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Withdraw -args 10000000 -gas-fee 1000000ugnot -gas-wanted 5000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Withdraw -args 10000000 -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test test1 stdout 'OK!' -gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 5000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 100000000 -args '' -broadcast -chainid=tendermint_test test1 stdout 'Total supply..: 14691356' stdout 'Known accounts..: 2' # should be 3 once we can use test2 stdout 'OK!' diff --git a/gnovm/stdlibs/crypto/bech32/bech32.gno b/gnovm/stdlibs/crypto/bech32/bech32.gno new file mode 100644 index 00000000000..92994b28813 --- /dev/null +++ b/gnovm/stdlibs/crypto/bech32/bech32.gno @@ -0,0 +1,445 @@ +// Copyright (c) 2017 The btcsuite developers +// Copyright (c) 2019 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package bech32 + +import ( + "strings" +) + +// charset is the set of characters used in the data section of bech32 strings. +// Note that this is ordered, such that for a given charset[i], i is the binary +// value of the character. +const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" + +// gen encodes the generator polynomial for the bech32 BCH checksum. +var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3} + +// toBytes converts each character in the string 'chars' to the value of the +// index of the corresponding character in 'charset'. +func toBytes(chars string) ([]byte, error) { + decoded := make([]byte, 0, len(chars)) + for i := 0; i < len(chars); i++ { + index := strings.IndexByte(charset, chars[i]) + if index < 0 { + return nil, ErrNonCharsetChar(chars[i]) + } + decoded = append(decoded, byte(index)) + } + return decoded, nil +} + +// bech32Polymod calculates the BCH checksum for a given hrp, values and +// checksum data. Checksum is optional, and if nil a 0 checksum is assumed. +// +// Values and checksum (if provided) MUST be encoded as 5 bits per element (base +// 32), otherwise the results are undefined. +// +// For more details on the polymod calculation, please refer to BIP 173. +func bech32Polymod(hrp string, values, checksum []byte) int { + chk := 1 + + // Account for the high bits of the HRP in the checksum. + for i := 0; i < len(hrp); i++ { + b := chk >> 25 + hiBits := int(hrp[i]) >> 5 + chk = (chk&0x1ffffff)<<5 ^ hiBits + for i := 0; i < 5; i++ { + if (b>>uint(i))&1 == 1 { + chk ^= gen[i] + } + } + } + + // Account for the separator (0) between high and low bits of the HRP. + // x^0 == x, so we eliminate the redundant xor used in the other rounds. + b := chk >> 25 + chk = (chk & 0x1ffffff) << 5 + for i := 0; i < 5; i++ { + if (b>>uint(i))&1 == 1 { + chk ^= gen[i] + } + } + + // Account for the low bits of the HRP. + for i := 0; i < len(hrp); i++ { + b := chk >> 25 + loBits := int(hrp[i]) & 31 + chk = (chk&0x1ffffff)<<5 ^ loBits + for i := 0; i < 5; i++ { + if (b>>uint(i))&1 == 1 { + chk ^= gen[i] + } + } + } + + // Account for the values. + for _, v := range values { + b := chk >> 25 + chk = (chk&0x1ffffff)<<5 ^ int(v) + for i := 0; i < 5; i++ { + if (b>>uint(i))&1 == 1 { + chk ^= gen[i] + } + } + } + + if checksum == nil { + // A nil checksum is used during encoding, so assume all bytes are zero. + // x^0 == x, so we eliminate the redundant xor used in the other rounds. + for v := 0; v < 6; v++ { + b := chk >> 25 + chk = (chk & 0x1ffffff) << 5 + for i := 0; i < 5; i++ { + if (b>>uint(i))&1 == 1 { + chk ^= gen[i] + } + } + } + } else { + // Checksum is provided during decoding, so use it. + for _, v := range checksum { + b := chk >> 25 + chk = (chk&0x1ffffff)<<5 ^ int(v) + for i := 0; i < 5; i++ { + if (b>>uint(i))&1 == 1 { + chk ^= gen[i] + } + } + } + } + + return chk +} + +// writeBech32Checksum calculates the checksum data expected for a string that +// will have the given hrp and payload data and writes it to the provided string +// builder. +// +// The payload data MUST be encoded as a base 32 (5 bits per element) byte slice +// and the hrp MUST only use the allowed character set (ascii chars between 33 +// and 126), otherwise the results are undefined. +// +// For more details on the checksum calculation, please refer to BIP 173. +func writeBech32Checksum(hrp string, data []byte, bldr *strings.Builder, + version Version) { + + bech32Const := int(VersionToConsts[version]) + polymod := bech32Polymod(hrp, data, nil) ^ bech32Const + for i := 0; i < 6; i++ { + b := byte((polymod >> uint(5*(5-i))) & 31) + + // This can't fail, given we explicitly cap the previous b byte by the + // first 31 bits. + c := charset[b] + bldr.WriteByte(c) + } +} + +// bech32VerifyChecksum verifies whether the bech32 string specified by the +// provided hrp and payload data (encoded as 5 bits per element byte slice) has +// the correct checksum suffix. The version of bech32 used (bech32 OG, or +// bech32m) is also returned to allow the caller to perform proper address +// validation (segwitv0 should use bech32, v1+ should use bech32m). +// +// Data MUST have more than 6 elements, otherwise this function panics. +// +// For more details on the checksum verification, please refer to BIP 173. +func bech32VerifyChecksum(hrp string, data []byte) (Version, bool) { + checksum := data[len(data)-6:] + values := data[:len(data)-6] + polymod := bech32Polymod(hrp, values, checksum) + + // Before BIP-350, we'd always check this against a static constant of + // 1 to know if the checksum was computed properly. As we want to + // generically support decoding for bech32m as well as bech32, we'll + // look up the returned value and compare it to the set of defined + // constants. + bech32Version, ok := ConstsToVersion[ChecksumConst(polymod)] + if ok { + return bech32Version, true + } + + return VersionUnknown, false +} + +// DecodeNoLimitWithVersion is a bech32 checksum version aware arbitrary string +// length decoder. This function will return the version of the decoded +// checksum constant so higher level validation can be performed to ensure the +// correct version of bech32 was used when encoding. +// +// Note that the returned data is 5-bit (base32) encoded and the human-readable +// part will be lowercase. +func DecodeNoLimitWithVersion(bech string) (string, []byte, Version, error) { + // The minimum allowed size of a bech32 string is 8 characters, since it + // needs a non-empty HRP, a separator, and a 6 character checksum. + if len(bech) < 8 { + return "", nil, VersionUnknown, ErrInvalidLength(len(bech)) + } + + // Only ASCII characters between 33 and 126 are allowed. + var hasLower, hasUpper bool + for i := 0; i < len(bech); i++ { + if bech[i] < 33 || bech[i] > 126 { + return "", nil, VersionUnknown, ErrInvalidCharacter(bech[i]) + } + + // The characters must be either all lowercase or all uppercase. Testing + // directly with ascii codes is safe here, given the previous test. + hasLower = hasLower || (bech[i] >= 97 && bech[i] <= 122) + hasUpper = hasUpper || (bech[i] >= 65 && bech[i] <= 90) + if hasLower && hasUpper { + return "", nil, VersionUnknown, ErrMixedCase{} + } + } + + // Bech32 standard uses only the lowercase for of strings for checksum + // calculation. + if hasUpper { + bech = strings.ToLower(bech) + } + + // The string is invalid if the last '1' is non-existent, it is the + // first character of the string (no human-readable part) or one of the + // last 6 characters of the string (since checksum cannot contain '1'). + one := strings.LastIndexByte(bech, '1') + if one < 1 || one+7 > len(bech) { + return "", nil, VersionUnknown, ErrInvalidSeparatorIndex(one) + } + + // The human-readable part is everything before the last '1'. + hrp := bech[:one] + data := bech[one+1:] + + // Each character corresponds to the byte with value of the index in + // 'charset'. + decoded, err := toBytes(data) + if err != nil { + return "", nil, VersionUnknown, err + } + + // Verify if the checksum (stored inside decoded[:]) is valid, given the + // previously decoded hrp. + bech32Version, ok := bech32VerifyChecksum(hrp, decoded) + if !ok { + // Invalid checksum. Calculate what it should have been, so that the + // error contains this information. + + // Extract the payload bytes and actual checksum in the string. + actual := bech[len(bech)-6:] + payload := decoded[:len(decoded)-6] + + // Calculate the expected checksum, given the hrp and payload + // data. We'll actually compute _both_ possibly valid checksum + // to further aide in debugging. + var expectedBldr strings.Builder + expectedBldr.Grow(6) + writeBech32Checksum(hrp, payload, &expectedBldr, Version0) + expectedVersion0 := expectedBldr.String() + + var b strings.Builder + b.Grow(6) + writeBech32Checksum(hrp, payload, &expectedBldr, VersionM) + expectedVersionM := expectedBldr.String() + + err = ErrInvalidChecksum{ + Expected: expectedVersion0, + ExpectedM: expectedVersionM, + Actual: actual, + } + return "", nil, VersionUnknown, err + } + + // We exclude the last 6 bytes, which is the checksum. + return hrp, decoded[:len(decoded)-6], bech32Version, nil +} + +// DecodeNoLimit decodes a bech32 encoded string, returning the human-readable +// part and the data part excluding the checksum. This function does NOT +// validate against the BIP-173 maximum length allowed for bech32 strings and +// is meant for use in custom applications (such as lightning network payment +// requests), NOT on-chain addresses. +// +// Note that the returned data is 5-bit (base32) encoded and the human-readable +// part will be lowercase. +func DecodeNoLimit(bech string) (string, []byte, error) { + hrp, data, _, err := DecodeNoLimitWithVersion(bech) + return hrp, data, err +} + +// Decode decodes a bech32 encoded string, returning the human-readable part and +// the data part excluding the checksum. +// +// Note that the returned data is 5-bit (base32) encoded and the human-readable +// part will be lowercase. +func Decode(bech string) (string, []byte, error) { + // The maximum allowed length for a bech32 string is 90. + if len(bech) > 90 { + return "", nil, ErrInvalidLength(len(bech)) + } + + hrp, data, _, err := DecodeNoLimitWithVersion(bech) + return hrp, data, err +} + +// DecodeGeneric is identical to the existing Decode method, but will also +// return bech32 version that matches the decoded checksum. This method should +// be used when decoding segwit addresses, as it enables additional +// verification to ensure the proper checksum is used. +func DecodeGeneric(bech string) (string, []byte, Version, error) { + // The maximum allowed length for a bech32 string is 90. + if len(bech) > 90 { + return "", nil, VersionUnknown, ErrInvalidLength(len(bech)) + } + + return DecodeNoLimitWithVersion(bech) +} + +// encodeGeneric is the base bech32 encoding function that is aware of the +// existence of the checksum versions. This method is private, as the Encode +// and EncodeM methods are intended to be used instead. +func encodeGeneric(hrp string, data []byte, + version Version) (string, error) { + + // The resulting bech32 string is the concatenation of the lowercase + // hrp, the separator 1, data and the 6-byte checksum. + hrp = strings.ToLower(hrp) + var bldr strings.Builder + bldr.Grow(len(hrp) + 1 + len(data) + 6) + bldr.WriteString(hrp) + bldr.WriteString("1") + + // Write the data part, using the bech32 charset. + for _, b := range data { + if int(b) >= len(charset) { + return "", ErrInvalidDataByte(b) + } + bldr.WriteByte(charset[b]) + } + + // Calculate and write the checksum of the data. + writeBech32Checksum(hrp, data, &bldr, version) + + return bldr.String(), nil +} + +// Encode encodes a byte slice into a bech32 string with the given +// human-readable part (HRP). The HRP will be converted to lowercase if needed +// since mixed cased encodings are not permitted and lowercase is used for +// checksum purposes. Note that the bytes must each encode 5 bits (base32). +func Encode(hrp string, data []byte) (string, error) { + return encodeGeneric(hrp, data, Version0) +} + +// EncodeM is the exactly same as the Encode method, but it uses the new +// bech32m constant instead of the original one. It should be used whenever one +// attempts to encode a segwit address of v1 and beyond. +func EncodeM(hrp string, data []byte) (string, error) { + return encodeGeneric(hrp, data, VersionM) +} + +// ConvertBits converts a byte slice where each byte is encoding fromBits bits, +// to a byte slice where each byte is encoding toBits bits. +func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error) { + if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 { + return nil, ErrInvalidBitGroups{} + } + + // Determine the maximum size the resulting array can have after base + // conversion, so that we can size it a single time. This might be off + // by a byte depending on whether padding is used or not and if the input + // data is a multiple of both fromBits and toBits, but we ignore that and + // just size it to the maximum possible. + maxSize := len(data)*int(fromBits)/int(toBits) + 1 + + // The final bytes, each byte encoding toBits bits. + regrouped := make([]byte, 0, maxSize) + + // Keep track of the next byte we create and how many bits we have + // added to it out of the toBits goal. + nextByte := byte(0) + filledBits := uint8(0) + + for _, b := range data { + + // Discard unused bits. + b <<= 8 - fromBits + + // How many bits remaining to extract from the input data. + remFromBits := fromBits + for remFromBits > 0 { + // How many bits remaining to be added to the next byte. + remToBits := toBits - filledBits + + // The number of bytes to next extract is the minimum of + // remFromBits and remToBits. + toExtract := remFromBits + if remToBits < toExtract { + toExtract = remToBits + } + + // Add the next bits to nextByte, shifting the already + // added bits to the left. + nextByte = (nextByte << toExtract) | (b >> (8 - toExtract)) + + // Discard the bits we just extracted and get ready for + // next iteration. + b <<= toExtract + remFromBits -= toExtract + filledBits += toExtract + + // If the nextByte is completely filled, we add it to + // our regrouped bytes and start on the next byte. + if filledBits == toBits { + regrouped = append(regrouped, nextByte) + filledBits = 0 + nextByte = 0 + } + } + } + + // We pad any unfinished group if specified. + if pad && filledBits > 0 { + nextByte <<= toBits - filledBits + regrouped = append(regrouped, nextByte) + filledBits = 0 + nextByte = 0 + } + + // Any incomplete group must be <= 4 bits, and all zeroes. + if filledBits > 0 && (filledBits > 4 || nextByte != 0) { + return nil, ErrInvalidIncompleteGroup{} + } + + return regrouped, nil +} + +// EncodeFromBase256 converts a base256-encoded byte slice into a base32-encoded +// byte slice and then encodes it into a bech32 string with the given +// human-readable part (HRP). The HRP will be converted to lowercase if needed +// since mixed cased encodings are not permitted and lowercase is used for +// checksum purposes. +func EncodeFromBase256(hrp string, data []byte) (string, error) { + converted, err := ConvertBits(data, 8, 5, true) + if err != nil { + return "", err + } + return Encode(hrp, converted) +} + +// DecodeToBase256 decodes a bech32-encoded string into its associated +// human-readable part (HRP) and base32-encoded data, converts that data to a +// base256-encoded byte slice and returns it along with the lowercase HRP. +func DecodeToBase256(bech string) (string, []byte, error) { + hrp, data, err := Decode(bech) + if err != nil { + return "", nil, err + } + converted, err := ConvertBits(data, 5, 8, false) + if err != nil { + return "", nil, err + } + return hrp, converted, nil +} diff --git a/gnovm/stdlibs/crypto/bech32/bech32_test.gno b/gnovm/stdlibs/crypto/bech32/bech32_test.gno new file mode 100644 index 00000000000..3f637c40345 --- /dev/null +++ b/gnovm/stdlibs/crypto/bech32/bech32_test.gno @@ -0,0 +1,691 @@ +// Copyright (c) 2017-2020 The btcsuite developers +// Copyright (c) 2019 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package bech32 + +import ( + "bytes" + "encoding/hex" + "fmt" + "strings" + "testing" +) + +// TestBech32 tests whether decoding and re-encoding the valid BIP-173 test +// vectors works and if decoding invalid test vectors fails for the correct +// reason. +func TestBech32(t *testing.T) { + tests := []struct { + str string + expectedError error + }{ + {"A12UEL5L", nil}, + {"a12uel5l", nil}, + {"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", nil}, + {"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", nil}, + {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", nil}, + {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", nil}, + {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", ErrInvalidChecksum{"2y9e3w", "2y9e3wlc445v", "2y9e2w"}}, // invalid checksum + {"s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", ErrInvalidCharacter(' ')}, // invalid character (space) in hrp + {"spl\x7Ft1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", ErrInvalidCharacter(127)}, // invalid character (DEL) in hrp + {"split1cheo2y9e2w", ErrNonCharsetChar('o')}, // invalid character (o) in data part + {"split1a2y9w", ErrInvalidSeparatorIndex(5)}, // too short data part + {"1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", ErrInvalidSeparatorIndex(0)}, // empty hrp + {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", ErrInvalidLength(91)}, // too long + + // Additional test vectors used in bitcoin core + {" 1nwldj5", ErrInvalidCharacter(' ')}, + {"\x7f" + "1axkwrx", ErrInvalidCharacter(0x7f)}, + {"\x801eym55h", ErrInvalidCharacter(0x80)}, + {"an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx", ErrInvalidLength(91)}, + {"pzry9x0s0muk", ErrInvalidSeparatorIndex(-1)}, + {"1pzry9x0s0muk", ErrInvalidSeparatorIndex(0)}, + {"x1b4n0q5v", ErrNonCharsetChar(98)}, + {"li1dgmt3", ErrInvalidSeparatorIndex(2)}, + {"de1lg7wt\xff", ErrInvalidCharacter(0xff)}, + {"A1G7SGD8", ErrInvalidChecksum{"2uel5l", "2uel5llqfn3a", "g7sgd8"}}, + {"10a06t8", ErrInvalidLength(7)}, + {"1qzzfhee", ErrInvalidSeparatorIndex(0)}, + {"a12UEL5L", ErrMixedCase{}}, + {"A12uEL5L", ErrMixedCase{}}, + } + + for i, test := range tests { + str := test.str + hrp, decoded, err := Decode(str) + if test.expectedError != err { + t.Errorf("%d: expected decoding error %v "+ + "instead got %v", i, test.expectedError, err) + continue + } + + if err != nil { + // End test case here if a decoding error was expected. + continue + } + + // Check that it encodes to the same string + encoded, err := Encode(hrp, decoded) + if err != nil { + t.Errorf("encoding failed: %v", err) + } + + if encoded != strings.ToLower(str) { + t.Errorf("expected data to encode to %v, but got %v", + str, encoded) + } + + // Flip a bit in the string an make sure it is caught. + pos := strings.LastIndexAny(str, "1") + flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:] + _, _, err = Decode(flipped) + if err == nil { + t.Error("expected decoding to fail") + } + } +} + +// TestBech32M tests that the following set of strings, based on the test +// vectors in BIP-350 are either valid or invalid using the new bech32m +// checksum algo. Some of these strings are similar to the set of above test +// vectors, but end up with different checksums. +func TestBech32M(t *testing.T) { + tests := []struct { + str string + expectedError error + }{ + {"A1LQFN3A", nil}, + {"a1lqfn3a", nil}, + {"an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", nil}, + {"abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx", nil}, + {"11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", nil}, + {"split1checkupstagehandshakeupstreamerranterredcaperredlc445v", nil}, + {"?1v759aa", nil}, + + // Additional test vectors used in bitcoin core + {"\x201xj0phk", ErrInvalidCharacter('\x20')}, + {"\x7f1g6xzxy", ErrInvalidCharacter('\x7f')}, + {"\x801vctc34", ErrInvalidCharacter('\x80')}, + {"an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4", ErrInvalidLength(91)}, + {"qyrz8wqd2c9m", ErrInvalidSeparatorIndex(-1)}, + {"1qyrz8wqd2c9m", ErrInvalidSeparatorIndex(0)}, + {"y1b0jsk6g", ErrNonCharsetChar(98)}, + {"lt1igcx5c0", ErrNonCharsetChar(105)}, + {"in1muywd", ErrInvalidSeparatorIndex(2)}, + {"mm1crxm3i", ErrNonCharsetChar(105)}, + {"au1s5cgom", ErrNonCharsetChar(111)}, + {"M1VUXWEZ", ErrInvalidChecksum{"mzl49c", "mzl49cw70eq6", "vuxwez"}}, + {"16plkw9", ErrInvalidLength(7)}, + {"1p2gdwpf", ErrInvalidSeparatorIndex(0)}, + + {" 1nwldj5", ErrInvalidCharacter(' ')}, + {"\x7f" + "1axkwrx", ErrInvalidCharacter(0x7f)}, + {"\x801eym55h", ErrInvalidCharacter(0x80)}, + } + + for i, test := range tests { + str := test.str + hrp, decoded, err := Decode(str) + if test.expectedError != err { + t.Errorf("%d: (%v) expected decoding error %v "+ + "instead got %v", i, str, test.expectedError, + err) + continue + } + + if err != nil { + // End test case here if a decoding error was expected. + continue + } + + // Check that it encodes to the same string, using bech32 m. + encoded, err := EncodeM(hrp, decoded) + if err != nil { + t.Errorf("encoding failed: %v", err) + } + + if encoded != strings.ToLower(str) { + t.Errorf("expected data to encode to %v, but got %v", + str, encoded) + } + + // Flip a bit in the string an make sure it is caught. + pos := strings.LastIndexAny(str, "1") + flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:] + _, _, err = Decode(flipped) + if err == nil { + t.Error("expected decoding to fail") + } + } +} + +// TestBech32DecodeGeneric tests that given a bech32 string, or a bech32m +// string, the proper checksum version is returned so that callers can perform +// segwit addr validation. +func TestBech32DecodeGeneric(t *testing.T) { + tests := []struct { + str string + version Version + }{ + {"A1LQFN3A", VersionM}, + {"a1lqfn3a", VersionM}, + {"an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", VersionM}, + {"abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx", VersionM}, + {"11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", VersionM}, + {"split1checkupstagehandshakeupstreamerranterredcaperredlc445v", VersionM}, + {"?1v759aa", VersionM}, + + {"A12UEL5L", Version0}, + {"a12uel5l", Version0}, + {"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", Version0}, + {"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", Version0}, + {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", Version0}, + {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", Version0}, + + {"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", Version0}, + {"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", Version0}, + {"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y", VersionM}, + {"BC1SW50QGDZ25J", VersionM}, + {"bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs", VersionM}, + {"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", Version0}, + {"tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c", VersionM}, + {"bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0", VersionM}, + } + for i, test := range tests { + _, _, version, err := DecodeGeneric(test.str) + if err != nil { + t.Errorf("%d: (%v) unexpected error during "+ + "decoding: %v", i, test.str, err) + continue + } + + if version != test.version { + t.Errorf("(%v): invalid version: expected %v, got %v", + test.str, test.version, version) + } + } +} + +// TestMixedCaseEncode ensures mixed case HRPs are converted to lowercase as +// expected when encoding and that decoding the produced encoding when converted +// to all uppercase produces the lowercase HRP and original data. +func TestMixedCaseEncode(t *testing.T) { + tests := []struct { + name string + hrp string + data string + encoded string + }{{ + name: "all uppercase HRP with no data", + hrp: "A", + data: "", + encoded: "a12uel5l", + }, { + name: "all uppercase HRP with data", + hrp: "UPPERCASE", + data: "787878", + encoded: "uppercase10pu8sss7kmp", + }, { + name: "mixed case HRP even offsets uppercase", + hrp: "AbCdEf", + data: "00443214c74254b635cf84653a56d7c675be77df", + encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", + }, { + name: "mixed case HRP odd offsets uppercase ", + hrp: "aBcDeF", + data: "00443214c74254b635cf84653a56d7c675be77df", + encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", + }, { + name: "all lowercase HRP", + hrp: "abcdef", + data: "00443214c74254b635cf84653a56d7c675be77df", + encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", + }} + + for _, test := range tests { + // Convert the text hex to bytes, convert those bytes from base256 to + // base32, then ensure the encoded result with the HRP provided in the + // test data is as expected. + data, err := hex.DecodeString(test.data) + if err != nil { + t.Errorf("%q: invalid hex %q: %v", test.name, test.data, err) + continue + } + convertedData, err := ConvertBits(data, 8, 5, true) + if err != nil { + t.Errorf("%q: unexpected convert bits error: %v", test.name, + err) + continue + } + gotEncoded, err := Encode(test.hrp, convertedData) + if err != nil { + t.Errorf("%q: unexpected encode error: %v", test.name, err) + continue + } + if gotEncoded != test.encoded { + t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name, + gotEncoded, test.encoded) + continue + } + + // Ensure the decoding the expected lowercase encoding converted to all + // uppercase produces the lowercase HRP and original data. + gotHRP, gotData, err := Decode(strings.ToUpper(test.encoded)) + if err != nil { + t.Errorf("%q: unexpected decode error: %v", test.name, err) + continue + } + wantHRP := strings.ToLower(test.hrp) + if gotHRP != wantHRP { + t.Errorf("%q: mismatched decoded HRP -- got %q, want %q", test.name, + gotHRP, wantHRP) + continue + } + convertedGotData, err := ConvertBits(gotData, 5, 8, false) + if err != nil { + t.Errorf("%q: unexpected convert bits error: %v", test.name, + err) + continue + } + if !bytes.Equal(convertedGotData, data) { + t.Errorf("%q: mismatched data -- got %x, want %x", test.name, + convertedGotData, data) + continue + } + } +} + +// TestCanDecodeUnlimitedBech32 tests whether decoding a large bech32 string works +// when using the DecodeNoLimit version +func TestCanDecodeUnlimitedBech32(t *testing.T) { + input := "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq5kx0yd" + + // Sanity check that an input of this length errors on regular Decode() + _, _, err := Decode(input) + if err == nil { + t.Fatalf("Test vector not appropriate") + } + + // Try and decode it. + hrp, data, err := DecodeNoLimit(input) + if err != nil { + t.Fatalf("Expected decoding of large string to work. Got error: %v", err) + } + + // Verify data for correctness. + if hrp != "1" { + t.Fatalf("Unexpected hrp: %v", hrp) + } + decodedHex := fmt.Sprintf("%x", data) + expected := "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000" + if decodedHex != expected { + t.Fatalf("Unexpected decoded data: %s", decodedHex) + } +} + +// TestBech32Base256 ensures decoding and encoding various bech32, HRPs, and +// data produces the expected results when using EncodeFromBase256 and +// DecodeToBase256. It includes tests for proper handling of case +// manipulations. +func TestBech32Base256(t *testing.T) { + tests := []struct { + name string // test name + encoded string // bech32 string to decode + hrp string // expected human-readable part + data string // expected hex-encoded data + err error // expected error + }{{ + name: "all uppercase, no data", + encoded: "A12UEL5L", + hrp: "a", + data: "", + }, { + name: "long hrp with separator and excluded chars, no data", + encoded: "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", + hrp: "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio", + data: "", + }, { + name: "6 char hrp with data with leading zero", + encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", + hrp: "abcdef", + data: "00443214c74254b635cf84653a56d7c675be77df", + }, { + name: "hrp same as separator and max length encoded string", + encoded: "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", + hrp: "1", + data: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, { + name: "5 char hrp with data chosen to produce human-readable data part", + encoded: "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", + hrp: "split", + data: "c5f38b70305f519bf66d85fb6cf03058f3dde463ecd7918f2dc743918f2d", + }, { + name: "same as previous but with checksum invalidated", + encoded: "split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", + err: ErrInvalidChecksum{"2y9e3w", "2y9e3wlc445v", "2y9e2w"}, + }, { + name: "hrp with invalid character (space)", + encoded: "s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", + err: ErrInvalidCharacter(' '), + }, { + name: "hrp with invalid character (DEL)", + encoded: "spl\x7ft1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", + err: ErrInvalidCharacter(127), + }, { + name: "data part with invalid character (o)", + encoded: "split1cheo2y9e2w", + err: ErrNonCharsetChar('o'), + }, { + name: "data part too short", + encoded: "split1a2y9w", + err: ErrInvalidSeparatorIndex(5), + }, { + name: "empty hrp", + encoded: "1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", + err: ErrInvalidSeparatorIndex(0), + }, { + name: "no separator", + encoded: "pzry9x0s0muk", + err: ErrInvalidSeparatorIndex(-1), + }, { + name: "too long by one char", + encoded: "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", + err: ErrInvalidLength(91), + }, { + name: "invalid due to mixed case in hrp", + encoded: "aBcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", + err: ErrMixedCase{}, + }, { + name: "invalid due to mixed case in data part", + encoded: "abcdef1Qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", + err: ErrMixedCase{}, + }} + + for _, test := range tests { + // Ensure the decode either produces an error or not as expected. + str := test.encoded + gotHRP, gotData, err := DecodeToBase256(str) + if test.err != err { + t.Errorf("%q: unexpected decode error -- got %v, want %v", + test.name, err, test.err) + continue + } + if err != nil { + // End test case here if a decoding error was expected. + continue + } + + // Ensure the expected HRP and original data are as expected. + if gotHRP != test.hrp { + t.Errorf("%q: mismatched decoded HRP -- got %q, want %q", test.name, + gotHRP, test.hrp) + continue + } + data, err := hex.DecodeString(test.data) + if err != nil { + t.Errorf("%q: invalid hex %q: %v", test.name, test.data, err) + continue + } + if !bytes.Equal(gotData, data) { + t.Errorf("%q: mismatched data -- got %x, want %x", test.name, + gotData, data) + continue + } + + // Encode the same data with the HRP converted to all uppercase and + // ensure the result is the lowercase version of the original encoded + // bech32 string. + gotEncoded, err := EncodeFromBase256(strings.ToUpper(test.hrp), data) + if err != nil { + t.Errorf("%q: unexpected uppercase HRP encode error: %v", test.name, + err) + } + wantEncoded := strings.ToLower(str) + if gotEncoded != wantEncoded { + t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name, + gotEncoded, wantEncoded) + } + + // Encode the same data with the HRP converted to all lowercase and + // ensure the result is the lowercase version of the original encoded + // bech32 string. + gotEncoded, err = EncodeFromBase256(strings.ToLower(test.hrp), data) + if err != nil { + t.Errorf("%q: unexpected lowercase HRP encode error: %v", test.name, + err) + } + if gotEncoded != wantEncoded { + t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name, + gotEncoded, wantEncoded) + } + + // Encode the same data with the HRP converted to mixed upper and + // lowercase and ensure the result is the lowercase version of the + // original encoded bech32 string. + var mixedHRPBuilder strings.Builder + for i, r := range test.hrp { + if i%2 == 0 { + mixedHRPBuilder.WriteString(strings.ToUpper(string(r))) + continue + } + mixedHRPBuilder.WriteRune(r) + } + gotEncoded, err = EncodeFromBase256(mixedHRPBuilder.String(), data) + if err != nil { + t.Errorf("%q: unexpected lowercase HRP encode error: %v", test.name, + err) + } + if gotEncoded != wantEncoded { + t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name, + gotEncoded, wantEncoded) + } + + // Ensure a bit flip in the string is caught. + pos := strings.LastIndexAny(test.encoded, "1") + flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:] + _, _, err = DecodeToBase256(flipped) + if err == nil { + t.Error("expected decoding to fail") + } + } +} + +// BenchmarkEncodeDecodeCycle performs a benchmark for a full encode/decode +// cycle of a bech32 string. It also reports the allocation count, which we +// expect to be 2 for a fully optimized cycle. +func BenchmarkEncodeDecodeCycle(b *testing.B) { + // Use a fixed, 49-byte raw data for testing. + inputData, err := hex.DecodeString("cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1") + if err != nil { + b.Fatalf("failed to initialize input data: %v", err) + } + + // Convert this into a 79-byte, base 32 byte slice. + base32Input, err := ConvertBits(inputData, 8, 5, true) + if err != nil { + b.Fatalf("failed to convert input to 32 bits-per-element: %v", err) + } + + // Use a fixed hrp for the tests. This should generate an encoded bech32 + // string of size 90 (the maximum allowed by BIP-173). + hrp := "bc" + + // Begin the benchmark. Given that we test one roundtrip per iteration + // (that is, one Encode() and one Decode() operation), we expect at most + // 2 allocations per reported test op. + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + str, err := Encode(hrp, base32Input) + if err != nil { + b.Fatalf("failed to encode input: %v", err) + } + + _, _, err = Decode(str) + if err != nil { + b.Fatalf("failed to decode string: %v", err) + } + } +} + +// TestConvertBits tests whether base conversion works using TestConvertBits(). +func TestConvertBits(t *testing.T) { + tests := []struct { + input string + output string + fromBits uint8 + toBits uint8 + pad bool + }{ + // Trivial empty conversions. + {"", "", 8, 5, false}, + {"", "", 8, 5, true}, + {"", "", 5, 8, false}, + {"", "", 5, 8, true}, + + // Conversions of 0 value with/without padding. + {"00", "00", 8, 5, false}, + {"00", "0000", 8, 5, true}, + {"0000", "00", 5, 8, false}, + {"0000", "0000", 5, 8, true}, + + // Testing when conversion ends exactly at the byte edge. This makes + // both padded and unpadded versions the same. + {"0000000000", "0000000000000000", 8, 5, false}, + {"0000000000", "0000000000000000", 8, 5, true}, + {"0000000000000000", "0000000000", 5, 8, false}, + {"0000000000000000", "0000000000", 5, 8, true}, + + // Conversions of full byte sequences. + {"ffffff", "1f1f1f1f1e", 8, 5, true}, + {"1f1f1f1f1e", "ffffff", 5, 8, false}, + {"1f1f1f1f1e", "ffffff00", 5, 8, true}, + + // Sample random conversions. + {"c9ca", "190705", 8, 5, false}, + {"c9ca", "19070500", 8, 5, true}, + {"19070500", "c9ca", 5, 8, false}, + {"19070500", "c9ca00", 5, 8, true}, + + // Test cases tested on TestConvertBitsFailures with their corresponding + // fixes. + {"ff", "1f1c", 8, 5, true}, + {"1f1c10", "ff20", 5, 8, true}, + + // Large conversions. + { + "cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1", + "190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408", + 8, 5, true, + }, + { + "190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408", + "cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed100", + 5, 8, true, + }, + } + + for i, tc := range tests { + input, err := hex.DecodeString(tc.input) + if err != nil { + t.Fatalf("invalid test input data: %v", err) + } + + expected, err := hex.DecodeString(tc.output) + if err != nil { + t.Fatalf("invalid test output data: %v", err) + } + + actual, err := ConvertBits(input, tc.fromBits, tc.toBits, tc.pad) + if err != nil { + t.Fatalf("test case %d failed: %v", i, err) + } + + if !bytes.Equal(actual, expected) { + t.Fatalf("test case %d has wrong output; expected=%x actual=%x", + i, expected, actual) + } + } +} + +// TestConvertBitsFailures tests for the expected conversion failures of +// ConvertBits(). +func TestConvertBitsFailures(t *testing.T) { + tests := []struct { + input string + fromBits uint8 + toBits uint8 + pad bool + err error + }{ + // Not enough output bytes when not using padding. + {"ff", 8, 5, false, ErrInvalidIncompleteGroup{}}, + {"1f1c10", 5, 8, false, ErrInvalidIncompleteGroup{}}, + + // Unsupported bit conversions. + {"", 0, 5, false, ErrInvalidBitGroups{}}, + {"", 10, 5, false, ErrInvalidBitGroups{}}, + {"", 5, 0, false, ErrInvalidBitGroups{}}, + {"", 5, 10, false, ErrInvalidBitGroups{}}, + } + + for i, tc := range tests { + input, err := hex.DecodeString(tc.input) + if err != nil { + t.Fatalf("invalid test input data: %v", err) + } + + _, err = ConvertBits(input, tc.fromBits, tc.toBits, tc.pad) + if err != tc.err { + t.Fatalf("test case %d failure: expected '%v' got '%v'", i, + tc.err, err) + } + } + +} + +// BenchmarkConvertBitsDown benchmarks the speed and memory allocation behavior +// of ConvertBits when converting from a higher base into a lower base (e.g. 8 +// => 5). +// +// Only a single allocation is expected, which is used for the output array. +func BenchmarkConvertBitsDown(b *testing.B) { + // Use a fixed, 49-byte raw data for testing. + inputData, err := hex.DecodeString("cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1") + if err != nil { + b.Fatalf("failed to initialize input data: %v", err) + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := ConvertBits(inputData, 8, 5, true) + if err != nil { + b.Fatalf("error converting bits: %v", err) + } + } +} + +// BenchmarkConvertBitsUp benchmarks the speed and memory allocation behavior +// of ConvertBits when converting from a lower base into a higher base (e.g. 5 +// => 8). +// +// Only a single allocation is expected, which is used for the output array. +func BenchmarkConvertBitsUp(b *testing.B) { + // Use a fixed, 79-byte raw data for testing. + inputData, err := hex.DecodeString("190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408") + if err != nil { + b.Fatalf("failed to initialize input data: %v", err) + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := ConvertBits(inputData, 8, 5, true) + if err != nil { + b.Fatalf("error converting bits: %v", err) + } + } +} diff --git a/gnovm/stdlibs/crypto/bech32/error.gno b/gnovm/stdlibs/crypto/bech32/error.gno new file mode 100644 index 00000000000..dafe9b68516 --- /dev/null +++ b/gnovm/stdlibs/crypto/bech32/error.gno @@ -0,0 +1,83 @@ +// Copyright (c) 2019 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package bech32 + +// ErrMixedCase is returned when the bech32 string has both lower and uppercase +// characters. +type ErrMixedCase struct{} + +func (e ErrMixedCase) Error() string { + return "string not all lowercase or all uppercase" +} + +// ErrInvalidBitGroups is returned when conversion is attempted between byte +// slices using bit-per-element of unsupported value. +type ErrInvalidBitGroups struct{} + +func (e ErrInvalidBitGroups) Error() string { + return "only bit groups between 1 and 8 allowed" +} + +// ErrInvalidIncompleteGroup is returned when then byte slice used as input has +// data of wrong length. +type ErrInvalidIncompleteGroup struct{} + +func (e ErrInvalidIncompleteGroup) Error() string { + return "invalid incomplete group" +} + +// ErrInvalidLength is returned when the bech32 string has an invalid length +// given the BIP-173 defined restrictions. +type ErrInvalidLength int + +func (e ErrInvalidLength) Error() string { + return "invalid bech32 string length" +} + +// ErrInvalidCharacter is returned when the bech32 string has a character +// outside the range of the supported charset. +type ErrInvalidCharacter rune + +func (e ErrInvalidCharacter) Error() string { + return "invalid character in string: " + string(e) +} + +// ErrInvalidSeparatorIndex is returned when the separator character '1' is +// in an invalid position in the bech32 string. +type ErrInvalidSeparatorIndex int + +func (e ErrInvalidSeparatorIndex) Error() string { + return "invalid separator index" + string(e) +} + +// ErrNonCharsetChar is returned when a character outside of the specific +// bech32 charset is used in the string. +type ErrNonCharsetChar rune + +func (e ErrNonCharsetChar) Error() string { + return "invalid character not part of charset" +} + +// ErrInvalidChecksum is returned when the extracted checksum of the string +// is different than what was expected. Both the original version, as well as +// the new bech32m checksum may be specified. +type ErrInvalidChecksum struct { + Expected string + ExpectedM string + Actual string +} + +func (e ErrInvalidChecksum) Error() string { + return "invalid checksum (expected (bech32=" + e.Expected + + " bech32m=)" + e.ExpectedM + ", got " + e.Actual + ")" +} + +// ErrInvalidDataByte is returned when a byte outside the range required for +// conversion into a string was found. +type ErrInvalidDataByte byte + +func (e ErrInvalidDataByte) Error() string { + return "invalid data byte: " + string(e) +} diff --git a/gnovm/stdlibs/crypto/bech32/version.gno b/gnovm/stdlibs/crypto/bech32/version.gno new file mode 100644 index 00000000000..147037db9aa --- /dev/null +++ b/gnovm/stdlibs/crypto/bech32/version.gno @@ -0,0 +1,43 @@ +package bech32 + +// ChecksumConst is a type that represents the currently defined bech32 +// checksum constants. +type ChecksumConst int + +const ( + // Version0Const is the original constant used in the checksum + // verification for bech32. + Version0Const ChecksumConst = 1 + + // VersionMConst is the new constant used for bech32m checksum + // verification. + VersionMConst ChecksumConst = 0x2bc830a3 +) + +// Version defines the current set of bech32 versions. +type Version uint8 + +const ( + // Version0 defines the original bech version. + Version0 Version = iota + + // VersionM is the new bech32 version defined in BIP-350, also known as + // bech32m. + VersionM + + // VersionUnknown denotes an unknown bech version. + VersionUnknown +) + +// VersionToConsts maps bech32 versions to the checksum constant to be used +// when encoding, and asserting a particular version when decoding. +var VersionToConsts = map[Version]ChecksumConst{ + Version0: Version0Const, + VersionM: VersionMConst, +} + +// ConstsToVersion maps a bech32 constant to the version it's associated with. +var ConstsToVersion = map[ChecksumConst]Version{ + Version0Const: Version0, + VersionMConst: VersionM, +} diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index d5ab052028f..6e757561ef2 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -640,106 +640,6 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, - { - "std", - "derivePkgAddr", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0 := libs_std.X_derivePkgAddr(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "std", - "encodeBech32", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("[20]byte")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - p1 [20]byte - rp1 = reflect.ValueOf(&p1).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) - - r0 := libs_std.X_encodeBech32(p0, p1) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "std", - "decodeBech32", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - {Name: gno.N("r1"), Type: gno.X("[20]byte")}, - {Name: gno.N("r2"), Type: gno.X("bool")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0, r1, r2 := libs_std.X_decodeBech32(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r1).Elem(), - )) - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r2).Elem(), - )) - }, - }, { "std", "assertCallerIsRealm", @@ -977,6 +877,7 @@ var initOrder = [...]string{ "bytes", "strings", "bufio", + "crypto/bech32", "encoding/binary", "math/bits", "math", diff --git a/gnovm/stdlibs/std/crypto.gno b/gnovm/stdlibs/std/crypto.gno index 402a6af3e22..adb6f687b56 100644 --- a/gnovm/stdlibs/std/crypto.gno +++ b/gnovm/stdlibs/std/crypto.gno @@ -1,7 +1,16 @@ package std +import ( + "crypto/bech32" + "crypto/sha256" + "errors" +) + type Address string // NOTE: bech32 +// bech32AddrPrefix defines the Bech32 prefix of an address +const bech32AddrPrefix = "g" + func (a Address) String() string { return string(a) } @@ -15,3 +24,61 @@ func (a Address) IsValid() bool { const RawAddressSize = 20 type RawAddress [RawAddressSize]byte + +func EncodeBech32(prefix string, bz [20]byte) Address { + b32, err := convertAndEncode(prefix, bz[:]) + if err != nil { + panic(err) // should not happen + } + return Address(b32) +} + +func DecodeBech32(addr Address) (string, [20]byte, bool) { + prefix, bz, err := decodeAndConvert(string(addr)) + if err != nil || len(bz) != 20 { + return "", [20]byte{}, false + } + return prefix, convertTo20Byte(bz), true +} + +func convertAndEncode(hrp string, data []byte) (string, error) { + converted, err := bech32.ConvertBits(data, 8, 5, true) + if err != nil { + return "", errors.New("encoding bech32 failed: " + err.Error()) + } + return bech32.Encode(hrp, converted) +} + +func decodeAndConvert(bech string) (string, []byte, error) { + hrp, data, err := bech32.DecodeNoLimit(bech) + if err != nil { + return "", nil, errors.New("decoding bech32 failed" + err.Error()) + } + converted, err := bech32.ConvertBits(data, 5, 8, false) + if err != nil { + return "", nil, errors.New("decoding bech32 failed" + err.Error()) + } + return hrp, converted, nil +} + +func DerivePkgAddr(pkgPath string) Address { + data := sumTruncated([]byte("pkgPath:" + pkgPath)) + return EncodeBech32(bech32AddrPrefix, data) +} + +func sumTruncated(bz []byte) [20]byte { + hash := sha256.Sum256(bz) + return convertTo20Byte(hash[:RawAddressSize]) +} + +func convertTo20Byte(in []byte) [20]byte { + /* For some reason [20]byte(bz) fails with: 'cannot convert []uint8 to ArrayKind' + Maybe there is an issue to create + */ + result := [20]byte{} + for index, b := range in { + result[index] = b + } + + return result +} diff --git a/gnovm/stdlibs/std/crypto_test.gno b/gnovm/stdlibs/std/crypto_test.gno index 75283c03523..70b42e43860 100644 --- a/gnovm/stdlibs/std/crypto_test.gno +++ b/gnovm/stdlibs/std/crypto_test.gno @@ -39,3 +39,22 @@ func TestValid(t *testing.T) { } } } + +func TestDerivePkgAddr(t *testing.T) { + type test struct { + inputPath string + expected string + } + + testCases := []test{ + {inputPath: "gno.land/r/gnoland/faucet", expected: "g1ttrq7mp4zy6dssnmgyyktnn4hcj3ys8xhju0n7"}, + {inputPath: "gno.land/r/demo/tamagotchi", expected: "g1a3tu874agjlkrpzt9x90xv3uzncapcn959yte4"}, + } + + for _, tc := range testCases { + result := DerivePkgAddr(tc.inputPath) + if result.String() != tc.expected { + t.Fatalf("Expected: %t, got: %t", tc.expected, result) + } + } +} diff --git a/gnovm/stdlibs/std/native.gno b/gnovm/stdlibs/std/native.gno index 0dcde1148e1..9cf8808a07e 100644 --- a/gnovm/stdlibs/std/native.gno +++ b/gnovm/stdlibs/std/native.gno @@ -45,25 +45,10 @@ func GetCallerAt(n int) Address { return Address(callerAt(n)) } -func DerivePkgAddr(pkgPath string) Address { - return Address(derivePkgAddr(pkgPath)) -} - -func EncodeBech32(prefix string, bz [20]byte) Address { - return Address(encodeBech32(prefix, bz)) -} - -func DecodeBech32(addr Address) (prefix string, bz [20]byte, ok bool) { - return decodeBech32(string(addr)) -} - // Variations which don't use named types. func origSend() (denoms []string, amounts []int64) func origCaller() string func origPkgAddr() string func callerAt(n int) string func getRealm(height int) (address string, pkgPath string) -func derivePkgAddr(pkgPath string) string -func encodeBech32(prefix string, bz [20]byte) string -func decodeBech32(addr string) (prefix string, bz [20]byte, ok bool) func assertCallerIsRealm() diff --git a/gnovm/stdlibs/std/native.go b/gnovm/stdlibs/std/native.go index fb181d9be31..9e398e907a2 100644 --- a/gnovm/stdlibs/std/native.go +++ b/gnovm/stdlibs/std/native.go @@ -2,7 +2,6 @@ package std import ( gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/tm2/pkg/bech32" "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/std" ) @@ -142,26 +141,6 @@ func currentRealm(m *gno.Machine) (address, pkgPath string) { return X_getRealm(m, 0) } -func X_derivePkgAddr(pkgPath string) string { - return string(gno.DerivePkgAddr(pkgPath).Bech32()) -} - -func X_encodeBech32(prefix string, bytes [20]byte) string { - b32, err := bech32.ConvertAndEncode(prefix, bytes[:]) - if err != nil { - panic(err) // should not happen - } - return b32 -} - -func X_decodeBech32(addr string) (prefix string, bytes [20]byte, ok bool) { - prefix, bz, err := bech32.Decode(addr) - if err != nil || len(bz) != 20 { - return "", [20]byte{}, false - } - return prefix, [20]byte(bz), true -} - func X_assertCallerIsRealm(m *gno.Machine) { frame := m.Frames[m.NumFrames()-2] if path := frame.LastPackage.PkgPath; !gno.IsRealmPath(path) { diff --git a/gnovm/tests/files/std5.gno b/gnovm/tests/files/std5.gno index e339d7a6364..2f9e98bb4ec 100644 --- a/gnovm/tests/files/std5.gno +++ b/gnovm/tests/files/std5.gno @@ -13,7 +13,7 @@ func main() { // Stacktrace: // panic: frame not found -// callerAt(n) +// callerAt(n) // gonative:std.callerAt // std.GetCallerAt(2) // std/native.gno:45 diff --git a/gnovm/tests/files/std8.gno b/gnovm/tests/files/std8.gno index ee717bf16be..dfc2b8ca5fd 100644 --- a/gnovm/tests/files/std8.gno +++ b/gnovm/tests/files/std8.gno @@ -23,7 +23,7 @@ func main() { // Stacktrace: // panic: frame not found -// callerAt(n) +// callerAt(n) // gonative:std.callerAt // std.GetCallerAt(4) // std/native.gno:45 diff --git a/gnovm/tests/files/zrealm_natbind0.gno b/gnovm/tests/files/zrealm_natbind0.gno index 8e5f641e734..e6ebef6252e 100644 --- a/gnovm/tests/files/zrealm_natbind0.gno +++ b/gnovm/tests/files/zrealm_natbind0.gno @@ -69,7 +69,7 @@ func main() { // "Closure": { // "@type": "/gno.RefValue", // "Escaped": true, -// "ObjectID": "a7f5397443359ea76c50be82c77f1f893a060925:9" +// "ObjectID": "a7f5397443359ea76c50be82c77f1f893a060925:10" // }, // "FileName": "native.gno", // "IsMethod": false, From d54d00470dd1be891e9c22896aa3841fcfe02eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20=C5=BDivkovi=C4=87?= Date: Tue, 14 Jan 2025 15:16:14 +0100 Subject: [PATCH 04/13] feat: add `EstimateGas` to gnoclient (#3498) ## Description Closes #1826 along with https://github.com/gnolang/tm2-js-client/pull/192 This PR introduces a method `EstimateGas` to estimate the gas used by a transaction in gnoclient. We can use this call to get a ballpark estimate if a transaction succeeds, and if it does, how much gas it actually used. --- gno.land/pkg/gnoclient/client_test.go | 157 ++++++++++++++++++++++++++ gno.land/pkg/gnoclient/client_txs.go | 47 +++++++- 2 files changed, 203 insertions(+), 1 deletion(-) diff --git a/gno.land/pkg/gnoclient/client_test.go b/gno.land/pkg/gnoclient/client_test.go index 1f8563d34fe..54a15420a66 100644 --- a/gno.land/pkg/gnoclient/client_test.go +++ b/gno.land/pkg/gnoclient/client_test.go @@ -1,8 +1,11 @@ package gnoclient import ( + "errors" "testing" + "github.com/gnolang/gno/tm2/pkg/amino" + abciErrors "github.com/gnolang/gno/tm2/pkg/bft/abci/example/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -1409,3 +1412,157 @@ func addPackageSigningSeparately(t *testing.T, client Client, cfg BaseTxCfg, msg require.NotNil(t, res) return res, nil } + +func TestClient_EstimateGas(t *testing.T) { + t.Parallel() + + t.Run("RPC client not set", func(t *testing.T) { + t.Parallel() + + c := &Client{ + RPCClient: nil, // not set + } + + estimate, err := c.EstimateGas(&std.Tx{}) + + assert.Zero(t, estimate) + assert.ErrorIs(t, err, ErrMissingRPCClient) + }) + + t.Run("unsuccessful query, rpc error", func(t *testing.T) { + t.Parallel() + + var ( + rpcErr = errors.New("rpc error") + mockRPCClient = &mockRPCClient{ + abciQuery: func(path string, data []byte) (*ctypes.ResultABCIQuery, error) { + require.Equal(t, simulatePath, path) + + var tx std.Tx + + require.NoError(t, amino.Unmarshal(data, &tx)) + + return nil, rpcErr + }, + } + ) + + c := &Client{ + RPCClient: mockRPCClient, + } + + estimate, err := c.EstimateGas(&std.Tx{}) + + assert.Zero(t, estimate) + assert.ErrorIs(t, err, rpcErr) + }) + + t.Run("unsuccessful query, process error", func(t *testing.T) { + t.Parallel() + + var ( + response = &ctypes.ResultABCIQuery{ + Response: abci.ResponseQuery{ + ResponseBase: abci.ResponseBase{ + Error: abciErrors.UnknownError{}, + }, + }, + } + mockRPCClient = &mockRPCClient{ + abciQuery: func(path string, data []byte) (*ctypes.ResultABCIQuery, error) { + require.Equal(t, simulatePath, path) + + var tx std.Tx + + require.NoError(t, amino.Unmarshal(data, &tx)) + + return response, nil + }, + } + ) + + c := &Client{ + RPCClient: mockRPCClient, + } + + estimate, err := c.EstimateGas(&std.Tx{}) + + assert.Zero(t, estimate) + assert.ErrorIs(t, err, abciErrors.UnknownError{}) + }) + + t.Run("invalid response format", func(t *testing.T) { + t.Parallel() + + var ( + response = &ctypes.ResultABCIQuery{ + Response: abci.ResponseQuery{ + Value: []byte("totally valid amino"), + }, + } + mockRPCClient = &mockRPCClient{ + abciQuery: func(path string, data []byte) (*ctypes.ResultABCIQuery, error) { + require.Equal(t, simulatePath, path) + + var tx std.Tx + + require.NoError(t, amino.Unmarshal(data, &tx)) + + return response, nil + }, + } + ) + + c := &Client{ + RPCClient: mockRPCClient, + } + + estimate, err := c.EstimateGas(&std.Tx{}) + + assert.Zero(t, estimate) + assert.ErrorContains(t, err, "unable to unmarshal gas estimation response") + }) + + t.Run("valid gas estimation", func(t *testing.T) { + t.Parallel() + + var ( + gasUsed = int64(100000) + deliverResp = &abci.ResponseDeliverTx{ + GasUsed: gasUsed, + } + ) + + // Encode the response + encodedResp, err := amino.Marshal(deliverResp) + require.NoError(t, err) + + var ( + response = &ctypes.ResultABCIQuery{ + Response: abci.ResponseQuery{ + Value: encodedResp, // valid amino binary + }, + } + mockRPCClient = &mockRPCClient{ + abciQuery: func(path string, data []byte) (*ctypes.ResultABCIQuery, error) { + require.Equal(t, simulatePath, path) + + var tx std.Tx + + require.NoError(t, amino.Unmarshal(data, &tx)) + + return response, nil + }, + } + ) + + c := &Client{ + RPCClient: mockRPCClient, + } + + estimate, err := c.EstimateGas(&std.Tx{}) + + require.NoError(t, err) + assert.Equal(t, gasUsed, estimate) + }) +} diff --git a/gno.land/pkg/gnoclient/client_txs.go b/gno.land/pkg/gnoclient/client_txs.go index d7f6f053242..ab520eceda1 100644 --- a/gno.land/pkg/gnoclient/client_txs.go +++ b/gno.land/pkg/gnoclient/client_txs.go @@ -1,8 +1,11 @@ package gnoclient import ( + "fmt" + "github.com/gnolang/gno/gno.land/pkg/sdk/vm" "github.com/gnolang/gno/tm2/pkg/amino" + abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" ctypes "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types" "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/sdk/bank" @@ -16,6 +19,8 @@ var ( ErrMissingRPCClient = errors.New("missing RPCClient") ) +const simulatePath = ".app/simulate" + // BaseTxCfg defines the base transaction configuration, shared by all message types type BaseTxCfg struct { GasFee string // Gas fee @@ -292,4 +297,44 @@ func (c *Client) BroadcastTxCommit(signedTx *std.Tx) (*ctypes.ResultBroadcastTxC return bres, nil } -// TODO: Add more functionality, examples, and unit tests. +// EstimateGas returns the least amount of gas required +// for the transaction to go through on the chain (minimum gas wanted). +// The estimation process assumes the transaction is properly signed +func (c *Client) EstimateGas(tx *std.Tx) (int64, error) { + // Make sure the RPC client is set + if err := c.validateRPCClient(); err != nil { + return 0, err + } + + // Prepare the transaction. + // The transaction needs to be amino-binary encoded + // in order to be estimated + encodedTx, err := amino.Marshal(tx) + if err != nil { + return 0, fmt.Errorf("unable to marshal tx: %w", err) + } + + // Perform the simulation query + resp, err := c.RPCClient.ABCIQuery(simulatePath, encodedTx) + if err != nil { + return 0, fmt.Errorf("unable to perform ABCI query: %w", err) + } + + // Extract the query response + if err = resp.Response.Error; err != nil { + return 0, fmt.Errorf("error encountered during ABCI query: %w", err) + } + + var deliverTx abci.ResponseDeliverTx + if err = amino.Unmarshal(resp.Response.Value, &deliverTx); err != nil { + return 0, fmt.Errorf("unable to unmarshal gas estimation response: %w", err) + } + + if err = deliverTx.Error; err != nil { + return 0, fmt.Errorf("error encountered during gas estimation: %w", err) + } + + // Return the actual value returned by the node + // for executing the transaction + return deliverTx.GasUsed, nil +} From 7761c3ba29695b1621c618d8382d696433622761 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Tue, 14 Jan 2025 17:20:59 +0100 Subject: [PATCH 05/13] chore: revert "feat(gnovm): implement overflow checking at VM level" (#3508) Revert #3250 This reverts commit 68aff6464dfba782903cdb5e3b318a9b233a479e. This PR was merged before discussions were complete. It was finally rejected because it does not comply with Go specification, which stipulates that overflow on signed integers do not trigger runtime panic. See https://go.dev/ref/spec#Integer_overflow --- examples/gno.land/p/demo/grc/grc20/token.gno | 22 +- gnovm/pkg/gnolang/op_bench_test.go | 70 --- gnovm/pkg/gnolang/op_binary.go | 305 +++++------ gnovm/pkg/gnolang/op_inc_dec.go | 25 +- gnovm/stdlibs/generated.go | 1 + gnovm/stdlibs/math/const_test.gno | 77 +-- gnovm/stdlibs/math/overflow/overflow.gno | 501 ++++++++++++++++++ gnovm/stdlibs/math/overflow/overflow_test.gno | 200 +++++++ gnovm/stdlibs/std/coins.gno | 26 +- gnovm/tests/files/overflow0.gno | 10 - gnovm/tests/files/overflow1.gno | 10 - gnovm/tests/files/overflow2.gno | 10 - gnovm/tests/files/overflow3.gno | 10 - gnovm/tests/files/overflow4.gno | 10 - gnovm/tests/files/overflow5.gno | 10 - gnovm/tests/files/recover14.gno | 2 +- misc/genstd/util.go | 3 +- 17 files changed, 874 insertions(+), 418 deletions(-) delete mode 100644 gnovm/pkg/gnolang/op_bench_test.go create mode 100644 gnovm/stdlibs/math/overflow/overflow.gno create mode 100644 gnovm/stdlibs/math/overflow/overflow_test.gno delete mode 100644 gnovm/tests/files/overflow0.gno delete mode 100644 gnovm/tests/files/overflow1.gno delete mode 100644 gnovm/tests/files/overflow2.gno delete mode 100644 gnovm/tests/files/overflow3.gno delete mode 100644 gnovm/tests/files/overflow4.gno delete mode 100644 gnovm/tests/files/overflow5.gno diff --git a/examples/gno.land/p/demo/grc/grc20/token.gno b/examples/gno.land/p/demo/grc/grc20/token.gno index 4986eaebf04..3ab3abc63a3 100644 --- a/examples/gno.land/p/demo/grc/grc20/token.gno +++ b/examples/gno.land/p/demo/grc/grc20/token.gno @@ -1,6 +1,7 @@ package grc20 import ( + "math/overflow" "std" "strconv" @@ -169,24 +170,17 @@ func (led *PrivateLedger) Approve(owner, spender std.Address, amount uint64) err } // Mint increases the total supply of the token and adds the specified amount to the specified address. -func (led *PrivateLedger) Mint(address std.Address, amount uint64) (err error) { +func (led *PrivateLedger) Mint(address std.Address, amount uint64) error { if !address.IsValid() { return ErrInvalidAddress } - defer func() { - if r := recover(); r != nil { - if r != "addition overflow" { - panic(r) - } - err = ErrOverflow - } - }() - - // Convert amount and totalSupply to signed integers to enable - // overflow checking (not occuring on unsigned) when computing the sum. - // The maximum value for totalSupply is therefore 1<<63. - sum := int64(led.totalSupply) + int64(amount) + // XXX: math/overflow is not supporting uint64. + // This checks prevents overflow but makes the totalSupply limited to a uint63. + sum, ok := overflow.Add64(int64(led.totalSupply), int64(amount)) + if !ok { + return ErrOverflow + } led.totalSupply = uint64(sum) currentBalance := led.balanceOf(address) diff --git a/gnovm/pkg/gnolang/op_bench_test.go b/gnovm/pkg/gnolang/op_bench_test.go deleted file mode 100644 index 5874f980285..00000000000 --- a/gnovm/pkg/gnolang/op_bench_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package gnolang - -import ( - "testing" - - "github.com/gnolang/gno/tm2/pkg/overflow" -) - -func BenchmarkOpAdd(b *testing.B) { - m := NewMachine("bench", nil) - x := TypedValue{T: IntType} - x.SetInt(4) - y := TypedValue{T: IntType} - y.SetInt(3) - - b.ResetTimer() - - for range b.N { - m.PushOp(OpHalt) - m.PushExpr(&BinaryExpr{}) - m.PushValue(x) - m.PushValue(y) - m.PushOp(OpAdd) - m.Run() - } -} - -//go:noinline -func AddNoOverflow(x, y int) int { return x + y } - -func BenchmarkAddNoOverflow(b *testing.B) { - x, y := 4, 3 - c := 0 - for range b.N { - c = AddNoOverflow(x, y) - } - if c != 7 { - b.Error("invalid result") - } -} - -func BenchmarkAddOverflow(b *testing.B) { - x, y := 4, 3 - c := 0 - for range b.N { - c = overflow.Addp(x, y) - } - if c != 7 { - b.Error("invalid result") - } -} - -func TestOpAdd1(t *testing.T) { - m := NewMachine("test", nil) - a := TypedValue{T: IntType} - a.SetInt(4) - b := TypedValue{T: IntType} - b.SetInt(3) - t.Log("a:", a, "b:", b) - - start := m.NumValues - m.PushOp(OpHalt) - m.PushExpr(&BinaryExpr{}) - m.PushValue(a) - m.PushValue(b) - m.PushOp(OpAdd) - m.Run() - res := m.ReapValues(start) - t.Log("res:", res) -} diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index 765f3ccbfbd..0e8eec9db23 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -7,7 +7,6 @@ import ( "github.com/cockroachdb/apd/v3" "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" - "github.com/gnolang/gno/tm2/pkg/overflow" ) // ---------------------------------------- @@ -185,9 +184,7 @@ func (m *Machine) doOpAdd() { } // add rv to lv. - if err := addAssign(m.Alloc, lv, rv); err != nil { - panic(err) - } + addAssign(m.Alloc, lv, rv) } func (m *Machine) doOpSub() { @@ -201,9 +198,7 @@ func (m *Machine) doOpSub() { } // sub rv from lv. - if err := subAssign(lv, rv); err != nil { - panic(err) - } + subAssign(lv, rv) } func (m *Machine) doOpBor() { @@ -259,7 +254,8 @@ func (m *Machine) doOpQuo() { } // lv / rv - if err := quoAssign(lv, rv); err != nil { + err := quoAssign(lv, rv) + if err != nil { panic(err) } } @@ -275,7 +271,8 @@ func (m *Machine) doOpRem() { } // lv % rv - if err := remAssign(lv, rv); err != nil { + err := remAssign(lv, rv) + if err != nil { panic(err) } } @@ -687,38 +684,23 @@ func isGeq(lv, rv *TypedValue) bool { } } -// addAssign adds lv to rv and stores the result to lv. -// It returns an exception in case of overflow on signed integers. -// The assignement is performed even in case of exception. -func addAssign(alloc *Allocator, lv, rv *TypedValue) *Exception { +// for doOpAdd and doOpAddAssign. +func addAssign(alloc *Allocator, lv, rv *TypedValue) { // set the result in lv. // NOTE this block is replicated in op_assign.go - ok := true switch baseOf(lv.T) { case StringType, UntypedStringType: lv.V = alloc.NewString(lv.GetString() + rv.GetString()) - // Signed integers may overflow, which triggers an exception. case IntType: - var r int - r, ok = overflow.Add(lv.GetInt(), rv.GetInt()) - lv.SetInt(r) + lv.SetInt(lv.GetInt() + rv.GetInt()) case Int8Type: - var r int8 - r, ok = overflow.Add8(lv.GetInt8(), rv.GetInt8()) - lv.SetInt8(r) + lv.SetInt8(lv.GetInt8() + rv.GetInt8()) case Int16Type: - var r int16 - r, ok = overflow.Add16(lv.GetInt16(), rv.GetInt16()) - lv.SetInt16(r) + lv.SetInt16(lv.GetInt16() + rv.GetInt16()) case Int32Type, UntypedRuneType: - var r int32 - r, ok = overflow.Add32(lv.GetInt32(), rv.GetInt32()) - lv.SetInt32(r) + lv.SetInt32(lv.GetInt32() + rv.GetInt32()) case Int64Type: - var r int64 - r, ok = overflow.Add64(lv.GetInt64(), rv.GetInt64()) - lv.SetInt64(r) - // Unsigned integers do not overflow, they just wrap. + lv.SetInt64(lv.GetInt64() + rv.GetInt64()) case UintType: lv.SetUint(lv.GetUint() + rv.GetUint()) case Uint8Type: @@ -758,42 +740,23 @@ func addAssign(alloc *Allocator, lv, rv *TypedValue) *Exception { lv.T, )) } - if !ok { - return &Exception{Value: typedString("addition overflow")} - } - return nil } -// subAssign subtracts lv to rv and stores the result to lv. -// It returns an exception in case of overflow on signed integers. -// The subtraction is performed even in case of exception. -func subAssign(lv, rv *TypedValue) *Exception { +// for doOpSub and doOpSubAssign. +func subAssign(lv, rv *TypedValue) { // set the result in lv. // NOTE this block is replicated in op_assign.go - ok := true switch baseOf(lv.T) { - // Signed integers may overflow, which triggers an exception. case IntType: - var r int - r, ok = overflow.Sub(lv.GetInt(), rv.GetInt()) - lv.SetInt(r) + lv.SetInt(lv.GetInt() - rv.GetInt()) case Int8Type: - var r int8 - r, ok = overflow.Sub8(lv.GetInt8(), rv.GetInt8()) - lv.SetInt8(r) + lv.SetInt8(lv.GetInt8() - rv.GetInt8()) case Int16Type: - var r int16 - r, ok = overflow.Sub16(lv.GetInt16(), rv.GetInt16()) - lv.SetInt16(r) + lv.SetInt16(lv.GetInt16() - rv.GetInt16()) case Int32Type, UntypedRuneType: - var r int32 - r, ok = overflow.Sub32(lv.GetInt32(), rv.GetInt32()) - lv.SetInt32(r) + lv.SetInt32(lv.GetInt32() - rv.GetInt32()) case Int64Type: - var r int64 - r, ok = overflow.Sub64(lv.GetInt64(), rv.GetInt64()) - lv.SetInt64(r) - // Unsigned integers do not overflow, they just wrap. + lv.SetInt64(lv.GetInt64() - rv.GetInt64()) case UintType: lv.SetUint(lv.GetUint() - rv.GetUint()) case Uint8Type: @@ -833,39 +796,23 @@ func subAssign(lv, rv *TypedValue) *Exception { lv.T, )) } - if !ok { - return &Exception{Value: typedString("subtraction overflow")} - } - return nil } // for doOpMul and doOpMulAssign. -func mulAssign(lv, rv *TypedValue) *Exception { +func mulAssign(lv, rv *TypedValue) { // set the result in lv. // NOTE this block is replicated in op_assign.go - ok := true switch baseOf(lv.T) { - // Signed integers may overflow, which triggers a panic. case IntType: - var r int - r, ok = overflow.Mul(lv.GetInt(), rv.GetInt()) - lv.SetInt(r) + lv.SetInt(lv.GetInt() * rv.GetInt()) case Int8Type: - var r int8 - r, ok = overflow.Mul8(lv.GetInt8(), rv.GetInt8()) - lv.SetInt8(r) + lv.SetInt8(lv.GetInt8() * rv.GetInt8()) case Int16Type: - var r int16 - r, ok = overflow.Mul16(lv.GetInt16(), rv.GetInt16()) - lv.SetInt16(r) + lv.SetInt16(lv.GetInt16() * rv.GetInt16()) case Int32Type, UntypedRuneType: - var r int32 - r, ok = overflow.Mul32(lv.GetInt32(), rv.GetInt32()) - lv.SetInt32(r) + lv.SetInt32(lv.GetInt32() * rv.GetInt32()) case Int64Type: - var r int64 - r, ok = overflow.Mul64(lv.GetInt64(), rv.GetInt64()) - lv.SetInt64(r) + lv.SetInt64(lv.GetInt64() * rv.GetInt64()) case UintType: lv.SetUint(lv.GetUint() * rv.GetUint()) case Uint8Type: @@ -903,102 +850,95 @@ func mulAssign(lv, rv *TypedValue) *Exception { lv.T, )) } - if !ok { - return &Exception{Value: typedString("multiplication overflow")} - } - return nil } // for doOpQuo and doOpQuoAssign. func quoAssign(lv, rv *TypedValue) *Exception { + expt := &Exception{ + Value: typedString("division by zero"), + } + // set the result in lv. // NOTE this block is replicated in op_assign.go - ok := true switch baseOf(lv.T) { - // Signed integers may overflow or cause a division by 0, which triggers a panic. case IntType: - var q int - q, _, ok = overflow.Quotient(lv.GetInt(), rv.GetInt()) - lv.SetInt(q) + if rv.GetInt() == 0 { + return expt + } + lv.SetInt(lv.GetInt() / rv.GetInt()) case Int8Type: - var q int8 - q, _, ok = overflow.Quotient8(lv.GetInt8(), rv.GetInt8()) - lv.SetInt8(q) + if rv.GetInt8() == 0 { + return expt + } + lv.SetInt8(lv.GetInt8() / rv.GetInt8()) case Int16Type: - var q int16 - q, _, ok = overflow.Quotient16(lv.GetInt16(), rv.GetInt16()) - lv.SetInt16(q) + if rv.GetInt16() == 0 { + return expt + } + lv.SetInt16(lv.GetInt16() / rv.GetInt16()) case Int32Type, UntypedRuneType: - var q int32 - q, _, ok = overflow.Quotient32(lv.GetInt32(), rv.GetInt32()) - lv.SetInt32(q) + if rv.GetInt32() == 0 { + return expt + } + lv.SetInt32(lv.GetInt32() / rv.GetInt32()) case Int64Type: - var q int64 - q, _, ok = overflow.Quotient64(lv.GetInt64(), rv.GetInt64()) - lv.SetInt64(q) - // Unsigned integers do not cause overflow, but a division by 0 may still occur. + if rv.GetInt64() == 0 { + return expt + } + lv.SetInt64(lv.GetInt64() / rv.GetInt64()) case UintType: - y := rv.GetUint() - ok = y != 0 - if ok { - lv.SetUint(lv.GetUint() / y) + if rv.GetUint() == 0 { + return expt } + lv.SetUint(lv.GetUint() / rv.GetUint()) case Uint8Type: - y := rv.GetUint8() - ok = y != 0 - if ok { - lv.SetUint8(lv.GetUint8() / y) + if rv.GetUint8() == 0 { + return expt } + lv.SetUint8(lv.GetUint8() / rv.GetUint8()) case DataByteType: - y := rv.GetUint8() - ok = y != 0 - if ok { - lv.SetDataByte(lv.GetDataByte() / y) + if rv.GetUint8() == 0 { + return expt } + lv.SetDataByte(lv.GetDataByte() / rv.GetUint8()) case Uint16Type: - y := rv.GetUint16() - ok = y != 0 - if ok { - lv.SetUint16(lv.GetUint16() / y) + if rv.GetUint16() == 0 { + return expt } + lv.SetUint16(lv.GetUint16() / rv.GetUint16()) case Uint32Type: - y := rv.GetUint32() - ok = y != 0 - if ok { - lv.SetUint32(lv.GetUint32() / y) + if rv.GetUint32() == 0 { + return expt } + lv.SetUint32(lv.GetUint32() / rv.GetUint32()) case Uint64Type: - y := rv.GetUint64() - ok = y != 0 - if ok { - lv.SetUint64(lv.GetUint64() / y) + if rv.GetUint64() == 0 { + return expt } - // XXX Handling float overflows is more complex. + lv.SetUint64(lv.GetUint64() / rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - ok = !softfloat.Feq32(rv.GetFloat32(), softfloat.Fintto32(0)) + ok := !softfloat.Feq32(rv.GetFloat32(), softfloat.Fintto32(0)) if ok { lv.SetFloat32(softfloat.Fdiv32(lv.GetFloat32(), rv.GetFloat32())) } case Float64Type: // NOTE: gno doesn't fuse *+. - ok = !softfloat.Feq64(rv.GetFloat64(), softfloat.Fintto64(0)) + ok := !softfloat.Feq64(rv.GetFloat64(), softfloat.Fintto64(0)) if ok { lv.SetFloat64(softfloat.Fdiv64(lv.GetFloat64(), rv.GetFloat64())) } case BigintType, UntypedBigintType: if rv.GetBigInt().Sign() == 0 { - ok = false - break + return expt } lb := lv.GetBigInt() lb = big.NewInt(0).Quo(lb, rv.GetBigInt()) lv.V = BigintValue{V: lb} case BigdecType, UntypedBigdecType: if rv.GetBigDec().Cmp(apd.New(0, 0)) == 0 { - ok = false - break + return expt } lb := lv.GetBigDec() rb := rv.GetBigDec() @@ -1015,83 +955,81 @@ func quoAssign(lv, rv *TypedValue) *Exception { )) } - if !ok { - return &Exception{Value: typedString("division by zero or overflow")} - } return nil } // for doOpRem and doOpRemAssign. func remAssign(lv, rv *TypedValue) *Exception { + expt := &Exception{ + Value: typedString("division by zero"), + } + // set the result in lv. // NOTE this block is replicated in op_assign.go - ok := true switch baseOf(lv.T) { - // Signed integers may overflow or cause a division by 0, which triggers a panic. case IntType: - var r int - _, r, ok = overflow.Quotient(lv.GetInt(), rv.GetInt()) - lv.SetInt(r) + if rv.GetInt() == 0 { + return expt + } + lv.SetInt(lv.GetInt() % rv.GetInt()) case Int8Type: - var r int8 - _, r, ok = overflow.Quotient8(lv.GetInt8(), rv.GetInt8()) - lv.SetInt8(r) + if rv.GetInt8() == 0 { + return expt + } + lv.SetInt8(lv.GetInt8() % rv.GetInt8()) case Int16Type: - var r int16 - _, r, ok = overflow.Quotient16(lv.GetInt16(), rv.GetInt16()) - lv.SetInt16(r) + if rv.GetInt16() == 0 { + return expt + } + lv.SetInt16(lv.GetInt16() % rv.GetInt16()) case Int32Type, UntypedRuneType: - var r int32 - _, r, ok = overflow.Quotient32(lv.GetInt32(), rv.GetInt32()) - lv.SetInt32(r) + if rv.GetInt32() == 0 { + return expt + } + lv.SetInt32(lv.GetInt32() % rv.GetInt32()) case Int64Type: - var r int64 - _, r, ok = overflow.Quotient64(lv.GetInt64(), rv.GetInt64()) - lv.SetInt64(r) - // Unsigned integers do not cause overflow, but a division by 0 may still occur. + if rv.GetInt64() == 0 { + return expt + } + lv.SetInt64(lv.GetInt64() % rv.GetInt64()) case UintType: - y := rv.GetUint() - ok = y != 0 - if ok { - lv.SetUint(lv.GetUint() % y) + if rv.GetUint() == 0 { + return expt } + lv.SetUint(lv.GetUint() % rv.GetUint()) case Uint8Type: - y := rv.GetUint8() - ok = y != 0 - if ok { - lv.SetUint8(lv.GetUint8() % y) + if rv.GetUint8() == 0 { + return expt } + lv.SetUint8(lv.GetUint8() % rv.GetUint8()) case DataByteType: - y := rv.GetUint8() - ok = y != 0 - if ok { - lv.SetDataByte(lv.GetDataByte() % y) + if rv.GetUint8() == 0 { + return expt } + lv.SetDataByte(lv.GetDataByte() % rv.GetUint8()) case Uint16Type: - y := rv.GetUint16() - ok = y != 0 - if ok { - lv.SetUint16(lv.GetUint16() % y) + if rv.GetUint16() == 0 { + return expt } + lv.SetUint16(lv.GetUint16() % rv.GetUint16()) case Uint32Type: - y := rv.GetUint32() - ok = y != 0 - if ok { - lv.SetUint32(lv.GetUint32() % y) + if rv.GetUint32() == 0 { + return expt } + lv.SetUint32(lv.GetUint32() % rv.GetUint32()) case Uint64Type: - y := rv.GetUint64() - ok = y != 0 - if ok { - lv.SetUint64(lv.GetUint64() % y) + if rv.GetUint64() == 0 { + return expt } + lv.SetUint64(lv.GetUint64() % rv.GetUint64()) case BigintType, UntypedBigintType: - ok = rv.GetBigInt().Sign() != 0 - if ok { - lb := lv.GetBigInt() - lb = big.NewInt(0).Rem(lb, rv.GetBigInt()) - lv.V = BigintValue{V: lb} + if rv.GetBigInt().Sign() == 0 { + return expt } + + lb := lv.GetBigInt() + lb = big.NewInt(0).Rem(lb, rv.GetBigInt()) + lv.V = BigintValue{V: lb} default: panic(fmt.Sprintf( "operators %% and %%= not defined for %s", @@ -1099,9 +1037,6 @@ func remAssign(lv, rv *TypedValue) *Exception { )) } - if !ok { - return &Exception{Value: typedString("division by zero or overflow")} - } return nil } diff --git a/gnovm/pkg/gnolang/op_inc_dec.go b/gnovm/pkg/gnolang/op_inc_dec.go index c67a4be6ed5..708aae821ac 100644 --- a/gnovm/pkg/gnolang/op_inc_dec.go +++ b/gnovm/pkg/gnolang/op_inc_dec.go @@ -6,7 +6,6 @@ import ( "github.com/cockroachdb/apd/v3" "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" - "github.com/gnolang/gno/tm2/pkg/overflow" ) func (m *Machine) doOpInc() { @@ -33,18 +32,16 @@ func (m *Machine) doOpInc() { // because it could be a type alias // type num int switch baseOf(lv.T) { - // Signed integers may overflow, which triggers a panic. case IntType: - lv.SetInt(overflow.Addp(lv.GetInt(), 1)) + lv.SetInt(lv.GetInt() + 1) case Int8Type: - lv.SetInt8(overflow.Add8p(lv.GetInt8(), 1)) + lv.SetInt8(lv.GetInt8() + 1) case Int16Type: - lv.SetInt16(overflow.Add16p(lv.GetInt16(), 1)) + lv.SetInt16(lv.GetInt16() + 1) case Int32Type: - lv.SetInt32(overflow.Add32p(lv.GetInt32(), 1)) + lv.SetInt32(lv.GetInt32() + 1) case Int64Type: - lv.SetInt64(overflow.Add64p(lv.GetInt64(), 1)) - // Unsigned integers do not overflow, they just wrap. + lv.SetInt64(lv.GetInt64() + 1) case UintType: lv.SetUint(lv.GetUint() + 1) case Uint8Type: @@ -105,18 +102,16 @@ func (m *Machine) doOpDec() { } } switch baseOf(lv.T) { - // Signed integers may overflow, which triggers a panic. case IntType: - lv.SetInt(overflow.Subp(lv.GetInt(), 1)) + lv.SetInt(lv.GetInt() - 1) case Int8Type: - lv.SetInt8(overflow.Sub8p(lv.GetInt8(), 1)) + lv.SetInt8(lv.GetInt8() - 1) case Int16Type: - lv.SetInt16(overflow.Sub16p(lv.GetInt16(), 1)) + lv.SetInt16(lv.GetInt16() - 1) case Int32Type: - lv.SetInt32(overflow.Sub32p(lv.GetInt32(), 1)) + lv.SetInt32(lv.GetInt32() - 1) case Int64Type: - lv.SetInt64(overflow.Sub64p(lv.GetInt64(), 1)) - // Unsigned integers do not overflow, they just wrap. + lv.SetInt64(lv.GetInt64() - 1) case UintType: lv.SetUint(lv.GetUint() - 1) case Uint8Type: diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index 6e757561ef2..ab35fc6b6bf 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -896,6 +896,7 @@ var initOrder = [...]string{ "hash", "hash/adler32", "html", + "math/overflow", "math/rand", "path", "sort", diff --git a/gnovm/stdlibs/math/const_test.gno b/gnovm/stdlibs/math/const_test.gno index fbe59d61878..b892a12898b 100644 --- a/gnovm/stdlibs/math/const_test.gno +++ b/gnovm/stdlibs/math/const_test.gno @@ -31,76 +31,19 @@ func TestMaxUint(t *testing.T) { } func TestMaxInt(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if r != "addition overflow" { - panic(r) - } - } - }() - v := int(math.MaxInt) - if v+1 == math.MinInt { - t.Errorf("int should overflow") + if v := int(math.MaxInt); v+1 != math.MinInt { + t.Errorf("MaxInt should wrap around to MinInt: %d", v+1) } - t.Errorf("expected panic did not occur") -} - -func TestMaxInt8(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if r != "addition overflow" { - panic(r) - } - } - }() - v := int8(math.MaxInt8) - if v+1 == math.MinInt8 { - t.Errorf("int8 should overflow") + if v := int8(math.MaxInt8); v+1 != math.MinInt8 { + t.Errorf("MaxInt8 should wrap around to MinInt8: %d", v+1) } - t.Errorf("expected panic did not occur") -} - -func TestMaxInt16(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if r != "addition overflow" { - panic(r) - } - } - }() - v := int16(math.MaxInt16) - if v+1 == math.MinInt16 { - t.Errorf("int16 should overflow") + if v := int16(math.MaxInt16); v+1 != math.MinInt16 { + t.Errorf("MaxInt16 should wrap around to MinInt16: %d", v+1) } - t.Errorf("expected panic did not occur") -} - -func TestMaxInt32(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if r != "addition overflow" { - panic(r) - } - } - }() - v := int32(math.MaxInt32) - if v+1 == math.MinInt32 { - t.Errorf("int32 should overflow") + if v := int32(math.MaxInt32); v+1 != math.MinInt32 { + t.Errorf("MaxInt32 should wrap around to MinInt32: %d", v+1) } - t.Errorf("expected panic did not occur") -} - -func TestMaxInt64(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if r != "addition overflow" { - panic(r) - } - } - }() - v := int64(math.MaxInt64) - if v+1 == math.MinInt64 { - t.Errorf("int64 should overflow") + if v := int64(math.MaxInt64); v+1 != math.MinInt64 { + t.Errorf("MaxInt64 should wrap around to MinInt64: %d", v+1) } - t.Errorf("expected panic did not occur") } diff --git a/gnovm/stdlibs/math/overflow/overflow.gno b/gnovm/stdlibs/math/overflow/overflow.gno new file mode 100644 index 00000000000..0bc2e03a522 --- /dev/null +++ b/gnovm/stdlibs/math/overflow/overflow.gno @@ -0,0 +1,501 @@ +// This is modified from https://github.com/JohnCGriffin/overflow (MIT). +// NOTE: there was a bug with the original Quotient* functions, and +// testing method. These have been fixed here, and tests ported to +// tests/files/maths_int*.go respectively. +// Note: moved over from p/demo/maths. + +/* +Package overflow offers overflow-checked integer arithmetic operations +for int, int32, and int64. Each of the operations returns a +result,bool combination. This was prompted by the need to know when +to flow into higher precision types from the math.big library. + +For instance, assuing a 64 bit machine: + +10 + 20 -> 30 +int(math.MaxInt64) + 1 -> -9223372036854775808 + +whereas + +overflow.Add(10,20) -> (30, true) +overflow.Add(math.MaxInt64,1) -> (0, false) + +Add, Sub, Mul, Div are for int. Add64, Add32, etc. are specifically sized. + +If anybody wishes an unsigned version, submit a pull request for code +and new tests. +*/ +package overflow + +import "math" + +//go:generate ./overflow_template.sh + +func _is64Bit() bool { + maxU32 := uint(math.MaxUint32) + return ((maxU32 << 1) >> 1) == maxU32 +} + +/********** PARTIAL TEST COVERAGE FROM HERE DOWN ************* + +The only way that I could see to do this is a combination of +my normal 64 bit system and a GopherJS running on Node. My +understanding is that its ints are 32 bit. + +So, FEEL FREE to carefully review the code visually. + +*************************************************************/ + +// Unspecified size, i.e. normal signed int + +// Add sums two ints, returning the result and a boolean status. +func Add(a, b int) (int, bool) { + if _is64Bit() { + r64, ok := Add64(int64(a), int64(b)) + return int(r64), ok + } + r32, ok := Add32(int32(a), int32(b)) + return int(r32), ok +} + +// Sub returns the difference of two ints and a boolean status. +func Sub(a, b int) (int, bool) { + if _is64Bit() { + r64, ok := Sub64(int64(a), int64(b)) + return int(r64), ok + } + r32, ok := Sub32(int32(a), int32(b)) + return int(r32), ok +} + +// Mul returns the product of two ints and a boolean status. +func Mul(a, b int) (int, bool) { + if _is64Bit() { + r64, ok := Mul64(int64(a), int64(b)) + return int(r64), ok + } + r32, ok := Mul32(int32(a), int32(b)) + return int(r32), ok +} + +// Div returns the quotient of two ints and a boolean status +func Div(a, b int) (int, bool) { + if _is64Bit() { + r64, ok := Div64(int64(a), int64(b)) + return int(r64), ok + } + r32, ok := Div32(int32(a), int32(b)) + return int(r32), ok +} + +// Quo returns the quotient, remainder and status of two ints +func Quo(a, b int) (int, int, bool) { + if _is64Bit() { + q64, r64, ok := Quo64(int64(a), int64(b)) + return int(q64), int(r64), ok + } + q32, r32, ok := Quo32(int32(a), int32(b)) + return int(q32), int(r32), ok +} + +/************* Panic versions for int ****************/ + +// Addp returns the sum of two ints, panicking on overflow +func Addp(a, b int) int { + r, ok := Add(a, b) + if !ok { + panic("addition overflow") + } + return r +} + +// Subp returns the difference of two ints, panicking on overflow. +func Subp(a, b int) int { + r, ok := Sub(a, b) + if !ok { + panic("subtraction overflow") + } + return r +} + +// Mulp returns the product of two ints, panicking on overflow. +func Mulp(a, b int) int { + r, ok := Mul(a, b) + if !ok { + panic("multiplication overflow") + } + return r +} + +// Divp returns the quotient of two ints, panicking on overflow. +func Divp(a, b int) int { + r, ok := Div(a, b) + if !ok { + panic("division failure") + } + return r +} + +//---------------------------------------- +// This is generated code, created by overflow_template.sh executed +// by "go generate" + +// Add8 performs + operation on two int8 operands +// returning a result and status +func Add8(a, b int8) (int8, bool) { + c := a + b + if (c > a) == (b > 0) { + return c, true + } + return c, false +} + +// Add8p is the unchecked panicking version of Add8 +func Add8p(a, b int8) int8 { + r, ok := Add8(a, b) + if !ok { + panic("addition overflow") + } + return r +} + +// Sub8 performs - operation on two int8 operands +// returning a result and status +func Sub8(a, b int8) (int8, bool) { + c := a - b + if (c < a) == (b > 0) { + return c, true + } + return c, false +} + +// Sub8p is the unchecked panicking version of Sub8 +func Sub8p(a, b int8) int8 { + r, ok := Sub8(a, b) + if !ok { + panic("subtraction overflow") + } + return r +} + +// Mul8 performs * operation on two int8 operands +// returning a result and status +func Mul8(a, b int8) (int8, bool) { + if a == 0 || b == 0 { + return 0, true + } + c := a * b + if (c < 0) == ((a < 0) != (b < 0)) { + if c/b == a { + return c, true + } + } + return c, false +} + +// Mul8p is the unchecked panicking version of Mul8 +func Mul8p(a, b int8) int8 { + r, ok := Mul8(a, b) + if !ok { + panic("multiplication overflow") + } + return r +} + +// Div8 performs / operation on two int8 operands +// returning a result and status +func Div8(a, b int8) (int8, bool) { + q, _, ok := Quo8(a, b) + return q, ok +} + +// Div8p is the unchecked panicking version of Div8 +func Div8p(a, b int8) int8 { + r, ok := Div8(a, b) + if !ok { + panic("division failure") + } + return r +} + +// Quo8 performs + operation on two int8 operands +// returning a quotient, a remainder and status +func Quo8(a, b int8) (int8, int8, bool) { + if b == 0 { + return 0, 0, false + } else if b == -1 && a == int8(math.MinInt8) { + return 0, 0, false + } + c := a / b + return c, a % b, true +} + +// Add16 performs + operation on two int16 operands +// returning a result and status +func Add16(a, b int16) (int16, bool) { + c := a + b + if (c > a) == (b > 0) { + return c, true + } + return c, false +} + +// Add16p is the unchecked panicking version of Add16 +func Add16p(a, b int16) int16 { + r, ok := Add16(a, b) + if !ok { + panic("addition overflow") + } + return r +} + +// Sub16 performs - operation on two int16 operands +// returning a result and status +func Sub16(a, b int16) (int16, bool) { + c := a - b + if (c < a) == (b > 0) { + return c, true + } + return c, false +} + +// Sub16p is the unchecked panicking version of Sub16 +func Sub16p(a, b int16) int16 { + r, ok := Sub16(a, b) + if !ok { + panic("subtraction overflow") + } + return r +} + +// Mul16 performs * operation on two int16 operands +// returning a result and status +func Mul16(a, b int16) (int16, bool) { + if a == 0 || b == 0 { + return 0, true + } + c := a * b + if (c < 0) == ((a < 0) != (b < 0)) { + if c/b == a { + return c, true + } + } + return c, false +} + +// Mul16p is the unchecked panicking version of Mul16 +func Mul16p(a, b int16) int16 { + r, ok := Mul16(a, b) + if !ok { + panic("multiplication overflow") + } + return r +} + +// Div16 performs / operation on two int16 operands +// returning a result and status +func Div16(a, b int16) (int16, bool) { + q, _, ok := Quo16(a, b) + return q, ok +} + +// Div16p is the unchecked panicking version of Div16 +func Div16p(a, b int16) int16 { + r, ok := Div16(a, b) + if !ok { + panic("division failure") + } + return r +} + +// Quo16 performs + operation on two int16 operands +// returning a quotient, a remainder and status +func Quo16(a, b int16) (int16, int16, bool) { + if b == 0 { + return 0, 0, false + } else if b == -1 && a == int16(math.MinInt16) { + return 0, 0, false + } + c := a / b + return c, a % b, true +} + +// Add32 performs + operation on two int32 operands +// returning a result and status +func Add32(a, b int32) (int32, bool) { + c := a + b + if (c > a) == (b > 0) { + return c, true + } + return c, false +} + +// Add32p is the unchecked panicking version of Add32 +func Add32p(a, b int32) int32 { + r, ok := Add32(a, b) + if !ok { + panic("addition overflow") + } + return r +} + +// Sub32 performs - operation on two int32 operands +// returning a result and status +func Sub32(a, b int32) (int32, bool) { + c := a - b + if (c < a) == (b > 0) { + return c, true + } + return c, false +} + +// Sub32p is the unchecked panicking version of Sub32 +func Sub32p(a, b int32) int32 { + r, ok := Sub32(a, b) + if !ok { + panic("subtraction overflow") + } + return r +} + +// Mul32 performs * operation on two int32 operands +// returning a result and status +func Mul32(a, b int32) (int32, bool) { + if a == 0 || b == 0 { + return 0, true + } + c := a * b + if (c < 0) == ((a < 0) != (b < 0)) { + if c/b == a { + return c, true + } + } + return c, false +} + +// Mul32p is the unchecked panicking version of Mul32 +func Mul32p(a, b int32) int32 { + r, ok := Mul32(a, b) + if !ok { + panic("multiplication overflow") + } + return r +} + +// Div32 performs / operation on two int32 operands +// returning a result and status +func Div32(a, b int32) (int32, bool) { + q, _, ok := Quo32(a, b) + return q, ok +} + +// Div32p is the unchecked panicking version of Div32 +func Div32p(a, b int32) int32 { + r, ok := Div32(a, b) + if !ok { + panic("division failure") + } + return r +} + +// Quo32 performs + operation on two int32 operands +// returning a quotient, a remainder and status +func Quo32(a, b int32) (int32, int32, bool) { + if b == 0 { + return 0, 0, false + } else if b == -1 && a == int32(math.MinInt32) { + return 0, 0, false + } + c := a / b + return c, a % b, true +} + +// Add64 performs + operation on two int64 operands +// returning a result and status +func Add64(a, b int64) (int64, bool) { + c := a + b + if (c > a) == (b > 0) { + return c, true + } + return c, false +} + +// Add64p is the unchecked panicking version of Add64 +func Add64p(a, b int64) int64 { + r, ok := Add64(a, b) + if !ok { + panic("addition overflow") + } + return r +} + +// Sub64 performs - operation on two int64 operands +// returning a result and status +func Sub64(a, b int64) (int64, bool) { + c := a - b + if (c < a) == (b > 0) { + return c, true + } + return c, false +} + +// Sub64p is the unchecked panicking version of Sub64 +func Sub64p(a, b int64) int64 { + r, ok := Sub64(a, b) + if !ok { + panic("subtraction overflow") + } + return r +} + +// Mul64 performs * operation on two int64 operands +// returning a result and status +func Mul64(a, b int64) (int64, bool) { + if a == 0 || b == 0 { + return 0, true + } + c := a * b + if (c < 0) == ((a < 0) != (b < 0)) { + if c/b == a { + return c, true + } + } + return c, false +} + +// Mul64p is the unchecked panicking version of Mul64 +func Mul64p(a, b int64) int64 { + r, ok := Mul64(a, b) + if !ok { + panic("multiplication overflow") + } + return r +} + +// Div64 performs / operation on two int64 operands +// returning a result and status +func Div64(a, b int64) (int64, bool) { + q, _, ok := Quo64(a, b) + return q, ok +} + +// Div64p is the unchecked panicking version of Div64 +func Div64p(a, b int64) int64 { + r, ok := Div64(a, b) + if !ok { + panic("division failure") + } + return r +} + +// Quo64 performs + operation on two int64 operands +// returning a quotient, a remainder and status +func Quo64(a, b int64) (int64, int64, bool) { + if b == 0 { + return 0, 0, false + } else if b == -1 && a == math.MinInt64 { + return 0, 0, false + } + c := a / b + return c, a % b, true +} diff --git a/gnovm/stdlibs/math/overflow/overflow_test.gno b/gnovm/stdlibs/math/overflow/overflow_test.gno new file mode 100644 index 00000000000..b7881aec480 --- /dev/null +++ b/gnovm/stdlibs/math/overflow/overflow_test.gno @@ -0,0 +1,200 @@ +package overflow + +import ( + "math" + "testing" +) + +// sample all possibilities of 8 bit numbers +// by checking against 64 bit numbers + +func TestAlgorithms(t *testing.T) { + errors := 0 + + for a64 := int64(math.MinInt8); a64 <= int64(math.MaxInt8); a64++ { + for b64 := int64(math.MinInt8); b64 <= int64(math.MaxInt8) && errors < 10; b64++ { + + a8 := int8(a64) + b8 := int8(b64) + + if int64(a8) != a64 || int64(b8) != b64 { + t.Fatal("LOGIC FAILURE IN TEST") + } + + // ADDITION + { + r64 := a64 + b64 + + // now the verification + result, ok := Add8(a8, b8) + if ok && int64(result) != r64 { + t.Errorf("failed to fail on %v + %v = %v instead of %v\n", + a8, b8, result, r64) + errors++ + } + if !ok && int64(result) == r64 { + t.Fail() + errors++ + } + } + + // SUBTRACTION + { + r64 := a64 - b64 + + // now the verification + result, ok := Sub8(a8, b8) + if ok && int64(result) != r64 { + t.Errorf("failed to fail on %v - %v = %v instead of %v\n", + a8, b8, result, r64) + } + if !ok && int64(result) == r64 { + t.Fail() + errors++ + } + } + + // MULTIPLICATION + { + r64 := a64 * b64 + + // now the verification + result, ok := Mul8(a8, b8) + if ok && int64(result) != r64 { + t.Errorf("failed to fail on %v * %v = %v instead of %v\n", + a8, b8, result, r64) + errors++ + } + if !ok && int64(result) == r64 { + t.Fail() + errors++ + } + } + + // DIVISION + if b8 != 0 { + r64 := a64 / b64 + rem64 := a64 % b64 + + // now the verification + result, rem, ok := Quo8(a8, b8) + if ok && int64(result) != r64 { + t.Errorf("failed to fail on %v / %v = %v instead of %v\n", + a8, b8, result, r64) + errors++ + } + if ok && int64(rem) != rem64 { + t.Errorf("failed to fail on %v %% %v = %v instead of %v\n", + a8, b8, rem, rem64) + errors++ + } + } + } + } +} + +func TestQuotient(t *testing.T) { + q, r, ok := Quo(100, 3) + if r != 1 || q != 33 || !ok { + t.Errorf("expected 100/3 => 33, r=1") + } + if _, _, ok = Quo(1, 0); ok { + t.Error("unexpected lack of failure") + } +} + +func TestLong(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctr := int64(0) + + for a64 := int64(math.MinInt16); a64 <= int64(math.MaxInt16); a64++ { + for b64 := int64(math.MinInt16); b64 <= int64(math.MaxInt16); b64++ { + a16 := int16(a64) + b16 := int16(b64) + if int64(a16) != a64 || int64(b16) != b64 { + panic("LOGIC FAILURE IN TEST") + } + ctr++ + + // ADDITION + { + r64 := a64 + b64 + + // now the verification + result, ok := Add16(a16, b16) + if int64(math.MinInt16) <= r64 && r64 <= int64(math.MaxInt16) { + if !ok || int64(result) != r64 { + println("add", a16, b16, result, r64) + panic("incorrect result for non-overflow") + } + } else { + if ok { + println("add", a16, b16, result, r64) + panic("incorrect ok result") + } + } + } + + // SUBTRACTION + { + r64 := a64 - b64 + + // now the verification + result, ok := Sub16(a16, b16) + if int64(math.MinInt16) <= r64 && r64 <= int64(math.MaxInt16) { + if !ok || int64(result) != r64 { + println("sub", a16, b16, result, r64) + panic("incorrect result for non-overflow") + } + } else { + if ok { + println("sub", a16, b16, result, r64) + panic("incorrect ok result") + } + } + } + + // MULTIPLICATION + { + r64 := a64 * b64 + + // now the verification + result, ok := Mul16(a16, b16) + if int64(math.MinInt16) <= r64 && r64 <= int64(math.MaxInt16) { + if !ok || int64(result) != r64 { + println("mul", a16, b16, result, r64) + panic("incorrect result for non-overflow") + } + } else { + if ok { + println("mul", a16, b16, result, r64) + panic("incorrect ok result") + } + } + } + + // DIVISION + if b16 != 0 { + r64 := a64 / b64 + + // now the verification + result, _, ok := Quo16(a16, b16) + if int64(math.MinInt16) <= r64 && r64 <= int64(math.MaxInt16) { + if !ok || int64(result) != r64 { + println("quo", a16, b16, result, r64) + panic("incorrect result for non-overflow") + } + } else { + if ok { + println("quo", a16, b16, result, r64) + panic("incorrect ok result") + } + } + } + } + } + println("done", ctr) +} diff --git a/gnovm/stdlibs/std/coins.gno b/gnovm/stdlibs/std/coins.gno index 679674e443e..47e88e238d2 100644 --- a/gnovm/stdlibs/std/coins.gno +++ b/gnovm/stdlibs/std/coins.gno @@ -1,6 +1,9 @@ package std -import "strconv" +import ( + "math/overflow" + "strconv" +) // NOTE: this is selectively copied over from tm2/pkgs/std/coin.go @@ -53,7 +56,13 @@ func (c Coin) IsEqual(other Coin) bool { // An invalid result panics. func (c Coin) Add(other Coin) Coin { mustMatchDenominations(c.Denom, other.Denom) - c.Amount += other.Amount + + sum, ok := overflow.Add64(c.Amount, other.Amount) + if !ok { + panic("coin add overflow/underflow: " + strconv.Itoa(int(c.Amount)) + " +/- " + strconv.Itoa(int(other.Amount))) + } + + c.Amount = sum return c } @@ -63,7 +72,13 @@ func (c Coin) Add(other Coin) Coin { // An invalid result panics. func (c Coin) Sub(other Coin) Coin { mustMatchDenominations(c.Denom, other.Denom) - c.Amount -= other.Amount + + dff, ok := overflow.Sub64(c.Amount, other.Amount) + if !ok { + panic("coin sub overflow/underflow: " + strconv.Itoa(int(c.Amount)) + " +/- " + strconv.Itoa(int(other.Amount))) + } + c.Amount = dff + return c } @@ -98,7 +113,10 @@ func NewCoins(coins ...Coin) Coins { for _, coin := range coins { if currentAmount, exists := coinMap[coin.Denom]; exists { - coinMap[coin.Denom] = currentAmount + coin.Amount + var ok bool + if coinMap[coin.Denom], ok = overflow.Add64(currentAmount, coin.Amount); !ok { + panic("coin sub overflow/underflow: " + strconv.Itoa(int(currentAmount)) + " +/- " + strconv.Itoa(int(coin.Amount))) + } } else { coinMap[coin.Denom] = coin.Amount } diff --git a/gnovm/tests/files/overflow0.gno b/gnovm/tests/files/overflow0.gno deleted file mode 100644 index 1313f064322..00000000000 --- a/gnovm/tests/files/overflow0.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - var a, b, c int8 = -1<<7, -1, 0 - c = a / b // overflow: -128 instead of 128 - println(c) -} - -// Error: -// division by zero or overflow diff --git a/gnovm/tests/files/overflow1.gno b/gnovm/tests/files/overflow1.gno deleted file mode 100644 index a416e9a3498..00000000000 --- a/gnovm/tests/files/overflow1.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - var a, b, c int16 = -1<<15, -1, 0 - c = a / b // overflow: -32768 instead of 32768 - println(c) -} - -// Error: -// division by zero or overflow diff --git a/gnovm/tests/files/overflow2.gno b/gnovm/tests/files/overflow2.gno deleted file mode 100644 index 353729bcdf2..00000000000 --- a/gnovm/tests/files/overflow2.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - var a, b, c int32 = -1<<31, -1, 0 - c = a / b // overflow: -2147483648 instead of 2147483648 - println(c) -} - -// Error: -// division by zero or overflow diff --git a/gnovm/tests/files/overflow3.gno b/gnovm/tests/files/overflow3.gno deleted file mode 100644 index a09c59dfb03..00000000000 --- a/gnovm/tests/files/overflow3.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - var a, b, c int64 = -1<<63, -1, 0 - c = a / b // overflow: -9223372036854775808 instead of 9223372036854775808 - println(c) -} - -// Error: -// division by zero or overflow diff --git a/gnovm/tests/files/overflow4.gno b/gnovm/tests/files/overflow4.gno deleted file mode 100644 index 26b05567b07..00000000000 --- a/gnovm/tests/files/overflow4.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - var a, b, c int = -1<<63, -1, 0 - c = a / b // overflow: -9223372036854775808 instead of 9223372036854775808 - println(c) -} - -// Error: -// division by zero or overflow diff --git a/gnovm/tests/files/overflow5.gno b/gnovm/tests/files/overflow5.gno deleted file mode 100644 index ef7f976eb24..00000000000 --- a/gnovm/tests/files/overflow5.gno +++ /dev/null @@ -1,10 +0,0 @@ -package main - -func main() { - var a, b, c int = -5, 7, 0 - c = a % b // 0 quotient triggers a false negative in gnolang/overflow - println(c) -} - -// Output: -// -5 diff --git a/gnovm/tests/files/recover14.gno b/gnovm/tests/files/recover14.gno index 3c96404fcbe..30a34ab291a 100644 --- a/gnovm/tests/files/recover14.gno +++ b/gnovm/tests/files/recover14.gno @@ -12,4 +12,4 @@ func main() { } // Output: -// recover: division by zero or overflow +// recover: division by zero diff --git a/misc/genstd/util.go b/misc/genstd/util.go index 13e90836f36..025fe4b673e 100644 --- a/misc/genstd/util.go +++ b/misc/genstd/util.go @@ -70,8 +70,7 @@ func findDirs() (gitRoot string, relPath string, err error) { } p := wd for { - // .git is normally a directory, or a file in case of a git worktree. - if _, e := os.Stat(filepath.Join(p, ".git")); e == nil { + if s, e := os.Stat(filepath.Join(p, ".git")); e == nil && s.IsDir() { // make relPath relative to the git root rp := strings.TrimPrefix(wd, p+string(filepath.Separator)) // normalize separator to / From 6909efaac0d4211c3ce894e052fd0d7b90112809 Mon Sep 17 00:00:00 2001 From: Morgan Date: Tue, 14 Jan 2025 17:23:39 +0100 Subject: [PATCH 06/13] refactor(gnovm): move go type checking to own file (#3491) --- gnovm/pkg/gnolang/go2gno.go | 173 ------------- gnovm/pkg/gnolang/go2gno_test.go | 352 ------------------------- gnovm/pkg/gnolang/gotypecheck.go | 179 +++++++++++++ gnovm/pkg/gnolang/gotypecheck_test.go | 359 ++++++++++++++++++++++++++ 4 files changed, 538 insertions(+), 525 deletions(-) create mode 100644 gnovm/pkg/gnolang/gotypecheck.go create mode 100644 gnovm/pkg/gnolang/gotypecheck_test.go diff --git a/gnovm/pkg/gnolang/go2gno.go b/gnovm/pkg/gnolang/go2gno.go index 82d5c69b08b..4c9de87a6a7 100644 --- a/gnovm/pkg/gnolang/go2gno.go +++ b/gnovm/pkg/gnolang/go2gno.go @@ -31,24 +31,16 @@ package gnolang */ import ( - "bytes" "fmt" "go/ast" - "go/format" "go/parser" "go/token" - "go/types" "os" - "path" "reflect" - "slices" "strconv" - "strings" "github.com/davecgh/go-spew/spew" - "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/tm2/pkg/errors" - "go.uber.org/multierr" ) func MustReadFile(path string) *FileNode { @@ -483,171 +475,6 @@ func Go2Gno(fs *token.FileSet, gon ast.Node) (n Node) { } } -//---------------------------------------- -// type checking (using go/types) -// XXX move to gotypecheck.go. - -// MemPackageGetter implements the GetMemPackage() method. It is a subset of -// [Store], separated for ease of testing. -type MemPackageGetter interface { - GetMemPackage(path string) *gnovm.MemPackage -} - -// TypeCheckMemPackage performs type validation and checking on the given -// mempkg. To retrieve dependencies, it uses getter. -// -// The syntax checking is performed entirely using Go's go/types package. -// -// If format is true, the code will be automatically updated with the -// formatted source code. -func TypeCheckMemPackage(mempkg *gnovm.MemPackage, getter MemPackageGetter, format bool) error { - return typeCheckMemPackage(mempkg, getter, false, format) -} - -// TypeCheckMemPackageTest performs the same type checks as [TypeCheckMemPackage], -// but allows re-declarations. -// -// Note: like TypeCheckMemPackage, this function ignores tests and filetests. -func TypeCheckMemPackageTest(mempkg *gnovm.MemPackage, getter MemPackageGetter) error { - return typeCheckMemPackage(mempkg, getter, true, false) -} - -func typeCheckMemPackage(mempkg *gnovm.MemPackage, getter MemPackageGetter, testing, format bool) error { - var errs error - imp := &gnoImporter{ - getter: getter, - cache: map[string]gnoImporterResult{}, - cfg: &types.Config{ - Error: func(err error) { - errs = multierr.Append(errs, err) - }, - }, - allowRedefinitions: testing, - } - imp.cfg.Importer = imp - - _, err := imp.parseCheckMemPackage(mempkg, format) - // prefer to return errs instead of err: - // err will generally contain only the first error encountered. - if errs != nil { - return errs - } - return err -} - -type gnoImporterResult struct { - pkg *types.Package - err error -} - -type gnoImporter struct { - getter MemPackageGetter - cache map[string]gnoImporterResult - cfg *types.Config - - // allow symbol redefinitions? (test standard libraries) - allowRedefinitions bool -} - -// Unused, but satisfies the Importer interface. -func (g *gnoImporter) Import(path string) (*types.Package, error) { - return g.ImportFrom(path, "", 0) -} - -type importNotFoundError string - -func (e importNotFoundError) Error() string { return "import not found: " + string(e) } - -// ImportFrom returns the imported package for the given import -// path when imported by a package file located in dir. -func (g *gnoImporter) ImportFrom(path, _ string, _ types.ImportMode) (*types.Package, error) { - if pkg, ok := g.cache[path]; ok { - return pkg.pkg, pkg.err - } - mpkg := g.getter.GetMemPackage(path) - if mpkg == nil { - err := importNotFoundError(path) - g.cache[path] = gnoImporterResult{err: err} - return nil, err - } - fmt := false - result, err := g.parseCheckMemPackage(mpkg, fmt) - g.cache[path] = gnoImporterResult{pkg: result, err: err} - return result, err -} - -func (g *gnoImporter) parseCheckMemPackage(mpkg *gnovm.MemPackage, fmt bool) (*types.Package, error) { - // This map is used to allow for function re-definitions, which are allowed - // in Gno (testing context) but not in Go. - // This map links each function identifier with a closure to remove its - // associated declaration. - var delFunc map[string]func() - if g.allowRedefinitions { - delFunc = make(map[string]func()) - } - - fset := token.NewFileSet() - files := make([]*ast.File, 0, len(mpkg.Files)) - var errs error - for _, file := range mpkg.Files { - // Ignore non-gno files. - // TODO: support filetest type checking. (should probably handle as each its - // own separate pkg, which should also be typechecked) - if !strings.HasSuffix(file.Name, ".gno") || - strings.HasSuffix(file.Name, "_test.gno") || - strings.HasSuffix(file.Name, "_filetest.gno") { - continue - } - - const parseOpts = parser.ParseComments | parser.DeclarationErrors | parser.SkipObjectResolution - f, err := parser.ParseFile(fset, path.Join(mpkg.Path, file.Name), file.Body, parseOpts) - if err != nil { - errs = multierr.Append(errs, err) - continue - } - - if delFunc != nil { - deleteOldIdents(delFunc, f) - } - - // enforce formatting - if fmt { - var buf bytes.Buffer - err = format.Node(&buf, fset, f) - if err != nil { - errs = multierr.Append(errs, err) - continue - } - file.Body = buf.String() - } - - files = append(files, f) - } - if errs != nil { - return nil, errs - } - - return g.cfg.Check(mpkg.Path, fset, files, nil) -} - -func deleteOldIdents(idents map[string]func(), f *ast.File) { - for _, decl := range f.Decls { - fd, ok := decl.(*ast.FuncDecl) - if !ok || fd.Recv != nil { // ignore methods - continue - } - if del := idents[fd.Name.Name]; del != nil { - del() - } - decl := decl - idents[fd.Name.Name] = func() { - // NOTE: cannot use the index as a file may contain multiple decls to be removed, - // so removing one would make all "later" indexes wrong. - f.Decls = slices.DeleteFunc(f.Decls, func(d ast.Decl) bool { return decl == d }) - } - } -} - //---------------------------------------- // utility methods diff --git a/gnovm/pkg/gnolang/go2gno_test.go b/gnovm/pkg/gnolang/go2gno_test.go index 8aba5d7f293..920c5acd9c8 100644 --- a/gnovm/pkg/gnolang/go2gno_test.go +++ b/gnovm/pkg/gnolang/go2gno_test.go @@ -4,10 +4,7 @@ import ( "fmt" "testing" - "github.com/gnolang/gno/gnovm" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.uber.org/multierr" ) func TestParseForLoop(t *testing.T) { @@ -28,352 +25,3 @@ func main(){ fmt.Printf("AST:\n%#v\n\n", n) fmt.Printf("AST.String():\n%s\n", n.String()) } - -type mockPackageGetter []*gnovm.MemPackage - -func (mi mockPackageGetter) GetMemPackage(path string) *gnovm.MemPackage { - for _, pkg := range mi { - if pkg.Path == path { - return pkg - } - } - return nil -} - -type mockPackageGetterCounts struct { - mockPackageGetter - counts map[string]int -} - -func (mpg mockPackageGetterCounts) GetMemPackage(path string) *gnovm.MemPackage { - mpg.counts[path]++ - return mpg.mockPackageGetter.GetMemPackage(path) -} - -func TestTypeCheckMemPackage(t *testing.T) { - t.Parallel() - - // if len(ss) > 0, then multierr.Errors must decompose it in errors, and - // each error in order must contain the associated string. - errContains := func(s0 string, ss ...string) func(*testing.T, error) { - return func(t *testing.T, err error) { - t.Helper() - errs := multierr.Errors(err) - if len(errs) == 0 { - t.Errorf("expected an error, got nil") - return - } - want := len(ss) + 1 - if len(errs) != want { - t.Errorf("expected %d errors, got %d", want, len(errs)) - return - } - assert.ErrorContains(t, errs[0], s0) - for idx, err := range errs[1:] { - assert.ErrorContains(t, err, ss[idx]) - } - } - } - - type testCase struct { - name string - pkg *gnovm.MemPackage - getter MemPackageGetter - check func(*testing.T, error) - } - tt := []testCase{ - { - "Simple", - &gnovm.MemPackage{ - Name: "hello", - Path: "gno.land/p/demo/hello", - Files: []*gnovm.MemFile{ - { - Name: "hello.gno", - Body: ` - package hello - type S struct{} - func A() S { return S{} } - func B() S { return A() }`, - }, - }, - }, - nil, - nil, - }, - { - "WrongReturn", - &gnovm.MemPackage{ - Name: "hello", - Path: "gno.land/p/demo/hello", - Files: []*gnovm.MemFile{ - { - Name: "hello.gno", - Body: ` - package hello - type S struct{} - func A() S { return S{} } - func B() S { return 11 }`, - }, - }, - }, - nil, - errContains("cannot use 11"), - }, - { - "ParseError", - &gnovm.MemPackage{ - Name: "hello", - Path: "gno.land/p/demo/hello", - Files: []*gnovm.MemFile{ - { - Name: "hello.gno", - Body: ` - package hello! - func B() int { return 11 }`, - }, - }, - }, - nil, - errContains("found '!'"), - }, - { - "MultiError", - &gnovm.MemPackage{ - Name: "main", - Path: "gno.land/p/demo/main", - Files: []*gnovm.MemFile{ - { - Name: "hello.gno", - Body: ` - package main - func main() { - _, _ = 11 - return 88, 88 - }`, - }, - }, - }, - nil, - errContains("assignment mismatch", "too many return values"), - }, - { - "TestsIgnored", - &gnovm.MemPackage{ - Name: "hello", - Path: "gno.land/p/demo/hello", - Files: []*gnovm.MemFile{ - { - Name: "hello.gno", - Body: ` - package hello - func B() int { return 11 }`, - }, - { - Name: "hello_test.gno", - Body: `This is not valid Gno code, but it doesn't matter because test - files are not checked.`, - }, - }, - }, - nil, - nil, - }, - { - "ImportFailed", - &gnovm.MemPackage{ - Name: "hello", - Path: "gno.land/p/demo/hello", - Files: []*gnovm.MemFile{ - { - Name: "hello.gno", - Body: ` - package hello - import "std" - func Hello() std.Address { return "hello" }`, - }, - }, - }, - mockPackageGetter{}, - errContains("import not found: std"), - }, - { - "ImportSucceeded", - &gnovm.MemPackage{ - Name: "hello", - Path: "gno.land/p/demo/hello", - Files: []*gnovm.MemFile{ - { - Name: "hello.gno", - Body: ` - package hello - import "std" - func Hello() std.Address { return "hello" }`, - }, - }, - }, - mockPackageGetter{ - &gnovm.MemPackage{ - Name: "std", - Path: "std", - Files: []*gnovm.MemFile{ - { - Name: "gnovm.gno", - Body: ` - package std - type Address string`, - }, - }, - }, - }, - nil, - }, - { - "ImportBadIdent", - &gnovm.MemPackage{ - Name: "hello", - Path: "gno.land/p/demo/hello", - Files: []*gnovm.MemFile{ - { - Name: "hello.gno", - Body: ` - package hello - import "std" - func Hello() std.Address { return "hello" }`, - }, - }, - }, - mockPackageGetter{ - &gnovm.MemPackage{ - Name: "a_completely_different_identifier", - Path: "std", - Files: []*gnovm.MemFile{ - { - Name: "gnovm.gno", - Body: ` - package a_completely_different_identifier - type Address string`, - }, - }, - }, - }, - errContains("undefined: std", "a_completely_different_identifier and not used"), - }, - } - - cacheMpg := mockPackageGetterCounts{ - mockPackageGetter{ - &gnovm.MemPackage{ - Name: "bye", - Path: "bye", - Files: []*gnovm.MemFile{ - { - Name: "bye.gno", - Body: ` - package bye - import "std" - func Bye() std.Address { return "bye" }`, - }, - }, - }, - &gnovm.MemPackage{ - Name: "std", - Path: "std", - Files: []*gnovm.MemFile{ - { - Name: "gnovm.gno", - Body: ` - package std - type Address string`, - }, - }, - }, - }, - make(map[string]int), - } - - tt = append(tt, testCase{ - "ImportWithCache", - // This test will make use of the importer's internal cache for package `std`. - &gnovm.MemPackage{ - Name: "hello", - Path: "gno.land/p/demo/hello", - Files: []*gnovm.MemFile{ - { - Name: "hello.gno", - Body: ` - package hello - import ( - "std" - "bye" - ) - func Hello() std.Address { return bye.Bye() }`, - }, - }, - }, - cacheMpg, - func(t *testing.T, err error) { - t.Helper() - require.NoError(t, err) - assert.Equal(t, map[string]int{"std": 1, "bye": 1}, cacheMpg.counts) - }, - }) - - for _, tc := range tt { - tc := tc - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - format := false - err := TypeCheckMemPackage(tc.pkg, tc.getter, format) - if tc.check == nil { - assert.NoError(t, err) - } else { - tc.check(t, err) - } - }) - } -} - -func TestTypeCheckMemPackage_format(t *testing.T) { - t.Parallel() - - input := ` - package hello - func Hello(name string) string {return "hello" + name -} - - - -` - - pkg := &gnovm.MemPackage{ - Name: "hello", - Path: "gno.land/p/demo/hello", - Files: []*gnovm.MemFile{ - { - Name: "hello.gno", - Body: input, - }, - }, - } - - mpkgGetter := mockPackageGetter{} - format := false - err := TypeCheckMemPackage(pkg, mpkgGetter, format) - assert.NoError(t, err) - assert.Equal(t, input, pkg.Files[0].Body) // unchanged - - expected := `package hello - -func Hello(name string) string { - return "hello" + name -} -` - - format = true - err = TypeCheckMemPackage(pkg, mpkgGetter, format) - assert.NoError(t, err) - assert.NotEqual(t, input, pkg.Files[0].Body) - assert.Equal(t, expected, pkg.Files[0].Body) -} diff --git a/gnovm/pkg/gnolang/gotypecheck.go b/gnovm/pkg/gnolang/gotypecheck.go new file mode 100644 index 00000000000..8f86deb3dc5 --- /dev/null +++ b/gnovm/pkg/gnolang/gotypecheck.go @@ -0,0 +1,179 @@ +package gnolang + +import ( + "bytes" + "go/ast" + "go/format" + "go/parser" + "go/token" + "go/types" + "path" + "slices" + "strings" + + "github.com/gnolang/gno/gnovm" + "go.uber.org/multierr" +) + +// type checking (using go/types) + +// MemPackageGetter implements the GetMemPackage() method. It is a subset of +// [Store], separated for ease of testing. +type MemPackageGetter interface { + GetMemPackage(path string) *gnovm.MemPackage +} + +// TypeCheckMemPackage performs type validation and checking on the given +// mempkg. To retrieve dependencies, it uses getter. +// +// The syntax checking is performed entirely using Go's go/types package. +// +// If format is true, the code will be automatically updated with the +// formatted source code. +func TypeCheckMemPackage(mempkg *gnovm.MemPackage, getter MemPackageGetter, format bool) error { + return typeCheckMemPackage(mempkg, getter, false, format) +} + +// TypeCheckMemPackageTest performs the same type checks as [TypeCheckMemPackage], +// but allows re-declarations. +// +// Note: like TypeCheckMemPackage, this function ignores tests and filetests. +func TypeCheckMemPackageTest(mempkg *gnovm.MemPackage, getter MemPackageGetter) error { + return typeCheckMemPackage(mempkg, getter, true, false) +} + +func typeCheckMemPackage(mempkg *gnovm.MemPackage, getter MemPackageGetter, testing, format bool) error { + var errs error + imp := &gnoImporter{ + getter: getter, + cache: map[string]gnoImporterResult{}, + cfg: &types.Config{ + Error: func(err error) { + errs = multierr.Append(errs, err) + }, + }, + allowRedefinitions: testing, + } + imp.cfg.Importer = imp + + _, err := imp.parseCheckMemPackage(mempkg, format) + // prefer to return errs instead of err: + // err will generally contain only the first error encountered. + if errs != nil { + return errs + } + return err +} + +type gnoImporterResult struct { + pkg *types.Package + err error +} + +type gnoImporter struct { + getter MemPackageGetter + cache map[string]gnoImporterResult + cfg *types.Config + + // allow symbol redefinitions? (test standard libraries) + allowRedefinitions bool +} + +// Unused, but satisfies the Importer interface. +func (g *gnoImporter) Import(path string) (*types.Package, error) { + return g.ImportFrom(path, "", 0) +} + +type importNotFoundError string + +func (e importNotFoundError) Error() string { return "import not found: " + string(e) } + +// ImportFrom returns the imported package for the given import +// path when imported by a package file located in dir. +func (g *gnoImporter) ImportFrom(path, _ string, _ types.ImportMode) (*types.Package, error) { + if pkg, ok := g.cache[path]; ok { + return pkg.pkg, pkg.err + } + mpkg := g.getter.GetMemPackage(path) + if mpkg == nil { + err := importNotFoundError(path) + g.cache[path] = gnoImporterResult{err: err} + return nil, err + } + fmt := false + result, err := g.parseCheckMemPackage(mpkg, fmt) + g.cache[path] = gnoImporterResult{pkg: result, err: err} + return result, err +} + +func (g *gnoImporter) parseCheckMemPackage(mpkg *gnovm.MemPackage, fmt bool) (*types.Package, error) { + // This map is used to allow for function re-definitions, which are allowed + // in Gno (testing context) but not in Go. + // This map links each function identifier with a closure to remove its + // associated declaration. + var delFunc map[string]func() + if g.allowRedefinitions { + delFunc = make(map[string]func()) + } + + fset := token.NewFileSet() + files := make([]*ast.File, 0, len(mpkg.Files)) + var errs error + for _, file := range mpkg.Files { + // Ignore non-gno files. + // TODO: support filetest type checking. (should probably handle as each its + // own separate pkg, which should also be typechecked) + if !strings.HasSuffix(file.Name, ".gno") || + strings.HasSuffix(file.Name, "_test.gno") || + strings.HasSuffix(file.Name, "_filetest.gno") { + continue + } + + const parseOpts = parser.ParseComments | parser.DeclarationErrors | parser.SkipObjectResolution + f, err := parser.ParseFile(fset, path.Join(mpkg.Path, file.Name), file.Body, parseOpts) + if err != nil { + errs = multierr.Append(errs, err) + continue + } + + if delFunc != nil { + deleteOldIdents(delFunc, f) + } + + // enforce formatting + if fmt { + var buf bytes.Buffer + err = format.Node(&buf, fset, f) + if err != nil { + errs = multierr.Append(errs, err) + continue + } + file.Body = buf.String() + } + + files = append(files, f) + } + if errs != nil { + return nil, errs + } + + return g.cfg.Check(mpkg.Path, fset, files, nil) +} + +func deleteOldIdents(idents map[string]func(), f *ast.File) { + for _, decl := range f.Decls { + fd, ok := decl.(*ast.FuncDecl) + if !ok || fd.Recv != nil { // ignore methods + continue + } + if del := idents[fd.Name.Name]; del != nil { + del() + } + decl := decl + idents[fd.Name.Name] = func() { + // NOTE: cannot use the index as a file may contain multiple decls to be removed, + // so removing one would make all "later" indexes wrong. + f.Decls = slices.DeleteFunc(f.Decls, func(d ast.Decl) bool { return decl == d }) + } + } +} diff --git a/gnovm/pkg/gnolang/gotypecheck_test.go b/gnovm/pkg/gnolang/gotypecheck_test.go new file mode 100644 index 00000000000..259a1bc3e78 --- /dev/null +++ b/gnovm/pkg/gnolang/gotypecheck_test.go @@ -0,0 +1,359 @@ +package gnolang + +import ( + "testing" + + "github.com/gnolang/gno/gnovm" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/multierr" +) + +type mockPackageGetter []*gnovm.MemPackage + +func (mi mockPackageGetter) GetMemPackage(path string) *gnovm.MemPackage { + for _, pkg := range mi { + if pkg.Path == path { + return pkg + } + } + return nil +} + +type mockPackageGetterCounts struct { + mockPackageGetter + counts map[string]int +} + +func (mpg mockPackageGetterCounts) GetMemPackage(path string) *gnovm.MemPackage { + mpg.counts[path]++ + return mpg.mockPackageGetter.GetMemPackage(path) +} + +func TestTypeCheckMemPackage(t *testing.T) { + t.Parallel() + + // if len(ss) > 0, then multierr.Errors must decompose it in errors, and + // each error in order must contain the associated string. + errContains := func(s0 string, ss ...string) func(*testing.T, error) { + return func(t *testing.T, err error) { + t.Helper() + errs := multierr.Errors(err) + if len(errs) == 0 { + t.Errorf("expected an error, got nil") + return + } + want := len(ss) + 1 + if len(errs) != want { + t.Errorf("expected %d errors, got %d", want, len(errs)) + return + } + assert.ErrorContains(t, errs[0], s0) + for idx, err := range errs[1:] { + assert.ErrorContains(t, err, ss[idx]) + } + } + } + + type testCase struct { + name string + pkg *gnovm.MemPackage + getter MemPackageGetter + check func(*testing.T, error) + } + tt := []testCase{ + { + "Simple", + &gnovm.MemPackage{ + Name: "hello", + Path: "gno.land/p/demo/hello", + Files: []*gnovm.MemFile{ + { + Name: "hello.gno", + Body: ` + package hello + type S struct{} + func A() S { return S{} } + func B() S { return A() }`, + }, + }, + }, + nil, + nil, + }, + { + "WrongReturn", + &gnovm.MemPackage{ + Name: "hello", + Path: "gno.land/p/demo/hello", + Files: []*gnovm.MemFile{ + { + Name: "hello.gno", + Body: ` + package hello + type S struct{} + func A() S { return S{} } + func B() S { return 11 }`, + }, + }, + }, + nil, + errContains("cannot use 11"), + }, + { + "ParseError", + &gnovm.MemPackage{ + Name: "hello", + Path: "gno.land/p/demo/hello", + Files: []*gnovm.MemFile{ + { + Name: "hello.gno", + Body: ` + package hello! + func B() int { return 11 }`, + }, + }, + }, + nil, + errContains("found '!'"), + }, + { + "MultiError", + &gnovm.MemPackage{ + Name: "main", + Path: "gno.land/p/demo/main", + Files: []*gnovm.MemFile{ + { + Name: "hello.gno", + Body: ` + package main + func main() { + _, _ = 11 + return 88, 88 + }`, + }, + }, + }, + nil, + errContains("assignment mismatch", "too many return values"), + }, + { + "TestsIgnored", + &gnovm.MemPackage{ + Name: "hello", + Path: "gno.land/p/demo/hello", + Files: []*gnovm.MemFile{ + { + Name: "hello.gno", + Body: ` + package hello + func B() int { return 11 }`, + }, + { + Name: "hello_test.gno", + Body: `This is not valid Gno code, but it doesn't matter because test + files are not checked.`, + }, + }, + }, + nil, + nil, + }, + { + "ImportFailed", + &gnovm.MemPackage{ + Name: "hello", + Path: "gno.land/p/demo/hello", + Files: []*gnovm.MemFile{ + { + Name: "hello.gno", + Body: ` + package hello + import "std" + func Hello() std.Address { return "hello" }`, + }, + }, + }, + mockPackageGetter{}, + errContains("import not found: std"), + }, + { + "ImportSucceeded", + &gnovm.MemPackage{ + Name: "hello", + Path: "gno.land/p/demo/hello", + Files: []*gnovm.MemFile{ + { + Name: "hello.gno", + Body: ` + package hello + import "std" + func Hello() std.Address { return "hello" }`, + }, + }, + }, + mockPackageGetter{ + &gnovm.MemPackage{ + Name: "std", + Path: "std", + Files: []*gnovm.MemFile{ + { + Name: "gnovm.gno", + Body: ` + package std + type Address string`, + }, + }, + }, + }, + nil, + }, + { + "ImportBadIdent", + &gnovm.MemPackage{ + Name: "hello", + Path: "gno.land/p/demo/hello", + Files: []*gnovm.MemFile{ + { + Name: "hello.gno", + Body: ` + package hello + import "std" + func Hello() std.Address { return "hello" }`, + }, + }, + }, + mockPackageGetter{ + &gnovm.MemPackage{ + Name: "a_completely_different_identifier", + Path: "std", + Files: []*gnovm.MemFile{ + { + Name: "gnovm.gno", + Body: ` + package a_completely_different_identifier + type Address string`, + }, + }, + }, + }, + errContains("undefined: std", "a_completely_different_identifier and not used"), + }, + } + + cacheMpg := mockPackageGetterCounts{ + mockPackageGetter{ + &gnovm.MemPackage{ + Name: "bye", + Path: "bye", + Files: []*gnovm.MemFile{ + { + Name: "bye.gno", + Body: ` + package bye + import "std" + func Bye() std.Address { return "bye" }`, + }, + }, + }, + &gnovm.MemPackage{ + Name: "std", + Path: "std", + Files: []*gnovm.MemFile{ + { + Name: "gnovm.gno", + Body: ` + package std + type Address string`, + }, + }, + }, + }, + make(map[string]int), + } + + tt = append(tt, testCase{ + "ImportWithCache", + // This test will make use of the importer's internal cache for package `std`. + &gnovm.MemPackage{ + Name: "hello", + Path: "gno.land/p/demo/hello", + Files: []*gnovm.MemFile{ + { + Name: "hello.gno", + Body: ` + package hello + import ( + "std" + "bye" + ) + func Hello() std.Address { return bye.Bye() }`, + }, + }, + }, + cacheMpg, + func(t *testing.T, err error) { + t.Helper() + require.NoError(t, err) + assert.Equal(t, map[string]int{"std": 1, "bye": 1}, cacheMpg.counts) + }, + }) + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + format := false + err := TypeCheckMemPackage(tc.pkg, tc.getter, format) + if tc.check == nil { + assert.NoError(t, err) + } else { + tc.check(t, err) + } + }) + } +} + +func TestTypeCheckMemPackage_format(t *testing.T) { + t.Parallel() + + input := ` + package hello + func Hello(name string) string {return "hello" + name +} + + + +` + + pkg := &gnovm.MemPackage{ + Name: "hello", + Path: "gno.land/p/demo/hello", + Files: []*gnovm.MemFile{ + { + Name: "hello.gno", + Body: input, + }, + }, + } + + mpkgGetter := mockPackageGetter{} + format := false + err := TypeCheckMemPackage(pkg, mpkgGetter, format) + assert.NoError(t, err) + assert.Equal(t, input, pkg.Files[0].Body) // unchanged + + expected := `package hello + +func Hello(name string) string { + return "hello" + name +} +` + + format = true + err = TypeCheckMemPackage(pkg, mpkgGetter, format) + assert.NoError(t, err) + assert.NotEqual(t, input, pkg.Files[0].Body) + assert.Equal(t, expected, pkg.Files[0].Body) +} From b3d4855050496222e565377ce2422677a7f1a961 Mon Sep 17 00:00:00 2001 From: Morgan Date: Tue, 14 Jan 2025 18:33:54 +0100 Subject: [PATCH 07/13] test(gnovm): move tests in values_conversions_test.go to filetests (#3490) --- gnovm/pkg/gnolang/values_conversions_test.go | 132 ------------------- gnovm/tests/files/overflow10.gno | 8 ++ gnovm/tests/files/overflow11.gno | 8 ++ gnovm/tests/files/overflow12.gno | 8 ++ gnovm/tests/files/overflow13.gno | 8 ++ gnovm/tests/files/overflow14.gno | 8 ++ gnovm/tests/files/overflow15.gno | 9 ++ gnovm/tests/files/overflow16.gno | 9 ++ gnovm/tests/files/overflow6.gno | 8 ++ gnovm/tests/files/overflow7.gno | 8 ++ gnovm/tests/files/overflow8.gno | 8 ++ gnovm/tests/files/overflow9.gno | 8 ++ 12 files changed, 90 insertions(+), 132 deletions(-) create mode 100644 gnovm/tests/files/overflow10.gno create mode 100644 gnovm/tests/files/overflow11.gno create mode 100644 gnovm/tests/files/overflow12.gno create mode 100644 gnovm/tests/files/overflow13.gno create mode 100644 gnovm/tests/files/overflow14.gno create mode 100644 gnovm/tests/files/overflow15.gno create mode 100644 gnovm/tests/files/overflow16.gno create mode 100644 gnovm/tests/files/overflow6.gno create mode 100644 gnovm/tests/files/overflow7.gno create mode 100644 gnovm/tests/files/overflow8.gno create mode 100644 gnovm/tests/files/overflow9.gno diff --git a/gnovm/pkg/gnolang/values_conversions_test.go b/gnovm/pkg/gnolang/values_conversions_test.go index 5538e973bdc..b8b06df4228 100644 --- a/gnovm/pkg/gnolang/values_conversions_test.go +++ b/gnovm/pkg/gnolang/values_conversions_test.go @@ -2,7 +2,6 @@ package gnolang import ( "math" - "strings" "testing" "github.com/cockroachdb/apd/v3" @@ -27,134 +26,3 @@ func TestConvertUntypedBigdecToFloat(t *testing.T) { require.True(t, softfloat.Feq64(dst.GetFloat64(), 0)) } - -func TestBitShiftingOverflow(t *testing.T) { - t.Parallel() - - testFunc := func(source, msg string) { - defer func() { - if len(msg) == 0 { - return - } - - r := recover() - - if r == nil { - t.Fail() - } - - err := r.(*PreprocessError) - c := strings.Contains(err.Error(), msg) - if !c { - t.Fatalf(`expected "%s", got "%s"`, msg, r) - } - }() - - m := NewMachine("test", nil) - - n := MustParseFile("main.go", source) - m.RunFiles(n) - m.RunMain() - } - - type cases struct { - source string - msg string - } - - tests := []cases{ - { - `package test - -func main() { - const a = int32(1) << 33 -}`, - `test/main.go:3:1: constant overflows`, - }, - { - `package test - -func main() { - const a1 = int8(1) << 8 -}`, - `test/main.go:3:1: constant overflows`, - }, - { - `package test - -func main() { - const a2 = int16(1) << 16 -}`, - `test/main.go:3:1: constant overflows`, - }, - { - `package test - -func main() { - const a3 = int32(1) << 33 -}`, - `test/main.go:3:1: constant overflows`, - }, - { - `package test - -func main() { - const a4 = int64(1) << 65 -}`, - `test/main.go:3:1: constant overflows`, - }, - { - `package test - -func main() { - const b1 = uint8(1) << 8 -}`, - `test/main.go:3:1: constant overflows`, - }, - { - `package test - -func main() { - const b2 = uint16(1) << 16 -}`, - `test/main.go:3:1: constant overflows`, - }, - { - `package test - -func main() { - const b3 = uint32(1) << 33 -}`, - `test/main.go:3:1: constant overflows`, - }, - { - `package test - -func main() { - const b4 = uint64(1) << 65 -}`, - `test/main.go:3:1: constant overflows`, - }, - { - `package test - - func main() { - const c1 = 1 << 128 - }`, - ``, - }, - { - `package test - - func main() { - const c1 = 1 << 128 - println(c1) - }`, - `test/main.go:5:4: bigint overflows target kind`, - }, - } - - for _, tc := range tests { - testFunc(tc.source, tc.msg) - } -} diff --git a/gnovm/tests/files/overflow10.gno b/gnovm/tests/files/overflow10.gno new file mode 100644 index 00000000000..c3224eaf471 --- /dev/null +++ b/gnovm/tests/files/overflow10.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const a4 = int64(1) << 65 +} + +// Error: +// main/files/overflow10.gno:3:1: constant overflows diff --git a/gnovm/tests/files/overflow11.gno b/gnovm/tests/files/overflow11.gno new file mode 100644 index 00000000000..bac883f104f --- /dev/null +++ b/gnovm/tests/files/overflow11.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const b1 = uint8(1) << 8 +} + +// Error: +// main/files/overflow11.gno:3:1: constant overflows diff --git a/gnovm/tests/files/overflow12.gno b/gnovm/tests/files/overflow12.gno new file mode 100644 index 00000000000..52ca8fc80d4 --- /dev/null +++ b/gnovm/tests/files/overflow12.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const b2 = uint16(1) << 16 +} + +// Error: +// main/files/overflow12.gno:3:1: constant overflows diff --git a/gnovm/tests/files/overflow13.gno b/gnovm/tests/files/overflow13.gno new file mode 100644 index 00000000000..40b6885b3ff --- /dev/null +++ b/gnovm/tests/files/overflow13.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const b3 = uint32(1) << 33 +} + +// Error: +// main/files/overflow13.gno:3:1: constant overflows diff --git a/gnovm/tests/files/overflow14.gno b/gnovm/tests/files/overflow14.gno new file mode 100644 index 00000000000..0da66bb7b9d --- /dev/null +++ b/gnovm/tests/files/overflow14.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const b4 = uint64(1) << 65 +} + +// Error: +// main/files/overflow14.gno:3:1: constant overflows diff --git a/gnovm/tests/files/overflow15.gno b/gnovm/tests/files/overflow15.gno new file mode 100644 index 00000000000..f41848d5d21 --- /dev/null +++ b/gnovm/tests/files/overflow15.gno @@ -0,0 +1,9 @@ +package main + +func main() { + const c1 = 1 << 128 + println(uint64(c1 >> 65)) +} + +// Output: +// 9223372036854775808 diff --git a/gnovm/tests/files/overflow16.gno b/gnovm/tests/files/overflow16.gno new file mode 100644 index 00000000000..36cc7689529 --- /dev/null +++ b/gnovm/tests/files/overflow16.gno @@ -0,0 +1,9 @@ +package main + +func main() { + const c1 = 1 << 128 + println(c1) +} + +// Error: +// main/files/overflow16.gno:5:2: bigint overflows target kind diff --git a/gnovm/tests/files/overflow6.gno b/gnovm/tests/files/overflow6.gno new file mode 100644 index 00000000000..b9c49027336 --- /dev/null +++ b/gnovm/tests/files/overflow6.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const a = int32(1) << 33 +} + +// Error: +// main/files/overflow6.gno:3:1: constant overflows diff --git a/gnovm/tests/files/overflow7.gno b/gnovm/tests/files/overflow7.gno new file mode 100644 index 00000000000..28202811fca --- /dev/null +++ b/gnovm/tests/files/overflow7.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const a1 = int8(1) << 8 +} + +// Error: +// main/files/overflow7.gno:3:1: constant overflows diff --git a/gnovm/tests/files/overflow8.gno b/gnovm/tests/files/overflow8.gno new file mode 100644 index 00000000000..f25fb0aa833 --- /dev/null +++ b/gnovm/tests/files/overflow8.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const a2 = int16(1) << 16 +} + +// Error: +// main/files/overflow8.gno:3:1: constant overflows diff --git a/gnovm/tests/files/overflow9.gno b/gnovm/tests/files/overflow9.gno new file mode 100644 index 00000000000..5eae14b67aa --- /dev/null +++ b/gnovm/tests/files/overflow9.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const a3 = int32(1) << 33 +} + +// Error: +// main/files/overflow9.gno:3:1: constant overflows From c79c16dc0d33d260f876b7e034531e180cc0ac86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 19:21:01 +0100 Subject: [PATCH 08/13] chore(deps): bump anchore/sbom-action from 0.17.8 to 0.17.9 in the actions group (#3476) Bumps the actions group with 1 update: [anchore/sbom-action](https://github.com/anchore/sbom-action). Updates `anchore/sbom-action` from 0.17.8 to 0.17.9
Release notes

Sourced from anchore/sbom-action's releases.

v0.17.9

Changes in v0.17.9

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=anchore/sbom-action&package-manager=github_actions&previous-version=0.17.8&new-version=0.17.9)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/releaser-master.yml | 2 +- .github/workflows/releaser-nightly.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/releaser-master.yml b/.github/workflows/releaser-master.yml index 6e3eed31914..7c81789b060 100644 --- a/.github/workflows/releaser-master.yml +++ b/.github/workflows/releaser-master.yml @@ -27,7 +27,7 @@ jobs: cache: true - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.8 + - uses: anchore/sbom-action/download-syft@v0.17.9 - uses: docker/login-action@v3 with: diff --git a/.github/workflows/releaser-nightly.yml b/.github/workflows/releaser-nightly.yml index 4f6e636af1b..47b6cabb223 100644 --- a/.github/workflows/releaser-nightly.yml +++ b/.github/workflows/releaser-nightly.yml @@ -24,7 +24,7 @@ jobs: cache: true - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.8 + - uses: anchore/sbom-action/download-syft@v0.17.9 - uses: docker/login-action@v3 with: From 3adb2ac390f60467e6d77c3aa7ff4507cb37e0e8 Mon Sep 17 00:00:00 2001 From: 6h057 <15034695+omarsy@users.noreply.github.com> Date: Tue, 14 Jan 2025 21:29:49 +0100 Subject: [PATCH 09/13] feat(gnovm): align Gno constant handling with Go specifications (#2828) Related Issues: Closes #2628 This PR aims to align Gno's constant handling with the Go specification regarding constant expressions (see [Go Specification on Constants](https://go.dev/ref/spec#Constant_expressions)). 1. **Primitive Type Requirement** - **Should Work:** ```go const t = 1 ``` - **Should Return an Error:** ```go const t = []string{"1"} ``` **Error:** ``` (const (slice[("1" string)] []string)) (value of type []string) is not constant ``` 2. **Function Calls Disallowed** Only built-in functions should be allowed. - **Should Work:** ```go const t = len("s") ``` - **Should Return an Error:** ```go func v() string { return "" } const t = v() ``` **Error:** ``` v() (value of type string) is not constant ``` 3. **Constant Operands Requirement** Constant expressions may contain only constant operands and are evaluated at compile time. - **Should Work:** ```go const t = 1 const v = t ``` - **Should Raise an Error:** ```go t := 1 const v = t ``` **Error:** ``` t (variable of type int) is not constant ``` 4. **Type Assertion Forbidden** - This code: ```go var i interface{} = 1 const t, ok = i.(int) ``` - **Should Raise This Error:** ``` i.(int) (comma, ok expression of type int) is not constant ``` 5. **Index Expression Forbidden** - This code: ```go var i = []string{} const t, ok = i[0] ``` - **Should Return This Error:** ``` i[0] (variable of type string) is not constant ```
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- .../r/demo/keystore/keystore_test.gno | 4 - gnovm/pkg/gnolang/preprocess.go | 1 + gnovm/pkg/gnolang/type_check.go | 145 ++++++++++++++++++ gnovm/tests/files/const23.gno | 11 ++ gnovm/tests/files/const24.gno | 82 ++++++++++ gnovm/tests/files/const25.gno | 11 ++ gnovm/tests/files/const26.gno | 15 ++ gnovm/tests/files/const27.gno | 16 ++ gnovm/tests/files/const28.gno | 12 ++ gnovm/tests/files/const29.gno | 12 ++ gnovm/tests/files/const30.gno | 15 ++ gnovm/tests/files/const31.gno | 15 ++ gnovm/tests/files/const32.gno | 11 ++ gnovm/tests/files/const33.gno | 12 ++ gnovm/tests/files/const34.gno | 10 ++ gnovm/tests/files/const35.gno | 12 ++ gnovm/tests/files/const36.gno | 13 ++ gnovm/tests/files/const37_native.gno | 10 ++ gnovm/tests/files/const37_stdlibs.gno | 10 ++ gnovm/tests/files/const38.gno | 11 ++ gnovm/tests/files/const39.gno | 14 ++ gnovm/tests/files/const40.gno | 8 + gnovm/tests/files/const41.gno | 8 + gnovm/tests/files/const42.gno | 8 + gnovm/tests/files/const43.gno | 10 ++ gnovm/tests/files/const44.gno | 10 ++ gnovm/tests/files/const45_a.gno | 14 ++ gnovm/tests/files/const45_b.gno | 14 ++ gnovm/tests/files/const46.gno | 10 ++ gnovm/tests/files/const47.gno | 10 ++ gnovm/tests/files/const48.gno | 9 ++ gnovm/tests/files/const49.gno | 16 ++ gnovm/tests/files/const50.gno | 12 ++ 33 files changed, 567 insertions(+), 4 deletions(-) create mode 100644 gnovm/tests/files/const23.gno create mode 100644 gnovm/tests/files/const24.gno create mode 100644 gnovm/tests/files/const25.gno create mode 100644 gnovm/tests/files/const26.gno create mode 100644 gnovm/tests/files/const27.gno create mode 100644 gnovm/tests/files/const28.gno create mode 100644 gnovm/tests/files/const29.gno create mode 100644 gnovm/tests/files/const30.gno create mode 100644 gnovm/tests/files/const31.gno create mode 100644 gnovm/tests/files/const32.gno create mode 100644 gnovm/tests/files/const33.gno create mode 100644 gnovm/tests/files/const34.gno create mode 100644 gnovm/tests/files/const35.gno create mode 100644 gnovm/tests/files/const36.gno create mode 100644 gnovm/tests/files/const37_native.gno create mode 100644 gnovm/tests/files/const37_stdlibs.gno create mode 100644 gnovm/tests/files/const38.gno create mode 100644 gnovm/tests/files/const39.gno create mode 100644 gnovm/tests/files/const40.gno create mode 100644 gnovm/tests/files/const41.gno create mode 100644 gnovm/tests/files/const42.gno create mode 100644 gnovm/tests/files/const43.gno create mode 100644 gnovm/tests/files/const44.gno create mode 100644 gnovm/tests/files/const45_a.gno create mode 100644 gnovm/tests/files/const45_b.gno create mode 100644 gnovm/tests/files/const46.gno create mode 100644 gnovm/tests/files/const47.gno create mode 100644 gnovm/tests/files/const48.gno create mode 100644 gnovm/tests/files/const49.gno create mode 100644 gnovm/tests/files/const50.gno diff --git a/examples/gno.land/r/demo/keystore/keystore_test.gno b/examples/gno.land/r/demo/keystore/keystore_test.gno index 41597016ea3..9b5fafa2f95 100644 --- a/examples/gno.land/r/demo/keystore/keystore_test.gno +++ b/examples/gno.land/r/demo/keystore/keystore_test.gno @@ -11,10 +11,6 @@ import ( ) func TestRender(t *testing.T) { - // https://github.com/gnolang/gno/pull/3375 changed const -> var : - // For some reason non native functions fails on constants with - // constant overflows (code=2), this does not happens when using a variable - // TODO: check this issue after and if this PR is merged var ( author1 std.Address = testutils.TestAddress("author1") author2 std.Address = testutils.TestAddress("author2") diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index ddfd1851989..ffa0f518331 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2294,6 +2294,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // NOTE: may or may not be a *ConstExpr, // but if not, make one now. for i, vx := range n.Values { + assertValidConstExpr(store, last, n, vx) n.Values[i] = evalConst(store, last, vx) } } else { diff --git a/gnovm/pkg/gnolang/type_check.go b/gnovm/pkg/gnolang/type_check.go index 70166116fcc..f96cb71e4b6 100644 --- a/gnovm/pkg/gnolang/type_check.go +++ b/gnovm/pkg/gnolang/type_check.go @@ -215,6 +215,151 @@ func assertAssignableTo(n Node, xt, dt Type, autoNative bool) { } } +func assertValidConstExpr(store Store, last BlockNode, n *ValueDecl, expr Expr) { + if n.Type != nil { + nt := evalStaticType(store, last, n.Type) + if xnt, ok := nt.(*NativeType); ok { + nt = go2GnoBaseType(xnt.Type) + } + + if _, ok := baseOf(nt).(PrimitiveType); !ok { + panic(fmt.Sprintf("invalid constant type %s", nt.String())) + } + } + + nt := evalStaticTypeOf(store, last, expr) + if xnt, ok := nt.(*NativeType); ok { + nt = go2GnoBaseType(xnt.Type) + } + + if nt == nil { + panic(fmt.Sprintf("%s (variable of type nil) is not constant", expr)) + } + + if _, ok := baseOf(nt).(PrimitiveType); !ok { + panic(fmt.Sprintf("%s (variable of type %s) is not constant", expr, nt)) + } + + assertValidConstValue(store, last, expr) +} + +func assertValidConstValue(store Store, last BlockNode, currExpr Expr) { +Main: + switch currExpr := currExpr.(type) { + case *ConstExpr: + case *UnaryExpr: + // *, & is filter out previously since they are not primitive + assertValidConstValue(store, last, currExpr.X) + case *TypeAssertExpr: + ty := evalStaticTypeOf(store, last, currExpr) + if _, ok := ty.(*TypeType); ok { + ty = evalStaticType(store, last, currExpr) + } + panic(fmt.Sprintf("%s (comma, ok expression of type %s) is not constant", currExpr.String(), currExpr.Type)) + case *CallExpr: + ift := evalStaticTypeOf(store, last, currExpr.Func) + switch baseOf(ift).(type) { + case *FuncType: + tup := evalStaticTypeOfRaw(store, last, currExpr).(*tupleType) + + // check for built-in functions + if cx, ok := currExpr.Func.(*ConstExpr); ok { + if fv, ok := cx.V.(*FuncValue); ok { + if fv.PkgPath == uversePkgPath { + // TODO: should support min, max, real, imag + switch { + case fv.Name == "len": + at := evalStaticTypeOf(store, last, currExpr.Args[0]) + if _, ok := baseOf(at).(*ArrayType); ok { + // ok + break Main + } + assertValidConstValue(store, last, currExpr.Args[0]) + break Main + case fv.Name == "cap": + at := evalStaticTypeOf(store, last, currExpr.Args[0]) + if _, ok := baseOf(at).(*ArrayType); ok { + // ok + break Main + } + assertValidConstValue(store, last, currExpr.Args[0]) + break Main + } + } + } + } + + switch { + case len(tup.Elts) == 0: + panic(fmt.Sprintf("%s (no value) used as value", currExpr.String())) + case len(tup.Elts) == 1: + panic(fmt.Sprintf("%s (value of type %s) is not constant", currExpr.String(), tup.Elts[0])) + default: + panic(fmt.Sprintf("multiple-value %s (value of type %s) in single-value context", currExpr.String(), tup.Elts)) + } + case *TypeType: + for _, arg := range currExpr.Args { + assertValidConstValue(store, last, arg) + } + case *NativeType: + // Todo: should add a test after the fix of https://github.com/gnolang/gno/issues/3006 + ty := evalStaticType(store, last, currExpr.Func) + panic(fmt.Sprintf("%s (variable of type %s) is not constant", currExpr.String(), ty)) + default: + panic(fmt.Sprintf( + "unexpected func type %v (%v)", + ift, reflect.TypeOf(ift))) + } + case *BinaryExpr: + assertValidConstValue(store, last, currExpr.Left) + assertValidConstValue(store, last, currExpr.Right) + case *SelectorExpr: + xt := evalStaticTypeOf(store, last, currExpr.X) + switch xt := xt.(type) { + case *PackageType: + var pv *PackageValue + if cx, ok := currExpr.X.(*ConstExpr); ok { + // NOTE: *Machine.TestMemPackage() needs this + // to pass in an imported package as *ConstEzpr. + pv = cx.V.(*PackageValue) + } else { + // otherwise, packages can only be referred to by + // *NameExprs, and cannot be copied. + pvc := evalConst(store, last, currExpr.X) + pv_, ok := pvc.V.(*PackageValue) + if !ok { + panic(fmt.Sprintf( + "missing package in selector expr %s", + currExpr.String())) + } + pv = pv_ + } + if pv.GetBlock(store).Source.GetIsConst(store, currExpr.Sel) { + break Main + } + + tt := pv.GetBlock(store).Source.GetStaticTypeOf(store, currExpr.Sel) + panic(fmt.Sprintf("%s (variable of type %s) is not constant", currExpr.String(), tt)) + case *PointerType, *DeclaredType, *StructType, *InterfaceType, *TypeType, *NativeType: + ty := evalStaticTypeOf(store, last, currExpr) + if _, ok := ty.(*TypeType); ok { + ty = evalStaticType(store, last, currExpr) + } + panic(fmt.Sprintf("%s (variable of type %s) is not constant", currExpr.String(), ty)) + default: + panic(fmt.Sprintf( + "unexpected selector expression type %v", + reflect.TypeOf(xt))) + } + default: + ift := evalStaticTypeOf(store, last, currExpr) + if _, ok := ift.(*TypeType); ok { + ift = evalStaticType(store, last, currExpr) + } + panic(fmt.Sprintf("%s (variable of type %s) is not constant", currExpr.String(), ift)) + } +} + // checkValDefineMismatch checks for mismatch between the number of variables and values in a ValueDecl or AssignStmt. func checkValDefineMismatch(n Node) { var ( diff --git a/gnovm/tests/files/const23.gno b/gnovm/tests/files/const23.gno new file mode 100644 index 00000000000..f445c3e8eb2 --- /dev/null +++ b/gnovm/tests/files/const23.gno @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + const t []string = []string{} + fmt.Println(t) +} + +// Error: +// main/files/const23.gno:6:8: invalid constant type []string diff --git a/gnovm/tests/files/const24.gno b/gnovm/tests/files/const24.gno new file mode 100644 index 00000000000..d82c50c86aa --- /dev/null +++ b/gnovm/tests/files/const24.gno @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + const a int = 1_000_000 + const b byte = byte(1) + const c float64 = 1_000_000.000 + const d string = "Hello, World!" + const e rune = 'a' + const g bool = true + const h uint = 1_000 + const i int8 = 1 + const j int16 = 1 + const k int32 = 1 + const l int64 = 1 + const m uint8 = 1 + const n uint16 = 1 + const o uint32 = 1 + const p uint64 = 1 + const r float32 = 1_000_000.000 + const s = r + const t = len("s") + const u = 1 + len("s") + 3 + ars := [10]string{} + const v = len(ars) + const w = cap(ars) + const x = time.Second + const y = +len("ay") + + fmt.Println(a) + fmt.Println(b) + fmt.Println(c) + fmt.Println(d) + fmt.Println(e) + fmt.Println(g) + fmt.Println(h) + fmt.Println(i) + fmt.Println(j) + fmt.Println(k) + fmt.Println(l) + fmt.Println(m) + fmt.Println(n) + fmt.Println(o) + fmt.Println(p) + fmt.Println(r) + fmt.Println(s) + fmt.Println(t) + fmt.Println(u) + fmt.Println(v) + fmt.Println(w) + println(x) + fmt.Println(y) +} + +// Output: +// 1000000 +// 1 +// 1e+06 +// Hello, World! +// 97 +// true +// 1000 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1e+06 +// 1e+06 +// 1 +// 5 +// 10 +// 10 +// 1s +// 2 diff --git a/gnovm/tests/files/const25.gno b/gnovm/tests/files/const25.gno new file mode 100644 index 00000000000..64e0358bdef --- /dev/null +++ b/gnovm/tests/files/const25.gno @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + const t = []string{"1"} + fmt.Println(t) +} + +// Error: +// main/files/const25.gno:6:8: [](const-type string){(const ("1" string))} (variable of type []string) is not constant diff --git a/gnovm/tests/files/const26.gno b/gnovm/tests/files/const26.gno new file mode 100644 index 00000000000..a1533e98c57 --- /dev/null +++ b/gnovm/tests/files/const26.gno @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func v() string { + return "" +} + +func main() { + const t = v() + fmt.Println(t) +} + +// Error: +// main/files/const26.gno:10:8: v() (value of type string) is not constant diff --git a/gnovm/tests/files/const27.gno b/gnovm/tests/files/const27.gno new file mode 100644 index 00000000000..4be731e16a7 --- /dev/null +++ b/gnovm/tests/files/const27.gno @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func v() string { + return "" +} + +func main() { + var i interface{} = 1 + const t, ok = i.(int) + fmt.Println(t, ok) +} + +// Error: +// main/files/const27.gno:11:8: i.((const-type int)) (comma, ok expression of type (const-type int)) is not constant diff --git a/gnovm/tests/files/const28.gno b/gnovm/tests/files/const28.gno new file mode 100644 index 00000000000..e4762c3205c --- /dev/null +++ b/gnovm/tests/files/const28.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + var s []string = []string{"1"} + const t, ok = s[0] + fmt.Println(t, ok) +} + +// Error: +// main/files/const28.gno:7:8: s[(const (0 int))] (variable of type string) is not constant diff --git a/gnovm/tests/files/const29.gno b/gnovm/tests/files/const29.gno new file mode 100644 index 00000000000..41d8d0a816d --- /dev/null +++ b/gnovm/tests/files/const29.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + s := "1" + const t = s + fmt.Println(t) +} + +// Error: +// main/files/const29.gno:7:8: s (variable of type string) is not constant diff --git a/gnovm/tests/files/const30.gno b/gnovm/tests/files/const30.gno new file mode 100644 index 00000000000..4a166013cdc --- /dev/null +++ b/gnovm/tests/files/const30.gno @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func v() { + return +} + +func main() { + const t = v() + fmt.Println(t) +} + +// Error: +// main/files/const30.gno:10:8: v (no value) used as value diff --git a/gnovm/tests/files/const31.gno b/gnovm/tests/files/const31.gno new file mode 100644 index 00000000000..e37577789e6 --- /dev/null +++ b/gnovm/tests/files/const31.gno @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func v() (string, string) { + return "", "" +} + +func main() { + const t, v = v() + fmt.Println(t) +} + +// Error: +// main/files/const31.gno:10:8: (const (v func()( string, string)))() (variable of type (string,string)) is not constant diff --git a/gnovm/tests/files/const32.gno b/gnovm/tests/files/const32.gno new file mode 100644 index 00000000000..83d3ae5e73c --- /dev/null +++ b/gnovm/tests/files/const32.gno @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + const t = 1 + 2 + len([]string{}) + fmt.Println(t) +} + +// Error: +// main/files/const32.gno:6:8: [](const-type string){} (variable of type []string) is not constant diff --git a/gnovm/tests/files/const33.gno b/gnovm/tests/files/const33.gno new file mode 100644 index 00000000000..42652d3b458 --- /dev/null +++ b/gnovm/tests/files/const33.gno @@ -0,0 +1,12 @@ +package main + +var x = 1 +var y = 1 + +const b = x == y + +func main() { + println("ok") +} +// Error: +// main/files/const33.gno:6:7: x (variable of type int) is not constant diff --git a/gnovm/tests/files/const34.gno b/gnovm/tests/files/const34.gno new file mode 100644 index 00000000000..9c79cf86b88 --- /dev/null +++ b/gnovm/tests/files/const34.gno @@ -0,0 +1,10 @@ +package main + +const a = func() { println("hey") } + +func main() { + println("ok") +} + +// Error: +// main/files/const34.gno:3:7: func func(){ (const (println func(xs ...interface{})()))((const ("hey" string))) } (variable of type func()()) is not constant diff --git a/gnovm/tests/files/const35.gno b/gnovm/tests/files/const35.gno new file mode 100644 index 00000000000..e85d68eb8db --- /dev/null +++ b/gnovm/tests/files/const35.gno @@ -0,0 +1,12 @@ +package main + +var x = 1 + +const ff = +(1 << x) + +func main() { + println("ok") +} + +// Error: +// main/files/const35.gno:5:7: x (variable of type int) is not constant diff --git a/gnovm/tests/files/const36.gno b/gnovm/tests/files/const36.gno new file mode 100644 index 00000000000..8a677a35be9 --- /dev/null +++ b/gnovm/tests/files/const36.gno @@ -0,0 +1,13 @@ +package main + +type s struct { + x int +} + +func main() { + s := s{1} + const v = s.x +} + +// Error: +// main/files/const36.gno:9:8: s.x (variable of type int) is not constant diff --git a/gnovm/tests/files/const37_native.gno b/gnovm/tests/files/const37_native.gno new file mode 100644 index 00000000000..6a164328a3b --- /dev/null +++ b/gnovm/tests/files/const37_native.gno @@ -0,0 +1,10 @@ +package main + +import "time" + +func main() { + const v = time.UTC +} + +// Error: +// main/files/const37_native.gno:6:8: time.UTC (variable of type *time.Location) is not constant diff --git a/gnovm/tests/files/const37_stdlibs.gno b/gnovm/tests/files/const37_stdlibs.gno new file mode 100644 index 00000000000..9ec614f2538 --- /dev/null +++ b/gnovm/tests/files/const37_stdlibs.gno @@ -0,0 +1,10 @@ +package main + +import "time" + +func main() { + const v = time.UTC +} + +// Error: +// main/files/const37_stdlibs.gno:6:8: time.UTC (variable of type *time.Location) is not constant \ No newline at end of file diff --git a/gnovm/tests/files/const38.gno b/gnovm/tests/files/const38.gno new file mode 100644 index 00000000000..815e74fa76a --- /dev/null +++ b/gnovm/tests/files/const38.gno @@ -0,0 +1,11 @@ +package main + +import "std" + +func main() { + v := std.Coin{} + const c = v.Denom +} + +// Error: +// main/files/const38.gno:7:8: v.Denom (variable of type string) is not constant diff --git a/gnovm/tests/files/const39.gno b/gnovm/tests/files/const39.gno new file mode 100644 index 00000000000..68ff7dd5630 --- /dev/null +++ b/gnovm/tests/files/const39.gno @@ -0,0 +1,14 @@ +package main + +type T struct { + a int +} + +func (tv T) Mv(a int) int { return 0 } + +func main() { + const t = T.Mv +} + +// Error: +// main/files/const39.gno:10:8: T.Mv (variable of type func(tv main.T,a int)( int)) is not constant diff --git a/gnovm/tests/files/const40.gno b/gnovm/tests/files/const40.gno new file mode 100644 index 00000000000..d1dedc382e6 --- /dev/null +++ b/gnovm/tests/files/const40.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const t = [0]string{} +} + +// Error: +// main/files/const40.gno:4:8: [(const (0 int))](const-type string){} (variable of type [0]string) is not constant diff --git a/gnovm/tests/files/const41.gno b/gnovm/tests/files/const41.gno new file mode 100644 index 00000000000..b4424dcef94 --- /dev/null +++ b/gnovm/tests/files/const41.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const t [0]string = [0]string{} +} + +// Error: +// main/files/const41.gno:4:8: invalid constant type [0]string \ No newline at end of file diff --git a/gnovm/tests/files/const42.gno b/gnovm/tests/files/const42.gno new file mode 100644 index 00000000000..5763a2fc121 --- /dev/null +++ b/gnovm/tests/files/const42.gno @@ -0,0 +1,8 @@ +package main + +func main() { + const t int +} + +// Error: +// main/files/const42.gno:4:8: missing init expr for t \ No newline at end of file diff --git a/gnovm/tests/files/const43.gno b/gnovm/tests/files/const43.gno new file mode 100644 index 00000000000..d929e526579 --- /dev/null +++ b/gnovm/tests/files/const43.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := [2]int{1, 2} + + const b = a +} + +// Error: +// main/files/const43.gno:6:8: a (variable of type [2]int) is not constant diff --git a/gnovm/tests/files/const44.gno b/gnovm/tests/files/const44.gno new file mode 100644 index 00000000000..69924b8ea9d --- /dev/null +++ b/gnovm/tests/files/const44.gno @@ -0,0 +1,10 @@ +package main + +const a = interface{}(nil) + +func main() { + println("ok") +} + +// Error: +// main/files/const44.gno:3:7: (const (undefined)) (variable of type interface{}) is not constant diff --git a/gnovm/tests/files/const45_a.gno b/gnovm/tests/files/const45_a.gno new file mode 100644 index 00000000000..fef13e2fc68 --- /dev/null +++ b/gnovm/tests/files/const45_a.gno @@ -0,0 +1,14 @@ +package main + +type MyStruct struct { + arr [2]int +} + +const a = len(MyStruct{arr: [2]int{1, 2}}.arr) + +func main() { + println("ok") +} + +// Output: +// ok diff --git a/gnovm/tests/files/const45_b.gno b/gnovm/tests/files/const45_b.gno new file mode 100644 index 00000000000..7da25d3268c --- /dev/null +++ b/gnovm/tests/files/const45_b.gno @@ -0,0 +1,14 @@ +package main + +type MyStruct struct { + arr []int +} + +const a = len(MyStruct{arr: []int{1, 2}}.arr) + +func main() { + println("ok") +} + +// Error: +// main/files/const45_b.gno:7:7: MyStruct{arr: [](const-type int){(const (1 int)), (const (2 int))}}.arr (variable of type []int) is not constant diff --git a/gnovm/tests/files/const46.gno b/gnovm/tests/files/const46.gno new file mode 100644 index 00000000000..4722cba294e --- /dev/null +++ b/gnovm/tests/files/const46.gno @@ -0,0 +1,10 @@ +package main + +const a = len(map[string][2]int{"arr": {1, 2}}["arr"]) + +func main() { + println("ok") +} + +// Output: +// ok diff --git a/gnovm/tests/files/const47.gno b/gnovm/tests/files/const47.gno new file mode 100644 index 00000000000..528ba469562 --- /dev/null +++ b/gnovm/tests/files/const47.gno @@ -0,0 +1,10 @@ +package main + +const a = len(map[string][2]interface{}{"arr": {1, 2}}["arr"]) + +func main() { + println("ok") +} + +// Output: +// ok diff --git a/gnovm/tests/files/const48.gno b/gnovm/tests/files/const48.gno new file mode 100644 index 00000000000..001fd911fa5 --- /dev/null +++ b/gnovm/tests/files/const48.gno @@ -0,0 +1,9 @@ +package main + +func main() { + const a = len(map[string][]int{"arr": {1, 2}}) + println("ok", a) +} + +// Error: +// main/files/const48.gno:4:8: map[(const-type string)] [](const-type int){(const ("arr" string)): (const-type []int){(const (1 int)), (const (2 int))}} (variable of type map[string][]int) is not constant diff --git a/gnovm/tests/files/const49.gno b/gnovm/tests/files/const49.gno new file mode 100644 index 00000000000..4b3f38e4d5e --- /dev/null +++ b/gnovm/tests/files/const49.gno @@ -0,0 +1,16 @@ +package main + +import "io" + +type ( + s [2]int + m s +) + +func main() { + const v = len(m{1, 2}) + println(v) +} + +// Output: +// 2 diff --git a/gnovm/tests/files/const50.gno b/gnovm/tests/files/const50.gno new file mode 100644 index 00000000000..5144173bf74 --- /dev/null +++ b/gnovm/tests/files/const50.gno @@ -0,0 +1,12 @@ +package main + +var x = "a" + +const v = len(x) + +func main() { + println("ok") +} + +// Error: +// main/files/const50.gno:5:7: x (variable of type string) is not constant From bd1d104e7bd88ab8980ad2d91bac65b7eaffc354 Mon Sep 17 00:00:00 2001 From: Ursulovic <97893481+Ursulovic@users.noreply.github.com> Date: Wed, 15 Jan 2025 00:08:43 +0100 Subject: [PATCH 10/13] feat(examples): Ivan's registry, home realm (#3354) Created registry for further development of realms, finalising home realm. --------- Co-authored-by: Ivan Ursulovic Co-authored-by: Ivan Ursulovic Co-authored-by: Morgan --- examples/gno.land/r/ursulovic/home/gno.mod | 1 + examples/gno.land/r/ursulovic/home/home.gno | 159 ++++++++++++++++++ .../gno.land/r/ursulovic/home/home_test.gno | 97 +++++++++++ .../gno.land/r/ursulovic/registry/gno.mod | 1 + .../r/ursulovic/registry/registry.gno | 59 +++++++ 5 files changed, 317 insertions(+) create mode 100644 examples/gno.land/r/ursulovic/home/gno.mod create mode 100644 examples/gno.land/r/ursulovic/home/home.gno create mode 100644 examples/gno.land/r/ursulovic/home/home_test.gno create mode 100644 examples/gno.land/r/ursulovic/registry/gno.mod create mode 100644 examples/gno.land/r/ursulovic/registry/registry.gno diff --git a/examples/gno.land/r/ursulovic/home/gno.mod b/examples/gno.land/r/ursulovic/home/gno.mod new file mode 100644 index 00000000000..78163ab2bb5 --- /dev/null +++ b/examples/gno.land/r/ursulovic/home/gno.mod @@ -0,0 +1 @@ +module gno.land/r/ursulovic/home diff --git a/examples/gno.land/r/ursulovic/home/home.gno b/examples/gno.land/r/ursulovic/home/home.gno new file mode 100644 index 00000000000..c03d8a66868 --- /dev/null +++ b/examples/gno.land/r/ursulovic/home/home.gno @@ -0,0 +1,159 @@ +package home + +import ( + "std" + "strconv" + "strings" + + "gno.land/p/demo/ownable" + "gno.land/p/moul/md" + "gno.land/r/leon/hof" + + "gno.land/r/ursulovic/registry" +) + +var ( + aboutMe string + selectedImage string + Ownable *ownable.Ownable + + githubUrl string + linkedinUrl string + connectUrl string + imageUpdatePrice int64 + + isValidUrl func(string) bool +) + +func init() { + Ownable = ownable.NewWithAddress(registry.MainAddress()) + + aboutMe = "Hi, I'm Ivan Ursulovic, a computer engineering graduate, blockchain enthusiast, and backend developer specializing in ASP.NET. I love learning new things and taking on challenges." + selectedImage = "https://i.ibb.co/W28NPkw/beograd.webp" + + githubUrl = "https://github.com/ursulovic" + linkedinUrl = "https://www.linkedin.com/in/ivan-ursulovic-953310190/" + imageUpdatePrice = 5000000 + isValidUrl = defaultURLValidation + hof.Register() +} + +func Render(s string) string { + var sb strings.Builder + sb.WriteString(renderAboutMe()) + sb.WriteString(renderSelectedImage()) + sb.WriteString(renderContactsUrl()) + return sb.String() +} + +func defaultURLValidation(url string) bool { + const urlPrefix string = "https://i.ibb.co/" + + if !strings.HasPrefix(url, urlPrefix) { + return false + } + + if !(strings.HasSuffix(url, ".jpg") || + strings.HasSuffix(url, ".png") || + strings.HasSuffix(url, ".gif") || + strings.HasSuffix(url, ".webp")) { + return false + } + + urlPath := strings.TrimPrefix(url, "https://i.ibb.co/") + parts := strings.Split(urlPath, "/") + + if len(parts) != 2 || len(parts[0]) == 0 || len(parts[1]) == 0 { + return false + } + + return true +} + +func UpdateSelectedImage(url string) { + if !isValidUrl(url) { + panic("Url is not valid!") + } + + sentCoins := std.GetOrigSend() + + if len(sentCoins) != 1 && sentCoins.AmountOf("ugnot") == imageUpdatePrice { + panic("Please send exactly " + strconv.Itoa(int(imageUpdatePrice)) + " ugnot") + } + + selectedImage = url +} + +func renderSelectedImage() string { + var sb strings.Builder + + sb.WriteString(md.HorizontalRule()) + sb.WriteString("\n") + + sb.WriteString(md.H2("📸 Featured Image")) + sb.WriteString("\n") + + sb.WriteString(md.Image("", selectedImage)) + sb.WriteString("\n") + + sb.WriteString(md.H4("✨ " + md.Link("Change this image for "+strconv.Itoa(int(imageUpdatePrice/1000000))+" GNOT. To update, set a direct image URL from ImgBB.", "https://gno.studio/connect/view/gno.land/r/ursulovic/home?network=portal-loop") + " ✨")) + + return sb.String() +} + +func renderAboutMe() string { + var sb strings.Builder + + sb.WriteString(md.H1("👋 Welcome to Ivan's Homepage!")) + sb.WriteString("\n") + + sb.WriteString(md.H2("👨‍💻 About Me")) + sb.WriteString("\n") + + sb.WriteString(md.Blockquote(aboutMe)) + + return sb.String() +} + +func renderContactsUrl() string { + var sb strings.Builder + + sb.WriteString(md.HorizontalRule()) + sb.WriteString("\n") + + sb.WriteString(md.H2("🔗 Let's Connect")) + sb.WriteString("\n") + + items := []string{ + "🐙 " + md.Link("GitHub", githubUrl), + "💼 " + md.Link("LinkedIn", linkedinUrl), + } + sb.WriteString(md.BulletList(items)) + + return sb.String() +} + +func UpdateGithubUrl(url string) { + Ownable.AssertCallerIsOwner() + githubUrl = url +} + +func UpdateLinkedinUrl(url string) { + Ownable.AssertCallerIsOwner() + linkedinUrl = url +} + +func UpdateAboutMe(text string) { + Ownable.AssertCallerIsOwner() + aboutMe = text +} + +func UpdateImagePrice(newPrice int64) { + Ownable.AssertCallerIsOwner() + imageUpdatePrice = newPrice +} + +func UpdateIsValidUrlFunction(f func(string) bool) { + Ownable.AssertCallerIsOwner() + isValidUrl = f +} diff --git a/examples/gno.land/r/ursulovic/home/home_test.gno b/examples/gno.land/r/ursulovic/home/home_test.gno new file mode 100644 index 00000000000..ff3f763d62a --- /dev/null +++ b/examples/gno.land/r/ursulovic/home/home_test.gno @@ -0,0 +1,97 @@ +package home + +import ( + "std" + "testing" + + "gno.land/p/demo/testutils" +) + +func TestUpdateGithubUrl(t *testing.T) { + caller := std.Address("g1d24j8fwnc0w5q427fauyey4gdd30qgu69k6n0x") + std.TestSetOrigCaller(caller) + + newUrl := "https://github.com/example" + + UpdateGithubUrl(newUrl) + + if githubUrl != newUrl { + t.Fatalf("GitHub url not updated properly!") + } +} + +func TestUpdateLinkedinUrl(t *testing.T) { + caller := std.Address("g1d24j8fwnc0w5q427fauyey4gdd30qgu69k6n0x") + std.TestSetOrigCaller(caller) + + newUrl := "https://www.linkedin.com/in/example" + + UpdateGithubUrl(newUrl) + + if githubUrl != newUrl { + t.Fatalf("LinkedIn url not updated properly!") + } +} + +func TestUpdateAboutMe(t *testing.T) { + caller := std.Address("g1d24j8fwnc0w5q427fauyey4gdd30qgu69k6n0x") + std.TestSetOrigCaller(caller) + + newAboutMe := "This is new description!" + + UpdateAboutMe(newAboutMe) + + if aboutMe != newAboutMe { + t.Fatalf("About mew not updated properly!") + } +} + +func TestUpdateSelectedImage(t *testing.T) { + var user = testutils.TestAddress("user") + std.TestSetOrigCaller(user) + + validImageUrl := "https://i.ibb.co/hLtmnX0/beautiful-rain-forest-ang-ka-nature-trail-doi-inthanon-national-park-thailand-36703721.webp" + + coinsSent := std.NewCoins(std.NewCoin("ugnot", 5000000)) // Update to match the price expected by your function + std.TestSetOrigSend(coinsSent, std.NewCoins()) + + UpdateSelectedImage(validImageUrl) + + if selectedImage != validImageUrl { + t.Fatalf("Valid image URL rejected!") + } + + invalidImageUrl := "https://ibb.co/Kb3rQNn" + + defer func() { + if r := recover(); r == nil { + t.Fatalf("Expected panic for invalid image URL, but got no panic") + } + }() + + UpdateSelectedImage(invalidImageUrl) + + invalidCoins := std.NewCoins(std.NewCoin("ugnot", 1000000)) + std.TestSetOrigSend(invalidCoins, std.NewCoins()) + + defer func() { + if r := recover(); r == nil { + t.Fatalf("Expected panic for incorrect coin denomination or amount, but got no panic") + } + }() + + UpdateSelectedImage(validImageUrl) +} + +func TestUpdateImagePrice(t *testing.T) { + caller := std.Address("g1d24j8fwnc0w5q427fauyey4gdd30qgu69k6n0x") + std.TestSetOrigCaller(caller) + + var newImageUpdatePrice int64 = 3000000 + + UpdateImagePrice(newImageUpdatePrice) + + if imageUpdatePrice != newImageUpdatePrice { + t.Fatalf("Image update price not updated properly!") + } +} diff --git a/examples/gno.land/r/ursulovic/registry/gno.mod b/examples/gno.land/r/ursulovic/registry/gno.mod new file mode 100644 index 00000000000..ee1f5d38780 --- /dev/null +++ b/examples/gno.land/r/ursulovic/registry/gno.mod @@ -0,0 +1 @@ +module gno.land/r/ursulovic/registry diff --git a/examples/gno.land/r/ursulovic/registry/registry.gno b/examples/gno.land/r/ursulovic/registry/registry.gno new file mode 100644 index 00000000000..0bbd6c80df5 --- /dev/null +++ b/examples/gno.land/r/ursulovic/registry/registry.gno @@ -0,0 +1,59 @@ +package registry + +import ( + "errors" + "std" +) + +var ( + mainAddress std.Address + backupAddress std.Address + + ErrInvalidAddr = errors.New("Ivan's registry: Invalid address") + ErrUnauthorized = errors.New("Ivan's registry: Unauthorized") +) + +func init() { + mainAddress = "g1d24j8fwnc0w5q427fauyey4gdd30qgu69k6n0x" + backupAddress = "g1mw2xft3eava9kfhqw3fjj3kkf3pkammty0mtv7" +} + +func MainAddress() std.Address { + return mainAddress +} + +func BackupAddress() std.Address { + return backupAddress +} + +func SetMainAddress(addr std.Address) error { + assertAuthorized() + + if !addr.IsValid() { + return ErrInvalidAddr + } + + mainAddress = addr + return nil +} + +func SetBackupAddress(addr std.Address) error { + assertAuthorized() + + if !addr.IsValid() { + return ErrInvalidAddr + } + + backupAddress = addr + return nil +} + +// It will stay here for now, might be useful later +func assertAuthorized() { + caller := std.PrevRealm().Addr() + isAuthorized := caller == mainAddress || caller == backupAddress + + if !isAuthorized { + panic(ErrUnauthorized) + } +} From 90ff3e440446a2604c32d185f0bb63d31c499a51 Mon Sep 17 00:00:00 2001 From: 6h057 <15034695+omarsy@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:19:20 +0100 Subject: [PATCH 11/13] fix(gnovm): save object when refCount changed (#2992) This PR a fix in the gnovm to ensure that objects are saved correctly when their reference count changes. closes: #2266 #1543
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
--- contribs/gnodev/pkg/dev/node_test.go | 2 +- examples/gno.land/p/demo/avl/z_0_filetest.gno | 113 - examples/gno.land/p/demo/avl/z_1_filetest.gno | 161 +- examples/gno.land/p/demo/avl/z_2_filetest.gno | 50 +- .../gno.land/r/demo/boards/z_4_filetest.gno | 19 + .../testdata/addpkg_namespace.txtar | 2 +- .../pkg/integration/testdata/ghverify.txtar | 2 +- .../pkg/integration/testdata/issue_1543.txtar | 41 + .../pkg/integration/testdata/issue_2266.txtar | 42 + .../integration/testdata/simulate_gas.txtar | 4 +- gno.land/pkg/sdk/vm/gas_test.go | 4 +- .../cmd/gno/testdata/test/realm_correct.txtar | 67 +- .../gno/testdata/test/realm_incorrect.txtar | 2 +- gnovm/cmd/gno/testdata/test/realm_sync.txtar | 65 - gnovm/pkg/gnolang/realm.go | 8 +- gnovm/pkg/gnolang/store.go | 4 +- .../more/realm_compositelit_filetest.gno | 146 -- gnovm/tests/files/heap_item_value.gno | 125 - gnovm/tests/files/heap_item_value_init.gno | 168 +- gnovm/tests/files/zrealm0.gno | 65 - gnovm/tests/files/zrealm1.gno | 156 -- gnovm/tests/files/zrealm13.gno | 77 + gnovm/tests/files/zrealm14.gno | 168 ++ gnovm/tests/files/zrealm15.gno | 178 ++ gnovm/tests/files/zrealm16.gno | 115 + gnovm/tests/files/zrealm2.gno | 192 -- gnovm/tests/files/zrealm3.gno | 186 -- gnovm/tests/files/zrealm4.gno | 120 +- gnovm/tests/files/zrealm5.gno | 120 +- gnovm/tests/files/zrealm6.gno | 141 +- gnovm/tests/files/zrealm7.gno | 236 +- gnovm/tests/files/zrealm_avl0.gno | 113 - gnovm/tests/files/zrealm_avl1.gno | 161 +- gnovm/tests/files/zrealm_crossrealm21.gno | 672 +---- gnovm/tests/files/zrealm_crossrealm22.gno | 2176 +---------------- gnovm/tests/files/zrealm_natbind0.gno | 150 -- gnovm/tests/files/zrealm_tests0.gno | 1665 +------------ 37 files changed, 1002 insertions(+), 6714 deletions(-) create mode 100644 gno.land/pkg/integration/testdata/issue_1543.txtar create mode 100644 gno.land/pkg/integration/testdata/issue_2266.txtar create mode 100644 gnovm/tests/files/zrealm13.gno create mode 100644 gnovm/tests/files/zrealm14.gno create mode 100644 gnovm/tests/files/zrealm15.gno create mode 100644 gnovm/tests/files/zrealm16.gno diff --git a/contribs/gnodev/pkg/dev/node_test.go b/contribs/gnodev/pkg/dev/node_test.go index 4a4acc232b9..38fab0a3360 100644 --- a/contribs/gnodev/pkg/dev/node_test.go +++ b/contribs/gnodev/pkg/dev/node_test.go @@ -438,7 +438,7 @@ func testingCallRealm(t *testing.T, node *Node, msgs ...vm.MsgCall) (*core_types txcfg := gnoclient.BaseTxCfg{ GasFee: ugnot.ValueString(1000000), // Gas fee - GasWanted: 2_000_000, // Gas wanted + GasWanted: 3_000_000, // Gas wanted } // Set Caller in the msgs diff --git a/examples/gno.land/p/demo/avl/z_0_filetest.gno b/examples/gno.land/p/demo/avl/z_0_filetest.gno index 2dce5e7f1ac..1db1adebd3e 100644 --- a/examples/gno.land/p/demo/avl/z_0_filetest.gno +++ b/examples/gno.land/p/demo/avl/z_0_filetest.gno @@ -215,116 +215,3 @@ func main() { // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "5", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "ae86874f9b47fa5e64c30b3e92e9d07f2ec967a4", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "z_0.gno", -// "IsMethod": false, -// "Name": "init.1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "z_0.gno", -// "Line": "10", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "z_0.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "z_0.gno", -// "Line": "15", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } diff --git a/examples/gno.land/p/demo/avl/z_1_filetest.gno b/examples/gno.land/p/demo/avl/z_1_filetest.gno index 97ca5ed2135..572c49333bc 100644 --- a/examples/gno.land/p/demo/avl/z_1_filetest.gno +++ b/examples/gno.land/p/demo/avl/z_1_filetest.gno @@ -24,6 +24,44 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ModTime": "11", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "1375f6f96a1a3f298347dc8fc0065afa36cb7f0f", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ModTime": "13", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "b28057ab7be6383785c0a5503e8a531bdbc21851", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// } +// } +// } // c[a8ada09dee16d791fd406d629fe29bb0ed084a30:15]={ // "Fields": [ // { @@ -143,7 +181,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "2f3adc5d0f2a3fe0331cfa93572a7abdde14c9aa", +// "Hash": "cafae89e4d4aaaefe7fdf0691084508d4274a981", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" // }, // "Index": "0", @@ -191,7 +229,7 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "fe20a19f956511f274dc77854e9e5468387260f4", +// "Hash": "b2e446f490656c19a83c43055de29c96e92a1549", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" // } // } @@ -235,7 +273,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "c89a71bdf045e8bde2059dc9d33839f916e02e5d", +// "Hash": "4e56eeb96eb1d9b27cf603140cd03a1622b6358b", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" // }, // "Index": "0", @@ -254,7 +292,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "90fa67f8c47db4b9b2a60425dff08d5a3385100f", +// "Hash": "7b61530859954d1d14b2f696c91c5f37d39c21e7", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" // }, // "Index": "0", @@ -283,123 +321,10 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "83e42caaf53070dd95b5f859053eb51ed900bbda", +// "Hash": "fedc6d430b38c985dc6a985b2fcaee97e88ba6da", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "9", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "1faa9fa4ba1935121a6d3f0a623772e9d4499b0a", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "z_1.gno", -// "IsMethod": false, -// "Name": "init.1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "z_1.gno", -// "Line": "10", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "z_1.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "z_1.gno", -// "Line": "15", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:4] // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:5] diff --git a/examples/gno.land/p/demo/avl/z_2_filetest.gno b/examples/gno.land/p/demo/avl/z_2_filetest.gno index 43067c31e8f..c45088075d6 100644 --- a/examples/gno.land/p/demo/avl/z_2_filetest.gno +++ b/examples/gno.land/p/demo/avl/z_2_filetest.gno @@ -23,6 +23,44 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ModTime": "12", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "ba7550123807b8da857e38b72f66204b1ec582a2", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ModTime": "14", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "3cb8485664c356fcb5c88dfb96b7455133a6b022", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" +// } +// } +// } // c[a8ada09dee16d791fd406d629fe29bb0ed084a30:16]={ // "Fields": [ // { @@ -142,7 +180,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "849a50d6c78d65742752e3c89ad8dd556e2e63cb", +// "Hash": "db39c9c0a60e0d5b30dbaf9be6150d3fec16aa4b", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" // }, // "Index": "0", @@ -190,7 +228,7 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "a1160b0060ad752dbfe5fe436f7734bb19136150", +// "Hash": "2e9127534f91b385426d76e8e164f50f635cc1de", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14" // } // } @@ -234,7 +272,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "fd95e08763159ac529e26986d652e752e78b6325", +// "Hash": "43e03b0c877b40c34e12bc2b15560e8ecd42ae9d", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" // }, // "Index": "0", @@ -253,7 +291,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "3ecdcf148fe2f9e97b72a3bedf303b2ba56d4f4b", +// "Hash": "4b123e2424d900a427f9dee88a70ce61f3cdcf5b", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" // }, // "Index": "0", @@ -282,7 +320,7 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "63126557dba88f8556f7a0ccbbfc1d218ae7a302", +// "Hash": "76d9227e755efd6674d8fa34e12decb7a9855488", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" // } // } @@ -301,7 +339,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "d31c7e797793e03ffe0bbcb72f963264f8300d22", +// "Hash": "ff46b4dd63457c3fd59801e725f65af524ec829d", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" // }, // "Index": "0", diff --git a/examples/gno.land/r/demo/boards/z_4_filetest.gno b/examples/gno.land/r/demo/boards/z_4_filetest.gno index c6cf6397b3a..b781e94e4db 100644 --- a/examples/gno.land/r/demo/boards/z_4_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_4_filetest.gno @@ -885,6 +885,25 @@ func main() { // "RefCount": "1" // } // } +// u[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:84]={ +// "ObjectInfo": { +// "ID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:84", +// "IsEscaped": true, +// "ModTime": "127", +// "RefCount": "6" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/boards.Board" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "a88a9b837af217656ee27084309f7cd02cd94cb3", +// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:85" +// } +// } +// } // switchrealm["gno.land/r/demo/boards"] // switchrealm["gno.land/r/demo/users"] // switchrealm["gno.land/r/demo/users"] diff --git a/gno.land/pkg/integration/testdata/addpkg_namespace.txtar b/gno.land/pkg/integration/testdata/addpkg_namespace.txtar index f529c176f36..2cfd00acda4 100644 --- a/gno.land/pkg/integration/testdata/addpkg_namespace.txtar +++ b/gno.land/pkg/integration/testdata/addpkg_namespace.txtar @@ -73,7 +73,7 @@ stdout 'OK!' # Test gui publishing on guiland/one # gui addpkg -> gno.land/r/guiland/one -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/guiland/one -gas-fee 1000000ugnot -gas-wanted 1700000 -broadcast -chainid=tendermint_test gui +gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/guiland/one -gas-fee 1000000ugnot -gas-wanted 1800000 -broadcast -chainid=tendermint_test gui stdout 'OK!' # Test admin publishing on guiland/two diff --git a/gno.land/pkg/integration/testdata/ghverify.txtar b/gno.land/pkg/integration/testdata/ghverify.txtar index b53849e85b5..0f2d21f6bd5 100644 --- a/gno.land/pkg/integration/testdata/ghverify.txtar +++ b/gno.land/pkg/integration/testdata/ghverify.txtar @@ -25,7 +25,7 @@ stdout "" stderr 'invalid ingest id: a' # the agent publishes their response to the task and the verification is complete -gnokey maketx call -pkgpath gno.land/r/gnoland/ghverify -func GnorkleEntrypoint -args 'ingest,g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5,OK' -gas-fee 1000000ugnot -gas-wanted 5000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/gnoland/ghverify -func GnorkleEntrypoint -args 'ingest,g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5,OK' -gas-fee 1000000ugnot -gas-wanted 6000000 -broadcast -chainid=tendermint_test test1 stdout OK! # get verified github handle by gno address diff --git a/gno.land/pkg/integration/testdata/issue_1543.txtar b/gno.land/pkg/integration/testdata/issue_1543.txtar new file mode 100644 index 00000000000..388f126fcda --- /dev/null +++ b/gno.land/pkg/integration/testdata/issue_1543.txtar @@ -0,0 +1,41 @@ +# test issue + +loadpkg gno.land/r/demo/realm $WORK + +# start a new node +gnoland start + + +gnokey maketx call -pkgpath gno.land/r/demo/realm --func Fill --args 0 --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/realm --func UnFill --args 0 --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/realm --func Fill --args 0 --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 + + +-- realm.gno -- +package main + +type A struct { + A string +} +type B struct { + A *A + B string +} + +var ( + a = &A{A: "here"} + b [2]*B +) + +func Fill(i int) { + c := B{ + A: a, + B: "", + } + b[i] = &c +} + +func UnFill(i int) { + b[i] = nil +} + diff --git a/gno.land/pkg/integration/testdata/issue_2266.txtar b/gno.land/pkg/integration/testdata/issue_2266.txtar new file mode 100644 index 00000000000..046f57802e3 --- /dev/null +++ b/gno.land/pkg/integration/testdata/issue_2266.txtar @@ -0,0 +1,42 @@ +# test issue + +loadpkg gno.land/r/demo/realm $WORK + +# start a new node +gnoland start + + +gnokey maketx call -pkgpath gno.land/r/demo/realm --func Fill --args 0 --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/realm --func Fill --args 1 --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/realm --func UnFill --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast -chainid=tendermint_test test1 + + +-- realm.gno -- +package main + +type A struct { + A string +} +type B struct { + A *A + B string +} + +var ( + a = &A{A: "here"} + b [2]*B +) + +func Fill(i int) { + c := B{ + A: a, + B: "", + } + b[i] = &c +} + +func UnFill() { + b[0] = nil + b[1] = nil +} + diff --git a/gno.land/pkg/integration/testdata/simulate_gas.txtar b/gno.land/pkg/integration/testdata/simulate_gas.txtar index 57be82b75ff..0dcb9ba424b 100644 --- a/gno.land/pkg/integration/testdata/simulate_gas.txtar +++ b/gno.land/pkg/integration/testdata/simulate_gas.txtar @@ -6,11 +6,11 @@ gnoland start # simulate only gnokey maketx call -pkgpath gno.land/r/simulate -func Hello -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test -simulate only test1 -stdout 'GAS USED: 99339' +stdout 'GAS USED: 99371' # simulate skip gnokey maketx call -pkgpath gno.land/r/simulate -func Hello -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test -simulate skip test1 -stdout 'GAS USED: 99339' # same as simulate only +stdout 'GAS USED: 99371' # same as simulate only -- package/package.gno -- diff --git a/gno.land/pkg/sdk/vm/gas_test.go b/gno.land/pkg/sdk/vm/gas_test.go index 276aa9db0b0..acde3d315c6 100644 --- a/gno.land/pkg/sdk/vm/gas_test.go +++ b/gno.land/pkg/sdk/vm/gas_test.go @@ -74,8 +74,8 @@ func TestAddPkgDeliverTx(t *testing.T) { assert.True(t, res.IsOK()) - // NOTE: let's try to keep this bellow 100_000 :) - assert.Equal(t, int64(135365), gasDeliver) + // NOTE: let's try to keep this bellow 150_000 :) + assert.Equal(t, int64(143845), gasDeliver) } // Enough gas for a failed transaction. diff --git a/gnovm/cmd/gno/testdata/test/realm_correct.txtar b/gnovm/cmd/gno/testdata/test/realm_correct.txtar index ced183bec67..ae1212133fd 100644 --- a/gnovm/cmd/gno/testdata/test/realm_correct.txtar +++ b/gnovm/cmd/gno/testdata/test/realm_correct.txtar @@ -18,69 +18,4 @@ func main() { } // Realm: -// switchrealm["gno.land/r/xx"] -// u[aea84df38908f9569d0f552575606e6e6e7e22dd:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "aea84df38908f9569d0f552575606e6e6e7e22dd:2", -// "IsEscaped": true, -// "ModTime": "3", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/xx" -// } -// }, -// "Values": [ -// { -// "N": "AQAAAAAAAAA=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "aea84df38908f9569d0f552575606e6e6e7e22dd:3" -// }, -// "FileName": "x.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/xx", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "x.gno", -// "Line": "6", -// "PkgPath": "gno.land/r/xx" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } +// switchrealm["gno.land/r/xx"] \ No newline at end of file diff --git a/gnovm/cmd/gno/testdata/test/realm_incorrect.txtar b/gnovm/cmd/gno/testdata/test/realm_incorrect.txtar index 234d0f81e77..84f4e3438ee 100644 --- a/gnovm/cmd/gno/testdata/test/realm_incorrect.txtar +++ b/gnovm/cmd/gno/testdata/test/realm_incorrect.txtar @@ -7,7 +7,7 @@ stderr '=== RUN file/x_filetest.gno' stderr 'Realm diff:' stderr '--- Expected' stderr '\+\+\+ Actual' -stderr '@@ -1,2 \+1,67 @@' +stderr '@@ -1,2 \+1,2 @@' stderr '-xxx' stderr '\+switchrealm\["gno.land/r/xx"\]' stderr 'x_filetest.gno failed' diff --git a/gnovm/cmd/gno/testdata/test/realm_sync.txtar b/gnovm/cmd/gno/testdata/test/realm_sync.txtar index c93e6d86e8f..65a930b2f03 100644 --- a/gnovm/cmd/gno/testdata/test/realm_sync.txtar +++ b/gnovm/cmd/gno/testdata/test/realm_sync.txtar @@ -33,68 +33,3 @@ func main() { // Realm: // switchrealm["gno.land/r/xx"] -// u[aea84df38908f9569d0f552575606e6e6e7e22dd:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "aea84df38908f9569d0f552575606e6e6e7e22dd:2", -// "IsEscaped": true, -// "ModTime": "3", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/xx" -// } -// }, -// "Values": [ -// { -// "N": "AQAAAAAAAAA=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "aea84df38908f9569d0f552575606e6e6e7e22dd:3" -// }, -// "FileName": "x.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/xx", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "x.gno", -// "Line": "6", -// "PkgPath": "gno.land/r/xx" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 04de760037a..509fcd67a60 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -192,6 +192,9 @@ func (rlm *Realm) DidUpdate(po, xo, co Object) { if co != nil { co.IncRefCount() if co.GetRefCount() > 1 { + if co.GetIsReal() { + rlm.MarkDirty(co) + } if co.GetIsEscaped() { // already escaped } else { @@ -211,6 +214,8 @@ func (rlm *Realm) DidUpdate(po, xo, co Object) { if xo.GetIsReal() { rlm.MarkNewDeleted(xo) } + } else if xo.GetIsReal() { + rlm.MarkDirty(xo) } } } @@ -464,6 +469,7 @@ func (rlm *Realm) incRefCreatedDescendants(store Store, oo Object) { child.SetIsNewReal(true) } } else if rc > 1 { + rlm.MarkDirty(child) if child.GetIsEscaped() { // already escaped, do nothing. } else { @@ -537,7 +543,7 @@ func (rlm *Realm) decRefDeletedDescendants(store Store, oo Object) { if rc == 0 { rlm.decRefDeletedDescendants(store, child) } else if rc > 0 { - // do nothing + rlm.MarkDirty(child) } else { panic("deleted descendants should not have a reference count of less than zero") } diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index bc56a7c6313..3a70d07381b 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -519,7 +519,7 @@ func (ds *defaultStore) SetObject(oo Object) { } ds.cacheObjects[oid] = oo // make store op log entry - if ds.opslog != nil { + if _, ok := oo.(*Block); !ok && ds.opslog != nil { var op StoreOpType if oo.GetIsNewReal() { op = StoreOpNew @@ -560,7 +560,7 @@ func (ds *defaultStore) DelObject(oo Object) { ds.baseStore.Delete([]byte(key)) } // make realm op log entry - if ds.opslog != nil { + if _, ok := oo.(*Block); !ok && ds.opslog != nil { ds.opslog = append(ds.opslog, StoreOp{Type: StoreOpDel, Object: oo}) } diff --git a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno index 45f83bade5f..8514c2676aa 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno @@ -89,149 +89,3 @@ func main() { // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "3", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.PrimitiveType", -// "value": "2048" -// }, -// "Methods": [], -// "Name": "word", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.SliceType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.word" -// }, -// "Vrd": false -// }, -// "Methods": [], -// "Name": "nat", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Int" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "3c89d875f7d6daa94113aa4c7e03432ba56202c2", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "abs", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.nat" -// } -// } -// ], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "Int", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/assign_unnamed_type/more/realm_compositelit.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/assign_unnamed_type/more/realm_compositelit.gno", -// "Line": "16", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } diff --git a/gnovm/tests/files/heap_item_value.gno b/gnovm/tests/files/heap_item_value.gno index 80bf702bec2..7a728d2c6f9 100644 --- a/gnovm/tests/files/heap_item_value.gno +++ b/gnovm/tests/files/heap_item_value.gno @@ -51,128 +51,3 @@ func main() { // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "3", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "A", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// } -// ], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "S", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.S" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.S" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/heap_item_value.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/heap_item_value.gno", -// "Line": "10", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } diff --git a/gnovm/tests/files/heap_item_value_init.gno b/gnovm/tests/files/heap_item_value_init.gno index 2722cce8675..6be9caed1f4 100644 --- a/gnovm/tests/files/heap_item_value_init.gno +++ b/gnovm/tests/files/heap_item_value_init.gno @@ -19,167 +19,23 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "IsEscaped": true, // "ModTime": "6", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", // "RefCount": "2" // }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "A", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// } -// } -// ], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "S", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.S" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.S" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/heap_item_value_init.gno", -// "IsMethod": false, -// "Name": "init.3", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/heap_item_value_init.gno", -// "Line": "10", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" // }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/heap_item_value_init.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/heap_item_value_init.gno", -// "Line": "16", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "a05e5e1e2d2a27d94408a9325a58068e60b504df", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" // } -// ] +// } // } diff --git a/gnovm/tests/files/zrealm0.gno b/gnovm/tests/files/zrealm0.gno index 5685da2154b..d3bf0e79223 100644 --- a/gnovm/tests/files/zrealm0.gno +++ b/gnovm/tests/files/zrealm0.gno @@ -20,68 +20,3 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "3", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "N": "AQAAAAAAAAA=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm0.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm0.gno", -// "Line": "6", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } diff --git a/gnovm/tests/files/zrealm1.gno b/gnovm/tests/files/zrealm1.gno index bb44a93bad4..eef42cc9378 100644 --- a/gnovm/tests/files/zrealm1.gno +++ b/gnovm/tests/files/zrealm1.gno @@ -47,159 +47,3 @@ func main() { // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "3", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.InnerNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "ae4e9e2d205cc0081d4ee249e1d188ebe270b220", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.InterfaceType", -// "Generic": "", -// "Methods": [], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "Node", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.InterfaceType", -// "Generic": "", -// "Methods": [], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "Key", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "Key", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Key" -// } -// }, -// { -// "Embedded": false, -// "Name": "Left", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Node" -// } -// }, -// { -// "Embedded": false, -// "Name": "Right", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Node" -// } -// } -// ], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "InnerNode", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm1.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm1.gno", -// "Line": "17", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } diff --git a/gnovm/tests/files/zrealm13.gno b/gnovm/tests/files/zrealm13.gno new file mode 100644 index 00000000000..f43f440f731 --- /dev/null +++ b/gnovm/tests/files/zrealm13.gno @@ -0,0 +1,77 @@ +// PKGPATH: gno.land/r/test +package test + +var ( + a = &A{A: "here"} + b [2]*B +) + + +type A struct { + A string +} +type B struct { + A *A + B string +} + +func init() { + c := B{ + A: a, + B: "c", + } + b[0] = &c + + d := B{ + A: a, + B: "d", + } + b[1] = &d +} + +func main() { + b[0] = nil +} + + +// Realm: +// switchrealm["gno.land/r/test"] +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// "Data": null, +// "List": [ +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.B" +// } +// } +// }, +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.B" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// }, +// "Index": "1", +// "TV": null +// } +// } +// ], +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ModTime": "9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" +// } +// } diff --git a/gnovm/tests/files/zrealm14.gno b/gnovm/tests/files/zrealm14.gno new file mode 100644 index 00000000000..ffffa4883fd --- /dev/null +++ b/gnovm/tests/files/zrealm14.gno @@ -0,0 +1,168 @@ +// PKGPATH: gno.land/r/test +package test + +var ( + a = &A{A: "here"} + b [2]*B +) + + +type A struct { + A string +} +type B struct { + A *A + B string +} + +func init() { + c := B{ + A: a, + B: "c", + } + b[0] = &c + + d := B{ + A: a, + B: "d", + } + b[1] = &d +} + +func main() { + b[0] = nil + b[1] = nil +} + +// Realm: +// switchrealm["gno.land/r/test"] +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// "Data": null, +// "List": [ +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.B" +// } +// } +// }, +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.B" +// } +// } +// } +// ], +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ModTime": "9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// "Fields": [ +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.A" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" +// }, +// "Index": "0", +// "TV": null +// } +// }, +// { +// "T": { +// "@type": "/gno.PrimitiveType", +// "value": "16" +// }, +// "V": { +// "@type": "/gno.StringValue", +// "value": "c" +// } +// } +// ], +// "ObjectInfo": { +// "Hash": "c22ccb7832b422c83fec9943b751cb134fcbed0b", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "RefCount": "0" +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ +// "Fields": [ +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.A" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" +// }, +// "Index": "0", +// "TV": null +// } +// }, +// { +// "T": { +// "@type": "/gno.PrimitiveType", +// "value": "16" +// }, +// "V": { +// "@type": "/gno.StringValue", +// "value": "d" +// } +// } +// ], +// "ObjectInfo": { +// "Hash": "86c916fd78da57d354cb38019923bf64c1a3471c", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "RefCount": "0" +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// "IsEscaped": true, +// "ModTime": "9", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.A" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "95dca2f5b12899b6367402ecdac04c7ca59a03d9", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// } +// } +// } +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:8] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:9] diff --git a/gnovm/tests/files/zrealm15.gno b/gnovm/tests/files/zrealm15.gno new file mode 100644 index 00000000000..4ca6ef3b03d --- /dev/null +++ b/gnovm/tests/files/zrealm15.gno @@ -0,0 +1,178 @@ +// PKGPATH: gno.land/r/test +package test + +var ( + a = &A{} + b [2]*B + s *S +) + +type S struct { + S string +} +type A struct { + A *S +} +type B struct { + A *A + B *S +} + +func init() { + s = &S{ + S: "c", + } + c := B{ + A: a, + B: s, + } + b[0] = &c + b[1] = &c + a.A = s +} + +func main() { + b[0] = nil + b[1] = nil + a.A = nil +} + + +// Realm: +// switchrealm["gno.land/r/test"] +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// "Data": null, +// "List": [ +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.B" +// } +// } +// }, +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.B" +// } +// } +// } +// ], +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ModTime": "10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ +// "Fields": [ +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.A" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" +// }, +// "Index": "0", +// "TV": null +// } +// }, +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// }, +// "Index": "0", +// "TV": null +// } +// } +// ], +// "ObjectInfo": { +// "Hash": "5bf603ab337f9f40f8b22441562319d67be402b2", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "ModTime": "0", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "RefCount": "0" +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// "Fields": [ +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" +// } +// } +// } +// ], +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ModTime": "10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// "RefCount": "1" +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "IsEscaped": true, +// "ModTime": "10", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "6e4c3c716e28df1d3a25efeb654a7b7a379ce3b0", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// "IsEscaped": true, +// "ModTime": "10", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.A" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "e82e410f22425e48d5f6c611160084a4dd50d3d1", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// } +// } +// } +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:10] diff --git a/gnovm/tests/files/zrealm16.gno b/gnovm/tests/files/zrealm16.gno new file mode 100644 index 00000000000..b7bef5028b0 --- /dev/null +++ b/gnovm/tests/files/zrealm16.gno @@ -0,0 +1,115 @@ +// PKGPATH: gno.land/r/test +package test + +var ( + a = &A{A: "here"} + a2 = &A{A: "here"} + b [2]*B +) + +type A struct { + A string +} +type B struct { + A *A + B string +} + +func init() { + c := B{ + A: a, + B: "c", + } + b[0] = &c + + d := B{ + A: a, + B: "d", + } + b[1] = &d +} + +func main() { + b[0].A = a2 +} + +// Realm: +// switchrealm["gno.land/r/test"] +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ +// "Fields": [ +// { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.A" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// }, +// "Index": "0", +// "TV": null +// } +// }, +// { +// "T": { +// "@type": "/gno.PrimitiveType", +// "value": "16" +// }, +// "V": { +// "@type": "/gno.StringValue", +// "value": "c" +// } +// } +// ], +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "ModTime": "11", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "RefCount": "1" +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "IsEscaped": true, +// "ModTime": "11", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "2" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.A" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "7c9f93a63419d852f132afaf2245ddcac5e8c3fb", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// "IsEscaped": true, +// "ModTime": "11", +// "RefCount": "2" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.A" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "95dca2f5b12899b6367402ecdac04c7ca59a03d9", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// } +// } +// } diff --git a/gnovm/tests/files/zrealm2.gno b/gnovm/tests/files/zrealm2.gno index 7bae02e48bc..57cd8bee349 100644 --- a/gnovm/tests/files/zrealm2.gno +++ b/gnovm/tests/files/zrealm2.gno @@ -50,196 +50,4 @@ func main() { // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "4", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.InnerNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "61d4aa77a87c01e07038c6030d6aca299d0fdc1b", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.InterfaceType", -// "Generic": "", -// "Methods": [], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "Node", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.InterfaceType", -// "Generic": "", -// "Methods": [], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "Key", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "Key", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Key" -// } -// }, -// { -// "Embedded": false, -// "Name": "Left", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Node" -// } -// }, -// { -// "Embedded": false, -// "Name": "Right", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Node" -// } -// } -// ], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "InnerNode", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm2.gno", -// "IsMethod": false, -// "Name": "init.4", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm2.gno", -// "Line": "17", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm2.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm2.gno", -// "Line": "23", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:4] diff --git a/gnovm/tests/files/zrealm3.gno b/gnovm/tests/files/zrealm3.gno index 386fd4fe470..cc9317c32fd 100644 --- a/gnovm/tests/files/zrealm3.gno +++ b/gnovm/tests/files/zrealm3.gno @@ -82,191 +82,5 @@ func main() { // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "5", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Node" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "8197b7c5b4f2c7bf9c12b1c614f6b4dc6e7ce8dd", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.InterfaceType", -// "Generic": "", -// "Methods": [], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "Key", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "Key", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Key" -// } -// }, -// { -// "Embedded": false, -// "Name": "Left", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Node" -// } -// } -// }, -// { -// "Embedded": false, -// "Name": "Right", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Node" -// } -// } -// } -// ], -// "PkgPath": "gno.land/r/test" -// }, -// "Methods": [], -// "Name": "Node", -// "PkgPath": "gno.land/r/test" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm3.gno", -// "IsMethod": false, -// "Name": "init.3", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm3.gno", -// "Line": "14", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm3.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm3.gno", -// "Line": "20", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:4] // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:5] diff --git a/gnovm/tests/files/zrealm4.gno b/gnovm/tests/files/zrealm4.gno index 8c3857aa37c..f8c5502fcb1 100644 --- a/gnovm/tests/files/zrealm4.gno +++ b/gnovm/tests/files/zrealm4.gno @@ -78,116 +78,22 @@ func main() { // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "ModTime": "5", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "7b9d58f40430bbbcbafd47eefb7a6dd342477f71", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", -// "TV": null -// } +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm4.gno", -// "IsMethod": false, -// "Name": "init.1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm4.gno", -// "Line": "11", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm4.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm4.gno", -// "Line": "15", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "d57ee28f5030eb8c612b374155fd545675633288", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" // } -// ] +// } // } diff --git a/gnovm/tests/files/zrealm5.gno b/gnovm/tests/files/zrealm5.gno index c1062d51e8d..13d6e4a6b64 100644 --- a/gnovm/tests/files/zrealm5.gno +++ b/gnovm/tests/files/zrealm5.gno @@ -162,116 +162,22 @@ func main() { // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "ModTime": "5", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "7b9d58f40430bbbcbafd47eefb7a6dd342477f71", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm5.gno", -// "IsMethod": false, -// "Name": "init.1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm5.gno", -// "Line": "11", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm5.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm5.gno", -// "Line": "15", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "115779a405a1cae45446397ea897a98a4043cbb2", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" // } -// ] +// } // } diff --git a/gnovm/tests/files/zrealm6.gno b/gnovm/tests/files/zrealm6.gno index 1c50baa2d15..ba162c4d468 100644 --- a/gnovm/tests/files/zrealm6.gno +++ b/gnovm/tests/files/zrealm6.gno @@ -163,6 +163,25 @@ func main() { // "RefCount": "1" // } // } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ModTime": "7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "5d64092f4f064ca58bdeffa32f6a119545b401c8", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// } +// } +// } // u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ // "Fields": [ // { @@ -213,7 +232,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "7c63a8fd451cd7c470c1851f1ead037246422ded", +// "Hash": "32593d23afa555fe99d433dbca1130b3843da97a", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" // }, // "Index": "0", @@ -228,116 +247,22 @@ func main() { // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "ModTime": "7", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "ade9fce2a987ef1924040a1d75c0172410c66952", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm6.gno", -// "IsMethod": false, -// "Name": "init.1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm6.gno", -// "Line": "11", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm6.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm6.gno", -// "Line": "16", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "131993c49dced230bd7071e9bae8d95e28733b73", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" // } -// ] +// } // } diff --git a/gnovm/tests/files/zrealm7.gno b/gnovm/tests/files/zrealm7.gno index e22b90f0e0f..5b932962db4 100644 --- a/gnovm/tests/files/zrealm7.gno +++ b/gnovm/tests/files/zrealm7.gno @@ -164,26 +164,7 @@ func main() { // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", -// "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", -// "RefCount": "1" -// }, -// "Value": { -// "T": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "2c172bbe0183ccc73c59d9acb196c45b0331c39e", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" -// } -// } -// } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ // "Fields": [ // { // "T": { @@ -192,7 +173,7 @@ func main() { // }, // "V": { // "@type": "/gno.StringValue", -// "value": "key1" +// "value": "key0" // } // }, // { @@ -202,11 +183,11 @@ func main() { // }, // "V": { // "@type": "/gno.StringValue", -// "value": "value1" +// "value": "value0" // } // }, // { -// "N": "AwAAAAAAAAA=", +// "N": "AQAAAAAAAAA=", // "T": { // "@type": "/gno.PrimitiveType", // "value": "32" @@ -219,16 +200,6 @@ func main() { // "@type": "/gno.RefType", // "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "a4fa9bdf45caf8c6b5be7a3752704423817b3ef2", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", -// "TV": null // } // }, // { @@ -238,27 +209,55 @@ func main() { // "@type": "/gno.RefType", // "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "43f69f24b7827a331921b4af0f667346d186e0c3", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" -// }, -// "Index": "0", -// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", // "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ModTime": "9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "d7fbb234dca9f194f35fe5409a62db9daf39b0fc", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ModTime": "9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "2c172bbe0183ccc73c59d9acb196c45b0331c39e", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ // "Fields": [ // { // "T": { @@ -267,7 +266,7 @@ func main() { // }, // "V": { // "@type": "/gno.StringValue", -// "value": "key0" +// "value": "key1" // } // }, // { @@ -277,11 +276,11 @@ func main() { // }, // "V": { // "@type": "/gno.StringValue", -// "value": "value0" +// "value": "value1" // } // }, // { -// "N": "AQAAAAAAAAA=", +// "N": "AwAAAAAAAAA=", // "T": { // "@type": "/gno.PrimitiveType", // "value": "32" @@ -294,6 +293,16 @@ func main() { // "@type": "/gno.RefType", // "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "76a40dcf03d32c312c2213265c14d4de1b12a810", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// }, +// "Index": "0", +// "TV": null // } // }, // { @@ -303,13 +312,23 @@ func main() { // "@type": "/gno.RefType", // "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" // } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Hash": "43f69f24b7827a331921b4af0f667346d186e0c3", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// }, +// "Index": "0", +// "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "RefCount": "1" // } // } @@ -327,121 +346,8 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "f56fbd9c8db299689cc0cf806fe741b6a6e641e6", +// "Hash": "92b2f4ebab764951f64086bce480f898f755de5a", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "9", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "github.com/gnolang/gno/_test/timtadh/data_structures/tree/avl.AvlNode" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "450aef9858564ed4ec1c418f1e8dac828079016b", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm7.gno", -// "IsMethod": false, -// "Name": "init.1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm7.gno", -// "Line": "11", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm7.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm7.gno", -// "Line": "17", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } diff --git a/gnovm/tests/files/zrealm_avl0.gno b/gnovm/tests/files/zrealm_avl0.gno index 362d04ec0f8..1db1adebd3e 100644 --- a/gnovm/tests/files/zrealm_avl0.gno +++ b/gnovm/tests/files/zrealm_avl0.gno @@ -215,116 +215,3 @@ func main() { // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "5", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "ae86874f9b47fa5e64c30b3e92e9d07f2ec967a4", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm_avl0.gno", -// "IsMethod": false, -// "Name": "init.1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm_avl0.gno", -// "Line": "10", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm_avl0.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm_avl0.gno", -// "Line": "15", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } diff --git a/gnovm/tests/files/zrealm_avl1.gno b/gnovm/tests/files/zrealm_avl1.gno index bfcf9f7975e..572c49333bc 100644 --- a/gnovm/tests/files/zrealm_avl1.gno +++ b/gnovm/tests/files/zrealm_avl1.gno @@ -24,6 +24,44 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ModTime": "11", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "1375f6f96a1a3f298347dc8fc0065afa36cb7f0f", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ModTime": "13", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "RefCount": "1" +// }, +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/p/demo/avl.Node" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "b28057ab7be6383785c0a5503e8a531bdbc21851", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// } +// } +// } // c[a8ada09dee16d791fd406d629fe29bb0ed084a30:15]={ // "Fields": [ // { @@ -143,7 +181,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "2f3adc5d0f2a3fe0331cfa93572a7abdde14c9aa", +// "Hash": "cafae89e4d4aaaefe7fdf0691084508d4274a981", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" // }, // "Index": "0", @@ -191,7 +229,7 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "fe20a19f956511f274dc77854e9e5468387260f4", +// "Hash": "b2e446f490656c19a83c43055de29c96e92a1549", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" // } // } @@ -235,7 +273,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "c89a71bdf045e8bde2059dc9d33839f916e02e5d", +// "Hash": "4e56eeb96eb1d9b27cf603140cd03a1622b6358b", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" // }, // "Index": "0", @@ -254,7 +292,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "90fa67f8c47db4b9b2a60425dff08d5a3385100f", +// "Hash": "7b61530859954d1d14b2f696c91c5f37d39c21e7", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" // }, // "Index": "0", @@ -283,123 +321,10 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "83e42caaf53070dd95b5f859053eb51ed900bbda", +// "Hash": "fedc6d430b38c985dc6a985b2fcaee97e88ba6da", // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "9", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/avl.Node" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "1faa9fa4ba1935121a6d3f0a623772e9d4499b0a", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm_avl1.gno", -// "IsMethod": false, -// "Name": "init.1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm_avl1.gno", -// "Line": "10", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm_avl1.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm_avl1.gno", -// "Line": "15", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:4] // d[a8ada09dee16d791fd406d629fe29bb0ed084a30:5] diff --git a/gnovm/tests/files/zrealm_crossrealm21.gno b/gnovm/tests/files/zrealm_crossrealm21.gno index 634fbea13c8..e3b29f671a4 100644 --- a/gnovm/tests/files/zrealm_crossrealm21.gno +++ b/gnovm/tests/files/zrealm_crossrealm21.gno @@ -24,673 +24,25 @@ func main() { // Realm: // switchrealm["gno.land/r/demo/tests/crossrealm"] -// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:2]={ -// "Blank": {}, +// u[0edc46caf30c00efd87b6c272673239eafbd051e:3]={ // "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", +// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:3", // "IsEscaped": true, // "ModTime": "5", +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:2", // "RefCount": "2" // }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "A", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// }, -// "Methods": [ -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "ls", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": null, -// "FileName": "crossrealm.gno", -// "IsMethod": true, -// "Name": "String", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "12", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "ls", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// } -// } -// } -// ], -// "Name": "LocalStruct", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "a75fdb389fedfcbbaa7f446d528c1e149726347c", -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "init.2", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "19", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/tests/p_crossrealm.Container" -// } -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "Make1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "24", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/tests/p_crossrealm.Container" -// } -// } -// } -// ] -// } -// } +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/tests/crossrealm_b.fooer" // }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.InterfaceType", -// "Generic": "", -// "Methods": [ -// { -// "Embedded": false, -// "Name": "Foo", -// "Tag": "", -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// }, -// "Methods": [], -// "Name": "Fooer", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm_b.fooer" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:3" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "f", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "SetFooer", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "35", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "f", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "GetFooer", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "40", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "CallFooerFoo", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "42", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "Methods": [], -// "Name": "FooerGetter", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "fg", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "SetFooerGetter", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "48", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "fg", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "GetFooerGetter", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "53", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "CallFooerGetterFoo", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "57", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "8222b763e9bc04b4b7805e165e9f1324a39f28b6", +// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:4" // } -// ] +// } // } // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] diff --git a/gnovm/tests/files/zrealm_crossrealm22.gno b/gnovm/tests/files/zrealm_crossrealm22.gno index 18985f7719d..afb9dab6d59 100644 --- a/gnovm/tests/files/zrealm_crossrealm22.gno +++ b/gnovm/tests/files/zrealm_crossrealm22.gno @@ -38,744 +38,25 @@ func main() { // Realm: // switchrealm["gno.land/r/demo/tests/crossrealm"] -// c[1712ac7adcfdc8e58a67e5615e20fb312394c4df:6]={ -// "Blank": {}, +// u[0edc46caf30c00efd87b6c272673239eafbd051e:3]={ // "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:6", -// "ModTime": "0", -// "OwnerID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", -// "RefCount": "1" -// }, -// "Parent": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "f5a516808f8976c33939133293d598ce3bca4e8d:3" -// }, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm_crossrealm22.gno", -// "Line": "11", -// "PkgPath": "gno.land/r/crossrealm_test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm_b.fooer" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:3" -// }, -// "Index": "0", -// "TV": null -// } -// } -// ] -// } -// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", +// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:3", // "IsEscaped": true, -// "ModTime": "5", +// "ModTime": "6", +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:2", // "RefCount": "2" // }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/tests/crossrealm_b.fooer" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "8222b763e9bc04b4b7805e165e9f1324a39f28b6", +// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:4" // } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "A", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// }, -// "Methods": [ -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "ls", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": null, -// "FileName": "crossrealm.gno", -// "IsMethod": true, -// "Name": "String", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "12", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "ls", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// } -// } -// } -// ], -// "Name": "LocalStruct", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "a75fdb389fedfcbbaa7f446d528c1e149726347c", -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "init.2", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "19", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/tests/p_crossrealm.Container" -// } -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "Make1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "24", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/tests/p_crossrealm.Container" -// } -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.InterfaceType", -// "Generic": "", -// "Methods": [ -// { -// "Embedded": false, -// "Name": "Foo", -// "Tag": "", -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// }, -// "Methods": [], -// "Name": "Fooer", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "f", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "SetFooer", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "35", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "f", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "GetFooer", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "40", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "CallFooerFoo", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "42", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "Methods": [], -// "Name": "FooerGetter", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Hash": "23de97a577d573252d00394ce9b71c24b0646546", -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:6" -// }, -// "FileName": "", -// "IsMethod": false, -// "Name": "", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/crossrealm_test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "28", -// "File": "files/zrealm_crossrealm22.gno", -// "Line": "13", -// "PkgPath": "gno.land/r/crossrealm_test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "fg", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "SetFooerGetter", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "48", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "fg", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "GetFooerGetter", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "53", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "CallFooerGetterFoo", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "57", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] +// } // } // switchrealm["gno.land/r/crossrealm_test"] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] @@ -826,701 +107,26 @@ func main() { // } // } // switchrealm["gno.land/r/demo/tests/crossrealm"] -// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:2]={ -// "Blank": {}, +// u[0edc46caf30c00efd87b6c272673239eafbd051e:3]={ // "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", +// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:3", // "IsEscaped": true, // "ModTime": "6", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:2", +// "RefCount": "1" // }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "A", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// }, -// "Methods": [ -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "ls", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": null, -// "FileName": "crossrealm.gno", -// "IsMethod": true, -// "Name": "String", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "12", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "ls", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// } -// } -// } -// ], -// "Name": "LocalStruct", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "a75fdb389fedfcbbaa7f446d528c1e149726347c", -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "init.2", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "19", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/tests/p_crossrealm.Container" -// } -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "Make1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "24", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/tests/p_crossrealm.Container" -// } -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.InterfaceType", -// "Generic": "", -// "Methods": [ -// { -// "Embedded": false, -// "Name": "Foo", -// "Tag": "", -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// }, -// "Methods": [], -// "Name": "Fooer", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "f", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "SetFooer", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "35", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "f", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "GetFooer", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "40", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "CallFooerFoo", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "42", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "Methods": [], -// "Name": "FooerGetter", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:5" -// }, -// "FileName": "", -// "IsMethod": false, -// "Name": "", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm_b", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "23", -// "File": "crossrealm.gno", -// "Line": "23", -// "PkgPath": "gno.land/r/demo/tests/crossrealm_b" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "fg", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "SetFooerGetter", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "48", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "fg", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "GetFooerGetter", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "53", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "CallFooerGetterFoo", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "57", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/tests/crossrealm_b.fooer" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "759fd5b507fff8ea1b18d401550d918387a63445", +// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:4" // } -// ] +// } // } -// d[1712ac7adcfdc8e58a67e5615e20fb312394c4df:6] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] @@ -1547,732 +153,6 @@ func main() { // } // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] -// c[1712ac7adcfdc8e58a67e5615e20fb312394c4df:7]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:7", -// "ModTime": "0", -// "OwnerID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", -// "RefCount": "1" -// }, -// "Parent": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:5" -// }, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "23", -// "File": "crossrealm.gno", -// "Line": "24", -// "PkgPath": "gno.land/r/demo/tests/crossrealm_b" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// } -// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", -// "IsEscaped": true, -// "ModTime": "6", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "A", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// }, -// "Methods": [ -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "ls", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": null, -// "FileName": "crossrealm.gno", -// "IsMethod": true, -// "Name": "String", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "12", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "ls", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// } -// } -// } -// ], -// "Name": "LocalStruct", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.LocalStruct" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "a75fdb389fedfcbbaa7f446d528c1e149726347c", -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "init.2", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "19", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/tests/p_crossrealm.Container" -// } -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "Make1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "24", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/p/demo/tests/p_crossrealm.Container" -// } -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.InterfaceType", -// "Generic": "", -// "Methods": [ -// { -// "Embedded": false, -// "Name": "Foo", -// "Tag": "", -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// }, -// "Methods": [], -// "Name": "Fooer", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "f", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "SetFooer", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "35", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "f", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "GetFooer", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "40", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "CallFooerFoo", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "42", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// }, -// "Methods": [], -// "Name": "FooerGetter", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Hash": "89352b352826005a86eee78e6c832b43ae0ab6a6", -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:7" -// }, -// "FileName": "", -// "IsMethod": false, -// "Name": "", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm_b", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "62", -// "File": "crossrealm.gno", -// "Line": "24", -// "PkgPath": "gno.land/r/demo/tests/crossrealm_b" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "fg", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "SetFooerGetter", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "48", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "fg", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "GetFooerGetter", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "53", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:3" -// }, -// "FileName": "crossrealm.gno", -// "IsMethod": false, -// "Name": "CallFooerGetterFoo", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests/crossrealm", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "crossrealm.gno", -// "Line": "57", -// "PkgPath": "gno.land/r/demo/tests/crossrealm" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] diff --git a/gnovm/tests/files/zrealm_natbind0.gno b/gnovm/tests/files/zrealm_natbind0.gno index e6ebef6252e..6f8045107dc 100644 --- a/gnovm/tests/files/zrealm_natbind0.gno +++ b/gnovm/tests/files/zrealm_natbind0.gno @@ -28,153 +28,3 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]={ -// "Blank": {}, -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// "ModTime": "3", -// "RefCount": "2" -// }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a7f5397443359ea76c50be82c77f1f893a060925:10" -// }, -// "FileName": "native.gno", -// "IsMethod": false, -// "Name": "GetChainID", -// "NativeName": "GetChainID", -// "NativePkg": "std", -// "PkgPath": "std", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "native.gno", -// "Line": "13", -// "PkgPath": "std" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm_natbind0.gno", -// "IsMethod": false, -// "Name": "init.1", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm_natbind0.gno", -// "Line": "10", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// }, -// "FileName": "files/zrealm_natbind0.gno", -// "IsMethod": false, -// "Name": "main", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/test", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "files/zrealm_natbind0.gno", -// "Line": "14", -// "PkgPath": "gno.land/r/test" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// } -// ] -// } diff --git a/gnovm/tests/files/zrealm_tests0.gno b/gnovm/tests/files/zrealm_tests0.gno index afb7e4a7c3b..872046ef795 100644 --- a/gnovm/tests/files/zrealm_tests0.gno +++ b/gnovm/tests/files/zrealm_tests0.gno @@ -80,7 +80,7 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "148d314678615253ee2032d7ecff6b144b474baf", +// "Hash": "4e0d77a91ba35733bf82329317bf8c8dffa6f655", // "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:12" // }, // "Index": "0", @@ -133,1644 +133,43 @@ func main() { // "RefCount": "1" // } // } -// u[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:2]={ -// "Blank": {}, +// u[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:12]={ // "ObjectInfo": { -// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:2", -// "IsEscaped": true, -// "ModTime": "16", -// "RefCount": "5" +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:12", +// "ModTime": "17", +// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:11", +// "RefCount": "1" // }, -// "Parent": null, -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "0", -// "File": "", -// "Line": "0", -// "PkgPath": "gno.land/r/demo/tests" +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/tests_foo.FooStringer" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "f163acee63433b44deb3168fef87beb588847322", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:13" // } +// } +// } +// u[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:15]={ +// "ObjectInfo": { +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:15", +// "ModTime": "17", +// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:14", +// "RefCount": "1" // }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.InterfaceType", -// "Generic": "", -// "Methods": [ -// { -// "Embedded": false, -// "Name": "String", -// "Tag": "", -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests" -// }, -// "Methods": [], -// "Name": "Stringer", -// "PkgPath": "gno.land/r/demo/tests" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.SliceType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.Stringer" -// }, -// "Vrd": false -// }, -// "V": { -// "@type": "/gno.SliceValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "3c58838c5667649add1ff8ee48a1cdc187fcd2ef", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:17" -// }, -// "Length": "3", -// "Maxcap": "3", -// "Offset": "0" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "str", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.Stringer" -// } -// } -// ], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:3" -// }, -// "FileName": "interfaces.gno", -// "IsMethod": false, -// "Name": "AddStringer", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "interfaces.gno", -// "Line": "13", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "str", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.Stringer" -// } -// } -// ], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "path", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:3" -// }, -// "FileName": "interfaces.gno", -// "IsMethod": false, -// "Name": "Render", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "interfaces.gno", -// "Line": "20", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "path", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.PrimitiveType", -// "value": "2048" -// }, -// "Methods": [], -// "Name": "Word", -// "PkgPath": "gno.land/r/demo/tests" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.SliceType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.Word" -// }, -// "Vrd": false -// }, -// "Methods": [ -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "n", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": null, -// "FileName": "realm_method38d.gno", -// "IsMethod": true, -// "Name": "Add", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "realm_method38d.gno", -// "Line": "5", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "n", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ] -// } -// } -// } -// ], -// "Name": "nat", -// "PkgPath": "gno.land/r/demo/tests" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.Int" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Hash": "49283398258e135138cd8e234142d5daaa8c661d", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:4" -// }, -// "Index": "0", -// "TV": null -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "neg", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// }, -// { -// "Embedded": false, -// "Name": "abs", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests" -// }, -// "Methods": [], -// "Name": "Int", -// "PkgPath": "gno.land/r/demo/tests" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:7" -// }, -// "FileName": "realm_compositelit.gno", -// "IsMethod": false, -// "Name": "GetZeroType", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "realm_compositelit.gno", -// "Line": "19", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:8" -// }, -// "FileName": "realm_method38d.gno", -// "IsMethod": false, -// "Name": "GetAbs", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "realm_method38d.gno", -// "Line": "9", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:8" -// }, -// "FileName": "realm_method38d.gno", -// "IsMethod": false, -// "Name": "AbsAdd", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "realm_method38d.gno", -// "Line": "15", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.nat" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "IncCounter", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "12", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "Counter", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "16", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "32" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "CurrentRealmPath", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "20", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "std.Address" -// }, -// "V": { -// "@type": "/gno.StringValue", -// "value": "g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "std.Address" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "InitOrigCaller", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "26", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "std.Address" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "CallAssertOriginCall", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "30", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "CallIsOriginCall", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "34", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "CallSubtestsAssertOriginCall", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "38", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "CallSubtestsIsOriginCall", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "42", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "Field", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests" -// }, -// "Methods": [ -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "t", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.TestRealmObject" -// } -// } -// } -// ], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": null, -// "FileName": "tests.gno", -// "IsMethod": true, -// "Name": "Modify", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "59", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "t", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.TestRealmObject" -// } -// } -// } -// ], -// "Results": [] -// } -// } -// } -// ], -// "Name": "TestRealmObject", -// "PkgPath": "gno.land/r/demo/tests" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.TestRealmObject" -// }, -// "V": { -// "@type": "/gno.RefValue", -// "Hash": "5e56ba76fc0add1a3a67f7a8b6709f4f27215f93", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:10" -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "t", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.TestRealmObject" -// } -// } -// } -// ], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "ModifyTestRealmObject", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "55", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "t", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.TestRealmObject" -// } -// } -// } -// ], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.TypeType" -// }, -// "V": { -// "@type": "/gno.TypeValue", -// "Type": { -// "@type": "/gno.DeclaredType", -// "Base": { -// "@type": "/gno.StructType", -// "Fields": [ -// { -// "Embedded": false, -// "Name": "Name", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "16" -// } -// }, -// { -// "Embedded": false, -// "Name": "Child", -// "Tag": "", -// "Type": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.TestNode" -// } -// } -// } -// ], -// "PkgPath": "gno.land/r/demo/tests" -// }, -// "Methods": [], -// "Name": "TestNode", -// "PkgPath": "gno.land/r/demo/tests" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.TestNode" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.TestNode" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests.TestNode" -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "InitTestNodes", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "77", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "ModTestNodes", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "82", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "PrintTestNodes", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "90", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "std.Realm" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "GetPrevRealm", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "94", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "std.Realm" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "std.Realm" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "GetRSubtestsPrevRealm", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "98", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.RefType", -// "ID": "std.Realm" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "fn", -// "Tag": "", -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// ], -// "Results": [] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "Exec", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "102", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [ -// { -// "Embedded": false, -// "Name": "fn", -// "Tag": "", -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [] -// } -// } -// ], -// "Results": [] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "IsCallerSubPath", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "106", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// } -// ] -// } -// } -// }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "IsCallerParentPath", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "110", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// } -// ] -// } -// } +// "Value": { +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/tests_foo.FooStringer" // }, -// { -// "T": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// } -// ] -// }, -// "V": { -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:9" -// }, -// "FileName": "tests.gno", -// "IsMethod": false, -// "Name": "HasCallerSameNamespace", -// "NativeName": "", -// "NativePkg": "", -// "PkgPath": "gno.land/r/demo/tests", -// "Source": { -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// "Column": "1", -// "File": "tests.gno", -// "Line": "114", -// "PkgPath": "gno.land/r/demo/tests" -// } -// }, -// "Type": { -// "@type": "/gno.FuncType", -// "Params": [], -// "Results": [ -// { -// "Embedded": false, -// "Name": "", -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// "value": "4" -// } -// } -// ] -// } -// } +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "2a96c074210eb2db31b7941e31d62deb04e59937", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:16" // } -// ] +// } // } // d[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:14] // switchrealm["gno.land/r/demo/tests_foo"] From 8cca690ae01f22f12683a6e4bf2f1265ac4cff04 Mon Sep 17 00:00:00 2001 From: Nemanja Matic <106317308+Nemanya8@users.noreply.github.com> Date: Wed, 15 Jan 2025 05:05:02 -0500 Subject: [PATCH 12/13] feat(cmd/gno): allow gno test to default to the current directory (#3453) This PR resolves https://github.com/gnolang/gno/issues/3420 by enhancing the gno test command. The command now assumes the current directory (.) as the default path when no directory is specified, aligning its behavior with go test. Changes to CI: - Removed the no_args test. - Added new tests to cover the following scenarios: - Valid test execution. - Valid file-based test. - Test with flags. - Empty directory. - Empty test file. This PR is a repost of https://github.com/gnolang/gno/pull/3429 with a cleaner commit history. CC @notJoon @moul --------- Co-authored-by: Nemanya21 Co-authored-by: Leon Hudak <33522493+leohhhn@users.noreply.github.com> --- gnovm/cmd/gno/test.go | 6 +- gnovm/cmd/gno/testdata/test/no_args.txtar | 6 -- .../gno/testdata/test/no_path_empty_dir.txtar | 6 ++ .../gno/testdata/test/no_path_empty_gno.txtar | 8 ++ .../gno/testdata/test/no_path_flag_run.txtar | 99 +++++++++++++++++++ 5 files changed, 117 insertions(+), 8 deletions(-) delete mode 100644 gnovm/cmd/gno/testdata/test/no_args.txtar create mode 100644 gnovm/cmd/gno/testdata/test/no_path_empty_dir.txtar create mode 100644 gnovm/cmd/gno/testdata/test/no_path_empty_gno.txtar create mode 100644 gnovm/cmd/gno/testdata/test/no_path_flag_run.txtar diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index fec0de7c221..ea06b25d8e2 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -146,8 +146,9 @@ func (c *testCfg) RegisterFlags(fs *flag.FlagSet) { } func execTest(cfg *testCfg, args []string, io commands.IO) error { - if len(args) < 1 { - return flag.ErrHelp + // Default to current directory if no args provided + if len(args) == 0 { + args = []string{"."} } // guess opts.RootDir @@ -159,6 +160,7 @@ func execTest(cfg *testCfg, args []string, io commands.IO) error { if err != nil { return fmt.Errorf("list targets from patterns: %w", err) } + if len(paths) == 0 { io.ErrPrintln("no packages to test") return nil diff --git a/gnovm/cmd/gno/testdata/test/no_args.txtar b/gnovm/cmd/gno/testdata/test/no_args.txtar deleted file mode 100644 index bd9cd4fc965..00000000000 --- a/gnovm/cmd/gno/testdata/test/no_args.txtar +++ /dev/null @@ -1,6 +0,0 @@ -# Run gno test without args - -! gno test - -! stdout .+ -stderr 'USAGE' diff --git a/gnovm/cmd/gno/testdata/test/no_path_empty_dir.txtar b/gnovm/cmd/gno/testdata/test/no_path_empty_dir.txtar new file mode 100644 index 00000000000..6f8b54d7ea4 --- /dev/null +++ b/gnovm/cmd/gno/testdata/test/no_path_empty_dir.txtar @@ -0,0 +1,6 @@ +# Run gno test without path argument on an empty dir + +gno test + +! stdout .+ +stderr '[no test files]' \ No newline at end of file diff --git a/gnovm/cmd/gno/testdata/test/no_path_empty_gno.txtar b/gnovm/cmd/gno/testdata/test/no_path_empty_gno.txtar new file mode 100644 index 00000000000..846ce5bbd88 --- /dev/null +++ b/gnovm/cmd/gno/testdata/test/no_path_empty_gno.txtar @@ -0,0 +1,8 @@ +# Test empty gno without path argument + +gno test + +! stdout .+ +stderr '\? \. \[no test files\]' + +-- empty.gno -- \ No newline at end of file diff --git a/gnovm/cmd/gno/testdata/test/no_path_flag_run.txtar b/gnovm/cmd/gno/testdata/test/no_path_flag_run.txtar new file mode 100644 index 00000000000..3db2a4c9295 --- /dev/null +++ b/gnovm/cmd/gno/testdata/test/no_path_flag_run.txtar @@ -0,0 +1,99 @@ +# Run test on gno.land/p/demo/ufmt without path argument + +gno test + +gno test -v + +! stdout .+ +stderr '=== RUN TestRun/hello' +stderr '=== RUN TestRun/hi_you' +stderr '=== RUN TestRun/hi_me' +stderr '=== RUN TestRun' +stderr '--- PASS: TestRun' + +gno test -v -run .* + +! stdout .+ +stderr '=== RUN TestRun/hello' +stderr '=== RUN TestRun/hi_you' +stderr '=== RUN TestRun/hi_me' +stderr '=== RUN TestRun' +stderr '--- PASS: TestRun' + +gno test -v -run NotExists + +! stdout .+ +! stderr '=== RUN TestRun' + +gno test -v -run .*/hello + +! stdout .+ +stderr '=== RUN TestRun/hello' +! stderr '=== RUN TestRun/hi_you' +! stderr '=== RUN TestRun/hi_me' +stderr '=== RUN TestRun' +stderr '--- PASS: TestRun' + +gno test -v -run .*/hi + +! stdout .+ +! stderr '=== RUN TestRun/hello' +stderr '=== RUN TestRun/hi_you' +stderr '=== RUN TestRun/hi_me' +stderr '=== RUN TestRun' +stderr '--- PASS: TestRun' + +gno test -v -run .*/NotExists + +! stdout .+ +stderr '=== RUN TestRun' +stderr '--- PASS: TestRun' + +gno test -v -run Run/.* + +! stdout .+ +stderr '=== RUN TestRun/hello' +stderr '=== RUN TestRun/hi_you' +stderr '=== RUN TestRun/hi_me' +stderr '=== RUN TestRun' +stderr '--- PASS: TestRun' + +gno test -v -run Run/ + +! stdout .+ +stderr '=== RUN TestRun/hello' +stderr '=== RUN TestRun/hi_you' +stderr '=== RUN TestRun/hi_me' +stderr '=== RUN TestRun' +stderr '--- PASS: TestRun' + +gno test -v -run Run/hello + +! stdout .+ +stderr '=== RUN TestRun/hello' +! stderr '=== RUN TestRun/hi_you' +! stderr '=== RUN TestRun/hi_me' +stderr '=== RUN TestRun' +stderr '--- PASS: TestRun' + +-- run.gno -- +package run + +-- run_test.gno -- +package run + +import ( + "fmt" + "testing" +) + +func TestRun(t *testing.T) { + cases := []string { + "hello", + "hi you", + "hi me", + } + for _, tc := range cases { + t.Run(tc, func(t *testing.T) {}) + } +} \ No newline at end of file From ae0c9f40340b854c0a033b8552dfa78ec9650b9b Mon Sep 17 00:00:00 2001 From: Alexis Colin Date: Wed, 15 Jan 2025 19:13:21 +0900 Subject: [PATCH 13/13] fix(gnoweb): fix mobile breadcrumb (#3516) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the breadcrumb bar of gnoweb on mobile. Before: Capture d’écran 2025-01-15 à 16 02 30 After: Capture d’écran 2025-01-15 à 16 03 05 --- gno.land/pkg/gnoweb/components/breadcrumb.gohtml | 6 +++--- gno.land/pkg/gnoweb/public/styles.css | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gno.land/pkg/gnoweb/components/breadcrumb.gohtml b/gno.land/pkg/gnoweb/components/breadcrumb.gohtml index 9295b17b6f5..3824eb5894f 100644 --- a/gno.land/pkg/gnoweb/components/breadcrumb.gohtml +++ b/gno.land/pkg/gnoweb/components/breadcrumb.gohtml @@ -2,15 +2,15 @@
    {{- range $index, $part := .Parts }} {{- if $index }} -
  1. +
  2. {{- else }} -
  3. +
  4. {{- end }} {{ $part.Name }}
  5. {{- end }} {{- if .Args }} -
  6. +
  7. {{ .Args }}
  8. {{- end }} diff --git a/gno.land/pkg/gnoweb/public/styles.css b/gno.land/pkg/gnoweb/public/styles.css index a6771695454..4ff1a266c0c 100644 --- a/gno.land/pkg/gnoweb/public/styles.css +++ b/gno.land/pkg/gnoweb/public/styles.css @@ -1,3 +1,3 @@ @font-face{font-family:Roboto;font-style:normal;font-weight:900;font-display:swap;src:url(fonts/roboto/roboto-mono-normal.woff2) format("woff2"),url(fonts/roboto/roboto-mono-normal.woff) format("woff")}@font-face{font-family:Inter var;font-weight:100 900;font-display:block;font-style:oblique 0deg 10deg;src:url(fonts/intervar/Intervar.woff2) format("woff2")}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: } -/*! tailwindcss v3.4.14 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #bdbdbd}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:Roboto,Menlo,Consolas,Ubuntu Mono,Roboto Mono,DejaVu Sans Mono,monospace;;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#7c7c7c}input::placeholder,textarea::placeholder{opacity:1;color:#7c7c7c}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));font-family:Inter var,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji,sans-serif;font-size:1rem;--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity));font-feature-settings:"kern" on,"liga" on,"calt" on,"zero" on;-webkit-font-feature-settings:"kern" on,"liga" on,"calt" on,"zero" on;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased;font-variant-ligatures:contextual common-ligatures;font-kerning:normal;text-rendering:optimizeLegibility}svg{max-height:100%;max-width:100%}form{margin-top:0;margin-bottom:0}.realm-content{overflow-wrap:break-word;padding-top:2.5rem;font-size:1rem}.realm-content>:first-child{margin-top:0!important}.realm-content a{font-weight:500;--tw-text-opacity:1;color:rgb(34 108 87/var(--tw-text-opacity))}.realm-content a:hover{text-decoration-line:underline}.realm-content h1,.realm-content h2,.realm-content h3,.realm-content h4{margin-top:3rem;line-height:1.25;--tw-text-opacity:1;color:rgb(8 8 9/var(--tw-text-opacity))}.realm-content h2,.realm-content h2 *{font-weight:700}.realm-content h3,.realm-content h3 *,.realm-content h4,.realm-content h4 *{font-weight:600}.realm-content h1+h2,.realm-content h2+h3,.realm-content h3+h4{margin-top:1rem}.realm-content h1{font-size:2.375rem;font-weight:700}.realm-content h2{font-size:1.5rem}.realm-content h3{margin-top:2.5rem;font-size:1.25rem}.realm-content h3,.realm-content h4{--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity))}.realm-content h4{margin-top:1.5rem;margin-bottom:1.5rem;font-size:1.125rem;font-weight:500}.realm-content p{margin-top:1.25rem;margin-bottom:1.25rem}.realm-content strong{font-weight:700;--tw-text-opacity:1;color:rgb(8 8 9/var(--tw-text-opacity))}.realm-content strong *{font-weight:700}.realm-content em{font-style:oblique 10deg}.realm-content blockquote{margin-top:1rem;margin-bottom:1rem;border-left-width:4px;--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity));padding-left:1rem;--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity));font-style:oblique 10deg}.realm-content ol,.realm-content ul{margin-top:1.5rem;margin-bottom:1.5rem;padding-left:1rem}.realm-content ol li,.realm-content ul li{margin-bottom:.5rem}.realm-content img{margin-top:2rem;margin-bottom:2rem;max-width:100%}.realm-content figure{margin-top:1.5rem;margin-bottom:1.5rem;text-align:center}.realm-content figcaption{font-size:.875rem;--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity))}.realm-content :not(pre)>code{border-radius:.25rem;background-color:rgb(226 226 226/var(--tw-bg-opacity));padding:.125rem .25rem;font-size:.96em}.realm-content :not(pre)>code,.realm-content pre{--tw-bg-opacity:1;font-family:Roboto,Menlo,Consolas,Ubuntu Mono,Roboto Mono,DejaVu Sans Mono,monospace;}.realm-content pre{overflow-x:auto;border-radius:.375rem;background-color:rgb(240 240 240/var(--tw-bg-opacity));padding:1rem}.realm-content hr{margin-top:2.5rem;margin-bottom:2.5rem;border-top-width:1px;--tw-border-opacity:1;border-color:rgb(226 226 226/var(--tw-border-opacity))}.realm-content table{margin-top:2rem;margin-bottom:2rem;width:100%;border-collapse:collapse}.realm-content td,.realm-content th{border-width:1px;--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity));padding:.5rem 1rem}.realm-content th{--tw-bg-opacity:1;background-color:rgb(226 226 226/var(--tw-bg-opacity));font-weight:700}.realm-content caption{margin-top:.5rem;text-align:left;font-size:.875rem;--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity))}.realm-content q{margin-top:1.5rem;margin-bottom:1.5rem;border-left-width:4px;--tw-border-opacity:1;border-left-color:rgb(204 204 204/var(--tw-border-opacity));padding-left:1rem;--tw-text-opacity:1;color:rgb(85 85 85/var(--tw-text-opacity));font-style:oblique 10deg;quotes:"“" "”" "‘" "’"}.realm-content q:after,.realm-content q:before{margin-right:.25rem;font-size:1.5rem;--tw-text-opacity:1;color:rgb(153 153 153/var(--tw-text-opacity));content:open-quote;vertical-align:-.4rem}.realm-content q:after{content:close-quote}.realm-content q:before{content:open-quote}.realm-content q:after{content:close-quote}.realm-content ol ol,.realm-content ol ul,.realm-content ul ol,.realm-content ul ul{margin-top:.75rem;margin-bottom:.5rem;padding-left:1rem}.realm-content ul{list-style-type:disc}.realm-content ol{list-style-type:decimal}.realm-content table th:first-child,.realm-content td:first-child{padding-left:0}.realm-content table th:last-child,.realm-content td:last-child{padding-right:0}.realm-content abbr[title]{cursor:help;border-bottom-width:1px;border-style:dotted}.realm-content details{margin-top:1.25rem;margin-bottom:1.25rem}.realm-content summary{cursor:pointer;font-weight:700}.realm-content a code{color:inherit}.realm-content video{margin-top:2rem;margin-bottom:2rem;max-width:100%}.realm-content math{font-family:Roboto,Menlo,Consolas,Ubuntu Mono,Roboto Mono,DejaVu Sans Mono,monospace;}.realm-content small{font-size:.875rem}.realm-content del{text-decoration-line:line-through}.realm-content sub{vertical-align:sub;font-size:.75rem}.realm-content sup{vertical-align:super;font-size:.75rem}.realm-content button,.realm-content input{border-width:1px;--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity));padding:.5rem 1rem}main :is(h1,h2,h3,h4){scroll-margin-top:6rem}::-moz-selection{--tw-bg-opacity:1;background-color:rgb(34 108 87/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}::selection{--tw-bg-opacity:1;background-color:rgb(34 108 87/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.sidemenu .peer:checked+label>svg{--tw-text-opacity:1;color:rgb(34 108 87/var(--tw-text-opacity))}.toc-expend-btn:has(#toc-expend:checked)+nav{display:block}.toc-expend-btn:has(#toc-expend:checked) .toc-expend-btn_ico{--tw-rotate:180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.main-header:has(#sidemenu-docs:checked)+main #sidebar #sidebar-docs,.main-header:has(#sidemenu-meta:checked)+main #sidebar #sidebar-meta,.main-header:has(#sidemenu-source:checked)+main #sidebar #sidebar-source,.main-header:has(#sidemenu-summary:checked)+main #sidebar #sidebar-summary{display:block}@media (min-width:40rem){:is(.main-header:has(#sidemenu-source:checked),.main-header:has(#sidemenu-docs:checked),.main-header:has(#sidemenu-meta:checked)) .main-navigation,:is(.main-header:has(#sidemenu-source:checked),.main-header:has(#sidemenu-docs:checked),.main-header:has(#sidemenu-meta:checked))+main .realm-content{grid-column:span 6/span 6}:is(.main-header:has(#sidemenu-source:checked),.main-header:has(#sidemenu-docs:checked),.main-header:has(#sidemenu-meta:checked)) .sidemenu,:is(.main-header:has(#sidemenu-source:checked),.main-header:has(#sidemenu-docs:checked),.main-header:has(#sidemenu-meta:checked))+main #sidebar{grid-column:span 4/span 4}}:is(.main-header:has(#sidemenu-source:checked),.main-header:has(#sidemenu-docs:checked),.main-header:has(#sidemenu-meta:checked))+main #sidebar:before{position:absolute;top:0;left:-1.75rem;z-index:-1;display:block;height:100%;width:50vw;--tw-bg-opacity:1;background-color:rgb(226 226 226/var(--tw-bg-opacity));--tw-content:"";content:var(--tw-content)}main :is(.source-code)>pre{overflow:scroll;border-radius:.375rem;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;padding:1rem .25rem;font-family:Roboto,Menlo,Consolas,Ubuntu Mono,Roboto Mono,DejaVu Sans Mono,monospace;;font-size:.875rem}@media (min-width:40rem){main :is(.source-code)>pre{padding:2rem .75rem;font-size:1rem}}main .realm-content>pre a:hover{text-decoration-line:none}main :is(.realm-content,.source-code)>pre .chroma-ln:target{background-color:transparent!important}main :is(.realm-content,.source-code)>pre .chroma-line:has(.chroma-ln:target),main :is(.realm-content,.source-code)>pre .chroma-line:has(.chroma-ln:target) .chroma-cl,main :is(.realm-content,.source-code)>pre .chroma-line:has(.chroma-lnlinks:hover),main :is(.realm-content,.source-code)>pre .chroma-line:has(.chroma-lnlinks:hover) .chroma-cl{border-radius:.375rem;--tw-bg-opacity:1!important;background-color:rgb(226 226 226/var(--tw-bg-opacity))!important}main :is(.realm-content,.source-code)>pre .chroma-ln{scroll-margin-top:6rem}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.bottom-1{bottom:.25rem}.left-0{left:0}.right-2{right:.5rem}.right-3{right:.75rem}.top-0{top:0}.top-1\/2{top:50%}.top-14{top:3.5rem}.top-2{top:.5rem}.z-1{z-index:1}.z-max{z-index:9999}.col-span-1{grid-column:span 1/span 1}.col-span-10{grid-column:span 10/span 10}.col-span-3{grid-column:span 3/span 3}.col-span-7{grid-column:span 7/span 7}.row-span-1{grid-row:span 1/span 1}.row-start-1{grid-row-start:1}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-8{margin-bottom:2rem}.mr-10{margin-right:2.5rem}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.max-h-screen{max-height:100vh}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-10{width:2.5rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-full{width:100%}.min-w-2{min-width:.5rem}.min-w-48{min-width:12rem}.max-w-screen-max{max-width:98.75rem}.shrink-0{flex-shrink:0}.grow-\[2\]{flex-grow:2}.-translate-y-1\/2{--tw-translate-y:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-flow-dense{grid-auto-flow:dense}.auto-rows-min{grid-auto-rows:min-content}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-20{-moz-column-gap:5rem;column-gap:5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-2{row-gap:.5rem}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.375rem}.rounded-sm{border-radius:.25rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-t{border-top-width:1px}.border-gray-100{--tw-border-opacity:1;border-color:rgb(226 226 226/var(--tw-border-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(226 226 226/var(--tw-bg-opacity))}.bg-gray-300{--tw-bg-opacity:1;background-color:rgb(153 153 153/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(240 240 240/var(--tw-bg-opacity))}.bg-light{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-px{padding-top:1px;padding-bottom:1px}.pb-24{padding-bottom:6rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pb-8{padding-bottom:2rem}.pl-4{padding-left:1rem}.pr-10{padding-right:2.5rem}.pt-0\.5{padding-top:.125rem}.pt-2{padding-top:.5rem}.font-mono{font-family:Roboto,Menlo,Consolas,Ubuntu Mono,Roboto Mono,DejaVu Sans Mono,monospace;}.text-100{font-size:.875rem}.text-200{font-size:1rem}.text-50{font-size:.75rem}.text-600{font-size:1.5rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.capitalize{text-transform:capitalize}.leading-tight{line-height:1.25}.text-gray-300{--tw-text-opacity:1;color:rgb(153 153 153/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(124 124 124/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(19 19 19/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(8 8 9/var(--tw-text-opacity))}.text-green-600{--tw-text-opacity:1;color:rgb(34 108 87/var(--tw-text-opacity))}.text-light{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.outline-none{outline:2px solid transparent;outline-offset:2px}.text-stroke{-webkit-text-stroke:currentColor;-webkit-text-stroke-width:.6px}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{-ms-overflow-style:none;scrollbar-width:none}.\*\:pl-0>*{padding-left:0}.before\:px-\[0\.18rem\]:before{content:var(--tw-content);padding-left:.18rem;padding-right:.18rem}.before\:text-gray-300:before{content:var(--tw-content);--tw-text-opacity:1;color:rgb(153 153 153/var(--tw-text-opacity))}.before\:content-\[\'\/\'\]:before{--tw-content:"/";content:var(--tw-content)}.before\:content-\[\'\:\'\]:before{--tw-content:":";content:var(--tw-content)}.before\:content-\[\'open\'\]:before{--tw-content:"open";content:var(--tw-content)}.after\:pointer-events-none:after{content:var(--tw-content);pointer-events:none}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:bottom-0:after{content:var(--tw-content);bottom:0}.after\:left-0:after{content:var(--tw-content);left:0}.after\:top-0:after{content:var(--tw-content);top:0}.after\:block:after{content:var(--tw-content);display:block}.after\:h-1:after{content:var(--tw-content);height:.25rem}.after\:h-full:after{content:var(--tw-content);height:100%}.after\:w-full:after{content:var(--tw-content);width:100%}.after\:rounded-t-sm:after{content:var(--tw-content);border-top-left-radius:.25rem;border-top-right-radius:.25rem}.after\:bg-gray-100:after{content:var(--tw-content);--tw-bg-opacity:1;background-color:rgb(226 226 226/var(--tw-bg-opacity))}.after\:bg-green-600:after{content:var(--tw-content);--tw-bg-opacity:1;background-color:rgb(34 108 87/var(--tw-bg-opacity))}.first\:border-t:first-child{border-top-width:1px}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(226 226 226/var(--tw-bg-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(240 240 240/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(34 108 87/var(--tw-bg-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity))}.hover\:text-green-600:hover{--tw-text-opacity:1;color:rgb(34 108 87/var(--tw-text-opacity))}.hover\:text-light:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:border-gray-300:focus{--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity))}.focus\:border-l-gray-300:focus{--tw-border-opacity:1;border-left-color:rgb(153 153 153/var(--tw-border-opacity))}.group:hover .group-hover\:border-gray-300{--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity))}.group:hover .group-hover\:border-l-gray-300{--tw-border-opacity:1;border-left-color:rgb(153 153 153/var(--tw-border-opacity))}.group.is-active .group-\[\.is-active\]\:text-green-600{--tw-text-opacity:1;color:rgb(34 108 87/var(--tw-text-opacity))}.peer:checked~.peer-checked\:before\:content-\[\'close\'\]:before{--tw-content:"close";content:var(--tw-content)}.peer:focus-within~.peer-focus-within\:hidden{display:none}.has-\[ul\:empty\]\:hidden:has(ul:empty){display:none}.has-\[\:focus-within\]\:border-gray-300:has(:focus-within){--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity))}.has-\[\:focus\]\:border-gray-300:has(:focus){--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity))}@media (min-width:30rem){.sm\:gap-6{gap:1.5rem}}@media (min-width:40rem){.md\:col-span-3{grid-column:span 3/span 3}.md\:mb-0{margin-bottom:0}.md\:h-4{height:1rem}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:gap-x-8{-moz-column-gap:2rem;column-gap:2rem}.md\:px-10{padding-left:2.5rem;padding-right:2.5rem}.md\:pb-0{padding-bottom:0}}@media (min-width:51.25rem){.lg\:order-2{order:2}.lg\:col-span-3{grid-column:span 3/span 3}.lg\:col-span-7{grid-column:span 7/span 7}.lg\:row-span-2{grid-row:span 2/span 2}.lg\:row-start-1{grid-row-start:1}.lg\:row-start-2{grid-row-start:2}.lg\:mb-4{margin-bottom:1rem}.lg\:mt-0{margin-top:0}.lg\:mt-10{margin-top:2.5rem}.lg\:block{display:block}.lg\:hidden{display:none}.lg\:grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.lg\:flex-row{flex-direction:row}.lg\:justify-start{justify-content:flex-start}.lg\:justify-between{justify-content:space-between}.lg\:gap-x-20{-moz-column-gap:5rem;column-gap:5rem}.lg\:border-none{border-style:none}.lg\:bg-transparent{background-color:transparent}.lg\:p-0{padding:0}.lg\:px-0{padding-left:0;padding-right:0}.lg\:px-2{padding-left:.5rem;padding-right:.5rem}.lg\:py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.lg\:pb-28{padding-bottom:7rem}.lg\:pt-2{padding-top:.5rem}.lg\:text-200{font-size:1rem}.lg\:font-semibold{font-weight:600}.lg\:hover\:bg-transparent:hover{background-color:transparent}}@media (min-width:63.75rem){.xl\:inline{display:inline}.xl\:hidden{display:none}.xl\:grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.xl\:flex-row{flex-direction:row}.xl\:items-center{align-items:center}.xl\:gap-20{gap:5rem}.xl\:gap-6{gap:1.5rem}.xl\:pt-0{padding-top:0}}@media (min-width:85.375rem){.xxl\:inline-block{display:inline-block}.xxl\:h-4{height:1rem}.xxl\:w-4{width:1rem}.xxl\:gap-20{gap:5rem}.xxl\:gap-x-32{-moz-column-gap:8rem;column-gap:8rem}.xxl\:pr-1{padding-right:.25rem}} \ No newline at end of file +/*! tailwindcss v3.4.14 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #bdbdbd}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:Roboto,Menlo,Consolas,Ubuntu Mono,Roboto Mono,DejaVu Sans Mono,monospace;;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#7c7c7c}input::placeholder,textarea::placeholder{opacity:1;color:#7c7c7c}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));font-family:Inter var,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji,sans-serif;font-size:1rem;--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity));font-feature-settings:"kern" on,"liga" on,"calt" on,"zero" on;-webkit-font-feature-settings:"kern" on,"liga" on,"calt" on,"zero" on;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased;font-variant-ligatures:contextual common-ligatures;font-kerning:normal;text-rendering:optimizeLegibility}svg{max-height:100%;max-width:100%}form{margin-top:0;margin-bottom:0}.realm-content{overflow-wrap:break-word;padding-top:2.5rem;font-size:1rem}.realm-content>:first-child{margin-top:0!important}.realm-content a{font-weight:500;--tw-text-opacity:1;color:rgb(34 108 87/var(--tw-text-opacity))}.realm-content a:hover{text-decoration-line:underline}.realm-content h1,.realm-content h2,.realm-content h3,.realm-content h4{margin-top:3rem;line-height:1.25;--tw-text-opacity:1;color:rgb(8 8 9/var(--tw-text-opacity))}.realm-content h2,.realm-content h2 *{font-weight:700}.realm-content h3,.realm-content h3 *,.realm-content h4,.realm-content h4 *{font-weight:600}.realm-content h1+h2,.realm-content h2+h3,.realm-content h3+h4{margin-top:1rem}.realm-content h1{font-size:2.375rem;font-weight:700}.realm-content h2{font-size:1.5rem}.realm-content h3{margin-top:2.5rem;font-size:1.25rem}.realm-content h3,.realm-content h4{--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity))}.realm-content h4{margin-top:1.5rem;margin-bottom:1.5rem;font-size:1.125rem;font-weight:500}.realm-content p{margin-top:1.25rem;margin-bottom:1.25rem}.realm-content strong{font-weight:700;--tw-text-opacity:1;color:rgb(8 8 9/var(--tw-text-opacity))}.realm-content strong *{font-weight:700}.realm-content em{font-style:oblique 10deg}.realm-content blockquote{margin-top:1rem;margin-bottom:1rem;border-left-width:4px;--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity));padding-left:1rem;--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity));font-style:oblique 10deg}.realm-content ol,.realm-content ul{margin-top:1.5rem;margin-bottom:1.5rem;padding-left:1rem}.realm-content ol li,.realm-content ul li{margin-bottom:.5rem}.realm-content img{margin-top:2rem;margin-bottom:2rem;max-width:100%}.realm-content figure{margin-top:1.5rem;margin-bottom:1.5rem;text-align:center}.realm-content figcaption{font-size:.875rem;--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity))}.realm-content :not(pre)>code{border-radius:.25rem;background-color:rgb(226 226 226/var(--tw-bg-opacity));padding:.125rem .25rem;font-size:.96em}.realm-content :not(pre)>code,.realm-content pre{--tw-bg-opacity:1;font-family:Roboto,Menlo,Consolas,Ubuntu Mono,Roboto Mono,DejaVu Sans Mono,monospace;}.realm-content pre{overflow-x:auto;border-radius:.375rem;background-color:rgb(240 240 240/var(--tw-bg-opacity));padding:1rem}.realm-content hr{margin-top:2.5rem;margin-bottom:2.5rem;border-top-width:1px;--tw-border-opacity:1;border-color:rgb(226 226 226/var(--tw-border-opacity))}.realm-content table{margin-top:2rem;margin-bottom:2rem;width:100%;border-collapse:collapse}.realm-content td,.realm-content th{border-width:1px;--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity));padding:.5rem 1rem}.realm-content th{--tw-bg-opacity:1;background-color:rgb(226 226 226/var(--tw-bg-opacity));font-weight:700}.realm-content caption{margin-top:.5rem;text-align:left;font-size:.875rem;--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity))}.realm-content q{margin-top:1.5rem;margin-bottom:1.5rem;border-left-width:4px;--tw-border-opacity:1;border-left-color:rgb(204 204 204/var(--tw-border-opacity));padding-left:1rem;--tw-text-opacity:1;color:rgb(85 85 85/var(--tw-text-opacity));font-style:oblique 10deg;quotes:"“" "”" "‘" "’"}.realm-content q:after,.realm-content q:before{margin-right:.25rem;font-size:1.5rem;--tw-text-opacity:1;color:rgb(153 153 153/var(--tw-text-opacity));content:open-quote;vertical-align:-.4rem}.realm-content q:after{content:close-quote}.realm-content q:before{content:open-quote}.realm-content q:after{content:close-quote}.realm-content ol ol,.realm-content ol ul,.realm-content ul ol,.realm-content ul ul{margin-top:.75rem;margin-bottom:.5rem;padding-left:1rem}.realm-content ul{list-style-type:disc}.realm-content ol{list-style-type:decimal}.realm-content table th:first-child,.realm-content td:first-child{padding-left:0}.realm-content table th:last-child,.realm-content td:last-child{padding-right:0}.realm-content abbr[title]{cursor:help;border-bottom-width:1px;border-style:dotted}.realm-content details{margin-top:1.25rem;margin-bottom:1.25rem}.realm-content summary{cursor:pointer;font-weight:700}.realm-content a code{color:inherit}.realm-content video{margin-top:2rem;margin-bottom:2rem;max-width:100%}.realm-content math{font-family:Roboto,Menlo,Consolas,Ubuntu Mono,Roboto Mono,DejaVu Sans Mono,monospace;}.realm-content small{font-size:.875rem}.realm-content del{text-decoration-line:line-through}.realm-content sub{vertical-align:sub;font-size:.75rem}.realm-content sup{vertical-align:super;font-size:.75rem}.realm-content button,.realm-content input{border-width:1px;--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity));padding:.5rem 1rem}main :is(h1,h2,h3,h4){scroll-margin-top:6rem}::-moz-selection{--tw-bg-opacity:1;background-color:rgb(34 108 87/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}::selection{--tw-bg-opacity:1;background-color:rgb(34 108 87/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.sidemenu .peer:checked+label>svg{--tw-text-opacity:1;color:rgb(34 108 87/var(--tw-text-opacity))}.toc-expend-btn:has(#toc-expend:checked)+nav{display:block}.toc-expend-btn:has(#toc-expend:checked) .toc-expend-btn_ico{--tw-rotate:180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.main-header:has(#sidemenu-docs:checked)+main #sidebar #sidebar-docs,.main-header:has(#sidemenu-meta:checked)+main #sidebar #sidebar-meta,.main-header:has(#sidemenu-source:checked)+main #sidebar #sidebar-source,.main-header:has(#sidemenu-summary:checked)+main #sidebar #sidebar-summary{display:block}@media (min-width:40rem){:is(.main-header:has(#sidemenu-source:checked),.main-header:has(#sidemenu-docs:checked),.main-header:has(#sidemenu-meta:checked)) .main-navigation,:is(.main-header:has(#sidemenu-source:checked),.main-header:has(#sidemenu-docs:checked),.main-header:has(#sidemenu-meta:checked))+main .realm-content{grid-column:span 6/span 6}:is(.main-header:has(#sidemenu-source:checked),.main-header:has(#sidemenu-docs:checked),.main-header:has(#sidemenu-meta:checked)) .sidemenu,:is(.main-header:has(#sidemenu-source:checked),.main-header:has(#sidemenu-docs:checked),.main-header:has(#sidemenu-meta:checked))+main #sidebar{grid-column:span 4/span 4}}:is(.main-header:has(#sidemenu-source:checked),.main-header:has(#sidemenu-docs:checked),.main-header:has(#sidemenu-meta:checked))+main #sidebar:before{position:absolute;top:0;left:-1.75rem;z-index:-1;display:block;height:100%;width:50vw;--tw-bg-opacity:1;background-color:rgb(226 226 226/var(--tw-bg-opacity));--tw-content:"";content:var(--tw-content)}main :is(.source-code)>pre{overflow:scroll;border-radius:.375rem;--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important;padding:1rem .25rem;font-family:Roboto,Menlo,Consolas,Ubuntu Mono,Roboto Mono,DejaVu Sans Mono,monospace;;font-size:.875rem}@media (min-width:40rem){main :is(.source-code)>pre{padding:2rem .75rem;font-size:1rem}}main .realm-content>pre a:hover{text-decoration-line:none}main :is(.realm-content,.source-code)>pre .chroma-ln:target{background-color:transparent!important}main :is(.realm-content,.source-code)>pre .chroma-line:has(.chroma-ln:target),main :is(.realm-content,.source-code)>pre .chroma-line:has(.chroma-ln:target) .chroma-cl,main :is(.realm-content,.source-code)>pre .chroma-line:has(.chroma-lnlinks:hover),main :is(.realm-content,.source-code)>pre .chroma-line:has(.chroma-lnlinks:hover) .chroma-cl{border-radius:.375rem;--tw-bg-opacity:1!important;background-color:rgb(226 226 226/var(--tw-bg-opacity))!important}main :is(.realm-content,.source-code)>pre .chroma-ln{scroll-margin-top:6rem}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.bottom-1{bottom:.25rem}.left-0{left:0}.right-2{right:.5rem}.right-3{right:.75rem}.top-0{top:0}.top-1\/2{top:50%}.top-14{top:3.5rem}.top-2{top:.5rem}.z-1{z-index:1}.z-max{z-index:9999}.col-span-1{grid-column:span 1/span 1}.col-span-10{grid-column:span 10/span 10}.col-span-3{grid-column:span 3/span 3}.col-span-7{grid-column:span 7/span 7}.row-span-1{grid-row:span 1/span 1}.row-start-1{grid-row-start:1}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-8{margin-bottom:2rem}.mr-10{margin-right:2.5rem}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.max-h-screen{max-height:100vh}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-10{width:2.5rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-full{width:100%}.min-w-2{min-width:.5rem}.min-w-48{min-width:12rem}.max-w-screen-max{max-width:98.75rem}.shrink-0{flex-shrink:0}.grow-\[2\]{flex-grow:2}.-translate-y-1\/2{--tw-translate-y:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-flow-dense{grid-auto-flow:dense}.auto-rows-min{grid-auto-rows:min-content}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.gap-x-20{-moz-column-gap:5rem;column-gap:5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-2{row-gap:.5rem}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.375rem}.rounded-sm{border-radius:.25rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-t{border-top-width:1px}.border-gray-100{--tw-border-opacity:1;border-color:rgb(226 226 226/var(--tw-border-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(226 226 226/var(--tw-bg-opacity))}.bg-gray-300{--tw-bg-opacity:1;background-color:rgb(153 153 153/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(240 240 240/var(--tw-bg-opacity))}.bg-light{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-px{padding-top:1px;padding-bottom:1px}.pb-24{padding-bottom:6rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pb-8{padding-bottom:2rem}.pl-4{padding-left:1rem}.pr-10{padding-right:2.5rem}.pt-0\.5{padding-top:.125rem}.pt-2{padding-top:.5rem}.font-mono{font-family:Roboto,Menlo,Consolas,Ubuntu Mono,Roboto Mono,DejaVu Sans Mono,monospace;}.text-100{font-size:.875rem}.text-200{font-size:1rem}.text-50{font-size:.75rem}.text-600{font-size:1.5rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.capitalize{text-transform:capitalize}.leading-tight{line-height:1.25}.text-gray-300{--tw-text-opacity:1;color:rgb(153 153 153/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(124 124 124/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(19 19 19/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(8 8 9/var(--tw-text-opacity))}.text-green-600{--tw-text-opacity:1;color:rgb(34 108 87/var(--tw-text-opacity))}.text-light{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.outline-none{outline:2px solid transparent;outline-offset:2px}.text-stroke{-webkit-text-stroke:currentColor;-webkit-text-stroke-width:.6px}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{-ms-overflow-style:none;scrollbar-width:none}.\*\:pl-0>*{padding-left:0}.before\:px-\[0\.18rem\]:before{content:var(--tw-content);padding-left:.18rem;padding-right:.18rem}.before\:text-gray-300:before{content:var(--tw-content);--tw-text-opacity:1;color:rgb(153 153 153/var(--tw-text-opacity))}.before\:content-\[\'\/\'\]:before{--tw-content:"/";content:var(--tw-content)}.before\:content-\[\'\:\'\]:before{--tw-content:":";content:var(--tw-content)}.before\:content-\[\'open\'\]:before{--tw-content:"open";content:var(--tw-content)}.after\:pointer-events-none:after{content:var(--tw-content);pointer-events:none}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:bottom-0:after{content:var(--tw-content);bottom:0}.after\:left-0:after{content:var(--tw-content);left:0}.after\:top-0:after{content:var(--tw-content);top:0}.after\:block:after{content:var(--tw-content);display:block}.after\:h-1:after{content:var(--tw-content);height:.25rem}.after\:h-full:after{content:var(--tw-content);height:100%}.after\:w-full:after{content:var(--tw-content);width:100%}.after\:rounded-t-sm:after{content:var(--tw-content);border-top-left-radius:.25rem;border-top-right-radius:.25rem}.after\:bg-gray-100:after{content:var(--tw-content);--tw-bg-opacity:1;background-color:rgb(226 226 226/var(--tw-bg-opacity))}.after\:bg-green-600:after{content:var(--tw-content);--tw-bg-opacity:1;background-color:rgb(34 108 87/var(--tw-bg-opacity))}.first\:border-t:first-child{border-top-width:1px}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(226 226 226/var(--tw-bg-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(240 240 240/var(--tw-bg-opacity))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(34 108 87/var(--tw-bg-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(84 89 93/var(--tw-text-opacity))}.hover\:text-green-600:hover{--tw-text-opacity:1;color:rgb(34 108 87/var(--tw-text-opacity))}.hover\:text-light:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.focus\:border-gray-300:focus{--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity))}.focus\:border-l-gray-300:focus{--tw-border-opacity:1;border-left-color:rgb(153 153 153/var(--tw-border-opacity))}.group:hover .group-hover\:border-gray-300{--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity))}.group:hover .group-hover\:border-l-gray-300{--tw-border-opacity:1;border-left-color:rgb(153 153 153/var(--tw-border-opacity))}.group.is-active .group-\[\.is-active\]\:text-green-600{--tw-text-opacity:1;color:rgb(34 108 87/var(--tw-text-opacity))}.peer:checked~.peer-checked\:before\:content-\[\'close\'\]:before{--tw-content:"close";content:var(--tw-content)}.peer:focus-within~.peer-focus-within\:hidden{display:none}.has-\[ul\:empty\]\:hidden:has(ul:empty){display:none}.has-\[\:focus-within\]\:border-gray-300:has(:focus-within){--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity))}.has-\[\:focus\]\:border-gray-300:has(:focus){--tw-border-opacity:1;border-color:rgb(153 153 153/var(--tw-border-opacity))}@media (min-width:30rem){.sm\:gap-6{gap:1.5rem}}@media (min-width:40rem){.md\:col-span-3{grid-column:span 3/span 3}.md\:mb-0{margin-bottom:0}.md\:h-4{height:1rem}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:gap-x-8{-moz-column-gap:2rem;column-gap:2rem}.md\:px-10{padding-left:2.5rem;padding-right:2.5rem}.md\:pb-0{padding-bottom:0}}@media (min-width:51.25rem){.lg\:order-2{order:2}.lg\:col-span-3{grid-column:span 3/span 3}.lg\:col-span-7{grid-column:span 7/span 7}.lg\:row-span-2{grid-row:span 2/span 2}.lg\:row-start-1{grid-row-start:1}.lg\:row-start-2{grid-row-start:2}.lg\:mb-4{margin-bottom:1rem}.lg\:mt-0{margin-top:0}.lg\:mt-10{margin-top:2.5rem}.lg\:block{display:block}.lg\:hidden{display:none}.lg\:grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.lg\:flex-row{flex-direction:row}.lg\:justify-start{justify-content:flex-start}.lg\:justify-between{justify-content:space-between}.lg\:gap-x-20{-moz-column-gap:5rem;column-gap:5rem}.lg\:border-none{border-style:none}.lg\:bg-transparent{background-color:transparent}.lg\:p-0{padding:0}.lg\:px-0{padding-left:0;padding-right:0}.lg\:px-2{padding-left:.5rem;padding-right:.5rem}.lg\:py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.lg\:pb-28{padding-bottom:7rem}.lg\:pt-2{padding-top:.5rem}.lg\:text-200{font-size:1rem}.lg\:font-semibold{font-weight:600}.lg\:hover\:bg-transparent:hover{background-color:transparent}}@media (min-width:63.75rem){.xl\:inline{display:inline}.xl\:hidden{display:none}.xl\:grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.xl\:flex-row{flex-direction:row}.xl\:items-center{align-items:center}.xl\:gap-20{gap:5rem}.xl\:gap-6{gap:1.5rem}.xl\:pt-0{padding-top:0}}@media (min-width:85.375rem){.xxl\:inline-block{display:inline-block}.xxl\:h-4{height:1rem}.xxl\:w-4{width:1rem}.xxl\:gap-20{gap:5rem}.xxl\:gap-x-32{-moz-column-gap:8rem;column-gap:8rem}.xxl\:pr-1{padding-right:.25rem}} \ No newline at end of file