Skip to content

Commit 278648a

Browse files
committed
Block-fetch mini-protocol
* add node-to-node mode to test program * implement NtN chain-sync * implement block-fetch * support multiple messages in same muxer segment * block hash calculation * common functions for decoding blocks and block headers
1 parent eaed010 commit 278648a

File tree

21 files changed

+939
-331
lines changed

21 files changed

+939
-331
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ but the node-to-node protocols will also be implemented in time.
1717
| Name | Status |
1818
| --- | --- |
1919
| Handshake | Implemented |
20-
| Chain-Sync | In Progress |
21-
| Block-Fetch | Not Implemented |
20+
| Chain-Sync | Implemented |
21+
| Block-Fetch | Implemented |
2222
| TxSubmission | Not Implemented |
2323
| Local TxSubmission | Not Implemented |
2424
| Local State Query | Not Implemented |

block/allegra.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66

77
const (
88
BLOCK_TYPE_ALLEGRA = 3
9+
10+
BLOCK_HEADER_TYPE_ALLEGRA = 2
911
)
1012

1113
type AllegraBlock struct {
@@ -20,6 +22,10 @@ type AllegraBlock struct {
2022
TransactionMetadataSet map[uint]cbor.RawMessage
2123
}
2224

25+
func (b *AllegraBlock) Id() string {
26+
return b.Header.Id()
27+
}
28+
2329
type AllegraTransaction struct {
2430
ShelleyTransaction
2531
ValidityIntervalStart uint64 `cbor:"8,keyasint,omitempty"`

block/alonzo.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66

77
const (
88
BLOCK_TYPE_ALONZO = 5
9+
10+
BLOCK_HEADER_TYPE_ALONZO = 4
911
)
1012

1113
type AlonzoBlock struct {
@@ -21,6 +23,10 @@ type AlonzoBlock struct {
2123
InvalidTransactions []uint
2224
}
2325

26+
func (b *AlonzoBlock) Id() string {
27+
return b.Header.Id()
28+
}
29+
2430
type AlonzoTransaction struct {
2531
MaryTransaction
2632
ScriptDataHash Blake2b256 `cbor:"11,keyasint,omitempty"`

block/bryon.go renamed to block/byron.go

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ import (
77
const (
88
BLOCK_TYPE_BYRON_EBB = 0
99
BLOCK_TYPE_BYRON_MAIN = 1
10+
11+
BLOCK_HEADER_TYPE_BYRON = 0
1012
)
1113

1214
type ByronMainBlockHeader struct {
1315
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
1416
_ struct{} `cbor:",toarray"`
17+
id string
1518
ProtocolMagic uint32
1619
PrevBlock Blake2b256
1720
BodyProof interface{}
@@ -54,6 +57,10 @@ type ByronMainBlockHeader struct {
5457
}
5558
}
5659

60+
func (h *ByronMainBlockHeader) Id() string {
61+
return h.id
62+
}
63+
5764
type ByronMainBlockBody struct {
5865
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
5966
_ struct{} `cbor:",toarray"`
@@ -68,11 +75,25 @@ type ByronMainBlockBody struct {
6875
type ByronEpochBoundaryBlockHeader struct {
6976
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
7077
_ struct{} `cbor:",toarray"`
78+
id string
7179
ProtocolMagic uint32
7280
PrevBlock Blake2b256
7381
BodyProof interface{}
74-
ConsensusData interface{}
75-
ExtraData interface{}
82+
ConsensusData struct {
83+
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
84+
_ struct{} `cbor:",toarray"`
85+
Epoch uint64
86+
Difficulty struct {
87+
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
88+
_ struct{} `cbor:",toarray"`
89+
Value uint64
90+
}
91+
}
92+
ExtraData interface{}
93+
}
94+
95+
func (h *ByronEpochBoundaryBlockHeader) Id() string {
96+
return h.id
7697
}
7798

7899
type ByronMainBlock struct {
@@ -83,6 +104,10 @@ type ByronMainBlock struct {
83104
Extra []interface{}
84105
}
85106

107+
func (b *ByronMainBlock) Id() string {
108+
return b.Header.Id()
109+
}
110+
86111
type ByronEpochBoundaryBlock struct {
87112
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
88113
_ struct{} `cbor:",toarray"`
@@ -91,28 +116,6 @@ type ByronEpochBoundaryBlock struct {
91116
Extra []interface{}
92117
}
93118

94-
/*
95-
blake2b-256 = bytes .size 32
96-
97-
txid = blake2b-256
98-
blockid = blake2b-256
99-
updid = blake2b-256
100-
hash = blake2b-256
101-
102-
blake2b-224 = bytes .size 28
103-
104-
addressid = blake2b-224
105-
stakeholderid = blake2b-224
106-
*/
107-
108-
// block = [ blockHeader, blockBody ]
109-
//
110-
// blockHeader = [ headerHash, chainHash, headerSlot, headerBlockNo, headerBodyHash ]
111-
// headerHash = int
112-
// chainHash = genesisHash / blockHash
113-
// genesisHash = [ ]
114-
// blockHash = [ int ]
115-
// blockBody = bstr
116-
// headerSlot = word64
117-
// headerBlockNo = word64
118-
// headerBodyHash = int
119+
func (b *ByronEpochBoundaryBlock) Id() string {
120+
return b.Header.Id()
121+
}

block/common.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package block
22

33
import (
44
"encoding/hex"
5+
"fmt"
6+
"github.com/fxamacker/cbor/v2"
7+
"golang.org/x/crypto/blake2b"
58
)
69

710
type Blake2b256 [32]byte
@@ -15,3 +18,108 @@ type Blake2b224 [28]byte
1518
func (b Blake2b224) String() string {
1619
return hex.EncodeToString([]byte(b[:]))
1720
}
21+
22+
func NewBlockFromCbor(blockType uint, data []byte) (interface{}, error) {
23+
var err error
24+
// Parse outer list to get at header CBOR
25+
var rawBlock []cbor.RawMessage
26+
if err := cbor.Unmarshal(data, &rawBlock); err != nil {
27+
return nil, err
28+
}
29+
switch blockType {
30+
case BLOCK_TYPE_BYRON_EBB:
31+
var byronEbbBlock ByronEpochBoundaryBlock
32+
if err := cbor.Unmarshal(data, &byronEbbBlock); err != nil {
33+
return nil, fmt.Errorf("chain-sync: decode error: %s", err)
34+
}
35+
// Prepend bytes for CBOR list wrapper
36+
// The block hash is calculated with these extra bytes, so we have to add them to
37+
// get the correct value
38+
byronEbbBlock.Header.id, err = generateBlockHeaderHash(rawBlock[0], []byte{0x82, BLOCK_TYPE_BYRON_EBB})
39+
return &byronEbbBlock, err
40+
case BLOCK_TYPE_BYRON_MAIN:
41+
var byronMainBlock ByronMainBlock
42+
if err := cbor.Unmarshal(data, &byronMainBlock); err != nil {
43+
return nil, fmt.Errorf("chain-sync: decode error: %s", err)
44+
}
45+
// Prepend bytes for CBOR list wrapper
46+
// The block hash is calculated with these extra bytes, so we have to add them to
47+
// get the correct value
48+
byronMainBlock.Header.id, err = generateBlockHeaderHash(rawBlock[0], []byte{0x82, BLOCK_TYPE_BYRON_MAIN})
49+
return &byronMainBlock, err
50+
case BLOCK_TYPE_SHELLEY:
51+
var shelleyBlock ShelleyBlock
52+
if err := cbor.Unmarshal(data, &shelleyBlock); err != nil {
53+
return nil, fmt.Errorf("chain-sync: decode error: %s", err)
54+
}
55+
shelleyBlock.Header.id, err = generateBlockHeaderHash(rawBlock[0], nil)
56+
return &shelleyBlock, err
57+
case BLOCK_TYPE_ALLEGRA:
58+
var allegraBlock AllegraBlock
59+
if err := cbor.Unmarshal(data, &allegraBlock); err != nil {
60+
return nil, fmt.Errorf("chain-sync: decode error: %s", err)
61+
}
62+
allegraBlock.Header.id, err = generateBlockHeaderHash(rawBlock[0], nil)
63+
return &allegraBlock, err
64+
case BLOCK_TYPE_MARY:
65+
var maryBlock MaryBlock
66+
if err := cbor.Unmarshal(data, &maryBlock); err != nil {
67+
return nil, fmt.Errorf("chain-sync: decode error: %s", err)
68+
}
69+
maryBlock.Header.id, err = generateBlockHeaderHash(rawBlock[0], nil)
70+
return &maryBlock, err
71+
case BLOCK_TYPE_ALONZO:
72+
var alonzoBlock AlonzoBlock
73+
if err := cbor.Unmarshal(data, &alonzoBlock); err != nil {
74+
return nil, fmt.Errorf("chain-sync: decode error: %s", err)
75+
}
76+
alonzoBlock.Header.id, err = generateBlockHeaderHash(rawBlock[0], nil)
77+
return &alonzoBlock, err
78+
}
79+
return nil, nil
80+
}
81+
82+
func NewBlockHeaderFromCbor(blockType uint, data []byte) (interface{}, error) {
83+
var err error
84+
switch blockType {
85+
case BLOCK_TYPE_BYRON_EBB:
86+
var byronEbbBlockHeader ByronEpochBoundaryBlockHeader
87+
if err := cbor.Unmarshal(data, &byronEbbBlockHeader); err != nil {
88+
return nil, fmt.Errorf("chain-sync: decode error: %s", err)
89+
}
90+
// Prepend bytes for CBOR list wrapper
91+
// The block hash is calculated with these extra bytes, so we have to add them to
92+
// get the correct value
93+
byronEbbBlockHeader.id, err = generateBlockHeaderHash(data, []byte{0x82, BLOCK_TYPE_BYRON_EBB})
94+
return &byronEbbBlockHeader, err
95+
case BLOCK_TYPE_BYRON_MAIN:
96+
var byronMainBlockHeader ByronMainBlockHeader
97+
if err := cbor.Unmarshal(data, &byronMainBlockHeader); err != nil {
98+
return nil, fmt.Errorf("chain-sync: decode error: %s", err)
99+
}
100+
// Prepend bytes for CBOR list wrapper
101+
// The block hash is calculated with these extra bytes, so we have to add them to
102+
// get the correct value
103+
byronMainBlockHeader.id, err = generateBlockHeaderHash(data, []byte{0x82, BLOCK_TYPE_BYRON_MAIN})
104+
return &byronMainBlockHeader, err
105+
default:
106+
var shelleyBlockHeader ShelleyBlockHeader
107+
if err := cbor.Unmarshal(data, &shelleyBlockHeader); err != nil {
108+
return nil, fmt.Errorf("chain-sync: decode error: %s", err)
109+
}
110+
shelleyBlockHeader.id, err = generateBlockHeaderHash(data, nil)
111+
return &shelleyBlockHeader, err
112+
}
113+
}
114+
115+
func generateBlockHeaderHash(data []byte, prefix []byte) (string, error) {
116+
tmpHash, err := blake2b.New256(nil)
117+
if err != nil {
118+
return "", err
119+
}
120+
if prefix != nil {
121+
tmpHash.Write(prefix)
122+
}
123+
tmpHash.Write(data)
124+
return hex.EncodeToString(tmpHash.Sum(nil)), nil
125+
}

block/mary.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package block
22

33
import (
4-
// "fmt"
54
"github.com/fxamacker/cbor/v2"
65
)
76

87
const (
98
BLOCK_TYPE_MARY = 4
9+
10+
BLOCK_HEADER_TYPE_MARY = 3
1011
)
1112

1213
type MaryBlock struct {
@@ -21,6 +22,10 @@ type MaryBlock struct {
2122
TransactionMetadataSet map[uint]cbor.RawMessage
2223
}
2324

25+
func (b *MaryBlock) Id() string {
26+
return b.Header.Id()
27+
}
28+
2429
type MaryTransaction struct {
2530
AllegraTransaction
2631
//Outputs []MaryTransactionOutput `cbor:"1,keyasint,omitempty"`

block/shelley.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66

77
const (
88
BLOCK_TYPE_SHELLEY = 2
9+
10+
BLOCK_HEADER_TYPE_SHELLEY = 1
911
)
1012

1113
type ShelleyBlock struct {
@@ -20,9 +22,14 @@ type ShelleyBlock struct {
2022
TransactionMetadataSet map[uint]cbor.RawMessage
2123
}
2224

25+
func (b *ShelleyBlock) Id() string {
26+
return b.Header.Id()
27+
}
28+
2329
type ShelleyBlockHeader struct {
2430
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
2531
_ struct{} `cbor:",toarray"`
32+
id string
2633
Body struct {
2734
// Tells the CBOR decoder to convert to/from a struct and a CBOR array
2835
_ struct{} `cbor:",toarray"`
@@ -45,6 +52,10 @@ type ShelleyBlockHeader struct {
4552
Signature interface{}
4653
}
4754

55+
func (h *ShelleyBlockHeader) Id() string {
56+
return h.id
57+
}
58+
4859
type ShelleyTransaction struct {
4960
Inputs []ShelleyTransactionInput `cbor:"0,keyasint,omitempty"`
5061
Outputs []ShelleyTransactionOutput `cbor:"1,keyasint,omitempty"`

0 commit comments

Comments
 (0)