Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
calbera committed Dec 18, 2024
1 parent 840d6dc commit bc99c1e
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 63 deletions.
6 changes: 4 additions & 2 deletions beacon/blockchain/deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (s *Service[
func (s *Service[
_, _, _, _, _, _, _, _, _,
]) fetchAndStoreDeposits(ctx context.Context, blockNum math.U64) {
deposits, _, err := s.depositContract.ReadDeposits(ctx, blockNum)
deposits, indexes, executionHash, err := s.depositContract.ReadDeposits(ctx, blockNum)
if err != nil {
s.logger.Error("Failed to read deposits", "error", err)
s.metrics.sink.IncrementCounter(
Expand All @@ -68,7 +68,9 @@ func (s *Service[
)
}

if err = s.depositStore.EnqueueDepositDatas(deposits); err != nil {
if err = s.depositStore.EnqueueDepositDatas(
deposits, indexes, executionHash, blockNum,
); err != nil {
s.logger.Error("Failed to store deposits", "error", err)
s.failedBlocksMu.Lock()
s.failedBlocks[blockNum] = struct{}{}
Expand Down
11 changes: 10 additions & 1 deletion beacon/blockchain/init_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,17 @@ func (s *Service[

// Store the genesis deposits.
genesisDepositDatas := genesisData.GetDepositDatas()
genesisDepositIndexes := make([]uint64, len(genesisDepositDatas))
for i := range genesisDepositDatas {
genesisDepositIndexes[i] = uint64(i)
}
genesisExecutionPayloadHeader := genesisData.GetExecutionPayloadHeader()
if err := s.depositStore.EnqueueDepositDatas(genesisDepositDatas); err != nil {
if err := s.depositStore.EnqueueDepositDatas(
genesisDepositDatas,
genesisDepositIndexes,
genesisExecutionPayloadHeader.BlockHash,
genesisExecutionPayloadHeader.Number,
); err != nil {
s.logger.Error("Failed to store genesis deposits", "error", err)
return nil, err
}
Expand Down
2 changes: 2 additions & 0 deletions beacon/blockchain/pruning.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ func (s *Service[
}

// Delete the deposits of the block previous to the one we just stored.
// TODO: remove this here. Pruning should be invoked when we know for sure that
// the deposits were included in a block.
finalizedEthBlock := beaconBlk.GetBody().GetExecutionPayload().Number.Unwrap()
height := finalizedEthBlock - s.chainSpec.Eth1FollowDistance() - 1
if err = s.depositStore.Prune(height); err != nil {
Expand Down
14 changes: 8 additions & 6 deletions execution/deposit/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func NewWrappedDepositContract(
// ReadDeposits reads deposits from the deposit contract.
func (dc *WrappedDepositContract) ReadDeposits(
ctx context.Context, blkNum math.U64,
) ([]*ctypes.DepositData, common.ExecutionHash, error) {
) ([]*ctypes.DepositData, []uint64, common.ExecutionHash, error) {
logs, err := dc.FilterDeposit(
&bind.FilterOpts{
Context: ctx,
Expand All @@ -76,12 +76,13 @@ func (dc *WrappedDepositContract) ReadDeposits(
},
)
if err != nil {
return nil, common.ExecutionHash{}, err
return nil, nil, common.ExecutionHash{}, err
}

var (
blockNumStr = blkNum.Base10()
deposits = make([]*ctypes.DepositData, 0)
indexes = make([]uint64, 0)
blockHash common.ExecutionHash
)
for logs.Next() {
Expand All @@ -92,20 +93,21 @@ func (dc *WrappedDepositContract) ReadDeposits(
)
pubKey, err = bytes.ToBytes48(logs.Event.Pubkey)
if err != nil {
return nil, blockHash, errors.Wrap(err, "failed reading pub key")
return nil, nil, blockHash, errors.Wrap(err, "failed reading pub key")
}
cred, err = bytes.ToBytes32(logs.Event.Credentials)
if err != nil {
return nil, blockHash, errors.Wrap(err, "failed reading credentials")
return nil, nil, blockHash, errors.Wrap(err, "failed reading credentials")
}
sign, err = bytes.ToBytes96(logs.Event.Signature)
if err != nil {
return nil, blockHash, errors.Wrap(err, "failed reading signature")
return nil, nil, blockHash, errors.Wrap(err, "failed reading signature")
}

deposits = append(deposits, ctypes.NewDepositData(
pubKey, ctypes.WithdrawalCredentials(cred), math.U64(logs.Event.Amount), sign,
))
indexes = append(indexes, logs.Event.Index)

if blockHash == (common.ExecutionHash{}) {
blockHash = common.ExecutionHash(logs.Event.Raw.BlockHash)
Expand All @@ -117,5 +119,5 @@ func (dc *WrappedDepositContract) ReadDeposits(
)
}

return deposits, blockHash, nil
return deposits, indexes, blockHash, nil
}
11 changes: 8 additions & 3 deletions execution/deposit/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,20 @@ type Contract interface {
// ReadDeposits reads deposits from the deposit contract.
ReadDeposits(
ctx context.Context, blockNumber math.U64,
) ([]*ctypes.DepositData, common.ExecutionHash, error)
) ([]*ctypes.DepositData, []uint64, common.ExecutionHash, error)
}

// Store defines the interface for managing deposit operations.
type Store interface {
// Prune prunes the deposit store of the given height.
Prune(height uint64) error
// EnqueueDepositDatas adds a list of deposits to the deposit store.
EnqueueDepositDatas(deposits []*ctypes.DepositData) error
// EnqueueDepositDatas adds a list of deposits to the deposit store for a given EL block.
EnqueueDepositDatas(
depositDatas []*ctypes.DepositData,
indexes []uint64,
executionHash common.ExecutionHash,
executionNumber math.U64,
) error
// GetDepositsByIndex gets a list of deposits from the deposit store.
GetDepositsByIndex(startIndex, numView uint64) (ctypes.Deposits, common.Root, error)
}
9 changes: 7 additions & 2 deletions node-api/backend/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,13 @@ type DepositStore interface {
GetDepositsByIndex(startIndex uint64, numView uint64) (ctypes.Deposits, common.Root, error)
// Prune prunes the deposit store of the given height.
Prune(height uint64) error
// EnqueueDepositDatas adds a list of deposits to the deposit store.
EnqueueDepositDatas(deposits []*ctypes.DepositData) error
// EnqueueDepositDatas adds a list of deposits to the deposit store for a given EL block.
EnqueueDepositDatas(
depositDatas []*ctypes.DepositData,
indexes []uint64,
executionHash common.ExecutionHash,
executionNumber math.U64,
) error
}

// Node is the interface for a node.
Expand Down
11 changes: 8 additions & 3 deletions node-core/components/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,13 @@ type (
GetDepositsByIndex(startIndex, numView uint64) (ctypes.Deposits, common.Root, error)
// Prune prunes the deposit store of the given height.
Prune(height uint64) error
// EnqueueDepositDatas adds a list of deposits to the deposit store.
EnqueueDepositDatas(deposits []*ctypes.DepositData) error
// EnqueueDepositDatas adds a list of deposits to the deposit store for a given EL block.
EnqueueDepositDatas(
depositDatas []*ctypes.DepositData,
indexes []uint64,
executionHash common.ExecutionHash,
executionNumber math.U64,
) error
}

// Genesis is the interface for the genesis.
Expand Down Expand Up @@ -456,7 +461,7 @@ type (
// InitializePreminedBeaconStateFromEth1 initializes the premined beacon
// state from the eth1 deposits.
InitializePreminedBeaconStateFromEth1(
BeaconStateT, ctypes.Deposits, common.Root,
BeaconStateT, ctypes.Deposits, common.Root,
*ctypes.ExecutionPayloadHeader, common.Version,
) (transition.ValidatorUpdates, error)
// ProcessSlot processes the slot.
Expand Down
7 changes: 7 additions & 0 deletions state-transition/core/state_processor_staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ func (sp *StateProcessor[

// Verify that the provided deposit count is consistent with our local view of the
// deposit tree.
blockDeposits := blk.GetBody().GetDeposits()
if len(blockDeposits) != len(localDeposits) {
return errors.Wrapf(
ErrDepositCountMismatch, "expected: %d, got: %d",
len(localDeposits), len(blockDeposits),
)
}
if uint64(len(localDeposits)) != min(
sp.cs.MaxDepositsPerBlock(), eth1Data.DepositCount.Unwrap()-depositIndex,
) {
Expand Down
29 changes: 16 additions & 13 deletions storage/deposit/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,24 @@ import (
"github.com/berachain/beacon-kit/primitives/math"
)

// Block holds the necessary information of pending deposits in a block.
type Block struct {
// the deposits included in the block.
deposits ctypes.Deposits
// block holds the necessary information of pending deposits in a block.
type block struct {
// the number of the finalized execution block, provided by EL.
executionNumber math.U64

// the index of the last deposit in the block.
lastDepositIndex uint64
// the hash of the finalized execution block, provided by EL.
executionHash common.ExecutionHash

// the root of the deposit tree at the end of the block (i.e. after all deposits
// from this block are inserted in the tree).
root common.Root
// the deposits (with the proofs) included in the block, determined by CL merkle tree.
deposits ctypes.Deposits

// the number of the finalized execution block.
executionNumber math.U64
// the root of the deposit tree at the end of processing each deposit in
// the tree, determined by CL merkle tree.
root []common.Root
}

// the hash of the finalized execution block.
executionHash common.ExecutionHash
// retrievalInfo holds the necessary information to retrieve deposits for the next CL
// block request.
type retrievalInfo struct {
// the index of the block that should be searched from.
}
78 changes: 45 additions & 33 deletions storage/deposit/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
ctypes "github.com/berachain/beacon-kit/consensus-types/types"
"github.com/berachain/beacon-kit/errors"
"github.com/berachain/beacon-kit/primitives/common"
"github.com/berachain/beacon-kit/primitives/math"
"github.com/berachain/beacon-kit/storage/deposit/merkle"
)

Expand All @@ -37,7 +38,10 @@ type Store struct {

// pendingDeposits holds the pending deposits for blocks that have yet to be
// processed by the CL.
pendingDeposits map[uint64]*Block
pendingDeposits []*Block

Check failure on line 41 in storage/deposit/store.go

View workflow job for this annotation

GitHub Actions / build

undefined: Block

Check failure on line 41 in storage/deposit/store.go

View workflow job for this annotation

GitHub Actions / nilaway

undefined: Block

Check failure on line 41 in storage/deposit/store.go

View workflow job for this annotation

GitHub Actions / test-unit-bench

undefined: Block

// lastUsedIndex is the index of the last deposit included in CL blocks.
lastUsedIndex uint64

// mu protects store for concurrent access.
mu sync.RWMutex
Expand All @@ -47,7 +51,7 @@ type Store struct {
func NewStore() *Store {
res := &Store{
tree: merkle.NewDepositTree(),
pendingDeposits: make(map[uint64]*Block),
pendingDeposits: make([]*Block, 0),

Check failure on line 54 in storage/deposit/store.go

View workflow job for this annotation

GitHub Actions / build

undefined: Block

Check failure on line 54 in storage/deposit/store.go

View workflow job for this annotation

GitHub Actions / nilaway

undefined: Block

Check failure on line 54 in storage/deposit/store.go

View workflow job for this annotation

GitHub Actions / test-unit-bench

undefined: Block
}
return res
}
Expand Down Expand Up @@ -91,55 +95,63 @@ func (s *Store) GetDepositsByIndex(
return deposits, depTreeRoot, nil
}

// EnqueueDepositDatas pushes multiple deposits to the queue.
// EnqueueDepositDatas pushes multiple deposits to the queue for a given EL block.
//
// TODO: ensure that in-order is maintained. i.e. ignore any deposits we've already seen.
func (s *Store) EnqueueDepositDatas(depositDatas []*ctypes.DepositData) error {
func (s *Store) EnqueueDepositDatas(
depositDatas []*ctypes.DepositData,
indexes []uint64,
executionHash common.ExecutionHash,
executionNumber math.U64,
) error {
s.mu.Lock()
defer s.mu.Unlock()

for _, depositData := range depositDatas {
// idx := depositData.GetIndex().Unwrap()

// Build the deposits information for the block while inserting into the deposit tree.
block := &Block{

Check failure on line 111 in storage/deposit/store.go

View workflow job for this annotation

GitHub Actions / build

undefined: Block

Check failure on line 111 in storage/deposit/store.go

View workflow job for this annotation

GitHub Actions / nilaway

undefined: Block

Check failure on line 111 in storage/deposit/store.go

View workflow job for this annotation

GitHub Actions / test-unit-bench

undefined: Block
executionHash: executionHash,
executionNumber: executionNumber,
deposits: make(ctypes.Deposits, len(depositDatas)),
root: make([]common.Root, len(depositDatas)),
}
for i, depositData := range depositDatas {
if err := s.tree.Insert(depositData.HashTreeRoot()); err != nil {
return errors.Wrapf(err, "failed to insert deposit %d into merkle tree", 0)
return errors.Wrapf(err,
"failed to insert deposit %d into merkle tree, execution number: %d",
indexes[i], executionNumber,
)
}

// proof, err := s.tree.MerkleProof(0)
// if err != nil {
// return errors.Wrapf(err, "failed to get merkle proof for deposit %d", 0)
// }
// deposit := ctypes.NewDeposit(proof, depositData)
// if err := s.store.Set(context.TODO(), idx, deposit); err != nil {
// return errors.Wrapf(err, "failed to set deposit %d in KVStore", idx)
// }
proof, err := s.tree.MerkleProof(indexes[i])
if err != nil {
return errors.Wrapf(err,
"failed to get merkle proof for deposit %d, execution number: %d",
indexes[i], executionNumber,
)
}
block.deposits[i] = ctypes.NewDeposit(proof, depositData)
block.root[i] = s.tree.HashTreeRoot()
}
s.pendingDeposits = append(s.pendingDeposits, block)

// s.endOfBlockDepositTreeRoots[idx] = s.tree.HashTreeRoot()
// Finalize the block's deposits in the tree. Error returned here means the
// EIP 4881 merkle library is broken. // TODO: could move this to when we delete block.
lastDepositIndex := indexes[len(indexes)-1]
if err := s.tree.Finalize(lastDepositIndex, executionHash, executionNumber); err != nil {
return errors.Wrapf(
err, "failed to finalize deposits in tree for block %d, index %d",
executionNumber, lastDepositIndex,
)
}

return nil
}

// Prune removes the deposits from the given height.
// NO-OP for now since the pruning call is not at the right time.
func (s *Store) Prune(height uint64) error {
s.mu.Lock()
defer s.mu.Unlock()

block, ok := s.pendingDeposits[height]
if !ok {
return nil
}

// Remove the block from the pending deposits.
delete(s.pendingDeposits, height)

// Finalize the block's deposits in the tree. Error returned here means the
// EIP 4881 merkle library is broken.
if err := s.tree.Finalize(
block.lastDepositIndex, block.executionHash, block.executionNumber,
); err != nil {
return errors.Wrapf(err, "failed to finalize deposits in tree for block %d", height)
}

return nil
}

0 comments on commit bc99c1e

Please sign in to comment.