Skip to content

Commit

Permalink
refactor: reintroduce the blobstream module
Browse files Browse the repository at this point in the history
  • Loading branch information
rach-id committed Jul 19, 2024
1 parent fbc63b6 commit da27e8a
Show file tree
Hide file tree
Showing 12 changed files with 422 additions and 320 deletions.
48 changes: 48 additions & 0 deletions nodebuilder/blobstream/blobstream.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package blobstream

import (
"context"
)

var _ Module = (*API)(nil)

// Module defines the API related to interacting with the data root tuples proofs
//
//go:generate mockgen -destination=mocks/api.go -package=mocks . Module
type Module interface {
// GetDataRootTupleRoot collects the data roots over a provided ordered range of blocks,
// and then creates a new Merkle root of those data roots. The range is end exclusive.
// It's in the header module because it only needs access to the headers to generate the proof.
GetDataRootTupleRoot(ctx context.Context, start, end uint64) (*DataRootTupleRoot, error)

// GetDataRootTupleInclusionProof creates an inclusion proof, for the data root tuple of block
// height `height`, in the set of blocks defined by `start` and `end`. The range
// is end exclusive.
// It's in the header module because it only needs access to the headers to generate the proof.
GetDataRootTupleInclusionProof(
ctx context.Context,
height, start, end uint64,
) (*DataRootTupleInclusionProof, error)
}

// API is a wrapper around the Module for RPC.
type API struct {
Internal struct {
GetDataRootTupleRoot func(ctx context.Context, start, end uint64) (*DataRootTupleRoot, error) `perm:"read"`
GetDataRootTupleInclusionProof func(
ctx context.Context,
height, start, end uint64,
) (*DataRootTupleInclusionProof, error) `perm:"read"`
}
}

func (api *API) GetDataRootTupleRoot(ctx context.Context, start, end uint64) (*DataRootTupleRoot, error) {
return api.Internal.GetDataRootTupleRoot(ctx, start, end)
}

func (api *API) GetDataRootTupleInclusionProof(
ctx context.Context,
height, start, end uint64,
) (*DataRootTupleInclusionProof, error) {
return api.Internal.GetDataRootTupleInclusionProof(ctx, height, start, end)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package header
package blobstream

import (
"context"
Expand All @@ -8,6 +8,8 @@ import (

"github.com/tendermint/tendermint/crypto/merkle"
"github.com/tendermint/tendermint/libs/bytes"

"github.com/celestiaorg/celestia-node/nodebuilder/header"
)

// DataRootTupleRoot is the root of the merkle tree created
Expand Down Expand Up @@ -102,7 +104,7 @@ const dataRootTupleRootBlocksLimit = 10_000 // ~33 hours of blocks assuming 12-s
// the defined set of heights by ensuring the range exists in the chain.
func (s *Service) validateDataRootTupleRootRange(ctx context.Context, start, end uint64) error {
if start == 0 {
return ErrHeightZero
return header.ErrHeightZero
}
if start >= end {
return fmt.Errorf("end block is smaller or equal to the start block")
Expand All @@ -113,7 +115,7 @@ func (s *Service) validateDataRootTupleRootRange(ctx context.Context, start, end
return fmt.Errorf("the query exceeds the limit of allowed blocks %d", dataRootTupleRootBlocksLimit)
}

currentLocalHeader, err := s.LocalHead(ctx)
currentLocalHeader, err := s.headerServ.LocalHead(ctx)
if err != nil {
return fmt.Errorf("couldn't get the local head to validate the data root tuple root range%w", err)
}
Expand Down Expand Up @@ -167,7 +169,7 @@ func proveDataRootTuples(encodedDataRootTuples [][]byte, rangeStartHeight, heigh
return nil, fmt.Errorf("cannot prove an empty list of encoded data root tuples")
}
if height == 0 || rangeStartHeight == 0 {
return nil, ErrHeightZero
return nil, header.ErrHeightZero
}
_, proofs := merkle.ProofsFromByteSlices(encodedDataRootTuples)
return proofs[height-rangeStartHeight], nil
Expand All @@ -178,11 +180,11 @@ func proveDataRootTuples(encodedDataRootTuples [][]byte, rangeStartHeight, heigh
// end is not included in the range.
func (s *Service) fetchEncodedDataRootTuples(ctx context.Context, start, end uint64) ([][]byte, error) {
encodedDataRootTuples := make([][]byte, 0, end-start)
startHeader, err := s.GetByHeight(ctx, start)
startHeader, err := s.headerServ.GetByHeight(ctx, start)
if err != nil {
return nil, err
}
headerRange, err := s.GetRangeByHeight(ctx, startHeader, end)
headerRange, err := s.headerServ.GetRangeByHeight(ctx, startHeader, end)
if err != nil {
return nil, err
}
Expand Down
66 changes: 66 additions & 0 deletions nodebuilder/blobstream/mocks/api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions nodebuilder/blobstream/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package blobstream

import "go.uber.org/fx"

func ConstructModule() fx.Option {
return fx.Module("blobstream",
fx.Provide(NewService),
fx.Provide(func(serv *Service) Module {
return serv
}),
)
}
81 changes: 81 additions & 0 deletions nodebuilder/blobstream/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package blobstream

import (
"context"

logging "github.com/ipfs/go-log/v2"

headerServ "github.com/celestiaorg/celestia-node/nodebuilder/header"
)

var _ Module = (*Service)(nil)

var log = logging.Logger("go-blobstream")

type Service struct {
headerServ headerServ.Module
}

func NewService(headerMod headerServ.Module) *Service {
return &Service{
headerServ: headerMod,
}
}

// GetDataRootTupleRoot collects the data roots over a provided ordered range of blocks,
// and then creates a new Merkle root of those data roots. The range is end exclusive.
func (s *Service) GetDataRootTupleRoot(ctx context.Context, start, end uint64) (*DataRootTupleRoot, error) {
log.Debugw("validating the data commitment range", "start", start, "end", end)
err := s.validateDataRootTupleRootRange(ctx, start, end)
if err != nil {
return nil, err
}
log.Debugw("fetching the data root tuples", "start", start, "end", end)
encodedDataRootTuples, err := s.fetchEncodedDataRootTuples(ctx, start, end)
if err != nil {
return nil, err
}
log.Debugw("hashing the data root tuples", "start", start, "end", end)
root, err := hashDataRootTuples(encodedDataRootTuples)
if err != nil {
return nil, err
}
// Create data commitment
dataRootTupleRoot := DataRootTupleRoot(root)
return &dataRootTupleRoot, nil
}

// GetDataRootTupleInclusionProof creates an inclusion proof for the data root of block
// height `height` in the set of blocks defined by `start` and `end`. The range
// is end exclusive.
func (s *Service) GetDataRootTupleInclusionProof(
ctx context.Context,
height, start, end uint64,
) (*DataRootTupleInclusionProof, error) {
log.Debugw(
"validating the data root inclusion proof request",
"start",
start,
"end",
end,
"height",
height,
)
err := s.validateDataRootInclusionProofRequest(ctx, height, start, end)
if err != nil {
return nil, err
}
log.Debugw("fetching the data root tuples", "start", start, "end", end)

encodedDataRootTuples, err := s.fetchEncodedDataRootTuples(ctx, start, end)
if err != nil {
return nil, err
}
log.Debugw("proving the data root tuples", "start", start, "end", end)
proof, err := proveDataRootTuples(encodedDataRootTuples, start, height)
if err != nil {
return nil, err
}
dataRootTupleInclusionProof := DataRootTupleInclusionProof(proof)
return &dataRootTupleInclusionProof, nil
}
Loading

0 comments on commit da27e8a

Please sign in to comment.