Skip to content

Commit

Permalink
Eval: Prefetching for heartbeat transactions (#6182)
Browse files Browse the repository at this point in the history
  • Loading branch information
jannotti authored Dec 3, 2024
1 parent de1c241 commit d2954e5
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 102 deletions.
2 changes: 1 addition & 1 deletion daemon/algod/api/algod.oas2.json
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@
},
"/v2/accounts/{address}": {
"get": {
"description": "Given a specific account public key, this call returns the accounts status, balance and spendable amounts",
"description": "Given a specific account public key, this call returns the account's status, balance and spendable amounts",
"tags": [
"public",
"nonparticipating"
Expand Down
2 changes: 1 addition & 1 deletion daemon/algod/api/algod.oas3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2978,7 +2978,7 @@
},
"/v2/accounts/{address}": {
"get": {
"description": "Given a specific account public key, this call returns the accounts status, balance and spendable amounts",
"description": "Given a specific account public key, this call returns the account's status, balance and spendable amounts",
"operationId": "AccountInformation",
"parameters": [
{
Expand Down
188 changes: 94 additions & 94 deletions daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion data/transactions/logic/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3218,7 +3218,21 @@ func TestIllegalOp(t *testing.T) {
}
}

func TestShortProgram(t *testing.T) {
func TestShortSimple(t *testing.T) {
partitiontest.PartitionTest(t)

t.Parallel()
for v := uint64(1); v <= AssemblerMaxVersion; v++ {
t.Run(fmt.Sprintf("v=%d", v), func(t *testing.T) {
ops := testProg(t, `int 8; store 7`, v)
testLogicBytes(t, ops.Program[:len(ops.Program)-1], nil,
"program ends short of immediate values",
"program ends short of immediate values")
})
}
}

func TestShortBranch(t *testing.T) {
partitiontest.PartitionTest(t)

t.Parallel()
Expand Down
9 changes: 5 additions & 4 deletions data/transactions/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ func (tx Header) Alive(tc TxnContext) error {

// MatchAddress checks if the transaction touches a given address.
func (tx Transaction) MatchAddress(addr basics.Address, spec SpecialAddresses) bool {
return slices.Contains(tx.RelevantAddrs(spec), addr)
return slices.Contains(tx.relevantAddrs(spec), addr)
}

var errKeyregTxnFirstVotingRoundGreaterThanLastVotingRound = errors.New("transaction first voting round need to be less than its last voting round")
Expand Down Expand Up @@ -714,9 +714,8 @@ func (tx Header) Last() basics.Round {
return tx.LastValid
}

// RelevantAddrs returns the addresses whose balance records this transaction will need to access.
// The header's default is to return just the sender and the fee sink.
func (tx Transaction) RelevantAddrs(spec SpecialAddresses) []basics.Address {
// relevantAddrs returns the addresses whose balance records this transaction will need to access.
func (tx Transaction) relevantAddrs(spec SpecialAddresses) []basics.Address {
addrs := []basics.Address{tx.Sender, spec.FeeSink}

switch tx.Type {
Expand All @@ -733,6 +732,8 @@ func (tx Transaction) RelevantAddrs(spec SpecialAddresses) []basics.Address {
if !tx.AssetTransferTxnFields.AssetSender.IsZero() {
addrs = append(addrs, tx.AssetTransferTxnFields.AssetSender)
}
case protocol.HeartbeatTx:
addrs = append(addrs, tx.HeartbeatTxnFields.HbAddress)
}

return addrs
Expand Down
4 changes: 4 additions & 0 deletions ledger/eval/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -1612,6 +1612,10 @@ func (eval *BlockEvaluator) recordProposal() error {
return nil
}

// proposerPayout determines how much the proposer should be paid, assuming it
// gets paid at all. It may not examine the actual proposer because it is
// called before the proposer is known. Agreement might zero out this value
// when the actual proposer is decided, if that proposer is ineligible.
func (eval *BlockEvaluator) proposerPayout() (basics.MicroAlgos, error) {
incentive, _ := basics.NewPercent(eval.proto.Payouts.Percent).DivvyAlgos(eval.block.FeesCollected)
total, o := basics.OAddA(incentive, eval.block.Bonus)
Expand Down
4 changes: 3 additions & 1 deletion ledger/eval/prefetcher/prefetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,9 @@ func (p *accountPrefetcher) prefetch(ctx context.Context) {
// since they might be non-used arbitrary values

case protocol.StateProofTx:
case protocol.KeyRegistrationTx:
case protocol.KeyRegistrationTx: // No extra accounts besides the sender
case protocol.HeartbeatTx:
loadAccountsAddAccountTask(&stxn.Txn.HbAddress, task, accountTasks, queue)
}

// If you add new addresses here, also add them in getTxnAddresses().
Expand Down
52 changes: 52 additions & 0 deletions ledger/eval/prefetcher/prefetcher_alignment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/algorand/go-algorand/crypto/stateproof"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/data/committee"
"github.com/algorand/go-algorand/data/stateproofmsg"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/ledger/eval"
Expand Down Expand Up @@ -1422,3 +1423,54 @@ func TestEvaluatorPrefetcherAlignmentStateProof(t *testing.T) {
prefetched.pretend(rewardsPool())
require.Equal(t, requested, prefetched)
}

func TestEvaluatorPrefetcherAlignmentHeartbeat(t *testing.T) {
partitiontest.PartitionTest(t)

// We need valid part keys to evaluate the Heartbeat.
const kd = 10
firstID := basics.OneTimeIDForRound(0, kd)
otss := crypto.GenerateOneTimeSignatureSecrets(firstID.Batch, 5)

l := &prefetcherAlignmentTestLedger{
balances: map[basics.Address]ledgercore.AccountData{
rewardsPool(): {
AccountBaseData: ledgercore.AccountBaseData{
MicroAlgos: basics.MicroAlgos{Raw: 1234567890},
},
},
makeAddress(1): {
AccountBaseData: ledgercore.AccountBaseData{
MicroAlgos: basics.MicroAlgos{Raw: 1000001},
},
},
makeAddress(2): {
AccountBaseData: ledgercore.AccountBaseData{
MicroAlgos: basics.MicroAlgos{Raw: 100_000},
},
VotingData: basics.VotingData{
VoteID: otss.OneTimeSignatureVerifier,
},
},
},
}

txn := transactions.Transaction{
Type: protocol.HeartbeatTx,
Header: transactions.Header{
Sender: makeAddress(1),
GenesisHash: genesisHash(),
Fee: basics.Algos(1), // Heartbeat txn is unusual in that it checks fees a bit.
},
HeartbeatTxnFields: transactions.HeartbeatTxnFields{
HbAddress: makeAddress(2),
HbProof: otss.Sign(firstID, committee.Seed(genesisHash())).ToHeartbeatProof(),
HbSeed: committee.Seed(genesisHash()),
},
}

requested, prefetched := run(t, l, txn)

prefetched.pretend(rewardsPool())
require.Equal(t, requested, prefetched)
}

0 comments on commit d2954e5

Please sign in to comment.