diff --git a/consensus-types/types/body.go b/consensus-types/types/body.go index 743bde8cea..d9482f1f7c 100644 --- a/consensus-types/types/body.go +++ b/consensus-types/types/body.go @@ -31,6 +31,7 @@ import ( "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" + "github.com/berachain/beacon-kit/primitives/math/log" "github.com/berachain/beacon-kit/primitives/version" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" @@ -68,9 +69,8 @@ func (b *BeaconBlockBody) Empty(forkVersion uint32) *BeaconBlockBody { } } -// BlockBodyKZGOffset returns the offset of the KZG commitments in the block -// body. -// TODO: I still feel like we need to clean this up somehow. +// BlockBodyKZGOffset returns the offset of the KZG commitments in the +// serialized block body. func BlockBodyKZGOffset( slot math.Slot, cs chain.ChainSpec, @@ -83,6 +83,40 @@ func BlockBodyKZGOffset( } } +// BlockBodyKZGPosition returns the index of the KZG Commitments in the +// block body. +func BlockBodyKZGPosition( + forkVersion uint32, +) (uint64, error) { + switch forkVersion { + case version.Deneb: + return KZGPositionDeneb, nil + default: + return 0, ErrForkVersionNotSupported + } +} + +// KZGCommitmentInclusionProofDepth as per the Ethereum 2.0 Specification: +// https://ethereum.github.io/consensus-specs/specs/deneb/p2p-interface/#preset +func KZGCommitmentInclusionProofDepth( + slot math.Slot, + cs chain.ChainSpec, +) (uint8, error) { + const maxUint8 = 255 + switch cs.ActiveForkVersionForSlot(slot) { + case version.Deneb: + sum := uint64(log.ILog2Floor(uint64(KZGMerkleIndexDeneb))) + + uint64(log.ILog2Ceil(cs.MaxBlobCommitmentsPerBlock())) + 1 + if sum > maxUint8 { + return 0, ErrInclusionProofDepthExceeded + } + //#nosec:G701 // we handle the overflow above, so this is safe + return uint8(sum), nil + default: + return 0, ErrForkVersionNotSupported + } +} + // BeaconBlockBody represents the body of a beacon block in the Deneb // chain. type BeaconBlockBody struct { diff --git a/consensus-types/types/errors.go b/consensus-types/types/errors.go index 95574e9d49..a8ab6f9109 100644 --- a/consensus-types/types/errors.go +++ b/consensus-types/types/errors.go @@ -36,6 +36,10 @@ var ( // version is not supported. ErrForkVersionNotSupported = errors.New("fork version not supported") + // ErrInclusionProofDepthExceeded is an error for when the + // KZG_COMMITMENT_INCLUSION_PROOF_DEPTH calculation overflows. + ErrInclusionProofDepthExceeded = errors.New("inclusion proof depth exceeded") + // ErrNilPayloadHeader is an error for when the payload header is nil. ErrNilPayloadHeader = errors.New("nil payload header") ) diff --git a/da/blob/factory.go b/da/blob/factory.go index a7697eb770..96ad0dc883 100644 --- a/da/blob/factory.go +++ b/da/blob/factory.go @@ -38,10 +38,6 @@ type SidecarFactory[ ] struct { // chainSpec defines the specifications of the blockchain. chainSpec ChainSpec - // kzgPosition is the position of the KZG commitment in the block. - // - // TODO: This needs to be made configurable / modular. - kzgPosition uint64 // metrics is used to collect and report factory metrics. metrics *factoryMetrics } @@ -51,15 +47,11 @@ func NewSidecarFactory[ BeaconBlockT BeaconBlock, ]( chainSpec ChainSpec, - // todo: calculate from config. - kzgPosition uint64, telemetrySink TelemetrySink, ) *SidecarFactory[BeaconBlockT] { return &SidecarFactory[BeaconBlockT]{ chainSpec: chainSpec, - // TODO: This should be configurable / modular. - kzgPosition: kzgPosition, - metrics: newFactoryMetrics(telemetrySink), + metrics: newFactoryMetrics(telemetrySink), } } @@ -106,11 +98,19 @@ func (f *SidecarFactory[BeaconBlockT]) BuildSidecars( } sigHeader := ctypes.NewSignedBeaconBlockHeader(header, signature) + // Calculate offsets + kzgPosition, err := ctypes.BlockBodyKZGPosition( + f.chainSpec.ActiveForkVersionForSlot(header.GetSlot()), + ) + if err != nil { + return nil, err + } + for i := range numBlobs { g.Go(func() error { //nolint:govet // shadow inclusionProof, err := f.BuildKZGInclusionProof( - body, math.U64(i), + body, math.U64(i), kzgPosition, ) if err != nil { return err @@ -134,6 +134,7 @@ func (f *SidecarFactory[BeaconBlockT]) BuildSidecars( func (f *SidecarFactory[_]) BuildKZGInclusionProof( body *ctypes.BeaconBlockBody, index math.U64, + kzgPosition uint64, ) ([]common.Root, error) { startTime := time.Now() defer f.metrics.measureBuildKZGInclusionProofDuration(startTime) @@ -146,7 +147,7 @@ func (f *SidecarFactory[_]) BuildKZGInclusionProof( } // Build the merkle proof for the body root. - bodyProof, err := f.BuildBlockBodyProof(body) + bodyProof, err := f.BuildBlockBodyProof(body, kzgPosition) if err != nil { return nil, err } @@ -159,6 +160,7 @@ func (f *SidecarFactory[_]) BuildKZGInclusionProof( // BuildBlockBodyProof builds a block body proof. func (f *SidecarFactory[_]) BuildBlockBodyProof( body *ctypes.BeaconBlockBody, + kzgPosition uint64, ) ([]common.Root, error) { startTime := time.Now() defer f.metrics.measureBuildBlockBodyProofDuration(startTime) @@ -170,7 +172,7 @@ func (f *SidecarFactory[_]) BuildBlockBodyProof( return nil, err } - return tree.MerkleProof(f.kzgPosition) + return tree.MerkleProof(kzgPosition) } // BuildCommitmentProof builds a commitment proof. diff --git a/da/blob/processor.go b/da/blob/processor.go index 682bebf157..364e638517 100644 --- a/da/blob/processor.go +++ b/da/blob/processor.go @@ -44,9 +44,6 @@ type Processor[ chainSpec chain.ChainSpec // verifier is responsible for verifying the blobs. verifier *verifier - // blockBodyOffsetFn is a function that calculates the block body offset - // based on the slot and chain specifications. - blockBodyOffsetFn func(math.Slot, chain.ChainSpec) (uint64, error) // metrics is used to collect and report processor metrics. metrics *processorMetrics } @@ -59,22 +56,20 @@ func NewProcessor[ logger log.Logger, chainSpec chain.ChainSpec, proofVerifier kzg.BlobProofVerifier, - blockBodyOffsetFn func(math.Slot, chain.ChainSpec) (uint64, error), telemetrySink TelemetrySink, ) *Processor[ AvailabilityStoreT, ConsensusSidecarsT, ] { - verifier := newVerifier(proofVerifier, telemetrySink) + verifier := newVerifier(proofVerifier, telemetrySink, chainSpec) return &Processor[ AvailabilityStoreT, ConsensusSidecarsT, ]{ - logger: logger, - chainSpec: chainSpec, - verifier: verifier, - blockBodyOffsetFn: blockBodyOffsetFn, - metrics: newProcessorMetrics(telemetrySink), + logger: logger, + chainSpec: chainSpec, + verifier: verifier, + metrics: newProcessorMetrics(telemetrySink), } } @@ -101,23 +96,15 @@ func (sp *Processor[ return nil } - kzgOffset, err := sp.blockBodyOffsetFn( - blkHeader.GetSlot(), sp.chainSpec, - ) - if err != nil { - return err - } - // Verify the blobs and ensure they match the local state. return sp.verifier.verifySidecars( sidecars, - kzgOffset, blkHeader, verifierFn, ) } -// slot := processes the blobs and ensures they match the local state. +// ProcessSidecars processes the blobs and ensures they match the local state. func (sp *Processor[ AvailabilityStoreT, _, ]) ProcessSidecars( diff --git a/da/blob/types.go b/da/blob/types.go index b7e07ffdec..96521c5efb 100644 --- a/da/blob/types.go +++ b/da/blob/types.go @@ -65,13 +65,17 @@ type Sidecars[SidecarT any] interface { Get(index int) SidecarT GetSidecars() []SidecarT ValidateBlockRoots() error - VerifyInclusionProofs(kzgOffset uint64) error + VerifyInclusionProofs( + kzgOffset uint64, + inclusionProofDepth uint8, + ) error } // ChainSpec represents a chain spec. type ChainSpec interface { MaxBlobCommitmentsPerBlock() uint64 DomainTypeProposer() common.DomainType + ActiveForkVersionForSlot(slot math.Slot) uint32 } // TelemetrySink is an interface for sending metrics to a telemetry backend. diff --git a/da/blob/verifier.go b/da/blob/verifier.go index 704d942193..4fcb94c629 100644 --- a/da/blob/verifier.go +++ b/da/blob/verifier.go @@ -25,6 +25,7 @@ import ( "fmt" "time" + "github.com/berachain/beacon-kit/chain-spec/chain" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/da/kzg" datypes "github.com/berachain/beacon-kit/da/types" @@ -40,16 +41,20 @@ type verifier struct { proofVerifier kzg.BlobProofVerifier // metrics collects and reports metrics related to the verification process. metrics *verifierMetrics + // chainSpec contains the chain specification + chainSpec chain.ChainSpec } // newVerifier creates a new Verifier with the given proof verifier. func newVerifier( proofVerifier kzg.BlobProofVerifier, telemetrySink TelemetrySink, + chainSpec chain.ChainSpec, ) *verifier { return &verifier{ proofVerifier: proofVerifier, metrics: newVerifierMetrics(telemetrySink), + chainSpec: chainSpec, } } @@ -57,7 +62,6 @@ func newVerifier( // as the KZG proofs. func (bv *verifier) verifySidecars( sidecars datypes.BlobSidecars, - kzgOffset uint64, blkHeader *ctypes.BeaconBlockHeader, verifierFn func( blkHeader *ctypes.BeaconBlockHeader, @@ -71,19 +75,22 @@ func (bv *verifier) verifySidecars( g, _ := errgroup.WithContext(context.Background()) - // check that sidecars block headers match with header of the - // corresponding block + // Verifying that sidecars block headers match with header of the + // corresponding block concurrently. for i, s := range sidecars.GetSidecars() { - if !s.GetSignedBeaconBlockHeader().GetHeader().Equals(blkHeader) { - return fmt.Errorf("unequal block header: idx: %d", i) - } g.Go(func() error { var sigHeader = s.GetSignedBeaconBlockHeader() - err := verifierFn( + + // Check BlobSidecar.Header equality with BeaconBlockHeader + if !sigHeader.GetHeader().Equals(blkHeader) { + return fmt.Errorf("unequal block header: idx: %d", i) + } + + // Verify BeaconBlockHeader with signature + if err := verifierFn( blkHeader, sigHeader.GetSignature(), - ) - if err != nil { + ); err != nil { return err } return nil @@ -92,11 +99,7 @@ func (bv *verifier) verifySidecars( // Verify the inclusion proofs on the blobs concurrently. g.Go(func() error { - // TODO: KZGOffset needs to be configurable and not - // passed in. - return bv.verifyInclusionProofs( - sidecars, kzgOffset, - ) + return bv.verifyInclusionProofs(sidecars, blkHeader.GetSlot()) }) // Verify the KZG proofs on the blobs concurrently. @@ -110,13 +113,30 @@ func (bv *verifier) verifySidecars( func (bv *verifier) verifyInclusionProofs( scs datypes.BlobSidecars, - kzgOffset uint64, + slot math.Slot, ) error { startTime := time.Now() defer bv.metrics.measureVerifyInclusionProofsDuration( startTime, math.U64(scs.Len()), ) - return scs.VerifyInclusionProofs(kzgOffset) + + // Grab the KZG offset for the fork version. + kzgOffset, err := ctypes.BlockBodyKZGOffset( + slot, bv.chainSpec, + ) + if err != nil { + return err + } + + // Grab the inclusion proof depth for the fork version. + inclusionProofDepth, err := ctypes.KZGCommitmentInclusionProofDepth( + slot, bv.chainSpec, + ) + if err != nil { + return err + } + + return scs.VerifyInclusionProofs(kzgOffset, inclusionProofDepth) } // verifyKZGProofs verifies the sidecars. diff --git a/da/types/sidecar.go b/da/types/sidecar.go index dbda4699a0..7f6d16fa21 100644 --- a/da/types/sidecar.go +++ b/da/types/sidecar.go @@ -72,15 +72,13 @@ func BuildBlobSidecar( // blob in the beacon body. func (b *BlobSidecar) HasValidInclusionProof( kzgOffset uint64, + inclusionProofDepth uint8, ) bool { header := b.GetSignedBeaconBlockHeader().GetHeader() return header != nil && merkle.IsValidMerkleBranch( b.KzgCommitment.HashTreeRoot(), b.InclusionProof, - //#nosec:G701 // safe. - uint8( - len(b.InclusionProof), - ), // TODO: use KZG_INCLUSION_PROOF_DEPTH calculation. + inclusionProofDepth, kzgOffset+b.Index, header.BodyRoot, ) diff --git a/da/types/sidecar_test.go b/da/types/sidecar_test.go index 7223642daf..a4cf2d13e9 100644 --- a/da/types/sidecar_test.go +++ b/da/types/sidecar_test.go @@ -80,6 +80,8 @@ func TestSidecarMarshalling(t *testing.T) { } func TestHasValidInclusionProof(t *testing.T) { + // Equates to KZG_COMMITMENT_INCLUSION_PROOF_DEPTH + const inclusionProofDepth = 17 tests := []struct { name string sidecar func(t *testing.T) *types.BlobSidecar @@ -137,7 +139,7 @@ func TestHasValidInclusionProof(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sidecar := tt.sidecar(t) - result := sidecar.HasValidInclusionProof(tt.kzgOffset) + result := sidecar.HasValidInclusionProof(tt.kzgOffset, inclusionProofDepth) require.Equal(t, tt.expectedResult, result, "Result should match expected value") }) diff --git a/da/types/sidecars.go b/da/types/sidecars.go index 6178c9ccde..71d2b728cc 100644 --- a/da/types/sidecars.go +++ b/da/types/sidecars.go @@ -71,6 +71,7 @@ func (bs *BlobSidecars) ValidateBlockRoots() error { // VerifyInclusionProofs verifies the inclusion proofs for all sidecars. func (bs *BlobSidecars) VerifyInclusionProofs( kzgOffset uint64, + inclusionProofDepth uint8, ) error { return errors.Join(iter.Map( *bs, @@ -81,7 +82,7 @@ func (bs *BlobSidecars) VerifyInclusionProofs( } // Verify the KZG inclusion proof. - if !sc.HasValidInclusionProof(kzgOffset) { + if !sc.HasValidInclusionProof(kzgOffset, inclusionProofDepth) { return ErrInvalidInclusionProof } return nil diff --git a/execution/client/errors.go b/execution/client/errors.go index 0fb089d4fd..eb30fdc44b 100644 --- a/execution/client/errors.go +++ b/execution/client/errors.go @@ -57,6 +57,11 @@ var ( func (s *EngineClient) handleRPCError( err error, ) error { + if err == nil { + //nolint:nilerr // appease nilaway + return err + } + // Check for timeout errors. if http.IsTimeoutError(err) { s.metrics.incrementHTTPTimeoutCounter() diff --git a/node-core/components/blobs.go b/node-core/components/blobs.go index c30f7b226b..ba025e044a 100644 --- a/node-core/components/blobs.go +++ b/node-core/components/blobs.go @@ -25,7 +25,6 @@ import ( "github.com/berachain/beacon-kit/chain-spec/chain" "github.com/berachain/beacon-kit/cli/flags" "github.com/berachain/beacon-kit/config" - "github.com/berachain/beacon-kit/consensus-types/types" dablob "github.com/berachain/beacon-kit/da/blob" "github.com/berachain/beacon-kit/da/kzg" "github.com/berachain/beacon-kit/log" @@ -84,7 +83,6 @@ func ProvideBlobProcessor[ in.Logger.With("service", "blob-processor"), in.ChainSpec, in.BlobProofVerifier, - types.BlockBodyKZGOffset, in.TelemetrySink, ) } diff --git a/node-core/components/sidecars.go b/node-core/components/sidecars.go index 998c3ee809..d4d98bf5ea 100644 --- a/node-core/components/sidecars.go +++ b/node-core/components/sidecars.go @@ -23,7 +23,6 @@ package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/chain-spec/chain" - "github.com/berachain/beacon-kit/consensus-types/types" dablob "github.com/berachain/beacon-kit/da/blob" "github.com/berachain/beacon-kit/node-core/components/metrics" ) @@ -39,7 +38,6 @@ func ProvideSidecarFactory[ ](in SidecarFactoryInput) *dablob.SidecarFactory[BeaconBlockT] { return dablob.NewSidecarFactory[BeaconBlockT]( in.ChainSpec, - types.KZGPositionDeneb, in.TelemetrySink, ) }