Skip to content

Apps: txn.Access list for access to more resources #6286

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 45 commits into from
Aug 6, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e19795b
Initial stuctures and consensus flags for txn.Access
jannotti Mar 26, 2025
98272a3
Committing before some state delta cleanup
jannotti Mar 28, 2025
b8578c3
TestAssets test coverage for tx.Access
jannotti Apr 2, 2025
872e497
wellFormed for tx.Acccess checks internal indices
jannotti Apr 2, 2025
dbbd1bd
Testing and fixes for cross-product resources
jannotti Apr 3, 2025
2ad657d
Many app call well-formed tests for tx.Access
jannotti Apr 4, 2025
13bf5c7
Reflection based testing for Empty() completeness
jannotti Apr 9, 2025
4609198
Correctly check and test for handling multiple types in one elt
jannotti Apr 9, 2025
62751b6
Test fixes for quota bump
jannotti Apr 9, 2025
728815a
NearZero testing
jannotti Apr 10, 2025
5b820c5
Add goal switches to populate access list transactions.
jannotti Apr 11, 2025
3e12d5a
Merge remote-tracking branch 'upstream/master' into access-list
jannotti May 2, 2025
3bcbb16
Merge remote-tracking branch 'upstream/master' into access-list
jannotti Jun 10, 2025
0bbfc58
Fixup Empty check
jannotti Jun 10, 2025
357404c
Shorter wait for deprecation window
jannotti Jun 12, 2025
aff49f2
Export the newly added types for access list
jannotti Jun 12, 2025
edadbff
Merge remote-tracking branch 'upstream/master' into access-list
jannotti Jun 13, 2025
1bac31f
goal e2e sub tests
jannotti Jun 17, 2025
a4831f7
Don't let pre resource sharing programs use tx.Access
jannotti Jun 23, 2025
7972351
Add checks for version / access
jannotti Jun 24, 2025
6551371
Merge remote-tracking branch 'upstream/master' into access-list
jannotti Jun 24, 2025
4628e98
Give a txn so checkprograms doesn't panic in test
jannotti Jun 24, 2025
b31d52e
Repeat app-assets e2e test, btu for --access
jannotti Jun 26, 2025
656e398
Fixups to use ver9 to test access, and shellcheck problems
jannotti Jun 27, 2025
3e00dbc
Use `exit 1` after bare use of `[[ ... ]]`
jannotti Jun 30, 2025
93cdf2f
Remove code that is useless since ver >= sharedResourcesVersion
jannotti Jun 30, 2025
db6cd4e
Use + to separate parts of a holding or local.
jannotti Jun 30, 2025
c1ea94b
Merge remote-tracking branch 'upstream/master' into access-list
jannotti Jul 1, 2025
481ce3b
Update data/transactions/logic/evalStateful_test.go
jannotti Jul 10, 2025
6d01ada
Describe availaibility under tx.Access
jannotti Jul 8, 2025
be9f82d
Unit test for cliAddress
jannotti Jul 10, 2025
f3b2375
Update scripts/export_sdk_types.py
jannotti Jul 10, 2025
658ac8f
clarity
jannotti Jul 10, 2025
801dc21
Remove inadvertant changes
jannotti Jul 10, 2025
82b6abb
No need for separate subtests, just assert in loop
jannotti Jul 10, 2025
81ae84a
CR typos
jannotti Jul 16, 2025
f806cb2
Don't use XXX in comment since people use it to mean TODO
jannotti Jul 17, 2025
7434d1f
comment on 0 interpretation
jannotti Jul 17, 2025
59e60b7
comment on 0 interpretation
jannotti Jul 17, 2025
dd13b79
Remove bad comment
jannotti Jul 18, 2025
b0e1211
CR updates
jannotti Jul 21, 2025
a28efb3
remove unneeded empty tests
jannotti Aug 5, 2025
bde4541
Merge remote-tracking branch 'upstream/master' into access-list
jannotti Aug 5, 2025
819129d
Merge remote-tracking branch 'upstream/master' into access-list
jannotti Aug 6, 2025
35572ee
Update data/transactions/logic/resources.go
jannotti Aug 6, 2025
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
15 changes: 13 additions & 2 deletions config/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,9 @@ type ConsensusParams struct {
// be read in the transaction
MaxAppTxnForeignAssets int

// maximum number of "foreign references" (accounts, asa, app, boxes)
// that can be attached to a single app call.
// maximum number of "foreign references" (accounts, asa, app, boxes) that
// can be attached to a single app call. Modern transactions can use
// MaxAccess references in txn.Access to access more.
MaxAppTotalTxnReferences int

// maximum cost of application approval program or clear state program
Expand Down Expand Up @@ -354,6 +355,9 @@ type ConsensusParams struct {
// Number of box references allowed
MaxAppBoxReferences int

// Number of references allowed in txn.Access
MaxAppAccess int

// Amount added to a txgroup's box I/O budget per box ref supplied.
// For reads: the sum of the sizes of all boxes in the group must be less than I/O budget
// For writes: the sum of the sizes of all boxes created or written must be less than I/O budget
Expand Down Expand Up @@ -449,6 +453,8 @@ type ConsensusParams struct {
// 6. checking that in the case of going online the VoteFirst is less or equal to the next network round.
EnableKeyregCoherencyCheck bool

// EnableExtraPagesOnAppUpdate allows updates to take advantage of the
// existing extra pages setting on an app, not _changing_ that setting.
EnableExtraPagesOnAppUpdate bool

// MaxProposedExpiredOnlineAccounts is the maximum number of online accounts
Expand Down Expand Up @@ -1553,6 +1559,11 @@ func initConsensusProtocols() {

vFuture.LogicSigVersion = 12 // When moving this to a release, put a new higher LogicSigVersion here

// txn.Access work
vFuture.MaxAppTxnAccounts = 8 // Accounts are no worse than others, they should be the same
vFuture.MaxAppAccess = 16 // Twice as many, though cross products are explicit
vFuture.BytesPerBoxReference = 2048 // Count is more important that bytes, loosen up

Consensus[protocol.ConsensusFuture] = vFuture

// vAlphaX versions are an separate series of consensus parameters and versions for alphanet
Expand Down
183 changes: 183 additions & 0 deletions data/basics/testing/nearzero.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Copyright (C) 2019-2025 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// go-algorand is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with go-algorand. If not, see <https://www.gnu.org/licenses/>.

package testing

import (
"reflect"
"testing"
"time"
)

// NearZeros takes a sample in order to retrieve its type. It returns a slice of
// the same type in which each element of the slice is the same type as the
// sample, but exactly one field (or sub-field) is set to a non-zero value. It
// returns one example for every sub-field.
func NearZeros(t *testing.T, sample any) []any {
typ := reflect.TypeOf(sample)
// If sample is a pointer, work with the underlying type.
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()

Check warning on line 33 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L33

Added line #L33 was not covered by tests
}
if typ.Kind() != reflect.Struct {
t.Fatalf("NearZeros: sample must be a struct, got %s", typ.Kind())

Check warning on line 36 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L36

Added line #L36 was not covered by tests
}
paths := CollectPaths(typ, []int{})
var results []any
for _, path := range paths {
inst := makeInstanceWithNonZeroField(typ, path)
results = append(results, inst)
}
return results
}

// CollectPaths walks over the struct type (recursively) and returns a slice of
// index paths. Each path points to exactly one (exported) sub-field.
func CollectPaths(typ reflect.Type, prefix []int) [][]int {
var paths [][]int

switch typ.Kind() {
case reflect.Ptr, reflect.Slice, reflect.Array:
// Look through container to the element
return CollectPaths(typ.Elem(), prefix)

case reflect.Map:

Check warning on line 57 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L57

Added line #L57 was not covered by tests
// Only collect paths into the value, not the key
return CollectPaths(typ.Elem(), prefix)

Check warning on line 59 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L59

Added line #L59 was not covered by tests

case reflect.Struct:
// Special case: skip known value-type structs like time.Time
if typ == reflect.TypeOf(time.Time{}) {
return [][]int{prefix}

Check warning on line 64 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L64

Added line #L64 was not covered by tests
}

for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
if !field.IsExported() {
continue
}
newPath := append(append([]int(nil), prefix...), i)
subPaths := CollectPaths(field.Type, newPath)

// If recursion yielded deeper paths, use them
if len(subPaths) > 0 {
paths = append(paths, subPaths...)
} else {
// Otherwise, it's a leaf field — include it
paths = append(paths, newPath)

Check warning on line 80 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L80

Added line #L80 was not covered by tests
}
}

default:
// Primitive type — record this as a leaf
paths = append(paths, prefix)
}

return paths
}

// makeInstanceWithNonZeroField creates a new instance of type typ and sets exactly one
// field (identified by the fieldPath) to a non-zero value.
func makeInstanceWithNonZeroField(typ reflect.Type, fieldPath []int) any {
// Create a new instance (as a value, not pointer).
inst := reflect.New(typ).Elem()
setFieldToNonZero(inst, fieldPath)
return inst.Interface()
}

// setFieldToNonZero navigates along the given path in the value v and sets that
// field to a non-zero value. The path is a slice of field indices.
func setFieldToNonZero(v reflect.Value, path []int) {
// Walk down the struct fields until the final field.
for i := 0; i < len(path)-1; i++ {
v = v.Field(path[i])
switch v.Kind() {
case reflect.Ptr:
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))

Check warning on line 110 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L108-L110

Added lines #L108 - L110 were not covered by tests
}
v = v.Elem()

Check warning on line 112 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L112

Added line #L112 was not covered by tests
case reflect.Slice:
if v.Len() == 0 {
slice := reflect.MakeSlice(v.Type(), 1, 1)
v.Set(slice)
}
v = v.Index(0)
case reflect.Array:
v = v.Index(0) // Already allocated, just descend

Check warning on line 120 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L119-L120

Added lines #L119 - L120 were not covered by tests
}
}
// Set the final field to an appropriate non-zero value.
field := v.Field(path[len(path)-1])
if field.CanSet() {
field.Set(exampleValue(field.Type()))
}
}

// exampleValue returns a non-zero value for a given type.
// For composite types (like arrays), it sets one element.
func exampleValue(t reflect.Type) reflect.Value {
switch t.Kind() {
case reflect.String:
return reflect.ValueOf("non-zero").Convert(t)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return reflect.ValueOf(1).Convert(t)

Check warning on line 137 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L134-L137

Added lines #L134 - L137 were not covered by tests
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return reflect.ValueOf(1).Convert(t)
case reflect.Bool:
return reflect.ValueOf(true).Convert(t)
case reflect.Float32, reflect.Float64:
return reflect.ValueOf(1.23).Convert(t)
case reflect.Ptr:

Check warning on line 144 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L140-L144

Added lines #L140 - L144 were not covered by tests
// For pointers, allocate a new element and set it to non-zero.
elem := reflect.New(t.Elem())
elem.Elem().Set(exampleValue(t.Elem()))
return elem

Check warning on line 148 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L146-L148

Added lines #L146 - L148 were not covered by tests
case reflect.Slice:
// Create a slice with one element.
slice := reflect.MakeSlice(t, 1, 1)
slice.Index(0).Set(exampleValue(t.Elem()))
return slice
case reflect.Map:

Check warning on line 154 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L154

Added line #L154 was not covered by tests
// Create a map with one key-value pair.
m := reflect.MakeMap(t)
m.SetMapIndex(exampleValue(t.Key()), exampleValue(t.Elem()))
return m

Check warning on line 158 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L156-L158

Added lines #L156 - L158 were not covered by tests
case reflect.Array:
// Create an array and set the first element.
arr := reflect.New(t).Elem()
if t.Len() > 0 {
arr.Index(0).Set(exampleValue(t.Elem()))
}
return arr
case reflect.Struct:

Check warning on line 166 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L166

Added line #L166 was not covered by tests
// For structs, set the first exported field (if any).
s := reflect.New(t).Elem()
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if f.IsExported() {
fv := s.Field(i)
if fv.CanSet() {
fv.Set(exampleValue(f.Type))
break

Check warning on line 175 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L168-L175

Added lines #L168 - L175 were not covered by tests
}
}
}
return s
default:
panic("unable to make a non-zero: " + t.String())

Check warning on line 181 in data/basics/testing/nearzero.go

View check run for this annotation

Codecov / codecov/patch

data/basics/testing/nearzero.go#L179-L181

Added lines #L179 - L181 were not covered by tests
}
}
Loading
Loading