Skip to content

Commit 7b4b397

Browse files
committed
feat: support for decoding localstatequery queries
1 parent 70be436 commit 7b4b397

File tree

3 files changed

+299
-3
lines changed

3 files changed

+299
-3
lines changed

protocol/localstatequery/localstatequery.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ type CallbackContext struct {
155155

156156
// Callback function types
157157
type AcquireFunc func(CallbackContext, AcquireTarget, bool) error
158-
type QueryFunc func(CallbackContext, any) (any, error)
158+
type QueryFunc func(CallbackContext, QueryWrapper) (any, error)
159159
type ReleaseFunc func(CallbackContext) error
160160

161161
// New returns a new LocalStateQuery object

protocol/localstatequery/messages.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,15 +154,17 @@ func NewMsgFailure(failure uint8) *MsgFailure {
154154

155155
type MsgQuery struct {
156156
protocol.MessageBase
157-
Query interface{}
157+
Query QueryWrapper
158158
}
159159

160160
func NewMsgQuery(query interface{}) *MsgQuery {
161161
m := &MsgQuery{
162162
MessageBase: protocol.MessageBase{
163163
MessageType: MessageTypeQuery,
164164
},
165-
Query: query,
165+
Query: QueryWrapper{
166+
Query: query,
167+
},
166168
}
167169
return m
168170
}

protocol/localstatequery/queries.go

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,280 @@ const (
6161
QueryTypeShelleyPoolDistr = 21
6262
)
6363

64+
// simpleQueryBase is a helper type used for various query types to reduce repeat code
65+
type simpleQueryBase struct {
66+
cbor.StructAsArray
67+
Type int
68+
}
69+
70+
// QueryWrapper is used for decoding a query from CBOR
71+
type QueryWrapper struct {
72+
cbor.DecodeStoreCbor
73+
Query any
74+
}
75+
76+
func (q *QueryWrapper) UnmarshalCBOR(data []byte) error {
77+
// Store original CBOR
78+
q.SetCbor(data)
79+
// Decode query
80+
tmpQuery, err := decodeQuery(
81+
data,
82+
"",
83+
map[int]any{
84+
QueryTypeBlock: &BlockQuery{},
85+
QueryTypeSystemStart: &SystemStartQuery{},
86+
QueryTypeChainBlockNo: &ChainBlockNoQuery{},
87+
QueryTypeChainPoint: &ChainPointQuery{},
88+
},
89+
)
90+
if err != nil {
91+
return err
92+
}
93+
q.Query = tmpQuery
94+
return nil
95+
}
96+
97+
func (q *QueryWrapper) MarshalCBOR() ([]byte, error) {
98+
return cbor.Encode(q.Query)
99+
}
100+
101+
type BlockQuery struct {
102+
Query any
103+
}
104+
105+
func (q *BlockQuery) UnmarshalCBOR(data []byte) error {
106+
// Unwrap
107+
tmpData := struct {
108+
cbor.StructAsArray
109+
Type int
110+
SubQuery cbor.RawMessage
111+
}{}
112+
if _, err := cbor.Decode(data, &tmpData); err != nil {
113+
return err
114+
}
115+
// Decode query
116+
tmpQuery, err := decodeQuery(
117+
tmpData.SubQuery,
118+
"Block",
119+
map[int]any{
120+
QueryTypeShelley: &ShelleyQuery{},
121+
QueryTypeHardFork: &HardForkQuery{},
122+
},
123+
)
124+
if err != nil {
125+
return err
126+
}
127+
q.Query = tmpQuery
128+
return nil
129+
}
130+
131+
type ShelleyQuery struct {
132+
Era uint
133+
Query any
134+
}
135+
136+
func (q *ShelleyQuery) UnmarshalCBOR(data []byte) error {
137+
// Unwrap
138+
tmpData := struct {
139+
cbor.StructAsArray
140+
Type int
141+
Inner struct {
142+
cbor.StructAsArray
143+
Era uint
144+
SubQuery cbor.RawMessage
145+
}
146+
}{}
147+
if _, err := cbor.Decode(data, &tmpData); err != nil {
148+
return err
149+
}
150+
// Decode query
151+
tmpQuery, err := decodeQuery(
152+
tmpData.Inner.SubQuery,
153+
"Block",
154+
map[int]any{
155+
QueryTypeShelleyLedgerTip: &ShelleyLedgerTipQuery{},
156+
QueryTypeShelleyEpochNo: &ShelleyEpochNoQuery{},
157+
QueryTypeShelleyNonMyopicMemberRewards: &ShelleyNonMyopicMemberRewardsQuery{},
158+
QueryTypeShelleyCurrentProtocolParams: &ShelleyCurrentProtocolParamsQuery{},
159+
QueryTypeShelleyProposedProtocolParamsUpdates: &ShelleyProposedProtocolParamsUpdatesQuery{},
160+
QueryTypeShelleyStakeDistribution: &ShelleyStakeDistributionQuery{},
161+
QueryTypeShelleyUtxoByAddress: &ShelleyUtxoByAddressQuery{},
162+
QueryTypeShelleyUtxoWhole: &ShelleyUtxoWholeQuery{},
163+
QueryTypeShelleyDebugEpochState: &ShelleyDebugEpochStateQuery{},
164+
QueryTypeShelleyCbor: &ShelleyCborQuery{},
165+
QueryTypeShelleyFilteredDelegationAndRewardAccounts: &ShelleyFilteredDelegationAndRewardAccountsQuery{},
166+
QueryTypeShelleyGenesisConfig: &ShelleyGenesisConfigQuery{},
167+
QueryTypeShelleyDebugNewEpochState: &ShelleyDebugNewEpochStateQuery{},
168+
QueryTypeShelleyDebugChainDepState: &ShelleyDebugChainDepStateQuery{},
169+
QueryTypeShelleyRewardProvenance: &ShelleyRewardProvenanceQuery{},
170+
QueryTypeShelleyUtxoByTxin: &ShelleyUtxoByTxinQuery{},
171+
QueryTypeShelleyStakePools: &ShelleyStakePoolsQuery{},
172+
QueryTypeShelleyStakePoolParams: &ShelleyStakePoolParamsQuery{},
173+
QueryTypeShelleyRewardInfoPools: &ShelleyRewardInfoPoolsQuery{},
174+
QueryTypeShelleyPoolState: &ShelleyPoolStateQuery{},
175+
QueryTypeShelleyStakeSnapshots: &ShelleyStakeSnapshotsQuery{},
176+
QueryTypeShelleyPoolDistr: &ShelleyPoolDistrQuery{},
177+
},
178+
)
179+
if err != nil {
180+
return err
181+
}
182+
q.Era = tmpData.Inner.Era
183+
q.Query = tmpQuery
184+
return nil
185+
}
186+
187+
type HardForkQuery struct {
188+
Query any
189+
}
190+
191+
func (q *HardForkQuery) UnmarshalCBOR(data []byte) error {
192+
// Unwrap
193+
tmpData := struct {
194+
cbor.StructAsArray
195+
Type int
196+
SubQuery cbor.RawMessage
197+
}{}
198+
if _, err := cbor.Decode(data, &tmpData); err != nil {
199+
return err
200+
}
201+
// Decode query
202+
tmpQuery, err := decodeQuery(
203+
tmpData.SubQuery,
204+
"Hard-fork",
205+
map[int]any{
206+
QueryTypeHardForkEraHistory: &HardForkEraHistoryQuery{},
207+
QueryTypeHardForkCurrentEra: &HardForkCurrentEraQuery{},
208+
},
209+
)
210+
if err != nil {
211+
return err
212+
}
213+
q.Query = tmpQuery
214+
return nil
215+
}
216+
217+
type ShelleyLedgerTipQuery struct {
218+
simpleQueryBase
219+
}
220+
221+
type ShelleyEpochNoQuery struct {
222+
simpleQueryBase
223+
}
224+
225+
type ShelleyNonMyopicMemberRewardsQuery struct {
226+
simpleQueryBase
227+
}
228+
229+
type ShelleyCurrentProtocolParamsQuery struct {
230+
simpleQueryBase
231+
}
232+
233+
type ShelleyProposedProtocolParamsUpdatesQuery struct {
234+
simpleQueryBase
235+
}
236+
237+
type ShelleyStakeDistributionQuery struct {
238+
simpleQueryBase
239+
}
240+
241+
type ShelleyUtxoByAddressQuery struct {
242+
cbor.StructAsArray
243+
Type int
244+
Addrs []ledger.Address
245+
}
246+
247+
type ShelleyUtxoWholeQuery struct {
248+
simpleQueryBase
249+
}
250+
251+
type ShelleyDebugEpochStateQuery struct {
252+
simpleQueryBase
253+
}
254+
255+
type ShelleyCborQuery struct {
256+
simpleQueryBase
257+
}
258+
259+
type ShelleyFilteredDelegationAndRewardAccountsQuery struct {
260+
simpleQueryBase
261+
// TODO: add params
262+
}
263+
264+
type ShelleyGenesisConfigQuery struct {
265+
simpleQueryBase
266+
}
267+
268+
type ShelleyDebugNewEpochStateQuery struct {
269+
simpleQueryBase
270+
}
271+
272+
type ShelleyDebugChainDepStateQuery struct {
273+
simpleQueryBase
274+
}
275+
276+
type ShelleyRewardProvenanceQuery struct {
277+
simpleQueryBase
278+
}
279+
280+
type ShelleyUtxoByTxinQuery struct {
281+
cbor.StructAsArray
282+
Type int
283+
TxIns []ledger.TransactionInput
284+
}
285+
286+
type ShelleyStakePoolsQuery struct {
287+
simpleQueryBase
288+
}
289+
290+
type ShelleyStakePoolParamsQuery struct {
291+
simpleQueryBase
292+
// TODO: add params
293+
}
294+
295+
type ShelleyRewardInfoPoolsQuery struct {
296+
simpleQueryBase
297+
}
298+
299+
type ShelleyPoolStateQuery struct {
300+
simpleQueryBase
301+
}
302+
303+
type ShelleyStakeSnapshotsQuery struct {
304+
simpleQueryBase
305+
}
306+
307+
type ShelleyPoolDistrQuery struct {
308+
simpleQueryBase
309+
}
310+
311+
func decodeQuery(data []byte, typeDesc string, queryTypes map[int]any) (any, error) {
312+
// Determine query type
313+
queryType, err := cbor.DecodeIdFromList(data)
314+
if err != nil {
315+
return nil, err
316+
}
317+
var tmpQuery any
318+
for typeId, queryObj := range queryTypes {
319+
if queryType == typeId {
320+
tmpQuery = queryObj
321+
break
322+
}
323+
}
324+
if tmpQuery == nil {
325+
errMsg := "unknown query type"
326+
if typeDesc != "" {
327+
errMsg = fmt.Sprintf("unknown %s query type", typeDesc)
328+
}
329+
return nil, fmt.Errorf("%s: %d", errMsg, queryType)
330+
}
331+
// Decode query
332+
if _, err := cbor.Decode(data, tmpQuery); err != nil {
333+
return nil, err
334+
}
335+
return tmpQuery, nil
336+
}
337+
64338
func buildQuery(queryType int, params ...interface{}) []interface{} {
65339
ret := []interface{}{queryType}
66340
if len(params) > 0 {
@@ -104,6 +378,10 @@ func buildShelleyQuery(
104378
return ret
105379
}
106380

381+
type SystemStartQuery struct {
382+
simpleQueryBase
383+
}
384+
107385
type SystemStartResult struct {
108386
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
109387
_ struct{} `cbor:",toarray"`
@@ -112,6 +390,22 @@ type SystemStartResult struct {
112390
Picoseconds uint64
113391
}
114392

393+
type ChainBlockNoQuery struct {
394+
simpleQueryBase
395+
}
396+
397+
type ChainPointQuery struct {
398+
simpleQueryBase
399+
}
400+
401+
type HardForkCurrentEraQuery struct {
402+
simpleQueryBase
403+
}
404+
405+
type HardForkEraHistoryQuery struct {
406+
simpleQueryBase
407+
}
408+
115409
type EraHistoryResult struct {
116410
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
117411
_ struct{} `cbor:",toarray"`

0 commit comments

Comments
 (0)