mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
9 Commits
inStateUpg
...
prysmctl-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90266bf2d9 | ||
|
|
e8c25effb0 | ||
|
|
cc454bb42c | ||
|
|
9529c73ff1 | ||
|
|
eca129d8ff | ||
|
|
ed9189db07 | ||
|
|
53a4939da4 | ||
|
|
efc1e06c6b | ||
|
|
dc038f3ee2 |
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/attestation"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -196,6 +197,22 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Could not update head")
|
||||
}
|
||||
if blockRoot != headRoot {
|
||||
receivedWeight, err := s.ForkChoicer().Weight(blockRoot)
|
||||
if err != nil {
|
||||
log.WithField("root", fmt.Sprintf("%#x", blockRoot)).Warn("could not determine node weight")
|
||||
}
|
||||
headWeight, err := s.ForkChoicer().Weight(headRoot)
|
||||
if err != nil {
|
||||
log.WithField("root", fmt.Sprintf("%#x", headRoot)).Warn("could not determine node weight")
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"receivedRoot": fmt.Sprintf("%#x", blockRoot),
|
||||
"receivedWeight": receivedWeight,
|
||||
"headRoot": fmt.Sprintf("%#x", headRoot),
|
||||
"headWeight": headWeight,
|
||||
}).Debug("Head block is not the received block")
|
||||
}
|
||||
newBlockHeadElapsedTime.Observe(float64(time.Since(start).Milliseconds()))
|
||||
|
||||
if err := s.notifyEngineIfChangedHead(ctx, headRoot); err != nil {
|
||||
|
||||
15
beacon-chain/cache/depositsnapshot/BUILD.bazel
vendored
15
beacon-chain/cache/depositsnapshot/BUILD.bazel
vendored
@@ -2,7 +2,20 @@ load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["merkle_tree.go"],
|
||||
srcs = [
|
||||
"deposit_tree.go",
|
||||
"deposit_tree_snapshot.go",
|
||||
"merkle_tree.go",
|
||||
"zerohashes.gen.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/cache/depositsnapshot",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//container/slice:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
157
beacon-chain/cache/depositsnapshot/deposit_tree.go
vendored
Normal file
157
beacon-chain/cache/depositsnapshot/deposit_tree.go
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
// Package depositsnapshot implements the EIP-4881 standard for minimal sparse Merkle tree.
|
||||
// The format proposed by the EIP allows for the pruning of deposits that are no longer needed to participate fully in consensus.
|
||||
// Full EIP-4881 specification can be found here: https://eips.ethereum.org/EIPS/eip-4881
|
||||
package depositsnapshot
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/math"
|
||||
eth "github.com/prysmaticlabs/prysm/v3/proto/eth/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrEmptyExecutionBlock occurs when the execution block is nil.
|
||||
ErrEmptyExecutionBlock = errors.New("empty execution block")
|
||||
// ErrInvalidSnapshotRoot occurs when the snapshot root does not match the calculated root.
|
||||
ErrInvalidSnapshotRoot = errors.New("snapshot root is invalid")
|
||||
// ErrInvalidMixInLength occurs when the value for mix in length is 0.
|
||||
ErrInvalidMixInLength = errors.New("mixInLength should be greater than 0")
|
||||
// ErrInvalidIndex occurs when the index is less than the number of finalized deposits.
|
||||
ErrInvalidIndex = errors.New("index should be greater than finalizedDeposits - 1")
|
||||
// ErrNoDeposits occurs when the number of deposits is 0.
|
||||
ErrNoDeposits = errors.New("number of deposits should be greater than 0")
|
||||
// ErrNoFinalizedDeposits occurs when the number of finalized deposits is 0.
|
||||
ErrNoFinalizedDeposits = errors.New("number of finalized deposits should be greater than 0")
|
||||
// ErrTooManyDeposits occurs when the number of deposits exceeds the capacity of the tree.
|
||||
ErrTooManyDeposits = errors.New("number of deposits should not be greater than the capacity of the tree")
|
||||
)
|
||||
|
||||
// DepositTree is the Merkle tree representation of deposits.
|
||||
type DepositTree struct {
|
||||
tree MerkleTreeNode
|
||||
mixInLength uint64 // number of deposits in the tree, reference implementation calls this mix_in_length.
|
||||
finalizedExecutionBlock executionBlock
|
||||
}
|
||||
|
||||
type executionBlock struct {
|
||||
Hash [32]byte
|
||||
Depth uint64
|
||||
}
|
||||
|
||||
// New creates an empty deposit tree.
|
||||
//
|
||||
//nolint:unused
|
||||
func New() *DepositTree {
|
||||
var leaves [][32]byte
|
||||
merkle := create(leaves, DepositContractDepth)
|
||||
return &DepositTree{
|
||||
tree: merkle,
|
||||
mixInLength: 0,
|
||||
finalizedExecutionBlock: executionBlock{},
|
||||
}
|
||||
}
|
||||
|
||||
// getSnapshot returns a deposit tree snapshot.
|
||||
//
|
||||
//nolint:unused
|
||||
func (d *DepositTree) getSnapshot() (DepositTreeSnapshot, error) {
|
||||
if d.finalizedExecutionBlock == (executionBlock{}) {
|
||||
return DepositTreeSnapshot{}, ErrEmptyExecutionBlock
|
||||
}
|
||||
var finalized [][32]byte
|
||||
depositCount, _ := d.tree.GetFinalized(finalized)
|
||||
return fromTreeParts(finalized, depositCount, d.finalizedExecutionBlock)
|
||||
}
|
||||
|
||||
// fromSnapshot returns a deposit tree from a deposit tree snapshot.
|
||||
//
|
||||
//nolint:unused
|
||||
func fromSnapshot(snapshot DepositTreeSnapshot) (DepositTree, error) {
|
||||
root, err := snapshot.CalculateRoot()
|
||||
if err != nil {
|
||||
return DepositTree{}, err
|
||||
}
|
||||
if snapshot.depositRoot != root {
|
||||
return DepositTree{}, ErrInvalidSnapshotRoot
|
||||
}
|
||||
if snapshot.depositCount >= math.PowerOf2(uint64(DepositContractDepth)) {
|
||||
return DepositTree{}, ErrTooManyDeposits
|
||||
}
|
||||
tree, err := fromSnapshotParts(snapshot.finalized, snapshot.depositCount, DepositContractDepth)
|
||||
if err != nil {
|
||||
return DepositTree{}, err
|
||||
}
|
||||
if snapshot.depositCount == 0 {
|
||||
return DepositTree{}, ErrNoDeposits
|
||||
}
|
||||
return DepositTree{
|
||||
tree: tree,
|
||||
mixInLength: snapshot.depositCount,
|
||||
finalizedExecutionBlock: snapshot.executionBlock,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// finalize marks a deposit as finalized.
|
||||
//
|
||||
//nolint:unused
|
||||
func (d *DepositTree) finalize(eth1data *eth.Eth1Data, executionBlockHeight uint64) error {
|
||||
var blockHash [32]byte
|
||||
copy(blockHash[:], eth1data.BlockHash)
|
||||
d.finalizedExecutionBlock = executionBlock{
|
||||
Hash: blockHash,
|
||||
Depth: executionBlockHeight,
|
||||
}
|
||||
_, err := d.tree.Finalize(eth1data.DepositCount, DepositContractDepth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getProof returns the Deposit tree proof.
|
||||
//
|
||||
//nolint:unused
|
||||
func (d *DepositTree) getProof(index uint64) ([32]byte, [][32]byte, error) {
|
||||
if d.mixInLength <= 0 {
|
||||
return [32]byte{}, nil, ErrInvalidMixInLength
|
||||
}
|
||||
finalizedDeposits, _ := d.tree.GetFinalized([][32]byte{})
|
||||
if finalizedDeposits == 0 {
|
||||
return [32]byte{}, nil, ErrNoFinalizedDeposits
|
||||
}
|
||||
if finalizedDeposits != 0 {
|
||||
finalizedDeposits = finalizedDeposits - 1
|
||||
}
|
||||
if index <= finalizedDeposits {
|
||||
return [32]byte{}, nil, ErrInvalidIndex
|
||||
}
|
||||
leaf, proof := generateProof(d.tree, index, DepositContractDepth)
|
||||
var mixInLength [32]byte
|
||||
copy(mixInLength[:], bytesutil.Uint64ToBytesLittleEndian32(d.mixInLength))
|
||||
proof = append(proof, mixInLength)
|
||||
return leaf, proof, nil
|
||||
}
|
||||
|
||||
// getRoot returns the root of the deposit tree.
|
||||
//
|
||||
//nolint:unused
|
||||
func (d *DepositTree) getRoot() [32]byte {
|
||||
root := d.tree.GetRoot()
|
||||
return sha256.Sum256(append(root[:], bytesutil.Uint64ToBytesLittleEndian32(d.mixInLength)...))
|
||||
}
|
||||
|
||||
// pushLeaf adds a new leaf to the tree.
|
||||
//
|
||||
//nolint:unused
|
||||
func (d *DepositTree) pushLeaf(leaf [32]byte) error {
|
||||
var err error
|
||||
d.tree, err = d.tree.PushLeaf(leaf, DepositContractDepth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.mixInLength++
|
||||
return nil
|
||||
}
|
||||
62
beacon-chain/cache/depositsnapshot/deposit_tree_snapshot.go
vendored
Normal file
62
beacon-chain/cache/depositsnapshot/deposit_tree_snapshot.go
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package depositsnapshot
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrZeroIndex occurs when the value of index is 0.
|
||||
ErrZeroIndex = errors.New("index should be greater than 0")
|
||||
)
|
||||
|
||||
// DepositTreeSnapshot represents the data used to create a
|
||||
// deposit tree given a snapshot.
|
||||
//
|
||||
//nolint:unused
|
||||
type DepositTreeSnapshot struct {
|
||||
finalized [][32]byte
|
||||
depositRoot [32]byte
|
||||
depositCount uint64
|
||||
executionBlock executionBlock
|
||||
}
|
||||
|
||||
// CalculateRoot returns the root of a deposit tree snapshot.
|
||||
func (ds *DepositTreeSnapshot) CalculateRoot() ([32]byte, error) {
|
||||
size := ds.depositCount
|
||||
index := len(ds.finalized)
|
||||
root := Zerohashes[0]
|
||||
for i := 0; i < DepositContractDepth; i++ {
|
||||
if (size & 1) == 1 {
|
||||
if index == 0 {
|
||||
return [32]byte{}, ErrZeroIndex
|
||||
}
|
||||
index--
|
||||
root = sha256.Sum256(append(ds.finalized[index][:], root[:]...))
|
||||
} else {
|
||||
root = sha256.Sum256(append(root[:], Zerohashes[i][:]...))
|
||||
}
|
||||
size >>= 1
|
||||
}
|
||||
return sha256.Sum256(append(root[:], bytesutil.Uint64ToBytesLittleEndian(ds.depositCount)...)), nil
|
||||
}
|
||||
|
||||
// fromTreeParts constructs the deposit tree from pre-existing data.
|
||||
//
|
||||
//nolint:unused
|
||||
func fromTreeParts(finalised [][32]byte, depositCount uint64, executionBlock executionBlock) (DepositTreeSnapshot, error) {
|
||||
snapshot := DepositTreeSnapshot{
|
||||
finalized: finalised,
|
||||
depositRoot: Zerohashes[0],
|
||||
depositCount: depositCount,
|
||||
executionBlock: executionBlock,
|
||||
}
|
||||
root, err := snapshot.CalculateRoot()
|
||||
if err != nil {
|
||||
return snapshot, ErrInvalidSnapshotRoot
|
||||
}
|
||||
snapshot.depositRoot = root
|
||||
return snapshot, nil
|
||||
}
|
||||
317
beacon-chain/cache/depositsnapshot/merkle_tree.go
vendored
317
beacon-chain/cache/depositsnapshot/merkle_tree.go
vendored
@@ -1,5 +1,28 @@
|
||||
package depositsnapshot
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/container/slice"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/hash"
|
||||
"github.com/prysmaticlabs/prysm/v3/math"
|
||||
)
|
||||
|
||||
const (
|
||||
// DepositContractDepth is the maximum tree depth as defined by EIP-4881.
|
||||
DepositContractDepth = 32
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrFinalizedNodeCannotPushLeaf may occur when attempting to push a leaf to a finalized node. When a node is finalized, it cannot be modified or changed.
|
||||
ErrFinalizedNodeCannotPushLeaf = errors.New("can't push a leaf to a finalized node")
|
||||
// ErrLeafNodeCannotPushLeaf may occur when attempting to push a leaf to a leaf node.
|
||||
ErrLeafNodeCannotPushLeaf = errors.New("can't push a leaf to a leaf node")
|
||||
// ErrZeroLevel occurs when the value of level is 0.
|
||||
ErrZeroLevel = errors.New("level should be greater than 0")
|
||||
// ErrZeroDepth occurs when the value of depth is 0.
|
||||
ErrZeroDepth = errors.New("depth should be greater than 0")
|
||||
)
|
||||
|
||||
// MerkleTreeNode is the interface for a Merkle tree.
|
||||
type MerkleTreeNode interface {
|
||||
// GetRoot returns the root of the Merkle tree.
|
||||
@@ -7,9 +30,295 @@ type MerkleTreeNode interface {
|
||||
// IsFull returns whether there is space left for deposits.
|
||||
IsFull() bool
|
||||
// Finalize marks deposits of the Merkle tree as finalized.
|
||||
Finalize(deposits uint, depth uint) MerkleTreeNode
|
||||
// GetFinalized returns a list of hashes of all the finalized nodes and the number of deposits.
|
||||
GetFinalized(result [][32]byte) ([][32]byte, uint)
|
||||
Finalize(depositsToFinalize uint64, depth uint64) (MerkleTreeNode, error)
|
||||
// GetFinalized returns the number of deposits and a list of hashes of all the finalized nodes.
|
||||
GetFinalized(result [][32]byte) (uint64, [][32]byte)
|
||||
// PushLeaf adds a new leaf node at the next available Zero node.
|
||||
PushLeaf(leaf [32]byte, deposits uint, depth uint) MerkleTreeNode
|
||||
PushLeaf(leaf [32]byte, depth uint64) (MerkleTreeNode, error)
|
||||
|
||||
// Right represents the right child of a node.
|
||||
Right() MerkleTreeNode
|
||||
// Left represents the left child of a node.
|
||||
Left() MerkleTreeNode
|
||||
}
|
||||
|
||||
// create builds a new merkle tree
|
||||
func create(leaves [][32]byte, depth uint64) MerkleTreeNode {
|
||||
length := uint64(len(leaves))
|
||||
if length == 0 {
|
||||
return &ZeroNode{depth: depth}
|
||||
}
|
||||
if depth == 0 {
|
||||
return &LeafNode{hash: leaves[0]}
|
||||
}
|
||||
split := math.Min(math.PowerOf2(depth-1), length)
|
||||
left := create(leaves[0:split], depth-1)
|
||||
right := create(leaves[split:], depth-1)
|
||||
return &InnerNode{left: left, right: right}
|
||||
}
|
||||
|
||||
// fromSnapshotParts creates a new Merkle tree from a list of finalized leaves, number of deposits and specified depth.
|
||||
//
|
||||
//nolint:unused
|
||||
func fromSnapshotParts(finalized [][32]byte, deposits uint64, level uint64) (_ MerkleTreeNode, err error) {
|
||||
if len(finalized) < 1 || deposits == 0 {
|
||||
return &ZeroNode{
|
||||
depth: level,
|
||||
}, nil
|
||||
}
|
||||
if deposits == math.PowerOf2(level) {
|
||||
return &FinalizedNode{
|
||||
depositCount: deposits,
|
||||
hash: finalized[0],
|
||||
}, nil
|
||||
}
|
||||
if level == 0 {
|
||||
return &ZeroNode{}, ErrZeroLevel
|
||||
}
|
||||
node := InnerNode{}
|
||||
if leftSubtree := math.PowerOf2(level - 1); deposits <= leftSubtree {
|
||||
node.left, err = fromSnapshotParts(finalized, deposits, level-1)
|
||||
if err != nil {
|
||||
return &ZeroNode{}, err
|
||||
}
|
||||
node.right = &ZeroNode{depth: level - 1}
|
||||
} else {
|
||||
node.left = &FinalizedNode{
|
||||
depositCount: leftSubtree,
|
||||
hash: finalized[0],
|
||||
}
|
||||
node.right, err = fromSnapshotParts(finalized[1:], deposits-leftSubtree, level-1)
|
||||
if err != nil {
|
||||
return &ZeroNode{}, err
|
||||
}
|
||||
}
|
||||
return &node, nil
|
||||
}
|
||||
|
||||
// generateProof returns a merkle proof and root
|
||||
//
|
||||
//nolint:unused
|
||||
func generateProof(tree MerkleTreeNode, index uint64, depth uint64) ([32]byte, [][32]byte) {
|
||||
var proof [][32]byte
|
||||
node := tree
|
||||
for depth > 0 {
|
||||
ithBit := (index >> (depth - 1)) & 0x1
|
||||
if ithBit == 1 {
|
||||
proof = append(proof, node.Left().GetRoot())
|
||||
node = node.Right()
|
||||
} else {
|
||||
proof = append(proof, node.Right().GetRoot())
|
||||
node = node.Left()
|
||||
}
|
||||
depth--
|
||||
}
|
||||
proof = slice.Reverse(proof)
|
||||
return node.GetRoot(), proof
|
||||
}
|
||||
|
||||
// FinalizedNode represents a finalized node and satisfies the MerkleTreeNode interface.
|
||||
type FinalizedNode struct {
|
||||
depositCount uint64
|
||||
hash [32]byte
|
||||
}
|
||||
|
||||
// GetRoot returns the root of the Merkle tree.
|
||||
func (f *FinalizedNode) GetRoot() [32]byte {
|
||||
return f.hash
|
||||
}
|
||||
|
||||
// IsFull returns whether there is space left for deposits.
|
||||
// A FinalizedNode will always return true as by definition it
|
||||
// is full and deposits can't be added to it.
|
||||
func (_ *FinalizedNode) IsFull() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Finalize marks deposits of the Merkle tree as finalized.
|
||||
func (f *FinalizedNode) Finalize(depositsToFinalize uint64, depth uint64) (MerkleTreeNode, error) {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// GetFinalized returns a list of hashes of all the finalized nodes and the number of deposits.
|
||||
func (f *FinalizedNode) GetFinalized(result [][32]byte) (uint64, [][32]byte) {
|
||||
return f.depositCount, append(result, f.hash)
|
||||
}
|
||||
|
||||
// PushLeaf adds a new leaf node at the next available zero node.
|
||||
func (_ *FinalizedNode) PushLeaf(_ [32]byte, _ uint64) (MerkleTreeNode, error) {
|
||||
return nil, ErrFinalizedNodeCannotPushLeaf
|
||||
}
|
||||
|
||||
// Right returns nil as a finalized node can't have any children.
|
||||
func (_ *FinalizedNode) Right() MerkleTreeNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Left returns nil as a finalized node can't have any children.
|
||||
func (_ *FinalizedNode) Left() MerkleTreeNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LeafNode represents a leaf node holding a deposit and satisfies the MerkleTreeNode interface.
|
||||
type LeafNode struct {
|
||||
hash [32]byte
|
||||
}
|
||||
|
||||
// GetRoot returns the root of the Merkle tree.
|
||||
func (l *LeafNode) GetRoot() [32]byte {
|
||||
return l.hash
|
||||
}
|
||||
|
||||
// IsFull returns whether there is space left for deposits.
|
||||
// A LeafNode will always return true as it is the last node
|
||||
// in the tree and therefore can't have any deposits added to it.
|
||||
func (_ *LeafNode) IsFull() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Finalize marks deposits of the Merkle tree as finalized.
|
||||
func (l *LeafNode) Finalize(depositsToFinalize uint64, depth uint64) (MerkleTreeNode, error) {
|
||||
return &FinalizedNode{1, l.hash}, nil
|
||||
}
|
||||
|
||||
// GetFinalized returns a list of hashes of all the finalized nodes and the number of deposits.
|
||||
func (_ *LeafNode) GetFinalized(result [][32]byte) (uint64, [][32]byte) {
|
||||
return 0, result
|
||||
}
|
||||
|
||||
// PushLeaf adds a new leaf node at the next available zero node.
|
||||
func (_ *LeafNode) PushLeaf(_ [32]byte, _ uint64) (MerkleTreeNode, error) {
|
||||
return nil, ErrLeafNodeCannotPushLeaf
|
||||
}
|
||||
|
||||
// Right returns nil as a leaf node is the last node and can't have any children.
|
||||
func (_ *LeafNode) Right() MerkleTreeNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Left returns nil as a leaf node is the last node and can't have any children.
|
||||
func (_ *LeafNode) Left() MerkleTreeNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InnerNode represents an inner node with two children and satisfies the MerkleTreeNode interface.
|
||||
type InnerNode struct {
|
||||
left, right MerkleTreeNode
|
||||
}
|
||||
|
||||
// GetRoot returns the root of the Merkle tree.
|
||||
func (n *InnerNode) GetRoot() [32]byte {
|
||||
left := n.left.GetRoot()
|
||||
right := n.right.GetRoot()
|
||||
return hash.Hash(append(left[:], right[:]...))
|
||||
}
|
||||
|
||||
// IsFull returns whether there is space left for deposits.
|
||||
func (n *InnerNode) IsFull() bool {
|
||||
return n.right.IsFull()
|
||||
}
|
||||
|
||||
// Finalize marks deposits of the Merkle tree as finalized.
|
||||
func (n *InnerNode) Finalize(depositsToFinalize uint64, depth uint64) (_ MerkleTreeNode, err error) {
|
||||
deposits := math.PowerOf2(depth)
|
||||
if deposits <= depositsToFinalize {
|
||||
return &FinalizedNode{deposits, n.GetRoot()}, nil
|
||||
}
|
||||
if depth == 0 {
|
||||
return &ZeroNode{}, ErrZeroDepth
|
||||
}
|
||||
n.left, err = n.left.Finalize(depositsToFinalize, depth-1)
|
||||
if err != nil {
|
||||
return &ZeroNode{}, err
|
||||
}
|
||||
if depositsToFinalize > deposits/2 {
|
||||
remaining := depositsToFinalize - deposits/2
|
||||
n.right, err = n.right.Finalize(remaining, depth-1)
|
||||
if err != nil {
|
||||
return &ZeroNode{}, err
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// GetFinalized returns a list of hashes of all the finalized nodes and the number of deposits.
|
||||
func (n *InnerNode) GetFinalized(result [][32]byte) (uint64, [][32]byte) {
|
||||
leftDeposits, result := n.left.GetFinalized(result)
|
||||
rightDeposits, result := n.right.GetFinalized(result)
|
||||
return leftDeposits + rightDeposits, result
|
||||
}
|
||||
|
||||
// PushLeaf adds a new leaf node at the next available zero node.
|
||||
func (n *InnerNode) PushLeaf(leaf [32]byte, depth uint64) (MerkleTreeNode, error) {
|
||||
if !n.left.IsFull() {
|
||||
left, err := n.left.PushLeaf(leaf, depth-1)
|
||||
if err == nil {
|
||||
n.left = left
|
||||
} else {
|
||||
return n, err
|
||||
}
|
||||
} else {
|
||||
right, err := n.right.PushLeaf(leaf, depth-1)
|
||||
if err == nil {
|
||||
n.right = right
|
||||
} else {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Right returns the child node on the right.
|
||||
func (n *InnerNode) Right() MerkleTreeNode {
|
||||
return n.right
|
||||
}
|
||||
|
||||
// Left returns the child node on the left.
|
||||
func (n *InnerNode) Left() MerkleTreeNode {
|
||||
return n.left
|
||||
}
|
||||
|
||||
// ZeroNode represents an empty node without a deposit and satisfies the MerkleTreeNode interface.
|
||||
type ZeroNode struct {
|
||||
depth uint64
|
||||
}
|
||||
|
||||
// GetRoot returns the root of the Merkle tree.
|
||||
func (z *ZeroNode) GetRoot() [32]byte {
|
||||
if z.depth == DepositContractDepth {
|
||||
return hash.Hash(append(Zerohashes[z.depth-1][:], Zerohashes[z.depth-1][:]...))
|
||||
}
|
||||
return Zerohashes[z.depth]
|
||||
}
|
||||
|
||||
// IsFull returns wh ether there is space left for deposits.
|
||||
// A ZeroNode will always return false as a ZeroNode is an empty node
|
||||
// that gets replaced by a deposit.
|
||||
func (_ *ZeroNode) IsFull() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Finalize marks deposits of the Merkle tree as finalized.
|
||||
func (_ *ZeroNode) Finalize(depositsToFinalize uint64, depth uint64) (MerkleTreeNode, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetFinalized returns a list of hashes of all the finalized nodes and the number of deposits.
|
||||
func (_ *ZeroNode) GetFinalized(result [][32]byte) (uint64, [][32]byte) {
|
||||
return 0, result
|
||||
}
|
||||
|
||||
// PushLeaf adds a new leaf node at the next available zero node.
|
||||
func (_ *ZeroNode) PushLeaf(leaf [32]byte, depth uint64) (MerkleTreeNode, error) {
|
||||
return create([][32]byte{leaf}, depth), nil
|
||||
}
|
||||
|
||||
// Right returns nil as a zero node can't have any children.
|
||||
func (_ *ZeroNode) Right() MerkleTreeNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Left returns nil as a zero node can't have any children.
|
||||
func (_ *ZeroNode) Left() MerkleTreeNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
69
beacon-chain/cache/depositsnapshot/zerohashes.gen.go
vendored
Normal file
69
beacon-chain/cache/depositsnapshot/zerohashes.gen.go
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// Code generated by gen_zerohashes. DO NOT EDIT.
|
||||
package depositsnapshot
|
||||
|
||||
var Zerohashes = [][32]byte{
|
||||
// 0000000000000000000000000000000000000000000000000000000000000000
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
// f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b
|
||||
{245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169, 39, 89, 251, 75},
|
||||
// db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71
|
||||
{219, 86, 17, 78, 0, 253, 212, 193, 248, 92, 137, 43, 243, 90, 201, 168, 146, 137, 170, 236, 177, 235, 208, 169, 108, 222, 96, 106, 116, 139, 93, 113},
|
||||
// c78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c
|
||||
{199, 128, 9, 253, 240, 127, 197, 106, 17, 241, 34, 55, 6, 88, 163, 83, 170, 165, 66, 237, 99, 228, 76, 75, 193, 95, 244, 205, 16, 90, 179, 60},
|
||||
// 536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c
|
||||
{83, 109, 152, 131, 127, 45, 209, 101, 165, 93, 94, 234, 233, 20, 133, 149, 68, 114, 213, 111, 36, 109, 242, 86, 191, 60, 174, 25, 53, 42, 18, 60},
|
||||
// 9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30
|
||||
{158, 253, 224, 82, 170, 21, 66, 159, 174, 5, 186, 212, 208, 177, 215, 198, 77, 166, 77, 3, 215, 161, 133, 74, 88, 140, 44, 184, 67, 12, 13, 48},
|
||||
// d88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1
|
||||
{216, 141, 223, 238, 212, 0, 168, 117, 85, 150, 178, 25, 66, 193, 73, 126, 17, 76, 48, 46, 97, 24, 41, 15, 145, 230, 119, 41, 118, 4, 31, 161},
|
||||
// 87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c
|
||||
{135, 235, 13, 219, 165, 126, 53, 246, 210, 134, 103, 56, 2, 164, 175, 89, 117, 226, 37, 6, 199, 207, 76, 100, 187, 107, 229, 238, 17, 82, 127, 44},
|
||||
// 26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193
|
||||
{38, 132, 100, 118, 253, 95, 197, 74, 93, 67, 56, 81, 103, 201, 81, 68, 242, 100, 63, 83, 60, 200, 91, 185, 209, 107, 120, 47, 141, 125, 177, 147},
|
||||
// 506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1
|
||||
{80, 109, 134, 88, 45, 37, 36, 5, 184, 64, 1, 135, 146, 202, 210, 191, 18, 89, 241, 239, 90, 165, 248, 135, 225, 60, 178, 240, 9, 79, 81, 225},
|
||||
// ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b
|
||||
{255, 255, 10, 215, 230, 89, 119, 47, 149, 52, 193, 149, 200, 21, 239, 196, 1, 78, 241, 225, 218, 237, 68, 4, 192, 99, 133, 209, 17, 146, 233, 43},
|
||||
// 6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220
|
||||
{108, 240, 65, 39, 219, 5, 68, 28, 216, 51, 16, 122, 82, 190, 133, 40, 104, 137, 14, 67, 23, 230, 160, 42, 180, 118, 131, 170, 117, 150, 66, 32},
|
||||
// b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f
|
||||
{183, 208, 95, 135, 95, 20, 0, 39, 239, 81, 24, 162, 36, 123, 187, 132, 206, 143, 47, 15, 17, 35, 98, 48, 133, 218, 247, 150, 12, 50, 159, 95},
|
||||
// df6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e
|
||||
{223, 106, 245, 245, 187, 219, 107, 233, 239, 138, 166, 24, 228, 191, 128, 115, 150, 8, 103, 23, 30, 41, 103, 111, 139, 40, 77, 234, 106, 8, 168, 94},
|
||||
// b58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784
|
||||
{181, 141, 144, 15, 94, 24, 46, 60, 80, 239, 116, 150, 158, 161, 108, 119, 38, 197, 73, 117, 124, 194, 53, 35, 195, 105, 88, 125, 167, 41, 55, 132},
|
||||
// d49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb
|
||||
{212, 154, 117, 2, 255, 207, 176, 52, 11, 29, 120, 133, 104, 133, 0, 202, 48, 129, 97, 167, 249, 107, 98, 223, 157, 8, 59, 113, 252, 200, 242, 187},
|
||||
// 8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb
|
||||
{143, 230, 177, 104, 146, 86, 192, 211, 133, 244, 47, 91, 190, 32, 39, 162, 44, 25, 150, 225, 16, 186, 151, 193, 113, 211, 229, 148, 141, 233, 43, 235},
|
||||
// 8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab
|
||||
{141, 13, 99, 195, 158, 186, 222, 133, 9, 224, 174, 60, 156, 56, 118, 251, 95, 161, 18, 190, 24, 249, 5, 236, 172, 254, 203, 146, 5, 118, 3, 171},
|
||||
// 95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4
|
||||
{149, 238, 200, 178, 229, 65, 202, 212, 233, 29, 227, 131, 133, 242, 224, 70, 97, 159, 84, 73, 108, 35, 130, 203, 108, 172, 213, 185, 140, 38, 245, 164},
|
||||
// f893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f
|
||||
{248, 147, 233, 8, 145, 119, 117, 182, 43, 255, 35, 41, 77, 187, 227, 161, 205, 142, 108, 193, 195, 91, 72, 1, 136, 123, 100, 106, 111, 129, 241, 127},
|
||||
// cddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa
|
||||
{205, 219, 167, 181, 146, 227, 19, 51, 147, 193, 97, 148, 250, 199, 67, 26, 191, 47, 84, 133, 237, 113, 29, 178, 130, 24, 60, 129, 158, 8, 235, 170},
|
||||
// 8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c
|
||||
{138, 141, 127, 227, 175, 140, 170, 8, 90, 118, 57, 168, 50, 0, 20, 87, 223, 185, 18, 138, 128, 97, 20, 42, 208, 51, 86, 41, 255, 35, 255, 156},
|
||||
// feb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167
|
||||
{254, 179, 195, 55, 215, 165, 26, 111, 191, 0, 185, 227, 76, 82, 225, 201, 25, 92, 150, 155, 212, 231, 160, 191, 213, 29, 92, 91, 237, 156, 17, 103},
|
||||
// e71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7
|
||||
{231, 31, 10, 168, 60, 195, 46, 223, 190, 250, 159, 77, 62, 1, 116, 202, 133, 24, 46, 236, 159, 58, 9, 246, 166, 192, 223, 99, 119, 165, 16, 215},
|
||||
// 31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0
|
||||
{49, 32, 111, 168, 10, 80, 187, 106, 190, 41, 8, 80, 88, 241, 98, 18, 33, 42, 96, 238, 200, 240, 73, 254, 203, 146, 216, 200, 224, 168, 75, 192},
|
||||
// 21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544
|
||||
{33, 53, 43, 254, 203, 237, 221, 233, 147, 131, 159, 97, 76, 61, 172, 10, 62, 227, 117, 67, 249, 180, 18, 177, 97, 153, 220, 21, 142, 35, 181, 68},
|
||||
// 619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765
|
||||
{97, 158, 49, 39, 36, 187, 109, 124, 49, 83, 237, 157, 231, 145, 215, 100, 163, 102, 179, 137, 175, 19, 197, 139, 248, 168, 217, 4, 129, 164, 103, 101},
|
||||
// 7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4
|
||||
{124, 221, 41, 134, 38, 130, 80, 98, 141, 12, 16, 227, 133, 197, 140, 97, 145, 230, 251, 224, 81, 145, 188, 192, 79, 19, 63, 44, 234, 114, 193, 196},
|
||||
// 848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1
|
||||
{132, 137, 48, 189, 123, 168, 202, 197, 70, 97, 7, 33, 19, 251, 39, 136, 105, 224, 123, 184, 88, 127, 145, 57, 41, 51, 55, 77, 1, 123, 203, 225},
|
||||
// 8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636
|
||||
{136, 105, 255, 44, 34, 178, 140, 193, 5, 16, 217, 133, 50, 146, 128, 51, 40, 190, 79, 176, 232, 4, 149, 232, 187, 141, 39, 31, 91, 136, 150, 54},
|
||||
// b5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c
|
||||
{181, 254, 40, 231, 159, 27, 133, 15, 134, 88, 36, 108, 233, 182, 161, 231, 180, 159, 192, 109, 183, 20, 62, 143, 224, 180, 242, 176, 197, 82, 58, 92},
|
||||
// 985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7
|
||||
{152, 94, 146, 159, 112, 175, 40, 208, 189, 209, 169, 10, 128, 143, 151, 127, 89, 124, 124, 119, 140, 72, 158, 152, 211, 189, 137, 16, 211, 26, 192, 247},
|
||||
}
|
||||
@@ -17,6 +17,10 @@ const ForkVersionByteLength = 4
|
||||
// DomainByteLength length of domain byte array.
|
||||
const DomainByteLength = 4
|
||||
|
||||
// digestMap maps the fork version and genesis validator root to the
|
||||
// resultant fork digest.
|
||||
var digestMap = make(map[string][32]byte)
|
||||
|
||||
// ErrSigFailedToVerify returns when a signature of a block object(ie attestation, slashing, exit... etc)
|
||||
// failed to verify.
|
||||
var ErrSigFailedToVerify = errors.New("signature did not verify")
|
||||
@@ -240,6 +244,9 @@ func domain(domainType [DomainByteLength]byte, forkDataRoot []byte) []byte {
|
||||
// genesis_validators_root=genesis_validators_root,
|
||||
// ))
|
||||
func computeForkDataRoot(version, root []byte) ([32]byte, error) {
|
||||
if val, ok := digestMap[string(version)+string(root)]; ok {
|
||||
return val, nil
|
||||
}
|
||||
r, err := (ðpb.ForkData{
|
||||
CurrentVersion: version,
|
||||
GenesisValidatorsRoot: root,
|
||||
@@ -247,6 +254,10 @@ func computeForkDataRoot(version, root []byte) ([32]byte, error) {
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
// Cache result of digest computation
|
||||
// as this is a hot path and doesn't need
|
||||
// to be constantly computed.
|
||||
digestMap[string(version)+string(root)] = r
|
||||
return r, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +136,25 @@ func TestFuzzverifySigningRoot_10000(_ *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDigestMap(t *testing.T) {
|
||||
testVersion := []byte{'A', 'B', 'C', 'D'}
|
||||
testValRoot := [32]byte{'t', 'e', 's', 't', 'r', 'o', 'o', 't'}
|
||||
digest, err := signing.ComputeForkDigest(testVersion, testValRoot[:])
|
||||
assert.NoError(t, err)
|
||||
|
||||
cachedDigest, err := signing.ComputeForkDigest(testVersion, testValRoot[:])
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, digest, cachedDigest)
|
||||
testVersion[3] = 'E'
|
||||
cachedDigest, err = signing.ComputeForkDigest(testVersion, testValRoot[:])
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, digest, cachedDigest)
|
||||
testValRoot[5] = 'z'
|
||||
cachedDigest2, err := signing.ComputeForkDigest(testVersion, testValRoot[:])
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, digest, cachedDigest2)
|
||||
assert.NotEqual(t, cachedDigest, cachedDigest2)
|
||||
}
|
||||
func TestBlockSignatureBatch_NoSigVerification(t *testing.T) {
|
||||
tests := []struct {
|
||||
pubkey []byte
|
||||
|
||||
@@ -14,6 +14,11 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// We recycle the BLS changes pool to avoid the backing map growing without
|
||||
// bound. The cycling operation is expensive because it copies all elements, so
|
||||
// we only do it when the map is smaller than this upper bound.
|
||||
const blsChangesPoolThreshold = 2000
|
||||
|
||||
// PoolManager maintains pending and seen BLS-to-execution-change objects.
|
||||
// This pool is used by proposers to insert BLS-to-execution-change objects into new blocks.
|
||||
type PoolManager interface {
|
||||
@@ -39,6 +44,15 @@ func NewPool() *Pool {
|
||||
}
|
||||
}
|
||||
|
||||
// Copies the internal map and returns a new one.
|
||||
func (p *Pool) cycleMap() {
|
||||
newMap := make(map[primitives.ValidatorIndex]*doublylinkedlist.Node[*ethpb.SignedBLSToExecutionChange])
|
||||
for k, v := range p.m {
|
||||
newMap[k] = v
|
||||
}
|
||||
p.m = newMap
|
||||
}
|
||||
|
||||
// PendingBLSToExecChanges returns all objects from the pool.
|
||||
func (p *Pool) PendingBLSToExecChanges() ([]*ethpb.SignedBLSToExecutionChange, error) {
|
||||
p.lock.RLock()
|
||||
@@ -150,6 +164,9 @@ func (p *Pool) MarkIncluded(change *ethpb.SignedBLSToExecutionChange) {
|
||||
|
||||
delete(p.m, change.Message.ValidatorIndex)
|
||||
p.pending.Remove(node)
|
||||
if p.numPending() == blsChangesPoolThreshold {
|
||||
p.cycleMap()
|
||||
}
|
||||
}
|
||||
|
||||
// ValidatorExists checks if the bls to execution change object exists
|
||||
@@ -162,3 +179,8 @@ func (p *Pool) ValidatorExists(idx primitives.ValidatorIndex) bool {
|
||||
|
||||
return node != nil
|
||||
}
|
||||
|
||||
// numPending returns the number of pending bls to execution changes in the pool
|
||||
func (p *Pool) numPending() int {
|
||||
return p.pending.Len()
|
||||
}
|
||||
|
||||
@@ -407,3 +407,29 @@ func TestValidatorExists(t *testing.T) {
|
||||
assert.Equal(t, false, pool.ValidatorExists(30))
|
||||
})
|
||||
}
|
||||
|
||||
func TestPoolCycleMap(t *testing.T) {
|
||||
pool := NewPool()
|
||||
firstChange := ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: primitives.ValidatorIndex(0),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(firstChange)
|
||||
secondChange := ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: primitives.ValidatorIndex(10),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(secondChange)
|
||||
thirdChange := ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: primitives.ValidatorIndex(30),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(thirdChange)
|
||||
|
||||
pool.cycleMap()
|
||||
require.Equal(t, true, pool.ValidatorExists(0))
|
||||
require.Equal(t, true, pool.ValidatorExists(10))
|
||||
require.Equal(t, true, pool.ValidatorExists(30))
|
||||
require.Equal(t, false, pool.ValidatorExists(20))
|
||||
|
||||
}
|
||||
|
||||
@@ -141,19 +141,36 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot primitives.Slot,
|
||||
SafeBlockHash: finalizedBlockHash,
|
||||
FinalizedBlockHash: finalizedBlockHash,
|
||||
}
|
||||
|
||||
p := &enginev1.PayloadAttributes{
|
||||
Timestamp: uint64(t.Unix()),
|
||||
PrevRandao: random,
|
||||
SuggestedFeeRecipient: feeRecipient.Bytes(),
|
||||
var attr payloadattribute.Attributer
|
||||
switch st.Version() {
|
||||
case version.Capella:
|
||||
withdrawals, err := st.ExpectedWithdrawals()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
attr, err = payloadattribute.New(&enginev1.PayloadAttributesV2{
|
||||
Timestamp: uint64(t.Unix()),
|
||||
PrevRandao: random,
|
||||
SuggestedFeeRecipient: feeRecipient.Bytes(),
|
||||
Withdrawals: withdrawals,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case version.Bellatrix:
|
||||
attr, err = payloadattribute.New(&enginev1.PayloadAttributes{
|
||||
Timestamp: uint64(t.Unix()),
|
||||
PrevRandao: random,
|
||||
SuggestedFeeRecipient: feeRecipient.Bytes(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("unknown beacon state version")
|
||||
}
|
||||
|
||||
// This will change in subsequent hardforks like Capella.
|
||||
pa, err := payloadattribute.New(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payloadID, _, err := vs.ExecutionEngineCaller.ForkchoiceUpdated(ctx, f, pa)
|
||||
payloadID, _, err := vs.ExecutionEngineCaller.ForkchoiceUpdated(ctx, f, attr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not prepare payload")
|
||||
}
|
||||
|
||||
@@ -59,6 +59,18 @@ func TestServer_getExecutionPayload(t *testing.T) {
|
||||
Root: b2r[:],
|
||||
}))
|
||||
|
||||
capellaTransitionState, _ := util.DeterministicGenesisStateCapella(t, 1)
|
||||
wrappedHeaderCapella, err := blocks.WrappedExecutionPayloadHeaderCapella(&pb.ExecutionPayloadHeaderCapella{BlockNumber: 1})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, capellaTransitionState.SetLatestExecutionPayloadHeader(wrappedHeaderCapella))
|
||||
b2pbCapella := util.NewBeaconBlockCapella()
|
||||
b2rCapella, err := b2pbCapella.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
util.SaveBlock(t, context.Background(), beaconDB, b2pbCapella)
|
||||
require.NoError(t, capellaTransitionState.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
||||
Root: b2rCapella[:],
|
||||
}))
|
||||
|
||||
require.NoError(t, beaconDB.SaveFeeRecipientsByValidatorIDs(context.Background(), []primitives.ValidatorIndex{0}, []common.Address{{}}))
|
||||
|
||||
tests := []struct {
|
||||
@@ -87,6 +99,12 @@ func TestServer_getExecutionPayload(t *testing.T) {
|
||||
payloadID: &pb.PayloadIDBytes{0x1},
|
||||
validatorIndx: 1,
|
||||
},
|
||||
{
|
||||
name: "transition completed, capella, happy case (doesn't have fee recipient in Db)",
|
||||
st: capellaTransitionState,
|
||||
payloadID: &pb.PayloadIDBytes{0x1},
|
||||
validatorIndx: 1,
|
||||
},
|
||||
{
|
||||
name: "transition completed, happy case, (payload ID cached)",
|
||||
st: transitionSt,
|
||||
|
||||
@@ -24,6 +24,21 @@ type Node[T any] struct {
|
||||
next *Node[T]
|
||||
}
|
||||
|
||||
// Copy returns a copy of the origina list.
|
||||
func (l *List[T]) Copy() *List[T] {
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
list := &List[T]{}
|
||||
if l.len == 0 {
|
||||
return list
|
||||
}
|
||||
for n := l.First(); n != nil; n = n.next {
|
||||
list.Append(n.Copy())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// First gets the reference to the first node in the list.
|
||||
func (l *List[T]) First() *Node[T] {
|
||||
return l.first
|
||||
@@ -111,3 +126,12 @@ func (n *Node[T]) Value() (T, error) {
|
||||
}
|
||||
return n.value, nil
|
||||
}
|
||||
|
||||
// Copy copies the given node and returns a new one. It does not do a deep copy
|
||||
// of T.
|
||||
func (n *Node[T]) Copy() *Node[T] {
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
return NewNode(n.value)
|
||||
}
|
||||
|
||||
@@ -123,3 +123,36 @@ func TestRemove(t *testing.T) {
|
||||
require.Equal(t, 2, list.len)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNodeCopy(t *testing.T) {
|
||||
first := NewNode(1)
|
||||
second := first.Copy()
|
||||
v, err := second.Value()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, first.value, v)
|
||||
}
|
||||
|
||||
func TestListCopy(t *testing.T) {
|
||||
list := &List[int]{}
|
||||
first := NewNode(1)
|
||||
second := NewNode(2)
|
||||
third := NewNode(3)
|
||||
list.Append(first)
|
||||
list.Append(second)
|
||||
list.Append(third)
|
||||
|
||||
copied := list.Copy()
|
||||
require.Equal(t, 3, copied.Len())
|
||||
m := copied.First()
|
||||
for n := list.First(); n != nil; n = n.next {
|
||||
nv, err := n.Value()
|
||||
require.NoError(t, err)
|
||||
mv, err := m.Value()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, nv, mv)
|
||||
|
||||
require.NotEqual(t, n, m)
|
||||
m, err = m.Next()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,3 +382,12 @@ func Unique[T comparable](a []T) []T {
|
||||
}
|
||||
return result[:end]
|
||||
}
|
||||
|
||||
// Reverse reverses any slice in place
|
||||
// Taken from https://github.com/faiface/generics/blob/8cf65f0b43803410724d8c671cb4d328543ba07d/examples/sliceutils/sliceutils.go
|
||||
func Reverse[E any](s []E) []E {
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -599,3 +599,20 @@ func TestUnique(t *testing.T) {
|
||||
require.DeepEqual(t, []uint64{1, 2}, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestReverse(t *testing.T) {
|
||||
tests := []struct {
|
||||
value [][32]byte
|
||||
want [][32]byte
|
||||
}{
|
||||
{[][32]byte{}, [][32]byte{}},
|
||||
{[][32]byte{{'A'}, {'B'}, {'C'}, {'D'}},
|
||||
[][32]byte{{'D'}, {'C'}, {'B'}, {'A'}}},
|
||||
{[][32]byte{{1}, {2}, {3}, {4}},
|
||||
[][32]byte{{4}, {3}, {2}, {1}}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
b := slice.Reverse(tt.value)
|
||||
require.DeepEqual(t, tt.want, b)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,14 @@ func Uint64ToBytesLittleEndian(i uint64) []byte {
|
||||
return buf
|
||||
}
|
||||
|
||||
// Uint64ToBytesLittleEndian32 conversion of a uint64 to a fix
|
||||
// sized 32 byte array in little endian order. Returns 32 byte array.
|
||||
func Uint64ToBytesLittleEndian32(i uint64) []byte {
|
||||
buf := make([]byte, 32)
|
||||
binary.LittleEndian.PutUint64(buf, i)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Uint64ToBytesBigEndian conversion.
|
||||
func Uint64ToBytesBigEndian(i uint64) []byte {
|
||||
buf := make([]byte, 8)
|
||||
|
||||
@@ -300,3 +300,26 @@ func TestUint64ToBytesLittleEndian(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint64ToBytesLittleEndian32(t *testing.T) {
|
||||
tests := []struct {
|
||||
value uint64
|
||||
want [32]byte
|
||||
}{
|
||||
{
|
||||
value: 0x01000000,
|
||||
want: [32]byte{0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
},
|
||||
{
|
||||
value: 0x00000001,
|
||||
want: [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(fmt.Sprintf("0x%08x", tt.value), func(t *testing.T) {
|
||||
if got := bytesutil.Uint64ToBytesLittleEndian32(tt.value); !bytes.Equal(got, tt.want[:]) {
|
||||
t.Errorf("Uint64ToBytesLittleEndian32() = got %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
22
prysm.bat
22
prysm.bat
@@ -5,7 +5,7 @@ SetLocal EnableDelayedExpansion & REM All variables are set local to this run &
|
||||
set PRYLABS_SIGNING_KEY=0AE0051D647BA3C1A917AF4072E33E4DF1A5036E
|
||||
|
||||
REM Complain if invalid arguments were provided.
|
||||
for %%a in (beacon-chain validator client-stats) do (
|
||||
for %%a in (beacon-chain validator prysmctl client-stats) do (
|
||||
if %1 equ %%a (
|
||||
goto validprocess
|
||||
)
|
||||
@@ -13,7 +13,7 @@ for %%a in (beacon-chain validator client-stats) do (
|
||||
echo [31mERROR: PROCESS missing or invalid[0m
|
||||
echo Usage: ./prysm.bat PROCESS FLAGS.
|
||||
echo.
|
||||
echo PROCESS can be beacon-chain, validator, or client-stats.
|
||||
echo PROCESS can be beacon-chain, validator, prysmctl or client-stats.
|
||||
echo FLAGS are the flags or arguments passed to the PROCESS.
|
||||
echo.
|
||||
echo Use this script to download the latest Prysm release binaries.
|
||||
@@ -70,6 +70,7 @@ IF defined USE_PRYSM_MODERN (
|
||||
)
|
||||
set VALIDATOR_REAL=%wrapper_dir%\validator-%prysm_version%-%system%-%arch%
|
||||
set CLIENT_STATS_REAL=%wrapper_dir%\client-stats-%prysm_version%-%system%-%arch%
|
||||
set PRYSMCTL_REAL=%wrapper_dir%\prysmctl-%prysm_version%-%system%-%arch%
|
||||
|
||||
if "%~1"=="beacon-chain" (
|
||||
if exist "%BEACON_CHAIN_REAL%" (
|
||||
@@ -130,6 +131,22 @@ if "%~1"=="client-stats" (
|
||||
)
|
||||
)
|
||||
|
||||
if "%~1"=="prysmctl" (
|
||||
if exist %PRYSMCTL_REAL% (
|
||||
echo [32mprysmctl is up to date.[0m
|
||||
) else (
|
||||
echo [35mDownloading prysmctl %prysm_version% to %PRYSMCTL_REAL% %reason%[0m
|
||||
for /f "delims=" %%i in ('curl --silent -o nul -w "%%{http_code}" https://prysmaticlabs.com/releases/prysmctl-%prysm_version%-%system%-%arch% ') do set "http=%%i" && echo %%i
|
||||
if "!http!"=="404" (
|
||||
echo [35mNo prysmctl found for %prysm_version%[0m
|
||||
exit /b 1
|
||||
)
|
||||
curl -L https://prysmaticlabs.com/releases/prysmctl-%prysm_version%-%system%-%arch% -o %PRYSMCTL_REAL%
|
||||
curl --silent -L https://prysmaticlabs.com/releases/prysmctl-%prysm_version%-%system%-%arch%.sha256 -o %wrapper_dir%\prysmctl-%prysm_version%-%system%-%arch%.sha256
|
||||
curl --silent -L https://prysmaticlabs.com/releases/prysmctl-%prysm_version%-%system%-%arch%.sig -o %wrapper_dir%\prysmctl-%prysm_version%-%system%-%arch%.sig
|
||||
)
|
||||
)
|
||||
|
||||
if "%~1"=="slasher" (
|
||||
echo [31mThe slasher binary is no longer available. Please use the --slasher flag with your beacon node. See: https://docs.prylabs.network/docs/prysm-usage/slasher/[0m
|
||||
exit /b 1
|
||||
@@ -138,6 +155,7 @@ if "%~1"=="slasher" (
|
||||
if "%~1"=="beacon-chain" ( set process=%BEACON_CHAIN_REAL%)
|
||||
if "%~1"=="validator" ( set process=%VALIDATOR_REAL%)
|
||||
if "%~1"=="client-stats" ( set process=%CLIENT_STATS_REAL%)
|
||||
if "%~1"=="prysmctl" ( set process=%PRYSMCTL_REAL%)
|
||||
|
||||
REM GPG not natively available on Windows, external module required
|
||||
echo [33mWARN GPG verification is not natively available on Windows.[0m
|
||||
|
||||
@@ -2,11 +2,11 @@ $folderDist = "dist";
|
||||
$ProgressPreference = 'SilentlyContinue' # Disable Invoke-WebRequest progress bar, makes it silent and faster.
|
||||
|
||||
# Complain if invalid arguments were provided.
|
||||
if ("beacon-chain", "validator", "client-stats" -notcontains $args[0]) {
|
||||
if ("beacon-chain", "validator","prysmctl", "client-stats" -notcontains $args[0]) {
|
||||
Write-Host @"
|
||||
Usage: ./prysm.sh1 PROCESS FLAGS.
|
||||
|
||||
PROCESS can be beacon-chain, validator, or client-stats.
|
||||
PROCESS can be beacon-chain, validator, prysmctl, or client-stats.
|
||||
FLAGS are the flags or arguments passed to the PROCESS.
|
||||
|
||||
Use this script to download the latest Prysm release binaries.
|
||||
|
||||
27
prysm.sh
27
prysm.sh
@@ -69,7 +69,7 @@ function get_realpath() {
|
||||
if [ "$#" -lt 1 ]; then
|
||||
color "31" "Usage: ./prysm.sh PROCESS FLAGS."
|
||||
color "31" " ./prysm.sh PROCESS --download-only."
|
||||
color "31" "PROCESS can be beacon-chain, validator, or client-stats."
|
||||
color "31" "PROCESS can be beacon-chain, validator, prysmctl, or client-stats."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -178,6 +178,7 @@ else
|
||||
fi
|
||||
VALIDATOR_REAL="${wrapper_dir}/validator-${prysm_version}-${system}-${arch}"
|
||||
CLIENT_STATS_REAL="${wrapper_dir}/client-stats-${prysm_version}-${system}-${arch}"
|
||||
PRYSMCTL_REAL="${wrapper_dir}/prysmctl-${prysm_version}-${system}-${arch}"
|
||||
|
||||
if [[ $1 == beacon-chain ]]; then
|
||||
if [[ ! -x $BEACON_CHAIN_REAL ]]; then
|
||||
@@ -236,6 +237,24 @@ if [[ $1 == client-stats ]]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $1 == prysmctl ]]; then
|
||||
if [[ ! -x $PRYSMCTL_REAL ]]; then
|
||||
color "34" "Downloading prysmctl@${prysm_version} to ${CLIENT_STATS_REAL} (${reason})"
|
||||
|
||||
file=prysmctl-${prysm_version}-${system}-${arch}
|
||||
res=$(curl -w '%{http_code}\n' -f -L "https://prysmaticlabs.com/releases/${file}" -o "$PRYSMCTL_REAL" | ( grep 404 || true ) )
|
||||
if [[ $res == 404 ]];then
|
||||
echo "No prysmctl found for ${prysm_version},(${file}) exit"
|
||||
exit 1
|
||||
fi
|
||||
curl --silent -L "https://prysmaticlabs.com/releases/${file}.sha256" -o "${wrapper_dir}/${file}.sha256"
|
||||
curl --silent -L "https://prysmaticlabs.com/releases/${file}.sig" -o "${wrapper_dir}/${file}.sig"
|
||||
chmod +x "$PRYSMCTL_REAL"
|
||||
else
|
||||
color "37" "prysmctl is up to date."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $1 == slasher ]]; then
|
||||
color "41" "The slasher binary is no longer available. Please use the --slasher flag with your beacon node. See: https://docs.prylabs.network/docs/prysm-usage/slasher/"
|
||||
exit 1
|
||||
@@ -254,11 +273,15 @@ client-stats)
|
||||
readonly process=$CLIENT_STATS_REAL
|
||||
;;
|
||||
|
||||
prysmctl)
|
||||
readonly process=$PRYSMCTL_REAL
|
||||
;;
|
||||
|
||||
*)
|
||||
color "31" "Process '$1' is not found!"
|
||||
color "31" "Usage: ./prysm.sh PROCESS FLAGS."
|
||||
color "31" " ./prysm.sh PROCESS --download-only."
|
||||
color "31" "PROCESS can be beacon-chain, validator, or client-stats."
|
||||
color "31" "PROCESS can be beacon-chain, validator, prysmctl, or client-stats."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -23,8 +23,8 @@ func (c beaconApiValidatorClient) getAttestationData(
|
||||
|
||||
query := buildURL("/eth/v1/validator/attestation_data", params)
|
||||
produceAttestationDataResponseJson := rpcmiddleware.ProduceAttestationDataResponseJson{}
|
||||
_, err := c.jsonRestHandler.GetRestJsonResponse(ctx, query, &produceAttestationDataResponseJson)
|
||||
if err != nil {
|
||||
|
||||
if _, err := c.jsonRestHandler.GetRestJsonResponse(ctx, query, &produceAttestationDataResponseJson); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get json response")
|
||||
}
|
||||
|
||||
|
||||
@@ -53,12 +53,11 @@ func (c *beaconApiValidatorClient) getFork(ctx context.Context) (*apimiddleware.
|
||||
|
||||
stateForkResponseJson := &apimiddleware.StateForkResponseJson{}
|
||||
|
||||
_, err := c.jsonRestHandler.GetRestJsonResponse(
|
||||
if _, err := c.jsonRestHandler.GetRestJsonResponse(
|
||||
ctx,
|
||||
endpoint,
|
||||
stateForkResponseJson,
|
||||
)
|
||||
if err != nil {
|
||||
); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get json response from `%s` REST endpoint", endpoint)
|
||||
}
|
||||
|
||||
@@ -70,12 +69,11 @@ func (c *beaconApiValidatorClient) getHeaders(ctx context.Context) (*apimiddlewa
|
||||
|
||||
blockHeadersResponseJson := &apimiddleware.BlockHeadersResponseJson{}
|
||||
|
||||
_, err := c.jsonRestHandler.GetRestJsonResponse(
|
||||
if _, err := c.jsonRestHandler.GetRestJsonResponse(
|
||||
ctx,
|
||||
endpoint,
|
||||
blockHeadersResponseJson,
|
||||
)
|
||||
if err != nil {
|
||||
); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get json response from `%s` REST endpoint", endpoint)
|
||||
}
|
||||
|
||||
@@ -105,12 +103,11 @@ func (c *beaconApiValidatorClient) getSyncing(ctx context.Context) (*apimiddlewa
|
||||
|
||||
syncingResponseJson := &apimiddleware.SyncingResponseJson{}
|
||||
|
||||
_, err := c.jsonRestHandler.GetRestJsonResponse(
|
||||
if _, err := c.jsonRestHandler.GetRestJsonResponse(
|
||||
ctx,
|
||||
endpoint,
|
||||
syncingResponseJson,
|
||||
)
|
||||
if err != nil {
|
||||
); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get json response from `%s` REST endpoint", endpoint)
|
||||
}
|
||||
|
||||
|
||||
@@ -53,8 +53,7 @@ func (c beaconApiStateValidatorsProvider) GetStateValidators(
|
||||
|
||||
stateValidatorsJson := &rpcmiddleware.StateValidatorsResponseJson{}
|
||||
|
||||
_, err := c.jsonRestHandler.GetRestJsonResponse(ctx, url, stateValidatorsJson)
|
||||
if err != nil {
|
||||
if _, err := c.jsonRestHandler.GetRestJsonResponse(ctx, url, stateValidatorsJson); err != nil {
|
||||
return &rpcmiddleware.StateValidatorsResponseJson{}, errors.Wrap(err, "failed to get json response")
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
@@ -77,8 +77,13 @@ func (c *beaconApiValidatorClient) getSyncCommitteeContribution(
|
||||
}
|
||||
|
||||
blockRoot := hexutil.Encode(blockRootResponse.Root)
|
||||
url := fmt.Sprintf("/eth/v1/validator/sync_committee_contribution?slot=%d&subcommittee_index=%d&beacon_block_root=%s",
|
||||
uint64(req.Slot), req.SubnetId, blockRoot)
|
||||
|
||||
params := url.Values{}
|
||||
params.Add("slot", strconv.FormatUint(uint64(req.Slot), 10))
|
||||
params.Add("subcommittee_index", strconv.FormatUint(req.SubnetId, 10))
|
||||
params.Add("beacon_block_root", blockRoot)
|
||||
|
||||
url := buildURL("/eth/v1/validator/sync_committee_contribution", params)
|
||||
|
||||
var resp apimiddleware.ProduceSyncCommitteeContributionResponseJson
|
||||
if _, err := c.jsonRestHandler.GetRestJsonResponse(ctx, url, &resp); err != nil {
|
||||
|
||||
@@ -228,8 +228,8 @@ func TestGetSyncCommitteeContribution(t *testing.T) {
|
||||
|
||||
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
||||
ctx,
|
||||
fmt.Sprintf("/eth/v1/validator/sync_committee_contribution?slot=%d&subcommittee_index=%d&beacon_block_root=%s",
|
||||
uint64(request.Slot), request.SubnetId, blockRoot),
|
||||
fmt.Sprintf("/eth/v1/validator/sync_committee_contribution?beacon_block_root=%s&slot=%d&subcommittee_index=%d",
|
||||
blockRoot, uint64(request.Slot), request.SubnetId),
|
||||
&apimiddleware.ProduceSyncCommitteeContributionResponseJson{},
|
||||
).SetArg(
|
||||
2,
|
||||
|
||||
Reference in New Issue
Block a user