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

agreement: split ValidatedBlock and AssembledBlock interfaces #19

Merged
merged 3 commits into from
Mar 29, 2024
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
29 changes: 18 additions & 11 deletions agreement/abstractions.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,6 @@ type BlockValidator interface {
// and can now be recorded in the ledger. This is an optimized version of
// calling EnsureBlock() on the Ledger.
type ValidatedBlock interface {
// WithProposer creates a copy of this ValidatedBlock 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.
//
// 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) ValidatedBlock

// Block returns the underlying block that has been validated.
Block() bookkeeping.Block
}
Expand All @@ -87,7 +77,24 @@ type BlockFactory interface {
// produce a ValidatedBlock 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) (ValidatedBlock, error)
AssembleBlock(basics.Round) (AssembledBlock, 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.
//
// 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

// Block returns the underlying block that has been assembled.
Block() bookkeeping.Block
}

// A Ledger represents the sequence of Entries agreed upon by the protocol.
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.ValidatedBlock {
func (b testValidatedBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) agreement.AssembledBlock {
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.ValidatedBlock, error) {
func (f testBlockFactory) AssembleBlock(r basics.Round) (agreement.AssembledBlock, error) {
return testValidatedBlock{Inside: bookkeeping.Block{BlockHeader: bookkeeping.BlockHeader{Round: r}}}, nil
}

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

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

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

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

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

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

Expand Down
32 changes: 21 additions & 11 deletions agreement/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,24 @@ type proposal struct {
validatedAt time.Duration
}

func makeProposal(ve ValidatedBlock, pf crypto.VrfProof, origPer period, origProp basics.Address) proposal {
func makeProposalFromAssembledBlock(blk AssembledBlock, pf crypto.VrfProof, origPer period, origProp basics.Address) proposal {
e := blk.Block()
var payload unauthenticatedProposal
payload.Block = e
payload.SeedProof = pf
payload.OriginalPeriod = origPer
payload.OriginalProposer = origProp
return proposal{unauthenticatedProposal: payload}
}

func makeProposalFromValidatedBlock(ve ValidatedBlock, pf crypto.VrfProof, origPer period, origProp basics.Address) proposal {
e := ve.Block()
var payload unauthenticatedProposal
payload.Block = e
payload.SeedProof = pf
payload.OriginalPeriod = origPer
payload.OriginalProposer = origProp
return proposal{unauthenticatedProposal: payload, ve: ve}
return proposal{unauthenticatedProposal: payload, ve: ve} // store ve to use when calling Ledger.EnsureValidatedBlock
}

func (p proposal) u() unauthenticatedProposal {
Expand Down Expand Up @@ -285,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, ve ValidatedBlock, period period, ledger LedgerReader) (proposal, proposalValue, error) {
rnd := ve.Block().Round()
func proposalForBlock(address basics.Address, vrf *crypto.VRFSecrets, blk AssembledBlock, period period, ledger LedgerReader) (proposal, proposalValue, error) {
rnd := blk.Block().Round()

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

ve = ve.WithProposer(newSeed, address, eligible)
proposal := makeProposal(ve, seedProof, period, address)
proposal.ve = nil
blk = blk.WithProposer(newSeed, address, eligible)
prop := makeProposalFromAssembledBlock(blk, seedProof, period, address)

value := proposalValue{
OriginalPeriod: period,
OriginalProposer: address,
BlockDigest: proposal.Block.Digest(),
EncodingDigest: crypto.HashObj(proposal),
BlockDigest: prop.Block.Digest(),
EncodingDigest: crypto.HashObj(prop),
}
return proposal, value, nil
return prop, value, nil
}

// validate returns true if the proposal is valid.
Expand All @@ -335,5 +345,5 @@ func (p unauthenticatedProposal) validate(ctx context.Context, current round, le
return invalid, fmt.Errorf("EntryValidator rejected entry: %w", err)
}

return makeProposal(ve, p.SeedProof, p.OriginalPeriod, p.OriginalProposer), nil
return makeProposalFromValidatedBlock(ve, p.SeedProof, p.OriginalPeriod, p.OriginalProposer), nil
}
18 changes: 18 additions & 0 deletions data/bookkeeping/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,24 @@ func (block Block) ProposerPayout() basics.MicroAlgos {
return block.BlockHeader.ProposerPayout
}

// WithProposer returns a copy of the Block with a modified seed and associated proposer
func (block Block) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) Block {
newblock := block
newblock.BlockHeader.Seed = s
// agreement is telling us who the proposer is and if they're eligible, but
// agreement does not consider the current config params, so here we decide
// what really goes into the BlockHeader.
proto := config.Consensus[block.CurrentProtocol]
if proto.Payouts.Enabled {
newblock.BlockHeader.Proposer = proposer
}
if !proto.Payouts.Enabled || !eligible {
newblock.BlockHeader.ProposerPayout = basics.MicroAlgos{}
}

return newblock
}

// NextRewardsState computes the RewardsState of the subsequent round
// given the subsequent consensus parameters, along with the incentive pool
// balance and the total reward units in the system as of the current round.
Expand Down
6 changes: 3 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.ValidatedBlock, error) {
func (i entryFactoryImpl) AssembleBlock(round basics.Round) (agreement.AssembledBlock, 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.Validated
return validatedBlock{blk: &b}, nil
}

// WithProposer implements the agreement.ValidatedBlock interface.
func (ve validatedBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) agreement.ValidatedBlock {
// WithProposer implements the agreement.AssembledBlock interface.
func (ve validatedBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) agreement.AssembledBlock {
newblock := *ve.blk
newblock.BlockHeader.Seed = s
newblock.BlockHeader.Proposer = proposer
Expand Down
6 changes: 3 additions & 3 deletions ledger/eval/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,7 @@ func (ledger *evalTestLedger) endBlock(t testing.TB, eval *BlockEvaluator) *ledg
// fake agreement's setting of header fields so later validates work.
seed := committee.Seed{}
crypto.RandBytes(seed[:])
*validatedBlock = validatedBlock.WithProposer(seed, testPoolAddr, true)
*validatedBlock = ledgercore.MakeValidatedBlock(validatedBlock.Block().WithProposer(seed, testPoolAddr, true), validatedBlock.Delta())
err = ledger.AddValidatedBlock(*validatedBlock, agreement.Certificate{})
require.NoError(t, err)
return validatedBlock
Expand Down Expand Up @@ -1212,7 +1212,7 @@ func TestEvalFunctionForExpiredAccounts(t *testing.T) {
require.NoError(t, err)

// fake agreement's setting of header fields so later validates work
*validatedBlock = validatedBlock.WithProposer(committee.Seed{}, testPoolAddr, true)
*validatedBlock = ledgercore.MakeValidatedBlock(validatedBlock.Block().WithProposer(committee.Seed{}, testPoolAddr, true), validatedBlock.Delta())

expired := false
for _, acct := range validatedBlock.Block().ExpiredParticipationAccounts {
Expand Down Expand Up @@ -1454,7 +1454,7 @@ func TestAbsenteeChecks(t *testing.T) {
require.NoError(t, err)

// fake agreement's setting of header fields so later validates work
*validatedBlock = validatedBlock.WithProposer(committee.Seed{}, testPoolAddr, true)
*validatedBlock = ledgercore.MakeValidatedBlock(validatedBlock.Block().WithProposer(committee.Seed{}, testPoolAddr, true), validatedBlock.Delta())

require.Zero(t, validatedBlock.Block().ExpiredParticipationAccounts)
require.Contains(t, validatedBlock.Block().AbsentParticipationAccounts, addrs[0], addrs[0].String())
Expand Down
24 changes: 0 additions & 24 deletions ledger/ledgercore/validatedBlock.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
package ledgercore

import (
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/data/committee"
)

// ValidatedBlock represents the result of a block validation. It can
Expand All @@ -41,27 +38,6 @@ func (vb ValidatedBlock) Delta() StateDelta {
return vb.delta
}

// WithProposer returns a copy of the ValidatedBlock with a modified seed and associated proposer
func (vb ValidatedBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) ValidatedBlock {
newblock := vb.blk
newblock.BlockHeader.Seed = s
// agreement is telling us who the proposer is and if they're eligible, but
// agreement does not consider the current config params, so here we decide
// what really goes into the BlockHeader.
proto := config.Consensus[vb.blk.CurrentProtocol]
if proto.Payouts.Enabled {
newblock.BlockHeader.Proposer = proposer
}
if !proto.Payouts.Enabled || !eligible {
newblock.BlockHeader.ProposerPayout = basics.MicroAlgos{}
}

return ValidatedBlock{
blk: newblock,
delta: vb.delta,
}
}

// MakeValidatedBlock creates a validated block.
func MakeValidatedBlock(blk bookkeeping.Block, delta StateDelta) ValidatedBlock {
return ValidatedBlock{
Expand Down
4 changes: 2 additions & 2 deletions ledger/simple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,11 @@
// can't call the agreement code, the eligibility of the prp is not
// considered.
if ledger.GenesisProto().Payouts.Enabled {
*gvb = gvb.WithProposer(committee.Seed(prp), prp, true)
*gvb = ledgercore.MakeValidatedBlock(vb.Block().WithProposer(committee.Seed(prp), prp, true), vb.Delta())

Check failure on line 164 in ledger/simple_test.go

View workflow job for this annotation

GitHub Actions / reviewdog-errors

[Lint Errors] reported by reviewdog 🐶 undefined: vb Raw Output: ledger/simple_test.go:164:40: undefined: vb

Check failure on line 164 in ledger/simple_test.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 undefined: vb Raw Output: ledger/simple_test.go:164:40: undefined: vb
} else {
// To more closely mimic the agreement code, we don't
// write the proposer when !Payouts.Enabled.
*gvb = gvb.WithProposer(committee.Seed(prp), basics.Address{}, false)
*gvb = ledgercore.MakeValidatedBlock(vb.Block().WithProposer(committee.Seed(prp), basics.Address{}, false), vb.Delta())

Check failure on line 168 in ledger/simple_test.go

View workflow job for this annotation

GitHub Actions / reviewdog-errors

[Lint Errors] reported by reviewdog 🐶 undefined: vb (typecheck) Raw Output: ledger/simple_test.go:168:40: undefined: vb (typecheck) // Copyright (C) 2019-2024 Algorand, Inc.

Check failure on line 168 in ledger/simple_test.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 undefined: vb (typecheck) Raw Output: ledger/simple_test.go:168:40: undefined: vb (typecheck) // Copyright (C) 2019-2024 Algorand, Inc.
}

vvb, err := validateWithoutSignatures(t, ledger, gvb.Block())
Expand Down
26 changes: 18 additions & 8 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -1290,20 +1290,30 @@ type validatedBlock struct {
vb *ledgercore.ValidatedBlock
}

// WithProposer satisfies the agreement.ValidatedBlock interface.
func (vb validatedBlock) WithProposer(s committee.Seed, proposer basics.Address, eligible bool) agreement.ValidatedBlock {
lvb := vb.vb.WithProposer(s, proposer, eligible)
return validatedBlock{vb: &lvb}
}

// Block satisfies the agreement.ValidatedBlock interface.
func (vb validatedBlock) Block() bookkeeping.Block {
blk := vb.vb.Block()
return blk
}

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

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

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

// AssembleBlock implements Ledger.AssembleBlock.
func (node *AlgorandFullNode) AssembleBlock(round basics.Round) (agreement.ValidatedBlock, error) {
func (node *AlgorandFullNode) AssembleBlock(round basics.Round) (agreement.AssembledBlock, error) {
deadline := time.Now().Add(node.config.ProposalAssemblyTime)
lvb, err := node.transactionPool.AssembleBlock(round, deadline)
if err != nil {
Expand All @@ -1324,7 +1334,7 @@ func (node *AlgorandFullNode) AssembleBlock(round basics.Round) (agreement.Valid
}
return nil, err
}
return validatedBlock{vb: lvb}, nil
return assembledBlock{blk: lvb.Block()}, nil
}

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