Examining Gno Core Stack

Differences between the Cosmos SDK and the Gnolang SDK

24 July 2023

Manfred Touron

VP Eng., Gno.land

What is Gno?

2

What is Gnolang?

3

Increment a counter in Gno

package demo

var x int

func Incr() {
    x += 1
}
4

Increment a counter in Cosmos SDK

// cli/cli.go, msg.go, handler.go, >keeper.go<
//  * keeper/handler pattern, "ctx", binary codec, determinism
import (
    "github.com/gnolang/gno/pkgs/sdk"
)

type Keeper struct{ storeKey storetypes.StoreKey } // expected to be prefix store.

func (k *Keeper) Incr(sdk.Context) {
    store := ctx.KVStore(k.storeKey)
    bz := store.Get("x")
    if bz == nil {
        panic("XXX")
    }
    x, err := strconv.Atoi(bz)
    if err != nil {
        panic("XXX")
    }
    x += 1 // all we wanted
    bz = strconv.Itoa(x)
    store.Set("x", bz)
}
5

Increment a counter in Cosmwasm/Rust

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::Increment {} => increment(deps),
    }
}

pub fn increment(deps: DepsMut) -> Result<Response, ContractError> {
    STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
        state.count += 1;
        Ok(state)
    })?;

    Ok(Response::new().add_attribute("method", "increment"))
}
6

Increment a counter in a Go app

package counter

import (
    "io/ioutil"
    "strconv"
)

func IncrementCounter() (int, error) {
    counterBytes, err := ioutil.ReadFile("counter.txt")
    if err != nil {
        return 0, err
    }
    counter, err := strconv.Atoi(string(counterBytes))
    if err != nil {
        return 0, err
    }
    counter += 1
    err = ioutil.WriteFile("counter.txt", []byte(strconv.Itoa(counter)), 0644)
    if err != nil {
        return 0, err
    }
    return counter, nil
}
7

What is Gno.land?

8

Gno.land interop

9

IBC2/GNO/x

10

Gno clients vs Gno SDK

11

Gno SDK

12

Gno SDK _potential_ API

// simple chicken-egg problem resolving
if sdk.RealmExists("gno.land/r/demo/foo") {}

// load the realm as a Go object
r := sdk.GetRealm("gno.land/r/demo/foo")

// retrieve the state of a variable without executing the contract, cheap
v, _ := r.GetState("things")

// similar to calling the contract from a transaction, more dynamic but expensive
ret, _ := r.Call("HasAccess", ...args)

// appends an event to contract's incoming queue, consumed later with `evt := <-std.Recv()`
r.Send(abci.Event{...})

// reads events from contract's outgoing queue
e := r.Recv()

// interact with realms' bankers methods
banker := r.Banker.XXX

// subscribe to specific events to trigger actions
sdk.Subscribe(filterFn, callbackFn)
13

GnoSDK example: chain configuration

// r/system/config: contributors DAO votes for chain configuration changes (runtime limits, etc)
func Propose() {}
func Apply{} 

// baseapp: the baseapp subscribes to changes happening in the contract
sdk.Subscribe(configChangedFilterFn, applyConfigChange)

// baseapp: to fetch the expected configuration
sdk.GetRealm("r/system/config").GetState("chainCfg")

// baseapp: during abci.EndBlocker
bft.XXX(opts...)
14

GnoSDK example: proof-of-contribution

// r/system/config: contributors DAO votes for chain configuration changes (runtime limits, etc)
func Propose() {}
func Apply() {}

// baseapp: the baseapp subscribes to changes happening in the contract
sdk.Subscribe(valsetChangedFilterFn, applyValsetFn)

// baseapp: to fetch the expected configuration
updates := sdk.GetRealm("r/system/validators").GetState("updates")

// baseapp: during abci.EndBlocker
bft.ValidateValidatorUpdates(updates)
15

GnoSDK example: chain fees distribution

// baseapp: chain fees (gas) are sent to the rewards' banker.
gasDestination := sdk.GetRealm("r/system/rewards").Banker().Addr()

// r/system/rewards: Distribution logic implemented in the contract,
// querying other contracts, applying rules.
import "gno.land/r/system/validators"
import "gno.land/r/gnoland/dao"
func Distribute() {
    // Split rewards among recipients.
}

// Baseapp: Relevant chain events (double sig, etc.) can be sent to the contract.
r.GetRealm("r/system/rewards").Send(abci.Event{})
16

GnoSDK example: namespace support for package paths

// baseapp: hook when `AddPkg` is called in a transaction
sdk.Subscribe(filterFn, callbackFn)

// baseapp: if realm does not exist, skip validation
if !sdk.HasRealm("r/system/names") {
    return true
}

// baseapp: returns list of available personal and team namespaces (manfred, gnocore, teamfoo)
sdk.GetRealm("r/system/names").Call("GetGroups", "manfred")

// baseapp: if namespace matches
if matches {
    return true
}
17

What is Game of realms?

 
     ______                              ____   ____             __
    / ____/___ _____ ___  ___     ____  / __/  / __ \___  ____ _/ /___ ___  _____
   / / __/ __ `/ __ `__ \/ _ \   / __ \/ /_   / /_/ / _ \/ __ `/ / __ `__ \/ ___/
  / /_/ / /_/ / / / / / /  __/  / /_/ / __/  / _, _/  __/ /_/ / / / / / / (__  )
  \____/\__,_/_/ /_/ /_/\___/   \____/_/    /_/ |_|\___/\__,_/_/_/ /_/ /_/____/
 
 
18

Action Items

19

Thank you

Manfred Touron

VP Eng., Gno.land

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)