Skip to content

Commit

Permalink
feat(gnodev): support MetadataTX
Browse files Browse the repository at this point in the history
Signed-off-by: gfanton <[email protected]>
  • Loading branch information
gfanton committed Oct 13, 2024
1 parent dcdbc02 commit 5865cd3
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 44 deletions.
9 changes: 4 additions & 5 deletions contribs/gnodev/cmd/gnodev/setup_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/gnolang/gno/contribs/gnodev/pkg/emitter"
"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/tm2/pkg/bft/types"
"github.com/gnolang/gno/tm2/pkg/std"
)

// setupDevNode initializes and returns a new DevNode.
Expand All @@ -24,7 +23,7 @@ func setupDevNode(

if devCfg.txsFile != "" { // Load txs files
var err error
nodeConfig.InitialTxs, err = parseTxs(devCfg.txsFile)
nodeConfig.InitialTxs, err = parseTxs(ctx, logger, devCfg.txsFile)
if err != nil {
return nil, fmt.Errorf("unable to load transactions: %w", err)
}
Expand All @@ -38,13 +37,13 @@ func setupDevNode(
nodeConfig.BalancesList = state.GenesisBalances()

stateTxs := state.GenesisTxs()
nodeConfig.InitialTxs = make([]std.Tx, len(stateTxs))
nodeConfig.InitialTxs = make([]gnoland.GenesisTx, len(stateTxs))

for index, nodeTx := range stateTxs {
nodeConfig.InitialTxs[index] = nodeTx.Tx()
nodeConfig.InitialTxs[index] = nodeTx
}

logger.Info("genesis file loaded", "path", devCfg.genesisFile, "txs", len(nodeConfig.InitialTxs))
logger.Info("genesis file loaded", "path", devCfg.genesisFile, "txs", len(stateTxs))
}

return gnodev.NewDevNode(ctx, nodeConfig)
Expand Down
52 changes: 50 additions & 2 deletions contribs/gnodev/cmd/gnodev/txs.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package main

import (
"bufio"
"context"
"errors"
"fmt"
"log/slog"
"os"

"github.com/gnolang/gno/contribs/gnodev/pkg/dev"
"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/std"
)

func parseTxs(txFile string) ([]std.Tx, error) {
func parseTxs(ctx context.Context, logger *slog.Logger, txFile string) ([]gnoland.GenesisTx, error) {
if txFile == "" {
return nil, nil
}
Expand All @@ -19,5 +25,47 @@ func parseTxs(txFile string) ([]std.Tx, error) {
}
defer file.Close()

return std.ParseTxs(context.Background(), file)
var txs []gnoland.GenesisTx
scanner := bufio.NewScanner(file)

for scanner.Scan() {
select {
case <-ctx.Done():
return nil, std.ErrTxsLoadingAborted
default:
}

// XXX this can be expensive if all th txs are std.Tx
// find a better way
line := scanner.Bytes()

var metatx gnoland.MetadataTx
unmarshalMetaTxErr := amino.Unmarshal(line, &metatx)
if unmarshalMetaTxErr == nil {
logger.Debug("load metatx", "tx", metatx.GenesisTx, "meta", metatx.TxMetadata)
txs = append(txs, &metatx)
continue
}

// fallback on std tx
var tx std.Tx
unmarshalTxErr := amino.Unmarshal(line, &tx)
if unmarshalTxErr == nil {
logger.Debug("load tx", "tx", metatx.GenesisTx, "meta", metatx.TxMetadata)
txs = append(txs, dev.GnoGenesisTx{StdTx: tx})
continue
}

return nil, fmt.Errorf("unable to unmarshal tx: %w", errors.Join(unmarshalMetaTxErr, unmarshalTxErr))
}

// Check for scanning errors
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf(
"error encountered while reading file, %w",
err,
)
}

return txs, nil
}
64 changes: 39 additions & 25 deletions contribs/gnodev/pkg/dev/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path/filepath"
"strings"
"sync"
"time"
"unicode"

"github.com/gnolang/gno/contribs/gnodev/pkg/emitter"
Expand Down Expand Up @@ -35,7 +36,7 @@ type NodeConfig struct {
BalancesList []gnoland.Balance
PackagesPathList []PackagePath
Emitter emitter.Emitter
InitialTxs []std.Tx
InitialTxs []gnoland.GenesisTx
TMConfig *tmcfg.Config
SkipFailingGenesisTxs bool
NoReplay bool
Expand Down Expand Up @@ -83,8 +84,11 @@ type Node struct {
// keep track of number of loaded package to be able to skip them on restore
loadedPackages int

// track starting time for genesis
startTime time.Time

// state
initialState, state []std.Tx
initialState, state []gnoland.GenesisTx
currentStateIndex int
}

Expand All @@ -96,7 +100,8 @@ func NewDevNode(ctx context.Context, cfg *NodeConfig) (*Node, error) {
return nil, fmt.Errorf("unable map pkgs list: %w", err)
}

pkgsTxs, err := mpkgs.Load(DefaultFee)
startTime := time.Now()
pkgsTxs, err := mpkgs.Load(DefaultFee, startTime)
if err != nil {
return nil, fmt.Errorf("unable to load genesis packages: %w", err)
}
Expand All @@ -109,18 +114,19 @@ func NewDevNode(ctx context.Context, cfg *NodeConfig) (*Node, error) {
pkgs: mpkgs,
logger: cfg.Logger,
loadedPackages: len(pkgsTxs),
startTime: startTime,
state: cfg.InitialTxs,
initialState: cfg.InitialTxs,
currentStateIndex: len(cfg.InitialTxs),
}

// generate genesis state
genesis := gnoland.GnoGenesisState{
genesis := NodeGenesisState{
Balances: cfg.BalancesList,
Txs: append(pkgsTxs, cfg.InitialTxs...),
}

if err := devnode.rebuildNode(ctx, genesis); err != nil {
if err := devnode.rebuildNode(ctx, &genesis); err != nil {
return nil, fmt.Errorf("unable to initialize the node: %w", err)
}

Expand Down Expand Up @@ -154,7 +160,7 @@ func (n *Node) GetRemoteAddress() string {

// GetBlockTransactions returns the transactions contained
// within the specified block, if any
func (n *Node) GetBlockTransactions(blockNum uint64) ([]std.Tx, error) {
func (n *Node) GetBlockTransactions(blockNum uint64) ([]gnoland.GenesisTx, error) {

Check warning on line 163 in contribs/gnodev/pkg/dev/node.go

View check run for this annotation

Codecov / codecov/patch

contribs/gnodev/pkg/dev/node.go#L163

Added line #L163 was not covered by tests
n.muNode.RLock()
defer n.muNode.RUnlock()

Expand All @@ -163,21 +169,27 @@ func (n *Node) GetBlockTransactions(blockNum uint64) ([]std.Tx, error) {

// GetBlockTransactions returns the transactions contained
// within the specified block, if any
func (n *Node) getBlockTransactions(blockNum uint64) ([]std.Tx, error) {
func (n *Node) getBlockTransactions(blockNum uint64) ([]gnoland.GenesisTx, error) {
int64BlockNum := int64(blockNum)
b, err := n.client.Block(&int64BlockNum)
if err != nil {
return []std.Tx{}, fmt.Errorf("unable to load block at height %d: %w", blockNum, err) // nothing to see here
return nil, fmt.Errorf("unable to load block at height %d: %w", blockNum, err) // nothing to see here

Check warning on line 176 in contribs/gnodev/pkg/dev/node.go

View check run for this annotation

Codecov / codecov/patch

contribs/gnodev/pkg/dev/node.go#L176

Added line #L176 was not covered by tests
}

txs := make([]std.Tx, len(b.Block.Data.Txs))
txs := make([]gnoland.GenesisTx, len(b.Block.Data.Txs))
for i, encodedTx := range b.Block.Data.Txs {
// fallback on std tx
var tx std.Tx
if unmarshalErr := amino.Unmarshal(encodedTx, &tx); unmarshalErr != nil {
return nil, fmt.Errorf("unable to unmarshal amino tx, %w", unmarshalErr)
return nil, fmt.Errorf("unable to unmarshal tx: %w", err)

Check warning on line 184 in contribs/gnodev/pkg/dev/node.go

View check run for this annotation

Codecov / codecov/patch

contribs/gnodev/pkg/dev/node.go#L184

Added line #L184 was not covered by tests
}

txs[i] = tx
txs[i] = &gnoland.MetadataTx{
GenesisTx: tx,
TxMetadata: gnoland.GenesisTxMetadata{
Timestamp: b.Block.Time.Unix(),
},
}
}

return txs, nil
Expand Down Expand Up @@ -263,26 +275,28 @@ func (n *Node) Reset(ctx context.Context) error {
}

// Generate a new genesis state based on the current packages
pkgsTxs, err := n.pkgs.Load(DefaultFee)
startTime := time.Now()
pkgsTxs, err := n.pkgs.Load(DefaultFee, startTime)
if err != nil {
return fmt.Errorf("unable to load pkgs: %w", err)
}

// Append initialTxs
txs := append(pkgsTxs, n.initialState...)
genesis := gnoland.GnoGenesisState{
genesis := NodeGenesisState{
Balances: n.config.BalancesList,
Txs: txs,
}

// Reset the node with the new genesis state.
err = n.rebuildNode(ctx, genesis)
err = n.rebuildNode(ctx, &genesis)
if err != nil {
return fmt.Errorf("unable to initialize a new node: %w", err)
}

n.loadedPackages = len(pkgsTxs)
n.currentStateIndex = len(n.initialState)
n.startTime = startTime
n.emitter.Emit(&events.Reset{})
return nil
}
Expand Down Expand Up @@ -347,15 +361,15 @@ func (n *Node) SendTransaction(tx *std.Tx) error {
return nil
}

func (n *Node) getBlockStoreState(ctx context.Context) ([]std.Tx, error) {
func (n *Node) getBlockStoreState(ctx context.Context) ([]gnoland.GenesisTx, error) {
// get current genesis state
genesis := n.GenesisDoc().AppState.(gnoland.GnoGenesis)

initialTxs := genesis.GenesisTxs()[n.loadedPackages:] // ignore previously loaded packages

state := make([]std.Tx, 0, len(initialTxs))
state := make([]gnoland.GenesisTx, 0, len(initialTxs))
for _, tx := range initialTxs {
state = append(state, tx.Tx())
state = append(state, tx)

Check warning on line 372 in contribs/gnodev/pkg/dev/node.go

View check run for this annotation

Codecov / codecov/patch

contribs/gnodev/pkg/dev/node.go#L372

Added line #L372 was not covered by tests
}

lastBlock := n.getLatestBlockNumber()
Expand Down Expand Up @@ -394,12 +408,12 @@ func (n *Node) rebuildNodeFromState(ctx context.Context) error {
// If NoReplay is true, simply reset the node to its initial state
n.logger.Warn("replay disabled")

txs, err := n.pkgs.Load(DefaultFee)
txs, err := n.pkgs.Load(DefaultFee, n.startTime)

Check warning on line 411 in contribs/gnodev/pkg/dev/node.go

View check run for this annotation

Codecov / codecov/patch

contribs/gnodev/pkg/dev/node.go#L411

Added line #L411 was not covered by tests
if err != nil {
return fmt.Errorf("unable to load pkgs: %w", err)
}

return n.rebuildNode(ctx, gnoland.GnoGenesisState{
return n.rebuildNode(ctx, &NodeGenesisState{

Check warning on line 416 in contribs/gnodev/pkg/dev/node.go

View check run for this annotation

Codecov / codecov/patch

contribs/gnodev/pkg/dev/node.go#L416

Added line #L416 was not covered by tests
Balances: n.config.BalancesList, Txs: txs,
})
}
Expand All @@ -410,19 +424,19 @@ func (n *Node) rebuildNodeFromState(ctx context.Context) error {
}

// Load genesis packages
pkgsTxs, err := n.pkgs.Load(DefaultFee)
pkgsTxs, err := n.pkgs.Load(DefaultFee, n.startTime)
if err != nil {
return fmt.Errorf("unable to load pkgs: %w", err)
}

// Create genesis with loaded pkgs + previous state
genesis := gnoland.GnoGenesisState{
genesis := NodeGenesisState{
Balances: n.config.BalancesList,
Txs: append(pkgsTxs, state...),
}

// Reset the node with the new genesis state.
err = n.rebuildNode(ctx, genesis)
err = n.rebuildNode(ctx, &genesis)
n.logger.Info("reload done", "pkgs", len(pkgsTxs), "state applied", len(state))

// Update node infos
Expand Down Expand Up @@ -465,7 +479,7 @@ func (n *Node) handleEventTX(evt tm2events.Event) {
}
}

func (n *Node) rebuildNode(ctx context.Context, genesis gnoland.GnoGenesis) (err error) {
func (n *Node) rebuildNode(ctx context.Context, genesis *NodeGenesisState) (err error) {
noopLogger := log.NewNoopLogger()

// Stop the node if it's currently running.
Expand Down Expand Up @@ -553,11 +567,11 @@ func (n *Node) genesisTxResultHandler(ctx sdk.Context, tx std.Tx, res sdk.Result
return
}

func newNodeConfig(tmc *tmcfg.Config, chainid string, appstate gnoland.GnoGenesis) *gnoland.InMemoryNodeConfig {
func newNodeConfig(tmc *tmcfg.Config, chainid string, appstate *NodeGenesisState) *gnoland.InMemoryNodeConfig {
// Create Mocked Identity
pv := gnoland.NewMockedPrivValidator()
genesis := gnoland.NewDefaultGenesisConfig(chainid)
genesis.AppState = appstate
genesis.AppState = appstate.MetadataGenesisState()

// Add self as validator
self := pv.GetPubKey()
Expand Down
Loading

0 comments on commit 5865cd3

Please sign in to comment.