Skip to content

Commit d2954e5

Browse files
authored
Eval: Prefetching for heartbeat transactions (#6182)
1 parent de1c241 commit d2954e5

File tree

8 files changed

+175
-102
lines changed

8 files changed

+175
-102
lines changed

daemon/algod/api/algod.oas2.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@
245245
},
246246
"/v2/accounts/{address}": {
247247
"get": {
248-
"description": "Given a specific account public key, this call returns the accounts status, balance and spendable amounts",
248+
"description": "Given a specific account public key, this call returns the account's status, balance and spendable amounts",
249249
"tags": [
250250
"public",
251251
"nonparticipating"

daemon/algod/api/algod.oas3.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2978,7 +2978,7 @@
29782978
},
29792979
"/v2/accounts/{address}": {
29802980
"get": {
2981-
"description": "Given a specific account public key, this call returns the accounts status, balance and spendable amounts",
2981+
"description": "Given a specific account public key, this call returns the account's status, balance and spendable amounts",
29822982
"operationId": "AccountInformation",
29832983
"parameters": [
29842984
{

daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go

Lines changed: 94 additions & 94 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

data/transactions/logic/eval_test.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3218,7 +3218,21 @@ func TestIllegalOp(t *testing.T) {
32183218
}
32193219
}
32203220

3221-
func TestShortProgram(t *testing.T) {
3221+
func TestShortSimple(t *testing.T) {
3222+
partitiontest.PartitionTest(t)
3223+
3224+
t.Parallel()
3225+
for v := uint64(1); v <= AssemblerMaxVersion; v++ {
3226+
t.Run(fmt.Sprintf("v=%d", v), func(t *testing.T) {
3227+
ops := testProg(t, `int 8; store 7`, v)
3228+
testLogicBytes(t, ops.Program[:len(ops.Program)-1], nil,
3229+
"program ends short of immediate values",
3230+
"program ends short of immediate values")
3231+
})
3232+
}
3233+
}
3234+
3235+
func TestShortBranch(t *testing.T) {
32223236
partitiontest.PartitionTest(t)
32233237

32243238
t.Parallel()

data/transactions/transaction.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ func (tx Header) Alive(tc TxnContext) error {
325325

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

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

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

722721
switch tx.Type {
@@ -733,6 +732,8 @@ func (tx Transaction) RelevantAddrs(spec SpecialAddresses) []basics.Address {
733732
if !tx.AssetTransferTxnFields.AssetSender.IsZero() {
734733
addrs = append(addrs, tx.AssetTransferTxnFields.AssetSender)
735734
}
735+
case protocol.HeartbeatTx:
736+
addrs = append(addrs, tx.HeartbeatTxnFields.HbAddress)
736737
}
737738

738739
return addrs

ledger/eval/eval.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,6 +1612,10 @@ func (eval *BlockEvaluator) recordProposal() error {
16121612
return nil
16131613
}
16141614

1615+
// proposerPayout determines how much the proposer should be paid, assuming it
1616+
// gets paid at all. It may not examine the actual proposer because it is
1617+
// called before the proposer is known. Agreement might zero out this value
1618+
// when the actual proposer is decided, if that proposer is ineligible.
16151619
func (eval *BlockEvaluator) proposerPayout() (basics.MicroAlgos, error) {
16161620
incentive, _ := basics.NewPercent(eval.proto.Payouts.Percent).DivvyAlgos(eval.block.FeesCollected)
16171621
total, o := basics.OAddA(incentive, eval.block.Bonus)

ledger/eval/prefetcher/prefetcher.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,9 @@ func (p *accountPrefetcher) prefetch(ctx context.Context) {
343343
// since they might be non-used arbitrary values
344344

345345
case protocol.StateProofTx:
346-
case protocol.KeyRegistrationTx:
346+
case protocol.KeyRegistrationTx: // No extra accounts besides the sender
347+
case protocol.HeartbeatTx:
348+
loadAccountsAddAccountTask(&stxn.Txn.HbAddress, task, accountTasks, queue)
347349
}
348350

349351
// If you add new addresses here, also add them in getTxnAddresses().

ledger/eval/prefetcher/prefetcher_alignment_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/algorand/go-algorand/crypto/stateproof"
3131
"github.com/algorand/go-algorand/data/basics"
3232
"github.com/algorand/go-algorand/data/bookkeeping"
33+
"github.com/algorand/go-algorand/data/committee"
3334
"github.com/algorand/go-algorand/data/stateproofmsg"
3435
"github.com/algorand/go-algorand/data/transactions"
3536
"github.com/algorand/go-algorand/ledger/eval"
@@ -1422,3 +1423,54 @@ func TestEvaluatorPrefetcherAlignmentStateProof(t *testing.T) {
14221423
prefetched.pretend(rewardsPool())
14231424
require.Equal(t, requested, prefetched)
14241425
}
1426+
1427+
func TestEvaluatorPrefetcherAlignmentHeartbeat(t *testing.T) {
1428+
partitiontest.PartitionTest(t)
1429+
1430+
// We need valid part keys to evaluate the Heartbeat.
1431+
const kd = 10
1432+
firstID := basics.OneTimeIDForRound(0, kd)
1433+
otss := crypto.GenerateOneTimeSignatureSecrets(firstID.Batch, 5)
1434+
1435+
l := &prefetcherAlignmentTestLedger{
1436+
balances: map[basics.Address]ledgercore.AccountData{
1437+
rewardsPool(): {
1438+
AccountBaseData: ledgercore.AccountBaseData{
1439+
MicroAlgos: basics.MicroAlgos{Raw: 1234567890},
1440+
},
1441+
},
1442+
makeAddress(1): {
1443+
AccountBaseData: ledgercore.AccountBaseData{
1444+
MicroAlgos: basics.MicroAlgos{Raw: 1000001},
1445+
},
1446+
},
1447+
makeAddress(2): {
1448+
AccountBaseData: ledgercore.AccountBaseData{
1449+
MicroAlgos: basics.MicroAlgos{Raw: 100_000},
1450+
},
1451+
VotingData: basics.VotingData{
1452+
VoteID: otss.OneTimeSignatureVerifier,
1453+
},
1454+
},
1455+
},
1456+
}
1457+
1458+
txn := transactions.Transaction{
1459+
Type: protocol.HeartbeatTx,
1460+
Header: transactions.Header{
1461+
Sender: makeAddress(1),
1462+
GenesisHash: genesisHash(),
1463+
Fee: basics.Algos(1), // Heartbeat txn is unusual in that it checks fees a bit.
1464+
},
1465+
HeartbeatTxnFields: transactions.HeartbeatTxnFields{
1466+
HbAddress: makeAddress(2),
1467+
HbProof: otss.Sign(firstID, committee.Seed(genesisHash())).ToHeartbeatProof(),
1468+
HbSeed: committee.Seed(genesisHash()),
1469+
},
1470+
}
1471+
1472+
requested, prefetched := run(t, l, txn)
1473+
1474+
prefetched.pretend(rewardsPool())
1475+
require.Equal(t, requested, prefetched)
1476+
}

0 commit comments

Comments
 (0)