Skip to content

Commit

Permalink
feat: implement new DALC API
Browse files Browse the repository at this point in the history
  • Loading branch information
tzdybal committed Apr 7, 2022
1 parent 1879977 commit 4db8cc2
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 62 deletions.
6 changes: 4 additions & 2 deletions block/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,12 @@ func (m *Manager) mustRetrieveBlock(ctx context.Context, height uint64) {

func (m *Manager) fetchBlock(ctx context.Context, height uint64) error {
var err error
blockRes := m.retriever.RetrieveBlock(height)
blockRes := m.retriever.RetrieveBlocks(height)
switch blockRes.Code {
case da.StatusSuccess:
m.blockInCh <- blockRes.Block
for _, block := range blockRes.Blocks {
m.blockInCh <- block
}
case da.StatusError:
err = fmt.Errorf("failed to retrieve block: %s", blockRes.Message)
case da.StatusTimeout:
Expand Down
10 changes: 6 additions & 4 deletions da/da.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ type DAResult struct {
Code StatusCode
// Message may contain DA layer specific information (like DA block height/hash, detailed error message, etc)
Message string
// DataLayerHeight informs about a height on Data Availability Layer for given result.
DataLayerHeight uint64
}

// ResultSubmitBlock contains information returned from DA layer after block submission.
Expand All @@ -47,7 +49,7 @@ type ResultRetrieveBlock struct {
DAResult
// Block is the full block retrieved from Data Availability Layer.
// If Code is not equal to StatusSuccess, it has to be nil.
Block *types.Block
Blocks []*types.Block
}

// DataAvailabilityLayerClient defines generic interface for DA layer block submission.
Expand All @@ -65,12 +67,12 @@ type DataAvailabilityLayerClient interface {
SubmitBlock(block *types.Block) ResultSubmitBlock

// CheckBlockAvailability queries DA layer to check data availability of block corresponding to given header.
CheckBlockAvailability(header *types.Header) ResultCheckBlock
CheckBlockAvailability(dataLayerHeight uint64) ResultCheckBlock
}

// BlockRetriever is additional interface that can be implemented by Data Availability Layer Client that is able to retrieve
// block data from DA layer. This gives the ability to use it for block synchronization.
type BlockRetriever interface {
// RetrieveBlock returns block at given height from data availability layer.
RetrieveBlock(height uint64) ResultRetrieveBlock
// RetrieveBlocks returns blocks at given data layer height from data availability layer.
RetrieveBlocks(dataLayerHeight uint64) ResultRetrieveBlock
}
28 changes: 18 additions & 10 deletions da/grpc/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,16 @@ func (d *DataAvailabilityLayerClient) SubmitBlock(block *types.Block) da.ResultS
}
}
return da.ResultSubmitBlock{
DAResult: da.DAResult{Code: da.StatusCode(resp.Result.Code), Message: resp.Result.Message},
DAResult: da.DAResult{
Code: da.StatusCode(resp.Result.Code),
Message: resp.Result.Message,
DataLayerHeight: resp.Result.DataLayerHeight,
},
}
}

func (d *DataAvailabilityLayerClient) CheckBlockAvailability(header *types.Header) da.ResultCheckBlock {
resp, err := d.client.CheckBlockAvailability(context.TODO(), &dalc.CheckBlockAvailabilityRequest{Header: header.ToProto()})
func (d *DataAvailabilityLayerClient) CheckBlockAvailability(dataLayerHeight uint64) da.ResultCheckBlock {
resp, err := d.client.CheckBlockAvailability(context.TODO(), &dalc.CheckBlockAvailabilityRequest{DataLayerHeight: dataLayerHeight})
if err != nil {
return da.ResultCheckBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}}
}
Expand All @@ -90,19 +94,23 @@ func (d *DataAvailabilityLayerClient) CheckBlockAvailability(header *types.Heade
}
}

func (d *DataAvailabilityLayerClient) RetrieveBlock(height uint64) da.ResultRetrieveBlock {
resp, err := d.client.RetrieveBlock(context.TODO(), &dalc.RetrieveBlockRequest{Height: height})
func (d *DataAvailabilityLayerClient) RetrieveBlocks(dataLayerHeight uint64) da.ResultRetrieveBlock {
resp, err := d.client.RetrieveBlocks(context.TODO(), &dalc.RetrieveBlocksRequest{DataLayerHeight: dataLayerHeight})
if err != nil {
return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}}
}

var b types.Block
err = b.FromProto(resp.Block)
if err != nil {
return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}}
blocks := make([]*types.Block, len(resp.Blocks))
for i, block := range resp.Blocks {
var b types.Block
err = b.FromProto(block)
if err != nil {
return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}}
}
blocks[i] = &b
}
return da.ResultRetrieveBlock{
DAResult: da.DAResult{Code: da.StatusCode(resp.Result.Code), Message: resp.Result.Message},
Block: &b,
Blocks: blocks,
}
}
30 changes: 16 additions & 14 deletions da/grpc/mockserv/mockserv.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import (
"context"
"os"

tmlog "github.com/tendermint/tendermint/libs/log"
"google.golang.org/grpc"

grpcda "github.com/celestiaorg/optimint/da/grpc"
"github.com/celestiaorg/optimint/da/mock"
"github.com/celestiaorg/optimint/store"
"github.com/celestiaorg/optimint/types"
"github.com/celestiaorg/optimint/types/pb/dalc"
tmlog "github.com/tendermint/tendermint/libs/log"
"google.golang.org/grpc"
"github.com/celestiaorg/optimint/types/pb/optimint"
)

func GetServer(kv store.KVStore, conf grpcda.Config) *grpc.Server {
Expand Down Expand Up @@ -40,19 +42,15 @@ func (m *mockImpl) SubmitBlock(_ context.Context, request *dalc.SubmitBlockReque
resp := m.mock.SubmitBlock(&b)
return &dalc.SubmitBlockResponse{
Result: &dalc.DAResponse{
Code: dalc.StatusCode(resp.Code),
Message: resp.Message,
Code: dalc.StatusCode(resp.Code),
Message: resp.Message,
DataLayerHeight: resp.DataLayerHeight,
},
}, nil
}

func (m *mockImpl) CheckBlockAvailability(_ context.Context, request *dalc.CheckBlockAvailabilityRequest) (*dalc.CheckBlockAvailabilityResponse, error) {
var h types.Header
err := h.FromProto(request.Header)
if err != nil {
return nil, err
}
resp := m.mock.CheckBlockAvailability(&h)
resp := m.mock.CheckBlockAvailability(request.DataLayerHeight)
return &dalc.CheckBlockAvailabilityResponse{
Result: &dalc.DAResponse{
Code: dalc.StatusCode(resp.Code),
Expand All @@ -62,13 +60,17 @@ func (m *mockImpl) CheckBlockAvailability(_ context.Context, request *dalc.Check
}, nil
}

func (m *mockImpl) RetrieveBlock(context context.Context, request *dalc.RetrieveBlockRequest) (*dalc.RetrieveBlockResponse, error) {
resp := m.mock.RetrieveBlock(request.Height)
return &dalc.RetrieveBlockResponse{
func (m *mockImpl) RetrieveBlocks(context context.Context, request *dalc.RetrieveBlocksRequest) (*dalc.RetrieveBlocksResponse, error) {
resp := m.mock.RetrieveBlocks(request.DataLayerHeight)
blocks := make([]*optimint.Block, len(resp.Blocks))
for i := range resp.Blocks {
blocks[i] = resp.Blocks[i].ToProto()
}
return &dalc.RetrieveBlocksResponse{
Result: &dalc.DAResponse{
Code: dalc.StatusCode(resp.Code),
Message: resp.Message,
},
Block: resp.Block.ToProto(),
Blocks: blocks,
}, nil
}
37 changes: 24 additions & 13 deletions da/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package mock
import (
"encoding/binary"
"errors"
"sync/atomic"

"github.com/celestiaorg/optimint/da"
"github.com/celestiaorg/optimint/log"
Expand All @@ -13,8 +14,9 @@ import (
// MockDataAvailabilityLayerClient is intended only for usage in tests.
// It does actually ensures DA - it stores data in-memory.
type MockDataAvailabilityLayerClient struct {
logger log.Logger
dalcKV store.KVStore
logger log.Logger
dalcKV store.KVStore
daHeight uint64
}

var _ da.DataAvailabilityLayerClient = &MockDataAvailabilityLayerClient{}
Expand Down Expand Up @@ -43,15 +45,17 @@ func (m *MockDataAvailabilityLayerClient) Stop() error {
// This should create a transaction which (potentially)
// triggers a state transition in the DA layer.
func (m *MockDataAvailabilityLayerClient) SubmitBlock(block *types.Block) da.ResultSubmitBlock {
m.logger.Debug("Submitting block to DA layer!", "height", block.Header.Height)
height := atomic.AddUint64(&m.daHeight, 1)
m.logger.Debug("Submitting block to DA layer!", "height", block.Header.Height, "dataLayerHeight", height)

hash := block.Header.Hash()
blob, err := block.MarshalBinary()
if err != nil {
return da.ResultSubmitBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}}
}

err = m.dalcKV.Set(getKey(block.Header.Height), hash[:])
// TODO(tzdybal): more than one optimint block per "mock" DA height
err = m.dalcKV.Set(getKey(height), hash[:])
if err != nil {
return da.ResultSubmitBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}}
}
Expand All @@ -62,16 +66,23 @@ func (m *MockDataAvailabilityLayerClient) SubmitBlock(block *types.Block) da.Res

return da.ResultSubmitBlock{
DAResult: da.DAResult{
Code: da.StatusSuccess,
Message: "OK",
Code: da.StatusSuccess,
Message: "OK",
DataLayerHeight: height,
},
}
}

// CheckBlockAvailability queries DA layer to check data availability of block corresponding to given header.
func (m *MockDataAvailabilityLayerClient) CheckBlockAvailability(header *types.Header) da.ResultCheckBlock {
hash := header.Hash()
_, err := m.dalcKV.Get(hash[:])
func (m *MockDataAvailabilityLayerClient) CheckBlockAvailability(dataLayerHeight uint64) da.ResultCheckBlock {
hash, err := m.dalcKV.Get(getKey(dataLayerHeight))
if errors.Is(err, store.ErrKeyNotFound) {
return da.ResultCheckBlock{DAResult: da.DAResult{Code: da.StatusSuccess}, DataAvailable: false}
}
if err != nil {
return da.ResultCheckBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}, DataAvailable: false}
}
_, err = m.dalcKV.Get(hash[:])
if errors.Is(err, store.ErrKeyNotFound) {
return da.ResultCheckBlock{DAResult: da.DAResult{Code: da.StatusSuccess}, DataAvailable: false}
}
Expand All @@ -81,9 +92,9 @@ func (m *MockDataAvailabilityLayerClient) CheckBlockAvailability(header *types.H
return da.ResultCheckBlock{DAResult: da.DAResult{Code: da.StatusSuccess}, DataAvailable: true}
}

// RetrieveBlock returns block at given height from data availability layer.
func (m *MockDataAvailabilityLayerClient) RetrieveBlock(height uint64) da.ResultRetrieveBlock {
hash, err := m.dalcKV.Get(getKey(height))
// RetrieveBlocks returns block at given height from data availability layer.
func (m *MockDataAvailabilityLayerClient) RetrieveBlocks(dataLayerHeight uint64) da.ResultRetrieveBlock {
hash, err := m.dalcKV.Get(getKey(dataLayerHeight))
if err != nil {
return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}}
}
Expand All @@ -98,7 +109,7 @@ func (m *MockDataAvailabilityLayerClient) RetrieveBlock(height uint64) da.Result
return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusError, Message: err.Error()}}
}

return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusSuccess}, Block: block}
return da.ResultRetrieveBlock{DAResult: da.DAResult{Code: da.StatusSuccess}, Blocks: []*types.Block{block}}
}

func getKey(height uint64) []byte {
Expand Down
16 changes: 9 additions & 7 deletions da/test/da_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,24 +66,25 @@ func doTestDALC(t *testing.T, dalc da.DataAvailabilityLayerClient) {
// only blocks b1 and b2 will be submitted to DA
b1 := getRandomBlock(1, 10)
b2 := getRandomBlock(2, 10)
b3 := getRandomBlock(1, 10)

resp := dalc.SubmitBlock(b1)
h1 := resp.DataLayerHeight
assert.Equal(da.StatusSuccess, resp.Code)

resp = dalc.SubmitBlock(b2)
h2 := resp.DataLayerHeight
assert.Equal(da.StatusSuccess, resp.Code)

check := dalc.CheckBlockAvailability(&b1.Header)
check := dalc.CheckBlockAvailability(h1)
assert.Equal(da.StatusSuccess, check.Code)
assert.True(check.DataAvailable)

check = dalc.CheckBlockAvailability(&b2.Header)
check = dalc.CheckBlockAvailability(h2)
assert.Equal(da.StatusSuccess, check.Code)
assert.True(check.DataAvailable)

// this block was never submitted to DA
check = dalc.CheckBlockAvailability(&b3.Header)
// this height should not be used by DALC
check = dalc.CheckBlockAvailability(42)
assert.Equal(da.StatusSuccess, check.Code)
assert.False(check.DataAvailable)
}
Expand Down Expand Up @@ -132,9 +133,10 @@ func doTestRetrieve(t *testing.T, dalc da.DataAvailabilityLayerClient) {
resp := dalc.SubmitBlock(b)
assert.Equal(da.StatusSuccess, resp.Code)

ret := retriever.RetrieveBlock(i)
ret := retriever.RetrieveBlocks(resp.DataLayerHeight)
assert.Equal(da.StatusSuccess, ret.Code)
assert.Equal(b, ret.Block)
require.NotEmpty(ret.Blocks)
assert.Equal(b, ret.Blocks[0])
}
}

Expand Down
18 changes: 11 additions & 7 deletions types/pb/dalc/dalc.pb.go

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

15 changes: 10 additions & 5 deletions types/pb/optimint/optimint.pb.go

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

0 comments on commit 4db8cc2

Please sign in to comment.