Skip to content

Commit 8e5061b

Browse files
authored
Merge pull request #413 from blinklabs-io/feat/ledger-conway-era
feat: conway era support
2 parents a35f995 + 6a17250 commit 8e5061b

File tree

5 files changed

+219
-1
lines changed

5 files changed

+219
-1
lines changed

ledger/block.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ func NewBlockFromCbor(blockType uint, data []byte) (Block, error) {
5252
return NewAlonzoBlockFromCbor(data)
5353
case BlockTypeBabbage:
5454
return NewBabbageBlockFromCbor(data)
55+
case BlockTypeConway:
56+
return NewConwayBlockFromCbor(data)
5557
}
5658
return nil, fmt.Errorf("unknown node-to-client block type: %d", blockType)
5759
}
@@ -66,7 +68,7 @@ func NewBlockHeaderFromCbor(blockType uint, data []byte) (BlockHeader, error) {
6668
// TODO: break into separate cases and parse as specific block header types
6769
case BlockTypeShelley, BlockTypeAllegra, BlockTypeMary, BlockTypeAlonzo:
6870
return NewShelleyBlockHeaderFromCbor(data)
69-
case BlockTypeBabbage:
71+
case BlockTypeBabbage, BlockTypeConway:
7072
return NewBabbageBlockHeaderFromCbor(data)
7173
}
7274
return nil, fmt.Errorf("unknown node-to-node block type: %d", blockType)

ledger/conway.go

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
// Copyright 2023 Blink Labs, LLC.
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 ledger
16+
17+
import (
18+
"fmt"
19+
20+
"github.com/blinklabs-io/gouroboros/cbor"
21+
)
22+
23+
const (
24+
EraIdConway = 6
25+
26+
BlockTypeConway = 7
27+
28+
BlockHeaderTypeConway = 6
29+
30+
TxTypeConway = 6
31+
)
32+
33+
type ConwayBlock struct {
34+
cbor.StructAsArray
35+
cbor.DecodeStoreCbor
36+
Header *ConwayBlockHeader
37+
TransactionBodies []ConwayTransactionBody
38+
TransactionWitnessSets []BabbageTransactionWitnessSet
39+
TransactionMetadataSet map[uint]*cbor.Value
40+
InvalidTransactions []uint
41+
}
42+
43+
func (b *ConwayBlock) UnmarshalCBOR(cborData []byte) error {
44+
return b.UnmarshalCbor(cborData, b)
45+
}
46+
47+
func (b *ConwayBlock) Hash() string {
48+
return b.Header.Hash()
49+
}
50+
51+
func (b *ConwayBlock) BlockNumber() uint64 {
52+
return b.Header.BlockNumber()
53+
}
54+
55+
func (b *ConwayBlock) SlotNumber() uint64 {
56+
return b.Header.SlotNumber()
57+
}
58+
59+
func (b *ConwayBlock) IssuerVkey() IssuerVkey {
60+
return b.Header.IssuerVkey()
61+
}
62+
63+
func (b *ConwayBlock) BlockBodySize() uint64 {
64+
return b.Header.BlockBodySize()
65+
}
66+
67+
func (b *ConwayBlock) Era() Era {
68+
return eras[EraIdConway]
69+
}
70+
71+
func (b *ConwayBlock) Transactions() []Transaction {
72+
ret := []Transaction{}
73+
for idx := range b.TransactionBodies {
74+
tmpTransaction := ConwayTransaction{
75+
Body: b.TransactionBodies[idx],
76+
WitnessSet: b.TransactionWitnessSets[idx],
77+
TxMetadata: b.TransactionMetadataSet[uint(idx)],
78+
}
79+
isValid := true
80+
for _, invalidTxIdx := range b.InvalidTransactions {
81+
if invalidTxIdx == uint(idx) {
82+
isValid = false
83+
break
84+
}
85+
}
86+
tmpTransaction.IsValid = isValid
87+
ret = append(ret, &tmpTransaction)
88+
}
89+
return ret
90+
}
91+
92+
type ConwayBlockHeader struct {
93+
BabbageBlockHeader
94+
}
95+
96+
func (h *ConwayBlockHeader) Era() Era {
97+
return eras[EraIdConway]
98+
}
99+
100+
type ConwayTransactionBody struct {
101+
BabbageTransactionBody
102+
VotingProcedures *cbor.Value `cbor:"19,keyasint,omitempty"`
103+
ProposalProcedures *cbor.Value `cbor:"20,keyasint,omitempty"`
104+
CurrentTreasuryValue int64 `cbor:"21,keyasint,omitempty"`
105+
Donation uint64 `cbor:"22,keyasint,omitempty"`
106+
}
107+
108+
func (b *ConwayTransactionBody) UnmarshalCBOR(cborData []byte) error {
109+
return b.UnmarshalCbor(cborData, b)
110+
}
111+
112+
type ConwayTransaction struct {
113+
cbor.StructAsArray
114+
cbor.DecodeStoreCbor
115+
Body ConwayTransactionBody
116+
WitnessSet BabbageTransactionWitnessSet
117+
IsValid bool
118+
TxMetadata *cbor.Value
119+
}
120+
121+
func (t ConwayTransaction) Hash() string {
122+
return t.Body.Hash()
123+
}
124+
125+
func (t ConwayTransaction) Inputs() []TransactionInput {
126+
return t.Body.Inputs()
127+
}
128+
129+
func (t ConwayTransaction) Outputs() []TransactionOutput {
130+
return t.Body.Outputs()
131+
}
132+
133+
func (t ConwayTransaction) Fee() uint64 {
134+
return t.Body.Fee()
135+
}
136+
137+
func (t ConwayTransaction) TTL() uint64 {
138+
return t.Body.TTL()
139+
}
140+
141+
func (t ConwayTransaction) Metadata() *cbor.Value {
142+
return t.TxMetadata
143+
}
144+
145+
func (t *ConwayTransaction) Cbor() []byte {
146+
// Return stored CBOR if we have any
147+
cborData := t.DecodeStoreCbor.Cbor()
148+
if cborData != nil {
149+
return cborData[:]
150+
}
151+
// Return immediately if the body CBOR is also empty, which implies an empty TX object
152+
if t.Body.Cbor() == nil {
153+
return nil
154+
}
155+
// Generate our own CBOR
156+
// This is necessary when a transaction is put together from pieces stored separately in a block
157+
tmpObj := []any{
158+
cbor.RawMessage(t.Body.Cbor()),
159+
cbor.RawMessage(t.WitnessSet.Cbor()),
160+
t.IsValid,
161+
}
162+
if t.TxMetadata != nil {
163+
tmpObj = append(tmpObj, cbor.RawMessage(t.TxMetadata.Cbor()))
164+
} else {
165+
tmpObj = append(tmpObj, nil)
166+
}
167+
// This should never fail, since we're only encoding a list and a bool value
168+
cborData, _ = cbor.Encode(&tmpObj)
169+
return cborData
170+
}
171+
172+
func NewConwayBlockFromCbor(data []byte) (*ConwayBlock, error) {
173+
var conwayBlock ConwayBlock
174+
if _, err := cbor.Decode(data, &conwayBlock); err != nil {
175+
return nil, fmt.Errorf("Conway block decode error: %s", err)
176+
}
177+
return &conwayBlock, nil
178+
}
179+
180+
func NewConwayBlockHeaderFromCbor(data []byte) (*ConwayBlockHeader, error) {
181+
var conwayBlockHeader ConwayBlockHeader
182+
if _, err := cbor.Decode(data, &conwayBlockHeader); err != nil {
183+
return nil, fmt.Errorf("Conway block header decode error: %s", err)
184+
}
185+
return &conwayBlockHeader, nil
186+
}
187+
188+
func NewConwayTransactionBodyFromCbor(
189+
data []byte,
190+
) (*ConwayTransactionBody, error) {
191+
var conwayTx ConwayTransactionBody
192+
if _, err := cbor.Decode(data, &conwayTx); err != nil {
193+
return nil, fmt.Errorf("Conway transaction body decode error: %s", err)
194+
}
195+
return &conwayTx, nil
196+
}
197+
198+
func NewConwayTransactionFromCbor(data []byte) (*ConwayTransaction, error) {
199+
var conwayTx ConwayTransaction
200+
if _, err := cbor.Decode(data, &conwayTx); err != nil {
201+
return nil, fmt.Errorf("Conway transaction decode error: %s", err)
202+
}
203+
return &conwayTx, nil
204+
}

ledger/era.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ var eras = map[uint8]Era{
4444
Id: EraIdBabbage,
4545
Name: "Babbage",
4646
},
47+
EraIdConway: Era{
48+
Id: EraIdConway,
49+
Name: "Conway",
50+
},
4751
}
4852

4953
func GetEraById(eraId uint8) *Era {

ledger/tx.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ func NewTransactionFromCbor(txType uint, data []byte) (Transaction, error) {
6464
return NewAlonzoTransactionFromCbor(data)
6565
case TxTypeBabbage:
6666
return NewBabbageTransactionFromCbor(data)
67+
case TxTypeConway:
68+
return NewConwayTransactionFromCbor(data)
6769
}
6870
return nil, fmt.Errorf("unknown transaction type: %d", txType)
6971
}
@@ -85,6 +87,8 @@ func NewTransactionBodyFromCbor(
8587
return NewAlonzoTransactionBodyFromCbor(data)
8688
case TxTypeBabbage:
8789
return NewBabbageTransactionBodyFromCbor(data)
90+
case TxTypeConway:
91+
return NewConwayTransactionBodyFromCbor(data)
8892
}
8993
return nil, fmt.Errorf("unknown transaction type: %d", txType)
9094
}
@@ -112,6 +116,9 @@ func DetermineTransactionType(data []byte) (uint, error) {
112116
if _, err := NewBabbageTransactionFromCbor(data); err == nil {
113117
return TxTypeBabbage, nil
114118
}
119+
if _, err := NewConwayTransactionFromCbor(data); err == nil {
120+
return TxTypeConway, nil
121+
}
115122
return 0, fmt.Errorf("unknown transaction type")
116123
}
117124

protocol/chainsync/client.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ func (c *Client) handleRollForward(msgGeneric protocol.Message) error {
282282
ledger.BlockHeaderTypeMary: ledger.BlockTypeMary,
283283
ledger.BlockHeaderTypeAlonzo: ledger.BlockTypeAlonzo,
284284
ledger.BlockHeaderTypeBabbage: ledger.BlockTypeBabbage,
285+
ledger.BlockHeaderTypeConway: ledger.BlockTypeConway,
285286
}
286287
blockType = blockTypeMap[blockEra]
287288
var err error

0 commit comments

Comments
 (0)