Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(header/p2p): implement GetVerifiedRangeByHeight #1305

Merged
merged 8 commits into from
Nov 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion das/daser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,15 @@ func (m getterStub) GetByHeight(_ context.Context, height uint64) (*header.Exten
DAH: &header.DataAvailabilityHeader{RowsRoots: make([][]byte, 0)}}, nil
}

func (m getterStub) GetRangeByHeight(ctx context.Context, from, to uint64) ([]*header.ExtendedHeader, error) {
func (m getterStub) GetRangeByHeight(ctx context.Context, from, amount uint64) ([]*header.ExtendedHeader, error) {
return nil, nil
}

func (m getterStub) GetVerifiedRange(
context.Context,
*header.ExtendedHeader,
uint64,
) ([]*header.ExtendedHeader, error) {
return nil, nil
}

Expand Down
17 changes: 17 additions & 0 deletions header/core/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,23 @@ func (ce *Exchange) GetRangeByHeight(ctx context.Context, from, amount uint64) (
return headers, nil
}

func (ce *Exchange) GetVerifiedRange(ctx context.Context, from *header.ExtendedHeader, amount uint64,
) ([]*header.ExtendedHeader, error) {
headers, err := ce.GetRangeByHeight(ctx, uint64(from.Height)+1, amount)
if err != nil {
return nil, err
}

for _, h := range headers {
err := from.VerifyAdjacent(h)
if err != nil {
return nil, err
}
from = h
}
return headers, nil
}

func (ce *Exchange) Get(ctx context.Context, hash tmbytes.HexBytes) (*header.ExtendedHeader, error) {
log.Debugw("requesting header", "hash", hash.String())
block, err := ce.fetcher.GetBlockByHash(ctx, hash)
Expand Down
8 changes: 6 additions & 2 deletions header/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,12 @@ type Getter interface {
// GetByHeight returns the ExtendedHeader corresponding to the given block height.
GetByHeight(context.Context, uint64) (*ExtendedHeader, error)

// GetRangeByHeight returns the given range [from:to) of ExtendedHeaders.
GetRangeByHeight(ctx context.Context, from, to uint64) ([]*ExtendedHeader, error)
// GetRangeByHeight returns the given range of ExtendedHeaders.
GetRangeByHeight(ctx context.Context, from, amount uint64) ([]*ExtendedHeader, error)

// GetVerifiedRange requests the header range from the provided ExtendedHeader and
// verifies that the returned headers are adjacent to each other.
GetVerifiedRange(ctx context.Context, from *ExtendedHeader, amount uint64) ([]*ExtendedHeader, error)
}

// Head contains the behavior necessary for a component to retrieve
Expand Down
5 changes: 5 additions & 0 deletions header/local/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ func (l *Exchange) GetRangeByHeight(ctx context.Context, origin, amount uint64)
return l.store.GetRangeByHeight(ctx, origin, origin+amount)
}

func (l *Exchange) GetVerifiedRange(ctx context.Context, from *header.ExtendedHeader, amount uint64,
) ([]*header.ExtendedHeader, error) {
return l.store.GetVerifiedRange(ctx, from, uint64(from.Height)+amount)
}

func (l *Exchange) Get(ctx context.Context, hash bytes.HexBytes) (*header.ExtendedHeader, error) {
return l.store.Get(ctx, hash)
}
25 changes: 25 additions & 0 deletions header/p2p/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,31 @@ func (ex *Exchange) GetRangeByHeight(ctx context.Context, from, amount uint64) (
return session.getRangeByHeight(ctx, from, amount)
}

// GetVerifiedRange performs a request for the given range of ExtendedHeaders to the network and ensures
// that returned headers are correct against the passed one.
func (ex *Exchange) GetVerifiedRange(
ctx context.Context,
from *header.ExtendedHeader,
amount uint64,
) ([]*header.ExtendedHeader, error) {
session := newSession(ex.ctx, ex.host, ex.peerTracker.peers(), ex.protocolID)
defer session.close()

headers, err := session.getRangeByHeight(ctx, uint64(from.Height)+1, amount)
if err != nil {
return nil, err
}

for _, h := range headers {
err := from.VerifyAdjacent(h)
if err != nil {
return nil, err
}
from = h
}
return headers, nil
}

// Get performs a request for the ExtendedHeader by the given hash corresponding
// to the RawHeader. Note that the ExtendedHeader must be verified thereafter.
func (ex *Exchange) Get(ctx context.Context, hash tmbytes.HexBytes) (*header.ExtendedHeader, error) {
Expand Down
27 changes: 27 additions & 0 deletions header/p2p/exchange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,25 @@ func TestExchange_RequestHeaders(t *testing.T) {
}
}

func TestExchange_RequestVerifiedHeaders(t *testing.T) {
hosts := createMocknet(t, 2)
exchg, store := createP2PExAndServer(t, hosts[0], hosts[1])
// perform expected request
h := store.headers[1]
_, err := exchg.GetVerifiedRange(context.Background(), h, 3)
require.NoError(t, err)
}

func TestExchange_RequestVerifiedHeadersFails(t *testing.T) {
hosts := createMocknet(t, 2)
exchg, store := createP2PExAndServer(t, hosts[0], hosts[1])
store.headers[2] = store.headers[3]
// perform expected request
h := store.headers[1]
_, err := exchg.GetVerifiedRange(context.Background(), h, 3)
require.Error(t, err)
}

// TestExchange_RequestFullRangeHeaders requests max amount of headers
// to verify how session will parallelize all requests.
func TestExchange_RequestFullRangeHeaders(t *testing.T) {
Expand Down Expand Up @@ -342,6 +361,14 @@ func (m *mockStore) GetRangeByHeight(ctx context.Context, from, to uint64) ([]*h
return headers, nil
}

func (m *mockStore) GetVerifiedRange(
ctx context.Context,
h *header.ExtendedHeader,
to uint64,
) ([]*header.ExtendedHeader, error) {
return m.GetRangeByHeight(ctx, uint64(h.Height)+1, to)
}

func (m *mockStore) Has(context.Context, tmbytes.HexBytes) (bool, error) {
return false, nil
}
Expand Down
4 changes: 3 additions & 1 deletion header/p2p/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,9 @@ func (s *session) processResponse(responses []*p2p_pb.ExtendedHeaderResponse) ([
}
headers = append(headers, header)
}

if len(headers) == 0 {
return nil, header.ErrNotFound
}
return headers, nil
}

Expand Down
23 changes: 23 additions & 0 deletions header/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,29 @@ func (s *Store) GetRangeByHeight(ctx context.Context, from, to uint64) ([]*heade
return headers, nil
}

func (s *Store) GetVerifiedRange(
ctx context.Context,
from *header.ExtendedHeader,
to uint64,
) ([]*header.ExtendedHeader, error) {
if uint64(from.Height) >= to {
return nil, fmt.Errorf("header/store: invalid range(%d,%d)", from.Height, to)
}
headers, err := s.GetRangeByHeight(ctx, uint64(from.Height)+1, to)
if err != nil {
return nil, err
}

for _, h := range headers {
err := from.VerifyAdjacent(h)
if err != nil {
return nil, err
}
from = h
}
return headers, nil
}

func (s *Store) Has(ctx context.Context, hash tmbytes.HexBytes) (bool, error) {
if ok := s.cache.Contains(hash.String()); ok {
return ok, nil
Expand Down
10 changes: 9 additions & 1 deletion header/sync/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,14 @@ func (e *exchangeCountingHead) GetByHeight(ctx context.Context, u uint64) (*head
panic("implement me")
}

func (e *exchangeCountingHead) GetRangeByHeight(c context.Context, from, to uint64) ([]*header.ExtendedHeader, error) {
func (e *exchangeCountingHead) GetRangeByHeight(
c context.Context,
from, amount uint64,
) ([]*header.ExtendedHeader, error) {
panic("implement me")
}

func (e *exchangeCountingHead) GetVerifiedRange(c context.Context, from *header.ExtendedHeader, amount uint64,
) ([]*header.ExtendedHeader, error) {
panic("implement me")
}