Skip to content

Commit

Permalink
first step of applying unfinishedBlock changes from algorand#5967 to a…
Browse files Browse the repository at this point in the history
  • Loading branch information
cce committed Apr 3, 2024
1 parent 82263e1 commit 2c40125
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 52 deletions.
33 changes: 19 additions & 14 deletions agreement/abstractions.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,34 +65,39 @@ var ErrAssembleBlockRoundStale = errors.New("requested round for AssembleBlock i
// An BlockFactory produces an Block which is suitable for proposal for a given
// Round.
type BlockFactory interface {
// AssembleBlock produces a new ValidatedBlock which is suitable for proposal
// at a given Round.
// AssembleBlock produces a new UnfinishedBlock for a given Round.
// It must be finalized before proposed by agreement. It is provided
// a list of participating addresses that may propose this block.
//
// AssembleBlock should produce a ValidatedBlock for which the corresponding
// AssembleBlock should produce a block for which the corresponding
// BlockValidator validates (i.e. for which BlockValidator.Validate
// returns true). If an insufficient number of nodes can assemble valid
// entries, the agreement protocol may lose liveness.
//
// AssembleBlock may return an error if the BlockFactory is unable to
// produce a ValidatedBlock for the given round. If an insufficient number of
// produce an UnfinishedBlock for the given round. If an insufficient number of
// nodes on the network can assemble entries, the agreement protocol may
// lose liveness.
AssembleBlock(basics.Round) (AssembledBlock, error)
AssembleBlock(rnd basics.Round, partAddresses []basics.Address) (UnfinishedBlock, error)
}

// An AssembledBlock represents a Block produced by a BlockFactory
// to be included in a proposal by agreement.
type AssembledBlock interface {
// WithProposer creates a copy of this AssembledBlock with its
// cryptographically random seed and proposer set. The block's
// ProposerPayout is zero'd if !eligible. Abstractly, it is how the
// agreement code "finishes" a block and makes it a proposal for a specific
// account.
// An UnfinishedBlock represents a Block produced by a BlockFactory
// and must be finalized before being proposed by agreement.
type UnfinishedBlock interface {
// WithSeed creates a copy of this UnfinishedBlock with its
// cryptographically random seed set to the given value.
//
// Calls to Seed() or to Digest() on the copy's Block must
// reflect the value of the new seed.
WithProposer(seed committee.Seed, proposer basics.Address, eligible bool) AssembledBlock
FinishBlock(seed committee.Seed, proposer basics.Address, eligible bool) ProposableBlock

Round() basics.Round
}

// An ProposableBlock represents a Block produced by a BlockFactory,
// that was later finalized by providing the seed and the proposer,
// and can now be proposed by agreement.
type ProposableBlock interface {
// Block returns the underlying block that has been assembled.
Block() bookkeeping.Block
}
Expand Down
4 changes: 2 additions & 2 deletions agreement/agreementtest/simulate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (b testValidatedBlock) Block() bookkeeping.Block {
return b.Inside
}

func (b testValidatedBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) agreement.AssembledBlock {
func (b testValidatedBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) agreement.UnfinishedBlock {
b.Inside.BlockHeader.Seed = s
b.Inside.BlockHeader.Proposer = proposer
if !eligible {
Expand All @@ -98,7 +98,7 @@ type testBlockFactory struct {
Owner int
}

func (f testBlockFactory) AssembleBlock(r basics.Round) (agreement.AssembledBlock, error) {
func (f testBlockFactory) AssembleBlock(r basics.Round) (agreement.UnfinishedBlock, error) {
return testValidatedBlock{Inside: bookkeeping.Block{BlockHeader: bookkeeping.BlockHeader{Round: r}}}, nil
}

Expand Down
13 changes: 9 additions & 4 deletions agreement/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,11 @@ func (b testValidatedBlock) Block() bookkeeping.Block {
return b.Inside
}

func (b testValidatedBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) AssembledBlock {
func (b testValidatedBlock) Round() basics.Round {
return b.Inside.Round()
}

func (b testValidatedBlock) FinishBlock(s committee.Seed, proposer basics.Address, eligible bool) ProposableBlock {
b.Inside.BlockHeader.Seed = s
b.Inside.BlockHeader.Proposer = proposer
if !eligible {
Expand All @@ -184,7 +188,7 @@ type testBlockFactory struct {
Owner int
}

func (f testBlockFactory) AssembleBlock(r basics.Round) (AssembledBlock, error) {
func (f testBlockFactory) AssembleBlock(r basics.Round, _ []basics.Address) (UnfinishedBlock, error) {
return testValidatedBlock{Inside: bookkeeping.Block{BlockHeader: bookkeeping.BlockHeader{Round: r}}}, nil
}

Expand Down Expand Up @@ -417,7 +421,7 @@ type testAccountData struct {
}

func makeProposalsTesting(accs testAccountData, round basics.Round, period period, factory BlockFactory, ledger Ledger) (ps []proposal, vs []vote) {
ve, err := factory.AssembleBlock(round)
ve, err := factory.AssembleBlock(round, accs.addresses)
if err != nil {
logging.Base().Errorf("Could not generate a proposal for round %d: %v", round, err)
return nil, nil
Expand Down Expand Up @@ -529,8 +533,9 @@ func (v *voteMakerHelper) MakeRandomProposalValue() *proposalValue {

func (v *voteMakerHelper) MakeRandomProposalPayload(t *testing.T, r round) (*proposal, *proposalValue) {
f := testBlockFactory{Owner: 1}
ve, err := f.AssembleBlock(r)
ue, err := f.AssembleBlock(r, nil)
require.NoError(t, err)
ve := ue.FinishBlock(committee.Seed{}, basics.Address{}, false)

var payload unauthenticatedProposal
payload.Block = ve.Block()
Expand Down
8 changes: 6 additions & 2 deletions agreement/fuzzer/ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@ func (b testValidatedBlock) Block() bookkeeping.Block {
return b.Inside
}

func (b testValidatedBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) agreement.AssembledBlock {
func (b testValidatedBlock) Round() basics.Round {
return b.Inside.Round()
}

func (b testValidatedBlock) FinishBlock(s committee.Seed, proposer basics.Address, eligible bool) agreement.ProposableBlock {
b.Inside.BlockHeader.Seed = s
b.Inside.BlockHeader.Proposer = proposer
if !eligible {
Expand All @@ -112,7 +116,7 @@ type testBlockFactory struct {
Owner int
}

func (f testBlockFactory) AssembleBlock(r basics.Round) (agreement.AssembledBlock, error) {
func (f testBlockFactory) AssembleBlock(r basics.Round, _ []basics.Address) (agreement.UnfinishedBlock, error) {
return testValidatedBlock{Inside: bookkeeping.Block{BlockHeader: bookkeeping.BlockHeader{Round: r}}}, nil
}

Expand Down
4 changes: 3 additions & 1 deletion agreement/player_permutation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ import (
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/committee"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/test/partitiontest"
)

func makeRandomProposalPayload(r round) *proposal {
f := testBlockFactory{Owner: 1}
ve, _ := f.AssembleBlock(r)
ue, _ := f.AssembleBlock(r, nil)
ve := ue.FinishBlock(committee.Seed{}, basics.Address{}, false)

var payload unauthenticatedProposal
payload.Block = ve.Block()
Expand Down
10 changes: 5 additions & 5 deletions agreement/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ type proposal struct {
validatedAt time.Duration
}

func makeProposalFromAssembledBlock(blk AssembledBlock, pf crypto.VrfProof, origPer period, origProp basics.Address) proposal {
func makeProposalFromProposableBlock(blk ProposableBlock, pf crypto.VrfProof, origPer period, origProp basics.Address) proposal {
e := blk.Block()
var payload unauthenticatedProposal
payload.Block = e
Expand Down Expand Up @@ -295,8 +295,8 @@ func payoutEligible(rnd basics.Round, proposer basics.Address, ledger LedgerRead
return eligible, balanceRecord, nil
}

func proposalForBlock(address basics.Address, vrf *crypto.VRFSecrets, blk AssembledBlock, period period, ledger LedgerReader) (proposal, proposalValue, error) {
rnd := blk.Block().Round()
func proposalForBlock(address basics.Address, vrf *crypto.VRFSecrets, blk UnfinishedBlock, period period, ledger LedgerReader) (proposal, proposalValue, error) {
rnd := blk.Round()

cparams, err := ledger.ConsensusParams(ParamsRound(rnd))
if err != nil {
Expand All @@ -313,8 +313,8 @@ func proposalForBlock(address basics.Address, vrf *crypto.VRFSecrets, blk Assemb
return proposal{}, proposalValue{}, fmt.Errorf("proposalForBlock: could determine eligibility: %w", err)
}

blk = blk.WithProposer(newSeed, address, eligible)
prop := makeProposalFromAssembledBlock(blk, seedProof, period, address)
proposableBlock := blk.FinishBlock(newSeed, address, eligible)
prop := makeProposalFromProposableBlock(proposableBlock, seedProof, period, address)

value := proposalValue{
OriginalPeriod: period,
Expand Down
16 changes: 8 additions & 8 deletions agreement/proposalStore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func TestBlockAssemblerPipeline(t *testing.T) {

round := player.Round
period := player.Period
testBlockFactory, err := factory.AssembleBlock(player.Round)
testBlockFactory, err := factory.AssembleBlock(player.Round, accounts.addresses)
require.NoError(t, err, "Could not generate a proposal for round %d: %v", round, err)

accountIndex := 0
Expand Down Expand Up @@ -132,7 +132,7 @@ func TestBlockAssemblerBind(t *testing.T) {

player, _, accounts, factory, ledger := testSetup(0)

testBlockFactory, err := factory.AssembleBlock(player.Round)
testBlockFactory, err := factory.AssembleBlock(player.Round, accounts.addresses)
require.NoError(t, err, "Could not generate a proposal for round %d: %v", player.Round, err)

accountIndex := 0
Expand Down Expand Up @@ -200,7 +200,7 @@ func TestBlockAssemblerAuthenticator(t *testing.T) {

player, _, accounts, factory, ledger := testSetup(0)

testBlockFactory, err := factory.AssembleBlock(player.Round)
testBlockFactory, err := factory.AssembleBlock(player.Round, accounts.addresses)
require.NoError(t, err, "Could not generate a proposal for round %d: %v", player.Round, err)
accountIndex := 0
proposalPayload, _, _ := proposalForBlock(accounts.addresses[accountIndex], accounts.vrfs[accountIndex], testBlockFactory, player.Period, ledger)
Expand Down Expand Up @@ -266,7 +266,7 @@ func TestBlockAssemblerTrim(t *testing.T) {

player, _, accounts, factory, ledger := testSetup(0)

testBlockFactory, err := factory.AssembleBlock(player.Round)
testBlockFactory, err := factory.AssembleBlock(player.Round, accounts.addresses)
require.NoError(t, err, "Could not generate a proposal for round %d: %v", player.Round, err)
accountIndex := 0
proposalPayload, _, _ := proposalForBlock(accounts.addresses[accountIndex], accounts.vrfs[accountIndex], testBlockFactory, player.Period, ledger)
Expand Down Expand Up @@ -339,7 +339,7 @@ func TestProposalStoreT(t *testing.T) {

player, _, accounts, factory, ledger := testSetup(0)

testBlockFactory, err := factory.AssembleBlock(player.Round)
testBlockFactory, err := factory.AssembleBlock(player.Round, accounts.addresses)
require.NoError(t, err, "Could not generate a proposal for round %d: %v", player.Round, err)
accountIndex := 0
proposalPayload, proposalV, _ := proposalForBlock(accounts.addresses[accountIndex], accounts.vrfs[accountIndex], testBlockFactory, player.Period, ledger)
Expand Down Expand Up @@ -413,7 +413,7 @@ func TestProposalStoreUnderlying(t *testing.T) {

player, _, accounts, factory, ledger := testSetup(0)

testBlockFactory, err := factory.AssembleBlock(player.Round)
testBlockFactory, err := factory.AssembleBlock(player.Round, accounts.addresses)
require.NoError(t, err, "Could not generate a proposal for round %d: %v", player.Round, err)
accountIndex := 0
proposalPayload, proposalV, _ := proposalForBlock(accounts.addresses[accountIndex], accounts.vrfs[accountIndex], testBlockFactory, player.Period, ledger)
Expand Down Expand Up @@ -477,7 +477,7 @@ func TestProposalStoreHandle(t *testing.T) {

proposalVoteEventBatch, proposalPayloadEventBatch, _ := generateProposalEvents(t, player, accounts, factory, ledger)

testBlockFactory, err := factory.AssembleBlock(player.Round)
testBlockFactory, err := factory.AssembleBlock(player.Round, accounts.addresses)
require.NoError(t, err, "Could not generate a proposal for round %d: %v", player.Round, err)
accountIndex := 0
_, proposalV0, _ := proposalForBlock(accounts.addresses[accountIndex], accounts.vrfs[accountIndex], testBlockFactory, player.Period, ledger)
Expand Down Expand Up @@ -661,7 +661,7 @@ func TestProposalStoreGetPinnedValue(t *testing.T) {

// create proposal Store
player, router, accounts, factory, ledger := testPlayerSetup()
testBlockFactory, err := factory.AssembleBlock(player.Round)
testBlockFactory, err := factory.AssembleBlock(player.Round, accounts.addresses)
require.NoError(t, err, "Could not generate a proposal for round %d: %v", player.Round, err)
accountIndex := 0
// create a route handler for the proposal store
Expand Down
6 changes: 3 additions & 3 deletions agreement/proposal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func testSetup(periodCount uint64) (player, rootRouter, testAccountData, testBlo
}

func createProposalsTesting(accs testAccountData, round basics.Round, period period, factory BlockFactory, ledger Ledger) (ps []proposal, vs []vote) {
ve, err := factory.AssembleBlock(round)
ve, err := factory.AssembleBlock(round, accs.addresses)
if err != nil {
logging.Base().Errorf("Could not generate a proposal for round %d: %v", round, err)
return nil, nil
Expand Down Expand Up @@ -122,7 +122,7 @@ func TestProposalFunctions(t *testing.T) {
player, _, accs, factory, ledger := testSetup(0)
round := player.Round
period := player.Period
ve, err := factory.AssembleBlock(player.Round)
ve, err := factory.AssembleBlock(player.Round, accs.addresses)
require.NoError(t, err, "Could not generate a proposal for round %d: %v", round, err)

validator := testBlockValidator{}
Expand Down Expand Up @@ -162,7 +162,7 @@ func TestProposalUnauthenticated(t *testing.T) {

round := player.Round
period := player.Period
testBlockFactory, err := factory.AssembleBlock(player.Round)
testBlockFactory, err := factory.AssembleBlock(player.Round, accounts.addresses)
require.NoError(t, err, "Could not generate a proposal for round %d: %v", round, err)

validator := testBlockValidator{}
Expand Down
6 changes: 5 additions & 1 deletion agreement/pseudonode.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,11 @@ func (n asyncPseudonode) makePseudonodeVerifier(voteVerifier *AsyncVoteVerifier)

// makeProposals creates a slice of block proposals for the given round and period.
func (n asyncPseudonode) makeProposals(round basics.Round, period period, accounts []account.ParticipationRecordForRound) ([]proposal, []unauthenticatedVote) {
ve, err := n.factory.AssembleBlock(round)
addresses := make([]basics.Address, len(accounts))
for i := range accounts {
addresses[i] = accounts[i].Account
}
ve, err := n.factory.AssembleBlock(round, addresses)
if err != nil {
if err != ErrAssembleBlockRoundStale {
n.log.Errorf("pseudonode.makeProposals: could not generate a proposal for round %d: %v", round, err)
Expand Down
11 changes: 8 additions & 3 deletions data/datatest/impls.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ type entryFactoryImpl struct {
}

// AssembleBlock implements Ledger.AssembleBlock.
func (i entryFactoryImpl) AssembleBlock(round basics.Round) (agreement.AssembledBlock, error) {
func (i entryFactoryImpl) AssembleBlock(round basics.Round, _ []basics.Address) (agreement.UnfinishedBlock, error) {
prev, err := i.l.BlockHdr(round - 1)
if err != nil {
return nil, fmt.Errorf("could not make proposals: could not read block from ledger at round %v: %v", round, err)
Expand All @@ -64,8 +64,8 @@ func (i entryFactoryImpl) AssembleBlock(round basics.Round) (agreement.Assembled
return validatedBlock{blk: &b}, nil
}

// WithProposer implements the agreement.AssembledBlock interface.
func (ve validatedBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) agreement.AssembledBlock {
// FinishBlock implements the agreement.UnfinishedBlock interface.
func (ve validatedBlock) FinishBlock(s committee.Seed, proposer basics.Address, eligible bool) agreement.ProposableBlock {
newblock := *ve.blk
newblock.BlockHeader.Seed = s
newblock.BlockHeader.Proposer = proposer
Expand All @@ -80,6 +80,11 @@ func (ve validatedBlock) Block() bookkeeping.Block {
return *ve.blk
}

// Round implements the agreement.UnfinishedBlock interface.
func (ve validatedBlock) Round() basics.Round {
return ve.blk.Round()
}

type ledgerImpl struct {
l *data.Ledger
}
Expand Down
28 changes: 19 additions & 9 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -1301,24 +1301,34 @@ func (vb validatedBlock) Block() bookkeeping.Block {
return blk
}

// assembledBlock satisfies agreement.AssembledBlock
type assembledBlock struct {
// unfinishedBlock satisfies agreement.UnfinishedBlock
type unfinishedBlock struct {
blk bookkeeping.Block
}

// WithProposer satisfies the agreement.ValidatedBlock interface.
func (ab assembledBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) agreement.AssembledBlock {
// proposableBlock satisfies agreement.ProposableBlock
type proposableBlock struct {
blk bookkeeping.Block
}

// FinishBlock satisfies the agreement.UnfinishedBlock interface.
func (ab unfinishedBlock) FinishBlock(s committee.Seed, proposer basics.Address, eligible bool) agreement.ProposableBlock {
nb := ab.blk.WithProposer(s, proposer, eligible)
return assembledBlock{blk: nb}
return proposableBlock{blk: nb}
}

// Round satisfies the agreement.UnfinishedBlock interface.
func (ab unfinishedBlock) Round() basics.Round {
return ab.blk.Round()
}

// Block satisfies the agreement.AssembledBlock interface.
func (ab assembledBlock) Block() bookkeeping.Block {
// Block satisfies the agreement.ProposableBlock interface.
func (ab proposableBlock) Block() bookkeeping.Block {
return ab.blk
}

// AssembleBlock implements Ledger.AssembleBlock.
func (node *AlgorandFullNode) AssembleBlock(round basics.Round) (agreement.AssembledBlock, error) {
func (node *AlgorandFullNode) AssembleBlock(round basics.Round, addrs []basics.Address) (agreement.UnfinishedBlock, error) {
deadline := time.Now().Add(node.config.ProposalAssemblyTime)
lvb, err := node.transactionPool.AssembleBlock(round, deadline)
if err != nil {
Expand All @@ -1339,7 +1349,7 @@ func (node *AlgorandFullNode) AssembleBlock(round basics.Round) (agreement.Assem
}
return nil, err
}
return assembledBlock{blk: lvb.Block()}, nil
return unfinishedBlock{blk: lvb.Block()}, nil
}

// getOfflineClosedStatus will return an int with the appropriate bit(s) set if it is offline and/or online
Expand Down

0 comments on commit 2c40125

Please sign in to comment.