mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 07:03:58 -05:00
EIP-4881: Spec implementation (#11720)
* Initial spec rewrite * Finish adding merkle tree implementation * Last bits * Move reverse function * Add comments * Add deposit tree snapshot * Add deposit tree * Add comments + cleanup * Fixes * Add missing errors * Small fixes * Add unhandled error * Cleanup * Fix unsafe file.Close * Add missing comments * Small fixes * Address some of deepSource' compaints * Add depositCount check * Add finalizedDeposit check * Replace pointer magic with copy() * Add test for slice reversal * add back bytes method * Add package level description * Remove zerohash gen and add additional checks * Add additional comments * Small lint fixes * Forgot an error * Small fixes * Move Uint64ToBytesLittleEndian32 + test * Fix uint subtraction issue * Move mixInLength below error handling * Fix * Fix deposit root --------- Co-authored-by: rauljordan <raul@prysmaticlabs.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
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},
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user