From ab4c8a703378d58a68d5f228aa255ca48f1c795f Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Mon, 25 Nov 2024 11:23:40 +0100 Subject: [PATCH 01/15] feat: new time pkg version to be handled by r/sys/params --- gnovm/stdlibs/time/format.gno | 46 +- gnovm/stdlibs/time/time.gno | 636 ++++------------------------ gnovm/stdlibs/time/timezoneinfo.gno | 26 +- 3 files changed, 108 insertions(+), 600 deletions(-) diff --git a/gnovm/stdlibs/time/format.gno b/gnovm/stdlibs/time/format.gno index 61a9eb3301b..f18026e8f52 100644 --- a/gnovm/stdlibs/time/format.gno +++ b/gnovm/stdlibs/time/format.gno @@ -4,7 +4,9 @@ package time -import "errors" +import ( + "errors" +) // These are predefined layouts for use in Time.Format and time.Parse. // The reference time used in these layouts is the specific time stamp: @@ -510,30 +512,6 @@ func formatNano(b []byte, nanosec uint, std int) []byte { // with an explicit format string. func (t Time) String() string { s := t.Format("2006-01-02 15:04:05.999999999 -0700 MST") - - // Format monotonic clock reading as m=±ddd.nnnnnnnnn. - if t.wall&hasMonotonic != 0 { - m2 := uint64(t.ext) - sign := byte('+') - if t.ext < 0 { - sign = '-' - m2 = -m2 - } - m1, m2 := m2/1e9, m2%1e9 - m0, m1 := m1/1e9, m1%1e9 - buf := make([]byte, 0, 24) - buf = append(buf, " m="...) - buf = append(buf, sign) - wid := 0 - if m0 != 0 { - buf = appendInt(buf, int(m0), 0) - wid = 9 - } - buf = appendInt(buf, int(m1), wid) - buf = append(buf, '.') - buf = appendInt(buf, int(m2), 9) - s += string(buf) - } return s } @@ -563,11 +541,9 @@ func (t Time) GoString() string { buf = append(buf, ", "...) buf = appendInt(buf, t.Nanosecond(), 0) buf = append(buf, ", "...) - switch loc := t.Location(); loc { + switch loc := timezoneChainParam; loc { case UTC, nil: buf = append(buf, "time.UTC"...) - case Local: - buf = append(buf, "time.Local"...) default: // there are several options for how we could display this, none of // which are great: @@ -639,13 +615,13 @@ func (t Time) AppendFormat(b []byte, layout string) []byte { // Compute year, month, day if needed. if year < 0 && std&stdNeedDate != 0 { - year, month, day, yday = absDate(abs, true) + year, month, day, yday = internalDate(abs, true) yday++ } // Compute hour, minute, second if needed. if hour < 0 && std&stdNeedClock != 0 { - hour, min, sec = absClock(abs) + hour, min, sec = internalClock(abs) } switch std & stdMask { @@ -667,9 +643,9 @@ func (t Time) AppendFormat(b []byte, layout string) []byte { case stdZeroMonth: b = appendInt(b, int(month), 2) case stdWeekDay: - b = append(b, absWeekday(abs).String()[:3]...) + b = append(b, internalWeekday(abs).String()[:3]...) case stdLongWeekDay: - s := absWeekday(abs).String() + s := internalWeekday(abs).String() b = append(b, s...) case stdDay: b = appendInt(b, day, 0) @@ -959,7 +935,7 @@ func skip(value, prefix string) (string, error) { // differ by the actual zone offset. To avoid such problems, prefer time layouts // that use a numeric zone offset, or use ParseInLocation. func Parse(layout, value string) (Time, error) { - return parse(layout, value, UTC, Local) + return parse(layout, value, UTC, timezoneChainParam) } // ParseInLocation is like Parse but differs in two important ways. @@ -1301,12 +1277,10 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error) // If that zone was in effect at the given time, use it. name, offset, _, _, _ := local.lookup(t.unixSec()) if offset == zoneOffset && (zoneName == "" || name == zoneName) { - t.setLoc(local) return t, nil } // Otherwise create fake zone to record offset. - t.setLoc(FixedZone(zoneName, zoneOffset)) return t, nil } @@ -1317,7 +1291,6 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error) offset, ok := local.lookupName(zoneName, t.unixSec()) if ok { t.addSec(-int64(offset)) - t.setLoc(local) return t, nil } @@ -1326,7 +1299,6 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error) offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT. offset *= 3600 } - t.setLoc(FixedZone(zoneName, offset)) return t, nil } diff --git a/gnovm/stdlibs/time/time.gno b/gnovm/stdlibs/time/time.gno index f3395142d1d..ad3f88df033 100644 --- a/gnovm/stdlibs/time/time.gno +++ b/gnovm/stdlibs/time/time.gno @@ -1,283 +1,45 @@ -// Copyright 2009 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 time provides functionality for measuring and displaying time. -// -// The calendrical calculations always assume a Gregorian calendar, with -// no leap seconds. -// -// # Monotonic Clocks -// -// Operating systems provide both a “wall clock,” which is subject to -// changes for clock synchronization, and a “monotonic clock,” which is -// not. The general rule is that the wall clock is for telling time and -// the monotonic clock is for measuring time. Rather than split the API, -// in this package the Time returned by time.Now contains both a wall -// clock reading and a monotonic clock reading; later time-telling -// operations use the wall clock reading, but later time-measuring -// operations, specifically comparisons and subtractions, use the -// monotonic clock reading. -// -// For example, this code always computes a positive elapsed time of -// approximately 20 milliseconds, even if the wall clock is changed during -// the operation being timed: -// -// start := time.Now() -// ... operation that takes 20 milliseconds ... -// t := time.Now() -// elapsed := t.Sub(start) -// -// Other idioms, such as time.Since(start), time.Until(deadline), and -// time.Now().Before(deadline), are similarly robust against wall clock -// resets. -// -// The rest of this section gives the precise details of how operations -// use monotonic clocks, but understanding those details is not required -// to use this package. -// -// The Time returned by time.Now contains a monotonic clock reading. -// If Time t has a monotonic clock reading, t.Add adds the same duration to -// both the wall clock and monotonic clock readings to compute the result. -// Because t.AddDate(y, m, d), t.Round(d), and t.Truncate(d) are wall time -// computations, they always strip any monotonic clock reading from their results. -// Because t.In, t.Local, and t.UTC are used for their effect on the interpretation -// of the wall time, they also strip any monotonic clock reading from their results. -// The canonical way to strip a monotonic clock reading is to use t = t.Round(0). -// -// If Times t and u both contain monotonic clock readings, the operations -// t.After(u), t.Before(u), t.Equal(u), and t.Sub(u) are carried out -// using the monotonic clock readings alone, ignoring the wall clock -// readings. If either t or u contains no monotonic clock reading, these -// operations fall back to using the wall clock readings. -// -// On some systems the monotonic clock will stop if the computer goes to sleep. -// On such a system, t.Sub(u) may not accurately reflect the actual -// time that passed between t and u. -// -// Because the monotonic clock reading has no meaning outside -// the current process, the serialized forms generated by t.GobEncode, -// t.MarshalBinary, t.MarshalJSON, and t.MarshalText omit the monotonic -// clock reading, and t.Format provides no format for it. Similarly, the -// constructors time.Date, time.Parse, time.ParseInLocation, and time.Unix, -// as well as the unmarshalers t.GobDecode, t.UnmarshalBinary. -// t.UnmarshalJSON, and t.UnmarshalText always create times with -// no monotonic clock reading. -// -// The monotonic clock reading exists only in Time values. It is not -// a part of Duration values or the Unix times returned by t.Unix and -// friends. -// -// Note that the Go == operator compares not just the time instant but -// also the Location and the monotonic clock reading. See the -// documentation for the Time type for a discussion of equality -// testing for Time values. -// -// For debugging, the result of t.String does include the monotonic -// clock reading if present. If t != u because of different monotonic clock readings, -// that difference will be visible when printing t.String() and u.String(). package time -import ( - "errors" -) +import "errors" -// A Time represents an instant in time with nanosecond precision. -// -// Programs using times should typically store and pass them as values, -// not pointers. That is, time variables and struct fields should be of -// type time.Time, not *time.Time. -// -// A Time value can be used by multiple goroutines simultaneously except -// that the methods GobDecode, UnmarshalBinary, UnmarshalJSON and -// UnmarshalText are not concurrency-safe. -// -// Time instants can be compared using the Before, After, and Equal methods. -// The Sub method subtracts two instants, producing a Duration. -// The Add method adds a Time and a Duration, producing a Time. -// -// The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC. -// As this time is unlikely to come up in practice, the IsZero method gives -// a simple way of detecting a time that has not been initialized explicitly. -// -// Each Time has associated with it a Location, consulted when computing the -// presentation form of the time, such as in the Format, Hour, and Year methods. -// The methods Local, UTC, and In return a Time with a specific location. -// Changing the location in this way changes only the presentation; it does not -// change the instant in time being denoted and therefore does not affect the -// computations described in earlier paragraphs. -// -// Representations of a Time value saved by the GobEncode, MarshalBinary, -// MarshalJSON, and MarshalText methods store the Time.Location's offset, but not -// the location name. They therefore lose information about Daylight Saving Time. -// -// In addition to the required “wall clock” reading, a Time may contain an optional -// reading of the current process's monotonic clock, to provide additional precision -// for comparison or subtraction. -// See the “Monotonic Clocks” section in the package documentation for details. -// -// Note that the Go == operator compares not just the time instant but also the -// Location and the monotonic clock reading. Therefore, Time values should not -// be used as map or database keys without first guaranteeing that the -// identical Location has been set for all values, which can be achieved -// through use of the UTC or Local method, and that the monotonic clock reading -// has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u) -// to t == u, since t.Equal uses the most accurate comparison available and -// correctly handles the case when only one of its arguments has a monotonic -// clock reading. type Time struct { - // wall and ext encode the wall time seconds, wall time nanoseconds, - // and optional monotonic clock reading in nanoseconds. - // - // From high to low bit position, wall encodes a 1-bit flag (hasMonotonic), - // a 33-bit seconds field, and a 30-bit wall time nanoseconds field. - // The nanoseconds field is in the range [0, 999999999]. - // If the hasMonotonic bit is 0, then the 33-bit field must be zero - // and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext. - // If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit - // unsigned wall seconds since Jan 1 year 1885, and ext holds a - // signed 64-bit monotonic clock reading, nanoseconds since process start. - wall uint64 - ext int64 - - // loc specifies the Location that should be used to - // determine the minute, hour, month, day, and year - // that correspond to this Time. - // The nil location means UTC. - // All UTC times are represented with loc==nil, never loc==&utcLoc. - loc *Location -} - -const ( - hasMonotonic = 1 << 63 - maxWall = wallToInternal + (1<<33 - 1) // year 2157 - minWall = wallToInternal // year 1885 - nsecMask = 1<<30 - 1 - nsecShift = 30 -) - -// These helpers for manipulating the wall and monotonic clock readings -// take pointer receivers, even when they don't modify the time, -// to make them cheaper to call. - -// nsec returns the time's nanoseconds. -func (t *Time) nsec() int32 { - return int32(t.wall & nsecMask) -} - -// sec returns the time's seconds since Jan 1 year 1. -func (t *Time) sec() int64 { - if t.wall&hasMonotonic != 0 { - return wallToInternal + int64(t.wall<<1>>(nsecShift+1)) - } - return t.ext + sec int64 + nsec int32 } // unixSec returns the time's seconds since Jan 1 1970 (Unix time). -func (t *Time) unixSec() int64 { return t.sec() + internalToUnix } +func (t *Time) unixSec() int64 { return t.sec + internalToUnix } // addSec adds d seconds to the time. func (t *Time) addSec(d int64) { - if t.wall&hasMonotonic != 0 { - sec := int64(t.wall << 1 >> (nsecShift + 1)) - dsec := sec + d - if 0 <= dsec && dsec <= 1<<33-1 { - t.wall = t.wall&nsecMask | uint64(dsec)< t.ext) == (d > 0) { - t.ext = sum + // Check if the sum of t.sec and d overflows and handle it properly. + sum := t.sec + d + if (sum > t.sec) == (d > 0) { + t.sec = sum } else if d > 0 { - t.ext = 1<<63 - 1 + t.sec = 1<<63 - 1 } else { - t.ext = -(1<<63 - 1) - } -} - -// setLoc sets the location associated with the time. -func (t *Time) setLoc(loc *Location) { - if loc == &utcLoc { - loc = nil - } - t.stripMono() - t.loc = loc -} - -// stripMono strips the monotonic clock reading in t. -func (t *Time) stripMono() { - if t.wall&hasMonotonic != 0 { - t.ext = t.sec() - t.wall &= nsecMask - } -} - -// setMono sets the monotonic clock reading in t. -// If t cannot hold a monotonic clock reading, -// because its wall time is too large, -// setMono is a no-op. -func (t *Time) setMono(m int64) { - if t.wall&hasMonotonic == 0 { - sec := t.ext - if sec < minWall || maxWall < sec { - return - } - t.wall |= hasMonotonic | uint64(sec-minWall)< u.ext - } - ts := t.sec() - us := u.sec() - return ts > us || ts == us && t.nsec() > u.nsec() + return t.sec > u.sec || t.sec == u.sec && t.nsec > u.nsec } // Before reports whether the time instant t is before u. func (t Time) Before(u Time) bool { - if t.wall&u.wall&hasMonotonic != 0 { - return t.ext < u.ext - } - ts := t.sec() - us := u.sec() - return ts < us || ts == us && t.nsec() < u.nsec() + return t.sec < u.sec || t.sec == u.sec && t.nsec < u.nsec } // Equal reports whether t and u represent the same time instant. -// Two times can be equal even if they are in different locations. -// For example, 6:00 +0200 and 4:00 UTC are Equal. // See the documentation on the Time type for the pitfalls of using == with // Time values; most code should use Equal instead. func (t Time) Equal(u Time) bool { - if t.wall&u.wall&hasMonotonic != 0 { - return t.ext == u.ext - } - return t.sec() == u.sec() && t.nsec() == u.nsec() + return t.sec == u.sec && t.nsec == u.nsec } -// A Month specifies a month of the year (January = 1, ...). type Month int const ( @@ -431,23 +193,18 @@ const ( // IsZero reports whether t represents the zero time instant, // January 1, year 1, 00:00:00 UTC. func (t Time) IsZero() bool { - return t.sec() == 0 && t.nsec() == 0 + return t.sec == 0 && t.nsec == 0 } -// abs returns the time t as an absolute time, adjusted by the zone offset. -// It is called when computing a presentation property like Month or Hour. -func (t Time) abs() uint64 { - l := t.loc - // Avoid function calls when possible. - if l == nil || l == &localLoc { - l = l.get() - } +// rename of the "abs" method in the original time.go +// since we removed the location & zoneinfo related code +func (t Time) internal() uint64 { sec := t.unixSec() - if l != &utcLoc { - if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd { - sec += int64(l.cacheZone.offset) + if timezoneChainParam != &utcLoc { + if timezoneChainParam.cacheZone != nil && timezoneChainParam.cacheStart <= sec && sec < timezoneChainParam.cacheEnd { + sec += int64(timezoneChainParam.cacheZone.offset) } else { - _, offset, _, _, _ := l.lookup(sec) + _, offset, _, _, _ := timezoneChainParam.lookup(sec) sec += int64(offset) } } @@ -457,10 +214,7 @@ func (t Time) abs() uint64 { // locabs is a combination of the Zone and abs methods, // extracting both return values from a single zone lookup. func (t Time) locabs() (name string, offset int, abs uint64) { - l := t.loc - if l == nil || l == &localLoc { - l = l.get() - } + l := timezoneChainParam // Avoid function call if we hit the local time cache. sec := t.unixSec() if l != &utcLoc { @@ -504,13 +258,12 @@ func (t Time) Day() int { // Weekday returns the day of the week specified by t. func (t Time) Weekday() Weekday { - return absWeekday(t.abs()) + return internalWeekday(t.internal()) } -// absWeekday is like Weekday but operates on an absolute time. -func absWeekday(abs uint64) Weekday { - // January 1 of the absolute year, like January 1 of 2001, was a Monday. - sec := (abs + uint64(Monday)*secondsPerDay) % secondsPerWeek +// internalWeekday is like Weekday but operates on an internal time. +func internalWeekday(it uint64) Weekday { + sec := (it + uint64(Monday)*secondsPerDay) % secondsPerWeek return Weekday(int(sec) / secondsPerDay) } @@ -529,26 +282,26 @@ func (t Time) ISOWeek() (year, week int) { // 1 2 3 4 5 6 7 // +3 +2 +1 0 -1 -2 -3 // the offset to Thursday - abs := t.abs() - d := Thursday - absWeekday(abs) + it := t.internal() + d := Thursday - internalWeekday(it) // handle Sunday if d == 4 { - d = -3 + d -= 3 } // find the Thursday of the calendar week - abs += uint64(d) * secondsPerDay - year, _, _, yday := absDate(abs, false) + it += uint64(d) * secondsPerDay + year, _, _, yday := internalDate(it, false) return year, yday/7 + 1 } // Clock returns the hour, minute, and second within the day specified by t. func (t Time) Clock() (hour, min, sec int) { - return absClock(t.abs()) + return internalClock(t.internal()) } -// absClock is like clock but operates on an absolute time. -func absClock(abs uint64) (hour, min, sec int) { - sec = int(abs % secondsPerDay) +// internalClock is like clock but operates on an internal time. +func internalClock(it uint64) (hour, min, sec int) { + sec = int(it % secondsPerDay) hour = sec / secondsPerHour sec -= hour * secondsPerHour min = sec / secondsPerMinute @@ -558,23 +311,23 @@ func absClock(abs uint64) (hour, min, sec int) { // Hour returns the hour within the day specified by t, in the range [0, 23]. func (t Time) Hour() int { - return int(t.abs()%secondsPerDay) / secondsPerHour + return int(t.internal()%secondsPerDay) / secondsPerHour } // Minute returns the minute offset within the hour specified by t, in the range [0, 59]. func (t Time) Minute() int { - return int(t.abs()%secondsPerHour) / secondsPerMinute + return int(t.internal()%secondsPerHour) / secondsPerMinute } // Second returns the second offset within the minute specified by t, in the range [0, 59]. func (t Time) Second() int { - return int(t.abs() % secondsPerMinute) + return int(t.internal() % secondsPerMinute) } // Nanosecond returns the nanosecond offset within the second specified by t, // in the range [0, 999999999]. func (t Time) Nanosecond() int { - return int(t.nsec()) + return int(t.nsec) } // YearDay returns the day of the year specified by t, in the range [1,365] for non-leap years, @@ -716,8 +469,7 @@ func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) { return w, v } -// fmtInt formats v into the tail of buf. -// It returns the index where the output begins. +// add v at the end of buf and return the index where the number starts in buf func fmtInt(buf []byte, v uint64) int { w := len(buf) if v == 0 { @@ -830,10 +582,10 @@ func (d Duration) Abs() Duration { } } -// Add returns the time t+d. +// Add returns the time t+d func (t Time) Add(d Duration) Time { dsec := int64(d / 1e9) - nsec := t.nsec() + int32(d%1e9) + nsec := t.nsec + int32(d%1e9) if nsec >= 1e9 { dsec++ nsec -= 1e9 @@ -841,18 +593,7 @@ func (t Time) Add(d Duration) Time { dsec-- nsec += 1e9 } - t.wall = t.wall&^nsecMask | uint64(nsec) // update nsec - t.addSec(dsec) - if t.wall&hasMonotonic != 0 { - te := t.ext + int64(d) - if d < 0 && te > t.ext || d > 0 && te < t.ext { - // Monotonic clock reading now out of range; degrade to wall-only. - t.stripMono() - } else { - t.ext = te - } - } - return t + return Time{t.sec + dsec, nsec} } // Sub returns the duration t-u. If the result exceeds the maximum (or minimum) @@ -860,54 +601,34 @@ func (t Time) Add(d Duration) Time { // will be returned. // To compute t-d for a duration d, use t.Add(-d). func (t Time) Sub(u Time) Duration { - if t.wall&u.wall&hasMonotonic != 0 { - te := t.ext - ue := u.ext - d := Duration(te - ue) - if d < 0 && te > ue { - return maxDuration // t - u is positive out of range - } - if d > 0 && te < ue { - return minDuration // t - u is negative out of range - } - return d + sec := t.sec - u.sec + nsec := t.nsec - u.nsec + if sec > 0 && nsec < 0 { + sec-- + nsec += 1e9 + } else if sec < 0 && nsec > 0 { + sec++ + nsec -= 1e9 } - d := Duration(t.sec()-u.sec())*Second + Duration(t.nsec()-u.nsec()) - // Check for overflow or underflow. - switch { - case u.Add(d).Equal(t): - return d // d is correct - case t.Before(u): - return minDuration // t - u is negative out of range - default: - return maxDuration // t - u is positive out of range + if sec > int64(maxDuration) { + return maxDuration + } + if sec < int64(minDuration) { + return minDuration } + return Duration(sec*1e9 + int64(nsec)) } // Since returns the time elapsed since t. // It is shorthand for time.Now().Sub(t). func Since(t Time) Duration { - var now Time - if t.wall&hasMonotonic != 0 { - // Common case optimization: if t has monotonic time, then Sub will use only it. - now = Time{hasMonotonic, runtimeNano() - startNano, nil} - } else { - now = Now() - } - return now.Sub(t) + return Now().Sub(t) } // Until returns the duration until t. // It is shorthand for t.Sub(time.Now()). func Until(t Time) Duration { - var now Time - if t.wall&hasMonotonic != 0 { - // Common case optimization: if t has monotonic time, then Sub will use only it. - now = Time{hasMonotonic, runtimeNano() - startNano, nil} - } else { - now = Now() - } - return t.Sub(now) + return t.Sub(Now()) } // AddDate returns the time corresponding to adding the @@ -921,7 +642,7 @@ func Until(t Time) Duration { func (t Time) AddDate(years int, months int, days int) Time { year, month, day := t.Date() hour, min, sec := t.Clock() - return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec()), t.Location()) + return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), timezoneChainParam) } const ( @@ -937,13 +658,12 @@ const ( // date computes the year, day of year, and when full=true, // the month and day in which t occurs. func (t Time) date(full bool) (year int, month Month, day int, yday int) { - return absDate(t.abs(), full) + return internalDate(t.internal(), full) } -// absDate is like date but operates on an absolute time. -func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) { - // Split into time and day. - d := abs / secondsPerDay +// internalDate is like date but operates on an internal time. +func internalDate(it uint64, full bool) (year int, month Month, day int, yday int) { + d := it / secondsPerDay // Account for 400 year cycles. n := d / daysPer400Years @@ -1068,93 +788,22 @@ func daysSinceEpoch(year int) uint64 { return d } -func now() (sec int64, nsec int32, mono int64) // injected +func now() (sec int64, nsec int32, mono int64) // injected by runtime -// runtimeNano returns the current value of the runtime clock in nanoseconds. -func runtimeNano() int64 { - _, _, mono := now() - return mono -} - -// Monotonic times are reported as offsets from startNano. -// We initialize startNano to runtimeNano() - 1 so that on systems where -// monotonic time resolution is fairly low (e.g. Windows 2008 -// which appears to have a default resolution of 15ms), -// we avoid ever reporting a monotonic time of 0. -// (Callers may want to use 0 as "time not set".) -var startNano int64 = runtimeNano() - 1 - -// Now returns the current local time. +// Now returns the current UTC time. func Now() Time { - sec, nsec, mono := now() - mono -= startNano - sec += unixToInternal - minWall - if uint64(sec)>>33 != 0 { - return Time{uint64(nsec), sec + minWall, Local} - } - return Time{hasMonotonic | uint64(sec)< 32767 { - return nil, errors.New("Time.MarshalBinary: unexpected zone offset") - } - offsetMin = int16(offset) - } - - sec := t.sec() - nsec := t.nsec() + sec := t.sec + nsec := t.nsec enc := []byte{ - version, // byte 0 : version - byte(sec >> 56), // bytes 1-8: seconds + // encode seconds (int64) / bytes 0 to 7 + byte(sec >> 56), byte(sec >> 48), byte(sec >> 40), byte(sec >> 32), @@ -1235,17 +859,12 @@ func (t Time) MarshalBinary() ([]byte, error) { byte(sec >> 16), byte(sec >> 8), byte(sec), - byte(nsec >> 24), // bytes 9-12: nanoseconds + // encode nanoseconds (int32) / bytes 8 to 11 + byte(nsec >> 24), byte(nsec >> 16), byte(nsec >> 8), byte(nsec), - byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes - byte(offsetMin), } - if version == timeBinaryVersionV2 { - enc = append(enc, byte(offsetSec)) - } - return enc, nil } @@ -1255,62 +874,22 @@ func (t *Time) UnmarshalBinary(data []byte) error { if len(buf) == 0 { return errors.New("Time.UnmarshalBinary: no data") } - - version := buf[0] - if version != timeBinaryVersionV1 && version != timeBinaryVersionV2 { - return errors.New("Time.UnmarshalBinary: unsupported version") - } - - wantLen := /*version*/ 1 + /*sec*/ 8 + /*nsec*/ 4 + /*zone offset*/ 2 - if version == timeBinaryVersionV2 { - wantLen++ - } - if len(buf) != wantLen { + if len(buf) != 12 { // 8 bytes for sec (int64) + 4 bytes for nsec (int32) return errors.New("Time.UnmarshalBinary: invalid length") } - - buf = buf[1:] sec := int64(buf[7]) | int64(buf[6])<<8 | int64(buf[5])<<16 | int64(buf[4])<<24 | int64(buf[3])<<32 | int64(buf[2])<<40 | int64(buf[1])<<48 | int64(buf[0])<<56 buf = buf[8:] nsec := int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24 - buf = buf[4:] - offset := int(int16(buf[1])|int16(buf[0])<<8) * 60 - if version == timeBinaryVersionV2 { - offset += int(buf[2]) - } - *t = Time{} - t.wall = uint64(nsec) - t.ext = sec - - if offset == -1*60 { - t.setLoc(&utcLoc) - } else if _, localoff, _, _, _ := Local.lookup(t.unixSec()); offset == localoff { - t.setLoc(Local) - } else { - t.setLoc(FixedZone("", offset)) - } + t.sec = sec + t.nsec = nsec return nil } -// TODO(rsc): Remove GobEncoder, GobDecoder, MarshalJSON, UnmarshalJSON in Go 2. -// The same semantics will be provided by the generic MarshalBinary, MarshalText, -// UnmarshalBinary, UnmarshalText. - -// GobEncode implements the gob.GobEncoder interface. -func (t Time) GobEncode() ([]byte, error) { - return t.MarshalBinary() -} - -// GobDecode implements the gob.GobDecoder interface. -func (t *Time) GobDecode(data []byte) error { - return t.UnmarshalBinary(data) -} - // MarshalJSON implements the json.Marshaler interface. // The time is a quoted string in RFC 3339 format, with sub-second precision added if present. func (t Time) MarshalJSON() ([]byte, error) { @@ -1360,6 +939,12 @@ func (t *Time) UnmarshalText(data []byte) error { return err } +// IsDST reports whether the time in the configured location is in Daylight Savings Time. +func (t Time) IsDST() bool { + _, _, _, _, isDST := timezoneChainParam.lookup(t.unixSec()) + return isDST +} + // Unix returns the local Time corresponding to the given Unix time, // sec seconds and nsec nanoseconds since January 1, 1970 UTC. // It is valid to pass nsec outside the range [0, 999999999]. @@ -1390,12 +975,6 @@ func UnixMicro(usec int64) Time { return Unix(usec/1e6, (usec%1e6)*1e3) } -// IsDST reports whether the time in the configured location is in Daylight Savings Time. -func (t Time) IsDST() bool { - _, _, _, _, isDST := t.loc.lookup(t.Unix()) - return isDST -} - func isLeap(year int) bool { return year%4 == 0 && (year%100 != 0 || year%400 == 0) } @@ -1422,20 +1001,10 @@ func norm(hi, lo, base int) (nhi, nlo int) { // // yyyy-mm-dd hh:mm:ss + nsec nanoseconds // -// in the appropriate zone for that time in the given location. -// // The month, day, hour, min, sec, and nsec values may be outside // their usual ranges and will be normalized during the conversion. // For example, October 32 converts to November 1. -// -// A daylight savings time transition skips or repeats times. -// For example, in the United States, March 13, 2011 2:15am never occurred, -// while November 6, 2011 1:15am occurred twice. In such cases, the -// choice of time zone, and therefore the time, is not well-defined. -// Date returns a time that is correct in one of the two zones involved -// in the transition, but it does not guarantee which. -// -// Date panics if loc is nil. +// Location is always UTC, regardless of the given time zone. func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time { if loc == nil { panic("time: missing Location in call to Date") @@ -1470,10 +1039,6 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T unix := int64(abs) + (absoluteToInternal + internalToUnix) - // Look for zone offset for expected time, so we can adjust to UTC. - // The lookup function expects UTC, so first we pass unix in the - // hope that it will not be too close to a zone transition, - // and then adjust if it is. _, offset, start, end, _ := loc.lookup(unix) if offset != 0 { utc := unix - int64(offset) @@ -1486,19 +1051,11 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T } t := unixTime(unix, int32(nsec)) - t.setLoc(loc) return t } // Truncate returns the result of rounding t down to a multiple of d (since the zero time). -// If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged. -// -// Truncate operates on the time as an absolute duration since the -// zero time; it does not operate on the presentation form of the -// time. Thus, Truncate(Hour) may return a time with a non-zero -// minute, depending on the time's Location. func (t Time) Truncate(d Duration) Time { - t.stripMono() if d <= 0 { return t } @@ -1508,14 +1065,7 @@ func (t Time) Truncate(d Duration) Time { // Round returns the result of rounding t to the nearest multiple of d (since the zero time). // The rounding behavior for halfway values is to round up. -// If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged. -// -// Round operates on the time as an absolute duration since the -// zero time; it does not operate on the presentation form of the -// time. Thus, Round(Hour) may return a time with a non-zero -// minute, depending on the time's Location. func (t Time) Round(d Duration) Time { - t.stripMono() if d <= 0 { return t } @@ -1531,8 +1081,8 @@ func (t Time) Round(d Duration) Time { // but it's still here in case we change our minds. func div(t Time, d Duration) (qmod2 int, r Duration) { neg := false - nsec := t.nsec() - sec := t.sec() + nsec := t.nsec + sec := t.sec if sec < 0 { // Operate on absolute value. neg = true diff --git a/gnovm/stdlibs/time/timezoneinfo.gno b/gnovm/stdlibs/time/timezoneinfo.gno index 826c2988a8c..e2abde9f2b2 100644 --- a/gnovm/stdlibs/time/timezoneinfo.gno +++ b/gnovm/stdlibs/time/timezoneinfo.gno @@ -63,6 +63,8 @@ const ( omega = 1<<63 - 1 // math.MaxInt64 ) +var timezoneChainParam *Location + // UTC represents Universal Coordinated Time (UTC). var UTC *Location = &utcLoc @@ -71,27 +73,14 @@ var UTC *Location = &utcLoc // even if a badly behaved client has changed UTC. var utcLoc = Location{name: "UTC"} -// Local represents the system's local time zone. -// On Unix systems, Local consults the TZ environment -// variable to find the time zone to use. No TZ means -// use the system default /etc/localtime. -// TZ="" means use UTC. -// TZ="foo" means use file foo in the system timezone directory. -var Local *Location = &localLoc - -// localLoc is separate so that initLocal can initialize -// it even if a client has changed Local. -var localLoc Location - -// XXX var localOnce sync.Once +func init() { + timezoneChainParam, _ = LoadLocation("UTC") +} func (l *Location) get() *Location { if l == nil { return &utcLoc } - if l == &localLoc { - // XXX localOnce.Do(initLocal) - } return l } @@ -307,7 +296,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in return "", 0, 0, 0, false, false } - year, _, _, yday := absDate(uint64(sec+unixToInternal+internalToAbsolute), false) + year, _, _, yday := internalDate(uint64(sec+unixToInternal+internalToAbsolute), false) ysec := int64(yday*secondsPerDay) + sec%secondsPerDay @@ -645,9 +634,6 @@ func LoadLocation(name string) (*Location, error) { if name == "" || name == "UTC" { return UTC, nil } - if name == "Local" { - return Local, nil - } if containsDotDot(name) || name[0] == '/' || name[0] == '\\' { // No valid IANA Time Zone name contains a single dot, // much less dot dot. Likewise, none begin with a slash. From 8044c1c4c5d2304829fb8a6e31996061c76269a1 Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Mon, 25 Nov 2024 11:43:19 +0100 Subject: [PATCH 02/15] feat: remove location usage in time.Date function --- examples/gno.land/r/demo/timetest/gno.mod | 1 + examples/gno.land/r/demo/timetest/test.gno | 15 +++++++++++++++ gnovm/stdlibs/time/time.gno | 6 ++---- gnovm/stdlibs/time/timezoneinfo.gno | 2 +- 4 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 examples/gno.land/r/demo/timetest/gno.mod create mode 100644 examples/gno.land/r/demo/timetest/test.gno diff --git a/examples/gno.land/r/demo/timetest/gno.mod b/examples/gno.land/r/demo/timetest/gno.mod new file mode 100644 index 00000000000..338fe68c46f --- /dev/null +++ b/examples/gno.land/r/demo/timetest/gno.mod @@ -0,0 +1 @@ +module gno.land/r/demo/timetest \ No newline at end of file diff --git a/examples/gno.land/r/demo/timetest/test.gno b/examples/gno.land/r/demo/timetest/test.gno new file mode 100644 index 00000000000..ba23e803bec --- /dev/null +++ b/examples/gno.land/r/demo/timetest/test.gno @@ -0,0 +1,15 @@ +package timetest + +import ( + "time" +) + +func Render(path string) string { + location, _ := time.LoadLocation("America/New_York") // Replace with your desired timezone + // Create a specific time in that timezone + year, month, day := 2024, time.November, 25 + hour, minute, second := 15, 30, 0 + nyTime := time.Date(year, month, day, hour, minute, second, 0, location) + + return nyTime.String() +} diff --git a/gnovm/stdlibs/time/time.gno b/gnovm/stdlibs/time/time.gno index ad3f88df033..ca9dc52ff68 100644 --- a/gnovm/stdlibs/time/time.gno +++ b/gnovm/stdlibs/time/time.gno @@ -1004,11 +1004,9 @@ func norm(hi, lo, base int) (nhi, nlo int) { // The month, day, hour, min, sec, and nsec values may be outside // their usual ranges and will be normalized during the conversion. // For example, October 32 converts to November 1. -// Location is always UTC, regardless of the given time zone. +// Location is always the timezone chain param no matter what is passed in. func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time { - if loc == nil { - panic("time: missing Location in call to Date") - } + loc = timezoneChainParam // Normalize month, overflowing into year. m := int(month) - 1 diff --git a/gnovm/stdlibs/time/timezoneinfo.gno b/gnovm/stdlibs/time/timezoneinfo.gno index e2abde9f2b2..d3d77e3fc06 100644 --- a/gnovm/stdlibs/time/timezoneinfo.gno +++ b/gnovm/stdlibs/time/timezoneinfo.gno @@ -74,7 +74,7 @@ var UTC *Location = &utcLoc var utcLoc = Location{name: "UTC"} func init() { - timezoneChainParam, _ = LoadLocation("UTC") + timezoneChainParam, _ = LoadLocation("Europe/Paris") } func (l *Location) get() *Location { From 192bef86d4479b44c38dd0dd33549a2a0ac217a3 Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Mon, 25 Nov 2024 11:50:12 +0100 Subject: [PATCH 03/15] feat: rename internal to abs --- gnovm/stdlibs/time/format.gno | 8 +++---- gnovm/stdlibs/time/time.gno | 34 ++++++++++++++--------------- gnovm/stdlibs/time/timezoneinfo.gno | 4 ++-- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/gnovm/stdlibs/time/format.gno b/gnovm/stdlibs/time/format.gno index f18026e8f52..1c741586273 100644 --- a/gnovm/stdlibs/time/format.gno +++ b/gnovm/stdlibs/time/format.gno @@ -615,13 +615,13 @@ func (t Time) AppendFormat(b []byte, layout string) []byte { // Compute year, month, day if needed. if year < 0 && std&stdNeedDate != 0 { - year, month, day, yday = internalDate(abs, true) + year, month, day, yday = absDate(abs, true) yday++ } // Compute hour, minute, second if needed. if hour < 0 && std&stdNeedClock != 0 { - hour, min, sec = internalClock(abs) + hour, min, sec = absClock(abs) } switch std & stdMask { @@ -643,9 +643,9 @@ func (t Time) AppendFormat(b []byte, layout string) []byte { case stdZeroMonth: b = appendInt(b, int(month), 2) case stdWeekDay: - b = append(b, internalWeekday(abs).String()[:3]...) + b = append(b, absWeekday(abs).String()[:3]...) case stdLongWeekDay: - s := internalWeekday(abs).String() + s := absWeekday(abs).String() b = append(b, s...) case stdDay: b = appendInt(b, day, 0) diff --git a/gnovm/stdlibs/time/time.gno b/gnovm/stdlibs/time/time.gno index ca9dc52ff68..b0be1fb4d49 100644 --- a/gnovm/stdlibs/time/time.gno +++ b/gnovm/stdlibs/time/time.gno @@ -196,9 +196,7 @@ func (t Time) IsZero() bool { return t.sec == 0 && t.nsec == 0 } -// rename of the "abs" method in the original time.go -// since we removed the location & zoneinfo related code -func (t Time) internal() uint64 { +func (t Time) abs() uint64 { sec := t.unixSec() if timezoneChainParam != &utcLoc { if timezoneChainParam.cacheZone != nil && timezoneChainParam.cacheStart <= sec && sec < timezoneChainParam.cacheEnd { @@ -258,11 +256,11 @@ func (t Time) Day() int { // Weekday returns the day of the week specified by t. func (t Time) Weekday() Weekday { - return internalWeekday(t.internal()) + return absWeekday(t.abs()) } -// internalWeekday is like Weekday but operates on an internal time. -func internalWeekday(it uint64) Weekday { +// absWeekday is like Weekday but operates on an absolute time. +func absWeekday(it uint64) Weekday { sec := (it + uint64(Monday)*secondsPerDay) % secondsPerWeek return Weekday(int(sec) / secondsPerDay) } @@ -282,25 +280,25 @@ func (t Time) ISOWeek() (year, week int) { // 1 2 3 4 5 6 7 // +3 +2 +1 0 -1 -2 -3 // the offset to Thursday - it := t.internal() - d := Thursday - internalWeekday(it) + it := t.abs() + d := Thursday - absWeekday(it) // handle Sunday if d == 4 { d -= 3 } // find the Thursday of the calendar week it += uint64(d) * secondsPerDay - year, _, _, yday := internalDate(it, false) + year, _, _, yday := absDate(it, false) return year, yday/7 + 1 } // Clock returns the hour, minute, and second within the day specified by t. func (t Time) Clock() (hour, min, sec int) { - return internalClock(t.internal()) + return absClock(t.abs()) } -// internalClock is like clock but operates on an internal time. -func internalClock(it uint64) (hour, min, sec int) { +// absClock is like clock but operates on an absolute time. +func absClock(it uint64) (hour, min, sec int) { sec = int(it % secondsPerDay) hour = sec / secondsPerHour sec -= hour * secondsPerHour @@ -311,17 +309,17 @@ func internalClock(it uint64) (hour, min, sec int) { // Hour returns the hour within the day specified by t, in the range [0, 23]. func (t Time) Hour() int { - return int(t.internal()%secondsPerDay) / secondsPerHour + return int(t.abs()%secondsPerDay) / secondsPerHour } // Minute returns the minute offset within the hour specified by t, in the range [0, 59]. func (t Time) Minute() int { - return int(t.internal()%secondsPerHour) / secondsPerMinute + return int(t.abs()%secondsPerHour) / secondsPerMinute } // Second returns the second offset within the minute specified by t, in the range [0, 59]. func (t Time) Second() int { - return int(t.internal() % secondsPerMinute) + return int(t.abs() % secondsPerMinute) } // Nanosecond returns the nanosecond offset within the second specified by t, @@ -658,11 +656,11 @@ const ( // date computes the year, day of year, and when full=true, // the month and day in which t occurs. func (t Time) date(full bool) (year int, month Month, day int, yday int) { - return internalDate(t.internal(), full) + return absDate(t.abs(), full) } -// internalDate is like date but operates on an internal time. -func internalDate(it uint64, full bool) (year int, month Month, day int, yday int) { +// absDate is like date but operates on an absolute time. +func absDate(it uint64, full bool) (year int, month Month, day int, yday int) { d := it / secondsPerDay // Account for 400 year cycles. diff --git a/gnovm/stdlibs/time/timezoneinfo.gno b/gnovm/stdlibs/time/timezoneinfo.gno index d3d77e3fc06..fd6d63257ec 100644 --- a/gnovm/stdlibs/time/timezoneinfo.gno +++ b/gnovm/stdlibs/time/timezoneinfo.gno @@ -74,7 +74,7 @@ var UTC *Location = &utcLoc var utcLoc = Location{name: "UTC"} func init() { - timezoneChainParam, _ = LoadLocation("Europe/Paris") + timezoneChainParam, _ = LoadLocation("UTC") } func (l *Location) get() *Location { @@ -296,7 +296,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in return "", 0, 0, 0, false, false } - year, _, _, yday := internalDate(uint64(sec+unixToInternal+internalToAbsolute), false) + year, _, _, yday := absDate(uint64(sec+unixToInternal+internalToAbsolute), false) ysec := int64(yday*secondsPerDay) + sec%secondsPerDay From 95ea22e314be6e142cfea9e9ca10b503e4302d88 Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Mon, 25 Nov 2024 12:06:12 +0100 Subject: [PATCH 04/15] tests: fix time pkg test --- .../gno.land/r/demo/boards/z_4_filetest.gno | 49 ++------ .../gno.land/r/demo/groups/z_1_a_filetest.gno | 4 +- .../gno.land/r/demo/groups/z_2_a_filetest.gno | 2 +- examples/gno.land/r/gnoland/events/events.gno | 6 - .../gno.land/r/gnoland/events/events_test.gno | 3 - .../gno.land/r/gnoland/monit/monit_test.gno | 6 +- gnovm/stdlibs/time/format.gno | 4 +- gnovm/stdlibs/time/timezoneinfo.gno | 6 +- gnovm/stdlibs/time/zoneinfo_read.gno | 4 +- gnovm/tests/files/time0_stdlibs.gno | 2 +- gnovm/tests/files/tz_locations.gno | 117 ------------------ 11 files changed, 20 insertions(+), 183 deletions(-) delete mode 100644 gnovm/tests/files/tz_locations.gno 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 fa0b9e20be5..475d5edaeec 100644 --- a/examples/gno.land/r/demo/boards/z_4_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_4_filetest.gno @@ -308,14 +308,7 @@ func main() { // c[f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:131]={ // "Fields": [ // { -// "N": "AAAAgJSeXbo=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "65536" -// } -// }, -// { -// "N": "AbSNdvQQIhE=", +// "N": "0vknwQ4AAAA=", // "T": { // "@type": "/gno.PrimitiveType", // "value": "1024" @@ -323,21 +316,8 @@ func main() { // }, // { // "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "time.Location" -// } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "336074805fc853987abe6f7fe3ad97a6a6f3077a:2" -// }, -// "Index": "182", -// "TV": null +// "@type": "/gno.PrimitiveType", +// "value": "512" // } // } // ], @@ -353,22 +333,13 @@ func main() { // { // "T": { // "@type": "/gno.PrimitiveType", -// "value": "65536" -// } -// }, -// { -// "T": { -// "@type": "/gno.PrimitiveType", // "value": "1024" // } // }, // { // "T": { -// "@type": "/gno.PointerType", -// "Elt": { -// "@type": "/gno.RefType", -// "ID": "time.Location" -// } +// "@type": "/gno.PrimitiveType", +// "value": "512" // } // } // ], @@ -497,7 +468,7 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "0fd3352422af0a56a77ef2c9e88f479054e3d51f", +// "Hash": "55cc9b7009f66b35f15d34ceed3fa25c9e36d54d", // "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:131" // } // }, @@ -508,7 +479,7 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "bed4afa8ffdbbf775451c947fc68b27a345ce32a", +// "Hash": "d8d66a5855b0427c262cfce9891c88d469ab2351", // "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:132" // } // } @@ -534,7 +505,7 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "c45bbd47a46681a63af973db0ec2180922e4a8ae", +// "Hash": "6b2cd34f216499f59540555be3fe11f40a67baa1", // "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:127" // } // } @@ -785,7 +756,7 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "a416a751c3a45a1e5cba11e737c51340b081e372", +// "Hash": "ed9d8105a90a05bc8d953538dd8810201e26ec6d", // "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:86" // } // }, @@ -803,7 +774,7 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "36299fccbc13f2a84c4629fad4cb940f0bd4b1c6", +// "Hash": "ef78d14dccddfaa802727058e543d3ecc87157f0", // "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:87" // } // }, diff --git a/examples/gno.land/r/demo/groups/z_1_a_filetest.gno b/examples/gno.land/r/demo/groups/z_1_a_filetest.gno index aeff9ab7774..c752441e38a 100644 --- a/examples/gno.land/r/demo/groups/z_1_a_filetest.gno +++ b/examples/gno.land/r/demo/groups/z_1_a_filetest.gno @@ -69,10 +69,10 @@ func main() { // // Group Creator: gnouser0 // -// Group createdAt: 2009-02-13 23:31:30 +0000 UTC m=+1234567890.000000001 +// Group createdAt: 2009-02-13 23:31:30 +0000 UTC // // Group Last MemberID: 0000000001 // // Group Members: // -// [0000000000, g1vahx7atnv4erxh6lta047h6lta047h6ll85gpy, 32, i am from UAE, 2009-02-13 23:31:30 +0000 UTC m=+1234567890.000000001], +// [0000000000, g1vahx7atnv4erxh6lta047h6lta047h6ll85gpy, 32, i am from UAE, 2009-02-13 23:31:30 +0000 UTC], diff --git a/examples/gno.land/r/demo/groups/z_2_a_filetest.gno b/examples/gno.land/r/demo/groups/z_2_a_filetest.gno index d1cc53d612f..7cece2d3712 100644 --- a/examples/gno.land/r/demo/groups/z_2_a_filetest.gno +++ b/examples/gno.land/r/demo/groups/z_2_a_filetest.gno @@ -71,7 +71,7 @@ func main() { // // Group Creator: gnouser0 // -// Group createdAt: 2009-02-13 23:31:30 +0000 UTC m=+1234567890.000000001 +// Group createdAt: 2009-02-13 23:31:30 +0000 UTC // // Group Last MemberID: 0000000001 // diff --git a/examples/gno.land/r/gnoland/events/events.gno b/examples/gno.land/r/gnoland/events/events.gno index baf9ba3d4af..ea7eb0c19f2 100644 --- a/examples/gno.land/r/gnoland/events/events.gno +++ b/examples/gno.land/r/gnoland/events/events.gno @@ -186,11 +186,5 @@ func parseTimes(startTime, endTime string) (time.Time, time.Time, error) { return time.Time{}, time.Time{}, ErrEndBeforeStart } - _, stOffset := st.Zone() - _, etOffset := et.Zone() - if stOffset != etOffset { - return time.Time{}, time.Time{}, ErrStartEndTimezonemMismatch - } - return st, et, nil } diff --git a/examples/gno.land/r/gnoland/events/events_test.gno b/examples/gno.land/r/gnoland/events/events_test.gno index 1d79b754ee4..26e196fc76f 100644 --- a/examples/gno.land/r/gnoland/events/events_test.gno +++ b/examples/gno.land/r/gnoland/events/events_test.gno @@ -159,9 +159,6 @@ func TestParseTimes(t *testing.T) { _, _, err = parseTimes("2009-02-13T23:30:30Z", "2009-02-13T21:30:30Z") uassert.ErrorContains(t, err, ErrEndBeforeStart.Error()) - - _, _, err = parseTimes("2009-02-10T23:30:30+02:00", "2009-02-13T21:30:33+05:00") - uassert.ErrorContains(t, err, ErrStartEndTimezonemMismatch.Error()) } func TestRenderEventWidget(t *testing.T) { diff --git a/examples/gno.land/r/gnoland/monit/monit_test.gno b/examples/gno.land/r/gnoland/monit/monit_test.gno index fc9b394b8ed..f09b14e7b73 100644 --- a/examples/gno.land/r/gnoland/monit/monit_test.gno +++ b/examples/gno.land/r/gnoland/monit/monit_test.gno @@ -23,7 +23,7 @@ status=KO` Incr() { expected := `counter=3 -last update=2009-02-13 23:31:30 +0000 UTC m=+1234567890.000000001 +last update=2009-02-13 23:31:30 +0000 UTC last caller=g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm status=OK` got := Render("") @@ -35,7 +35,7 @@ status=OK` use std.TestSkipTime(time.Hour) { expected := `counter=3 - last update=2009-02-13 22:31:30 +0000 UTC m=+1234564290.000000001 + last update=2009-02-13 22:31:30 +0000 UTC last caller=g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm status=KO` got := Render("") @@ -46,7 +46,7 @@ status=OK` Incr() { expected := `counter=4 - last update=2009-02-13 23:31:30 +0000 UTC m=+1234567890.000000001 + last update=2009-02-13 23:31:30 +0000 UTC last caller=g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm status=OK` got := Render("") diff --git a/gnovm/stdlibs/time/format.gno b/gnovm/stdlibs/time/format.gno index 1c741586273..99fc40e38c9 100644 --- a/gnovm/stdlibs/time/format.gno +++ b/gnovm/stdlibs/time/format.gno @@ -4,9 +4,7 @@ package time -import ( - "errors" -) +import "errors" // These are predefined layouts for use in Time.Format and time.Parse. // The reference time used in these layouts is the specific time stamp: diff --git a/gnovm/stdlibs/time/timezoneinfo.gno b/gnovm/stdlibs/time/timezoneinfo.gno index fd6d63257ec..223946e6294 100644 --- a/gnovm/stdlibs/time/timezoneinfo.gno +++ b/gnovm/stdlibs/time/timezoneinfo.gno @@ -4,11 +4,7 @@ package time -import ( - "errors" - // "sync" XXX - // "syscall" XXX -) +import "errors" //go:generate env ZONEINFO=$GOROOT/lib/time/zoneinfo.zip go run genzabbrs.go -output zoneinfo_abbrs_windows.go diff --git a/gnovm/stdlibs/time/zoneinfo_read.gno b/gnovm/stdlibs/time/zoneinfo_read.gno index 2621b2b6631..5cdf1783262 100644 --- a/gnovm/stdlibs/time/zoneinfo_read.gno +++ b/gnovm/stdlibs/time/zoneinfo_read.gno @@ -9,9 +9,7 @@ package time -import ( - "errors" -) +import "errors" // Simple I/O interface to binary blob of data. type dataIO struct { diff --git a/gnovm/tests/files/time0_stdlibs.gno b/gnovm/tests/files/time0_stdlibs.gno index d9f7e64d958..da1db306396 100644 --- a/gnovm/tests/files/time0_stdlibs.gno +++ b/gnovm/tests/files/time0_stdlibs.gno @@ -9,4 +9,4 @@ func main() { } // Output: -// 2009-02-13 23:31:30 +0000 UTC m=+1234567890.000000001 +// 2009-02-13 23:31:30 +0000 UTC diff --git a/gnovm/tests/files/tz_locations.gno b/gnovm/tests/files/tz_locations.gno deleted file mode 100644 index 83ba201bbeb..00000000000 --- a/gnovm/tests/files/tz_locations.gno +++ /dev/null @@ -1,117 +0,0 @@ -package main - -import "time" - -func main() { - const layout = "2006-01-02 15:04:05 -0700 MST" - - loc, err := time.LoadLocation("America/New_York") - if err != nil { - panic(err) - } - - // US eastern war time - t := time.Date(1944, time.August, 15, 0, 0, 0, 0, loc) - println(t.Format(layout)) - - // Us eastern peace time - t = t.Add(24 * time.Hour * 30 * 13) - println(t.Format(layout)) - - loc, err = time.LoadLocation("America/Chicago") - if err != nil { - panic(err) - } - - // US central time - t = time.Date(1935, time.April, 5, 11, 11, 11, 0, loc) - println(t.Format(layout)) - - // US eastern time for a bit - t = t.Add(24 * time.Hour * 365) - println(t.Format(layout)) - - // They didn't like it -- stayed light too late -- back to central - t = t.Add(24 * time.Hour * 365) - println(t.Format(layout)) - - loc, err = time.LoadLocation("Asia/Kathmandu") - if err != nil { - panic(err) - } - - // Nepalese time -- :30 off the hour - t = time.Date(1985, time.September, 17, 12, 12, 12, 0, loc) - println(t.Format(layout)) - - // :30 off the hour is too hard so let's change it to on the hour. - // Wait, no, let's switch to :45 off the hour, for convenience :) - t = t.Add(24 * time.Hour * 365) - println(t.Format(layout)) - - loc, err = time.LoadLocation("Pacific/Kwajalein") - if err != nil { - panic(err) - } - - // Marshall Islands -- where the world's day ends - t = time.Date(1993, time.July, 4, 8, 0, 0, 0, loc) - println(t.Format(layout)) - - // They didn't like that. They want to be where the world's day begins. - t = t.Add(24 * time.Hour * 60) - println(t.Format(layout)) - - loc, err = time.LoadLocation("Pacific/Guam") - if err != nil { - panic(err) - } - - // Guam - t = time.Date(1999, time.December, 25, 12, 0, 0, 0, loc) - println(t.Format(layout)) - - // Sometimes you want to change your timezone abbreviation for the sake of national identity. - // A merry Christmas indeed! - t = t.Add(24 * time.Hour * 365) - println(t.Format(layout)) - - loc, err = time.LoadLocation("Europe/Paris") - if err != nil { - panic(err) - } - - // Paris -- days of yore -- local mean time, determined by longitude - t = time.Date(1891, time.February, 14, 9, 0, 0, 0, loc) - println(t.Format(layout)) - - // Paris mean time - t = t.Add(24 * time.Hour * 365) - println(t.Format(layout)) - - // Paris in the present -- CET -- a month earlier than the original date - // due to 130 years worth of leap days. - t = t.Add(24 * time.Hour * 365 * 130) - println(t.Format(layout)) - - // Paris in the summer -- CEST - t = t.Add(24 * time.Hour * 30 * 5) - println(t.Format(layout)) -} - -// Output: -// 1944-08-15 00:00:00 -0400 EWT -// 1945-09-09 00:00:00 -0400 EPT -// 1935-04-05 11:11:11 -0600 CST -// 1936-04-04 12:11:11 -0500 EST -// 1937-04-04 11:11:11 -0600 CST -// 1985-09-17 12:12:12 +0530 +0530 -// 1986-09-17 12:27:12 +0545 +0545 -// 1993-07-04 08:00:00 -1200 -12 -// 1993-09-03 08:00:00 +1200 +12 -// 1999-12-25 12:00:00 +1000 GST -// 2000-12-24 12:00:00 +1000 ChST -// 1891-02-14 09:00:00 +0009 LMT -// 1892-02-14 09:00:00 +0009 PMT -// 2022-01-13 09:50:39 +0100 CET -// 2022-06-12 10:50:39 +0200 CEST From 750f5b8b498032c0fb401c76dc4e97a58277daf5 Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Mon, 25 Nov 2024 14:51:05 +0100 Subject: [PATCH 05/15] feat: add chain tz as a param --- contribs/gnodev/cmd/gnodev/main.go | 9 +++++ contribs/gnodev/cmd/gnodev/setup_node.go | 2 +- contribs/gnodev/pkg/dev/node.go | 10 +++--- contribs/gnodev/pkg/dev/node_test.go | 6 ++-- .../cmd/gnoland/testdata/genesis_params.txtar | 12 ++++++- gno.land/genesis/genesis_params.toml | 26 +++++++------- gno.land/pkg/gnoland/node_inmemory.go | 7 +++- gnovm/stdlibs/time/context.go | 34 +++++++++++++++++++ gnovm/stdlibs/time/timezoneinfo.gno | 3 ++ gnovm/stdlibs/time/timezoneinfo.go | 13 +++++++ 10 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 gnovm/stdlibs/time/context.go create mode 100644 gnovm/stdlibs/time/timezoneinfo.go diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index 2c694b608bb..962fc4bdcf1 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -67,12 +67,14 @@ type devCfg struct { noReplay bool maxGas int64 chainId string + chainTz string serverMode bool unsafeAPI bool } var defaultDevOptions = &devCfg{ chainId: "dev", + chainTz: "UTC", maxGas: 10_000_000_000, webListenerAddr: "127.0.0.1:8888", nodeRPCListenerAddr: "127.0.0.1:26657", @@ -203,6 +205,13 @@ func (c *devCfg) RegisterFlags(fs *flag.FlagSet) { "set node ChainID", ) + fs.StringVar( + &c.chainTz, + "chain-tz", + defaultDevOptions.chainTz, + "set node Chain Timezone", + ) + fs.BoolVar( &c.noWatch, "no-watch", diff --git a/contribs/gnodev/cmd/gnodev/setup_node.go b/contribs/gnodev/cmd/gnodev/setup_node.go index 4b3619b4a7d..08f53d16241 100644 --- a/contribs/gnodev/cmd/gnodev/setup_node.go +++ b/contribs/gnodev/cmd/gnodev/setup_node.go @@ -57,7 +57,7 @@ func setupDevNodeConfig( balances gnoland.Balances, pkgspath []gnodev.PackagePath, ) *gnodev.NodeConfig { - config := gnodev.DefaultNodeConfig(cfg.root) + config := gnodev.DefaultNodeConfig(cfg.root, cfg.chainTz) config.Logger = logger config.Emitter = emitter diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 9b3f838b8a0..28927f70778 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -42,9 +42,10 @@ type NodeConfig struct { NoReplay bool MaxGasPerBlock int64 ChainID string + ChainTz string } -func DefaultNodeConfig(rootdir string) *NodeConfig { +func DefaultNodeConfig(rootdir string, timezone string) *NodeConfig { tmc := gnoland.NewDefaultTMConfig(rootdir) tmc.Consensus.SkipTimeoutCommit = false // avoid time drifting, see issue #1507 tmc.Consensus.WALDisabled = true @@ -64,6 +65,7 @@ func DefaultNodeConfig(rootdir string) *NodeConfig { DefaultDeployer: defaultDeployer, BalancesList: balances, ChainID: tmc.ChainID(), + ChainTz: timezone, TMConfig: tmc, SkipFailingGenesisTxs: true, MaxGasPerBlock: 10_000_000_000, @@ -477,7 +479,7 @@ func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesisState) } // Setup node config - nodeConfig := newNodeConfig(n.config.TMConfig, n.config.ChainID, genesis) + nodeConfig := newNodeConfig(n.config.TMConfig, n.config.ChainID, n.config.ChainTz, genesis) nodeConfig.GenesisTxResultHandler = n.genesisTxResultHandler // Speed up stdlib loading after first start (saves about 2-3 seconds on each reload). nodeConfig.CacheStdlibLoad = true @@ -556,10 +558,10 @@ func (n *Node) genesisTxResultHandler(ctx sdk.Context, tx std.Tx, res sdk.Result return } -func newNodeConfig(tmc *tmcfg.Config, chainid string, appstate gnoland.GnoGenesisState) *gnoland.InMemoryNodeConfig { +func newNodeConfig(tmc *tmcfg.Config, chainid string, chaintz string, appstate gnoland.GnoGenesisState) *gnoland.InMemoryNodeConfig { // Create Mocked Identity pv := gnoland.NewMockedPrivValidator() - genesis := gnoland.NewDefaultGenesisConfig(chainid) + genesis := gnoland.NewDefaultGenesisConfig(chainid, chaintz) genesis.AppState = appstate // Add self as validator diff --git a/contribs/gnodev/pkg/dev/node_test.go b/contribs/gnodev/pkg/dev/node_test.go index 11b0a2090d7..b47c85a21f3 100644 --- a/contribs/gnodev/pkg/dev/node_test.go +++ b/contribs/gnodev/pkg/dev/node_test.go @@ -34,7 +34,7 @@ func TestNewNode_NoPackages(t *testing.T) { logger := log.NewTestingLogger(t) // Call NewDevNode with no package should work - cfg := DefaultNodeConfig(gnoenv.RootDir()) + cfg := DefaultNodeConfig(gnoenv.RootDir(), "UTC") cfg.Logger = logger node, err := NewDevNode(ctx, cfg) require.NoError(t, err) @@ -62,7 +62,7 @@ func Render(_ string) string { return "foo" } logger := log.NewTestingLogger(t) // Call NewDevNode with no package should work - cfg := DefaultNodeConfig(gnoenv.RootDir()) + cfg := DefaultNodeConfig(gnoenv.RootDir(), "UTC") cfg.PackagesPathList = []PackagePath{pkgpath} cfg.Logger = logger node, err := NewDevNode(ctx, cfg) @@ -295,7 +295,7 @@ func newTestingDevNode(t *testing.T, pkgslist ...PackagePath) (*Node, *mock.Serv emitter := &mock.ServerEmitter{} // Call NewDevNode with no package should work - cfg := DefaultNodeConfig(gnoenv.RootDir()) + cfg := DefaultNodeConfig(gnoenv.RootDir(), "UTC") cfg.PackagesPathList = pkgslist cfg.Emitter = emitter cfg.Logger = logger diff --git a/gno.land/cmd/gnoland/testdata/genesis_params.txtar b/gno.land/cmd/gnoland/testdata/genesis_params.txtar index 43ecd8ccacb..f67a716cd43 100644 --- a/gno.land/cmd/gnoland/testdata/genesis_params.txtar +++ b/gno.land/cmd/gnoland/testdata/genesis_params.txtar @@ -1,7 +1,17 @@ -# test for https://github.com/gnolang/gno/pull/3003 +# Test for #3003, #2911, #3193. gnoland start +# Query and validate official parameters. +# These parameters should ideally be tested in a txtar format to ensure that a +# default initialization of "gnoland" provides the expected default values. + +# Verify the default chain domain parameter for Gno.land +gnokey query params/vm/gno.land/r/sys/params.vm.chain_tz.string +stdout 'data: "UTC"$' + +# Test custom parameters to confirm they return the expected values and types. + gnokey query params/vm/gno.land/r/sys/params.test.foo.string stdout 'data: "bar"$' gnokey query params/vm/gno.land/r/sys/params.test.foo.int64 diff --git a/gno.land/genesis/genesis_params.toml b/gno.land/genesis/genesis_params.toml index 5f4d9c5015c..b1756554d88 100644 --- a/gno.land/genesis/genesis_params.toml +++ b/gno.land/genesis/genesis_params.toml @@ -1,17 +1,17 @@ ## gno.land ["gno.land/r/sys/params.sys"] - users_pkgpath.string = "gno.land/r/sys/users" # if empty, no namespace support. - # TODO: validators_pkgpath.string = "gno.land/r/sys/validators" - # TODO: rewards_pkgpath.string = "gno.land/r/sys/rewards" - # TODO: token_lock.bool = true +users_pkgpath.string = "gno.land/r/sys/users" # if empty, no namespace support. +# TODO: validators_pkgpath.string = "gno.land/r/sys/validators" +# TODO: rewards_pkgpath.string = "gno.land/r/sys/rewards" +# TODO: token_lock.bool = true ## gnovm ["gno.land/r/sys/params.vm"] - # TODO: chain_domain.string = "gno.land" - # TODO: max_gas.int64 = 100_000_000 - # TODO: chain_tz.string = "UTC" - # TODO: default_storage_allowance.string = "" +chain_tz.string = "UTC" +# TODO: chain_domain.string = "gno.land" +# TODO: max_gas.int64 = 100_000_000 +# TODO: default_storage_allowance.string = "" ## tm2 ["gno.land/r/sys/params.tm2"] @@ -22,8 +22,8 @@ ## testing # do not remove these lines. they are needed for a txtar integration test. ["gno.land/r/sys/params.test"] - foo.string = "bar" - foo.int64 = -1337 - foo.uint64 = 42 - foo.bool = true - #foo.bytes = todo +foo.string = "bar" +foo.int64 = -1337 +foo.uint64 = 42 +foo.bool = true +#foo.bytes = todo diff --git a/gno.land/pkg/gnoland/node_inmemory.go b/gno.land/pkg/gnoland/node_inmemory.go index 426a8c780c7..7a5f06f59fe 100644 --- a/gno.land/pkg/gnoland/node_inmemory.go +++ b/gno.land/pkg/gnoland/node_inmemory.go @@ -36,7 +36,9 @@ func NewMockedPrivValidator() bft.PrivValidator { } // NewDefaultGenesisConfig creates a default configuration for an in-memory node. -func NewDefaultGenesisConfig(chainid string) *bft.GenesisDoc { +func NewDefaultGenesisConfig(chainid string, chaintz string) *bft.GenesisDoc { + var tzParam Param + _ = tzParam.Parse("gno.land/r/sys/params.vm.chain_tz.string=" + chaintz) return &bft.GenesisDoc{ GenesisTime: time.Now(), ChainID: chainid, @@ -46,6 +48,9 @@ func NewDefaultGenesisConfig(chainid string) *bft.GenesisDoc { AppState: &GnoGenesisState{ Balances: []Balance{}, Txs: []TxWithMetadata{}, + Params: []Param{ + tzParam, + }, }, } } diff --git a/gnovm/stdlibs/time/context.go b/gnovm/stdlibs/time/context.go new file mode 100644 index 00000000000..01fa5aeaa01 --- /dev/null +++ b/gnovm/stdlibs/time/context.go @@ -0,0 +1,34 @@ +package time + +import ( + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" +) + +type ExecContext struct { + ChainTz string +} + +// GetContext returns the execution context. +// This is used to allow extending the exec context using interfaces, +// for instance when testing. +func (e ExecContext) GetExecContext() ExecContext { + return e +} + +var _ ExecContexter = ExecContext{} + +// ExecContexter is a type capable of returning the parent [ExecContext]. When +// using these standard libraries, m.Context should always implement this +// interface. This can be obtained by embedding [ExecContext]. +type ExecContexter interface { + GetExecContext() ExecContext +} + +// NOTE: In order to make this work by simply embedding ExecContext in another +// context (like TestExecContext), the method needs to be something other than +// the field name. + +// GetContext returns the context from the Gno machine. +func GetContext(m *gno.Machine) ExecContext { + return m.Context.(ExecContexter).GetExecContext() +} diff --git a/gnovm/stdlibs/time/timezoneinfo.gno b/gnovm/stdlibs/time/timezoneinfo.gno index 223946e6294..16468bfa82b 100644 --- a/gnovm/stdlibs/time/timezoneinfo.gno +++ b/gnovm/stdlibs/time/timezoneinfo.gno @@ -70,9 +70,12 @@ var UTC *Location = &utcLoc var utcLoc = Location{name: "UTC"} func init() { + chainTz := GetChainTz() timezoneChainParam, _ = LoadLocation("UTC") } +func GetChainTz() string // injected + func (l *Location) get() *Location { if l == nil { return &utcLoc diff --git a/gnovm/stdlibs/time/timezoneinfo.go b/gnovm/stdlibs/time/timezoneinfo.go new file mode 100644 index 00000000000..a2db8959312 --- /dev/null +++ b/gnovm/stdlibs/time/timezoneinfo.go @@ -0,0 +1,13 @@ +package time + +import ( + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" +) + +func X_GetChainTz(m *gno.Machine) string { + if m == nil || m.Context == nil { + return "UTC" + } + + return GetContext(m).ChainTz +} From e46c332382dbdce5011869ff1e9413e28906da2a Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Mon, 25 Nov 2024 15:27:46 +0100 Subject: [PATCH 06/15] feat: include chain tz in exec context of gno machine --- gnovm/stdlibs/std/context.go | 1 + gnovm/stdlibs/time/context.go | 34 ----------------------------- gnovm/stdlibs/time/timezoneinfo.gno | 2 +- gnovm/stdlibs/time/timezoneinfo.go | 5 +++-- 4 files changed, 5 insertions(+), 37 deletions(-) delete mode 100644 gnovm/stdlibs/time/context.go diff --git a/gnovm/stdlibs/std/context.go b/gnovm/stdlibs/std/context.go index a0dafe5dc44..7779897a63a 100644 --- a/gnovm/stdlibs/std/context.go +++ b/gnovm/stdlibs/std/context.go @@ -9,6 +9,7 @@ import ( type ExecContext struct { ChainID string + ChainTz string Height int64 Timestamp int64 // seconds TimestampNano int64 // nanoseconds, only used for testing. diff --git a/gnovm/stdlibs/time/context.go b/gnovm/stdlibs/time/context.go deleted file mode 100644 index 01fa5aeaa01..00000000000 --- a/gnovm/stdlibs/time/context.go +++ /dev/null @@ -1,34 +0,0 @@ -package time - -import ( - gno "github.com/gnolang/gno/gnovm/pkg/gnolang" -) - -type ExecContext struct { - ChainTz string -} - -// GetContext returns the execution context. -// This is used to allow extending the exec context using interfaces, -// for instance when testing. -func (e ExecContext) GetExecContext() ExecContext { - return e -} - -var _ ExecContexter = ExecContext{} - -// ExecContexter is a type capable of returning the parent [ExecContext]. When -// using these standard libraries, m.Context should always implement this -// interface. This can be obtained by embedding [ExecContext]. -type ExecContexter interface { - GetExecContext() ExecContext -} - -// NOTE: In order to make this work by simply embedding ExecContext in another -// context (like TestExecContext), the method needs to be something other than -// the field name. - -// GetContext returns the context from the Gno machine. -func GetContext(m *gno.Machine) ExecContext { - return m.Context.(ExecContexter).GetExecContext() -} diff --git a/gnovm/stdlibs/time/timezoneinfo.gno b/gnovm/stdlibs/time/timezoneinfo.gno index 16468bfa82b..24082c60178 100644 --- a/gnovm/stdlibs/time/timezoneinfo.gno +++ b/gnovm/stdlibs/time/timezoneinfo.gno @@ -71,7 +71,7 @@ var utcLoc = Location{name: "UTC"} func init() { chainTz := GetChainTz() - timezoneChainParam, _ = LoadLocation("UTC") + timezoneChainParam, _ = LoadLocation(chainTz) } func GetChainTz() string // injected diff --git a/gnovm/stdlibs/time/timezoneinfo.go b/gnovm/stdlibs/time/timezoneinfo.go index a2db8959312..1af436f12e4 100644 --- a/gnovm/stdlibs/time/timezoneinfo.go +++ b/gnovm/stdlibs/time/timezoneinfo.go @@ -2,12 +2,13 @@ package time import ( gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/gnovm/stdlibs/std" ) -func X_GetChainTz(m *gno.Machine) string { +func GetChainTz(m *gno.Machine) string { if m == nil || m.Context == nil { return "UTC" } - return GetContext(m).ChainTz + return std.GetContext(m).ChainTz } From 5b8aeec7d4ed24da40cf4b6c1b7d2bf13f08f610 Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Mon, 25 Nov 2024 15:31:47 +0100 Subject: [PATCH 07/15] feat: include a getter chain tz in stdlib --- gnovm/stdlibs/std/native.gno | 1 + gnovm/stdlibs/std/native.go | 4 ++++ gnovm/stdlibs/time/timezoneinfo.gno | 4 ++-- gnovm/stdlibs/time/timezoneinfo.go | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/gnovm/stdlibs/std/native.gno b/gnovm/stdlibs/std/native.gno index 5421e231de2..12b3da1c36f 100644 --- a/gnovm/stdlibs/std/native.gno +++ b/gnovm/stdlibs/std/native.gno @@ -11,6 +11,7 @@ func AssertOriginCall() // injected func IsOriginCall() bool // injected func GetChainID() string // injected +func GetChainTz() string // injected func GetHeight() int64 // injected func GetOrigSend() Coins { diff --git a/gnovm/stdlibs/std/native.go b/gnovm/stdlibs/std/native.go index 3fe5fbb9889..334d8ca1e14 100644 --- a/gnovm/stdlibs/std/native.go +++ b/gnovm/stdlibs/std/native.go @@ -27,6 +27,10 @@ func GetChainID(m *gno.Machine) string { return GetContext(m).ChainID } +func GetChainTz(m *gno.Machine) string { + return GetContext(m).ChainTz +} + func GetHeight(m *gno.Machine) int64 { return GetContext(m).Height } diff --git a/gnovm/stdlibs/time/timezoneinfo.gno b/gnovm/stdlibs/time/timezoneinfo.gno index 24082c60178..71235d7bdd7 100644 --- a/gnovm/stdlibs/time/timezoneinfo.gno +++ b/gnovm/stdlibs/time/timezoneinfo.gno @@ -70,11 +70,11 @@ var UTC *Location = &utcLoc var utcLoc = Location{name: "UTC"} func init() { - chainTz := GetChainTz() + chainTz := getChainTz() timezoneChainParam, _ = LoadLocation(chainTz) } -func GetChainTz() string // injected +func getChainTz() string // injected func (l *Location) get() *Location { if l == nil { diff --git a/gnovm/stdlibs/time/timezoneinfo.go b/gnovm/stdlibs/time/timezoneinfo.go index 1af436f12e4..6f1fe2613a1 100644 --- a/gnovm/stdlibs/time/timezoneinfo.go +++ b/gnovm/stdlibs/time/timezoneinfo.go @@ -5,7 +5,7 @@ import ( "github.com/gnolang/gno/gnovm/stdlibs/std" ) -func GetChainTz(m *gno.Machine) string { +func X_getChainTz(m *gno.Machine) string { if m == nil || m.Context == nil { return "UTC" } From 41c5f31ecf7ca9dceac8ad03263dbc9cf777166a Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Mon, 25 Nov 2024 15:41:23 +0100 Subject: [PATCH 08/15] feat: generate go native injection --- gnovm/stdlibs/generated.go | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index a2d82b0bc60..72a6aaf8ec2 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -468,6 +468,26 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, + { + "std", + "GetChainTz", + []gno.FieldTypeExpr{}, + []gno.FieldTypeExpr{ + {Name: gno.N("r0"), Type: gno.X("string")}, + }, + true, + func(m *gno.Machine) { + r0 := libs_std.GetChainTz( + m, + ) + + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r0).Elem(), + )) + }, + }, { "std", "GetHeight", @@ -912,6 +932,26 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, + { + "time", + "getChainTz", + []gno.FieldTypeExpr{}, + []gno.FieldTypeExpr{ + {Name: gno.N("r0"), Type: gno.X("string")}, + }, + true, + func(m *gno.Machine) { + r0 := libs_time.X_getChainTz( + m, + ) + + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r0).Elem(), + )) + }, + }, { "time", "loadFromEmbeddedTZData", From 67cf3eb020cd8c2f01bcd926a495d1e6ba4ea4ba Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Mon, 25 Nov 2024 15:41:50 +0100 Subject: [PATCH 09/15] feat: add function to retrive param from sys realm --- gno.land/pkg/sdk/vm/keeper.go | 4 ++++ gno.land/pkg/sdk/vm/params.go | 13 +++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 gno.land/pkg/sdk/vm/params.go diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 5fa2075b8f7..20e2cbee29c 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -237,6 +237,7 @@ func (vm *VMKeeper) checkNamespacePermission(ctx sdk.Context, creator crypto.Add if sysUsersPkg == "" { return nil } + chainTz := vm.getChainTzParam(ctx) store := vm.getGnoTransactionStore(ctx) @@ -263,6 +264,7 @@ func (vm *VMKeeper) checkNamespacePermission(ctx sdk.Context, creator crypto.Add pkgAddr := gno.DerivePkgAddr(pkgPath) msgCtx := stdlibs.ExecContext{ ChainID: ctx.ChainID(), + ChainTz: chainTz, Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), OrigCaller: creator.Bech32(), @@ -533,6 +535,7 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { gnostore := vm.getGnoTransactionStore(ctx) send := msg.Send memPkg := msg.Package + chainTz := vm.getChainTzParam(ctx) // coerce path to right one. // the path in the message must be "" or the following path. @@ -563,6 +566,7 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { // Parse and run the files, construct *PV. msgCtx := stdlibs.ExecContext{ ChainID: ctx.ChainID(), + ChainTz: chainTz, Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), Msg: msg, diff --git a/gno.land/pkg/sdk/vm/params.go b/gno.land/pkg/sdk/vm/params.go new file mode 100644 index 00000000000..2625794817f --- /dev/null +++ b/gno.land/pkg/sdk/vm/params.go @@ -0,0 +1,13 @@ +package vm + +import "github.com/gnolang/gno/tm2/pkg/sdk" + +const ( + chainTzParamPath = "gno.land/r/sys/params.chain.tz.string" +) + +func (vm *VMKeeper) getChainTzParam(ctx sdk.Context) string { + chainTz := "UTC" // default + vm.prmk.GetString(ctx, chainTzParamPath, &chainTz) + return chainTz +} From a0254514f2687bd6847960ededc8280f2ac349a0 Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Mon, 25 Nov 2024 16:52:48 +0100 Subject: [PATCH 10/15] feat: wip --- contribs/gnodev/cmd/gnodev/main.go | 2 +- examples/gno.land/r/demo/timetest/test.gno | 10 ++++------ gno.land/pkg/sdk/vm/params.go | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index 962fc4bdcf1..03187d5760b 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -303,7 +303,7 @@ func execDev(cfg *devCfg, args []string, io commands.IO) (err error) { } defer devNode.Close() - nodeLogger.Info("node started", "lisn", devNode.GetRemoteAddress(), "chainID", cfg.chainId) + nodeLogger.Info("node started", "lisn", devNode.GetRemoteAddress(), "chainID", cfg.chainId, "chainTz", cfg.chainTz) // Create server mux := http.NewServeMux() diff --git a/examples/gno.land/r/demo/timetest/test.gno b/examples/gno.land/r/demo/timetest/test.gno index ba23e803bec..561d728c374 100644 --- a/examples/gno.land/r/demo/timetest/test.gno +++ b/examples/gno.land/r/demo/timetest/test.gno @@ -1,15 +1,13 @@ package timetest import ( + "std" "time" ) func Render(path string) string { - location, _ := time.LoadLocation("America/New_York") // Replace with your desired timezone - // Create a specific time in that timezone - year, month, day := 2024, time.November, 25 - hour, minute, second := 15, 30, 0 - nyTime := time.Date(year, month, day, hour, minute, second, 0, location) + time2 := time.Now() + tz := std.GetChainID() - return nyTime.String() + return time2.String() + " | " + tz } diff --git a/gno.land/pkg/sdk/vm/params.go b/gno.land/pkg/sdk/vm/params.go index 2625794817f..5e500ad0390 100644 --- a/gno.land/pkg/sdk/vm/params.go +++ b/gno.land/pkg/sdk/vm/params.go @@ -3,7 +3,7 @@ package vm import "github.com/gnolang/gno/tm2/pkg/sdk" const ( - chainTzParamPath = "gno.land/r/sys/params.chain.tz.string" + chainTzParamPath = "gno.land/r/sys/params.chain_tz.string" ) func (vm *VMKeeper) getChainTzParam(ctx sdk.Context) string { From 3e0601ec8223151d8f55f1f3320ff90f8594bcac Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Tue, 26 Nov 2024 18:19:45 +0100 Subject: [PATCH 11/15] feat: wip --- contribs/gnodev/cmd/gnodev/main.go | 2 +- contribs/gnodev/pkg/dev/node.go | 4 ++-- examples/gno.land/r/demo/timetest/test.gno | 2 +- gno.land/pkg/gnoland/node_inmemory.go | 1 + gno.land/pkg/sdk/vm/keeper.go | 9 +++++++++ gno.land/pkg/sdk/vm/params.go | 6 ++++-- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/contribs/gnodev/cmd/gnodev/main.go b/contribs/gnodev/cmd/gnodev/main.go index 03187d5760b..962fc4bdcf1 100644 --- a/contribs/gnodev/cmd/gnodev/main.go +++ b/contribs/gnodev/cmd/gnodev/main.go @@ -303,7 +303,7 @@ func execDev(cfg *devCfg, args []string, io commands.IO) (err error) { } defer devNode.Close() - nodeLogger.Info("node started", "lisn", devNode.GetRemoteAddress(), "chainID", cfg.chainId, "chainTz", cfg.chainTz) + nodeLogger.Info("node started", "lisn", devNode.GetRemoteAddress(), "chainID", cfg.chainId) // Create server mux := http.NewServeMux() diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 28927f70778..52939adcc80 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -45,7 +45,7 @@ type NodeConfig struct { ChainTz string } -func DefaultNodeConfig(rootdir string, timezone string) *NodeConfig { +func DefaultNodeConfig(rootdir string, tz string) *NodeConfig { tmc := gnoland.NewDefaultTMConfig(rootdir) tmc.Consensus.SkipTimeoutCommit = false // avoid time drifting, see issue #1507 tmc.Consensus.WALDisabled = true @@ -65,7 +65,7 @@ func DefaultNodeConfig(rootdir string, timezone string) *NodeConfig { DefaultDeployer: defaultDeployer, BalancesList: balances, ChainID: tmc.ChainID(), - ChainTz: timezone, + ChainTz: tz, TMConfig: tmc, SkipFailingGenesisTxs: true, MaxGasPerBlock: 10_000_000_000, diff --git a/examples/gno.land/r/demo/timetest/test.gno b/examples/gno.land/r/demo/timetest/test.gno index 561d728c374..e2620be5912 100644 --- a/examples/gno.land/r/demo/timetest/test.gno +++ b/examples/gno.land/r/demo/timetest/test.gno @@ -7,7 +7,7 @@ import ( func Render(path string) string { time2 := time.Now() - tz := std.GetChainID() + tz := std.GetChainTz() return time2.String() + " | " + tz } diff --git a/gno.land/pkg/gnoland/node_inmemory.go b/gno.land/pkg/gnoland/node_inmemory.go index 7a5f06f59fe..db286feb519 100644 --- a/gno.land/pkg/gnoland/node_inmemory.go +++ b/gno.land/pkg/gnoland/node_inmemory.go @@ -39,6 +39,7 @@ func NewMockedPrivValidator() bft.PrivValidator { func NewDefaultGenesisConfig(chainid string, chaintz string) *bft.GenesisDoc { var tzParam Param _ = tzParam.Parse("gno.land/r/sys/params.vm.chain_tz.string=" + chaintz) + fmt.Println("tzParam", tzParam) return &bft.GenesisDoc{ GenesisTime: time.Now(), ChainID: chainid, diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 20e2cbee29c..35cd847cd32 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -322,6 +322,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { memPkg := msg.Package deposit := msg.Deposit gnostore := vm.getGnoTransactionStore(ctx) + chainTz := vm.getChainTzParam(ctx) // Validate arguments. if creator.IsZero() { @@ -365,6 +366,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { // Parse and run the files, construct *PV. msgCtx := stdlibs.ExecContext{ ChainID: ctx.ChainID(), + ChainTz: chainTz, Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), Msg: msg, @@ -428,6 +430,8 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { mpn := gno.NewPackageNode("main", "main", nil) mpn.Define("pkg", gno.TypedValue{T: &gno.PackageType{}, V: pv}) mpv := mpn.NewPackage() + chainTz := vm.getChainTzParam(ctx) + // Parse expression. argslist := "" for i := range msg.Args { @@ -466,6 +470,7 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { // could it be safely partially memoized? msgCtx := stdlibs.ExecContext{ ChainID: ctx.ChainID(), + ChainTz: chainTz, Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), Msg: msg, @@ -716,6 +721,7 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res alloc := gno.NewAllocator(maxAllocQuery) gnostore := vm.newGnoTransactionStore(ctx) // throwaway (never committed) pkgAddr := gno.DerivePkgAddr(pkgPath) + chainTz := vm.getChainTzParam(ctx) // Get Package. pv := gnostore.GetPackage(pkgPath, false) if pv == nil { @@ -731,6 +737,7 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res // Construct new machine. msgCtx := stdlibs.ExecContext{ ChainID: ctx.ChainID(), + ChainTz: chainTz, Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), // Msg: msg, @@ -783,6 +790,7 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string alloc := gno.NewAllocator(maxAllocQuery) gnostore := vm.newGnoTransactionStore(ctx) // throwaway (never committed) pkgAddr := gno.DerivePkgAddr(pkgPath) + chainTz := vm.getChainTzParam(ctx) // Get Package. pv := gnostore.GetPackage(pkgPath, false) if pv == nil { @@ -798,6 +806,7 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string // Construct new machine. msgCtx := stdlibs.ExecContext{ ChainID: ctx.ChainID(), + ChainTz: chainTz, Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), // Msg: msg, diff --git a/gno.land/pkg/sdk/vm/params.go b/gno.land/pkg/sdk/vm/params.go index 5e500ad0390..23efb2b13fb 100644 --- a/gno.land/pkg/sdk/vm/params.go +++ b/gno.land/pkg/sdk/vm/params.go @@ -1,9 +1,11 @@ package vm -import "github.com/gnolang/gno/tm2/pkg/sdk" +import ( + "github.com/gnolang/gno/tm2/pkg/sdk" +) const ( - chainTzParamPath = "gno.land/r/sys/params.chain_tz.string" + chainTzParamPath = "gno.land/r/sys/params.vm.chain_tz.string" ) func (vm *VMKeeper) getChainTzParam(ctx sdk.Context) string { From 9b2bf1f6e353e283ee6cddcb33af1938203e8833 Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Tue, 26 Nov 2024 19:12:10 +0100 Subject: [PATCH 12/15] test: add unit test about tz as a chain param --- gnovm/tests/file.go | 1 + gnovm/tests/files/std5_stdlibs.gno | 4 ++-- gnovm/tests/files/std8_stdlibs.gno | 4 ++-- gnovm/tests/files/time_natbind1_stdlib.gno | 16 ++++++++++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 gnovm/tests/files/time_natbind1_stdlib.gno diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go index 98dbab6ac0e..26b174e1aa4 100644 --- a/gnovm/tests/file.go +++ b/gnovm/tests/file.go @@ -61,6 +61,7 @@ func TestContext(pkgPath string, send std.Coins) *teststd.TestExecContext { params := newTestParams() ctx := stdlibs.ExecContext{ ChainID: "dev", + ChainTz: "Etc/UTC", Height: 123, Timestamp: 1234567890, Msg: nil, diff --git a/gnovm/tests/files/std5_stdlibs.gno b/gnovm/tests/files/std5_stdlibs.gno index 4afa09da8d3..061df0d6ac0 100644 --- a/gnovm/tests/files/std5_stdlibs.gno +++ b/gnovm/tests/files/std5_stdlibs.gno @@ -13,10 +13,10 @@ func main() { // Stacktrace: // panic: frame not found -// callerAt(n) +// callerAt(n) // gonative:std.callerAt // std.GetCallerAt(2) -// std/native.gno:44 +// std/native.gno:45 // main() // main/files/std5_stdlibs.gno:10 diff --git a/gnovm/tests/files/std8_stdlibs.gno b/gnovm/tests/files/std8_stdlibs.gno index ab5e15bd618..b59a7a59a84 100644 --- a/gnovm/tests/files/std8_stdlibs.gno +++ b/gnovm/tests/files/std8_stdlibs.gno @@ -23,10 +23,10 @@ func main() { // Stacktrace: // panic: frame not found -// callerAt(n) +// callerAt(n) // gonative:std.callerAt // std.GetCallerAt(4) -// std/native.gno:44 +// std/native.gno:45 // fn() // main/files/std8_stdlibs.gno:16 // testutils.WrapCall(inner) diff --git a/gnovm/tests/files/time_natbind1_stdlib.gno b/gnovm/tests/files/time_natbind1_stdlib.gno new file mode 100644 index 00000000000..6385ec31d58 --- /dev/null +++ b/gnovm/tests/files/time_natbind1_stdlib.gno @@ -0,0 +1,16 @@ +// PKGPATH: gno.land/r/test +package test + +import ( + "std" +) + +func main() { + println(std.GetChainTz()) +} + +// Output: +// Etc/UTC + +// Realm: +// switchrealm["gno.land/r/test"] From 28578640ce450783da76bcfb2f1a5f221dbcec0e Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Tue, 26 Nov 2024 19:31:41 +0100 Subject: [PATCH 13/15] test: add unit test about tz as a chain param --- .../{time_natbind1_stdlib.gno => zrealm_natbind1_stdlibs.gno} | 3 --- 1 file changed, 3 deletions(-) rename gnovm/tests/files/{time_natbind1_stdlib.gno => zrealm_natbind1_stdlibs.gno} (73%) diff --git a/gnovm/tests/files/time_natbind1_stdlib.gno b/gnovm/tests/files/zrealm_natbind1_stdlibs.gno similarity index 73% rename from gnovm/tests/files/time_natbind1_stdlib.gno rename to gnovm/tests/files/zrealm_natbind1_stdlibs.gno index 6385ec31d58..ce8585b0990 100644 --- a/gnovm/tests/files/time_natbind1_stdlib.gno +++ b/gnovm/tests/files/zrealm_natbind1_stdlibs.gno @@ -11,6 +11,3 @@ func main() { // Output: // Etc/UTC - -// Realm: -// switchrealm["gno.land/r/test"] From cc2bbe15cbca4728cb85504e566ff298a414711a Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Wed, 27 Nov 2024 11:18:25 +0100 Subject: [PATCH 14/15] test: fix add UTC default on creating testing node config --- contribs/gnodev/pkg/dev/node_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/gnodev/pkg/dev/node_test.go b/contribs/gnodev/pkg/dev/node_test.go index 4a32a1952c9..954404bca3b 100644 --- a/contribs/gnodev/pkg/dev/node_test.go +++ b/contribs/gnodev/pkg/dev/node_test.go @@ -475,7 +475,7 @@ func generateTestingPackage(t *testing.T, nameFile ...string) PackagePath { } func createDefaultTestingNodeConfig(pkgslist ...PackagePath) *NodeConfig { - cfg := DefaultNodeConfig(gnoenv.RootDir()) + cfg := DefaultNodeConfig(gnoenv.RootDir(), "UTC") cfg.PackagesPathList = pkgslist return cfg } From c3ecc9706d7a0f0db509af2d16639a7cd2f77f1c Mon Sep 17 00:00:00 2001 From: MikaelVallenet Date: Thu, 28 Nov 2024 20:05:07 +0100 Subject: [PATCH 15/15] feat: add tz param in gnodev genesis --- contribs/gnodev/pkg/dev/node.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 4937d38c17b..d083e167849 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -123,10 +123,16 @@ func NewDevNode(ctx context.Context, cfg *NodeConfig) (*Node, error) { currentStateIndex: len(cfg.InitialTxs), } + var tzParam gnoland.Param + _ = tzParam.Parse("gno.land/r/sys/params.vm.chain_tz.string=" + cfg.ChainTz) + // generate genesis state genesis := gnoland.GnoGenesisState{ Balances: cfg.BalancesList, Txs: append(pkgsTxs, cfg.InitialTxs...), + Params: []gnoland.Param{ + tzParam, + }, } if err := devnode.rebuildNode(ctx, genesis); err != nil {