-
Notifications
You must be signed in to change notification settings - Fork 670
/
block.go
109 lines (88 loc) · 2.99 KB
/
block.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
// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package block
import (
"crypto/x509"
"errors"
"time"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/hashing"
"github.com/ava-labs/avalanchego/utils/wrappers"
)
var (
errUnexpectedProposer = errors.New("expected no proposer but one was provided")
errMissingProposer = errors.New("expected proposer but one was provided")
)
type Block interface {
ID() ids.ID
ParentID() ids.ID
Block() []byte
Bytes() []byte
initialize(bytes []byte) error
}
type SignedBlock interface {
Block
PChainHeight() uint64
Timestamp() time.Time
Proposer() ids.ShortID
Verify(shouldHaveProposer bool, chainID ids.ID) error
}
type statelessUnsignedBlock struct {
ParentID ids.ID `serialize:"true"`
Timestamp int64 `serialize:"true"`
PChainHeight uint64 `serialize:"true"`
Certificate []byte `serialize:"true"`
Block []byte `serialize:"true"`
}
type statelessBlock struct {
StatelessBlock statelessUnsignedBlock `serialize:"true"`
Signature []byte `serialize:"true"`
id ids.ID
timestamp time.Time
cert *x509.Certificate
proposer ids.ShortID
bytes []byte
}
func (b *statelessBlock) ID() ids.ID { return b.id }
func (b *statelessBlock) ParentID() ids.ID { return b.StatelessBlock.ParentID }
func (b *statelessBlock) Block() []byte { return b.StatelessBlock.Block }
func (b *statelessBlock) Bytes() []byte { return b.bytes }
func (b *statelessBlock) initialize(bytes []byte) error {
b.bytes = bytes
// The serialized form of the block is the unsignedBytes followed by the
// signature, which is prefixed by a uint32. So, we need to strip off the
// signature as well as it's length prefix to get the unsigned bytes.
lenUnsignedBytes := len(bytes) - wrappers.IntLen - len(b.Signature)
unsignedBytes := bytes[:lenUnsignedBytes]
b.id = hashing.ComputeHash256Array(unsignedBytes)
b.timestamp = time.Unix(b.StatelessBlock.Timestamp, 0)
if len(b.StatelessBlock.Certificate) == 0 {
return nil
}
cert, err := x509.ParseCertificate(b.StatelessBlock.Certificate)
if err != nil {
return err
}
b.cert = cert
b.proposer = hashing.ComputeHash160Array(hashing.ComputeHash256(cert.Raw))
return nil
}
func (b *statelessBlock) PChainHeight() uint64 { return b.StatelessBlock.PChainHeight }
func (b *statelessBlock) Timestamp() time.Time { return b.timestamp }
func (b *statelessBlock) Proposer() ids.ShortID { return b.proposer }
func (b *statelessBlock) Verify(shouldHaveProposer bool, chainID ids.ID) error {
if !shouldHaveProposer {
if len(b.Signature) > 0 || len(b.StatelessBlock.Certificate) > 0 {
return errUnexpectedProposer
}
return nil
} else if b.cert == nil {
return errMissingProposer
}
header, err := BuildHeader(chainID, b.StatelessBlock.ParentID, b.id)
if err != nil {
return err
}
headerBytes := header.Bytes()
return b.cert.CheckSignature(b.cert.SignatureAlgorithm, headerBytes, b.Signature)
}