From 7f9912106fdd6b03a2096af6d250357cbc16ada8 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:12:14 +0200 Subject: [PATCH 01/12] feat: refactor govdao execution mechanism and examples Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../gno.land/r/gov/dao/prop1_filetest.gno | 85 +++++++++++++++++++ examples/gno.land/r/gov/integration/gno.mod | 3 - .../r/gov/integration/integration.gno | 4 - .../gno.land/r/gov/integration/z_filetest.gno | 45 ---------- .../gno.land/r/gov/proposals/prop1/gno.mod | 6 -- .../gno.land/r/gov/proposals/prop1/prop1.gno | 36 -------- .../gno.land/r/sys/validators/validators.gno | 13 +++ 7 files changed, 98 insertions(+), 94 deletions(-) create mode 100644 examples/gno.land/r/gov/dao/prop1_filetest.gno delete mode 100644 examples/gno.land/r/gov/integration/gno.mod delete mode 100644 examples/gno.land/r/gov/integration/integration.gno delete mode 100644 examples/gno.land/r/gov/integration/z_filetest.gno delete mode 100644 examples/gno.land/r/gov/proposals/prop1/gno.mod delete mode 100644 examples/gno.land/r/gov/proposals/prop1/prop1.gno diff --git a/examples/gno.land/r/gov/dao/prop1_filetest.gno b/examples/gno.land/r/gov/dao/prop1_filetest.gno new file mode 100644 index 00000000000..7072618a4a7 --- /dev/null +++ b/examples/gno.land/r/gov/dao/prop1_filetest.gno @@ -0,0 +1,85 @@ +// Please note that this package is intended for demonstration purposes only. +// You could execute this code (the init part) by running a `maketx run` command +// or by uploading a similar package to a personal namespace. +// +// For the specific case of validators, a `r/gnoland/valopers` will be used to +// organize the lifecycle of validators (register, etc), and this more complex +// contract will be responsible to generate proposals. +package main + +import ( + "std" + + govdao "gno.land/r/gov/dao" + "gno.land/r/sys/validators" +) + +func init() { + // Create the validators change proposal. + changesFn := func() []validators.Change { + return []validators.Change{ + // add a new validator. + {Address: std.Address("g12345678"), Power: 1}, + // remove an existing validator. + {Address: std.Address("g000000000"), Power: 0}, + } + } + + // Wraps changesFn to emit a certified event only if executed from a + // complete governance proposal process. + executor := validators.NewPropExecutor(changesFn) + + // Create a proposal. + // XXX: payment + comment := "manual valset changes proposal example" + govdao.Propose(comment, executor) +} + +func main() { + println("--") + println(govdao.Render("")) + println("--") + println(govdao.Render("1")) + println("--") + govdao.VoteOnProposal(1, "YES") + println("--") + println(govdao.Render("1")) + println("--") + println(validators.Render("")) + println("--") + govdao.ExecuteProposal(1) + println("--") + println(govdao.Render("1")) + println("--") + println(validators.Render("")) +} + +// Output: +// -- +// - [/r/gov/dao:0](0) - manual valset changes proposal example (by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) +// -- +// # Prop#0 +// +// manual valset changes proposal example +// Status: active +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// -- +// -- +// # Prop#0 +// +// manual valset changes proposal example +// Status: accepted +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// -- +// No valset changes to apply. +// -- +// -- +// # Prop#0 +// +// manual valset changes proposal example +// Status: success +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// -- +// Valset changes to apply: +// - g12345678 (1) +// - g000000000 (0) diff --git a/examples/gno.land/r/gov/integration/gno.mod b/examples/gno.land/r/gov/integration/gno.mod deleted file mode 100644 index f584f375133..00000000000 --- a/examples/gno.land/r/gov/integration/gno.mod +++ /dev/null @@ -1,3 +0,0 @@ -// Draft - -module integration diff --git a/examples/gno.land/r/gov/integration/integration.gno b/examples/gno.land/r/gov/integration/integration.gno deleted file mode 100644 index 5b47b3dec83..00000000000 --- a/examples/gno.land/r/gov/integration/integration.gno +++ /dev/null @@ -1,4 +0,0 @@ -// Package integration tests the govdao ecosystem from an external perspective. -// It aims to confirm that the system can remain static while supporting -// additional DAO use cases over time. -package integration diff --git a/examples/gno.land/r/gov/integration/z_filetest.gno b/examples/gno.land/r/gov/integration/z_filetest.gno deleted file mode 100644 index a85588e4f11..00000000000 --- a/examples/gno.land/r/gov/integration/z_filetest.gno +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - govdao "gno.land/r/gov/dao" - _ "gno.land/r/gov/proposals/prop1" -) - -func main() { - println("--") - println(govdao.Render("")) - println("--") - println(govdao.Render("1")) - println("--") - govdao.VoteOnProposal(1, "YES") - println("--") - println(govdao.Render("1")) - println("--") - govdao.ExecuteProposal(1) - println("--") - println(govdao.Render("1")) -} - -// Output: -// -- -// - [/r/gov/dao:0](0) - manual valset changes proposal example (by g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3) -// -- -// # Prop#0 -// -// manual valset changes proposal example -// Status: active -// Author: g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3 -// -- -// -- -// # Prop#0 -// -// manual valset changes proposal example -// Status: accepted -// Author: g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3 -// -- -// -- -// # Prop#0 -// -// manual valset changes proposal example -// Status: success -// Author: g1tk0fscr3p5g8hnhxq6v93jxcpm5g3cstlxfxa3 diff --git a/examples/gno.land/r/gov/proposals/prop1/gno.mod b/examples/gno.land/r/gov/proposals/prop1/gno.mod deleted file mode 100644 index 97faf2aff27..00000000000 --- a/examples/gno.land/r/gov/proposals/prop1/gno.mod +++ /dev/null @@ -1,6 +0,0 @@ -module gno.land/r/gov/proposals/prop1 - -require ( - gno.land/r/gov/dao v0.0.0-latest - gno.land/r/sys/validators v0.0.0-latest -) diff --git a/examples/gno.land/r/gov/proposals/prop1/prop1.gno b/examples/gno.land/r/gov/proposals/prop1/prop1.gno deleted file mode 100644 index 68cd9d60bfa..00000000000 --- a/examples/gno.land/r/gov/proposals/prop1/prop1.gno +++ /dev/null @@ -1,36 +0,0 @@ -// Package prop1 is an example of proposal creation using a contract. -// -// Please note that this package is intended for demonstration purposes only. -// You could execute this code by running a `maketx run` command or by uploading -// a similar package to a personal namespace. -// -// For the specific case of validators, a `r/gnoland/valopers` will be used to -// organize the lifecycle of validators (register, etc), and this more complex -// contract will be responsible to generate proposals. -package prop1 - -import ( - "std" - - govdao "gno.land/r/gov/dao" - "gno.land/r/sys/validators" -) - -func init() { - // Create the validators change proposal. - changesFn := func() []validators.Change { - return []validators.Change{ - {Address: std.Address("g12345678"), Power: 1}, // add a new validator - {Address: std.Address("g000000000"), Power: 0}, // remove an existing validator - } - } - - // Wraps changesFn to emit a certified event only if executed from a - // complete governance proposal process. - executor := validators.NewPropExecutor(changesFn) - - // Create a proposal. - // XXX: payment - comment := "manual valset changes proposal example" - govdao.Propose(comment, executor) -} diff --git a/examples/gno.land/r/sys/validators/validators.gno b/examples/gno.land/r/sys/validators/validators.gno index 5fb08ebbfc7..669b688727a 100644 --- a/examples/gno.land/r/sys/validators/validators.gno +++ b/examples/gno.land/r/sys/validators/validators.gno @@ -3,6 +3,7 @@ package validators import ( "std" + "strconv" "gno.land/p/gov/proposal" ) @@ -45,3 +46,15 @@ func getAndResetChanges() []Change { unappliedChanges = []Change{} return cpy } + +func Render(_ string) string { + if len(unappliedChanges) == 0 { + return "No valset changes to apply." + } + + output := "Valset changes to apply:\n" + for _, change := range unappliedChanges { + output += "- " + string(change.Address) + " (" + strconv.Itoa(change.Power) + ")\n" + } + return output +} From ce00e2e21a13bf5aedbc65835f50b243fc4784e0 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:37:48 +0200 Subject: [PATCH 02/12] feat: new pattern for govdao Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../gno.land/r/gov/dao/prop2_filetest.gno | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 examples/gno.land/r/gov/dao/prop2_filetest.gno diff --git a/examples/gno.land/r/gov/dao/prop2_filetest.gno b/examples/gno.land/r/gov/dao/prop2_filetest.gno new file mode 100644 index 00000000000..794a4c7c396 --- /dev/null +++ b/examples/gno.land/r/gov/dao/prop2_filetest.gno @@ -0,0 +1,81 @@ +package main + +import ( + "std" + "time" + + "gno.land/p/gov/proposal" + gnoblog "gno.land/r/gnoland/blog" + govdao "gno.land/r/gov/dao" +) + +func init() { + executor := proposal.NewExecutor(func() error { + gnoblog.ModAddPost( + "hello-from-govdao", // slug + "Hello from GovDAO!", // title + "This post was published by a GovDAO proposal.", // body + time.Now().String(), // publidation date + "moul", // authors + "govdao,example", // tags + ) + return nil + }) + + // Create a proposal. + // XXX: payment + comment := "post a new blogpost about govdao" + govdao.Propose(comment, executor) +} + +func main() { + println("--") + println(govdao.Render("")) + println("--") + println(govdao.Render("1")) + println("--") + govdao.VoteOnProposal(1, "YES") + println("--") + println(govdao.Render("1")) + println("--") + println(gnoblog.Render("")) + println("--") + govdao.ExecuteProposal(1) + println("--") + println(govdao.Render("1")) + println("--") + println(gnoblog.Render("")) +} + +// Output: +// -- +// - [/r/gov/dao:0](0) - post a new blogpost about govdao (by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) +// -- +// # Prop#0 +// +// post a new blogpost about govdao +// Status: active +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// -- +// -- +// # Prop#0 +// +// post a new blogpost about govdao +// Status: accepted +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// -- +// # Gnoland's Blog +// +// No posts. +// -- +// @@@@@@@@@@@@@@@@@@@@@@@@ +// -- +// # Prop#0 +// +// post a new blogpost about govdao +// Status: success +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// -- +// # Gnoland's Blog +// +// No posts. From f924fa9dc82a3616c3a2c931e054e272df9722d7 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:32:41 +0200 Subject: [PATCH 03/12] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/r/gnoland/blog/admin.gno | 5 +++- .../gno.land/r/gov/dao/prop1_filetest.gno | 12 ++++++---- .../gno.land/r/gov/dao/prop2_filetest.gno | 23 ++++++++++++------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index 3becb7022dd..0c2f4c07ad5 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -40,7 +40,10 @@ func AdminRemoveModerator(addr std.Address) { } func ModAddPost(slug, title, body, publicationDate, authors, tags string) { - assertIsModerator() + println("@@@@@@@@@") + println(std.PrevRealm().PkgPath()) + println("#########") + // assertIsModerator() caller := std.GetOrigCaller() diff --git a/examples/gno.land/r/gov/dao/prop1_filetest.gno b/examples/gno.land/r/gov/dao/prop1_filetest.gno index 7072618a4a7..ce3f37afe82 100644 --- a/examples/gno.land/r/gov/dao/prop1_filetest.gno +++ b/examples/gno.land/r/gov/dao/prop1_filetest.gno @@ -1,3 +1,5 @@ +// PKGPATH: gno.land/r/foo/prop01 +// // Please note that this package is intended for demonstration purposes only. // You could execute this code (the init part) by running a `maketx run` command // or by uploading a similar package to a personal namespace. @@ -5,7 +7,7 @@ // For the specific case of validators, a `r/gnoland/valopers` will be used to // organize the lifecycle of validators (register, etc), and this more complex // contract will be responsible to generate proposals. -package main +package prop01 import ( "std" @@ -56,20 +58,20 @@ func main() { // Output: // -- -// - [/r/gov/dao:0](0) - manual valset changes proposal example (by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) +// - [/r/gov/dao:0](0) - manual valset changes proposal example (by g1acws3q8u0hjl9pndjy8rqz58q3x05dnd6d99qa) // -- // # Prop#0 // // manual valset changes proposal example // Status: active -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Author: g1acws3q8u0hjl9pndjy8rqz58q3x05dnd6d99qa // -- // -- // # Prop#0 // // manual valset changes proposal example // Status: accepted -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Author: g1acws3q8u0hjl9pndjy8rqz58q3x05dnd6d99qa // -- // No valset changes to apply. // -- @@ -78,7 +80,7 @@ func main() { // // manual valset changes proposal example // Status: success -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Author: g1acws3q8u0hjl9pndjy8rqz58q3x05dnd6d99qa // -- // Valset changes to apply: // - g12345678 (1) diff --git a/examples/gno.land/r/gov/dao/prop2_filetest.gno b/examples/gno.land/r/gov/dao/prop2_filetest.gno index 794a4c7c396..6fc3429bc33 100644 --- a/examples/gno.land/r/gov/dao/prop2_filetest.gno +++ b/examples/gno.land/r/gov/dao/prop2_filetest.gno @@ -1,4 +1,5 @@ -package main +// PKGPATH: gno.land/r/foo/prop02 +package prop02 import ( "std" @@ -15,7 +16,7 @@ func init() { "hello-from-govdao", // slug "Hello from GovDAO!", // title "This post was published by a GovDAO proposal.", // body - time.Now().String(), // publidation date + time.Now().Format(time.RFC3339), // publidation date "moul", // authors "govdao,example", // tags ) @@ -49,33 +50,39 @@ func main() { // Output: // -- -// - [/r/gov/dao:0](0) - post a new blogpost about govdao (by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) +// - [/r/gov/dao:0](0) - post a new blogpost about govdao (by g1qzu77x7g9z0klhnavmewmhxcz4jcckflhl7sce) // -- // # Prop#0 // // post a new blogpost about govdao // Status: active -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Author: g1qzu77x7g9z0klhnavmewmhxcz4jcckflhl7sce // -- // -- // # Prop#0 // // post a new blogpost about govdao // Status: accepted -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Author: g1qzu77x7g9z0klhnavmewmhxcz4jcckflhl7sce // -- // # Gnoland's Blog // // No posts. // -- -// @@@@@@@@@@@@@@@@@@@@@@@@ +// @@@@@@@@@ +// gno.land/r/foo/prop02 +// ######### // -- // # Prop#0 // // post a new blogpost about govdao // Status: success -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Author: g1qzu77x7g9z0klhnavmewmhxcz4jcckflhl7sce // -- // # Gnoland's Blog // -// No posts. +//
+// +// ### [Hello from GovDAO!](/r/gnoland/blog:p/hello-from-govdao) +// 13 Feb 2009 +//
From 86c168505ee44fb5dedf7d577fb39350e2b0d128 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:59:28 +0200 Subject: [PATCH 04/12] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/r/gnoland/blog/admin.gno | 2 +- examples/gno.land/r/gov/dao/prop2_filetest.gno | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index 0c2f4c07ad5..d128a7a682c 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -41,7 +41,7 @@ func AdminRemoveModerator(addr std.Address) { func ModAddPost(slug, title, body, publicationDate, authors, tags string) { println("@@@@@@@@@") - println(std.PrevRealm().PkgPath()) + println(std.PrevRealm()) println("#########") // assertIsModerator() diff --git a/examples/gno.land/r/gov/dao/prop2_filetest.gno b/examples/gno.land/r/gov/dao/prop2_filetest.gno index 6fc3429bc33..dcd3a24a8a9 100644 --- a/examples/gno.land/r/gov/dao/prop2_filetest.gno +++ b/examples/gno.land/r/gov/dao/prop2_filetest.gno @@ -70,7 +70,7 @@ func main() { // No posts. // -- // @@@@@@@@@ -// gno.land/r/foo/prop02 +// (struct{("g1qzu77x7g9z0klhnavmewmhxcz4jcckflhl7sce" std.Address),("gno.land/r/foo/prop02" string)} std.Realm) // ######### // -- // # Prop#0 From e5dfe54acf32e1412d262bf651d944e1704bb7d2 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 18 Jun 2024 17:00:41 +0200 Subject: [PATCH 05/12] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/demo/context/context.gno | 72 ++++++++++++++ .../gno.land/p/demo/context/context_test.gno | 96 +++++++++++++++++++ examples/gno.land/p/demo/context/gno.mod | 1 + 3 files changed, 169 insertions(+) create mode 100644 examples/gno.land/p/demo/context/context.gno create mode 100644 examples/gno.land/p/demo/context/context_test.gno create mode 100644 examples/gno.land/p/demo/context/gno.mod diff --git a/examples/gno.land/p/demo/context/context.gno b/examples/gno.land/p/demo/context/context.gno new file mode 100644 index 00000000000..92d191012eb --- /dev/null +++ b/examples/gno.land/p/demo/context/context.gno @@ -0,0 +1,72 @@ +// Package context provides a minimal implementation of Go context with support +// for Value and WithValue. +// +// Adapted from https://github.com/golang/go/tree/master/src/context/. +// Copyright 2016 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 context + +type Context interface { + // Value returns the value associated with this context for key, or nil + // if no value is associated with key. + Value(key interface{}) interface{} +} + +// Empty returns a non-nil, empty context, similar with context.Background and +// context.TODO in Go. +func Empty() Context { + return &emptyCtx{} +} + +type emptyCtx struct{} + +func (ctx emptyCtx) Value(key interface{}) interface{} { + return nil +} + +func (ctx emptyCtx) String() string { + return "context.Empty" +} + +type valueCtx struct { + parent Context + key, val interface{} +} + +func (ctx *valueCtx) Value(key interface{}) interface{} { + if ctx.key == key { + return ctx.val + } + return ctx.parent.Value(key) +} + +func stringify(v interface{}) string { + switch s := v.(type) { + case stringer: + return s.String() + case string: + return s + } + return "non-stringer" +} + +type stringer interface { + String() string +} + +func (c *valueCtx) String() string { + return stringify(c.parent) + ".WithValue(" + + stringify(c.key) + ", " + + stringify(c.val) + ")" +} + +// WithValue returns a copy of parent in which the value associated with key is +// val. +func WithValue(parent Context, key, val interface{}) Context { + if key == nil { + panic("nil key") + } + // XXX: if !reflect.TypeOf(key).Comparable() { panic("key is not comparable") } + return &valueCtx{parent, key, val} +} diff --git a/examples/gno.land/p/demo/context/context_test.gno b/examples/gno.land/p/demo/context/context_test.gno new file mode 100644 index 00000000000..0059f0d2a25 --- /dev/null +++ b/examples/gno.land/p/demo/context/context_test.gno @@ -0,0 +1,96 @@ +package context + +import "testing" + +func TestContextExample(t *testing.T) { + type favContextKey string + + k := favContextKey("language") + ctx := WithValue(Empty(), k, "Gno") + + if v := ctx.Value(k); v != nil { + if string(v) != "Gno" { + t.Errorf("language value should be Gno, but is %s", v) + } + } else { + t.Errorf("language key value was not found") + } + + if v := ctx.Value(favContextKey("color")); v != nil { + t.Errorf("color key was found") + } +} + +// otherContext is a Context that's not one of the types defined in context.go. +// This lets us test code paths that differ based on the underlying type of the +// Context. +type otherContext struct { + Context +} + +type ( + key1 int + key2 int +) + +// func (k key2) String() string { return fmt.Sprintf("%[1]T(%[1]d)", k) } + +var ( + k1 = key1(1) + k2 = key2(1) // same int as k1, different type + k3 = key2(3) // same type as k2, different int +) + +func TestValues(t *testing.T) { + check := func(c Context, nm, v1, v2, v3 string) { + if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 { + t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0) + } + if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 { + t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0) + } + if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 { + t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0) + } + } + + c0 := Empty() + check(c0, "c0", "", "", "") + + t.Skip() // XXX: depends on https://github.com/gnolang/gno/issues/2386 + + c1 := WithValue(Empty(), k1, "c1k1") + check(c1, "c1", "c1k1", "", "") + + /*if got, want := c1.String(), `context.Empty.WithValue(context_test.key1, c1k1)`; got != want { + t.Errorf("c.String() = %q want %q", got, want) + }*/ + + c2 := WithValue(c1, k2, "c2k2") + check(c2, "c2", "c1k1", "c2k2", "") + + /*if got, want := fmt.Sprint(c2), `context.Empty.WithValue(context_test.key1, c1k1).WithValue(context_test.key2(1), c2k2)`; got != want { + t.Errorf("c.String() = %q want %q", got, want) + }*/ + + c3 := WithValue(c2, k3, "c3k3") + check(c3, "c2", "c1k1", "c2k2", "c3k3") + + c4 := WithValue(c3, k1, nil) + check(c4, "c4", "", "c2k2", "c3k3") + + o0 := otherContext{Empty()} + check(o0, "o0", "", "", "") + + o1 := otherContext{WithValue(Empty(), k1, "c1k1")} + check(o1, "o1", "c1k1", "", "") + + o2 := WithValue(o1, k2, "o2k2") + check(o2, "o2", "c1k1", "o2k2", "") + + o3 := otherContext{c4} + check(o3, "o3", "", "c2k2", "c3k3") + + o4 := WithValue(o3, k3, nil) + check(o4, "o4", "", "c2k2", "") +} diff --git a/examples/gno.land/p/demo/context/gno.mod b/examples/gno.land/p/demo/context/gno.mod new file mode 100644 index 00000000000..9ae6f3fd43c --- /dev/null +++ b/examples/gno.land/p/demo/context/gno.mod @@ -0,0 +1 @@ +module context From 44da7b75d615ad92561d570f1f2d788ce6862337 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 18 Jun 2024 18:11:47 +0200 Subject: [PATCH 06/12] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/gov/proposal/proposal.gno | 53 +++++++++++++++++-- examples/gno.land/r/gnoland/blog/admin.gno | 17 ++++-- .../gno.land/r/gov/dao/prop2_filetest.gno | 13 +++-- 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/examples/gno.land/p/gov/proposal/proposal.gno b/examples/gno.land/p/gov/proposal/proposal.gno index d4f151f935a..7fdcd0289ce 100644 --- a/examples/gno.land/p/gov/proposal/proposal.gno +++ b/examples/gno.land/p/gov/proposal/proposal.gno @@ -1,7 +1,11 @@ // Package proposal provides a structure for executing proposals. package proposal -import "std" +import ( + "std" + + "gno.land/p/demo/context" +) const daoPkgPath = "gno.land/r/gov/dao" // XXX: make it configurable with r/sys/vars? @@ -13,11 +17,20 @@ func NewExecutor(callback func() error) Executor { } } +// NewCtxExecutor creates a new executor with the provided callback function. +func NewCtxExecutor(callback func(ctx context.Context) error) Executor { + return &executorImpl{ + callbackCtx: callback, + done: false, + } +} + // executorImpl is an implementation of the Executor interface. type executorImpl struct { - callback func() error - done bool - success bool + callback func() error + callbackCtx func(ctx context.Context) error + done bool + success bool } // execute runs the executor's callback function. @@ -26,7 +39,14 @@ func (exec *executorImpl) Execute() error { return ErrAlreadyDone } assertCalledByGovdao() - err := exec.callback() + + var err error + if exec.callback != nil { + err = exec.callback() + } else if exec.callbackCtx != nil { + ctx := context.WithValue(context.Empty(), statusContextKey, approvedStatus) + err = exec.callbackCtx(ctx) + } exec.done = true exec.success = err == nil return err @@ -53,9 +73,32 @@ func (exec executorImpl) Status() Status { } } +func IsApprovedByGovdaoContext(ctx context.Context) bool { + v := ctx.Value(statusContextKey) + if v == nil { + return false + } + return v.(string) == approvedStatus +} + +func AssertContextApprovedByGovDAO(ctx context.Context) { + if !IsApprovedByGovdaoContext(ctx) { + panic("not approved by govdao") + } +} + func assertCalledByGovdao() { caller := std.CurrentRealm().PkgPath() if caller != daoPkgPath { panic("only gov/dao can execute proposals") } } + +type propContextKey string + +func (k propContextKey) String() string { return string(k) } + +const ( + statusContextKey = propContextKey("govdao-prop-status") + approvedStatus = "approved" +) diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index d128a7a682c..08b0911cf24 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -5,6 +5,8 @@ import ( "strings" "gno.land/p/demo/avl" + "gno.land/p/demo/context" + "gno.land/p/gov/proposal" ) var ( @@ -39,14 +41,19 @@ func AdminRemoveModerator(addr std.Address) { moderatorList.Set(addr.String(), false) // FIXME: delete instead? } -func ModAddPost(slug, title, body, publicationDate, authors, tags string) { - println("@@@@@@@@@") - println(std.PrevRealm()) - println("#########") - // assertIsModerator() +func DaoAddPost(ctx context.Context, slug, title, body, publicationDate, authors, tags string) { + proposal.AssertContextApprovedByGovDAO(ctx) + caller := std.DerivePkgAddr("gno.land/r/gov/dao") + addPost(caller, slug, title, body, publicationDate, authors, tags) +} +func ModAddPost(slug, title, body, publicationDate, authors, tags string) { + assertIsModerator() caller := std.GetOrigCaller() + addPost(caller, slug, title, body, publicationDate, authors, tags) +} +func addPost(caller std.Address, slug, title, body, publicationDate, authors, tags string) { var tagList []string if tags != "" { tagList = strings.Split(tags, ",") diff --git a/examples/gno.land/r/gov/dao/prop2_filetest.gno b/examples/gno.land/r/gov/dao/prop2_filetest.gno index dcd3a24a8a9..814be4813ed 100644 --- a/examples/gno.land/r/gov/dao/prop2_filetest.gno +++ b/examples/gno.land/r/gov/dao/prop2_filetest.gno @@ -5,16 +5,18 @@ import ( "std" "time" + "gno.land/p/demo/context" "gno.land/p/gov/proposal" gnoblog "gno.land/r/gnoland/blog" govdao "gno.land/r/gov/dao" ) func init() { - executor := proposal.NewExecutor(func() error { - gnoblog.ModAddPost( - "hello-from-govdao", // slug - "Hello from GovDAO!", // title + executor := proposal.NewCtxExecutor(func(ctx context.Context) error { + gnoblog.DaoAddPost( + ctx, + "hello-from-govdao", // slug + "Hello from GovDAO!", // title "This post was published by a GovDAO proposal.", // body time.Now().Format(time.RFC3339), // publidation date "moul", // authors @@ -69,9 +71,6 @@ func main() { // // No posts. // -- -// @@@@@@@@@ -// (struct{("g1qzu77x7g9z0klhnavmewmhxcz4jcckflhl7sce" std.Address),("gno.land/r/foo/prop02" string)} std.Realm) -// ######### // -- // # Prop#0 // From cc3294be2d396098174718315e6589d79871dbf0 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 18 Jun 2024 18:28:43 +0200 Subject: [PATCH 07/12] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/gov/proposal/gno.mod | 2 ++ examples/gno.land/r/gnoland/blog/gno.mod | 2 ++ 2 files changed, 4 insertions(+) diff --git a/examples/gno.land/p/gov/proposal/gno.mod b/examples/gno.land/p/gov/proposal/gno.mod index f03a60e3714..75e599ca6f1 100644 --- a/examples/gno.land/p/gov/proposal/gno.mod +++ b/examples/gno.land/p/gov/proposal/gno.mod @@ -1 +1,3 @@ module gno.land/p/gov/proposal + +require gno.land/p/demo/context v0.0.0-latest diff --git a/examples/gno.land/r/gnoland/blog/gno.mod b/examples/gno.land/r/gnoland/blog/gno.mod index 1d64238cdc8..17c17e0cfa6 100644 --- a/examples/gno.land/r/gnoland/blog/gno.mod +++ b/examples/gno.land/r/gnoland/blog/gno.mod @@ -3,4 +3,6 @@ module gno.land/r/gnoland/blog require ( gno.land/p/demo/avl v0.0.0-latest gno.land/p/demo/blog v0.0.0-latest + gno.land/p/demo/context v0.0.0-latest + gno.land/p/gov/proposal v0.0.0-latest ) From b44c69a59c0c5a69af6a772b33f2b12b5b1e5b1c Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:54:21 +0200 Subject: [PATCH 08/12] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/r/gov/dao/prop1_filetest.gno | 2 +- examples/gno.land/r/gov/dao/prop2_filetest.gno | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/r/gov/dao/prop1_filetest.gno b/examples/gno.land/r/gov/dao/prop1_filetest.gno index a91d2e1f1d0..b052b0342a4 100644 --- a/examples/gno.land/r/gov/dao/prop1_filetest.gno +++ b/examples/gno.land/r/gov/dao/prop1_filetest.gno @@ -91,7 +91,7 @@ func main() { // // manual valset changes proposal example // Status: succeeded -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Author: g1acws3q8u0hjl9pndjy8rqz58q3x05dnd6d99qa // -- // Valset changes to apply: // - g12345678 (10) diff --git a/examples/gno.land/r/gov/dao/prop2_filetest.gno b/examples/gno.land/r/gov/dao/prop2_filetest.gno index 814be4813ed..9292fd62441 100644 --- a/examples/gno.land/r/gov/dao/prop2_filetest.gno +++ b/examples/gno.land/r/gov/dao/prop2_filetest.gno @@ -75,7 +75,7 @@ func main() { // # Prop#0 // // post a new blogpost about govdao -// Status: success +// Status: succeeded // Author: g1qzu77x7g9z0klhnavmewmhxcz4jcckflhl7sce // -- // # Gnoland's Blog From 9bad4b99d8e6c70dab2e6118cc4bcdfd9f33e552 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:55:34 +0200 Subject: [PATCH 09/12] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/p/gov/proposal/gno.mod | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/p/gov/proposal/gno.mod b/examples/gno.land/p/gov/proposal/gno.mod index 9746576bbf5..8604740f898 100644 --- a/examples/gno.land/p/gov/proposal/gno.mod +++ b/examples/gno.land/p/gov/proposal/gno.mod @@ -1,4 +1,6 @@ module gno.land/p/gov/proposal -require gno.land/p/demo/context v0.0.0-latest -require gno.land/p/demo/uassert v0.0.0-latest +require ( + gno.land/p/demo/context v0.0.0-latest + gno.land/p/demo/uassert v0.0.0-latest +) From f958c615fd556d4c69fd26c9f8c41e1e83d8b5fa Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Tue, 2 Jul 2024 20:00:03 +0200 Subject: [PATCH 10/12] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/r/gov/dao/prop2_filetest.gno | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/gno.land/r/gov/dao/prop2_filetest.gno b/examples/gno.land/r/gov/dao/prop2_filetest.gno index 9292fd62441..8391630e21b 100644 --- a/examples/gno.land/r/gov/dao/prop2_filetest.gno +++ b/examples/gno.land/r/gov/dao/prop2_filetest.gno @@ -2,7 +2,6 @@ package prop02 import ( - "std" "time" "gno.land/p/demo/context" From 036d7e4b54529dfd2274e2a47adec0042717efd9 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:11:51 +0200 Subject: [PATCH 11/12] Update examples/gno.land/p/demo/context/gno.mod Co-authored-by: Antonio Navarro Perez --- examples/gno.land/p/demo/context/gno.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/p/demo/context/gno.mod b/examples/gno.land/p/demo/context/gno.mod index 9ae6f3fd43c..a04ae1f91f8 100644 --- a/examples/gno.land/p/demo/context/gno.mod +++ b/examples/gno.land/p/demo/context/gno.mod @@ -1 +1 @@ -module context +module gno.land/p/demo/context From b7c212cecd230767449810c5f6fbe71facf0a63f Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:12:00 +0200 Subject: [PATCH 12/12] Update examples/gno.land/p/gov/proposal/proposal.gno Co-authored-by: Antonio Navarro Perez --- examples/gno.land/p/gov/proposal/proposal.gno | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/gno.land/p/gov/proposal/proposal.gno b/examples/gno.land/p/gov/proposal/proposal.gno index 82a0c4a6576..79303b62a82 100644 --- a/examples/gno.land/p/gov/proposal/proposal.gno +++ b/examples/gno.land/p/gov/proposal/proposal.gno @@ -82,7 +82,8 @@ func IsApprovedByGovdaoContext(ctx context.Context) bool { if v == nil { return false } - return v.(string) == approvedStatus + vs, ok := v.(string) + return ok && vs == approvedStatus } func AssertContextApprovedByGovDAO(ctx context.Context) {