@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.
Files changed (192) hide show
  1. package/README.md +2 -1
  2. package/{bin/dingo → dingo} +0 -0
  3. package/dingo.yaml.example +53 -0
  4. package/package.json +2 -2
  5. package/.github/CODEOWNERS +0 -5
  6. package/.github/assets/dingo-ate-my-blockchain.png +0 -0
  7. package/.github/assets/dingo-illustration.png +0 -0
  8. package/.github/assets/dingo-logo-with-text-horizontal.png +0 -0
  9. package/.github/assets/dingo-logo-with-text.png +0 -0
  10. package/.github/dependabot.yml +0 -19
  11. package/.github/dingo-20241210.png +0 -0
  12. package/.github/dingo.md +0 -56
  13. package/.github/workflows/ci-docker.yml +0 -36
  14. package/.github/workflows/conventional-commits.yml +0 -17
  15. package/.github/workflows/go-test.yml +0 -29
  16. package/.github/workflows/golangci-lint.yml +0 -23
  17. package/.github/workflows/publish.yml +0 -207
  18. package/Dockerfile +0 -25
  19. package/Makefile +0 -53
  20. package/blockfetch.go +0 -144
  21. package/chain/chain.go +0 -504
  22. package/chain/chain_test.go +0 -468
  23. package/chain/errors.go +0 -80
  24. package/chain/event.go +0 -33
  25. package/chain/iter.go +0 -64
  26. package/chainsync/chainsync.go +0 -97
  27. package/chainsync.go +0 -223
  28. package/cmd/dingo/load.go +0 -52
  29. package/cmd/dingo/main.go +0 -118
  30. package/cmd/dingo/serve.go +0 -49
  31. package/config/cardano/node.go +0 -192
  32. package/config/cardano/node_test.go +0 -85
  33. package/config/cardano/preview/README.md +0 -4
  34. package/config/cardano/preview/alonzo-genesis.json +0 -196
  35. package/config/cardano/preview/byron-genesis.json +0 -117
  36. package/config/cardano/preview/config.json +0 -114
  37. package/config/cardano/preview/conway-genesis.json +0 -297
  38. package/config/cardano/preview/shelley-genesis.json +0 -68
  39. package/config.go +0 -245
  40. package/connmanager/connection_manager.go +0 -105
  41. package/connmanager/connection_manager_test.go +0 -185
  42. package/connmanager/event.go +0 -37
  43. package/connmanager/listener.go +0 -140
  44. package/connmanager/outbound.go +0 -93
  45. package/connmanager/socket.go +0 -55
  46. package/connmanager/unix.go +0 -78
  47. package/custom-p2p-topology.json +0 -24
  48. package/custom-p2p-topology.json.backup +0 -24
  49. package/custom-p2p-topology.json.mainnet +0 -37
  50. package/database/account.go +0 -180
  51. package/database/block.go +0 -362
  52. package/database/certs.go +0 -53
  53. package/database/commit_timestamp.go +0 -77
  54. package/database/database.go +0 -118
  55. package/database/database_test.go +0 -62
  56. package/database/drep.go +0 -47
  57. package/database/epoch.go +0 -121
  58. package/database/immutable/chunk.go +0 -182
  59. package/database/immutable/immutable.go +0 -350
  60. package/database/immutable/immutable_test.go +0 -59
  61. package/database/immutable/primary.go +0 -106
  62. package/database/immutable/secondary.go +0 -103
  63. package/database/immutable/testdata/08893.chunk +0 -0
  64. package/database/immutable/testdata/08893.primary +0 -0
  65. package/database/immutable/testdata/08893.secondary +0 -0
  66. package/database/immutable/testdata/08894.chunk +0 -0
  67. package/database/immutable/testdata/08894.primary +0 -0
  68. package/database/immutable/testdata/08894.secondary +0 -0
  69. package/database/immutable/testdata/README.md +0 -4
  70. package/database/plugin/blob/badger/commit_timestamp.go +0 -50
  71. package/database/plugin/blob/badger/database.go +0 -152
  72. package/database/plugin/blob/badger/logger.go +0 -63
  73. package/database/plugin/blob/badger/metrics.go +0 -98
  74. package/database/plugin/blob/blob.go +0 -19
  75. package/database/plugin/blob/store.go +0 -40
  76. package/database/plugin/log.go +0 -27
  77. package/database/plugin/metadata/metadata.go +0 -19
  78. package/database/plugin/metadata/sqlite/account.go +0 -313
  79. package/database/plugin/metadata/sqlite/certs.go +0 -58
  80. package/database/plugin/metadata/sqlite/commit_timestamp.go +0 -68
  81. package/database/plugin/metadata/sqlite/database.go +0 -218
  82. package/database/plugin/metadata/sqlite/drep.go +0 -140
  83. package/database/plugin/metadata/sqlite/epoch.go +0 -120
  84. package/database/plugin/metadata/sqlite/models/account.go +0 -118
  85. package/database/plugin/metadata/sqlite/models/auth_committee_hot.go +0 -26
  86. package/database/plugin/metadata/sqlite/models/drep.go +0 -52
  87. package/database/plugin/metadata/sqlite/models/epoch.go +0 -31
  88. package/database/plugin/metadata/sqlite/models/models.go +0 -46
  89. package/database/plugin/metadata/sqlite/models/pool.go +0 -97
  90. package/database/plugin/metadata/sqlite/models/pparam_update.go +0 -27
  91. package/database/plugin/metadata/sqlite/models/pparams.go +0 -27
  92. package/database/plugin/metadata/sqlite/models/resign_committee_cold.go +0 -27
  93. package/database/plugin/metadata/sqlite/models/stake_vote_delegation.go +0 -27
  94. package/database/plugin/metadata/sqlite/models/tip.go +0 -26
  95. package/database/plugin/metadata/sqlite/models/update_drep.go +0 -27
  96. package/database/plugin/metadata/sqlite/models/utxo.go +0 -30
  97. package/database/plugin/metadata/sqlite/models/vote_delegation.go +0 -26
  98. package/database/plugin/metadata/sqlite/models/vote_registration_delegation.go +0 -15
  99. package/database/plugin/metadata/sqlite/pool.go +0 -240
  100. package/database/plugin/metadata/sqlite/pparams.go +0 -110
  101. package/database/plugin/metadata/sqlite/tip.go +0 -83
  102. package/database/plugin/metadata/sqlite/utxo.go +0 -292
  103. package/database/plugin/metadata/store.go +0 -198
  104. package/database/plugin/option.go +0 -190
  105. package/database/plugin/plugin.go +0 -20
  106. package/database/plugin/register.go +0 -118
  107. package/database/pparams.go +0 -145
  108. package/database/tip.go +0 -45
  109. package/database/txn.go +0 -147
  110. package/database/types/types.go +0 -74
  111. package/database/types/types_test.go +0 -83
  112. package/database/utxo.go +0 -263
  113. package/dist/artifacts.json +0 -1
  114. package/dist/checksums.txt +0 -22
  115. package/dist/config.yaml +0 -253
  116. package/dist/dingo-0.5.0-SNAPSHOT-d9431e4.tar.gz +0 -0
  117. package/dist/dingo-0.5.0-SNAPSHOT-d9431e4.tar.gz.sbom.json +0 -1
  118. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_arm64.tar.gz +0 -0
  119. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_arm64.tar.gz.sbom.json +0 -1
  120. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_x86_64.tar.gz +0 -0
  121. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_x86_64.tar.gz.sbom.json +0 -1
  122. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.apk +0 -0
  123. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.apk.sbom.json +0 -1
  124. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.deb +0 -0
  125. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.deb.sbom.json +0 -1
  126. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.rpm +0 -0
  127. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.rpm.sbom.json +0 -1
  128. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.apk +0 -0
  129. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.apk.sbom.json +0 -1
  130. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.deb +0 -0
  131. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.deb.sbom.json +0 -1
  132. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.rpm +0 -0
  133. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.rpm.sbom.json +0 -1
  134. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.tar.gz +0 -0
  135. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.tar.gz.sbom.json +0 -1
  136. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_x86_64.tar.gz +0 -0
  137. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_x86_64.tar.gz.sbom.json +0 -1
  138. package/dist/dingo_darwin_amd64_v1/dingo +0 -0
  139. package/dist/dingo_darwin_arm64_v8.0/dingo +0 -0
  140. package/dist/dingo_linux_amd64_v1/dingo +0 -0
  141. package/dist/dingo_linux_arm64_v8.0/dingo +0 -0
  142. package/dist/homebrew/dingo.rb +0 -51
  143. package/dist/metadata.json +0 -1
  144. package/event/event.go +0 -141
  145. package/event/event_test.go +0 -115
  146. package/event/metrics.go +0 -44
  147. package/go.mod +0 -98
  148. package/go.sum +0 -358
  149. package/internal/config/config.go +0 -145
  150. package/internal/config/config_test.go +0 -118
  151. package/internal/node/load.go +0 -149
  152. package/internal/node/node.go +0 -176
  153. package/internal/version/version.go +0 -33
  154. package/ledger/certs.go +0 -164
  155. package/ledger/chainsync.go +0 -504
  156. package/ledger/delta.go +0 -99
  157. package/ledger/eras/allegra.go +0 -154
  158. package/ledger/eras/alonzo.go +0 -156
  159. package/ledger/eras/babbage.go +0 -154
  160. package/ledger/eras/byron.go +0 -42
  161. package/ledger/eras/conway.go +0 -166
  162. package/ledger/eras/eras.go +0 -44
  163. package/ledger/eras/mary.go +0 -154
  164. package/ledger/eras/shelley.go +0 -164
  165. package/ledger/error.go +0 -19
  166. package/ledger/event.go +0 -50
  167. package/ledger/metrics.go +0 -53
  168. package/ledger/queries.go +0 -258
  169. package/ledger/slot.go +0 -127
  170. package/ledger/slot_test.go +0 -147
  171. package/ledger/state.go +0 -821
  172. package/ledger/view.go +0 -73
  173. package/localstatequery.go +0 -50
  174. package/localtxmonitor.go +0 -44
  175. package/localtxsubmission.go +0 -52
  176. package/mempool/consumer.go +0 -98
  177. package/mempool/mempool.go +0 -322
  178. package/node.go +0 -320
  179. package/peergov/event.go +0 -27
  180. package/peergov/peer.go +0 -67
  181. package/peergov/peergov.go +0 -290
  182. package/peersharing.go +0 -70
  183. package/preview-local-topology.json +0 -23
  184. package/topology/topology.go +0 -69
  185. package/topology/topology_test.go +0 -179
  186. package/tracing.go +0 -65
  187. package/txsubmission.go +0 -233
  188. package/utxorpc/query.go +0 -311
  189. package/utxorpc/submit.go +0 -395
  190. package/utxorpc/sync.go +0 -276
  191. package/utxorpc/utxorpc.go +0 -166
  192. package/utxorpc/watch.go +0 -310
package/blockfetch.go DELETED
@@ -1,144 +0,0 @@
1
- // Copyright 2024 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 dingo
16
-
17
- import (
18
- "fmt"
19
- "time"
20
-
21
- "github.com/blinklabs-io/dingo/event"
22
- "github.com/blinklabs-io/dingo/ledger"
23
- ouroboros "github.com/blinklabs-io/gouroboros"
24
- gledger "github.com/blinklabs-io/gouroboros/ledger"
25
- "github.com/blinklabs-io/gouroboros/protocol/blockfetch"
26
- ocommon "github.com/blinklabs-io/gouroboros/protocol/common"
27
- )
28
-
29
- func (n *Node) blockfetchServerConnOpts() []blockfetch.BlockFetchOptionFunc {
30
- return []blockfetch.BlockFetchOptionFunc{
31
- blockfetch.WithRequestRangeFunc(n.blockfetchServerRequestRange),
32
- }
33
- }
34
-
35
- func (n *Node) blockfetchClientConnOpts() []blockfetch.BlockFetchOptionFunc {
36
- return []blockfetch.BlockFetchOptionFunc{
37
- blockfetch.WithBlockFunc(n.blockfetchClientBlock),
38
- blockfetch.WithBatchDoneFunc(n.blockfetchClientBatchDone),
39
- blockfetch.WithBatchStartTimeout(2 * time.Second),
40
- blockfetch.WithBlockTimeout(2 * time.Second),
41
- // Set the recv queue size to 2x our block batch size
42
- blockfetch.WithRecvQueueSize(1000),
43
- }
44
- }
45
-
46
- func (n *Node) blockfetchServerRequestRange(
47
- ctx blockfetch.CallbackContext,
48
- start ocommon.Point,
49
- end ocommon.Point,
50
- ) error {
51
- // TODO: check if we have requested block range available and send NoBlocks if not (#397)
52
- chainIter, err := n.ledgerState.GetChainFromPoint(start, true)
53
- if err != nil {
54
- return err
55
- }
56
- // Start async process to send requested block range
57
- go func() {
58
- if err := ctx.Server.StartBatch(); err != nil {
59
- return
60
- }
61
- for {
62
- next, _ := chainIter.Next(false)
63
- if next == nil {
64
- break
65
- }
66
- if next.Block.Slot > end.Slot {
67
- break
68
- }
69
- blockBytes := next.Block.Cbor[:]
70
- err := ctx.Server.Block(
71
- next.Block.Type,
72
- blockBytes,
73
- )
74
- if err != nil {
75
- // TODO: push this error somewhere (#398)
76
- return
77
- }
78
- // Make sure we don't hang waiting for the next block if we've already hit the end
79
- if next.Block.Slot == end.Slot {
80
- break
81
- }
82
- }
83
- if err := ctx.Server.BatchDone(); err != nil {
84
- return
85
- }
86
- }()
87
- return nil
88
- }
89
-
90
- // blockfetchClientRequestRange is called by the ledger when it needs to request a range of block bodies
91
- func (n *Node) blockfetchClientRequestRange(
92
- connId ouroboros.ConnectionId,
93
- start ocommon.Point,
94
- end ocommon.Point,
95
- ) error {
96
- conn := n.connManager.GetConnectionById(connId)
97
- if conn == nil {
98
- return fmt.Errorf("failed to lookup connection ID: %s", connId.String())
99
- }
100
- if err := conn.BlockFetch().Client.GetBlockRange(start, end); err != nil {
101
- return err
102
- }
103
- return nil
104
- }
105
-
106
- func (n *Node) blockfetchClientBlock(
107
- ctx blockfetch.CallbackContext,
108
- blockType uint,
109
- block gledger.Block,
110
- ) error {
111
- // Generate event
112
- n.eventBus.Publish(
113
- ledger.BlockfetchEventType,
114
- event.NewEvent(
115
- ledger.BlockfetchEventType,
116
- ledger.BlockfetchEvent{
117
- Point: ocommon.NewPoint(
118
- block.SlotNumber(),
119
- block.Hash().Bytes(),
120
- ),
121
- Type: blockType,
122
- Block: block,
123
- },
124
- ),
125
- )
126
- return nil
127
- }
128
-
129
- func (n *Node) blockfetchClientBatchDone(
130
- ctx blockfetch.CallbackContext,
131
- ) error {
132
- // Generate event
133
- n.eventBus.Publish(
134
- ledger.BlockfetchEventType,
135
- event.NewEvent(
136
- ledger.BlockfetchEventType,
137
- ledger.BlockfetchEvent{
138
- ConnectionId: ctx.ConnectionId,
139
- BatchDone: true,
140
- },
141
- ),
142
- )
143
- return nil
144
- }
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
- }