-
Notifications
You must be signed in to change notification settings - Fork 2
/
crosslink.go
154 lines (136 loc) · 4.13 KB
/
crosslink.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package types
import (
"encoding/hex"
"encoding/json"
"math/big"
"sort"
"github.com/PositionExchange/posichain/block"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
)
// CrossLink is only used on beacon chain to store the hash links from other shards
// signature and bitmap correspond to |blockNumber|parentHash| byte array
// Capital to enable rlp encoding
// Here we replace header to signatures only, the basic assumption is the committee will not be
// corrupted during one epoch, which is the same as consensus assumption
type CrossLink struct {
HashF common.Hash
BlockNumberF *big.Int
ViewIDF *big.Int
SignatureF [96]byte //aggregated signature
BitmapF []byte //corresponding bitmap mask for agg signature
ShardIDF uint32 //will be verified with signature on |blockNumber|blockHash| is correct
EpochF *big.Int
}
// NewCrossLink returns a new cross link object
func NewCrossLink(header *block.Header, parentHeader *block.Header) *CrossLink {
parentBlockNum := big.NewInt(0)
parentViewID := big.NewInt(0)
parentEpoch := big.NewInt(0)
if parentHeader != nil { // Should always happen, default values to be defensive.
parentBlockNum = parentHeader.Number()
parentViewID = parentHeader.ViewID()
parentEpoch = parentHeader.Epoch()
}
return &CrossLink{
HashF: header.ParentHash(),
BlockNumberF: parentBlockNum,
ViewIDF: parentViewID,
SignatureF: header.LastCommitSignature(),
BitmapF: header.LastCommitBitmap(),
ShardIDF: header.ShardID(),
EpochF: parentEpoch,
}
}
// ShardID returns shardID
func (cl *CrossLink) ShardID() uint32 {
return cl.ShardIDF
}
// Number returns blockNum with big.Int format
func (cl *CrossLink) Number() *big.Int {
return cl.BlockNumberF
}
// ViewID returns viewID with big.Int format
func (cl *CrossLink) ViewID() *big.Int {
return cl.ViewIDF
}
// Epoch returns epoch with big.Int format
func (cl *CrossLink) Epoch() *big.Int {
return cl.EpochF
}
// BlockNum returns blockNum
func (cl *CrossLink) BlockNum() uint64 {
return cl.BlockNumberF.Uint64()
}
// Hash returns hash
func (cl *CrossLink) Hash() common.Hash {
return cl.HashF
}
// Bitmap returns bitmap
func (cl *CrossLink) Bitmap() []byte {
return cl.BitmapF
}
// Signature returns aggregated signature
func (cl *CrossLink) Signature() [96]byte {
return cl.SignatureF
}
// MarshalJSON ..
func (cl *CrossLink) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Hash common.Hash `json:"hash"`
BlockNumber *big.Int `json:"block-number"`
ViewID *big.Int `json:"view-id"`
Signature string `json:"signature"`
Bitmap string `json:"signature-bitmap"`
ShardID uint32 `json:"shard-id"`
EpochNumber *big.Int `json:"epoch-number"`
}{
cl.HashF,
cl.BlockNumberF,
cl.ViewIDF,
hex.EncodeToString(cl.SignatureF[:]),
hex.EncodeToString(cl.BitmapF),
cl.ShardIDF,
cl.EpochF,
})
}
// Serialize returns bytes of cross link rlp-encoded content
func (cl *CrossLink) Serialize() []byte {
bytes, _ := rlp.EncodeToBytes(cl)
return bytes
}
// DeserializeCrossLink rlp-decode the bytes into cross link object.
func DeserializeCrossLink(bytes []byte) (*CrossLink, error) {
cl := &CrossLink{}
err := rlp.DecodeBytes(bytes, cl)
if err != nil {
return nil, err
}
return cl, err
}
// CrossLinks is a collection of cross links
type CrossLinks []CrossLink
// Sort crosslinks by shardID and then tie break by blockNum then by viewID
func (cls CrossLinks) Sort() {
sort.Slice(cls, func(i, j int) bool {
if s1, s2 := cls[i].ShardID(), cls[j].ShardID(); s1 != s2 {
return s1 < s2
}
if s1, s2 := cls[i].Number(), cls[j].Number(); s1.Cmp(s2) != 0 {
return s1.Cmp(s2) < 0
}
return cls[i].ViewID().Cmp(cls[j].ViewID()) < 0
})
}
// IsSorted checks whether the cross links are sorted
func (cls CrossLinks) IsSorted() bool {
return sort.SliceIsSorted(cls, func(i, j int) bool {
if s1, s2 := cls[i].ShardID(), cls[j].ShardID(); s1 != s2 {
return s1 < s2
}
if s1, s2 := cls[i].Number(), cls[j].Number(); s1.Cmp(s2) != 0 {
return s1.Cmp(s2) < 0
}
return cls[i].ViewID().Cmp(cls[j].ViewID()) < 0
})
}