-
Notifications
You must be signed in to change notification settings - Fork 379
/
node_inmemory.go
178 lines (149 loc) · 4.84 KB
/
node_inmemory.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package gnoland
import (
"fmt"
"sync"
"time"
"golang.org/x/exp/slog"
abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types"
tmcfg "github.com/gnolang/gno/tm2/pkg/bft/config"
"github.com/gnolang/gno/tm2/pkg/bft/node"
"github.com/gnolang/gno/tm2/pkg/bft/proxy"
bft "github.com/gnolang/gno/tm2/pkg/bft/types"
"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/crypto/ed25519"
"github.com/gnolang/gno/tm2/pkg/db"
"github.com/gnolang/gno/tm2/pkg/events"
"github.com/gnolang/gno/tm2/pkg/p2p"
"github.com/gnolang/gno/tm2/pkg/std"
)
type InMemoryNodeConfig struct {
PrivValidator bft.PrivValidator // identity of the validator
Genesis *bft.GenesisDoc
TMConfig *tmcfg.Config
SkipFailingGenesisTxs bool
GenesisMaxVMCycles int64
}
// NewMockedPrivValidator generate a new key
func NewMockedPrivValidator() bft.PrivValidator {
return bft.NewMockPVWithParams(ed25519.GenPrivKey(), false, false)
}
// NewInMemoryNodeConfig creates a default configuration for an in-memory node.
func NewDefaultGenesisConfig(pk crypto.PubKey, chainid string) *bft.GenesisDoc {
return &bft.GenesisDoc{
GenesisTime: time.Now(),
ChainID: chainid,
ConsensusParams: abci.ConsensusParams{
Block: &abci.BlockParams{
MaxTxBytes: 1_000_000, // 1MB,
MaxDataBytes: 2_000_000, // 2MB,
MaxGas: 10_0000_000, // 10M gas
TimeIotaMS: 100, // 100ms
},
},
AppState: &GnoGenesisState{
Balances: []Balance{},
Txs: []std.Tx{},
},
}
}
func NewDefaultTMConfig(rootdir string) *tmcfg.Config {
// We use `TestConfig` here otherwise ChainID will be empty, and
// there is no other way to update it than using a config file
return tmcfg.TestConfig().SetRootDir(rootdir)
}
// NewInMemoryNodeConfig creates a default configuration for an in-memory node.
func NewDefaultInMemoryNodeConfig(rootdir string) *InMemoryNodeConfig {
tm := NewDefaultTMConfig(rootdir)
// Create Mocked Identity
pv := NewMockedPrivValidator()
genesis := NewDefaultGenesisConfig(pv.GetPubKey(), tm.ChainID())
// Add self as validator
self := pv.GetPubKey()
genesis.Validators = []bft.GenesisValidator{
{
Address: self.Address(),
PubKey: self,
Power: 10,
Name: "self",
},
}
return &InMemoryNodeConfig{
PrivValidator: pv,
TMConfig: tm,
Genesis: genesis,
GenesisMaxVMCycles: 10_000_000,
}
}
func (cfg *InMemoryNodeConfig) validate() error {
if cfg.PrivValidator == nil {
return fmt.Errorf("`PrivValidator` is required but not provided")
}
if cfg.TMConfig == nil {
return fmt.Errorf("`TMConfig` is required but not provided")
}
if cfg.TMConfig.RootDir == "" {
return fmt.Errorf("`TMConfig.RootDir` is required to locate `stdlibs` directory")
}
return nil
}
// NewInMemoryNode creates an in-memory gnoland node. In this mode, the node does not
// persist any data and uses an in-memory database. The `InMemoryNodeConfig.TMConfig.RootDir`
// should point to the correct gno repository to load the stdlibs.
func NewInMemoryNode(logger *slog.Logger, cfg *InMemoryNodeConfig) (*node.Node, error) {
if err := cfg.validate(); err != nil {
return nil, fmt.Errorf("validate config error: %w", err)
}
// Initialize the application with the provided options
gnoApp, err := NewAppWithOptions(&AppOptions{
Logger: logger,
GnoRootDir: cfg.TMConfig.RootDir,
SkipFailingGenesisTxs: cfg.SkipFailingGenesisTxs,
MaxCycles: cfg.GenesisMaxVMCycles,
DB: db.NewMemDB(),
})
if err != nil {
return nil, fmt.Errorf("error initializing new app: %w", err)
}
cfg.TMConfig.LocalApp = gnoApp
// Setup app client creator
appClientCreator := proxy.DefaultClientCreator(
cfg.TMConfig.LocalApp,
cfg.TMConfig.ProxyApp,
cfg.TMConfig.ABCI,
cfg.TMConfig.DBDir(),
)
// Create genesis factory
genProvider := func() (*bft.GenesisDoc, error) { return cfg.Genesis, nil }
dbProvider := func(*node.DBContext) (db.DB, error) { return db.NewMemDB(), nil }
// generate p2p node identity
// XXX: do we need to configur
nodekey := &p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
// Create and return the in-memory node instance
return node.NewNode(cfg.TMConfig,
cfg.PrivValidator, nodekey,
appClientCreator,
genProvider,
dbProvider,
logger,
)
}
// GetNodeReadiness waits until the node is ready, signaling via the EventNewBlock event.
// XXX: This should be replace by https://github.com/gnolang/gno/pull/1216
func GetNodeReadiness(n *node.Node) <-chan struct{} {
const listenerID = "first_block_listener"
var once sync.Once
nb := make(chan struct{})
ready := func() {
close(nb)
n.EventSwitch().RemoveListener(listenerID)
}
n.EventSwitch().AddListener(listenerID, func(ev events.Event) {
if _, ok := ev.(bft.EventNewBlock); ok {
once.Do(ready)
}
})
if n.BlockStore().Height() > 0 {
once.Do(ready)
}
return nb
}