Skip to content

Commit 5ca3018

Browse files
committed
feat: finish implementing local-state-query
This commit also moves the Point definition to a common package to make it easier to reuse. NOTE: many of the query result structures are not currently defined, but we can do those later Fixes #44 and #109
1 parent 2fa8b17 commit 5ca3018

File tree

13 files changed

+864
-120
lines changed

13 files changed

+864
-120
lines changed

cmd/go-ouroboros-network/chainsync.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
ouroboros "github.com/cloudstruct/go-ouroboros-network"
99
"github.com/cloudstruct/go-ouroboros-network/protocol/blockfetch"
1010
"github.com/cloudstruct/go-ouroboros-network/protocol/chainsync"
11+
"github.com/cloudstruct/go-ouroboros-network/protocol/common"
1112
"github.com/cloudstruct/go-ouroboros-network/utils"
1213
"os"
1314
)
@@ -133,25 +134,25 @@ func testChainSync(f *globalFlags) {
133134

134135
syncState.oConn = o
135136
syncState.nodeToNode = f.ntnProto
136-
var point chainsync.Point
137+
var point common.Point
137138
if len(eraIntersect[f.networkMagic][chainSyncFlags.startEra]) > 0 {
138139
// Slot
139140
slot := uint64(eraIntersect[f.networkMagic][chainSyncFlags.startEra][0].(int))
140141
// Block hash
141142
hash, _ := hex.DecodeString(eraIntersect[f.networkMagic][chainSyncFlags.startEra][1].(string))
142-
point = chainsync.NewPoint(slot, hash)
143+
point = common.NewPoint(slot, hash)
143144
} else {
144-
point = chainsync.NewPointOrigin()
145+
point = common.NewPointOrigin()
145146
}
146-
if err := o.ChainSync.Client.Sync([]chainsync.Point{point}); err != nil {
147+
if err := o.ChainSync.Client.Sync([]common.Point{point}); err != nil {
147148
fmt.Printf("ERROR: failed to start chain-sync: %s\n", err)
148149
os.Exit(1)
149150
}
150151
// Wait forever...the rest of the sync operations are async
151152
select {}
152153
}
153154

154-
func chainSyncRollBackwardHandler(point chainsync.Point, tip chainsync.Tip) error {
155+
func chainSyncRollBackwardHandler(point common.Point, tip chainsync.Tip) error {
155156
fmt.Printf("roll backward: point = %#v, tip = %#v\n", point, tip)
156157
return nil
157158
}

cmd/go-ouroboros-network/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ func main() {
7676
testLocalTxSubmission(f)
7777
case "server":
7878
testServer(f)
79+
case "query":
80+
testQuery(f)
7981
default:
8082
fmt.Printf("Unknown subcommand: %s\n", f.flagset.Arg(0))
8183
os.Exit(1)

cmd/go-ouroboros-network/query.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
ouroboros "github.com/cloudstruct/go-ouroboros-network"
7+
"github.com/cloudstruct/go-ouroboros-network/protocol/localstatequery"
8+
"os"
9+
)
10+
11+
type queryFlags struct {
12+
flagset *flag.FlagSet
13+
}
14+
15+
func newQueryFlags() *queryFlags {
16+
f := &queryFlags{
17+
flagset: flag.NewFlagSet("query", flag.ExitOnError),
18+
}
19+
return f
20+
}
21+
22+
func buildLocalStateQueryConfig() localstatequery.Config {
23+
return localstatequery.Config{}
24+
}
25+
26+
func testQuery(f *globalFlags) {
27+
queryFlags := newQueryFlags()
28+
err := queryFlags.flagset.Parse(f.flagset.Args()[1:])
29+
if err != nil {
30+
fmt.Printf("failed to parse subcommand args: %s\n", err)
31+
os.Exit(1)
32+
}
33+
if len(queryFlags.flagset.Args()) < 1 {
34+
fmt.Printf("ERROR: you must specify a query\n")
35+
os.Exit(1)
36+
}
37+
38+
conn := createClientConnection(f)
39+
errorChan := make(chan error)
40+
go func() {
41+
for {
42+
err := <-errorChan
43+
fmt.Printf("ERROR: %s\n", err)
44+
os.Exit(1)
45+
}
46+
}()
47+
o, err := ouroboros.New(
48+
ouroboros.WithConnection(conn),
49+
ouroboros.WithNetworkMagic(uint32(f.networkMagic)),
50+
ouroboros.WithErrorChan(errorChan),
51+
ouroboros.WithNodeToNode(f.ntnProto),
52+
ouroboros.WithKeepAlive(true),
53+
ouroboros.WithLocalStateQueryConfig(buildLocalStateQueryConfig()),
54+
)
55+
if err != nil {
56+
fmt.Printf("ERROR: %s\n", err)
57+
os.Exit(1)
58+
}
59+
o.LocalStateQuery.Client.Start()
60+
61+
switch queryFlags.flagset.Args()[0] {
62+
case "current-era":
63+
era, err := o.LocalStateQuery.Client.GetCurrentEra()
64+
if err != nil {
65+
fmt.Printf("ERROR: failure querying current era: %s\n", err)
66+
os.Exit(1)
67+
}
68+
fmt.Printf("current-era: %d\n", era)
69+
case "tip":
70+
era, err := o.LocalStateQuery.Client.GetCurrentEra()
71+
if err != nil {
72+
fmt.Printf("ERROR: failure querying current era: %s\n", err)
73+
os.Exit(1)
74+
}
75+
epochNo, err := o.LocalStateQuery.Client.GetEpochNo()
76+
if err != nil {
77+
fmt.Printf("ERROR: failure querying current epoch: %s\n", err)
78+
os.Exit(1)
79+
}
80+
blockNo, err := o.LocalStateQuery.Client.GetChainBlockNo()
81+
if err != nil {
82+
fmt.Printf("ERROR: failure querying current chain block number: %s\n", err)
83+
os.Exit(1)
84+
}
85+
point, err := o.LocalStateQuery.Client.GetChainPoint()
86+
if err != nil {
87+
fmt.Printf("ERROR: failure querying current chain point: %s\n", err)
88+
os.Exit(1)
89+
}
90+
fmt.Printf("tip: era = %d, epoch = %d, blockNo = %d, slot = %d, hash = %x\n", era, epochNo, blockNo, point.Slot, point.Hash)
91+
case "system-start":
92+
systemStart, err := o.LocalStateQuery.Client.GetSystemStart()
93+
if err != nil {
94+
fmt.Printf("ERROR: failure querying system start: %s\n", err)
95+
os.Exit(1)
96+
}
97+
fmt.Printf("system-start: year = %d, day = %d, picoseconds = %d\n", systemStart.Year, systemStart.Day, systemStart.Picoseconds)
98+
case "era-history":
99+
eraHistory, err := o.LocalStateQuery.Client.GetEraHistory()
100+
if err != nil {
101+
fmt.Printf("ERROR: failure querying era history: %s\n", err)
102+
os.Exit(1)
103+
}
104+
fmt.Printf("era-history: %#v", *eraHistory)
105+
default:
106+
fmt.Printf("ERROR: unknown query: %s\n", queryFlags.flagset.Args()[0])
107+
os.Exit(1)
108+
}
109+
}

protocol/chainsync/chainsync.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package chainsync
22

33
import (
44
"github.com/cloudstruct/go-ouroboros-network/protocol"
5+
"github.com/cloudstruct/go-ouroboros-network/protocol/common"
56
)
67

78
const (
@@ -95,7 +96,7 @@ type Config struct {
9596
}
9697

9798
// Callback function types
98-
type RollBackwardFunc func(Point, Tip) error
99+
type RollBackwardFunc func(common.Point, Tip) error
99100
type RollForwardFunc func(uint, interface{}, Tip) error
100101

101102
func New(protoOptions protocol.ProtocolOptions, cfg *Config) *ChainSync {

protocol/chainsync/client.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"github.com/cloudstruct/go-cardano-ledger"
66
"github.com/cloudstruct/go-ouroboros-network/protocol"
7+
"github.com/cloudstruct/go-ouroboros-network/protocol/common"
78
"sync"
89
)
910

@@ -74,7 +75,7 @@ func (c *Client) Stop() error {
7475
return nil
7576
}
7677

77-
func (c *Client) Sync(intersectPoints []Point) error {
78+
func (c *Client) Sync(intersectPoints []common.Point) error {
7879
c.busyMutex.Lock()
7980
defer c.busyMutex.Unlock()
8081
msg := NewMsgFindIntersect(intersectPoints)

protocol/chainsync/messages.go

Lines changed: 8 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package chainsync
33
import (
44
"fmt"
55
"github.com/cloudstruct/go-ouroboros-network/protocol"
6+
"github.com/cloudstruct/go-ouroboros-network/protocol/common"
67
"github.com/cloudstruct/go-ouroboros-network/utils"
78
"github.com/fxamacker/cbor/v2"
89
)
@@ -139,11 +140,11 @@ func NewMsgRollForwardNtN(era uint, byronType uint, blockCbor []byte, tip Tip) *
139140

140141
type MsgRollBackward struct {
141142
protocol.MessageBase
142-
Point Point
143+
Point common.Point
143144
Tip Tip
144145
}
145146

146-
func NewMsgRollBackward(point Point, tip Tip) *MsgRollBackward {
147+
func NewMsgRollBackward(point common.Point, tip Tip) *MsgRollBackward {
147148
m := &MsgRollBackward{
148149
MessageBase: protocol.MessageBase{
149150
MessageType: MESSAGE_TYPE_ROLL_BACKWARD,
@@ -156,10 +157,10 @@ func NewMsgRollBackward(point Point, tip Tip) *MsgRollBackward {
156157

157158
type MsgFindIntersect struct {
158159
protocol.MessageBase
159-
Points []Point
160+
Points []common.Point
160161
}
161162

162-
func NewMsgFindIntersect(points []Point) *MsgFindIntersect {
163+
func NewMsgFindIntersect(points []common.Point) *MsgFindIntersect {
163164
m := &MsgFindIntersect{
164165
MessageBase: protocol.MessageBase{
165166
MessageType: MESSAGE_TYPE_FIND_INTERSECT,
@@ -171,11 +172,11 @@ func NewMsgFindIntersect(points []Point) *MsgFindIntersect {
171172

172173
type MsgIntersectFound struct {
173174
protocol.MessageBase
174-
Point Point
175+
Point common.Point
175176
Tip Tip
176177
}
177178

178-
func NewMsgIntersectFound(point Point, tip Tip) *MsgIntersectFound {
179+
func NewMsgIntersectFound(point common.Point, tip Tip) *MsgIntersectFound {
179180
m := &MsgIntersectFound{
180181
MessageBase: protocol.MessageBase{
181182
MessageType: MESSAGE_TYPE_INTERSECT_FOUND,
@@ -217,49 +218,6 @@ func NewMsgDone() *MsgDone {
217218
type Tip struct {
218219
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
219220
_ struct{} `cbor:",toarray"`
220-
Point Point
221+
Point common.Point
221222
BlockNumber uint64
222223
}
223-
224-
type Point struct {
225-
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
226-
_ struct{} `cbor:",toarray"`
227-
Slot uint64
228-
Hash []byte
229-
}
230-
231-
func NewPoint(slot uint64, blockHash []byte) Point {
232-
return Point{
233-
Slot: slot,
234-
Hash: blockHash,
235-
}
236-
}
237-
238-
func NewPointOrigin() Point {
239-
return Point{}
240-
}
241-
242-
// A "point" can sometimes be empty, but the CBOR library gets grumpy about this
243-
// when doing automatic decoding from an array, so we have to handle this case specially
244-
func (p *Point) UnmarshalCBOR(data []byte) error {
245-
var tmp []interface{}
246-
if err := cbor.Unmarshal(data, &tmp); err != nil {
247-
return err
248-
}
249-
if len(tmp) > 0 {
250-
p.Slot = tmp[0].(uint64)
251-
p.Hash = tmp[1].([]byte)
252-
}
253-
return nil
254-
}
255-
256-
func (p *Point) MarshalCBOR() ([]byte, error) {
257-
var data []interface{}
258-
if p.Slot == 0 && p.Hash == nil {
259-
// Return an empty list if values are zero
260-
data = make([]interface{}, 0)
261-
} else {
262-
data = []interface{}{p.Slot, p.Hash}
263-
}
264-
return utils.CborEncode(data)
265-
}

0 commit comments

Comments
 (0)