Skip to content

Commit

Permalink
Extend global and txn field tests for all TEAL versions and protocols (
Browse files Browse the repository at this point in the history
…#2669)

* Move tests from backwardCompat_test.go to fields_test.go
* Check every field on a version before it was introduced
* Enable txna fields checks
* Fix TestGlobal to prevent invalid version specs in tests map
  • Loading branch information
algorandskiy authored Aug 3, 2021
1 parent c1b17d9 commit 5d7ce82
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 147 deletions.
147 changes: 0 additions & 147 deletions data/transactions/logic/backwardCompat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ import (
"strings"
"testing"

"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/test/partitiontest"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -373,151 +371,6 @@ func TestBackwardCompatTEALv1(t *testing.T) {

}

// ensure v2 fields error on pre TEAL v2 logicsig version
// ensure v2 fields error in v1 program
func TestBackwardCompatGlobalFields(t *testing.T) {
partitiontest.PartitionTest(t)

t.Parallel()
var fields []globalFieldSpec
for _, fs := range globalFieldSpecs {
if fs.version > 1 {
fields = append(fields, fs)
}
}
require.Greater(t, len(fields), 1)

ledger := makeTestLedger(nil)
for _, field := range fields {
text := fmt.Sprintf("global %s", field.gfield.String())
// check assembler fails if version before introduction
testLine(t, text, assemblerNoVersion, "...available in version...")
for v := uint64(0); v < field.version; v++ {
testLine(t, text, v, "...available in version...")
}

ops := testProg(t, text, AssemblerMaxVersion)

proto := config.Consensus[protocol.ConsensusV23]
require.False(t, proto.Application)
ep := defaultEvalParams(nil, nil)
ep.Proto = &proto
ep.Ledger = ledger

// check failure with version check
_, err := Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "greater than protocol supported version")
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "greater than protocol supported version")

// check opcodes failures
ops.Program[0] = 1 // set version to 1
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid global[")
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid global[")

// check opcodes failures
ops.Program[0] = 0 // set version to 0
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid global[")
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid global[")
}
}

// ensure v2 fields error in v1 program
func TestBackwardCompatTxnFields(t *testing.T) {
partitiontest.PartitionTest(t)

t.Parallel()
var fields []txnFieldSpec
for _, fs := range txnFieldSpecs {
if fs.version > 1 {
fields = append(fields, fs)
}
}
require.Greater(t, len(fields), 1)

tests := []string{
"txn %s",
"gtxn 0 %s",
}

ledger := makeTestLedger(nil)
txn := makeSampleTxn()
// We'll reject too early if we have a nonzero RekeyTo, because that
// field must be zero for every txn in the group if this is an old
// TEAL version
txn.Txn.RekeyTo = basics.Address{}
txgroup := makeSampleTxnGroup(txn)
for _, fs := range fields {
field := fs.field.String()
for _, command := range tests {
text := fmt.Sprintf(command, field)
asmError := "...available in version ..."
if _, ok := txnaFieldSpecByField[fs.field]; ok {
parts := strings.Split(text, " ")
op := parts[0]
asmError = fmt.Sprintf("found array field %#v in %s op", field, op)
}
// check assembler fails if version before introduction
testLine(t, text, assemblerNoVersion, asmError)
for v := uint64(0); v < fs.version; v++ {
testLine(t, text, v, asmError)
}

ops, err := AssembleStringWithVersion(text, AssemblerMaxVersion)
if _, ok := txnaFieldSpecByField[fs.field]; ok {
// "txn Accounts" is invalid, so skip evaluation
require.Error(t, err, asmError)
continue
} else {
require.NoError(t, err)
}

proto := config.Consensus[protocol.ConsensusV23]
require.False(t, proto.Application)
ep := defaultEvalParams(nil, nil)
ep.Proto = &proto
ep.Ledger = ledger
ep.TxnGroup = txgroup

// check failure with version check
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "greater than protocol supported version")
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "greater than protocol supported version")

// check opcodes failures
ops.Program[0] = 1 // set version to 1
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid txn field")
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid txn field")

// check opcodes failures
ops.Program[0] = 0 // set version to 0
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid txn field")
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid txn field")
}
}
}

func TestBackwardCompatAssemble(t *testing.T) {
partitiontest.PartitionTest(t)

Expand Down
3 changes: 3 additions & 0 deletions data/transactions/logic/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func defaultEvalProtoWithVersion(version uint64) config.ConsensusParams {
return config.ConsensusParams{
LogicSigVersion: version,
LogicSigMaxCost: 20000,
Application: version >= appsEnabledVersion,
MaxAppProgramCost: 700,
MaxAppKeyLen: 64,
MaxAppBytesValueLen: 64,
Expand Down Expand Up @@ -1026,6 +1027,8 @@ func TestGlobal(t *testing.T) {
EvalStateful, CheckStateful,
},
}
// tests keys are versions so they must be in a range 1..AssemblerMaxVersion plus zero version
require.LessOrEqual(t, len(tests), AssemblerMaxVersion+1)
ledger := makeTestLedger(nil)
ledger.appID = 42
addr, err := basics.UnmarshalChecksumAddress(testAddr)
Expand Down
152 changes: 152 additions & 0 deletions data/transactions/logic/fields_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,164 @@
package logic

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"

"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/test/partitiontest"
)

func TestArrayFields(t *testing.T) {
require.Equal(t, len(TxnaFieldNames), len(TxnaFieldTypes))
require.Equal(t, len(txnaFieldSpecByField), len(TxnaFieldTypes))
}

// ensure v2+ fields fail in TEAL assembler and evaluator on a version before they introduced
// ensure v2+ fields error in v1 program
func TestGlobalFieldsVersions(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()

var fields []globalFieldSpec
for _, fs := range globalFieldSpecs {
if fs.version > 1 {
fields = append(fields, fs)
}
}
require.Greater(t, len(fields), 1)

ledger := makeTestLedger(nil)
for _, field := range fields {
text := fmt.Sprintf("global %s", field.gfield.String())
// check assembler fails if version before introduction
testLine(t, text, assemblerNoVersion, "...available in version...")
for v := uint64(0); v < field.version; v++ {
testLine(t, text, v, "...available in version...")
}
testLine(t, text, field.version, "")

ops := testProg(t, text, AssemblerMaxVersion)

// check on a version before the field version
preLogicVersion := field.version - 1
proto := defaultEvalProtoWithVersion(preLogicVersion)
if preLogicVersion < appsEnabledVersion {
require.False(t, proto.Application)
}
ep := defaultEvalParams(nil, nil)
ep.Proto = &proto
ep.Ledger = ledger

// check failure with version check
_, err := Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "greater than protocol supported version")

// check opcodes failures
ops.Program[0] = byte(preLogicVersion) // set version
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid global[")

// check opcodes failures on 0 version
ops.Program[0] = 0 // set version to 0
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid global[")
}
}

// ensure v2+ fields error in programs of previous TEAL version, similarly to global fields test
func TestTxnFieldVersions(t *testing.T) {
partitiontest.PartitionTest(t)

t.Parallel()
var fields []txnFieldSpec
for _, fs := range txnFieldSpecs {
if fs.version > 1 {
fields = append(fields, fs)
}
}
require.Greater(t, len(fields), 1)

tests := []string{
"txn %s",
"gtxn 0 %s",
}
subs := map[string]string{
tests[0]: "txna %s 0",
tests[1]: "gtxna 0 %s 0",
}
txnaVersion := uint64(appsEnabledVersion)

ledger := makeTestLedger(nil)
txn := makeSampleTxn()
// We'll reject too early if we have a nonzero RekeyTo, because that
// field must be zero for every txn in the group if this is an old
// TEAL version
txn.Txn.RekeyTo = basics.Address{}
txgroup := makeSampleTxnGroup(txn)
asmDefaultError := "...available in version ..."
for _, fs := range fields {
field := fs.field.String()
for _, command := range tests {
text := fmt.Sprintf(command, field)
asmError := asmDefaultError
txnaMode := false
if _, ok := txnaFieldSpecByField[fs.field]; ok {
text = fmt.Sprintf(subs[command], field)
asmError = "...txna opcode was introduced in ..."
txnaMode = true
}
// check assembler fails if version before introduction
testLine(t, text, assemblerNoVersion, asmError)
for v := uint64(0); v < fs.version; v++ {
if txnaMode && v >= txnaVersion {
asmError = asmDefaultError
}
testLine(t, text, v, asmError)
}
testLine(t, text, fs.version, "")

ops, err := AssembleStringWithVersion(text, AssemblerMaxVersion)
require.NoError(t, err)

preLogicVersion := fs.version - 1
proto := defaultEvalProtoWithVersion(preLogicVersion)
if preLogicVersion < appsEnabledVersion {
require.False(t, proto.Application)
}
ep := defaultEvalParams(nil, nil)
ep.Proto = &proto
ep.Ledger = ledger
ep.TxnGroup = txgroup

// check failure with version check
_, err = Eval(ops.Program, ep)
require.Error(t, err)
require.Contains(t, err.Error(), "greater than protocol supported version")

// check opcodes failures
ops.Program[0] = byte(preLogicVersion) // set version
_, err = Eval(ops.Program, ep)
require.Error(t, err)
if txnaMode && preLogicVersion < txnaVersion {
require.Contains(t, err.Error(), "illegal opcode")
} else {
require.Contains(t, err.Error(), "invalid txn field")
}

// check opcodes failures on 0 version
ops.Program[0] = 0 // set version to 0
_, err = Eval(ops.Program, ep)
require.Error(t, err)
if txnaMode {
require.Contains(t, err.Error(), "illegal opcode")
} else {
require.Contains(t, err.Error(), "invalid txn field")
}
}
}
}

0 comments on commit 5d7ce82

Please sign in to comment.