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

catchup: Fix empty cert if ledger already has a block #5846

Merged
merged 4 commits into from
Nov 28, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 7 additions & 4 deletions catchup/catchpointService.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,9 @@
var blk *bookkeeping.Block
var cert *agreement.Certificate
// check to see if the current ledger might have this block. If so, we should try this first instead of downloading anything.
if ledgerBlock, err := cs.ledger.Block(blockRound); err == nil {
if ledgerBlock, ledgerCert, err0 := cs.ledger.BlockCert(blockRound); err0 == nil {
blk = &ledgerBlock
cert = &ledgerCert
}
var protoParams config.ConsensusParams
var ok bool
Expand Down Expand Up @@ -551,15 +552,17 @@
}

blk = nil
cert = nil
// check to see if the current ledger might have this block. If so, we should try this first instead of downloading anything.
if ledgerBlock, err := cs.ledger.Block(topBlock.Round() - basics.Round(blocksFetched)); err == nil {
if ledgerBlock, ledgerCert, err0 := cs.ledger.BlockCert(topBlock.Round() - basics.Round(blocksFetched)); err0 == nil {
blk = &ledgerBlock
cert = &ledgerCert
} else {
switch err.(type) {
switch err0.(type) {

Check warning on line 561 in catchup/catchpointService.go

View check run for this annotation

Codecov / codecov/patch

catchup/catchpointService.go#L561

Added line #L561 was not covered by tests
case ledgercore.ErrNoEntry:
// this is expected, ignore this one.
default:
cs.log.Warnf("processStageBlocksDownload encountered the following error when attempting to retrieve the block for round %d : %v", topBlock.Round()-basics.Round(blocksFetched), err)
cs.log.Warnf("processStageBlocksDownload encountered the following error when attempting to retrieve the block for round %d : %v", topBlock.Round()-basics.Round(blocksFetched), err0)

Check warning on line 565 in catchup/catchpointService.go

View check run for this annotation

Codecov / codecov/patch

catchup/catchpointService.go#L565

Added line #L565 was not covered by tests
}
}

Expand Down
70 changes: 67 additions & 3 deletions catchup/catchpointService_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,37 @@ import (

"github.com/stretchr/testify/require"

"github.com/algorand/go-algorand/agreement"
"github.com/algorand/go-algorand/components/mocks"
"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/ledger"
"github.com/algorand/go-algorand/ledger/ledgercore"
"github.com/algorand/go-algorand/logging"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/test/partitiontest"
)

type catchpointCatchupLedger struct {
}

func (l *catchpointCatchupLedger) Block(rnd basics.Round) (blk bookkeeping.Block, err error) {
func (l *catchpointCatchupLedger) BlockCert(rnd basics.Round) (blk bookkeeping.Block, cert agreement.Certificate, err error) {
jannotti marked this conversation as resolved.
Show resolved Hide resolved
blk = bookkeeping.Block{
BlockHeader: bookkeeping.BlockHeader{
UpgradeState: bookkeeping.UpgradeState{
CurrentProtocol: protocol.ConsensusCurrentVersion,
},
},
}
cert = agreement.Certificate{}
commitments, err := blk.PaysetCommit()
if err != nil {
return blk, err
return blk, cert, err
}
blk.TxnCommitments = commitments

return blk, nil
return blk, cert, nil
}

func (l *catchpointCatchupLedger) GenesisHash() (d crypto.Digest) {
Expand Down Expand Up @@ -95,3 +98,64 @@ func TestCatchpointServicePeerRank(t *testing.T) {
err := cs.processStageLatestBlockDownload()
require.NoError(t, err)
}

type catchpointAccessorMock struct {
mocks.MockCatchpointCatchupAccessor
t *testing.T
topBlk bookkeeping.Block
}

func (m *catchpointAccessorMock) EnsureFirstBlock(ctx context.Context) (blk bookkeeping.Block, err error) {
return m.topBlk, nil
}

func (m *catchpointAccessorMock) StoreBlock(ctx context.Context, blk *bookkeeping.Block, cert *agreement.Certificate) (err error) {
require.NotNil(m.t, blk)
require.NotNil(m.t, cert)
return nil
}

type catchpointCatchupLedger2 struct {
catchpointCatchupLedger
blk bookkeeping.Block
}

func (l *catchpointCatchupLedger2) BlockCert(rnd basics.Round) (blk bookkeeping.Block, cert agreement.Certificate, err error) {
return l.blk, agreement.Certificate{}, nil
}

// TestProcessStageBlocksDownloadNilCert ensures StoreBlock does not receive a nil certificate when ledger has already had a block.
// It uses two mocks catchpointAccessorMock and catchpointCatchupLedger2 and pre-crafted blocks to make a single iteration of processStageBlocksDownload.
func TestProcessStageBlocksDownloadNilCert(t *testing.T) {
partitiontest.PartitionTest(t)

var err error
blk1 := bookkeeping.Block{
BlockHeader: bookkeeping.BlockHeader{
Round: 1,
UpgradeState: bookkeeping.UpgradeState{
CurrentProtocol: protocol.ConsensusCurrentVersion,
},
},
}
blk1.TxnCommitments, err = blk1.PaysetCommit()
require.NoError(t, err)

blk2 := blk1
blk2.BlockHeader.Round = 2
blk2.BlockHeader.Branch = blk1.Hash()
blk2.TxnCommitments, err = blk2.PaysetCommit()
require.NoError(t, err)

ctx, cf := context.WithCancel(context.Background())
cs := CatchpointCatchupService{
ctx: ctx,
cancelCtxFunc: cf,
ledgerAccessor: &catchpointAccessorMock{topBlk: blk2, t: t},
ledger: &catchpointCatchupLedger2{blk: blk1},
log: logging.TestingLog(t),
}

err = cs.processStageBlocksDownload()
require.NoError(t, err)
}
2 changes: 1 addition & 1 deletion ledger/catchupaccessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ const (

// CatchupAccessorClientLedger represents ledger interface needed for catchpoint accessor clients
type CatchupAccessorClientLedger interface {
Block(rnd basics.Round) (blk bookkeeping.Block, err error)
BlockCert(rnd basics.Round) (blk bookkeeping.Block, cert agreement.Certificate, err error)
jannotti marked this conversation as resolved.
Show resolved Hide resolved
GenesisHash() crypto.Digest
BlockHdr(rnd basics.Round) (blk bookkeeping.BlockHeader, err error)
Latest() (rnd basics.Round)
Expand Down