Skip to content

Commit

Permalink
Small CI fixups
Browse files Browse the repository at this point in the history
  • Loading branch information
jannotti committed Oct 15, 2024
1 parent eb2acd4 commit 6f3f3c1
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 127 deletions.
29 changes: 26 additions & 3 deletions data/transactions/logic/ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,14 @@ import (
)

type balanceRecord struct {
addr basics.Address
auth basics.Address
balance uint64
addr basics.Address
auth basics.Address
balance uint64
voting basics.VotingData

proposed basics.Round // The last round that this account proposed the accepted block
heartbeat basics.Round // The last round that this account sent a heartbeat to show it was online.

locals map[basics.AppIndex]basics.TealKeyValue
holdings map[basics.AssetIndex]basics.AssetHolding
mods map[basics.AppIndex]map[string]basics.ValueDelta
Expand Down Expand Up @@ -119,6 +124,18 @@ func (l *Ledger) NewAccount(addr basics.Address, balance uint64) {
l.balances[addr] = newBalanceRecord(addr, balance)
}

// NewVoting sets VoteID on the account. Could expand to set other voting data
// if that became useful in tests.
func (l *Ledger) NewVoting(addr basics.Address, voteID crypto.OneTimeSignatureVerifier) {
br, ok := l.balances[addr]
if !ok {
br = newBalanceRecord(addr, 0)
}
br.voting.VoteID = voteID
br.voting.VoteKeyDilution = 10_000
l.balances[addr] = br
}

// NewApp add a new AVM app to the Ledger. In most uses, it only sets up the id
// and schema but no code, as testing will want to try many different code
// sequences.
Expand Down Expand Up @@ -312,7 +329,11 @@ func (l *Ledger) AccountData(addr basics.Address) (ledgercore.AccountData, error

TotalBoxes: uint64(boxesTotal),
TotalBoxBytes: uint64(boxBytesTotal),

LastProposed: br.proposed,
LastHeartbeat: br.heartbeat,
},
VotingData: br.voting,
}, nil
}

Expand Down Expand Up @@ -952,6 +973,8 @@ func (l *Ledger) Get(addr basics.Address, withPendingRewards bool) (basics.Accou
Assets: map[basics.AssetIndex]basics.AssetHolding{},
AppLocalStates: map[basics.AppIndex]basics.AppLocalState{},
AppParams: map[basics.AppIndex]basics.AppParams{},
LastProposed: br.proposed,
LastHeartbeat: br.heartbeat,
}, nil
}

Expand Down
6 changes: 3 additions & 3 deletions heartbeat/abstractions.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2019-2023 Algorand, Inc.
// Copyright (C) 2019-2024 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -30,8 +30,8 @@ type txnBroadcaster interface {
BroadcastInternalSignedTxGroup([]transactions.SignedTxn) error
}

// ledger represents the aspects of the "real" Ledger that heartbeat needs.
// to interact with.
// ledger represents the aspects of the "real" Ledger that the heartbeat service
// needs to interact with
type ledger interface {
// LastRound tells the round is ready for checking
LastRound() basics.Round
Expand Down
2 changes: 1 addition & 1 deletion heartbeat/service.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2019-2023 Algorand, Inc.
// Copyright (C) 2019-2024 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
Expand Down
155 changes: 35 additions & 120 deletions heartbeat/service_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2019-2023 Algorand, Inc.
// Copyright (C) 2019-2024 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
Expand All @@ -21,6 +21,7 @@ import (
"testing"
"time"

"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/data/account"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
Expand Down Expand Up @@ -69,6 +70,7 @@ type mockedLedger struct {
waiters map[basics.Round]chan struct{}
history []table
version protocol.ConsensusVersion
hdrs map[basics.Round]bookkeeping.BlockHeader
}

func newMockedLedger() mockedLedger {
Expand Down Expand Up @@ -110,12 +112,25 @@ func (l *mockedLedger) WaitMem(r basics.Round) chan struct{} {

// BlockHdr allows the service access to consensus values
func (l *mockedLedger) BlockHdr(r basics.Round) (bookkeeping.BlockHeader, error) {
if r > l.LastRound() {
return bookkeeping.BlockHeader{}, fmt.Errorf("%d is beyond current block (%d)", r, l.LastRound())
}
if hdr, ok := l.hdrs[r]; ok {
return hdr, nil
}
// just return a simple hdr
var hdr bookkeeping.BlockHeader
hdr.Round = r
hdr.CurrentProtocol = l.version
return hdr, nil
}

// addHeader places a block header into the ledger's history. It is used to make
// challenges occur as we'd like.
func (l *mockedLedger) addHeader(hdr bookkeeping.BlockHeader) {
l.hdrs[hdr.Round] = hdr
}

func (l *mockedLedger) addBlock(delta table) error {
l.mu.Lock()
defer l.mu.Unlock()
Expand Down Expand Up @@ -197,7 +212,7 @@ func makeBlock(r basics.Round) bookkeeping.Block {
}
}

func TestHeartBeatOnlyWhenSuspended(t *testing.T) {
func TestHeartBeatOnlyWhenChallenged(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()

Expand All @@ -208,15 +223,8 @@ func TestHeartBeatOnlyWhenSuspended(t *testing.T) {
s := NewService(accts, &ledger, &sink, logging.TestingLog(t))
s.Start()

// ensure Donor can pay
a.NoError(ledger.addBlock(table{Donor: ledgercore.AccountData{
AccountBaseData: ledgercore.AccountBaseData{
MicroAlgos: basics.MicroAlgos{Raw: 1_000_000},
},
}}))
a.Empty(sink)

joe := basics.Address{1, 1}
// joe is a simple, non-online account, service will not heartbeat
joe := basics.Address{0xcc} // 0xcc will matter when we set the challenge
accts.add(joe)

acct := ledgercore.AccountData{}
Expand All @@ -225,123 +233,30 @@ func TestHeartBeatOnlyWhenSuspended(t *testing.T) {
ledger.waitFor(s, a)
a.Empty(sink)

// now joe is online, but not challenged, so no heartbeat
acct.Status = basics.Online

a.NoError(ledger.addBlock(table{joe: acct}))
a.Empty(sink)

acct.Status = basics.Suspended
// now we have to make it seem like joe has been challenged. We obtain the
// payout rules to find the first challenge round, skip forward to it, then
// go forward half a grace period. Only then should the service heartbeat
hdr, err := ledger.BlockHdr(ledger.LastRound())
a.NoError(err)
rules := config.Consensus[hdr.CurrentProtocol].Payouts
for ledger.LastRound() < basics.Round(rules.ChallengeInterval) {
a.NoError(ledger.addBlock(table{}))
ledger.waitFor(s, a)
a.Empty(sink)
}

a.NoError(ledger.addBlock(table{joe: acct}))
ledger.waitFor(s, a)
a.Len(sink, 1) // only one heartbeat so far
a.Len(sink[0], 1) // will probably end up being 3 to pay for `heartbeat` opcode
a.Len(sink, 1) // only one heartbeat so far
a.Len(sink[0], 1)
a.Equal(sink[0][0].Txn.Type, protocol.HeartbeatTx)
a.Equal(sink[0][0].Txn.HeartbeatAddress, joe)

s.Stop()
}

func TestHeartBeatOnlyWhenDonorFunded(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()

a := require.New(t)
sink := txnSink{}
accts := &mockParticipants{}
ledger := newMockedLedger()
s := NewService(accts, &ledger, &sink, logging.TestingLog(t))
s.Start()

joe := basics.Address{1, 1}
accts.add(joe)

acct := ledgercore.AccountData{}

a.NoError(ledger.addBlock(table{joe: acct}))
a.Empty(sink)

acct.Status = basics.Suspended

a.NoError(ledger.addBlock(table{joe: acct}))
ledger.waitFor(s, a)
a.Empty(sink) // no funded donor, no heartbeat

// Donor exists, has enough for fee, but not enough when MBR is considered
a.NoError(ledger.addBlock(table{Donor: ledgercore.AccountData{
AccountBaseData: ledgercore.AccountBaseData{
MicroAlgos: basics.MicroAlgos{Raw: 100_000},
},
}}))
a.NoError(ledger.addBlock(table{joe: acct}))
ledger.waitFor(s, a)
a.Empty(sink)

a.NoError(ledger.addBlock(table{Donor: ledgercore.AccountData{
AccountBaseData: ledgercore.AccountBaseData{
MicroAlgos: basics.MicroAlgos{Raw: 200_000},
},
}}))
ledger.waitFor(s, a)
a.Len(sink, 1) // only one heartbeat so far
a.Len(sink[0], 1) // will probably end up being 3 to pay for `heartbeat` opcode
s.Stop()
}

func TestHeartBeatForm(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()

a := require.New(t)
sink := txnSink{}
accts := &mockParticipants{}
ledger := newMockedLedger()
s := NewService(accts, &ledger, &sink, logging.TestingLog(t))
s.Start()

joe := basics.Address{1, 1}
accts.add(joe)

// Fund the donor, suspend joe
a.NoError(ledger.addBlock(table{
Donor: ledgercore.AccountData{
AccountBaseData: ledgercore.AccountBaseData{
MicroAlgos: basics.MicroAlgos{Raw: 200_000},
},
},
joe: ledgercore.AccountData{
AccountBaseData: ledgercore.AccountBaseData{
Status: basics.Suspended,
MicroAlgos: basics.MicroAlgos{Raw: 2_000_000},
},
},
}))
ledger.waitFor(s, a)
a.Len(sink, 1) // only one heartbeat so far
a.Len(sink[0], 1) // will probably end up being 3 to pay for `heartbeat` opcode

grp := sink[0]
require.Equal(t, grp[0].Txn.Sender, Donor)
require.Equal(t, grp[0].Lsig, transactions.LogicSig{Logic: DonorByteCode})

a.NoError(ledger.addBlock(nil))
ledger.waitFor(s, a)
a.Len(sink, 2) // still suspended, another heartbeat
inc := sink[0]
inc[0].Txn.FirstValid++
inc[0].Txn.LastValid++
a.Equal(inc, sink[1])

// mark joe online again
a.NoError(ledger.addBlock(table{
joe: ledgercore.AccountData{
AccountBaseData: ledgercore.AccountBaseData{
Status: basics.Online,
MicroAlgos: basics.MicroAlgos{Raw: 2_000_000},
},
},
}))
ledger.waitFor(s, a)
a.Len(sink, 2) // no further heartbeat

s.Stop()

}

0 comments on commit 6f3f3c1

Please sign in to comment.