From 5051793a8a9a241882035a5e40cc54ebae134b0a Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Wed, 18 Jan 2023 16:49:45 -0500 Subject: [PATCH 01/29] Initial implementation. Needs unit tests for access to resources in non-appl calls. --- data/basics/userBalance.go | 14 ++ data/transactions/logic/blackbox_test.go | 123 ++++++++++++ data/transactions/logic/eval.go | 201 +++++++++++++------ data/transactions/logic/evalAppTxn_test.go | 2 +- data/transactions/logic/evalStateful_test.go | 54 ++++- data/transactions/logic/eval_test.go | 5 +- data/transactions/logic/ledger_test.go | 30 +-- data/transactions/logic/opcodes.go | 4 + data/transactions/logic/resources.go | 165 +++++++++++++++ ledger/eval_simple_test.go | 194 +++++++++++++++++- ledger/internal/cow_creatables.go | 4 +- ledger/simple_test.go | 16 ++ 12 files changed, 715 insertions(+), 97 deletions(-) create mode 100644 data/transactions/logic/resources.go diff --git a/data/basics/userBalance.go b/data/basics/userBalance.go index f10c326354..cec1534df2 100644 --- a/data/basics/userBalance.go +++ b/data/basics/userBalance.go @@ -343,6 +343,20 @@ type CreatableLocator struct { Index CreatableIndex } +// HoldingLocator stores enough information to name a "Holding" the balance of +// an ASA for a particular account. +type HoldingLocator struct { + Address Address + Index AssetIndex +} + +// LocalsLocator stores enough information to find the Local State that an +// account has with a particular app. +type LocalsLocator struct { + Address Address + Index AppIndex +} + // AssetHolding describes an asset held by an account. type AssetHolding struct { _struct struct{} `codec:",omitempty,omitemptyarray"` diff --git a/data/transactions/logic/blackbox_test.go b/data/transactions/logic/blackbox_test.go index 79029f2c38..49641ed7a2 100644 --- a/data/transactions/logic/blackbox_test.go +++ b/data/transactions/logic/blackbox_test.go @@ -97,3 +97,126 @@ func TestNewAppEvalParams(t *testing.T) { } } } + +// TestAppSharing confirms that as of v9, assets can be accessed across +// groups, but that before then, they could not. +func TestAppSharing(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + // Create some sample transactions. The main reason this a blackbox test + // (_test package) is to have access to txntest. + appl0 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{1, 2, 3, 4}, + ForeignApps: []basics.AppIndex{500}, + } + + appl1 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{4, 3, 2, 1}, + } + + appl2 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{1, 2, 3, 4}, + } + + getSchema := ` +int 500 +app_params_get AppGlobalNumByteSlice +!; assert; pop; int 1 +` + sources := []string{getSchema, getSchema} + // In v8, the first tx can read app params of 500, because it's in its + // foreign array, but the second can't + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.NewExpect(1, "invalid App reference 500")) + // In v9, the second can, because the first can. + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil) + + getLocalEx := ` +int 0 // Sender +int 500 +byte "some-key" +app_local_get_ex +pop; pop; int 1 +` + + sources = []string{getLocalEx, getLocalEx} + // In contrast, here there's no help from v9, because the second tx is + // reading the locals for a different account. + + // app_local_get* requires the address and the app exist, else the program fails + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.NewExpect(0, "no account")) + + _, _, ledger := logic.MakeSampleEnv() + ledger.NewAccount(appl0.Sender, 100_000) + ledger.NewApp(appl0.Sender, 500, basics.AppParams{}) + ledger.NewLocals(appl0.Sender, 500) // opt in + // Now txn0 passes, but txn1 has an error because it can't see app 500 + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, ledger, + logic.NewExpect(1, "invalid Local State access")) + + // But it's ok in appl2, because appl2 uses the same Sender, even though the + // foreign-app is not repeated in appl2 so the holding being accessed is is + // the one from tx0. + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl2), 9, ledger) +} + +// TestAssetSharing confirms that as of v9, assets can be accessed across +// groups, but that before then, they could not. +func TestAssetSharing(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + // Create some sample transactions. The main reason this a blackbox test + // (_test package) is to have access to txntest. + appl0 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{1, 2, 3, 4}, + ForeignAssets: []basics.AssetIndex{400}, + } + + appl1 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{4, 3, 2, 1}, + } + + appl2 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{1, 2, 3, 4}, + } + + getTotal := ` +int 400 +asset_params_get AssetTotal +pop; pop; int 1 +` + sources := []string{getTotal, getTotal} + // In v8, the first tx can read asset 400, because it's in its foreign arry, + // but the second can't + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.NewExpect(1, "invalid Asset reference 400")) + // In v9, the second can, because the first can. + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil) + + getBalance := ` +int 0 +int 400 +asset_holding_get AssetBalance +pop; pop; int 1 +` + + sources = []string{getBalance, getBalance} + // In contrast, here there's no help from v9, because the second tx is + // reading a holding for a different account. + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.NewExpect(1, "invalid Asset reference 400")) + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil, + logic.NewExpect(1, "invalid Holding access")) + // But it's ok in appl2, because the same account is used, even though the + // foreign-asset is not repeated in appl2. + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl2), 9, nil) +} diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 3de0f101d6..726c6158c3 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -242,25 +242,6 @@ type LedgerForLogic interface { Counter() uint64 } -// resources contains a catalog of available resources. It's used to track the -// apps, assets, and boxes that are available to a transaction, outside the -// direct foreign array mechanism. -type resources struct { - asas []basics.AssetIndex - apps []basics.AppIndex - - // boxes are all of the top-level box refs from the txgroup. Most are added - // during NewEvalParams(). refs using 0 on an appl create are resolved and - // added when the appl executes. The boolean value indicates the "dirtiness" - // of the box - has it been modified in this txngroup? If yes, the size of - // the box counts against the group writeBudget. So delete is NOT a dirtying - // operation. - boxes map[boxRef]bool - - // dirtyBytes maintains a running count of the number of dirty bytes in `boxes` - dirtyBytes uint64 -} - // boxRef is the "hydrated" form of a BoxRef - it has the actual app id, not an index type boxRef struct { app basics.AppIndex @@ -349,30 +330,9 @@ func copyWithClearAD(txgroup []transactions.SignedTxnWithAD) []transactions.Sign // NewEvalParams creates an EvalParams to use while evaluating a top-level txgroup func NewEvalParams(txgroup []transactions.SignedTxnWithAD, proto *config.ConsensusParams, specials *transactions.SpecialAddresses) *EvalParams { apps := 0 - var allBoxes map[boxRef]bool for _, tx := range txgroup { if tx.Txn.Type == protocol.ApplicationCallTx { apps++ - if allBoxes == nil && len(tx.Txn.Boxes) > 0 { - allBoxes = make(map[boxRef]bool) - } - for _, br := range tx.Txn.Boxes { - var app basics.AppIndex - if br.Index == 0 { - // "current app": Ignore if this is a create, else use ApplicationID - if tx.Txn.ApplicationID == 0 { - // When the create actually happens, and we learn the appID, we'll add it. - continue - } - app = tx.Txn.ApplicationID - } else { - // Bounds check will already have been done by - // WellFormed. For testing purposes, it's better to panic - // now than after returning a nil. - app = tx.Txn.ForeignApps[br.Index-1] // shift for the 0=this convention - } - allBoxes[boxRef{app, string(br.Name)}] = false - } } } @@ -392,17 +352,17 @@ func NewEvalParams(txgroup []transactions.SignedTxnWithAD, proto *config.Consens credit := feeCredit(txgroup, proto.MinTxnFee) - if proto.EnableAppCostPooling && apps > 0 { + if proto.EnableAppCostPooling { pooledApplicationBudget = new(int) *pooledApplicationBudget = apps * proto.MaxAppProgramCost } - if proto.EnableInnerTransactionPooling && apps > 0 { + if proto.EnableInnerTransactionPooling { pooledAllowedInners = new(int) *pooledAllowedInners = proto.MaxTxGroupSize * proto.MaxInnerTransactions } - return &EvalParams{ + ep := &EvalParams{ TxnGroup: copyWithClearAD(txgroup), Proto: proto, Specials: specials, @@ -411,9 +371,44 @@ func NewEvalParams(txgroup []transactions.SignedTxnWithAD, proto *config.Consens FeeCredit: &credit, PooledApplicationBudget: pooledApplicationBudget, pooledAllowedInners: pooledAllowedInners, - available: &resources{boxes: allBoxes}, appAddrCache: make(map[basics.AppIndex]basics.Address), } + // resources are computed after ep is constructed because app addresses are + // calculated there, and we'd like to use the caching mechanism built into + // the EvalParams. Perhaps we can make the computation even lazier, so it is + // only computed if needed (some program actually refers to a resource that + // isn't available in the old way). + ep.available = ep.computeAvailability() + return ep +} + +func (ep *EvalParams) computeAvailability() *resources { + available := &resources{ + sharedAccounts: make(map[basics.Address]struct{}), + sharedAsas: make(map[basics.AssetIndex]struct{}), + sharedApps: make(map[basics.AppIndex]struct{}), + sharedHoldings: make(map[basics.HoldingLocator]struct{}), + sharedLocals: make(map[basics.LocalsLocator]struct{}), + boxes: make(map[boxRef]bool), + } + for i := range ep.TxnGroup { + tx := &ep.TxnGroup[i] + switch tx.Txn.Type { + case protocol.PaymentTx: + available.fillPayment(&tx.Txn.Header, &tx.Txn.PaymentTxnFields) + case protocol.KeyRegistrationTx: + available.fillKeyRegistration(&tx.Txn.Header) + case protocol.AssetConfigTx: + available.fillAssetConfig(&tx.Txn.Header, &tx.Txn.AssetConfigTxnFields) + case protocol.AssetTransferTx: + available.fillAssetTransfer(&tx.Txn.Header, &tx.Txn.AssetTransferTxnFields) + case protocol.AssetFreezeTx: + available.fillAssetFreeze(&tx.Txn.Header, &tx.Txn.AssetFreezeTxnFields) + case protocol.ApplicationCallTx: + available.fillApplicationCall(ep, &tx.Txn.Header, &tx.Txn.ApplicationCallTxnFields) + } + } + return available } // feeCredit returns the extra fee supplied in this top-level txgroup compared @@ -531,10 +526,10 @@ func (ep *EvalParams) RecordAD(gi int, ad transactions.ApplyData) { } ep.TxnGroup[gi].ApplyData = ad if aid := ad.ConfigAsset; aid != 0 { - ep.available.asas = append(ep.available.asas, aid) + ep.available.createdAsas = append(ep.available.createdAsas, aid) } if aid := ad.ApplicationID; aid != 0 { - ep.available.apps = append(ep.available.apps, aid) + ep.available.createdApps = append(ep.available.createdApps, aid) } } @@ -3256,14 +3251,14 @@ func (cx *EvalContext) getLatestTimestamp() (uint64, error) { } // getApplicationAddress memoizes app.Address() across a tx group's evaluation -func (cx *EvalContext) getApplicationAddress(app basics.AppIndex) basics.Address { +func (ep *EvalParams) getApplicationAddress(app basics.AppIndex) basics.Address { /* Do not instantiate the cache here, that would mask a programming error. The cache must be instantiated at EvalParams construction time, so that proper sharing with inner EvalParams can work. */ - appAddr, ok := cx.appAddrCache[app] + appAddr, ok := ep.appAddrCache[app] if !ok { appAddr = app.Address() - cx.appAddrCache[app] = appAddr + ep.appAddrCache[app] = appAddr } return appAddr @@ -4005,11 +4000,12 @@ func opExtract64Bits(cx *EvalContext) error { // accountReference yields the address and Accounts offset designated by a // stackValue. If the stackValue is the app account, an account of an app in -// created.apps, or an account of an app in foreignApps, and it is not in the -// Accounts array, then len(Accounts) + 1 is returned as the index. This would -// let us catch the mistake if the index is used for set/del. If the txn somehow -// "psychically" predicted the address, and therefore it IS in txn.Accounts, -// then happy day, we can set/del it. Return the proper index. +// created.apps, an account of an app in foreignApps, or an account made +// available by another txn, and it is not in the Accounts array, then +// len(Accounts) + 1 is returned as the index. This would let us catch the +// mistake if the index is used for set/del. If the txn somehow "psychically" +// predicted the address, and therefore it IS in txn.Accounts, then happy day, +// we can set/del it. Return the proper index. // If we ever want apps to be able to change local state on these accounts // (which includes this app's own account!), we will need a change to @@ -4030,7 +4026,7 @@ func (cx *EvalContext) accountReference(account stackValue) (basics.Address, uin invalidIndex := uint64(len(cx.txn.Txn.Accounts) + 1) // Allow an address for an app that was created in group if err != nil && cx.version >= createdResourcesVersion { - for _, appID := range cx.available.apps { + for _, appID := range cx.available.createdApps { createdAddress := cx.getApplicationAddress(appID) if addr == createdAddress { return addr, invalidIndex, nil @@ -4038,6 +4034,13 @@ func (cx *EvalContext) accountReference(account stackValue) (basics.Address, uin } } + // or some other txn mentioned it + if err != nil && cx.version >= resourceSharingVersion { + if _, ok := cx.available.sharedAccounts[addr]; ok { + return addr, invalidIndex, nil + } + } + // Allow an address for an app that was provided in the foreign apps array. if err != nil && cx.version >= appAddressAvailableVersion { for _, appID := range cx.txn.Txn.ForeignApps { @@ -4177,6 +4180,11 @@ func opAppLocalGetImpl(cx *EvalContext, appID uint64, key []byte, acct stackValu return } + if !cx.availableLocals(addr, app) { + err = fmt.Errorf("invalid Local State access %s x %d", addr, app) + return + } + tv, ok, err := cx.Ledger.GetLocal(addr, app, string(key), accountIdx) if err != nil { return @@ -4410,12 +4418,18 @@ func appReference(cx *EvalContext, ref uint64, foreign bool) (basics.AppIndex, e } // or was created in group if cx.version >= createdResourcesVersion { - for _, appID := range cx.available.apps { + for _, appID := range cx.available.createdApps { if appID == basics.AppIndex(ref) { return appID, nil } } } + // or some other txn mentioned it + if cx.version >= resourceSharingVersion { + if _, ok := cx.available.sharedApps[basics.AppIndex(ref)]; ok { + return basics.AppIndex(ref), nil + } + } // Allow use of indexes, but this comes last so that clear advice can be // given to anyone who cares about semantics in the first few rounds of // a new network - don't use indexes for references, use the App ID @@ -4449,12 +4463,19 @@ func asaReference(cx *EvalContext, ref uint64, foreign bool) (basics.AssetIndex, } // or was created in group if cx.version >= createdResourcesVersion { - for _, assetID := range cx.available.asas { + for _, assetID := range cx.available.createdAsas { if assetID == basics.AssetIndex(ref) { return assetID, nil } } } + // or some other txn mentioned it + if cx.version >= resourceSharingVersion { + if _, ok := cx.available.sharedAsas[basics.AssetIndex(ref)]; ok { + return basics.AssetIndex(ref), nil + } + } + // Allow use of indexes, but this comes last so that clear advice can be // given to anyone who cares about semantics in the first few rounds of // a new network - don't use indexes for references, use the asa ID. @@ -4497,16 +4518,22 @@ func opAssetHoldingGet(cx *EvalContext) error { return err } + if !cx.availableHolding(addr, asset) { + return fmt.Errorf("invalid Holding access %s x %d", addr, asset) + } + + fmt.Printf("> %s %d\n", addr, asset) var exist uint64 = 0 var value stackValue if holding, err := cx.Ledger.AssetHolding(addr, asset); err == nil { - // the holding exist, read the value + // the holding exists, read the value exist = 1 value, err = cx.assetHoldingToValue(&holding, fs) if err != nil { return err } } + fmt.Printf("err=%v\n", err) cx.stack[prev] = value cx.stack[last].Uint = exist @@ -4756,13 +4783,20 @@ func (cx *EvalContext) availableAsset(sv stackValue) (basics.AssetIndex, error) } // or was created in group if cx.version >= createdResourcesVersion { - for _, assetID := range cx.available.asas { + for _, assetID := range cx.available.createdAsas { if assetID == aid { return aid, nil } } } + // or some other txn mentioned it + if cx.version >= resourceSharingVersion { + if _, ok := cx.available.sharedAsas[aid]; ok { + return aid, nil + } + } + return basics.AssetIndex(0), fmt.Errorf("invalid Asset reference %d", aid) } @@ -4784,7 +4818,7 @@ func (cx *EvalContext) availableApp(sv stackValue) (basics.AppIndex, error) { } // or was created in group if cx.version >= createdResourcesVersion { - for _, appID := range cx.available.apps { + for _, appID := range cx.available.createdApps { if appID == aid { return aid, nil } @@ -4795,9 +4829,56 @@ func (cx *EvalContext) availableApp(sv stackValue) (basics.AppIndex, error) { return aid, nil } + // or some other txn mentioned it + if cx.version >= resourceSharingVersion { + if _, ok := cx.available.sharedApps[aid]; ok { + return aid, nil + } + } + return 0, fmt.Errorf("invalid App reference %d", aid) } +// availableHolding is an additional check, required since +// resourceSharingVersion. It will work in previous versions too, since +// cx.available will be populated to make it work. But it must protect for < +// directRefEnabledVersion, because unnamed holdings could be read then. +func (cx *EvalContext) availableHolding(addr basics.Address, ai basics.AssetIndex) bool { + if cx.version < directRefEnabledVersion { + return true + } + if _, ok := cx.available.sharedHoldings[basics.HoldingLocator{Address: addr, Index: ai}]; ok { + return true + } + // All holdings of created assets are available + for _, created := range cx.available.createdAsas { + if created == ai { + return true + } + } + return false +} + +// availableLocals is an additional check, required since +// resourceSharingVersion. It will work in previous versions too, since +// cx.available will be populated to make it work. But it must protect for < +// directRefEnabledVersion, because unnamed holdings could be read then. +func (cx *EvalContext) availableLocals(addr basics.Address, ai basics.AppIndex) bool { + if cx.version < directRefEnabledVersion { + return true + } + if _, ok := cx.available.sharedLocals[basics.LocalsLocator{Address: addr, Index: ai}]; ok { + return true + } + // All locals of created apps are available + for _, created := range cx.available.createdApps { + if created == ai { + return true + } + } + return false +} + func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *transactions.Transaction) (err error) { switch fs.field { case Type: diff --git a/data/transactions/logic/evalAppTxn_test.go b/data/transactions/logic/evalAppTxn_test.go index 2886b57a52..cdcced4301 100644 --- a/data/transactions/logic/evalAppTxn_test.go +++ b/data/transactions/logic/evalAppTxn_test.go @@ -1153,7 +1153,7 @@ int 5000; app_params_get AppGlobalNumByteSlice; !; assert; !; assert; int 1 `, ep) // Can't call it either - TestApp(t, call, ep, "no such app 5000") + TestApp(t, call, ep, "no app 5000") } diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index f6ab14a078..d4a47634fa 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -70,6 +70,50 @@ func makeOldAndNewEnv(version uint64) (*EvalParams, *EvalParams, *Ledger) { return old, new, sharedLedger } +func (r *resources) String() string { + sb := strings.Builder{} + if len(r.createdAsas) > 0 { + fmt.Fprintf(&sb, "createdAsas: %v\n", r.createdAsas) + } + if len(r.createdApps) > 0 { + fmt.Fprintf(&sb, "createdApps: %v\n", r.createdApps) + } + + if len(r.sharedAccounts) > 0 { + fmt.Fprintf(&sb, "sharedAccts:\n") + for addr := range r.sharedAccounts { + fmt.Fprintf(&sb, " %s\n", addr) + } + } + if len(r.sharedAsas) > 0 { + fmt.Fprintf(&sb, "sharedAsas:\n") + for id := range r.sharedAsas { + fmt.Fprintf(&sb, " %d\n", id) + } + } + if len(r.sharedApps) > 0 { + fmt.Fprintf(&sb, "sharedApps:\n") + for id := range r.sharedApps { + fmt.Fprintf(&sb, " %d\n", id) + } + } + + if len(r.sharedHoldings) > 0 { + fmt.Fprintf(&sb, "sharedHoldings:\n") + for hl := range r.sharedHoldings { + fmt.Fprintf(&sb, " %s x %d\n", hl.Address, hl.Index) + } + } + if len(r.sharedLocals) > 0 { + fmt.Fprintf(&sb, "sharedLocals:\n") + for hl := range r.sharedLocals { + fmt.Fprintf(&sb, " %s x %d\n", hl.Address, hl.Index) + } + } + + return sb.String() +} + func TestEvalModes(t *testing.T) { partitiontest.PartitionTest(t) @@ -618,7 +662,7 @@ byte 0x414c474f testApp(t, strings.Replace(text, "int 100 // app id", "int 2", -1), pre, "is not opted into") testApp(t, strings.Replace(text, "int 100 // app id", "int 9", -1), now, "invalid App reference 9") testApp(t, strings.Replace(text, "int 1 // account idx", "byte \"aoeuiaoeuiaoeuiaoeuiaoeuiaoeui00\"", -1), now, - "no such address") + "no account") // opt into 123, and try again ledger.NewApp(now.TxnGroup[0].Txn.Receiver, 123, basics.AppParams{}) @@ -729,7 +773,7 @@ byte 0x414c474f now.TxnGroup[0].Txn.ApplicationID = 100 now.TxnGroup[0].Txn.ForeignApps = []basics.AppIndex{now.TxnGroup[0].Txn.ApplicationID} - testApp(t, text, now, "no such app") + testApp(t, text, now, "no app 100") // create the app and check the value from ApplicationArgs[0] (protocol.PaymentTx) does not exist ledger.NewApp(now.TxnGroup[0].Txn.Sender, 100, basics.AppParams{}) @@ -1645,7 +1689,7 @@ int 1 ep, txn, ledger := makeSampleEnv() txn.ApplicationID = basics.AppIndex(100) - testAppBytes(t, ops.Program, ep, "no such app") + testAppBytes(t, ops.Program, ep, "no app 100") ledger.NewApp(txn.Sender, 100, makeApp(0, 0, 1, 0)) @@ -1873,7 +1917,7 @@ byte "myval" ledger.NewAccount(txn.Sender, 1) ledger.NewApp(txn.Sender, 100, basics.AppParams{}) - delta := testApp(t, source, ep, "no such app") + delta := testApp(t, source, ep, "no app 101") require.Empty(t, delta.GlobalDelta) require.Empty(t, delta.LocalDeltas) @@ -2791,7 +2835,7 @@ app_local_del ` testApp(t, source, ep, "invalid Account reference for mutation") - /* But let's just check normal access is working properly. */ + /* But let's just check read access is working properly. */ source = ` global CurrentApplicationAddress byte "hey" diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go index 5d5f321280..1037f78bcf 100644 --- a/data/transactions/logic/eval_test.go +++ b/data/transactions/logic/eval_test.go @@ -168,12 +168,9 @@ func (ep *EvalParams) reset() { ep.TxnGroup[i].ApplyData = transactions.ApplyData{} } if ep.available != nil { - ep.available.apps = nil - ep.available.asas = nil - // reinitialize boxes because evaluation can add box refs for app creates. available := NewEvalParams(ep.TxnGroup, ep.Proto, ep.Specials).available if available != nil { - ep.available.boxes = available.boxes + ep.available = available } ep.available.dirtyBytes = 0 } diff --git a/data/transactions/logic/ledger_test.go b/data/transactions/logic/ledger_test.go index ecda755627..9d6106e57b 100644 --- a/data/transactions/logic/ledger_test.go +++ b/data/transactions/logic/ledger_test.go @@ -328,7 +328,7 @@ func (l *Ledger) Authorizer(addr basics.Address) (basics.Address, error) { func (l *Ledger) GetGlobal(appIdx basics.AppIndex, key string) (basics.TealValue, bool, error) { params, ok := l.applications[appIdx] if !ok { - return basics.TealValue{}, false, fmt.Errorf("no such app %d", appIdx) + return basics.TealValue{}, false, fmt.Errorf("no app %d", appIdx) } // return most recent value if available @@ -351,7 +351,7 @@ func (l *Ledger) GetGlobal(appIdx basics.AppIndex, key string) (basics.TealValue func (l *Ledger) SetGlobal(appIdx basics.AppIndex, key string, value basics.TealValue) error { params, ok := l.applications[appIdx] if !ok { - return fmt.Errorf("no such app %d", appIdx) + return fmt.Errorf("no app %d", appIdx) } // if writing the same value, return @@ -375,7 +375,7 @@ func (l *Ledger) SetGlobal(appIdx basics.AppIndex, key string, value basics.Teal func (l *Ledger) DelGlobal(appIdx basics.AppIndex, key string) error { params, ok := l.applications[appIdx] if !ok { - return fmt.Errorf("no such app %d", appIdx) + return fmt.Errorf("no app %d", appIdx) } exist := false @@ -405,7 +405,7 @@ func (l *Ledger) NewBox(appIdx basics.AppIndex, key string, value []byte, appAdd } params, ok := l.applications[appIdx] if !ok { - return fmt.Errorf("no such app %d", appIdx) + return fmt.Errorf("no app %d", appIdx) } if params.boxMods == nil { params.boxMods = make(map[string][]byte) @@ -449,7 +449,7 @@ func (l *Ledger) SetBox(appIdx basics.AppIndex, key string, value []byte) error return err } if !ok { - return fmt.Errorf("no such box %d", appIdx) + return fmt.Errorf("no box %d", appIdx) } params := l.applications[appIdx] // assured, based on above if params.boxMods == nil { @@ -487,7 +487,7 @@ func (l *Ledger) DelBox(appIdx basics.AppIndex, key string, appAddr basics.Addre func (l *Ledger) GetLocal(addr basics.Address, appIdx basics.AppIndex, key string, accountIdx uint64) (basics.TealValue, bool, error) { br, ok := l.balances[addr] if !ok { - return basics.TealValue{}, false, fmt.Errorf("no such address") + return basics.TealValue{}, false, fmt.Errorf("no account: %s", addr) } tkvd, ok := br.locals[appIdx] if !ok { @@ -513,7 +513,7 @@ func (l *Ledger) GetLocal(addr basics.Address, appIdx basics.AppIndex, key strin func (l *Ledger) SetLocal(addr basics.Address, appIdx basics.AppIndex, key string, value basics.TealValue, accountIdx uint64) error { br, ok := l.balances[addr] if !ok { - return fmt.Errorf("no such address") + return fmt.Errorf("no account: %s", addr) } tkv, ok := br.locals[appIdx] if !ok { @@ -541,7 +541,7 @@ func (l *Ledger) SetLocal(addr basics.Address, appIdx basics.AppIndex, key strin func (l *Ledger) DelLocal(addr basics.Address, appIdx basics.AppIndex, key string, accountIdx uint64) error { br, ok := l.balances[addr] if !ok { - return fmt.Errorf("no such address") + return fmt.Errorf("no account: %s", addr) } tkv, ok := br.locals[appIdx] if !ok { @@ -573,7 +573,7 @@ func (l *Ledger) DelLocal(addr basics.Address, appIdx basics.AppIndex, key strin func (l *Ledger) OptedIn(addr basics.Address, appIdx basics.AppIndex) (bool, error) { br, ok := l.balances[addr] if !ok { - return false, fmt.Errorf("no such address") + return false, fmt.Errorf("no account: %s", addr) } _, ok = br.locals[appIdx] return ok, nil @@ -586,9 +586,9 @@ func (l *Ledger) AssetHolding(addr basics.Address, assetID basics.AssetIndex) (b if asset, ok := br.holdings[assetID]; ok { return asset, nil } - return basics.AssetHolding{}, fmt.Errorf("No asset for account") + return basics.AssetHolding{}, fmt.Errorf("no asset %d for account %s", assetID, addr) } - return basics.AssetHolding{}, fmt.Errorf("no such address") + return basics.AssetHolding{}, fmt.Errorf("no account: %s", addr) } // AssetParams gives the parameters of an ASA if it exists @@ -596,7 +596,7 @@ func (l *Ledger) AssetParams(assetID basics.AssetIndex) (basics.AssetParams, bas if asset, ok := l.assets[assetID]; ok { return asset.AssetParams, asset.Creator, nil } - return basics.AssetParams{}, basics.Address{}, fmt.Errorf("no such asset") + return basics.AssetParams{}, basics.Address{}, fmt.Errorf("no asset %d", assetID) } // AppParams gives the parameters of an App if it exists @@ -604,7 +604,7 @@ func (l *Ledger) AppParams(appID basics.AppIndex) (basics.AppParams, basics.Addr if app, ok := l.applications[appID]; ok { return app.AppParams, app.Creator, nil } - return basics.AppParams{}, basics.Address{}, fmt.Errorf("no such app %d", appID) + return basics.AppParams{}, basics.Address{}, fmt.Errorf("no app %d", appID) } func (l *Ledger) move(from basics.Address, to basics.Address, amount uint64) error { @@ -905,7 +905,7 @@ func (l *Ledger) Perform(gi int, ep *EvalParams) error { func (l *Ledger) Get(addr basics.Address, withPendingRewards bool) (basics.AccountData, error) { br, ok := l.balances[addr] if !ok { - return basics.AccountData{}, fmt.Errorf("addr %s not in test.Ledger", addr.String()) + return basics.AccountData{}, fmt.Errorf("no account %s", addr) } return basics.AccountData{ MicroAlgos: basics.MicroAlgos{Raw: br.balance}, @@ -926,7 +926,7 @@ func (l *Ledger) GetCreator(cidx basics.CreatableIndex, ctype basics.CreatableTy params, found := l.applications[basics.AppIndex(cidx)] return params.Creator, found, nil } - return basics.Address{}, false, fmt.Errorf("%v %d is not in test.Ledger", ctype, cidx) + return basics.Address{}, false, fmt.Errorf("no creatable %v %d", ctype, cidx) } // SetKey creates a new key-value in {addr, aidx, global} storage diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index 5dd6f20d12..afb6c10af7 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -57,6 +57,10 @@ const txnEffectsVersion = 6 // the Foreign arrays. const createdResourcesVersion = 6 +// resourceSharingVersion is the first version in which apps are allowed to +// access resource referenced in other transactions. +const resourceSharingVersion = 9 + // appAddressAvailableVersion is the first version that allows access to the // accounts of applications that were provided in the foreign apps transaction // field. diff --git a/data/transactions/logic/resources.go b/data/transactions/logic/resources.go new file mode 100644 index 0000000000..e8578b1c37 --- /dev/null +++ b/data/transactions/logic/resources.go @@ -0,0 +1,165 @@ +// Copyright (C) 2019-2023 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 . + +package logic + +import ( + "github.com/algorand/go-algorand/data/basics" + "github.com/algorand/go-algorand/data/transactions" +) + +// resources contains a catalog of available resources. It's used to track the +// apps, assets, and boxes that are available to a transaction, outside the +// direct foreign array mechanism. +type resources struct { + // These resources were created previously in the group, so they can be used + // by later transactions. + createdAsas []basics.AssetIndex + createdApps []basics.AppIndex + + // These resources have been mentioned by some txn in the group, so they are + // available. But only their "main" data is available. For example, if an + // account is mentioned, its algo balance is available, but not necessarily + // its asset balance for any old ASA. + sharedAccounts map[basics.Address]struct{} + sharedAsas map[basics.AssetIndex]struct{} + sharedApps map[basics.AppIndex]struct{} + // We need to carefully track the "cross-product" availability, because if + // tx0 mentions an account A, and tx1 mentions an ASA X, that does _not_ + // make the holding AX available + sharedHoldings map[basics.HoldingLocator]struct{} + sharedLocals map[basics.LocalsLocator]struct{} + + // boxes are all of the top-level box refs from the txgroup. Most are added + // during NewEvalParams(). refs using 0 on an appl create are resolved and + // added when the appl executes. The boolean value indicates the "dirtiness" + // of the box - has it been modified in this txngroup? If yes, the size of + // the box counts against the group writeBudget. So delete is NOT a dirtying + // operation. + boxes map[boxRef]bool + + // dirtyBytes maintains a running count of the number of dirty bytes in `boxes` + dirtyBytes uint64 +} + +func (r *resources) shareHolding(addr basics.Address, id basics.AssetIndex) { + r.sharedHoldings[basics.HoldingLocator{Address: addr, Index: id}] = struct{}{} +} + +func (r *resources) shareLocal(addr basics.Address, id basics.AppIndex) { + r.sharedLocals[basics.LocalsLocator{Address: addr, Index: id}] = struct{}{} +} + +// In the fill routines, we pass the header and the fields in separately, even +// though they are pointers into the same structure. That prevents dumb attempts +// to use other fields from the transaction. + +func (r *resources) fillKeyRegistration(hdr *transactions.Header) { + r.sharedAccounts[hdr.Sender] = struct{}{} +} + +func (r *resources) fillPayment(hdr *transactions.Header, tx *transactions.PaymentTxnFields) { + r.sharedAccounts[hdr.Sender] = struct{}{} + r.sharedAccounts[tx.Receiver] = struct{}{} + if !tx.CloseRemainderTo.IsZero() { + r.sharedAccounts[tx.CloseRemainderTo] = struct{}{} + } +} + +func (r *resources) fillAssetConfig(hdr *transactions.Header, tx *transactions.AssetConfigTxnFields) { + r.sharedAccounts[hdr.Sender] = struct{}{} + if id := tx.ConfigAsset; id != 0 { + r.sharedAsas[id] = struct{}{} + r.shareHolding(hdr.Sender, id) + } + // We don't need to read the special addresses, so they don't go in. +} + +func (r *resources) fillAssetTransfer(hdr *transactions.Header, tx *transactions.AssetTransferTxnFields) { + r.sharedAccounts[hdr.Sender] = struct{}{} + id := tx.XferAsset + r.sharedAsas[id] = struct{}{} + r.shareHolding(hdr.Sender, id) + + if !tx.AssetSender.IsZero() { + r.shareHolding(tx.AssetSender, id) + } + r.shareHolding(tx.AssetReceiver, id) + if !tx.AssetCloseTo.IsZero() { + r.shareHolding(tx.AssetCloseTo, id) + } +} + +func (r *resources) fillAssetFreeze(hdr *transactions.Header, tx *transactions.AssetFreezeTxnFields) { + r.sharedAccounts[hdr.Sender] = struct{}{} + id := tx.FreezeAsset + r.sharedAsas[id] = struct{}{} + r.shareHolding(tx.FreezeAccount, id) +} + +func (r *resources) fillApplicationCall(ep *EvalParams, hdr *transactions.Header, tx *transactions.ApplicationCallTxnFields) { + txAccounts := make([]basics.Address, 0, 2+len(tx.Accounts)+len(tx.ForeignApps)) + txAccounts = append(txAccounts, hdr.Sender) + txAccounts = append(txAccounts, tx.Accounts...) + for _, id := range tx.ForeignAssets { + r.sharedAsas[id] = struct{}{} + } + // Make the app account associated with app calls available. We + // don't have to add code to make the accounts of freshly created + // apps available, because that is already handled by looking at + // `createdApps`. + if id := tx.ApplicationID; id != 0 { + txAccounts = append(txAccounts, ep.getApplicationAddress(id)) + r.sharedApps[id] = struct{}{} + } + for _, id := range tx.ForeignApps { + txAccounts = append(txAccounts, ep.getApplicationAddress(id)) + r.sharedApps[id] = struct{}{} + } + for _, address := range txAccounts { + r.sharedAccounts[address] = struct{}{} + + for _, id := range tx.ForeignAssets { + r.shareHolding(address, id) + } + // Similar to note about app accounts, availableLocals allows + // all createdApps holdings, so we don't care if id == 0 here. + if id := tx.ApplicationID; id != 0 { + r.shareLocal(address, id) + } + for _, id := range tx.ForeignApps { + r.shareLocal(address, id) + } + } + + for _, br := range tx.Boxes { + var app basics.AppIndex + if br.Index == 0 { + // "current app": Ignore if this is a create, else use ApplicationID + if tx.ApplicationID == 0 { + // When the create actually happens, and we learn the appID, we'll add it. + continue + } + app = tx.ApplicationID + } else { + // Bounds check will already have been done by + // WellFormed. For testing purposes, it's better to panic + // now than after returning a nil. + app = tx.ForeignApps[br.Index-1] // shift for the 0=this convention + } + r.boxes[boxRef{app, string(br.Name)}] = false + } +} diff --git a/ledger/eval_simple_test.go b/ledger/eval_simple_test.go index c5c9354520..436a9ad398 100644 --- a/ledger/eval_simple_test.go +++ b/ledger/eval_simple_test.go @@ -210,18 +210,192 @@ func TestBlockEvaluator(t *testing.T) { require.Equal(t, bal2new.MicroAlgos.Raw, bal2.MicroAlgos.Raw-minFee.Raw) } +// TestHoldingGet tests some of the corner cases for the asset_holding_get +// opcode: the asset doesn't exist, the account doesn't exist, account not opted +// in, vs it has none of the asset. This is tested here, even though it should +// be well tested in 'logic' package, because we want to make sure that errors +// come out of the real ledger in the way that the logic package expects (it +// uses a mock ledger for testing). +func TestHoldingGet(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + genBalances, addrs, _ := ledgertesting.NewTestGenesis() + // 24 is first version with apps + ledgertesting.TestConsensusRange(t, 24, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion) { + dl := NewDoubleLedger(t, genBalances, cv) + defer dl.Close() + + makegold := txntest.Txn{ + Type: protocol.AssetConfigTx, + Sender: addrs[0], + AssetParams: basics.AssetParams{ + Total: 10, + UnitName: "gold", + AssetName: "oz", + }, + } + + // written without assert or swap, so we can use teal v2 and test back to consensus v24 + source := ` +#pragma version 2 +txn ApplicationID +bnz main +int 1; return +main: + txn NumAccounts // Sender, or Accounts[n] + txn ApplicationArgs 0; btoi + asset_holding_get AssetBalance + txn ApplicationArgs 1; btoi; ==; bz bad + txn ApplicationArgs 2; btoi; ==; return +bad: err +` + + // Advance the ledger so that there's ambiguity of asset index or foreign array index + for i := 0; i < 10; i++ { + dl.fullBlock(&txntest.Txn{Type: "pay", Sender: addrs[2], Receiver: addrs[2]}) + } + + checker := basics.AppIndex(11) + gold := basics.AssetIndex(13) + create := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: addrs[0], + ApprovalProgram: source, + } + + dl.fullBlock(&create) // create the app + + check := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: addrs[0], + ApplicationID: checker, + ApplicationArgs: [][]byte{{byte(gold)}, {0}, {0}}, // exist=0 value=0 + } + + dl.fullBlock(&check) + + dl.fullBlock(&makegold) + + // confirm hardcoded "gold" is correct + b, ok := holding(t, dl.generator, addrs[0], gold) + require.True(t, ok) + require.EqualValues(t, 10, b) + + // The asset exists now. asset_holding_get gives 1,10 for the creator + // (who is auto-opted in) + check.ApplicationArgs = [][]byte{{byte(gold)}, {1}, {10}} // exist=1 value=10 + dl.fullBlock(&check) + + // but still gives 0,0 for un opted-in addrs[1], because it means + // "exists" in the given account, i.e. opted in + check.Sender = addrs[1] + check.ApplicationArgs = [][]byte{{byte(gold)}, {0}, {0}} + dl.fullBlock(&check) + + // opt-in addr[1] + dl.fullBlock(&txntest.Txn{Type: "axfer", XferAsset: gold, Sender: addrs[1], AssetReceiver: addrs[1]}) + check.ApplicationArgs = [][]byte{{byte(gold)}, {1}, {0}} + dl.fullBlock(&check) + + // non-existent account, with existing asset, cleanly reports exists=0, value=0 + check.Accounts = []basics.Address{{0x01, 0x02}} + check.ApplicationArgs = [][]byte{{byte(gold)}, {0}, {0}} + dl.fullBlock(&check) + }) +} + +// TestLocalGetEx tests some of the corner cases for the app_local_get_ex +// opcode: the app doesn't exist, the account doesn't exist, account not opted +// in, local key doesn't exists. This is tested here, even though it should be +// well tested in 'logic' package, because we want to make sure that errors come +// out of the real ledger in the way that the logic package expects (it uses a +// mock ledger for testing). +func TestLocalGetEx(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + genBalances, addrs, _ := ledgertesting.NewTestGenesis() + // 24 is first version with apps + ledgertesting.TestConsensusRange(t, 24, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion) { + dl := NewDoubleLedger(t, genBalances, cv) + defer dl.Close() + + makeapp := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + LocalStateSchema: basics.StateSchema{ + NumUint: 1, + }, + GlobalStateSchema: basics.StateSchema{ + NumByteSlice: 3, + }, + } + + // written without assert or swap, so we can use teal v2 and test back to consensus v24 + source := ` +#pragma version 2 +txn ApplicationID +bnz main +int 1; return +main: + txn NumAccounts // Sender, or Accounts[n] + txn ApplicationArgs 0; btoi + byte "KEY" + app_local_get_ex + txn ApplicationArgs 1; btoi; ==; bz bad + txn ApplicationArgs 2; btoi; ==; return +bad: err +` + + // Advance the ledger so that there's ambiguity of app index or foreign array index + for i := 0; i < 10; i++ { + dl.fullBlock(&txntest.Txn{Type: "pay", Sender: addrs[2], Receiver: addrs[2]}) + } + + checker := basics.AppIndex(11) // the app that checks state + state := basics.AppIndex(12) // the app with state + create := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: addrs[0], + ApprovalProgram: source, + } + + dl.fullBlock(&create) // create the checker app + + check := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: addrs[0], + ApplicationID: checker, + ApplicationArgs: [][]byte{{byte(state)}, {0}, {0}}, // exist=0 value=0 + } + + // unlike assets, you can't even as `app_local_get_ex` for address that + // have not been opted in. For local state, the existence bit is only + // used to distinguish "key existence". The local state bundle MUST + // exist of program fails. + dl.txn(&check, "cannot fetch key") + + // so we make the app and try again + dl.fullBlock(&makeapp) + // confirm hardcoded "state" index is correct + g, ok := globals(t, dl.generator, addrs[0], state) + require.True(t, ok) + require.EqualValues(t, 3, g.GlobalStateSchema.NumByteSlice) + + // still no good, because creating an app does not opt in the creator + dl.txn(&check, "cannot fetch key") + + // opt-in addr[0] + dl.fullBlock(&txntest.Txn{Type: "appl", ApplicationID: state, Sender: addrs[0], OnCompletion: transactions.OptInOC}) + check.ApplicationArgs = [][]byte{{byte(state)}, {0}, {0}} + dl.fullBlock(&check) + }) +} + func TestRekeying(t *testing.T) { partitiontest.PartitionTest(t) - // t.Parallel() NO! This test manipulates []protocol.Consensus - - // Pretend rekeying is supported - actual := config.Consensus[protocol.ConsensusCurrentVersion] - pretend := actual - pretend.SupportRekeying = true - config.Consensus[protocol.ConsensusCurrentVersion] = pretend - defer func() { - config.Consensus[protocol.ConsensusCurrentVersion] = actual - }() + t.Parallel() // Bring up a ledger genesisInitState, addrs, keys := ledgertesting.Genesis(10) diff --git a/ledger/internal/cow_creatables.go b/ledger/internal/cow_creatables.go index d43135cf89..c49e358d22 100644 --- a/ledger/internal/cow_creatables.go +++ b/ledger/internal/cow_creatables.go @@ -73,8 +73,8 @@ func (cs *roundCowState) GetAssetHolding(addr basics.Address, aidx basics.AssetI return } if d.Holding == nil { - // found and not deleled => must exist. Err if not - err = fmt.Errorf("GetAppLocalState got a nil entry for (%s, %d): %p, %v", addr.String(), aidx, d.Holding, d.Deleted) + // found and not deleted => must exist. Err if not + err = fmt.Errorf("GetAssetHoilding got a nil entry for (%s, %d): %p, %v", addr, aidx, d.Holding, d.Deleted) } ret = *d.Holding return diff --git a/ledger/simple_test.go b/ledger/simple_test.go index d4e44f0c3f..63190787a6 100644 --- a/ledger/simple_test.go +++ b/ledger/simple_test.go @@ -180,3 +180,19 @@ func asaParams(t testing.TB, ledger *Ledger, asset basics.AssetIndex) (basics.As } return basics.AssetParams{}, fmt.Errorf("bad lookup (%d)", asset) } + +// globals gets the AppParams for an address, app index pair (only works if addr is the creator) +func globals(t testing.TB, ledger *Ledger, addr basics.Address, app basics.AppIndex) (basics.AppParams, bool) { + if globals, ok := lookup(t, ledger, addr).AppParams[app]; ok { + return globals, true + } + return basics.AppParams{}, false +} + +// locals gets the AppLocalState for an address, app index pair +func locals(t testing.TB, ledger *Ledger, addr basics.Address, app basics.AppIndex) (basics.AppLocalState, bool) { + if locals, ok := lookup(t, ledger, addr).AppLocalStates[app]; ok { + return locals, true + } + return basics.AppLocalState{}, false +} From 97e2269540d3e3c4e4436e05303efaf2ffb6c2d5 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 24 Jan 2023 13:23:50 -0500 Subject: [PATCH 02/29] Re-org availability checks in prep for changes --- data/transactions/application.go | 3 +- data/transactions/logic/blackbox_test.go | 122 +++++++++++++++ data/transactions/logic/eval.go | 189 +++++++++++------------ 3 files changed, 216 insertions(+), 98 deletions(-) diff --git a/data/transactions/application.go b/data/transactions/application.go index 6ae70ed651..9099f1dd0a 100644 --- a/data/transactions/application.go +++ b/data/transactions/application.go @@ -230,8 +230,7 @@ func (ac *ApplicationCallTxnFields) AddressByIndex(accountIdx uint64, sender bas // An index > 0 corresponds to an offset into txn.Accounts. Check to // make sure the index is valid. if accountIdx > uint64(len(ac.Accounts)) { - err := fmt.Errorf("invalid Account reference %d", accountIdx) - return basics.Address{}, err + return basics.Address{}, fmt.Errorf("invalid Account reference %d", accountIdx) } // accountIdx must be in [1, len(ac.Accounts)] diff --git a/data/transactions/logic/blackbox_test.go b/data/transactions/logic/blackbox_test.go index 49641ed7a2..865ffad1ad 100644 --- a/data/transactions/logic/blackbox_test.go +++ b/data/transactions/logic/blackbox_test.go @@ -220,3 +220,125 @@ pop; pop; int 1 // foreign-asset is not repeated in appl2. logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl2), 9, nil) } + +// TestOtherTxSharing tests resource sharing across other kinds of transactions besides appl. +func TestOtherTxSharing(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + _, _, ledger := logic.MakeSampleEnv() + + senderAcct := basics.Address{1, 2, 3, 4, 5, 6, 1} + ledger.NewAccount(senderAcct, 2001) + senderBalance := "txn ApplicationArgs 0; balance; int 2001; ==" + + receiverAcct := basics.Address{1, 2, 3, 4, 5, 6, 2} + ledger.NewAccount(receiverAcct, 2002) + receiverBalance := "txn ApplicationArgs 0; balance; int 2002; ==" + + otherAcct := basics.Address{1, 2, 3, 4, 5, 6, 3} + ledger.NewAccount(otherAcct, 2003) + otherBalance := "txn ApplicationArgs 0; balance; int 2003; ==" + + appl := txntest.Txn{ + Type: protocol.ApplicationCallTx, + ApplicationArgs: [][]byte{senderAcct[:]}, + } + + keyreg := txntest.Txn{ + Type: protocol.KeyRegistrationTx, + Sender: senderAcct, + } + pay := txntest.Txn{ + Type: protocol.PaymentTx, + Sender: senderAcct, + Receiver: receiverAcct, + } + acfg := txntest.Txn{ + Type: protocol.AssetConfigTx, + Sender: senderAcct, + } + axfer := txntest.Txn{ + Type: protocol.AssetTransferTx, + XferAsset: 100, // must be < 256, later code assumes it fits in a byte + Sender: senderAcct, + AssetReceiver: receiverAcct, + AssetSender: otherAcct, + } + afrz := txntest.Txn{ + Type: protocol.AssetFreezeTx, + Sender: senderAcct, + FreezeAccount: otherAcct, + } + + sources := []string{"", senderBalance} + rsources := []string{senderBalance, ""} + for _, send := range []txntest.Txn{keyreg, pay, acfg, axfer, afrz} { + logic.TestApps(t, sources, txntest.SignedTxns(&send, &appl), 9, ledger) + logic.TestApps(t, rsources, txntest.SignedTxns(&appl, &send), 9, ledger) + + logic.TestApps(t, sources, txntest.SignedTxns(&send, &appl), 8, ledger, + logic.NewExpect(1, "invalid Account reference")) + logic.TestApps(t, rsources, txntest.SignedTxns(&appl, &send), 8, ledger, + logic.NewExpect(0, "invalid Account reference")) + } + + holdingAccess := ` + txn ApplicationArgs 0 + txn ApplicationArgs 1; btoi + asset_holding_get AssetBalance + pop; pop +` + sources = []string{"", holdingAccess} + rsources = []string{holdingAccess, ""} + + t.Run("keyreg", func(t *testing.T) { + appl.ApplicationArgs = [][]byte{senderAcct[:], {200}} + logic.TestApps(t, sources, txntest.SignedTxns(&keyreg, &appl), 9, ledger, + logic.NewExpect(1, "invalid Asset reference 200")) + withRef := appl + withRef.ForeignAssets = []basics.AssetIndex{200} + logic.TestApps(t, sources, txntest.SignedTxns(&keyreg, &withRef), 9, ledger, + logic.NewExpect(1, "invalid Holding access "+senderAcct.String())) + }) + t.Run("pay", func(t *testing.T) { + // The receiver is available for algo balance reading + appl.ApplicationArgs = [][]byte{receiverAcct[:]} + logic.TestApps(t, []string{"", receiverBalance}, txntest.SignedTxns(&pay, &appl), 9, ledger) + + // The other account is not (it's not even in the pay txn) + appl.ApplicationArgs = [][]byte{otherAcct[:]} + logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&pay, &appl), 9, ledger, + logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) + + // The other account becomes accessible because used in CloseRemainderTo + withClose := pay + withClose.CloseRemainderTo = otherAcct + logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&withClose, &appl), 9, ledger) + }) + + t.Run("acfg", func(t *testing.T) { + }) + + t.Run("axfer", func(t *testing.T) { + // The receiver is NOT available for algo balance reading (only the holding for the asa) + appl.ApplicationArgs = [][]byte{receiverAcct[:]} + logic.TestApps(t, []string{"", receiverBalance}, txntest.SignedTxns(&axfer, &appl), 9, ledger, + logic.NewExpect(1, "invalid Account reference "+receiverAcct.String())) + + appl.ApplicationArgs = [][]byte{receiverAcct[:], {byte(axfer.XferAsset)}} + /* + logic.TestApps(t, []string{"", holdingAccess}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + + // The other account becomes accessible because used in CloseRemainderTo (for asa, not algo) + withClose := axfer + withClose.AssetCloseTo = otherAcct + logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&withClose, &appl), 9, ledger, + logic.NewExpect(1, "bad")) + logic.TestApps(t, []string{"", holdingAccess}, txntest.SignedTxns(&withClose, &appl), 9, ledger) + */ + }) + + t.Run("afrz", func(t *testing.T) { + }) +} diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 726c6158c3..f405a67ac8 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -376,8 +376,7 @@ func NewEvalParams(txgroup []transactions.SignedTxnWithAD, proto *config.Consens // resources are computed after ep is constructed because app addresses are // calculated there, and we'd like to use the caching mechanism built into // the EvalParams. Perhaps we can make the computation even lazier, so it is - // only computed if needed (some program actually refers to a resource that - // isn't available in the old way). + // only computed if needed. ep.available = ep.computeAvailability() return ep } @@ -4067,8 +4066,6 @@ func (cx *EvalContext) mutableAccountReference(account stackValue) (basics.Addre if err == nil && accountIdx > uint64(len(cx.txn.Txn.Accounts)) { // There was no error, but accountReference has signaled that accountIdx // is not for mutable ops (because it can't encode it in EvalDelta) - // This also tells us that account.address() will work. - addr, _ := account.address() err = fmt.Errorf("invalid Account reference for mutation %s", addr) } return addr, accountIdx, err @@ -4119,7 +4116,7 @@ func opAppOptedIn(cx *EvalContext) error { return err } - app, err := appReference(cx, cx.stack[last].Uint, false) + app, err := cx.appReference(cx.stack[last].Uint, false) if err != nil { return err } @@ -4175,7 +4172,7 @@ func opAppLocalGetImpl(cx *EvalContext, appID uint64, key []byte, acct stackValu return } - app, err := appReference(cx, appID, false) + app, err := cx.appReference(appID, false) if err != nil { return } @@ -4197,7 +4194,7 @@ func opAppLocalGetImpl(cx *EvalContext, appID uint64, key []byte, acct stackValu } func opAppGetGlobalStateImpl(cx *EvalContext, appIndex uint64, key []byte) (result stackValue, ok bool, err error) { - app, err := appReference(cx, appIndex, true) + app, err := cx.appReference(appIndex, true) if err != nil { return } @@ -4406,30 +4403,16 @@ func opAppGlobalDel(cx *EvalContext) error { // more than 2 or so, and was often called an "index". But it was not a // basics.AssetIndex or basics.ApplicationIndex. -func appReference(cx *EvalContext, ref uint64, foreign bool) (basics.AppIndex, error) { +func (cx *EvalContext) appReference(ref uint64, foreign bool) (basics.AppIndex, error) { if cx.version >= directRefEnabledVersion { if ref == 0 || ref == uint64(cx.appID) { return cx.appID, nil } - for _, appID := range cx.txn.Txn.ForeignApps { - if appID == basics.AppIndex(ref) { - return appID, nil - } - } - // or was created in group - if cx.version >= createdResourcesVersion { - for _, appID := range cx.available.createdApps { - if appID == basics.AppIndex(ref) { - return appID, nil - } - } - } - // or some other txn mentioned it - if cx.version >= resourceSharingVersion { - if _, ok := cx.available.sharedApps[basics.AppIndex(ref)]; ok { - return basics.AppIndex(ref), nil - } + aid := basics.AppIndex(ref) + if cx.availableApp(aid) { + return aid, nil } + // Allow use of indexes, but this comes last so that clear advice can be // given to anyone who cares about semantics in the first few rounds of // a new network - don't use indexes for references, use the App ID @@ -4454,26 +4437,11 @@ func appReference(cx *EvalContext, ref uint64, foreign bool) (basics.AppIndex, e return basics.AppIndex(0), fmt.Errorf("invalid App reference %d", ref) } -func asaReference(cx *EvalContext, ref uint64, foreign bool) (basics.AssetIndex, error) { +func (cx *EvalContext) assetReference(ref uint64, foreign bool) (basics.AssetIndex, error) { if cx.version >= directRefEnabledVersion { - for _, assetID := range cx.txn.Txn.ForeignAssets { - if assetID == basics.AssetIndex(ref) { - return assetID, nil - } - } - // or was created in group - if cx.version >= createdResourcesVersion { - for _, assetID := range cx.available.createdAsas { - if assetID == basics.AssetIndex(ref) { - return assetID, nil - } - } - } - // or some other txn mentioned it - if cx.version >= resourceSharingVersion { - if _, ok := cx.available.sharedAsas[basics.AssetIndex(ref)]; ok { - return basics.AssetIndex(ref), nil - } + aid := basics.AssetIndex(ref) + if cx.availableAsset(aid) { + return aid, nil } // Allow use of indexes, but this comes last so that clear advice can be @@ -4498,6 +4466,24 @@ func asaReference(cx *EvalContext, ref uint64, foreign bool) (basics.AssetIndex, } +func (cx *EvalContext) holdingReference(account stackValue, ref uint64) (addr basics.Address, asset basics.AssetIndex, err error) { + addr, _, err = cx.accountReference(account) + if err != nil { + return + } + asset, err = cx.assetReference(ref, false) + if err != nil { + return + } + + if !cx.availableHolding(addr, asset) { + err = fmt.Errorf("invalid Holding access %s x %d", addr, asset) + return + } + + return +} + func opAssetHoldingGet(cx *EvalContext) error { last := len(cx.stack) - 1 // asset prev := last - 1 // account @@ -4508,21 +4494,11 @@ func opAssetHoldingGet(cx *EvalContext) error { return fmt.Errorf("invalid asset_holding_get field %d", holdingField) } - addr, _, err := cx.accountReference(cx.stack[prev]) + addr, asset, err := cx.holdingReference(cx.stack[prev], cx.stack[last].Uint) if err != nil { return err } - asset, err := asaReference(cx, cx.stack[last].Uint, false) - if err != nil { - return err - } - - if !cx.availableHolding(addr, asset) { - return fmt.Errorf("invalid Holding access %s x %d", addr, asset) - } - - fmt.Printf("> %s %d\n", addr, asset) var exist uint64 = 0 var value stackValue if holding, err := cx.Ledger.AssetHolding(addr, asset); err == nil { @@ -4549,7 +4525,7 @@ func opAssetParamsGet(cx *EvalContext) error { return fmt.Errorf("invalid asset_params_get field %d", paramField) } - asset, err := asaReference(cx, cx.stack[last].Uint, true) + asset, err := cx.assetReference(cx.stack[last].Uint, true) if err != nil { return err } @@ -4579,7 +4555,7 @@ func opAppParamsGet(cx *EvalContext) error { return fmt.Errorf("invalid app_params_get field %d", paramField) } - app, err := appReference(cx, cx.stack[last].Uint, true) + app, err := cx.appReference(cx.stack[last].Uint, true) if err != nil { return err } @@ -4753,39 +4729,53 @@ func opItxnNext(cx *EvalContext) error { return addInnerTxn(cx) } -// availableAccount is used instead of accountReference for more recent opcodes -// that don't need (or want!) to allow low numbers to represent the account at -// that index in Accounts array. -func (cx *EvalContext) availableAccount(sv stackValue) (basics.Address, error) { - if sv.argType() != StackBytes || len(sv.Bytes) != crypto.DigestSize { - return basics.Address{}, fmt.Errorf("not an address") +// assignAccount is used to convert a stackValue into a 32-byte account value, +// enforcing any "availability" restrictions in force. +func (cx *EvalContext) assignAccount(sv stackValue) (basics.Address, error) { + addr, err := sv.address() + if err != nil { + return basics.Address{}, err } - addr, _, err := cx.accountReference(sv) + addr, _, err = cx.accountReference(sv) return addr, err } -// availableAsset is used instead of asaReference for more recent opcodes that -// don't need (or want!) to allow low numbers to represent the asset at that -// index in ForeignAssets array. -func (cx *EvalContext) availableAsset(sv stackValue) (basics.AssetIndex, error) { +// assignAsset is used to convert a stackValue to a uint64 assetIndex, reporting +// any errors due to availablity rules or type checking. +func (cx *EvalContext) assignAsset(sv stackValue) (basics.AssetIndex, error) { uint, err := sv.uint() if err != nil { return basics.AssetIndex(0), err } aid := basics.AssetIndex(uint) + if cx.availableAsset(aid) { + return aid, nil + } + + return basics.AssetIndex(0), fmt.Errorf("invalid Asset reference %d", aid) +} + +// availableAsset determines whether an asset is "available". Before +// resourceSharingVersion, an asset had to be available for for asset param +// lookups, asset holding lookups, and asset id assignments to inner +// transactions. After resourceSharingVersion, the distinction must be more fine +// grained. It must be available for asset param lookups, or use in an asset +// transaction (axfer,acfg,afrz), but not for holding lookups or assignments to +// an inner static array. +func (cx *EvalContext) availableAsset(aid basics.AssetIndex) bool { // Ensure that aid is in Foreign Assets for _, assetID := range cx.txn.Txn.ForeignAssets { if assetID == aid { - return aid, nil + return true } } // or was created in group if cx.version >= createdResourcesVersion { for _, assetID := range cx.available.createdAsas { if assetID == aid { - return aid, nil + return true } } } @@ -4793,50 +4783,57 @@ func (cx *EvalContext) availableAsset(sv stackValue) (basics.AssetIndex, error) // or some other txn mentioned it if cx.version >= resourceSharingVersion { if _, ok := cx.available.sharedAsas[aid]; ok { - return aid, nil + return true } } - return basics.AssetIndex(0), fmt.Errorf("invalid Asset reference %d", aid) + return false } -// availableApp is used instead of appReference for more recent (stateful) -// opcodes that don't need (or want!) to allow low numbers to represent the app -// at that index in ForeignApps array. -func (cx *EvalContext) availableApp(sv stackValue) (basics.AppIndex, error) { +// assignApp is used to convert a stackValue to a uint64 appIndex, reporting +// any errors due to availablity rules or type checking. +func (cx *EvalContext) assignApp(sv stackValue) (basics.AppIndex, error) { uint, err := sv.uint() if err != nil { return basics.AppIndex(0), err } aid := basics.AppIndex(uint) + if cx.availableApp(aid) { + return aid, nil + } + + return 0, fmt.Errorf("invalid App reference %d", aid) +} + +func (cx *EvalContext) availableApp(aid basics.AppIndex) bool { // Ensure that aid is in Foreign Apps for _, appID := range cx.txn.Txn.ForeignApps { if appID == aid { - return aid, nil + return true } } // or was created in group if cx.version >= createdResourcesVersion { for _, appID := range cx.available.createdApps { if appID == aid { - return aid, nil + return true } } } // Or, it can be the current app if cx.appID == aid { - return aid, nil + return true } // or some other txn mentioned it if cx.version >= resourceSharingVersion { if _, ok := cx.available.sharedApps[aid]; ok { - return aid, nil + return true } } - return 0, fmt.Errorf("invalid App reference %d", aid) + return false } // availableHolding is an additional check, required since @@ -4910,7 +4907,7 @@ func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *t return fmt.Errorf("%d is not a valid TypeEnum", i) } case Sender: - txn.Sender, err = cx.availableAccount(sv) + txn.Sender, err = cx.assignAccount(sv) case Fee: txn.Fee.Raw, err = sv.uint() // FirstValid, LastValid unsettable: little motivation (maybe a app call @@ -4960,25 +4957,25 @@ func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *t // Payment case Receiver: - txn.Receiver, err = cx.availableAccount(sv) + txn.Receiver, err = cx.assignAccount(sv) case Amount: txn.Amount.Raw, err = sv.uint() case CloseRemainderTo: - txn.CloseRemainderTo, err = cx.availableAccount(sv) + txn.CloseRemainderTo, err = cx.assignAccount(sv) // AssetTransfer case XferAsset: - txn.XferAsset, err = cx.availableAsset(sv) + txn.XferAsset, err = cx.assignAsset(sv) case AssetAmount: txn.AssetAmount, err = sv.uint() case AssetSender: - txn.AssetSender, err = cx.availableAccount(sv) + txn.AssetSender, err = cx.assignAccount(sv) case AssetReceiver: - txn.AssetReceiver, err = cx.availableAccount(sv) + txn.AssetReceiver, err = cx.assignAccount(sv) case AssetCloseTo: - txn.AssetCloseTo, err = cx.availableAccount(sv) + txn.AssetCloseTo, err = cx.assignAccount(sv) // AssetConfig case ConfigAsset: - txn.ConfigAsset, err = cx.availableAsset(sv) + txn.ConfigAsset, err = cx.assignAsset(sv) case ConfigAssetTotal: txn.AssetParams.Total, err = sv.uint() case ConfigAssetDecimals: @@ -5014,15 +5011,15 @@ func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *t txn.AssetParams.Clawback, err = sv.address() // Freeze case FreezeAsset: - txn.FreezeAsset, err = cx.availableAsset(sv) + txn.FreezeAsset, err = cx.assignAsset(sv) case FreezeAssetAccount: - txn.FreezeAccount, err = cx.availableAccount(sv) + txn.FreezeAccount, err = cx.assignAccount(sv) case FreezeAssetFrozen: txn.AssetFrozen, err = sv.bool() // ApplicationCall case ApplicationID: - txn.ApplicationID, err = cx.availableApp(sv) + txn.ApplicationID, err = cx.assignApp(sv) case OnCompletion: var onc uint64 onc, err = sv.uintMaxed(uint64(transactions.DeleteApplicationOC)) @@ -5046,7 +5043,7 @@ func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *t txn.ApplicationArgs = append(txn.ApplicationArgs, new) case Accounts: var new basics.Address - new, err = cx.availableAccount(sv) + new, err = cx.assignAccount(sv) if err != nil { return err } @@ -5082,7 +5079,7 @@ func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *t } case Assets: var new basics.AssetIndex - new, err = cx.availableAsset(sv) + new, err = cx.assignAsset(sv) if err != nil { return err } @@ -5092,7 +5089,7 @@ func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *t txn.ForeignAssets = append(txn.ForeignAssets, new) case Applications: var new basics.AppIndex - new, err = cx.availableApp(sv) + new, err = cx.assignApp(sv) if err != nil { return err } From bbaa278eef34d9e4573ca642f88034d1ee6e483f Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 26 Jan 2023 12:10:46 -0500 Subject: [PATCH 03/29] Checkpoint with new approach, needs v9 -> v8 tests Does not yet have the extra check to ensure v9 can't expose new resources by putting accounts from one tx and assets from another into static arrays of a called v8 app. --- data/basics/userBalance.go | 14 - data/transactions/logic/blackbox_test.go | 245 ----------- data/transactions/logic/eval.go | 93 +++-- data/transactions/logic/evalStateful_test.go | 16 +- data/transactions/logic/resources.go | 51 ++- data/transactions/logic/resources_test.go | 416 +++++++++++++++++++ 6 files changed, 519 insertions(+), 316 deletions(-) create mode 100644 data/transactions/logic/resources_test.go diff --git a/data/basics/userBalance.go b/data/basics/userBalance.go index cec1534df2..f10c326354 100644 --- a/data/basics/userBalance.go +++ b/data/basics/userBalance.go @@ -343,20 +343,6 @@ type CreatableLocator struct { Index CreatableIndex } -// HoldingLocator stores enough information to name a "Holding" the balance of -// an ASA for a particular account. -type HoldingLocator struct { - Address Address - Index AssetIndex -} - -// LocalsLocator stores enough information to find the Local State that an -// account has with a particular app. -type LocalsLocator struct { - Address Address - Index AppIndex -} - // AssetHolding describes an asset held by an account. type AssetHolding struct { _struct struct{} `codec:",omitempty,omitemptyarray"` diff --git a/data/transactions/logic/blackbox_test.go b/data/transactions/logic/blackbox_test.go index 865ffad1ad..79029f2c38 100644 --- a/data/transactions/logic/blackbox_test.go +++ b/data/transactions/logic/blackbox_test.go @@ -97,248 +97,3 @@ func TestNewAppEvalParams(t *testing.T) { } } } - -// TestAppSharing confirms that as of v9, assets can be accessed across -// groups, but that before then, they could not. -func TestAppSharing(t *testing.T) { - partitiontest.PartitionTest(t) - t.Parallel() - - // Create some sample transactions. The main reason this a blackbox test - // (_test package) is to have access to txntest. - appl0 := txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: basics.Address{1, 2, 3, 4}, - ForeignApps: []basics.AppIndex{500}, - } - - appl1 := txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: basics.Address{4, 3, 2, 1}, - } - - appl2 := txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: basics.Address{1, 2, 3, 4}, - } - - getSchema := ` -int 500 -app_params_get AppGlobalNumByteSlice -!; assert; pop; int 1 -` - sources := []string{getSchema, getSchema} - // In v8, the first tx can read app params of 500, because it's in its - // foreign array, but the second can't - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, - logic.NewExpect(1, "invalid App reference 500")) - // In v9, the second can, because the first can. - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil) - - getLocalEx := ` -int 0 // Sender -int 500 -byte "some-key" -app_local_get_ex -pop; pop; int 1 -` - - sources = []string{getLocalEx, getLocalEx} - // In contrast, here there's no help from v9, because the second tx is - // reading the locals for a different account. - - // app_local_get* requires the address and the app exist, else the program fails - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, - logic.NewExpect(0, "no account")) - - _, _, ledger := logic.MakeSampleEnv() - ledger.NewAccount(appl0.Sender, 100_000) - ledger.NewApp(appl0.Sender, 500, basics.AppParams{}) - ledger.NewLocals(appl0.Sender, 500) // opt in - // Now txn0 passes, but txn1 has an error because it can't see app 500 - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, ledger, - logic.NewExpect(1, "invalid Local State access")) - - // But it's ok in appl2, because appl2 uses the same Sender, even though the - // foreign-app is not repeated in appl2 so the holding being accessed is is - // the one from tx0. - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl2), 9, ledger) -} - -// TestAssetSharing confirms that as of v9, assets can be accessed across -// groups, but that before then, they could not. -func TestAssetSharing(t *testing.T) { - partitiontest.PartitionTest(t) - t.Parallel() - - // Create some sample transactions. The main reason this a blackbox test - // (_test package) is to have access to txntest. - appl0 := txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: basics.Address{1, 2, 3, 4}, - ForeignAssets: []basics.AssetIndex{400}, - } - - appl1 := txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: basics.Address{4, 3, 2, 1}, - } - - appl2 := txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: basics.Address{1, 2, 3, 4}, - } - - getTotal := ` -int 400 -asset_params_get AssetTotal -pop; pop; int 1 -` - sources := []string{getTotal, getTotal} - // In v8, the first tx can read asset 400, because it's in its foreign arry, - // but the second can't - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, - logic.NewExpect(1, "invalid Asset reference 400")) - // In v9, the second can, because the first can. - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil) - - getBalance := ` -int 0 -int 400 -asset_holding_get AssetBalance -pop; pop; int 1 -` - - sources = []string{getBalance, getBalance} - // In contrast, here there's no help from v9, because the second tx is - // reading a holding for a different account. - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, - logic.NewExpect(1, "invalid Asset reference 400")) - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil, - logic.NewExpect(1, "invalid Holding access")) - // But it's ok in appl2, because the same account is used, even though the - // foreign-asset is not repeated in appl2. - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl2), 9, nil) -} - -// TestOtherTxSharing tests resource sharing across other kinds of transactions besides appl. -func TestOtherTxSharing(t *testing.T) { - partitiontest.PartitionTest(t) - t.Parallel() - - _, _, ledger := logic.MakeSampleEnv() - - senderAcct := basics.Address{1, 2, 3, 4, 5, 6, 1} - ledger.NewAccount(senderAcct, 2001) - senderBalance := "txn ApplicationArgs 0; balance; int 2001; ==" - - receiverAcct := basics.Address{1, 2, 3, 4, 5, 6, 2} - ledger.NewAccount(receiverAcct, 2002) - receiverBalance := "txn ApplicationArgs 0; balance; int 2002; ==" - - otherAcct := basics.Address{1, 2, 3, 4, 5, 6, 3} - ledger.NewAccount(otherAcct, 2003) - otherBalance := "txn ApplicationArgs 0; balance; int 2003; ==" - - appl := txntest.Txn{ - Type: protocol.ApplicationCallTx, - ApplicationArgs: [][]byte{senderAcct[:]}, - } - - keyreg := txntest.Txn{ - Type: protocol.KeyRegistrationTx, - Sender: senderAcct, - } - pay := txntest.Txn{ - Type: protocol.PaymentTx, - Sender: senderAcct, - Receiver: receiverAcct, - } - acfg := txntest.Txn{ - Type: protocol.AssetConfigTx, - Sender: senderAcct, - } - axfer := txntest.Txn{ - Type: protocol.AssetTransferTx, - XferAsset: 100, // must be < 256, later code assumes it fits in a byte - Sender: senderAcct, - AssetReceiver: receiverAcct, - AssetSender: otherAcct, - } - afrz := txntest.Txn{ - Type: protocol.AssetFreezeTx, - Sender: senderAcct, - FreezeAccount: otherAcct, - } - - sources := []string{"", senderBalance} - rsources := []string{senderBalance, ""} - for _, send := range []txntest.Txn{keyreg, pay, acfg, axfer, afrz} { - logic.TestApps(t, sources, txntest.SignedTxns(&send, &appl), 9, ledger) - logic.TestApps(t, rsources, txntest.SignedTxns(&appl, &send), 9, ledger) - - logic.TestApps(t, sources, txntest.SignedTxns(&send, &appl), 8, ledger, - logic.NewExpect(1, "invalid Account reference")) - logic.TestApps(t, rsources, txntest.SignedTxns(&appl, &send), 8, ledger, - logic.NewExpect(0, "invalid Account reference")) - } - - holdingAccess := ` - txn ApplicationArgs 0 - txn ApplicationArgs 1; btoi - asset_holding_get AssetBalance - pop; pop -` - sources = []string{"", holdingAccess} - rsources = []string{holdingAccess, ""} - - t.Run("keyreg", func(t *testing.T) { - appl.ApplicationArgs = [][]byte{senderAcct[:], {200}} - logic.TestApps(t, sources, txntest.SignedTxns(&keyreg, &appl), 9, ledger, - logic.NewExpect(1, "invalid Asset reference 200")) - withRef := appl - withRef.ForeignAssets = []basics.AssetIndex{200} - logic.TestApps(t, sources, txntest.SignedTxns(&keyreg, &withRef), 9, ledger, - logic.NewExpect(1, "invalid Holding access "+senderAcct.String())) - }) - t.Run("pay", func(t *testing.T) { - // The receiver is available for algo balance reading - appl.ApplicationArgs = [][]byte{receiverAcct[:]} - logic.TestApps(t, []string{"", receiverBalance}, txntest.SignedTxns(&pay, &appl), 9, ledger) - - // The other account is not (it's not even in the pay txn) - appl.ApplicationArgs = [][]byte{otherAcct[:]} - logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&pay, &appl), 9, ledger, - logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) - - // The other account becomes accessible because used in CloseRemainderTo - withClose := pay - withClose.CloseRemainderTo = otherAcct - logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&withClose, &appl), 9, ledger) - }) - - t.Run("acfg", func(t *testing.T) { - }) - - t.Run("axfer", func(t *testing.T) { - // The receiver is NOT available for algo balance reading (only the holding for the asa) - appl.ApplicationArgs = [][]byte{receiverAcct[:]} - logic.TestApps(t, []string{"", receiverBalance}, txntest.SignedTxns(&axfer, &appl), 9, ledger, - logic.NewExpect(1, "invalid Account reference "+receiverAcct.String())) - - appl.ApplicationArgs = [][]byte{receiverAcct[:], {byte(axfer.XferAsset)}} - /* - logic.TestApps(t, []string{"", holdingAccess}, txntest.SignedTxns(&axfer, &appl), 9, ledger) - - // The other account becomes accessible because used in CloseRemainderTo (for asa, not algo) - withClose := axfer - withClose.AssetCloseTo = otherAcct - logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&withClose, &appl), 9, ledger, - logic.NewExpect(1, "bad")) - logic.TestApps(t, []string{"", holdingAccess}, txntest.SignedTxns(&withClose, &appl), 9, ledger) - */ - }) - - t.Run("afrz", func(t *testing.T) { - }) -} diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index f405a67ac8..0b902bc9dd 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -386,26 +386,12 @@ func (ep *EvalParams) computeAvailability() *resources { sharedAccounts: make(map[basics.Address]struct{}), sharedAsas: make(map[basics.AssetIndex]struct{}), sharedApps: make(map[basics.AppIndex]struct{}), - sharedHoldings: make(map[basics.HoldingLocator]struct{}), - sharedLocals: make(map[basics.LocalsLocator]struct{}), + sharedHoldings: make(map[ledgercore.AccountAsset]struct{}), + sharedLocals: make(map[ledgercore.AccountApp]struct{}), boxes: make(map[boxRef]bool), } for i := range ep.TxnGroup { - tx := &ep.TxnGroup[i] - switch tx.Txn.Type { - case protocol.PaymentTx: - available.fillPayment(&tx.Txn.Header, &tx.Txn.PaymentTxnFields) - case protocol.KeyRegistrationTx: - available.fillKeyRegistration(&tx.Txn.Header) - case protocol.AssetConfigTx: - available.fillAssetConfig(&tx.Txn.Header, &tx.Txn.AssetConfigTxnFields) - case protocol.AssetTransferTx: - available.fillAssetTransfer(&tx.Txn.Header, &tx.Txn.AssetTransferTxnFields) - case protocol.AssetFreezeTx: - available.fillAssetFreeze(&tx.Txn.Header, &tx.Txn.AssetFreezeTxnFields) - case protocol.ApplicationCallTx: - available.fillApplicationCall(ep, &tx.Txn.Header, &tx.Txn.ApplicationCallTxnFields) - } + available.fill(&ep.TxnGroup[i].Txn, ep) } return available } @@ -4466,22 +4452,59 @@ func (cx *EvalContext) assetReference(ref uint64, foreign bool) (basics.AssetInd } -func (cx *EvalContext) holdingReference(account stackValue, ref uint64) (addr basics.Address, asset basics.AssetIndex, err error) { - addr, _, err = cx.accountReference(account) - if err != nil { - return +func (cx *EvalContext) holdingReference(account stackValue, ref uint64) (basics.Address, basics.AssetIndex, error) { + if cx.version >= resourceSharingVersion { + var addr basics.Address + var err error + if account.Bytes != nil { + addr, err = account.address() + } else { + addr, err = cx.txn.Txn.AddressByIndex(account.Uint, cx.txn.Txn.Sender) + } + if err != nil { + return basics.Address{}, basics.AssetIndex(0), err + } + aid := basics.AssetIndex(ref) + if cx.availableHolding(addr, aid) { + return addr, aid, nil + } + if ref < uint64(len(cx.txn.Txn.ForeignAssets)) { + aid := cx.txn.Txn.ForeignAssets[ref] + if cx.availableHolding(addr, aid) { + return addr, aid, nil + } + } + + // Do some extra lookups to give a more concise err. Whenever a holding + // is available, its account and asset must be as well (but not vice + // versa, anymore). So, if (only) one of them is not available, yell + // about it, specifically. + + _, _, acctErr := cx.accountReference(account) + _, assetErr := cx.assetReference(ref, false) + switch { + case acctErr != nil && assetErr == nil: + err = acctErr + case acctErr == nil && assetErr != nil: + err = assetErr + default: + err = fmt.Errorf("invalid Holding access %s x %d", addr, aid) + } + + return basics.Address{}, basics.AssetIndex(0), err } - asset, err = cx.assetReference(ref, false) + + // Pre group resource sharing, the rule is just that account and asset are + // each available. + addr, _, err := cx.accountReference(account) if err != nil { - return + return basics.Address{}, basics.AssetIndex(0), err } - - if !cx.availableHolding(addr, asset) { - err = fmt.Errorf("invalid Holding access %s x %d", addr, asset) - return + asset, err := cx.assetReference(ref, false) + if err != nil { + return basics.Address{}, basics.AssetIndex(0), err } - - return + return addr, asset, nil } func opAssetHoldingGet(cx *EvalContext) error { @@ -4836,15 +4859,9 @@ func (cx *EvalContext) availableApp(aid basics.AppIndex) bool { return false } -// availableHolding is an additional check, required since -// resourceSharingVersion. It will work in previous versions too, since -// cx.available will be populated to make it work. But it must protect for < -// directRefEnabledVersion, because unnamed holdings could be read then. +// availableHolding checks if a holding is available under the txgroup sharing rules func (cx *EvalContext) availableHolding(addr basics.Address, ai basics.AssetIndex) bool { - if cx.version < directRefEnabledVersion { - return true - } - if _, ok := cx.available.sharedHoldings[basics.HoldingLocator{Address: addr, Index: ai}]; ok { + if _, ok := cx.available.sharedHoldings[ledgercore.AccountAsset{Address: addr, Asset: ai}]; ok { return true } // All holdings of created assets are available @@ -4864,7 +4881,7 @@ func (cx *EvalContext) availableLocals(addr basics.Address, ai basics.AppIndex) if cx.version < directRefEnabledVersion { return true } - if _, ok := cx.available.sharedLocals[basics.LocalsLocator{Address: addr, Index: ai}]; ok { + if _, ok := cx.available.sharedLocals[ledgercore.AccountApp{Address: addr, App: ai}]; ok { return true } // All locals of created apps are available diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index d4a47634fa..2c69715094 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -101,13 +101,13 @@ func (r *resources) String() string { if len(r.sharedHoldings) > 0 { fmt.Fprintf(&sb, "sharedHoldings:\n") for hl := range r.sharedHoldings { - fmt.Fprintf(&sb, " %s x %d\n", hl.Address, hl.Index) + fmt.Fprintf(&sb, " %s x %d\n", hl.Address, hl.Asset) } } if len(r.sharedLocals) > 0 { fmt.Fprintf(&sb, "sharedLocals:\n") for hl := range r.sharedLocals { - fmt.Fprintf(&sb, " %s x %d\n", hl.Address, hl.Index) + fmt.Fprintf(&sb, " %s x %d\n", hl.Address, hl.App) } } @@ -412,18 +412,22 @@ func testApps(t *testing.T, programs []string, txgroup []transactions.SignedTxn, func testAppsBytes(t *testing.T, programs [][]byte, ep *EvalParams, expected ...Expect) { t.Helper() - require.Equal(t, len(programs), len(ep.TxnGroup)) + require.LessOrEqual(t, len(programs), len(ep.TxnGroup)) for i := range ep.TxnGroup { - if programs[i] != nil { + program := ep.TxnGroup[i].Txn.ApprovalProgram + if len(programs) > i && programs[i] != nil { + program = programs[i] + } + if program != nil { appID := ep.TxnGroup[i].Txn.ApplicationID if appID == 0 { appID = basics.AppIndex(888) } if len(expected) > 0 && expected[0].l == i { - testAppFull(t, programs[i], i, appID, ep, expected[0].s) + testAppFull(t, program, i, appID, ep, expected[0].s) break // Stop after first failure } else { - testAppFull(t, programs[i], i, appID, ep) + testAppFull(t, program, i, appID, ep) } } } diff --git a/data/transactions/logic/resources.go b/data/transactions/logic/resources.go index e8578b1c37..3658ab1fcb 100644 --- a/data/transactions/logic/resources.go +++ b/data/transactions/logic/resources.go @@ -19,6 +19,8 @@ package logic import ( "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/transactions" + "github.com/algorand/go-algorand/ledger/ledgercore" + "github.com/algorand/go-algorand/protocol" ) // resources contains a catalog of available resources. It's used to track the @@ -40,8 +42,8 @@ type resources struct { // We need to carefully track the "cross-product" availability, because if // tx0 mentions an account A, and tx1 mentions an ASA X, that does _not_ // make the holding AX available - sharedHoldings map[basics.HoldingLocator]struct{} - sharedLocals map[basics.LocalsLocator]struct{} + sharedHoldings map[ledgercore.AccountAsset]struct{} + sharedLocals map[ledgercore.AccountApp]struct{} // boxes are all of the top-level box refs from the txgroup. Most are added // during NewEvalParams(). refs using 0 on an appl create are resolved and @@ -56,17 +58,41 @@ type resources struct { } func (r *resources) shareHolding(addr basics.Address, id basics.AssetIndex) { - r.sharedHoldings[basics.HoldingLocator{Address: addr, Index: id}] = struct{}{} + r.sharedHoldings[ledgercore.AccountAsset{Address: addr, Asset: id}] = struct{}{} +} + +func (r *resources) shareAccountAndHolding(addr basics.Address, id basics.AssetIndex) { + r.sharedAccounts[addr] = struct{}{} + if id != 0 { + r.sharedHoldings[ledgercore.AccountAsset{Address: addr, Asset: id}] = struct{}{} + } } func (r *resources) shareLocal(addr basics.Address, id basics.AppIndex) { - r.sharedLocals[basics.LocalsLocator{Address: addr, Index: id}] = struct{}{} + r.sharedLocals[ledgercore.AccountApp{Address: addr, App: id}] = struct{}{} } -// In the fill routines, we pass the header and the fields in separately, even +// In the fill* routines, we pass the header and the fields in separately, even // though they are pointers into the same structure. That prevents dumb attempts // to use other fields from the transaction. +func (r *resources) fill(tx *transactions.Transaction, ep *EvalParams) { + switch tx.Type { + case protocol.PaymentTx: + r.fillPayment(&tx.Header, &tx.PaymentTxnFields) + case protocol.KeyRegistrationTx: + r.fillKeyRegistration(&tx.Header) + case protocol.AssetConfigTx: + r.fillAssetConfig(&tx.Header, &tx.AssetConfigTxnFields) + case protocol.AssetTransferTx: + r.fillAssetTransfer(&tx.Header, &tx.AssetTransferTxnFields) + case protocol.AssetFreezeTx: + r.fillAssetFreeze(&tx.Header, &tx.AssetFreezeTxnFields) + case protocol.ApplicationCallTx: + r.fillApplicationCall(ep, &tx.Header, &tx.ApplicationCallTxnFields) + } +} + func (r *resources) fillKeyRegistration(hdr *transactions.Header) { r.sharedAccounts[hdr.Sender] = struct{}{} } @@ -80,26 +106,25 @@ func (r *resources) fillPayment(hdr *transactions.Header, tx *transactions.Payme } func (r *resources) fillAssetConfig(hdr *transactions.Header, tx *transactions.AssetConfigTxnFields) { - r.sharedAccounts[hdr.Sender] = struct{}{} + r.shareAccountAndHolding(hdr.Sender, tx.ConfigAsset) if id := tx.ConfigAsset; id != 0 { r.sharedAsas[id] = struct{}{} - r.shareHolding(hdr.Sender, id) } // We don't need to read the special addresses, so they don't go in. } func (r *resources) fillAssetTransfer(hdr *transactions.Header, tx *transactions.AssetTransferTxnFields) { - r.sharedAccounts[hdr.Sender] = struct{}{} id := tx.XferAsset r.sharedAsas[id] = struct{}{} - r.shareHolding(hdr.Sender, id) + r.shareAccountAndHolding(hdr.Sender, id) + r.shareAccountAndHolding(tx.AssetReceiver, id) if !tx.AssetSender.IsZero() { - r.shareHolding(tx.AssetSender, id) + r.shareAccountAndHolding(tx.AssetSender, id) } - r.shareHolding(tx.AssetReceiver, id) + if !tx.AssetCloseTo.IsZero() { - r.shareHolding(tx.AssetCloseTo, id) + r.shareAccountAndHolding(tx.AssetCloseTo, id) } } @@ -107,7 +132,7 @@ func (r *resources) fillAssetFreeze(hdr *transactions.Header, tx *transactions.A r.sharedAccounts[hdr.Sender] = struct{}{} id := tx.FreezeAsset r.sharedAsas[id] = struct{}{} - r.shareHolding(tx.FreezeAccount, id) + r.shareAccountAndHolding(tx.FreezeAccount, id) } func (r *resources) fillApplicationCall(ep *EvalParams, hdr *transactions.Header, tx *transactions.ApplicationCallTxnFields) { diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go new file mode 100644 index 0000000000..313125857b --- /dev/null +++ b/data/transactions/logic/resources_test.go @@ -0,0 +1,416 @@ +// Copyright (C) 2019-2023 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 . + +package logic_test + +import ( + "fmt" + "testing" + + "github.com/algorand/go-algorand/data/basics" + "github.com/algorand/go-algorand/data/transactions/logic" + "github.com/algorand/go-algorand/data/txntest" + "github.com/algorand/go-algorand/protocol" + "github.com/algorand/go-algorand/test/partitiontest" +) + +// TestAppSharing confirms that as of v9, assets can be accessed across +// groups, but that before then, they could not. +func TestAppSharing(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + // Create some sample transactions. The main reason this a blackbox test + // (_test package) is to have access to txntest. + appl0 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{1, 2, 3, 4}, + ForeignApps: []basics.AppIndex{500}, + } + + appl1 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{4, 3, 2, 1}, + } + + appl2 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{1, 2, 3, 4}, + } + + getSchema := ` +int 500 +app_params_get AppGlobalNumByteSlice +!; assert; pop; int 1 +` + sources := []string{getSchema, getSchema} + // In v8, the first tx can read app params of 500, because it's in its + // foreign array, but the second can't + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.NewExpect(1, "invalid App reference 500")) + // In v9, the second can, because the first can. + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil) + + getLocalEx := ` +int 0 // Sender +int 500 +byte "some-key" +app_local_get_ex +pop; pop; int 1 +` + + sources = []string{getLocalEx, getLocalEx} + // In contrast, here there's no help from v9, because the second tx is + // reading the locals for a different account. + + // app_local_get* requires the address and the app exist, else the program fails + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.NewExpect(0, "no account")) + + _, _, ledger := logic.MakeSampleEnv() + ledger.NewAccount(appl0.Sender, 100_000) + ledger.NewApp(appl0.Sender, 500, basics.AppParams{}) + ledger.NewLocals(appl0.Sender, 500) // opt in + // Now txn0 passes, but txn1 has an error because it can't see app 500 + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, ledger, + logic.NewExpect(1, "invalid Local State access")) + + // But it's ok in appl2, because appl2 uses the same Sender, even though the + // foreign-app is not repeated in appl2 so the holding being accessed is is + // the one from tx0. + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl2), 9, ledger) +} + +// TestAssetSharing confirms that as of v9, assets can be accessed across +// groups, but that before then, they could not. +func TestAssetSharing(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + // Create some sample transactions. The main reason this a blackbox test + // (_test package) is to have access to txntest. + appl0 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{1, 2, 3, 4}, + ForeignAssets: []basics.AssetIndex{400}, + } + + appl1 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{4, 3, 2, 1}, + } + + appl2 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{1, 2, 3, 4}, + } + + getTotal := ` +int 400 +asset_params_get AssetTotal +pop; pop; int 1 +` + sources := []string{getTotal, getTotal} + // In v8, the first tx can read asset 400, because it's in its foreign arry, + // but the second can't + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.NewExpect(1, "invalid Asset reference 400")) + // In v9, the second can, because the first can. + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil) + + getBalance := ` +int 0 +int 400 +asset_holding_get AssetBalance +pop; pop; int 1 +` + + sources = []string{getBalance, getBalance} + // In contrast, here there's no help from v9, because the second tx is + // reading a holding for a different account. + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.NewExpect(1, "invalid Asset reference 400")) + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil, + logic.NewExpect(1, "invalid Holding access")) + // But it's ok in appl2, because the same account is used, even though the + // foreign-asset is not repeated in appl2. + logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl2), 9, nil) +} + +// TestOtherTxSharing tests resource sharing across other kinds of transactions besides appl. +func TestOtherTxSharing(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + _, _, ledger := logic.MakeSampleEnv() + + senderAcct := basics.Address{1, 2, 3, 4, 5, 6, 1} + ledger.NewAccount(senderAcct, 2001) + senderBalance := "txn ApplicationArgs 0; balance; int 2001; ==" + + receiverAcct := basics.Address{1, 2, 3, 4, 5, 6, 2} + ledger.NewAccount(receiverAcct, 2002) + receiverBalance := "txn ApplicationArgs 0; balance; int 2002; ==" + + otherAcct := basics.Address{1, 2, 3, 4, 5, 6, 3} + ledger.NewAccount(otherAcct, 2003) + otherBalance := "txn ApplicationArgs 0; balance; int 2003; ==" + + appl := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{5, 5, 5, 5}, // different from all other accounts used + ApplicationArgs: [][]byte{senderAcct[:]}, + } + + keyreg := txntest.Txn{ + Type: protocol.KeyRegistrationTx, + Sender: senderAcct, + } + pay := txntest.Txn{ + Type: protocol.PaymentTx, + Sender: senderAcct, + Receiver: receiverAcct, + } + acfg := txntest.Txn{ + Type: protocol.AssetConfigTx, + Sender: senderAcct, + AssetParams: basics.AssetParams{ + Manager: otherAcct, // other is here to show they _don't_ become available + Reserve: otherAcct, + Freeze: otherAcct, + Clawback: otherAcct, + }, + } + axfer := txntest.Txn{ + Type: protocol.AssetTransferTx, + XferAsset: 100, // must be < 256, later code assumes it fits in a byte + Sender: senderAcct, + AssetReceiver: receiverAcct, + AssetSender: otherAcct, + } + afrz := txntest.Txn{ + Type: protocol.AssetFreezeTx, + FreezeAsset: 200, // must be < 256, later code assumes it fits in a byte + Sender: senderAcct, + FreezeAccount: otherAcct, + } + + sources := []string{"", senderBalance} + rsources := []string{senderBalance, ""} + for _, send := range []txntest.Txn{keyreg, pay, acfg, axfer, afrz} { + logic.TestApps(t, sources, txntest.SignedTxns(&send, &appl), 9, ledger) + logic.TestApps(t, rsources, txntest.SignedTxns(&appl, &send), 9, ledger) + + logic.TestApps(t, sources, txntest.SignedTxns(&send, &appl), 8, ledger, + logic.NewExpect(1, "invalid Account reference")) + logic.TestApps(t, rsources, txntest.SignedTxns(&appl, &send), 8, ledger, + logic.NewExpect(0, "invalid Account reference")) + } + + holdingAccess := ` + txn ApplicationArgs 0 + txn ApplicationArgs 1; btoi + asset_holding_get AssetBalance + pop; pop; int 1 +` + sources = []string{"", holdingAccess} + rsources = []string{holdingAccess, ""} + + t.Run("keyreg", func(t *testing.T) { + appl.ApplicationArgs = [][]byte{senderAcct[:], {200}} + logic.TestApps(t, sources, txntest.SignedTxns(&keyreg, &appl), 9, ledger, + logic.NewExpect(1, "invalid Asset reference 200")) + withRef := appl + withRef.ForeignAssets = []basics.AssetIndex{200} + logic.TestApps(t, sources, txntest.SignedTxns(&keyreg, &withRef), 9, ledger, + logic.NewExpect(1, "invalid Holding access "+senderAcct.String())) + }) + t.Run("pay", func(t *testing.T) { + // The receiver is available for algo balance reading + appl.ApplicationArgs = [][]byte{receiverAcct[:]} + logic.TestApps(t, []string{"", receiverBalance}, txntest.SignedTxns(&pay, &appl), 9, ledger) + + // The other account is not (it's not even in the pay txn) + appl.ApplicationArgs = [][]byte{otherAcct[:]} + logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&pay, &appl), 9, ledger, + logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) + + // The other account becomes accessible because used in CloseRemainderTo + withClose := pay + withClose.CloseRemainderTo = otherAcct + logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&withClose, &appl), 9, ledger) + }) + + t.Run("acfg", func(t *testing.T) { + // The other account is not available even though it's all the extra addresses + appl.ApplicationArgs = [][]byte{otherAcct[:]} + logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&acfg, &appl), 9, ledger, + logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) + }) + + t.Run("axfer", func(t *testing.T) { + // The receiver is also available for algo balance reading + appl.ApplicationArgs = [][]byte{receiverAcct[:]} + logic.TestApps(t, []string{"", receiverBalance}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + + // as is the "other" (AssetSender) + appl.ApplicationArgs = [][]byte{otherAcct[:]} + logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + + // receiver holding is available + appl.ApplicationArgs = [][]byte{receiverAcct[:], {byte(axfer.XferAsset)}} + logic.TestApps(t, []string{"", holdingAccess}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + + // The other account becomes accessible because used in CloseRemainderTo + // (for asa and algo) + withClose := axfer + withClose.AssetCloseTo = otherAcct + appl.ApplicationArgs = [][]byte{otherAcct[:], {byte(axfer.XferAsset)}} + logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&withClose, &appl), 9, ledger) + logic.TestApps(t, []string{"", holdingAccess}, txntest.SignedTxns(&withClose, &appl), 9, ledger) + }) + + t.Run("afrz", func(t *testing.T) { + // The other account is available (for algo and asset) + appl.ApplicationArgs = [][]byte{otherAcct[:], {byte(afrz.FreezeAsset)}} + logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&afrz, &appl), 9, ledger) + logic.TestApps(t, []string{"", holdingAccess}, txntest.SignedTxns(&afrz, &appl), 9, ledger) + }) +} + +// TestSharedInnerTxns checks how inner txns access resources. +func TestSharedInnerTxns(t *testing.T) { + _, _, ledger := logic.MakeSampleEnv() + + const asa1 = 201 + const asa2 = 202 + + senderAcct := basics.Address{1, 2, 3, 4, 5, 6, 1} + ledger.NewAccount(senderAcct, 2001) + ledger.NewHolding(senderAcct, asa1, 1, false) + + receiverAcct := basics.Address{1, 2, 3, 4, 5, 6, 2} + ledger.NewAccount(receiverAcct, 2002) + ledger.NewHolding(receiverAcct, asa1, 1, false) + + otherAcct := basics.Address{1, 2, 3, 4, 5, 6, 3} + ledger.NewAccount(otherAcct, 2003) + ledger.NewHolding(otherAcct, asa1, 1, false) + + unusedAcct := basics.Address{1, 2, 3, 4, 5, 6, 4} + + payToArg := ` +itxn_begin + int pay; itxn_field TypeEnum + int 100; itxn_field Amount + txn ApplicationArgs 0; itxn_field Receiver +itxn_submit +int 1 +` + axferToArgs := ` +itxn_begin + int axfer; itxn_field TypeEnum + int 2; itxn_field AssetAmount + txn ApplicationArgs 0; itxn_field AssetReceiver + txn ApplicationArgs 1; btoi; itxn_field XferAsset +itxn_submit +int 1 +` + + appl := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: basics.Address{5, 5, 5, 5}, // different from all other accounts used + } + // App will do a lot of txns. Start well funded. + ledger.NewAccount(basics.AppIndex(888).Address(), 1_000_000) + // And needs some ASAs for inner axfer testing + ledger.NewHolding(basics.AppIndex(888).Address(), asa1, 1_000_000, false) + + t.Run("keyreg", func(t *testing.T) { + keyreg := txntest.Txn{ + Type: protocol.KeyRegistrationTx, + Sender: senderAcct, + } + + // appl has no foreign ref to senderAcct, but can still inner pay it + appl.ApplicationArgs = [][]byte{senderAcct[:]} + logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&keyreg, &appl), 9, ledger) + logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&keyreg, &appl), 8, ledger, + logic.NewExpect(1, "invalid Account reference "+senderAcct.String())) + + // confirm you can't just pay _anybody_. receiverAcct is not in use at all. + appl.ApplicationArgs = [][]byte{receiverAcct[:]} + logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&keyreg, &appl), 9, ledger, + logic.NewExpect(1, "invalid Account reference "+receiverAcct.String())) + }) + + t.Run("pay", func(t *testing.T) { + pay := txntest.Txn{ + Type: protocol.PaymentTx, + Sender: senderAcct, + Receiver: receiverAcct, + } + + // appl has no foreign ref to senderAcct or receiverAcct, but can still inner pay them + appl.ApplicationArgs = [][]byte{senderAcct[:]} + logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&pay, &appl), 9, ledger) + logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&pay, &appl), 8, ledger, + logic.NewExpect(1, "invalid Account reference "+senderAcct.String())) + + appl.ApplicationArgs = [][]byte{receiverAcct[:]} + logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&pay, &appl), 9, ledger) + logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&pay, &appl), 8, ledger, + logic.NewExpect(1, "invalid Account reference "+receiverAcct.String())) + + // confirm you can't just pay _anybody_. otherAcct is not in use at all. + appl.ApplicationArgs = [][]byte{otherAcct[:]} + logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&pay, &appl), 9, ledger, + logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) + }) + + t.Run("axfer", func(t *testing.T) { + axfer := txntest.Txn{ + Type: protocol.AssetTransferTx, + XferAsset: asa1, + Sender: senderAcct, + AssetReceiver: receiverAcct, + AssetSender: otherAcct, + } + + // appl can pay or axfer to the sender + appl.ApplicationArgs = [][]byte{senderAcct[:], {asa1}} + logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", axferToArgs}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + // and to the receiver + appl.ApplicationArgs = [][]byte{receiverAcct[:], {asa1}} + logic.TestApps(t, []string{payToArg}, txntest.SignedTxns(&appl, &axfer), 9, ledger) + logic.TestApps(t, []string{axferToArgs}, txntest.SignedTxns(&appl, &axfer), 9, ledger) + // and to the clawback + appl.ApplicationArgs = [][]byte{otherAcct[:], {asa1}} + logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", axferToArgs}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + + // but can't axfer a different asset + appl.ApplicationArgs = [][]byte{senderAcct[:], {asa2}} + logic.TestApps(t, []string{"", axferToArgs}, txntest.SignedTxns(&axfer, &appl), 9, ledger, + logic.NewExpect(1, fmt.Sprintf("invalid Asset reference %d", asa2))) + // or correct asset to an unknown address + appl.ApplicationArgs = [][]byte{unusedAcct[:], {asa1}} + logic.TestApps(t, []string{"", axferToArgs}, txntest.SignedTxns(&axfer, &appl), 9, ledger, + logic.NewExpect(1, "invalid Account reference")) + }) + +} From 857d17edad9d94f29a0a63001021da4b4c435894 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 26 Jan 2023 12:22:28 -0500 Subject: [PATCH 04/29] Adjust names after rebase --- data/transactions/logic/eval.go | 4 +- data/transactions/logic/resources_test.go | 86 +++++++++++------------ 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 0b902bc9dd..ed81bab72b 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -4765,7 +4765,7 @@ func (cx *EvalContext) assignAccount(sv stackValue) (basics.Address, error) { } // assignAsset is used to convert a stackValue to a uint64 assetIndex, reporting -// any errors due to availablity rules or type checking. +// any errors due to availability rules or type checking. func (cx *EvalContext) assignAsset(sv stackValue) (basics.AssetIndex, error) { uint, err := sv.uint() if err != nil { @@ -4814,7 +4814,7 @@ func (cx *EvalContext) availableAsset(aid basics.AssetIndex) bool { } // assignApp is used to convert a stackValue to a uint64 appIndex, reporting -// any errors due to availablity rules or type checking. +// any errors due to availability rules or type checking. func (cx *EvalContext) assignApp(sv stackValue) (basics.AppIndex, error) { uint, err := sv.uint() if err != nil { diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 313125857b..8617e56ad8 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -59,10 +59,10 @@ app_params_get AppGlobalNumByteSlice sources := []string{getSchema, getSchema} // In v8, the first tx can read app params of 500, because it's in its // foreign array, but the second can't - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 8, nil, logic.NewExpect(1, "invalid App reference 500")) // In v9, the second can, because the first can. - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil) + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, nil) getLocalEx := ` int 0 // Sender @@ -77,7 +77,7 @@ pop; pop; int 1 // reading the locals for a different account. // app_local_get* requires the address and the app exist, else the program fails - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 8, nil, logic.NewExpect(0, "no account")) _, _, ledger := logic.MakeSampleEnv() @@ -85,13 +85,13 @@ pop; pop; int 1 ledger.NewApp(appl0.Sender, 500, basics.AppParams{}) ledger.NewLocals(appl0.Sender, 500) // opt in // Now txn0 passes, but txn1 has an error because it can't see app 500 - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, ledger, + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, ledger, logic.NewExpect(1, "invalid Local State access")) // But it's ok in appl2, because appl2 uses the same Sender, even though the // foreign-app is not repeated in appl2 so the holding being accessed is is // the one from tx0. - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl2), 9, ledger) + logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, ledger) } // TestAssetSharing confirms that as of v9, assets can be accessed across @@ -126,10 +126,10 @@ pop; pop; int 1 sources := []string{getTotal, getTotal} // In v8, the first tx can read asset 400, because it's in its foreign arry, // but the second can't - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 8, nil, logic.NewExpect(1, "invalid Asset reference 400")) // In v9, the second can, because the first can. - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil) + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, nil) getBalance := ` int 0 @@ -141,13 +141,13 @@ pop; pop; int 1 sources = []string{getBalance, getBalance} // In contrast, here there's no help from v9, because the second tx is // reading a holding for a different account. - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 8, nil, + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 8, nil, logic.NewExpect(1, "invalid Asset reference 400")) - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl1), 9, nil, + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, nil, logic.NewExpect(1, "invalid Holding access")) // But it's ok in appl2, because the same account is used, even though the // foreign-asset is not repeated in appl2. - logic.TestApps(t, sources, txntest.SignedTxns(&appl0, &appl2), 9, nil) + logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, nil) } // TestOtherTxSharing tests resource sharing across other kinds of transactions besides appl. @@ -211,12 +211,12 @@ func TestOtherTxSharing(t *testing.T) { sources := []string{"", senderBalance} rsources := []string{senderBalance, ""} for _, send := range []txntest.Txn{keyreg, pay, acfg, axfer, afrz} { - logic.TestApps(t, sources, txntest.SignedTxns(&send, &appl), 9, ledger) - logic.TestApps(t, rsources, txntest.SignedTxns(&appl, &send), 9, ledger) + logic.TestApps(t, sources, txntest.Group(&send, &appl), 9, ledger) + logic.TestApps(t, rsources, txntest.Group(&appl, &send), 9, ledger) - logic.TestApps(t, sources, txntest.SignedTxns(&send, &appl), 8, ledger, + logic.TestApps(t, sources, txntest.Group(&send, &appl), 8, ledger, logic.NewExpect(1, "invalid Account reference")) - logic.TestApps(t, rsources, txntest.SignedTxns(&appl, &send), 8, ledger, + logic.TestApps(t, rsources, txntest.Group(&appl, &send), 8, ledger, logic.NewExpect(0, "invalid Account reference")) } @@ -231,63 +231,63 @@ func TestOtherTxSharing(t *testing.T) { t.Run("keyreg", func(t *testing.T) { appl.ApplicationArgs = [][]byte{senderAcct[:], {200}} - logic.TestApps(t, sources, txntest.SignedTxns(&keyreg, &appl), 9, ledger, + logic.TestApps(t, sources, txntest.Group(&keyreg, &appl), 9, ledger, logic.NewExpect(1, "invalid Asset reference 200")) withRef := appl withRef.ForeignAssets = []basics.AssetIndex{200} - logic.TestApps(t, sources, txntest.SignedTxns(&keyreg, &withRef), 9, ledger, + logic.TestApps(t, sources, txntest.Group(&keyreg, &withRef), 9, ledger, logic.NewExpect(1, "invalid Holding access "+senderAcct.String())) }) t.Run("pay", func(t *testing.T) { // The receiver is available for algo balance reading appl.ApplicationArgs = [][]byte{receiverAcct[:]} - logic.TestApps(t, []string{"", receiverBalance}, txntest.SignedTxns(&pay, &appl), 9, ledger) + logic.TestApps(t, []string{"", receiverBalance}, txntest.Group(&pay, &appl), 9, ledger) // The other account is not (it's not even in the pay txn) appl.ApplicationArgs = [][]byte{otherAcct[:]} - logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&pay, &appl), 9, ledger, + logic.TestApps(t, []string{"", otherBalance}, txntest.Group(&pay, &appl), 9, ledger, logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) // The other account becomes accessible because used in CloseRemainderTo withClose := pay withClose.CloseRemainderTo = otherAcct - logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&withClose, &appl), 9, ledger) + logic.TestApps(t, []string{"", otherBalance}, txntest.Group(&withClose, &appl), 9, ledger) }) t.Run("acfg", func(t *testing.T) { // The other account is not available even though it's all the extra addresses appl.ApplicationArgs = [][]byte{otherAcct[:]} - logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&acfg, &appl), 9, ledger, + logic.TestApps(t, []string{"", otherBalance}, txntest.Group(&acfg, &appl), 9, ledger, logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) }) t.Run("axfer", func(t *testing.T) { // The receiver is also available for algo balance reading appl.ApplicationArgs = [][]byte{receiverAcct[:]} - logic.TestApps(t, []string{"", receiverBalance}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", receiverBalance}, txntest.Group(&axfer, &appl), 9, ledger) // as is the "other" (AssetSender) appl.ApplicationArgs = [][]byte{otherAcct[:]} - logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", otherBalance}, txntest.Group(&axfer, &appl), 9, ledger) // receiver holding is available appl.ApplicationArgs = [][]byte{receiverAcct[:], {byte(axfer.XferAsset)}} - logic.TestApps(t, []string{"", holdingAccess}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", holdingAccess}, txntest.Group(&axfer, &appl), 9, ledger) // The other account becomes accessible because used in CloseRemainderTo // (for asa and algo) withClose := axfer withClose.AssetCloseTo = otherAcct appl.ApplicationArgs = [][]byte{otherAcct[:], {byte(axfer.XferAsset)}} - logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&withClose, &appl), 9, ledger) - logic.TestApps(t, []string{"", holdingAccess}, txntest.SignedTxns(&withClose, &appl), 9, ledger) + logic.TestApps(t, []string{"", otherBalance}, txntest.Group(&withClose, &appl), 9, ledger) + logic.TestApps(t, []string{"", holdingAccess}, txntest.Group(&withClose, &appl), 9, ledger) }) t.Run("afrz", func(t *testing.T) { // The other account is available (for algo and asset) appl.ApplicationArgs = [][]byte{otherAcct[:], {byte(afrz.FreezeAsset)}} - logic.TestApps(t, []string{"", otherBalance}, txntest.SignedTxns(&afrz, &appl), 9, ledger) - logic.TestApps(t, []string{"", holdingAccess}, txntest.SignedTxns(&afrz, &appl), 9, ledger) + logic.TestApps(t, []string{"", otherBalance}, txntest.Group(&afrz, &appl), 9, ledger) + logic.TestApps(t, []string{"", holdingAccess}, txntest.Group(&afrz, &appl), 9, ledger) }) } @@ -347,13 +347,13 @@ int 1 // appl has no foreign ref to senderAcct, but can still inner pay it appl.ApplicationArgs = [][]byte{senderAcct[:]} - logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&keyreg, &appl), 9, ledger) - logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&keyreg, &appl), 8, ledger, + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&keyreg, &appl), 9, ledger) + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&keyreg, &appl), 8, ledger, logic.NewExpect(1, "invalid Account reference "+senderAcct.String())) // confirm you can't just pay _anybody_. receiverAcct is not in use at all. appl.ApplicationArgs = [][]byte{receiverAcct[:]} - logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&keyreg, &appl), 9, ledger, + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&keyreg, &appl), 9, ledger, logic.NewExpect(1, "invalid Account reference "+receiverAcct.String())) }) @@ -366,18 +366,18 @@ int 1 // appl has no foreign ref to senderAcct or receiverAcct, but can still inner pay them appl.ApplicationArgs = [][]byte{senderAcct[:]} - logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&pay, &appl), 9, ledger) - logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&pay, &appl), 8, ledger, + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&pay, &appl), 9, ledger) + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&pay, &appl), 8, ledger, logic.NewExpect(1, "invalid Account reference "+senderAcct.String())) appl.ApplicationArgs = [][]byte{receiverAcct[:]} - logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&pay, &appl), 9, ledger) - logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&pay, &appl), 8, ledger, + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&pay, &appl), 9, ledger) + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&pay, &appl), 8, ledger, logic.NewExpect(1, "invalid Account reference "+receiverAcct.String())) // confirm you can't just pay _anybody_. otherAcct is not in use at all. appl.ApplicationArgs = [][]byte{otherAcct[:]} - logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&pay, &appl), 9, ledger, + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&pay, &appl), 9, ledger, logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) }) @@ -392,24 +392,24 @@ int 1 // appl can pay or axfer to the sender appl.ApplicationArgs = [][]byte{senderAcct[:], {asa1}} - logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&axfer, &appl), 9, ledger) - logic.TestApps(t, []string{"", axferToArgs}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger) // and to the receiver appl.ApplicationArgs = [][]byte{receiverAcct[:], {asa1}} - logic.TestApps(t, []string{payToArg}, txntest.SignedTxns(&appl, &axfer), 9, ledger) - logic.TestApps(t, []string{axferToArgs}, txntest.SignedTxns(&appl, &axfer), 9, ledger) + logic.TestApps(t, []string{payToArg}, txntest.Group(&appl, &axfer), 9, ledger) + logic.TestApps(t, []string{axferToArgs}, txntest.Group(&appl, &axfer), 9, ledger) // and to the clawback appl.ApplicationArgs = [][]byte{otherAcct[:], {asa1}} - logic.TestApps(t, []string{"", payToArg}, txntest.SignedTxns(&axfer, &appl), 9, ledger) - logic.TestApps(t, []string{"", axferToArgs}, txntest.SignedTxns(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger) // but can't axfer a different asset appl.ApplicationArgs = [][]byte{senderAcct[:], {asa2}} - logic.TestApps(t, []string{"", axferToArgs}, txntest.SignedTxns(&axfer, &appl), 9, ledger, + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger, logic.NewExpect(1, fmt.Sprintf("invalid Asset reference %d", asa2))) // or correct asset to an unknown address appl.ApplicationArgs = [][]byte{unusedAcct[:], {asa1}} - logic.TestApps(t, []string{"", axferToArgs}, txntest.SignedTxns(&axfer, &appl), 9, ledger, + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger, logic.NewExpect(1, "invalid Account reference")) }) From bc2a5af417f1fe96563ffeaa459d1bf43564973d Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Wed, 1 Feb 2023 16:06:01 -0500 Subject: [PATCH 05/29] Add checks for inner txn resource access Also, enhance EvalDelta to allow modifications of local states for addresses that are not in txn.Accounts. This probably needs a bit of work on the REST endpoints that emit them. --- agreement/msgp_gen.go | 16 +- data/transactions/application.go | 42 --- data/transactions/application_test.go | 27 -- data/transactions/logic/eval.go | 215 +++++++++----- data/transactions/logic/evalAppTxn_test.go | 4 + data/transactions/logic/evalStateful_test.go | 94 +++++- data/transactions/logic/resources.go | 146 ++++++++- data/transactions/logic/resources_test.go | 157 +++++++++- data/transactions/msgp_gen.go | 294 ++++++++++++------- data/transactions/teal.go | 4 +- ledger/internal/cow.go | 4 +- 11 files changed, 723 insertions(+), 280 deletions(-) diff --git a/agreement/msgp_gen.go b/agreement/msgp_gen.go index bf1c46f98c..8a3fc90705 100644 --- a/agreement/msgp_gen.go +++ b/agreement/msgp_gen.go @@ -3555,10 +3555,10 @@ func (z *player) MarshalMsg(b []byte) (o []byte) { // map header, size 8 // string "Deadline" o = append(o, 0x88, 0xa8, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65) - o = msgp.AppendDuration(o, (*z).Deadline) + o = (*z).Deadline.MarshalMsg(o) // string "FastRecoveryDeadline" o = append(o, 0xb4, 0x46, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65) - o = msgp.AppendDuration(o, (*z).FastRecoveryDeadline) + o = (*z).FastRecoveryDeadline.MarshalMsg(o) // string "LastConcluding" o = append(o, 0xae, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67) o = msgp.AppendUint64(o, uint64((*z).LastConcluding)) @@ -3644,7 +3644,7 @@ func (z *player) UnmarshalMsg(bts []byte) (o []byte, err error) { } if zb0001 > 0 { zb0001-- - (*z).Deadline, bts, err = msgp.ReadDurationBytes(bts) + bts, err = (*z).Deadline.UnmarshalMsg(bts) if err != nil { err = msgp.WrapError(err, "struct-from-array", "Deadline") return @@ -3660,7 +3660,7 @@ func (z *player) UnmarshalMsg(bts []byte) (o []byte, err error) { } if zb0001 > 0 { zb0001-- - (*z).FastRecoveryDeadline, bts, err = msgp.ReadDurationBytes(bts) + bts, err = (*z).FastRecoveryDeadline.UnmarshalMsg(bts) if err != nil { err = msgp.WrapError(err, "struct-from-array", "FastRecoveryDeadline") return @@ -3734,7 +3734,7 @@ func (z *player) UnmarshalMsg(bts []byte) (o []byte, err error) { (*z).LastConcluding = step(zb0008) } case "Deadline": - (*z).Deadline, bts, err = msgp.ReadDurationBytes(bts) + bts, err = (*z).Deadline.UnmarshalMsg(bts) if err != nil { err = msgp.WrapError(err, "Deadline") return @@ -3746,7 +3746,7 @@ func (z *player) UnmarshalMsg(bts []byte) (o []byte, err error) { return } case "FastRecoveryDeadline": - (*z).FastRecoveryDeadline, bts, err = msgp.ReadDurationBytes(bts) + bts, err = (*z).FastRecoveryDeadline.UnmarshalMsg(bts) if err != nil { err = msgp.WrapError(err, "FastRecoveryDeadline") return @@ -3777,13 +3777,13 @@ func (_ *player) CanUnmarshalMsg(z interface{}) bool { // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *player) Msgsize() (s int) { - s = 1 + 6 + (*z).Round.Msgsize() + 7 + msgp.Uint64Size + 5 + msgp.Uint64Size + 15 + msgp.Uint64Size + 9 + msgp.DurationSize + 8 + msgp.BoolSize + 21 + msgp.DurationSize + 8 + (*z).Pending.Msgsize() + s = 1 + 6 + (*z).Round.Msgsize() + 7 + msgp.Uint64Size + 5 + msgp.Uint64Size + 15 + msgp.Uint64Size + 9 + (*z).Deadline.Msgsize() + 8 + msgp.BoolSize + 21 + (*z).FastRecoveryDeadline.Msgsize() + 8 + (*z).Pending.Msgsize() return } // MsgIsZero returns whether this is a zero value func (z *player) MsgIsZero() bool { - return ((*z).Round.MsgIsZero()) && ((*z).Period == 0) && ((*z).Step == 0) && ((*z).LastConcluding == 0) && ((*z).Deadline == 0) && ((*z).Napping == false) && ((*z).FastRecoveryDeadline == 0) && ((*z).Pending.MsgIsZero()) + return ((*z).Round.MsgIsZero()) && ((*z).Period == 0) && ((*z).Step == 0) && ((*z).LastConcluding == 0) && ((*z).Deadline.MsgIsZero()) && ((*z).Napping == false) && ((*z).FastRecoveryDeadline.MsgIsZero()) && ((*z).Pending.MsgIsZero()) } // MarshalMsg implements msgp.Marshaler diff --git a/data/transactions/application.go b/data/transactions/application.go index 9099f1dd0a..c303093c8d 100644 --- a/data/transactions/application.go +++ b/data/transactions/application.go @@ -255,45 +255,3 @@ func (ac *ApplicationCallTxnFields) IndexByAddress(target basics.Address, sender return 0, fmt.Errorf("invalid Account reference %s", target) } - -// AppIDByIndex converts an integer index into an application id associated with the -// transaction. Index 0 corresponds to the current app, and an index > 0 -// corresponds to an offset into txn.ForeignApps. Returns an error if the index is -// not valid. -func (ac *ApplicationCallTxnFields) AppIDByIndex(i uint64) (basics.AppIndex, error) { - - // Index 0 always corresponds to the current app - if i == 0 { - return ac.ApplicationID, nil - } - - // An index > 0 corresponds to an offset into txn.ForeignApps. Check to - // make sure the index is valid. - if i > uint64(len(ac.ForeignApps)) { - err := fmt.Errorf("invalid Foreign App reference %d", i) - return basics.AppIndex(0), err - } - - // aidx must be in [1, len(ac.ForeignApps)] - return ac.ForeignApps[i-1], nil -} - -// IndexByAppID converts an application id into an integer offset into [current app, -// txn.ForeignApps[0], ...], returning the index at the first match. It returns -// an error if there is no such match. -func (ac *ApplicationCallTxnFields) IndexByAppID(appID basics.AppIndex) (uint64, error) { - - // Index 0 always corresponds to the current app - if appID == ac.ApplicationID { - return 0, nil - } - - // Otherwise we index into ac.ForeignApps - for i, id := range ac.ForeignApps { - if appID == id { - return uint64(i) + 1, nil - } - } - - return 0, fmt.Errorf("invalid Foreign App reference %d", appID) -} diff --git a/data/transactions/application_test.go b/data/transactions/application_test.go index 24bff87a02..a0a839b132 100644 --- a/data/transactions/application_test.go +++ b/data/transactions/application_test.go @@ -124,30 +124,3 @@ func TestEncodedAppTxnAllocationBounds(t *testing.T) { } } } - -func TestIDByIndex(t *testing.T) { - partitiontest.PartitionTest(t) - - a := require.New(t) - ac := ApplicationCallTxnFields{} - ac.ApplicationID = 1 - appID, err := ac.AppIDByIndex(0) - a.NoError(err) - a.Equal(basics.AppIndex(1), appID) - appID, err = ac.AppIDByIndex(1) - a.Contains(err.Error(), "invalid Foreign App reference") - -} - -func TestIndexByID(t *testing.T) { - partitiontest.PartitionTest(t) - - a := require.New(t) - ac := ApplicationCallTxnFields{} - ac.ApplicationID = 1 - aidx, err := ac.IndexByAppID(1) - a.NoError(err) - a.Equal(uint64(0), aidx) - aidx, err = ac.IndexByAppID(2) - a.Contains(err.Error(), "invalid Foreign App reference") -} diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index ed81bab72b..a604950b0a 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -3992,10 +3992,11 @@ func opExtract64Bits(cx *EvalContext) error { // predicted the address, and therefore it IS in txn.Accounts, then happy day, // we can set/del it. Return the proper index. -// If we ever want apps to be able to change local state on these accounts -// (which includes this app's own account!), we will need a change to -// EvalDelta's on disk format, so that the addr can be encoded explicitly rather -// than by index into txn.Accounts. +// Starting in v9, apps can change local state on these accounts by adding the +// address to EvalDelta.ShardAccounts and indexing it there. But at this level, +// we still report the "failure" to find an index with `invalidIndex=len+1` That +// value allows mutableAccountReference to decide whether to report an error or +// not, based on version. func (cx *EvalContext) accountReference(account stackValue) (basics.Address, uint64, error) { if account.argType() == StackUint64 { @@ -4049,10 +4050,20 @@ func (cx *EvalContext) accountReference(account stackValue) (basics.Address, uin func (cx *EvalContext) mutableAccountReference(account stackValue) (basics.Address, uint64, error) { addr, accountIdx, err := cx.accountReference(account) - if err == nil && accountIdx > uint64(len(cx.txn.Txn.Accounts)) { + if err != nil { + return basics.Address{}, 0, err + } + if accountIdx > uint64(len(cx.txn.Txn.Accounts)) { // There was no error, but accountReference has signaled that accountIdx // is not for mutable ops (because it can't encode it in EvalDelta) - err = fmt.Errorf("invalid Account reference for mutation %s", addr) + if cx.version < resourceSharingVersion { + return basics.Address{}, 0, fmt.Errorf("invalid Account reference for mutation %s", addr) + } + // fall through, which means that starting in v9, the accountIdx + // returned can be > len(tx.Accounts). It will end up getting passed to + // GetLocal, which seems bad, since GetLocal can record that index. But + // that record is only done in very old consenus versions. At that point + // v9 did not exist. } return addr, accountIdx, err } @@ -4153,21 +4164,11 @@ func opAppLocalGetEx(cx *EvalContext) error { } func opAppLocalGetImpl(cx *EvalContext, appID uint64, key []byte, acct stackValue) (result stackValue, ok bool, err error) { - addr, accountIdx, err := cx.accountReference(acct) - if err != nil { - return - } - - app, err := cx.appReference(appID, false) + addr, app, accountIdx, err := cx.localsReference(acct, appID) if err != nil { return } - if !cx.availableLocals(addr, app) { - err = fmt.Errorf("invalid Local State access %s x %d", addr, app) - return - } - tv, ok, err := cx.Ledger.GetLocal(addr, app, string(key), accountIdx) if err != nil { return @@ -4226,6 +4227,32 @@ func opAppGlobalGetEx(cx *EvalContext) error { return nil } +// ensureLocalDelta is used to get accountIdx that is usable in the LocalDeltas +// of the EvalDelta. The input accountIdx is "tentative" - if it's longer that +// the txn.Accounts, then we may need to add the address into SharedAccounts, +// and index into it. +func (cx *EvalContext) ensureLocalDelta(accountIdx uint64, addr basics.Address) uint64 { + if accountIdx > uint64(len(cx.txn.Txn.Accounts)) { + // the returned accountIdx was just a signal that the account was + // not in txn, so we look in SharedAccounts, allocating space if needed. + found := false + for i, shared := range cx.txn.EvalDelta.SharedAccts { + if shared == addr { + found = true + accountIdx = uint64(len(cx.txn.Txn.Accounts) + 1 + i) + } + } + if !found { + cx.txn.EvalDelta.SharedAccts = append(cx.txn.EvalDelta.SharedAccts, addr) + accountIdx = uint64(len(cx.txn.Txn.Accounts) + len(cx.txn.EvalDelta.SharedAccts)) + } + } + if _, ok := cx.txn.EvalDelta.LocalDeltas[accountIdx]; !ok { + cx.txn.EvalDelta.LocalDeltas[accountIdx] = basics.StateDelta{} + } + return accountIdx +} + func opAppLocalPut(cx *EvalContext) error { last := len(cx.stack) - 1 // value prev := last - 1 // state key @@ -4255,9 +4282,7 @@ func opAppLocalPut(cx *EvalContext) error { tv := sv.toTealValue() if !ok || tv != etv { - if _, ok := cx.txn.EvalDelta.LocalDeltas[accountIdx]; !ok { - cx.txn.EvalDelta.LocalDeltas[accountIdx] = basics.StateDelta{} - } + accountIdx = cx.ensureLocalDelta(accountIdx, addr) cx.txn.EvalDelta.LocalDeltas[accountIdx][key] = tv.ToValueDelta() } @@ -4342,9 +4367,7 @@ func opAppLocalDel(cx *EvalContext) error { if err != nil { return err } - if _, ok := cx.txn.EvalDelta.LocalDeltas[accountIdx]; !ok { - cx.txn.EvalDelta.LocalDeltas[accountIdx] = basics.StateDelta{} - } + accountIdx = cx.ensureLocalDelta(accountIdx, addr) cx.txn.EvalDelta.LocalDeltas[accountIdx][key] = basics.ValueDelta{ Action: basics.DeleteAction, } @@ -4420,7 +4443,73 @@ func (cx *EvalContext) appReference(ref uint64, foreign bool) (basics.AppIndex, return basics.AppIndex(ref), nil } } - return basics.AppIndex(0), fmt.Errorf("invalid App reference %d", ref) + return 0, fmt.Errorf("invalid App reference %d", ref) +} + +// localsReference has the main job of resolving the account (as bytes or u64) +// and the App, taking access rules into account. It has the funny side job of +// also reporting which "slot" the address appears in, if it is in txn.Accounts +// (or is the Sender, which yields 0). But it only needs to do this funny side +// job in certainly old versions that need the slot index while doing a lookup. +func (cx *EvalContext) localsReference(account stackValue, ref uint64) (basics.Address, basics.AppIndex, uint64, error) { + if cx.version >= resourceSharingVersion { + unused := uint64(0) // see function comment + var addr basics.Address + var err error + if account.Bytes != nil { + addr, err = account.address() + } else { + addr, err = cx.txn.Txn.AddressByIndex(account.Uint, cx.txn.Txn.Sender) + } + if err != nil { + return basics.Address{}, 0, 0, err + } + aid := basics.AppIndex(ref) + if cx.available.allowsLocals(addr, aid) { + return addr, aid, unused, nil + } + if ref == 0 { + aid := cx.appID + if cx.available.allowsLocals(addr, aid) { + return addr, aid, unused, nil + } + } else if ref <= uint64(len(cx.txn.Txn.ForeignApps)) { + aid := cx.txn.Txn.ForeignApps[ref-1] + if cx.available.allowsLocals(addr, aid) { + return addr, aid, unused, nil + } + } + + // Do some extra lookups to give a more concise err. Whenever a locals + // is available, its account and app must be as well (but not vice + // versa, anymore). So, if (only) one of them is not available, yell + // about it, specifically. + + _, _, acctErr := cx.accountReference(account) + _, appErr := cx.appReference(ref, false) + switch { + case acctErr != nil && appErr == nil: + err = acctErr + case acctErr == nil && appErr != nil: + err = appErr + default: + err = fmt.Errorf("invalid Local State access %s x %d", addr, aid) + } + + return basics.Address{}, 0, 0, err + } + + // Pre group resource sharing, the rule is just that account and app are + // each available. + addr, addrIdx, err := cx.accountReference(account) + if err != nil { + return basics.Address{}, 0, 0, err + } + app, err := cx.appReference(ref, false) + if err != nil { + return basics.Address{}, 0, 0, err + } + return addr, app, addrIdx, nil } func (cx *EvalContext) assetReference(ref uint64, foreign bool) (basics.AssetIndex, error) { @@ -4448,7 +4537,7 @@ func (cx *EvalContext) assetReference(ref uint64, foreign bool) (basics.AssetInd return basics.AssetIndex(ref), nil } } - return basics.AssetIndex(0), fmt.Errorf("invalid Asset reference %d", ref) + return 0, fmt.Errorf("invalid Asset reference %d", ref) } @@ -4462,15 +4551,15 @@ func (cx *EvalContext) holdingReference(account stackValue, ref uint64) (basics. addr, err = cx.txn.Txn.AddressByIndex(account.Uint, cx.txn.Txn.Sender) } if err != nil { - return basics.Address{}, basics.AssetIndex(0), err + return basics.Address{}, 0, err } aid := basics.AssetIndex(ref) - if cx.availableHolding(addr, aid) { + if cx.available.allowsHolding(addr, aid) { return addr, aid, nil } if ref < uint64(len(cx.txn.Txn.ForeignAssets)) { aid := cx.txn.Txn.ForeignAssets[ref] - if cx.availableHolding(addr, aid) { + if cx.available.allowsHolding(addr, aid) { return addr, aid, nil } } @@ -4491,18 +4580,18 @@ func (cx *EvalContext) holdingReference(account stackValue, ref uint64) (basics. err = fmt.Errorf("invalid Holding access %s x %d", addr, aid) } - return basics.Address{}, basics.AssetIndex(0), err + return basics.Address{}, 0, err } // Pre group resource sharing, the rule is just that account and asset are // each available. addr, _, err := cx.accountReference(account) if err != nil { - return basics.Address{}, basics.AssetIndex(0), err + return basics.Address{}, 0, err } asset, err := cx.assetReference(ref, false) if err != nil { - return basics.Address{}, basics.AssetIndex(0), err + return basics.Address{}, 0, err } return addr, asset, nil } @@ -4532,7 +4621,6 @@ func opAssetHoldingGet(cx *EvalContext) error { return err } } - fmt.Printf("err=%v\n", err) cx.stack[prev] = value cx.stack[last].Uint = exist @@ -4755,12 +4843,12 @@ func opItxnNext(cx *EvalContext) error { // assignAccount is used to convert a stackValue into a 32-byte account value, // enforcing any "availability" restrictions in force. func (cx *EvalContext) assignAccount(sv stackValue) (basics.Address, error) { - addr, err := sv.address() + _, err := sv.address() if err != nil { return basics.Address{}, err } - addr, _, err = cx.accountReference(sv) + addr, _, err := cx.accountReference(sv) return addr, err } @@ -4769,7 +4857,7 @@ func (cx *EvalContext) assignAccount(sv stackValue) (basics.Address, error) { func (cx *EvalContext) assignAsset(sv stackValue) (basics.AssetIndex, error) { uint, err := sv.uint() if err != nil { - return basics.AssetIndex(0), err + return 0, err } aid := basics.AssetIndex(uint) @@ -4777,7 +4865,7 @@ func (cx *EvalContext) assignAsset(sv stackValue) (basics.AssetIndex, error) { return aid, nil } - return basics.AssetIndex(0), fmt.Errorf("invalid Asset reference %d", aid) + return 0, fmt.Errorf("invalid Asset reference %d", aid) } // availableAsset determines whether an asset is "available". Before @@ -4818,7 +4906,7 @@ func (cx *EvalContext) availableAsset(aid basics.AssetIndex) bool { func (cx *EvalContext) assignApp(sv stackValue) (basics.AppIndex, error) { uint, err := sv.uint() if err != nil { - return basics.AppIndex(0), err + return 0, err } aid := basics.AppIndex(uint) @@ -4859,40 +4947,6 @@ func (cx *EvalContext) availableApp(aid basics.AppIndex) bool { return false } -// availableHolding checks if a holding is available under the txgroup sharing rules -func (cx *EvalContext) availableHolding(addr basics.Address, ai basics.AssetIndex) bool { - if _, ok := cx.available.sharedHoldings[ledgercore.AccountAsset{Address: addr, Asset: ai}]; ok { - return true - } - // All holdings of created assets are available - for _, created := range cx.available.createdAsas { - if created == ai { - return true - } - } - return false -} - -// availableLocals is an additional check, required since -// resourceSharingVersion. It will work in previous versions too, since -// cx.available will be populated to make it work. But it must protect for < -// directRefEnabledVersion, because unnamed holdings could be read then. -func (cx *EvalContext) availableLocals(addr basics.Address, ai basics.AppIndex) bool { - if cx.version < directRefEnabledVersion { - return true - } - if _, ok := cx.available.sharedLocals[ledgercore.AccountApp{Address: addr, App: ai}]; ok { - return true - } - // All locals of created apps are available - for _, created := range cx.available.createdApps { - if created == ai { - return true - } - } - return false -} - func (cx *EvalContext) stackIntoTxnField(sv stackValue, fs *txnFieldSpec, txn *transactions.Transaction) (err error) { switch fs.field { case Type: @@ -5215,6 +5269,8 @@ func opItxnSubmit(cx *EvalContext) (err error) { return err } + var calledVersion uint64 + // Disallow reentrancy, limit inner app call depth, and do version checks if cx.subtxns[itx].Txn.Type == protocol.ApplicationCallTx { if cx.appID == cx.subtxns[itx].Txn.ApplicationID { @@ -5245,13 +5301,13 @@ func opItxnSubmit(cx *EvalContext) (err error) { } // Can't call old versions in inner apps. - v, _, err := transactions.ProgramVersion(program) + calledVersion, _, err = transactions.ProgramVersion(program) if err != nil { return err } - if v < cx.Proto.MinInnerApplVersion { + if calledVersion < cx.Proto.MinInnerApplVersion { return fmt.Errorf("inner app call with version v%d < v%d", - v, cx.Proto.MinInnerApplVersion) + calledVersion, cx.Proto.MinInnerApplVersion) } // Don't allow opt-in if the CSP is not runnable as an inner. @@ -5275,7 +5331,18 @@ func opItxnSubmit(cx *EvalContext) (err error) { csv, cx.Proto.MinInnerApplVersion) } } + } + // Starting in v9, it's possible for apps to create transactions that + // should not be allowed to run, because they require access to + // resources that the caller does not have. This can only happen for + // Holdings and Local States. The caller might have access to the + // account and the asa or app, but not the holding or locals, because + // the caller gained access to the two top resources by group sharing + // from two different transactions. + err = cx.available.allows(cx.EvalParams, &cx.subtxns[itx].Txn, cx.version, calledVersion) + if err != nil { + return err } if isGroup { diff --git a/data/transactions/logic/evalAppTxn_test.go b/data/transactions/logic/evalAppTxn_test.go index cdcced4301..3936e76b81 100644 --- a/data/transactions/logic/evalAppTxn_test.go +++ b/data/transactions/logic/evalAppTxn_test.go @@ -369,8 +369,12 @@ func TestAppAxfer(t *testing.T) { itxn_field TypeEnum itxn_submit ` + + was := ep.Proto.LogicSigVersion + ep.Proto.LogicSigVersion = 8 TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100"+noid+"int 1", ep, fmt.Sprintf("Sender (%s) not opted in to 0", appAddr(888))) + ep.Proto.LogicSigVersion = was TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100"+axfer+"int 1", ep) diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index 2c69715094..55bc8d949b 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -383,7 +383,7 @@ func TestBalance(t *testing.T) { } func testApps(t *testing.T, programs []string, txgroup []transactions.SignedTxn, version uint64, ledger *Ledger, - expected ...Expect) { + expected ...Expect) *EvalParams { t.Helper() codes := make([][]byte, len(programs)) for i, program := range programs { @@ -408,6 +408,7 @@ func testApps(t *testing.T, programs []string, txgroup []transactions.SignedTxn, ep.Ledger = ledger ep.SigLedger = ledger testAppsBytes(t, codes, ep, expected...) + return ep } func testAppsBytes(t *testing.T, programs [][]byte, ep *EvalParams, expected ...Expect) { @@ -2810,11 +2811,11 @@ int 695 testApp(t, source, defaultEvalParams()) } -func TestSelfMutate(t *testing.T) { +func TestSelfMutateV8(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - ep, _, ledger := makeSampleEnv() + ep, _, ledger := makeSampleEnvWithVersion(8) /* In order to test the added protection of mutableAccountReference, we're going to set up a ledger in which an app account is opted into @@ -2849,3 +2850,90 @@ int 77 ` testApp(t, source, ep) } + +func TestSelfMutateCurrent(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + ep, tx, ledger := makeSampleEnv() + + /* In order to test that apps can now mutate their own app's local state, + we're going to set up a ledger in which an app account is opted into + itself. */ + ledger.NewLocals(basics.AppIndex(888).Address(), 888) + ledger.NewLocal(basics.AppIndex(888).Address(), 888, "hey", + basics.TealValue{Type: basics.TealUintType, Uint: 77}) + + source := ` +global CurrentApplicationAddress +byte "hey" +int 42 +app_local_put +int 1 +` + ed := testApp(t, source, ep) + require.Len(t, ed.LocalDeltas, 1) + require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 + + require.Contains(t, ed.LocalDeltas, uint64(2)) + sd := ed.LocalDeltas[2] + require.Len(t, sd, 1) + require.Contains(t, sd, "hey") + require.EqualValues(t, 42, sd["hey"].Uint) + require.Len(t, ed.SharedAccts, 1) + require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) + + /* Confirm it worked. */ + source = ` +global CurrentApplicationAddress +byte "hey" +app_local_get +int 42 +== +` + testApp(t, source, ep) + + source = ` +global CurrentApplicationAddress +byte "hey" +app_local_del +int 1 +` + ed = testApp(t, source, ep) + require.Len(t, ed.LocalDeltas, 1) + require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 + + require.Contains(t, ed.LocalDeltas, uint64(2)) + sd = ed.LocalDeltas[2] + require.Len(t, sd, 1) + require.Contains(t, sd, "hey") + require.EqualValues(t, basics.DeleteAction, sd["hey"].Action) + require.Len(t, ed.SharedAccts, 1) + require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) + + // Now, repeat the "put" test with multiple keys, to ensure only one address is added to SharedAccts + source = ` +global CurrentApplicationAddress +byte "hey" +int 42 +app_local_put +global CurrentApplicationAddress +byte "joe" +int 21 +app_local_put +int 1 +` + ed = testApp(t, source, ep) + require.Len(t, ed.LocalDeltas, 1) + require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 + + require.Contains(t, ed.LocalDeltas, uint64(2)) + sd = ed.LocalDeltas[2] + require.Len(t, sd, 2) + require.Contains(t, sd, "hey") + require.EqualValues(t, 42, sd["hey"].Uint) + require.Contains(t, sd, "joe") + require.EqualValues(t, 21, sd["joe"].Uint) + require.Len(t, ed.SharedAccts, 1) + require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) +} diff --git a/data/transactions/logic/resources.go b/data/transactions/logic/resources.go index 3658ab1fcb..1ec61a1af8 100644 --- a/data/transactions/logic/resources.go +++ b/data/transactions/logic/resources.go @@ -17,6 +17,8 @@ package logic import ( + "fmt" + "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/transactions" "github.com/algorand/go-algorand/ledger/ledgercore" @@ -72,9 +74,9 @@ func (r *resources) shareLocal(addr basics.Address, id basics.AppIndex) { r.sharedLocals[ledgercore.AccountApp{Address: addr, App: id}] = struct{}{} } -// In the fill* routines, we pass the header and the fields in separately, even -// though they are pointers into the same structure. That prevents dumb attempts -// to use other fields from the transaction. +// In the fill* and allows* routines, we pass the header and the fields in +// separately, even though they are pointers into the same structure. That +// prevents dumb attempts to use other fields from the transaction. func (r *resources) fill(tx *transactions.Transaction, ep *EvalParams) { switch tx.Type { @@ -93,6 +95,22 @@ func (r *resources) fill(tx *transactions.Transaction, ep *EvalParams) { } } +func (r *resources) allows(ep *EvalParams, tx *transactions.Transaction, callerVer, calleeVer uint64) error { + switch tx.Type { + case protocol.PaymentTx, protocol.KeyRegistrationTx, protocol.AssetConfigTx: + // these transactions don't touch cross-product resources, so no error is possible + return nil + case protocol.AssetTransferTx: + return r.allowsAssetTransfer(&tx.Header, &tx.AssetTransferTxnFields) + case protocol.AssetFreezeTx: + return r.allowsAssetFreeze(&tx.Header, &tx.AssetFreezeTxnFields) + case protocol.ApplicationCallTx: + return r.allowsApplicationCall(ep, &tx.Header, &tx.ApplicationCallTxnFields, callerVer, calleeVer) + default: + return fmt.Errorf("unknown inner transaction type %s", tx.Type) + } +} + func (r *resources) fillKeyRegistration(hdr *transactions.Header) { r.sharedAccounts[hdr.Sender] = struct{}{} } @@ -106,7 +124,7 @@ func (r *resources) fillPayment(hdr *transactions.Header, tx *transactions.Payme } func (r *resources) fillAssetConfig(hdr *transactions.Header, tx *transactions.AssetConfigTxnFields) { - r.shareAccountAndHolding(hdr.Sender, tx.ConfigAsset) + r.sharedAccounts[hdr.Sender] = struct{}{} if id := tx.ConfigAsset; id != 0 { r.sharedAsas[id] = struct{}{} } @@ -128,6 +146,75 @@ func (r *resources) fillAssetTransfer(hdr *transactions.Header, tx *transactions } } +// allowsHolding checks if a holding is available under the txgroup sharing rules +func (r *resources) allowsHolding(addr basics.Address, ai basics.AssetIndex) bool { + if _, ok := r.sharedHoldings[ledgercore.AccountAsset{Address: addr, Asset: ai}]; ok { + return true + } + // All holdings of created assets are available + for _, created := range r.createdAsas { + if created == ai { + return true + } + } + return false +} + +// allowsLocals checks if a local state is available under the txgroup sharing rules +func (r *resources) allowsLocals(addr basics.Address, ai basics.AppIndex) bool { + if _, ok := r.sharedLocals[ledgercore.AccountApp{Address: addr, App: ai}]; ok { + return true + } + // All locals of created apps are available + for _, created := range r.createdApps { + if created == ai { + return true + } + } + return false +} + +func (r *resources) requireHolding(acct basics.Address, id basics.AssetIndex) error { + /* Previous versions allowed inner appls with zeros in "required" places, + even if that 0 resource should have be inaccessible, because the check + was done at itxn_field time, and maybe the app siimply didn't set the + field. */ + if id == 0 || acct.IsZero() { + return nil + } + if !r.allowsHolding(acct, id) { + return fmt.Errorf("invalid Holding access %s x %d", acct, id) + } + return nil +} + +func (r *resources) requireLocals(acct basics.Address, id basics.AppIndex) error { + if !r.allowsLocals(acct, id) { + return fmt.Errorf("invalid Local State access %s x %d", acct, id) + } + return nil +} + +func (r *resources) allowsAssetTransfer(hdr *transactions.Header, tx *transactions.AssetTransferTxnFields) error { + err := r.requireHolding(hdr.Sender, tx.XferAsset) + if err != nil { + return fmt.Errorf("axfer Sender: %v", err) + } + err = r.requireHolding(tx.AssetReceiver, tx.XferAsset) + if err != nil { + return fmt.Errorf("axfer AssetReceiver: %v", err) + } + err = r.requireHolding(tx.AssetSender, tx.XferAsset) + if err != nil { + return fmt.Errorf("axfer AssetSender: %v", err) + } + err = r.requireHolding(tx.AssetCloseTo, tx.XferAsset) + if err != nil { + return fmt.Errorf("axfer AssetCloseTo: %v", err) + } + return nil +} + func (r *resources) fillAssetFreeze(hdr *transactions.Header, tx *transactions.AssetFreezeTxnFields) { r.sharedAccounts[hdr.Sender] = struct{}{} id := tx.FreezeAsset @@ -135,6 +222,14 @@ func (r *resources) fillAssetFreeze(hdr *transactions.Header, tx *transactions.A r.shareAccountAndHolding(tx.FreezeAccount, id) } +func (r *resources) allowsAssetFreeze(hdr *transactions.Header, tx *transactions.AssetFreezeTxnFields) error { + err := r.requireHolding(tx.FreezeAccount, tx.FreezeAsset) + if err != nil { + return fmt.Errorf("afrz FreezeAccount: %v", err) + } + return nil +} + func (r *resources) fillApplicationCall(ep *EvalParams, hdr *transactions.Header, tx *transactions.ApplicationCallTxnFields) { txAccounts := make([]basics.Address, 0, 2+len(tx.Accounts)+len(tx.ForeignApps)) txAccounts = append(txAccounts, hdr.Sender) @@ -188,3 +283,46 @@ func (r *resources) fillApplicationCall(ep *EvalParams, hdr *transactions.Header r.boxes[boxRef{app, string(br.Name)}] = false } } + +func (r *resources) allowsApplicationCall(ep *EvalParams, hdr *transactions.Header, tx *transactions.ApplicationCallTxnFields, callerVer, calleeVer uint64) error { + // If an old (pre resorce sharing) app is being called from an app that has + // resource sharing enabled, we need to confirm that no new "cross-product" + // resources have become available. + if callerVer < resourceSharingVersion || calleeVer >= resourceSharingVersion { + return nil + } + + // This should closely match the `fillApplicationCall` routine, as the idea + // is to find all of the cross product resources this attempted call will + // have access to, and check that they are already available. + txAccounts := make([]basics.Address, 0, 2+len(tx.Accounts)+len(tx.ForeignApps)) + txAccounts = append(txAccounts, hdr.Sender) + txAccounts = append(txAccounts, tx.Accounts...) + if id := tx.ApplicationID; id != 0 { + txAccounts = append(txAccounts, ep.getApplicationAddress(id)) + } + for _, id := range tx.ForeignApps { + txAccounts = append(txAccounts, ep.getApplicationAddress(id)) + } + for _, address := range txAccounts { + for _, id := range tx.ForeignAssets { + err := r.requireHolding(address, id) + if err != nil { + return fmt.Errorf("appl ForeignAssets: %v", err) + } + } + if id := tx.ApplicationID; id != 0 { + err := r.requireLocals(address, id) + if err != nil { + return fmt.Errorf("appl ApplicationID: %v", err) + } + } + for _, id := range tx.ForeignApps { + err := r.requireLocals(address, id) + if err != nil { + return fmt.Errorf("appl ForeignApps: %v", err) + } + } + } + return nil +} diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 8617e56ad8..56b31e4469 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -25,9 +25,10 @@ import ( "github.com/algorand/go-algorand/data/txntest" "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" + "github.com/stretchr/testify/require" ) -// TestAppSharing confirms that as of v9, assets can be accessed across +// TestAppSharing confirms that as of v9, apps can be accessed across // groups, but that before then, they could not. func TestAppSharing(t *testing.T) { partitiontest.PartitionTest(t) @@ -89,9 +90,37 @@ pop; pop; int 1 logic.NewExpect(1, "invalid Local State access")) // But it's ok in appl2, because appl2 uses the same Sender, even though the - // foreign-app is not repeated in appl2 so the holding being accessed is is - // the one from tx0. + // foreign-app is not repeated in appl2 because the holding being accessed + // is the one from tx0. logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, ledger) + + // Now, confirm that *setting* a local state in tx1 that was made available + // in tx0 works. The extra check here is that the change is recorded + // properly in EvalDelta. + putLocal := ` +txn ApplicationArgs 0 +byte "X" +int 74 +app_local_put +int 1 +` + noop := `int 1` + sources = []string{noop, putLocal} + appl1.ApplicationArgs = [][]byte{appl0.Sender[:]} // tx1 will try to modify local state exposed in tx0 + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, ledger, + logic.NewExpect(1, "account "+appl0.Sender.String()+" is not opted into 888")) + ledger.NewLocals(appl0.Sender, 888) // opt in + ep := logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, ledger) + require.Len(t, ep.TxnGroup, 2) + ed := ep.TxnGroup[1].ApplyData.EvalDelta + require.Len(t, ed.LocalDeltas, 1) + require.Contains(t, ed.LocalDeltas, uint64(1)) // no tx.Accounts, 1 indicates first in SharedAccts + sd := ed.LocalDeltas[1] + require.Len(t, sd, 1) + require.Contains(t, sd, "X") + require.EqualValues(t, 74, sd["X"].Uint) + require.Len(t, ed.SharedAccts, 1) + require.Equal(t, ep.TxnGroup[0].Txn.Sender, ed.SharedAccts[0]) } // TestAssetSharing confirms that as of v9, assets can be accessed across @@ -328,16 +357,26 @@ itxn_begin txn ApplicationArgs 1; btoi; itxn_field XferAsset itxn_submit int 1 +` + + acfgArg := ` +itxn_begin + int acfg; itxn_field TypeEnum + txn ApplicationArgs 0; btoi; itxn_field ConfigAsset +itxn_submit +int 1 ` appl := txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: basics.Address{5, 5, 5, 5}, // different from all other accounts used + Type: protocol.ApplicationCallTx, + ApplicationID: 1234, + Sender: basics.Address{5, 5, 5, 5}, // different from all other accounts used } + appAcct := appl.ApplicationID.Address() // App will do a lot of txns. Start well funded. - ledger.NewAccount(basics.AppIndex(888).Address(), 1_000_000) + ledger.NewAccount(appAcct, 1_000_000) // And needs some ASAs for inner axfer testing - ledger.NewHolding(basics.AppIndex(888).Address(), asa1, 1_000_000, false) + ledger.NewHolding(appAcct, asa1, 1_000_000, false) t.Run("keyreg", func(t *testing.T) { keyreg := txntest.Txn{ @@ -390,17 +429,30 @@ int 1 AssetSender: otherAcct, } - // appl can pay or axfer to the sender + // appl can pay the axfer sender appl.ApplicationArgs = [][]byte{senderAcct[:], {asa1}} logic.TestApps(t, []string{"", payToArg}, txntest.Group(&axfer, &appl), 9, ledger) - logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger) + // bur can't axfer to them, because appAcct doesn't have holding access + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger, + logic.NewExpect(1, "invalid Holding access")) // and to the receiver appl.ApplicationArgs = [][]byte{receiverAcct[:], {asa1}} logic.TestApps(t, []string{payToArg}, txntest.Group(&appl, &axfer), 9, ledger) - logic.TestApps(t, []string{axferToArgs}, txntest.Group(&appl, &axfer), 9, ledger) + logic.TestApps(t, []string{axferToArgs}, txntest.Group(&appl, &axfer), 9, ledger, + logic.NewExpect(0, "invalid Holding access")) // and to the clawback appl.ApplicationArgs = [][]byte{otherAcct[:], {asa1}} logic.TestApps(t, []string{"", payToArg}, txntest.Group(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger, + logic.NewExpect(1, "invalid Holding access")) + + // Those axfers become possible by adding the asa to the appl's ForeignAssets + appl.ForeignAssets = []basics.AssetIndex{asa1} + appl.ApplicationArgs = [][]byte{senderAcct[:], {asa1}} + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger) + appl.ApplicationArgs = [][]byte{receiverAcct[:], {asa1}} + logic.TestApps(t, []string{axferToArgs}, txntest.Group(&appl, &axfer), 9, ledger) + appl.ApplicationArgs = [][]byte{otherAcct[:], {asa1}} logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger) // but can't axfer a different asset @@ -411,6 +463,91 @@ int 1 appl.ApplicationArgs = [][]byte{unusedAcct[:], {asa1}} logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger, logic.NewExpect(1, "invalid Account reference")) + + // appl can acfg the asset from tx0 (which requires asset available, not holding) + appl.ApplicationArgs = [][]byte{{asa1}} + logic.TestApps(t, []string{"", acfgArg}, txntest.Group(&axfer, &appl), 9, ledger) + appl.ApplicationArgs = [][]byte{{asa2}} // but not asa2 + logic.TestApps(t, []string{"", acfgArg}, txntest.Group(&axfer, &appl), 9, ledger, + logic.NewExpect(1, fmt.Sprintf("invalid Asset reference %d", asa2))) + + // Now, confirm that access to account from a pay in one tx, and asa + // from another don't allow inner axfer in the third (because there's no + // access to that payer's holding.) + payAcct := basics.Address{3, 2, 3, 2, 3, 2} + pay := txntest.Txn{ + Type: protocol.PaymentTx, + Sender: payAcct, + Receiver: payAcct, + } + // the asset is acfg-able + appl.ApplicationArgs = [][]byte{{asa1}} + logic.TestApps(t, []string{"", "", acfgArg}, txntest.Group(&pay, &axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", "", acfgArg}, txntest.Group(&axfer, &pay, &appl), 9, ledger) + // payAcct (the pay sender) is payable + appl.ApplicationArgs = [][]byte{payAcct[:]} + logic.TestApps(t, []string{"", "", payToArg}, txntest.Group(&axfer, &pay, &appl), 9, ledger) + // but the cross-product is not available, so no axfer (opting in first, to prevent that error) + ledger.NewHolding(payAcct, asa1, 1, false) + appl.ApplicationArgs = [][]byte{payAcct[:], {asa1}} + logic.TestApps(t, []string{"", "", axferToArgs}, txntest.Group(&axfer, &pay, &appl), 9, ledger, + logic.NewExpect(2, "invalid Holding access "+payAcct.String())) + }) + + t.Run("afrz", func(t *testing.T) { + appl.ForeignAssets = []basics.AssetIndex{} // reset after previous test + afrz := txntest.Txn{ + Type: protocol.AssetFreezeTx, + FreezeAsset: asa1, + Sender: senderAcct, + FreezeAccount: otherAcct, + } + + // appl can pay to the sender & freeze account + appl.ApplicationArgs = [][]byte{senderAcct[:], {asa1}} + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&afrz, &appl), 9, ledger) + appl.ApplicationArgs = [][]byte{otherAcct[:], {asa1}} + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&afrz, &appl), 9, ledger) + + // can't axfer to the afrz sender because appAcct holding is not available from afrz + appl.ApplicationArgs = [][]byte{senderAcct[:], {asa1}} + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&afrz, &appl), 9, ledger, + logic.NewExpect(1, "invalid Holding access "+appAcct.String())) + appl.ForeignAssets = []basics.AssetIndex{asa1} + // _still_ can't axfer to sender because afrz sender's holding does NOT + // become available (not note that complaint is now about that account) + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&afrz, &appl), 9, ledger, + logic.NewExpect(1, "invalid Holding access "+senderAcct.String())) + + // and not to the receiver which isn't in afrz + appl.ApplicationArgs = [][]byte{receiverAcct[:], {asa1}} + logic.TestApps(t, []string{payToArg}, txntest.Group(&appl, &afrz), 9, ledger, + logic.NewExpect(0, "invalid Account reference "+receiverAcct.String())) + logic.TestApps(t, []string{axferToArgs}, txntest.Group(&appl, &afrz), 9, ledger, + logic.NewExpect(0, "invalid Account reference "+receiverAcct.String())) + + // otherAcct is the afrz target, it's holding and account are available + appl.ApplicationArgs = [][]byte{otherAcct[:], {asa1}} + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&afrz, &appl), 9, ledger) + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&afrz, &appl), 9, ledger) + + // but still can't axfer a different asset + appl.ApplicationArgs = [][]byte{otherAcct[:], {asa2}} + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&afrz, &appl), 9, ledger, + logic.NewExpect(1, fmt.Sprintf("invalid Asset reference %d", asa2))) + appl.ForeignAssets = []basics.AssetIndex{asa2} + // once added to appl's foreign array, the appl still lacks access to other's holding + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&afrz, &appl), 9, ledger, + logic.NewExpect(1, "invalid Holding access "+otherAcct.String())) + + // appl can acfg the asset from tx0 (which requires asset available, not holding) + appl.ForeignAssets = []basics.AssetIndex{} + appl.ApplicationArgs = [][]byte{{asa1}} + logic.TestApps(t, []string{"", acfgArg}, txntest.Group(&afrz, &appl), 9, ledger) + appl.ApplicationArgs = [][]byte{{asa2}} // but not asa2 + logic.TestApps(t, []string{"", acfgArg}, txntest.Group(&afrz, &appl), 9, ledger, + logic.NewExpect(1, fmt.Sprintf("invalid Asset reference %d", asa2))) + }) } diff --git a/data/transactions/msgp_gen.go b/data/transactions/msgp_gen.go index 641e541c7b..a8c31a2c18 100644 --- a/data/transactions/msgp_gen.go +++ b/data/transactions/msgp_gen.go @@ -1875,33 +1875,37 @@ func (z *BoxRef) MsgIsZero() bool { func (z *EvalDelta) MarshalMsg(b []byte) (o []byte) { o = msgp.Require(b, z.Msgsize()) // omitempty: check for empty values - zb0005Len := uint32(4) - var zb0005Mask uint8 /* 5 bits */ + zb0006Len := uint32(5) + var zb0006Mask uint8 /* 6 bits */ if (*z).GlobalDelta.MsgIsZero() { - zb0005Len-- - zb0005Mask |= 0x2 + zb0006Len-- + zb0006Mask |= 0x2 } if len((*z).InnerTxns) == 0 { - zb0005Len-- - zb0005Mask |= 0x4 + zb0006Len-- + zb0006Mask |= 0x4 } if len((*z).LocalDeltas) == 0 { - zb0005Len-- - zb0005Mask |= 0x8 + zb0006Len-- + zb0006Mask |= 0x8 } if len((*z).Logs) == 0 { - zb0005Len-- - zb0005Mask |= 0x10 + zb0006Len-- + zb0006Mask |= 0x10 + } + if len((*z).SharedAccts) == 0 { + zb0006Len-- + zb0006Mask |= 0x20 } - // variable map header, size zb0005Len - o = append(o, 0x80|uint8(zb0005Len)) - if zb0005Len != 0 { - if (zb0005Mask & 0x2) == 0 { // if not empty + // variable map header, size zb0006Len + o = append(o, 0x80|uint8(zb0006Len)) + if zb0006Len != 0 { + if (zb0006Mask & 0x2) == 0 { // if not empty // string "gd" o = append(o, 0xa2, 0x67, 0x64) o = (*z).GlobalDelta.MarshalMsg(o) } - if (zb0005Mask & 0x4) == 0 { // if not empty + if (zb0006Mask & 0x4) == 0 { // if not empty // string "itx" o = append(o, 0xa3, 0x69, 0x74, 0x78) if (*z).InnerTxns == nil { @@ -1909,11 +1913,11 @@ func (z *EvalDelta) MarshalMsg(b []byte) (o []byte) { } else { o = msgp.AppendArrayHeader(o, uint32(len((*z).InnerTxns))) } - for zb0004 := range (*z).InnerTxns { - o = (*z).InnerTxns[zb0004].MarshalMsg(o) + for zb0005 := range (*z).InnerTxns { + o = (*z).InnerTxns[zb0005].MarshalMsg(o) } } - if (zb0005Mask & 0x8) == 0 { // if not empty + if (zb0006Mask & 0x8) == 0 { // if not empty // string "ld" o = append(o, 0xa2, 0x6c, 0x64) if (*z).LocalDeltas == nil { @@ -1933,7 +1937,7 @@ func (z *EvalDelta) MarshalMsg(b []byte) (o []byte) { o = zb0002.MarshalMsg(o) } } - if (zb0005Mask & 0x10) == 0 { // if not empty + if (zb0006Mask & 0x10) == 0 { // if not empty // string "lg" o = append(o, 0xa2, 0x6c, 0x67) if (*z).Logs == nil { @@ -1941,8 +1945,20 @@ func (z *EvalDelta) MarshalMsg(b []byte) (o []byte) { } else { o = msgp.AppendArrayHeader(o, uint32(len((*z).Logs))) } - for zb0003 := range (*z).Logs { - o = msgp.AppendString(o, (*z).Logs[zb0003]) + for zb0004 := range (*z).Logs { + o = msgp.AppendString(o, (*z).Logs[zb0004]) + } + } + if (zb0006Mask & 0x20) == 0 { // if not empty + // string "sa" + o = append(o, 0xa2, 0x73, 0x61) + if (*z).SharedAccts == nil { + o = msgp.AppendNil(o) + } else { + o = msgp.AppendArrayHeader(o, uint32(len((*z).SharedAccts))) + } + for zb0003 := range (*z).SharedAccts { + o = (*z).SharedAccts[zb0003].MarshalMsg(o) } } } @@ -1958,46 +1974,46 @@ func (_ *EvalDelta) CanMarshalMsg(z interface{}) bool { func (z *EvalDelta) UnmarshalMsg(bts []byte) (o []byte, err error) { var field []byte _ = field - var zb0005 int - var zb0006 bool - zb0005, zb0006, bts, err = msgp.ReadMapHeaderBytes(bts) + var zb0006 int + var zb0007 bool + zb0006, zb0007, bts, err = msgp.ReadMapHeaderBytes(bts) if _, ok := err.(msgp.TypeError); ok { - zb0005, zb0006, bts, err = msgp.ReadArrayHeaderBytes(bts) + zb0006, zb0007, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err) return } - if zb0005 > 0 { - zb0005-- + if zb0006 > 0 { + zb0006-- bts, err = (*z).GlobalDelta.UnmarshalMsg(bts) if err != nil { err = msgp.WrapError(err, "struct-from-array", "GlobalDelta") return } } - if zb0005 > 0 { - zb0005-- - var zb0007 int - var zb0008 bool - zb0007, zb0008, bts, err = msgp.ReadMapHeaderBytes(bts) + if zb0006 > 0 { + zb0006-- + var zb0008 int + var zb0009 bool + zb0008, zb0009, bts, err = msgp.ReadMapHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "struct-from-array", "LocalDeltas") return } - if zb0007 > config.MaxEvalDeltaAccounts { - err = msgp.ErrOverflow(uint64(zb0007), uint64(config.MaxEvalDeltaAccounts)) + if zb0008 > config.MaxEvalDeltaAccounts { + err = msgp.ErrOverflow(uint64(zb0008), uint64(config.MaxEvalDeltaAccounts)) err = msgp.WrapError(err, "struct-from-array", "LocalDeltas") return } - if zb0008 { + if zb0009 { (*z).LocalDeltas = nil } else if (*z).LocalDeltas == nil { - (*z).LocalDeltas = make(map[uint64]basics.StateDelta, zb0007) + (*z).LocalDeltas = make(map[uint64]basics.StateDelta, zb0008) } - for zb0007 > 0 { + for zb0008 > 0 { var zb0001 uint64 var zb0002 basics.StateDelta - zb0007-- + zb0008-- zb0001, bts, err = msgp.ReadUint64Bytes(bts) if err != nil { err = msgp.WrapError(err, "struct-from-array", "LocalDeltas") @@ -2011,66 +2027,95 @@ func (z *EvalDelta) UnmarshalMsg(bts []byte) (o []byte, err error) { (*z).LocalDeltas[zb0001] = zb0002 } } - if zb0005 > 0 { - zb0005-- - var zb0009 int - var zb0010 bool - zb0009, zb0010, bts, err = msgp.ReadArrayHeaderBytes(bts) + if zb0006 > 0 { + zb0006-- + var zb0010 int + var zb0011 bool + zb0010, zb0011, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "struct-from-array", "SharedAccts") + return + } + if zb0010 > 4 { + err = msgp.ErrOverflow(uint64(zb0010), uint64(4)) + err = msgp.WrapError(err, "struct-from-array", "SharedAccts") + return + } + if zb0011 { + (*z).SharedAccts = nil + } else if (*z).SharedAccts != nil && cap((*z).SharedAccts) >= zb0010 { + (*z).SharedAccts = ((*z).SharedAccts)[:zb0010] + } else { + (*z).SharedAccts = make([]basics.Address, zb0010) + } + for zb0003 := range (*z).SharedAccts { + bts, err = (*z).SharedAccts[zb0003].UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "struct-from-array", "SharedAccts", zb0003) + return + } + } + } + if zb0006 > 0 { + zb0006-- + var zb0012 int + var zb0013 bool + zb0012, zb0013, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "struct-from-array", "Logs") return } - if zb0009 > config.MaxLogCalls { - err = msgp.ErrOverflow(uint64(zb0009), uint64(config.MaxLogCalls)) + if zb0012 > config.MaxLogCalls { + err = msgp.ErrOverflow(uint64(zb0012), uint64(config.MaxLogCalls)) err = msgp.WrapError(err, "struct-from-array", "Logs") return } - if zb0010 { + if zb0013 { (*z).Logs = nil - } else if (*z).Logs != nil && cap((*z).Logs) >= zb0009 { - (*z).Logs = ((*z).Logs)[:zb0009] + } else if (*z).Logs != nil && cap((*z).Logs) >= zb0012 { + (*z).Logs = ((*z).Logs)[:zb0012] } else { - (*z).Logs = make([]string, zb0009) + (*z).Logs = make([]string, zb0012) } - for zb0003 := range (*z).Logs { - (*z).Logs[zb0003], bts, err = msgp.ReadStringBytes(bts) + for zb0004 := range (*z).Logs { + (*z).Logs[zb0004], bts, err = msgp.ReadStringBytes(bts) if err != nil { - err = msgp.WrapError(err, "struct-from-array", "Logs", zb0003) + err = msgp.WrapError(err, "struct-from-array", "Logs", zb0004) return } } } - if zb0005 > 0 { - zb0005-- - var zb0011 int - var zb0012 bool - zb0011, zb0012, bts, err = msgp.ReadArrayHeaderBytes(bts) + if zb0006 > 0 { + zb0006-- + var zb0014 int + var zb0015 bool + zb0014, zb0015, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "struct-from-array", "InnerTxns") return } - if zb0011 > config.MaxInnerTransactionsPerDelta { - err = msgp.ErrOverflow(uint64(zb0011), uint64(config.MaxInnerTransactionsPerDelta)) + if zb0014 > config.MaxInnerTransactionsPerDelta { + err = msgp.ErrOverflow(uint64(zb0014), uint64(config.MaxInnerTransactionsPerDelta)) err = msgp.WrapError(err, "struct-from-array", "InnerTxns") return } - if zb0012 { + if zb0015 { (*z).InnerTxns = nil - } else if (*z).InnerTxns != nil && cap((*z).InnerTxns) >= zb0011 { - (*z).InnerTxns = ((*z).InnerTxns)[:zb0011] + } else if (*z).InnerTxns != nil && cap((*z).InnerTxns) >= zb0014 { + (*z).InnerTxns = ((*z).InnerTxns)[:zb0014] } else { - (*z).InnerTxns = make([]SignedTxnWithAD, zb0011) + (*z).InnerTxns = make([]SignedTxnWithAD, zb0014) } - for zb0004 := range (*z).InnerTxns { - bts, err = (*z).InnerTxns[zb0004].UnmarshalMsg(bts) + for zb0005 := range (*z).InnerTxns { + bts, err = (*z).InnerTxns[zb0005].UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "struct-from-array", "InnerTxns", zb0004) + err = msgp.WrapError(err, "struct-from-array", "InnerTxns", zb0005) return } } } - if zb0005 > 0 { - err = msgp.ErrTooManyArrayFields(zb0005) + if zb0006 > 0 { + err = msgp.ErrTooManyArrayFields(zb0006) if err != nil { err = msgp.WrapError(err, "struct-from-array") return @@ -2081,11 +2126,11 @@ func (z *EvalDelta) UnmarshalMsg(bts []byte) (o []byte, err error) { err = msgp.WrapError(err) return } - if zb0006 { + if zb0007 { (*z) = EvalDelta{} } - for zb0005 > 0 { - zb0005-- + for zb0006 > 0 { + zb0006-- field, bts, err = msgp.ReadMapKeyZC(bts) if err != nil { err = msgp.WrapError(err) @@ -2099,27 +2144,27 @@ func (z *EvalDelta) UnmarshalMsg(bts []byte) (o []byte, err error) { return } case "ld": - var zb0013 int - var zb0014 bool - zb0013, zb0014, bts, err = msgp.ReadMapHeaderBytes(bts) + var zb0016 int + var zb0017 bool + zb0016, zb0017, bts, err = msgp.ReadMapHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "LocalDeltas") return } - if zb0013 > config.MaxEvalDeltaAccounts { - err = msgp.ErrOverflow(uint64(zb0013), uint64(config.MaxEvalDeltaAccounts)) + if zb0016 > config.MaxEvalDeltaAccounts { + err = msgp.ErrOverflow(uint64(zb0016), uint64(config.MaxEvalDeltaAccounts)) err = msgp.WrapError(err, "LocalDeltas") return } - if zb0014 { + if zb0017 { (*z).LocalDeltas = nil } else if (*z).LocalDeltas == nil { - (*z).LocalDeltas = make(map[uint64]basics.StateDelta, zb0013) + (*z).LocalDeltas = make(map[uint64]basics.StateDelta, zb0016) } - for zb0013 > 0 { + for zb0016 > 0 { var zb0001 uint64 var zb0002 basics.StateDelta - zb0013-- + zb0016-- zb0001, bts, err = msgp.ReadUint64Bytes(bts) if err != nil { err = msgp.WrapError(err, "LocalDeltas") @@ -2132,57 +2177,84 @@ func (z *EvalDelta) UnmarshalMsg(bts []byte) (o []byte, err error) { } (*z).LocalDeltas[zb0001] = zb0002 } + case "sa": + var zb0018 int + var zb0019 bool + zb0018, zb0019, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "SharedAccts") + return + } + if zb0018 > 4 { + err = msgp.ErrOverflow(uint64(zb0018), uint64(4)) + err = msgp.WrapError(err, "SharedAccts") + return + } + if zb0019 { + (*z).SharedAccts = nil + } else if (*z).SharedAccts != nil && cap((*z).SharedAccts) >= zb0018 { + (*z).SharedAccts = ((*z).SharedAccts)[:zb0018] + } else { + (*z).SharedAccts = make([]basics.Address, zb0018) + } + for zb0003 := range (*z).SharedAccts { + bts, err = (*z).SharedAccts[zb0003].UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "SharedAccts", zb0003) + return + } + } case "lg": - var zb0015 int - var zb0016 bool - zb0015, zb0016, bts, err = msgp.ReadArrayHeaderBytes(bts) + var zb0020 int + var zb0021 bool + zb0020, zb0021, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "Logs") return } - if zb0015 > config.MaxLogCalls { - err = msgp.ErrOverflow(uint64(zb0015), uint64(config.MaxLogCalls)) + if zb0020 > config.MaxLogCalls { + err = msgp.ErrOverflow(uint64(zb0020), uint64(config.MaxLogCalls)) err = msgp.WrapError(err, "Logs") return } - if zb0016 { + if zb0021 { (*z).Logs = nil - } else if (*z).Logs != nil && cap((*z).Logs) >= zb0015 { - (*z).Logs = ((*z).Logs)[:zb0015] + } else if (*z).Logs != nil && cap((*z).Logs) >= zb0020 { + (*z).Logs = ((*z).Logs)[:zb0020] } else { - (*z).Logs = make([]string, zb0015) + (*z).Logs = make([]string, zb0020) } - for zb0003 := range (*z).Logs { - (*z).Logs[zb0003], bts, err = msgp.ReadStringBytes(bts) + for zb0004 := range (*z).Logs { + (*z).Logs[zb0004], bts, err = msgp.ReadStringBytes(bts) if err != nil { - err = msgp.WrapError(err, "Logs", zb0003) + err = msgp.WrapError(err, "Logs", zb0004) return } } case "itx": - var zb0017 int - var zb0018 bool - zb0017, zb0018, bts, err = msgp.ReadArrayHeaderBytes(bts) + var zb0022 int + var zb0023 bool + zb0022, zb0023, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "InnerTxns") return } - if zb0017 > config.MaxInnerTransactionsPerDelta { - err = msgp.ErrOverflow(uint64(zb0017), uint64(config.MaxInnerTransactionsPerDelta)) + if zb0022 > config.MaxInnerTransactionsPerDelta { + err = msgp.ErrOverflow(uint64(zb0022), uint64(config.MaxInnerTransactionsPerDelta)) err = msgp.WrapError(err, "InnerTxns") return } - if zb0018 { + if zb0023 { (*z).InnerTxns = nil - } else if (*z).InnerTxns != nil && cap((*z).InnerTxns) >= zb0017 { - (*z).InnerTxns = ((*z).InnerTxns)[:zb0017] + } else if (*z).InnerTxns != nil && cap((*z).InnerTxns) >= zb0022 { + (*z).InnerTxns = ((*z).InnerTxns)[:zb0022] } else { - (*z).InnerTxns = make([]SignedTxnWithAD, zb0017) + (*z).InnerTxns = make([]SignedTxnWithAD, zb0022) } - for zb0004 := range (*z).InnerTxns { - bts, err = (*z).InnerTxns[zb0004].UnmarshalMsg(bts) + for zb0005 := range (*z).InnerTxns { + bts, err = (*z).InnerTxns[zb0005].UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "InnerTxns", zb0004) + err = msgp.WrapError(err, "InnerTxns", zb0005) return } } @@ -2215,19 +2287,23 @@ func (z *EvalDelta) Msgsize() (s int) { } } s += 3 + msgp.ArrayHeaderSize - for zb0003 := range (*z).Logs { - s += msgp.StringPrefixSize + len((*z).Logs[zb0003]) + for zb0003 := range (*z).SharedAccts { + s += (*z).SharedAccts[zb0003].Msgsize() + } + s += 3 + msgp.ArrayHeaderSize + for zb0004 := range (*z).Logs { + s += msgp.StringPrefixSize + len((*z).Logs[zb0004]) } s += 4 + msgp.ArrayHeaderSize - for zb0004 := range (*z).InnerTxns { - s += (*z).InnerTxns[zb0004].Msgsize() + for zb0005 := range (*z).InnerTxns { + s += (*z).InnerTxns[zb0005].Msgsize() } return } // MsgIsZero returns whether this is a zero value func (z *EvalDelta) MsgIsZero() bool { - return ((*z).GlobalDelta.MsgIsZero()) && (len((*z).LocalDeltas) == 0) && (len((*z).Logs) == 0) && (len((*z).InnerTxns) == 0) + return ((*z).GlobalDelta.MsgIsZero()) && (len((*z).LocalDeltas) == 0) && (len((*z).SharedAccts) == 0) && (len((*z).Logs) == 0) && (len((*z).InnerTxns) == 0) } // MarshalMsg implements msgp.Marshaler diff --git a/data/transactions/teal.go b/data/transactions/teal.go index 9472fd3b92..dafd10ea8d 100644 --- a/data/transactions/teal.go +++ b/data/transactions/teal.go @@ -32,9 +32,11 @@ type EvalDelta struct { GlobalDelta basics.StateDelta `codec:"gd"` // When decoding EvalDeltas, the integer key represents an offset into - // [txn.Sender, txn.Accounts[0], txn.Accounts[1], ...] + // [txn.Sender, txn.Accounts[0], txn.Accounts[1], ..., SharedAccts[0], SharedAccts[1], ...] LocalDeltas map[uint64]basics.StateDelta `codec:"ld,allocbound=config.MaxEvalDeltaAccounts"` + SharedAccts []basics.Address `codec:"sa,allocbound=4"` + Logs []string `codec:"lg,allocbound=config.MaxLogCalls"` InnerTxns []SignedTxnWithAD `codec:"itx,allocbound=config.MaxInnerTransactionsPerDelta"` diff --git a/ledger/internal/cow.go b/ledger/internal/cow.go index ade61f8204..8d2eb113ca 100644 --- a/ledger/internal/cow.go +++ b/ledger/internal/cow.go @@ -84,10 +84,10 @@ type roundCowState struct { // must be incorporated into mods.accts before passing deltas forward sdeltas map[basics.Address]map[storagePtr]*storageDelta - // either or not maintain compatibility with original app refactoring behavior + // whether or not to maintain compatibility with original app refactoring behavior // this is needed for generating old eval delta in new code compatibilityMode bool - // cache mainaining accountIdx used in getKey for local keys access + // cache maintaining accountIdx used in getKey for local keys access compatibilityGetKeyCache map[basics.Address]map[storagePtr]uint64 // prevTotals contains the accounts totals for the previous round. It's being used to calculate the totals for the new round From 726be12bf2bb64a28049e3081b26663f37bc2d5b Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 2 Feb 2023 13:22:28 -0500 Subject: [PATCH 06/29] Account for "shared" indexes in EvalDelta --- agreement/msgp_gen.go | 16 ++++++++-------- daemon/algod/api/server/v2/utils.go | 17 ++++++++++------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/agreement/msgp_gen.go b/agreement/msgp_gen.go index 8a3fc90705..bf1c46f98c 100644 --- a/agreement/msgp_gen.go +++ b/agreement/msgp_gen.go @@ -3555,10 +3555,10 @@ func (z *player) MarshalMsg(b []byte) (o []byte) { // map header, size 8 // string "Deadline" o = append(o, 0x88, 0xa8, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65) - o = (*z).Deadline.MarshalMsg(o) + o = msgp.AppendDuration(o, (*z).Deadline) // string "FastRecoveryDeadline" o = append(o, 0xb4, 0x46, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65) - o = (*z).FastRecoveryDeadline.MarshalMsg(o) + o = msgp.AppendDuration(o, (*z).FastRecoveryDeadline) // string "LastConcluding" o = append(o, 0xae, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67) o = msgp.AppendUint64(o, uint64((*z).LastConcluding)) @@ -3644,7 +3644,7 @@ func (z *player) UnmarshalMsg(bts []byte) (o []byte, err error) { } if zb0001 > 0 { zb0001-- - bts, err = (*z).Deadline.UnmarshalMsg(bts) + (*z).Deadline, bts, err = msgp.ReadDurationBytes(bts) if err != nil { err = msgp.WrapError(err, "struct-from-array", "Deadline") return @@ -3660,7 +3660,7 @@ func (z *player) UnmarshalMsg(bts []byte) (o []byte, err error) { } if zb0001 > 0 { zb0001-- - bts, err = (*z).FastRecoveryDeadline.UnmarshalMsg(bts) + (*z).FastRecoveryDeadline, bts, err = msgp.ReadDurationBytes(bts) if err != nil { err = msgp.WrapError(err, "struct-from-array", "FastRecoveryDeadline") return @@ -3734,7 +3734,7 @@ func (z *player) UnmarshalMsg(bts []byte) (o []byte, err error) { (*z).LastConcluding = step(zb0008) } case "Deadline": - bts, err = (*z).Deadline.UnmarshalMsg(bts) + (*z).Deadline, bts, err = msgp.ReadDurationBytes(bts) if err != nil { err = msgp.WrapError(err, "Deadline") return @@ -3746,7 +3746,7 @@ func (z *player) UnmarshalMsg(bts []byte) (o []byte, err error) { return } case "FastRecoveryDeadline": - bts, err = (*z).FastRecoveryDeadline.UnmarshalMsg(bts) + (*z).FastRecoveryDeadline, bts, err = msgp.ReadDurationBytes(bts) if err != nil { err = msgp.WrapError(err, "FastRecoveryDeadline") return @@ -3777,13 +3777,13 @@ func (_ *player) CanUnmarshalMsg(z interface{}) bool { // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *player) Msgsize() (s int) { - s = 1 + 6 + (*z).Round.Msgsize() + 7 + msgp.Uint64Size + 5 + msgp.Uint64Size + 15 + msgp.Uint64Size + 9 + (*z).Deadline.Msgsize() + 8 + msgp.BoolSize + 21 + (*z).FastRecoveryDeadline.Msgsize() + 8 + (*z).Pending.Msgsize() + s = 1 + 6 + (*z).Round.Msgsize() + 7 + msgp.Uint64Size + 5 + msgp.Uint64Size + 15 + msgp.Uint64Size + 9 + msgp.DurationSize + 8 + msgp.BoolSize + 21 + msgp.DurationSize + 8 + (*z).Pending.Msgsize() return } // MsgIsZero returns whether this is a zero value func (z *player) MsgIsZero() bool { - return ((*z).Round.MsgIsZero()) && ((*z).Period == 0) && ((*z).Step == 0) && ((*z).LastConcluding == 0) && ((*z).Deadline.MsgIsZero()) && ((*z).Napping == false) && ((*z).FastRecoveryDeadline.MsgIsZero()) && ((*z).Pending.MsgIsZero()) + return ((*z).Round.MsgIsZero()) && ((*z).Period == 0) && ((*z).Step == 0) && ((*z).LastConcluding == 0) && ((*z).Deadline == 0) && ((*z).Napping == false) && ((*z).FastRecoveryDeadline == 0) && ((*z).Pending.MsgIsZero()) } // MarshalMsg implements msgp.Marshaler diff --git a/daemon/algod/api/server/v2/utils.go b/daemon/algod/api/server/v2/utils.go index b2b4e4a351..7b73c1df9c 100644 --- a/daemon/algod/api/server/v2/utils.go +++ b/daemon/algod/api/server/v2/utils.go @@ -277,18 +277,21 @@ func convertToDeltas(txn node.TxnWithStatus) (*[]model.AccountStateDelta, *model if len(txn.ApplyData.EvalDelta.LocalDeltas) > 0 { d := make([]model.AccountStateDelta, 0) accounts := txn.Txn.Txn.Accounts + shared := txn.ApplyData.EvalDelta.SharedAccts for k, v := range txn.ApplyData.EvalDelta.LocalDeltas { // Resolve address from index var addr string - if k == 0 { + // k is an index into [Sender, accounts[0], accounts[1], ..., shared[0], shared[1], ...] + switch { + case k == 0: addr = txn.Txn.Txn.Sender.String() - } else { - if int(k-1) < len(accounts) { - addr = txn.Txn.Txn.Accounts[k-1].String() - } else { - addr = fmt.Sprintf("Invalid Address Index: %d", k-1) - } + case int(k-1) < len(accounts): + addr = txn.Txn.Txn.Accounts[k-1].String() + case int(k-1)-len(accounts) < len(shared): + addr = shared[int(k-1)-len(accounts)].String() + default: + addr = fmt.Sprintf("Invalid Account Index %d in LocalDelta", k) } d = append(d, model.AccountStateDelta{ Address: addr, From a48886e73f64398de8ecf03cd1de6ad1770932a3 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 2 Feb 2023 13:28:04 -0500 Subject: [PATCH 07/29] oas2 fixups --- daemon/algod/api/algod.oas2.json | 12 +- daemon/algod/api/algod.oas3.yml | 4 +- .../api/server/v2/generated/data/routes.go | 74 +++ .../v2/generated/experimental/routes.go | 335 +++++++++++++ .../api/server/v2/generated/model/types.go | 4 +- .../nonparticipating/private/routes.go | 68 +++ .../nonparticipating/public/routes.go | 448 ++++++++++++++++++ .../generated/participating/private/routes.go | 71 +++ .../generated/participating/public/routes.go | 354 ++++++++++++++ 9 files changed, 1360 insertions(+), 10 deletions(-) diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json index ed48f36663..2cd586b51a 100644 --- a/daemon/algod/api/algod.oas2.json +++ b/daemon/algod/api/algod.oas2.json @@ -2943,15 +2943,15 @@ "type": "integer" }, "local-state-schema": { - "description": "[\\lsch\\] local schema", + "description": "\\[lsch\\] local schema", "$ref": "#/definitions/ApplicationStateSchema" }, "global-state-schema": { - "description": "[\\gsch\\] global schema", + "description": "\\[gsch\\] global schema", "$ref": "#/definitions/ApplicationStateSchema" }, "global-state": { - "description": "[\\gs\\] global schema", + "description": "\\[gs\\] global schema", "$ref": "#/definitions/TealKeyValueStore" } } @@ -3321,18 +3321,18 @@ "type": "integer" }, "local-state-delta": { - "description": "\\[ld\\] Local state key/value changes for the application being executed by this transaction.", + "description": "Local state key/value changes for the application being executed by this transaction.", "type": "array", "items": { "$ref": "#/definitions/AccountStateDelta" } }, "global-state-delta": { - "description": "\\[gd\\] Global state key/value changes for the application being executed by this transaction.", + "description": "Global state key/value changes for the application being executed by this transaction.", "$ref": "#/definitions/StateDelta" }, "logs": { - "description": "\\[lg\\] Logs for the application being executed by this transaction.", + "description": "Logs for the application being executed by this transaction.", "type": "array", "items": { "type": "string", diff --git a/daemon/algod/api/algod.oas3.yml b/daemon/algod/api/algod.oas3.yml index 846f60a156..1910d46cf2 100644 --- a/daemon/algod/api/algod.oas3.yml +++ b/daemon/algod/api/algod.oas3.yml @@ -1795,14 +1795,14 @@ "type": "array" }, "local-state-delta": { - "description": "\\[ld\\] Local state key/value changes for the application being executed by this transaction.", + "description": "Local state key/value changes for the application being executed by this transaction.", "items": { "$ref": "#/components/schemas/AccountStateDelta" }, "type": "array" }, "logs": { - "description": "\\[lg\\] Logs for the application being executed by this transaction.", + "description": "Logs for the application being executed by this transaction.", "items": { "format": "byte", "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$", diff --git a/daemon/algod/api/server/v2/generated/data/routes.go b/daemon/algod/api/server/v2/generated/data/routes.go index 4556670809..d2193d9a1a 100644 --- a/daemon/algod/api/server/v2/generated/data/routes.go +++ b/daemon/algod/api/server/v2/generated/data/routes.go @@ -278,6 +278,7 @@ var swaggerSpec = []string{ "XQELTNqrHQW+lAUo/5vP0LWj5OwCwleB0C1zSWXmW0TtDN6EkYycR730Ll/wvov0sh6ZNUGa/YSeSOEn", "DMVNc2H0r2QonrkdFxk+no/RH7bkN0Z8GryWIN3raajs5UJBooUP6hzDY4wU7qH3mxBBDRZbtMgNlkB5", "29R4waKzFEueUBfZEk6QSCiowU4GlViGxxwj9gv73Wew+KKje80pNb/uLzTvw3OZ6hEx5Polcafl/syY", +<<<<<<< HEAD "m1hWGOf2rVYVK8vCDSlD038pRVal9oAON0ZtfZpc9GhElESNEml/lr37ZY4lwF4FeYYXsDu0qr8v1e+X", "MsTeqlB2DkFef2e179ToFL9f5ys7gdWd4Pk5DTfzWSlEngzY+k/71WW6e+CCpReQEXN2+MC2gWdLyH00", "MdfO3Mv1zldTKUvgkD04IOSE21Bi79dtlzfuDM7v6bHxtzhqVtmCT86mdPCex2MysRSTvKV882DGpZoC", @@ -313,6 +314,79 @@ var swaggerSpec = []string{ "0H3gM/bz4cf2AzMt455aVzoTl0FfdAjbaIa+za9+crH19+ElZTpZCumyPLAAcL+zBpofuvolnV+blOHe", "F8yDDn4MQ7Sivx7W9dWjH7uG19hXZ3gcaOSrT/nPjeMldGSghKxdGO8+GPmE1Tud8Gzs8seHhxg5vRZK", "H86u5h87Nvvw44eaJXxZt1kp2QazxD9c/f8AAAD//8pjb+JPxQAA", +||||||| constructed merge base + "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", + "Er5i26yUbIMJ4B+u/n8AAAD//y/FazkqxQAA", +======= + "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", + "7v3h6v8HAAD//xIUAlAYxQAA", +>>>>>>> oas2 fixups } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/experimental/routes.go b/daemon/algod/api/server/v2/generated/experimental/routes.go index 3e8edb58bd..af4ebe9e41 100644 --- a/daemon/algod/api/server/v2/generated/experimental/routes.go +++ b/daemon/algod/api/server/v2/generated/experimental/routes.go @@ -75,6 +75,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ +<<<<<<< HEAD "H4sIAAAAAAAC/+x9+3PcNtLgv4Ka76vy44aS/Ih3rarUd4qdZHVxHJelZO9by5dgyJ4ZrEiAAUDNTHz6", "36/QAEiQBDnUI/Zu1f1kawg0Go1Go9EvfJqloigFB67V7PjTrKSSFqBB4l80TUXFdcIy81cGKpWs1Ezw", "2bH/RpSWjK9m8xkzv5ZUr2fzGacFNG1M//lMwu8Vk5DNjrWsYD5T6RoKagDrXWla15C2yUokDsSJBXH6", @@ -235,6 +236,340 @@ var swaggerSpec = []string{ "9qnffYki9vPhp3Yl1BYXqnWlM7EJ+uLNxV67++PVbwO0/j7cUKaNLuLCEbBSTb+zBpofukSbzq9NbGvv", "CwbsBj+236uP/HpYFwKLfuxKiNhXt0MGGvk0Sf+50RDCE3d2/CE4az98vP5ovknTGj81B8jx4SG6+NZC", "6cPZ9fxT53AJP36secznH89Kya4wnPnj9f8LAAD//+4FyDz4swAA", +||||||| constructed merge base + "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", + "vwAA", +======= + "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", +>>>>>>> oas2 fixups } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/model/types.go b/daemon/algod/api/server/v2/generated/model/types.go index 5837057832..3e0716ae85 100644 --- a/daemon/algod/api/server/v2/generated/model/types.go +++ b/daemon/algod/api/server/v2/generated/model/types.go @@ -589,10 +589,10 @@ type PendingTransactionResponse struct { // InnerTxns Inner transactions produced by application execution. InnerTxns *[]PendingTransactionResponse `json:"inner-txns,omitempty"` - // LocalStateDelta \[ld\] Local state key/value changes for the application being executed by this transaction. + // LocalStateDelta Local state key/value changes for the application being executed by this transaction. LocalStateDelta *[]AccountStateDelta `json:"local-state-delta,omitempty"` - // Logs \[lg\] Logs for the application being executed by this transaction. + // Logs Logs for the application being executed by this transaction. Logs *[][]byte `json:"logs,omitempty"` // PoolError Indicates that the transaction was kicked out of this node's transaction pool (and specifies why that happened). An empty string indicates the transaction wasn't kicked out of this node's txpool due to an error. diff --git a/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go b/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go index 5bf532b490..b89b4db42e 100644 --- a/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go +++ b/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go @@ -263,6 +263,7 @@ var swaggerSpec = []string{ "V66ABSbt1Y4CX8oCtP/NZ+jSKLm4gPBVIHTLXPEy8y2idgZvwki2nEe99C5f8L6L9LweWTRBmv2Enkjh", "JwzFTXNl9a9kKJ65HRcZPp6P0R9U8hsjPi1ecyjd62mo7OVKQ2KUD+rchsc2UriH3m9CBD1YbJGQGyyB", "8q6p8YJFZzmWPOEusiWcICthxS12ZVCJZXjMbcR+Sd99BosvOrrTnFLz6+5C8z48V+geEUOunzN3Wu7O", +<<<<<<< HEAD "jLmJZUVISW+16lhZFmlJGZr+i1JlVUoHdLgxauvT6KJHW0RJ1CiR9mfZu1/mWALsdZBneAGbQ1L9fal+", "v5Qh9qRC0RyCvP7Oat+p0Sl+v84XNIHFneD5JQ0300mhVJ4M2PpP+9VlunvgQqQXkDF7dvjAtoFnS9h9", "NDHXztyr5cZXUykKkJA9OGDsRFIosffrtssbdwaX98y28dc4alZRwSdnUzr4IOMxmViKqbylfPNgtks1", @@ -295,6 +296,73 @@ var swaggerSpec = []string{ "DlXnWHKYvVEZ9I8lPHh+q6DcNCePw3Eybcklx1iRMnm3FvN9MXK9H9uhaZz8On3mqB+fav19eMWFsYeX", "i3dFivY7G+D5ocvk7vzaJE/1vmBGWPBj6KyO/npYV5qNfuxeQWNf3RVsoJGvw+E/Nyao0KSDLFEbc95/", "tCuLdcwctzQWiuPDQ4whWyptDifX008d60X48WO9mL7ATb2o1x+v/ycAAP//m8e6KFm+AAA=", +||||||| constructed merge base + "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", +======= + "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", +>>>>>>> oas2 fixups } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go b/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go index c5e3638286..7d9661be67 100644 --- a/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go +++ b/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go @@ -572,6 +572,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ +<<<<<<< HEAD "H4sIAAAAAAAC/+x9a3Mbt5LoX0Fxt8qP5VB+Zk9Uldor23loYzsuS8nuObFvAs40SRwNgTkARiLj6/9+", "Cw1gBjODIYcSLdmJPtni4NFoNBqNfn4YpWJZCA5cq9Hhh1FBJV2CBol/0TQVJdcJy8xfGahUskIzwUeH", "/htRWjI+H41HzPxaUL0YjUecLqFuY/qPRxL+VTIJ2ehQyxLGI5UuYEnNwHpdmNbVSKtkLhI3xJEd4vjF", @@ -800,6 +801,453 @@ var swaggerSpec = []string{ "Ntq50W7r0n/WBRU+5SPhU6/mU705PDNWhGLV3vA8t3Ii2uNNFWHa8bwpEDineYk80WV9dy/xCTmtOWbl", "610ql4w0XVDGXQ6aKioB4dAuYbL2GRr3pZakF3rFnVbSMj9URxpsQFpKptf4HKEF++0MzP/fG3neVhG1", "L5VS5qPD0ULr4vDgAAvvL4TSB6OP4/Cban18X4H/wT8yCsnOsQ7P+4//PwAA//+FikGliEkBAA==", +||||||| constructed merge base + "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", +======= + "H4sIAAAAAAAC/+x9a3PbuJLoX0FptyqPFeW898RVU3udZB7eSTKp2DO754xzZyCyJeGYAngA0JYmN//9", + "FhoACZKgRNmOncz4U2IRj0aj0Wj08+MoFctCcOBajfY/jgoq6RI0SPyLpqkouU5YZv7KQKWSFZoJPtr3", + "34jSkvH5aDxi5teC6sVoPOJ0CXUb0388kvCvkknIRvtaljAeqXQBS2oG1uvCtK5GWiVzkbghDuwQh69G", + "nzZ8oFkmQakulD/xfE0YT/MyA6Il5Yqm5pMi50wviF4wRVxnwjgRHIiYEb1oNCYzBnmmJn6R/ypBroNV", + "usn7l/SpBjGRIocunC/Fcso4eKigAqraEKIFyWCGjRZUEzODgdU31IIooDJdkJmQW0C1QITwAi+Xo/1f", + "Rwp4BhJ3KwV2hv+dSYA/INFUzkGPPoxji5tpkIlmy8jSDh32Jagy14pgW1zjnJ0BJ6bXhLwplSZTIJST", + "99+9JI8fP35uFrKkWkPmiKx3VfXs4Zps99H+KKMa/OcurdF8LiTlWVK1f//dS5z/yC1waCuqFMQPy4H5", + "Qg5f9S3Ad4yQEOMa5rgPDeo3PSKHov55CjMhYeCe2MZXuinh/De6KynV6aIQjOvIvhD8SuznKA8Lum/i", + "YRUAjfaFwZQ0g/76IHn+4ePD8cMHn/7t14PkH+7Pp48/DVz+y2rcLRiINkxLKYGn62QugeJpWVDexcd7", + "Rw9qIco8Iwt6hptPl8jqXV9i+lrWeUbz0tAJS6U4yOdCEerIKIMZLXNN/MSk5LlhU2Y0R+2EKVJIccYy", + "yMaG+54vWLogKVV2CGxHzlmeGxosFWR9tBZf3YbD9ClEiYHrQvjABX25yKjXtQUTsEJukKS5UJBoseV6", + "8jcO5RkJL5T6rlK7XVbkeAEEJzcf7GWLuOOGpvN8TTTua0aoIpT4q2lM2IysRUnOcXNydor93WoM1pbE", + "IA03p3GPmsPbh74OMiLImwqRA+WIPH/uuijjMzYvJShyvgC9cHeeBFUIroCI6T8h1Wbb//vop7dESPIG", + "lKJzeEfTUwI8FRlkE3I4I1zogDQcLSEOTc++dTi4Ypf8P5UwNLFU84Kmp/EbPWdLFlnVG7piy3JJeLmc", + "gjRb6q8QLYgEXUreB5AdcQspLumqO+mxLHmK+19P25DlDLUxVeR0jQhb0tU3D8YOHEVonpMCeMb4nOgV", + "75XjzNzbwUukKHk2QMzRZk+Di1UVkLIZg4xUo2yAxE2zDR7Gd4OnFr4CcPwgveBUs2wBh8MqQjPmdJsv", + "pKBzCEhmQn52zA2/anEKvCJ0Ml3jp0LCGROlqjr1wIhTb5bAudCQFBJmLEJjRw4dhsHYNo4DL50MlAqu", + "KeOQGeaMQAsNlln1whRMuPm9073Fp1TBsyd9d3z9deDuz0R71zfu+KDdxkaJPZKRq9N8dQc2Llk1+g94", + "H4ZzKzZP7M+djWTzY3PbzFiON9E/zf55NJQKmUADEf5uUmzOqS4l7J/w++YvkpAjTXlGZWZ+Wdqf3pS5", + "Zkdsbn7K7U+vxZylR2zeg8wK1uiDC7st7T9mvDg71qvou+K1EKdlES4obTxcp2ty+Kpvk+2YuxLmQfXa", + "DR8exyv/GNm1h15VG9kDZC/uCmoansJagoGWpjP8ZzVDeqIz+Yf5pyhy01sXsxhqDR27KxnVB06tcFAU", + "OUupQeJ799l8NUwA7EOC1i328ELd/xiAWEhRgNTMDkqLIslFSvNEaapxpH+XMBvtj/5tr9a/7Nnuai+Y", + "/LXpdYSdjMhqxaCEFsUOY7wzoo/awCwMg8ZPyCYs20OhiXG7iYaUmGHBOZxRrif1k6XBD6oD/Kubqca3", + "lXYsvltPsF6EE9twCspKwLbhHUUC1BNEK0G0okA6z8W0+uHuQVHUGMTvB0Vh8YHSIzAUzGDFlFb3cPm0", + "PknhPIevJuT7cGwUxQXP1+ZysKKGuRtm7tZyt1ilW3JrqEe8owhup5ATszUeDUbMvwqKw2fFQuRG6tlK", + "K6bxD65tSGbm90Gdvw4SC3HbT1z40HKYs28c/CV43NxtUU6XcJy6Z0IO2n0vRjZmlDjBXIhWNu6nHXcD", + "HisUnktaWADdF3uXMo6PNNvIwnpJbjqQ0UVhDs5wQGsI1YXP2tbzEIUESaEFw4tcpKc/ULW4gjM/9WN1", + "jx9OQxZAM5BkQdViMopJGeHxqkcbcsRMQ3zgk2kw1aRa4lUtb8vSMqppsDQHb1wssajHfsj0QEbeLj/h", + "f2hOzGdztg3rt8NOyDEyMGWPszMyZOa1bx8IdibTALUQgiztA5+YV/dOUL6sJ4/v06A9+tbqFNwOuUXg", + "DonVlR+DF2IVg+GFWHWOgFiBugr6MOOgGKlhqQbA98pBJnD/HfqolHTdRTKOPQTJZoFGdFV4Gnh445tZ", + "auXswVTIi3GfFlvhpFY5E2pGDZjvuIUkbFoWiSPFiNrKNmgNVFv5NjON9vAxjDWwcKTpZ8CCMqNeBRaa", + "A101FsSyYDlcAekvokx/ShU8fkSOfjh4+vDRb4+ePjMkWUgxl3RJpmsNitx1bzOi9DqHe92V4euozHV8", + "9GdPvKKyOW5sHCVKmcKSFt2hrALUikC2GTHtulhrohlXXQE45HAeg+HkFu3E6vYNaK+YMhLWcnolm9GH", + "sKyeJSMOkgy2EtOuy6unWYdLlGtZXsVTFqQUMqJfwyOmRSry5AykYiJiTXnnWhDXwou3Rft3Cy05p4qY", + "uVH1W3IUKCKUpVd8ON+3Qx+veI2bjZzfrjeyOjfvkH1pIt9rEhUpQCZ6xUkG03LeeAnNpFgSSjLsiHf0", + "96CP1jxFrdpVEGn/M23JOKr41ZqnwZvNbFQO2byxCZd/m7Wx4vVzdqo7KgKOQcdr/IzP+leQa3rl8kt7", + "ghjsL/1GWmBJZhriK/g1my90IGC+k0LMrh7G2CwxQPGDFc9z06crpL8VGZjFluoKLuN6sJrWzZ6GFE6n", + "otSEEi4yQI1KqeLXdI/lHk2GaOnU4c2vF1binoIhpJSWZrVlQdCO1+EcdceEppZ6E0SN6rFiVOYn28pO", + "Z63CuQSamVc9cCKmzlTgjBi4SIpGSO0vOickRM5SA65CihSUgixxKoqtoPl2lonoDXhCwBHgahaiBJlR", + "eWlgT8+2wnkK6wRN5orc/fEXde8G4NVC03wLYrFNDL3Vg8/Zg7pQD5t+E8G1Jw/Jjkognuea16VhEDlo", + "6EPhTjjp3b82RJ1dvDxazkCiZeazUryf5HIEVIH6men9stCWRY8jmHvoHLMl6u045UJBKnimooPlVOlk", + "G1s2jRqvMbOCgBPGODEO3COUvKZKW2si4xkqQex1gvNYAcVM0Q9wr0BqRv7Fy6LdsVNzD3JVqkowVWVR", + "CKkhi62Bw2rDXG9hVc0lZsHYlfSrBSkVbBu5D0vB+A5ZdiUWQVRXSndnbu8uDlXT5p5fR1HZAKJGxCZA", + "jnyrALuhM0wPIEzViLaEw1SLcioPnPFIaVEUhlvopORVvz40HdnWB/rnum2XuKiu7+1MgEIfHNfeQX5u", + "MWvdoBbUPKFxZLKkp0b2wAexNXt2YTaHMVGMp5BsonxzLI9Mq/AIbD2kZTGXNIMkg5yuu4P+bD8T+3nT", + "ALjj9cNHaEisP0t802tK9u4DG4YWOJ6KCY8Ev5DUHEHz8qgJxPXeMnIGOHaMOTk6ulMNhXNFt8iPh8u2", + "Wx0ZEW/DM6HNjltyQIgdQx8Cbw8aqpEvjgnsnNTPsvYUfwflJqjEiN0nWYPqW0I9/k4L6FGmOU/h4Li0", + "uHuLAUe5Zi8X28JG+k5sj2bvHZWapazAp86PsL7yl197gqi9iWSgKcshI8EH+woswv7EOmK0x7zYS3CQ", + "EqYLfkcLE1lOzhRKPE3gT2GNT+531sPvOPALvIKnbGRUcz1RThBQ7zdkJPCwCaxoqvO1kdP0AtbkHCQQ", + "VU6XTGvrudt86WpRJOEAUQX3hhmdNcd6x/kdGGJeOsKhguV1t2I8sk+CzfAdt94FDXS4p0AhRD5AedRB", + "RhSCQYZ/Ugiz68w5EXs3Uk9JDSAd00ZTXnX731ENNOMKyN9FSVLK8cVVaqhEGiFRTkD50cxgJLBqTmfi", + "rzEEOSzBPiTxy/377YXfv+/2nCkyg3PveW8attFx/z6qcd4JpRuH6wpUhea4HUauD9T8473nnBdaPGW7", + "idmNPGQn37UGr8wF5kwp5QjXLP/SDKB1MldD1h7SyDDzOo47SKkfDB1bN+77EVuWOdVXYb7YKI9W7wm2", + "XELGqIZ8TQoJKVjvaiNgKQuLAY1Yv6t0Qfkc5Wopyrlz/LHjIGMsldVgyJJ3hogKH3rFk7kUZRFjlM7Z", + "0zvYG7EDqHn5BIjEzlbOP6fVfC6mYsgN5hEe7M73Zsw+q8J41PswNEg9qx+GFjnNKIE4FjDsIVFlmgJE", + "XYBjT65qqa1oyDq+xQ1oxIZSWh8oQlNd0jykOnI4I5Svm2GSlOXKcEGmCLYznWu/2rFdm49hmdHc2mYj", + "QRXhSWlIfMHO1yhto2Kg3QGJxEhDXcoICdAcL0PGn0eHXw8dg7I7ceB0VX/s87sy7+98fQVikB2ISCgk", + "KLy0Qr2Vsl/FLIx9creaWisNy65q33b9rYfRvO99QAqeMw7JUnBYR8N9GYc3+DHKOPDi7OmMIkxf3/ar", + "pAF/C6zmPEOo8bL4xd0OeNG7yuHwCja/PW7LqhNGfaHWEvKCUJLmDHWagisty1SfcIpak+CwRRwz/Puw", + "X4/20jeJK+4iejU31Amn6JRT6VKixuQZRBQH3wF4dZoq53NQLf5JZgAn3LVinJScaZxrafYrsRtWgETv", + "iIltuaRrwwJR7fcHSEGmpW7yZIw8UdqwS2tiMtMQMTvhVJMczJv6DePHKxzOm2g9zXDQ50KeVliIXyFz", + "4KCYSuIOJN/br+jb55a/cH5+GClsP1ujhBm/Dk9Zo1Kljn79v3f/a//Xg+QfNPnjQfL8P/Y+fHzy6d79", + "zo+PPn3zzf9r/vT40zf3/uvfYzvlYY/FRTjID1+5x9rhK5TIa6tEB/Zr00gvGU+iRBba3lu0Re5iDKAj", + "oHtNfY1ewAnXK24I6YzmLDMi10XIoc3iOmfRno4W1TQ2oqWf8WvdUc69BJchESbTYo0Xvsa7PlfxCCQ0", + "k7mgIjwvs5LbrfSCrnWw974vYjauosxsAop9giFIC+odt9yfj54+G43r0KHq+2g8cl8/RCiZZauodAir", + "2PPFHRA8GHcUKehaQY8AirBH3Xyst0E47BLMu1ctWHH9nEJpNo1zOO+27NQgK37IrT+xOT9odFs7Xb6Y", + "XT/cWho5vNCLWGB6Q1LAVvVuArQcIQopzoCPCZvApK2GyMzTzDkc5UBnGCCNDz0xJAyjOgeW0DxVBFgP", + "FzLorR+jHxRuHbf+NB65y19duTzuBo7B1Z6zsrD5v7Ugd77/9pjsOYap7thYRTt0EF0WebW6AIqGi4zh", + "ZjYdhw3WPOEn/BXMGGfm+/4Jz6ime1OqWKr2SgXyBc0pT2EyF2Tfx2S8opqe8I6k1ZsxJ4iGIUU5zVlK", + "TkOJuCZPmwWhO8LJya80n4uTkw8db4Gu/OqmivIXO0FyzvRClDpxMdyJhHMqY9YYVcXw4sg2ScOmWcfE", + "jW1ZsYsRd+PHeR4tCtWO5esuvyhys/yADJWLVDNbRpQW0ssiRkCx0OD+vhXuYpD03KswSgWK/L6kxa+M", + "6w8kOSkfPHgMpBHc9ru78g1NrgsYrMjojTVs6y9w4fZdAystaVLQeczqc3LyqwZa4O6jvLzER3aeE+zW", + "CKrzTsM4VL0Aj4/+DbBw7BwghIs7sr18vp74EvATbiG2MeJGbYq+6H4FYXYX3q5WqF5nl0q9SMzZjq5K", + "GRL3O1Ol8ZgbIcv7Byg2Rx9Ml/FkCiRdQHrqUlHAstDrcaO7d0FxgqZnHUzZJCU2SAbD5FFnPgVSFhl1", + "onhbgzRdEwVaeyfQ93AK62NRR9nvEqDcjJdVfQcVKTWQLg2xhsfWjdHefOfnhCquovBhpxh/5Mliv6IL", + "36f/IFuR9woOcYwoGvGcfYigMoIIS/w9KLjAQs14lyL92PLMK2Nqb75IwhLP+4lrUj+enEtSuBpUcNvv", + "S8CMR+JckSk1crtwyXpsTGjAxUpF59AjIYdmi4GRlw1TBw6y7d6L3nRi1r7QOvdNFGTbODFrjlIKmC+G", + "VPAx03JE8zNZy5gzAmAOPoewaY5iUuWxZ5kOlQ3zkU0q1gdanIBB8lrg8GA0MRJKNguqfB4hTLfkz/Ig", + "GeAzxjhvymwRKvSDnEqVft3z3PY57bwuXX4Ln9TCZ7IIn5YDslIYCR/dtmPbITgKQBnkMLcLt409odTx", + "1vUGGTh+ms1yxoEkMXcsqpRImU0EVV8zbg4w8vF9QqwKmAweIUbGAdho8cWByVsRnk0+3wVI7uLFqR8b", + "bcXB3xAPbbEOykbkEYVh4azHgJR6DkCdD191f7U8SXEYwviYGDZ3RnPD5tyLrx6kk2ABxdZWOgXnc3Cv", + "T5zdoIG3F8tOa7JX0UVWE8pMHui4QLcB4qlYJTa2LSrxTldTQ+9Rn22MtIsdTJvK4o4iU7FCPxa8WqyP", + "8BZY+uHwYAQv/BVTSK/Yr+82t8BsmnazNBWjQoUk49R5Fbn0iRNDpu6RYPrI5W6QneJCALSUHXWqV/f4", + "3fpIbYon3cu8vtXGddYlHw4TO/59Ryi6Sz3462phqnwS79oSS1RP0XTHaKbSCETIGNEbNtE10nRNQQpy", + "wEdB0hCiktOY6c68bQBvnCPfLVBeYMIOytf3Ah8fCXOmNNRKdO+ScBPqSYp5woSY9a9OF3Jm1vdeiOqa", + "solosGNjmde+AvSRnTGpdIIWiOgSTKPvFD6qvzNN47JS04vIZtVkWZw34LSnsE4ylpdxenXz/vjKTPu2", + "YomqnCK/Zdz6hkwxC2zUt3DD1Nb9dOOCX9sFv6ZXtt5hp8E0NRNLQy7NOb6Sc9HivJvYQYQAY8TR3bVe", + "lG5gkEFIaJc7BnKTPZwYEjrZpH3tHKbMj73VbcQHpvbdUXak6FoChcHGVTA0ExmxhOkgiWo3VrPnDNCi", + "YNmqpQu1o/a+mOlOCg+feqqFBdxdN9gWDAR6z1i4iATVzDJWC/g2HW4jycdkEGaOm7nAQoYQTsWUT+be", + "RVQVTrYNV8dA8x9h/Ytpi8sZfRqPLqc6jeHajbgF1++q7Y3iGU3zVpXWsITsiHJaFFKc0TxxCuY+0pTi", + "zJEmNvf66GtmdXE15vG3B6/fOfA/jUdpDlQmlajQuypsV3w1q7IJzXoOiE8Wbd58Xma3omSw+VUWplAp", + "fb4Al3U3kEY76QFrg0NwFJ2Sehb3ENqqcna2EbvEDTYSKCoTSa2+sxaSplWEnlGWe72Zh7bHmwcXNyzH", + "ZJQrhANc2roSGMmSK2U3ndMdPx01dW3hSeFcG/ICL23qa0UEb5vQ0b14XTir+5Jicj+rFekyJ14uUZOQ", + "qJylcR0rnypDHNzazkxjgo17hFEzYsl6TLG8ZMFYppka8NBtARnMEUWmTxTZh7upcGVNSs7+VQJhGXBt", + "Pkk8la2DitkUnba9e50a2aE7lxvYaujr4S8jY4SJLds3HgKxWcAILXUdcF9VT2a/0Eojhe7WtUliB4N/", + "OGPnStxgrHf04ajZOi8umha3sApJl/8ZwrDpqLeXQPGPV5dhs2eOaEkTppKZFH9A/J2Hz+NIKI5P5cnQ", + "y+UP4AN8zmvtTl2ZpZ69d7v7pJtQC9V0Uuihetz5wCyHOQW9hppyu9W2wkDD1y1OMKFX6Z4dvyYYB3PH", + "Ezen51MaS7hohAwD00FtAG7o0rUgvrPHvaoCG+zsJLAlV22ZjbIuQNZRct2MLRcUGOy0g0WFWjJAqg1l", + "grG1/+VKRIYp+TnltlCF6WePkuutwCq/TK9zITFHgoqr/TNI2ZLmcckhS7sq3ozNma3BUCoIkvy7gWx9", + "G0tFrlBCFa7jUHM4Iw/GQaURtxsZO2OKTXPAFg9tiylVyMkrRVTVxSwPuF4obP5oQPNFyTMJmV4oi1gl", + "SCXU4fOmMl5NQZ8DcPIA2z18Tu6i2U6xM7hnsOju59H+w+eodLV/PIhdAK6GxiZukiE7+R/HTuJ0jHZL", + "O4Zh3G7USTSc3BbR6mdcG06T7TrkLGFLx+u2n6Ul5XQOcU+R5RaYbF/cTVSktfDCM1sBRmkp1oTp+Pyg", + "qeFPPd7nhv1ZMEgqlkuml864o8TS0FOdwd9O6oez5WRc8lUPl/+INtLCm4haj8jrVZra+y22arRkv6VL", + "aKJ1TKhNjJGz2nvBp4Qmhz7vDmajrZLQWtyYuczSUcxBZ4YZKSTjGh8WpZ4lfyPpgkqaGvY36QM3mT57", + "EsnA28wEyXcD/NrxLkGBPIujXvaQvZchXF9ylwueLA1Hye7V0R7Bqew15sbNdn22w81DDxXKzChJL7mV", + "DXKjAae+FOHxDQNekhSr9exEjzuv7Nops5Rx8qCl2aGf3792UsZSyFgyvfq4O4lDgpYMztB3L75JZsxL", + "7oXMB+3CZaC/WcuDFzkDscyf5dhD4IWIvE59VuhKk+581SPagb5jaj4YMpi6ocakmYH3+o1+XvncNT6Z", + "Lx5W/KMN7A1vKSLZr6BnE4Ps4NHtzKrvgf2bkhdiNXRTWyfEb+wXgJooSkqWZ7/UUZmt5OuS8nQRtWdN", + "Tcff6jJR1eLs/RTNWbegnEMeHc7Kgr95mTEi1f5TDJ1nyfjAtu188Ha5rcXVgDfB9ED5CQ16mc7NBCFW", + "mwFvlUN1PhcZwXnqBGk19+zWEQiyPf+rBKVjwUP4wTp1od7SvHdtsmECPMPX4oR8byvBLoA00t/gK63K", + "IuBS31qFelnkgmZjTORw/O3Ba2JntX1ssROb7HiOj5TmKlr6qiD34zD3YF+3JB66MHyczb7UZtVKYzYq", + "pemyiAWHmhbHvgFGoIY6fHy+hNiZkFdBTUcbR2qGMPQwY3JpXlzVaFZ2QZow/9Gapgt8kjVYaj/JD8/S", + "7alSBZXxqgo3VUJEPHcGbpeo2+bpHhNh3s3nTNkCoHAGzXjUKjjbqQR8fGpzebLk3FJKVPbYlDzgImj3", + "wFlHDa/mj0LWQvyOArlNcr9r0vIj7BVN0NTOgN4piWejG6vKJb6wc0q54CzF9Eixq9lVCh1iAxuQSaqt", + "ZPVH3J3QyOGK5l2v3OQcFnszsXtG6BDXVcIHX82mWuqwf2osSbmgmsxBK8fZIBv78gFOD8i4ApfgEuvK", + "BnxSyIZdETlk1FSdVCaNHckIw2J6HnbfmW9v3bMf/cVPGUcB36HNuaZbTR0WMtTmVcA0mQtQbj3N2GD1", + "q+kzwTDZDFYfJr7woc0Gg2Y5s2xrg+4OdeAt0s4CbNq+NG1dnqDq54YHsp30oCjcpP3FJaLygF7xXgRH", + "LIuJN+0EyK3GD0fbQG4bXUnwPjWEBmdoiIYC7+EOYVSFFlpFfIzQaikKWxDrwhXNYMB4BIzXjENdljNy", + "QaTRKwE3Bs9rTz+VSqqtCDiIpx0DzdH6HGNoSjvTw2WHaucSMijBNfo5+rexrhHRwziqBrXgRvm6qgZq", + "qDsQJl5iGWKHyG7FB5SqnBCVYURBqwZEjHEYxu2rzDQvgO4x6MpEtruW1J6cXW6iviDRaZnNQSc0y2IZ", + "qV7gV4JffXIpWEFaVokpi4KkmBOlmSSmS21uolRwVS43zOUbXHK6oKhKhBrCwi5+hzEIZbrGf2NZGft3", + "xjlh7OwG6D0uXBWKHeXm5kgdqdfQdKLYPBmOCbxTLo+OeuqLEXrd/0opPRfzJiDXnBpiE5cL9yjG3741", + "F0eYOaGTatReLVViA3S6E74UHj4bq5DcJlfCq6yTexSNPVWprc0KiP6iWWO8/Hpcb4OEGNTer9Z62OeA", + "m/b6i1PtItc0JRtZUG80kPXesXE/CEVcc9rnsWMddsznTu9hkmFHzsaxNyLUu4J1AfrR+5mSgjJnGq+Z", + "RRezziO9X1246dDVG9xehPPz7tXY/XjW55NNFOPzHAh+b5cZOgUXzl7Vmbdr9V5J/klof3VlXu14lVd8", + "dP1d7wSc6mbVoL1K22OX0t4u073Jf/zF+rAR4FquvwAVbmfTO0WautKuVU/VTUiVDnlQeuTGrRivt9Sf", + "/6jOeYT0VAjF6hTcsUJMA33djrGWUpC/qTuWdzQ5g1Rj3vXagC4BdsnmZCYLivzd5kHqeTtWLoEu/dGm", + "nEfdZOtbLrROWFIQWmcTVU+GZ/g5qNykkClhBtw5cFdnrxlwMNjteTaDVLOzLWFg/7MAHoQYjb0SwtbL", + "DaLCWOVGi1lEdlex1QBtitLaCE+Qze/S4PQFgZzC+o4iDWqIZs4e+3vlIgkkEAPIHRJDIkLF3BCs1tRZ", + "hpmqKAOx4N1+bHeoU3H11twJghovOJcnSXPj1oGOG6aMF/0YNJfpulP4L3qE9kWKdYsG9Avbr7BGg6rq", + "4fkEFOGTlBx20/SduwQWGLRXGQp8KgtQ/jcfoWtnydkphFWB0CxzTmXmW0T1DF6FkWy4jzrhXT7hfRvo", + "WTUzq500uwE9kcRP6Iqb5sLIX0mfP3PTLzIsno/eHzblN3p8GrhmIF31NBT2cqEg0cI7dW6CYxMqXKH3", + "iyBB9SZbtMD1pkB5X+d4waSzFFOeUOfZEi6QSFhSA50MMrH0z7kJ2S/tdx/B4pOOblWnVPS6PdG8d89l", + "qoPEkOpnxN2W2yNjLqJZYZzbWq0qlpaFG1SGqv9CiqxM7QUdHoxK+zQ46dEGVhJVSqTdVbYE4iC88BTW", + "e1bi9xn6/Q6GQFvJyYIehPO3NvlKdU0qBvf8SsC7STXNeFQIkSc9mv3Dbi6ZNsWfsvQUMmJuCu/G1lOk", + "hNxFhXJluj1frH3ulKIADtm9CSEH3DoOeytuM5lxa3J+R2+af4WzZqVN7+Q0SJMTHvfAxMRL8pLczA+z", + "mYcpMKzuklPZQbZkKln15LGR9DxSsmcy9Anatau2y6jURGWhiMkkWwpWRGzGvgKCr6fh41O0WLK0WzOh", + "IzjMsPZUQiODH1bsetyoDMhaZTp8RiFblCGlVlwzTwXK8lKCixOwRXJayfMLqhd++0zzrlBlLmhQ6MRv", + "E7BTZZ8A/iniKvS0z4UokhzOoGE2cMELZZqCUuwMwuo+tjPJAAp8mLevi5g+PKSrFg9xa08CjeoQ7EaZ", + "ikWs3SmyhWP0lF5PLHmooSRkIDpjWUkb+FOXKLwysJJ7COvAE7Lz4YgvrnM0XHGUpErdFlNbuuARv4WG", + "futCLi1xKCi4Uo3ZU3mywsJlRI9e1MYxe7GUGYPooavBjhyZoMjKZj1LmFGndtWV1hCC7zJ/6tpb+qY+", + "jcPKvfgOW8AL1W9BwRcvCTlwbtif9k2FlGApvZTQWP42jZ5bYM2+gi2yvNss0+Y3s75YzX0J1LXqZaUF", + "7avC1FaWYvocwTGlWFfJqtAwhpnJQ8IxvFue0fz6FaWYV+kA8eGq2sYXGmraQiRbVKqLObW9poPmDrRq", + "Vzc1f4eK3f8Bs0dRi6Ybylk4KlnB24GQZdKc5KKuZ4dDknMc05pAHz4jUxeQU0hImWKtWMVznzS5Uixh", + "DYG62PFmTda2df4i9CXIeObFF/K2TsCqBd4YNYT1Eb1hptJzcqNUHqO+DllE8BfjUWFmjC3XxWnDNmoT", + "Wrec/oSEK7aRBt5OO9pIuzk/hi7P2gHNpVMq6K5z8G3dwG3koq7XNtTA30XupiydQ+zy8eS7pjs6BliE", + "YOZqgqCS3x/+TiTMsDSNIPfv4wT3749d098fNT+b43z/fryo8nW5BFgcuTHcvDGK+aXPSdw6QvfEI7T2", + "o2R5to0wGtEldXEnjJ/4zcWX3Uh5qd+s5aZ7VF2Jj12ckdqbgIiJrLUxeTBVEDcyIGTEdYsEiKBWJC0l", + "02tMe+MV/ey3qPPC95Vt0NmWq0QJ7u7T4hSqxEm1JbFU/nb9XtAc7yMjU6MrmMZCut+u6LLIwR2Ub+5M", + "/xMe/+1J9uDxw/+c/u3B0wcpPHn6/MED+vwJffj88UN49LenTx7Aw9mz59NH2aMnj6ZPHj159vR5+vjJ", + "w+mTZ8//847hQwZkC+jIB1mP/hdrsCUH7w6TYwNsjRNasKp+tiFjX0iGpngSYUlZPtr3P/0ff8ImqVjW", + "w/tfRy6Gc7TQulD7e3vn5+eTsMveHE0HiRZlutjz83TrFr87rOJw7NMSd9SGWHiVgSeFA/z2/tujY3Lw", + "7nAS1MXcHz2YPJg8xLKJBXBasNH+6DH+hKdngfu+54httP/x03i0twCao6Xd/LEELVnqP6lzOp+DnLiK", + "Ouans0d7XpTY++jMJp/MqPNYQiAbURSEkXQLzTgTLLpl2oihRuJ25fKIj6t0/k5rwTMM9LCWCMPaKmQd", + "ZnXe2sOaUfnsPTad4f6vkTqDMzY37+hG/dRWZVbz8v7vo5/eEiGJe9K8o+lp5SRDDmc2E4MUZwzjB7Ig", + "6MT0nHia/VcJcl3TlON2Yao+n53dRWUs1bxoujDXklSsfHisqA/ObEghIObKyFkzKy1LCCGpWa9hpw+S", + "5x8+Pv3bp9EAQNDirgATOfxO8/x3Ww8WVmi29KmQXKqLcSQTOUrQ49pohh3qnRyjD3b1NSw2U7VpRv78", + "zgWH3/u2wQEW3Qea56ah4BDbgw+YagCJBc/ZowcPrqxKVRXsZj25q1E8SVxgoC4Tsp8ihWd9saqeqrNP", + "rnChTVfVSy+3PVxn0S9ohgVAQGm7lIdf7VIOOTq9mEuB2Evv03j09Cvem0NueA7NCbYM8vh0L5qf+SkX", + "59y3NAJPuVxSuUZxJqhS1AqkpXOFFhVkkfZsN+qSjD586r319sKyC3sfG34T2aXuxE7FmcNXW67JO6qP", + "c3azYLaqOpjvVdJ+tKy70hVYRkDdm5Dvw97IvTGphE3ZUEoOmXd78LdelSXL596qYbujwnwb0Us7UBHf", + "3t83fX8fNBUcjUyLMWAap2AjTB3fq8teoN14qVbdvgvVxQvqK1wgS/VnLR7Uel/amT7Enn9bGfUt7npw", + "1ycmBfBWElOzLsbnZ80+PqG6SRpXxmdk3F+50PeG5oZOguW2Yrdt+tFbYfAvIwxW7ri2/K7PuH058RBr", + "7+x99Cllr0AkdCl1BwiD4bM66BukPL3bYif3JjY/bNjmYjzD+d9uFfMw0e+tgPcFCHjdJNoxMOrUyDcn", + "1CEMizrL9i61cxtFsXbKBv6VSnF/YWT1im0G0u0C2wXYZ0cYc8z6s7HVP6UQ5pB2K379pcWvKirmUgJY", + "Iw2+i7MKzFiX0t61tXNMV5JYMzIq4GxV0WF3hMd1yR7DYjCLkk+gocb+ZYgmVPtotJs17rwbuyLW9xA+", + "UF+sD19tk66+Ij3P4Gx+kVsgvjefm5dGzQ7vr8fsMIw3PXnw5PogCHfhrdDkO7zFPzOH/KwsLU5Wu7Kw", + "TRxpb2rzDG/iSrzFlpBR1PmDAx6FZRrCHMXWI+OuK44Z5n24NyE+m7GqajO4bANzQfM6qxKVc9vJ8DiD", + "BHLH/7mP49+ZkO8wIkCrMTqWaZe4n9xhXO8/fPT4iWsi6bn122q3mz57sn/wzTeuWZ272r5vOs2VlvsL", + "yHPhOri7oTuu+bD/v3//x2QyubOVnYrVi/VbmyjuS+Gp41g8QbXxfbv1lW9S7JXuEvhtRd21mO1fiFWU", + "+4vV7e1zY7ePwf6f4taZNsnIPUArDWYjuv4KbyF7THa5h8Y+F7ThO9VlMiFvhUt0UuZUEiEzkK6Yzbyk", + "knINkE08pWLUmrKJHdKcAdfmwYjlOWSiWAY2PnxeSshIzpZYv1bCGfrD4/T4lm9AsJ3Ro9fsF8vk39BV", + "kPxgWl3TWrglo7pzSVe+QBCWwBASf/rmG/JgXL9a8twMkFSIiTHXJV2NrlHbVxHbIF/zZg7/rc64OPYQ", + "zVEt/dhabLSZMPyvzbm/Wondkrvb2CvinDsbfGqDTqg/cOlENmoOrGBnywdhPZt1Hc5rpDwvQsVZnJlh", + "qFLgC7YNbFVJRx+fbfTeHuLbx/+lWEmboHZkGxhhqvY+oi0j5Bmdc4sRcn8tM2lgM5Ji6Y1GgsxApwsX", + "nNtCfYQ9+QoC/bxpU/3Iq5ZqcBe7CazDbI5Y13BgwpAgbhINdyAjRPyTT+ZrPrOZzVDhq0P4MqlokmK+", + "clhVNMyVVmTK+/H7GF6ziztB+bKevCuQIVquwu55i+DdENxhjt/6ClWIMbeIP4Onv39KJuStqEPEXXGE", + "P6PJ8XPe7J97QW8FB2tbN5KvpcVbM2oldqAKH5Hic4PY90uVpvrCIsier7W2UQ75wVY62yiLDLm9zWRf", + "5RX+Q7SKceOWMWubbE18UI82hDmbhjajdDOX9A2+Ym6En36BT5ub4FjXw2LwkHo+48QCfrVMB9PtWGLe", + "q9II93GgeGb2wdxIi8r9LJpMfQq54HP1ZbKiTdQRx0uESqqc9fHE9H+9s/sSM/mYJ6/1fHS5nRTjKdha", + "gr6cvEu8ZiH82/VBqNnS5+LkYczqDXOXpw8eX9/0RyDPWArkGJaFkFSyfE1+5lXdx8twO0y7X+Va89rg", + "aKUFtDY1c4ClYcKiizPBhsvaR71i2aftzDDI2LcjH2Q84INhfkFaFEDlxRngdtPVcWvGw1ehV3AjG3yV", + "PSsCikHRjo7x/zEaqHfCcHcxc5dfyS2gPtOXYxPOZVfMxpVzjJECxGyfnPD7RC3o04ePfnv09Jn/89HT", + "Zz2aMzOPS9DT1Z3VA5nPdpghCrSvWh14tVJ7hd/9697t3TZxPGLZKpovuq4A08ma68SyO4oUdN2bVL7Y", + "UsEmHLauZnP9iQ2VZtNF9H3lnz9VjdtD/qJ6Bdvse67wy23lmp6giYDPGEKrS9hUWN9czWaDNNkiy6ps", + "yHU/TuvgAnvReeTJ1p1zo4KuvqlHaoJvVOBesGmi5eZkSsxpPg7M3VXVcPRdKYtCSF2dbjUZJO5Bn9mu", + "Ie31Ee5OwlxKdbooi72P+B/M5vWpDjiwdToDO5/73VbU37NW/E1y3pFtcck7sSVQW9+BVi51n1jOeRaI", + "GXnDUikOMFW+u27UWmlYdrL/ua6/barVHr2aBM8Zh2QpeCwn3U/49Q1+jCbjF5rmfZ2Pzce+vi3m2IS/", + "BVZzniGc8bL4/UKe4pdSIbVWK8Ec47qamaX/HY+aPzRrnnZP0pqn3WPWKKnW8/Pex8afzofHtVSLUmfi", + "POiLD0DLi4aY74Nc2cP15tWbqJVzWpEMlCHar09JFeAhdmKqr5FMZEFG9N5kZH9RtdWM8axFJChRpuIM", + "pKoUGtK729zqrv48uqvB+74Tj7WZN7dxtFJdrUTyVmRgx20mu42Fi3KRgUsQ2hVEKhks/t73t1LdrvUC", + "S2k5X2hSFkSL2Fuv7pjQ1DJZW3RRbatSZ1v5aitnQGgugWZrMgXgREzNopvVPglV6CrvH4xO0owXW6vh", + "KqRIQSnIEh8euw20Ku0qPi/1Bjwh4AhwNQtRgsyovDSwp2db4axSlSty98df1L0bgNeKgpsRax10I+it", + "nICctNeFetj0mwiuPXlIdlQC8aIB6rfEssjBabgiKNwJJ73714aos4uXRwuqgNhnpng/yeUIqAL1M9P7", + "ZaEti8Tc35FykPbrMVuiJMYpFwpSwTPVX7R1G1vGciHBWpRZQcAJY5wYB+55cL6mSr93xo6wqldQlsRM", + "saHKbF9KfDPyL1VC/M7YqbkPuSpVlTXfKTDilbU4rDbM9RZW1VxobfJjVxoSLUipYNvIfVgKxnfIUmHZ", + "WB2YibBoSHdxmNOEOgVFF5UNIGpEbALkyLdqlIyrTRg9gDBVI7qqDtmknKA8ltKiKLBqXVLyql8fmo5s", + "6wP9c922S1yucBHe25kAFWqvHOTnFrMKgzYWVBEHB1nSU6fgmrucT5GSXmwJCRqmk02Ub47lkWkVHoGt", + "h7Qs5pJmWE6URlQpP9vPxH7eNADuuCdPrNWcTGEWLUJiNr2mZNmrIqqGFjieigmPWNpZkdQcwRlWxfEE", + "4npvGTmDnrrSx0H1S9cc54pukR8Pl223ukctZcYwO27JASF2DH0IvD1oqEa+OCawc1JrD9pT/B2Um6AS", + "I3afZA2qbwn1+DstoK3NC++vxkXR4u4tBhzlmr1cbAsb6TuxMf3hVxnU1zbbfkaftKb+NHj/TS7ytt07", + "p0wnMyFdtXw60yAjqrxWSQPKtI8ZtAYULZzHBMER3LXpxnFV1+vEG46JWBCIr9LJlpE8Pmaq74QcFPjT", + "dG+jTJOSa5YHwc/VS/nL0xfe6gBudQC3OoBbHcCtDuBWB3CrA7jVAdzqAG51ALc6gFsdwF9WB3BTkXyJ", + "Fzi8fzMXPOEwp5qdQRXid5t86E8V+VJdVV4ngVqMc8q0S+VJqBcD8MvlAv800BxxwHLksYVQvTmSsPCz", + "EqVMgaQGQsZJkVPzNICVrhLLNVOW+iTKrvQzZkGlCh4/Ikc/HHgH/YVzJG+2vXvgkpErvc7hnkvdUNVm", + "9TkcgBukuxQO1F8JPgGdS8fHciDKoPdbbP0KziAXBUjr+0u0LCMan2Og+UuHmy0Kn0ZpTTPa7+OGnsmh", + "bUmLoMQ9rpUqQm3URrMy5ozmqr80ph1vSYtYDrjq4rOqIOQmL0S2bp0Qs2t7uIHNs1G76TNO5ToSotM5", + "ER3S0MLwK0dYXV3WpysPJukSbZfMtlFYTFqXoKLneBOVR6Moqg3rDGWDfWYtOomWjm6HDowqAIc4wBp6", + "9ntC3tt+NxuqjhC5I1Yz8y/Gb7DZsmIa2NY8Ihzr+Vrjyj3io6cXz/7YEHZWpkCYVsTHo2y/XsajVWJG", + "mgNPHANKpiJbJw32NWrcQhlTVClYTrffRCH/dFmP3eVjvmy+p27mGnkVLG4TTw6JZpU4BtzDndcaBvPm", + "Cls4omPPAcY/N4vuY6MhCMTxp5hSqV1rZkemV0+zvmV8t4wvOI0tiYBxF7/XZiKTz8j45FqWvJ/nfbuC", + "tDTAhSf5Lmrn0SQHK92wa2YwLedzzN7csdGZpQGOxwS/IVZolzuUC+5GQXbwKqPnZZNItYfrcpcgVu2u", + "kGQuRVncs2Wq+BqNGcuC8rU3+UKi2LLMLQ5t4rurZbQ2xK7rCIDmWKf769Nqv/Mqv0B3667a5u8WLeSc", + "KmL3FzJS8sxFDnUCcVd8eOZoO/TxitdsemPuaLveyOrcvEOuCL/LLsSlMnMXIBO94vZANdO724Bfe3In", + "t1lr/xrXxjubcaGHwXaDV2uGcEW3hwz4Gl4fQYqSOhSuWWvLVgLsCxwJ85XYllfqPNIZvulDEtThszZS", + "yAtCfUmBVHClZZnqE07RRhMsbNL1L/Ha6H7+9tI3iZsJI1Y8N9QJp5hxvrLcRPncDCJmiu8APBtV5XwO", + "yvDKkEhmACfctWKclNy8tMSMLFkqRWLDUM0ZMvLJxLZc0jWZ0RyNjH+AFGRqbvZg163CWGmW586hxUxD", + "xOyEU01yoEqTN8xwWTOczyVWeXKBPhfytMJCPH3FHDgoppK48uV7+xUzRLjleyUfKizt5zqy+3pTQ3jY", + "WdYL+eErAzfFZDg5U7r2gejAfm327yXjSZTIjhdAnEtYm7bIXcwV4wjoXtM6pBdwws0NpwVBrk71xcih", + "bebpnEV7OlpU09iIljXIr3XQE+9KuAyJMJlb08qfKDAzoANvvsSNx1o07b3f0Yyysbxl7KvLKNbTyD0S", + "wH+2pwjveLMsSEvJ9BrtELRgv52C+f+HTx/MN3nmTRSlzEf7o4XWxf7eHtatXAil90afxuE31fr4oVr5", + "R29tKCQ7wzTWHz79/wAAAP//mPC/k7U8AQA=", +>>>>>>> oas2 fixups } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/participating/private/routes.go b/daemon/algod/api/server/v2/generated/participating/private/routes.go index b513cffac6..b0b11c18eb 100644 --- a/daemon/algod/api/server/v2/generated/participating/private/routes.go +++ b/daemon/algod/api/server/v2/generated/participating/private/routes.go @@ -291,6 +291,7 @@ var swaggerSpec = []string{ "pu/SFbDApL3aUeBLWYDyv/kMXTtLzs4hfBUI3TKXVGa+RdTO4E0Yych91Evv8gXvu0Av65lZE6TZT+iJ", "FH7CUNw0F0b+SobimdtxkeHj+Rj9YUt+Y8SngWsJ0r2ehsJeLhQkWvigzjE4xlDhHnq/CRLUYLFFC9xg", "CZQPTY0XLDpLseQJdZEt4QKJhIIa6GRQiWV4zjFkv7LffQaLLzq605xS0+vuQvM+PJepHhJDql8Sd1vu", +<<<<<<< HEAD "zoy5iWWFcW7falWxsizcoDI0/ZdSZFVqL+jwYNTWp8lFj0ZYSdQokfZX2dMvcywB9jbIMzyH7b4V/X2p", "fr+VIfRWhLJrCPL6O7t9p0anuH6dr+wCVncC55c03MxnpRB5MmDrP+5Xl+megXOWnkNGzN3hA9sGni0h", "D9HEXDtzL9dbX02lLIFD9miPkCNuQ4m9X7dd3rgzOX+gx+bf4KxZZQs+OZvS3hmPx2RiKSZ5S/7mhxnn", @@ -325,6 +326,76 @@ var swaggerSpec = []string{ "bLxP3w5cP0ra+nv/kjKdLIV0eVBYIrvfWQPN912Fn86vTVJ97wtWCgh+DIMYo7/u1y8QRD92XROxr840", "P9DI12fznxvXZOjqQ9ZeO/k+fjJsGevbOq7feK4O9/cxt2AtlN6fXc0/d7xa4cdPNQl8ru8KRwpXn67+", "XwAAAP//qWbn/XHIAAA=", +||||||| constructed merge base + "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", + "yAAA", +======= + "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", +>>>>>>> oas2 fixups } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/participating/public/routes.go b/daemon/algod/api/server/v2/generated/participating/public/routes.go index f197fd7aa7..d67ba24df9 100644 --- a/daemon/algod/api/server/v2/generated/participating/public/routes.go +++ b/daemon/algod/api/server/v2/generated/participating/public/routes.go @@ -177,6 +177,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ +<<<<<<< HEAD "H4sIAAAAAAAC/+x9/XPcNpLov4I3d1W2dUNJ/kh2rarUPdlOsrrYjstSsrtn+WUxZM8MViTABUDNTPz8", "v1+hAZAgCc5wJMXe3PonW0N8NBqNRn/jwyQVRSk4cK0mJx8mJZW0AA0S/6JpKiquE5aZvzJQqWSlZoJP", "Tvw3orRkfDGZTpj5taR6OZlOOC2gaWP6TycS/lExCdnkRMsKphOVLqGgZmC9KU3reqR1shCJG+LUDnH2", @@ -352,6 +353,359 @@ var swaggerSpec = []string{ "b08P+n+McZ//S0vpt0hhuBUj3Tp2j6t+4Sqfgqt8dr7ye/dNBubD/5Vi5pPjJ7/bBYXG5tdCk+8wyv12", "4lhd4TlWiOKmgpYvF+7NfU2kbBh5irdoHXP67r25CPC5FXfBNoGUJ0dHmOq+FEofTcz11w6yDD++r2H2", "dfgnpWTXWNbv/cf/CQAA///C44qjANcAAA==", +||||||| constructed merge base + "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", + "/J8AAAD//7X6ZKDq1gAA", +======= + "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", + "c85b2NYAAA==", +>>>>>>> oas2 fixups } // GetSwagger returns the content of the embedded swagger specification file From 28aa602eb45c39ddbfddd7ec5475c81dcf363471 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Fri, 3 Feb 2023 12:41:57 -0500 Subject: [PATCH 08/29] e2e test for shared resource access --- test/scripts/e2e_subs/shared-resources.py | 95 +++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100755 test/scripts/e2e_subs/shared-resources.py diff --git a/test/scripts/e2e_subs/shared-resources.py b/test/scripts/e2e_subs/shared-resources.py new file mode 100755 index 0000000000..768c8151aa --- /dev/null +++ b/test/scripts/e2e_subs/shared-resources.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python + +import os +import sys +import algosdk.encoding as enc +import algosdk.future.transaction as txn +from goal import Goal + +from datetime import datetime + +stamp = datetime.now().strftime("%Y%m%d_%H%M%S") +print(f"{os.path.basename(sys.argv[0])} start {stamp}") + +goal = Goal(sys.argv[1], autosend=True) + +joe = goal.new_account() + +txinfo, err = goal.pay(goal.account, joe, amt=500_000) +assert not err, err + +putTeal = """ +#pragma version 8 +txn ApplicationID +bz end + +txn ApplicationArgs 0 +byte 0x1032 +txn ApplicationArgs 1 +btoi +app_local_put + +end: int 1 +""" + +txinfo, err = goal.app_create(joe, goal.assemble(putTeal), + local_schema=(2, 0)) +assert not err, err +app_id = txinfo['application-index'] +assert app_id + +print("goal.account: ", goal.account) +print("joe: ", joe) + +goal.autosend = False +grp1 = goal.app_call(goal.account, app_id, + on_complete=txn.OnComplete.OptInOC, + app_args=[enc.decode_address(goal.account), 10]) +grp2 = goal.app_call(joe, app_id, + app_args=[enc.decode_address(goal.account), 20]) +[grp1_info, grp2_info], err = goal.send_group([grp1, grp2]) + +# Won't work, because v8 can't modify an account (goal.account) that +# isn't in the `grp2` txn +assert err +assert "invalid Account reference "+goal.account in str(err) + +# Now, upgrade program to same thing, but v9 + +optin = goal.app_call(joe, app_id, + on_complete=txn.OnComplete.OptInOC, + app_args=[enc.decode_address(joe), 40]) +optin_info, err = goal.send(optin) +assert not err, err + +putTealV9 = putTeal.replace("#pragma version 8", "#pragma version 9") + +update = goal.app_call(joe, app_id, + on_complete=txn.OnComplete.UpdateApplicationOC, + approval_program=goal.assemble(putTealV9), + clear_program=goal.assemble(putTealV9), + app_args=[enc.decode_address(joe), 50]) +update_info, err = goal.send(update) +assert not err, err + +# Won't work this time, because v8 program +grp1 = goal.app_call(goal.account, app_id, + on_complete=txn.OnComplete.OptInOC, + app_args=[enc.decode_address(goal.account), 60]) +grp2 = goal.app_call(joe, app_id, + app_args=[enc.decode_address(goal.account), 70]) +[grp1_info, grp2_info], err = goal.send_group([grp1, grp2]) +assert not err, err + +# Both txns should have a local-state-delta that modified +# goal.account, even though that would have been impossible in v8 +# because goal.account does not appear in the `grp2` transaction. +assert len(grp1_info["local-state-delta"]) == 1 +assert grp1_info["local-state-delta"][0]["address"] == goal.account +assert grp1_info["local-state-delta"][0]["delta"][0]["value"]["uint"] == 60 + +assert len(grp2_info["local-state-delta"]) == 1 +assert grp2_info["local-state-delta"][0]["address"] == goal.account +assert grp2_info["local-state-delta"][0]["delta"][0]["value"]["uint"] == 70 + +print(f"{os.path.basename(sys.argv[0])} OK {stamp}") From 86dfb5930536792c32c49a654e036a5780f4135f Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Wed, 15 Feb 2023 16:13:41 -0500 Subject: [PATCH 09/29] Several more tests, and handling created apps/accounts --- data/transactions/logic/eval.go | 46 +++++---- data/transactions/logic/evalAppTxn_test.go | 2 +- data/transactions/logic/resources.go | 100 ++++++++++++-------- data/transactions/logic/resources_test.go | 27 +++++- ledger/apptxn_test.go | 104 +++++++++++++++++++++ ledger/boxtxn_test.go | 3 +- 6 files changed, 222 insertions(+), 60 deletions(-) diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index a604950b0a..acdd5b3781 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -4007,45 +4007,53 @@ func (cx *EvalContext) accountReference(account stackValue) (basics.Address, uin if err != nil { return addr, 0, err } + idx, err := cx.txn.Txn.IndexByAddress(addr, cx.txn.Txn.Sender) + if err == nil { + return addr, idx, nil + } + ok := cx.availableAccount(addr) + if !ok { + return addr, 0, err + } invalidIndex := uint64(len(cx.txn.Txn.Accounts) + 1) + return addr, invalidIndex, nil +} + +func (cx *EvalContext) availableAccount(addr basics.Address) bool { // Allow an address for an app that was created in group - if err != nil && cx.version >= createdResourcesVersion { + if cx.version >= createdResourcesVersion { for _, appID := range cx.available.createdApps { createdAddress := cx.getApplicationAddress(appID) if addr == createdAddress { - return addr, invalidIndex, nil + return true } } } // or some other txn mentioned it - if err != nil && cx.version >= resourceSharingVersion { + if cx.version >= resourceSharingVersion { if _, ok := cx.available.sharedAccounts[addr]; ok { - return addr, invalidIndex, nil + return true } } // Allow an address for an app that was provided in the foreign apps array. - if err != nil && cx.version >= appAddressAvailableVersion { + if cx.version >= appAddressAvailableVersion { for _, appID := range cx.txn.Txn.ForeignApps { foreignAddress := cx.getApplicationAddress(appID) if addr == foreignAddress { - return addr, invalidIndex, nil + return true } } } - // this app's address is also allowed - if err != nil { - appAddr := cx.getApplicationAddress(cx.appID) - if appAddr == addr { - return addr, invalidIndex, nil - } + if cx.getApplicationAddress(cx.appID) == addr { + return true } - return addr, idx, err + return false } func (cx *EvalContext) mutableAccountReference(account stackValue) (basics.Address, uint64, error) { @@ -4465,17 +4473,17 @@ func (cx *EvalContext) localsReference(account stackValue, ref uint64) (basics.A return basics.Address{}, 0, 0, err } aid := basics.AppIndex(ref) - if cx.available.allowsLocals(addr, aid) { + if cx.allowsLocals(addr, aid) { return addr, aid, unused, nil } if ref == 0 { aid := cx.appID - if cx.available.allowsLocals(addr, aid) { + if cx.allowsLocals(addr, aid) { return addr, aid, unused, nil } } else if ref <= uint64(len(cx.txn.Txn.ForeignApps)) { aid := cx.txn.Txn.ForeignApps[ref-1] - if cx.available.allowsLocals(addr, aid) { + if cx.allowsLocals(addr, aid) { return addr, aid, unused, nil } } @@ -4554,12 +4562,12 @@ func (cx *EvalContext) holdingReference(account stackValue, ref uint64) (basics. return basics.Address{}, 0, err } aid := basics.AssetIndex(ref) - if cx.available.allowsHolding(addr, aid) { + if cx.allowsHolding(addr, aid) { return addr, aid, nil } if ref < uint64(len(cx.txn.Txn.ForeignAssets)) { aid := cx.txn.Txn.ForeignAssets[ref] - if cx.available.allowsHolding(addr, aid) { + if cx.allowsHolding(addr, aid) { return addr, aid, nil } } @@ -5340,7 +5348,7 @@ func opItxnSubmit(cx *EvalContext) (err error) { // account and the asa or app, but not the holding or locals, because // the caller gained access to the two top resources by group sharing // from two different transactions. - err = cx.available.allows(cx.EvalParams, &cx.subtxns[itx].Txn, cx.version, calledVersion) + err = cx.allows(&cx.subtxns[itx].Txn, calledVersion) if err != nil { return err } diff --git a/data/transactions/logic/evalAppTxn_test.go b/data/transactions/logic/evalAppTxn_test.go index 3936e76b81..f396158bac 100644 --- a/data/transactions/logic/evalAppTxn_test.go +++ b/data/transactions/logic/evalAppTxn_test.go @@ -109,7 +109,7 @@ func TestFieldTypes(t *testing.T) { TestApp(t, "itxn_begin; byte \"\"; itxn_field CloseRemainderTo;", ep, "not an address") TestApp(t, "itxn_begin; byte \"\"; itxn_field AssetSender;", ep, "not an address") // can't really tell if it's an addres, so 32 bytes gets further - TestApp(t, "itxn_begin; byte \"01234567890123456789012345678901\"; itxn_field AssetReceiver;", + TestApp(t, "itxn_begin; byte \"01234567890123456789012345678901\"; itxn_field AssetReceiver; int 1", ep, "invalid Account reference") // but a b32 string rep is not an account TestApp(t, "itxn_begin; byte \"GAYTEMZUGU3DOOBZGAYTEMZUGU3DOOBZGAYTEMZUGU3DOOBZGAYZIZD42E\"; itxn_field AssetCloseTo;", diff --git a/data/transactions/logic/resources.go b/data/transactions/logic/resources.go index 1ec61a1af8..dffbb9ced2 100644 --- a/data/transactions/logic/resources.go +++ b/data/transactions/logic/resources.go @@ -92,20 +92,22 @@ func (r *resources) fill(tx *transactions.Transaction, ep *EvalParams) { r.fillAssetFreeze(&tx.Header, &tx.AssetFreezeTxnFields) case protocol.ApplicationCallTx: r.fillApplicationCall(ep, &tx.Header, &tx.ApplicationCallTxnFields) + default: + panic(tx.Type) } } -func (r *resources) allows(ep *EvalParams, tx *transactions.Transaction, callerVer, calleeVer uint64) error { +func (cx *EvalContext) allows(tx *transactions.Transaction, calleeVer uint64) error { switch tx.Type { case protocol.PaymentTx, protocol.KeyRegistrationTx, protocol.AssetConfigTx: // these transactions don't touch cross-product resources, so no error is possible return nil case protocol.AssetTransferTx: - return r.allowsAssetTransfer(&tx.Header, &tx.AssetTransferTxnFields) + return cx.allowsAssetTransfer(&tx.Header, &tx.AssetTransferTxnFields) case protocol.AssetFreezeTx: - return r.allowsAssetFreeze(&tx.Header, &tx.AssetFreezeTxnFields) + return cx.allowsAssetFreeze(&tx.Header, &tx.AssetFreezeTxnFields) case protocol.ApplicationCallTx: - return r.allowsApplicationCall(ep, &tx.Header, &tx.ApplicationCallTxnFields, callerVer, calleeVer) + return cx.allowsApplicationCall(&tx.Header, &tx.ApplicationCallTxnFields, cx.version, calleeVer) default: return fmt.Errorf("unknown inner transaction type %s", tx.Type) } @@ -147,70 +149,92 @@ func (r *resources) fillAssetTransfer(hdr *transactions.Header, tx *transactions } // allowsHolding checks if a holding is available under the txgroup sharing rules -func (r *resources) allowsHolding(addr basics.Address, ai basics.AssetIndex) bool { +func (cx *EvalContext) allowsHolding(addr basics.Address, ai basics.AssetIndex) bool { + r := cx.available if _, ok := r.sharedHoldings[ledgercore.AccountAsset{Address: addr, Asset: ai}]; ok { return true } - // All holdings of created assets are available + // If an ASA was created in this group, then allow holding access for any allowed account. for _, created := range r.createdAsas { if created == ai { - return true + return cx.availableAccount(addr) + } + } + // If the address was "created" by making its app in this group, then allow for allowed assets. + for _, created := range r.createdApps { + if cx.getApplicationAddress(created) == addr { + return cx.availableAsset(ai) } } + // If the current txn is a creation, the new appID won't be in r.createdApps + // yet, but it should get the same special treatment. + if cx.txn.Txn.ApplicationID == 0 && cx.getApplicationAddress(cx.appID) == addr { + return cx.availableAsset(ai) + } return false } // allowsLocals checks if a local state is available under the txgroup sharing rules -func (r *resources) allowsLocals(addr basics.Address, ai basics.AppIndex) bool { +func (cx *EvalContext) allowsLocals(addr basics.Address, ai basics.AppIndex) bool { + r := cx.available if _, ok := r.sharedLocals[ledgercore.AccountApp{Address: addr, App: ai}]; ok { return true } // All locals of created apps are available for _, created := range r.createdApps { if created == ai { - return true + return cx.availableAccount(addr) } } + // All locals of created app accounts are available + for _, created := range r.createdApps { + if cx.getApplicationAddress(created) == addr { + return cx.availableApp(ai) + } + } + if cx.txn.Txn.ApplicationID == 0 && cx.getApplicationAddress(cx.appID) == addr { + return cx.availableApp(ai) + } return false } -func (r *resources) requireHolding(acct basics.Address, id basics.AssetIndex) error { +func (cx *EvalContext) requireHolding(acct basics.Address, id basics.AssetIndex) error { /* Previous versions allowed inner appls with zeros in "required" places, even if that 0 resource should have be inaccessible, because the check - was done at itxn_field time, and maybe the app siimply didn't set the + was done at itxn_field time, and maybe the app simply didn't set the field. */ if id == 0 || acct.IsZero() { return nil } - if !r.allowsHolding(acct, id) { - return fmt.Errorf("invalid Holding access %s x %d", acct, id) + if !cx.allowsHolding(acct, id) { + return fmt.Errorf("invalid Holding access %s x %d would be possible", acct, id) } return nil } -func (r *resources) requireLocals(acct basics.Address, id basics.AppIndex) error { - if !r.allowsLocals(acct, id) { - return fmt.Errorf("invalid Local State access %s x %d", acct, id) +func (cx *EvalContext) requireLocals(acct basics.Address, id basics.AppIndex) error { + if !cx.allowsLocals(acct, id) { + return fmt.Errorf("invalid Local State access %s x %d would be possible", acct, id) } return nil } -func (r *resources) allowsAssetTransfer(hdr *transactions.Header, tx *transactions.AssetTransferTxnFields) error { - err := r.requireHolding(hdr.Sender, tx.XferAsset) +func (cx *EvalContext) allowsAssetTransfer(hdr *transactions.Header, tx *transactions.AssetTransferTxnFields) error { + err := cx.requireHolding(hdr.Sender, tx.XferAsset) if err != nil { - return fmt.Errorf("axfer Sender: %v", err) + return fmt.Errorf("axfer Sender: %w", err) } - err = r.requireHolding(tx.AssetReceiver, tx.XferAsset) + err = cx.requireHolding(tx.AssetReceiver, tx.XferAsset) if err != nil { - return fmt.Errorf("axfer AssetReceiver: %v", err) + return fmt.Errorf("axfer AssetReceiver: %w", err) } - err = r.requireHolding(tx.AssetSender, tx.XferAsset) + err = cx.requireHolding(tx.AssetSender, tx.XferAsset) if err != nil { - return fmt.Errorf("axfer AssetSender: %v", err) + return fmt.Errorf("axfer AssetSender: %w", err) } - err = r.requireHolding(tx.AssetCloseTo, tx.XferAsset) + err = cx.requireHolding(tx.AssetCloseTo, tx.XferAsset) if err != nil { - return fmt.Errorf("axfer AssetCloseTo: %v", err) + return fmt.Errorf("axfer AssetCloseTo: %w", err) } return nil } @@ -222,10 +246,10 @@ func (r *resources) fillAssetFreeze(hdr *transactions.Header, tx *transactions.A r.shareAccountAndHolding(tx.FreezeAccount, id) } -func (r *resources) allowsAssetFreeze(hdr *transactions.Header, tx *transactions.AssetFreezeTxnFields) error { - err := r.requireHolding(tx.FreezeAccount, tx.FreezeAsset) +func (cx *EvalContext) allowsAssetFreeze(hdr *transactions.Header, tx *transactions.AssetFreezeTxnFields) error { + err := cx.requireHolding(tx.FreezeAccount, tx.FreezeAsset) if err != nil { - return fmt.Errorf("afrz FreezeAccount: %v", err) + return fmt.Errorf("afrz FreezeAccount: %w", err) } return nil } @@ -284,8 +308,8 @@ func (r *resources) fillApplicationCall(ep *EvalParams, hdr *transactions.Header } } -func (r *resources) allowsApplicationCall(ep *EvalParams, hdr *transactions.Header, tx *transactions.ApplicationCallTxnFields, callerVer, calleeVer uint64) error { - // If an old (pre resorce sharing) app is being called from an app that has +func (cx *EvalContext) allowsApplicationCall(hdr *transactions.Header, tx *transactions.ApplicationCallTxnFields, callerVer, calleeVer uint64) error { + // If an old (pre resource sharing) app is being called from an app that has // resource sharing enabled, we need to confirm that no new "cross-product" // resources have become available. if callerVer < resourceSharingVersion || calleeVer >= resourceSharingVersion { @@ -299,28 +323,28 @@ func (r *resources) allowsApplicationCall(ep *EvalParams, hdr *transactions.Head txAccounts = append(txAccounts, hdr.Sender) txAccounts = append(txAccounts, tx.Accounts...) if id := tx.ApplicationID; id != 0 { - txAccounts = append(txAccounts, ep.getApplicationAddress(id)) + txAccounts = append(txAccounts, cx.getApplicationAddress(id)) } for _, id := range tx.ForeignApps { - txAccounts = append(txAccounts, ep.getApplicationAddress(id)) + txAccounts = append(txAccounts, cx.getApplicationAddress(id)) } for _, address := range txAccounts { for _, id := range tx.ForeignAssets { - err := r.requireHolding(address, id) + err := cx.requireHolding(address, id) if err != nil { - return fmt.Errorf("appl ForeignAssets: %v", err) + return fmt.Errorf("appl ForeignAssets: %w", err) } } if id := tx.ApplicationID; id != 0 { - err := r.requireLocals(address, id) + err := cx.requireLocals(address, id) if err != nil { - return fmt.Errorf("appl ApplicationID: %v", err) + return fmt.Errorf("appl ApplicationID: %w", err) } } for _, id := range tx.ForeignApps { - err := r.requireLocals(address, id) + err := cx.requireLocals(address, id) if err != nil { - return fmt.Errorf("appl ForeignApps: %v", err) + return fmt.Errorf("appl ForeignApps: %w", err) } } } diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 56b31e4469..8cb017ab33 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -179,6 +179,31 @@ pop; pop; int 1 logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, nil) } +// TestNewAppAccount checks whether a newly created app can put its own address +// into `itxn_field Accounts`. +func TestNewAppAccount(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + ep, tx, ledger := logic.MakeSampleEnv() + + accept := logic.TestProg(t, "int 1", 6) + alice := basics.Address{1, 1, 1, 1, 1} + ledger.NewApp(alice, 4, basics.AppParams{ + ApprovalProgram: accept.Program, + }) + callWithMyAccount := ` +itxn_begin + int appl; itxn_field TypeEnum + int 4; itxn_field ApplicationID + global CurrentApplicationAddress; itxn_field Accounts +itxn_submit +int 1` + tx.ForeignApps = []basics.AppIndex{4} + ledger.NewAccount(appAddr(888), 50_000) + logic.TestApp(t, callWithMyAccount, ep) +} + // TestOtherTxSharing tests resource sharing across other kinds of transactions besides appl. func TestOtherTxSharing(t *testing.T) { partitiontest.PartitionTest(t) @@ -432,7 +457,7 @@ int 1 // appl can pay the axfer sender appl.ApplicationArgs = [][]byte{senderAcct[:], {asa1}} logic.TestApps(t, []string{"", payToArg}, txntest.Group(&axfer, &appl), 9, ledger) - // bur can't axfer to them, because appAcct doesn't have holding access + // but can't axfer to sender, because appAcct doesn't have holding access for the asa logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger, logic.NewExpect(1, "invalid Holding access")) // and to the receiver diff --git a/ledger/apptxn_test.go b/ledger/apptxn_test.go index fa840b40a4..d40ce4f048 100644 --- a/ledger/apptxn_test.go +++ b/ledger/apptxn_test.go @@ -1833,6 +1833,110 @@ assert endBlock(t, l, eval) } +// TestSelfCheckHoldingNewApp checks whether a newly created app can check its +// own holdings. There can't really be any value in it from before this group, +// since it could not have opted in. But it should be legal to look. +func TestSelfCheckHoldingNewApp(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + genBalances, addrs, _ := ledgertesting.NewTestGenesis() + + // 31 allowed inner appls. + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion) { + dl := NewDoubleLedger(t, genBalances, cv) + defer dl.Close() + + asset := txntest.Txn{ + Type: "acfg", + Sender: addrs[0], + ConfigAsset: 0, + AssetParams: basics.AssetParams{ + Total: 10, + Decimals: 1, + UnitName: "X", + AssetName: "TEN", + }, + } + vb := dl.fullBlock(&asset) + assetID := vb.Block().Payset[0].ApplyData.ConfigAsset + + selfcheck := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: ` + global CurrentApplicationAddress + txn Assets 0 + asset_holding_get AssetBalance + !; assert // is not opted in, so exists=0 + ! // value is also 0 +`, + ForeignAssets: []basics.AssetIndex{assetID}, + } + vb = dl.fullBlock(&selfcheck) + selfcheck.ApplicationID = vb.Block().Payset[0].ApplicationID + + dl.txn(&selfcheck) + + }) +} + +// TestCheckHoldingNewApp checks whether a newly created app (account) can have +// its holding value checked in a later txn. There can't really be any value in +// it from before this group, since it could not have opted in. But it should be +// legal to look. +func TestCheckHoldingNewApp(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + genBalances, addrs, _ := ledgertesting.NewTestGenesis() + + // 31 allowed inner appls. + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion) { + dl := NewDoubleLedger(t, genBalances, cv) + defer dl.Close() + + asset := txntest.Txn{ + Type: "acfg", + Sender: addrs[0], + ConfigAsset: 0, + AssetParams: basics.AssetParams{ + Total: 10, + Decimals: 1, + UnitName: "X", + AssetName: "TEN", + }, + } + vb := dl.fullBlock(&asset) + assetID := vb.Block().Payset[0].ApplyData.ConfigAsset + + check := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` + gaid 0 + app_params_get AppAddress + assert + txn Assets 0 + asset_holding_get AssetBalance + !; assert // is not opted in, so exists=0 + !; assert // value is also 0 +`), + ForeignAssets: []basics.AssetIndex{assetID}, + } + vb = dl.fullBlock(&check) + check.ApplicationID = vb.Block().Payset[0].ApplicationID + + create := txntest.Txn{ + Type: "appl", + Sender: addrs[1], + ApplicationID: 0, + } + dl.txgroup("", &create, &check) + + }) +} + // TestInnerAppVersionCalling ensure that inner app calls must be the >=v6 apps func TestInnerAppVersionCalling(t *testing.T) { partitiontest.PartitionTest(t) diff --git a/ledger/boxtxn_test.go b/ledger/boxtxn_test.go index 47291575bf..ca36770fc7 100644 --- a/ledger/boxtxn_test.go +++ b/ledger/boxtxn_test.go @@ -277,7 +277,8 @@ func TestBoxCreateAvailability(t *testing.T) { `, } - // We know box_create worked because we finished and checked MBR + // We know box_create worked because this failure (checking the MBR) + // happens at the end of the group evaluation. dl.txn(&accessInCreate, "balance 0 below min") // But let's fund it and be sure. This is "psychic". We're going to fund From e9dfd0260e22180d31a049f2d618b0550e760ba5 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 16 Feb 2023 11:13:01 -0500 Subject: [PATCH 10/29] allocbound --- data/transactions/msgp_gen.go | 8 ++++---- data/transactions/teal.go | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/data/transactions/msgp_gen.go b/data/transactions/msgp_gen.go index a8c31a2c18..053330615f 100644 --- a/data/transactions/msgp_gen.go +++ b/data/transactions/msgp_gen.go @@ -2036,8 +2036,8 @@ func (z *EvalDelta) UnmarshalMsg(bts []byte) (o []byte, err error) { err = msgp.WrapError(err, "struct-from-array", "SharedAccts") return } - if zb0010 > 4 { - err = msgp.ErrOverflow(uint64(zb0010), uint64(4)) + if zb0010 > config.MaxEvalDeltaAccounts { + err = msgp.ErrOverflow(uint64(zb0010), uint64(config.MaxEvalDeltaAccounts)) err = msgp.WrapError(err, "struct-from-array", "SharedAccts") return } @@ -2185,8 +2185,8 @@ func (z *EvalDelta) UnmarshalMsg(bts []byte) (o []byte, err error) { err = msgp.WrapError(err, "SharedAccts") return } - if zb0018 > 4 { - err = msgp.ErrOverflow(uint64(zb0018), uint64(4)) + if zb0018 > config.MaxEvalDeltaAccounts { + err = msgp.ErrOverflow(uint64(zb0018), uint64(config.MaxEvalDeltaAccounts)) err = msgp.WrapError(err, "SharedAccts") return } diff --git a/data/transactions/teal.go b/data/transactions/teal.go index dafd10ea8d..37388a0d9f 100644 --- a/data/transactions/teal.go +++ b/data/transactions/teal.go @@ -35,7 +35,10 @@ type EvalDelta struct { // [txn.Sender, txn.Accounts[0], txn.Accounts[1], ..., SharedAccts[0], SharedAccts[1], ...] LocalDeltas map[uint64]basics.StateDelta `codec:"ld,allocbound=config.MaxEvalDeltaAccounts"` - SharedAccts []basics.Address `codec:"sa,allocbound=4"` + // If a program modifies the local of an account that is not the Sender, or + // in txn.Accounts, it must be recorded here, so that the key in LocalDeltas + // can refer to it. + SharedAccts []basics.Address `codec:"sa,allocbound=config.MaxEvalDeltaAccounts"` Logs []string `codec:"lg,allocbound=config.MaxLogCalls"` From bea0c92aa7a30e3eff859429fd0a42446d550d96 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 16 Feb 2023 14:29:12 -0500 Subject: [PATCH 11/29] coverage --- data/transactions/logic/eval.go | 6 +- data/transactions/logic/resources_test.go | 78 +++++++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index acdd5b3781..922c7b3c71 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -4236,9 +4236,9 @@ func opAppGlobalGetEx(cx *EvalContext) error { } // ensureLocalDelta is used to get accountIdx that is usable in the LocalDeltas -// of the EvalDelta. The input accountIdx is "tentative" - if it's longer that -// the txn.Accounts, then we may need to add the address into SharedAccounts, -// and index into it. +// of the EvalDelta. The input accountIdx is "tentative" - if it's longer than +// txn.Accounts, then we may need to add the address into SharedAccounts, and +// index into it. func (cx *EvalContext) ensureLocalDelta(accountIdx uint64, addr basics.Address) uint64 { if accountIdx > uint64(len(cx.txn.Txn.Accounts)) { // the returned accountIdx was just a signal that the account was diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 8cb017ab33..b1d9666655 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -17,6 +17,7 @@ package logic_test import ( + "encoding/binary" "fmt" "testing" @@ -123,6 +124,45 @@ int 1 require.Equal(t, ep.TxnGroup[0].Txn.Sender, ed.SharedAccts[0]) } +// TestBetterLocalErrors convirms that we get specific errors about the missing +// address or app when accessesing a Local State with only one available. +func TestBetterLocalErrors(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + joe := basics.Address{9, 9, 9} + + ep, tx, ledger := logic.MakeSampleEnv() + ledger.NewAccount(joe, 5000000) + ledger.NewApp(joe, 500, basics.AppParams{}) + ledger.NewLocals(joe, 500) + + getLocalEx := ` +txn ApplicationArgs 0 +txn ApplicationArgs 1; btoi +byte "some-key" +app_local_get_ex +pop; pop; int 1 +` + app := make([]byte, 8) + binary.BigEndian.PutUint64(app, 500) + + tx.ApplicationArgs = [][]byte{joe[:], app} + logic.TestApp(t, getLocalEx, ep, "invalid Local State") + tx.Accounts = []basics.Address{joe} + logic.TestApp(t, getLocalEx, ep, "invalid App reference 500") + tx.ForeignApps = []basics.AppIndex{500} + logic.TestApp(t, getLocalEx, ep) + binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 1) + logic.TestApp(t, getLocalEx, ep) + binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 2) // beyond the txn.ForeignApps array + logic.TestApp(t, getLocalEx, ep, "invalid App reference 2") + + binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 1) + tx.Accounts = []basics.Address{} + logic.TestApp(t, getLocalEx, ep, "invalid Account reference "+joe.String()) +} + // TestAssetSharing confirms that as of v9, assets can be accessed across // groups, but that before then, they could not. func TestAssetSharing(t *testing.T) { @@ -179,6 +219,44 @@ pop; pop; int 1 logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, nil) } +// TestBetterHoldingErrors convirms that we get specific errors about the missing +// address or asa when accessesing a holding with only one available. +func TestBetterHoldingErrors(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + joe := basics.Address{9, 9, 9} + + ep, tx, ledger := logic.MakeSampleEnv() + ledger.NewAccount(joe, 5000000) + ledger.NewAsset(joe, 200, basics.AssetParams{}) + // as creator, joe will also be opted in + + getHoldingBalance := ` +txn ApplicationArgs 0 +txn ApplicationArgs 1; btoi +asset_holding_get AssetBalance +pop; pop; int 1 +` + asa := make([]byte, 8) + binary.BigEndian.PutUint64(asa, 200) + + tx.ApplicationArgs = [][]byte{joe[:], asa} + logic.TestApp(t, getHoldingBalance, ep, "invalid Holding access "+joe.String()) + tx.Accounts = []basics.Address{joe} + logic.TestApp(t, getHoldingBalance, ep, "invalid Asset reference 200") + tx.ForeignAssets = []basics.AssetIndex{200} + logic.TestApp(t, getHoldingBalance, ep) + binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 0) + logic.TestApp(t, getHoldingBalance, ep) + binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 1) // beyond the txn.ForeignAssets array + logic.TestApp(t, getHoldingBalance, ep, "invalid Asset reference 1") + + binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 0) + tx.Accounts = []basics.Address{} + logic.TestApp(t, getHoldingBalance, ep, "invalid Account reference "+joe.String()) +} + // TestNewAppAccount checks whether a newly created app can put its own address // into `itxn_field Accounts`. func TestNewAppAccount(t *testing.T) { From ef20192a099844b2cedef43f819f3ebb36be29d2 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 16 Feb 2023 16:30:03 -0500 Subject: [PATCH 12/29] Test account passing across versions for more coverage --- data/transactions/logic/resources.go | 2 +- data/transactions/logic/resources_test.go | 40 ++++++++++++++--------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/data/transactions/logic/resources.go b/data/transactions/logic/resources.go index dffbb9ced2..8188e7bf98 100644 --- a/data/transactions/logic/resources.go +++ b/data/transactions/logic/resources.go @@ -160,7 +160,7 @@ func (cx *EvalContext) allowsHolding(addr basics.Address, ai basics.AssetIndex) return cx.availableAccount(addr) } } - // If the address was "created" by making its app in this group, then allow for allowed assets. + // If the address was "created" by making its app in this group, then allow for available assets. for _, created := range r.createdApps { if cx.getApplicationAddress(created) == addr { return cx.availableAsset(ai) diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index b1d9666655..6682489ea5 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -124,7 +124,7 @@ int 1 require.Equal(t, ep.TxnGroup[0].Txn.Sender, ed.SharedAccts[0]) } -// TestBetterLocalErrors convirms that we get specific errors about the missing +// TestBetterLocalErrors confirms that we get specific errors about the missing // address or app when accessesing a Local State with only one available. func TestBetterLocalErrors(t *testing.T) { partitiontest.PartitionTest(t) @@ -219,7 +219,7 @@ pop; pop; int 1 logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, nil) } -// TestBetterHoldingErrors convirms that we get specific errors about the missing +// TestBetterHoldingErrors confirms that we get specific errors about the missing // address or asa when accessesing a holding with only one available. func TestBetterHoldingErrors(t *testing.T) { partitiontest.PartitionTest(t) @@ -257,29 +257,37 @@ pop; pop; int 1 logic.TestApp(t, getHoldingBalance, ep, "invalid Account reference "+joe.String()) } -// TestNewAppAccount checks whether a newly created app can put its own address -// into `itxn_field Accounts`. -func TestNewAppAccount(t *testing.T) { +// TestAccountPassing checks that some special accounts can be passed in +// txn.Accounts for a called app. +func TestAccountPassing(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - ep, tx, ledger := logic.MakeSampleEnv() + for v := uint64(7); v <= logic.LogicVersion; v++ { + ep, tx, ledger := logic.MakeSampleEnvWithVersion(v) - accept := logic.TestProg(t, "int 1", 6) - alice := basics.Address{1, 1, 1, 1, 1} - ledger.NewApp(alice, 4, basics.AppParams{ - ApprovalProgram: accept.Program, - }) - callWithMyAccount := ` + accept := logic.TestProg(t, "int 1", 6) + alice := basics.Address{1, 1, 1, 1, 1} + ledger.NewApp(alice, 4, basics.AppParams{ + ApprovalProgram: accept.Program, + }) + callWithAccount := ` itxn_begin int appl; itxn_field TypeEnum int 4; itxn_field ApplicationID - global CurrentApplicationAddress; itxn_field Accounts + %s; itxn_field Accounts itxn_submit int 1` - tx.ForeignApps = []basics.AppIndex{4} - ledger.NewAccount(appAddr(888), 50_000) - logic.TestApp(t, callWithMyAccount, ep) + tx.ForeignApps = []basics.AppIndex{4} + ledger.NewAccount(appAddr(888), 50_000) + // First show that we're not just letting anything get passed in + logic.TestApp(t, fmt.Sprintf(callWithAccount, "int 32; bzero; byte 0x07; b|"), ep, + "invalid Account reference AAAAA") + // Now show we can pass our own address + logic.TestApp(t, fmt.Sprintf(callWithAccount, "global CurrentApplicationAddress"), ep) + // Or the address of one of our ForeignApps + logic.TestApp(t, fmt.Sprintf(callWithAccount, "addr "+basics.AppIndex(4).Address().String()), ep) + } } // TestOtherTxSharing tests resource sharing across other kinds of transactions besides appl. From 8b09e825fd1b6d9c77c206cda92c91c06b69617f Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Fri, 17 Feb 2023 21:11:42 -0500 Subject: [PATCH 13/29] Bob CR --- data/transactions/logic/eval.go | 33 +++++++++++------------ data/transactions/logic/resources_test.go | 3 +++ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 922c7b3c71..934d01b622 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -3983,6 +3983,18 @@ func opExtract64Bits(cx *EvalContext) error { return opExtractNBytes(cx, 8) // extract 8 bytes } +// assignAccount is used to convert a stackValue into a 32-byte account value, +// enforcing any "availability" restrictions in force. +func (cx *EvalContext) assignAccount(sv stackValue) (basics.Address, error) { + _, err := sv.address() + if err != nil { + return basics.Address{}, err + } + + addr, _, err := cx.accountReference(sv) + return addr, err +} + // accountReference yields the address and Accounts offset designated by a // stackValue. If the stackValue is the app account, an account of an app in // created.apps, an account of an app in foreignApps, or an account made @@ -3993,8 +4005,8 @@ func opExtract64Bits(cx *EvalContext) error { // we can set/del it. Return the proper index. // Starting in v9, apps can change local state on these accounts by adding the -// address to EvalDelta.ShardAccounts and indexing it there. But at this level, -// we still report the "failure" to find an index with `invalidIndex=len+1` That +// address to EvalDelta.SharedAccounts and indexing it there. But at this level, +// we still report the "failure" to find an index with `len(Accounts)+1` That // value allows mutableAccountReference to decide whether to report an error or // not, based on version. @@ -4017,8 +4029,7 @@ func (cx *EvalContext) accountReference(account stackValue) (basics.Address, uin if !ok { return addr, 0, err } - invalidIndex := uint64(len(cx.txn.Txn.Accounts) + 1) - return addr, invalidIndex, nil + return addr, uint64(len(cx.txn.Txn.Accounts) + 1), nil } func (cx *EvalContext) availableAccount(addr basics.Address) bool { @@ -4848,18 +4859,6 @@ func opItxnNext(cx *EvalContext) error { return addInnerTxn(cx) } -// assignAccount is used to convert a stackValue into a 32-byte account value, -// enforcing any "availability" restrictions in force. -func (cx *EvalContext) assignAccount(sv stackValue) (basics.Address, error) { - _, err := sv.address() - if err != nil { - return basics.Address{}, err - } - - addr, _, err := cx.accountReference(sv) - return addr, err -} - // assignAsset is used to convert a stackValue to a uint64 assetIndex, reporting // any errors due to availability rules or type checking. func (cx *EvalContext) assignAsset(sv stackValue) (basics.AssetIndex, error) { @@ -4877,7 +4876,7 @@ func (cx *EvalContext) assignAsset(sv stackValue) (basics.AssetIndex, error) { } // availableAsset determines whether an asset is "available". Before -// resourceSharingVersion, an asset had to be available for for asset param +// resourceSharingVersion, an asset had to be available for asset param // lookups, asset holding lookups, and asset id assignments to inner // transactions. After resourceSharingVersion, the distinction must be more fine // grained. It must be available for asset param lookups, or use in an asset diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 6682489ea5..8fda5174ef 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -433,6 +433,9 @@ func TestOtherTxSharing(t *testing.T) { // TestSharedInnerTxns checks how inner txns access resources. func TestSharedInnerTxns(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + _, _, ledger := logic.MakeSampleEnv() const asa1 = 201 From c70f0b6ecf9149c95503dd4f3aa5994078e107df Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 21 Feb 2023 14:54:23 -0500 Subject: [PATCH 14/29] Fix suggested by @jasonpaulos See TestAccessMyLocals for evidence of proper beahior --- data/transactions/logic/eval.go | 4 +- data/transactions/logic/resources.go | 4 ++ data/transactions/logic/resources_test.go | 45 +++++++++++++++++++++++ ledger/apptxn_test.go | 8 ++-- ledger/eval_simple_test.go | 8 ++-- 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 934d01b622..2012f7d713 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -4488,12 +4488,12 @@ func (cx *EvalContext) localsReference(account stackValue, ref uint64) (basics.A return addr, aid, unused, nil } if ref == 0 { - aid := cx.appID + aid = cx.appID if cx.allowsLocals(addr, aid) { return addr, aid, unused, nil } } else if ref <= uint64(len(cx.txn.Txn.ForeignApps)) { - aid := cx.txn.Txn.ForeignApps[ref-1] + aid = cx.txn.Txn.ForeignApps[ref-1] if cx.allowsLocals(addr, aid) { return addr, aid, unused, nil } diff --git a/data/transactions/logic/resources.go b/data/transactions/logic/resources.go index 8188e7bf98..ad5e242b16 100644 --- a/data/transactions/logic/resources.go +++ b/data/transactions/logic/resources.go @@ -186,6 +186,10 @@ func (cx *EvalContext) allowsLocals(addr basics.Address, ai basics.AppIndex) boo return cx.availableAccount(addr) } } + if cx.txn.Txn.ApplicationID == 0 && cx.appID == ai { + return cx.availableAccount(addr) + } + // All locals of created app accounts are available for _, created := range r.createdApps { if cx.getApplicationAddress(created) == addr { diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 8fda5174ef..2bc0d7001d 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/algorand/go-algorand/data/basics" + "github.com/algorand/go-algorand/data/transactions" "github.com/algorand/go-algorand/data/transactions/logic" "github.com/algorand/go-algorand/data/txntest" "github.com/algorand/go-algorand/protocol" @@ -665,3 +666,47 @@ int 1 }) } + +// TestAccessMyLocals confirms that apps can access their OWN locals if they opt +// in at creation time. +func TestAccessMyLocals(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + ep, tx, ledger := logic.MakeSampleEnv() + + sender := basics.Address{1, 2, 3, 4} + ledger.NewAccount(sender, 1_000_000) + // we don't really process transactions in these tests, so despite the + // OptInOC below, we must manually opt the sender into the app that + // will get created for this test. + ledger.NewLocals(sender, 888) + + *tx = txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: sender, + ApplicationID: 0, + OnCompletion: transactions.OptInOC, + LocalStateSchema: basics.StateSchema{ + NumUint: 1, + }, + }.Txn() + source := ` + int 0 + byte "X" + app_local_get + ! + assert + int 0 + byte "X" + int 7 + app_local_put + int 0 + byte "X" + app_local_get + int 7 + == +` + logic.TestApp(t, source, ep) + +} diff --git a/ledger/apptxn_test.go b/ledger/apptxn_test.go index d40ce4f048..0ec1cd9b9d 100644 --- a/ledger/apptxn_test.go +++ b/ledger/apptxn_test.go @@ -1843,8 +1843,8 @@ func TestSelfCheckHoldingNewApp(t *testing.T) { genBalances, addrs, _ := ledgertesting.NewTestGenesis() // 31 allowed inner appls. - ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion) { - dl := NewDoubleLedger(t, genBalances, cv) + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) defer dl.Close() asset := txntest.Txn{ @@ -1892,8 +1892,8 @@ func TestCheckHoldingNewApp(t *testing.T) { genBalances, addrs, _ := ledgertesting.NewTestGenesis() // 31 allowed inner appls. - ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion) { - dl := NewDoubleLedger(t, genBalances, cv) + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) defer dl.Close() asset := txntest.Txn{ diff --git a/ledger/eval_simple_test.go b/ledger/eval_simple_test.go index 436a9ad398..c817e0c143 100644 --- a/ledger/eval_simple_test.go +++ b/ledger/eval_simple_test.go @@ -222,8 +222,8 @@ func TestHoldingGet(t *testing.T) { genBalances, addrs, _ := ledgertesting.NewTestGenesis() // 24 is first version with apps - ledgertesting.TestConsensusRange(t, 24, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion) { - dl := NewDoubleLedger(t, genBalances, cv) + ledgertesting.TestConsensusRange(t, 24, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) defer dl.Close() makegold := txntest.Txn{ @@ -317,8 +317,8 @@ func TestLocalGetEx(t *testing.T) { genBalances, addrs, _ := ledgertesting.NewTestGenesis() // 24 is first version with apps - ledgertesting.TestConsensusRange(t, 24, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion) { - dl := NewDoubleLedger(t, genBalances, cv) + ledgertesting.TestConsensusRange(t, 24, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) defer dl.Close() makeapp := txntest.Txn{ From b106666c6f3699912cf5d0380534a7ff422a3507 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Wed, 22 Feb 2023 13:52:46 -0500 Subject: [PATCH 15/29] Add (and use) a simpler way to do cross version app testing --- data/transactions/logic/evalStateful_test.go | 193 +++++++++++-------- data/transactions/logic/export_test.go | 1 + data/transactions/logic/resources_test.go | 51 ++--- 3 files changed, 139 insertions(+), 106 deletions(-) diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index 55bc8d949b..3f09798a2d 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -510,6 +510,30 @@ func testAppFull(t *testing.T, program []byte, gi int, aid basics.AppIndex, ep * return delta } +// testLogicRange allows for running tests against a range of avm +// versions. Generally `start` will be the version that introduced the feature, +// and `stop` will be 0 to indicate it should work right on up through the +// current version. `stop` will be an actual version number if we're confirming +// that something STOPS working as of a particular version. Note that this does +// *not* use different consensus versions. It is tempting to make it find the +// lowest possible consensus version in the loop in order to support the `v` it +// it working on. For super confidence, one might argue this should be a nested +// loop over all of the consensus versions that work with the `v`, from the +// first possible, to vFuture. +func testLogicRange(t *testing.T, start, stop int, test func(t *testing.T, ep *EvalParams, tx *transactions.Transaction, ledger *Ledger)) { + t.Helper() + if stop == 0 { // Treat 0 as current max + stop = LogicVersion + } + + for v := uint64(start); v <= uint64(stop); v++ { + t.Run(fmt.Sprintf("v=%d", v), func(t *testing.T) { + ep, tx, ledger := makeSampleEnvWithVersion(v) + test(t, ep, tx, ledger) + }) + } +} + func TestMinBalance(t *testing.T) { partitiontest.PartitionTest(t) @@ -1152,16 +1176,18 @@ intc_1 func TestAppParams(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - ep, tx, ledger := makeSampleEnv() - ledger.NewAccount(tx.Sender, 1) - ledger.NewApp(tx.Sender, 100, basics.AppParams{}) - - /* app id is in ForeignApps, but does not exist */ - source := "int 56; app_params_get AppExtraProgramPages; int 0; ==; assert; int 0; ==" - testApp(t, source, ep) - /* app id is in ForeignApps, but has zero ExtraProgramPages */ - source = "int 100; app_params_get AppExtraProgramPages; int 1; ==; assert; int 0; ==" - testApp(t, source, ep) + // start at 5 for app_params_get + testLogicRange(t, 5, 0, func(t *testing.T, ep *EvalParams, tx *transactions.Transaction, ledger *Ledger) { + ledger.NewAccount(tx.Sender, 1) + ledger.NewApp(tx.Sender, 100, basics.AppParams{}) + + /* app id is in ForeignApps, but does not exist */ + source := "int 56; app_params_get AppExtraProgramPages; int 0; ==; assert; int 0; ==" + testApp(t, source, ep) + /* app id is in ForeignApps, but has zero ExtraProgramPages */ + source = "int 100; app_params_get AppExtraProgramPages; int 1; ==; assert; int 0; ==" + testApp(t, source, ep) + }) } func TestAcctParams(t *testing.T) { @@ -1240,6 +1266,7 @@ func TestAcctParams(t *testing.T) { testApp(t, source, ep) } +// TestGlobalNonDelete ensures that a deletion is not inserted in the delta if the global didn't exist func TestGlobalNonDelete(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() @@ -1256,6 +1283,7 @@ int 1 require.Empty(t, delta.LocalDeltas) } +// TestLocalNonDelete ensures that a deletion is not inserted in the delta if the local didn't exist func TestLocalNonDelete(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() @@ -1916,24 +1944,26 @@ byte "myval" == ` - ep, txn, ledger := makeSampleEnv() - txn.ApplicationID = 100 - txn.ForeignApps = []basics.AppIndex{txn.ApplicationID, 101} - ledger.NewAccount(txn.Sender, 1) - ledger.NewApp(txn.Sender, 100, basics.AppParams{}) - - delta := testApp(t, source, ep, "no app 101") - require.Empty(t, delta.GlobalDelta) - require.Empty(t, delta.LocalDeltas) - - ledger.NewApp(txn.Receiver, 101, basics.AppParams{}) - ledger.NewApp(txn.Receiver, 100, basics.AppParams{}) // this keeps current app id = 100 - algoValue := basics.TealValue{Type: basics.TealBytesType, Bytes: "myval"} - ledger.NewGlobal(101, "mykey", algoValue) - - delta = testApp(t, source, ep) - require.Empty(t, delta.GlobalDelta) - require.Empty(t, delta.LocalDeltas) + // app_global_get_ex starts in v2 + testLogicRange(t, 2, 0, func(t *testing.T, ep *EvalParams, txn *transactions.Transaction, ledger *Ledger) { + txn.ApplicationID = 100 + txn.ForeignApps = []basics.AppIndex{txn.ApplicationID, 101} + ledger.NewAccount(txn.Sender, 1) + ledger.NewApp(txn.Sender, 100, basics.AppParams{}) + + delta := testApp(t, source, ep, "no app 101") + require.Empty(t, delta.GlobalDelta) + require.Empty(t, delta.LocalDeltas) + + ledger.NewApp(txn.Receiver, 101, basics.AppParams{}) + ledger.NewApp(txn.Receiver, 100, basics.AppParams{}) // this keeps current app id = 100 + algoValue := basics.TealValue{Type: basics.TealBytesType, Bytes: "myval"} + ledger.NewGlobal(101, "mykey", algoValue) + + delta = testApp(t, source, ep) + require.Empty(t, delta.GlobalDelta) + require.Empty(t, delta.LocalDeltas) + }) } func TestBlankKey(t *testing.T) { @@ -2318,7 +2348,7 @@ int 1 require.Equal(t, 1, len(delta.LocalDeltas[0])) } -func TestEnumFieldErrors(t *testing.T) { // nolint:paralleltest // manipulates globalFieldSpecs +func TestEnumFieldErrors(t *testing.T) { // nolint:paralleltest // manipulates txnFieldSpecs partitiontest.PartitionTest(t) source := `txn Amount` @@ -2855,64 +2885,64 @@ func TestSelfMutateCurrent(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - ep, tx, ledger := makeSampleEnv() - - /* In order to test that apps can now mutate their own app's local state, - we're going to set up a ledger in which an app account is opted into - itself. */ - ledger.NewLocals(basics.AppIndex(888).Address(), 888) - ledger.NewLocal(basics.AppIndex(888).Address(), 888, "hey", - basics.TealValue{Type: basics.TealUintType, Uint: 77}) + // start at 9, when such mutation became legal + testLogicRange(t, 9, 0, func(t *testing.T, ep *EvalParams, tx *transactions.Transaction, ledger *Ledger) { + /* In order to test that apps can now mutate their own app's local state, + we're going to set up a ledger in which an app account is opted into + itself. */ + ledger.NewLocals(basics.AppIndex(888).Address(), 888) + ledger.NewLocal(basics.AppIndex(888).Address(), 888, "hey", + basics.TealValue{Type: basics.TealUintType, Uint: 77}) - source := ` + source := ` global CurrentApplicationAddress byte "hey" int 42 app_local_put int 1 ` - ed := testApp(t, source, ep) - require.Len(t, ed.LocalDeltas, 1) - require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 - - require.Contains(t, ed.LocalDeltas, uint64(2)) - sd := ed.LocalDeltas[2] - require.Len(t, sd, 1) - require.Contains(t, sd, "hey") - require.EqualValues(t, 42, sd["hey"].Uint) - require.Len(t, ed.SharedAccts, 1) - require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) - - /* Confirm it worked. */ - source = ` + ed := testApp(t, source, ep) + require.Len(t, ed.LocalDeltas, 1) + require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 + + require.Contains(t, ed.LocalDeltas, uint64(2)) + sd := ed.LocalDeltas[2] + require.Len(t, sd, 1) + require.Contains(t, sd, "hey") + require.EqualValues(t, 42, sd["hey"].Uint) + require.Len(t, ed.SharedAccts, 1) + require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) + + /* Confirm it worked. */ + source = ` global CurrentApplicationAddress byte "hey" app_local_get int 42 == ` - testApp(t, source, ep) + testApp(t, source, ep) - source = ` + source = ` global CurrentApplicationAddress byte "hey" app_local_del int 1 ` - ed = testApp(t, source, ep) - require.Len(t, ed.LocalDeltas, 1) - require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 - - require.Contains(t, ed.LocalDeltas, uint64(2)) - sd = ed.LocalDeltas[2] - require.Len(t, sd, 1) - require.Contains(t, sd, "hey") - require.EqualValues(t, basics.DeleteAction, sd["hey"].Action) - require.Len(t, ed.SharedAccts, 1) - require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) - - // Now, repeat the "put" test with multiple keys, to ensure only one address is added to SharedAccts - source = ` + ed = testApp(t, source, ep) + require.Len(t, ed.LocalDeltas, 1) + require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 + + require.Contains(t, ed.LocalDeltas, uint64(2)) + sd = ed.LocalDeltas[2] + require.Len(t, sd, 1) + require.Contains(t, sd, "hey") + require.EqualValues(t, basics.DeleteAction, sd["hey"].Action) + require.Len(t, ed.SharedAccts, 1) + require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) + + // Now, repeat the "put" test with multiple keys, to ensure only one address is added to SharedAccts + source = ` global CurrentApplicationAddress byte "hey" int 42 @@ -2923,17 +2953,18 @@ int 21 app_local_put int 1 ` - ed = testApp(t, source, ep) - require.Len(t, ed.LocalDeltas, 1) - require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 - - require.Contains(t, ed.LocalDeltas, uint64(2)) - sd = ed.LocalDeltas[2] - require.Len(t, sd, 2) - require.Contains(t, sd, "hey") - require.EqualValues(t, 42, sd["hey"].Uint) - require.Contains(t, sd, "joe") - require.EqualValues(t, 21, sd["joe"].Uint) - require.Len(t, ed.SharedAccts, 1) - require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) + ed = testApp(t, source, ep) + require.Len(t, ed.LocalDeltas, 1) + require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 + + require.Contains(t, ed.LocalDeltas, uint64(2)) + sd = ed.LocalDeltas[2] + require.Len(t, sd, 2) + require.Contains(t, sd, "hey") + require.EqualValues(t, 42, sd["hey"].Uint) + require.Contains(t, sd, "joe") + require.EqualValues(t, 21, sd["joe"].Uint) + require.Len(t, ed.SharedAccts, 1) + require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) + }) } diff --git a/data/transactions/logic/export_test.go b/data/transactions/logic/export_test.go index 6ee072aff5..44f90f0400 100644 --- a/data/transactions/logic/export_test.go +++ b/data/transactions/logic/export_test.go @@ -56,6 +56,7 @@ var TestLogic = testLogic var TestApp = testApp var TestAppBytes = testAppBytes var TestApps = testApps +var TestLogicRange = testLogicRange var TestProg = testProg var WithPanicOpcode = withPanicOpcode diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 2bc0d7001d..df2b456810 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -194,7 +194,7 @@ asset_params_get AssetTotal pop; pop; int 1 ` sources := []string{getTotal, getTotal} - // In v8, the first tx can read asset 400, because it's in its foreign arry, + // In v8, the first tx can read asset 400, because it's in its foreign array, // but the second can't logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 8, nil, logic.NewExpect(1, "invalid Asset reference 400")) @@ -264,9 +264,9 @@ func TestAccountPassing(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - for v := uint64(7); v <= logic.LogicVersion; v++ { - ep, tx, ledger := logic.MakeSampleEnvWithVersion(v) - + // appAddressVersion=7 + logic.TestLogicRange(t, 7, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + t.Parallel() accept := logic.TestProg(t, "int 1", 6) alice := basics.Address{1, 1, 1, 1, 1} ledger.NewApp(alice, 4, basics.AppParams{ @@ -288,7 +288,7 @@ int 1` logic.TestApp(t, fmt.Sprintf(callWithAccount, "global CurrentApplicationAddress"), ep) // Or the address of one of our ForeignApps logic.TestApp(t, fmt.Sprintf(callWithAccount, "addr "+basics.AppIndex(4).Address().String()), ep) - } + }) } // TestOtherTxSharing tests resource sharing across other kinds of transactions besides appl. @@ -673,25 +673,25 @@ func TestAccessMyLocals(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - ep, tx, ledger := logic.MakeSampleEnv() - - sender := basics.Address{1, 2, 3, 4} - ledger.NewAccount(sender, 1_000_000) - // we don't really process transactions in these tests, so despite the - // OptInOC below, we must manually opt the sender into the app that - // will get created for this test. - ledger.NewLocals(sender, 888) - - *tx = txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: sender, - ApplicationID: 0, - OnCompletion: transactions.OptInOC, - LocalStateSchema: basics.StateSchema{ - NumUint: 1, - }, - }.Txn() - source := ` + // start at 3, needs assert + logic.TestLogicRange(t, 3, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + sender := basics.Address{1, 2, 3, 4} + ledger.NewAccount(sender, 1_000_000) + // we don't really process transactions in these tests, so despite the + // OptInOC below, we must manually opt the sender into the app that + // will get created for this test. + ledger.NewLocals(sender, 888) + + *tx = txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: sender, + ApplicationID: 0, + OnCompletion: transactions.OptInOC, + LocalStateSchema: basics.StateSchema{ + NumUint: 1, + }, + }.Txn() + source := ` int 0 byte "X" app_local_get @@ -707,6 +707,7 @@ func TestAccessMyLocals(t *testing.T) { int 7 == ` - logic.TestApp(t, source, ep) + logic.TestApp(t, source, ep) + }) } From d60380c47c4844283ec9804ec83aeec1cc28e3aa Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Wed, 22 Feb 2023 16:17:30 -0500 Subject: [PATCH 16/29] Fix app_opted_in for resource sharing, and initial spec changes --- data/transactions/logic/README.md | 34 +++++++++++++++++++++++ data/transactions/logic/README_in.md | 34 +++++++++++++++++++++++ data/transactions/logic/TEAL_opcodes.md | 4 +-- data/transactions/logic/doc.go | 4 +-- data/transactions/logic/eval.go | 7 +---- data/transactions/logic/langspec.json | 4 +-- data/transactions/logic/resources_test.go | 30 ++++++++++++++++++++ 7 files changed, 105 insertions(+), 12 deletions(-) diff --git a/data/transactions/logic/README.md b/data/transactions/logic/README.md index 324cd7d536..6af976489e 100644 --- a/data/transactions/logic/README.md +++ b/data/transactions/logic/README.md @@ -193,6 +193,40 @@ _available_. * Since v7, the account associated with any contract present in the `txn.ForeignApplications` field is _available_. + + * Since v9, there is group-level resource sharing. Any resource that + is available in _some_ top-level transaction in a transaction group + is available in _all_ v9 or later application calls in the group, + whether those application calls are top-level or inner. + + * When considering whether an asset holding or application local + state is available by group-level resource sharing, the holding or + local state must be available in a top-level transaction without + considering group sharing. For example, if account A is made + available in one transaction, and asset X is made available in + another, group resource sharing does _not_ make A's X holding + available. + + * Top-level transactions that are not application calls also make + resources available to group-level resource sharing. The following + resources are made available other transaction types. + + 1. `pay` - `txn.Sender`, `txn.Receiver`, and `txn.CloseRemainderTo` + + 1. `keyreg` - `txn.Sender` + + 1. `acfg` - `txn.Sender`, `txn.ConfigAsset`, and the + `txn.ConfigAsset` holding of `txn.Sender`. + + 1. `axfer` - `txn.Sender`, `txn.AssetSender`, `txnAssetCloseTo`, + `txn.XferAsset` and the `txn.XferAsset` holding of each of + those accounts. + + 1. `afrz` - `txn.Sender`, `txn.FreezeAccount`, `txn.FreezeAsset`, + and the `txn.FreezeAsset` holding of `txn.FreezeAccount`. The + `txn.FreezeAsset` holding of `txn.Sender` is _not_ made + available. + * A Box is _available_ to an Approval Program if _any_ transaction in the same group contains a box reference (`txn.Boxes`) that denotes diff --git a/data/transactions/logic/README_in.md b/data/transactions/logic/README_in.md index 58652ebcf7..9c0e9ec4d9 100644 --- a/data/transactions/logic/README_in.md +++ b/data/transactions/logic/README_in.md @@ -193,6 +193,40 @@ _available_. * Since v7, the account associated with any contract present in the `txn.ForeignApplications` field is _available_. + + * Since v9, there is group-level resource sharing. Any resource that + is available in _some_ top-level transaction in a transaction group + is available in _all_ v9 or later application calls in the group, + whether those application calls are top-level or inner. + + * When considering whether an asset holding or application local + state is available by group-level resource sharing, the holding or + local state must be available in a top-level transaction without + considering group sharing. For example, if account A is made + available in one transaction, and asset X is made available in + another, group resource sharing does _not_ make A's X holding + available. + + * Top-level transactions that are not application calls also make + resources available to group-level resource sharing. The following + resources are made available other transaction types. + + 1. `pay` - `txn.Sender`, `txn.Receiver`, and `txn.CloseRemainderTo` + + 1. `keyreg` - `txn.Sender` + + 1. `acfg` - `txn.Sender`, `txn.ConfigAsset`, and the + `txn.ConfigAsset` holding of `txn.Sender`. + + 1. `axfer` - `txn.Sender`, `txn.AssetSender`, `txnAssetCloseTo`, + `txn.XferAsset` and the `txn.XferAsset` holding of each of + those accounts. + + 1. `afrz` - `txn.Sender`, `txn.FreezeAccount`, `txn.FreezeAsset`, + and the `txn.FreezeAsset` holding of `txn.FreezeAccount`. The + `txn.FreezeAsset` holding of `txn.Sender` is _not_ made + available. + * A Box is _available_ to an Approval Program if _any_ transaction in the same group contains a box reference (`txn.Boxes`) that denotes diff --git a/data/transactions/logic/TEAL_opcodes.md b/data/transactions/logic/TEAL_opcodes.md index 54a80db8f9..7752b1c182 100644 --- a/data/transactions/logic/TEAL_opcodes.md +++ b/data/transactions/logic/TEAL_opcodes.md @@ -838,7 +838,7 @@ Almost all smart contracts should use simpler and smaller methods (such as the [ - Availability: v2 - Mode: Application -params: Txn.Accounts offset (or, since v4, an _available_ account address), _available_ application id (or, since v4, a Txn.ForeignApps offset). Return: value. +params: Txn.Accounts offset (or, since v4, an _available_ account address). Return: value. ## app_opted_in @@ -1037,7 +1037,7 @@ params: Txn.ForeignApps offset or an _available_ app id. Return: did_exist flag - Availability: v3 - Mode: Application -params: Txn.Accounts offset (or, since v4, an _available_ account address), _available_ application id (or, since v4, a Txn.ForeignApps offset). Return: value. +params: Txn.Accounts offset (or, since v4, an _available_ account address). Return: value. ## pushbytes bytes diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go index 31a0412fa3..c64dbff672 100644 --- a/data/transactions/logic/doc.go +++ b/data/transactions/logic/doc.go @@ -337,8 +337,8 @@ var opDocExtras = map[string]string{ "pushints": "pushints args are not added to the intcblock during assembly processes", "getbit": "see explanation of bit ordering in setbit", "setbit": "When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on the integer 0 yields 8, or 2^3. When A is a byte array, index 0 is the leftmost bit of the leftmost byte. Setting bits 0 through 11 to 1 in a 4-byte-array of 0s yields the byte array 0xfff00000. Setting bit 3 to 1 on the 1-byte-array 0x00 yields the byte array 0x10.", - "balance": "params: Txn.Accounts offset (or, since v4, an _available_ account address), _available_ application id (or, since v4, a Txn.ForeignApps offset). Return: value.", - "min_balance": "params: Txn.Accounts offset (or, since v4, an _available_ account address), _available_ application id (or, since v4, a Txn.ForeignApps offset). Return: value.", + "balance": "params: Txn.Accounts offset (or, since v4, an _available_ account address). Return: value.", + "min_balance": "params: Txn.Accounts offset (or, since v4, an _available_ account address). Return: value.", "app_opted_in": "params: Txn.Accounts offset (or, since v4, an _available_ account address), _available_ application id (or, since v4, a Txn.ForeignApps offset). Return: 1 if opted in and 0 otherwise.", "app_local_get": "params: Txn.Accounts offset (or, since v4, an _available_ account address), state key. Return: value. The value is zero (of type uint64) if the key does not exist.", "app_local_get_ex": "params: Txn.Accounts offset (or, since v4, an _available_ account address), _available_ application id (or, since v4, a Txn.ForeignApps offset), state key. Return: did_exist flag (top of the stack, 1 if the application and key existed and 0 otherwise), value. The value is zero (of type uint64) if the key does not exist.", diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 2012f7d713..9445213639 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -4127,12 +4127,7 @@ func opAppOptedIn(cx *EvalContext) error { last := len(cx.stack) - 1 // app prev := last - 1 // account - addr, _, err := cx.accountReference(cx.stack[prev]) - if err != nil { - return err - } - - app, err := cx.appReference(cx.stack[last].Uint, false) + addr, app, _, err := cx.localsReference(cx.stack[prev], cx.stack[last].Uint) if err != nil { return err } diff --git a/data/transactions/logic/langspec.json b/data/transactions/logic/langspec.json index cbfb4b0d95..a5c42c7b15 100644 --- a/data/transactions/logic/langspec.json +++ b/data/transactions/logic/langspec.json @@ -1462,7 +1462,7 @@ "Returns": "U", "Size": 1, "Doc": "balance for account A, in microalgos. The balance is observed after the effects of previous transactions in the group, and after the fee for the current transaction is deducted. Changes caused by inner transactions are observable immediately following `itxn_submit`", - "DocExtra": "params: Txn.Accounts offset (or, since v4, an _available_ account address), _available_ application id (or, since v4, a Txn.ForeignApps offset). Return: value.", + "DocExtra": "params: Txn.Accounts offset (or, since v4, an _available_ account address). Return: value.", "IntroducedVersion": 2, "Groups": [ "State Access" @@ -1689,7 +1689,7 @@ "Returns": "U", "Size": 1, "Doc": "minimum required balance for account A, in microalgos. Required balance is affected by ASA, App, and Box usage. When creating or opting into an app, the minimum balance grows before the app code runs, therefore the increase is visible there. When deleting or closing out, the minimum balance decreases after the app executes. Changes caused by inner transactions or box usage are observable immediately following the opcode effecting the change.", - "DocExtra": "params: Txn.Accounts offset (or, since v4, an _available_ account address), _available_ application id (or, since v4, a Txn.ForeignApps offset). Return: value.", + "DocExtra": "params: Txn.Accounts offset (or, since v4, an _available_ account address). Return: value.", "IntroducedVersion": 3, "Groups": [ "State Access" diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index df2b456810..32d2f4591b 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -85,6 +85,7 @@ pop; pop; int 1 _, _, ledger := logic.MakeSampleEnv() ledger.NewAccount(appl0.Sender, 100_000) + ledger.NewAccount(appl1.Sender, 100_000) ledger.NewApp(appl0.Sender, 500, basics.AppParams{}) ledger.NewLocals(appl0.Sender, 500) // opt in // Now txn0 passes, but txn1 has an error because it can't see app 500 @@ -96,6 +97,27 @@ pop; pop; int 1 // is the one from tx0. logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, ledger) + // Checking if an account is opted in has pretty much the same rules + optInCheck := ` +int 0 // Sender +int 500 +app_opted_in +` + + sources = []string{optInCheck, optInCheck} + // app_opted_in requires the address and the app exist, else the program fails + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 8, nil, + logic.NewExpect(0, "no account")) + + // Now txn0 passes, but txn1 has an error because it can't see app 500 + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, ledger, + logic.NewExpect(1, "invalid Local State access")) + + // But it's ok in appl2, because appl2 uses the same Sender, even though the + // foreign-app is not repeated in appl2 because the holding being accessed + // is the one from tx0. + logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, ledger) + // Now, confirm that *setting* a local state in tx1 that was made available // in tx0 works. The extra check here is that the change is recorded // properly in EvalDelta. @@ -706,6 +728,14 @@ func TestAccessMyLocals(t *testing.T) { app_local_get int 7 == +` + logic.TestApp(t, source, ep) + + // They can also see that they are opted in, though it's a weird question to ask. + source = ` + int 0 + int 0 + app_opted_in ` logic.TestApp(t, source, ep) }) From bf98ae4148d44a8dcf9128993ad9926fcb1fcaae Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 23 Feb 2023 13:25:13 -0500 Subject: [PATCH 17/29] Improvements from CR. Some more tests to come. --- data/transactions/logic/README.md | 9 +- data/transactions/logic/README_in.md | 9 +- data/transactions/logic/evalAppTxn_test.go | 305 ++++++++++--------- data/transactions/logic/evalStateful_test.go | 58 ++-- data/transactions/logic/resources.go | 11 +- data/transactions/logic/resources_test.go | 35 ++- test/scripts/e2e_subs/shared-resources.py | 4 +- 7 files changed, 241 insertions(+), 190 deletions(-) diff --git a/data/transactions/logic/README.md b/data/transactions/logic/README.md index 6af976489e..299f2a6560 100644 --- a/data/transactions/logic/README.md +++ b/data/transactions/logic/README.md @@ -211,16 +211,17 @@ _available_. resources available to group-level resource sharing. The following resources are made available other transaction types. - 1. `pay` - `txn.Sender`, `txn.Receiver`, and `txn.CloseRemainderTo` + 1. `pay` - `txn.Sender`, `txn.Receiver`, and + `txn.CloseRemainderTo` (if set) 1. `keyreg` - `txn.Sender` 1. `acfg` - `txn.Sender`, `txn.ConfigAsset`, and the `txn.ConfigAsset` holding of `txn.Sender`. - 1. `axfer` - `txn.Sender`, `txn.AssetSender`, `txnAssetCloseTo`, - `txn.XferAsset` and the `txn.XferAsset` holding of each of - those accounts. + 1. `axfer` - `txn.Sender`, `txn.AssetReceiver`, `txn.AssetSender` + (if set), `txnAssetCloseTo` (if set), `txn.XferAsset` and the + `txn.XferAsset` holding of each of those accounts. 1. `afrz` - `txn.Sender`, `txn.FreezeAccount`, `txn.FreezeAsset`, and the `txn.FreezeAsset` holding of `txn.FreezeAccount`. The diff --git a/data/transactions/logic/README_in.md b/data/transactions/logic/README_in.md index 9c0e9ec4d9..aef3cafe81 100644 --- a/data/transactions/logic/README_in.md +++ b/data/transactions/logic/README_in.md @@ -211,16 +211,17 @@ _available_. resources available to group-level resource sharing. The following resources are made available other transaction types. - 1. `pay` - `txn.Sender`, `txn.Receiver`, and `txn.CloseRemainderTo` + 1. `pay` - `txn.Sender`, `txn.Receiver`, and + `txn.CloseRemainderTo` (if set) 1. `keyreg` - `txn.Sender` 1. `acfg` - `txn.Sender`, `txn.ConfigAsset`, and the `txn.ConfigAsset` holding of `txn.Sender`. - 1. `axfer` - `txn.Sender`, `txn.AssetSender`, `txnAssetCloseTo`, - `txn.XferAsset` and the `txn.XferAsset` holding of each of - those accounts. + 1. `axfer` - `txn.Sender`, `txn.AssetReceiver`, `txn.AssetSender` + (if set), `txnAssetCloseTo` (if set), `txn.XferAsset` and the + `txn.XferAsset` holding of each of those accounts. 1. `afrz` - `txn.Sender`, `txn.FreezeAccount`, `txn.FreezeAsset`, and the `txn.FreezeAsset` holding of `txn.FreezeAccount`. The diff --git a/data/transactions/logic/evalAppTxn_test.go b/data/transactions/logic/evalAppTxn_test.go index f396158bac..c9cddc5cfc 100644 --- a/data/transactions/logic/evalAppTxn_test.go +++ b/data/transactions/logic/evalAppTxn_test.go @@ -25,6 +25,7 @@ import ( "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/transactions" + "github.com/algorand/go-algorand/data/transactions/logic" . "github.com/algorand/go-algorand/data/transactions/logic" "github.com/algorand/go-algorand/data/txntest" "github.com/algorand/go-algorand/protocol" @@ -145,49 +146,52 @@ func TestAppPay(t *testing.T) { int 1 ` - ep, tx, ledger := MakeSampleEnv() - ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) - TestApp(t, "txn Sender; balance; int 0; ==;", ep) - TestApp(t, "txn Sender; txn Accounts 1; int 100"+pay, ep, "unauthorized") - TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100"+pay, ep, - "insufficient balance") - ledger.NewAccount(appAddr(888), 1000000) - - // You might NewExpect this to fail because of min balance issue - // (receiving account only gets 100 microalgos). It does not fail at - // this level, instead, we must be certain that the existing min - // balance check in eval.transaction() properly notices and fails - // the transaction later. This fits with the model that we check - // min balances once at the end of each "top-level" transaction. - TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100"+pay, ep) - - // 100 of 1000000 spent, plus MinTxnFee in our fake protocol is 1001 - TestApp(t, "global CurrentApplicationAddress; balance; int 998899; ==", ep) - TestApp(t, "txn Receiver; balance; int 100; ==", ep) - - close := ` + // v5 added inners + logic.TestLogicRange(t, 5, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) + TestApp(t, "txn Sender; balance; int 0; ==;", ep) + TestApp(t, "txn Sender; txn Accounts 1; int 100"+pay, ep, "unauthorized") + TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100"+pay, ep, + "insufficient balance") + ledger.NewAccount(appAddr(888), 1000000) + + // You might NewExpect this to fail because of min balance issue + // (receiving account only gets 100 microalgos). It does not fail at + // this level, instead, we must be certain that the existing min + // balance check in eval.transaction() properly notices and fails + // the transaction later. This fits with the model that we check + // min balances once at the end of each "top-level" transaction. + TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100"+pay, ep) + + // 100 of 1000000 spent, plus MinTxnFee in our fake protocol is 1001 + TestApp(t, "global CurrentApplicationAddress; balance; int 998899; ==", ep) + TestApp(t, "txn Receiver; balance; int 100; ==", ep) + + close := ` itxn_begin int pay; itxn_field TypeEnum txn Receiver; itxn_field CloseRemainderTo itxn_submit int 1 ` - TestApp(t, close, ep) - TestApp(t, "global CurrentApplicationAddress; balance; !", ep) - // Receiver got most of the algos (except 1001 for fee) - TestApp(t, "txn Receiver; balance; int 997998; ==", ep) + TestApp(t, close, ep) + TestApp(t, "global CurrentApplicationAddress; balance; !", ep) + // Receiver got most of the algos (except 1001 for fee) + TestApp(t, "txn Receiver; balance; int 997998; ==", ep) + }) } func TestAppAssetOptIn(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - ep, tx, ledger := MakeSampleEnv() - // Establish 888 as the app id, and fund it. - ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) - ledger.NewAccount(basics.AppIndex(888).Address(), 200000) + // v5 added inners + logic.TestLogicRange(t, 5, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + // Establish 888 as the app id, and fund it. + ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) + ledger.NewAccount(basics.AppIndex(888).Address(), 200000) - axfer := ` + axfer := ` itxn_begin int axfer; itxn_field TypeEnum; int 25; itxn_field XferAsset; @@ -196,10 +200,10 @@ txn Sender; itxn_field AssetReceiver; itxn_submit int 1 ` - TestApp(t, axfer, ep, "invalid Asset reference") - tx.ForeignAssets = append(tx.ForeignAssets, 25) - TestApp(t, axfer, ep, "not opted in") // app account not opted in - optin := ` + TestApp(t, axfer, ep, "invalid Asset reference") + tx.ForeignAssets = append(tx.ForeignAssets, 25) + TestApp(t, axfer, ep, "not opted in") // app account not opted in + optin := ` itxn_begin int axfer; itxn_field TypeEnum; int 25; itxn_field XferAsset; @@ -208,25 +212,25 @@ global CurrentApplicationAddress; itxn_field AssetReceiver; itxn_submit int 1 ` - TestApp(t, optin, ep, "does not exist") - // Asset 25 - ledger.NewAsset(tx.Sender, 25, basics.AssetParams{ - Total: 10, - UnitName: "x", - AssetName: "Cross", - }) - TestApp(t, optin, ep) + TestApp(t, optin, ep, "does not exist") + // Asset 25 + ledger.NewAsset(tx.Sender, 25, basics.AssetParams{ + Total: 10, + UnitName: "x", + AssetName: "Cross", + }) + TestApp(t, optin, ep) - TestApp(t, axfer, ep, "insufficient balance") // opted in, but balance=0 + TestApp(t, axfer, ep, "insufficient balance") // opted in, but balance=0 - // Fund the app account with the asset - ledger.NewHolding(basics.AppIndex(888).Address(), 25, 5, false) - TestApp(t, axfer, ep) - TestApp(t, axfer, ep) - TestApp(t, axfer, ep, "insufficient balance") // balance = 1, tried to move 2) - TestApp(t, "global CurrentApplicationAddress; int 25; asset_holding_get AssetBalance; assert; int 1; ==", ep) + // Fund the app account with the asset + ledger.NewHolding(basics.AppIndex(888).Address(), 25, 5, false) + TestApp(t, axfer, ep) + TestApp(t, axfer, ep) + TestApp(t, axfer, ep, "insufficient balance") // balance = 1, tried to move 2) + TestApp(t, "global CurrentApplicationAddress; int 25; asset_holding_get AssetBalance; assert; int 1; ==", ep) - close := ` + close := ` itxn_begin int axfer; itxn_field TypeEnum; int 25; itxn_field XferAsset; @@ -236,8 +240,9 @@ txn Sender; itxn_field AssetCloseTo; itxn_submit int 1 ` - TestApp(t, close, ep) - TestApp(t, "global CurrentApplicationAddress; int 25; asset_holding_get AssetBalance; !; assert; !", ep) + TestApp(t, close, ep) + TestApp(t, "global CurrentApplicationAddress; int 25; asset_holding_get AssetBalance; !; assert; !", ep) + }) } func TestRekeyPay(t *testing.T) { @@ -254,16 +259,18 @@ func TestRekeyPay(t *testing.T) { itxn_submit ` - ep, tx, ledger := MakeSampleEnv() - ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) - TestApp(t, "txn Sender; balance; int 0; ==;", ep) - TestApp(t, "txn Sender; txn Accounts 1; int 100"+pay, ep, "unauthorized") - ledger.NewAccount(tx.Sender, 120+ep.Proto.MinTxnFee) - ledger.Rekey(tx.Sender, basics.AppIndex(888).Address()) - TestApp(t, "txn Sender; txn Accounts 1; int 100"+pay+"; int 1", ep) - // Note that the Sender would fail min balance check if we did it here. - // It seems proper to wait until end of txn though. - // See explanation in cowRoundState's Perform() + // v5 added inners + logic.TestLogicRange(t, 5, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) + TestApp(t, "txn Sender; balance; int 0; ==;", ep) + TestApp(t, "txn Sender; txn Accounts 1; int 100"+pay, ep, "unauthorized") + ledger.NewAccount(tx.Sender, 120+ep.Proto.MinTxnFee) + ledger.Rekey(tx.Sender, basics.AppIndex(888).Address()) + TestApp(t, "txn Sender; txn Accounts 1; int 100"+pay+"; int 1", ep) + // Note that the Sender would fail min balance check if we did it here. + // It seems proper to wait until end of txn though. + // See explanation in cowRoundState's Perform() + }) } func TestRekeyBack(t *testing.T) { @@ -282,15 +289,17 @@ func TestRekeyBack(t *testing.T) { itxn_submit ` - ep, tx, ledger := MakeSampleEnv() - ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) - TestApp(t, "txn Sender; balance; int 0; ==;", ep) - TestApp(t, "txn Sender; txn Accounts 1; int 100"+payAndUnkey, ep, "unauthorized") - ledger.NewAccount(tx.Sender, 120+3*ep.Proto.MinTxnFee) - ledger.Rekey(tx.Sender, basics.AppIndex(888).Address()) - TestApp(t, "txn Sender; txn Accounts 1; int 100"+payAndUnkey+"; int 1", ep) - // now rekeyed back to original - TestApp(t, "txn Sender; txn Accounts 1; int 100"+payAndUnkey, ep, "unauthorized") + // v6 added inner rekey + logic.TestLogicRange(t, 6, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) + TestApp(t, "txn Sender; balance; int 0; ==;", ep) + TestApp(t, "txn Sender; txn Accounts 1; int 100"+payAndUnkey, ep, "unauthorized") + ledger.NewAccount(tx.Sender, 120+3*ep.Proto.MinTxnFee) + ledger.Rekey(tx.Sender, basics.AppIndex(888).Address()) + TestApp(t, "txn Sender; txn Accounts 1; int 100"+payAndUnkey+"; int 1", ep) + // now rekeyed back to original + TestApp(t, "txn Sender; txn Accounts 1; int 100"+payAndUnkey, ep, "unauthorized") + }) } func TestDefaultSender(t *testing.T) { @@ -306,13 +315,15 @@ func TestDefaultSender(t *testing.T) { itxn_submit ` - ep, tx, ledger := MakeSampleEnv() - ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) - tx.Accounts = append(tx.Accounts, appAddr(888)) - TestApp(t, "txn Accounts 1; int 100"+pay, ep, "insufficient balance") - ledger.NewAccount(appAddr(888), 1000000) - TestApp(t, "txn Accounts 1; int 100"+pay+"int 1", ep) - TestApp(t, "global CurrentApplicationAddress; balance; int 998899; ==", ep) + // v5 added inners + logic.TestLogicRange(t, 5, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) + tx.Accounts = append(tx.Accounts, appAddr(888)) + TestApp(t, "txn Accounts 1; int 100"+pay, ep, "insufficient balance") + ledger.NewAccount(appAddr(888), 1000000) + TestApp(t, "txn Accounts 1; int 100"+pay+"int 1", ep) + TestApp(t, "global CurrentApplicationAddress; balance; int 998899; ==", ep) + }) } func TestAppAxfer(t *testing.T) { @@ -331,36 +342,37 @@ func TestAppAxfer(t *testing.T) { itxn_submit ` - ep, tx, ledger := MakeSampleEnv() - ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) - ledger.NewAsset(tx.Receiver, 777, basics.AssetParams{}) // not in foreign-assets of sample - ledger.NewAsset(tx.Receiver, 77, basics.AssetParams{}) // in foreign-assets of sample - TestApp(t, "txn Sender; int 777; asset_holding_get AssetBalance; assert; int 0; ==;", ep, - "invalid Asset reference") // 777 not in foreign-assets - TestApp(t, "txn Sender; int 77; asset_holding_get AssetBalance; assert; int 0; ==;", ep, - "assert failed") // because Sender not opted-in - TestApp(t, "global CurrentApplicationAddress; int 77; asset_holding_get AssetBalance; assert; int 0; ==;", ep, - "assert failed") // app account not opted in - - ledger.NewAccount(appAddr(888), 10000) // plenty for fees - ledger.NewHolding(appAddr(888), 77, 3000, false) - TestApp(t, "global CurrentApplicationAddress; int 77; asset_holding_get AssetBalance; assert; int 3000; ==;", ep) - - TestApp(t, "txn Sender; txn Accounts 1; int 100"+axfer, ep, "unauthorized") - TestApp(t, "global CurrentApplicationAddress; txn Accounts 0; int 100"+axfer, ep, - fmt.Sprintf("Receiver (%s) not opted in", tx.Sender)) // txn.Sender (receiver of the axfer) isn't opted in - TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100000"+axfer, ep, - "insufficient balance") - - // Temporarily remove from ForeignAssets to ensure App Account - // doesn't get some sort of free pass to send arbitrary assets. - save := tx.ForeignAssets - tx.ForeignAssets = []basics.AssetIndex{6, 10} - TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100000"+axfer, ep, - "invalid Asset reference 77") - tx.ForeignAssets = save - - noid := ` + // v5 added inners + logic.TestLogicRange(t, 5, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) + ledger.NewAsset(tx.Receiver, 777, basics.AssetParams{}) // not in foreign-assets of sample + ledger.NewAsset(tx.Receiver, 77, basics.AssetParams{}) // in foreign-assets of sample + TestApp(t, "txn Sender; int 777; asset_holding_get AssetBalance; assert; int 0; ==;", ep, + "invalid Asset reference") // 777 not in foreign-assets + TestApp(t, "txn Sender; int 77; asset_holding_get AssetBalance; assert; int 0; ==;", ep, + "assert failed") // because Sender not opted-in + TestApp(t, "global CurrentApplicationAddress; int 77; asset_holding_get AssetBalance; assert; int 0; ==;", ep, + "assert failed") // app account not opted in + + ledger.NewAccount(appAddr(888), 10000) // plenty for fees + ledger.NewHolding(appAddr(888), 77, 3000, false) + TestApp(t, "global CurrentApplicationAddress; int 77; asset_holding_get AssetBalance; assert; int 3000; ==;", ep) + + TestApp(t, "txn Sender; txn Accounts 1; int 100"+axfer, ep, "unauthorized") + TestApp(t, "global CurrentApplicationAddress; txn Accounts 0; int 100"+axfer, ep, + fmt.Sprintf("Receiver (%s) not opted in", tx.Sender)) // txn.Sender (receiver of the axfer) isn't opted in + TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100000"+axfer, ep, + "insufficient balance") + + // Temporarily remove from ForeignAssets to ensure App Account + // doesn't get some sort of free pass to send arbitrary assets. + save := tx.ForeignAssets + tx.ForeignAssets = []basics.AssetIndex{6, 10} + TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100000"+axfer, ep, + "invalid Asset reference 77") + tx.ForeignAssets = save + + noid := ` itxn_begin itxn_field AssetAmount itxn_field AssetReceiver @@ -370,17 +382,20 @@ func TestAppAxfer(t *testing.T) { itxn_submit ` - was := ep.Proto.LogicSigVersion - ep.Proto.LogicSigVersion = 8 - TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100"+noid+"int 1", ep, - fmt.Sprintf("Sender (%s) not opted in to 0", appAddr(888))) - ep.Proto.LogicSigVersion = was + // Here, the XferAsset is never set, so it is defaulted to 0. Therefore + // v8 and below had no opportunity to complain about the inavailability + // of the implied holding. Of course, there is no 0 asset, so the axfer + // is going to fail anyway, but to keep the behavior consistent, v9 + // allows the zero asset (and zero account) in `requireHolding`. + TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100"+noid+"int 1", ep, + fmt.Sprintf("Sender (%s) not opted in to 0", appAddr(888))) - TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100"+axfer+"int 1", ep) + TestApp(t, "global CurrentApplicationAddress; txn Accounts 1; int 100"+axfer+"int 1", ep) - // 100 of 3000 spent - TestApp(t, "global CurrentApplicationAddress; int 77; asset_holding_get AssetBalance; assert; int 2900; ==", ep) - TestApp(t, "txn Accounts 1; int 77; asset_holding_get AssetBalance; assert; int 100; ==", ep) + // 100 of 3000 spent + TestApp(t, "global CurrentApplicationAddress; int 77; asset_holding_get AssetBalance; assert; int 2900; ==", ep) + TestApp(t, "txn Accounts 1; int 77; asset_holding_get AssetBalance; assert; int 100; ==", ep) + }) } func TestExtraFields(t *testing.T) { @@ -560,12 +575,14 @@ func TestAssetCreate(t *testing.T) { itxn_submit int 1 ` - ep, tx, ledger := MakeSampleEnv() - ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) - TestApp(t, create, ep, "insufficient balance") - // Give it enough for fee. Recall that we don't check min balance at this level. - ledger.NewAccount(appAddr(888), MakeTestProto().MinTxnFee) - TestApp(t, create, ep) + // v5 added inners + logic.TestLogicRange(t, 5, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) + TestApp(t, create, ep, "insufficient balance") + // Give it enough for fee. Recall that we don't check min balance at this level. + ledger.NewAccount(appAddr(888), MakeTestProto().MinTxnFee) + TestApp(t, create, ep) + }) } func TestAssetFreeze(t *testing.T) { @@ -586,13 +603,14 @@ func TestAssetFreeze(t *testing.T) { int 5000 == ` - ep, tx, ledger := MakeSampleEnv() - ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) - // Give it enough for fees. Recall that we don't check min balance at this level. - ledger.NewAccount(appAddr(888), 12*MakeTestProto().MinTxnFee) - TestApp(t, create, ep) + // v5 added inners + logic.TestLogicRange(t, 5, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) + // Give it enough for fees. Recall that we don't check min balance at this level. + ledger.NewAccount(appAddr(888), 12*MakeTestProto().MinTxnFee) + TestApp(t, create, ep) - freeze := ` + freeze := ` itxn_begin int afrz ; itxn_field TypeEnum int 5000 ; itxn_field FreezeAsset @@ -601,20 +619,21 @@ func TestAssetFreeze(t *testing.T) { itxn_submit int 1 ` - TestApp(t, freeze, ep, "invalid Asset reference") - tx.ForeignAssets = []basics.AssetIndex{basics.AssetIndex(5000)} - tx.ApplicationArgs = [][]byte{{0x01}} - TestApp(t, freeze, ep, "does not hold Asset") - ledger.NewHolding(tx.Receiver, 5000, 55, false) - TestApp(t, freeze, ep) - holding, err := ledger.AssetHolding(tx.Receiver, 5000) - require.NoError(t, err) - require.Equal(t, true, holding.Frozen) - tx.ApplicationArgs = [][]byte{{0x00}} - TestApp(t, freeze, ep) - holding, err = ledger.AssetHolding(tx.Receiver, 5000) - require.NoError(t, err) - require.Equal(t, false, holding.Frozen) + TestApp(t, freeze, ep, "invalid Asset reference") + tx.ForeignAssets = []basics.AssetIndex{basics.AssetIndex(5000)} + tx.ApplicationArgs = [][]byte{{0x01}} + TestApp(t, freeze, ep, "does not hold Asset") + ledger.NewHolding(tx.Receiver, 5000, 55, false) + TestApp(t, freeze, ep) + holding, err := ledger.AssetHolding(tx.Receiver, 5000) + require.NoError(t, err) + require.Equal(t, true, holding.Frozen) + tx.ApplicationArgs = [][]byte{{0x00}} + TestApp(t, freeze, ep) + holding, err = ledger.AssetHolding(tx.Receiver, 5000) + require.NoError(t, err) + require.Equal(t, false, holding.Frozen) + }) } func TestKeyReg(t *testing.T) { diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index 3f09798a2d..c33c81d767 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -2902,16 +2902,16 @@ app_local_put int 1 ` ed := testApp(t, source, ep) - require.Len(t, ed.LocalDeltas, 1) require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 - - require.Contains(t, ed.LocalDeltas, uint64(2)) - sd := ed.LocalDeltas[2] - require.Len(t, sd, 1) - require.Contains(t, sd, "hey") - require.EqualValues(t, 42, sd["hey"].Uint) - require.Len(t, ed.SharedAccts, 1) - require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) + require.Equal(t, map[uint64]basics.StateDelta{ + 2: { + "hey": { + Action: basics.SetUintAction, + Uint: 42, + }, + }, + }, ed.LocalDeltas) + require.Equal(t, []basics.Address{tx.ApplicationID.Address()}, ed.SharedAccts) /* Confirm it worked. */ source = ` @@ -2930,16 +2930,15 @@ app_local_del int 1 ` ed = testApp(t, source, ep) - require.Len(t, ed.LocalDeltas, 1) require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 - - require.Contains(t, ed.LocalDeltas, uint64(2)) - sd = ed.LocalDeltas[2] - require.Len(t, sd, 1) - require.Contains(t, sd, "hey") - require.EqualValues(t, basics.DeleteAction, sd["hey"].Action) - require.Len(t, ed.SharedAccts, 1) - require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) + require.Equal(t, map[uint64]basics.StateDelta{ + 2: { + "hey": { + Action: basics.DeleteAction, + }, + }, + }, ed.LocalDeltas) + require.Equal(t, []basics.Address{tx.ApplicationID.Address()}, ed.SharedAccts) // Now, repeat the "put" test with multiple keys, to ensure only one address is added to SharedAccts source = ` @@ -2954,17 +2953,20 @@ app_local_put int 1 ` ed = testApp(t, source, ep) - require.Len(t, ed.LocalDeltas, 1) require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 + require.Equal(t, map[uint64]basics.StateDelta{ + 2: { + "hey": { + Action: basics.SetUintAction, + Uint: 42, + }, + "joe": { + Action: basics.SetUintAction, + Uint: 21, + }, + }, + }, ed.LocalDeltas) - require.Contains(t, ed.LocalDeltas, uint64(2)) - sd = ed.LocalDeltas[2] - require.Len(t, sd, 2) - require.Contains(t, sd, "hey") - require.EqualValues(t, 42, sd["hey"].Uint) - require.Contains(t, sd, "joe") - require.EqualValues(t, 21, sd["joe"].Uint) - require.Len(t, ed.SharedAccts, 1) - require.Equal(t, tx.ApplicationID.Address(), ed.SharedAccts[0]) + require.Equal(t, []basics.Address{tx.ApplicationID.Address()}, ed.SharedAccts) }) } diff --git a/data/transactions/logic/resources.go b/data/transactions/logic/resources.go index ad5e242b16..510900b4c0 100644 --- a/data/transactions/logic/resources.go +++ b/data/transactions/logic/resources.go @@ -34,10 +34,10 @@ type resources struct { createdAsas []basics.AssetIndex createdApps []basics.AppIndex - // These resources have been mentioned by some txn in the group, so they are - // available. But only their "main" data is available. For example, if an - // account is mentioned, its algo balance is available, but not necessarily - // its asset balance for any old ASA. + // These resources have been used by some txn in the group, so they are + // available. These maps track the availability of the basic objects (often + // called "params"), not the "cross-product" objects (which are tracked + // below) sharedAccounts map[basics.Address]struct{} sharedAsas map[basics.AssetIndex]struct{} sharedApps map[basics.AppIndex]struct{} @@ -92,6 +92,9 @@ func (r *resources) fill(tx *transactions.Transaction, ep *EvalParams) { r.fillAssetFreeze(&tx.Header, &tx.AssetFreezeTxnFields) case protocol.ApplicationCallTx: r.fillApplicationCall(ep, &tx.Header, &tx.ApplicationCallTxnFields) + case protocol.StateProofTx: + // state proof txns add nothing to availability (they can't even appear + // in a group with an appl. but still.) default: panic(tx.Type) } diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 32d2f4591b..06ed6ba27f 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -148,7 +148,7 @@ int 1 } // TestBetterLocalErrors confirms that we get specific errors about the missing -// address or app when accessesing a Local State with only one available. +// address or app when accessing a Local State with only one available. func TestBetterLocalErrors(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() @@ -332,6 +332,10 @@ func TestOtherTxSharing(t *testing.T) { ledger.NewAccount(otherAcct, 2003) otherBalance := "txn ApplicationArgs 0; balance; int 2003; ==" + other2Acct := basics.Address{1, 2, 3, 4, 5, 6, 4} + ledger.NewAccount(other2Acct, 2004) + other2Balance := "txn ApplicationArgs 0; balance; int 2004; ==" + appl := txntest.Txn{ Type: protocol.ApplicationCallTx, Sender: basics.Address{5, 5, 5, 5}, // different from all other accounts used @@ -433,16 +437,29 @@ func TestOtherTxSharing(t *testing.T) { appl.ApplicationArgs = [][]byte{otherAcct[:]} logic.TestApps(t, []string{"", otherBalance}, txntest.Group(&axfer, &appl), 9, ledger) + // sender holding is available + appl.ApplicationArgs = [][]byte{senderAcct[:], {byte(axfer.XferAsset)}} + logic.TestApps(t, []string{"", holdingAccess}, txntest.Group(&axfer, &appl), 9, ledger) + // receiver holding is available appl.ApplicationArgs = [][]byte{receiverAcct[:], {byte(axfer.XferAsset)}} logic.TestApps(t, []string{"", holdingAccess}, txntest.Group(&axfer, &appl), 9, ledger) - // The other account becomes accessible because used in CloseRemainderTo - // (for asa and algo) - withClose := axfer - withClose.AssetCloseTo = otherAcct + // asset sender (other) account is available appl.ApplicationArgs = [][]byte{otherAcct[:], {byte(axfer.XferAsset)}} - logic.TestApps(t, []string{"", otherBalance}, txntest.Group(&withClose, &appl), 9, ledger) + logic.TestApps(t, []string{"", holdingAccess}, txntest.Group(&axfer, &appl), 9, ledger) + + // AssetCloseTo holding becomes available when set + appl.ApplicationArgs = [][]byte{other2Acct[:], {byte(axfer.XferAsset)}} + logic.TestApps(t, []string{"", other2Balance}, txntest.Group(&axfer, &appl), 9, ledger, + logic.NewExpect(1, "invalid Account reference "+other2Acct.String())) + logic.TestApps(t, []string{"", holdingAccess}, txntest.Group(&axfer, &appl), 9, ledger, + logic.NewExpect(1, "invalid Account reference "+other2Acct.String())) + + withClose := axfer + withClose.AssetCloseTo = other2Acct + appl.ApplicationArgs = [][]byte{other2Acct[:], {byte(axfer.XferAsset)}} + logic.TestApps(t, []string{"", other2Balance}, txntest.Group(&withClose, &appl), 9, ledger) logic.TestApps(t, []string{"", holdingAccess}, txntest.Group(&withClose, &appl), 9, ledger) }) @@ -451,6 +468,12 @@ func TestOtherTxSharing(t *testing.T) { appl.ApplicationArgs = [][]byte{otherAcct[:], {byte(afrz.FreezeAsset)}} logic.TestApps(t, []string{"", otherBalance}, txntest.Group(&afrz, &appl), 9, ledger) logic.TestApps(t, []string{"", holdingAccess}, txntest.Group(&afrz, &appl), 9, ledger) + + // The sender holding is _not_ (because the freezeaccount's holding is irrelevant to afrz) + appl.ApplicationArgs = [][]byte{senderAcct[:], {byte(afrz.FreezeAsset)}} + logic.TestApps(t, []string{"", senderBalance}, txntest.Group(&afrz, &appl), 9, ledger) + logic.TestApps(t, []string{"", holdingAccess}, txntest.Group(&afrz, &appl), 9, ledger, + logic.NewExpect(1, "invalid Holding access "+senderAcct.String())) }) } diff --git a/test/scripts/e2e_subs/shared-resources.py b/test/scripts/e2e_subs/shared-resources.py index 768c8151aa..d4c1c95945 100755 --- a/test/scripts/e2e_subs/shared-resources.py +++ b/test/scripts/e2e_subs/shared-resources.py @@ -72,7 +72,9 @@ update_info, err = goal.send(update) assert not err, err -# Won't work this time, because v8 program +# Works now, because a v9 program is allowed to modify a "non-local" +# account. Under the covers, the txn gets a "SharedAccts" array, and +# the index points there. But the REST API hides that. grp1 = goal.app_call(goal.account, app_id, on_complete=txn.OnComplete.OptInOC, app_args=[enc.decode_address(goal.account), 60]) From cf2bfebecfa4d9d3040257cb815d9bd02657aff6 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Fri, 24 Feb 2023 15:04:03 -0500 Subject: [PATCH 18/29] New tests, including v9 calling v8 showing blocked access --- data/transactions/logic/evalAppTxn_test.go | 25 +++ data/transactions/logic/resources_test.go | 175 +++++++++++++++++---- 2 files changed, 173 insertions(+), 27 deletions(-) diff --git a/data/transactions/logic/evalAppTxn_test.go b/data/transactions/logic/evalAppTxn_test.go index c9cddc5cfc..84040dddf1 100644 --- a/data/transactions/logic/evalAppTxn_test.go +++ b/data/transactions/logic/evalAppTxn_test.go @@ -398,6 +398,31 @@ func TestAppAxfer(t *testing.T) { }) } +func TestInnerAppl(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + appl := ` + itxn_begin + int appl; itxn_field TypeEnum + int 56 // present in ForeignApps of sample txn + itxn_field ApplicationID + itxn_submit + int 1 +` + + // v6 added inner appls + TestLogicRange(t, 6, 0, func(t *testing.T, ep *logic.EvalParams, tx *transactions.Transaction, ledger *logic.Ledger) { + // Establish 888 as the app id, and fund it. + ledger.NewApp(tx.Receiver, 888, basics.AppParams{}) + ledger.NewAccount(basics.AppIndex(888).Address(), 200000) + + ops := TestProg(t, "int 1", 5) + ledger.NewApp(basics.Address{0x01}, 56, basics.AppParams{ApprovalProgram: ops.Program}) + TestApp(t, appl, ep) + }) +} + func TestExtraFields(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 06ed6ba27f..583a338b38 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -30,8 +30,8 @@ import ( "github.com/stretchr/testify/require" ) -// TestAppSharing confirms that as of v9, apps can be accessed across -// groups, but that before then, they could not. +// TestAppSharing confirms that as of v9, apps can be accessed across groups, +// but that before then, they could not. func TestAppSharing(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() @@ -39,19 +39,22 @@ func TestAppSharing(t *testing.T) { // Create some sample transactions. The main reason this a blackbox test // (_test package) is to have access to txntest. appl0 := txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: basics.Address{1, 2, 3, 4}, - ForeignApps: []basics.AppIndex{500}, + Type: protocol.ApplicationCallTx, + ApplicationID: 900, + Sender: basics.Address{1, 2, 3, 4}, + ForeignApps: []basics.AppIndex{500}, } appl1 := txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: basics.Address{4, 3, 2, 1}, + Type: protocol.ApplicationCallTx, + ApplicationID: 901, + Sender: basics.Address{4, 3, 2, 1}, } appl2 := txntest.Txn{ - Type: protocol.ApplicationCallTx, - Sender: basics.Address{1, 2, 3, 4}, + Type: protocol.ApplicationCallTx, + ApplicationID: 902, + Sender: basics.Address{1, 2, 3, 4}, } getSchema := ` @@ -96,27 +99,46 @@ pop; pop; int 1 // foreign-app is not repeated in appl2 because the holding being accessed // is the one from tx0. logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, ledger) + logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 8, ledger, // version 8 does not get sharing + logic.NewExpect(1, "invalid App reference 500")) // Checking if an account is opted in has pretty much the same rules - optInCheck := ` + optInCheck500 := ` int 0 // Sender int 500 app_opted_in ` - sources = []string{optInCheck, optInCheck} + sources = []string{optInCheck500, optInCheck500} // app_opted_in requires the address and the app exist, else the program fails - logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 8, nil, - logic.NewExpect(0, "no account")) + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, nil, // nil ledger, no account + logic.NewExpect(0, "no account: "+appl0.Sender.String())) - // Now txn0 passes, but txn1 has an error because it can't see app 500 + // Now txn0 passes, but txn1 has an error because it can't see app 500 locals for appl1.Sender logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, ledger, - logic.NewExpect(1, "invalid Local State access")) + logic.NewExpect(1, "invalid Local State access "+appl1.Sender.String())) // But it's ok in appl2, because appl2 uses the same Sender, even though the // foreign-app is not repeated in appl2 because the holding being accessed // is the one from tx0. logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, ledger) + logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 8, ledger, // version 8 does not get sharing + logic.NewExpect(1, "invalid App reference 500")) + + // Confirm sharing applies to the app id called in tx0, not just foreign app array + optInCheck900 := ` +int 0 // Sender +int 900 +app_opted_in +! // we did not opt any senders into 900 +` + sources = []string{optInCheck900, optInCheck900} + // as above, appl1 can't see the local state, but appl2 can b/c sender is same as appl0 + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, ledger, + logic.NewExpect(1, "invalid Local State access "+appl1.Sender.String())) + logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, ledger) + logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 8, ledger, // version 8 does not get sharing + logic.NewExpect(1, "invalid App reference 900")) // Now, confirm that *setting* a local state in tx1 that was made available // in tx0 works. The extra check here is that the change is recorded @@ -132,17 +154,19 @@ int 1 sources = []string{noop, putLocal} appl1.ApplicationArgs = [][]byte{appl0.Sender[:]} // tx1 will try to modify local state exposed in tx0 logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, ledger, - logic.NewExpect(1, "account "+appl0.Sender.String()+" is not opted into 888")) - ledger.NewLocals(appl0.Sender, 888) // opt in + logic.NewExpect(1, "account "+appl0.Sender.String()+" is not opted into 901")) + ledger.NewLocals(appl0.Sender, 901) // opt in ep := logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, ledger) require.Len(t, ep.TxnGroup, 2) ed := ep.TxnGroup[1].ApplyData.EvalDelta - require.Len(t, ed.LocalDeltas, 1) - require.Contains(t, ed.LocalDeltas, uint64(1)) // no tx.Accounts, 1 indicates first in SharedAccts - sd := ed.LocalDeltas[1] - require.Len(t, sd, 1) - require.Contains(t, sd, "X") - require.EqualValues(t, 74, sd["X"].Uint) + require.Equal(t, map[uint64]basics.StateDelta{ + 1: { // no tx.Accounts, 1 indicates first in SharedAccts + "X": { + Action: basics.SetUintAction, + Uint: 74, + }, + }, + }, ed.LocalDeltas) require.Len(t, ed.SharedAccts, 1) require.Equal(t, ep.TxnGroup[0].Txn.Sender, ed.SharedAccts[0]) } @@ -280,8 +304,8 @@ pop; pop; int 1 logic.TestApp(t, getHoldingBalance, ep, "invalid Account reference "+joe.String()) } -// TestAccountPassing checks that some special accounts can be passed in -// txn.Accounts for a called app. +// TestAccountPassing checks that the current app account and foreign app's +// accounts can be passed in txn.Accounts for a called app. func TestAccountPassing(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() @@ -592,6 +616,8 @@ int 1 // appl can pay the axfer sender appl.ApplicationArgs = [][]byte{senderAcct[:], {asa1}} logic.TestApps(t, []string{"", payToArg}, txntest.Group(&axfer, &appl), 9, ledger) + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&axfer, &appl), 8, ledger, + logic.NewExpect(1, "invalid Account reference "+senderAcct.String())) // but can't axfer to sender, because appAcct doesn't have holding access for the asa logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&axfer, &appl), 9, ledger, logic.NewExpect(1, "invalid Holding access")) @@ -655,7 +681,7 @@ int 1 }) t.Run("afrz", func(t *testing.T) { - appl.ForeignAssets = []basics.AssetIndex{} // reset after previous test + appl.ForeignAssets = []basics.AssetIndex{} // reset after previous tests afrz := txntest.Txn{ Type: protocol.AssetFreezeTx, FreezeAsset: asa1, @@ -710,6 +736,102 @@ int 1 }) + t.Run("appl", func(t *testing.T) { + appl.ForeignAssets = []basics.AssetIndex{} // reset after previous test + appl.Accounts = []basics.Address{} // reset after previous tests + appl0 := txntest.Txn{ + Type: protocol.ApplicationCallTx, + Sender: senderAcct, + Accounts: []basics.Address{otherAcct}, + ForeignAssets: []basics.AssetIndex{asa1}, + } + + // appl can pay to the otherAcct because it was in tx0 + appl.ApplicationArgs = [][]byte{otherAcct[:], {asa1}} + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&appl0, &appl), 9, ledger) + logic.TestApps(t, []string{"", payToArg}, txntest.Group(&appl0, &appl), 8, ledger, // version 8 does not get sharing + logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) + // appl can (almost) axfer asa1 to the otherAcct because both are in tx0 + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&appl0, &appl), 9, ledger, + logic.NewExpect(1, "axfer Sender: invalid Holding")) + // but it can't take access it's OWN asa1, unless added to ForeignAssets + appl.ForeignAssets = []basics.AssetIndex{asa1} + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&appl0, &appl), 9, ledger) + + // but it can't use 202 at all. notice the error is more direct that + // above, as the problem is not the axfer Sender, only, it's that 202 + // can't be used at all. + appl.ApplicationArgs = [][]byte{otherAcct[:], {asa2}} + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&appl0, &appl), 9, ledger, + logic.NewExpect(1, "invalid Asset reference 202")) + // And adding asa2 does not fix this problem, because the other x 202 holding is unavailable + appl.ForeignAssets = []basics.AssetIndex{asa2} + logic.TestApps(t, []string{"", axferToArgs}, txntest.Group(&appl0, &appl), 9, ledger, + logic.NewExpect(1, "axfer AssetReceiver: invalid Holding access "+otherAcct.String()+" x 202")) + + // Now, conduct similar tests, but with the apps performing the + // pays/axfers invoked from an outer app. Use various versions to check + // cross version sharing. + + // add v8 and v9 versions of the pay app to the ledger for inner calling + payToArgV8 := logic.TestProg(t, payToArg, 8) + ledger.NewApp(senderAcct, 88, basics.AppParams{ApprovalProgram: payToArgV8.Program}) + ledger.NewAccount(appAddr(88), 1_000_000) + payToArgV9 := logic.TestProg(t, payToArg, 9) + ledger.NewApp(senderAcct, 99, basics.AppParams{ApprovalProgram: payToArgV9.Program}) + ledger.NewAccount(appAddr(99), 1_000_000) + + approvalV8 := logic.TestProg(t, "int 1", 8) + ledger.NewApp(senderAcct, 11, basics.AppParams{ApprovalProgram: approvalV8.Program}) + + innerCallTemplate := ` +itxn_begin +int appl; itxn_field TypeEnum; +txn ApplicationArgs 0; btoi; itxn_field ApplicationID +txn ApplicationArgs 1; itxn_field ApplicationArgs +txn ApplicationArgs 2; itxn_field ApplicationArgs +%s +itxn_submit +int 1 +` + innerCall := fmt.Sprintf(innerCallTemplate, "") + + appl.ForeignApps = []basics.AppIndex{11, 88, 99} + + appl.ApplicationArgs = [][]byte{{99}, otherAcct[:], {asa1}} + logic.TestApps(t, []string{"", innerCall}, txntest.Group(&appl0, &appl), 9, ledger) + // when the inner program is v8, it can't perform the pay + appl.ApplicationArgs = [][]byte{{88}, otherAcct[:], {asa1}} + logic.TestApps(t, []string{"", innerCall}, txntest.Group(&appl0, &appl), 9, ledger, + logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) + // unless the caller passes in the account, but it can't because that + // would give the called app access to the passed account's locate state + innerCallWithAccount := fmt.Sprintf(innerCallTemplate, "addr "+otherAcct.String()+"; itxn_field Accounts") + logic.TestApps(t, []string{"", innerCallWithAccount}, txntest.Group(&appl0, &appl), 9, ledger, + logic.NewExpect(1, "appl ApplicationID: invalid Local State access "+otherAcct.String())) + // the caller can't fix by passing 88 as a foreign app, because doing so + // gives the v8 app access to that local state that the caller does not + // have access to. + innerCallWithBoth := fmt.Sprintf(innerCallTemplate, + "addr "+otherAcct.String()+"; itxn_field Accounts; int 88; itxn_field Applications") + logic.TestApps(t, []string{"", innerCallWithBoth}, txntest.Group(&appl0, &appl), 9, ledger, + logic.NewExpect(1, "appl ApplicationID: invalid Local State access "+otherAcct.String())) + + // the caller *can* do it if it originally had access to that 88 holding. + appl0.ForeignApps = []basics.AppIndex{88} + logic.TestApps(t, []string{"", innerCallWithAccount}, txntest.Group(&appl0, &appl), 9, ledger) + + // here we confirm that even if we try calling another, simple app, we + // can't pass in other and 88, because that would give the app accesss + // to that local state. (this is confirming we check the cross product + // of the foreign arrays, not just the accounts against called app id) + appl.ApplicationArgs = [][]byte{{11}, otherAcct[:], {asa1}} + appl0.ForeignApps = []basics.AppIndex{11} + logic.TestApps(t, []string{"", innerCallWithBoth}, txntest.Group(&appl0, &appl), 9, ledger, + logic.NewExpect(1, "appl ForeignApps: invalid Local State access "+otherAcct.String())) + + }) + } // TestAccessMyLocals confirms that apps can access their OWN locals if they opt @@ -762,5 +884,4 @@ func TestAccessMyLocals(t *testing.T) { ` logic.TestApp(t, source, ep) }) - } From 2bd96e10df8e36c72af9bc32a801090ac179d9ac Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Wed, 1 Mar 2023 12:34:28 -0500 Subject: [PATCH 19/29] Zeph CR typos --- data/transactions/logic/README.md | 6 +++--- data/transactions/logic/README_in.md | 6 +++--- data/transactions/logic/opcodes.go | 2 +- ledger/internal/cow_creatables.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/data/transactions/logic/README.md b/data/transactions/logic/README.md index 299f2a6560..0e5dc8ff27 100644 --- a/data/transactions/logic/README.md +++ b/data/transactions/logic/README.md @@ -209,10 +209,10 @@ _available_. * Top-level transactions that are not application calls also make resources available to group-level resource sharing. The following - resources are made available other transaction types. + resources are made available by other transaction types. 1. `pay` - `txn.Sender`, `txn.Receiver`, and - `txn.CloseRemainderTo` (if set) + `txn.CloseRemainderTo` (if set). 1. `keyreg` - `txn.Sender` @@ -220,7 +220,7 @@ _available_. `txn.ConfigAsset` holding of `txn.Sender`. 1. `axfer` - `txn.Sender`, `txn.AssetReceiver`, `txn.AssetSender` - (if set), `txnAssetCloseTo` (if set), `txn.XferAsset` and the + (if set), `txnAssetCloseTo` (if set), `txn.XferAsset`, and the `txn.XferAsset` holding of each of those accounts. 1. `afrz` - `txn.Sender`, `txn.FreezeAccount`, `txn.FreezeAsset`, diff --git a/data/transactions/logic/README_in.md b/data/transactions/logic/README_in.md index aef3cafe81..ff5b524c80 100644 --- a/data/transactions/logic/README_in.md +++ b/data/transactions/logic/README_in.md @@ -209,10 +209,10 @@ _available_. * Top-level transactions that are not application calls also make resources available to group-level resource sharing. The following - resources are made available other transaction types. + resources are made available by other transaction types. 1. `pay` - `txn.Sender`, `txn.Receiver`, and - `txn.CloseRemainderTo` (if set) + `txn.CloseRemainderTo` (if set). 1. `keyreg` - `txn.Sender` @@ -220,7 +220,7 @@ _available_. `txn.ConfigAsset` holding of `txn.Sender`. 1. `axfer` - `txn.Sender`, `txn.AssetReceiver`, `txn.AssetSender` - (if set), `txnAssetCloseTo` (if set), `txn.XferAsset` and the + (if set), `txnAssetCloseTo` (if set), `txn.XferAsset`, and the `txn.XferAsset` holding of each of those accounts. 1. `afrz` - `txn.Sender`, `txn.FreezeAccount`, `txn.FreezeAsset`, diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index afb6c10af7..0e9f1161c1 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -58,7 +58,7 @@ const txnEffectsVersion = 6 const createdResourcesVersion = 6 // resourceSharingVersion is the first version in which apps are allowed to -// access resource referenced in other transactions. +// access resources referenced in other transactions. const resourceSharingVersion = 9 // appAddressAvailableVersion is the first version that allows access to the diff --git a/ledger/internal/cow_creatables.go b/ledger/internal/cow_creatables.go index c49e358d22..d43b6e7a03 100644 --- a/ledger/internal/cow_creatables.go +++ b/ledger/internal/cow_creatables.go @@ -74,7 +74,7 @@ func (cs *roundCowState) GetAssetHolding(addr basics.Address, aidx basics.AssetI } if d.Holding == nil { // found and not deleted => must exist. Err if not - err = fmt.Errorf("GetAssetHoilding got a nil entry for (%s, %d): %p, %v", addr, aidx, d.Holding, d.Deleted) + err = fmt.Errorf("GetAssetHolding got a nil entry for (%s, %d): %p, %v", addr, aidx, d.Holding, d.Deleted) } ret = *d.Holding return From 1ef746b4238d97d46142db578f49242e6abccfa1 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 20 Mar 2023 09:40:28 -0400 Subject: [PATCH 20/29] regenetate --- .../api/server/v2/generated/data/routes.go | 90 +-- .../v2/generated/experimental/routes.go | 389 +---------- .../nonparticipating/private/routes.go | 80 +-- .../nonparticipating/public/routes.go | 638 +++--------------- .../generated/participating/private/routes.go | 97 +-- .../generated/participating/public/routes.go | 378 +---------- 6 files changed, 161 insertions(+), 1511 deletions(-) diff --git a/daemon/algod/api/server/v2/generated/data/routes.go b/daemon/algod/api/server/v2/generated/data/routes.go index d2193d9a1a..8791ef0041 100644 --- a/daemon/algod/api/server/v2/generated/data/routes.go +++ b/daemon/algod/api/server/v2/generated/data/routes.go @@ -278,79 +278,6 @@ var swaggerSpec = []string{ "XQELTNqrHQW+lAUo/5vP0LWj5OwCwleB0C1zSWXmW0TtDN6EkYycR730Ll/wvov0sh6ZNUGa/YSeSOEn", "DMVNc2H0r2QonrkdFxk+no/RH7bkN0Z8GryWIN3raajs5UJBooUP6hzDY4wU7qH3mxBBDRZbtMgNlkB5", "29R4waKzFEueUBfZEk6QSCiowU4GlViGxxwj9gv73Wew+KKje80pNb/uLzTvw3OZ6hEx5Polcafl/syY", -<<<<<<< HEAD - "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", -||||||| constructed merge base - "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", - "Er5i26yUbIMJ4B+u/n8AAAD//y/FazkqxQAA", -======= "m1hWGOf2rVYVK8vCDSlD038pRVal9oAON0ZtfZpc9GhElESNEml/lh2FOEgvvIDdodX4fYV+v4Ih0lZz", "sqgH6fydRb5TW5OK4b26E/Q+p5lmPiuFyJMBy/5pv5ZMl+MvWHoBGTEnhQ9jG3ikhNxHg3Ltur1c73zt", "lLIEDtmDA0JOuA0c9l7cdjHjzuD8nh4bf4ujZpUt7+QsSAfveTwCEwsvyVtKMw9mXIYpMKLulkNZIHsq", @@ -378,15 +305,14 @@ var swaggerSpec = []string{ "joGvVfEPWCcBEUUh8fjo6M6e2Oqt7JWNR6/BebxuA7EnU1/4k7LFhkY2Pj16dGdza4fW3npiXXC9WZ1y", "jGwxkp/Ykw0n9PQvO6EXeIM2HL9kPLPvI2iKe9puUJzfl3/Z+WlWeA8ax6dmQKEC8OwON9inZ0Kjh9Oc", "YEs7myd/2dmcgdywFMg5FKWQVLJ8R37idS5pUD+qf8z9xC+4uOSeEEbRroqCyp07AinpiqrwmfrWa39G", - "w6MrhQ4+rNg9m9vo+g9X7ui1guzQvg7dnMj+5x13mVw5xOKifuIKrEXVp3DveDp0HmPjsx1P39aHZO9w", - "wI35xzFxf51qfFFcYODMHyzNp4nfZ5+SCp92732yzfIWCrEBVT+I3DCnUaDMpcS+jSxFEfDwwcimmQ8q", - "ps7R0B/JO1ka4D0tdc+euOnjwiNhUZPw3BPHaMFPeYu1fuu0kzdhh7oXW6DZvwTBvwTBHQoCXUk+uEWD", - "8wtje6G0gUwkpekaDqYfojuehpfYUsQKp5yNCAtXLmJIVpy1ZcWf+ir74U9xvr+g3O/n1orb8DIqcway", - "5gLK+xU8/iUF/sdIAVuKyJmL5kRDnqtw72uBe99GCbiUDW6jNybKge5LnbGfDz+2X4pp2e3UutKZuAz6", - "oq/XBir0zXn124mtvw8vKdPJUkiXroGVfPudNdD80BUi6fza5P72vmBCc/BjGH0V/fWwLpQe/di1qca+", - "OpviQCNfRsp/bnwqoY8CJWTtnXj3wcgnLMPphGdjcj8+PMQQ6LVQ+nB2Nf/YMceHHz/ULOHrs81KyTaY", - "7v3h6v8HAAD//xIUAlAYxQAA", ->>>>>>> oas2 fixups + "w6MrhQ4+rNg9m89cohhsS5CsAI41KK7cSdz6tT6frbQ7tE9I93/ecZfulUMseOonrsCaXX2e946nQ4c2", + "Nj7b8fRtfZL2ThDcvX8cp/cXs8YXZQpG1/zBIn+ajH72KanwaTfoJ9tRb6EQG1D1q8kNcxoty9xc7APK", + "UhQBDx8M7qwPeO2Pa6/OG9EfyXtiGuA9VXbPnrjpC8QjsVOT8NwT7GjBT3mwtX4QtZNcYYe6F1ug2b8E", + "wb8EwR0KAl1JPrhFg/MLA4ChtNFOJKXpGsbkQf+0DG+6pYhVVzkbERaupsSQrDhry4o/9X33w5/ifH9B", + "ud/PrRW3MWhU5gxkzQWU98t8/EsK/I+RArZekbMpzYmGPFfh3tcC974NJXB5HdyGeEyUA93nPGM/H35s", + "PyfTMu6pdaUzcRn0RYewjWbo2/zqBxZbfx9eUqaTpZAupwPL/fY7a6D5oatW0vm1SRDufcGs5+DHMEQr", + "+uthXU09+rFreI19dYbHgUa+1pT/3DheQkcGSsjahfHug5FPWKvTCc/GLn98eIhx0muh9OHsav6xY7MP", + "P36oWcIXcZuVkm0wJ/zD1f8PAAD//zfw1S49xQAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/experimental/routes.go b/daemon/algod/api/server/v2/generated/experimental/routes.go index af4ebe9e41..64a451182d 100644 --- a/daemon/algod/api/server/v2/generated/experimental/routes.go +++ b/daemon/algod/api/server/v2/generated/experimental/routes.go @@ -75,7 +75,6 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ -<<<<<<< HEAD "H4sIAAAAAAAC/+x9+3PcNtLgv4Ka76vy44aS/Ih3rarUd4qdZHVxHJelZO9by5dgyJ4ZrEiAAUDNTHz6", "36/QAEiQBDnUI/Zu1f1kawg0Go1Go9EvfJqloigFB67V7PjTrKSSFqBB4l80TUXFdcIy81cGKpWs1Ezw", "2bH/RpSWjK9m8xkzv5ZUr2fzGacFNG1M//lMwu8Vk5DNjrWsYD5T6RoKagDrXWla15C2yUokDsSJBXH6", @@ -209,367 +208,33 @@ var swaggerSpec = []string{ "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", -||||||| constructed merge base - "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", - "vwAA", -======= - "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", ->>>>>>> oas2 fixups + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go b/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go index b89b4db42e..a88933e8b1 100644 --- a/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go +++ b/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go @@ -263,73 +263,6 @@ var swaggerSpec = []string{ "V66ABSbt1Y4CX8oCtP/NZ+jSKLm4gPBVIHTLXPEy8y2idgZvwki2nEe99C5f8L6L9LweWTRBmv2Enkjh", "JwzFTXNl9a9kKJ65HRcZPp6P0R9U8hsjPi1ecyjd62mo7OVKQ2KUD+rchsc2UriH3m9CBD1YbJGQGyyB", "8q6p8YJFZzmWPOEusiWcICthxS12ZVCJZXjMbcR+Sd99BosvOrrTnFLz6+5C8z48V+geEUOunzN3Wu7O", -<<<<<<< HEAD - "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", -||||||| constructed merge base - "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", -======= "jLmJZUVISW+16lhZFmlJGZr+i1JlVUoHdLgxauvT6KJHW0RJ1CiR9mfZUYiD9MIL2BySxu8r9PsVDJEm", "zYlQD9L5O4t8p7YmHcN7cSfofUkzzXRSKJUnA5b9034tmS7HX4j0AjJmTwofxjbwSAm7jwbl2nV7tdz4", "2ilFARKyBweMnUgKHPZe3HYx487g8p7ZNv4aR80qKu/kLEgHH2Q8AhMLL5W3lGYezHYZpsGKulsORUB2", @@ -356,13 +289,12 @@ var swaggerSpec = []string{ "/ih58fHTo+mjo+u/2PPE/fnsyfXIyImXNVx2Vh8WIxt+xBIGaIjB/fv46OgWj3ueyID8tEjBG7K9qkC0", "EsO2R7dUHUCsJsaOVOsO+NhrYdfTydM9Z7zVftSKhY28+vU1z5jPpMSxH32+sU8lxq1Yuc7o3LqeTp59", "ztmfSsvyPGfYMqid01/6n+SFVFfSt7RKRrVa8XLjt7FuCQXmFhuPMr7Q6MkoxSVH3U4q2XoQZPIRvWex", - "bNYBeaMNv4G8ObO9/i1vPpe8wUW6C3nTBnTH8ubxnnv+zz/jf0vYP5uEPSNxdysJ6xQ+SiDqa6CU6n9I", - "r5H3f97INPpjH1D3VazYz4ef2lXZWzqyXlYmU1dUhyJ6KGDpUZ67OmVoBK0vVEYxD6AJn2U/uvSWfIOW", - "X5EB45h3ryrT3Hht59qjW/skLITmxbyFkDgAGpdxFCrIx4PANA2pkvS+VOcAcpi9URn0DyA8Yn6roNw0", - "Z4zDcTJtSSDHQpHyd7cW6H2Bcb0fg6ERnDw4feaoH5Vq/X14xYWxx5SLY0WK9jsb4Pmhy9Du/NokRfW+", - "YKZX8GPolo7+elhXkI1+7F42Y1/dZWugka+v4T83xqbQeIMsUZtt3n+0K4v1yRy3NLaI48NDjA1bKm0O", - "J9fTTx07RfjxY72YvnBNvajXH6//JwAA//9bJ5F3Mb4AAA==", ->>>>>>> oas2 fixups + "bNYBeaMNv4G8ObO9/i1vPpe8wUW6C3nTBnTH8ubxnnv+zz/jf0vYP5uEPSNxdysJ6xQ+SiDqa6CwLqAU", + "K5BUxsj9SgUADumN8v7PG5lGf+yD776VFfv58FO7VntLc9bLymTqiqpTRI8KLEjKc1e9DE2j9TXLKOYB", + "NEG17EeX9JJv0B4sMmAcs/FVZZp7sO1c+3lrT4WF0LyjtxASB0CTM45CZfp4EK6mIVWSXp3qHEsOszcq", + "g/6xhAfPbxWUm+bkcThOpi255BgrUhTv1mK+L0au92M7NI2TX6fPHPVTU62/D6+4MPbwctGtSNF+ZwM8", + "P3R5251fm1Sp3hfM/wp+DJ3V0V8P67qy0Y/dK2jsq7uCDTTyVTf858YEFZp0kCVqY877j3ZlsWqZ45bG", + "QnF8eIgRY0ulzeHkevqpY70IP36sF9OXs6kX9frj9f8EAAD//6hJpJBHvgAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go b/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go index 7d9661be67..9c5cd496fd 100644 --- a/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go +++ b/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go @@ -572,7 +572,6 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ -<<<<<<< HEAD "H4sIAAAAAAAC/+x9a3Mbt5LoX0Fxt8qP5VB+Zk9Uldor23loYzsuS8nuObFvAs40SRwNgTkARiLj6/9+", "Cw1gBjODIYcSLdmJPtni4NFoNBqNfn4YpWJZCA5cq9Hhh1FBJV2CBol/0TQVJdcJy8xfGahUskIzwUeH", "/htRWjI+H41HzPxaUL0YjUecLqFuY/qPRxL+VTIJ2ehQyxLGI5UuYEnNwHpdmNbVSKtkLhI3xJEd4vjF", @@ -706,548 +705,101 @@ var swaggerSpec = []string{ "eng+AUX4JCXH3TR9Fy6BBQbtVYYCn8oClP/NR+jaWXJ2BmFVIDTLXFCZ+RZRPYNXYSQb7qNOeJdPeN8G", "elbNzGonzW5ATyTxE7riprkw8lfS58/c9IsMi+ej94dN+Y0enwauGUhXPQ2FvVwoSLTwTp2b4NiEClfo", "/TJIUL3JFi1wvSlQ3tY5XjDpLMWUJ9R5toQLJBKW1EAng0ws/XNuQvZz+91HsPiko1vVKRW9bk80791z", - "meogMaT6GXG35fbImMtoVhjntlariqVl4QaVoeq/kCIrU3tBhwej0j4NTnq0gZVElRJpd5Wd92WOKcBe", - "BnGGZ7A+sKK/T9XvtzKE3opQdg1BXH9rt/eqdIq/r/O5XcB8L3DepOJmPCqEyJMeXf9xN7tM+wycsfQM", - "MmLuDu/Y1lO2hNxFFXNlzL1YrH02laIADtm9CSFH3LoSe7tuM71xa3J+R2+af4WzZqVN+OR0SpN3PO6T", - "iamY5BX5mx9mM1dTYJjfFaeyg2zJXbLqyWwj6UWkiM9k6KO0a2ltF1apicpCEZNStpSwiFiRfU0EX2HD", - "R6xosWRpt4pCR5SYYTWqhEYGP64Y+LhRK5C1Cnf4HEO2TENKrQBnHg+U5aUEFzlgy+a00ukXVC/89pnm", - "XTHLXNmg0K3fpmSnyj4K/OPE1expnwtRJDmcQ8OQ4MIZyjQFpdg5hPV+bGeSART4VG9fIDENeUhXLR7i", - "1p4EOtYh2I0yFYtYu1NkC8foKcaeWPJQQ0nIQHTOspI28KeuUIplYG33ENaBJ2TnwxFfXOdouHIpSZXM", - "LabIdOEkfgsN/dalXVoCUlCCpRqzpxZlhYWrCCO9qI1j9nJJNAbRQ1enHTkyQdmVzZqXMMdO7bwrrWkE", - "X2r+1LW39FV9GocVgPEdtoAXKuSCEjBeEnLg3LCH7asKKcFSeimhsfxtOj63wJp9BVtkebdZps14Zr2z", - "mvsSKHDV80ov2leXqa0+xYQ6gmOSsa7aVaGpDHOVh4RjeLc8p/n1q04x09IR4sPVuY0vNNS9hUi2qFSX", - "c3N7SQfNHejZ9jc1f4Oq3v8Bs0dRG6cbytk8KlnBW4aQZdKc5KKucIdDkgsc0xpFH35Fpi5Ep5CQMsVa", - "0YsXPo1ypWrCqgJ1+ePNuq1t6/xF6CuQ8cyLL+R1nZJVC7wxagjrI3rDTKXn5EapPEZ9HbKI4C/Go8Jc", - "GVuui7OGtdSmuG65AQoJe7aaBv5PO1pNu1lAhi7PWgbNpVMq6K5z8G3dwG3koq7XNtTk30XuprydQyz1", - "8XS8pju6CliEYC5rgqCS3x/+TiTMsFiNIPfv4wT3749d098fNT+b43z/frzM8nU5CVgcuTHcvDGK+aXP", - "bdy6RvdEKLT2o2R5to0wGvEmdbknjKj4zUWc3UjBqd+sLad7VF3Rj13ck9qbgIiJrLUxeTBVEEkyIIjE", - "dYuEjKBWJC0l02tMhONV/+y3qDvD95W10Fmbq9QJ7u7T4gyqVEq1bbFU/nb9XtAc7yMjU6NzmMbSut+u", - "6LLIwR2Ub+5M/xMe/+1J9uDxw/+c/u3B0wcpPHn69YMH9Osn9OHXjx/Co789ffIAHs6++nr6KHv05NH0", - "yaMnXz39On385OH0yVdf/+cdw4cMyBbQkQ+7Hv0vVmVLjt4cJ6cG2BontGBVRW1Dxr60DE3xJMKSsnx0", - "6H/6P/6ETVKxrIf3v45cVOdooXWhDg8OLi4uJmGXgzkaExItynRx4OfpVjJ+c1xF5tinJe6oDbrwKgNP", - "Ckf47e23J6fk6M3xJKiUeTh6MHkweYiFFAvgtGCjw9Fj/AlPzwL3/cAR2+jww8fx6GABNEfbu/ljCVqy", - "1H9SF3Q+BzlxNXbMT+ePDrwocfDBGVI+mlHnsRRBNsYoCCzplp5xRll01LQxRI1U7splFh9XCf6d1oJn", - "GPphbROGtVXIOs7qTLbHNaPy+XxsgsPDXyOVB2dsbt7RjYqqrVqt5uX93yc/vSZCEvekeUPTs8pthhzP", - "bG4GKc4ZRhRkQRiK6TnxNPuvEuS6pinH7cLkfT5fu4vTWKp50XRqriWpWEHxWJkfnNmQQkDMldmzZlZa", - "lhBCUrNew04fJF+///D0bx9HAwBBG7wCTO3wO83z322FWFihIdMnR3LJL8aR3OQoQY9rMxp2qHdyjF7Z", - "1dew/EzVphkL9DsXHH7v2wYHWHQfaJ6bhoJDbA/eY/IBJBY8Z48ePNhb3aoq/M36dlejeJK4xEBdJmQ/", - "RUrR+vJVPXVon+xxoU3n1Ssvtz1cZ9HPaIYlQUBpu5SHX+xSjjm6wZhLgdhL7+N49PQL3ptjbngOzQm2", - "DDL7dC+an/kZFxfctzQCT7lcUrlGcSaoW9QKraVzhRYVZJH2bDcqlYzef+y99Q7CQgwHHxqeFNmV7sRO", - "DZrjF1uuyTuqj3N282K26jyY71Uaf7S1u2IWWFhA3ZuQ78PeyL0xzYRN4lBKDpl3hPC3XpU3y2fjqmG7", - "o8IMHNFLO1AR397fN31/HzUVHI3cizFgGqdgI0wdb6yrXqDdCKpWJb9LVcoLKi5cIm/1Jy0n1Hpf2pne", - "x55/Wxn1Le56cNcnJgXwVhJTs1LGp2fNPmKhukkaV8YnZNxfuND3iuaGToLltqK5bULSW2HwLyMMVg66", - "tiCvz8F9NfEQq/EcfPBJZvcgErokuwOEwfBZHfQNkqDebbGTexObMTZsczme4Txyt4p5mPr3VsD7DAS8", - "blrtGBh1suSbE+oQhkWdd3uXarqNMlk75Qf/QqW4vzCyesU2A+l2ge0S7LMjjDlm/cnY6p9SCHNIuxW/", - "/tLiVxUncyUBrJEY30VeBWasK2nv2to5pitJrBkrFXC2qgyxO8LjuoiPYTGYV8mn1FBj/zJEE6p9NNrN", - "GnfejV0R63sIH6jP1scvtklXX5CeZ3B+v8gtEN+bT81Lo2aHt9djdhjGm548eHJ9EIS78Fpo8h3e4p+Y", - "Q35SlhYnq11Z2CaOdDC1mYc3cSXeYkvIKOqMwgGPwsINYdZi65Fx15XLDDNB3JsQn99YVdUaXP6BuaB5", - "nWeJyrntZHicQQK54/88xPHvTMh3GBGg1Rgdy7RL5U/uMK4PHz56/MQ1kfTC+m21202/enJ49M03rlmd", - "zdq+bzrNlZaHC8hz4Tq4u6E7rvlw+L9//8dkMrmzlZ2K1bP1a5s67nPhqeNYPEG18X279YVvUuyV7lL6", - "bUXdtZjtn4lVlPuL1e3tc2O3j8H+n+LWmTbJyD1AKw1mI95+j7eQPSa73ENjnx3a8J3qMpmQ18KlPilz", - "KomQGUhX3mZeUkm5BsgmnlIxak3ZVA9pzoBr82DEgh0yUSwDGzE+LyVkJGdLrGgr4Rz94XF6fMs3INjO", - "6NFr9rNl8q/oKkiHMK2uaS3cklHduaQrXzIIi2IIiT998w15MK5fLXluBkgqxMSY65KuRteo7auIbZCv", - "eTOr/1ZnXBx7iOaoln5sdTbaTCH+1+bcX6zEbsndbeyeOOfOBp/aoBPqD1yCkY2aAyvY2YJCWOFmXYfz", - "GinPi1BxFmdmGKoU+IxtA1tV0tHHZxu9t4f49vF/JVbSJqgd2QZGmKqDD2jLCHlG59xihNxfy0wa2Iyk", - "WHqjkSAz0OnCBee2UB9hT76mQD9v2lRRct9SDe5iN6V1mN8RKx0OTBgSxE2i4Q5khIh/8ul9zWc2sxkq", - "fL0IXzgVTVLM1xKryoi5YotMeT9+H8NrdnEnKJ/Xk3cFMkTLPuyetwjeDcEd5vitr1mFGHOL+DN4+vun", - "ZEJeizpE3JVL+DOaHD/lzf6pF/RacLC2dSP5Wlq8NaNWYgeq8BEpPjeIfb9UiasvLYIc+OprG+WQH2zt", - "s42yyJDb20z2RV7hP0TrGjduGbO2ydbEB/VoQ5izaWhzTDezS9/gK+ZG+Oln+LS5CY51PSwGD6nnM04s", - "4PtlOphuxxLzQZVYuI8DxXO1D+ZGWlTuZ9H06lPIBZ+rz5MVbaKOOF4iVFJlsY+nqv/rnd3nmMnHPHmt", - "56PL7aQYT8FWF/QF5l3iNQvh364PQs2WPhcnD2NWb5i7PH3w+PqmPwF5zlIgp7AshKSS5WvyM68qQV6F", - "22Ei/irXmtcGR2svoLWpmQMsDRMWXZ4JNlzWPugVyz5uZ4ZBxr4d+SDjAR8M8wvSogAqL88At5uuTlsz", - "Hr8IvYIb+eGr7FkRUAyKdnSM/4/RQL0ThruLmbv8Sm4B9Zm+HJtwLrtiNq6cY4wUIGaH5B2/T9SCPn34", - "6LdHT7/yfz56+lWP5szM4xL0dHVn9UDmsx1miALti1YH7ldqr/B7eN27vdsmjkcsW0XzRdc1YTpZc51Y", - "dkeRgq5708wXW2rahMPW9W2uP7Gh0my6iL6v/POnqnp7zJ9Vr2Cbfc+VgrmtZdMTNBHwGUNodVGbCuub", - "69tskCZbZFkVErnux2kdXGAvOo882bpzblTQ1Tf1SE3wjQrcCzZNtNycTIk5zceBubuqI46+K2VRCKmr", - "060mg8Q96DPbNaS9PsLdSZhLqU4XZXHwAf+D2bw+1gEHtnJnYOdzv8OqAMmM6IiFe9yvtvL+gbXtb5L+", - "TmyLK96ULTHbehS0Mqz7dHPO30DMyCuWSnGECfTdJaTWSsOykxPQdf1tU0336IUleM44JEvBY5nqfsKv", - "r/BjNEW/0DTv63xqPvb1bbHMJvwtsJrzDOGXV8XvZ/JAv5JiqbVaCeZw11XPLP3veAD9oVnztHuS1jzt", - "Hr5G6bWenw8+NP50nj2upVqUOhMXQV98FloONcSoH2TQHq5Nr15KrUzUimSgDNF+eaqrAA+xE1N9jeQn", - "C/Kk96Yo+4sqs2aMZy0iQTkzFecgVaXmkN4J51aj9efRaA3e9514rM3HuY2jlWq/EslrkYEdt5kCNxZE", - "ykUGLm1oVxCpJLO4FsDfSnW71rsspeV8oUlZEC1iL8C6Y0JTy2RtcUa1rZqdbeVrsJwDobkEmq3JFIAT", - "MTWLblYFJVShA71/Rjr5M16UrYarkCIFpSBLfNDsNtCqZKz46NQb8ISAI8DVLEQJMqPyysCenW+Fs0pg", - "rsjdH39R924AXisKbkasdduNoLdyDXLSXhfqYdNvIrj25CHZUQnEiwao9RLLIgen94qgcCec9O5fG6LO", - "Ll4dLagYYp+Y4v0kVyOgCtRPTO9XhbYsEnN/R8pG2q+nbImSGKdcKEgFz1R/cddtbBmLiARrUWYFASeM", - "cWIcuOfB+ZIq/daZQMJaX0GxEjPFhmq0fYnyzci/VGnyO2On5j7kqlRVLn2n1ojX2+Kw2jDXa1hVc6EN", - "yo9d6U20IKWCbSP3YSkY3yFLheVldWA8wlIi3cVhphPqFBRdVDaAqBGxCZAT36pRSK42bPQAwlSN6Kpm", - "ZJNygqJZSouiwFp2Scmrfn1oOrGtj/TPddsucblyRnhvZwJUqNNykF9YzCoM5VhQRRwcZEnPnNpr7jJB", - "RQp9sSUkaK5ONlG+OZYnplV4BLYe0rKYS5ph2VEaUaX8bD8T+3nTALjjnjyxpnMyhVm0NInZ9JqSZa+K", - "qBpa4HgqJjxiCWhFUnMEZ1grxxOI671l5Ax66k+fBjUxXXOcK7pFfjxctt3qHrWUGcPsuCUHhNgx9CHw", - "9qChGvnymMDOSa09aE/xd1BugkqM2H2SNai+JdTj77SAtjYvvL8aF0WLu7cYcJRr9nKxLWyk78TG9Idf", - "ZKhf25j7CT3VmvrT4P03uczb9uCCMp3MhHRV9elMg4yo8lqFDijTPpLQmlW0cH4UBEdw16Ybx1Vnr9Nx", - "OCZiQSC+didbRrL7mKm+E3JQOFDT6Y0yTUquWR6ERFcv5c9PX3irA7jVAdzqAG51ALc6gFsdwK0O4FYH", - "cKsDuNUB3OoAbnUAf1kdwE3F9yVe4PBez1zwhMOcanYOVeDfbUqiP1U8THVVeZ0EajEuKNMuwSehXgzA", - "L1cLB9RAc8QBy5HHFkL1Zk7CctBKlDIFkhoIGSdFTs3TAFa6SjfXTGTqUyu7gtCYG5UqePyInPxw5N32", - "F869vNn27pFLUa70Ood7LqFDVbHVZ3YAbpDuEjtQfyX4tHQuSR/LgSiD3m+x9Qs4h1wUIK1HMNGyjGh8", - "ToHmzx1utih8GgU3zWi/jxt6Joe2JS2Cwve4VqoItbEczXqZM5qr/oKZdrwlLWKZ4aqLz6qCkJs8E9m6", - "dULMrh3gBjbPRu28zziV60jgTudEdEhDC8OvHGF1dVkf9x5i0iXaLplto7CYtC5BRc/xJiqPxlZUG9YZ", - "yoYAzVp0Ei0o3Q4oGFUADnGANfTs94S8tf1uNoAdIXJHrGbmn43fYLNlxTSwrXlEONbzpUabe8RHTy+e", - "/bEh7KxMgTCtiI9S2X69jEerxIw0B544BpRMRbZOGuxr1LiFMqaoUrCcbr+JQv7pciG7y8d82XxP3cw1", - "8iJY3CaeHBLNKnEMuIc7rzUM5s0VtnBEx54DjH9qFt3HRkMQiONPMaVSuwLNjkyvnmZ9y/huGV9wGlsS", - "AeMuqq/NRCafkPHJtSx5P8/7dgVpaYALT/Jd1M6jSQ5WumHXzGBazueY07ljozNLAxyPCX5DrNAudygX", - "3I2C7OBVns+rppZqD9flLkEE210hyVyKsrhni1fxNRozlgXla2/yhUSxZZlbHNp0ePtltDbwrusIgOZY", - "p/vr02q/8Sq/QHfrrtrm7xYt5IIqYvcXMlLyzEUOdcJzV3x4Pmk79OmK12x6Y0Zpu97I6ty8Q64Iv8su", - "xKUycxcgE73i9kA1k77bMGB7cie3uWz/GtfGG5uHoYfBdkNaa4awp9tDBnwNr48gcUkdCteswGXrA/YF", - "joRZTGzLvTqPdIZv+pAE1fmsjRTyglBfaCAVXGlZpvodp2ijCRY26fqXeG10P3977pvEzYQRK54b6h2n", - "mIe+stxE+dwMImaK7wA8G1XlfA7K8MqQSGYA77hrxTgpuXlpiRlZslSKxIahmjNk5JOJbbmkazKjORoZ", - "/wApyNTc7MGuW4Wx0izPnUOLmYaI2TtONcmBKk1eMcNlzXA+w1jlyQX6QsizCgvxpBZz4KCYSuLKl+/t", - "V8wb4ZbvlXyosLSf63jv600Y4WFnWS/kxy8M3BRT5ORM6doHogP7tdm/l4wnUSI7XQBxLmFt2iJ3MYOM", - "I6B7TeuQXsA7bm44LQhydaovRw5tM0/nLNrT0aKaxka0rEF+rYOeeHvhMiTCZG5NK3+iwMyADrz5Ejce", - "K9S0935HM8rGopexry7PWE8j90hoKMKaF/eJa3HaAPnPm6P+/b60ZsNtGgtAnlnp+EPOqgWp9ujTas42", - "upTUOeWWS8gY1ZCvSSEhBczkgr429YNzYmP2SbqgfI73jhTl3JWDtuNcgIQq/ZZ547WHiGf8WPEEBd2I", - "48ARsco6T17m6GHBwxCd2NlyZ/Oo9Ki1CRWGPBsjx+F7M2bfK3I86pUSDVLPa98ui5zmGYlj4UKUeZao", - "Mk0h5qFxHPWaqpbaFOBwLCu7uQEhI1kpbWVsQlNdYg2aKebFFLbkFOXr5vWPtbuEDPJnEkoUm3OqSwlj", - "uzb0FJsCQYPjJOI+07rcG9d0sPM1Stuo2Ed5gdtjcHsM/nzHoHPpvHVEMmupEixlhAT4pyoMUWeOO3Il", - "Ntq50W7r0n/WBRU+5SPhU6/mU705PDNWhGLV3vA8t3Ii2uNNFWHa8bwpEDineYk80WV9dy/xCTmtOWbl", - "610ql4w0XVDGXQ6aKioB4dAuYbL2GRr3pZakF3rFnVbSMj9URxpsQFpKptf4HKEF++0MzP/fG3neVhG1", - "L5VS5qPD0ULr4vDgAAvvL4TSB6OP4/Cban18X4H/wT8yCsnOsQ7P+4//PwAA//+FikGliEkBAA==", -||||||| constructed merge base - "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", -======= - "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", - "R29tKCQ7wzTWHz79/wAAAP//mPC/k7U8AQA=", ->>>>>>> oas2 fixups + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/participating/private/routes.go b/daemon/algod/api/server/v2/generated/participating/private/routes.go index b0b11c18eb..9a9f6a233b 100644 --- a/daemon/algod/api/server/v2/generated/participating/private/routes.go +++ b/daemon/algod/api/server/v2/generated/participating/private/routes.go @@ -291,77 +291,6 @@ var swaggerSpec = []string{ "pu/SFbDApL3aUeBLWYDyv/kMXTtLzs4hfBUI3TKXVGa+RdTO4E0Yych91Evv8gXvu0Av65lZE6TZT+iJ", "FH7CUNw0F0b+SobimdtxkeHj+Rj9YUt+Y8SngWsJ0r2ehsJeLhQkWvigzjE4xlDhHnq/CRLUYLFFC9xg", "CZQPTY0XLDpLseQJdZEt4QKJhIIa6GRQiWV4zjFkv7LffQaLLzq605xS0+vuQvM+PJepHhJDql8Sd1vu", -<<<<<<< HEAD - "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", - "XwAAAP//qWbn/XHIAAA=", -||||||| constructed merge base - "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", - "yAAA", -======= "zoy5iWWFcW7falWxsizcoDI0/ZdSZFVqL+jwYNTWp8lFj0ZYSdQokfZX2RGIg/TCc9juW4nfV+j3OxgC", "bSUnC3qQzt/Z5Du1NakY3Ks7Ae9Lmmnms1KIPBmw7B/3a8l0Kf6cpeeQEXNT+DC2gUdKyEM0KNeu28v1", "1tdOKUvgkD3aI+SI28Bh78VtFzPuTM4f6LH5NzhrVtnyTs6CtHfG4xGYWHhJ3pKb+WHGeZgCw+puOZUd", @@ -383,19 +312,19 @@ var swaggerSpec = []string{ "OGdrrUt1uL9/eXm5F3bZX6HrINGiStf7fp7+u8Xvj+s8HKta4o7aFAtvMvCkcITfPnx/ckqO3h/vBe9i", "Hs4O9g72nuCziSVwWrLZ4ewZ/oSnZ437vu+IbXb4+Wo+218DzdHTbv4oQEuW+k/qkq5WIPfcizrmp4un", "+16U2P/s3CZXY9/2w+LU+59b3qVsR08sXrv/2ddkGW/dKnrivGpBh4lQjDXbX2Cq59SmoILGw0tBBUPt", - "f0YRefD3fZf/Fv+Iqoo9A/veBRtv2cLSZ70xsHZ6uAf49z/jf5AmA7BstGkfXJsXtm+fruz/vOVp9Mf+", - "QL0nFFYQTWnD5DI69kg8ngJ7gI4z5Gu69+Y91mO2Vg48HE8PDv4cz98/vyagozaVVnxoBJiXNCM+uxDn", - "fnJ/cx9zjOUwvI5YXo4QPL8/CNrFr3+ELXknNPkBlY6r+eyb+9yJY25EIJoTbBnUtukfkZ/5OReX3Lc0", - "QkBVFFRuJx8fTVcKHQ6SXVAnggXvIcw+oYfLZpy2j9pRlvWI3gpDoPRLkW1HMFaoVemyQRqkNbIg42YJ", - "fWWy/8Bk7436c9gS6+33jgIuMpiFUpqWFVzdkif8aZ/T/8pTvvIUaad/dn/Tn4C8YCmQUyhKIalk+Zb8", - "zOtc3hvzuKMsi0ZSto/+Th5n9OxUZLACnjgGlixEtvX1ClsTnINV+3qCzP7ndtFxKwLOMshBR6PEzO/1", - "c5D9RSy25Ph1T8Kx3bqc9+UWmwbFvA8/frZ6k1EKGrWmC2KPM4Z1pLu86VOca46RvVnISmhisZC5RX1l", - "RF8Z0a2Em8mHZ4p8E9U+bKUM2ruz577oRazcEdV9UKboKF/0+N7Jxvf1n5i+YyNSISPBB5s60UXzVxbx", - "lUXcjkW8gchhxFPrmEaE6K6nD01lGBhsk3Wf9kHXgW9e5VQSBVPNHEc4ojNu3AfXuG+lLoorq9NR3rx+", - "FtnAu9XzvrK8ryzvz8PyjnYzmrZgcmvN6By2BS1rfUitK52Jy8CTgLDYyJ6+Hbh+bLT19/4lZTpZCuny", - "m7D0db+zBprvu8o9nV+bZPneF6wAEPwYhitGf92vXxaIfuw6IWJfnRF+oJGvu+Y/N07I0KmHrL125338", - "ZNgy1q11XL/xUR3u72POwFoovT+7mn/u+K/Cj59qEvhc3xWOFK4+Xf2/AAAA//+PISaEScgAAA==", ->>>>>>> oas2 fixups + "f0YRefD3fZf/Fv+Iqoo9A/veBRtv2cLSZ70xsHZ6uAf49z/jf5AmA7BstGkfXNiUIJkRstDZ7H612WL7", + "9kHL/s9bnkZ/7A/fe1hhBdFEN0w5o2NPx+PZsMfqOENup3sv4WOVZmv7wCPz9ODgz/Eo/vNrAjpqaWlF", + "jUaAeUkz4nMOce4n9zf3MccID8MBieXwCMHz+4OgXRL7R9iSd0KTH1AVuZrPvrnPnTjmRjCiOcGWQcWb", + "/hH5mZ9zccl9SyMaVEVB5Xby8dF0pdANIdkFdYJZ8ErC7BP6vWweavuoHWVZj+itiARKvxTZdgRjhVqV", + "LkekQVojITJultBXMfvPTvZerj+HLbExAN59wEUGs1B207KCq1vyhD/tI/tfecpXniLt9M/ub/oTkBcs", + "BXIKRSkklSzfkp95neF7Yx53lGXR+Mr20d/J44z2nYoMVsATx8CShci2vopha4JzsMpgT5DZ/9wuRW4F", + "w1kGOeho7Jj5vX4ksr+IxZYcv+5JOLZbl/O+3GLToMT34cfPVpsyqkKj7HRB7HHGsLp0lzd9inPNMbI3", + "C1kJTSwWMreor4zoKyO6lXAz+fBMkW+i2oetn0F7d/bcl8KIFUGiug/KFB3lix7fO9n4vv4T03dsnCpk", + "JPhgEyq6aP7KIr6yiNuxiDcQOYx4ah3TiBDd9fShqQwDQ3Cy7oM/6FDwzaucSqJgqpnjCEd0xo374Br3", + "rdRFcWV1OsqbN9EiG3i3et5XlveV5f15WN7RbkbTFkxurRmdw7agZa0PqXWlM3EZ+BcQFhvv07cD10+Q", + "tv7ev6RMJ0shXdYTFsTud9ZA831Xz6fza5NC3/uCdQGCH8Mgxuiv+/V7A9GPXddE7KszzQ808tXY/OfG", + "NRm6+pC1106+j58MW8Zqto7rN56rw/19zCRYC6X3Z1fzzx2vVvjxU00Cn+u7wpHC1aer/xcAAP//w2O7", + "v1/IAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/participating/public/routes.go b/daemon/algod/api/server/v2/generated/participating/public/routes.go index d67ba24df9..e196683d77 100644 --- a/daemon/algod/api/server/v2/generated/participating/public/routes.go +++ b/daemon/algod/api/server/v2/generated/participating/public/routes.go @@ -177,359 +177,6 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ -<<<<<<< HEAD - "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", - "dfgnpWTXWNbv/cf/CQAA///C44qjANcAAA==", -||||||| constructed merge base - "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", - "/J8AAAD//7X6ZKDq1gAA", -======= "H4sIAAAAAAAC/+x9f3PcNpLoV8GbuyrbuqEk/0h2rarUPdlOsrrYjstSsrtn+WUxZM8MViTABUDNTPz8", "3a/QAEiQBGc4kmJvbv2XrSHQaDQajUb/wodJKopScOBaTU4+TEoqaQEaJP5F01RUXCcsM39loFLJSs0E", "n5z4b0RpyfhiMp0w82tJ9XIynXBaQNPG9J9OJPyjYhKyyYmWFUwnKl1CQQ1gvSlN6xrSOlmIxIE4tSDO", @@ -693,19 +340,18 @@ var swaggerSpec = []string{ "roJPjh/+bmd4xjHczqijxKrbH6eTr37HS3bGjWJDc4It7Wwe/25ncw7ymqVALqAohaSS5RvyE6+TpYMC", "aX3x9xO/4mLFPSHMTbIqCio3TommtcypeJC+vlX+9GIXGkUbpShdKHRzo4o6aT2qxReT9x/9HWDkxWJb", "s6MZVm8Z2xRU0Hj4doI+A3X0Aa3eg78fuZIW8Y/ofbDX2iMfVRlv2br4fNBrg2unR0p1uqzKow/4H7xm", - "BmjZBLI+urbUw5F9jb7/84an0R/7gLqvosV+PvrQrsrfIqhaVjoTq6Av2tWtU6g/Xv1OVevvoxVl2mgI", - "LjQWqyb2O2ug+ZFL+u782uRZ9b5g8ljwY0enKIWty9G+zr2lq4uW11jaQh3PRLbZIm3WyYxx3IKhiGis", - "ZfZj/37Qf4J7CbbYsHc4RhQwLchMCpqlVGExPlceoXcx/HjLy0dHb1yfRdxJiCbetftRlmYzHe70MSDc", - "PV8nD2rYoqarlH9l/LfUSnoYPaMZ8YVcEvKK5mbBISOnTvdtUeO31ig+vwrwmc/sT3bIPvObTxGKkWWt", - "25GMRPe4GCi3UcecqOYKZQTAAnjiRFAyE9nGl2SWdKXXNg6tK9yO6tra0Y93YIb757a97TK5fbF0fbF0", - "fbGFfLF0fVndL5aukZauL3agL3agf0k70D7Gn5ia6Ywfw9om1rekrXHt3Y42qZW1iG9H+zNd62T9UsZM", - "HxJygYlr1JwScA2S5vjcgwoyUQsMLMScAchOLnnSwsSG75mB7zf/tXGT7jX94wfdPkqzPA9lc78v6rv4", - "ydZ4+YZcTi4nPUgSCnENmc2HD1N7bK+dYP9PDffHXk4gplLjG84+tYCoaj5nKbMkzwVfELoQTcyvkduE", - "C/wC0iBnKysQpqeuVAdTZGUm76qMtjOQ2pp7XwM4a5Zwp8+8wy5xd7lhvD195f8xxlH+L62l3yJZ4VaC", - "dCvsnlT9IlU+hVT57HLl9+6FDMyH/yvVzCfHT363EwqNza+FJt9hPPvt1LG6cnOswMRNFS1fBtyb+5qY", - "2DDGFE/ROrr03XtzEOAzKu6AbUImT46OMIV9KZQ+mpjjrx1OGX58X+Ps6+tPSsmusVzf+4//EwAA//8h", - "c85b2NYAAA==", ->>>>>>> oas2 fixups + "BmjZBLI+urAuQTIjyzF+1P1qC0Ac2Tfq+z9veBr9sQ+++1Za7OejD+1a/S0yq2WlM7EK+qK13bqK+uPV", + "r1e1/j5aUaaN3uACZrGWYr+zBpofuVTwzq9N9lXvC6aUBT92NI1S2God7UveW7q6aPmSpS3f8Uxkmy0y", + "aJ3MGMeNGQqOxoZmP/ZvDf2HuZdgSxB7N2RELdOCzKSgWUoVluhzRRN618WPt7ySdLTJ9VnEyYRo4g28", + "H3tpttjhTs8Dwt3zzfKgsi3qv0r5t8d/S12lh9EzmhFf3iUhr2huFhwycuo04hY1fms94/MrBp/5JP9k", + "R+8zv/kUoRhv1rozyUjMj4uMcht1zDlrLlZGACyAJ04EJTORbXyhZklXem2j07rC7aiuuB39eAfGuX9u", + "i9wuQ9wX+9cX+9cXC8kX+9eX1f1i/xpp//piHfpiHfqXtA7tYxKKqZnOJDKsbWLVS9oa197taJNwWYv4", + "dg4A07VO1i9wzPQhIReYzkbNKQHXIGmOj0CoID+1wHBDzCSA7OSSJy1MbFCfGfh+818bTene2D9+0O2j", + "NMvzUDb3+6K+i59s5ZdvyOXkctKDJKEQ15DZLPkw4cf22gn2/9Rwf+xlCmKCNb7s7BMOiKrmc5YyS/Jc", + "8AWhC9FEAhu5TbjALyANcrbeAmF66gp4MEVWZvKu9mg7L6mtufc1gLNmCXd60jvsEneiG8bb04P+H2Pc", + "5//SWvotUhhuJUi3wu5J1S9S5VNIlc8uV37vvsnAfPi/Us18cvzkdzuh0Nj8WmjyHUa5304dq+s5x8pO", + "3FTR8sXBvbmviZQNI0/xFK1jTt+9NwcBPq7iDtgmkPLk6AgT25dC6aOJOf7aQZbhx/c1zr7q/qSU7BqL", + "+L3/+D8BAAD//1Q+mv/u1gAA", } // GetSwagger returns the content of the embedded swagger specification file From 8f738fbac271cfa683804e5bbca6ec9adafebe07 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Wed, 22 Mar 2023 14:15:20 -0400 Subject: [PATCH 21/29] Comment clarity --- data/transactions/logic/eval.go | 5 +++++ data/transactions/logic/resources_test.go | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 9445213639..b1448abc5c 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -4025,8 +4025,13 @@ func (cx *EvalContext) accountReference(account stackValue) (basics.Address, uin return addr, idx, nil } + // IndexByAddress's `err` tells us we can't return the idx into + // txn.Accounts, but the account might still be available (because it was + // created in earlier in the group, or because of group sharing) ok := cx.availableAccount(addr) if !ok { + // nope, it's not available at all. So return the `err` we have from + // above, indicating that it was not found. return addr, 0, err } return addr, uint64(len(cx.txn.Txn.Accounts) + 1), nil diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 583a338b38..80e14fab48 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -804,8 +804,9 @@ int 1 appl.ApplicationArgs = [][]byte{{88}, otherAcct[:], {asa1}} logic.TestApps(t, []string{"", innerCall}, txntest.Group(&appl0, &appl), 9, ledger, logic.NewExpect(1, "invalid Account reference "+otherAcct.String())) - // unless the caller passes in the account, but it can't because that - // would give the called app access to the passed account's locate state + // unless the caller passes in the account, but it can't pass the + // account because that also would give the called app access to the + // passed account's local state (which isn't available to the caller) innerCallWithAccount := fmt.Sprintf(innerCallTemplate, "addr "+otherAcct.String()+"; itxn_field Accounts") logic.TestApps(t, []string{"", innerCallWithAccount}, txntest.Group(&appl0, &appl), 9, ledger, logic.NewExpect(1, "appl ApplicationID: invalid Local State access "+otherAcct.String())) @@ -821,8 +822,8 @@ int 1 appl0.ForeignApps = []basics.AppIndex{88} logic.TestApps(t, []string{"", innerCallWithAccount}, txntest.Group(&appl0, &appl), 9, ledger) - // here we confirm that even if we try calling another, simple app, we - // can't pass in other and 88, because that would give the app accesss + // here we confirm that even if we try calling another app, we still + // can't pass in `other` and 88, because that would give the app access // to that local state. (this is confirming we check the cross product // of the foreign arrays, not just the accounts against called app id) appl.ApplicationArgs = [][]byte{{11}, otherAcct[:], {asa1}} From 41f4f86877cefdbd4dfe2098d0380b41f8a5c10e Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 23 Mar 2023 12:33:47 -0400 Subject: [PATCH 22/29] Pavel CR --- daemon/algod/api/server/v2/utils.go | 30 ++++++------ data/transactions/logic/eval.go | 22 ++++----- data/transactions/logic/evalStateful_test.go | 49 +++++++++++++++++++- data/transactions/logic/opcodes.go | 4 +- data/transactions/logic/resources.go | 2 +- data/transactions/logic/resources_test.go | 11 ++--- 6 files changed, 79 insertions(+), 39 deletions(-) diff --git a/daemon/algod/api/server/v2/utils.go b/daemon/algod/api/server/v2/utils.go index 7b73c1df9c..846ffac51a 100644 --- a/daemon/algod/api/server/v2/utils.go +++ b/daemon/algod/api/server/v2/utils.go @@ -272,29 +272,29 @@ func stateDeltaToStateDelta(d basics.StateDelta) *model.StateDelta { return &delta } +func edIndexToAddress(index uint64, txn *transactions.Transaction, shared []basics.Address) string { + // index into [Sender, txn.Accounts[0], txn.Accounts[1], ..., shared[0], shared[1], ...] + switch { + case index == 0: + return txn.Sender.String() + case int(index-1) < len(txn.Accounts): + return txn.Accounts[index-1].String() + case int(index-1)-len(txn.Accounts) < len(shared): + return shared[int(index-1)-len(txn.Accounts)].String() + default: + return fmt.Sprintf("Invalid Account Index %d in LocalDelta", index) + } +} + func convertToDeltas(txn node.TxnWithStatus) (*[]model.AccountStateDelta, *model.StateDelta) { var localStateDelta *[]model.AccountStateDelta if len(txn.ApplyData.EvalDelta.LocalDeltas) > 0 { d := make([]model.AccountStateDelta, 0) - accounts := txn.Txn.Txn.Accounts shared := txn.ApplyData.EvalDelta.SharedAccts for k, v := range txn.ApplyData.EvalDelta.LocalDeltas { - // Resolve address from index - var addr string - // k is an index into [Sender, accounts[0], accounts[1], ..., shared[0], shared[1], ...] - switch { - case k == 0: - addr = txn.Txn.Txn.Sender.String() - case int(k-1) < len(accounts): - addr = txn.Txn.Txn.Accounts[k-1].String() - case int(k-1)-len(accounts) < len(shared): - addr = shared[int(k-1)-len(accounts)].String() - default: - addr = fmt.Sprintf("Invalid Account Index %d in LocalDelta", k) - } d = append(d, model.AccountStateDelta{ - Address: addr, + Address: edIndexToAddress(k, &txn.Txn.Txn, shared), Delta: *(stateDeltaToStateDelta(v)), }) } diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index b1448abc5c..c0e55f82db 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -4049,7 +4049,7 @@ func (cx *EvalContext) availableAccount(addr basics.Address) bool { } // or some other txn mentioned it - if cx.version >= resourceSharingVersion { + if cx.version >= sharedResourcesVersion { if _, ok := cx.available.sharedAccounts[addr]; ok { return true } @@ -4080,14 +4080,14 @@ func (cx *EvalContext) mutableAccountReference(account stackValue) (basics.Addre if accountIdx > uint64(len(cx.txn.Txn.Accounts)) { // There was no error, but accountReference has signaled that accountIdx // is not for mutable ops (because it can't encode it in EvalDelta) - if cx.version < resourceSharingVersion { + if cx.version < sharedResourcesVersion { return basics.Address{}, 0, fmt.Errorf("invalid Account reference for mutation %s", addr) } // fall through, which means that starting in v9, the accountIdx // returned can be > len(tx.Accounts). It will end up getting passed to - // GetLocal, which seems bad, since GetLocal can record that index. But - // that record is only done in very old consenus versions. At that point - // v9 did not exist. + // GetLocal, which can record that index in order to produce old-style + // EDS. But those EDs are only made in old consenus versions - at that + // point v9 did not exist, so no backward incompatible change occurs. } return addr, accountIdx, err } @@ -4471,7 +4471,7 @@ func (cx *EvalContext) appReference(ref uint64, foreign bool) (basics.AppIndex, // (or is the Sender, which yields 0). But it only needs to do this funny side // job in certainly old versions that need the slot index while doing a lookup. func (cx *EvalContext) localsReference(account stackValue, ref uint64) (basics.Address, basics.AppIndex, uint64, error) { - if cx.version >= resourceSharingVersion { + if cx.version >= sharedResourcesVersion { unused := uint64(0) // see function comment var addr basics.Address var err error @@ -4561,7 +4561,7 @@ func (cx *EvalContext) assetReference(ref uint64, foreign bool) (basics.AssetInd } func (cx *EvalContext) holdingReference(account stackValue, ref uint64) (basics.Address, basics.AssetIndex, error) { - if cx.version >= resourceSharingVersion { + if cx.version >= sharedResourcesVersion { var addr basics.Address var err error if account.Bytes != nil { @@ -4876,9 +4876,9 @@ func (cx *EvalContext) assignAsset(sv stackValue) (basics.AssetIndex, error) { } // availableAsset determines whether an asset is "available". Before -// resourceSharingVersion, an asset had to be available for asset param +// sharedResourcesVersion, an asset had to be available for asset param // lookups, asset holding lookups, and asset id assignments to inner -// transactions. After resourceSharingVersion, the distinction must be more fine +// transactions. After sharedResourcesVersion, the distinction must be more fine // grained. It must be available for asset param lookups, or use in an asset // transaction (axfer,acfg,afrz), but not for holding lookups or assignments to // an inner static array. @@ -4899,7 +4899,7 @@ func (cx *EvalContext) availableAsset(aid basics.AssetIndex) bool { } // or some other txn mentioned it - if cx.version >= resourceSharingVersion { + if cx.version >= sharedResourcesVersion { if _, ok := cx.available.sharedAsas[aid]; ok { return true } @@ -4945,7 +4945,7 @@ func (cx *EvalContext) availableApp(aid basics.AppIndex) bool { } // or some other txn mentioned it - if cx.version >= resourceSharingVersion { + if cx.version >= sharedResourcesVersion { if _, ok := cx.available.sharedApps[aid]; ok { return true } diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index c33c81d767..c5a17e839b 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -2881,7 +2881,9 @@ int 77 testApp(t, source, ep) } -func TestSelfMutateCurrent(t *testing.T) { +// TestSelfMutateV9AndUp tests that apps can mutate their own app's local state +// starting with v9. Includes tests to the EvalDelta created. +func TestSelfMutateV9AndUp(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() @@ -2894,16 +2896,29 @@ func TestSelfMutateCurrent(t *testing.T) { ledger.NewLocal(basics.AppIndex(888).Address(), 888, "hey", basics.TealValue{Type: basics.TealUintType, Uint: 77}) + // and we'll modify the passed account's locals, to better check the ED + ledger.NewLocals(tx.Accounts[0], 888) + source := ` global CurrentApplicationAddress byte "hey" int 42 app_local_put +txn Accounts 1 +byte "acct" +int 43 +app_local_put int 1 ` ed := testApp(t, source, ep) require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 require.Equal(t, map[uint64]basics.StateDelta{ + 1: { + "acct": { + Action: basics.SetUintAction, + Uint: 43, + }, + }, 2: { "hey": { Action: basics.SetUintAction, @@ -2926,12 +2941,26 @@ int 42 source = ` global CurrentApplicationAddress byte "hey" +int 10 +app_local_put // this will get wiped out by del +global CurrentApplicationAddress +byte "hey" app_local_del +txn Accounts 1 +byte "acct" +int 7 +app_local_put int 1 ` ed = testApp(t, source, ep) require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 require.Equal(t, map[uint64]basics.StateDelta{ + 1: { + "acct": { + Action: basics.SetUintAction, + Uint: 7, + }, + }, 2: { "hey": { Action: basics.DeleteAction, @@ -2940,12 +2969,22 @@ int 1 }, ed.LocalDeltas) require.Equal(t, []basics.Address{tx.ApplicationID.Address()}, ed.SharedAccts) - // Now, repeat the "put" test with multiple keys, to ensure only one address is added to SharedAccts + // Now, repeat the "put" test with multiple keys, to ensure only one + // address is added to SharedAccts and we'll modify the Sender too, to + // better check the ED + ledger.NewLocals(tx.Sender, 888) + source = ` +txn Sender +byte "hey" +int 40 +app_local_put + global CurrentApplicationAddress byte "hey" int 42 app_local_put + global CurrentApplicationAddress byte "joe" int 21 @@ -2955,6 +2994,12 @@ int 1 ed = testApp(t, source, ep) require.Len(t, tx.Accounts, 1) // Sender + 1 tx.Accounts means LocalDelta index should be 2 require.Equal(t, map[uint64]basics.StateDelta{ + 0: { + "hey": { + Action: basics.SetUintAction, + Uint: 40, + }, + }, 2: { "hey": { Action: basics.SetUintAction, diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index 0e9f1161c1..19c4d57cad 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -57,9 +57,9 @@ const txnEffectsVersion = 6 // the Foreign arrays. const createdResourcesVersion = 6 -// resourceSharingVersion is the first version in which apps are allowed to +// sharedResourcesVersion is the first version in which apps are allowed to // access resources referenced in other transactions. -const resourceSharingVersion = 9 +const sharedResourcesVersion = 9 // appAddressAvailableVersion is the first version that allows access to the // accounts of applications that were provided in the foreign apps transaction diff --git a/data/transactions/logic/resources.go b/data/transactions/logic/resources.go index 510900b4c0..849440a26c 100644 --- a/data/transactions/logic/resources.go +++ b/data/transactions/logic/resources.go @@ -319,7 +319,7 @@ func (cx *EvalContext) allowsApplicationCall(hdr *transactions.Header, tx *trans // If an old (pre resource sharing) app is being called from an app that has // resource sharing enabled, we need to confirm that no new "cross-product" // resources have become available. - if callerVer < resourceSharingVersion || calleeVer >= resourceSharingVersion { + if callerVer < sharedResourcesVersion || calleeVer >= sharedResourcesVersion { return nil } diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 80e14fab48..151cbaae14 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -811,8 +811,8 @@ int 1 logic.TestApps(t, []string{"", innerCallWithAccount}, txntest.Group(&appl0, &appl), 9, ledger, logic.NewExpect(1, "appl ApplicationID: invalid Local State access "+otherAcct.String())) // the caller can't fix by passing 88 as a foreign app, because doing so - // gives the v8 app access to that local state that the caller does not - // have access to. + // is not much different than the current situation: 88 is being called, + // it's already available. innerCallWithBoth := fmt.Sprintf(innerCallTemplate, "addr "+otherAcct.String()+"; itxn_field Accounts; int 88; itxn_field Applications") logic.TestApps(t, []string{"", innerCallWithBoth}, txntest.Group(&appl0, &appl), 9, ledger, @@ -878,11 +878,6 @@ func TestAccessMyLocals(t *testing.T) { logic.TestApp(t, source, ep) // They can also see that they are opted in, though it's a weird question to ask. - source = ` - int 0 - int 0 - app_opted_in -` - logic.TestApp(t, source, ep) + logic.TestApp(t, "int 0; int 0; app_opted_in", ep) }) } From 56b2b5552b9e33bb18ce72050c7231c43d250eba Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 30 Mar 2023 12:48:28 -0400 Subject: [PATCH 23/29] Add tests for interpretation of integers as resource or slot --- data/transactions/logic/evalStateful_test.go | 77 ++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index c5a17e839b..a3072264aa 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -1173,6 +1173,83 @@ intc_1 testApp(t, notrack(source), now, "cannot compare ([]byte to uint64)") } +// TestAssetDisambiguation ensures we have a consistent interpretation of low +// numbers when used as an argument to asset_*_get. A low number is an asset ID +// if that asset ID is available, or a slot number in txn.Assets if not. +func TestAssetDisambiguation(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + // start at 4 when the two meanings were added, stop at 8 because 9 removed the dual meaning + testLogicRange(t, 4, 8, func(t *testing.T, ep *EvalParams, tx *transactions.Transaction, ledger *Ledger) { + ledger.NewAsset(tx.Sender, 1, basics.AssetParams{AssetName: "one", Total: 1}) + ledger.NewAsset(tx.Sender, 20, basics.AssetParams{AssetName: "twenty", Total: 20}) + ledger.NewAsset(tx.Sender, 30, basics.AssetParams{AssetName: "thirty", Total: 30}) + tx.ForeignAssets = []basics.AssetIndex{20, 30} + // Since 1 is not available, 1 must mean the 1th asset slot = 30 + testApp(t, `int 1; asset_params_get AssetName; assert; byte "thirty"; ==`, ep) + testApp(t, `int 0; int 1; asset_holding_get AssetBalance; assert; int 30; ==`, ep) + + tx.ForeignAssets = []basics.AssetIndex{1, 30} + // Since 1 IS available, 1 means the assetid=1, not the 1th slot + testApp(t, `int 1; asset_params_get AssetName; assert; byte "one"; ==`, ep) + testApp(t, `int 0; int 1; asset_holding_get AssetBalance; assert; int 1; ==`, ep) + }) +} + +// TestAppDisambiguation ensures we have a consistent interpretation of low +// numbers when used as an argument to app_(global,local)_get. A low number is +// an app ID if that app ID is available, or a slot number in +// txn.ForeignApplications if not. +func TestAppDisambiguation(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + // start at 4 when the two meanings were added, stop at 8 because 9 removed the dual meaning + testLogicRange(t, 4, 8, func(t *testing.T, ep *EvalParams, tx *transactions.Transaction, ledger *Ledger) { + ledger.NewApp(tx.Sender, 1, basics.AppParams{ + GlobalState: map[string]basics.TealValue{"a": { + Type: basics.TealUintType, + Uint: 1, + }}, + ExtraProgramPages: 1, + }) + ledger.NewLocals(tx.Sender, 1) + ledger.NewLocal(tx.Sender, 1, "x", basics.TealValue{Type: basics.TealUintType, Uint: 100}) + ledger.NewApp(tx.Sender, 20, basics.AppParams{ + GlobalState: map[string]basics.TealValue{"a": { + Type: basics.TealUintType, + Uint: 20, + }}, + ExtraProgramPages: 20, + }) + ledger.NewLocals(tx.Sender, 20) + ledger.NewLocal(tx.Sender, 20, "x", basics.TealValue{Type: basics.TealUintType, Uint: 200}) + ledger.NewApp(tx.Sender, 30, basics.AppParams{ + GlobalState: map[string]basics.TealValue{"a": { + Type: basics.TealUintType, + Uint: 30, + }}, + ExtraProgramPages: 30, + }) + tx.ForeignApps = []basics.AppIndex{20, 30} + // Since 1 is not available, 1 must mean the first app slot = 20 (recall, 0 mean "this app") + if ep.Proto.LogicSigVersion >= 5 { + testApp(t, `int 1; app_params_get AppExtraProgramPages; assert; int 20; ==`, ep) + } + testApp(t, `int 1; byte "a"; app_global_get_ex; assert; int 20; ==`, ep) + testApp(t, `int 0; int 1; byte "x"; app_local_get_ex; assert; int 200; ==`, ep) + + tx.ForeignApps = []basics.AppIndex{1, 30} + // Since 1 IS available, 1 means the assetid=1, not the 1th slot + if ep.Proto.LogicSigVersion >= 5 { + testApp(t, `int 1; app_params_get AppExtraProgramPages; assert; int 1; ==`, ep) + } + testApp(t, `int 1; byte "a"; app_global_get_ex; assert; int 1; ==`, ep) + testApp(t, `int 0; int 1; byte "x"; app_local_get_ex; assert; int 100; ==`, ep) + }) +} + func TestAppParams(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() From b4e63e86a2137000cd4ec2365f08742bb788eb71 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Thu, 30 Mar 2023 15:17:46 -0400 Subject: [PATCH 24/29] Remove use of slots for app and asset indexes This changes the behavior of several opcodes in v9. We will probably rename them in v9, to force writers to notice, but that is not in this commit. --- data/transactions/logic/eval.go | 48 ++- data/transactions/logic/evalStateful_test.go | 315 ++++++++++--------- data/transactions/logic/fields_test.go | 3 +- data/transactions/logic/opcodes.go | 1 + data/transactions/logic/resources_test.go | 14 +- 5 files changed, 198 insertions(+), 183 deletions(-) diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index c0e55f82db..a22924aedc 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -1256,6 +1256,10 @@ func (cx *EvalContext) ensureStackCap(targetCap int) { } } +func opDeprecated(cx *EvalContext) error { + return fmt.Errorf("deprecated opcode %d executed", cx.program[cx.pc]) +} + func opErr(cx *EvalContext) error { return errors.New("err opcode executed") } @@ -4441,11 +4445,13 @@ func (cx *EvalContext) appReference(ref uint64, foreign bool) (basics.AppIndex, return aid, nil } - // Allow use of indexes, but this comes last so that clear advice can be - // given to anyone who cares about semantics in the first few rounds of - // a new network - don't use indexes for references, use the App ID - if ref <= uint64(len(cx.txn.Txn.ForeignApps)) { - return basics.AppIndex(cx.txn.Txn.ForeignApps[ref-1]), nil + if cx.version < sharedResourcesVersion { + // Allow use of indexes, but this comes last so that clear advice can be + // given to anyone who cares about semantics in the first few rounds of + // a new network - don't use indexes for references, use the App ID + if ref <= uint64(len(cx.txn.Txn.ForeignApps)) { + return basics.AppIndex(cx.txn.Txn.ForeignApps[ref-1]), nil + } } } else { // Old rules @@ -4484,19 +4490,11 @@ func (cx *EvalContext) localsReference(account stackValue, ref uint64) (basics.A return basics.Address{}, 0, 0, err } aid := basics.AppIndex(ref) - if cx.allowsLocals(addr, aid) { - return addr, aid, unused, nil - } if ref == 0 { aid = cx.appID - if cx.allowsLocals(addr, aid) { - return addr, aid, unused, nil - } - } else if ref <= uint64(len(cx.txn.Txn.ForeignApps)) { - aid = cx.txn.Txn.ForeignApps[ref-1] - if cx.allowsLocals(addr, aid) { - return addr, aid, unused, nil - } + } + if cx.allowsLocals(addr, aid) { + return addr, aid, unused, nil } // Do some extra lookups to give a more concise err. Whenever a locals @@ -4538,11 +4536,13 @@ func (cx *EvalContext) assetReference(ref uint64, foreign bool) (basics.AssetInd return aid, nil } - // Allow use of indexes, but this comes last so that clear advice can be - // given to anyone who cares about semantics in the first few rounds of - // a new network - don't use indexes for references, use the asa ID. - if ref < uint64(len(cx.txn.Txn.ForeignAssets)) { - return basics.AssetIndex(cx.txn.Txn.ForeignAssets[ref]), nil + if cx.version < sharedResourcesVersion { + // Allow use of indexes, but this comes last so that clear advice can be + // given to anyone who cares about semantics in the first few rounds of + // a new network - don't use indexes for references, use the asa ID. + if ref < uint64(len(cx.txn.Txn.ForeignAssets)) { + return basics.AssetIndex(cx.txn.Txn.ForeignAssets[ref]), nil + } } } else { // Old rules @@ -4576,12 +4576,6 @@ func (cx *EvalContext) holdingReference(account stackValue, ref uint64) (basics. if cx.allowsHolding(addr, aid) { return addr, aid, nil } - if ref < uint64(len(cx.txn.Txn.ForeignAssets)) { - aid := cx.txn.Txn.ForeignAssets[ref] - if cx.allowsHolding(addr, aid) { - return addr, aid, nil - } - } // Do some extra lookups to give a more concise err. Whenever a holding // is available, its account and asset must be as well (but not vice diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index a3072264aa..4ea5355f10 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -233,7 +233,7 @@ intc 5 // 5 asset_holding_get AssetBalance pop && -intc_0 +intc 5 // 5 asset_params_get AssetTotal pop && @@ -1819,11 +1819,12 @@ int 1 func TestAppGlobalReadWrite(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() - // check writing ints and bytes - source := `byte 0x414c474f // key "ALGO" + testLogicRange(t, 2, 0, func(t *testing.T, ep *EvalParams, txn *transactions.Transaction, ledger *Ledger) { + + // check writing ints and bytes + source := `byte 0x414c474f // key "ALGO" int 0x77 // value app_global_put byte 0x414c474f41 // key "ALGOA" @@ -1845,7 +1846,7 @@ byte 0x414c474f == && // check generic with exact app id -int 1 // ForeignApps index - current app +THISAPP byte 0x414c474f41 // key "ALGOA" app_global_get_ex bnz ok1 @@ -1871,7 +1872,7 @@ int 0x77 == && // check generic with exact app id -int 1 // ForeignApps index - current app +THISAPP byte 0x414c474f app_global_get_ex bnz ok3 @@ -1881,33 +1882,35 @@ int 0x77 == && ` - txn := makeSampleAppl(100) - txn.Txn.ForeignApps = []basics.AppIndex{txn.Txn.ApplicationID} - ep := defaultEvalParams(txn) - ledger := NewLedger( - map[basics.Address]uint64{ - txn.Txn.Sender: 1, - }, - ) - ep.Ledger = ledger - ep.SigLedger = ledger - ledger.NewApp(txn.Txn.Sender, 100, basics.AppParams{}) - delta := testApp(t, source, ep) + txn.Type = protocol.ApplicationCallTx + txn.ApplicationID = 100 + txn.ForeignApps = []basics.AppIndex{txn.ApplicationID} + ledger.NewAccount(txn.Sender, 1) + ledger.NewApp(txn.Sender, 100, basics.AppParams{}) - require.Len(t, delta.GlobalDelta, 2) - require.Empty(t, delta.LocalDeltas) + if ep.Proto.LogicSigVersion < sharedResourcesVersion { + // 100 is in the ForeignApps array, name it by slot + source = strings.ReplaceAll(source, "THISAPP", "int 1") + } else { + // use the actual app number, slots no longer allowed + source = strings.ReplaceAll(source, "THISAPP", "int 100") + } + delta := testApp(t, source, ep) - vd := delta.GlobalDelta["ALGO"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x77), vd.Uint) + require.Len(t, delta.GlobalDelta, 2) + require.Empty(t, delta.LocalDeltas) - vd = delta.GlobalDelta["ALGOA"] - require.Equal(t, basics.SetBytesAction, vd.Action) - require.Equal(t, "ALGO", vd.Bytes) + vd := delta.GlobalDelta["ALGO"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x77), vd.Uint) - // write existing value before read - source = `byte 0x414c474f // key "ALGO" + vd = delta.GlobalDelta["ALGOA"] + require.Equal(t, basics.SetBytesAction, vd.Action) + require.Equal(t, "ALGO", vd.Bytes) + + // write existing value before read + source = `byte 0x414c474f // key "ALGO" int 0x77 // value app_global_put byte 0x414c474f @@ -1915,19 +1918,19 @@ app_global_get int 0x77 == ` - ledger.Reset() - ledger.NoGlobal(100, "ALGOA") - ledger.NoGlobal(100, "ALGO") + ledger.Reset() + ledger.NoGlobal(100, "ALGOA") + ledger.NoGlobal(100, "ALGO") - algoValue := basics.TealValue{Type: basics.TealUintType, Uint: 0x77} - ledger.NewGlobal(100, "ALGO", algoValue) + algoValue := basics.TealValue{Type: basics.TealUintType, Uint: 0x77} + ledger.NewGlobal(100, "ALGO", algoValue) - delta = testApp(t, source, ep) - require.Empty(t, delta.GlobalDelta) - require.Empty(t, delta.LocalDeltas) + delta = testApp(t, source, ep) + require.Empty(t, delta.GlobalDelta) + require.Empty(t, delta.LocalDeltas) - // write existing value after read - source = `int 0 + // write existing value after read + source = `int 0 byte 0x414c474f app_global_get_ex bnz ok @@ -1942,16 +1945,16 @@ app_global_get int 0x77 == ` - ledger.Reset() - ledger.NoGlobal(100, "ALGOA") - ledger.NewGlobal(100, "ALGO", algoValue) + ledger.Reset() + ledger.NoGlobal(100, "ALGOA") + ledger.NewGlobal(100, "ALGO", algoValue) - delta = testApp(t, source, ep) - require.Empty(t, delta.GlobalDelta) - require.Empty(t, delta.LocalDeltas) + delta = testApp(t, source, ep) + require.Empty(t, delta.GlobalDelta) + require.Empty(t, delta.LocalDeltas) - // write new values after and before read - source = `int 0 + // write new values after and before read + source = `int 0 byte 0x414c474f app_global_get_ex bnz ok @@ -1982,36 +1985,40 @@ byte 0x414c474f == && ` - ledger.Reset() - ledger.NoGlobal(100, "ALGOA") - ledger.NewGlobal(100, "ALGO", algoValue) + ledger.Reset() + ledger.NoGlobal(100, "ALGOA") + ledger.NewGlobal(100, "ALGO", algoValue) - delta = testApp(t, source, ep) + delta = testApp(t, source, ep) - require.Len(t, delta.GlobalDelta, 2) - require.Empty(t, delta.LocalDeltas) + require.Len(t, delta.GlobalDelta, 2) + require.Empty(t, delta.LocalDeltas) - vd = delta.GlobalDelta["ALGO"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x78), vd.Uint) + vd = delta.GlobalDelta["ALGO"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x78), vd.Uint) - vd = delta.GlobalDelta["ALGOA"] - require.Equal(t, basics.SetBytesAction, vd.Action) - require.Equal(t, "ALGO", vd.Bytes) + vd = delta.GlobalDelta["ALGOA"] + require.Equal(t, basics.SetBytesAction, vd.Action) + require.Equal(t, "ALGO", vd.Bytes) + }) } func TestAppGlobalReadOtherApp(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - source := `int 2 // ForeignApps index + // app_global_get_ex starts in v2 + testLogicRange(t, 2, 0, func(t *testing.T, ep *EvalParams, txn *transactions.Transaction, ledger *Ledger) { + source := ` +OTHERAPP byte "mykey1" app_global_get_ex bz ok1 err ok1: pop -int 2 // ForeignApps index +OTHERAPP byte "mykey" app_global_get_ex bnz ok2 @@ -2021,8 +2028,14 @@ byte "myval" == ` - // app_global_get_ex starts in v2 - testLogicRange(t, 2, 0, func(t *testing.T, ep *EvalParams, txn *transactions.Transaction, ledger *Ledger) { + if ep.Proto.LogicSigVersion < sharedResourcesVersion { + // 100 is in the ForeignApps array, name it by slot + source = strings.ReplaceAll(source, "OTHERAPP", "int 2") + } else { + // use the actual app number, slots no longer allowed + source = strings.ReplaceAll(source, "OTHERAPP", "int 101") + } + txn.ApplicationID = 100 txn.ForeignApps = []basics.AppIndex{txn.ApplicationID, 101} ledger.NewAccount(txn.Sender, 1) @@ -2079,23 +2092,24 @@ func TestAppGlobalDelete(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - // check write/delete/read - source := `byte 0x414c474f // key "ALGO" + testLogicRange(t, 2, 0, func(t *testing.T, ep *EvalParams, txn *transactions.Transaction, ledger *Ledger) { + // check write/delete/read + source := `byte "ALGO" int 0x77 // value app_global_put -byte 0x414c474f41 // key "ALGOA" -byte 0x414c474f +byte "ALGOA" +byte "ALGO" app_global_put -byte 0x414c474f +byte "ALGO" app_global_del -byte 0x414c474f41 +byte "ALGOA" app_global_del int 0 -byte 0x414c474f +byte "ALGO" app_global_get_ex bnz error int 0 -byte 0x414c474f41 +byte "ALGOA" app_global_get_ex bnz error == @@ -2105,116 +2119,124 @@ err ok: int 1 ` - ep, txn, ledger := makeSampleEnv() - ledger.NewAccount(txn.Sender, 1) - txn.ApplicationID = 100 - ledger.NewApp(txn.Sender, 100, basics.AppParams{}) - delta := testApp(t, source, ep) - require.Len(t, delta.GlobalDelta, 2) - require.Empty(t, delta.LocalDeltas) + ledger.NewAccount(txn.Sender, 1) + txn.ApplicationID = 100 + ledger.NewApp(txn.Sender, 100, basics.AppParams{}) - ledger.Reset() - ledger.NoGlobal(100, "ALGOA") - ledger.NoGlobal(100, "ALGO") + delta := testApp(t, source, ep) + require.Len(t, delta.GlobalDelta, 2) + require.Empty(t, delta.LocalDeltas) - algoValue := basics.TealValue{Type: basics.TealUintType, Uint: 0x77} - ledger.NewGlobal(100, "ALGO", algoValue) + ledger.Reset() + ledger.NoGlobal(100, "ALGOA") + ledger.NoGlobal(100, "ALGO") - // check delete existing - source = `byte 0x414c474f // key "ALGO" + algoValue := basics.TealValue{Type: basics.TealUintType, Uint: 0x77} + ledger.NewGlobal(100, "ALGO", algoValue) + + // check delete existing + source = `byte "ALGO" app_global_del -int 1 -byte 0x414c474f +THISAPP +byte "ALGO" app_global_get_ex == // two zeros ` - txn.ForeignApps = []basics.AppIndex{txn.ApplicationID} - delta = testApp(t, source, ep) - require.Len(t, delta.GlobalDelta, 1) - vd := delta.GlobalDelta["ALGO"] - require.Equal(t, basics.DeleteAction, vd.Action) - require.Equal(t, uint64(0), vd.Uint) - require.Equal(t, "", vd.Bytes) - require.Equal(t, 0, len(delta.LocalDeltas)) - ledger.Reset() - ledger.NoGlobal(100, "ALGOA") - ledger.NoGlobal(100, "ALGO") + if ep.Proto.LogicSigVersion < sharedResourcesVersion { + // 100 is in the ForeignApps array, name it by slot + source = strings.ReplaceAll(source, "THISAPP", "int 1") + } else { + // use the actual app number, slots no longer allowed + source = strings.ReplaceAll(source, "THISAPP", "int 100") + } + txn.ForeignApps = []basics.AppIndex{txn.ApplicationID} + delta = testApp(t, source, ep) + require.Len(t, delta.GlobalDelta, 1) + vd := delta.GlobalDelta["ALGO"] + require.Equal(t, basics.DeleteAction, vd.Action) + require.Equal(t, uint64(0), vd.Uint) + require.Equal(t, "", vd.Bytes) + require.Equal(t, 0, len(delta.LocalDeltas)) - ledger.NewGlobal(100, "ALGO", algoValue) + ledger.Reset() + ledger.NoGlobal(100, "ALGOA") + ledger.NoGlobal(100, "ALGO") - // check delete and write non-existing - source = `byte 0x414c474f41 // key "ALGOA" + ledger.NewGlobal(100, "ALGO", algoValue) + + // check delete and write non-existing + source = `byte "ALGOA" app_global_del int 0 -byte 0x414c474f41 +byte "ALGOA" app_global_get_ex == // two zeros -byte 0x414c474f41 +byte "ALGOA" int 0x78 app_global_put ` - delta = testApp(t, source, ep) - require.Len(t, delta.GlobalDelta, 1) - vd = delta.GlobalDelta["ALGOA"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x78), vd.Uint) - require.Equal(t, "", vd.Bytes) - require.Empty(t, delta.LocalDeltas) + delta = testApp(t, source, ep) + require.Len(t, delta.GlobalDelta, 1) + vd = delta.GlobalDelta["ALGOA"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x78), vd.Uint) + require.Equal(t, "", vd.Bytes) + require.Empty(t, delta.LocalDeltas) - ledger.Reset() - ledger.NoGlobal(100, "ALGOA") - ledger.NoGlobal(100, "ALGO") + ledger.Reset() + ledger.NoGlobal(100, "ALGOA") + ledger.NoGlobal(100, "ALGO") - ledger.NewGlobal(100, "ALGO", algoValue) + ledger.NewGlobal(100, "ALGO", algoValue) - // check delete and write existing - source = `byte 0x414c474f // key "ALGO" + // check delete and write existing + source = `byte "ALGO" app_global_del -byte 0x414c474f +byte "ALGO" int 0x78 app_global_put int 1 ` - delta = testApp(t, source, ep) - require.Len(t, delta.GlobalDelta, 1) - vd = delta.GlobalDelta["ALGO"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Empty(t, delta.LocalDeltas) + delta = testApp(t, source, ep) + require.Len(t, delta.GlobalDelta, 1) + vd = delta.GlobalDelta["ALGO"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Empty(t, delta.LocalDeltas) - ledger.Reset() - ledger.Reset() - ledger.NoGlobal(100, "ALGOA") - ledger.NoGlobal(100, "ALGO") + ledger.Reset() + ledger.Reset() + ledger.NoGlobal(100, "ALGOA") + ledger.NoGlobal(100, "ALGO") - ledger.NewGlobal(100, "ALGO", algoValue) + ledger.NewGlobal(100, "ALGO", algoValue) - // check delete,write,delete existing - source = `byte 0x414c474f // key "ALGO" + // check delete,write,delete existing + source = `byte "ALGO" app_global_del -byte 0x414c474f +byte "ALGO" int 0x78 app_global_put -byte 0x414c474f +byte "ALGO" app_global_del int 1 ` - delta = testApp(t, source, ep) - require.Len(t, delta.GlobalDelta, 1) - vd = delta.GlobalDelta["ALGO"] - require.Equal(t, basics.DeleteAction, vd.Action) - require.Empty(t, delta.LocalDeltas) + delta = testApp(t, source, ep) + require.Len(t, delta.GlobalDelta, 1) + vd = delta.GlobalDelta["ALGO"] + require.Equal(t, basics.DeleteAction, vd.Action) + require.Empty(t, delta.LocalDeltas) - ledger.Reset() - ledger.Reset() - ledger.NoGlobal(100, "ALGOA") - ledger.NoGlobal(100, "ALGO") + ledger.Reset() + ledger.Reset() + ledger.NoGlobal(100, "ALGOA") + ledger.NoGlobal(100, "ALGO") - ledger.NewGlobal(100, "ALGO", algoValue) + ledger.NewGlobal(100, "ALGO", algoValue) - // check delete, write, delete non-existing - source = `byte 0x414c474f41 // key "ALGOA" + // check delete, write, delete non-existing + source = `byte 0x414c474f41 // key "ALGOA" app_global_del byte 0x414c474f41 int 0x78 @@ -2223,9 +2245,10 @@ byte 0x414c474f41 app_global_del int 1 ` - delta = testApp(t, source, ep) - require.Len(t, delta.GlobalDelta, 1) - require.Len(t, delta.LocalDeltas, 0) + delta = testApp(t, source, ep) + require.Len(t, delta.GlobalDelta, 1) + require.Len(t, delta.LocalDeltas, 0) + }) } func TestAppLocalDelete(t *testing.T) { @@ -2484,7 +2507,7 @@ assert testApp(t, source, ep, "AssetBalance expected field type is []byte but got uint64") - source = `int 0 + source = `int 55 asset_params_get AssetTotal assert ` diff --git a/data/transactions/logic/fields_test.go b/data/transactions/logic/fields_test.go index cbe425d5f4..91abc84457 100644 --- a/data/transactions/logic/fields_test.go +++ b/data/transactions/logic/fields_test.go @@ -219,7 +219,7 @@ func TestAssetParamsFieldsVersions(t *testing.T) { for _, field := range fields { // Need to use intc so we can "backversion" the // program and not have it fail because of pushint. - text := fmt.Sprintf("intcblock 0 1; intc_0; asset_params_get %s; bnz ok; err; ok: ", field.field.String()) + text := fmt.Sprintf("intcblock 55 1; intc_0; asset_params_get %s; bnz ok; err; ok: ", field.field.String()) switch field.ftype { case StackUint64: // ensure the return type is uint64 by adding text += " intc_1; +" @@ -229,7 +229,6 @@ func TestAssetParamsFieldsVersions(t *testing.T) { // check assembler fails if version before introduction for v := uint64(2); v <= AssemblerMaxVersion; v++ { ep, txn, ledger := makeSampleEnv() - // Create app 55, since txn.ForeignApps[0] == 55 ledger.NewAsset(txn.Sender, 55, basics.AssetParams{}) ep.Proto.LogicSigVersion = v if field.version > v { diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index 19c4d57cad..47bef35667 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -532,6 +532,7 @@ var OpSpecs = []OpSpec{ {0x60, "balance", opBalance, proto("i:i"), 2, only(ModeApp)}, {0x60, "balance", opBalance, proto("a:i"), directRefEnabledVersion, only(ModeApp)}, + // {0x60, "balance", opDeprecated, proto("a:i"), sharedResourcesVersion, only(ModeApp)}, {0x61, "app_opted_in", opAppOptedIn, proto("ii:i"), 2, only(ModeApp)}, {0x61, "app_opted_in", opAppOptedIn, proto("ai:i"), directRefEnabledVersion, only(ModeApp)}, {0x62, "app_local_get", opAppLocalGet, proto("ib:a"), 2, only(ModeApp)}, diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 151cbaae14..8c5e67f31d 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -200,12 +200,12 @@ pop; pop; int 1 logic.TestApp(t, getLocalEx, ep, "invalid App reference 500") tx.ForeignApps = []basics.AppIndex{500} logic.TestApp(t, getLocalEx, ep) - binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 1) + binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 500) logic.TestApp(t, getLocalEx, ep) - binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 2) // beyond the txn.ForeignApps array - logic.TestApp(t, getLocalEx, ep, "invalid App reference 2") + binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 501) + logic.TestApp(t, getLocalEx, ep, "invalid App reference 501") - binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 1) + binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 500) tx.Accounts = []basics.Address{} logic.TestApp(t, getLocalEx, ep, "invalid Account reference "+joe.String()) } @@ -295,11 +295,9 @@ pop; pop; int 1 tx.ForeignAssets = []basics.AssetIndex{200} logic.TestApp(t, getHoldingBalance, ep) binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 0) - logic.TestApp(t, getHoldingBalance, ep) - binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 1) // beyond the txn.ForeignAssets array - logic.TestApp(t, getHoldingBalance, ep, "invalid Asset reference 1") + logic.TestApp(t, getHoldingBalance, ep, "invalid Asset reference 0") // slots not allowed - binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 0) + binary.BigEndian.PutUint64(tx.ApplicationArgs[1], 200) tx.Accounts = []basics.Address{} logic.TestApp(t, getHoldingBalance, ep, "invalid Account reference "+joe.String()) } From 946309e6cb33418290607902beddc91652f6f4ff Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Fri, 31 Mar 2023 15:32:11 -0400 Subject: [PATCH 25/29] Remove slot usage for account access opcodes --- data/transactions/logic/assembler_test.go | 59 +- data/transactions/logic/box_test.go | 2 +- data/transactions/logic/eval.go | 24 +- data/transactions/logic/evalStateful_test.go | 949 ++++++++++--------- data/transactions/logic/eval_test.go | 8 +- data/transactions/logic/fields_test.go | 18 +- data/transactions/logic/opcodes.go | 18 +- data/transactions/logic/resources_test.go | 18 +- 8 files changed, 574 insertions(+), 522 deletions(-) diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index 665741e96e..bfea7c3504 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -428,7 +428,8 @@ pushbytess "1" "2" "1" const v8Nonsense = v7Nonsense + switchNonsense + frameNonsense + matchNonsense + boxNonsense -const v9Nonsense = v8Nonsense + pairingNonsense +const v9Nonsense = v8Nonsense +const v10Nonsense = v9Nonsense + pairingNonsense const v6Compiled = "2004010002b7a60c26050242420c68656c6c6f20776f726c6421070123456789abcd208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292b0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f2310231123122313231418191a1b1c28171615400003290349483403350222231d4a484848482b50512a632223524100034200004322602261222704634848222862482864286548482228246628226723286828692322700048482371004848361c0037001a0031183119311b311d311e311f312023221e312131223123312431253126312731283129312a312b312c312d312e312f447825225314225427042455220824564c4d4b0222382124391c0081e80780046a6f686e2281d00f23241f880003420001892224902291922494249593a0a1a2a3a4a5a6a7a8a9aaabacadae24af3a00003b003c003d816472064e014f012a57000823810858235b235a2359b03139330039b1b200b322c01a23c1001a2323c21a23c3233e233f8120af06002a494905002a49490700b400b53a03b6b7043cb8033a0c2349c42a9631007300810881088120978101c53a8101c6003a" @@ -444,18 +445,20 @@ const matchCompiled = "83030102018e02fff500008203013101320131" const v8Compiled = v7Compiled + switchCompiled + frameCompiled + matchCompiled + boxCompiled -const v9Compiled = v8Compiled + pairingCompiled +const v9Compiled = v8Compiled +const v10Compiled = v9Compiled + pairingCompiled var nonsense = map[uint64]string{ - 1: v1Nonsense, - 2: v2Nonsense, - 3: v3Nonsense, - 4: v4Nonsense, - 5: v5Nonsense, - 6: v6Nonsense, - 7: v7Nonsense, - 8: v8Nonsense, - 9: v9Nonsense, + 1: v1Nonsense, + 2: v2Nonsense, + 3: v3Nonsense, + 4: v4Nonsense, + 5: v5Nonsense, + 6: v6Nonsense, + 7: v7Nonsense, + 8: v8Nonsense, + 9: v9Nonsense, + 10: v9Nonsense, } var compiled = map[uint64]string{ @@ -468,6 +471,8 @@ var compiled = map[uint64]string{ 7: "07" + v7Compiled, 8: "08" + v8Compiled, 9: "09" + v9Compiled, + + 10: "10" + v10Compiled, } func pseudoOp(opcode string) bool { @@ -1774,7 +1779,7 @@ func TestAssembleDisassembleErrors(t *testing.T) { require.Contains(t, err.Error(), "invalid opcode") source = "int 0\nint 0\nasset_holding_get AssetFrozen" - ops, err = AssembleStringWithVersion(source, AssemblerMaxVersion) + ops, err = AssembleStringWithVersion(source, sharedResourcesVersion-1) require.NoError(t, err) ops.Program[7] = 0x50 // holding field _, err = Disassemble(ops.Program) @@ -1885,10 +1890,20 @@ func TestAssembleAsset(t *testing.T) { Expect{1, "asset_holding_get ABC 1 expects 2 stack arguments..."}) testProg(t, "int 1; asset_holding_get ABC 1", v, Expect{1, "asset_holding_get ABC 1 expects 2 stack arguments..."}) - testProg(t, "int 1; int 1; asset_holding_get ABC 1", v, - Expect{1, "asset_holding_get expects 1 immediate argument"}) - testProg(t, "int 1; int 1; asset_holding_get ABC", v, - Expect{1, "asset_holding_get unknown field: \"ABC\""}) + + if v < sharedResourcesVersion { + testProg(t, "int 1; int 1; asset_holding_get ABC 1", v, + Expect{1, "asset_holding_get expects 1 immediate argument"}) + testProg(t, "int 1; int 1; asset_holding_get ABC", v, + Expect{1, "asset_holding_get unknown field: \"ABC\""}) + } else { + testProg(t, "int 1; int 1; asset_holding_get ABC 1", v, + Expect{1, "asset_holding_get ABC 1 arg 0 wanted type..."}) + testProg(t, "txn Sender; int 1; asset_holding_get ABC 1", v, + Expect{1, "asset_holding_get expects 1 immediate argument"}) + testProg(t, "txn Sender; int 1; asset_holding_get ABC", v, + Expect{1, "asset_holding_get unknown field: \"ABC\""}) + } testProg(t, "byte 0x1234; asset_params_get ABC 1", v, Expect{1, "asset_params_get ABC 1 arg 0 wanted type uint64..."}) @@ -2159,15 +2174,17 @@ func TestHasStatefulOps(t *testing.T) { require.NoError(t, err) require.False(t, has) - source = `int 1 -int 1 -app_opted_in -err -` + source = `txn Sender; int 1; app_opted_in; err` ops = testProg(t, source, AssemblerMaxVersion) has, err = HasStatefulOps(ops.Program) require.NoError(t, err) require.True(t, has) + + source = `int 1; int 1; app_opted_in; err` + ops = testProg(t, source, sharedResourcesVersion-1) + has, err = HasStatefulOps(ops.Program) + require.NoError(t, err) + require.True(t, has) } func TestStringLiteralParsing(t *testing.T) { diff --git a/data/transactions/logic/box_test.go b/data/transactions/logic/box_test.go index 77c3adf1b2..f73cdf52a9 100644 --- a/data/transactions/logic/box_test.go +++ b/data/transactions/logic/box_test.go @@ -556,7 +556,7 @@ func TestBoxTotals(t *testing.T) { ledger.NewApp(txn.Sender, 888, basics.AppParams{}) // The SENDER certainly has no boxes (but does exist) - logic.TestApp(t, `int 0; acct_params_get AcctTotalBoxes; pop; !`, ep) + logic.TestApp(t, `txn Sender; acct_params_get AcctTotalBoxes; pop; !`, ep) // Nor does the app account, to start logic.TestApp(t, `int 888; app_params_get AppAddress; assert; acct_params_get AcctTotalBoxes; pop; !; `, ep) diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index a22924aedc..2604d2b9bf 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -4015,9 +4015,11 @@ func (cx *EvalContext) assignAccount(sv stackValue) (basics.Address, error) { // not, based on version. func (cx *EvalContext) accountReference(account stackValue) (basics.Address, uint64, error) { - if account.argType() == StackUint64 { - addr, err := cx.txn.Txn.AddressByIndex(account.Uint, cx.txn.Txn.Sender) - return addr, account.Uint, err + if cx.version < sharedResourcesVersion { + if account.argType() == StackUint64 { + addr, err := cx.txn.Txn.AddressByIndex(account.Uint, cx.txn.Txn.Sender) + return addr, account.Uint, err + } } addr, err := account.address() if err != nil { @@ -4479,13 +4481,7 @@ func (cx *EvalContext) appReference(ref uint64, foreign bool) (basics.AppIndex, func (cx *EvalContext) localsReference(account stackValue, ref uint64) (basics.Address, basics.AppIndex, uint64, error) { if cx.version >= sharedResourcesVersion { unused := uint64(0) // see function comment - var addr basics.Address - var err error - if account.Bytes != nil { - addr, err = account.address() - } else { - addr, err = cx.txn.Txn.AddressByIndex(account.Uint, cx.txn.Txn.Sender) - } + addr, err := account.address() if err != nil { return basics.Address{}, 0, 0, err } @@ -4562,13 +4558,7 @@ func (cx *EvalContext) assetReference(ref uint64, foreign bool) (basics.AssetInd func (cx *EvalContext) holdingReference(account stackValue, ref uint64) (basics.Address, basics.AssetIndex, error) { if cx.version >= sharedResourcesVersion { - var addr basics.Address - var err error - if account.Bytes != nil { - addr, err = account.address() - } else { - addr, err = cx.txn.Txn.AddressByIndex(account.Uint, cx.txn.Txn.Sender) - } + addr, err := account.address() if err != nil { return basics.Address{}, 0, err } diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index 4ea5355f10..053931df47 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -123,7 +123,7 @@ func TestEvalModes(t *testing.T) { // check modeAny (v1 + txna/gtxna) are available in RunModeSignature // check all opcodes available in runModeApplication opcodesRunModeAny := `intcblock 0 1 1 1 1 5 100 - bytecblock 0x414c474f 0x1337 0x2001 0xdeadbeef 0x70077007 + bytecblock "ALGO" 0x1337 0x2001 0xdeadbeef 0x70077007 bytec 0 sha256 keccak256 @@ -195,24 +195,24 @@ arg 4 && ` - opcodesRunModeApplication := `int 0 + opcodesRunModeApplication := `txn Sender balance && -int 0 +txn Sender min_balance && -intc_0 +txn Sender intc 6 // 100 app_opted_in && -intc_0 +txn Sender bytec_0 // ALGO intc_1 app_local_put bytec_0 intc_1 app_global_put -intc_0 +txn Sender intc 6 bytec_0 app_local_get_ex @@ -223,12 +223,12 @@ bytec_0 app_global_get_ex pop && -intc_0 +txn Sender bytec_0 app_local_del bytec_0 app_global_del -intc_0 +txn Sender intc 5 // 5 asset_holding_get AssetBalance pop @@ -325,20 +325,20 @@ log // check stateful opcodes are not allowed in stateless mode statefulOpcodeCalls := []string{ - "int 0\nbalance", - "int 0\nmin_balance", - "int 0\nint 0\napp_opted_in", - "int 0\nint 0\nbyte 0x01\napp_local_get_ex", - "byte 0x01\napp_global_get", - "int 0\nbyte 0x01\napp_global_get_ex", - "int 1\nbyte 0x01\nbyte 0x01\napp_local_put", - "byte 0x01\nint 0\napp_global_put", - "int 0\nbyte 0x01\napp_local_del", - "byte 0x01\napp_global_del", - "int 0\nint 0\nasset_holding_get AssetFrozen", - "int 0\nint 0\nasset_params_get AssetManager", - "int 0\nint 0\napp_params_get AppApprovalProgram", - "byte 0x01\nlog", + "txn Sender; balance", + "txn Sender; min_balance", + "txn Sender; int 0; app_opted_in", + "txn Sender; int 0; byte 0x01; app_local_get_ex", + "byte 0x01; app_global_get", + "int 0; byte 0x01; app_global_get_ex", + "txn Sender; byte 0x01; byte 0x01; app_local_put", + "byte 0x01; int 0; app_global_put", + "txn Sender; byte 0x01; app_local_del", + "byte 0x01; app_global_del", + "txn Sender; int 0; asset_holding_get AssetFrozen", + "int 0; int 0; asset_params_get AssetManager", + "int 0; int 0; app_params_get AppApprovalProgram", + "byte 0x01; log", } for _, source := range statefulOpcodeCalls { @@ -355,31 +355,32 @@ log func TestBalance(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() - ep, tx, ledger := makeSampleEnv() - text := "int 2; balance; int 177; ==" - ledger.NewAccount(tx.Receiver, 177) - testApp(t, text, ep, "invalid Account reference") - - text = `int 1; balance; int 177; ==` - testApp(t, text, ep) - - text = `txn Accounts 1; balance; int 177; ==;` - // won't assemble in old version teal - testProg(t, text, directRefEnabledVersion-1, Expect{1, "balance arg 0 wanted type uint64..."}) - // but legal after that - testApp(t, text, ep) - - text = "int 0; balance; int 13; ==; assert; int 1" - var addr basics.Address - copy(addr[:], []byte("aoeuiaoeuiaoeuiaoeuiaoeuiaoeui02")) - ledger.NewAccount(addr, 13) - testApp(t, text, ep, "assert failed") - - ledger.NewAccount(tx.Sender, 13) - testApp(t, text, ep) + testLogicRange(t, 2, 0, func(t *testing.T, ep *EvalParams, tx *transactions.Transaction, ledger *Ledger) { + ledger.NewAccount(tx.Receiver, 177) + if ep.Proto.LogicSigVersion < sharedResourcesVersion { + testApp(t, "int 2; balance; int 177; ==", ep, "invalid Account reference") + testApp(t, `int 1; balance; int 177; ==`, ep) + } + + source := `txn Accounts 1; balance; int 177; ==;` + // won't assemble in old version teal + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + testProg(t, source, ep.Proto.LogicSigVersion, + Expect{1, "balance arg 0 wanted type uint64..."}) + return + } + + // but legal after that + testApp(t, source, ep) + + source = "txn Sender; balance; int 13; ==; assert; int 1" + testApp(t, source, ep, "assert failed") + + ledger.NewAccount(tx.Sender, 13) + testApp(t, source, ep) + }) } func testApps(t *testing.T, programs []string, txgroup []transactions.SignedTxn, version uint64, ledger *Ledger, @@ -536,43 +537,45 @@ func testLogicRange(t *testing.T, start, stop int, test func(t *testing.T, ep *E func TestMinBalance(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() - ep, tx, ledger := makeSampleEnv() - - ledger.NewAccount(tx.Sender, 234) - ledger.NewAccount(tx.Receiver, 123) + // since v3 is before directRefEnabledVersion, do a quick test on it separately + ep, tx, ledger := makeSampleEnvWithVersion(3) + ledger.NewAccount(tx.Sender, 100) testApp(t, "int 0; min_balance; int 1001; ==", ep) // Sender makes an asset, min balance goes up ledger.NewAsset(tx.Sender, 7, basics.AssetParams{Total: 1000}) testApp(t, "int 0; min_balance; int 2002; ==", ep) - schemas := makeApp(1, 2, 3, 4) - ledger.NewApp(tx.Sender, 77, schemas) - ledger.NewLocals(tx.Sender, 77) - // create + optin + 10 schema base + 4 ints + 6 bytes (local - // and global count b/c NewLocals opts the creator in) - minb := 1002 + 1006 + 10*1003 + 4*1004 + 6*1005 - testApp(t, fmt.Sprintf("int 0; min_balance; int %d; ==", 2002+minb), ep) - // request extra program pages, min balance increase - withepp := makeApp(1, 2, 3, 4) - withepp.ExtraProgramPages = 2 - ledger.NewApp(tx.Sender, 77, withepp) - minb += 2 * 1002 - testApp(t, fmt.Sprintf("int 0; min_balance; int %d; ==", 2002+minb), ep) - - testApp(t, "int 1; min_balance; int 1001; ==", ep) // 1 == Accounts[0] - testProg(t, "txn Accounts 1; min_balance; int 1001; ==", directRefEnabledVersion-1, - Expect{1, "min_balance arg 0 wanted type uint64..."}) - testProg(t, "txn Accounts 1; min_balance; int 1001; ==", directRefEnabledVersion) - testApp(t, "txn Accounts 1; min_balance; int 1001; ==", ep) // 1 == Accounts[0] - // Receiver opts in - ledger.NewHolding(tx.Receiver, 7, 1, true) - testApp(t, "int 1; min_balance; int 2002; ==", ep) // 1 == Accounts[0] - - testApp(t, "int 2; min_balance; int 1001; ==", ep, "invalid Account reference 2") + // no test in more detail v4 and on + testLogicRange(t, 4, 0, func(t *testing.T, ep *EvalParams, tx *transactions.Transaction, ledger *Ledger) { + ledger.NewAccount(tx.Sender, 234) + ledger.NewAccount(tx.Receiver, 123) + + testApp(t, "txn Sender; min_balance; int 1001; ==", ep) + // Sender makes an asset, min balance goes up + ledger.NewAsset(tx.Sender, 7, basics.AssetParams{Total: 1000}) + testApp(t, "txn Sender; min_balance; int 2002; ==", ep) + schemas := makeApp(1, 2, 3, 4) + ledger.NewApp(tx.Sender, 77, schemas) + ledger.NewLocals(tx.Sender, 77) + // create + optin + 10 schema base + 4 ints + 6 bytes (local + // and global count b/c NewLocals opts the creator in) + minb := 1002 + 1006 + 10*1003 + 4*1004 + 6*1005 + testApp(t, fmt.Sprintf("txn Sender; min_balance; int %d; ==", 2002+minb), ep) + // request extra program pages, min balance increase + withepp := makeApp(1, 2, 3, 4) + withepp.ExtraProgramPages = 2 + ledger.NewApp(tx.Sender, 77, withepp) + minb += 2 * 1002 + testApp(t, fmt.Sprintf("txn Sender; min_balance; int %d; ==", 2002+minb), ep) + + testApp(t, "txn Accounts 1; min_balance; int 1001; ==", ep) + // Receiver opts in + ledger.NewHolding(tx.Receiver, 7, 1, true) + testApp(t, "txn Receiver; min_balance; int 2002; ==", ep) // 1 == Accounts[0] + }) } func TestAppCheckOptedIn(t *testing.T) { @@ -674,7 +677,7 @@ app_local_get_ex bnz exist err exist: -byte 0x414c474f +byte "ALGO" ==` ledger.NewLocal(now.TxnGroup[0].Txn.Receiver, 100, string(protocol.PaymentTx), basics.TealValue{Type: basics.TealBytesType, Bytes: "ALGO"}) @@ -716,7 +719,7 @@ app_local_get_ex bnz exist err exist: -byte 0x414c474f +byte "ALGO" ==` ledger.NewLocal(now.TxnGroup[0].Txn.Sender, 100, string(protocol.PaymentTx), basics.TealValue{Type: basics.TealBytesType, Bytes: "ALGO"}) @@ -735,7 +738,7 @@ app_local_get_ex bnz exist err exist: -byte 0x414c474f +byte "ALGO" ==` ledger.NewLocals(now.TxnGroup[0].Txn.Sender, 56) @@ -746,7 +749,7 @@ byte 0x414c474f text = `int 0 // account idx txn ApplicationArgs 0 app_local_get -byte 0x414c474f +byte "ALGO" ==` ledger.NewLocal(now.TxnGroup[0].Txn.Sender, 100, string(protocol.PaymentTx), basics.TealValue{Type: basics.TealBytesType, Bytes: "ALGO"}) @@ -761,7 +764,7 @@ byte 0x414c474f // check app_local_get default value text = `int 0 // account idx -byte 0x414c474f +byte "ALGO" app_local_get int 0 ==` @@ -780,7 +783,7 @@ app_global_get_ex bnz exist err exist: -byte 0x414c474f +byte "ALGO" == int 1 // ForeignApps index txn ApplicationArgs 0 @@ -788,12 +791,12 @@ app_global_get_ex bnz exist1 err exist1: -byte 0x414c474f +byte "ALGO" == && txn ApplicationArgs 0 app_global_get -byte 0x414c474f +byte "ALGO" == && ` @@ -817,7 +820,7 @@ byte 0x414c474f text = "int 2; txn ApplicationArgs 0; app_global_get_ex" testApp(t, text, now, "invalid App reference 2") // check that actual app id ok instead of indirect reference - text = "int 100; txn ApplicationArgs 0; app_global_get_ex; int 1; ==; assert; byte 0x414c474f; ==" + text = `int 100; txn ApplicationArgs 0; app_global_get_ex; int 1; ==; assert; byte "ALGO"; ==` testApp(t, text, now) testApp(t, text, pre, "invalid App reference 100") // but not in old teal @@ -897,7 +900,7 @@ int 0//params asset_params_get AssetUnitName ! bnz error -byte 0x414c474f +byte "ALGO" == && int 0//params @@ -1272,31 +1275,31 @@ func TestAcctParams(t *testing.T) { t.Parallel() ep, tx, ledger := makeSampleEnv() - source := "int 0; acct_params_get AcctBalance; !; assert; int 0; ==" + source := "txn Sender; acct_params_get AcctBalance; !; assert; int 0; ==" testApp(t, source, ep) - source = "int 0; acct_params_get AcctMinBalance; !; assert; int 1001; ==" + source = "txn Sender; acct_params_get AcctMinBalance; !; assert; int 1001; ==" testApp(t, source, ep) ledger.NewAccount(tx.Sender, 42) - source = "int 0; acct_params_get AcctBalance; assert; int 42; ==" + source = "txn Sender; acct_params_get AcctBalance; assert; int 42; ==" testApp(t, source, ep) - source = "int 0; acct_params_get AcctMinBalance; assert; int 1001; ==" + source = "txn Sender; acct_params_get AcctMinBalance; assert; int 1001; ==" testApp(t, source, ep) - source = "int 0; acct_params_get AcctAuthAddr; assert; global ZeroAddress; ==" + source = "txn Sender; acct_params_get AcctAuthAddr; assert; global ZeroAddress; ==" testApp(t, source, ep) // No apps or schema at first, then 1 created and the global schema noted - source = "int 0; acct_params_get AcctTotalAppsCreated; assert; !" + source = "txn Sender; acct_params_get AcctTotalAppsCreated; assert; !" testApp(t, source, ep) - source = "int 0; acct_params_get AcctTotalNumUint; assert; !" + source = "txn Sender; acct_params_get AcctTotalNumUint; assert; !" testApp(t, source, ep) - source = "int 0; acct_params_get AcctTotalNumByteSlice; assert; !" + source = "txn Sender; acct_params_get AcctTotalNumByteSlice; assert; !" testApp(t, source, ep) - source = "int 0; acct_params_get AcctTotalExtraAppPages; assert; !" + source = "txn Sender; acct_params_get AcctTotalExtraAppPages; assert; !" testApp(t, source, ep) ledger.NewApp(tx.Sender, 2000, basics.AppParams{ StateSchemas: basics.StateSchemas{ @@ -1311,35 +1314,35 @@ func TestAcctParams(t *testing.T) { }, ExtraProgramPages: 2, }) - source = "int 0; acct_params_get AcctTotalAppsCreated; assert; int 1; ==" + source = "txn Sender; acct_params_get AcctTotalAppsCreated; assert; int 1; ==" testApp(t, source, ep) - source = "int 0; acct_params_get AcctTotalNumUint; assert; int 8; ==" + source = "txn Sender; acct_params_get AcctTotalNumUint; assert; int 8; ==" testApp(t, source, ep) - source = "int 0; acct_params_get AcctTotalNumByteSlice; assert; int 9; ==" + source = "txn Sender; acct_params_get AcctTotalNumByteSlice; assert; int 9; ==" testApp(t, source, ep) - source = "int 0; acct_params_get AcctTotalExtraAppPages; assert; int 2; ==" + source = "txn Sender; acct_params_get AcctTotalExtraAppPages; assert; int 2; ==" testApp(t, source, ep) // Not opted in at first, then opted into 1, schema added - source = "int 0; acct_params_get AcctTotalAppsOptedIn; assert; !" + source = "txn Sender; acct_params_get AcctTotalAppsOptedIn; assert; !" testApp(t, source, ep) ledger.NewLocals(tx.Sender, 2000) - source = "int 0; acct_params_get AcctTotalAppsOptedIn; assert; int 1; ==" + source = "txn Sender; acct_params_get AcctTotalAppsOptedIn; assert; int 1; ==" testApp(t, source, ep) - source = "int 0; acct_params_get AcctTotalNumUint; assert; int 8; int 6; +; ==" + source = "txn Sender; acct_params_get AcctTotalNumUint; assert; int 8; int 6; +; ==" testApp(t, source, ep) - source = "int 0; acct_params_get AcctTotalNumByteSlice; assert; int 9; int 7; +; ==" + source = "txn Sender; acct_params_get AcctTotalNumByteSlice; assert; int 9; int 7; +; ==" testApp(t, source, ep) // No ASAs at first, then 1 created AND in total - source = "int 0; acct_params_get AcctTotalAssetsCreated; assert; !" + source = "txn Sender; acct_params_get AcctTotalAssetsCreated; assert; !" testApp(t, source, ep) - source = "int 0; acct_params_get AcctTotalAssets; assert; !" + source = "txn Sender; acct_params_get AcctTotalAssets; assert; !" testApp(t, source, ep) ledger.NewAsset(tx.Sender, 3000, basics.AssetParams{}) - source = "int 0; acct_params_get AcctTotalAssetsCreated; assert; int 1; ==" + source = "txn Sender; acct_params_get AcctTotalAssetsCreated; assert; int 1; ==" testApp(t, source, ep) - source = "int 0; acct_params_get AcctTotalAssets; assert; int 1; ==" + source = "txn Sender; acct_params_get AcctTotalAssets; assert; int 1; ==" testApp(t, source, ep) } @@ -1367,7 +1370,7 @@ func TestLocalNonDelete(t *testing.T) { ep, txn, ledger := makeSampleEnv() source := ` -int 0 +txn Sender byte "none" app_local_del int 1 @@ -1385,8 +1388,8 @@ func TestAppLocalReadWriteDeleteErrors(t *testing.T) { t.Parallel() sourceRead := `intcblock 0 100 0x77 1 -bytecblock 0x414c474f 0x414c474f41 -intc_0 // 0, account idx (txn.Sender) +bytecblock "ALGO" "ALGOA" +txn Sender intc_1 // 100, app id bytec_0 // key "ALGO" app_local_get_ex @@ -1394,7 +1397,7 @@ app_local_get_ex bnz error intc_2 // 0x77 == -intc_0 // 0 +txn Sender intc_1 // 100 bytec_1 // ALGOA app_local_get_ex @@ -1410,36 +1413,34 @@ ok: intc_3 // 1 ` sourceWrite := `intcblock 0 100 1 -bytecblock 0x414c474f -intc_0 // 0, account idx (txn.Sender) +bytecblock "ALGO" +txn Sender bytec_0 // key "ALGO" intc_1 // 100 app_local_put intc_2 // 1 ` sourceDelete := `intcblock 0 100 -bytecblock 0x414c474f -intc_0 // account idx +bytecblock "ALGO" +txn Sender bytec_0 // key "ALGO" app_local_del intc_1 ` type cmdtest struct { - source string - accNumOffset int + source string } tests := map[string]cmdtest{ - "read": {sourceRead, 20}, - "write": {sourceWrite, 13}, - "delete": {sourceDelete, 12}, + "read": {sourceRead}, + "write": {sourceWrite}, + "delete": {sourceDelete}, } for name, cmdtest := range tests { name, cmdtest := name, cmdtest t.Run(fmt.Sprintf("test=%s", name), func(t *testing.T) { t.Parallel() source := cmdtest.source - firstCmdOffset := cmdtest.accNumOffset ops := testProg(t, source, AssemblerMaxVersion) @@ -1458,14 +1459,6 @@ intc_1 ep.Ledger = ledger ep.SigLedger = ledger - saved := ops.Program[firstCmdOffset] - require.Equal(t, OpsByName[0]["intc_0"].Opcode, saved) - ops.Program[firstCmdOffset] = OpsByName[0]["intc_1"].Opcode - _, err = EvalApp(ops.Program, 0, 100, ep) - require.Error(t, err) - require.Contains(t, err.Error(), "invalid Account reference 100") - - ops.Program[firstCmdOffset] = saved _, err = EvalApp(ops.Program, 0, 100, ep) require.Error(t, err) require.Contains(t, err.Error(), "is not opted into") @@ -1501,39 +1494,34 @@ func TestAppLocalStateReadWrite(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - txn := makeSampleAppl(100) - ep := defaultEvalParams(txn) - ledger := NewLedger( - map[basics.Address]uint64{ - txn.Txn.Sender: 1, - }, - ) - ep.Ledger = ledger - ep.SigLedger = ledger - ledger.NewApp(txn.Txn.Sender, 100, basics.AppParams{}) - ledger.NewLocals(txn.Txn.Sender, 100) + testLogicRange(t, 2, 0, func(t *testing.T, ep *EvalParams, txn *transactions.Transaction, ledger *Ledger) { - // write int and bytes values - source := `int 0 // account -byte 0x414c474f // key "ALGO" + txn.ApplicationID = 100 + ledger.NewAccount(txn.Sender, 1) + ledger.NewApp(txn.Sender, 100, basics.AppParams{}) + ledger.NewLocals(txn.Sender, 100) + + // write int and bytes values + source := `txn Sender +byte "ALGO" // key int 0x77 // value app_local_put -int 0 // account -byte 0x414c474f41 // key "ALGOA" -byte 0x414c474f // value +txn Sender +byte "ALGOA" // key +byte "ALGO" // value app_local_put -int 0 // account +txn Sender int 100 // app id -byte 0x414c474f41 // key "ALGOA" +byte "ALGOA" // key app_local_get_ex bnz exist err exist: -byte 0x414c474f +byte "ALGO" == -int 0 // account +txn Sender int 100 // app id -byte 0x414c474f // key "ALGO" +byte "ALGO" // key app_local_get_ex bnz exist2 err @@ -1542,27 +1530,30 @@ int 0x77 == && ` - delta := testApp(t, source, ep) - require.Empty(t, delta.GlobalDelta) - require.Len(t, delta.LocalDeltas, 1) + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + delta := testApp(t, source, ep) + require.Empty(t, delta.GlobalDelta) + require.Len(t, delta.LocalDeltas, 1) - require.Len(t, delta.LocalDeltas[0], 2) - vd := delta.LocalDeltas[0]["ALGO"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x77), vd.Uint) + require.Len(t, delta.LocalDeltas[0], 2) + vd := delta.LocalDeltas[0]["ALGO"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x77), vd.Uint) - vd = delta.LocalDeltas[0]["ALGOA"] - require.Equal(t, basics.SetBytesAction, vd.Action) - require.Equal(t, "ALGO", vd.Bytes) + vd = delta.LocalDeltas[0]["ALGOA"] + require.Equal(t, basics.SetBytesAction, vd.Action) + require.Equal(t, "ALGO", vd.Bytes) - // write same value without writing, expect no local delta - source = `int 0 // account -byte 0x414c474f // key + // write same value without writing, expect no local delta + source = `txn Sender +byte "ALGO" // key int 0x77 // value app_local_put -int 0 // account +txn Sender int 100 // app id -byte 0x414c474f // key +byte "ALGO" // key app_local_get_ex bnz exist err @@ -1570,73 +1561,82 @@ exist: int 0x77 == ` - ledger.Reset() - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") - ledger.NoLocal(txn.Txn.Sender, 100, "ALGO") + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + ledger.Reset() + ledger.NoLocal(txn.Sender, 100, "ALGOA") + ledger.NoLocal(txn.Sender, 100, "ALGO") - algoValue := basics.TealValue{Type: basics.TealUintType, Uint: 0x77} - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) + algoValue := basics.TealValue{Type: basics.TealUintType, Uint: 0x77} + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) - delta = testApp(t, source, ep) - require.Empty(t, delta.GlobalDelta) - require.Empty(t, delta.LocalDeltas) + delta = testApp(t, source, ep) + require.Empty(t, delta.GlobalDelta) + require.Empty(t, delta.LocalDeltas) - // write same value after reading, expect no local delta - source = `int 0 // account + // write same value after reading, expect no local delta + source = `txn Sender int 100 // app id -byte 0x414c474f // key +byte "ALGO" // key app_local_get_ex bnz exist err exist: -int 0 // account -byte 0x414c474f // key +txn Sender +byte "ALGO" // key int 0x77 // value app_local_put -int 0 // account +txn Sender int 100 // app id -byte 0x414c474f // key +byte "ALGO" // key app_local_get_ex bnz exist2 err exist2: == ` - ledger.Reset() - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") + ledger.Reset() + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) + ledger.NoLocal(txn.Sender, 100, "ALGOA") - delta = testApp(t, source, ep) - require.Empty(t, delta.GlobalDelta) - require.Empty(t, delta.LocalDeltas) + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + delta = testApp(t, source, ep) + require.Empty(t, delta.GlobalDelta) + require.Empty(t, delta.LocalDeltas) - // write a value and expect local delta change - source = `int 0 // account -byte 0x414c474f41 // key "ALGOA" -int 0x78 // value + // write a value and expect local delta change + source = `txn Sender +byte "ALGOA" // key +int 0x78 // value app_local_put int 1 ` - ledger.Reset() - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") + ledger.Reset() + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) + ledger.NoLocal(txn.Sender, 100, "ALGOA") - delta = testApp(t, source, ep) - require.Empty(t, delta.GlobalDelta) - require.Len(t, delta.LocalDeltas, 1) - require.Len(t, delta.LocalDeltas[0], 1) - vd = delta.LocalDeltas[0]["ALGOA"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x78), vd.Uint) - - // write a value to existing key and expect delta change and reading the new value - source = `int 0 // account -byte 0x414c474f // key "ALGO" + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + delta = testApp(t, source, ep) + require.Empty(t, delta.GlobalDelta) + require.Len(t, delta.LocalDeltas, 1) + require.Len(t, delta.LocalDeltas[0], 1) + vd = delta.LocalDeltas[0]["ALGOA"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x78), vd.Uint) + + // write a value to existing key and expect delta change and reading the new value + source = `txn Sender +byte "ALGO" // key int 0x78 // value app_local_put -int 0 // account +txn Sender int 100 // app id -byte 0x414c474f // key "ALGO" +byte "ALGO" // key app_local_get_ex bnz exist err @@ -1644,85 +1644,96 @@ exist: int 0x78 == ` - ledger.Reset() - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") + ledger.Reset() + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) + ledger.NoLocal(txn.Sender, 100, "ALGOA") - delta = testApp(t, source, ep) - require.Empty(t, delta.GlobalDelta) - require.Len(t, delta.LocalDeltas, 1) - require.Len(t, delta.LocalDeltas[0], 1) - vd = delta.LocalDeltas[0]["ALGO"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x78), vd.Uint) - - // write a value after read and expect delta change - source = `int 0 // account + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + delta = testApp(t, source, ep) + require.Empty(t, delta.GlobalDelta) + require.Len(t, delta.LocalDeltas, 1) + require.Len(t, delta.LocalDeltas[0], 1) + vd = delta.LocalDeltas[0]["ALGO"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x78), vd.Uint) + + // write a value after read and expect delta change + source = `txn Sender int 100 // app id -byte 0x414c474f // key "ALGO" +byte "ALGO" // key app_local_get_ex bnz exist err exist: -int 0 // account -byte 0x414c474f // key "ALGO" +txn Sender +byte "ALGO" // key int 0x78 // value app_local_put ` - ledger.Reset() - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") + ledger.Reset() + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) + ledger.NoLocal(txn.Sender, 100, "ALGOA") - delta = testApp(t, source, ep) - require.Empty(t, delta.GlobalDelta) - require.Len(t, delta.LocalDeltas, 1) - require.Len(t, delta.LocalDeltas[0], 1) - vd = delta.LocalDeltas[0]["ALGO"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x78), vd.Uint) - - // write a few values and expect delta change only for unique changed - source = `int 0 // account -byte 0x414c474f // key "ALGO" + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + delta = testApp(t, source, ep) + require.Empty(t, delta.GlobalDelta) + require.Len(t, delta.LocalDeltas, 1) + require.Len(t, delta.LocalDeltas[0], 1) + vd = delta.LocalDeltas[0]["ALGO"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x78), vd.Uint) + + // write a few values and expect delta change only for unique changed + source = `txn Sender +byte "ALGO" // key int 0x77 // value app_local_put -int 0 // account -byte 0x414c474f // key "ALGO" +txn Sender +byte "ALGO" // key int 0x78 // value app_local_put -int 0 // account -byte 0x414c474f41 // key "ALGOA" +txn Sender +byte "ALGOA" // key int 0x78 // value app_local_put -int 1 // account -byte 0x414c474f // key "ALGO" +txn Accounts 1 +byte "ALGO" // key int 0x79 // value app_local_put int 1 ` - ledger.Reset() - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") + ledger.Reset() + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) + ledger.NoLocal(txn.Sender, 100, "ALGOA") - ledger.NewAccount(txn.Txn.Receiver, 500) - ledger.NewLocals(txn.Txn.Receiver, 100) + ledger.NewAccount(txn.Receiver, 500) + ledger.NewLocals(txn.Receiver, 100) - delta = testApp(t, source, ep) - require.Empty(t, delta.GlobalDelta) - require.Len(t, delta.LocalDeltas, 2) - require.Len(t, delta.LocalDeltas[0], 2) - require.Len(t, delta.LocalDeltas[1], 1) - vd = delta.LocalDeltas[0]["ALGO"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x78), vd.Uint) - - vd = delta.LocalDeltas[0]["ALGOA"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x78), vd.Uint) - - vd = delta.LocalDeltas[1]["ALGO"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x79), vd.Uint) + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + source = strings.ReplaceAll(source, "txn Accounts 1", "int 1") + } + delta = testApp(t, source, ep) + require.Empty(t, delta.GlobalDelta) + require.Len(t, delta.LocalDeltas, 2) + require.Len(t, delta.LocalDeltas[0], 2) + require.Len(t, delta.LocalDeltas[1], 1) + vd = delta.LocalDeltas[0]["ALGO"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x78), vd.Uint) + + vd = delta.LocalDeltas[0]["ALGOA"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x78), vd.Uint) + + vd = delta.LocalDeltas[1]["ALGO"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x79), vd.Uint) + }) } func TestAppLocalGlobalErrorCases(t *testing.T) { @@ -1737,22 +1748,22 @@ func TestAppLocalGlobalErrorCases(t *testing.T) { testApp(t, fmt.Sprintf(`byte "%v"; int 1; app_global_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppKeyLen)), ep) ledger.NewLocals(tx.Sender, 888) - testApp(t, fmt.Sprintf(`int 0; byte "%v"; int 1; app_local_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppKeyLen+1)), ep, "key too long") + testApp(t, fmt.Sprintf(`txn Sender; byte "%v"; int 1; app_local_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppKeyLen+1)), ep, "key too long") - testApp(t, fmt.Sprintf(`int 0; byte "%v"; int 1; app_local_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppKeyLen)), ep) + testApp(t, fmt.Sprintf(`txn Sender; byte "%v"; int 1; app_local_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppKeyLen)), ep) testApp(t, fmt.Sprintf(`byte "foo"; byte "%v"; app_global_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppBytesValueLen+1)), ep, "value too long for key") testApp(t, fmt.Sprintf(`byte "foo"; byte "%v"; app_global_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppBytesValueLen)), ep) - testApp(t, fmt.Sprintf(`int 0; byte "foo"; byte "%v"; app_local_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppBytesValueLen+1)), ep, "value too long for key") + testApp(t, fmt.Sprintf(`txn Sender; byte "foo"; byte "%v"; app_local_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppBytesValueLen+1)), ep, "value too long for key") - testApp(t, fmt.Sprintf(`int 0; byte "foo"; byte "%v"; app_local_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppBytesValueLen)), ep) + testApp(t, fmt.Sprintf(`txn Sender; byte "foo"; byte "%v"; app_local_put; int 1`, strings.Repeat("v", ep.Proto.MaxAppBytesValueLen)), ep) ep.Proto.MaxAppSumKeyValueLens = 2 // Override to generate error. testApp(t, `byte "foo"; byte "foo"; app_global_put; int 1`, ep, "key/value total too long for key") - testApp(t, `int 0; byte "foo"; byte "foo"; app_local_put; int 1`, ep, "key/value total too long for key") + testApp(t, `txn Sender; byte "foo"; byte "foo"; app_local_put; int 1`, ep, "key/value total too long for key") } func TestAppGlobalReadWriteDeleteErrors(t *testing.T) { @@ -1761,7 +1772,7 @@ func TestAppGlobalReadWriteDeleteErrors(t *testing.T) { t.Parallel() sourceRead := `int 0 -byte 0x414c474f // key "ALGO" +byte "ALGO" // key app_global_get_ex bnz ok err @@ -1769,18 +1780,18 @@ ok: int 0x77 == ` - sourceReadSimple := `byte 0x414c474f // key "ALGO" + sourceReadSimple := `byte "ALGO" // key app_global_get int 0x77 == ` - sourceWrite := `byte 0x414c474f // key "ALGO" + sourceWrite := `byte "ALGO" // key int 100 app_global_put int 1 ` - sourceDelete := `byte 0x414c474f // key "ALGO" + sourceDelete := `byte "ALGO" // key app_global_del int 1 ` @@ -1824,46 +1835,46 @@ func TestAppGlobalReadWrite(t *testing.T) { testLogicRange(t, 2, 0, func(t *testing.T, ep *EvalParams, txn *transactions.Transaction, ledger *Ledger) { // check writing ints and bytes - source := `byte 0x414c474f // key "ALGO" + source := `byte "ALGO" // key int 0x77 // value app_global_put -byte 0x414c474f41 // key "ALGOA" -byte 0x414c474f // value +byte "ALGOA" // key "ALGOA" +byte "ALGO" // value app_global_put // check simple -byte 0x414c474f41 // key "ALGOA" +byte "ALGOA" // key "ALGOA" app_global_get -byte 0x414c474f +byte "ALGO" == // check generic with alias int 0 // current app id alias -byte 0x414c474f41 // key "ALGOA" +byte "ALGOA" // key "ALGOA" app_global_get_ex bnz ok err ok: -byte 0x414c474f +byte "ALGO" == && // check generic with exact app id THISAPP -byte 0x414c474f41 // key "ALGOA" +byte "ALGOA" // key "ALGOA" app_global_get_ex bnz ok1 err ok1: -byte 0x414c474f +byte "ALGO" == && // check simple -byte 0x414c474f +byte "ALGO" app_global_get int 0x77 == && // check generic with alias int 0 // ForeignApps index - current app -byte 0x414c474f +byte "ALGO" app_global_get_ex bnz ok2 err @@ -1873,7 +1884,7 @@ int 0x77 && // check generic with exact app id THISAPP -byte 0x414c474f +byte "ALGO" app_global_get_ex bnz ok3 err @@ -1910,10 +1921,10 @@ int 0x77 require.Equal(t, "ALGO", vd.Bytes) // write existing value before read - source = `byte 0x414c474f // key "ALGO" + source = `byte "ALGO" // key int 0x77 // value app_global_put -byte 0x414c474f +byte "ALGO" app_global_get int 0x77 == @@ -1931,16 +1942,16 @@ int 0x77 // write existing value after read source = `int 0 -byte 0x414c474f +byte "ALGO" app_global_get_ex bnz ok err ok: pop -byte 0x414c474f +byte "ALGO" int 0x77 app_global_put -byte 0x414c474f +byte "ALGO" app_global_get int 0x77 == @@ -1955,33 +1966,33 @@ int 0x77 // write new values after and before read source = `int 0 -byte 0x414c474f +byte "ALGO" app_global_get_ex bnz ok err ok: pop -byte 0x414c474f +byte "ALGO" int 0x78 app_global_put int 0 -byte 0x414c474f +byte "ALGO" app_global_get_ex bnz ok2 err ok2: int 0x78 == -byte 0x414c474f41 -byte 0x414c474f +byte "ALGOA" +byte "ALGO" app_global_put int 0 -byte 0x414c474f41 +byte "ALGOA" app_global_get_ex bnz ok3 err ok3: -byte 0x414c474f +byte "ALGO" == && ` @@ -2236,12 +2247,12 @@ int 1 ledger.NewGlobal(100, "ALGO", algoValue) // check delete, write, delete non-existing - source = `byte 0x414c474f41 // key "ALGOA" + source = `byte "ALGOA" // key "ALGOA" app_global_del -byte 0x414c474f41 +byte "ALGOA" int 0x78 app_global_put -byte 0x414c474f41 +byte "ALGOA" app_global_del int 1 ` @@ -2255,29 +2266,30 @@ func TestAppLocalDelete(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - // check write/delete/read - source := `int 0 // sender -byte 0x414c474f // key "ALGO" + testLogicRange(t, 2, 0, func(t *testing.T, ep *EvalParams, txn *transactions.Transaction, ledger *Ledger) { + // check write/delete/read + source := `int 0 // sender +byte "ALGO" int 0x77 // value app_local_put -int 1 -byte 0x414c474f41 // key "ALGOA" -byte 0x414c474f +int 1 // other +byte "ALGOA" // key "ALGOA" +byte "ALGO" app_local_put int 0 // sender -byte 0x414c474f +byte "ALGO" app_local_del -int 1 -byte 0x414c474f41 +int 1 // other +byte "ALGOA" app_local_del int 0 // sender int 0 // app -byte 0x414c474f +byte "ALGO" app_local_get_ex bnz error -int 1 +int 1 // other int 100 -byte 0x414c474f41 +byte "ALGOA" app_local_get_ex bnz error == @@ -2287,165 +2299,180 @@ err ok: int 1 ` - txn := makeSampleAppl(100) - ep := defaultEvalParams(txn) - ledger := NewLedger( - map[basics.Address]uint64{ - txn.Txn.Sender: 1, - }, - ) - ep.Ledger = ledger - ep.SigLedger = ledger - ledger.NewApp(txn.Txn.Sender, 100, basics.AppParams{}) - ledger.NewLocals(txn.Txn.Sender, 100) - ledger.NewAccount(txn.Txn.Receiver, 1) - ledger.NewLocals(txn.Txn.Receiver, 100) + txn.ApplicationID = 100 + ledger.NewAccount(txn.Sender, 1) + ledger.NewApp(txn.Sender, 100, basics.AppParams{}) + ledger.NewLocals(txn.Sender, 100) + ledger.NewAccount(txn.Receiver, 1) + ledger.NewLocals(txn.Receiver, 100) - ep.Trace = &strings.Builder{} + ep.Trace = &strings.Builder{} - delta := testApp(t, source, ep) - require.Equal(t, 0, len(delta.GlobalDelta)) - require.Equal(t, 2, len(delta.LocalDeltas)) + if ep.Proto.LogicSigVersion < sharedResourcesVersion { + delta := testApp(t, source, ep) + require.Equal(t, 0, len(delta.GlobalDelta)) + require.Equal(t, 2, len(delta.LocalDeltas)) + ledger.Reset() + } - ledger.Reset() - // test that app_local_put and _app_local_del can use byte addresses - delta = testApp(t, strings.Replace(source, "int 0 // sender", "byte \"aoeuiaoeuiaoeuiaoeuiaoeuiaoeui00\"", -1), ep) - // But won't even compile in old teal - testProg(t, strings.Replace(source, "int 0 // sender", "byte \"aoeuiaoeuiaoeuiaoeuiaoeuiaoeui00\"", -1), directRefEnabledVersion-1, - Expect{4, "app_local_put arg 0 wanted..."}, Expect{11, "app_local_del arg 0 wanted..."}) - require.Equal(t, 0, len(delta.GlobalDelta)) - require.Equal(t, 2, len(delta.LocalDeltas)) + if ep.Proto.LogicSigVersion >= directRefEnabledVersion { + // test that app_local_put and _app_local_del can use byte addresses + withBytes := strings.ReplaceAll(source, "int 0 // sender", "txn Sender") + withBytes = strings.ReplaceAll(withBytes, "int 1 // other", "txn Accounts 1") + delta := testApp(t, withBytes, ep) + // But won't even compile in old teal + testProg(t, withBytes, directRefEnabledVersion-1, + Expect{4, "app_local_put arg 0 wanted..."}, Expect{11, "app_local_del arg 0 wanted..."}) + require.Equal(t, 0, len(delta.GlobalDelta)) + require.Equal(t, 2, len(delta.LocalDeltas)) + ledger.Reset() + } - ledger.Reset() - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") - ledger.NoLocal(txn.Txn.Sender, 100, "ALGO") - ledger.NoLocal(txn.Txn.Receiver, 100, "ALGOA") - ledger.NoLocal(txn.Txn.Receiver, 100, "ALGO") + ledger.NoLocal(txn.Sender, 100, "ALGOA") + ledger.NoLocal(txn.Sender, 100, "ALGO") + ledger.NoLocal(txn.Receiver, 100, "ALGOA") + ledger.NoLocal(txn.Receiver, 100, "ALGO") - algoValue := basics.TealValue{Type: basics.TealUintType, Uint: 0x77} - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) + algoValue := basics.TealValue{Type: basics.TealUintType, Uint: 0x77} + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) - // check delete existing - source = `int 0 // account -byte 0x414c474f // key "ALGO" + // check delete existing + source = `txn Sender +byte "ALGO" app_local_del -int 0 +txn Sender int 100 -byte 0x414c474f +byte "ALGO" app_local_get_ex == // two zeros ` - delta = testApp(t, source, ep) - require.Equal(t, 0, len(delta.GlobalDelta)) - require.Equal(t, 1, len(delta.LocalDeltas)) - vd := delta.LocalDeltas[0]["ALGO"] - require.Equal(t, basics.DeleteAction, vd.Action) - require.Equal(t, uint64(0), vd.Uint) - require.Equal(t, "", vd.Bytes) + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + delta := testApp(t, source, ep) + require.Equal(t, 0, len(delta.GlobalDelta)) + require.Equal(t, 1, len(delta.LocalDeltas)) + vd := delta.LocalDeltas[0]["ALGO"] + require.Equal(t, basics.DeleteAction, vd.Action) + require.Equal(t, uint64(0), vd.Uint) + require.Equal(t, "", vd.Bytes) - ledger.Reset() - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") - ledger.NoLocal(txn.Txn.Sender, 100, "ALGO") + ledger.Reset() + ledger.NoLocal(txn.Sender, 100, "ALGOA") + ledger.NoLocal(txn.Sender, 100, "ALGO") - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) - // check delete and write non-existing - source = `int 0 // account -byte 0x414c474f41 // key "ALGOA" + // check delete and write non-existing + source = `txn Sender +byte "ALGOA" app_local_del +txn Sender int 0 -int 0 -byte 0x414c474f41 +byte "ALGOA" app_local_get_ex == // two zeros -int 0 -byte 0x414c474f41 +txn Sender +byte "ALGOA" int 0x78 app_local_put ` - delta = testApp(t, source, ep) - require.Equal(t, 0, len(delta.GlobalDelta)) - require.Equal(t, 1, len(delta.LocalDeltas)) - vd = delta.LocalDeltas[0]["ALGOA"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x78), vd.Uint) - require.Equal(t, "", vd.Bytes) + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + delta = testApp(t, source, ep) + require.Equal(t, 0, len(delta.GlobalDelta)) + require.Equal(t, 1, len(delta.LocalDeltas)) + vd = delta.LocalDeltas[0]["ALGOA"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x78), vd.Uint) + require.Equal(t, "", vd.Bytes) - ledger.Reset() - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") - ledger.NoLocal(txn.Txn.Sender, 100, "ALGO") + ledger.Reset() + ledger.NoLocal(txn.Sender, 100, "ALGOA") + ledger.NoLocal(txn.Sender, 100, "ALGO") - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) - // check delete and write existing - source = `int 0 // account -byte 0x414c474f // key "ALGO" + // check delete and write existing + source = `txn Sender +byte "ALGO" app_local_del -int 0 -byte 0x414c474f +txn Sender +byte "ALGO" int 0x78 app_local_put int 1 ` - delta = testApp(t, source, ep) - require.Equal(t, 0, len(delta.GlobalDelta)) - require.Equal(t, 1, len(delta.LocalDeltas)) - vd = delta.LocalDeltas[0]["ALGO"] - require.Equal(t, basics.SetUintAction, vd.Action) - require.Equal(t, uint64(0x78), vd.Uint) - require.Equal(t, "", vd.Bytes) + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + delta = testApp(t, source, ep) + require.Equal(t, 0, len(delta.GlobalDelta)) + require.Equal(t, 1, len(delta.LocalDeltas)) + vd = delta.LocalDeltas[0]["ALGO"] + require.Equal(t, basics.SetUintAction, vd.Action) + require.Equal(t, uint64(0x78), vd.Uint) + require.Equal(t, "", vd.Bytes) - ledger.Reset() - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") - ledger.NoLocal(txn.Txn.Sender, 100, "ALGO") + ledger.Reset() + ledger.NoLocal(txn.Sender, 100, "ALGOA") + ledger.NoLocal(txn.Sender, 100, "ALGO") - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) - // check delete,write,delete existing - source = `int 0 // account -byte 0x414c474f // key "ALGO" + // check delete,write,delete existing + source = `txn Sender +byte "ALGO" app_local_del -int 0 -byte 0x414c474f +txn Sender +byte "ALGO" int 0x78 app_local_put -int 0 -byte 0x414c474f +txn Sender +byte "ALGO" app_local_del int 1 ` - delta = testApp(t, source, ep) - require.Equal(t, 0, len(delta.GlobalDelta)) - require.Equal(t, 1, len(delta.LocalDeltas)) - vd = delta.LocalDeltas[0]["ALGO"] - require.Equal(t, basics.DeleteAction, vd.Action) - require.Equal(t, uint64(0), vd.Uint) - require.Equal(t, "", vd.Bytes) + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + delta = testApp(t, source, ep) + require.Equal(t, 0, len(delta.GlobalDelta)) + require.Equal(t, 1, len(delta.LocalDeltas)) + vd = delta.LocalDeltas[0]["ALGO"] + require.Equal(t, basics.DeleteAction, vd.Action) + require.Equal(t, uint64(0), vd.Uint) + require.Equal(t, "", vd.Bytes) - ledger.Reset() - ledger.NoLocal(txn.Txn.Sender, 100, "ALGOA") - ledger.NoLocal(txn.Txn.Sender, 100, "ALGO") + ledger.Reset() + ledger.NoLocal(txn.Sender, 100, "ALGOA") + ledger.NoLocal(txn.Sender, 100, "ALGO") - ledger.NewLocal(txn.Txn.Sender, 100, "ALGO", algoValue) + ledger.NewLocal(txn.Sender, 100, "ALGO", algoValue) - // check delete, write, delete non-existing - source = `int 0 // account -byte 0x414c474f41 // key "ALGOA" + // check delete, write, delete non-existing + source = `txn Sender +byte "ALGOA" app_local_del -int 0 -byte 0x414c474f41 +txn Sender +byte "ALGOA" int 0x78 app_local_put -int 0 -byte 0x414c474f41 +txn Sender +byte "ALGOA" app_local_del int 1 ` - delta = testApp(t, source, ep) - require.Equal(t, 0, len(delta.GlobalDelta)) - require.Equal(t, 1, len(delta.LocalDeltas)) - require.Equal(t, 1, len(delta.LocalDeltas[0])) + if ep.Proto.LogicSigVersion < directRefEnabledVersion { + source = strings.ReplaceAll(source, "txn Sender", "int 0") + } + delta = testApp(t, source, ep) + require.Equal(t, 0, len(delta.GlobalDelta)) + require.Equal(t, 1, len(delta.LocalDeltas)) + require.Equal(t, 1, len(delta.LocalDeltas[0])) + }) } func TestEnumFieldErrors(t *testing.T) { // nolint:paralleltest // manipulates txnFieldSpecs @@ -2492,7 +2519,7 @@ func TestEnumFieldErrors(t *testing.T) { // nolint:paralleltest // manipulates t } ledger.NewAsset(tx.Sender, 55, params) - source = `int 0 + source = `txn Sender int 55 asset_holding_get AssetBalance assert @@ -2541,40 +2568,50 @@ func TestReturnTypes(t *testing.T) { // opcodes that need to set up their own stack inputs, a ": at the front of // the string means "start with an empty stack". specialCmd := map[string]string{ - "txn": "txn Sender", - "txna": "txna ApplicationArgs 0", - "gtxn": "gtxn 0 Sender", - "gtxna": "gtxna 0 ApplicationArgs 0", - "global": "global MinTxnFee", - "gaids": ": int 0; gaids", - "gloads": ": int 0; gloads 0", // Needs txn index = 0 to work - "gloadss": ": int 0; int 1; gloadss", // Needs txn index = 0 to work - "intc": "intcblock 0; intc 0", - "intc_0": "intcblock 0; intc_0", - "intc_1": "intcblock 0 0; intc_1", - "intc_2": "intcblock 0 0 0; intc_2", - "intc_3": "intcblock 0 0 0 0; intc_3", - "bytec": "bytecblock 0x32; bytec 0", - "bytec_0": "bytecblock 0x32; bytec_0", - "bytec_1": "bytecblock 0x32 0x33; bytec_1", - "bytec_2": "bytecblock 0x32 0x33 0x34; bytec_2", - "bytec_3": "bytecblock 0x32 0x33 0x34 0x35; bytec_3", - "substring": "substring 0 2", - "extract_uint32": ": byte 0x0102030405; int 1; extract_uint32", - "extract_uint64": ": byte 0x010203040506070809; int 1; extract_uint64", - "replace2": ": byte 0x0102030405; byte 0x0809; replace2 2", - "replace3": ": byte 0x0102030405; int 2; byte 0x0809; replace3", - "asset_params_get": "asset_params_get AssetUnitName", - "asset_holding_get": "asset_holding_get AssetBalance", - "gtxns": "gtxns Sender", - "gtxnsa": ": int 0; gtxnsa ApplicationArgs 0", - "app_params_get": "app_params_get AppGlobalNumUint", - "acct_params_get": "acct_params_get AcctMinBalance", - "extract": "extract 0 2", - "txnas": "txnas ApplicationArgs", - "gtxnas": "gtxnas 0 ApplicationArgs", - "gtxnsas": ": int 0; int 0; gtxnsas ApplicationArgs", - "divw": ": int 1; int 2; int 3; divw", + "txn": "txn Sender", + "txna": "txna ApplicationArgs 0", + "gtxn": "gtxn 0 Sender", + "gtxna": "gtxna 0 ApplicationArgs 0", + "global": "global MinTxnFee", + "gaids": ": int 0; gaids", + "gloads": ": int 0; gloads 0", // Needs txn index = 0 to work + "gloadss": ": int 0; int 1; gloadss", // Needs txn index = 0 to work + "intc": "intcblock 0; intc 0", + "intc_0": "intcblock 0; intc_0", + "intc_1": "intcblock 0 0; intc_1", + "intc_2": "intcblock 0 0 0; intc_2", + "intc_3": "intcblock 0 0 0 0; intc_3", + "bytec": "bytecblock 0x32; bytec 0", + "bytec_0": "bytecblock 0x32; bytec_0", + "bytec_1": "bytecblock 0x32 0x33; bytec_1", + "bytec_2": "bytecblock 0x32 0x33 0x34; bytec_2", + "bytec_3": "bytecblock 0x32 0x33 0x34 0x35; bytec_3", + "substring": "substring 0 2", + "extract_uint32": ": byte 0x0102030405; int 1; extract_uint32", + "extract_uint64": ": byte 0x010203040506070809; int 1; extract_uint64", + "replace2": ": byte 0x0102030405; byte 0x0809; replace2 2", + "replace3": ": byte 0x0102030405; int 2; byte 0x0809; replace3", + "asset_params_get": "asset_params_get AssetUnitName", + "gtxns": "gtxns Sender", + "gtxnsa": ": int 0; gtxnsa ApplicationArgs 0", + "app_params_get": "app_params_get AppGlobalNumUint", + "extract": "extract 0 2", + "txnas": "txnas ApplicationArgs", + "gtxnas": "gtxnas 0 ApplicationArgs", + "gtxnsas": ": int 0; int 0; gtxnsas ApplicationArgs", + "divw": ": int 1; int 2; int 3; divw", + + // opcodes that require addresses, not just bytes + "balance": ": txn Sender; balance", + "min_balance": ": txn Sender; min_balance", + "acct_params_get": ": txn Sender; acct_params_get AcctMinBalance", + // Use "bury" here to take advantage of args pushed on stack by test + "app_local_get": "txn Accounts 1; bury 2; app_local_get", + "app_local_get_ex": "txn Accounts 1; bury 3; app_local_get_ex", + "app_local_del": "txn Accounts 1; bury 2; app_local_del", + "app_local_put": "txn Accounts 1; bury 3; app_local_put", + "app_opted_in": "txn Sender; bury 2; app_opted_in", + "asset_holding_get": "txn Sender; bury 2; asset_holding_get AssetBalance", "itxn_field": "itxn_begin; itxn_field TypeEnum", "itxn_next": "itxn_begin; int pay; itxn_field TypeEnum; itxn_next", diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go index 1037f78bcf..29231d3448 100644 --- a/data/transactions/logic/eval_test.go +++ b/data/transactions/logic/eval_test.go @@ -4309,7 +4309,7 @@ func TestAllowedOpcodesV2(t *testing.T) { "gtxn": true, } - ep := defaultEvalParams() + ep := defaultEvalParamsWithVersion(2) cnt := 0 for _, spec := range OpSpecs { @@ -4317,7 +4317,7 @@ func TestAllowedOpcodesV2(t *testing.T) { source, ok := tests[spec.Name] require.True(t, ok, "Missed opcode in the test: %s", spec.Name) require.Contains(t, source, spec.Name) - ops := testProg(t, source, AssemblerMaxVersion) + ops := testProg(t, source, 2) // all opcodes allowed in stateful mode so use CheckStateful/EvalContract err := CheckContract(ops.Program, ep) require.NoError(t, err, source) @@ -4362,7 +4362,7 @@ func TestAllowedOpcodesV3(t *testing.T) { "pushbytes": `pushbytes "stringsfail?"`, } - ep := defaultEvalParams() + ep := defaultEvalParamsWithVersion(3) cnt := 0 for _, spec := range OpSpecs { @@ -4370,7 +4370,7 @@ func TestAllowedOpcodesV3(t *testing.T) { source, ok := tests[spec.Name] require.True(t, ok, "Missed opcode in the test: %s", spec.Name) require.Contains(t, source, spec.Name) - ops := testProg(t, source, AssemblerMaxVersion) + ops := testProg(t, source, 3) // all opcodes allowed in stateful mode so use CheckStateful/EvalContract testAppBytes(t, ops.Program, ep, "REJECT") diff --git a/data/transactions/logic/fields_test.go b/data/transactions/logic/fields_test.go index 91abc84457..2d58854d5e 100644 --- a/data/transactions/logic/fields_test.go +++ b/data/transactions/logic/fields_test.go @@ -269,19 +269,13 @@ func TestAcctParamsFieldsVersions(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - var fields []acctParamsFieldSpec - for _, fs := range acctParamsFieldSpecs { - if fs.version > 6 { - fields = append(fields, fs) + for _, field := range acctParamsFieldSpecs { + text := fmt.Sprintf("txn Sender; acct_params_get %s; assert;", field.field.String()) + if field.ftype == StackBytes { + text += "global ZeroAddress; concat; len" // use concat to prove we have bytes + } else { + text += "global ZeroAddress; len; +" // use + to prove we have an int } - } - require.Greater(t, len(fields), 0) - - for _, field := range fields { - // Need to use intc so we can "backversion" the program and not have it - // fail because of pushint. - // Use of '+' confirms the type, which is uint64 for all fields - text := fmt.Sprintf("intcblock 0 1; intc_0; acct_params_get %s; assert; intc_1; +", field.field.String()) // check assembler fails if version before introduction for v := uint64(2); v <= AssemblerMaxVersion; v++ { ep, txn, ledger := makeSampleEnv() diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index 47bef35667..f7575f774c 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -57,10 +57,6 @@ const txnEffectsVersion = 6 // the Foreign arrays. const createdResourcesVersion = 6 -// sharedResourcesVersion is the first version in which apps are allowed to -// access resources referenced in other transactions. -const sharedResourcesVersion = 9 - // appAddressAvailableVersion is the first version that allows access to the // accounts of applications that were provided in the foreign apps transaction // field. @@ -70,10 +66,12 @@ const fidoVersion = 7 // base64, json, secp256r1 const randomnessVersion = 7 // vrf_verify, block const fpVersion = 8 // changes for frame pointers and simpler function discipline +const sharedResourcesVersion = 9 // apps can access resources from other transactions. + // EXPERIMENTAL. These should be revisited whenever a new LogicSigVersion is // moved from vFuture to a new consensus version. If they remain unready, bump // their version, and fixup TestAssemble() in assembler_test.go. -const pairingVersion = 9 // bn256 opcodes. will add bls12-381, and unify the available opcodes. +const pairingVersion = 10 // bn256 opcodes. will add bls12-381, and unify the available opcodes. // Unlimited Global Storage opcodes const boxVersion = 8 // box_* @@ -532,30 +530,38 @@ var OpSpecs = []OpSpec{ {0x60, "balance", opBalance, proto("i:i"), 2, only(ModeApp)}, {0x60, "balance", opBalance, proto("a:i"), directRefEnabledVersion, only(ModeApp)}, - // {0x60, "balance", opDeprecated, proto("a:i"), sharedResourcesVersion, only(ModeApp)}, + {0x60, "balance", opBalance, proto("b:i"), sharedResourcesVersion, only(ModeApp)}, {0x61, "app_opted_in", opAppOptedIn, proto("ii:i"), 2, only(ModeApp)}, {0x61, "app_opted_in", opAppOptedIn, proto("ai:i"), directRefEnabledVersion, only(ModeApp)}, + {0x61, "app_opted_in", opAppOptedIn, proto("bi:i"), sharedResourcesVersion, only(ModeApp)}, {0x62, "app_local_get", opAppLocalGet, proto("ib:a"), 2, only(ModeApp)}, {0x62, "app_local_get", opAppLocalGet, proto("ab:a"), directRefEnabledVersion, only(ModeApp)}, + {0x62, "app_local_get", opAppLocalGet, proto("bb:a"), sharedResourcesVersion, only(ModeApp)}, {0x63, "app_local_get_ex", opAppLocalGetEx, proto("iib:ai"), 2, only(ModeApp)}, {0x63, "app_local_get_ex", opAppLocalGetEx, proto("aib:ai"), directRefEnabledVersion, only(ModeApp)}, + {0x63, "app_local_get_ex", opAppLocalGetEx, proto("bib:ai"), sharedResourcesVersion, only(ModeApp)}, {0x64, "app_global_get", opAppGlobalGet, proto("b:a"), 2, only(ModeApp)}, {0x65, "app_global_get_ex", opAppGlobalGetEx, proto("ib:ai"), 2, only(ModeApp)}, {0x66, "app_local_put", opAppLocalPut, proto("iba:"), 2, only(ModeApp)}, {0x66, "app_local_put", opAppLocalPut, proto("aba:"), directRefEnabledVersion, only(ModeApp)}, + {0x66, "app_local_put", opAppLocalPut, proto("bba:"), sharedResourcesVersion, only(ModeApp)}, {0x67, "app_global_put", opAppGlobalPut, proto("ba:"), 2, only(ModeApp)}, {0x68, "app_local_del", opAppLocalDel, proto("ib:"), 2, only(ModeApp)}, {0x68, "app_local_del", opAppLocalDel, proto("ab:"), directRefEnabledVersion, only(ModeApp)}, + {0x68, "app_local_del", opAppLocalDel, proto("bb:"), sharedResourcesVersion, only(ModeApp)}, {0x69, "app_global_del", opAppGlobalDel, proto("b:"), 2, only(ModeApp)}, {0x70, "asset_holding_get", opAssetHoldingGet, proto("ii:ai"), 2, field("f", &AssetHoldingFields).only(ModeApp)}, {0x70, "asset_holding_get", opAssetHoldingGet, proto("ai:ai"), directRefEnabledVersion, field("f", &AssetHoldingFields).only(ModeApp)}, + {0x70, "asset_holding_get", opAssetHoldingGet, proto("bi:ai"), sharedResourcesVersion, field("f", &AssetHoldingFields).only(ModeApp)}, {0x71, "asset_params_get", opAssetParamsGet, proto("i:ai"), 2, field("f", &AssetParamsFields).only(ModeApp)}, {0x72, "app_params_get", opAppParamsGet, proto("i:ai"), 5, field("f", &AppParamsFields).only(ModeApp)}, {0x73, "acct_params_get", opAcctParamsGet, proto("a:ai"), 6, field("f", &AcctParamsFields).only(ModeApp)}, + {0x73, "acct_params_get", opAcctParamsGet, proto("b:ai"), sharedResourcesVersion, field("f", &AcctParamsFields).only(ModeApp)}, {0x78, "min_balance", opMinBalance, proto("i:i"), 3, only(ModeApp)}, {0x78, "min_balance", opMinBalance, proto("a:i"), directRefEnabledVersion, only(ModeApp)}, + {0x78, "min_balance", opMinBalance, proto("b:i"), sharedResourcesVersion, only(ModeApp)}, // Immediate bytes and ints. Smaller code size for single use of constant. {0x80, "pushbytes", opPushBytes, proto(":b"), 3, constants(asmPushBytes, opPushBytes, "bytes", immBytes)}, diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 8c5e67f31d..6d340d6b48 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -19,6 +19,7 @@ package logic_test import ( "encoding/binary" "fmt" + "strings" "testing" "github.com/algorand/go-algorand/data/basics" @@ -71,7 +72,7 @@ app_params_get AppGlobalNumByteSlice logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, nil) getLocalEx := ` -int 0 // Sender +txn Sender int 500 byte "some-key" app_local_get_ex @@ -104,7 +105,7 @@ pop; pop; int 1 // Checking if an account is opted in has pretty much the same rules optInCheck500 := ` -int 0 // Sender +txn Sender int 500 app_opted_in ` @@ -127,7 +128,7 @@ app_opted_in // Confirm sharing applies to the app id called in tx0, not just foreign app array optInCheck900 := ` -int 0 // Sender +txn Sender int 900 app_opted_in ! // we did not opt any senders into 900 @@ -248,7 +249,7 @@ pop; pop; int 1 logic.TestApps(t, sources, txntest.Group(&appl0, &appl1), 9, nil) getBalance := ` -int 0 +txn Sender int 400 asset_holding_get AssetBalance pop; pop; int 1 @@ -873,9 +874,16 @@ func TestAccessMyLocals(t *testing.T) { int 7 == ` + if ep.Proto.LogicSigVersion >= 9 { + source = strings.ReplaceAll(source, "int 0\n", "txn Sender\n") + } logic.TestApp(t, source, ep) // They can also see that they are opted in, though it's a weird question to ask. - logic.TestApp(t, "int 0; int 0; app_opted_in", ep) + if ep.Proto.LogicSigVersion >= 9 { + logic.TestApp(t, "txn Sender; int 0; app_opted_in", ep) + } else { + logic.TestApp(t, "int 0; int 0; app_opted_in", ep) + } }) } From ccdd661d907047b91386c1400cc76d32ac338116 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Sun, 2 Apr 2023 13:52:33 -0400 Subject: [PATCH 26/29] adjust ledger tests for v9 --- ledger/apptxn_test.go | 40 +++++++++++++++++++++++++------- ledger/testing/consensusRange.go | 4 ++-- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/ledger/apptxn_test.go b/ledger/apptxn_test.go index 0ec1cd9b9d..1d356b2cfd 100644 --- a/ledger/apptxn_test.go +++ b/ledger/apptxn_test.go @@ -3236,19 +3236,29 @@ func TestForeignAppAccountsImmutable(t *testing.T) { appA := txntest.Txn{ Type: "appl", Sender: addrs[0], + ApprovalProgram: main(` +itxn_begin +int appl; itxn_field TypeEnum +txn Applications 1; itxn_field ApplicationID +int OptIn; itxn_field OnCompletion +itxn_submit +`), } appB := txntest.Txn{ Type: "appl", Sender: addrs[0], ApprovalProgram: main(` +txn NumApplications // allow "bare" optin +bz end txn Applications 1 app_params_get AppAddress +assert byte "X" byte "ABC" app_local_put -int 1 `), + LocalStateSchema: basics.StateSchema{NumByteSlice: 1}, } vb := dl.fullBlock(&appA, &appB) @@ -3264,6 +3274,13 @@ int 1 fund0 := fund1 fund0.Receiver = index0.Address() + optin := txntest.Txn{ + Type: "appl", + Sender: addrs[2], + ApplicationID: index0, + ForeignApps: []basics.AppIndex{index1}, + } + callTx := txntest.Txn{ Type: "appl", Sender: addrs[2], @@ -3271,9 +3288,14 @@ int 1 ForeignApps: []basics.AppIndex{index0}, } - dl.beginBlock() - dl.txgroup("invalid Account reference", &fund0, &fund1, &callTx) - dl.endBlock() + var problem string + switch { + case ver < 34: // before v7, app accounts not available at all + problem = "invalid Account reference " + index0.Address().String() + case ver < 37: // as of v7, it's the mutation that's the problem + problem = "invalid Account reference for mutation" + } + dl.txgroup(problem, &fund0, &fund1, &optin, &callTx) }) } @@ -3511,14 +3533,14 @@ func TestRewardsInAD(t *testing.T) { }) } -// TestDeleteNonExistantKeys checks if the EvalDeltas from deleting missing keys are correct -func TestDeleteNonExistantKeys(t *testing.T) { +// TestDeleteNonExistentKeys checks if the EvalDeltas from deleting missing keys are correct +func TestDeleteNonExistentKeys(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - // AVM v2 (apps) - ledgertesting.TestConsensusRange(t, 24, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + // AVM v4 start, so we can use `txn Sender` + ledgertesting.TestConsensusRange(t, 28, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { dl := NewDoubleLedger(t, genBalances, cv, cfg) defer dl.Close() @@ -3530,7 +3552,7 @@ func TestDeleteNonExistantKeys(t *testing.T) { ApprovalProgram: main(` byte "missing_global" app_global_del -int 0 +txn Sender byte "missing_local" app_local_del `), diff --git a/ledger/testing/consensusRange.go b/ledger/testing/consensusRange.go index 02ae83fce9..5408195f71 100644 --- a/ledger/testing/consensusRange.go +++ b/ledger/testing/consensusRange.go @@ -47,9 +47,9 @@ var consensusByNumber = []protocol.ConsensusVersion{ protocol.ConsensusV23, protocol.ConsensusV24, // AVM v2 (apps) protocol.ConsensusV25, - protocol.ConsensusV26, + protocol.ConsensusV26, // AVM v3 protocol.ConsensusV27, - protocol.ConsensusV28, + protocol.ConsensusV28, // AVM v4 (direct refs) protocol.ConsensusV29, protocol.ConsensusV30, // AVM v5 (inner txs) protocol.ConsensusV31, // AVM v6 (inner txs with appls) From 2239746dd0869e3fa5861472d80e6f632911e746 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 3 Apr 2023 12:32:42 -0400 Subject: [PATCH 27/29] add extra test discussed with Pavel --- data/transactions/logic/resources_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/data/transactions/logic/resources_test.go b/data/transactions/logic/resources_test.go index 6d340d6b48..01f784c12b 100644 --- a/data/transactions/logic/resources_test.go +++ b/data/transactions/logic/resources_test.go @@ -170,6 +170,16 @@ int 1 }, ed.LocalDeltas) require.Len(t, ed.SharedAccts, 1) require.Equal(t, ep.TxnGroup[0].Txn.Sender, ed.SharedAccts[0]) + + // when running all three, appl2 can't read the locals of app in tx0 and addr in tx1 + sources = []string{"", "", "gtxn 1 Sender; gtxn 0 Applications 0; byte 0xAA; app_local_get_ex"} + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1, &appl2), 9, nil, + logic.NewExpect(2, "invalid Local State access")) // note that the error message is for Locals, not specialized + // same test of account in array of tx1 rather than Sender + appl1.Accounts = []basics.Address{{7, 7}} + sources = []string{"", "", "gtxn 1 Accounts 1; gtxn 0 Applications 0; byte 0xAA; app_local_get_ex"} + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1, &appl2), 9, nil, + logic.NewExpect(2, "invalid Local State access")) // note that the error message is for Locals, not specialized } // TestBetterLocalErrors confirms that we get specific errors about the missing @@ -265,6 +275,16 @@ pop; pop; int 1 // But it's ok in appl2, because the same account is used, even though the // foreign-asset is not repeated in appl2. logic.TestApps(t, sources, txntest.Group(&appl0, &appl2), 9, nil) + + // when running all three, appl2 can't read the holding of asset in tx0 and addr in tx1 + sources = []string{"", "", "gtxn 1 Sender; gtxn 0 Assets 0; asset_holding_get AssetBalance"} + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1, &appl2), 9, nil, + logic.NewExpect(2, "invalid Holding access")) // note that the error message is for Holding, not specialized + // same test of account in array of tx1 rather than Sender + appl1.Accounts = []basics.Address{{7, 7}} + sources = []string{"", "", "gtxn 1 Accounts 1; gtxn 0 Assets 0; asset_holding_get AssetBalance"} + logic.TestApps(t, sources, txntest.Group(&appl0, &appl1, &appl2), 9, nil, + logic.NewExpect(2, "invalid Holding access")) // note that the error message is for Holding, not specialized } // TestBetterHoldingErrors confirms that we get specific errors about the missing From 0eb3923c6667c91c1352033cda46818cb886a39d Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 4 Apr 2023 15:32:41 -0400 Subject: [PATCH 28/29] fix long standing typo --- daemon/algod/api/algod.oas2.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json index 8788711dc7..3f63053140 100644 --- a/daemon/algod/api/algod.oas2.json +++ b/daemon/algod/api/algod.oas2.json @@ -2981,7 +2981,7 @@ "$ref": "#/definitions/ApplicationStateSchema" }, "global-state": { - "description": "\\[gs\\] global schema", + "description": "\\[gs\\] global state", "$ref": "#/definitions/TealKeyValueStore" } } From 530c76a60a564c7ad539bbd7ab0f68b95f120a7b Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Fri, 7 Apr 2023 09:14:19 -0400 Subject: [PATCH 29/29] Final (?) cr fixes and an obscure bug fix I already have tests for the bug fix (the change is in EvalContext.availableAccount(), but they rely on a fair bit of code I have in the next PR, so I will include it there. --- data/transactions/logic/assembler_test.go | 2 +- data/transactions/logic/eval.go | 5 +++++ data/transactions/logic/evalStateful_test.go | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index bfea7c3504..843fb19aee 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -458,7 +458,7 @@ var nonsense = map[uint64]string{ 7: v7Nonsense, 8: v8Nonsense, 9: v9Nonsense, - 10: v9Nonsense, + 10: v10Nonsense, } var compiled = map[uint64]string{ diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 2604d2b9bf..14ab082c50 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -4044,6 +4044,11 @@ func (cx *EvalContext) accountReference(account stackValue) (basics.Address, uin } func (cx *EvalContext) availableAccount(addr basics.Address) bool { + _, err := cx.txn.Txn.IndexByAddress(addr, cx.txn.Txn.Sender) + if err == nil { + return true + } + // Allow an address for an app that was created in group if cx.version >= createdResourcesVersion { for _, appID := range cx.available.createdApps { diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index 053931df47..ae573724bf 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -548,7 +548,7 @@ func TestMinBalance(t *testing.T) { ledger.NewAsset(tx.Sender, 7, basics.AssetParams{Total: 1000}) testApp(t, "int 0; min_balance; int 2002; ==", ep) - // no test in more detail v4 and on + // now test in more detail v4 and on testLogicRange(t, 4, 0, func(t *testing.T, ep *EvalParams, tx *transactions.Transaction, ledger *Ledger) { ledger.NewAccount(tx.Sender, 234) ledger.NewAccount(tx.Receiver, 123) @@ -2040,7 +2040,7 @@ byte "myval" ` if ep.Proto.LogicSigVersion < sharedResourcesVersion { - // 100 is in the ForeignApps array, name it by slot + // 101 is in the ForeignApps array, name it by slot source = strings.ReplaceAll(source, "OTHERAPP", "int 2") } else { // use the actual app number, slots no longer allowed