@blinklabs/dingo 0.17.0 → 0.19.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.
@@ -0,0 +1,306 @@
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).
package/README.md CHANGED
@@ -13,6 +13,8 @@
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.
17
+
16
18
  <div align="center">
17
19
  <img src="./.github/dingo-20241210.png" alt="dingo screenshot" width="640">
18
20
  </div>
@@ -62,6 +64,78 @@ This behavior can be changed via the following environment variables:
62
64
  (default: empty)
63
65
  - `TLS_KEY_FILE_PATH` - SSL certificate key to use (default: empty)
64
66
 
67
+ ## Database Plugins
68
+
69
+ Dingo supports pluggable storage backends for both blob storage (blocks, transactions) and metadata storage. This allows you to choose the best storage solution for your use case.
70
+
71
+ ### Available Plugins
72
+
73
+ **Blob Storage Plugins:**
74
+ - `badger` - BadgerDB local key-value store (default)
75
+ - `gcs` - Google Cloud Storage blob store
76
+ - `s3` - AWS S3 blob store
77
+
78
+ **Metadata Storage Plugins:**
79
+ - `sqlite` - SQLite relational database (default)
80
+
81
+ ### Plugin Selection
82
+
83
+ Plugins can be selected via command-line flags, environment variables, or configuration file:
84
+
85
+ ```bash
86
+ # Command line
87
+ ./dingo --blob gcs --metadata sqlite
88
+
89
+ # Environment variables
90
+ DINGO_DATABASE_BLOB_PLUGIN=gcs
91
+ DINGO_DATABASE_METADATA_PLUGIN=sqlite
92
+
93
+ # Configuration file (dingo.yaml)
94
+ database:
95
+ blob:
96
+ plugin: "gcs"
97
+ metadata:
98
+ plugin: "sqlite"
99
+ ```
100
+
101
+ ### Plugin Configuration
102
+
103
+ Each plugin supports specific configuration options. See `dingo.yaml.example` for detailed configuration examples.
104
+
105
+ **BadgerDB Options:**
106
+ - `data-dir` - Directory for database files
107
+ - `block-cache-size` - Block cache size in bytes
108
+ - `index-cache-size` - Index cache size in bytes
109
+ - `gc` - Enable garbage collection
110
+
111
+ **Google Cloud Storage Options:**
112
+ - `bucket` - GCS bucket name
113
+ - `project-id` - Google Cloud project ID
114
+ - `prefix` - Path prefix within bucket
115
+ - `credentials-file` - Path to service account credentials file (optional - uses Application Default Credentials if not provided)
116
+
117
+ **AWS S3 Options:**
118
+ - `bucket` - S3 bucket name
119
+ - `region` - AWS region
120
+ - `prefix` - Path prefix within bucket
121
+ - `access-key-id` - AWS access key ID (optional - uses default credential chain if not provided)
122
+ - `secret-access-key` - AWS secret access key (optional - uses default credential chain if not provided)
123
+
124
+ **SQLite Options:**
125
+ - `data-dir` - Path to SQLite database file
126
+
127
+ ### Listing Available Plugins
128
+
129
+ You can see all available plugins and their descriptions:
130
+
131
+ ```bash
132
+ ./dingo list
133
+ ```
134
+
135
+ ## Plugin Development
136
+
137
+ For information on developing custom storage plugins, see [PLUGIN_DEVELOPMENT.md](PLUGIN_DEVELOPMENT.md).
138
+
65
139
  ### Example
66
140
 
67
141
  Running on mainnet (:sweat_smile:):
@@ -0,0 +1,130 @@
1
+ # Dingo Ledger & Database Benchmark Results
2
+
3
+ ## Latest Results
4
+
5
+ ### Test Environment
6
+ - **Date**: November 26, 2025
7
+ - **Go Version**: 1.24.1
8
+ - **OS**: Linux
9
+ - **Architecture**: aarch64
10
+ - **CPU Cores**: 128
11
+ - **Data Source**: Real Cardano preview testnet data (40k+ blocks, slots 0-863,996)
12
+
13
+ ### Benchmark Results
14
+
15
+ All benchmarks run with `-benchmem` flag showing memory allocations and operation counts.
16
+
17
+ | Benchmark | Operations/sec | Time/op | Memory/op | Allocs/op |
18
+ |-----------|----------------|---------|-----------|-----------|
19
+ | Pool Lookup By Key Hash No Data | 36231 | 33604ns | 4KB | 79 |
20
+ | Pool Registration Lookups No Data | 24210 | 46595ns | 10KB | 93 |
21
+ | Account Lookup By Stake Key Real Data | 39950 | 34026ns | 4KB | 75 |
22
+ | Utxo Lookup By Address No Data | 109825 | 16460ns | 2KB | 19 |
23
+ | Storage Backends/memory | 32593 | 34818ns | 13KB | 70 |
24
+ | Transaction Validation | 230958193 | 5.238ns | 0B | 0 |
25
+ | Real Block Reading | 22 | 53427289ns | 2183KB | 74472 |
26
+ | Block Retrieval By Index Real Data | 303981 | 3868ns | 472B | 11 |
27
+ | Index Building Time | 14078 | 87080ns | 17KB | 119 |
28
+ | Chain Sync From Genesis | 74 | 15096067ns | 100.0blocks_processed | 2247880 |
29
+ | Block Retrieval By Index No Data | 315110 | 3652ns | 472B | 11 |
30
+ | Transaction Create | 77013 | 16824ns | 2KB | 18 |
31
+ | Utxo Lookup By Address Real Data | 82125 | 16014ns | 2KB | 19 |
32
+ | Era Transition Performance | 459890545 | 2.178ns | 0B | 0 |
33
+ | Protocol Parameters Lookup By Epoch Real Data | 44181 | 32903ns | 5KB | 62 |
34
+ | Pool Registration Lookups Real Data | 22616 | 48729ns | 10KB | 93 |
35
+ | Stake Registration Lookups Real Data | 38761 | 33724ns | 5KB | 69 |
36
+ | Era Transition Performance Real Data | 4340 | 267246ns | 83KB | 490 |
37
+ | Real Block Processing | 13651 | 84993ns | 17KB | 119 |
38
+ | Utxo Lookup By Ref No Data | 10461 | 119506ns | 8KB | 131 |
39
+ | Storage Backends/disk | 33004 | 32561ns | 13KB | 70 |
40
+ | Test Load/memory | 1912 | 650898ns | 260KB | 1400 |
41
+ | Stake Registration Lookups No Data | 33963 | 33887ns | 5KB | 69 |
42
+ | Utxo Lookup By Ref Real Data | 10000 | 122404ns | 8KB | 131 |
43
+ | Protocol Parameters Lookup By Epoch No Data | 37996 | 32298ns | 5KB | 62 |
44
+ | Datum Lookup By Hash No Data | 32635 | 34072ns | 4KB | 69 |
45
+ | Block Processing Throughput | 3904 | 290370ns | 3444blocks/sec | 22462 |
46
+ | Real Data Queries | 68570 | 17752ns | 5KB | 43 |
47
+ | Block Nonce Lookup Real Data | 34851 | 37815ns | 4KB | 73 |
48
+ | Test Load/disk | 2068 | 536686ns | 260KB | 1400 |
49
+ | Pool Lookup By Key Hash Real Data | 40214 | 33631ns | 4KB | 79 |
50
+ | D Rep Lookup By Key Hash No Data | 35266 | 36094ns | 4KB | 77 |
51
+ | Transaction History Queries No Data | 34167 | 33889ns | 4KB | 78 |
52
+ | Datum Lookup By Hash Real Data | 44810 | 33686ns | 4KB | 69 |
53
+ | Block Nonce Lookup No Data | 32011 | 36515ns | 4KB | 73 |
54
+ | Account Lookup By Stake Key No Data | 34898 | 35142ns | 4KB | 75 |
55
+ | Transaction History Queries Real Data | 37575 | 34812ns | 4KB | 78 |
56
+ | Concurrent Queries | 15408 | 68781ns | 14581queries/sec | 3943 |
57
+ | D Rep Lookup By Key Hash Real Data | 39360 | 34907ns | 4KB | 77 |
58
+ | Block Memory Usage | 29292 | 44369ns | 14KB | 49 |
59
+
60
+ ## Performance Changes
61
+
62
+ Changes since **November 26, 2025**:
63
+
64
+ ### Summary
65
+ - **Faster benchmarks**: 19
66
+ - **Slower benchmarks**: 20
67
+ - **New benchmarks**: 0
68
+ - **Removed benchmarks**: 0
69
+
70
+ ### Top Improvements
71
+ - Utxo Lookup By Address No Data (+44%)
72
+ - Transaction Validation (+0%)
73
+ - Test Load/memory (+19%)
74
+ - Test Load/disk (+31%)
75
+ - Storage Backends/memory (+3%)
76
+
77
+ ### Performance Regressions
78
+ - Pool Lookup By Key Hash No Data (-0%)
79
+ - Index Building Time (-0%)
80
+ - Account Lookup By Stake Key No Data (-0%)
81
+ - Transaction History Queries No Data (-1%)
82
+ - Stake Registration Lookups No Data (-1%)
83
+
84
+
85
+ ## Historical Results
86
+
87
+ ### November 26, 2025
88
+
89
+ | Benchmark | Operations/sec | Time/op | Memory/op | Allocs/op |
90
+ |-----------|----------------|---------|-----------|-----------|
91
+ | Pool Lookup By Key Hash No Data | 36328 | 33556ns | 4KB | 79 |
92
+ | Pool Registration Lookups No Data | 24898 | 51298ns | 10KB | 93 |
93
+ | Account Lookup By Stake Key Real Data | 39936 | 33871ns | 4KB | 75 |
94
+ | Utxo Lookup By Address No Data | 75966 | 16953ns | 2KB | 19 |
95
+ | Storage Backends/memory | 31369 | 33394ns | 13KB | 70 |
96
+ | Transaction Validation | 230637091 | 5.213ns | 0B | 0 |
97
+ | Real Block Reading | 20 | 55046083ns | 2183KB | 74472 |
98
+ | Block Retrieval By Index Real Data | 312492 | 4102ns | 472B | 11 |
99
+ | Index Building Time | 14168 | 86378ns | 17KB | 119 |
100
+ | Chain Sync From Genesis | 100 | 14189212ns | 100.0blocks_processed | 2247966 |
101
+ | Block Retrieval By Index No Data | 277410 | 4025ns | 472B | 11 |
102
+ | Transaction Create | 92761 | 16456ns | 2KB | 18 |
103
+ | Utxo Lookup By Address Real Data | 86467 | 15705ns | 2KB | 19 |
104
+ | Era Transition Performance | 499031763 | 2.139ns | 0B | 0 |
105
+ | Protocol Parameters Lookup By Epoch Real Data | 44150 | 30066ns | 5KB | 62 |
106
+ | Pool Registration Lookups Real Data | 23724 | 48201ns | 10KB | 93 |
107
+ | Stake Registration Lookups Real Data | 40082 | 32844ns | 5KB | 69 |
108
+ | Era Transition Performance Real Data | 3525 | 305364ns | 83KB | 490 |
109
+ | Real Block Processing | 13509 | 87846ns | 17KB | 119 |
110
+ | Utxo Lookup By Ref No Data | 10724 | 111792ns | 8KB | 131 |
111
+ | Storage Backends/disk | 28960 | 37643ns | 13KB | 70 |
112
+ | Test Load/memory | 1605 | 669272ns | 260KB | 1400 |
113
+ | Stake Registration Lookups No Data | 34359 | 36417ns | 5KB | 69 |
114
+ | Utxo Lookup By Ref Real Data | 10000 | 111756ns | 8KB | 131 |
115
+ | Protocol Parameters Lookup By Epoch No Data | 37886 | 32905ns | 5KB | 62 |
116
+ | Datum Lookup By Hash No Data | 40302 | 29076ns | 4KB | 69 |
117
+ | Block Processing Throughput | 4632 | 287053ns | 3484blocks/sec | 22466 |
118
+ | Real Data Queries | 62532 | 19011ns | 5KB | 43 |
119
+ | Block Nonce Lookup Real Data | 35782 | 38514ns | 4KB | 73 |
120
+ | Test Load/disk | 1574 | 711525ns | 260KB | 1400 |
121
+ | Pool Lookup By Key Hash Real Data | 39812 | 33599ns | 4KB | 79 |
122
+ | D Rep Lookup By Key Hash No Data | 35139 | 35088ns | 4KB | 77 |
123
+ | Transaction History Queries No Data | 34530 | 36887ns | 4KB | 78 |
124
+ | Datum Lookup By Hash Real Data | 36972 | 31369ns | 4KB | 69 |
125
+ | Block Nonce Lookup No Data | 32977 | 36460ns | 4KB | 73 |
126
+ | Account Lookup By Stake Key No Data | 35020 | 32890ns | 4KB | 75 |
127
+ | Transaction History Queries Real Data | 38739 | 35904ns | 4KB | 78 |
128
+ | D Rep Lookup By Key Hash Real Data | 38977 | 36859ns | 4KB | 77 |
129
+ | Concurrent Queries | 19104 | 59527ns | 168280queries/sec | 3851 |
130
+ | Block Memory Usage | 26552 | 46212ns | 14KB | 49 |
package/devnet.sh CHANGED
@@ -1,5 +1,19 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
+ # Copyright 2025 Blink Labs Software
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
3
17
  export CARDANO_NETWORK=devnet
4
18
  export CARDANO_CONFIG=./config/cardano/devnet/config.json
5
19
  export CARDANO_DATABASE_PATH=.devnet
@@ -9,8 +9,51 @@ bindAddr: "0.0.0.0"
9
9
  # Can be overridden with the config environment variable
10
10
  cardanoConfig: "./config/cardano/preview/config.json"
11
11
 
12
- # A directory which contains the ledger database files
13
- databasePath: ".dingo"
12
+ # Database configuration
13
+ database:
14
+ # Blob storage plugin configuration
15
+ blob:
16
+ # Plugin to use for blob storage (badger, gcs, s3)
17
+ plugin: "badger"
18
+ # Configuration options for each plugin
19
+ badger:
20
+ # Data directory for BadgerDB storage
21
+ data-dir: ".dingo/badger"
22
+ # Block cache size in bytes (default: 1610612736 ~1.5GB)
23
+ block-cache-size: 1610612736
24
+ # Index cache size in bytes (default: 536870912 ~512MB)
25
+ index-cache-size: 536870912
26
+ # Enable garbage collection (default: true)
27
+ gc: true
28
+ gcs:
29
+ # Google Cloud Storage bucket name
30
+ bucket: ""
31
+ # Google Cloud project ID
32
+ project-id: ""
33
+ # Path prefix within the bucket
34
+ prefix: ""
35
+ # Path to service account credentials file (optional - uses Application Default Credentials if not set)
36
+ credentials-file: ""
37
+ s3:
38
+ # AWS S3 bucket name
39
+ bucket: ""
40
+ # AWS region
41
+ region: ""
42
+ # Path prefix within the bucket
43
+ prefix: ""
44
+ # AWS access key ID (optional - uses default credential chain if not set)
45
+ access-key-id: ""
46
+ # AWS secret access key (optional - uses default credential chain if not set)
47
+ secret-access-key: ""
48
+
49
+ # Metadata storage plugin configuration
50
+ metadata:
51
+ # Plugin to use for metadata storage (sqlite)
52
+ plugin: "sqlite"
53
+ # Configuration options for each plugin
54
+ sqlite:
55
+ # Data directory for SQLite database file
56
+ data-dir: ".dingo/metadata.db"
14
57
 
15
58
  # Path to the UNIX domain socket file used by the server
16
59
  socketPath: "dingo.socket"
@@ -52,10 +95,6 @@ utxorpcPort: 9090
52
95
  # This is experimental and may break — use with caution
53
96
  intersectTip: false
54
97
 
55
- # Maximum cache size in bytes used by BadgerDB for block/index cache
56
- # Default: 1073741824 (1 GB)
57
- badgerCacheSize: 1073741824
58
-
59
98
  # Maximum total size (in bytes) of all transactions allowed in the mempool.
60
99
  # Transactions exceeding this limit will be rejected.
61
100
  # Default: 1048576 (1 MB)
@@ -0,0 +1,469 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Copyright 2025 Blink Labs Software
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # Script to generate benchmark results for Dingo ledger and database with historical tracking
18
+ # Usage: ./generate_benchmarks.sh [output_file] [--write]
19
+ # --write: Write results to file (default: display only)
20
+
21
+ WRITE_TO_FILE=false
22
+ OUTPUT_FILE="benchmark_results.md"
23
+
24
+ # Parse arguments
25
+ while [[ $# -gt 0 ]]; do
26
+ case $1 in
27
+ --write)
28
+ WRITE_TO_FILE=true
29
+ shift
30
+ ;;
31
+ -*)
32
+ echo "Unknown option: $1"
33
+ echo "Usage: $0 [output_file] [--write]"
34
+ exit 1
35
+ ;;
36
+ *)
37
+ # First non-option argument is the output file
38
+ if [[ -z "$OUTPUT_FILE_SET" ]]; then
39
+ OUTPUT_FILE="$1"
40
+ OUTPUT_FILE_SET=true
41
+ else
42
+ echo "Too many arguments. Usage: $0 [output_file] [--write]"
43
+ exit 1
44
+ fi
45
+ shift
46
+ ;;
47
+ esac
48
+ done
49
+
50
+ DATE=$(date +"%B %d, %Y")
51
+
52
+ # Initialize environment information for benchmark report
53
+ GO_VERSION=$(go version | awk '{print $3}' | sed 's/go//')
54
+ OS=$(uname -s)
55
+ ARCH=$(uname -m)
56
+ CPU_CORES=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo "unknown")
57
+
58
+ echo "Running all Dingo benchmarks..."
59
+ echo "==============================="
60
+
61
+ # Run benchmarks with progress output first
62
+ echo "Executing benchmarks (this may take a few minutes)..."
63
+
64
+ # Enable pipefail to catch go test failures in the pipeline
65
+ set -o pipefail
66
+
67
+ # Run go test once, capture output while showing progress
68
+ BENCHMARK_OUTPUT=$(go test -bench=. -benchmem ./... -run=^$ 2>&1)
69
+ GO_TEST_EXIT_CODE=$?
70
+
71
+ # Show progress by parsing benchmark names from output
72
+ echo "$BENCHMARK_OUTPUT" | grep "^Benchmark" | sed 's/Benchmark//' | sed 's/-[0-9]*$//' | while read -r name rest; do
73
+ echo "Running: $name-128"
74
+ done
75
+
76
+ # Check if go test succeeded
77
+ if [[ $GO_TEST_EXIT_CODE -ne 0 ]]; then
78
+ echo "Benchmark run failed!"
79
+ exit 1
80
+ fi
81
+
82
+ # Count benchmarks
83
+ BENCHMARK_COUNT=$(echo "$BENCHMARK_OUTPUT" | grep "^Benchmark" | wc -l)
84
+
85
+ echo "Found $BENCHMARK_COUNT benchmarks across all packages"
86
+ echo ""
87
+
88
+ # Function to parse benchmark line
89
+ parse_benchmark() {
90
+ local line="$1"
91
+ local name
92
+ name=$(echo "$line" | awk '{print $1}' | sed 's/Benchmark//' | sed 's/-[0-9]*$//')
93
+ local ops_sec
94
+ ops_sec=$(echo "$line" | awk '{print $2}' | sed 's/,//g')
95
+ local time_val
96
+ time_val=$(echo "$line" | awk '{print $3}')
97
+ local time_unit
98
+ time_unit=$(echo "$line" | awk '{print $4}')
99
+ local mem_val
100
+ mem_val=$(echo "$line" | awk '{print $5}')
101
+ local mem_unit
102
+ mem_unit=$(echo "$line" | awk '{print $6}')
103
+ local allocs_op
104
+ allocs_op=$(echo "$line" | awk '{print $7}')
105
+
106
+ # Format time
107
+ if [[ "$time_unit" == "ns/op" ]]; then
108
+ time_op="${time_val}ns"
109
+ elif [[ "$time_unit" == "μs/op" ]] || [[ "$time_unit" == "µs/op" ]]; then
110
+ time_op="${time_val}μs"
111
+ elif [[ "$time_unit" == "ms/op" ]]; then
112
+ time_op="${time_val}ms"
113
+ elif [[ "$time_unit" == "s/op" ]]; then
114
+ time_op="${time_val}s"
115
+ else
116
+ time_op="${time_val}${time_unit}"
117
+ fi
118
+
119
+ # Format memory
120
+ if [[ "$mem_unit" == "B/op" ]]; then
121
+ if [[ $mem_val -gt 1000 ]]; then
122
+ mem_kb=$((mem_val / 1000))
123
+ mem_op="${mem_kb}KB"
124
+ else
125
+ mem_op="${mem_val}B"
126
+ fi
127
+ else
128
+ mem_op="${mem_val}${mem_unit}"
129
+ fi
130
+
131
+ # Format benchmark name nicely
132
+ formatted_name=$(echo "$name" | sed 's/\([A-Z]\)/ \1/g' | sed 's/^ //' | sed 's/NoData$/ (No Data)/' | sed 's/RealData$/ (Real Data)/')
133
+
134
+ echo "$formatted_name|$ops_sec|$time_op|$mem_op|$allocs_op"
135
+ }
136
+
137
+ # Parse current results into temporary file
138
+ CURRENT_RESULTS_FILE=$(mktemp "${TMPDIR:-/tmp}/dingo_bench_XXXXXX")
139
+ while IFS= read -r line; do
140
+ if [[ "$line" =~ ^Benchmark ]]; then
141
+ parsed=$(parse_benchmark "$line")
142
+ name=$(echo "$parsed" | cut -d'|' -f1)
143
+ data=$(echo "$parsed" | cut -d'|' -f2-)
144
+ echo "$name|$data" >> "$CURRENT_RESULTS_FILE"
145
+ fi
146
+ done <<< "$BENCHMARK_OUTPUT"
147
+
148
+ # Deduplicate benchmark names
149
+ sort -t'|' -k1,1 -u "$CURRENT_RESULTS_FILE" > "$CURRENT_RESULTS_FILE.tmp" && mv "$CURRENT_RESULTS_FILE.tmp" "$CURRENT_RESULTS_FILE"
150
+
151
+ # Display current results summary
152
+ echo "Current Benchmark Summary"
153
+ echo "-------------------------"
154
+ echo "Fastest benchmarks (>100k ops/sec):"
155
+ echo "$BENCHMARK_OUTPUT" | grep "^Benchmark" | sort -k2 -nr | head -3 | while read -r line; do
156
+ name=$(echo "$line" | awk '{print $1}' | sed 's/Benchmark//' | sed 's/-128$//')
157
+ ops=$(echo "$line" | awk '{print $2}' | sed 's/,//g')
158
+ echo " - $name: ${ops} ops/sec"
159
+ done
160
+
161
+ echo ""
162
+ echo "Slowest benchmarks (<1k ops/sec):"
163
+ echo "$BENCHMARK_OUTPUT" | grep "^Benchmark" | awk '$2 < 1000' | while read -r line; do
164
+ name=$(echo "$line" | awk '{print $1}' | sed 's/Benchmark//' | sed 's/-128$//')
165
+ ops=$(echo "$line" | awk '{print $2}' | sed 's/,//g')
166
+ echo " - $name: ${ops} ops/sec"
167
+ done
168
+
169
+ echo ""
170
+ echo "Memory usage:"
171
+ echo "$BENCHMARK_OUTPUT" | grep "^Benchmark" | sort -k5 -nr | head -3 | while read -r line; do
172
+ name=$(echo "$line" | awk '{print $1}' | sed 's/Benchmark//' | sed 's/-128$//')
173
+ mem=$(echo "$line" | awk '{print $5}')
174
+ echo " - $name: ${mem}B per op"
175
+ done
176
+
177
+ # Read previous results if file exists and we're comparing
178
+ PREVIOUS_RESULTS_FILE=$(mktemp "${TMPDIR:-/tmp}/dingo_bench_XXXXXX")
179
+ trap 'rm -f "$CURRENT_RESULTS_FILE" "$PREVIOUS_RESULTS_FILE"' EXIT
180
+ previous_date=""
181
+ MAJOR_CHANGES=false
182
+
183
+ if [[ -f "$OUTPUT_FILE" && "$WRITE_TO_FILE" == "true" ]]; then
184
+ echo ""
185
+ echo "Comparing with previous results..."
186
+ # Extract previous date
187
+ previous_date=$(grep "\*\*Date\*\*:" "$OUTPUT_FILE" | head -1 | sed 's/.*\*\*Date\*\*: //' || echo "")
188
+
189
+ # Parse previous benchmark table
190
+ in_table=false
191
+ while IFS= read -r line; do
192
+ # Stop parsing at performance changes or historical results sections
193
+ if [[ "$line" == "## Performance Changes" || "$line" == "## Historical Results" ]]; then
194
+ break
195
+ fi
196
+ if [[ "$line" == "| Benchmark | Operations/sec | Time/op | Memory/op | Allocs/op |" ]]; then
197
+ in_table=true
198
+ continue
199
+ fi
200
+ if [[ "$in_table" == true && "$line" =~ ^\|.*\|.*\|.*\|.*\|.*\|$ && "$line" != "|-----------|*" ]]; then
201
+ # Parse table row
202
+ benchmark=$(echo "$line" | sed 's/^| //' | cut -d'|' -f1 | sed 's/ *$//')
203
+ ops_sec=$(echo "$line" | sed 's/^| //' | cut -d'|' -f2 | sed 's/ //g' | sed 's/,//g')
204
+ time_op=$(echo "$line" | sed 's/^| //' | cut -d'|' -f3 | sed 's/ //g')
205
+ mem_op=$(echo "$line" | sed 's/^| //' | cut -d'|' -f4 | sed 's/ //g')
206
+ allocs_op=$(echo "$line" | sed 's/^| //' | cut -d'|' -f5 | sed 's/ //g')
207
+ if [[ -n "$benchmark" && -n "$ops_sec" ]]; then
208
+ echo "$benchmark|$ops_sec|$time_op|$mem_op|$allocs_op" >> "$PREVIOUS_RESULTS_FILE"
209
+ fi
210
+ fi
211
+ if [[ "$in_table" == true && "$line" == "" ]]; then
212
+ in_table=false
213
+ fi
214
+ done < "$OUTPUT_FILE"
215
+ fi
216
+
217
+ # Deduplicate previous benchmark names
218
+ sort -t'|' -k1,1 -u "$PREVIOUS_RESULTS_FILE" > "$PREVIOUS_RESULTS_FILE.tmp" && mv "$PREVIOUS_RESULTS_FILE.tmp" "$PREVIOUS_RESULTS_FILE"
219
+
220
+ # Helper functions to get data from temp files
221
+ get_current_data() {
222
+ local benchmark="$1"
223
+ awk -F'|' '$1 == "'"$benchmark"'" {print substr($0, index($0, "|")+1)}' "$CURRENT_RESULTS_FILE"
224
+ }
225
+
226
+ get_previous_data() {
227
+ local benchmark="$1"
228
+ awk -F'|' '$1 == "'"$benchmark"'" {print substr($0, index($0, "|")+1)}' "$PREVIOUS_RESULTS_FILE"
229
+ }
230
+
231
+ list_current_benchmarks() {
232
+ awk -F'|' '!seen[$1]++ {print $1}' "$CURRENT_RESULTS_FILE"
233
+ }
234
+
235
+ list_previous_benchmarks() {
236
+ awk -F'|' '!seen[$1]++ {print $1}' "$PREVIOUS_RESULTS_FILE"
237
+ }
238
+
239
+ # Generate performance comparison if we have previous results
240
+ if [[ -n "$previous_date" && "$WRITE_TO_FILE" == "true" ]]; then
241
+ # Track changes
242
+ faster_benchmarks=""
243
+ slower_benchmarks=""
244
+ new_benchmarks=""
245
+ removed_benchmarks=""
246
+
247
+ # Compare results
248
+ while IFS= read -r benchmark; do
249
+ if [[ -n "$(get_previous_data "$benchmark")" ]]; then
250
+ # Benchmark exists in both
251
+ current_data=$(get_current_data "$benchmark")
252
+ previous_data=$(get_previous_data "$benchmark")
253
+
254
+ current_ops=$(echo "$current_data" | cut -d'|' -f1)
255
+ previous_ops=$(echo "$previous_data" | cut -d'|' -f1)
256
+
257
+ if [[ "$current_ops" =~ ^[0-9]+$ && "$previous_ops" =~ ^[0-9]+$ && $previous_ops -gt 0 ]]; then
258
+ change=$(( (current_ops - previous_ops) * 100 / previous_ops ))
259
+ if [[ $change -gt 10 ]]; then
260
+ faster_benchmarks="$faster_benchmarks
261
+ $benchmark (+${change}%)"
262
+ elif [[ $change -lt -10 ]]; then
263
+ change_abs=$(( (previous_ops - current_ops) * 100 / previous_ops ))
264
+ slower_benchmarks="$slower_benchmarks
265
+ $benchmark (-${change_abs}%)"
266
+ MAJOR_CHANGES=true
267
+ fi
268
+ fi
269
+ else
270
+ new_benchmarks="$new_benchmarks
271
+ $benchmark"
272
+ fi
273
+ done < <(list_current_benchmarks)
274
+
275
+ # Check for removed benchmarks
276
+ while IFS= read -r benchmark; do
277
+ if [[ -z "$(get_current_data "$benchmark")" ]]; then
278
+ removed_benchmarks="$removed_benchmarks
279
+ $benchmark"
280
+ fi
281
+ done < <(list_previous_benchmarks)
282
+
283
+ # Count items (remove empty lines and count)
284
+ faster_count=$(echo "$faster_benchmarks" | grep -c "^." || echo "0")
285
+ slower_count=$(echo "$slower_benchmarks" | grep -c "^." || echo "0")
286
+ new_count=$(echo "$new_benchmarks" | grep -c "^." || echo "0")
287
+ removed_count=$(echo "$removed_benchmarks" | grep -c "^." || echo "0")
288
+
289
+ echo ""
290
+ echo "Performance Changes Summary:"
291
+ echo " Faster: $faster_count | Slower: $slower_count | New: $new_count | Removed: $removed_count"
292
+
293
+ # Report changes if any improvements, regressions, or new benchmarks detected
294
+ if [[ $faster_count -gt 0 || $slower_count -gt 0 || $new_count -gt 0 ]]; then
295
+ MAJOR_CHANGES=true
296
+ fi
297
+ fi
298
+
299
+ # Decide whether to write to file
300
+ if [[ "$WRITE_TO_FILE" == "true" ]]; then
301
+ echo ""
302
+ if [[ "$MAJOR_CHANGES" == "true" ]]; then
303
+ echo "Writing results to file (major changes detected)..."
304
+ elif [[ -z "$previous_date" ]]; then
305
+ echo "Writing results to file (first benchmark run)..."
306
+ else
307
+ echo "Writing results to file (--write flag used)..."
308
+ fi
309
+
310
+ # Generate performance comparison for file
311
+ generate_comparison() {
312
+ echo "## Performance Changes"
313
+ echo ""
314
+ if [[ -z "$previous_date" ]]; then
315
+ echo "No previous results found. This is the first benchmark run."
316
+ echo ""
317
+ return
318
+ fi
319
+
320
+ echo "Changes since **$previous_date**:"
321
+ echo ""
322
+
323
+ # Track changes
324
+ faster_benchmarks=""
325
+ slower_benchmarks=""
326
+ new_benchmarks=""
327
+ removed_benchmarks=""
328
+
329
+ # Compare results
330
+ while IFS= read -r benchmark; do
331
+ if [[ -n "$(get_previous_data "$benchmark")" ]]; then
332
+ # Benchmark exists in both
333
+ current_data=$(get_current_data "$benchmark")
334
+ previous_data=$(get_previous_data "$benchmark")
335
+
336
+ current_ops=$(echo "$current_data" | cut -d'|' -f1)
337
+ previous_ops=$(echo "$previous_data" | cut -d'|' -f1)
338
+
339
+ if [[ "$current_ops" =~ ^[0-9]+$ && "$previous_ops" =~ ^[0-9]+$ && $previous_ops -gt 0 ]]; then
340
+ if [[ $current_ops -gt $previous_ops ]]; then
341
+ change=$(( (current_ops - previous_ops) * 100 / previous_ops ))
342
+ faster_benchmarks="$faster_benchmarks
343
+ $benchmark (+${change}%)"
344
+ elif [[ $current_ops -lt $previous_ops ]]; then
345
+ change=$(( (previous_ops - current_ops) * 100 / previous_ops ))
346
+ slower_benchmarks="$slower_benchmarks
347
+ $benchmark (-${change}%)"
348
+ fi
349
+ fi
350
+ else
351
+ new_benchmarks="$new_benchmarks
352
+ $benchmark"
353
+ fi
354
+ done < <(list_current_benchmarks)
355
+
356
+ # Check for removed benchmarks
357
+ while IFS= read -r benchmark; do
358
+ if [[ -z "$(get_current_data "$benchmark")" ]]; then
359
+ removed_benchmarks="$removed_benchmarks
360
+ $benchmark"
361
+ fi
362
+ done < <(list_previous_benchmarks)
363
+
364
+ # Count items
365
+ faster_count=$(echo "$faster_benchmarks" | grep -c "^." || echo "0")
366
+ slower_count=$(echo "$slower_benchmarks" | grep -c "^." || echo "0")
367
+ new_count=$(echo "$new_benchmarks" | grep -c "^." || echo "0")
368
+ removed_count=$(echo "$removed_benchmarks" | grep -c "^." || echo "0")
369
+
370
+ echo "### Summary"
371
+ echo "- **Faster benchmarks**: $faster_count"
372
+ echo "- **Slower benchmarks**: $slower_count"
373
+ echo "- **New benchmarks**: $new_count"
374
+ echo "- **Removed benchmarks**: $removed_count"
375
+ echo ""
376
+
377
+ if [[ $faster_count -gt 0 ]]; then
378
+ echo "### Top Improvements"
379
+ echo "$faster_benchmarks" | grep "^." | sort -t'(' -k2 -nr | head -5 | sed 's/^/- /'
380
+ echo ""
381
+ fi
382
+
383
+ if [[ $slower_count -gt 0 ]]; then
384
+ echo "### Performance Regressions"
385
+ echo "$slower_benchmarks" | grep "^." | sort -t'(' -k2 -nr | head -5 | sed 's/^/- /'
386
+ echo ""
387
+ fi
388
+
389
+ if [[ $new_count -gt 0 ]]; then
390
+ echo "### New Benchmarks Added"
391
+ echo "$new_benchmarks" | grep "^." | sed 's/^/- /'
392
+ echo ""
393
+ fi
394
+
395
+ if [[ $removed_count -gt 0 ]]; then
396
+ echo "### Benchmarks Removed"
397
+ echo "$removed_benchmarks" | grep "^." | sed 's/^/- /'
398
+ echo ""
399
+ fi
400
+ }
401
+
402
+ # Create the markdown file
403
+ cat > "$OUTPUT_FILE.tmp" << EOF
404
+ # Dingo Ledger & Database Benchmark Results
405
+
406
+ ## Latest Results
407
+
408
+ ### Test Environment
409
+ - **Date**: $DATE
410
+ - **Go Version**: $GO_VERSION
411
+ - **OS**: $OS
412
+ - **Architecture**: $ARCH
413
+ - **CPU Cores**: $CPU_CORES
414
+ - **Data Source**: Real Cardano preview testnet data (40k+ blocks, slots 0-863,996)
415
+
416
+ ### Benchmark Results
417
+
418
+ All benchmarks run with \`-benchmem\` flag showing memory allocations and operation counts.
419
+
420
+ | Benchmark | Operations/sec | Time/op | Memory/op | Allocs/op |
421
+ |-----------|----------------|---------|-----------|-----------|
422
+ EOF
423
+
424
+ # Add current results to table
425
+ while IFS= read -r benchmark; do
426
+ data=$(get_current_data "$benchmark")
427
+ ops_sec=$(echo "$data" | cut -d'|' -f1)
428
+ time_op=$(echo "$data" | cut -d'|' -f2)
429
+ mem_op=$(echo "$data" | cut -d'|' -f3)
430
+ allocs_op=$(echo "$data" | cut -d'|' -f4)
431
+ echo "| $benchmark | $ops_sec | $time_op | $mem_op | $allocs_op |" >> "$OUTPUT_FILE.tmp"
432
+ done < <(list_current_benchmarks)
433
+
434
+ # Add comparison section
435
+ generate_comparison >> "$OUTPUT_FILE.tmp"
436
+
437
+ # Add historical section if previous results exist
438
+ if [[ -n "$previous_date" ]]; then
439
+ echo "" >> "$OUTPUT_FILE.tmp"
440
+ echo "## Historical Results" >> "$OUTPUT_FILE.tmp"
441
+ echo "" >> "$OUTPUT_FILE.tmp"
442
+ echo "### $previous_date" >> "$OUTPUT_FILE.tmp"
443
+ echo "" >> "$OUTPUT_FILE.tmp"
444
+ echo "| Benchmark | Operations/sec | Time/op | Memory/op | Allocs/op |" >> "$OUTPUT_FILE.tmp"
445
+ echo "|-----------|----------------|---------|-----------|-----------|" >> "$OUTPUT_FILE.tmp"
446
+
447
+ # Add previous results
448
+ while IFS= read -r benchmark; do
449
+ data=$(get_previous_data "$benchmark")
450
+ ops_sec=$(echo "$data" | cut -d'|' -f1)
451
+ time_op=$(echo "$data" | cut -d'|' -f2)
452
+ mem_op=$(echo "$data" | cut -d'|' -f3)
453
+ allocs_op=$(echo "$data" | cut -d'|' -f4)
454
+ echo "| $benchmark | $ops_sec | $time_op | $mem_op | $allocs_op |" >> "$OUTPUT_FILE.tmp"
455
+ done < <(list_previous_benchmarks)
456
+ fi
457
+
458
+ # Move temp file to final location
459
+ mv "$OUTPUT_FILE.tmp" "$OUTPUT_FILE"
460
+
461
+ echo "Benchmark results saved to $OUTPUT_FILE"
462
+ else
463
+ echo ""
464
+ echo "To save these results to file, run: ./generate_benchmarks.sh --write"
465
+ echo "Results are only saved when major performance changes are detected."
466
+ fi
467
+
468
+ echo ""
469
+ echo "Benchmark run complete!"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blinklabs/dingo",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "Dingo is a Cardano blockchain data node",
5
5
  "main": "index.js",
6
6
  "bin": {