Skip to content

Commit 1ca4ef8

Browse files
authored
Introduce V28 consensus version (#2255)
* TEAL v4 * Larger programs * Larger app/asset lookup limits * Longer asset URL * Fee pooling within a group * Keyreg txn additional checks Removed InitialRewardsRateCalculation and PaysetCommit from vFuture since it is already in v26 Fixed some tests after exposing zero fees and strict keyreg as current consensus
1 parent 02eacd1 commit 1ca4ef8

File tree

8 files changed

+93
-67
lines changed

8 files changed

+93
-67
lines changed

config/consensus.go

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ type ConsensusParams struct {
8989
// DefaultKeyDilution specifies the granularity of top-level ephemeral
9090
// keys. KeyDilution is the number of second-level keys in each batch,
9191
// signed by a top-level "batch" key. The default value can be
92-
// overriden in the account state.
92+
// overridden in the account state.
9393
DefaultKeyDilution uint64
9494

9595
// MinBalance specifies the minimum balance that can appear in
@@ -938,52 +938,51 @@ func initConsensusProtocols() {
938938
// a bit :
939939
v26.ApprovedUpgrades[protocol.ConsensusV27] = 60000
940940

941-
// ConsensusFuture is used to test features that are implemented
942-
// but not yet released in a production protocol version.
943-
vFuture := v27
944-
vFuture.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
945-
946-
// Let the bytes value take more space. Key+Value is still limited to 128
947-
vFuture.MaxAppBytesValueLen = 128
948-
949-
// FilterTimeout for period 0 should take a new optimized, configured value, need to revisit this later
950-
vFuture.AgreementFilterTimeoutPeriod0 = 4 * time.Second
951-
952-
// Enable compact certificates.
953-
vFuture.CompactCertRounds = 128
954-
vFuture.CompactCertTopVoters = 1024 * 1024
955-
vFuture.CompactCertVotersLookback = 16
956-
vFuture.CompactCertWeightThreshold = (1 << 32) * 30 / 100
957-
vFuture.CompactCertSecKQ = 128
958-
959-
vFuture.EnableKeyregCoherencyCheck = true
941+
// v28 introduces new TEAL features, larger program size, fee pooling and longer asset max URL
942+
v28 := v27
943+
v28.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
960944

945+
// Enable TEAL 4
946+
v28.LogicSigVersion = 4
961947
// Enable support for larger app program size
962-
vFuture.MaxExtraAppProgramPages = 3
963-
vFuture.MaxAppProgramLen = 2048
948+
v28.MaxExtraAppProgramPages = 3
949+
v28.MaxAppProgramLen = 2048
950+
// Increase asset URL length to allow for IPFS URLs
951+
v28.MaxAssetURLBytes = 96
952+
// Let the bytes value take more space. Key+Value is still limited to 128
953+
v28.MaxAppBytesValueLen = 128
964954

965955
// Individual limits raised
966-
vFuture.MaxAppTxnForeignApps = 8
967-
vFuture.MaxAppTxnForeignAssets = 8
968-
// but MaxAppTxnReferences is unchanged.
956+
v28.MaxAppTxnForeignApps = 8
957+
v28.MaxAppTxnForeignAssets = 8
969958

970959
// MaxAppTxnAccounts has not been raised yet. It is already
971960
// higher (4) and there is a multiplicative effect in
972961
// "reachability" between accounts and creatables, so we
973962
// retain 4 x 4 as worst case.
974963

975-
// enable the InitialRewardsRateCalculation fix
976-
vFuture.InitialRewardsRateCalculation = true
977-
// Enable transaction Merkle tree.
978-
vFuture.PaysetCommit = PaysetCommitMerkle
964+
v28.EnableFeePooling = true
965+
v28.EnableKeyregCoherencyCheck = true
979966

980-
// Enable TEAL 4
981-
vFuture.LogicSigVersion = 4
967+
Consensus[protocol.ConsensusV28] = v28
982968

983-
// Increase asset URL length to allow for IPFS URLs
984-
vFuture.MaxAssetURLBytes = 96
969+
// v27 can be upgraded to v28, with an update delay of 7 days ( see calculation above )
970+
v27.ApprovedUpgrades[protocol.ConsensusV28] = 140000
985971

986-
vFuture.EnableFeePooling = true
972+
// ConsensusFuture is used to test features that are implemented
973+
// but not yet released in a production protocol version.
974+
vFuture := v28
975+
vFuture.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
976+
977+
// FilterTimeout for period 0 should take a new optimized, configured value, need to revisit this later
978+
vFuture.AgreementFilterTimeoutPeriod0 = 4 * time.Second
979+
980+
// Enable compact certificates.
981+
vFuture.CompactCertRounds = 128
982+
vFuture.CompactCertTopVoters = 1024 * 1024
983+
vFuture.CompactCertVotersLookback = 16
984+
vFuture.CompactCertWeightThreshold = (1 << 32) * 30 / 100
985+
vFuture.CompactCertSecKQ = 128
987986

988987
Consensus[protocol.ConsensusFuture] = vFuture
989988
}

data/transactions/transaction_test.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,12 @@ func generateDummyGoNonparticpatingTransaction(addr basics.Address) (tx Transact
6868
FirstValid: 1,
6969
LastValid: 300,
7070
},
71-
KeyregTxnFields: KeyregTxnFields{Nonparticipation: true},
71+
KeyregTxnFields: KeyregTxnFields{
72+
Nonparticipation: true,
73+
VoteFirst: 0,
74+
VoteLast: 0,
75+
},
7276
}
73-
tx.KeyregTxnFields.VoteFirst = 1
74-
tx.KeyregTxnFields.VoteLast = 300
75-
tx.KeyregTxnFields.VoteKeyDilution = 1
7677

7778
tx.KeyregTxnFields.Nonparticipation = true
7879
return tx
@@ -250,9 +251,20 @@ func TestWellFormedErrors(t *testing.T) {
250251
},
251252
},
252253
spec: specialAddr,
253-
proto: curProto,
254+
proto: protoV27,
254255
expectedError: makeMinFeeErrorf("transaction had fee %d, which is less than the minimum %d", 100, curProto.MinTxnFee),
255256
},
257+
{
258+
tx: Transaction{
259+
Type: protocol.PaymentTx,
260+
Header: Header{
261+
Sender: addr1,
262+
Fee: basics.MicroAlgos{Raw: 100},
263+
},
264+
},
265+
spec: specialAddr,
266+
proto: curProto,
267+
},
256268
{
257269
tx: Transaction{
258270
Type: protocol.PaymentTx,
@@ -426,7 +438,7 @@ func TestWellFormedErrors(t *testing.T) {
426438
Header: okHeader,
427439
ApplicationCallTxnFields: ApplicationCallTxnFields{
428440
ApplicationID: 1,
429-
Accounts: []basics.Address{basics.Address{}, basics.Address{}, basics.Address{}},
441+
Accounts: []basics.Address{{}, {}, {}},
430442
ForeignApps: []basics.AppIndex{14, 15, 16, 17},
431443
ForeignAssets: []basics.AssetIndex{14, 15, 16, 17},
432444
},

ledger/apply/keyreg_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ func TestKeyregApply(t *testing.T) {
9494
KeyregTxnFields: transactions.KeyregTxnFields{
9595
VotePK: crypto.OneTimeSignatureVerifier(secretParticipation.SignatureVerifier),
9696
SelectionPK: vrfSecrets.PK,
97+
VoteFirst: 0,
98+
VoteLast: 100,
9799
},
98100
}
99101
err := Keyreg(tx.KeyregTxnFields, tx.Header, makeMockBalances(protocol.ConsensusCurrentVersion), transactions.SpecialAddresses{FeeSink: feeSink}, nil, basics.Round(0))

ledger/apply/payment_test.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ func TestPaymentValidation(t *testing.T) {
149149
txn.GenesisHash = genHash
150150
payments[i] = txn
151151
}
152+
tcpast := transactions.ExplicitTxnContext{
153+
Proto: config.Consensus[protocol.ConsensusV27],
154+
GenHash: genHash,
155+
}
152156
tc := transactions.ExplicitTxnContext{
153157
Proto: config.Consensus[protocol.ConsensusCurrentVersion],
154158
GenHash: genHash,
@@ -218,14 +222,16 @@ func TestPaymentValidation(t *testing.T) {
218222

219223
badFee := txn
220224
badFee.Fee = basics.MicroAlgos{}
221-
if badFee.WellFormed(spec, tc.Proto) == nil {
225+
if badFee.WellFormed(spec, tcpast.Proto) == nil {
222226
t.Errorf("transaction with no fee %#v verified incorrectly", badFee)
223227
}
228+
require.Nil(t, badFee.WellFormed(spec, tc.Proto))
229+
224230
badFee.Fee.Raw = 1
225-
if badFee.WellFormed(spec, tc.Proto) == nil {
231+
if badFee.WellFormed(spec, tcpast.Proto) == nil {
226232
t.Errorf("transaction with low fee %#v verified incorrectly", badFee)
227233
}
228-
234+
require.Nil(t, badFee.WellFormed(spec, tc.Proto))
229235
}
230236
}
231237

node/node.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ func (node *AlgorandFullNode) AssembleBlock(round basics.Round, deadline time.Ti
10691069
return validatedBlock{vb: lvb}, nil
10701070
}
10711071

1072-
// VotingKeys implements the key maanger's VotingKeys method, and provides additional validation with the ledger.
1072+
// VotingKeys implements the key manager's VotingKeys method, and provides additional validation with the ledger.
10731073
// that allows us to load multiple overlapping keys for the same account, and filter these per-round basis.
10741074
func (node *AlgorandFullNode) VotingKeys(votingRound, keysRound basics.Round) []account.Participation {
10751075
keys := node.accountManager.Keys(votingRound)

protocol/consensus.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ const ConsensusV27 = ConsensusVersion(
148148
"https://github.com/algorandfoundation/specs/tree/d050b3cade6d5c664df8bd729bf219f179812595",
149149
)
150150

151+
// ConsensusV28 introduces new TEAL features, larger program size, fee pooling and longer asset max URL
152+
const ConsensusV28 = ConsensusVersion(
153+
"https://github.com/algorandfoundation/specs/tree/65b4ab3266c52c56a0fa7d591754887d68faad0a",
154+
)
155+
151156
// ConsensusFuture is a protocol that should not appear in any production
152157
// network, but is used to test features before they are released.
153158
const ConsensusFuture = ConsensusVersion(
@@ -160,7 +165,7 @@ const ConsensusFuture = ConsensusVersion(
160165

161166
// ConsensusCurrentVersion is the latest version and should be used
162167
// when a specific version is not provided.
163-
const ConsensusCurrentVersion = ConsensusV27
168+
const ConsensusCurrentVersion = ConsensusV28
164169

165170
// Error is used to indicate that an unsupported protocol has been detected.
166171
type Error ConsensusVersion

test/e2e-go/features/participation/overlappingParticipationKeys_test.go

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package participation
1818

1919
import (
2020
"context"
21+
"encoding/hex"
2122
"os"
2223
"path/filepath"
2324
"runtime"
@@ -44,8 +45,10 @@ func TestOverlappingParticipationKeys(t *testing.T) {
4445
consensus := make(config.ConsensusProtocols)
4546
shortPartKeysProtocol := config.Consensus[protocol.ConsensusCurrentVersion]
4647
shortPartKeysProtocol.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
48+
// keys round = current - 2 * (2 * 1) (see selector.go)
49+
// new keys must exist at least 4 rounds prior use
4750
shortPartKeysProtocol.SeedLookback = 2
48-
shortPartKeysProtocol.SeedRefreshInterval = 8
51+
shortPartKeysProtocol.SeedRefreshInterval = 1
4952
if runtime.GOARCH == "amd64" {
5053
// amd64 platforms are generally quite capable, so accelerate the round times to make the test run faster.
5154
shortPartKeysProtocol.AgreementFilterTimeoutPeriod0 = 1 * time.Second
@@ -55,6 +58,8 @@ func TestOverlappingParticipationKeys(t *testing.T) {
5558

5659
var fixture fixtures.RestClientFixture
5760
fixture.SetConsensus(consensus)
61+
// ShortParticipationKeys template has LastPartKeyRound=8
62+
// to allow the 3rd key to be registered and appear after 4+4 round for its first use
5863
fixture.SetupNoStart(t, filepath.Join("nettemplates", "ShortParticipationKeys.json"))
5964
defer fixture.Shutdown()
6065

@@ -72,7 +77,7 @@ func TestOverlappingParticipationKeys(t *testing.T) {
7277
genesisHash := crypto.HashObj(genesis)
7378
rootKeys := make(map[int]*account.Root)
7479
regTransactions := make(map[int]transactions.SignedTxn)
75-
lastRound := uint64(64)
80+
lastRound := uint64(39) // check 3 rounds of keys rotations
7681

7782
// prepare the participation keys ahead of time.
7883
for round := uint64(1); round < lastRound; round++ {
@@ -81,9 +86,9 @@ func TestOverlappingParticipationKeys(t *testing.T) {
8186
}
8287
acctIdx := (round - 1) % 10
8388
txStartRound := round
84-
txEndRound := txStartRound + 36 + 10
85-
regStartRound := round + 32
86-
regEndRound := regStartRound + 11
89+
txEndRound := txStartRound + 10 + 4
90+
regStartRound := round
91+
regEndRound := regStartRound + 11 + 4
8792
err = prepareParticipationKey(a, &fixture, acctIdx, txStartRound, txEndRound, regStartRound, regEndRound, genesisHash, rootKeys, regTransactions)
8893
a.NoError(err)
8994
}
@@ -97,13 +102,13 @@ func TestOverlappingParticipationKeys(t *testing.T) {
97102
currentRound++
98103
if (currentRound-1)%10 < uint64(accountsNum) {
99104
acctIdx := (currentRound - 1) % 10
100-
startRound := currentRound + 2
101-
endRound := startRound + 36 + 10 - 2
102-
regStartRound := currentRound + 32
103-
regEndRound := regStartRound + 11
104-
err = addParticipationKey(a, &fixture, acctIdx, startRound, endRound, regTransactions)
105+
startRound := currentRound + 2 // +2 and -2 below to balance, start/end must match in part key file name
106+
endRound := startRound + 10 + 4 - 2
107+
regStartRound := currentRound
108+
regEndRound := regStartRound + 11 + 4
109+
pk, err := addParticipationKey(a, &fixture, acctIdx, startRound, endRound, regTransactions)
105110
a.NoError(err)
106-
t.Logf("[.] Round %d, Added reg key for node %d range [%d..%d]\n", currentRound, acctIdx, regStartRound, regEndRound)
111+
t.Logf("[.] Round %d, Added reg key for node %d range [%d..%d] %s\n", currentRound, acctIdx, regStartRound, regEndRound, hex.EncodeToString(pk[:8]))
107112
} else {
108113
t.Logf("[.] Round %d\n", currentRound)
109114
}
@@ -115,25 +120,22 @@ func TestOverlappingParticipationKeys(t *testing.T) {
115120

116121
}
117122

118-
func addParticipationKey(a *require.Assertions, fixture *fixtures.RestClientFixture, acctNum uint64, startRound, endRound uint64, regTransactions map[int]transactions.SignedTxn) error {
123+
func addParticipationKey(a *require.Assertions, fixture *fixtures.RestClientFixture, acctNum uint64, startRound, endRound uint64, regTransactions map[int]transactions.SignedTxn) (crypto.OneTimeSignatureVerifier, error) {
119124
dataDir := fixture.NodeDataDirs()[acctNum]
120125
nc := fixture.GetNodeControllerForDataDir(dataDir)
121126
genesisDir, err := nc.GetGenesisDir()
122127

123128
partKeyName := filepath.Join(dataDir, config.PartKeyFilename("Wallet", startRound, endRound))
124129
partKeyNameTarget := filepath.Join(genesisDir, config.PartKeyFilename("Wallet", startRound, endRound))
125130

126-
// make the rename in the background to ensure it won't take too long. We have ~32 rounds to complete this.
131+
// make the rename in the background to ensure it won't take too long. We have ~4 rounds to complete this.
127132
go os.Rename(partKeyName, partKeyNameTarget)
128133

129134
signedTxn := regTransactions[int(startRound-2)]
130135
a.NotEmpty(signedTxn.Sig)
131136
_, err = fixture.GetAlgodClientForController(nc).SendRawTransaction(signedTxn)
132-
if err != nil {
133-
a.NoError(err)
134-
return err
135-
}
136-
return err
137+
a.NoError(err)
138+
return signedTxn.Txn.KeyregTxnFields.VotePK, err
137139
}
138140

139141
func prepareParticipationKey(a *require.Assertions, fixture *fixtures.RestClientFixture, acctNum uint64, txStartRound, txEndRound, regStartRound, regEndRound uint64, genesisHash crypto.Digest, rootKeys map[int]*account.Root, regTransactions map[int]transactions.SignedTxn) error {
@@ -190,15 +192,15 @@ func prepareParticipationKey(a *require.Assertions, fixture *fixtures.RestClient
190192
return err
191193
}
192194

193-
persistedPerticipation, err := account.FillDBWithParticipationKeys(partkeyHandle, rootAccount.Address(), basics.Round(regStartRound), basics.Round(regEndRound), fixture.LibGoalFixture.Genesis().PartKeyDilution)
195+
persistedParticipation, err := account.FillDBWithParticipationKeys(partkeyHandle, rootAccount.Address(), basics.Round(regStartRound), basics.Round(regEndRound), fixture.LibGoalFixture.Genesis().PartKeyDilution)
194196
if err != nil {
195197
a.NoError(err)
196198
return err
197199
}
198200
partkeyHandle.Vacuum(context.Background())
199-
persistedPerticipation.Close()
201+
persistedParticipation.Close()
200202

201-
unsignedTxn := persistedPerticipation.GenerateRegistrationTransaction(basics.MicroAlgos{Raw: 1000}, basics.Round(txStartRound), basics.Round(txEndRound), [32]byte{})
203+
unsignedTxn := persistedParticipation.GenerateRegistrationTransaction(basics.MicroAlgos{Raw: 1000}, basics.Round(txStartRound), basics.Round(txEndRound), [32]byte{})
202204
copy(unsignedTxn.GenesisHash[:], genesisHash[:])
203205
if err != nil {
204206
a.NoError(err)

test/testdata/nettemplates/ShortParticipationKeys.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"NetworkName": "shortpartkeys",
44
"ConsensusProtocol": "shortpartkeysprotocol",
55
"FirstPartKeyRound": 0,
6-
"LastPartKeyRound": 36,
6+
"LastPartKeyRound": 8,
77
"PartKeyDilution": 8,
88
"Wallets": [
99
{

0 commit comments

Comments
 (0)