Skip to content

Commit

Permalink
Merge pull request #2704 from algorand/hotfix/v2.9.1
Browse files Browse the repository at this point in the history
Hotfix/v2.9.1
  • Loading branch information
algojohnlee committed Aug 10, 2021
2 parents 1ad773e + 8ce1e6c commit 7b53f6f
Show file tree
Hide file tree
Showing 26 changed files with 713 additions and 182 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ if: tag IS blank

stages:
- name: build_commit
if: NOT (branch =~ /^rel\//) AND type != pull_request
if: NOT (branch =~ /^hotfix\//) AND NOT (branch =~ /^rel\//) AND type != pull_request
- name: build_pr
if: type = pull_request
- name: build_release
if: branch =~ /^rel\// AND type != pull_request
if: (branch =~ /^hotfix\// OR branch =~ /^rel\//) AND type != pull_request
- name: deploy
if: branch =~ /^rel\// AND type != pull_request
- name: post_deploy
Expand Down
2 changes: 1 addition & 1 deletion buildnumber.dat
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0
1
16 changes: 15 additions & 1 deletion config/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ type ConsensusParams struct {
// 5. checking that in the case of going online the VoteFirst is less or equal to the LastValid+1.
// 6. checking that in the case of going online the VoteFirst is less or equal to the next network round.
EnableKeyregCoherencyCheck bool

EnableExtraPagesOnAppUpdate bool
}

// PaysetCommitType enumerates possible ways for the block header to commit to
Expand Down Expand Up @@ -969,9 +971,21 @@ func initConsensusProtocols() {
// v27 can be upgraded to v28, with an update delay of 7 days ( see calculation above )
v27.ApprovedUpgrades[protocol.ConsensusV28] = 140000

// v29 fixes application update by using ExtraProgramPages in size calculations
v29 := v28
v29.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}

// Enable ExtraProgramPages for application update
v29.EnableExtraPagesOnAppUpdate = true

Consensus[protocol.ConsensusV29] = v29

// v28 can be upgraded to v29, with an update delay of 3 days ( see calculation above )
v28.ApprovedUpgrades[protocol.ConsensusV29] = 60000

// ConsensusFuture is used to test features that are implemented
// but not yet released in a production protocol version.
vFuture := v28
vFuture := v29
vFuture.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}

// FilterTimeout for period 0 should take a new optimized, configured value, need to revisit this later
Expand Down
2 changes: 1 addition & 1 deletion config/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const VersionMajor = 2

// VersionMinor is the Minor semantic version number (x.#.z) - changed when backwards-compatible features are introduced.
// Not enforced until after initial public release (x > 0).
const VersionMinor = 8
const VersionMinor = 9

// Version is the type holding our full version information.
type Version struct {
Expand Down
8 changes: 8 additions & 0 deletions daemon/algod/api/client/restClient.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,14 @@ func (client RestClient) PendingTransactionInformation(transactionID string) (re
return
}

// PendingTransactionInformationV2 gets information about a recently issued
// transaction. See PendingTransactionInformation for more details.
func (client RestClient) PendingTransactionInformationV2(transactionID string) (response generatedV2.PendingTransactionResponse, err error) {
transactionID = stripTransaction(transactionID)
err = client.get(&response, fmt.Sprintf("/v2/transactions/pending/%s", transactionID), nil)
return
}

// SuggestedFee gets the recommended transaction fee from the node
func (client RestClient) SuggestedFee() (response v1.TransactionFee, err error) {
err = client.get(&response, "/v1/transactions/fee", nil)
Expand Down
32 changes: 32 additions & 0 deletions data/basics/overflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ func OAdd16(a uint16, b uint16) (res uint16, overflowed bool) {
return
}

// OAdd32 adds 2 uint32 values with overflow detection
func OAdd32(a uint32, b uint32) (res uint32, overflowed bool) {
res = a + b
overflowed = res < a
return
}

// OAdd adds 2 values with overflow detection
func OAdd(a uint64, b uint64) (res uint64, overflowed bool) {
res = a + b
Expand All @@ -47,6 +54,13 @@ func OSub(a uint64, b uint64) (res uint64, overflowed bool) {
return
}

// OSub32 subtracts b from a with overflow detection
func OSub32(a uint32, b uint32) (res uint32, overflowed bool) {
res = a - b
overflowed = res > a
return
}

// OMul multiplies 2 values with overflow detection
func OMul(a uint64, b uint64) (res uint64, overflowed bool) {
if b == 0 {
Expand Down Expand Up @@ -78,6 +92,15 @@ func AddSaturate(a uint64, b uint64) uint64 {
return res
}

// AddSaturate32 adds 2 uint32 values with saturation on overflow
func AddSaturate32(a uint32, b uint32) uint32 {
res, overflowed := OAdd32(a, b)
if overflowed {
return math.MaxUint32
}
return res
}

// SubSaturate subtracts 2 values with saturation on underflow
func SubSaturate(a uint64, b uint64) uint64 {
res, overflowed := OSub(a, b)
Expand All @@ -87,6 +110,15 @@ func SubSaturate(a uint64, b uint64) uint64 {
return res
}

// SubSaturate32 subtracts 2 uint32 values with saturation on underflow
func SubSaturate32(a uint32, b uint32) uint32 {
res, overflowed := OSub32(a, b)
if overflowed {
return 0
}
return res
}

// Add16 adds 2 uint16 values with overflow detection
func (t *OverflowTracker) Add16(a uint16, b uint16) uint16 {
res, overflowed := OAdd16(a, b)
Expand Down
18 changes: 18 additions & 0 deletions data/basics/units_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package basics

import (
"math"
"testing"

"github.com/stretchr/testify/require"
Expand All @@ -30,6 +31,23 @@ func TestSubSaturate(t *testing.T) {
require.Equal(t, b.SubSaturate(a), Round(1))
}

func TestSubSaturate32(t *testing.T) {
require.Equal(t, uint32(0), SubSaturate32(0, 1))
require.Equal(t, uint32(0), SubSaturate32(1, 2))
require.Equal(t, uint32(0), SubSaturate32(1, 1))
require.Equal(t, uint32(0), SubSaturate32(1, math.MaxUint32))
require.Equal(t, uint32(1), SubSaturate32(2, 1))
require.Equal(t, uint32(math.MaxUint32-1), SubSaturate32(math.MaxUint32, 1))
}

func TestAddSaturate32(t *testing.T) {
require.Equal(t, uint32(1), AddSaturate32(0, 1))
require.Equal(t, uint32(math.MaxUint32-1), AddSaturate32(math.MaxUint32-2, 1))
require.Equal(t, uint32(math.MaxUint32), AddSaturate32(math.MaxUint32, 0))
require.Equal(t, uint32(math.MaxUint32), AddSaturate32(math.MaxUint32-1, 1))
require.Equal(t, uint32(math.MaxUint32), AddSaturate32(math.MaxUint32, 2))
}

func TestRoundUpToMultipleOf(t *testing.T) {
r := Round(24)
for n := Round(1); n < Round(100); n++ {
Expand Down
8 changes: 7 additions & 1 deletion data/transactions/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ func (tx Transaction) WellFormed(spec SpecialAddresses, proto config.ConsensusPa
}
}

effectiveEPP := tx.ExtraProgramPages
// Schemas and ExtraProgramPages may only be set during application creation
if tx.ApplicationID != 0 {
if tx.LocalStateSchema != (basics.StateSchema{}) ||
Expand All @@ -353,6 +354,11 @@ func (tx Transaction) WellFormed(spec SpecialAddresses, proto config.ConsensusPa
if tx.ExtraProgramPages != 0 {
return fmt.Errorf("tx.ExtraProgramPages is immutable")
}

if proto.EnableExtraPagesOnAppUpdate {
effectiveEPP = uint32(proto.MaxExtraAppProgramPages)
}

}

// Limit total number of arguments
Expand Down Expand Up @@ -396,7 +402,7 @@ func (tx Transaction) WellFormed(spec SpecialAddresses, proto config.ConsensusPa

lap := len(tx.ApprovalProgram)
lcs := len(tx.ClearStateProgram)
pages := int(1 + tx.ExtraProgramPages)
pages := int(1 + effectiveEPP)
if lap > pages*proto.MaxAppProgramLen {
return fmt.Errorf("approval program too long. max len %d bytes", pages*proto.MaxAppProgramLen)
}
Expand Down
49 changes: 49 additions & 0 deletions data/transactions/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ func TestWellFormedErrors(t *testing.T) {
curProto := config.Consensus[protocol.ConsensusCurrentVersion]
futureProto := config.Consensus[protocol.ConsensusFuture]
protoV27 := config.Consensus[protocol.ConsensusV27]
protoV28 := config.Consensus[protocol.ConsensusV28]
addr1, err := basics.UnmarshalChecksumAddress("NDQCJNNY5WWWFLP4GFZ7MEF2QJSMZYK6OWIV2AQ7OMAVLEFCGGRHFPKJJA")
require.NoError(t, err)
okHeader := Header{
Expand Down Expand Up @@ -447,6 +448,54 @@ func TestWellFormedErrors(t *testing.T) {
proto: futureProto,
expectedError: fmt.Errorf("tx has too many references, max is 8"),
},
{
tx: Transaction{
Type: protocol.ApplicationCallTx,
Header: okHeader,
ApplicationCallTxnFields: ApplicationCallTxnFields{
ApplicationID: 1,
ApprovalProgram: []byte(strings.Repeat("X", 1025)),
ClearStateProgram: []byte(strings.Repeat("X", 1025)),
ExtraProgramPages: 0,
OnCompletion: UpdateApplicationOC,
},
},
spec: specialAddr,
proto: protoV28,
expectedError: fmt.Errorf("app programs too long. max total len %d bytes", curProto.MaxAppProgramLen),
},
{
tx: Transaction{
Type: protocol.ApplicationCallTx,
Header: okHeader,
ApplicationCallTxnFields: ApplicationCallTxnFields{
ApplicationID: 1,
ApprovalProgram: []byte(strings.Repeat("X", 1025)),
ClearStateProgram: []byte(strings.Repeat("X", 1025)),
ExtraProgramPages: 0,
OnCompletion: UpdateApplicationOC,
},
},
spec: specialAddr,
proto: futureProto,
},
{
tx: Transaction{
Type: protocol.ApplicationCallTx,
Header: okHeader,
ApplicationCallTxnFields: ApplicationCallTxnFields{
ApplicationID: 1,
ApplicationArgs: [][]byte{
[]byte("write"),
},
ExtraProgramPages: 1,
OnCompletion: UpdateApplicationOC,
},
},
spec: specialAddr,
proto: protoV28,
expectedError: fmt.Errorf("tx.ExtraProgramPages is immutable"),
},
}
for _, usecase := range usecases {
err := usecase.tx.WellFormed(usecase.spec, usecase.proto)
Expand Down
25 changes: 22 additions & 3 deletions ledger/appcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func errAlreadyStorage(addr basics.Address, aidx basics.AppIndex, global bool) e
}

// Allocate creates kv storage for a given {addr, aidx, global}. It is called on app creation (global) or opting in (local)
func (cb *roundCowState) Allocate(addr basics.Address, aidx basics.AppIndex, global bool, space basics.StateSchema) error {
func (cb *roundCowState) AllocateApp(addr basics.Address, aidx basics.AppIndex, global bool, space basics.StateSchema) error {
// Check that account is not already opted in
allocated, err := cb.allocated(addr, aidx, global)
if err != nil {
Expand All @@ -241,11 +241,21 @@ func (cb *roundCowState) Allocate(addr basics.Address, aidx basics.AppIndex, glo
lsd.action = allocAction
lsd.maxCounts = &space

if global {
cb.mods.Creatables[basics.CreatableIndex(aidx)] = ledgercore.ModifiedCreatable{
Ctype: basics.AppCreatable,
Creator: addr,
Created: true,
}
}

cb.trackCreatable(basics.CreatableIndex(aidx))

return nil
}

// Deallocate clears storage for {addr, aidx, global}. It happens on app deletion (global) or closing out (local)
func (cb *roundCowState) Deallocate(addr basics.Address, aidx basics.AppIndex, global bool) error {
func (cb *roundCowState) DeallocateApp(addr basics.Address, aidx basics.AppIndex, global bool) error {
// Check that account has allocated storage
allocated, err := cb.allocated(addr, aidx, global)
if err != nil {
Expand All @@ -265,6 +275,15 @@ func (cb *roundCowState) Deallocate(addr basics.Address, aidx basics.AppIndex, g
lsd.counts = &basics.StateSchema{}
lsd.maxCounts = &basics.StateSchema{}
lsd.kvCow = make(stateDelta)

if global {
cb.mods.Creatables[basics.CreatableIndex(aidx)] = ledgercore.ModifiedCreatable{
Ctype: basics.AppCreatable,
Creator: addr,
Created: false,
}
}

return nil
}

Expand Down Expand Up @@ -619,7 +638,7 @@ func applyStorageDelta(data basics.AccountData, aapp storagePtr, store *storageD
delete(owned, aapp.aidx)
case allocAction, remainAllocAction:
// note: these should always exist because they were
// at least preceded by a call to PutWithCreatable
// at least preceded by a call to Put()
params, ok := owned[aapp.aidx]
if !ok {
return basics.AccountData{}, fmt.Errorf("could not find existing params for %v", aapp.aidx)
Expand Down
4 changes: 2 additions & 2 deletions ledger/appcow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ func TestCowStorage(t *testing.T) {
NumUint: rand.Uint64(),
NumByteSlice: rand.Uint64(),
}
err := cow.Allocate(addr, sptr.aidx, sptr.global, rschema)
err := cow.AllocateApp(addr, sptr.aidx, sptr.global, rschema)
if actuallyAllocated {
require.Error(t, err)
require.Contains(t, err.Error(), "cannot allocate")
Expand All @@ -253,7 +253,7 @@ func TestCowStorage(t *testing.T) {
// Deallocate
if rand.Float32() < 0.25 {
actuallyAllocated := st.allocated(aapp)
err := cow.Deallocate(addr, sptr.aidx, sptr.global)
err := cow.DeallocateApp(addr, sptr.aidx, sptr.global)
if actuallyAllocated {
require.NoError(t, err)
err := st.dealloc(aapp)
Expand Down

0 comments on commit 7b53f6f

Please sign in to comment.