forked from erigontech/erigon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
empty_step.go
135 lines (118 loc) · 3.63 KB
/
empty_step.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
package aura
import (
"bytes"
"sort"
"sync"
"github.com/NebojsaHorvat/secp256k1"
libcommon "github.com/nebojsa94/erigon/erigon-lib/common"
"github.com/nebojsa94/erigon/crypto"
"github.com/nebojsa94/erigon/rlp"
)
// A message broadcast by authorities when it's their turn to seal a block but there are no
// transactions. Other authorities accumulate these messages and later include them in the seal as
// proof.
//
// An empty step message is created _instead of_ a block if there are no pending transactions.
// It cannot itself be a parent, and `parent_hash` always points to the most recent block. E.g.:
// - Validator A creates block `bA`.
// - Validator B has no pending transactions, so it signs an empty step message `mB`
// instead whose hash points to block `bA`.
// - Validator C also has no pending transactions, so it also signs an empty step message `mC`
// instead whose hash points to block `bA`.
// - Validator D creates block `bD`. The parent is block `bA`, and the header includes `mB` and `mC`.
type EmptyStep struct {
// The signature of the other two fields, by the message's author.
signature []byte // H520
// This message's step number.
step uint64
// The hash of the most recent block.
parentHash libcommon.Hash // H256
}
func (s *EmptyStep) Less(other *EmptyStep) bool {
if s.step < other.step {
return true
}
if bytes.Compare(s.parentHash[:], other.parentHash[:]) < 0 {
return true
}
if bytes.Compare(s.signature, other.signature) < 0 {
return true
}
return false
}
func (s *EmptyStep) LessOrEqual(other *EmptyStep) bool {
if s.step <= other.step {
return true
}
if bytes.Compare(s.parentHash[:], other.parentHash[:]) <= 0 {
return true
}
if bytes.Compare(s.signature, other.signature) <= 0 {
return true
}
return false
}
// Returns `true` if the message has a valid signature by the expected proposer in the message's step.
func (s *EmptyStep) verify(validators ValidatorSet) (bool, error) { //nolint
//sRlp, err := EmptyStepRlp(s.step, s.parentHash)
//if err != nil {
// return false, err
//}
//message := crypto.Keccak256(sRlp)
/*
let correct_proposer = step_proposer(validators, &self.parent_hash, self.step);
publickey::verify_address(&correct_proposer, &self.signature.into(), &message)
.map_err(|e| e.into())
*/
return true, nil
}
// nolint
func (s *EmptyStep) author() (libcommon.Address, error) {
sRlp, err := EmptyStepRlp(s.step, s.parentHash)
if err != nil {
return libcommon.Address{}, err
}
message := crypto.Keccak256(sRlp)
public, err := secp256k1.RecoverPubkey(message, s.signature)
if err != nil {
return libcommon.Address{}, err
}
ecdsa, err := crypto.UnmarshalPubkeyStd(public)
if err != nil {
return libcommon.Address{}, err
}
return crypto.PubkeyToAddress(*ecdsa), nil
}
type EmptyStepSet struct {
lock sync.Mutex
list []*EmptyStep
}
func (s *EmptyStepSet) Less(i, j int) bool { return s.list[i].Less(s.list[j]) }
func (s *EmptyStepSet) Swap(i, j int) { s.list[i], s.list[j] = s.list[j], s.list[i] }
func (s *EmptyStepSet) Len() int { return len(s.list) }
func (s *EmptyStepSet) Sort() {
s.lock.Lock()
defer s.lock.Unlock()
sort.Stable(s)
}
func (s *EmptyStepSet) ForEach(f func(int, *EmptyStep)) {
s.lock.Lock()
defer s.lock.Unlock()
for i, el := range s.list {
f(i, el)
}
}
func EmptyStepFullRlp(signature []byte, emptyStepRlp []byte) ([]byte, error) {
type A struct {
s []byte
r []byte
}
return rlp.EncodeToBytes(A{s: signature, r: emptyStepRlp})
}
func EmptyStepRlp(step uint64, parentHash libcommon.Hash) ([]byte, error) {
type A struct {
s uint64
h libcommon.Hash
}
return rlp.EncodeToBytes(A{s: step, h: parentHash})
}