Skip to content

gnovm: random global variable pary #4182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
paulogarithm opened this issue Apr 18, 2025 · 3 comments
Open

gnovm: random global variable pary #4182

paulogarithm opened this issue Apr 18, 2025 · 3 comments

Comments

@paulogarithm
Copy link

Description

related to #4039, this describes a deeper issue on the gnovm.

problematic : how do we manage random global variable to store the seed ?

to make random, we need a seed that will define the overall state of the randomness, with some pseudo random methods to edit the number based on the seed, with chaotic-like maths evaluations.

but here, in gno, we cant store anything in a stdlib, because it (kind of) act like a pure package, so how to counter that ?

so as thehowl said here, we must get rid of the global variable, but how do we store the seed ?

Golang singleton

so one way would be to create a function to get the seed as a global variable internal to gno, so the global object is coded in the gno software (so coded in golang) and the function to get the object is called in gno

func GetGlobalSeed() *Rand

so instead of using this globalRand variable, we could actually call GetGlobalSeed() and this function will return the Rand object from gno software directly, and not stored in a gno file.

Use a pseudo realm package

since pure packages cant store variables, why not using packages that behaves like the r/ packages (that can actually hold data) and require it in the rand

import "r/rand/global"

global.Random.hi = x

so i know we cant directly use gno.land/r packages in stdlibs, since we have to differenciate gno and gno.land, but its just an idea

Give up

just remove the random, since some people thinks its useless in gno, because it leads to less predicatable behaviours.

Do you have any other ideas ?

@notJoon
Copy link
Member

notJoon commented Apr 23, 2025

I wrote a txtar test based on the reproduction method suggested in the previous issue, and this time it was successful. It seems that it was affected by the addition of the cross-realm feature (maybe #4060?). Below are the test and execution method.

cd gno.land/pkg/integration
go test -v . -run Testdata/rand

txtar script

// PATH: gno.land/pkg/integration/testdata/rand.txtar
loadpkg gno.land/p/demo/ufmt

gnoland start

gnokey maketx addpkg -pkgdir $WORK/mygenerator -pkgpath gno.land/p/demo/mygenerator -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test test1
stdout 'OK!'

gnokey maketx addpkg -pkgdir $WORK/showgeneration -pkgpath gno.land/r/demo/showgeneration -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test test1
stdout 'OK!'

# call Render function
gnokey maketx call -pkgpath gno.land/r/demo/showgeneration -func Render -args "" -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1

-- mygenerator/gno.mod --
module gno.land/p/demo/mygenerator

-- mygenerator/mygenerator.gno --
package mygenerator

import (
    "math/rand"
)

func MySuperGenerator() int {
    return rand.Int()
}

-- showgeneration/gno.mod --
module gno.land/r/demo/showgeneration

-- showgeneration/showgeneration.gno --
package showgeneration

import (
    "strconv"
    "gno.land/p/demo/mygenerator"
)

func Render(_ string) string {
    crossing()
    return strconv.Itoa(mygenerator.MySuperGenerator())
}

Result

=== RUN   TestTestdata
=== PAUSE TestTestdata
=== CONT  TestTestdata
=== RUN   TestTestdata/rand
=== PAUSE TestTestdata/rand
=== CONT  TestTestdata/rand
    testscript.go:584: WORK=$WORK
        PATH=/usr/local/go/bin:/usr/local/go/bin:/opt/homebrew/opt/postgresql@17/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/usr/local/go/bin:/Users/notJoon/.opam/default/bin:/Users/notJoon/go/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/Users/notJoon/.cargo/bin
        GOTRACEBACK=system
        HOME=/no-home
        TMPDIR=$WORK/.tmp
        devnull=/dev/null
        /=/
        :=:
        $=$
        exe=
        UPDATE_SCRIPTS=false
        TESTWORK=false
        test1_user_seed=source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast
        test1_user_addr=g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5
        GNO_DBDIR=/var/folders/sb/8c04v17n44zd7x__zvgs2vz00000gn/T/TestTestdata1700366533/002
        SID=eb51f0f
        GNOROOT=/Users/notJoon/gno-core
        GNOHOME=/var/folders/sb/8c04v17n44zd7x__zvgs2vz00000gn/T/TestTestdata1700366533/001/gno
        
        > loadpkg gno.land/p/demo/ufmt
        "gno.land/p/demo/ufmt" package was added to genesis
        > gnoland start
        time=2025-04-23T17:25:44.663+09:00 level=ERROR msg="Error on catchup replay. Proceeding to start ConsensusState anyway" module=consensus err="WAL should not contain #ENDHEIGHT 1"
        READY:tcp://127.0.0.1:64843
        ["test1"] account number: 41
        ["test1"] account sequence: 41
        [stdout]
        node started successfully
        
        > gnokey maketx addpkg -pkgdir $WORK/mygenerator -pkgpath gno.land/p/demo/mygenerator -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test test1
        [stdout]
        
        OK!
        GAS WANTED: 100000000
        GAS USED:   3908489
        HEIGHT:     29
        EVENTS:     []
        INFO:       
        TX HASH:    yJwQVB4ksGfPLmuiscvACL8vbx5oHwUZI0NQr71ytXk=
        
        [stderr]
        Enter password.
        
        > stdout 'OK!'
        > gnokey maketx addpkg -pkgdir $WORK/showgeneration -pkgpath gno.land/r/demo/showgeneration -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test test1
        [stdout]
        
        OK!
        GAS WANTED: 100000000
        GAS USED:   7330651
        HEIGHT:     50
        EVENTS:     []
        INFO:       
        TX HASH:    SQdcK9lrrc34hxHotKwiBN5UWkL9T0qMdjX4YHOQ5fg=
        
        [stderr]
        Enter password.
        
        > stdout 'OK!'
        # call Render function (0.648s)
        > gnokey maketx call -pkgpath gno.land/r/demo/showgeneration -func Render -args "" -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1
        [stdout]
        ("4107282207882862730" string)
        
        
        OK!
        GAS WANTED: 4000000
        GAS USED:   3022637
        HEIGHT:     73
        EVENTS:     []
        INFO:       
        TX HASH:    h4mPLKKcvRkzUeM9mxqhSfGtx/oObtxyGj6Fdgxs6uk=
        
        [stderr]
        Enter password.
        
        PASS
        
--- PASS: TestTestdata (0.05s)
    --- PASS: TestTestdata/rand (5.84s)
PASS
ok      github.com/gnolang/gno/gno.land/pkg/integration 8.075s

As shown in the test results, when calling the Render function with gnokey, you can see that the value ("4107282207882862730" string) is output, which is the expected behavior.

Still we need to do more verification, but it seems like we don't need to modify or delete the rand functionality anymore. What do you think?

@paulogarithm
Copy link
Author

@notJoon so basically you used the native golang random ? As you mentioned in the previous issue ? That's right ?
If it's that I think it's a great idea imo, but we can discuss it all together to see what people thinks

@thehowl
Copy link
Member

thehowl commented May 20, 2025

The math/rand package should provide the interfaces and some basic algorithms from Go's stdlib, but it should not be used to centralize RNG.

I think we should have 1. a realm that provides a global Rand + top-level methods from math/rand, so that users can use it to get simple random numbers 2. other good VRF's that can be used as Source interfaces.

I think most can get away with creating a gRandom in their realm, with a simple rand.NewPCG source.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Triage
Development

No branches or pull requests

3 participants