@blinklabs/dingo 0.6.0 → 0.8.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/.dingo/blob/000001.sst +0 -0
- package/.dingo/blob/000001.vlog +0 -0
- package/.dingo/blob/DISCARD +0 -0
- package/.dingo/blob/KEYREGISTRY +2 -0
- package/.dingo/blob/MANIFEST +0 -0
- package/.dingo/metadata.sqlite +0 -0
- package/.github/workflows/golangci-lint.yml +1 -1
- package/.github/workflows/publish.yml +1 -7
- package/README.md +2 -1
- package/{dist/dingo_darwin_amd64_v1/dingo → dingo} +0 -0
- package/dingo.yaml.example +53 -0
- package/package.json +5 -5
- 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 -138
- 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 -27
- 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 -224
- 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/epoch.go +0 -120
- package/database/plugin/metadata/sqlite/models/account.go +0 -81
- package/database/plugin/metadata/sqlite/models/auth_committee_hot.go +0 -26
- package/database/plugin/metadata/sqlite/models/deregistration_drep.go +0 -26
- package/database/plugin/metadata/sqlite/models/drep.go +0 -27
- package/database/plugin/metadata/sqlite/models/epoch.go +0 -31
- package/database/plugin/metadata/sqlite/models/models.go +0 -45
- 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/registration_drep.go +0 -28
- package/database/plugin/metadata/sqlite/models/resign_committee_cold.go +0 -27
- package/database/plugin/metadata/sqlite/models/stake_registration_delegation.go +0 -27
- package/database/plugin/metadata/sqlite/models/stake_vote_delegation.go +0 -27
- package/database/plugin/metadata/sqlite/models/stake_vote_registration_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 -26
- 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 -168
- 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_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 -113
- package/ledger/chainsync.go +0 -578
- 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 -158
- 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 -260
- package/ledger/slot.go +0 -127
- package/ledger/slot_test.go +0 -147
- package/ledger/state.go +0 -726
- 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/chain/chain.go
DELETED
|
@@ -1,504 +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 chain
|
|
16
|
-
|
|
17
|
-
import (
|
|
18
|
-
"encoding/hex"
|
|
19
|
-
"errors"
|
|
20
|
-
"fmt"
|
|
21
|
-
"slices"
|
|
22
|
-
"sync"
|
|
23
|
-
|
|
24
|
-
"github.com/blinklabs-io/dingo/database"
|
|
25
|
-
"github.com/blinklabs-io/dingo/event"
|
|
26
|
-
"github.com/blinklabs-io/gouroboros/ledger"
|
|
27
|
-
ochainsync "github.com/blinklabs-io/gouroboros/protocol/chainsync"
|
|
28
|
-
ocommon "github.com/blinklabs-io/gouroboros/protocol/common"
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
const (
|
|
32
|
-
initialBlockIndex uint64 = 1
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
type Chain struct {
|
|
36
|
-
mutex sync.RWMutex
|
|
37
|
-
db *database.Database
|
|
38
|
-
eventBus *event.EventBus
|
|
39
|
-
currentTip ochainsync.Tip
|
|
40
|
-
tipBlockIndex uint64
|
|
41
|
-
persistent bool
|
|
42
|
-
lastDbSlot uint64
|
|
43
|
-
lastDbBlockIndex uint64
|
|
44
|
-
blocks []database.Block
|
|
45
|
-
headers []ledger.BlockHeader
|
|
46
|
-
waitingChan chan struct{}
|
|
47
|
-
waitingChanMutex sync.Mutex
|
|
48
|
-
iterators []*ChainIterator
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
func NewChain(
|
|
52
|
-
db *database.Database,
|
|
53
|
-
eventBus *event.EventBus,
|
|
54
|
-
persistent bool,
|
|
55
|
-
) (*Chain, error) {
|
|
56
|
-
c := &Chain{
|
|
57
|
-
db: db,
|
|
58
|
-
eventBus: eventBus,
|
|
59
|
-
persistent: persistent,
|
|
60
|
-
}
|
|
61
|
-
if persistent && db == nil {
|
|
62
|
-
return nil, errors.New("persistence enabled but no database provided")
|
|
63
|
-
}
|
|
64
|
-
if db != nil {
|
|
65
|
-
if err := c.load(); err != nil {
|
|
66
|
-
return nil, fmt.Errorf("failed to load chain: %w", err)
|
|
67
|
-
}
|
|
68
|
-
// Set last block index and slot from database
|
|
69
|
-
c.lastDbBlockIndex = c.tipBlockIndex
|
|
70
|
-
c.lastDbSlot = c.currentTip.Point.Slot
|
|
71
|
-
}
|
|
72
|
-
return c, nil
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
func (c *Chain) load() error {
|
|
76
|
-
recentBlocks, err := database.BlocksRecent(c.db, 1)
|
|
77
|
-
if err != nil {
|
|
78
|
-
return err
|
|
79
|
-
}
|
|
80
|
-
if len(recentBlocks) > 0 {
|
|
81
|
-
c.currentTip = ochainsync.Tip{
|
|
82
|
-
Point: ocommon.Point{
|
|
83
|
-
Slot: recentBlocks[0].Slot,
|
|
84
|
-
Hash: recentBlocks[0].Hash,
|
|
85
|
-
},
|
|
86
|
-
BlockNumber: recentBlocks[0].Number,
|
|
87
|
-
}
|
|
88
|
-
c.tipBlockIndex = recentBlocks[0].ID
|
|
89
|
-
}
|
|
90
|
-
return nil
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
func (c *Chain) Tip() ochainsync.Tip {
|
|
94
|
-
c.mutex.RLock()
|
|
95
|
-
defer c.mutex.RUnlock()
|
|
96
|
-
return c.currentTip
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
func (c *Chain) HeaderTip() ochainsync.Tip {
|
|
100
|
-
c.mutex.RLock()
|
|
101
|
-
defer c.mutex.RUnlock()
|
|
102
|
-
return c.headerTip()
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
func (c *Chain) headerTip() ochainsync.Tip {
|
|
106
|
-
if len(c.headers) == 0 {
|
|
107
|
-
return c.currentTip
|
|
108
|
-
}
|
|
109
|
-
lastHeader := c.headers[len(c.headers)-1]
|
|
110
|
-
return ochainsync.Tip{
|
|
111
|
-
Point: ocommon.Point{
|
|
112
|
-
Slot: lastHeader.SlotNumber(),
|
|
113
|
-
Hash: lastHeader.Hash().Bytes(),
|
|
114
|
-
},
|
|
115
|
-
BlockNumber: lastHeader.BlockNumber(),
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
func (c *Chain) AddBlockHeader(header ledger.BlockHeader) error {
|
|
120
|
-
c.mutex.Lock()
|
|
121
|
-
defer c.mutex.Unlock()
|
|
122
|
-
// Make sure header fits on chain tip
|
|
123
|
-
if c.tipBlockIndex >= initialBlockIndex ||
|
|
124
|
-
len(c.headers) > 0 {
|
|
125
|
-
headerTip := c.headerTip()
|
|
126
|
-
if string(header.PrevHash().Bytes()) != string(headerTip.Point.Hash) {
|
|
127
|
-
return NewBlockNotFitChainTipError(
|
|
128
|
-
header.Hash().String(),
|
|
129
|
-
header.PrevHash().String(),
|
|
130
|
-
hex.EncodeToString(headerTip.Point.Hash),
|
|
131
|
-
)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
// Add header
|
|
135
|
-
c.headers = append(c.headers, header)
|
|
136
|
-
return nil
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
func (c *Chain) AddBlock(
|
|
140
|
-
block ledger.Block,
|
|
141
|
-
blockNonce []byte,
|
|
142
|
-
txn *database.Txn,
|
|
143
|
-
) error {
|
|
144
|
-
c.mutex.Lock()
|
|
145
|
-
defer c.mutex.Unlock()
|
|
146
|
-
// Check that the new block matches our first header, if any
|
|
147
|
-
if len(c.headers) > 0 {
|
|
148
|
-
firstHeader := c.headers[0]
|
|
149
|
-
if block.Hash().String() != firstHeader.Hash().String() {
|
|
150
|
-
return NewBlockNotMatchHeaderError(
|
|
151
|
-
block.Hash().String(),
|
|
152
|
-
firstHeader.Hash().String(),
|
|
153
|
-
)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// Check that this block fits on the current chain tip
|
|
157
|
-
if c.tipBlockIndex >= initialBlockIndex {
|
|
158
|
-
if string(block.PrevHash().Bytes()) != string(c.currentTip.Point.Hash) {
|
|
159
|
-
return NewBlockNotFitChainTipError(
|
|
160
|
-
block.Hash().String(),
|
|
161
|
-
block.PrevHash().String(),
|
|
162
|
-
hex.EncodeToString(c.currentTip.Point.Hash),
|
|
163
|
-
)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
// Build new block record
|
|
167
|
-
tmpPoint := ocommon.NewPoint(
|
|
168
|
-
block.SlotNumber(),
|
|
169
|
-
block.Hash().Bytes(),
|
|
170
|
-
)
|
|
171
|
-
newBlockIndex := c.tipBlockIndex + 1
|
|
172
|
-
tmpBlock := database.Block{
|
|
173
|
-
ID: newBlockIndex,
|
|
174
|
-
Slot: tmpPoint.Slot,
|
|
175
|
-
Hash: tmpPoint.Hash,
|
|
176
|
-
Number: block.BlockNumber(),
|
|
177
|
-
Type: uint(block.Type()), //nolint:gosec
|
|
178
|
-
PrevHash: block.PrevHash().Bytes(),
|
|
179
|
-
Nonce: blockNonce,
|
|
180
|
-
Cbor: block.Cbor(),
|
|
181
|
-
}
|
|
182
|
-
if c.persistent {
|
|
183
|
-
// Add block to database
|
|
184
|
-
if err := c.db.BlockCreate(tmpBlock, txn); err != nil {
|
|
185
|
-
return err
|
|
186
|
-
}
|
|
187
|
-
c.lastDbBlockIndex = newBlockIndex
|
|
188
|
-
c.lastDbSlot = tmpPoint.Slot
|
|
189
|
-
} else {
|
|
190
|
-
// Add block to memory buffer
|
|
191
|
-
c.blocks = append(
|
|
192
|
-
c.blocks,
|
|
193
|
-
tmpBlock,
|
|
194
|
-
)
|
|
195
|
-
}
|
|
196
|
-
// Remove matching header entry, if any
|
|
197
|
-
if len(c.headers) > 0 {
|
|
198
|
-
c.headers = slices.Delete(c.headers, 0, 1)
|
|
199
|
-
}
|
|
200
|
-
// Update tip
|
|
201
|
-
c.currentTip = ochainsync.Tip{
|
|
202
|
-
Point: tmpPoint,
|
|
203
|
-
BlockNumber: block.BlockNumber(),
|
|
204
|
-
}
|
|
205
|
-
c.tipBlockIndex = newBlockIndex
|
|
206
|
-
// Notify waiting iterators
|
|
207
|
-
if c.waitingChan != nil {
|
|
208
|
-
close(c.waitingChan)
|
|
209
|
-
c.waitingChan = nil
|
|
210
|
-
}
|
|
211
|
-
// Generate event
|
|
212
|
-
if c.eventBus != nil {
|
|
213
|
-
c.eventBus.Publish(
|
|
214
|
-
ChainUpdateEventType,
|
|
215
|
-
event.NewEvent(
|
|
216
|
-
ChainUpdateEventType,
|
|
217
|
-
ChainBlockEvent{
|
|
218
|
-
Point: tmpPoint,
|
|
219
|
-
Block: tmpBlock,
|
|
220
|
-
},
|
|
221
|
-
),
|
|
222
|
-
)
|
|
223
|
-
}
|
|
224
|
-
return nil
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
func (c *Chain) AddBlocks(blocks []ledger.Block) error {
|
|
228
|
-
batchOffset := 0
|
|
229
|
-
batchSize := 0
|
|
230
|
-
for {
|
|
231
|
-
batchSize = min(
|
|
232
|
-
50,
|
|
233
|
-
len(blocks)-batchOffset,
|
|
234
|
-
)
|
|
235
|
-
if batchSize == 0 {
|
|
236
|
-
break
|
|
237
|
-
}
|
|
238
|
-
txn := c.db.BlobTxn(true)
|
|
239
|
-
err := txn.Do(func(txn *database.Txn) error {
|
|
240
|
-
for _, tmpBlock := range blocks[batchOffset : batchOffset+batchSize] {
|
|
241
|
-
if err := c.AddBlock(tmpBlock, nil, txn); err != nil {
|
|
242
|
-
return err
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
return nil
|
|
246
|
-
})
|
|
247
|
-
if err != nil {
|
|
248
|
-
return err
|
|
249
|
-
}
|
|
250
|
-
batchOffset += batchSize
|
|
251
|
-
}
|
|
252
|
-
return nil
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
func (c *Chain) Rollback(point ocommon.Point) error {
|
|
256
|
-
c.mutex.Lock()
|
|
257
|
-
defer c.mutex.Unlock()
|
|
258
|
-
// Check headers for rollback point
|
|
259
|
-
if len(c.headers) > 0 {
|
|
260
|
-
for idx, header := range c.headers {
|
|
261
|
-
if header.SlotNumber() == point.Slot &&
|
|
262
|
-
string(header.Hash().Bytes()) == string(point.Hash) {
|
|
263
|
-
// Remove headers after rollback point
|
|
264
|
-
if idx < len(c.headers)-1 {
|
|
265
|
-
c.headers = slices.Delete(c.headers, idx+1, len(c.headers))
|
|
266
|
-
}
|
|
267
|
-
return nil
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
// Lookup block for rollback point
|
|
272
|
-
var rollbackBlockIndex uint64
|
|
273
|
-
var tmpBlock database.Block
|
|
274
|
-
if point.Slot > 0 {
|
|
275
|
-
var err error
|
|
276
|
-
tmpBlock, err = c.BlockByPoint(point, nil)
|
|
277
|
-
if err != nil {
|
|
278
|
-
return err
|
|
279
|
-
}
|
|
280
|
-
rollbackBlockIndex = tmpBlock.ID
|
|
281
|
-
}
|
|
282
|
-
// Delete any rolled-back blocks
|
|
283
|
-
for i := c.tipBlockIndex; i > rollbackBlockIndex; i-- {
|
|
284
|
-
if c.persistent {
|
|
285
|
-
// Remove from database
|
|
286
|
-
txn := c.db.BlobTxn(true)
|
|
287
|
-
err := txn.Do(func(txn *database.Txn) error {
|
|
288
|
-
tmpBlock, err := c.db.BlockByIndex(i, txn)
|
|
289
|
-
if err != nil {
|
|
290
|
-
return err
|
|
291
|
-
}
|
|
292
|
-
if err := database.BlockDeleteTxn(txn, tmpBlock); err != nil {
|
|
293
|
-
return err
|
|
294
|
-
}
|
|
295
|
-
return nil
|
|
296
|
-
})
|
|
297
|
-
if err != nil {
|
|
298
|
-
return err
|
|
299
|
-
}
|
|
300
|
-
} else {
|
|
301
|
-
// Return an error if we try to rollback beyond memory buffer
|
|
302
|
-
if i <= c.lastDbBlockIndex {
|
|
303
|
-
return ErrRollbackBeyondEphemeralChain
|
|
304
|
-
}
|
|
305
|
-
// Remove from memory buffer
|
|
306
|
-
memBlockIndex := int(i - c.lastDbBlockIndex - initialBlockIndex) //nolint:gosec
|
|
307
|
-
c.blocks = slices.Delete(
|
|
308
|
-
c.blocks,
|
|
309
|
-
memBlockIndex,
|
|
310
|
-
memBlockIndex+1,
|
|
311
|
-
)
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
// Clear out any headers
|
|
315
|
-
c.headers = slices.Delete(c.headers, 0, len(c.headers))
|
|
316
|
-
// Update tip
|
|
317
|
-
c.currentTip = ochainsync.Tip{
|
|
318
|
-
Point: point,
|
|
319
|
-
BlockNumber: tmpBlock.Number,
|
|
320
|
-
}
|
|
321
|
-
c.tipBlockIndex = rollbackBlockIndex
|
|
322
|
-
// Update iterators for rollback
|
|
323
|
-
for _, iter := range c.iterators {
|
|
324
|
-
if iter.lastPoint.Slot > point.Slot {
|
|
325
|
-
// Don't update rollback point if the iterator already has an older one pending
|
|
326
|
-
if iter.needsRollback && point.Slot > iter.rollbackPoint.Slot {
|
|
327
|
-
continue
|
|
328
|
-
}
|
|
329
|
-
iter.rollbackPoint = point
|
|
330
|
-
iter.needsRollback = true
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
// Generate event
|
|
334
|
-
if c.eventBus != nil {
|
|
335
|
-
c.eventBus.Publish(
|
|
336
|
-
ChainUpdateEventType,
|
|
337
|
-
event.NewEvent(
|
|
338
|
-
ChainUpdateEventType,
|
|
339
|
-
ChainRollbackEvent{
|
|
340
|
-
Point: point,
|
|
341
|
-
},
|
|
342
|
-
),
|
|
343
|
-
)
|
|
344
|
-
}
|
|
345
|
-
return nil
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
func (c *Chain) HeaderCount() int {
|
|
349
|
-
c.mutex.RLock()
|
|
350
|
-
defer c.mutex.RUnlock()
|
|
351
|
-
return len(c.headers)
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
func (c *Chain) HeaderRange(count int) (ocommon.Point, ocommon.Point) {
|
|
355
|
-
c.mutex.RLock()
|
|
356
|
-
defer c.mutex.RUnlock()
|
|
357
|
-
var startPoint, endPoint ocommon.Point
|
|
358
|
-
if len(c.headers) > 0 {
|
|
359
|
-
firstHeader := c.headers[0]
|
|
360
|
-
startPoint = ocommon.Point{
|
|
361
|
-
Slot: firstHeader.SlotNumber(),
|
|
362
|
-
Hash: firstHeader.Hash().Bytes(),
|
|
363
|
-
}
|
|
364
|
-
lastHeaderIdx := min(count, len(c.headers)) - 1
|
|
365
|
-
lastHeader := c.headers[lastHeaderIdx]
|
|
366
|
-
endPoint = ocommon.Point{
|
|
367
|
-
Slot: lastHeader.SlotNumber(),
|
|
368
|
-
Hash: lastHeader.Hash().Bytes(),
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
return startPoint, endPoint
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// FromPoint returns a ChainIterator starting at the specified point. If inclusive is true, the iterator
|
|
375
|
-
// will start at the specified point. Otherwise it will start at the point following the specified point
|
|
376
|
-
func (c *Chain) FromPoint(
|
|
377
|
-
point ocommon.Point,
|
|
378
|
-
inclusive bool,
|
|
379
|
-
) (*ChainIterator, error) {
|
|
380
|
-
c.mutex.Lock()
|
|
381
|
-
defer c.mutex.Unlock()
|
|
382
|
-
iter, err := newChainIterator(
|
|
383
|
-
c,
|
|
384
|
-
point,
|
|
385
|
-
inclusive,
|
|
386
|
-
)
|
|
387
|
-
if err != nil {
|
|
388
|
-
return nil, err
|
|
389
|
-
}
|
|
390
|
-
c.iterators = append(c.iterators, iter)
|
|
391
|
-
return iter, nil
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
func (c *Chain) BlockByPoint(
|
|
395
|
-
point ocommon.Point,
|
|
396
|
-
txn *database.Txn,
|
|
397
|
-
) (database.Block, error) {
|
|
398
|
-
if point.Slot <= c.lastDbSlot {
|
|
399
|
-
// Query database
|
|
400
|
-
tmpBlock, err := database.BlockByPoint(c.db, point)
|
|
401
|
-
if err != nil {
|
|
402
|
-
if errors.Is(err, database.ErrBlockNotFound) {
|
|
403
|
-
return database.Block{}, ErrBlockNotFound
|
|
404
|
-
}
|
|
405
|
-
return database.Block{}, err
|
|
406
|
-
}
|
|
407
|
-
return tmpBlock, nil
|
|
408
|
-
}
|
|
409
|
-
// Search memory buffer
|
|
410
|
-
for _, block := range c.blocks {
|
|
411
|
-
if point.Slot != block.Slot {
|
|
412
|
-
continue
|
|
413
|
-
}
|
|
414
|
-
if string(point.Hash) != string(block.Hash) {
|
|
415
|
-
continue
|
|
416
|
-
}
|
|
417
|
-
return block, nil
|
|
418
|
-
}
|
|
419
|
-
return database.Block{}, ErrBlockNotFound
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
func (c *Chain) blockByIndex(
|
|
423
|
-
blockIndex uint64,
|
|
424
|
-
txn *database.Txn,
|
|
425
|
-
) (database.Block, error) {
|
|
426
|
-
if blockIndex <= c.lastDbBlockIndex {
|
|
427
|
-
// Query database
|
|
428
|
-
tmpBlock, err := c.db.BlockByIndex(blockIndex, txn)
|
|
429
|
-
if err != nil {
|
|
430
|
-
if errors.Is(err, database.ErrBlockNotFound) {
|
|
431
|
-
return database.Block{}, ErrBlockNotFound
|
|
432
|
-
}
|
|
433
|
-
return database.Block{}, err
|
|
434
|
-
}
|
|
435
|
-
return tmpBlock, nil
|
|
436
|
-
}
|
|
437
|
-
// Get from memory buffer
|
|
438
|
-
//nolint:gosec
|
|
439
|
-
memBlockIndex := int(
|
|
440
|
-
blockIndex - c.lastDbBlockIndex - initialBlockIndex,
|
|
441
|
-
)
|
|
442
|
-
if memBlockIndex < 0 || len(c.blocks) < memBlockIndex+1 {
|
|
443
|
-
return database.Block{}, ErrBlockNotFound
|
|
444
|
-
}
|
|
445
|
-
return c.blocks[memBlockIndex], nil
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
func (c *Chain) iterNext(
|
|
449
|
-
iter *ChainIterator,
|
|
450
|
-
blocking bool,
|
|
451
|
-
) (*ChainIteratorResult, error) {
|
|
452
|
-
c.mutex.RLock()
|
|
453
|
-
// Check for pending rollback
|
|
454
|
-
if iter.needsRollback {
|
|
455
|
-
ret := &ChainIteratorResult{}
|
|
456
|
-
ret.Point = iter.rollbackPoint
|
|
457
|
-
ret.Rollback = true
|
|
458
|
-
iter.lastPoint = iter.rollbackPoint
|
|
459
|
-
iter.needsRollback = false
|
|
460
|
-
if iter.rollbackPoint.Slot > 0 {
|
|
461
|
-
// Lookup block index for rollback point
|
|
462
|
-
tmpBlock, err := c.BlockByPoint(iter.rollbackPoint, nil)
|
|
463
|
-
if err != nil {
|
|
464
|
-
c.mutex.RUnlock()
|
|
465
|
-
return nil, err
|
|
466
|
-
}
|
|
467
|
-
iter.nextBlockIndex = tmpBlock.ID + 1
|
|
468
|
-
}
|
|
469
|
-
c.mutex.RUnlock()
|
|
470
|
-
return ret, nil
|
|
471
|
-
}
|
|
472
|
-
ret := &ChainIteratorResult{}
|
|
473
|
-
// Lookup next block in metadata DB
|
|
474
|
-
tmpBlock, err := c.blockByIndex(iter.nextBlockIndex, nil)
|
|
475
|
-
// Return immedidately if a block is found
|
|
476
|
-
if err == nil {
|
|
477
|
-
ret.Point = ocommon.NewPoint(tmpBlock.Slot, tmpBlock.Hash)
|
|
478
|
-
ret.Block = tmpBlock
|
|
479
|
-
iter.nextBlockIndex++
|
|
480
|
-
iter.lastPoint = ret.Point
|
|
481
|
-
c.mutex.RUnlock()
|
|
482
|
-
return ret, nil
|
|
483
|
-
}
|
|
484
|
-
// Return any actual error
|
|
485
|
-
if !errors.Is(err, ErrBlockNotFound) {
|
|
486
|
-
c.mutex.RUnlock()
|
|
487
|
-
return ret, err
|
|
488
|
-
}
|
|
489
|
-
// Return immediately if we're not blocking
|
|
490
|
-
if !blocking {
|
|
491
|
-
c.mutex.RUnlock()
|
|
492
|
-
return nil, ErrIteratorChainTip
|
|
493
|
-
}
|
|
494
|
-
c.mutex.RUnlock()
|
|
495
|
-
// Wait for chain update
|
|
496
|
-
c.waitingChanMutex.Lock()
|
|
497
|
-
if c.waitingChan == nil {
|
|
498
|
-
c.waitingChan = make(chan struct{})
|
|
499
|
-
}
|
|
500
|
-
c.waitingChanMutex.Unlock()
|
|
501
|
-
<-c.waitingChan
|
|
502
|
-
// Call ourselves again now that we should have new data
|
|
503
|
-
return c.iterNext(iter, blocking)
|
|
504
|
-
}
|