Skip to content

Commit f3be4a3

Browse files
authored
Merge pull request #6297 from Algo-devops-service/relstable4.0.3
2 parents 6b94028 + 31875fb commit f3be4a3

File tree

8 files changed

+191
-26
lines changed

8 files changed

+191
-26
lines changed

.github/workflows/codegen_verification.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66
pull_request:
77
jobs:
88
codegen_verification:
9-
runs-on: ubuntu-20.04
9+
runs-on: ubuntu-22.04
1010
services:
1111
converter:
1212
image: swaggerapi/swagger-converter@sha256:dcfd1c2537f5f271cb4ec942d08aa59ca41b9a24078040061a772afca7e548ae # v1.0.4

Makefile

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ else
2020
endif
2121
S3_RELEASE_BUCKET = $$S3_RELEASE_BUCKET
2222

23-
GOLANG_VERSIONS := $(shell ./scripts/get_golang_version.sh all)
24-
GOLANG_VERSION_BUILD := $(firstword $(GOLANG_VERSIONS))
25-
GOLANG_VERSION_SUPPORT := $(lastword $(GOLANG_VERSIONS))
26-
GOLANG_VERSION_BUILD_MAJOR := $(shell echo $(GOLANG_VERSION_BUILD) | cut -d'.' -f1,2)
27-
CURRENT_GO_VERSION := $(shell go version | cut -d " " -f 3 | tr -d 'go')
28-
CURRENT_GO_VERSION_MAJOR := $(shell echo $(CURRENT_GO_VERSION) | cut -d'.' -f1,2)
23+
GOLANG_VERSIONS := $(shell ./scripts/get_golang_version.sh all)
24+
GOLANG_VERSION_BUILD := $(firstword $(GOLANG_VERSIONS))
25+
GOLANG_VERSION_BUILD_MAJOR := $(shell echo $(GOLANG_VERSION_BUILD) | cut -d'.' -f1,2)
26+
GOLANG_VERSION_MIN := $(lastword $(GOLANG_VERSIONS))
27+
GOLANG_VERSION_SUPPORT := $(shell echo $(GOLANG_VERSION_MIN) | cut -d'.' -f1,2)
28+
CURRENT_GO_VERSION := $(shell go version | cut -d " " -f 3 | tr -d 'go')
29+
CURRENT_GO_VERSION_MAJOR := $(shell echo $(CURRENT_GO_VERSION) | cut -d'.' -f1,2)
2930

3031
# If build number already set, use it - to ensure same build number across multiple platforms being built
3132
BUILDNUMBER ?= $(shell ./scripts/compute_build_number.sh)

buildnumber.dat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2
1+
3

ledger/acctdeltas.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,14 @@ func onlineAccountsNewRoundImpl(
10321032
prevAcct = updated
10331033
}
10341034
} else {
1035+
if prevAcct.AccountData.IsVotingEmpty() && newAcct.IsVotingEmpty() {
1036+
// if both old and new are offline, ignore
1037+
// otherwise the following could happen:
1038+
// 1. there are multiple offline account deltas so all of them could be inserted
1039+
// 2. delta.oldAcct is often pulled from a cache that is only updated on new rows insert so
1040+
// it could pull a very old already deleted offline value resulting one more insert
1041+
continue
1042+
}
10351043
// "delete" by inserting a zero entry
10361044
var ref trackerdb.OnlineAccountRef
10371045
ref, err = writer.InsertOnlineAccount(data.address, 0, trackerdb.BaseOnlineAccountData{}, updRound, 0)

ledger/acctdeltas_test.go

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3442,3 +3442,160 @@ func TestEncodedBaseResourceSize(t *testing.T) {
34423442
require.Less(t, len(encodedAsset), len(encodedApp))
34433443
require.GreaterOrEqual(t, MaxEncodedBaseResourceDataSize, len(encodedApp))
34443444
}
3445+
3446+
// TestOnlineAccountsExceedOfflineRows checks for extra rows for offline accounts in online accounts table:
3447+
// 1. Account is online
3448+
// 2. Account goes offline and recorded in baseOnlineAccounts cache
3449+
// 3. Many (>320 normally) rounds later, account gets deleted by prunning
3450+
// 4. Account updated with a transfer
3451+
// 5. Since it is still in baseOnlineAccounts, it fetched as offline and a new offline row is inserted
3452+
// ==> 5 <== could lead to a ghost row in online accounts table that:
3453+
// - are not needed but still correct
3454+
// - make catchpoint generation inconsistent across nodes since it content depends on dynamic baseOnlineAccounts cache.
3455+
//
3456+
// 6. A similar behavior is exposed when there are multiple offline updates in a batch with the same result
3457+
// of extra unnesesary rows in the online accounts table.
3458+
func TestOnlineAccountsExceedOfflineRows(t *testing.T) {
3459+
partitiontest.PartitionTest(t)
3460+
t.Parallel()
3461+
3462+
dbs, _ := storetesting.DbOpenTest(t, true)
3463+
storetesting.SetDbLogging(t, dbs)
3464+
defer dbs.Close()
3465+
3466+
tx, err := dbs.Wdb.Handle.Begin()
3467+
require.NoError(t, err)
3468+
defer tx.Rollback()
3469+
3470+
proto := config.Consensus[protocol.ConsensusCurrentVersion]
3471+
3472+
var accts map[basics.Address]basics.AccountData
3473+
sqlitedriver.AccountsInitTest(t, tx, accts, protocol.ConsensusCurrentVersion)
3474+
3475+
addrA := ledgertesting.RandomAddress()
3476+
3477+
// acct A is new, offline and then online => exercise new entry for account
3478+
deltaA := onlineAccountDelta{
3479+
address: addrA,
3480+
newAcct: []trackerdb.BaseOnlineAccountData{
3481+
{
3482+
MicroAlgos: basics.MicroAlgos{Raw: 100_000_000},
3483+
BaseVotingData: trackerdb.BaseVotingData{VoteFirstValid: 1, VoteLastValid: 5},
3484+
},
3485+
{
3486+
MicroAlgos: basics.MicroAlgos{Raw: 100_000_000},
3487+
},
3488+
},
3489+
updRound: []uint64{1, 2},
3490+
newStatus: []basics.Status{basics.Online, basics.Offline},
3491+
}
3492+
updates := compactOnlineAccountDeltas{}
3493+
updates.deltas = append(updates.deltas, deltaA)
3494+
writer, err := sqlitedriver.MakeOnlineAccountsSQLWriter(tx, updates.len() > 0)
3495+
require.NoError(t, err)
3496+
defer writer.Close()
3497+
3498+
lastUpdateRound := basics.Round(2)
3499+
updated, err := onlineAccountsNewRoundImpl(writer, updates, proto, lastUpdateRound)
3500+
require.NoError(t, err)
3501+
require.Len(t, updated, 2)
3502+
3503+
var baseOnlineAccounts lruOnlineAccounts
3504+
baseOnlineAccounts.init(logging.TestingLog(t), 1000, 800)
3505+
for _, persistedAcct := range updated {
3506+
baseOnlineAccounts.write(persistedAcct)
3507+
}
3508+
3509+
// make sure baseOnlineAccounts has the entry
3510+
entry, has := baseOnlineAccounts.read(addrA)
3511+
require.True(t, has)
3512+
require.True(t, entry.AccountData.IsVotingEmpty())
3513+
require.Equal(t, basics.Round(2), entry.UpdRound)
3514+
3515+
queries, err := sqlitedriver.OnlineAccountsInitDbQueries(tx)
3516+
require.NoError(t, err)
3517+
3518+
// make sure both rows are in the db
3519+
history, _, err := queries.LookupOnlineHistory(addrA)
3520+
require.NoError(t, err)
3521+
require.Len(t, history, 2)
3522+
// ASC ordered by updRound
3523+
require.False(t, history[0].AccountData.IsVotingEmpty())
3524+
require.Equal(t, basics.Round(1), history[0].UpdRound)
3525+
require.True(t, history[1].AccountData.IsVotingEmpty())
3526+
require.Equal(t, basics.Round(2), history[1].UpdRound)
3527+
3528+
// test case 1
3529+
// simulate compact online delta construction with baseOnlineAccounts use
3530+
acctDelta := ledgercore.AccountDeltas{}
3531+
ad := ledgercore.AccountData{
3532+
AccountBaseData: ledgercore.AccountBaseData{
3533+
Status: basics.Offline,
3534+
MicroAlgos: basics.MicroAlgos{Raw: 100_000_000 - 1},
3535+
},
3536+
}
3537+
acctDelta.Upsert(addrA, ad)
3538+
deltas := []ledgercore.AccountDeltas{acctDelta}
3539+
updates = makeCompactOnlineAccountDeltas(deltas, 3, baseOnlineAccounts)
3540+
3541+
// make sure old is filled from baseOnlineAccounts
3542+
require.Empty(t, updates.misses)
3543+
require.Len(t, updates.deltas, 1)
3544+
require.NotEmpty(t, updates.deltas[0].oldAcct)
3545+
require.True(t, updates.deltas[0].oldAcct.AccountData.IsVotingEmpty())
3546+
require.Equal(t, 1, updates.deltas[0].nOnlineAcctDeltas)
3547+
require.Equal(t, basics.Offline, updates.deltas[0].newStatus[0])
3548+
require.True(t, updates.deltas[0].newAcct[0].IsVotingEmpty())
3549+
3550+
// insert and make sure no new rows are inserted
3551+
lastUpdateRound = basics.Round(3)
3552+
updated, err = onlineAccountsNewRoundImpl(writer, updates, proto, lastUpdateRound)
3553+
require.NoError(t, err)
3554+
require.Len(t, updated, 0)
3555+
3556+
history, _, err = queries.LookupOnlineHistory(addrA)
3557+
require.NoError(t, err)
3558+
require.Len(t, history, 2)
3559+
3560+
// test case 2
3561+
// multiple offline entries in a single batch
3562+
3563+
addrB := ledgertesting.RandomAddress()
3564+
3565+
// acct A is new, offline and then online => exercise new entry for account
3566+
deltaB := onlineAccountDelta{
3567+
address: addrB,
3568+
newAcct: []trackerdb.BaseOnlineAccountData{
3569+
{
3570+
MicroAlgos: basics.MicroAlgos{Raw: 100_000_000},
3571+
BaseVotingData: trackerdb.BaseVotingData{VoteFirstValid: 1, VoteLastValid: 5},
3572+
},
3573+
{
3574+
MicroAlgos: basics.MicroAlgos{Raw: 100_000_000},
3575+
},
3576+
{
3577+
MicroAlgos: basics.MicroAlgos{Raw: 100_000_000 - 1},
3578+
},
3579+
},
3580+
updRound: []uint64{4, 5, 6},
3581+
newStatus: []basics.Status{basics.Online, basics.Offline, basics.Offline},
3582+
}
3583+
updates = compactOnlineAccountDeltas{}
3584+
updates.deltas = append(updates.deltas, deltaB)
3585+
3586+
lastUpdateRound = basics.Round(4)
3587+
updated, err = onlineAccountsNewRoundImpl(writer, updates, proto, lastUpdateRound)
3588+
require.NoError(t, err)
3589+
require.Len(t, updated, 2) // 3rd update is ignored
3590+
3591+
// make sure the last offline entry is ignored
3592+
history, _, err = queries.LookupOnlineHistory(addrB)
3593+
require.NoError(t, err)
3594+
require.Len(t, history, 2)
3595+
3596+
// ASC ordered by updRound
3597+
require.False(t, history[0].AccountData.IsVotingEmpty())
3598+
require.Equal(t, basics.Round(4), history[0].UpdRound)
3599+
require.True(t, history[1].AccountData.IsVotingEmpty())
3600+
require.Equal(t, basics.Round(5), history[1].UpdRound)
3601+
}

ledger/catchpointtracker.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,12 @@ func (ct *catchpointTracker) finishFirstStageAfterCrash(dbRound basics.Round, bl
326326
return err
327327
}
328328

329-
// pass dbRound+1-maxBalLookback as the onlineAccountsForgetBefore parameter: since we can't be sure whether
329+
// pass 0 as the onlineAccountsForgetBefore parameter: since we can't be sure whether
330330
// there are more than 320 rounds of history in the online accounts tables, this ensures the catchpoint
331331
// will only contain the most recent 320 rounds.
332-
onlineAccountsForgetBefore := catchpointLookbackHorizonForNextRound(dbRound, config.Consensus[blockProto])
332+
// Inside finishFirstStage, this has the same effect as the voters tracker returning a "lowestRound" of 0,
333+
// which causes finishFirstStage to calculate the correct horizon and filter out data older than dbround+1-320.
334+
onlineAccountsForgetBefore := basics.Round(0)
333335
return ct.finishFirstStage(context.Background(), dbRound, onlineAccountsForgetBefore, blockProto, 0)
334336
}
335337

scripts/check_golang_version.sh

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,31 @@ set -eo pipefail
1515
read -ra GOLANG_VERSIONS <<< "$(./scripts/get_golang_version.sh all)"
1616
BUILD_VERSION="${GOLANG_VERSIONS[0]}"
1717
MIN_VERSION="${GOLANG_VERSIONS[1]}"
18-
GO_MOD_SUPPORT="${GOLANG_VERSIONS[2]}"
1918

2019
# Get the field "go1.1.1" and then remove the "go" prefix.
2120
SYSTEM_GOLANG_VERSION=$(go version | awk '{ gsub(/go/, "", $3); print $3 }')
2221

2322
# https://golang.org/doc/go1.11#modules
24-
if [[ "${SYSTEM_GOLANG_VERSION}" < "$GO_MOD_SUPPORT" ]]; then
25-
echo "[$0] ERROR: The version of go on the system (${SYSTEM_GOLANG_VERSION}) is too old and does not support go modules. Please update to at least ${MIN_VERSION}"
23+
if [[ "$(printf '%s\n' ${SYSTEM_GOLANG_VERSION} 1.11 | sort -V | head -n1)" != "1.11" ]]; then
24+
echo "[$0] ERROR: The version of go on the system (${SYSTEM_GOLANG_VERSION}) is too old and does not support go modules. Please update to at least 1.11."
2625
exit 1
2726
fi
2827

29-
if [ "$1" == "dev" ]; then
30-
if [[ "${SYSTEM_GOLANG_VERSION}" < "${MIN_VERSION}" ]]; then
31-
echo "[$0] WARNING: The version of go on the system (${SYSTEM_GOLANG_VERSION}) is below the recommended version (${MIN_VERSION}) and therefore may not build correctly."
28+
if [[ "$(printf '%s\n' "$SYSTEM_GOLANG_VERSION" "$MIN_VERSION" | sort -V | head -n1)" != "$MIN_VERSION" ]]; then
29+
# We are below the minimum version
30+
if [ "$1" == "dev" ]; then
31+
echo "[$0] WARNING: The version of go on the system (${SYSTEM_GOLANG_VERSION}) is below the recommended minimum version (${MIN_VERSION}) and therefore may not build correctly."
3232
echo "[$0] Please update to at least ${MIN_VERSION}"
33-
fi
34-
elif [ "$1" == "build" ]; then
35-
if [[ "${SYSTEM_GOLANG_VERSION}" < "${MIN_VERSION}" ]]; then
36-
echo "[$0] ERROR: The version of go on the system (${SYSTEM_GOLANG_VERSION}) is below the necessary version (${MIN_VERSION}) and therefore will not build correctly."
33+
elif [ "$1" == "build" ]; then
34+
echo "[$0] ERROR: The version of go on the system (${SYSTEM_GOLANG_VERSION}) is below the necessary minimum version (${MIN_VERSION}) and therefore will not build correctly."
3735
exit 1
3836
fi
3937
else
4038
# Check to make sure that it matches what is specified in `go.mod`.
41-
GOMOD_VERSION=$(go mod edit -print | awk '/^go[ \t]+[0-9]+\.[0-9]+(\.[0-9]+)?[ \t]*$/{print $2}')
39+
GOMOD_TOOL_VERSION=$(go mod edit -print | awk '$1 == "toolchain" {sub(/^go/, "", $2); print $2}')
4240

43-
if [[ ! "${BUILD_VERSION}" =~ ^"${GOMOD_VERSION}" ]]; then
44-
echo "[$0] ERROR: go version mismatch, go mod version ${GOMOD_VERSION} does not match required version ${BUILD_VERSION}"
41+
if [[ "${BUILD_VERSION}" != "${GOMOD_TOOL_VERSION}" ]]; then
42+
echo "[$0] ERROR: go version mismatch, go mod tool version ${GOMOD_TOOL_VERSION} does not match required version ${BUILD_VERSION}"
4543
exit 1
4644
else
4745
echo "${BUILD_VERSION}"

scripts/get_golang_version.sh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@
1212
# build a new image whenever the version number has been changed.
1313

1414
BUILD=1.23.3
15-
MIN=1.23
16-
GO_MOD_SUPPORT=1.23
15+
MIN=$(echo $BUILD | cut -d. -f1-2).0
1716

1817
if [ "$1" = all ]
1918
then
20-
echo $BUILD $MIN $GO_MOD_SUPPORT
19+
echo $BUILD $MIN
2120
elif [ "$1" = dev ]
2221
then
2322
echo $MIN

0 commit comments

Comments
 (0)