Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions config/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,16 @@ type ConsensusParams struct {
// max sum([len(arg) for arg in txn.ApplicationArgs])
MaxAppTotalArgLen int

// maximum length of application approval program or clear state
// program in bytes
// maximum byte len of application approval program or clear state
// When MaxExtraAppProgramPages > 0, this is the size of those pages.
// So two "extra pages" would mean 3*MaxAppProgramLen bytes are available.
MaxAppProgramLen int

// maximum total length of an application's programs (approval + clear state)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it needs clarification about extra pages, like "total combined length per page" or something

// When MaxExtraAppProgramPages > 0, this is the size of those pages.
// So two "extra pages" would mean 3*MaxAppTotalProgramLen bytes are available.
MaxAppTotalProgramLen int

// extra length for application program in pages. A page is MaxAppProgramLen bytes
MaxExtraAppProgramPages int

Expand Down Expand Up @@ -827,6 +833,7 @@ func initConsensusProtocols() {
v24.MaxAppArgs = 16
v24.MaxAppTotalArgLen = 2048
v24.MaxAppProgramLen = 1024
v24.MaxAppTotalProgramLen = 2048 // No effect until v28, when MaxAppProgramLen increased
v24.MaxAppKeyLen = 64
v24.MaxAppBytesValueLen = 64

Expand Down Expand Up @@ -932,6 +939,7 @@ func initConsensusProtocols() {

// Enable support for larger app program size
vFuture.MaxExtraAppProgramPages = 3
vFuture.MaxAppProgramLen = 2048

// enable the InitialRewardsRateCalculation fix
vFuture.InitialRewardsRateCalculation = true
Expand Down
4 changes: 2 additions & 2 deletions data/transactions/logic/README_in.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ Starting from version 2 TEAL evaluator can run programs in two modes:
2. Application run (stateful)

Differences between modes include:
1. Max program length (consensus parameters LogicSigMaxSize, MaxApprovalProgramLen and MaxClearStateProgramLen)
1. Max program length (consensus parameters LogicSigMaxSize, MaxAppProgramLen & MaxExtraAppProgramPages)
2. Max program cost (consensus parameters LogicSigMaxCost, MaxAppProgramCost)
3. Opcodes availability. For example, all stateful operations are only available in stateful mode. Refer to [opcodes document](TEAL_opcodes.md) for details.
3. Opcode availability. For example, all stateful operations are only available in stateful mode. Refer to [opcodes document](TEAL_opcodes.md) for details.

## Constants

Expand Down
17 changes: 11 additions & 6 deletions data/transactions/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ func (tx Transaction) WellFormed(spec SpecialAddresses, proto config.ConsensusPa
return fmt.Errorf("local and global state schemas are immutable")
}
if tx.ExtraProgramPages != 0 {
return fmt.Errorf("ExtraProgramPages field is immutable")
return fmt.Errorf("tx.ExtraProgramPages is immutable")
}
}

Expand Down Expand Up @@ -389,12 +389,17 @@ func (tx Transaction) WellFormed(spec SpecialAddresses, proto config.ConsensusPa
return fmt.Errorf("tx.ExtraProgramPages too large, max number of extra pages is %d", proto.MaxExtraAppProgramPages)
}

if uint32(len(tx.ApprovalProgram)) > ((1 + tx.ExtraProgramPages) * uint32(proto.MaxAppProgramLen)) {
return fmt.Errorf("approval program too long. max len %d bytes", (1+tx.ExtraProgramPages)*uint32(proto.MaxAppProgramLen))
lap := len(tx.ApprovalProgram)
lcs := len(tx.ClearStateProgram)
pages := int(1 + tx.ExtraProgramPages)
if lap > pages*proto.MaxAppProgramLen {
return fmt.Errorf("approval program too long. max len %d bytes", pages*proto.MaxAppProgramLen)
}

if uint32(len(tx.ClearStateProgram)) > ((1 + tx.ExtraProgramPages) * uint32(proto.MaxAppProgramLen)) {
return fmt.Errorf("clear state program too long. max len %d bytes", (1+tx.ExtraProgramPages)*uint32(proto.MaxAppProgramLen))
if lcs > pages*proto.MaxAppProgramLen {
return fmt.Errorf("clear state program too long. max len %d bytes", pages*proto.MaxAppProgramLen)
}
if lap+lcs > pages*proto.MaxAppTotalProgramLen {
return fmt.Errorf("app programs too long. max total len %d bytes", pages*proto.MaxAppTotalProgramLen)
}

if tx.LocalStateSchema.NumEntries() > proto.MaxLocalSchemaEntries {
Expand Down
93 changes: 70 additions & 23 deletions data/transactions/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package transactions
import (
"flag"
"fmt"
"strings"
"testing"

"github.com/algorand/go-algorand/config"
Expand Down Expand Up @@ -228,6 +229,12 @@ func TestWellFormedErrors(t *testing.T) {
protoV27 := config.Consensus[protocol.ConsensusV27]
addr1, err := basics.UnmarshalChecksumAddress("NDQCJNNY5WWWFLP4GFZ7MEF2QJSMZYK6OWIV2AQ7OMAVLEFCGGRHFPKJJA")
require.NoError(t, err)
okHeader := Header{
Sender: addr1,
Fee: basics.MicroAlgos{Raw: 1000},
LastValid: 105,
FirstValid: 100,
}
usecases := []struct {
tx Transaction
spec SpecialAddresses
Expand Down Expand Up @@ -262,15 +269,10 @@ func TestWellFormedErrors(t *testing.T) {
},
{
tx: Transaction{
Type: protocol.ApplicationCallTx,
Header: Header{
Sender: addr1,
Fee: basics.MicroAlgos{Raw: 1000},
LastValid: 105,
FirstValid: 100,
},
Type: protocol.ApplicationCallTx,
Header: okHeader,
ApplicationCallTxnFields: ApplicationCallTxnFields{
ApplicationID: 0,
ApplicationID: 0, // creation
ApplicationArgs: [][]byte{
[]byte("write"),
},
Expand All @@ -279,17 +281,67 @@ func TestWellFormedErrors(t *testing.T) {
},
spec: specialAddr,
proto: protoV27,
expectedError: fmt.Errorf("tx.ExtraProgramPages too large, max number of extra pages is %d", curProto.MaxExtraAppProgramPages),
expectedError: fmt.Errorf("tx.ExtraProgramPages too large, max number of extra pages is %d", protoV27.MaxExtraAppProgramPages),
},
{
tx: Transaction{
Type: protocol.ApplicationCallTx,
Header: Header{
Sender: addr1,
Fee: basics.MicroAlgos{Raw: 1000},
LastValid: 105,
FirstValid: 100,
Type: protocol.ApplicationCallTx,
Header: okHeader,
ApplicationCallTxnFields: ApplicationCallTxnFields{
ApplicationID: 0, // creation
ApprovalProgram: []byte(strings.Repeat("X", 1025)),
ClearStateProgram: []byte("junk"),
},
},
spec: specialAddr,
proto: protoV27,
expectedError: fmt.Errorf("approval program too long. max len 1024 bytes"),
},
{
tx: Transaction{
Type: protocol.ApplicationCallTx,
Header: okHeader,
ApplicationCallTxnFields: ApplicationCallTxnFields{
ApplicationID: 0, // creation
ApprovalProgram: []byte(strings.Repeat("X", 1025)),
ClearStateProgram: []byte("junk"),
},
},
spec: specialAddr,
proto: futureProto,
},
{
tx: Transaction{
Type: protocol.ApplicationCallTx,
Header: okHeader,
ApplicationCallTxnFields: ApplicationCallTxnFields{
ApplicationID: 0, // creation
ApprovalProgram: []byte(strings.Repeat("X", 1025)),
ClearStateProgram: []byte(strings.Repeat("X", 1025)),
},
},
spec: specialAddr,
proto: futureProto,
expectedError: fmt.Errorf("app programs too long. max total len 2048 bytes"),
},
{
tx: Transaction{
Type: protocol.ApplicationCallTx,
Header: okHeader,
ApplicationCallTxnFields: ApplicationCallTxnFields{
ApplicationID: 0, // creation
ApprovalProgram: []byte(strings.Repeat("X", 1025)),
ClearStateProgram: []byte(strings.Repeat("X", 1025)),
ExtraProgramPages: 1,
},
},
spec: specialAddr,
proto: futureProto,
},
{
tx: Transaction{
Type: protocol.ApplicationCallTx,
Header: okHeader,
ApplicationCallTxnFields: ApplicationCallTxnFields{
ApplicationID: 1,
ApplicationArgs: [][]byte{
Expand All @@ -300,17 +352,12 @@ func TestWellFormedErrors(t *testing.T) {
},
spec: specialAddr,
proto: futureProto,
expectedError: fmt.Errorf("ExtraProgramPages field is immutable"),
expectedError: fmt.Errorf("tx.ExtraProgramPages is immutable"),
},
{
tx: Transaction{
Type: protocol.ApplicationCallTx,
Header: Header{
Sender: addr1,
Fee: basics.MicroAlgos{Raw: 1000},
LastValid: 105,
FirstValid: 100,
},
Type: protocol.ApplicationCallTx,
Header: okHeader,
ApplicationCallTxnFields: ApplicationCallTxnFields{
ApplicationID: 0,
ApplicationArgs: [][]byte{
Expand Down
27 changes: 15 additions & 12 deletions test/scripts/e2e_client_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
# Usage:
# ./e2e_client_runner.py e2e_subs/*.sh
#
# Reads each bash script for `# TIMEOUT=N` line to configure timeout to N seconds. (default timeout is 200 seconds)
# Reads each bash script for `# TIMEOUT=N` line to configure timeout
# to N seconds. The default is 10 seconds less than the timeout
# associated with the entire set of tests, which defaults to 500, but
# can be controlled with --timeout

import argparse
import atexit
Expand Down Expand Up @@ -67,7 +70,7 @@ def read_script_for_timeout(fname):
return int(m.group(1))
except:
logger.debug('read timeout match err', exc_info=True)
return 200
return None


def create_kmd_config_with_unsafe_scrypt(working_dir):
Expand All @@ -94,9 +97,8 @@ def create_kmd_config_with_unsafe_scrypt(working_dir):
json.dump(kmd_conf_data,f)




def _script_thread_inner(runset, scriptname):
def _script_thread_inner(runset, scriptname, timeout):
start = time.time()
algod, kmd = runset.connect()
pubw, maxpubaddr = runset.get_pub_wallet()
Expand Down Expand Up @@ -138,7 +140,9 @@ def _script_thread_inner(runset, scriptname):
p = subprocess.Popen([scriptname, walletname], env=env, cwd=repodir, stdout=cmdlog, stderr=subprocess.STDOUT)
cmdlog.close()
runset.running(scriptname, p)
timeout = read_script_for_timeout(scriptname)
script_timeout = read_script_for_timeout(scriptname)
if script_timeout:
timeout = script_timeout
try:
retcode = p.wait(timeout)
except subprocess.TimeoutExpired as te:
Expand Down Expand Up @@ -175,10 +179,10 @@ def _script_thread_inner(runset, scriptname):
runset.done(scriptname, retcode == 0, dt)
return

def script_thread(runset, scriptname):
def script_thread(runset, scriptname, to):
start = time.time()
try:
_script_thread_inner(runset, scriptname)
_script_thread_inner(runset, scriptname, to)
except Exception as e:
logger.error('error in e2e_client_runner.py', exc_info=True)
runset.done(scriptname, False, time.time() - start)
Expand Down Expand Up @@ -218,10 +222,9 @@ def _connect(self):
if self.algod and self.kmd:
return


# should run from inside self.lock
algodata = self.env['ALGORAND_DATA']

xrun(['goal', 'kmd', 'start', '-t', '3600','-d', algodata], env=self.env, timeout=5)
self.kmd = openkmd(algodata)
self.algod = openalgod(algodata)
Expand Down Expand Up @@ -250,11 +253,11 @@ def get_pub_wallet(self):
self.maxpubaddr = maxpubaddr
return self.pubw, self.maxpubaddr

def start(self, scriptname):
def start(self, scriptname, timeout):
with self.lock:
if not self.ok:
return
t = threading.Thread(target=script_thread, args=(self, scriptname,))
t = threading.Thread(target=script_thread, args=(self, scriptname, timeout))
t.start()
with self.lock:
self.threads[scriptname] = t
Expand Down Expand Up @@ -450,7 +453,7 @@ def main():

rs = RunSet(env)
for scriptname in args.scripts:
rs.start(scriptname)
rs.start(scriptname, args.timeout-10)
rs.wait(args.timeout)
if rs.errors:
retcode = 1
Expand Down