Skip to content

Commit 526a457

Browse files
authored
Merge pull request #199 from cloudstruct/feat/blockfetch-simpler-interface
feat: simpler interface for blockfetch protocol
2 parents dc94533 + ecb7560 commit 526a457

File tree

5 files changed

+96
-104
lines changed

5 files changed

+96
-104
lines changed

cmd/go-ouroboros-network/chainsync.go

Lines changed: 11 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"fmt"
77
"github.com/cloudstruct/go-cardano-ledger"
88
ouroboros "github.com/cloudstruct/go-ouroboros-network"
9-
"github.com/cloudstruct/go-ouroboros-network/protocol/blockfetch"
109
"github.com/cloudstruct/go-ouroboros-network/protocol/chainsync"
1110
"github.com/cloudstruct/go-ouroboros-network/protocol/common"
1211
"os"
@@ -86,15 +85,6 @@ func buildChainSyncConfig() chainsync.Config {
8685
)
8786
}
8887

89-
func buildBlockFetchConfig() blockfetch.Config {
90-
return blockfetch.NewConfig(
91-
blockfetch.WithStartBatchFunc(blockFetchStartBatchHandler),
92-
blockfetch.WithNoBlocksFunc(blockFetchNoBlocksHandler),
93-
blockfetch.WithBlockFunc(blockFetchBlockHandler),
94-
blockfetch.WithBatchDoneFunc(blockFetchBatchDoneHandler),
95-
)
96-
}
97-
9888
func testChainSync(f *globalFlags) {
9989
chainSyncFlags := newChainSyncFlags()
10090
err := chainSyncFlags.flagset.Parse(f.flagset.Args()[1:])
@@ -133,7 +123,6 @@ func testChainSync(f *globalFlags) {
133123
ouroboros.WithErrorChan(errorChan),
134124
ouroboros.WithNodeToNode(f.ntnProto),
135125
ouroboros.WithKeepAlive(true),
136-
ouroboros.WithBlockFetchConfig(buildBlockFetchConfig()),
137126
ouroboros.WithChainSyncConfig(buildChainSyncConfig()),
138127
)
139128
if err != nil {
@@ -177,72 +166,46 @@ func chainSyncRollBackwardHandler(point common.Point, tip chainsync.Tip) error {
177166
}
178167

179168
func chainSyncRollForwardHandler(blockType uint, blockData interface{}, tip chainsync.Tip) error {
169+
var block ledger.Block
180170
switch v := blockData.(type) {
181171
case ledger.Block:
182-
switch blockType {
183-
case ledger.BLOCK_TYPE_BYRON_EBB:
184-
byronEbbBlock := v.(*ledger.ByronEpochBoundaryBlock)
185-
fmt.Printf("era = Byron (EBB), epoch = %d, id = %s\n", byronEbbBlock.Header.ConsensusData.Epoch, byronEbbBlock.Hash())
186-
case ledger.BLOCK_TYPE_BYRON_MAIN:
187-
byronBlock := v.(*ledger.ByronMainBlock)
188-
fmt.Printf("era = Byron, epoch = %d, slot = %d, id = %s\n", byronBlock.Header.ConsensusData.SlotId.Epoch, byronBlock.SlotNumber(), byronBlock.Hash())
189-
default:
190-
fmt.Printf("era = %s, slot = %d, block_no = %d, id = %s\n", v.Era().Name, v.SlotNumber(), v.BlockNumber(), v.Hash())
191-
}
172+
block = v
192173
case ledger.BlockHeader:
193174
var blockSlot uint64
194175
var blockHash []byte
195176
switch blockType {
196177
case ledger.BLOCK_TYPE_BYRON_EBB:
197178
byronEbbHeader := v.(*ledger.ByronEpochBoundaryBlockHeader)
198-
//fmt.Printf("era = Byron (EBB), epoch = %d, id = %s\n", h.ConsensusData.Epoch, h.Hash())
199179
if syncState.byronEpochSlot > 0 {
200180
syncState.byronEpochBaseSlot += syncState.byronEpochSlot + 1
201181
}
202182
blockSlot = syncState.byronEpochBaseSlot
203183
blockHash, _ = hex.DecodeString(byronEbbHeader.Hash())
204184
case ledger.BLOCK_TYPE_BYRON_MAIN:
205185
byronHeader := v.(*ledger.ByronMainBlockHeader)
206-
//fmt.Printf("era = Byron, epoch = %d, slot = %d, id = %s\n", h.ConsensusData.SlotId.Epoch, h.ConsensusData.SlotId.Slot, h.Hash())
207186
syncState.byronEpochSlot = uint64(byronHeader.ConsensusData.SlotId.Slot)
208187
blockSlot = syncState.byronEpochBaseSlot + syncState.byronEpochSlot
209188
blockHash, _ = hex.DecodeString(byronHeader.Hash())
210189
default:
211190
blockSlot = v.SlotNumber()
212191
blockHash, _ = hex.DecodeString(v.Hash())
213192
}
214-
if err := syncState.oConn.BlockFetch().Client.RequestRange([]interface{}{blockSlot, blockHash}, []interface{}{blockSlot, blockHash}); err != nil {
215-
fmt.Printf("error calling RequestRange: %s\n", err)
193+
var err error
194+
block, err = syncState.oConn.BlockFetch().Client.GetBlock(common.NewPoint(blockSlot, blockHash))
195+
if err != nil {
216196
return err
217197
}
218198
}
219-
return nil
220-
}
221-
222-
func blockFetchStartBatchHandler() error {
223-
return nil
224-
}
225-
226-
func blockFetchNoBlocksHandler() error {
227-
fmt.Printf("blockFetchNoBlocksHandler()\n")
228-
return nil
229-
}
230-
231-
func blockFetchBlockHandler(blockType uint, blockData interface{}) error {
199+
// Display block info
232200
switch blockType {
233201
case ledger.BLOCK_TYPE_BYRON_EBB:
234-
b := blockData.(*ledger.ByronEpochBoundaryBlock)
235-
fmt.Printf("era = Byron (EBB), id = %s\n", b.Hash())
202+
byronEbbBlock := block.(*ledger.ByronEpochBoundaryBlock)
203+
fmt.Printf("era = Byron (EBB), epoch = %d, id = %s\n", byronEbbBlock.Header.ConsensusData.Epoch, byronEbbBlock.Hash())
236204
case ledger.BLOCK_TYPE_BYRON_MAIN:
237-
b := blockData.(*ledger.ByronMainBlock)
238-
fmt.Printf("era = Byron, epoch = %d, slot = %d, id = %s\n", b.Header.ConsensusData.SlotId.Epoch, b.SlotNumber(), b.Hash())
205+
byronBlock := block.(*ledger.ByronMainBlock)
206+
fmt.Printf("era = Byron, epoch = %d, slot = %d, id = %s\n", byronBlock.Header.ConsensusData.SlotId.Epoch, byronBlock.SlotNumber(), byronBlock.Hash())
239207
default:
240-
b := blockData.(ledger.Block)
241-
fmt.Printf("era = %s, slot = %d, block_no = %d, id = %s\n", b.Era().Name, b.SlotNumber(), b.BlockNumber(), b.Hash())
208+
fmt.Printf("era = %s, slot = %d, block_no = %d, id = %s\n", block.Era().Name, block.SlotNumber(), block.BlockNumber(), block.Hash())
242209
}
243210
return nil
244211
}
245-
246-
func blockFetchBatchDoneHandler() error {
247-
return nil
248-
}

protocol/blockfetch/blockfetch.go

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"time"
55

66
"github.com/cloudstruct/go-ouroboros-network/protocol"
7+
8+
"github.com/cloudstruct/go-cardano-ledger"
79
)
810

911
const (
@@ -69,19 +71,13 @@ type BlockFetch struct {
6971
}
7072

7173
type Config struct {
72-
StartBatchFunc StartBatchFunc
73-
NoBlocksFunc NoBlocksFunc
7474
BlockFunc BlockFunc
75-
BatchDoneFunc BatchDoneFunc
7675
BatchStartTimeout time.Duration
7776
BlockTimeout time.Duration
7877
}
7978

8079
// Callback function types
81-
type StartBatchFunc func() error
82-
type NoBlocksFunc func() error
83-
type BlockFunc func(uint, interface{}) error
84-
type BatchDoneFunc func() error
80+
type BlockFunc func(ledger.Block) error
8581

8682
func New(protoOptions protocol.ProtocolOptions, cfg *Config) *BlockFetch {
8783
b := &BlockFetch{
@@ -105,30 +101,12 @@ func NewConfig(options ...BlockFetchOptionFunc) Config {
105101
return c
106102
}
107103

108-
func WithStartBatchFunc(startBatchFunc StartBatchFunc) BlockFetchOptionFunc {
109-
return func(c *Config) {
110-
c.StartBatchFunc = startBatchFunc
111-
}
112-
}
113-
114-
func WithNoBlocksFunc(noBlocksFunc NoBlocksFunc) BlockFetchOptionFunc {
115-
return func(c *Config) {
116-
c.NoBlocksFunc = noBlocksFunc
117-
}
118-
}
119-
120104
func WithBlockFunc(blockFunc BlockFunc) BlockFetchOptionFunc {
121105
return func(c *Config) {
122106
c.BlockFunc = blockFunc
123107
}
124108
}
125109

126-
func WithBatchDoneFunc(BatchDoneFunc BatchDoneFunc) BlockFetchOptionFunc {
127-
return func(c *Config) {
128-
c.BatchDoneFunc = BatchDoneFunc
129-
}
130-
}
131-
132110
func WithBatchStartTimeout(timeout time.Duration) BlockFetchOptionFunc {
133111
return func(c *Config) {
134112
c.BatchStartTimeout = timeout

protocol/blockfetch/client.go

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,22 @@ package blockfetch
22

33
import (
44
"fmt"
5-
"github.com/cloudstruct/go-cardano-ledger"
5+
"sync"
6+
67
"github.com/cloudstruct/go-ouroboros-network/protocol"
8+
"github.com/cloudstruct/go-ouroboros-network/protocol/common"
79
"github.com/cloudstruct/go-ouroboros-network/utils"
10+
11+
"github.com/cloudstruct/go-cardano-ledger"
812
)
913

1014
type Client struct {
1115
*protocol.Protocol
12-
config *Config
16+
config *Config
17+
blockChan chan ledger.Block
18+
startBatchResultChan chan error
19+
busyMutex sync.Mutex
20+
blockUseCallback bool
1321
}
1422

1523
func NewClient(protoOptions protocol.ProtocolOptions, cfg *Config) *Client {
@@ -18,7 +26,9 @@ func NewClient(protoOptions protocol.ProtocolOptions, cfg *Config) *Client {
1826
cfg = &tmpCfg
1927
}
2028
c := &Client{
21-
config: cfg,
29+
config: cfg,
30+
blockChan: make(chan ledger.Block),
31+
startBatchResultChan: make(chan error),
2232
}
2333
// Update state map with timeouts
2434
stateMap := StateMap.Copy()
@@ -44,17 +54,55 @@ func NewClient(protoOptions protocol.ProtocolOptions, cfg *Config) *Client {
4454
InitialState: STATE_IDLE,
4555
}
4656
c.Protocol = protocol.New(protoConfig)
57+
// Start goroutine to cleanup resources on protocol shutdown
58+
go func() {
59+
<-c.Protocol.DoneChan()
60+
close(c.blockChan)
61+
}()
4762
return c
4863
}
4964

50-
func (c *Client) RequestRange(start []interface{}, end []interface{}) error {
51-
msg := NewMsgRequestRange(start, end)
65+
func (c *Client) Stop() error {
66+
msg := NewMsgClientDone()
5267
return c.SendMessage(msg)
5368
}
5469

55-
func (c *Client) ClientDone() error {
56-
msg := NewMsgClientDone()
57-
return c.SendMessage(msg)
70+
// GetBlockRange starts an async process to fetch all blocks in the specified range (inclusive)
71+
func (c *Client) GetBlockRange(start common.Point, end common.Point) error {
72+
c.busyMutex.Lock()
73+
c.blockUseCallback = true
74+
msg := NewMsgRequestRange(start, end)
75+
if err := c.SendMessage(msg); err != nil {
76+
c.busyMutex.Unlock()
77+
return err
78+
}
79+
err := <-c.startBatchResultChan
80+
if err != nil {
81+
c.busyMutex.Unlock()
82+
return err
83+
}
84+
return nil
85+
}
86+
87+
// GetBlock requests and returns a single block specified by the provided point
88+
func (c *Client) GetBlock(point common.Point) (ledger.Block, error) {
89+
c.busyMutex.Lock()
90+
c.blockUseCallback = false
91+
msg := NewMsgRequestRange(point, point)
92+
if err := c.SendMessage(msg); err != nil {
93+
c.busyMutex.Unlock()
94+
return nil, err
95+
}
96+
err := <-c.startBatchResultChan
97+
if err != nil {
98+
c.busyMutex.Unlock()
99+
return nil, err
100+
}
101+
block, ok := <-c.blockChan
102+
if !ok {
103+
return nil, protocol.ProtocolShuttingDownError
104+
}
105+
return block, nil
58106
}
59107

60108
func (c *Client) messageHandler(msg protocol.Message, isResponse bool) error {
@@ -75,25 +123,17 @@ func (c *Client) messageHandler(msg protocol.Message, isResponse bool) error {
75123
}
76124

77125
func (c *Client) handleStartBatch() error {
78-
if c.config.StartBatchFunc == nil {
79-
return fmt.Errorf("received block-fetch StartBatch message but no callback function is defined")
80-
}
81-
// Call the user callback function
82-
return c.config.StartBatchFunc()
126+
c.startBatchResultChan <- nil
127+
return nil
83128
}
84129

85130
func (c *Client) handleNoBlocks() error {
86-
if c.config.NoBlocksFunc == nil {
87-
return fmt.Errorf("received block-fetch NoBlocks message but no callback function is defined")
88-
}
89-
// Call the user callback function
90-
return c.config.NoBlocksFunc()
131+
err := fmt.Errorf("block(s) not found")
132+
c.startBatchResultChan <- err
133+
return nil
91134
}
92135

93136
func (c *Client) handleBlock(msgGeneric protocol.Message) error {
94-
if c.config.BlockFunc == nil {
95-
return fmt.Errorf("received block-fetch Block message but no callback function is defined")
96-
}
97137
msg := msgGeneric.(*MsgBlock)
98138
// Decode only enough to get the block type value
99139
var wrappedBlock WrappedBlock
@@ -104,14 +144,18 @@ func (c *Client) handleBlock(msgGeneric protocol.Message) error {
104144
if err != nil {
105145
return err
106146
}
107-
// Call the user callback function
108-
return c.config.BlockFunc(wrappedBlock.Type, blk)
147+
// We use the callback when requesting ranges and the internal channel for a single block
148+
if c.blockUseCallback {
149+
if err := c.config.BlockFunc(blk); err != nil {
150+
return err
151+
}
152+
} else {
153+
c.blockChan <- blk
154+
}
155+
return nil
109156
}
110157

111158
func (c *Client) handleBatchDone() error {
112-
if c.config.BatchDoneFunc == nil {
113-
return fmt.Errorf("received block-fetch BatchDone message but no callback function is defined")
114-
}
115-
// Call the user callback function
116-
return c.config.BatchDoneFunc()
159+
c.busyMutex.Unlock()
160+
return nil
117161
}

protocol/error.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package protocol
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
var ProtocolShuttingDownError = fmt.Errorf("protocol is shutting down")

protocol/localtxmonitor/client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func (c *Client) HasTx(txId []byte) (bool, error) {
143143
}
144144
result, ok := <-c.hasTxResultChan
145145
if !ok {
146-
return false, fmt.Errorf("protocol is shutting down")
146+
return false, protocol.ProtocolShuttingDownError
147147
}
148148
return result, nil
149149
}
@@ -163,7 +163,7 @@ func (c *Client) NextTx() ([]byte, error) {
163163
}
164164
tx, ok := <-c.nextTxResultChan
165165
if !ok {
166-
return nil, fmt.Errorf("protocol is shutting down")
166+
return nil, protocol.ProtocolShuttingDownError
167167
}
168168
return tx, nil
169169
}
@@ -183,7 +183,7 @@ func (c *Client) GetSizes() (uint32, uint32, uint32, error) {
183183
}
184184
result, ok := <-c.getSizesResultChan
185185
if !ok {
186-
return 0, 0, 0, fmt.Errorf("protocol is shutting down")
186+
return 0, 0, 0, protocol.ProtocolShuttingDownError
187187
}
188188
return result.Capacity, result.Size, result.NumberOfTxs, nil
189189
}

0 commit comments

Comments
 (0)