Skip to content

Commit 5df2b13

Browse files
authored
Merge pull request #962 from onetechnical/johnlee/beta2.0.13
Johnlee/beta2.0.13
2 parents da0f0c8 + 142261c commit 5df2b13

File tree

12 files changed

+369
-10
lines changed

12 files changed

+369
-10
lines changed

buildnumber.dat

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
12
1+
13

config/consensus.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,12 @@ type ConsensusParams struct {
192192
MaxTxGroupSize int
193193

194194
// support for transaction leases
195+
// note: if FixTransactionLeases is not set, the transaction
196+
// leases supported are faulty; specifically, they do not
197+
// enforce exclusion correctly when the FirstValid of
198+
// transactions do not match.
195199
SupportTransactionLeases bool
200+
FixTransactionLeases bool
196201

197202
// 0 for no support, otherwise highest version supported
198203
LogicSigVersion uint64
@@ -551,9 +556,18 @@ func initConsensusProtocols() {
551556
// v21 can be upgraded to v22.
552557
v21.ApprovedUpgrades[protocol.ConsensusV22] = 0
553558

559+
// v23 is an upgrade which fixes the behavior of leases so that
560+
// it conforms with the intended spec.
561+
v23 := v22
562+
v23.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
563+
v23.FixTransactionLeases = true
564+
Consensus[protocol.ConsensusV23] = v23
565+
// v22 can be upgraded to v23.
566+
v22.ApprovedUpgrades[protocol.ConsensusV23] = 10000
567+
554568
// ConsensusFuture is used to test features that are implemented
555569
// but not yet released in a production protocol version.
556-
vFuture := v22
570+
vFuture := v23
557571
vFuture.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}
558572
Consensus[protocol.ConsensusFuture] = vFuture
559573
}

data/bookkeeping/block.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ func (s UpgradeState) applyUpgradeVote(r basics.Round, vote UpgradeVote) (res Up
316316

317317
upgradeDelay := uint64(vote.UpgradeDelay)
318318
if upgradeDelay > params.MaxUpgradeWaitRounds || upgradeDelay < params.MinUpgradeWaitRounds {
319-
err = fmt.Errorf("applyUpgradeVote: proposed upgrade wait rounds %d out of permissible range", upgradeDelay)
319+
err = fmt.Errorf("applyUpgradeVote: proposed upgrade wait rounds %d out of permissible range [%d, %d]", upgradeDelay, params.MinUpgradeWaitRounds, params.MaxUpgradeWaitRounds)
320320
return
321321
}
322322

ledger/ledger_test.go

+80
Original file line numberDiff line numberDiff line change
@@ -777,3 +777,83 @@ func TestLedgerSingleTxApplyDataV18(t *testing.T) {
777777
func TestLedgerSingleTxApplyDataFuture(t *testing.T) {
778778
testLedgerSingleTxApplyData(t, protocol.ConsensusFuture)
779779
}
780+
781+
func TestLedgerRegressionFaultyLeaseFirstValidCheckOld(t *testing.T) {
782+
testLedgerRegressionFaultyLeaseFirstValidCheck2f3880f7(t, protocol.ConsensusV22)
783+
}
784+
785+
func TestLedgerRegressionFaultyLeaseFirstValidCheckV23(t *testing.T) {
786+
testLedgerRegressionFaultyLeaseFirstValidCheck2f3880f7(t, protocol.ConsensusV23)
787+
}
788+
789+
func TestLedgerRegressionFaultyLeaseFirstValidCheck(t *testing.T) {
790+
testLedgerRegressionFaultyLeaseFirstValidCheck2f3880f7(t, protocol.ConsensusCurrentVersion)
791+
}
792+
793+
func TestLedgerRegressionFaultyLeaseFirstValidCheckFuture(t *testing.T) {
794+
testLedgerRegressionFaultyLeaseFirstValidCheck2f3880f7(t, protocol.ConsensusFuture)
795+
}
796+
797+
func testLedgerRegressionFaultyLeaseFirstValidCheck2f3880f7(t *testing.T, version protocol.ConsensusVersion) {
798+
a := require.New(t)
799+
800+
backlogPool := execpool.MakeBacklog(nil, 0, execpool.LowPriority, nil)
801+
defer backlogPool.Shutdown()
802+
803+
genesisInitState, initSecrets := testGenerateInitState(t, version)
804+
const inMem = true
805+
const archival = true
806+
log := logging.TestingLog(t)
807+
l, err := OpenLedger(log, t.Name(), inMem, genesisInitState, archival)
808+
a.NoError(err, "could not open ledger")
809+
defer l.Close()
810+
811+
proto := config.Consensus[version]
812+
poolAddr := testPoolAddr
813+
sinkAddr := testSinkAddr
814+
815+
initAccounts := genesisInitState.Accounts
816+
var addrList []basics.Address
817+
for addr := range initAccounts {
818+
if addr != poolAddr && addr != sinkAddr {
819+
addrList = append(addrList, addr)
820+
}
821+
}
822+
823+
correctTxHeader := transactions.Header{
824+
Sender: addrList[0],
825+
Fee: basics.MicroAlgos{Raw: proto.MinTxnFee * 2},
826+
FirstValid: l.Latest() + 1,
827+
LastValid: l.Latest() + 10,
828+
GenesisID: t.Name(),
829+
GenesisHash: crypto.Hash([]byte(t.Name())),
830+
}
831+
832+
correctPayFields := transactions.PaymentTxnFields{
833+
Receiver: addrList[1],
834+
Amount: basics.MicroAlgos{Raw: initAccounts[addrList[0]].MicroAlgos.Raw / 10},
835+
}
836+
837+
correctPay := transactions.Transaction{
838+
Type: protocol.PaymentTx,
839+
Header: correctTxHeader,
840+
PaymentTxnFields: correctPayFields,
841+
}
842+
843+
var ad transactions.ApplyData
844+
845+
correctPayLease := correctPay
846+
correctPayLease.Sender = addrList[3]
847+
correctPayLease.Lease[0] = 1
848+
849+
a.NoError(l.appendUnvalidatedTx(t, initAccounts, initSecrets, correctPayLease, ad), "could not add initial payment transaction")
850+
851+
correctPayLease.FirstValid = l.Latest() + 1
852+
correctPayLease.LastValid = l.Latest() + 10
853+
854+
if proto.FixTransactionLeases {
855+
a.Error(l.appendUnvalidatedTx(t, initAccounts, initSecrets, correctPayLease, ad), "added payment transaction with overlapping lease")
856+
} else {
857+
a.NoError(l.appendUnvalidatedTx(t, initAccounts, initSecrets, correctPayLease, ad), "should allow leasing payment transaction with newer FirstValid")
858+
}
859+
}

ledger/txtail.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type txTail struct {
3636

3737
lastValid map[basics.Round]map[transactions.Txid]struct{} // map tx.LastValid -> tx confirmed set
3838

39-
// duplicate detection queries with LastValid not before
39+
// duplicate detection queries with LastValid before
4040
// lowWaterMark are not guaranteed to succeed
4141
lowWaterMark basics.Round // the last round known to be committed to disk
4242
}
@@ -128,7 +128,14 @@ func (t *txTail) isDup(proto config.ConsensusParams, current basics.Round, first
128128
}
129129

130130
if proto.SupportTransactionLeases && (txl.lease != [32]byte{}) {
131-
for rnd := firstValid; rnd <= lastValid; rnd++ {
131+
firstChecked := firstValid
132+
lastChecked := lastValid
133+
if proto.FixTransactionLeases {
134+
firstChecked = current.SubSaturate(basics.Round(proto.MaxTxnLife))
135+
lastChecked = current
136+
}
137+
138+
for rnd := firstChecked; rnd <= lastChecked; rnd++ {
132139
expires, ok := t.recent[rnd].txleases[txl]
133140
if ok && current <= expires {
134141
return true, nil

protocol/consensus.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ const ConsensusV22 = ConsensusVersion(
123123
"https://github.com/algorandfoundation/specs/tree/57016b942f6d97e6d4c0688b373bb0a2fc85a1a2",
124124
)
125125

126+
// ConsensusV23 fixes lease behavior.
127+
const ConsensusV23 = ConsensusVersion(
128+
"https://github.com/algorandfoundation/specs/tree/e5f565421d720c6f75cdd186f7098495caf9101f",
129+
)
130+
126131
// ConsensusFuture is a protocol that should not appear in any production
127132
// network, but is used to test features before they are released.
128133
const ConsensusFuture = ConsensusVersion(
@@ -135,7 +140,7 @@ const ConsensusFuture = ConsensusVersion(
135140

136141
// ConsensusCurrentVersion is the latest version and should be used
137142
// when a specific version is not provided.
138-
const ConsensusCurrentVersion = ConsensusV22
143+
const ConsensusCurrentVersion = ConsensusV23
139144

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

test/e2e-go/features/catchup/basicCatchup_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ func TestStoppedCatchupOnUnsupported(t *testing.T) {
213213
testUnupgradedProtocol.UpgradeVoteRounds = 3
214214
testUnupgradedProtocol.UpgradeThreshold = 2
215215
testUnupgradedProtocol.DefaultUpgradeWaitRounds = 3
216+
testUnupgradedProtocol.MinUpgradeWaitRounds = 0
216217

217218
testUnupgradedProtocol.ApprovedUpgrades[consensusTestUnupgradedToProtocol] = 0
218219
consensus[consensusTestUnupgradedProtocol] = testUnupgradedProtocol

test/e2e-go/features/transactions/lease_test.go

+135-4
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestLeaseTransactionsSameSender(t *testing.T) {
3131
a := require.New(t)
3232

3333
var fixture fixtures.RestClientFixture
34-
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50EachFuture.json"))
34+
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50Each.json"))
3535
defer fixture.Shutdown()
3636

3737
client := fixture.LibGoalClient
@@ -85,12 +85,143 @@ func TestLeaseTransactionsSameSender(t *testing.T) {
8585
a.Equal(bal2, uint64(0))
8686
}
8787

88+
func TestLeaseRegressionFaultyFirstValidCheckOld_2f3880f7(t *testing.T) {
89+
t.Parallel()
90+
a := require.New(t)
91+
92+
var fixture fixtures.RestClientFixture
93+
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50EachV22.json"))
94+
defer fixture.Shutdown()
95+
96+
client := fixture.LibGoalClient
97+
accountList, err := fixture.GetWalletsSortedByBalance()
98+
a.NoError(err)
99+
account0 := accountList[0].Address
100+
wh, err := client.GetUnencryptedWalletHandle()
101+
a.NoError(err)
102+
103+
account1, err := client.GenerateAddress(wh)
104+
a.NoError(err)
105+
106+
account2, err := client.GenerateAddress(wh)
107+
a.NoError(err)
108+
109+
lease := [32]byte{1, 2, 3, 4}
110+
111+
// construct transactions for sending money to account1 and account2
112+
// from same sender with identical lease
113+
tx1, err := client.ConstructPayment(account0, account1, 0, 1000000, nil, "", lease, 0, 0)
114+
a.NoError(err)
115+
116+
stx1, err := client.SignTransactionWithWallet(wh, nil, tx1)
117+
a.NoError(err)
118+
119+
// submitting the first transaction should succeed
120+
_, err = client.BroadcastTransaction(stx1)
121+
a.NoError(err)
122+
123+
// wait for the txids and check balance
124+
txids := make(map[string]string)
125+
txids[stx1.Txn.ID().String()] = account0
126+
127+
_, curRound := fixture.GetBalanceAndRound(account0)
128+
confirmed := fixture.WaitForAllTxnsToConfirm(curRound+5, txids)
129+
a.True(confirmed, "lease txn confirmed")
130+
131+
bal1, _ := fixture.GetBalanceAndRound(account1)
132+
bal2, _ := fixture.GetBalanceAndRound(account2)
133+
a.Equal(bal1, uint64(1000000))
134+
a.Equal(bal2, uint64(0))
135+
136+
tx2, err := client.ConstructPayment(account0, account2, 0, 2000000, nil, "", lease, 0, 0)
137+
a.NoError(err)
138+
139+
stx2, err := client.SignTransactionWithWallet(wh, nil, tx2)
140+
a.NoError(err)
141+
142+
// submitting the second transaction should succeed
143+
_, err = client.BroadcastTransaction(stx2)
144+
a.NoError(err)
145+
146+
// wait for the txids and check balance
147+
txids = make(map[string]string)
148+
txids[stx2.Txn.ID().String()] = account0
149+
150+
_, curRound = fixture.GetBalanceAndRound(account0)
151+
confirmed = fixture.WaitForAllTxnsToConfirm(curRound+5, txids)
152+
a.True(confirmed, "lease txn confirmed")
153+
154+
bal1, _ = fixture.GetBalanceAndRound(account1)
155+
bal2, _ = fixture.GetBalanceAndRound(account2)
156+
a.Equal(bal1, uint64(1000000))
157+
a.Equal(bal2, uint64(2000000))
158+
}
159+
160+
func TestLeaseRegressionFaultyFirstValidCheckNew_2f3880f7(t *testing.T) {
161+
t.Parallel()
162+
a := require.New(t)
163+
164+
var fixture fixtures.RestClientFixture
165+
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50Each.json"))
166+
defer fixture.Shutdown()
167+
168+
client := fixture.LibGoalClient
169+
accountList, err := fixture.GetWalletsSortedByBalance()
170+
a.NoError(err)
171+
account0 := accountList[0].Address
172+
wh, err := client.GetUnencryptedWalletHandle()
173+
a.NoError(err)
174+
175+
account1, err := client.GenerateAddress(wh)
176+
a.NoError(err)
177+
178+
account2, err := client.GenerateAddress(wh)
179+
a.NoError(err)
180+
181+
lease := [32]byte{1, 2, 3, 4}
182+
183+
// construct transactions for sending money to account1 and account2
184+
// from same sender with identical lease
185+
tx1, err := client.ConstructPayment(account0, account1, 0, 1000000, nil, "", lease, 0, 0)
186+
a.NoError(err)
187+
188+
stx1, err := client.SignTransactionWithWallet(wh, nil, tx1)
189+
a.NoError(err)
190+
191+
// submitting the first transaction should succeed
192+
_, err = client.BroadcastTransaction(stx1)
193+
a.NoError(err)
194+
195+
// wait for the txids and check balance
196+
txids := make(map[string]string)
197+
txids[stx1.Txn.ID().String()] = account0
198+
199+
_, curRound := fixture.GetBalanceAndRound(account0)
200+
confirmed := fixture.WaitForAllTxnsToConfirm(curRound+5, txids)
201+
a.True(confirmed, "lease txn confirmed")
202+
203+
bal1, _ := fixture.GetBalanceAndRound(account1)
204+
bal2, _ := fixture.GetBalanceAndRound(account2)
205+
a.Equal(bal1, uint64(1000000))
206+
a.Equal(bal2, uint64(0))
207+
208+
tx2, err := client.ConstructPayment(account0, account2, 0, 2000000, nil, "", lease, 0, 0)
209+
a.NoError(err)
210+
211+
stx2, err := client.SignTransactionWithWallet(wh, nil, tx2)
212+
a.NoError(err)
213+
214+
// submitting the second transaction should fail
215+
_, err = client.BroadcastTransaction(stx2)
216+
a.Error(err)
217+
}
218+
88219
func TestLeaseTransactionsSameSenderDifferentLease(t *testing.T) {
89220
t.Parallel()
90221
a := require.New(t)
91222

92223
var fixture fixtures.RestClientFixture
93-
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50EachFuture.json"))
224+
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50Each.json"))
94225
defer fixture.Shutdown()
95226

96227
client := fixture.LibGoalClient
@@ -151,7 +282,7 @@ func TestLeaseTransactionsDifferentSender(t *testing.T) {
151282
a := require.New(t)
152283

153284
var fixture fixtures.RestClientFixture
154-
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50EachFuture.json"))
285+
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50Each.json"))
155286
defer fixture.Shutdown()
156287

157288
client := fixture.LibGoalClient
@@ -225,7 +356,7 @@ func TestOverlappingLeases(t *testing.T) {
225356
a := require.New(t)
226357

227358
var fixture fixtures.RestClientFixture
228-
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50EachFuture.json"))
359+
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50Each.json"))
229360
defer fixture.Shutdown()
230361

231362
client := fixture.LibGoalClient

test/e2e-go/upgrades/send_receive_upgrade_test.go

+16
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,20 @@ func TestAccountsCanSendMoneyAcrossUpgradeV15toV16(t *testing.T) {
104104
testAccountsCanSendMoneyAcrossUpgrade(t, filepath.Join("nettemplates", "TwoNodes50EachV15Upgrade.json"))
105105
}
106106

107+
func TestAccountsCanSendMoneyAcrossUpgradeV21toV22(t *testing.T) {
108+
if runtime.GOOS == "darwin" {
109+
t.Skip()
110+
}
111+
testAccountsCanSendMoneyAcrossUpgrade(t, filepath.Join("nettemplates", "TwoNodes50EachV21Upgrade.json"))
112+
}
113+
114+
func TestAccountsCanSendMoneyAcrossUpgradeV22toV23(t *testing.T) {
115+
if runtime.GOOS == "darwin" {
116+
t.Skip()
117+
}
118+
testAccountsCanSendMoneyAcrossUpgrade(t, filepath.Join("nettemplates", "TwoNodes50EachV22Upgrade.json"))
119+
}
120+
107121
// ConsensusTestFastUpgrade is meant for testing of protocol upgrades:
108122
// during testing, it is equivalent to another protocol with the exception
109123
// of the upgrade parameters, which allow for upgrades to take place after
@@ -120,6 +134,8 @@ func generateFastUpgradeConsensus() (fastUpgradeProtocols config.ConsensusProtoc
120134
fastParams.UpgradeVoteRounds = 5
121135
fastParams.UpgradeThreshold = 3
122136
fastParams.DefaultUpgradeWaitRounds = 5
137+
fastParams.MinUpgradeWaitRounds = 0
138+
fastParams.MaxUpgradeWaitRounds = 0
123139
fastParams.MaxVersionStringLen += len(consensusTestFastUpgrade(""))
124140
fastParams.ApprovedUpgrades = make(map[protocol.ConsensusVersion]uint64)
125141

0 commit comments

Comments
 (0)