@blinklabs/dingo 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,7 +13,15 @@
13
13
 
14
14
  ⚠️ This is a work in progress and is currently under heavy development
15
15
 
16
- **Note:** On Windows systems, named pipes are used instead of Unix sockets for node-to-client communication.
16
+ A high-performance Cardano blockchain node implementation in Go by Blink Labs. Dingo provides:
17
+ - Full chain synchronization and validation via Ouroboros consensus protocol
18
+ - UTxO tracking with 41 UTXO validation rules and Plutus smart contract execution
19
+ - Client connectivity for wallets and applications
20
+ - Pluggable storage backends (Badger, SQLite, PostgreSQL, GCS, S3)
21
+ - Peer governance with dynamic peer selection and topology support
22
+ - Chain rollback support for handling forks with automatic state restoration
23
+
24
+ Note: On Windows systems, named pipes are used instead of Unix sockets for node-to-client communication.
17
25
 
18
26
  <div align="center">
19
27
  <img src="./.github/dingo-20241210.png" alt="dingo screenshot" width="640">
@@ -77,6 +85,7 @@ Dingo supports pluggable storage backends for both blob storage (blocks, transac
77
85
 
78
86
  **Metadata Storage Plugins:**
79
87
  - `sqlite` - SQLite relational database (default)
88
+ - `postgres` - PostgreSQL relational database
80
89
 
81
90
  ### Plugin Selection
82
91
 
@@ -123,6 +132,13 @@ Each plugin supports specific configuration options. See `dingo.yaml.example` fo
123
132
  **SQLite Options:**
124
133
  - `data-dir` - Path to SQLite database file
125
134
 
135
+ **PostgreSQL Options:**
136
+ - `host` - PostgreSQL server hostname
137
+ - `port` - PostgreSQL server port
138
+ - `username` - Database user
139
+ - `password` - Database password
140
+ - `database` - Database name
141
+
126
142
  ### Listing Available Plugins
127
143
 
128
144
  You can see all available plugins and their descriptions:
@@ -164,10 +180,12 @@ testing, so success/failure reports are very welcome and encouraged!
164
180
  - [x] LocalTxMonitor
165
181
  - [x] LocalTxSubmission
166
182
  - [x] LocalStateQuery
167
- - [ ] Peer governor
183
+ - [x] Peer governor
168
184
  - [x] Topology config
169
- - [ ] Peer churn
170
- - [ ] Ledger peers
185
+ - [x] Peer churn (full PeerChurnEvent with gossip/public root churn, bootstrap events)
186
+ - [x] Ledger peers
187
+ - [x] Peer sharing
188
+ - [x] Denied peers tracking
171
189
  - [x] Connection manager
172
190
  - [x] Inbound connections
173
191
  - [x] Node-to-client over TCP
@@ -178,12 +196,14 @@ testing, so success/failure reports are very welcome and encouraged!
178
196
  - [ ] Ledger
179
197
  - [x] Blocks
180
198
  - [x] Block storage
181
- - [ ] Chain selection
199
+ - [x] Chain selection (density comparison, VRF tie-breaker, ChainForkEvent)
182
200
  - [x] UTxO tracking
183
201
  - [x] Protocol parameters
202
+ - [x] Genesis validation
184
203
  - [ ] Certificates
185
204
  - [x] Pool registration
186
205
  - [x] Stake registration/delegation
206
+ - [x] Account registration checks
187
207
  - [ ] Governance
188
208
  - [ ] Transaction validation
189
209
  - [ ] Phase 1 validation
@@ -201,6 +221,14 @@ testing, so success/failure reports are very welcome and encouraged!
201
221
  - [x] Validation of transaction on add
202
222
  - [x] Consumer tracking
203
223
  - [x] Transaction purging on chain update
224
+ - [x] Database Recovery
225
+ - [x] Chain rollback support (SQLite and PostgreSQL plugins)
226
+ - [x] State restoration on rollback
227
+ - [x] WAL mode for crash recovery
228
+ - [x] Automatic rollback on transaction error
229
+ - [x] Plutus Validation
230
+ - [x] Plutus V3 smart contract validation
231
+ - [ ] Plutus V1/V2 smart contract validation
204
232
 
205
233
  Additional planned features can be found in our issue tracker and project boards.
206
234
 
@@ -46,12 +46,50 @@ database:
46
46
 
47
47
  # Metadata storage plugin configuration
48
48
  metadata:
49
- # Plugin to use for metadata storage (sqlite)
49
+ # Plugin to use for metadata storage (sqlite, postgres, mysql)
50
50
  plugin: "sqlite"
51
51
  # Configuration options for each plugin
52
52
  sqlite:
53
- # Data directory for SQLite database file
53
+ # Path to SQLite database file
54
54
  data-dir: ".dingo/metadata.db"
55
+ postgres:
56
+ # NOTE: These are example values for local development only.
57
+ # Do not use these credentials in production environments.
58
+ # Postgres host
59
+ host: "localhost"
60
+ # Postgres port
61
+ port: 5432
62
+ # Postgres user
63
+ user: "postgres"
64
+ # Postgres password (required - no default)
65
+ password: ""
66
+ # Postgres database name
67
+ database: "postgres"
68
+ # Postgres sslmode
69
+ ssl-mode: "disable"
70
+ # Postgres TimeZone
71
+ timezone: "UTC"
72
+ # Full Postgres DSN (overrides other options when set)
73
+ dsn: ""
74
+ mysql:
75
+ # NOTE: These are example values for local development only.
76
+ # Do not use these credentials in production environments.
77
+ # MySQL host
78
+ host: "localhost"
79
+ # MySQL port
80
+ port: 3306
81
+ # MySQL user
82
+ user: "root"
83
+ # MySQL password (required - no default)
84
+ password: ""
85
+ # MySQL database name
86
+ database: "mysql"
87
+ # MySQL TLS mode (mapped to tls= in DSN)
88
+ ssl-mode: ""
89
+ # MySQL time zone location
90
+ timezone: "UTC"
91
+ # Full MySQL DSN (overrides other options when set)
92
+ dsn: ""
55
93
 
56
94
  # Path to the UNIX domain socket file used by the server
57
95
  socketPath: "dingo.socket"
@@ -98,9 +136,44 @@ intersectTip: false
98
136
  # Default: 1048576 (1 MB)
99
137
  mempoolCapacity: 1048576
100
138
 
101
- # Enable development mode which prevents outbound connections
102
- # Default: false
103
- devMode: false
139
+ # Operational mode: "serve" (default), "load", or "dev"
140
+ # - serve: Full node with network connectivity (default)
141
+ # - load: Batch import from ImmutableDB (requires immutableDbPath)
142
+ # - dev: Development mode (forge blocks, disable outbound, skip topology)
143
+ # Note: CLI commands (serve, load) take priority over this setting
144
+ #
145
+ # Can be overridden with the DINGO_RUN_MODE environment variable
146
+ runMode: "serve"
147
+
148
+ # Path to ImmutableDB for batch import (used when runMode is "load")
149
+ # Can also be provided as argument to 'dingo load' command
150
+ #
151
+ # Can be overridden with the DINGO_IMMUTABLE_DB_PATH environment variable
152
+ immutableDbPath: ""
104
153
 
105
154
  # Validate historical blocks during ledger processing (default: false)
106
155
  validateHistorical: false
156
+
157
+ # Peer targets - target number of peers in each state
158
+ # These are goals the system works toward, not hard limits.
159
+ # Use 0 for default values, -1 for unlimited
160
+ # Default: known=150, established=50, active=20
161
+ #
162
+ # Target number of known (cold) peers
163
+ targetNumberOfKnownPeers: 0
164
+ # Target number of established (warm) peers
165
+ targetNumberOfEstablishedPeers: 0
166
+ # Target number of active (hot) peers
167
+ targetNumberOfActivePeers: 0
168
+
169
+ # Per-source quotas for active peers
170
+ # These specify how active peer slots are distributed by source.
171
+ # Use 0 for default values.
172
+ # Default: topology=3, gossip=12, ledger=5
173
+ #
174
+ # Active peer slots for topology sources (local + public roots)
175
+ activePeersTopologyQuota: 0
176
+ # Active peer slots for gossip sources
177
+ activePeersGossipQuota: 0
178
+ # Active peer slots for ledger sources
179
+ activePeersLedgerQuota: 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blinklabs/dingo",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "Dingo is a Cardano blockchain data node",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -1,306 +0,0 @@
1
- # Plugin Development Guide
2
-
3
- This guide explains how to develop plugins for Dingo's storage system.
4
-
5
- ## Overview
6
-
7
- Dingo supports pluggable storage backends through a registration-based plugin system. Plugins can extend the system with new blob storage (blocks, transactions) and metadata storage (indexes, state) implementations.
8
-
9
- ## Plugin Types
10
-
11
- ### Blob Storage Plugins
12
- Store blockchain data (blocks, transactions, etc.). Examples:
13
- - `badger` - Local BadgerDB key-value store
14
- - `gcs` - Google Cloud Storage
15
- - `s3` - AWS S3
16
-
17
- #### Iterator lifetime note
18
- Blob plugins expose iterators via `NewIterator(txn, opts)`. Items returned by the
19
- iterator's `Item()` must only be accessed while the transaction used to create
20
- the iterator is still active — implementations may validate transaction state at
21
- access time and will return errors if the transaction has been committed or
22
- rolled back. See `database/types/types.go` `BlobIterator` for details.
23
-
24
- ### Metadata Storage Plugins
25
- Store metadata and indexes. Examples:
26
- - `sqlite` - SQLite relational database
27
-
28
- ## Plugin Interface
29
-
30
- All plugins must implement the `plugin.Plugin` interface:
31
-
32
- ```go
33
- type Plugin interface {
34
- Start() error
35
- Stop() error
36
- }
37
- ```
38
-
39
- ## Plugin Registration
40
-
41
- Plugins register themselves during package initialization using the `plugin.Register()` function:
42
-
43
- ```go
44
- func init() {
45
- plugin.Register(plugin.PluginEntry{
46
- Type: plugin.PluginTypeBlob, // or PluginTypeMetadata
47
- Name: "myplugin",
48
- Description: "My custom storage plugin",
49
- NewFromOptionsFunc: NewFromCmdlineOptions,
50
- Options: []plugin.PluginOption{
51
- // Plugin-specific options
52
- },
53
- })
54
- }
55
- ```
56
-
57
- ## Plugin Options
58
-
59
- Plugins define configuration options using the `PluginOption` struct:
60
-
61
- ```go
62
- plugin.PluginOption{
63
- Name: "data-dir", // Option name
64
- Type: plugin.PluginOptionTypeString, // Data type
65
- Description: "Data directory path", // Help text
66
- DefaultValue: "/tmp/data", // Default value
67
- Dest: &cmdlineOptions.dataDir, // Destination variable
68
- }
69
- ```
70
-
71
- Supported option types:
72
- - `PluginOptionTypeString`
73
- - `PluginOptionTypeBool`
74
- - `PluginOptionTypeInt`
75
- - `PluginOptionTypeUint`
76
-
77
- ## Environment Variables
78
-
79
- Plugins automatically support environment variables with the pattern:
80
- `DINGO_DATABASE_{TYPE}_{PLUGIN}_{OPTION}`
81
-
82
- Examples:
83
- - `DINGO_DATABASE_BLOB_BADGER_DATA_DIR=/data`
84
- - `DINGO_DATABASE_METADATA_SQLITE_DATA_DIR=/metadata.db`
85
-
86
- ## YAML Configuration
87
-
88
- Plugins can be configured in `dingo.yaml`:
89
-
90
- ```yaml
91
- database:
92
- blob:
93
- plugin: "myplugin"
94
- myplugin:
95
- option1: "value1"
96
- option2: 42
97
- metadata:
98
- plugin: "sqlite"
99
- sqlite:
100
- data-dir: "/data/metadata.db"
101
- ```
102
-
103
- ## Configuration Precedence
104
-
105
- 1. Command-line flags (highest priority)
106
- 2. Environment variables
107
- 3. YAML configuration
108
- 4. Default values (lowest priority)
109
-
110
- ## Command Line Options
111
-
112
- Plugins support command-line flags with the pattern:
113
- `--{type}-{plugin}-{option}`
114
-
115
- Examples:
116
- - `--blob-badger-data-dir /data`
117
- - `--metadata-sqlite-data-dir /metadata.db`
118
-
119
- ## Plugin Development Steps
120
-
121
- ### 1. Create Plugin Structure
122
-
123
- ```text
124
- database/plugin/{type}/{name}/
125
- ├── plugin.go # Registration and options
126
- ├── options.go # Option functions
127
- ├── database.go # Core implementation
128
- └── options_test.go # Unit tests
129
- ```
130
-
131
- ### 2. Implement Core Plugin
132
-
133
- Create the main plugin struct that implements `plugin.Plugin`:
134
-
135
- ```go
136
- type MyPlugin struct {
137
- // Fields
138
- }
139
-
140
- func (p *MyPlugin) Start() error {
141
- // Initialize resources
142
- return nil
143
- }
144
-
145
- func (p *MyPlugin) Stop() error {
146
- // Clean up resources
147
- return nil
148
- }
149
- ```
150
-
151
- ### 3. Define Options
152
-
153
- Create option functions following the pattern:
154
-
155
- ```go
156
- func WithOptionName(value Type) OptionFunc {
157
- return func(p *MyPlugin) {
158
- p.field = value
159
- }
160
- }
161
- ```
162
-
163
- ### 4. Implement Constructors
164
-
165
- Provide both options-based and legacy constructors:
166
-
167
- ```go
168
- func NewWithOptions(opts ...OptionFunc) (*MyPlugin, error) {
169
- p := &MyPlugin{}
170
- for _, opt := range opts {
171
- opt(p)
172
- }
173
- return p, nil
174
- }
175
-
176
- func New(legacyParam1, legacyParam2) (*MyPlugin, error) {
177
- // For backward compatibility
178
- return NewWithOptions(
179
- WithOption1(legacyParam1),
180
- WithOption2(legacyParam2),
181
- )
182
- }
183
- ```
184
-
185
- ### 5. Register Plugin
186
-
187
- In `plugin.go`, register during initialization:
188
-
189
- ```go
190
- var cmdlineOptions struct {
191
- option1 string
192
- option2 int
193
- }
194
-
195
- func init() {
196
- plugin.Register(plugin.PluginEntry{
197
- Type: plugin.PluginTypeBlob,
198
- Name: "myplugin",
199
- Description: "My custom plugin",
200
- NewFromOptionsFunc: NewFromCmdlineOptions,
201
- Options: []plugin.PluginOption{
202
- {
203
- Name: "option1",
204
- Type: plugin.PluginOptionTypeString,
205
- Description: "First option",
206
- DefaultValue: "default",
207
- Dest: &cmdlineOptions.option1,
208
- },
209
- // More options...
210
- },
211
- })
212
- }
213
-
214
- func NewFromCmdlineOptions() plugin.Plugin {
215
- p, err := NewWithOptions(
216
- WithOption1(cmdlineOptions.option1),
217
- WithOption2(cmdlineOptions.option2),
218
- )
219
- if err != nil {
220
- panic(err)
221
- }
222
- return p
223
- }
224
- ```
225
-
226
- ### 6. Add Tests
227
-
228
- Create comprehensive tests:
229
-
230
- ```go
231
- func TestOptions(t *testing.T) {
232
- // Test option functions
233
- }
234
-
235
- func TestLifecycle(t *testing.T) {
236
- p, err := NewWithOptions(WithOption1("test"))
237
- // Test Start/Stop
238
- }
239
- ```
240
-
241
- ### 7. Update Imports
242
-
243
- Add your plugin to the import list in the appropriate store file:
244
- - `database/plugin/blob/blob.go` for blob plugins
245
- - `database/plugin/metadata/metadata.go` for metadata plugins
246
-
247
- ## Example: Complete Plugin
248
-
249
- See the existing plugins for complete examples:
250
- - `database/plugin/blob/badger/` - BadgerDB implementation
251
- - `database/plugin/metadata/sqlite/` - SQLite implementation
252
- - `database/plugin/blob/gcs/` - Google Cloud Storage implementation
253
- - `database/plugin/blob/aws/` - AWS S3 implementation
254
-
255
- ## Best Practices
256
-
257
- 1. **Error Handling**: Always return descriptive errors
258
- 2. **Resource Management**: Properly implement Start/Stop for resource lifecycle
259
- 3. **Thread Safety**: Ensure plugins are safe for concurrent use
260
- 4. **Configuration Validation**: Validate configuration during construction
261
- 5. **Backward Compatibility**: Maintain compatibility with existing deployments
262
- 6. **Documentation**: Document all options and their effects
263
- 7. **Testing**: Provide comprehensive unit and integration tests
264
-
265
- ## Testing Your Plugin
266
-
267
- ### Unit Tests
268
- Test individual components and option functions.
269
-
270
- ### Integration Tests
271
- Test the complete plugin lifecycle and interaction with the plugin system.
272
-
273
- ### CLI Testing
274
- Use the CLI to test plugin listing and selection:
275
-
276
- ```bash
277
- ./dingo --blob list
278
- ./dingo --metadata list
279
- ```
280
-
281
- ### Configuration Testing
282
- Test environment variables and YAML configuration:
283
-
284
- ```bash
285
- DINGO_DATABASE_BLOB_MYPLUGIN_OPTION1=value ./dingo --blob myplugin
286
- ```
287
-
288
- ## Programmatic Option Overrides (for tests)
289
-
290
- When writing tests or programmatically constructing database instances you can override plugin options
291
- without importing plugin implementation packages directly by using the plugin registry helper:
292
-
293
- ```go
294
- // Set data-dir for the blob plugin to a per-test temp directory
295
- plugin.SetPluginOption(plugin.PluginTypeBlob, "badger", "data-dir", t.TempDir())
296
-
297
- // Set data-dir for the metadata plugin
298
- plugin.SetPluginOption(plugin.PluginTypeMetadata, "sqlite", "data-dir", t.TempDir())
299
- ```
300
-
301
- The helper sets the plugin option's destination variable in the registry before plugin instantiation.
302
- If the requested option is not defined by the targeted plugin the call is non-fatal and returns nil,
303
- allowing tests to run regardless of which plugin implementation is selected.
304
-
305
- Using `t.TempDir()` guarantees each test uses its own on-disk path and prevents concurrent tests from
306
- colliding on shared directories (for example the default `.dingo` Badger directory).