erigon-pulse/consensus/aura/empty_step.go
Somnath Banerjee 71231140a5
Block Gas limit contract integration for Chiado (#7727)
Changes summary:
- Continue with the gasLimit check skip in ``verifyHeader`` of
``merge.go`` for unless pre-merge block and blockGasLimitContract
present
- Refactor ``aura.go`` a bit
- Have ``sysCall`` method customized to be able to call state (contract)
at a parent (or any other) header state
2023-06-19 22:06:51 +05:30

136 lines
3.6 KiB
Go

package aura
import (
"bytes"
"sort"
"sync"
"github.com/ledgerwatch/secp256k1"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/crypto"
"github.com/ledgerwatch/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})
}