mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-05-02 03:02:54 -04:00
* PeerDAS: Implement sync * Fix Potuz's comment. * Fix Potuz's comment. * Fix Potuz's comment. * Fix Potuz's comment. * Fix Potuz's comment. * Implement `TestFetchDataColumnSidecarsFromPeers`. * Implement `TestSelectPeers`. * Fix James' comment. * Fix flakiness in `TestSelectPeers`. * Revert "Fix Potuz's comment." This reverts commitc45230b455. * Revert "Fix James' comment." This reverts commita3f919205a. * `selectPeers`: Avoid map with key but empty value. * Fix Potuz's comment. * Add DataColumnStorage and SubscribeAllDataSubnets flag. * getBlobsV2: retry if reconstruction isnt successful * test: engine client and sync package, metrics * lint: fmt and log capitalisation * lint: return error when it is not nil * config: make retry interval configurable * sidecar: recover function and different context for retrying * lint: remove unused field * beacon: default retry interval * reconstruct: load once, correctly deliver the result to all waiting goroutines * reconstruct: simplify multi goroutine case and avoid race condition * engine: remove isDataAlreadyAvailable function * sync: no goroutine, getblobsv2 in absence of block as well, wrap error * exec: hardcode retry interval * da: non blocking checks * sync: remove unwanted checks * execution: fix test * execution: retry atomicity test * da: updated IsDataAvailable * sync: remove unwanted tests * bazel: bazel run //:gazelle -- fix * blockchain: fix CustodyGroupCount return * lint: formatting * lint: lint and use unused metrics * execution: retry logic inside ReconstructDataColumnSidecars itself * lint: format * execution: ensure the retry actually happens when it needs to * execution: ensure single responsibility, execution should not do DA check * sync: don't call ReconstructDataColumnSidecars if not required * blockchain: move IsDataAvailable interface to blockchain package * execution: make reconstructSingleflight part of the service struct * blockchain: cleaner DA check * lint: formatting and remove confusing comment * sync: fix lint, test and add extra test for when data is actually not available * sync: new appropriate mock service * execution: edge case - delete activeRetries on success * execution: use service context instead of function's for retry * blockchain: get variable samplesPerSlot only when required * remove redundant function and fix name * fix test * fix more tests * put samplesPerSlot at appropriate place * tidy up IsDataAvailable * correct bad merge * fix bad merge * remove redundant flag option * refactor to deduplicate sidecar construction code * - Add godocs - Rename some functions to be closer to the spec - Add err in return of commitments * Replace mutating public method (but only internally used) `Populate` but private not mutating method `extract`. * Implement a unique `processDataColumnSidecarsFromExecution` instead 2 separate functions from block and from sidecar. * `ReceiveBlock`: Wrap errors. * Remove useless tests. * `ConstructionPopulator`: Add tests. * Fix tests * Move functions to be consistent with blobs. * `fetchCellsAndProofsFromExecution`: Avoid useless flattening. * `processDataColumnSidecarsFromExecution`: Stop using DB cache. --------- Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com> Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
176 lines
6.3 KiB
Go
176 lines
6.3 KiB
Go
package testing
|
|
|
|
import (
|
|
"context"
|
|
"math/big"
|
|
|
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/peerdas"
|
|
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
|
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
|
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
|
payloadattribute "github.com/OffchainLabs/prysm/v6/consensus-types/payload-attribute"
|
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
|
pb "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/holiman/uint256"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// EngineClient --
|
|
type EngineClient struct {
|
|
NewPayloadResp []byte
|
|
PayloadIDBytes *pb.PayloadIDBytes
|
|
ForkChoiceUpdatedResp []byte
|
|
ExecutionBlock *pb.ExecutionBlock
|
|
Err error
|
|
ErrLatestExecBlock error
|
|
ErrExecBlockByHash error
|
|
ErrForkchoiceUpdated error
|
|
ErrNewPayload error
|
|
ExecutionPayloadByBlockHash map[[32]byte]*pb.ExecutionPayload
|
|
BlockByHashMap map[[32]byte]*pb.ExecutionBlock
|
|
NumReconstructedPayloads uint64
|
|
TerminalBlockHash []byte
|
|
TerminalBlockHashExists bool
|
|
OverrideValidHash [32]byte
|
|
GetPayloadResponse *blocks.GetPayloadResponse
|
|
ErrGetPayload error
|
|
BlobSidecars []blocks.VerifiedROBlob
|
|
ErrorBlobSidecars error
|
|
DataColumnSidecars []blocks.VerifiedRODataColumn
|
|
ErrorDataColumnSidecars error
|
|
}
|
|
|
|
// NewPayload --
|
|
func (e *EngineClient) NewPayload(_ context.Context, _ interfaces.ExecutionData, _ []common.Hash, _ *common.Hash, _ *pb.ExecutionRequests) ([]byte, error) {
|
|
return e.NewPayloadResp, e.ErrNewPayload
|
|
}
|
|
|
|
// ForkchoiceUpdated --
|
|
func (e *EngineClient) ForkchoiceUpdated(
|
|
_ context.Context, fcs *pb.ForkchoiceState, _ payloadattribute.Attributer,
|
|
) (*pb.PayloadIDBytes, []byte, error) {
|
|
if e.OverrideValidHash != [32]byte{} && bytesutil.ToBytes32(fcs.HeadBlockHash) == e.OverrideValidHash {
|
|
return e.PayloadIDBytes, e.ForkChoiceUpdatedResp, nil
|
|
}
|
|
return e.PayloadIDBytes, e.ForkChoiceUpdatedResp, e.ErrForkchoiceUpdated
|
|
}
|
|
|
|
// GetPayload --
|
|
func (e *EngineClient) GetPayload(_ context.Context, _ [8]byte, _ primitives.Slot) (*blocks.GetPayloadResponse, error) {
|
|
return e.GetPayloadResponse, e.ErrGetPayload
|
|
}
|
|
|
|
// LatestExecutionBlock --
|
|
func (e *EngineClient) LatestExecutionBlock(_ context.Context) (*pb.ExecutionBlock, error) {
|
|
return e.ExecutionBlock, e.ErrLatestExecBlock
|
|
}
|
|
|
|
// ExecutionBlockByHash --
|
|
func (e *EngineClient) ExecutionBlockByHash(_ context.Context, h common.Hash, _ bool) (*pb.ExecutionBlock, error) {
|
|
b, ok := e.BlockByHashMap[h]
|
|
if !ok {
|
|
return nil, errors.New("block not found")
|
|
}
|
|
return b, e.ErrExecBlockByHash
|
|
}
|
|
|
|
// ReconstructFullBlock --
|
|
func (e *EngineClient) ReconstructFullBlock(
|
|
_ context.Context, blindedBlock interfaces.ReadOnlySignedBeaconBlock,
|
|
) (interfaces.SignedBeaconBlock, error) {
|
|
if !blindedBlock.Block().IsBlinded() {
|
|
return nil, errors.New("block must be blinded")
|
|
}
|
|
header, err := blindedBlock.Block().Body().Execution()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
payload, ok := e.ExecutionPayloadByBlockHash[bytesutil.ToBytes32(header.BlockHash())]
|
|
if !ok {
|
|
return nil, errors.New("block not found")
|
|
}
|
|
e.NumReconstructedPayloads++
|
|
return blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload)
|
|
}
|
|
|
|
// ReconstructFullBellatrixBlockBatch --
|
|
func (e *EngineClient) ReconstructFullBellatrixBlockBatch(
|
|
ctx context.Context, blindedBlocks []interfaces.ReadOnlySignedBeaconBlock,
|
|
) ([]interfaces.SignedBeaconBlock, error) {
|
|
fullBlocks := make([]interfaces.SignedBeaconBlock, 0, len(blindedBlocks))
|
|
for _, b := range blindedBlocks {
|
|
newBlock, err := e.ReconstructFullBlock(ctx, b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
fullBlocks = append(fullBlocks, newBlock)
|
|
}
|
|
return fullBlocks, nil
|
|
}
|
|
|
|
// ReconstructBlobSidecars is a mock implementation of the ReconstructBlobSidecars method.
|
|
func (e *EngineClient) ReconstructBlobSidecars(context.Context, interfaces.ReadOnlySignedBeaconBlock, [fieldparams.RootLength]byte, func(uint64) bool) ([]blocks.VerifiedROBlob, error) {
|
|
return e.BlobSidecars, e.ErrorBlobSidecars
|
|
}
|
|
|
|
// ConstructDataColumnSidecars is a mock implementation of the ConstructDataColumnSidecars method.
|
|
func (e *EngineClient) ConstructDataColumnSidecars(context.Context, peerdas.ConstructionPopulator) ([]blocks.VerifiedRODataColumn, error) {
|
|
return e.DataColumnSidecars, e.ErrorDataColumnSidecars
|
|
}
|
|
|
|
// GetTerminalBlockHash --
|
|
func (e *EngineClient) GetTerminalBlockHash(ctx context.Context, transitionTime uint64) ([]byte, bool, error) {
|
|
ttd := new(big.Int)
|
|
ttd.SetString(params.BeaconConfig().TerminalTotalDifficulty, 10)
|
|
terminalTotalDifficulty, overflows := uint256.FromBig(ttd)
|
|
if overflows {
|
|
return nil, false, errors.New("could not convert terminal total difficulty to uint256")
|
|
}
|
|
blk, err := e.LatestExecutionBlock(ctx)
|
|
if err != nil {
|
|
return nil, false, errors.Wrap(err, "could not get latest execution block")
|
|
}
|
|
if blk == nil {
|
|
return nil, false, errors.New("latest execution block is nil")
|
|
}
|
|
|
|
for {
|
|
b, err := hexutil.DecodeBig(blk.TotalDifficulty)
|
|
if err != nil {
|
|
return nil, false, errors.Wrap(err, "could not convert total difficulty to uint256")
|
|
}
|
|
currentTotalDifficulty, _ := uint256.FromBig(b)
|
|
blockReachedTTD := currentTotalDifficulty.Cmp(terminalTotalDifficulty) >= 0
|
|
|
|
parentHash := blk.ParentHash
|
|
if parentHash == params.BeaconConfig().ZeroHash {
|
|
return nil, false, nil
|
|
}
|
|
parentBlk, err := e.ExecutionBlockByHash(ctx, parentHash, false /* with txs */)
|
|
if err != nil {
|
|
return nil, false, errors.Wrap(err, "could not get parent execution block")
|
|
}
|
|
if blockReachedTTD {
|
|
b, err := hexutil.DecodeBig(parentBlk.TotalDifficulty)
|
|
if err != nil {
|
|
return nil, false, errors.Wrap(err, "could not convert total difficulty to uint256")
|
|
}
|
|
parentTotalDifficulty, _ := uint256.FromBig(b)
|
|
parentReachedTTD := parentTotalDifficulty.Cmp(terminalTotalDifficulty) >= 0
|
|
if blk.Time >= transitionTime {
|
|
return nil, false, nil
|
|
}
|
|
if !parentReachedTTD {
|
|
return blk.Hash[:], true, nil
|
|
}
|
|
} else {
|
|
return nil, false, nil
|
|
}
|
|
blk = parentBlk
|
|
}
|
|
}
|