Merge pull request #11565 from filecoin-project/asr/harden-sync

feat: exchange: change GetBlocks to always fetch the requested number of tipsets
This commit is contained in:
Jiaying Wang 2024-01-11 18:13:10 +08:00 committed by GitHub
commit 512c70bb39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 18 deletions

View File

@ -284,16 +284,18 @@ func (c *client) validateCompressedIndices(chain []*BSTipSet) error {
len(msgs.SecpkIncludes), blocksNum) len(msgs.SecpkIncludes), blocksNum)
} }
blsLen := uint64(len(msgs.Bls))
secpLen := uint64(len(msgs.Secpk))
for blockIdx := 0; blockIdx < blocksNum; blockIdx++ { for blockIdx := 0; blockIdx < blocksNum; blockIdx++ {
for _, mi := range msgs.BlsIncludes[blockIdx] { for _, mi := range msgs.BlsIncludes[blockIdx] {
if int(mi) >= len(msgs.Bls) { if mi >= blsLen {
return xerrors.Errorf("index in BlsIncludes (%d) exceeds number of messages (%d)", return xerrors.Errorf("index in BlsIncludes (%d) exceeds number of messages (%d)",
mi, len(msgs.Bls)) mi, len(msgs.Bls))
} }
} }
for _, mi := range msgs.SecpkIncludes[blockIdx] { for _, mi := range msgs.SecpkIncludes[blockIdx] {
if int(mi) >= len(msgs.Secpk) { if mi >= secpLen {
return xerrors.Errorf("index in SecpkIncludes (%d) exceeds number of messages (%d)", return xerrors.Errorf("index in SecpkIncludes (%d) exceeds number of messages (%d)",
mi, len(msgs.Secpk)) mi, len(msgs.Secpk))
} }
@ -315,18 +317,36 @@ func (c *client) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int)
) )
} }
var ret []*types.TipSet
start := tsk.Cids()
for len(ret) < count {
req := &Request{ req := &Request{
Head: tsk.Cids(), Head: start,
Length: uint64(count), Length: uint64(count - len(ret)),
Options: Headers, Options: Headers,
} }
validRes, err := c.doRequest(ctx, req, nil, nil) validRes, err := c.doRequest(ctx, req, nil, nil)
if err != nil { if err != nil {
return nil, err return nil, xerrors.Errorf("failed to doRequest: %w", err)
} }
return validRes.tipsets, nil if len(validRes.tipsets) == 0 {
return nil, xerrors.Errorf("doRequest fetched zero tipsets: %w", err)
}
ret = append(ret, validRes.tipsets...)
last := validRes.tipsets[len(validRes.tipsets)-1]
if last.Height() <= 1 {
// we've walked all the way up to genesis, return
break
}
start = last.Parents().Cids()
}
return ret, nil
} }
// GetFullTipSet implements Client.GetFullTipSet(). Refer to the godocs there. // GetFullTipSet implements Client.GetFullTipSet(). Refer to the godocs there.
@ -341,12 +361,16 @@ func (c *client) GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipS
validRes, err := c.doRequest(ctx, req, &peer, nil) validRes, err := c.doRequest(ctx, req, &peer, nil)
if err != nil { if err != nil {
return nil, err return nil, xerrors.Errorf("failed to doRequest: %w", err)
} }
return validRes.toFullTipSets()[0], nil fullTipsets := validRes.toFullTipSets()
// If `doRequest` didn't fail we are guaranteed to have at least
// *one* tipset here, so it's safe to index directly. if len(fullTipsets) == 0 {
return nil, xerrors.New("unexpectedly got no tipsets in exchange")
}
return fullTipsets[0], nil
} }
// GetChainMessages implements Client.GetChainMessages(). Refer to the godocs there. // GetChainMessages implements Client.GetChainMessages(). Refer to the godocs there.

View File

@ -28,8 +28,8 @@ type Server interface {
// used by the Syncer. // used by the Syncer.
type Client interface { type Client interface {
// GetBlocks fetches block headers from the network, from the provided // GetBlocks fetches block headers from the network, from the provided
// tipset *backwards*, returning as many tipsets as the count parameter, // tipset *backwards*, returning as many tipsets as the count parameter.
// or less. // The ONLY case in which we return fewer than `count` tipsets is if we hit genesis.
GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error)
// GetChainMessages fetches messages from the network, starting from the first provided tipset // GetChainMessages fetches messages from the network, starting from the first provided tipset