@blinklabs/dingo 0.7.0 → 0.8.1
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 +2 -1
- package/{bin/dingo → dingo} +0 -0
- package/dingo.yaml.example +53 -0
- package/package.json +2 -2
- package/.github/CODEOWNERS +0 -5
- package/.github/assets/dingo-ate-my-blockchain.png +0 -0
- package/.github/assets/dingo-illustration.png +0 -0
- package/.github/assets/dingo-logo-with-text-horizontal.png +0 -0
- package/.github/assets/dingo-logo-with-text.png +0 -0
- package/.github/dependabot.yml +0 -19
- package/.github/dingo-20241210.png +0 -0
- package/.github/dingo.md +0 -56
- package/.github/workflows/ci-docker.yml +0 -36
- package/.github/workflows/conventional-commits.yml +0 -17
- package/.github/workflows/go-test.yml +0 -29
- package/.github/workflows/golangci-lint.yml +0 -23
- package/.github/workflows/publish.yml +0 -207
- package/Dockerfile +0 -25
- package/Makefile +0 -53
- package/blockfetch.go +0 -144
- package/chain/chain.go +0 -504
- package/chain/chain_test.go +0 -468
- package/chain/errors.go +0 -80
- package/chain/event.go +0 -33
- package/chain/iter.go +0 -64
- package/chainsync/chainsync.go +0 -97
- package/chainsync.go +0 -223
- package/cmd/dingo/load.go +0 -52
- package/cmd/dingo/main.go +0 -118
- package/cmd/dingo/serve.go +0 -49
- package/config/cardano/node.go +0 -192
- package/config/cardano/node_test.go +0 -85
- package/config/cardano/preview/README.md +0 -4
- package/config/cardano/preview/alonzo-genesis.json +0 -196
- package/config/cardano/preview/byron-genesis.json +0 -117
- package/config/cardano/preview/config.json +0 -114
- package/config/cardano/preview/conway-genesis.json +0 -297
- package/config/cardano/preview/shelley-genesis.json +0 -68
- package/config.go +0 -245
- package/connmanager/connection_manager.go +0 -105
- package/connmanager/connection_manager_test.go +0 -185
- package/connmanager/event.go +0 -37
- package/connmanager/listener.go +0 -140
- package/connmanager/outbound.go +0 -93
- package/connmanager/socket.go +0 -55
- package/connmanager/unix.go +0 -78
- package/custom-p2p-topology.json +0 -24
- package/custom-p2p-topology.json.backup +0 -24
- package/custom-p2p-topology.json.mainnet +0 -37
- package/database/account.go +0 -180
- package/database/block.go +0 -362
- package/database/certs.go +0 -53
- package/database/commit_timestamp.go +0 -77
- package/database/database.go +0 -118
- package/database/database_test.go +0 -62
- package/database/drep.go +0 -47
- package/database/epoch.go +0 -121
- package/database/immutable/chunk.go +0 -182
- package/database/immutable/immutable.go +0 -350
- package/database/immutable/immutable_test.go +0 -59
- package/database/immutable/primary.go +0 -106
- package/database/immutable/secondary.go +0 -103
- package/database/immutable/testdata/08893.chunk +0 -0
- package/database/immutable/testdata/08893.primary +0 -0
- package/database/immutable/testdata/08893.secondary +0 -0
- package/database/immutable/testdata/08894.chunk +0 -0
- package/database/immutable/testdata/08894.primary +0 -0
- package/database/immutable/testdata/08894.secondary +0 -0
- package/database/immutable/testdata/README.md +0 -4
- package/database/plugin/blob/badger/commit_timestamp.go +0 -50
- package/database/plugin/blob/badger/database.go +0 -152
- package/database/plugin/blob/badger/logger.go +0 -63
- package/database/plugin/blob/badger/metrics.go +0 -98
- package/database/plugin/blob/blob.go +0 -19
- package/database/plugin/blob/store.go +0 -40
- package/database/plugin/log.go +0 -27
- package/database/plugin/metadata/metadata.go +0 -19
- package/database/plugin/metadata/sqlite/account.go +0 -313
- package/database/plugin/metadata/sqlite/certs.go +0 -58
- package/database/plugin/metadata/sqlite/commit_timestamp.go +0 -68
- package/database/plugin/metadata/sqlite/database.go +0 -218
- package/database/plugin/metadata/sqlite/drep.go +0 -140
- package/database/plugin/metadata/sqlite/epoch.go +0 -120
- package/database/plugin/metadata/sqlite/models/account.go +0 -118
- package/database/plugin/metadata/sqlite/models/auth_committee_hot.go +0 -26
- package/database/plugin/metadata/sqlite/models/drep.go +0 -52
- package/database/plugin/metadata/sqlite/models/epoch.go +0 -31
- package/database/plugin/metadata/sqlite/models/models.go +0 -46
- package/database/plugin/metadata/sqlite/models/pool.go +0 -97
- package/database/plugin/metadata/sqlite/models/pparam_update.go +0 -27
- package/database/plugin/metadata/sqlite/models/pparams.go +0 -27
- package/database/plugin/metadata/sqlite/models/resign_committee_cold.go +0 -27
- package/database/plugin/metadata/sqlite/models/stake_vote_delegation.go +0 -27
- package/database/plugin/metadata/sqlite/models/tip.go +0 -26
- package/database/plugin/metadata/sqlite/models/update_drep.go +0 -27
- package/database/plugin/metadata/sqlite/models/utxo.go +0 -30
- package/database/plugin/metadata/sqlite/models/vote_delegation.go +0 -26
- package/database/plugin/metadata/sqlite/models/vote_registration_delegation.go +0 -15
- package/database/plugin/metadata/sqlite/pool.go +0 -240
- package/database/plugin/metadata/sqlite/pparams.go +0 -110
- package/database/plugin/metadata/sqlite/tip.go +0 -83
- package/database/plugin/metadata/sqlite/utxo.go +0 -292
- package/database/plugin/metadata/store.go +0 -198
- package/database/plugin/option.go +0 -190
- package/database/plugin/plugin.go +0 -20
- package/database/plugin/register.go +0 -118
- package/database/pparams.go +0 -145
- package/database/tip.go +0 -45
- package/database/txn.go +0 -147
- package/database/types/types.go +0 -74
- package/database/types/types_test.go +0 -83
- package/database/utxo.go +0 -263
- package/dist/artifacts.json +0 -1
- package/dist/checksums.txt +0 -22
- package/dist/config.yaml +0 -253
- package/dist/dingo-0.5.0-SNAPSHOT-d9431e4.tar.gz +0 -0
- package/dist/dingo-0.5.0-SNAPSHOT-d9431e4.tar.gz.sbom.json +0 -1
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_arm64.tar.gz +0 -0
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_arm64.tar.gz.sbom.json +0 -1
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_x86_64.tar.gz +0 -0
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_x86_64.tar.gz.sbom.json +0 -1
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.apk +0 -0
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.apk.sbom.json +0 -1
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.deb +0 -0
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.deb.sbom.json +0 -1
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.rpm +0 -0
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.rpm.sbom.json +0 -1
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.apk +0 -0
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.apk.sbom.json +0 -1
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.deb +0 -0
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.deb.sbom.json +0 -1
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.rpm +0 -0
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.rpm.sbom.json +0 -1
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.tar.gz +0 -0
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.tar.gz.sbom.json +0 -1
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_x86_64.tar.gz +0 -0
- package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_x86_64.tar.gz.sbom.json +0 -1
- package/dist/dingo_darwin_amd64_v1/dingo +0 -0
- package/dist/dingo_darwin_arm64_v8.0/dingo +0 -0
- package/dist/dingo_linux_amd64_v1/dingo +0 -0
- package/dist/dingo_linux_arm64_v8.0/dingo +0 -0
- package/dist/homebrew/dingo.rb +0 -51
- package/dist/metadata.json +0 -1
- package/event/event.go +0 -141
- package/event/event_test.go +0 -115
- package/event/metrics.go +0 -44
- package/go.mod +0 -98
- package/go.sum +0 -358
- package/internal/config/config.go +0 -145
- package/internal/config/config_test.go +0 -118
- package/internal/node/load.go +0 -149
- package/internal/node/node.go +0 -176
- package/internal/version/version.go +0 -33
- package/ledger/certs.go +0 -164
- package/ledger/chainsync.go +0 -504
- package/ledger/delta.go +0 -99
- package/ledger/eras/allegra.go +0 -154
- package/ledger/eras/alonzo.go +0 -156
- package/ledger/eras/babbage.go +0 -154
- package/ledger/eras/byron.go +0 -42
- package/ledger/eras/conway.go +0 -166
- package/ledger/eras/eras.go +0 -44
- package/ledger/eras/mary.go +0 -154
- package/ledger/eras/shelley.go +0 -164
- package/ledger/error.go +0 -19
- package/ledger/event.go +0 -50
- package/ledger/metrics.go +0 -53
- package/ledger/queries.go +0 -258
- package/ledger/slot.go +0 -127
- package/ledger/slot_test.go +0 -147
- package/ledger/state.go +0 -821
- package/ledger/view.go +0 -73
- package/localstatequery.go +0 -50
- package/localtxmonitor.go +0 -44
- package/localtxsubmission.go +0 -52
- package/mempool/consumer.go +0 -98
- package/mempool/mempool.go +0 -322
- package/node.go +0 -320
- package/peergov/event.go +0 -27
- package/peergov/peer.go +0 -67
- package/peergov/peergov.go +0 -290
- package/peersharing.go +0 -70
- package/preview-local-topology.json +0 -23
- package/topology/topology.go +0 -69
- package/topology/topology_test.go +0 -179
- package/tracing.go +0 -65
- package/txsubmission.go +0 -233
- package/utxorpc/query.go +0 -311
- package/utxorpc/submit.go +0 -395
- package/utxorpc/sync.go +0 -276
- package/utxorpc/utxorpc.go +0 -166
- package/utxorpc/watch.go +0 -310
package/ledger/state.go
DELETED
|
@@ -1,821 +0,0 @@
|
|
|
1
|
-
// Copyright 2025 Blink Labs Software
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
package ledger
|
|
16
|
-
|
|
17
|
-
import (
|
|
18
|
-
"encoding/hex"
|
|
19
|
-
"errors"
|
|
20
|
-
"fmt"
|
|
21
|
-
"io"
|
|
22
|
-
"log/slog"
|
|
23
|
-
"slices"
|
|
24
|
-
"sync"
|
|
25
|
-
"time"
|
|
26
|
-
|
|
27
|
-
"github.com/blinklabs-io/dingo/chain"
|
|
28
|
-
"github.com/blinklabs-io/dingo/config/cardano"
|
|
29
|
-
"github.com/blinklabs-io/dingo/database"
|
|
30
|
-
"github.com/blinklabs-io/dingo/event"
|
|
31
|
-
"github.com/blinklabs-io/dingo/ledger/eras"
|
|
32
|
-
ouroboros "github.com/blinklabs-io/gouroboros"
|
|
33
|
-
"github.com/blinklabs-io/gouroboros/cbor"
|
|
34
|
-
"github.com/blinklabs-io/gouroboros/ledger"
|
|
35
|
-
lcommon "github.com/blinklabs-io/gouroboros/ledger/common"
|
|
36
|
-
ochainsync "github.com/blinklabs-io/gouroboros/protocol/chainsync"
|
|
37
|
-
ocommon "github.com/blinklabs-io/gouroboros/protocol/common"
|
|
38
|
-
"github.com/prometheus/client_golang/prometheus"
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
const (
|
|
42
|
-
cleanupConsumedUtxosInterval = 5 * time.Minute
|
|
43
|
-
cleanupConsumedUtxosSlotWindow = 50000 // TODO: calculate this from params (#395)
|
|
44
|
-
|
|
45
|
-
validateHistoricalThreshold = 14 * (24 * time.Hour) // 2 weeks
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
type LedgerStateConfig struct {
|
|
49
|
-
Logger *slog.Logger
|
|
50
|
-
DataDir string
|
|
51
|
-
EventBus *event.EventBus
|
|
52
|
-
CardanoNodeConfig *cardano.CardanoNodeConfig
|
|
53
|
-
PromRegistry prometheus.Registerer
|
|
54
|
-
ValidateHistorical bool
|
|
55
|
-
// Callback(s)
|
|
56
|
-
BlockfetchRequestRangeFunc BlockfetchRequestRangeFunc
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// BlockfetchRequestRangeFunc describes a callback function used to start a blockfetch request for
|
|
60
|
-
// a range of blocks
|
|
61
|
-
type BlockfetchRequestRangeFunc func(ouroboros.ConnectionId, ocommon.Point, ocommon.Point) error
|
|
62
|
-
|
|
63
|
-
type LedgerState struct {
|
|
64
|
-
sync.RWMutex
|
|
65
|
-
chainsyncMutex sync.Mutex
|
|
66
|
-
config LedgerStateConfig
|
|
67
|
-
db *database.Database
|
|
68
|
-
timerCleanupConsumedUtxos *time.Timer
|
|
69
|
-
currentPParams lcommon.ProtocolParameters
|
|
70
|
-
currentEpoch database.Epoch
|
|
71
|
-
epochCache []database.Epoch
|
|
72
|
-
currentEra eras.EraDesc
|
|
73
|
-
currentTip ochainsync.Tip
|
|
74
|
-
currentTipBlockNonce []byte
|
|
75
|
-
metrics stateMetrics
|
|
76
|
-
chainsyncBlockEvents []BlockfetchEvent
|
|
77
|
-
chainsyncBlockfetchBusyTime time.Time
|
|
78
|
-
chainsyncBlockfetchDoneChan chan struct{}
|
|
79
|
-
chainsyncBlockfetchMutex sync.Mutex
|
|
80
|
-
chainsyncBlockfetchWaiting bool
|
|
81
|
-
chain *chain.Chain
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
func NewLedgerState(cfg LedgerStateConfig) (*LedgerState, error) {
|
|
85
|
-
ls := &LedgerState{
|
|
86
|
-
config: cfg,
|
|
87
|
-
}
|
|
88
|
-
if cfg.Logger == nil {
|
|
89
|
-
// Create logger to throw away logs
|
|
90
|
-
// We do this so we don't have to add guards around every log operation
|
|
91
|
-
cfg.Logger = slog.New(slog.NewJSONHandler(io.Discard, nil))
|
|
92
|
-
}
|
|
93
|
-
// Init metrics
|
|
94
|
-
ls.metrics.init(ls.config.PromRegistry)
|
|
95
|
-
// Load database
|
|
96
|
-
needsRecovery := false
|
|
97
|
-
db, err := database.New(cfg.Logger, cfg.DataDir)
|
|
98
|
-
if db == nil {
|
|
99
|
-
ls.config.Logger.Error(
|
|
100
|
-
"failed to create database",
|
|
101
|
-
"error",
|
|
102
|
-
"empty database returned",
|
|
103
|
-
"component",
|
|
104
|
-
"ledger",
|
|
105
|
-
)
|
|
106
|
-
return nil, errors.New("empty database returned")
|
|
107
|
-
}
|
|
108
|
-
ls.db = db
|
|
109
|
-
if err != nil {
|
|
110
|
-
var dbErr database.CommitTimestampError
|
|
111
|
-
if !errors.As(err, &dbErr) {
|
|
112
|
-
return nil, fmt.Errorf("failed to open database: %w", err)
|
|
113
|
-
}
|
|
114
|
-
ls.config.Logger.Warn(
|
|
115
|
-
"database initialization error, needs recovery",
|
|
116
|
-
"error",
|
|
117
|
-
err,
|
|
118
|
-
"component",
|
|
119
|
-
"ledger",
|
|
120
|
-
)
|
|
121
|
-
needsRecovery = true
|
|
122
|
-
}
|
|
123
|
-
// Load chain
|
|
124
|
-
chain, err := chain.NewChain(
|
|
125
|
-
ls.db,
|
|
126
|
-
ls.config.EventBus,
|
|
127
|
-
true, // persistent
|
|
128
|
-
)
|
|
129
|
-
if err != nil {
|
|
130
|
-
return nil, fmt.Errorf("failed to load chain: %w", err)
|
|
131
|
-
}
|
|
132
|
-
ls.chain = chain
|
|
133
|
-
// Run recovery if needed
|
|
134
|
-
if needsRecovery {
|
|
135
|
-
if err := ls.recoverCommitTimestampConflict(); err != nil {
|
|
136
|
-
return nil, fmt.Errorf("failed to recover database: %w", err)
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// Setup event handlers
|
|
140
|
-
ls.config.EventBus.SubscribeFunc(
|
|
141
|
-
ChainsyncEventType,
|
|
142
|
-
ls.handleEventChainsync,
|
|
143
|
-
)
|
|
144
|
-
ls.config.EventBus.SubscribeFunc(
|
|
145
|
-
BlockfetchEventType,
|
|
146
|
-
ls.handleEventBlockfetch,
|
|
147
|
-
)
|
|
148
|
-
// Schedule periodic process to purge consumed UTxOs outside of the rollback window
|
|
149
|
-
ls.scheduleCleanupConsumedUtxos()
|
|
150
|
-
// Load epoch info from DB
|
|
151
|
-
if err := ls.loadEpochs(nil); err != nil {
|
|
152
|
-
return nil, fmt.Errorf("failed to load epoch info: %w", err)
|
|
153
|
-
}
|
|
154
|
-
// Load current protocol parameters from DB
|
|
155
|
-
if err := ls.loadPParams(); err != nil {
|
|
156
|
-
return nil, fmt.Errorf("failed to load pparams: %w", err)
|
|
157
|
-
}
|
|
158
|
-
// Load current tip
|
|
159
|
-
if err := ls.loadTip(); err != nil {
|
|
160
|
-
return nil, fmt.Errorf("failed to load tip: %w", err)
|
|
161
|
-
}
|
|
162
|
-
// Create genesis block
|
|
163
|
-
if err := ls.createGenesisBlock(); err != nil {
|
|
164
|
-
return nil, fmt.Errorf("failed to create genesis block: %w", err)
|
|
165
|
-
}
|
|
166
|
-
// Start goroutine to process new blocks
|
|
167
|
-
go ls.ledgerProcessBlocks()
|
|
168
|
-
return ls, nil
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
func (ls *LedgerState) recoverCommitTimestampConflict() error {
|
|
172
|
-
// Load current ledger tip
|
|
173
|
-
tmpTip, err := ls.db.GetTip(nil)
|
|
174
|
-
if err != nil {
|
|
175
|
-
return fmt.Errorf("failed to get tip: %w", err)
|
|
176
|
-
}
|
|
177
|
-
// Check if we can lookup tip block in chain
|
|
178
|
-
_, err = ls.chain.BlockByPoint(tmpTip.Point, nil)
|
|
179
|
-
if err != nil {
|
|
180
|
-
// Rollback to raw chain tip on error
|
|
181
|
-
chainTip := ls.chain.Tip()
|
|
182
|
-
if err = ls.rollback(chainTip.Point); err != nil {
|
|
183
|
-
return fmt.Errorf(
|
|
184
|
-
"failed to rollback ledger: %w",
|
|
185
|
-
err,
|
|
186
|
-
)
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return nil
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
func (ls *LedgerState) Chain() *chain.Chain {
|
|
193
|
-
return ls.chain
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
func (ls *LedgerState) Close() error {
|
|
197
|
-
return ls.db.Close()
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
func (ls *LedgerState) scheduleCleanupConsumedUtxos() {
|
|
201
|
-
ls.Lock()
|
|
202
|
-
defer ls.Unlock()
|
|
203
|
-
if ls.timerCleanupConsumedUtxos != nil {
|
|
204
|
-
ls.timerCleanupConsumedUtxos.Stop()
|
|
205
|
-
}
|
|
206
|
-
ls.timerCleanupConsumedUtxos = time.AfterFunc(
|
|
207
|
-
cleanupConsumedUtxosInterval,
|
|
208
|
-
func() {
|
|
209
|
-
defer func() {
|
|
210
|
-
// Schedule the next run
|
|
211
|
-
ls.scheduleCleanupConsumedUtxos()
|
|
212
|
-
}()
|
|
213
|
-
// Get the current tip, since we're querying by slot
|
|
214
|
-
tip := ls.Tip()
|
|
215
|
-
// Delete UTxOs that are marked as deleted and older than our slot window
|
|
216
|
-
ls.config.Logger.Debug(
|
|
217
|
-
"cleaning up consumed UTxOs",
|
|
218
|
-
"component", "ledger",
|
|
219
|
-
)
|
|
220
|
-
ls.Lock()
|
|
221
|
-
err := ls.db.UtxosDeleteConsumed(
|
|
222
|
-
tip.Point.Slot-cleanupConsumedUtxosSlotWindow,
|
|
223
|
-
nil,
|
|
224
|
-
)
|
|
225
|
-
ls.Unlock()
|
|
226
|
-
if err != nil {
|
|
227
|
-
ls.config.Logger.Error(
|
|
228
|
-
"failed to cleanup consumed UTxOs",
|
|
229
|
-
"component", "ledger",
|
|
230
|
-
"error", err,
|
|
231
|
-
)
|
|
232
|
-
return
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
)
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
func (ls *LedgerState) rollback(point ocommon.Point) error {
|
|
239
|
-
// Start a transaction
|
|
240
|
-
txn := ls.db.Transaction(true)
|
|
241
|
-
err := txn.Do(func(txn *database.Txn) error {
|
|
242
|
-
// Delete rolled-back UTxOs
|
|
243
|
-
err := ls.db.UtxosDeleteRolledback(point.Slot, txn)
|
|
244
|
-
if err != nil {
|
|
245
|
-
return fmt.Errorf("remove rolled-back UTxOs: %w", err)
|
|
246
|
-
}
|
|
247
|
-
// Restore spent UTxOs
|
|
248
|
-
err = ls.db.UtxosUnspend(point.Slot, txn)
|
|
249
|
-
if err != nil {
|
|
250
|
-
return fmt.Errorf(
|
|
251
|
-
"restore spent UTxOs after rollback: %w",
|
|
252
|
-
err,
|
|
253
|
-
)
|
|
254
|
-
}
|
|
255
|
-
// Update tip
|
|
256
|
-
ls.currentTip = ochainsync.Tip{
|
|
257
|
-
Point: point,
|
|
258
|
-
}
|
|
259
|
-
if point.Slot > 0 {
|
|
260
|
-
rollbackBlock, err := ls.chain.BlockByPoint(point, txn)
|
|
261
|
-
if err != nil {
|
|
262
|
-
return fmt.Errorf("failed to get rollback block: %w", err)
|
|
263
|
-
}
|
|
264
|
-
ls.currentTip.BlockNumber = rollbackBlock.Number
|
|
265
|
-
}
|
|
266
|
-
if err = ls.db.SetTip(ls.currentTip, txn); err != nil {
|
|
267
|
-
return fmt.Errorf("failed to set tip: %w", err)
|
|
268
|
-
}
|
|
269
|
-
ls.updateTipMetrics()
|
|
270
|
-
return nil
|
|
271
|
-
})
|
|
272
|
-
if err != nil {
|
|
273
|
-
return err
|
|
274
|
-
}
|
|
275
|
-
// Reload tip
|
|
276
|
-
if err := ls.loadTip(); err != nil {
|
|
277
|
-
return fmt.Errorf("failed to load tip: %w", err)
|
|
278
|
-
}
|
|
279
|
-
var hash string
|
|
280
|
-
if point.Slot == 0 {
|
|
281
|
-
hash = "<genesis>"
|
|
282
|
-
} else {
|
|
283
|
-
hash = hex.EncodeToString(point.Hash)
|
|
284
|
-
}
|
|
285
|
-
ls.config.Logger.Info(
|
|
286
|
-
fmt.Sprintf(
|
|
287
|
-
"chain rolled back, new tip: %s at slot %d",
|
|
288
|
-
hash,
|
|
289
|
-
point.Slot,
|
|
290
|
-
),
|
|
291
|
-
"component",
|
|
292
|
-
"ledger",
|
|
293
|
-
)
|
|
294
|
-
return nil
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
func (ls *LedgerState) transitionToEra(
|
|
298
|
-
txn *database.Txn,
|
|
299
|
-
nextEraId uint,
|
|
300
|
-
startEpoch uint64,
|
|
301
|
-
addedSlot uint64,
|
|
302
|
-
) error {
|
|
303
|
-
nextEra := eras.Eras[nextEraId]
|
|
304
|
-
if nextEra.HardForkFunc != nil {
|
|
305
|
-
// Perform hard fork
|
|
306
|
-
// This generally means upgrading pparams from previous era
|
|
307
|
-
newPParams, err := nextEra.HardForkFunc(
|
|
308
|
-
ls.config.CardanoNodeConfig,
|
|
309
|
-
ls.currentPParams,
|
|
310
|
-
)
|
|
311
|
-
if err != nil {
|
|
312
|
-
return fmt.Errorf("hard fork failed: %w", err)
|
|
313
|
-
}
|
|
314
|
-
ls.currentPParams = newPParams
|
|
315
|
-
ls.config.Logger.Debug(
|
|
316
|
-
"updated protocol params",
|
|
317
|
-
"pparams",
|
|
318
|
-
fmt.Sprintf("%#v", ls.currentPParams),
|
|
319
|
-
)
|
|
320
|
-
// Write pparams update to DB
|
|
321
|
-
pparamsCbor, err := cbor.Encode(&ls.currentPParams)
|
|
322
|
-
if err != nil {
|
|
323
|
-
return fmt.Errorf("failed to encode pparams: %w", err)
|
|
324
|
-
}
|
|
325
|
-
err = ls.db.SetPParams(
|
|
326
|
-
pparamsCbor,
|
|
327
|
-
addedSlot,
|
|
328
|
-
startEpoch,
|
|
329
|
-
nextEraId,
|
|
330
|
-
txn,
|
|
331
|
-
)
|
|
332
|
-
if err != nil {
|
|
333
|
-
return fmt.Errorf("failed to set pparams: %w", err)
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
ls.currentEra = nextEra
|
|
337
|
-
return nil
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// consumeUtxo marks a UTxO as "deleted" without actually deleting it. This allows for a UTxO
|
|
341
|
-
// to be easily on rollback
|
|
342
|
-
func (ls *LedgerState) consumeUtxo(
|
|
343
|
-
txn *database.Txn,
|
|
344
|
-
utxoId ledger.TransactionInput,
|
|
345
|
-
slot uint64,
|
|
346
|
-
) error {
|
|
347
|
-
return ls.db.UtxoConsume(
|
|
348
|
-
utxoId,
|
|
349
|
-
slot,
|
|
350
|
-
txn,
|
|
351
|
-
)
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
func (ls *LedgerState) ledgerProcessBlocks() {
|
|
355
|
-
iter, err := ls.chain.FromPoint(ls.currentTip.Point, false)
|
|
356
|
-
if err != nil {
|
|
357
|
-
ls.config.Logger.Error(
|
|
358
|
-
"failed to create chain iterator: " + err.Error(),
|
|
359
|
-
)
|
|
360
|
-
return
|
|
361
|
-
}
|
|
362
|
-
shouldBlock := false
|
|
363
|
-
shouldValidate := ls.config.ValidateHistorical
|
|
364
|
-
// We chose 500 as an arbitrary max batch size. A "chain extended" message will be logged after each batch
|
|
365
|
-
nextBatch := make([]*chain.ChainIteratorResult, 0, 500)
|
|
366
|
-
var next, nextRollback, cachedNext *chain.ChainIteratorResult
|
|
367
|
-
var tmpBlock ledger.Block
|
|
368
|
-
var needsRollback, needsEpochRollover bool
|
|
369
|
-
var nextEpochEraId uint
|
|
370
|
-
var end, i int
|
|
371
|
-
var txn *database.Txn
|
|
372
|
-
for {
|
|
373
|
-
if needsEpochRollover {
|
|
374
|
-
needsEpochRollover = false
|
|
375
|
-
txn := ls.db.Transaction(true)
|
|
376
|
-
err := txn.Do(func(txn *database.Txn) error {
|
|
377
|
-
// Check for era change
|
|
378
|
-
if nextEpochEraId != ls.currentEra.Id {
|
|
379
|
-
// Transition through every era between the current and the target era
|
|
380
|
-
for nextEraId := ls.currentEra.Id + 1; nextEraId <= nextEpochEraId; nextEraId++ {
|
|
381
|
-
if err := ls.transitionToEra(txn, nextEraId, ls.currentEpoch.EpochId, ls.currentEpoch.StartSlot+uint64(ls.currentEpoch.LengthInSlots)); err != nil {
|
|
382
|
-
return err
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
// Process epoch rollover
|
|
387
|
-
if err := ls.processEpochRollover(txn); err != nil {
|
|
388
|
-
return err
|
|
389
|
-
}
|
|
390
|
-
return nil
|
|
391
|
-
})
|
|
392
|
-
if err != nil {
|
|
393
|
-
ls.config.Logger.Error(
|
|
394
|
-
"failed to process epoch rollover: " + err.Error(),
|
|
395
|
-
)
|
|
396
|
-
return
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
// Gather up next batch of blocks
|
|
400
|
-
for {
|
|
401
|
-
if cachedNext != nil {
|
|
402
|
-
next = cachedNext
|
|
403
|
-
cachedNext = nil
|
|
404
|
-
} else {
|
|
405
|
-
next, err = iter.Next(shouldBlock)
|
|
406
|
-
shouldBlock = false
|
|
407
|
-
if err != nil {
|
|
408
|
-
if !errors.Is(err, chain.ErrIteratorChainTip) {
|
|
409
|
-
ls.config.Logger.Error(
|
|
410
|
-
"failed to get next block from chain iterator: " + err.Error(),
|
|
411
|
-
)
|
|
412
|
-
return
|
|
413
|
-
}
|
|
414
|
-
shouldBlock = true
|
|
415
|
-
// Break out of inner loop to flush DB transaction and log
|
|
416
|
-
break
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
if next == nil {
|
|
420
|
-
ls.config.Logger.Error("next block from chain iterator is nil")
|
|
421
|
-
return
|
|
422
|
-
}
|
|
423
|
-
// End batch and cache next if we get a block from after the current epoch end, or if we need the initial epoch
|
|
424
|
-
if next.Point.Slot >= (ls.currentEpoch.StartSlot+uint64(ls.currentEpoch.LengthInSlots)) ||
|
|
425
|
-
ls.currentEpoch.SlotLength == 0 {
|
|
426
|
-
cachedNext = next
|
|
427
|
-
needsEpochRollover = true
|
|
428
|
-
// Decode next block to get era ID
|
|
429
|
-
tmpBlock, err = next.Block.Decode()
|
|
430
|
-
if err != nil {
|
|
431
|
-
ls.config.Logger.Error(
|
|
432
|
-
"failed to decode block: " + err.Error(),
|
|
433
|
-
)
|
|
434
|
-
return
|
|
435
|
-
}
|
|
436
|
-
nextEpochEraId = uint(tmpBlock.Era().Id)
|
|
437
|
-
break
|
|
438
|
-
}
|
|
439
|
-
if next.Rollback {
|
|
440
|
-
// End existing batch and cache rollback if we have any blocks in the batch
|
|
441
|
-
// We need special processing for rollbacks below
|
|
442
|
-
if len(nextBatch) > 0 {
|
|
443
|
-
cachedNext = next
|
|
444
|
-
break
|
|
445
|
-
}
|
|
446
|
-
needsRollback = true
|
|
447
|
-
}
|
|
448
|
-
// Enable validation if we're getting near current tip
|
|
449
|
-
if !shouldValidate && len(nextBatch) == 0 {
|
|
450
|
-
// Determine wall time for next block slot
|
|
451
|
-
slotTime, err := ls.SlotToTime(next.Point.Slot)
|
|
452
|
-
if err != nil {
|
|
453
|
-
ls.config.Logger.Error(
|
|
454
|
-
"failed to convert slot to time: " + err.Error(),
|
|
455
|
-
)
|
|
456
|
-
return
|
|
457
|
-
}
|
|
458
|
-
// Check difference from current time
|
|
459
|
-
timeDiff := time.Since(slotTime)
|
|
460
|
-
if timeDiff < validateHistoricalThreshold {
|
|
461
|
-
shouldValidate = true
|
|
462
|
-
ls.config.Logger.Debug(
|
|
463
|
-
"enabling validation as we approach tip",
|
|
464
|
-
)
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
// Add to batch
|
|
468
|
-
nextBatch = append(nextBatch, next)
|
|
469
|
-
// Don't exceed our pre-allocated capacity
|
|
470
|
-
if len(nextBatch) == cap(nextBatch) {
|
|
471
|
-
break
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
// Process rollback
|
|
475
|
-
if needsRollback {
|
|
476
|
-
needsRollback = false
|
|
477
|
-
// The rollback should be alone in the batch
|
|
478
|
-
nextRollback = nextBatch[0]
|
|
479
|
-
ls.Lock()
|
|
480
|
-
if err = ls.rollback(nextRollback.Point); err != nil {
|
|
481
|
-
ls.Unlock()
|
|
482
|
-
ls.config.Logger.Error(
|
|
483
|
-
"failed to process rollback: " + err.Error(),
|
|
484
|
-
)
|
|
485
|
-
return
|
|
486
|
-
}
|
|
487
|
-
ls.Unlock()
|
|
488
|
-
// Clear out batch buffer
|
|
489
|
-
nextBatch = slices.Delete(nextBatch, 0, len(nextBatch))
|
|
490
|
-
continue
|
|
491
|
-
}
|
|
492
|
-
// Process batch in groups of 50 to stay under DB txn limits
|
|
493
|
-
for i = 0; i < len(nextBatch); i += 50 {
|
|
494
|
-
ls.Lock()
|
|
495
|
-
end = min(
|
|
496
|
-
len(nextBatch),
|
|
497
|
-
i+50,
|
|
498
|
-
)
|
|
499
|
-
txn = ls.db.Transaction(true)
|
|
500
|
-
err = txn.Do(func(txn *database.Txn) error {
|
|
501
|
-
for _, next := range nextBatch[i:end] {
|
|
502
|
-
// Process block
|
|
503
|
-
tmpBlock, err = next.Block.Decode()
|
|
504
|
-
if err != nil {
|
|
505
|
-
return fmt.Errorf("block decode failed: %w", err)
|
|
506
|
-
}
|
|
507
|
-
if err = ls.ledgerProcessBlock(txn, next.Point, tmpBlock, shouldValidate); err != nil {
|
|
508
|
-
return err
|
|
509
|
-
}
|
|
510
|
-
// Update tip
|
|
511
|
-
ls.currentTip = ochainsync.Tip{
|
|
512
|
-
Point: next.Point,
|
|
513
|
-
BlockNumber: next.Block.Number,
|
|
514
|
-
}
|
|
515
|
-
// Update tip block nonce
|
|
516
|
-
ls.currentTipBlockNonce = next.Block.Nonce
|
|
517
|
-
}
|
|
518
|
-
// Update tip in database
|
|
519
|
-
if err := ls.db.SetTip(ls.currentTip, txn); err != nil {
|
|
520
|
-
return fmt.Errorf("failed to set tip: %w", err)
|
|
521
|
-
}
|
|
522
|
-
ls.updateTipMetrics()
|
|
523
|
-
return nil
|
|
524
|
-
})
|
|
525
|
-
if err != nil {
|
|
526
|
-
ls.Unlock()
|
|
527
|
-
ls.config.Logger.Error(
|
|
528
|
-
"failed to process block: " + err.Error(),
|
|
529
|
-
)
|
|
530
|
-
return
|
|
531
|
-
}
|
|
532
|
-
ls.Unlock()
|
|
533
|
-
}
|
|
534
|
-
if len(nextBatch) > 0 {
|
|
535
|
-
// Clear out batch buffer
|
|
536
|
-
nextBatch = slices.Delete(nextBatch, 0, len(nextBatch))
|
|
537
|
-
ls.config.Logger.Info(
|
|
538
|
-
fmt.Sprintf(
|
|
539
|
-
"chain extended, new tip: %x at slot %d",
|
|
540
|
-
ls.currentTip.Point.Hash,
|
|
541
|
-
ls.currentTip.Point.Slot,
|
|
542
|
-
),
|
|
543
|
-
"component",
|
|
544
|
-
"ledger",
|
|
545
|
-
)
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
func (ls *LedgerState) ledgerProcessBlock(
|
|
551
|
-
txn *database.Txn,
|
|
552
|
-
point ocommon.Point,
|
|
553
|
-
block ledger.Block,
|
|
554
|
-
shouldValidate bool,
|
|
555
|
-
) error {
|
|
556
|
-
// Check that we're processing things in order
|
|
557
|
-
if len(ls.currentTip.Point.Hash) > 0 {
|
|
558
|
-
if string(
|
|
559
|
-
block.PrevHash().Bytes(),
|
|
560
|
-
) != string(
|
|
561
|
-
ls.currentTip.Point.Hash,
|
|
562
|
-
) {
|
|
563
|
-
return fmt.Errorf(
|
|
564
|
-
"block %s (with prev hash %s) does not fit on current chain tip (%x)",
|
|
565
|
-
block.Hash().String(),
|
|
566
|
-
block.PrevHash().String(),
|
|
567
|
-
ls.currentTip.Point.Hash,
|
|
568
|
-
)
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
// Process transactions
|
|
572
|
-
var delta *LedgerDelta
|
|
573
|
-
for _, tx := range block.Transactions() {
|
|
574
|
-
if delta == nil {
|
|
575
|
-
delta = &LedgerDelta{
|
|
576
|
-
Point: point,
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
// Validate transaction
|
|
580
|
-
if shouldValidate {
|
|
581
|
-
if ls.currentEra.ValidateTxFunc != nil {
|
|
582
|
-
lv := &LedgerView{
|
|
583
|
-
txn: txn,
|
|
584
|
-
ls: ls,
|
|
585
|
-
}
|
|
586
|
-
err := ls.currentEra.ValidateTxFunc(
|
|
587
|
-
tx,
|
|
588
|
-
point.Slot,
|
|
589
|
-
lv,
|
|
590
|
-
ls.currentPParams,
|
|
591
|
-
)
|
|
592
|
-
if err != nil {
|
|
593
|
-
ls.config.Logger.Warn(
|
|
594
|
-
"TX " + tx.Hash().
|
|
595
|
-
String() +
|
|
596
|
-
" failed validation: " + err.Error(),
|
|
597
|
-
)
|
|
598
|
-
// return fmt.Errorf("TX validation failure: %w", err)
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
// Populate ledger delta from transaction
|
|
603
|
-
if err := delta.processTransaction(tx); err != nil {
|
|
604
|
-
return fmt.Errorf("process transaction: %w", err)
|
|
605
|
-
}
|
|
606
|
-
// Apply delta immediately if we may need the data to validate the next TX
|
|
607
|
-
if shouldValidate {
|
|
608
|
-
if err := delta.apply(ls, txn); err != nil {
|
|
609
|
-
return err
|
|
610
|
-
}
|
|
611
|
-
delta = nil
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
if delta != nil {
|
|
615
|
-
if err := delta.apply(ls, txn); err != nil {
|
|
616
|
-
return fmt.Errorf("apply ledger delta: %w", err)
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
return nil
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
func (ls *LedgerState) updateTipMetrics() {
|
|
623
|
-
// Update metrics
|
|
624
|
-
ls.metrics.blockNum.Set(float64(ls.currentTip.BlockNumber))
|
|
625
|
-
ls.metrics.slotNum.Set(float64(ls.currentTip.Point.Slot))
|
|
626
|
-
ls.metrics.slotInEpoch.Set(
|
|
627
|
-
float64(ls.currentTip.Point.Slot - ls.currentEpoch.StartSlot),
|
|
628
|
-
)
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
func (ls *LedgerState) loadPParams() error {
|
|
632
|
-
pparams, err := ls.db.GetPParams(
|
|
633
|
-
ls.currentEpoch.EpochId,
|
|
634
|
-
ls.currentEra.DecodePParamsFunc,
|
|
635
|
-
nil,
|
|
636
|
-
)
|
|
637
|
-
if err != nil {
|
|
638
|
-
return err
|
|
639
|
-
}
|
|
640
|
-
ls.currentPParams = pparams
|
|
641
|
-
return nil
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
func (ls *LedgerState) loadEpochs(txn *database.Txn) error {
|
|
645
|
-
// Load and cache all epochs
|
|
646
|
-
epochs, err := ls.db.GetEpochs(txn)
|
|
647
|
-
if err != nil {
|
|
648
|
-
return err
|
|
649
|
-
}
|
|
650
|
-
ls.epochCache = epochs
|
|
651
|
-
// Set current epoch
|
|
652
|
-
if len(epochs) > 0 {
|
|
653
|
-
ls.currentEpoch = epochs[len(epochs)-1]
|
|
654
|
-
ls.currentEra = eras.Eras[ls.currentEpoch.EraId]
|
|
655
|
-
}
|
|
656
|
-
// Update metrics
|
|
657
|
-
ls.metrics.epochNum.Set(float64(ls.currentEpoch.EpochId))
|
|
658
|
-
return nil
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
func (ls *LedgerState) loadTip() error {
|
|
662
|
-
tmpTip, err := ls.db.GetTip(nil)
|
|
663
|
-
if err != nil {
|
|
664
|
-
return err
|
|
665
|
-
}
|
|
666
|
-
ls.currentTip = tmpTip
|
|
667
|
-
// Load tip block and set cached block nonce
|
|
668
|
-
if ls.currentTip.Point.Slot > 0 {
|
|
669
|
-
tipBlock, err := ls.chain.BlockByPoint(ls.currentTip.Point, nil)
|
|
670
|
-
if err != nil {
|
|
671
|
-
return fmt.Errorf("failed to get tip block: %w", err)
|
|
672
|
-
}
|
|
673
|
-
ls.currentTipBlockNonce = tipBlock.Nonce
|
|
674
|
-
}
|
|
675
|
-
ls.updateTipMetrics()
|
|
676
|
-
return nil
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
func (ls *LedgerState) GetBlock(point ocommon.Point) (*database.Block, error) {
|
|
680
|
-
ret, err := ls.chain.BlockByPoint(point, nil)
|
|
681
|
-
if err != nil {
|
|
682
|
-
return nil, err
|
|
683
|
-
}
|
|
684
|
-
return &ret, nil
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// RecentChainPoints returns the requested count of recent chain points in descending order. This is used mostly
|
|
688
|
-
// for building a set of intersect points when acting as a chainsync client
|
|
689
|
-
func (ls *LedgerState) RecentChainPoints(count int) ([]ocommon.Point, error) {
|
|
690
|
-
tmpBlocks, err := database.BlocksRecent(ls.db, count)
|
|
691
|
-
if err != nil {
|
|
692
|
-
return nil, err
|
|
693
|
-
}
|
|
694
|
-
ret := []ocommon.Point{}
|
|
695
|
-
var tmpBlock database.Block
|
|
696
|
-
for _, tmpBlock = range tmpBlocks {
|
|
697
|
-
ret = append(
|
|
698
|
-
ret,
|
|
699
|
-
ocommon.NewPoint(tmpBlock.Slot, tmpBlock.Hash),
|
|
700
|
-
)
|
|
701
|
-
}
|
|
702
|
-
return ret, nil
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
// GetIntersectPoint returns the intersect between the specified points and the current chain
|
|
706
|
-
func (ls *LedgerState) GetIntersectPoint(
|
|
707
|
-
points []ocommon.Point,
|
|
708
|
-
) (*ocommon.Point, error) {
|
|
709
|
-
tip := ls.Tip()
|
|
710
|
-
var ret ocommon.Point
|
|
711
|
-
var tmpBlock database.Block
|
|
712
|
-
var err error
|
|
713
|
-
foundOrigin := false
|
|
714
|
-
txn := ls.db.Transaction(false)
|
|
715
|
-
err = txn.Do(func(txn *database.Txn) error {
|
|
716
|
-
for _, point := range points {
|
|
717
|
-
// Ignore points with a slot later than our current tip
|
|
718
|
-
if point.Slot > tip.Point.Slot {
|
|
719
|
-
continue
|
|
720
|
-
}
|
|
721
|
-
// Ignore points with a slot earlier than an existing match
|
|
722
|
-
if point.Slot < ret.Slot {
|
|
723
|
-
continue
|
|
724
|
-
}
|
|
725
|
-
// Check for special origin point
|
|
726
|
-
if point.Slot == 0 && len(point.Hash) == 0 {
|
|
727
|
-
foundOrigin = true
|
|
728
|
-
continue
|
|
729
|
-
}
|
|
730
|
-
// Lookup block in metadata DB
|
|
731
|
-
tmpBlock, err = ls.chain.BlockByPoint(point, txn)
|
|
732
|
-
if err != nil {
|
|
733
|
-
if errors.Is(err, chain.ErrBlockNotFound) {
|
|
734
|
-
continue
|
|
735
|
-
}
|
|
736
|
-
return fmt.Errorf("failed to get block: %w", err)
|
|
737
|
-
}
|
|
738
|
-
// Update return value
|
|
739
|
-
ret.Slot = tmpBlock.Slot
|
|
740
|
-
ret.Hash = tmpBlock.Hash
|
|
741
|
-
}
|
|
742
|
-
return nil
|
|
743
|
-
})
|
|
744
|
-
if err != nil {
|
|
745
|
-
return nil, err
|
|
746
|
-
}
|
|
747
|
-
if ret.Slot > 0 || foundOrigin {
|
|
748
|
-
return &ret, nil
|
|
749
|
-
}
|
|
750
|
-
return nil, nil
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
// GetChainFromPoint returns a ChainIterator starting at the specified point. If inclusive is true, the iterator
|
|
754
|
-
// will start at the requested point, otherwise it will start at the next block.
|
|
755
|
-
func (ls *LedgerState) GetChainFromPoint(
|
|
756
|
-
point ocommon.Point,
|
|
757
|
-
inclusive bool,
|
|
758
|
-
) (*chain.ChainIterator, error) {
|
|
759
|
-
return ls.chain.FromPoint(point, inclusive)
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
// Tip returns the current chain tip
|
|
763
|
-
func (ls *LedgerState) Tip() ochainsync.Tip {
|
|
764
|
-
return ls.currentTip
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
// GetCurrentPParams returns the currentPParams value
|
|
768
|
-
func (ls *LedgerState) GetCurrentPParams() lcommon.ProtocolParameters {
|
|
769
|
-
return ls.currentPParams
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
// UtxoByRef returns a single UTxO by reference
|
|
773
|
-
func (ls *LedgerState) UtxoByRef(
|
|
774
|
-
txId []byte,
|
|
775
|
-
outputIdx uint32,
|
|
776
|
-
) (database.Utxo, error) {
|
|
777
|
-
return ls.db.UtxoByRef(txId, outputIdx, nil)
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
// UtxosByAddress returns all UTxOs that belong to the specified address
|
|
781
|
-
func (ls *LedgerState) UtxosByAddress(
|
|
782
|
-
addr ledger.Address,
|
|
783
|
-
) ([]database.Utxo, error) {
|
|
784
|
-
ret := []database.Utxo{}
|
|
785
|
-
utxos, err := ls.db.UtxosByAddress(addr, nil)
|
|
786
|
-
if err != nil {
|
|
787
|
-
return ret, err
|
|
788
|
-
}
|
|
789
|
-
var tmpUtxo database.Utxo
|
|
790
|
-
for _, utxo := range utxos {
|
|
791
|
-
tmpUtxo = database.Utxo(utxo)
|
|
792
|
-
ret = append(ret, tmpUtxo)
|
|
793
|
-
}
|
|
794
|
-
return ret, nil
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
// ValidateTx runs ledger validation on the provided transaction
|
|
798
|
-
func (ls *LedgerState) ValidateTx(
|
|
799
|
-
tx lcommon.Transaction,
|
|
800
|
-
) error {
|
|
801
|
-
if ls.currentEra.ValidateTxFunc != nil {
|
|
802
|
-
txn := ls.db.Transaction(false)
|
|
803
|
-
err := txn.Do(func(txn *database.Txn) error {
|
|
804
|
-
lv := &LedgerView{
|
|
805
|
-
txn: txn,
|
|
806
|
-
ls: ls,
|
|
807
|
-
}
|
|
808
|
-
err := ls.currentEra.ValidateTxFunc(
|
|
809
|
-
tx,
|
|
810
|
-
ls.currentTip.Point.Slot,
|
|
811
|
-
lv,
|
|
812
|
-
ls.currentPParams,
|
|
813
|
-
)
|
|
814
|
-
return err
|
|
815
|
-
})
|
|
816
|
-
if err != nil {
|
|
817
|
-
return fmt.Errorf("TX %s failed validation: %w", tx.Hash(), err)
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
return nil
|
|
821
|
-
}
|