From 1b69e7a95e29244dda8009cea263b97f73cee106 Mon Sep 17 00:00:00 2001 From: 0xhoanvarmeta Date: Mon, 19 May 2025 17:47:22 +0700 Subject: [PATCH 1/5] cache path in node --- .../pkg/cachepath/cache_path_manual_deploy.go | 30 +++++++++++++++++++ contribs/gnodev/pkg/dev/node.go | 18 +++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 contribs/gnodev/pkg/cachepath/cache_path_manual_deploy.go diff --git a/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy.go b/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy.go new file mode 100644 index 00000000000..ac3e230c156 --- /dev/null +++ b/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy.go @@ -0,0 +1,30 @@ +package cachepath + +import ( + "sync" +) + +type CachePath struct { + data map[string]bool + mu sync.RWMutex +} + +var cache *CachePath + +func init() { + cache = &CachePath{ + data: make(map[string]bool), + } +} + +func Set(key string) { + cache.mu.Lock() + defer cache.mu.Unlock() + cache.data[key] = true +} + +func Get(key string) bool { + cache.mu.RLock() + defer cache.mu.RUnlock() + return cache.data[key] +} diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 0b25234f350..4e080643416 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -12,6 +12,7 @@ import ( "time" "unicode" + "github.com/gnolang/gno/contribs/gnodev/pkg/cachepath" "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" "github.com/gnolang/gno/contribs/gnodev/pkg/events" "github.com/gnolang/gno/contribs/gnodev/pkg/packages" @@ -280,6 +281,11 @@ func (n *Node) getBlockTransactions(blockNum uint64) ([]gnoland.TxWithMetadata, if unmarshalErr := amino.Unmarshal(encodedTx, &tx); unmarshalErr != nil { return nil, fmt.Errorf("unable to unmarshal tx: %w", unmarshalErr) } + for _, msg := range tx.Msgs { + if addpkg, ok := msg.(vm.MsgAddPackage); ok && addpkg.Package != nil { + cachepath.Set(addpkg.Package.Path) + } + } metaTxs = append(metaTxs, gnoland.TxWithMetadata{ Tx: tx, @@ -497,6 +503,15 @@ func (n *Node) rebuildNodeFromState(ctx context.Context) error { // Load genesis packages pkgs, err := n.loader.Load(n.paths...) + filterPackages := make([]packages.Package, 0, len(pkgs)) + for _, pkg := range pkgs { + if !cachepath.Get(pkg.Path) { + filterPackages = append(filterPackages, pkg) + } else { + n.logger.Error("Can't reload package, package conflict in ", "path", pkg.Path) + } + } + if err != nil { return fmt.Errorf("unable to load pkgs: %w", err) } @@ -506,7 +521,7 @@ func (n *Node) rebuildNodeFromState(ctx context.Context) error { genesis.Balances = n.config.BalancesList // Generate txs - pkgsTxs := n.generateTxs(DefaultFee, pkgs) + pkgsTxs := n.generateTxs(DefaultFee, filterPackages) genesis.Txs = append(pkgsTxs, state...) // Reset the node with the new genesis state. @@ -520,7 +535,6 @@ func (n *Node) rebuildNodeFromState(ctx context.Context) error { // Update node infos n.pkgs = pkgs n.loadedPackages = len(pkgsTxs) - // Emit reload event n.emitter.Emit(&events.Reload{}) return nil From 9d67d9189b461c252f12e0e9f59eaf04faf3b535 Mon Sep 17 00:00:00 2001 From: 0xhoanvarmeta Date: Tue, 20 May 2025 09:39:43 +0700 Subject: [PATCH 2/5] add test file for cachepath --- .../cache_path_manual_deploy_test.go | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go diff --git a/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go b/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go new file mode 100644 index 00000000000..940274a8981 --- /dev/null +++ b/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go @@ -0,0 +1,49 @@ +package cachepath + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCachePath(t *testing.T) { + + assert.NotNil(t, cache, "Cache should be initialized") + assert.NotNil(t, cache.data, "Cache data map should be initialized") + + t.Run("Set and Get", func(t *testing.T) { + path := "gno.land/r/test/example" + + exists := Get(path) + assert.False(t, exists, "Path should not exist before setting") + + Set(path) + + exists = Get(path) + assert.True(t, exists, "Path should exist after setting") + }) + + t.Run("Multiple paths", func(t *testing.T) { + + cache.data = make(map[string]bool) + + paths := []string{ + "gno.land/r/test/path1", + "gno.land/r/test/path2", + "gno.land/p/demo/path3", + } + + for _, path := range paths { + Set(path) + } + + for _, path := range paths { + exists := Get(path) + assert.True(t, exists, "Path %s should exist after setting", path) + } + + nonExistentPath := "gno.land/r/test/nonexistent" + exists := Get(nonExistentPath) + assert.False(t, exists, "Non-existent path should not exist") + }) +} From 83fdfd8b1fba2f36d61b2a59c9654ba7262ae8bb Mon Sep 17 00:00:00 2001 From: 0xhoanvarmeta Date: Tue, 20 May 2025 13:19:08 +0700 Subject: [PATCH 3/5] refactor --- .../gnodev/pkg/cachepath/cache_path_manual_deploy_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go b/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go index 940274a8981..ed8cd125e63 100644 --- a/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go +++ b/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go @@ -7,10 +7,8 @@ import ( ) func TestCachePath(t *testing.T) { - assert.NotNil(t, cache, "Cache should be initialized") assert.NotNil(t, cache.data, "Cache data map should be initialized") - t.Run("Set and Get", func(t *testing.T) { path := "gno.land/r/test/example" @@ -24,9 +22,7 @@ func TestCachePath(t *testing.T) { }) t.Run("Multiple paths", func(t *testing.T) { - cache.data = make(map[string]bool) - paths := []string{ "gno.land/r/test/path1", "gno.land/r/test/path2", From ea720703e2da741becd677eaab848df0f7b4653b Mon Sep 17 00:00:00 2001 From: 0xhoanvarmeta Date: Tue, 27 May 2025 15:32:43 +0700 Subject: [PATCH 4/5] follow change request --- .../pkg/cachepath/cache_path_manual_deploy.go | 30 ----- .../cache_path_manual_deploy_test.go | 45 ------- contribs/gnodev/pkg/dev/node.go | 39 ++++-- contribs/gnodev/pkg/dev/node_test.go | 122 ++++++++++++++++++ 4 files changed, 148 insertions(+), 88 deletions(-) delete mode 100644 contribs/gnodev/pkg/cachepath/cache_path_manual_deploy.go delete mode 100644 contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go diff --git a/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy.go b/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy.go deleted file mode 100644 index ac3e230c156..00000000000 --- a/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy.go +++ /dev/null @@ -1,30 +0,0 @@ -package cachepath - -import ( - "sync" -) - -type CachePath struct { - data map[string]bool - mu sync.RWMutex -} - -var cache *CachePath - -func init() { - cache = &CachePath{ - data: make(map[string]bool), - } -} - -func Set(key string) { - cache.mu.Lock() - defer cache.mu.Unlock() - cache.data[key] = true -} - -func Get(key string) bool { - cache.mu.RLock() - defer cache.mu.RUnlock() - return cache.data[key] -} diff --git a/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go b/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go deleted file mode 100644 index ed8cd125e63..00000000000 --- a/contribs/gnodev/pkg/cachepath/cache_path_manual_deploy_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package cachepath - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestCachePath(t *testing.T) { - assert.NotNil(t, cache, "Cache should be initialized") - assert.NotNil(t, cache.data, "Cache data map should be initialized") - t.Run("Set and Get", func(t *testing.T) { - path := "gno.land/r/test/example" - - exists := Get(path) - assert.False(t, exists, "Path should not exist before setting") - - Set(path) - - exists = Get(path) - assert.True(t, exists, "Path should exist after setting") - }) - - t.Run("Multiple paths", func(t *testing.T) { - cache.data = make(map[string]bool) - paths := []string{ - "gno.land/r/test/path1", - "gno.land/r/test/path2", - "gno.land/p/demo/path3", - } - - for _, path := range paths { - Set(path) - } - - for _, path := range paths { - exists := Get(path) - assert.True(t, exists, "Path %s should exist after setting", path) - } - - nonExistentPath := "gno.land/r/test/nonexistent" - exists := Get(nonExistentPath) - assert.False(t, exists, "Non-existent path should not exist") - }) -} diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 4e080643416..2f49874c9ba 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -12,7 +12,6 @@ import ( "time" "unicode" - "github.com/gnolang/gno/contribs/gnodev/pkg/cachepath" "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" "github.com/gnolang/gno/contribs/gnodev/pkg/events" "github.com/gnolang/gno/contribs/gnodev/pkg/packages" @@ -117,6 +116,23 @@ func DefaultNodeConfig(rootdir, domain string) *NodeConfig { } } +type CachePath struct { + data map[string]bool + mu sync.RWMutex +} + +func (cp *CachePath) Set(key string) { + cp.mu.Lock() + defer cp.mu.Unlock() + cp.data[key] = true +} + +func (cp *CachePath) Get(key string) bool { + cp.mu.RLock() + defer cp.mu.RUnlock() + return cp.data[key] +} + // Node is not thread safe type Node struct { *node.Node @@ -130,7 +146,7 @@ type Node struct { pkgs []packages.Package pkgsModifier map[string]QueryPath // path -> QueryPath paths []string - + cachepath *CachePath // keep track of number of loaded package to be able to skip them on restore loadedPackages int @@ -164,6 +180,7 @@ func NewDevNode(ctx context.Context, cfg *NodeConfig, pkgpaths ...string) (*Node currentStateIndex: len(cfg.InitialTxs), paths: pkgpaths, pkgsModifier: pkgsModifier, + cachepath: &CachePath{data: make(map[string]bool)}, } // XXX: MOVE THIS, passing context here can be confusing @@ -283,7 +300,7 @@ func (n *Node) getBlockTransactions(blockNum uint64) ([]gnoland.TxWithMetadata, } for _, msg := range tx.Msgs { if addpkg, ok := msg.(vm.MsgAddPackage); ok && addpkg.Package != nil { - cachepath.Set(addpkg.Package.Path) + n.cachepath.Set(addpkg.Package.Path) } } @@ -429,6 +446,11 @@ func (n *Node) getBlockStoreState(ctx context.Context) ([]gnoland.TxWithMetadata func (n *Node) generateTxs(fee std.Fee, pkgs []packages.Package) []gnoland.TxWithMetadata { metatxs := make([]gnoland.TxWithMetadata, 0, len(pkgs)) for _, pkg := range pkgs { + if n.cachepath.Get(pkg.Path) { + n.logger.Error("Can't reload package, package conflict in ", "path", pkg.Path) + continue + } + msg := vm.MsgAddPackage{ Creator: n.config.DefaultCreator, Deposit: n.config.DefaultDeposit, @@ -503,14 +525,6 @@ func (n *Node) rebuildNodeFromState(ctx context.Context) error { // Load genesis packages pkgs, err := n.loader.Load(n.paths...) - filterPackages := make([]packages.Package, 0, len(pkgs)) - for _, pkg := range pkgs { - if !cachepath.Get(pkg.Path) { - filterPackages = append(filterPackages, pkg) - } else { - n.logger.Error("Can't reload package, package conflict in ", "path", pkg.Path) - } - } if err != nil { return fmt.Errorf("unable to load pkgs: %w", err) @@ -521,9 +535,8 @@ func (n *Node) rebuildNodeFromState(ctx context.Context) error { genesis.Balances = n.config.BalancesList // Generate txs - pkgsTxs := n.generateTxs(DefaultFee, filterPackages) + pkgsTxs := n.generateTxs(DefaultFee, pkgs) genesis.Txs = append(pkgsTxs, state...) - // Reset the node with the new genesis state. err = n.rebuildNode(ctx, genesis) n.logger.Info("reload done", diff --git a/contribs/gnodev/pkg/dev/node_test.go b/contribs/gnodev/pkg/dev/node_test.go index 1a9c041d37e..757910732fc 100644 --- a/contribs/gnodev/pkg/dev/node_test.go +++ b/contribs/gnodev/pkg/dev/node_test.go @@ -1,8 +1,10 @@ package dev import ( + "bytes" "context" "encoding/json" + "log/slog" "testing" "time" @@ -78,6 +80,90 @@ func Render(_ string) string { return "foo" } require.NoError(t, node.Close()) } +// TestNewNode_WithPackage tests the NewDevNode with a single package. +func TestNewNode_ConflictPackage(t *testing.T) { + + // Define 2 packages with same path + fooPkg := std.MemPackage{ + Name: "foo", + Path: "gno.land/r/dev/foo", + Files: []*std.MemFile{ + { + Name: "foo.gno", + Body: `package foo +func Render(_ string) string { return "foo" } +`, + }, + }, + } + + conflictPkg := std.MemPackage{ + Name: "foo", + Path: "gno.land/r/dev/foo", + Files: []*std.MemFile{ + { + Name: "foo.gno", + Body: `package foo + func Render(_ string) string { return "conflict" } + `, + }, + }, + } + + node, emitter := newTestingDevNode(t) + + // Create a message to add the package + pkg := vm.MsgAddPackage{ + Package: &fooPkg, + Deposit: std.Coins{{Denom: "ugnot", Amount: 1000}}, + } + + // Add the realm to the node + res, err := testingAddRealm(t, node, pkg) + require.NoError(t, err) + require.NoError(t, res.CheckTx.Error) + require.NoError(t, res.DeliverTx.Error) + assert.Equal(t, emitter.NextEvent().Type(), events.EvtTxResult) + + // Check that the realm has been added + render, err := testingRenderRealm(t, node, "gno.land/r/dev/foo") + require.NoError(t, err) + require.Equal(t, "foo", render) + + // Update the node's loader with the conflicting package + conflictLoader := packages.NewLoader(packages.NewMockResolver(&conflictPkg)) + node.loader = conflictLoader + + node.AddPackagePaths(conflictPkg.Path) + + // Create a buffer to capture logs + var logBuffer bytes.Buffer + + // Create a custom logger that writes to the buffer + customLogger := slog.New(slog.NewTextHandler(&logBuffer, &slog.HandlerOptions{ + Level: slog.LevelDebug, + })) + + node.logger = customLogger + + // Reload the node to apply changes from the new loader + err = node.Reload(context.Background()) + require.Equal(t, true, node.cachepath.Get("gno.land/r/dev/foo")) + + require.NoError(t, err) + assert.Equal(t, emitter.NextEvent().Type(), events.EvtReload) + + // Check the log buffer to confirm the error was logged + logOutput := logBuffer.String() + assert.Contains(t, logOutput, "Can't reload package, package conflict in") + assert.Contains(t, logOutput, "gno.land/r/dev/foo") + + // Check the realm after reload + render, err = testingRenderRealm(t, node, "gno.land/r/dev/foo") + require.NoError(t, err) + require.Equal(t, "foo", render) +} + func TestNodeAddPackage(t *testing.T) { // Setup a Node instance fooPkg := std.MemPackage{ @@ -569,6 +655,42 @@ func testingCallRealmWithConfig(t *testing.T, node *Node, bcfg gnoclient.BaseTxC return cli.Call(bcfg, vmMsgs...) } +func testingAddRealm(t *testing.T, node *Node, msgs ...vm.MsgAddPackage) (*core_types.ResultBroadcastTxCommit, error) { + t.Helper() + + defaultCfg := gnoclient.BaseTxCfg{ + GasFee: ugnot.ValueString(1000000), // Gas fee + GasWanted: 3_000_000, // Gas wanted + } + + return testingAddRealmWithConfig(t, node, defaultCfg, msgs...) +} + +func testingAddRealmWithConfig(t *testing.T, node *Node, bcfg gnoclient.BaseTxCfg, msgs ...vm.MsgAddPackage) (*core_types.ResultBroadcastTxCommit, error) { + t.Helper() + + signer := newInMemorySigner(t, node.Config().ChainID()) + cli := gnoclient.Client{ + Signer: signer, + RPCClient: node.Client(), + } + + // Set Creator in the msgs + caller, err := signer.Info() + require.NoError(t, err) + + // Create new messages with the caller set as Creator + newMsgs := make([]vm.MsgAddPackage, 0, len(msgs)) + for _, msg := range msgs { + newMsg := msg + newMsg.Creator = caller.GetAddress() + newMsgs = append(newMsgs, newMsg) + } + + // Call AddPackage + return cli.AddPackage(bcfg, newMsgs...) +} + func newTestingNodeConfig(pkgs ...*std.MemPackage) *NodeConfig { var loader packages.BaseLoader gnoroot := gnoenv.RootDir() From 7fdf2d1157432e5f0859209abee17d071e8607a8 Mon Sep 17 00:00:00 2001 From: 0xhoanvarmeta Date: Tue, 27 May 2025 15:37:59 +0700 Subject: [PATCH 5/5] lint --- contribs/gnodev/pkg/dev/node.go | 1 - contribs/gnodev/pkg/dev/node_test.go | 1 - 2 files changed, 2 deletions(-) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 2f49874c9ba..e1e90a71838 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -525,7 +525,6 @@ func (n *Node) rebuildNodeFromState(ctx context.Context) error { // Load genesis packages pkgs, err := n.loader.Load(n.paths...) - if err != nil { return fmt.Errorf("unable to load pkgs: %w", err) } diff --git a/contribs/gnodev/pkg/dev/node_test.go b/contribs/gnodev/pkg/dev/node_test.go index 757910732fc..44defa6c9b6 100644 --- a/contribs/gnodev/pkg/dev/node_test.go +++ b/contribs/gnodev/pkg/dev/node_test.go @@ -82,7 +82,6 @@ func Render(_ string) string { return "foo" } // TestNewNode_WithPackage tests the NewDevNode with a single package. func TestNewNode_ConflictPackage(t *testing.T) { - // Define 2 packages with same path fooPkg := std.MemPackage{ Name: "foo",