summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Lee <64482439+algojohnlee@users.noreply.github.com>2023-07-24 21:01:51 -0400
committerGitHub <noreply@github.com>2023-07-24 21:01:51 -0400
commita0e31a77656a9ab2ea32140e5b4cb15d371a2973 (patch)
tree5e362776b4df6541fdfdfcfbc9b7cf6f0704d851
parent18a33c9c091becb4a9c70a212121b88080e0ed85 (diff)
parentfbdcd057a4236acf4fc85945ed967625c844f9db (diff)
Merge pull request #5601 from Algo-devops-service/relbeta3.17.0v3.17.0-beta
-rw-r--r--.circleci/config.yml11
-rw-r--r--catchup/catchpointService.go6
-rw-r--r--catchup/catchpointService_test.go6
-rw-r--r--catchup/service.go25
-rw-r--r--cmd/catchpointdump/file.go15
-rw-r--r--cmd/goal/clerk.go12
-rw-r--r--components/mocks/mockCatchpointCatchupAccessor.go7
-rw-r--r--daemon/algod/api/algod.oas2.json66
-rw-r--r--daemon/algod/api/algod.oas3.yml67
-rw-r--r--daemon/algod/api/server/v2/generated/data/routes.go362
-rw-r--r--daemon/algod/api/server/v2/generated/experimental/routes.go354
-rw-r--r--daemon/algod/api/server/v2/generated/model/types.go36
-rw-r--r--daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go364
-rw-r--r--daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go510
-rw-r--r--daemon/algod/api/server/v2/generated/participating/private/routes.go366
-rw-r--r--daemon/algod/api/server/v2/generated/participating/public/routes.go386
-rw-r--r--daemon/algod/api/server/v2/handlers_test.go6
-rw-r--r--daemon/algod/api/server/v2/utils.go60
-rw-r--r--data/basics/teal.go4
-rw-r--r--data/transactions/logic/assembler.go10
-rw-r--r--data/transactions/logic/assembler_test.go8
-rw-r--r--data/transactions/logic/box.go62
-rw-r--r--data/transactions/logic/debugger.go8
-rw-r--r--data/transactions/logic/eval.go1063
-rw-r--r--data/transactions/logic/evalStateful_test.go4
-rw-r--r--data/transactions/logic/frames.go32
-rw-r--r--data/transactions/logic/opcodes.go168
-rw-r--r--data/transactions/logic/pairing.go30
-rw-r--r--docker/Dockerfile2
-rw-r--r--docker/build/Dockerfile2
-rw-r--r--docker/build/Dockerfile-deploy2
-rw-r--r--docker/build/cicd.alpine.Dockerfile3
-rw-r--r--docker/build/cicd.centos.Dockerfile2
-rw-r--r--docker/build/cicd.centos8.Dockerfile1
-rw-r--r--docker/build/cicd.ubuntu.Dockerfile2
-rw-r--r--docs/follower_node.md1
-rw-r--r--ledger/catchpointtracker.go41
-rw-r--r--ledger/catchpointtracker_test.go20
-rw-r--r--ledger/catchpointwriter.go23
-rw-r--r--ledger/catchpointwriter_test.go22
-rw-r--r--ledger/catchupaccessor.go69
-rw-r--r--ledger/simulation/simulation_eval_test.go613
-rw-r--r--ledger/simulation/trace.go48
-rw-r--r--ledger/simulation/tracer.go98
-rw-r--r--ledger/store/trackerdb/sqlitedriver/catchpoint.go4
-rw-r--r--ledger/store/trackerdb/sqlitedriver/sqlitedriver.go38
-rw-r--r--ledger/store/trackerdb/store.go8
-rw-r--r--protocol/codec_tester.go3
-rw-r--r--rpcs/ledgerService.go25
-rwxr-xr-xscripts/check_deps.sh6
-rw-r--r--scripts/release/common/docker/centos.Dockerfile2
-rw-r--r--scripts/release/common/docker/centos8.Dockerfile2
-rwxr-xr-xscripts/release/common/setup.sh2
-rw-r--r--shared/pingpong/pingpong.go20
-rw-r--r--test/e2e-go/restAPI/restClient_test.go1060
-rw-r--r--test/heapwatch/client_ram_report.py91
-rwxr-xr-xtest/heapwatch/plot_crr_csv.py71
-rwxr-xr-xtest/scripts/e2e_client_runner.py18
-rwxr-xr-xtest/scripts/e2e_subs/e2e-app-simulate.sh47
-rw-r--r--test/scripts/e2e_subs/tealprogs/stack-scratch.teal45
-rw-r--r--tools/block-generator/Makefile4
-rw-r--r--tools/block-generator/README.md30
-rw-r--r--tools/block-generator/generator/config_test.go2
-rw-r--r--tools/block-generator/generator/test_scenario.yml (renamed from tools/block-generator/test_config.yml)0
-rwxr-xr-xtools/block-generator/run_tests.sh97
-rw-r--r--tools/block-generator/scripts/print_tps.py (renamed from tools/block-generator/print_tps.py)0
-rwxr-xr-xtools/block-generator/scripts/run_postgres.sh (renamed from tools/block-generator/run_postgres.sh)2
-rw-r--r--tools/block-generator/scripts/run_runner.py (renamed from tools/block-generator/run_runner.py)2
-rwxr-xr-xtools/block-generator/scripts/run_runner.sh (renamed from tools/block-generator/run_runner.sh)14
69 files changed, 4342 insertions, 2248 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 192921564..d2898da25 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -47,19 +47,20 @@ executors:
resource_class: arm.large
mac_amd64_medium:
macos:
- xcode: 13.2.1
- resource_class: medium
+ xcode: 14.2.0
+ resource_class: macos.x86.medium.gen2
environment:
HOMEBREW_NO_AUTO_UPDATE: "true"
mac_amd64_large:
macos:
- xcode: 13.2.1
- resource_class: large
+ xcode: 14.2.0
+ # Since they removed the large class for amd64, we will use medium here too.
+ resource_class: macos.x86.medium.gen2
environment:
HOMEBREW_NO_AUTO_UPDATE: "true"
mac_arm64: &executor-mac-arm64
machine: true
- resource_class: algorand/macstadium-m1-macos11
+ resource_class: algorand/macstadium-m1
environment:
HOMEBREW_NO_AUTO_UPDATE: "true"
# these are required b/c jobs explicitly assign sizes to the executors
diff --git a/catchup/catchpointService.go b/catchup/catchpointService.go
index 24fdd9bc0..801901048 100644
--- a/catchup/catchpointService.go
+++ b/catchup/catchpointService.go
@@ -38,10 +38,6 @@ const (
// noPeersAvailableSleepInterval is the sleep interval that the node would wait if no peers are available to download the next block from.
// this delay is intended to ensure to give the network package some time to download the list of relays.
noPeersAvailableSleepInterval = 50 * time.Millisecond
-
- // checkLedgerDownloadRetries is the number of times the catchpoint service will attempt to HEAD request the
- // ledger from peers when `Start`ing catchpoint catchup
- checkLedgerDownloadRetries = 10
)
// CatchpointCatchupNodeServices defines the external node support needed
@@ -826,7 +822,7 @@ func (cs *CatchpointCatchupService) checkLedgerDownload() error {
}
peerSelector := makePeerSelector(cs.net, []peerClass{{initialRank: peerRankInitialFirstPriority, peerClass: network.PeersPhonebookRelays}})
ledgerFetcher := makeLedgerFetcher(cs.net, cs.ledgerAccessor, cs.log, cs, cs.config)
- for i := 0; i < checkLedgerDownloadRetries; i++ {
+ for i := 0; i < cs.config.CatchupLedgerDownloadRetryAttempts; i++ {
psp, peerError := peerSelector.getNextPeer()
if peerError != nil {
return err
diff --git a/catchup/catchpointService_test.go b/catchup/catchpointService_test.go
index de91b456e..48cea110d 100644
--- a/catchup/catchpointService_test.go
+++ b/catchup/catchpointService_test.go
@@ -27,6 +27,7 @@ import (
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/ledger"
+ "github.com/algorand/go-algorand/ledger/ledgercore"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/test/partitiontest"
)
@@ -76,6 +77,11 @@ func (m *catchpointCatchupAccessorMock) Ledger() (l ledger.CatchupAccessorClient
return m.l
}
+// GetVerifyData returns the balances hash, spver hash and totals used by VerifyCatchpoint
+func (m *catchpointCatchupAccessorMock) GetVerifyData(ctx context.Context) (balancesHash crypto.Digest, spverHash crypto.Digest, totals ledgercore.AccountTotals, err error) {
+ return crypto.Digest{}, crypto.Digest{}, ledgercore.AccountTotals{}, nil
+}
+
// TestCatchpointServicePeerRank ensures CatchpointService does not crash when a block fetched
// from the local ledger and not from network when ranking a peer
func TestCatchpointServicePeerRank(t *testing.T) {
diff --git a/catchup/service.go b/catchup/service.go
index 5a25a8c9b..5c08e60e3 100644
--- a/catchup/service.go
+++ b/catchup/service.go
@@ -20,6 +20,7 @@ import (
"context"
"errors"
"fmt"
+ "strings"
"sync"
"sync/atomic"
"time"
@@ -744,17 +745,19 @@ func (s *Service) fetchRound(cert agreement.Certificate, verifier *agreement.Asy
if cert.Round == fetchedCert.Round &&
cert.Proposal.BlockDigest != fetchedCert.Proposal.BlockDigest &&
fetchedCert.Authenticate(*block, s.ledger, verifier) == nil {
- s := "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
- s += "!!!!!!!!!! FORK DETECTED !!!!!!!!!!!\n"
- s += "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
- s += "fetchRound called with a cert authenticating block with hash %v.\n"
- s += "We fetched a valid cert authenticating a different block, %v. This indicates a fork.\n\n"
- s += "Cert from our agreement service:\n%#v\n\n"
- s += "Cert from the fetcher:\n%#v\n\n"
- s += "Block from the fetcher:\n%#v\n\n"
- s += "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
- s += "!!!!!!!!!! FORK DETECTED !!!!!!!!!!!\n"
- s += "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+ var builder strings.Builder
+ builder.WriteString("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
+ builder.WriteString("!!!!!!!!!! FORK DETECTED !!!!!!!!!!!\n")
+ builder.WriteString("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
+ builder.WriteString("fetchRound called with a cert authenticating block with hash %v.\n")
+ builder.WriteString("We fetched a valid cert authenticating a different block, %v. This indicates a fork.\n\n")
+ builder.WriteString("Cert from our agreement service:\n%#v\n\n")
+ builder.WriteString("Cert from the fetcher:\n%#v\n\n")
+ builder.WriteString("Block from the fetcher:\n%#v\n\n")
+ builder.WriteString("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
+ builder.WriteString("!!!!!!!!!! FORK DETECTED !!!!!!!!!!!\n")
+ builder.WriteString("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
+ s := builder.String()
s = fmt.Sprintf(s, cert.Proposal.BlockDigest, fetchedCert.Proposal.BlockDigest, cert, fetchedCert, block)
fmt.Println(s)
logging.Base().Error(s)
diff --git a/cmd/catchpointdump/file.go b/cmd/catchpointdump/file.go
index e99a0b406..2e3580b76 100644
--- a/cmd/catchpointdump/file.go
+++ b/cmd/catchpointdump/file.go
@@ -35,6 +35,7 @@ import (
"github.com/algorand/avm-abi/apps"
cmdutil "github.com/algorand/go-algorand/cmd/util"
"github.com/algorand/go-algorand/config"
+ "github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/ledger"
@@ -48,11 +49,13 @@ import (
var catchpointFile string
var outFileName string
var excludedFields = cmdutil.MakeCobraStringSliceValue(nil, []string{"version", "catchpoint"})
+var printDigests bool
func init() {
fileCmd.Flags().StringVarP(&catchpointFile, "tar", "t", "", "Specify the catchpoint file (either .tar or .tar.gz) to process")
fileCmd.Flags().StringVarP(&outFileName, "output", "o", "", "Specify an outfile for the dump ( i.e. tracker.dump.txt )")
fileCmd.Flags().BoolVarP(&loadOnly, "load", "l", false, "Load only, do not dump")
+ fileCmd.Flags().BoolVarP(&printDigests, "digest", "d", false, "Print balances and spver digests")
fileCmd.Flags().VarP(excludedFields, "exclude-fields", "e", "List of fields to exclude from the dump: ["+excludedFields.AllowedString()+"]")
}
@@ -206,6 +209,18 @@ func loadCatchpointIntoDatabase(ctx context.Context, catchupAccessor ledger.Catc
header, err := tarReader.Next()
if err != nil {
if err == io.EOF {
+ if printDigests {
+ err = catchupAccessor.BuildMerkleTrie(ctx, func(uint64, uint64) {})
+ if err != nil {
+ return fileHeader, err
+ }
+ var balanceHash, spverHash crypto.Digest
+ balanceHash, spverHash, _, err = catchupAccessor.GetVerifyData(ctx)
+ if err != nil {
+ return fileHeader, err
+ }
+ fmt.Printf("accounts digest=%s, spver digest=%s\n\n", balanceHash, spverHash)
+ }
return fileHeader, nil
}
return fileHeader, err
diff --git a/cmd/goal/clerk.go b/cmd/goal/clerk.go
index e4a33c941..d84d43bec 100644
--- a/cmd/goal/clerk.go
+++ b/cmd/goal/clerk.go
@@ -74,6 +74,8 @@ var (
simulateAllowMoreOpcodeBudget bool
simulateExtraOpcodeBudget uint64
simulateEnableRequestTrace bool
+ simulateStackChange bool
+ simulateScratchChange bool
)
func init() {
@@ -97,7 +99,7 @@ func init() {
sendCmd.Flags().Uint64VarP(&amount, "amount", "a", 0, "The amount to be transferred (required), in microAlgos")
sendCmd.Flags().StringVarP(&closeToAddress, "close-to", "c", "", "Close account and send remainder to this address")
sendCmd.Flags().StringVar(&rekeyToAddress, "rekey-to", "", "Rekey account to the given spending key/address. (Future transactions from this account will need to be signed with the new key.)")
- sendCmd.Flags().StringVarP(&programSource, "from-program", "F", "", "Program source to use as account logic")
+ sendCmd.Flags().StringVarP(&programSource, "from-program", "F", "", "Program source file to use as account logic")
sendCmd.Flags().StringVarP(&progByteFile, "from-program-bytes", "P", "", "Program binary to use as account logic")
sendCmd.Flags().StringSliceVar(&argB64Strings, "argb64", nil, "Base64 encoded args to pass to transaction logic")
sendCmd.Flags().StringVarP(&logicSigFile, "logic-sig", "L", "", "LogicSig to apply to transaction")
@@ -117,7 +119,7 @@ func init() {
signCmd.Flags().StringVarP(&txFilename, "infile", "i", "", "Partially-signed transaction file to add signature to")
signCmd.Flags().StringVarP(&outFilename, "outfile", "o", "", "Filename for writing the signed transaction")
signCmd.Flags().StringVarP(&signerAddress, "signer", "S", "", "Address of key to sign with, if different from transaction \"from\" address due to rekeying")
- signCmd.Flags().StringVarP(&programSource, "program", "p", "", "Program source to use as account logic")
+ signCmd.Flags().StringVarP(&programSource, "program", "p", "", "Program source file to use as account logic")
signCmd.Flags().StringVarP(&logicSigFile, "logic-sig", "L", "", "LogicSig to apply to transaction")
signCmd.Flags().StringSliceVar(&argB64Strings, "argb64", nil, "Base64 encoded args to pass to transaction logic")
signCmd.Flags().StringVarP(&protoVersion, "proto", "P", "", "Consensus protocol version id string")
@@ -163,6 +165,8 @@ func init() {
simulateCmd.Flags().BoolVar(&simulateAllowMoreOpcodeBudget, "allow-more-opcode-budget", false, "Apply max extra opcode budget for apps per transaction group (default 320000) during simulation")
simulateCmd.Flags().Uint64Var(&simulateExtraOpcodeBudget, "extra-opcode-budget", 0, "Apply extra opcode budget for apps per transaction group during simulation")
simulateCmd.Flags().BoolVar(&simulateEnableRequestTrace, "trace", false, "Enable simulation time execution trace of app calls")
+ simulateCmd.Flags().BoolVar(&simulateStackChange, "stack", false, "Report stack change during simulation time")
+ simulateCmd.Flags().BoolVar(&simulateScratchChange, "scratch", false, "Report scratch change during simulation time")
}
var clerkCmd = &cobra.Command{
@@ -1365,6 +1369,8 @@ func decodeTxnsFromFile(file string) []transactions.SignedTxn {
func traceCmdOptionToSimulateTraceConfigModel() simulation.ExecTraceConfig {
return simulation.ExecTraceConfig{
- Enable: simulateEnableRequestTrace,
+ Enable: simulateEnableRequestTrace,
+ Stack: simulateStackChange,
+ Scratch: simulateScratchChange,
}
}
diff --git a/components/mocks/mockCatchpointCatchupAccessor.go b/components/mocks/mockCatchpointCatchupAccessor.go
index 0b45f42be..f488879e7 100644
--- a/components/mocks/mockCatchpointCatchupAccessor.go
+++ b/components/mocks/mockCatchpointCatchupAccessor.go
@@ -19,9 +19,11 @@ package mocks
import (
"context"
+ "github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/ledger"
+ "github.com/algorand/go-algorand/ledger/ledgercore"
)
// MockCatchpointCatchupAccessor is a dummy CatchpointCatchupAccessor implementation which doesn't do anything.
@@ -67,6 +69,11 @@ func (m *MockCatchpointCatchupAccessor) GetCatchupBlockRound(ctx context.Context
return basics.Round(0), nil
}
+// GetVerifyData returns the balances hash, spver hash and totals used by VerifyCatchpoint
+func (m *MockCatchpointCatchupAccessor) GetVerifyData(ctx context.Context) (balancesHash crypto.Digest, spverHash crypto.Digest, totals ledgercore.AccountTotals, err error) {
+ return crypto.Digest{}, crypto.Digest{}, ledgercore.AccountTotals{}, nil
+}
+
// VerifyCatchpoint verifies that the catchpoint is valid by reconstructing the label.
func (m *MockCatchpointCatchupAccessor) VerifyCatchpoint(ctx context.Context, blk *bookkeeping.Block) (err error) {
return nil
diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json
index 7bad1a032..5adf01711 100644
--- a/daemon/algod/api/algod.oas2.json
+++ b/daemon/algod/api/algod.oas2.json
@@ -3108,6 +3108,29 @@
}
}
},
+ "AvmValue": {
+ "description": "Represents an AVM value.",
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "description": "value type. Value `1` refers to **bytes**, value `2` refers to **uint64**",
+ "type": "integer"
+ },
+ "bytes": {
+ "description": "bytes value.",
+ "type": "string",
+ "format": "byte"
+ },
+ "uint": {
+ "description": "uint value.",
+ "type": "integer",
+ "x-algorand-format": "uint64"
+ }
+ }
+ },
"StateDelta": {
"description": "Application state delta.",
"type": "array",
@@ -3491,6 +3514,14 @@
"enable": {
"description": "A boolean option for opting in execution trace features simulation endpoint.",
"type": "boolean"
+ },
+ "stack-change": {
+ "description": "A boolean option enabling returning stack changes together with execution trace during simulation.",
+ "type": "boolean"
+ },
+ "scratch-change": {
+ "description": "A boolean option enabling returning scratch slot changes together with execution trace during simulation.",
+ "type": "boolean"
}
}
},
@@ -3853,6 +3884,23 @@
}
}
},
+ "ScratchChange": {
+ "description": "A write operation into a scratch slot.",
+ "type": "object",
+ "required": [
+ "slot",
+ "new-value"
+ ],
+ "properties": {
+ "slot": {
+ "description": "The scratch slot written.",
+ "type": "integer"
+ },
+ "new-value": {
+ "$ref": "#/definitions/AvmValue"
+ }
+ }
+ },
"SimulationOpcodeTraceUnit": {
"description": "The set of trace information and effect from evaluating a single opcode.",
"type": "object",
@@ -3864,12 +3912,30 @@
"description": "The program counter of the current opcode being evaluated.",
"type": "integer"
},
+ "scratch-changes": {
+ "description": "The writes into scratch slots.",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ScratchChange"
+ }
+ },
"spawned-inners": {
"description": "The indexes of the traces for inner transactions spawned by this opcode, if any.",
"type": "array",
"items": {
"type": "integer"
}
+ },
+ "stack-pop-count": {
+ "description": "The number of deleted stack values by this opcode.",
+ "type": "integer"
+ },
+ "stack-additions": {
+ "description": "The values added by this opcode to the stack.",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/AvmValue"
+ }
}
}
},
diff --git a/daemon/algod/api/algod.oas3.yml b/daemon/algod/api/algod.oas3.yml
index b32dda4c7..f29797fe4 100644
--- a/daemon/algod/api/algod.oas3.yml
+++ b/daemon/algod/api/algod.oas3.yml
@@ -1400,6 +1400,30 @@
],
"type": "object"
},
+ "AvmValue": {
+ "description": "Represents an AVM value.",
+ "properties": {
+ "bytes": {
+ "description": "bytes value.",
+ "format": "byte",
+ "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$",
+ "type": "string"
+ },
+ "type": {
+ "description": "value type. Value `1` refers to **bytes**, value `2` refers to **uint64**",
+ "type": "integer"
+ },
+ "uint": {
+ "description": "uint value.",
+ "type": "integer",
+ "x-algorand-format": "uint64"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ },
"Box": {
"description": "Box name and its content.",
"properties": {
@@ -1910,6 +1934,23 @@
],
"type": "object"
},
+ "ScratchChange": {
+ "description": "A write operation into a scratch slot.",
+ "properties": {
+ "new-value": {
+ "$ref": "#/components/schemas/AvmValue"
+ },
+ "slot": {
+ "description": "The scratch slot written.",
+ "type": "integer"
+ }
+ },
+ "required": [
+ "new-value",
+ "slot"
+ ],
+ "type": "object"
+ },
"SimulateRequest": {
"description": "Request type for simulation endpoint.",
"properties": {
@@ -1966,6 +2007,14 @@
"enable": {
"description": "A boolean option for opting in execution trace features simulation endpoint.",
"type": "boolean"
+ },
+ "scratch-change": {
+ "description": "A boolean option enabling returning scratch slot changes together with execution trace during simulation.",
+ "type": "boolean"
+ },
+ "stack-change": {
+ "description": "A boolean option enabling returning stack changes together with execution trace during simulation.",
+ "type": "boolean"
}
},
"type": "object"
@@ -2057,12 +2106,30 @@
"description": "The program counter of the current opcode being evaluated.",
"type": "integer"
},
+ "scratch-changes": {
+ "description": "The writes into scratch slots.",
+ "items": {
+ "$ref": "#/components/schemas/ScratchChange"
+ },
+ "type": "array"
+ },
"spawned-inners": {
"description": "The indexes of the traces for inner transactions spawned by this opcode, if any.",
"items": {
"type": "integer"
},
"type": "array"
+ },
+ "stack-additions": {
+ "description": "The values added by this opcode to the stack.",
+ "items": {
+ "$ref": "#/components/schemas/AvmValue"
+ },
+ "type": "array"
+ },
+ "stack-pop-count": {
+ "description": "The number of deleted stack values by this opcode.",
+ "type": "integer"
}
},
"required": [
diff --git a/daemon/algod/api/server/v2/generated/data/routes.go b/daemon/algod/api/server/v2/generated/data/routes.go
index b9b56a883..af7c75e2d 100644
--- a/daemon/algod/api/server/v2/generated/data/routes.go
+++ b/daemon/algod/api/server/v2/generated/data/routes.go
@@ -114,185 +114,189 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
+ "H4sIAAAAAAAC/+x9a5PcNpLgX0HUboRsXbFbL3vHipjYa0u2t8+yrXC3vbcr6TwoMqsK0yyAA4DdVdbp",
+ "v18gEyBBEqxidbelmYv5JHURj0QikchM5OP9LFebSkmQ1syev59VXPMNWND4F89zVUubicL9VYDJtais",
+ "UHL2PHxjxmohV7P5TLhfK27Xs/lM8g20bVz/+UzD32qhoZg9t7qG+czka9hwN7DdVa51M9I2W6nMD3FG",
+ "Q5y/nH3Y84EXhQZjhlD+JMsdEzIv6wKY1VwanrtPht0Iu2Z2LQzznZmQTElgasnsutOYLQWUhTkJi/xb",
+ "DXoXrdJPPr6kDy2ImVYlDOF8oTYLISFABQ1QzYYwq1gBS2y05pa5GRysoaFVzADX+ZotlT4AKgERwwuy",
+ "3syev5kZkAVo3K0cxDX+d6kBfofMcr0CO3s3Ty1uaUFnVmwSSzv32Ndg6tIahm1xjStxDZK5Xifsh9pY",
+ "tgDGJfv52xfs6dOnX7mFbLi1UHgiG11VO3u8Juo+ez4ruIXweUhrvFwpzWWRNe1//vYFzn/hFzi1FTcG",
+ "0oflzH1h5y/HFhA6JkhISAsr3IcO9bseiUPR/ryApdIwcU+o8b1uSjz/J92VnNt8XSkhbWJfGH5l9DnJ",
+ "w6Lu+3hYA0CnfeUwpd2gbx5lX717/3j++NGHf3lzlv23//OLpx8mLv9FM+4BDCQb5rXWIPNdttLA8bSs",
+ "uRzi42dPD2at6rJga36Nm883yOp9X+b6Euu85mXt6ETkWp2VK2UY92RUwJLXpWVhYlbL0rEpN5qndiYM",
+ "q7S6FgUUc8d9b9YiX7OcGxoC27EbUZaOBmsDxRitpVe35zB9iFHi4LoVPnBBf7/IaNd1ABOwRW6Q5aUy",
+ "kFl14HoKNw6XBYsvlPauMsddVuxyDQwndx/oskXcSUfTZbljFve1YNwwzsLVNGdiyXaqZje4OaW4wv5+",
+ "NQ5rG+aQhpvTuUfd4R1D3wAZCeQtlCqBS0ReOHdDlMmlWNUaDLtZg137O0+DqZQ0wNTir5Bbt+3/6+Kn",
+ "H5nS7Acwhq/gNc+vGMhcFVCcsPMlk8pGpOFpCXHoeo6tw8OVuuT/apSjiY1ZVTy/St/opdiIxKp+4Fux",
+ "qTdM1psFaLel4QqximmwtZZjANGIB0hxw7fDSS91LXPc/3bajiznqE2YquQ7RNiGb//8aO7BMYyXJatA",
+ "FkKumN3KUTnOzX0YvEyrWhYTxBzr9jS6WE0FuVgKKFgzyh5I/DSH4BHyOHha4SsCJwwyCk4zywFwJGwT",
+ "NONOt/vCKr6CiGRO2C+eueFXq65ANoTOFjv8VGm4Fqo2TacRGHHq/RK4VBaySsNSJGjswqPDMRhq4znw",
+ "xstAuZKWCwmFY84ItLJAzGoUpmjC/frO8BZfcANfPhu749uvE3d/qfq7vnfHJ+02NsroSCauTvfVH9i0",
+ "ZNXpP0E/jOc2YpXRz4ONFKtLd9ssRYk30V/d/gU01AaZQAcR4W4yYiW5rTU8fysfur9Yxi4slwXXhftl",
+ "Qz/9UJdWXIiV+6mkn16plcgvxGoEmQ2sSYULu23oHzdemh3bbVKveKXUVV3FC8o7iutix85fjm0yjXks",
+ "YZ412m6seFxugzJybA+7bTZyBMhR3FXcNbyCnQYHLc+X+M92ifTEl/p3909Vla63rZYp1Do69lcymg+8",
+ "WeGsqkqRc4fEn/1n99UxASBFgrctTvFCff4+ArHSqgJtBQ3KqyorVc7LzFhucaR/1bCcPZ/9y2lrfzml",
+ "7uY0mvyV63WBnZzISmJQxqvqiDFeO9HH7GEWjkHjJ2QTxPZQaBKSNtGRknAsuIRrLu1Jq7J0+EFzgN/4",
+ "mVp8k7RD+O6pYKMIZ9RwAYYkYGr4wLAI9QzRyhCtKJCuSrVofvjsrKpaDOL3s6oifKD0CAIFM9gKY83n",
+ "uHzenqR4nvOXJ+y7eGwUxZUsd+5yIFHD3Q1Lf2v5W6yxLfk1tCM+MAy3U+kTtzUBDU7Mvw+KQ7VirUon",
+ "9RykFdf4P3zbmMzc75M6/2OQWIzbceJCRctjjnQc/CVSbj7rUc6QcLy554Sd9fvejmzcKGmCuRWt7N1P",
+ "GncPHhsU3mheEYD+C92lQqKSRo0I1jty04mMLglzdIYjWkOobn3WDp6HJCRICj0Yvi5VfvUf3Kzv4cwv",
+ "wljD44fTsDXwAjRbc7M+maWkjPh4taNNOWKuISr4bBFNddIs8b6Wd2BpBbc8WpqHNy2WEOqxHzI90And",
+ "5Sf8Dy+Z++zOtmP9NOwJu0QGZug4+0eGwmn7pCDQTK4BWiEU25CCz5zWfRSUL9rJ0/s0aY++IZuC3yG/",
+ "CNwhtb33Y/C12qZg+FptB0dAbcHcB324cVCMtLAxE+B76SFTuP8efVxrvhsiGceegmS3QCe6GjwNMr7x",
+ "3SytcfZsofTtuE+PrUjWmpwZd6NGzHfeQxI2ravMk2LCbEUNegO1r3z7mUZ/+BTGOli4sPwPwIJxo94H",
+ "FroD3TcW1KYSJdwD6a+TTH/BDTx9wi7+4+yLx09+e/LFl44kK61Wmm/YYmfBsM+8bsaM3ZXw+XBlqB3V",
+ "pU2P/uWzYKjsjpsax6ha57Dh1XAoMoCSCETNmGs3xFoXzbjqBsAph/MSHCcntDOy7TvQXgrjJKzN4l42",
+ "YwxhRTtLwTwkBRwkpmOX106zi5eod7q+D1UWtFY6YV/DI2ZVrsrsGrQRKvGa8tq3YL5FEG+r/u8ELbvh",
+ "hrm50fRbSxQoEpRlt3I636ehL7eyxc1ezk/rTazOzztlX7rID5ZEwyrQmd1KVsCiXnU0oaVWG8ZZgR3x",
+ "jv4OLIoCl2IDF5Zvqp+Wy/tRFRUOlFDZxAaMm4lRCyfXG8iVJE+IA9qZH3UKevqICSY6Ow6Ax8jFTuZo",
+ "Z7yPYzuuuG6ExEcPs5N5pMU6GEsoVh2yvLu2OoYOmuqBSYDj0PEKP6Oh4yWUln+r9GVrCfxOq7q6dyGv",
+ "P+fU5XC/GG9KKVzfoEMLuSq73jcrB/tJao2fZEEvwvH1a0DokSJfidXaRmrFa63U8v5hTM2SAhQ/kFJW",
+ "uj5D1exHVThmYmtzDyJYO1jL4RzdxnyNL1RtGWdSFYCbX5u0cDbir4EPxfi+bWN5z65Jz1qAo66c1261",
+ "dcXw9XZwX7QdM57TCc0QNWbk7ap5dKRWNB35ApQaeLFjCwDJ1MI/EPmnK1wkx6dnG8QbLxom+EUHrkqr",
+ "HIyBIvOGqYOghXZ0ddg9eELAEeBmFmYUW3J9Z2Cvrg/CeQW7DB0lDPvs+1/N558AXqssLw8gFtuk0Nuo",
+ "+f4VcAj1tOn3EVx/8pjsuAYW7hVmFUqzJVgYQ+FROBndvz5Eg128O1quQeN73B9K8WGSuxFQA+ofTO93",
+ "hbauRtz/vHrrJDy3YZJLFQSr1GAlNzY7xJZdo44O7lYQccIUJ8aBRwSvV9xYekMWskDTF10nOA8JYW6K",
+ "cYBH1RA38q9BAxmOnbt7UJraNOqIqatKaQtFag0Stnvm+hG2zVxqGY3d6DxWsdrAoZHHsBSN75FFKyEE",
+ "cds8tXgni+Hi8EHC3fO7JCo7QLSI2AfIRWgVYTd2gRoBRJgW0UQ4wvQop/G7ms+MVVXluIXNatn0G0PT",
+ "BbU+s7+0bYfExW17bxcKDHpe+fYe8hvCLDm/rblhHg624VdO9kAzCD12D2F2hzEzQuaQ7aN8VPFcq/gI",
+ "HDykdbXSvICsgJLvhoP+Qp8Zfd43AO54q+4qCxl5MaU3vaXk4DSyZ2iF45mU8MjwC8vdEXSqQEsgvveB",
+ "kQvAsVPMydPRg2YonCu5RWE8XDZtdWJEvA2vlXU77ukBQfYcfQrAI3hohr49KrBz1uqe/Sn+C4yfoJEj",
+ "jp9kB2ZsCe34Ry1gxIbqHcSj89Jj7z0OnGSbo2zsAB8ZO7IjBt3XXFuRiwp1ne9hd++qX3+C5DMjK8By",
+ "UULBog+kBlZxf0b+N/0xb6cKTrK9DcEfGN8SyymFQZGnC/wV7FDnfk2OnZGp4z502cSo7n7ikiGgwV3M",
+ "ieBxE9jy3JY7J6jZNezYDWhgpl5shLXksN1Vda2qsniA5LvGnhn9Ix45RYYdmPKqeIFDRcsbbsV8RjrB",
+ "fvgue4pBBx1eF6iUKidYyAbISEIwyd+DVcrtuvC+48F7OFBSB0jPtPEFt7n+H5gOmnEF7L9UzXIuUeWq",
+ "LTQyjdIoKKAA6WZwIlgzp/fsaDEEJWyANEn88vBhf+EPH/o9F4Yt4SYEXLiGfXQ8fIh2nNfK2M7hugd7",
+ "qDtu54nrAx983MXntZA+TznsWeBHnrKTr3uDN69E7kwZ4wnXLf/ODKB3MrdT1h7TyDSvChx30ltONHRq",
+ "3bjvF2JTl9zex6sVXPMyU9egtSjgICf3Ewslv7nm5U9NNwwmgdzRaA5ZjiEQE8eCS9eHoiYO6YatN5nY",
+ "bKAQ3EK5Y5WGHMjL34l8poHxhJH/X77mcoWSvlb1yjug0TjIqWtDNhVdy8EQSWnIbmWG1ukU5/ZOxyHQ",
+ "w8lBwJ0u1jdtk+Zxw5v5fGzPlCs1Ql7f1J983ZrPRlVVh9TrVlUl5HSjVSZw8Y6gFuGnnXjiGwiizgkt",
+ "Q3zF2+JOgdvcP8bW3g6dgnI4ceQS134c84pzenK5uwdphQZiGioNBu+W2L5k6KtaxpFp/vIxO2NhMzTB",
+ "U9ffRo7fz6OKnpKlkJBtlIRdMhhbSPgBPyaPE95vI51R0hjr21ceOvD3wOrOM4Ua74pf3O3+Ce0/NZlv",
+ "lb6vt0wacLJcPuHp8OA7uZ/ytg+cvCwTb4I+bqXPAMy8iZMXmnFjVC5Q2DovzJwOmn9G9EEuXfS/brxx",
+ "7+Hs9cftPX7FIZFo3IWyYpzlpUDTr5LG6jq3byVH41K01ITXUtCix82NL0KTtH0zYX70Q72VHD3WGpNT",
+ "0tNiCQn7yrcAwepo6tUKjO0pKUuAt9K3EpLVUlica+OOS0bnpQKNrkMn1HLDd2zpaMIq9jtoxRa17Yrt",
+ "GJZlrChL/xLnpmFq+VZyy0rgxrIfhLzc4nDhtT4cWQn2RumrBgvp230FEowwWdq76jv6io6vfvlr7wSL",
+ "YfT0md5u3Pht7NYObU9taPj/+ezfn785y/6bZ78/yr76H6fv3j/78PnDwY9PPvz5z/+3+9PTD3/+/N//",
+ "NbVTAfZU0JCH/PylV2nPX6Le0j7eDGD/aIb7jZBZkshiN4webbHPMEDWE9DnXauWXcNbabfSEdI1L0Xh",
+ "eMttyKF/wwzOIp2OHtV0NqJnxQprPVIbuAOXYQkm02ONt5aihg6J6fA8fE30EXd4Xpa1pK0M0jdFnwTH",
+ "MLWcNyGYlJ3lOcP4vDUPXo3+zydffDmbt3F1zffZfOa/vktQsii2qejJArYpJc8fEDwYDwyr+M6ATXMP",
+ "hD3pA0dOGfGwG9gsQJu1qD4+pzBWLNIcLvj0e2PRVp5LcrZ35wffJnf+yUMtPz7cVgMUUNl1KmtDR1DD",
+ "Vu1uAvT8RSqtrkHOmTiBk76xpnD6ovfGK4EvMXsAap9qijbUnAMitEAVEdbjhUyyiKToB0Uez60/zGf+",
+ "8jf3rg75gVNw9edsHiLD31axB999c8lOPcM0DyiQl4aOQi8TqrSPLup4EjluRrlqSMh7K9/Kl7AUUrjv",
+ "z9/Kglt+uuBG5Oa0NqC/5iWXOZysFHseApZecsvfyoGkNZpOKgoVY1W9KEXOrmKFpCVPShEyHOHt2ze8",
+ "XKm3b98NnCqG6oOfKslfaILMCcKqtplPcJBpuOE69WhlmgB3HJkymOyblYRsVZNlMyRQ8OOneR6vKtMP",
+ "dB0uv6pKt/yIDI0P43RbxoxVOsgiTkAhaHB/f1T+YtD8JthVagOG/WXDqzdC2ncse1s/evQUWCfy8y/+",
+ "ync0uatgsnVlNBC3b1TBhZNaCVureVbxVept7O3bNxZ4hbuP8vIGbRxlybBbJ+I0eNTjUO0CAj7GN4Dg",
+ "ODp6Dhd3Qb1CMqv0EvATbiG2ceJG+2J/2/2KYlBvvV29ONbBLtV2nbmznVyVcSQedqbJcbNyQlZwozBi",
+ "hdqqTwe0AJavIb/yeVpgU9ndvNM9eOp4QTOwDmEogw9FkGEOCXxZWACrq4J7UZzLXT+Y34C1wR/4Z7iC",
+ "3aVqU1AcE73fDSY3YwcVKTWSLh2xxsfWj9HffO8Ohop9VYWYbAzOC2TxvKGL0Gf8IJPIew+HOEUUnWDn",
+ "MURwnUAEEf8ICm6xUDfenUg/tTynZSzo5ktk8wm8n/kmrfLkPbfi1aDVnb5vANOBqRvDFtzJ7cpnsqKA",
+ "6YiL1YavYERCjh93JoYldx6EcJBD917yplPL/oU2uG+SIFPjzK05SSngvjhSQWWm568XZqL3Q/8ygQkq",
+ "PcIWJYpJjWMjMR2uO49slHFvDLQ0AYOWrcARwOhiJJZs1tyEJFuYiyyc5UkywB+YAGBf2pfzyNUsSjjW",
+ "JHUJPLd/TgfapU/+EjK+hDQvsWo5IWWLk/DRuz21HUqiAFRACStaODUOhNImI2g3yMHx03JZCgksS3mt",
+ "RWbQ6Jrxc4CTjx8yRhZ4NnmEFBlHYOO7OA7MflTx2ZSrY4CUPpkCD2Pji3r0N6TjvsiP24k8qnIsXIy8",
+ "auWBA3Dv6tjcXz2HWxyGCTlnjs1d89KxOa/xtYMMso+g2NrLNeI9Mz4fE2f3PIDQxXLUmugqus1qYpkp",
+ "AJ0W6PZAvFDbjAI/kxLvYrtw9J50bccw1NTBpDwvDwxbqC16++DVQq7UB2AZhyOAEWn4W2GQXrHf2G1O",
+ "wOybdr80laJCgyTjzXkNuYyJE1OmHpFgxsjlsyh1y60A6Bk72jzIXvk9qKR2xZPhZd7eavM2JVmIGkod",
+ "/7EjlNylEfwNrTBNspXXfYklaafoOq1088xEImSK6B2bGD7SDJ+CDJSASkHWEaKyq9TLqdNtAG+ci9At",
+ "Ml5gNhsud59HnlAaVsJYaI3owU/iU5gnOSbRU2o5vjpb6aVb389KNdcUPSNix84yP/oK0JV4KbSxGb5A",
+ "JJfgGn1rUKn+1jVNy0pdXytKOSuKNG/Aaa9glxWirNP06uf9/qWb9seGJZp6gfxWSHJYWWCK5KQH5p6p",
+ "yUl374Jf0YJf8Xtb77TT4Jq6ibUjl+4c/yDnosd597GDBAGmiGO4a6Mo3cMgo8jZIXeM5Kbojf9kn/V1",
+ "cJiKMPZBr50Qvzt2R9FIybVEBoO9qxD4TOTEEmGjDMPDkNaRM8CrShTbni2URh3VmPlRBo+Ql62HBdxd",
+ "P9gBDER2z1RUjQbTTcHXCviUK7qTAedkEmYuu4nyYoYQTyVMqHQwRFQTdXcIV5fAy+9h96tri8uZfZjP",
+ "7mY6TeHaj3gA16+b7U3iGZ/myZTWeQk5EuW8qrS65mXmDcxjpKnVtSdNbB7s0R+Z1aXNmJffnL167cH/",
+ "MJ/lJXCdNaLC6KqwXfUPsyrK9jdyQEImdafzBZmdRMlo85sUZbFR+mYNPiV1JI0Ocme2Dw7RUfRG6mXa",
+ "Q+igydm/jdAS97yRQNU8kbTmO3oh6b6K8GsuymA3C9COePPg4qYlYE1yhXiAO7+uRI9k2b2ym8HpTp+O",
+ "lroO8KR4rj1JszeUF94wJftP6OjzvKv8q/uGY+ZLsooMmZOsN2hJyEwp8rSNVS6MIw5Jb2euMcPGI8Ko",
+ "G7EWI0+xshbRWK7ZlNw2PSCjOZLINMn0Oi3uFsrX/Kml+FsNTBQgrfuk8VT2DiqmSfHW9uF16mSH4Vx+",
+ "YLLQt8PfRcaIs772bzwEYr+AEb/UDcB92ajMYaGNRcr9ED1JHPHgH884uBL3PNZ7+vDUTM6L6+6LW1yi",
+ "Z8j/HGFQrvbD9YGC8urTz47Mkaz3I0y21Op3SOt5qB4nApZCnluBXi6/QxzoEFe56LCYxrrTli1qZx/d",
+ "7jHpJrZCdZ0URqgedz56lsOEm8FCzSVtNQWSdHzd0gQTe5We0vgtwXiYB564Jb9Z8FQ2UidkOJjO2gfg",
+ "ji3dKhY6B9ybJtqCZmfRW3LTVlAwegW6jSUcJra5pcBA004WFVrJAKk2lgnm9P5XGpUYppY3XFIVF9eP",
+ "jpLvbYCMX67XjdKYSsKkzf4F5GLDy7TkUORDE28hVoIKlNQGogoYfiAq/kRU5KuINDFEHjXnS/ZoHpXh",
+ "8btRiGthxKIEbPGYWiy4QU7eGKKaLm55IO3aYPMnE5qva1loKOzaEGKNYo1Qh+pN83i1AHsDINkjbPf4",
+ "K/YZPtsZcQ2fOyz6+3n2/PFXaHSlPx6lLgBfYGYfNymQnfynZydpOsZ3SxrDMW4/6kky6p4qzI0zrj2n",
+ "ibpOOUvY0vO6w2dpwyVfQdpTZHMAJuqLu4mGtB5eZEHlkYzVaseETc8Pljv+NOJ97tgfgcFytdkIu/GP",
+ "O0ZtHD215S1o0jAc1VrymYkDXOEjvpFW4Ymop0R+XKMp3W+pVeNL9o98A120zhmn/CGlaL0XQr50dh7S",
+ "E2Gq5iZDM+HGzeWWjmIOOjMsWaWFtKhY1HaZ/Ynla6557tjfyRi42eLLZ4n01N00qfI4wD863jUY0Ndp",
+ "1OsRsg8yhO/LPpNKZhvHUYrP22iP6FSOPuamn+3G3g73Dz1VKHOjZKPkVnfIjUec+k6EJ/cMeEdSbNZz",
+ "FD0evbKPTpm1TpMHr90O/fLzKy9lbJRO5Rxsj7uXODRYLeAafffSm+TGvONe6HLSLtwF+k/78hBEzkgs",
+ "C2c5qQhcb34NZtlRn30nwv/6gy+nOJC9R/wMyJGg6fORYxGSLkkkoaEbH8NVs788/gvTsPQFEh8+RKAf",
+ "Ppx7Ye4vT7qfiUk9fJjOxJO0abhfWywcxQr7mQpc39Qefq0SFoaQ9r55DfHxBgkLzxirdR/cUV74oeas",
+ "m2L849+F9+PJln6tTJ+Ct2/f4JeAB/yjj4hPfORxA1t/DFrJCKFEJRaSJFM03yM/Cc6+VtuphNPjpIF4",
+ "/g5QlERJLcri1zZ6t8faNJf5OvnuuXAdf2tr7TWLo8ObTAG55lJCmRyOdIbfgm6R0H7+qqbOsxFyYtt+",
+ "UQ1abm9xLeBdMANQYUKHXmFLN0GM1W5gZON4X65UwXCeNt9ge1yHxViilPl/q8HY1IWFH8j5D+3bjh1Q",
+ "xnYGskCrwgn7jsppr4F1kkmhNh+yfXQj3+uqVLyYYxaSy2/OXjGalfpQxSjKGL9CZba7ip5dM0qlOs2N",
+ "PBR/Soe4TB9nv8+9W7WxWZPgPRVE7Fq0KehF760H1dwYOyfsZVQYl+KN3RAMk9DojdPMm9FIxkWacP+x",
+ "ludrVN07rHWc5KeXOghUaaLyok2ZsCa/KJ47B7evdkDFDuZM2TXoG2GoijJcQzduuQni96ajEMfcXZ6u",
+ "pSRKOTnilmuyiR6L9gAcXZHhOSgJWQ/xRypuVCnk2MoPF9grme6sX0ZiUFeUomCb8k+hOn7OpZIix2Rj",
+ "qSval1ue8lY6IS9b3xgfjrg/oYnDlSxe0bhTeiyOlrMIjNAjbvhYE311m0rUQX9arOu75patwBrP2aCY",
+ "hxos3l4spAGfLxaLc0d8UunO+zNyyKRLQ9Y8fR1JRhg+NWIA+NZ9+9GbhzCu4EpIVAQ92rzgRxZdrAZr",
+ "nfYoLFspMH493Rhy88b1OcFw6gK2705C9Vgcg55v3bLJV2E41FnwXPCeAq7tC9fWJ7lqfu54qtOkZ1Xl",
+ "Jx2v0JOUB+xWjiI48QKdhSfACLnN+PFoe8htr8sR3qeO0OAaHRagwnt4QBhNtZpeJTQntBJFYQtGrn7J",
+ "TBdCJsB4JSS0tY0TF0SevBJwY/C8jvQzueaWRMBJPO0SeEkKdYKhGeufqO46VD/Fl0MJrjHMMb6NbaGd",
+ "EcbRNGgFNy53TUllR92RMPECa7l7RA7L5qBU5YWoAiNPeoV0UozDMe5Qqqt7AYzo+R2ZiLpjvrtjb6Kx",
+ "YOJFXazAZrwoUul7v8avDL+yokbJAbaQ102a16piOebO6SYTGlKbnyhX0tSbPXOFBnecLqpMlaCGuDpW",
+ "2GEMVlrs8N9UjtPxnfHOOke7iwbPnOK4DFpD99eU1OtoOjNilU3HBN4pd0dHO/XtCL3tf6+UXqpVF5BP",
+ "YbYb4XLxHqX42zfu4ogzbAwS99LV0iTAQOdMFeqJotrYhG53uRJeZYNMvvgo2NQr3G+AGK88OMfLb8RF",
+ "OzbC0v1KhskxR+18NK6AWx/haDnby4JGo8bIy6tn1h1a2Mc8u8ix6/7MoX6texEaXAaHAH0f/JFZxYV3",
+ "oWiZxRCzPnJhGEsyxae53eD+Inw8wKjF7vvrMd/9kFAPv/crk12BT3tQabgWqg7OCcF7LaiE9GunzlcT",
+ "PZFc/9DwilN9WnPoqPH20leIoGV6nfz7X8nXkYG0evd3YModbPqg5tlQ2iXzVNuENcnFJyUb79yKU5JN",
+ "pvIaetmwU3XtQM24AVm9nCIODGvAzWfnxVEXZio35oxGSR27dEW38dRhbbowPGKVMqLN8Z8q9TbRTfQS",
+ "q7VFqc+GYwUfrWvILRZ2aH1PNMAxidDcZFHx2H+mEBtRpxtvWp85bF+6sGE1hwN3/CCiL4pKpUz4J9OT",
+ "Y501HobIpzGj9Qqkr9/ajdWZHDGwXEJuxfWBCMr/XIOMovPmwS5DddijgErReKBjAp7jrY4tQPsCHPfC",
+ "EyXCvDM4Y/FTV7B7YFiHGpKp+efhqr1N7hXEAHKHzJGIMikPHjIke6cKYRrKQCwEjznqDm0Wu9GqXlE8",
+ "8C3nCiTpLo42RnjPlOmyQpPmcl2PipxHZ+qxIMthVZJx/eMlFoExTcXNkLsl1tLZ+TDD5Y3P/YLxrs3b",
+ "ScgCAyb8FoLbaZZSXEFcdwxfqm64LkKLpOklWHWyPffRIDIyVNToA71sZhatf/MwFi6RMw292PNSOTEi",
+ "GwsF6LoUN/44Dww5TlEKf3SWdnAtQfv6jCj/lspAZlXwh94Hxz5UkHfYrZBgRvOUEnCj2YN+btMjYb5m",
+ "jtmCuHcKixfINGy4g05HSYzG59yH7Bf0PQR/hXy9By1MDb0eLhwRPNuFGSAxpvol87fl4aCy2xibhJRU",
+ "A9ykMhpJ0N3XkEqros7pgo4PRmOQm5wvbA8rSdpp8uEqezpCFJl7BbtTUoJCxY2wgzHQJDkR6FEmjN4m",
+ "36v5zaTgXt0LeJ/ScjWfVUqV2chjx/kwDVOf4q9EfgUFczdF8AAdqYLEPkMbe/OafbPehbRDVQUSis9P",
+ "GDuT5HMfHra7ecB7k8sHdt/8W5y1qCkzmjeqnbyVaedlzFmm78jNwjD7eZgBx+ruOBUNciDJz3YkBZTm",
+ "N4maYCdTtfLhU3O/TlNLVARFSia5oBerF3jQU4ajGy0seMcGusTdRjL/0sVMqVJOgnAzLX6/cSh1O1Kq",
+ "kYs7ngwBsiCnxHk2UPjBkwhoajAdcBRqfITa8jWtn9BQPCpLdZPhMcqaJHYppcu1694SIW1v282R2wIi",
+ "hyNuvASxY2tesFxpDXncIx2nQ0BtlIasVOh/lHoaXVonEG7QOV+yUq2YqpyeT7kgwyNSsrZSNNd91ZGi",
+ "mHOCIKMXr5GsHmB8jLkHlxoP4d1Tyun4MlGX64ThCjcs7NbRtaA8wR1dwiUCcwKhHzbanaVKXXXX1S+6",
+ "NlYC0aqNyNPo/sdy1xl1sklRbwoVPosyRXFiMzzgMU9pXmfx9AzRDJIvyiSv9sfPv1Ihnbv/4hXeH5ct",
+ "wTOXEX6WqNlMbDjLRy+LHgAIKYUW2VpT6uWYlTcF3dSKQhHxja0P6ESGg64Md4PNjXCfQH3YTyipim+J",
+ "g9Dsji9IF2KpRw5V0kliv08CVQFdTPVMaDLNT+SfEQDjvgodGCZ5LBwLxhKr6mY8geTzRk+cd4qei94l",
+ "EbKAEjPMOdmJ1sDc2LUGH9tL5T979cYqbtdBbnTNh9YcWcAWDAbeUtEkbsj2GGygvvZoXyBXVVbCNXRc",
+ "OHzAcZ3nYIy4hrhuKXVmBUCFLwJ9PTXlmxBfhz3lxa89i163p2A3qc0QYmmn2AFVJalYbWVGx8RMPUoO",
+ "omtR1LyDP3OHCo5jxRsT93WA9d00TnE0k0gvbh+LOOhNhDSfPJcy7UwUx7s3ZkicrWieK4gI25NtKn4j",
+ "x9X2IVG24ub02qcRYr/ZQo5Xd9db5u44YTgYM71cFqNypm52+Lbmn1Eq20dkg0qwaT0MQiXvOO1U0BV8",
+ "38TVSIZqYRIDCNPyBvS9hda3M2q24TtWiOUSND3FGctlwXURNxeS5aAtF5Ld8J25vU7moNU1zA+qZY5T",
+ "46CBWaUUNLQqEyDlziv8YyrTBFUH310Tag5d21aNFakd7Eo6GIhvnWqIXpEjROBTUaBiSIdVSZTK2YZf",
+ "wZHzGPE77J8GE0R5y71VOOuUKT7spfWfEHV44H+Rwu6ldpL3+m6q9I5IxBhoUK5aZwbanCENpjyLL6lU",
+ "Wuxd3K88EvaajJo0H4xkUu2K6SO7iGYd75Yey+RmurrasRyl/JeJh2fI280edwUwUa223Jubh2LJ4FIg",
+ "pMy99/eRUgupC7woxFhp/DX4dOX+bHWnbUyAbpzplu7I3pWGqFJVlk95wyqgBMdqSGvxkHZhnGAjq/ID",
+ "10LykhzhSl0VSS2RP+CxINEAvX2aC3He90PrCgHNwcO6y3mtUYy94bvDKTFbQSDtwk8jBx08eCY1UPsN",
+ "piNuqJRPMuPkMQJiguukqtkMc/3d/2IoNqV9Pf/jluPfx9ILOJNeUcIahfvorVWlAqkkaI3LXYpphBeg",
+ "WyxwTD6c4F19b1vVnJY/YoOSl+TtUkBPAm3oaZvAZlSzfb/zU5whvk1boMlhG50lgkba5xc/tJrqtOrx",
+ "ocMB8GKfuKh+fHie9OB84vj/HxqkREt5N0YJneUfcrPzC2xV+2iLvLRsLVC9DooZ7e5L5ENpXjSuiSNX",
+ "88CDEdPBO/GsLBOejyTAU3HxiHDcvaivefnxvRexTsAZ4gOKn8f9HWL3txjJhEpzu+DbV3zS3JGr2/1N",
+ "LV+jt+V/gtuj5LXgh/I2gwHzR/WLl/Q0tQyVhq9Bshsckyy2j79kC59gqtKQC9O3RdyEIoCNtxfWxPUB",
+ "z1t7wL3s0Dp/VfYOZLwMpj32Y1tQDF9fVrKFsD2in5ipjJzcJJWnqG9AFgn8pXhUnOn5wHVx1YnhaKW6",
+ "6EZTGu45liOKyjwylmOYw3rq8ihewV06tYHhOiff1h3cJi7qdm1TA5EmZ4PCak9T4ofSmZtcdwxgupcU",
+ "TkclcPoDQpcIR34MP2+KYn4dS2ZBCRtG8qb09qMWZXGIMDpZcD40NfIxz8tvPl/ax71LAwTkTj08qr5k",
+ "9R1iQAgxibV2Jo+mivLbTEht47slEtmgq1Jea2F3mMY9aLzit2SQ1XeNw74P+GiMqP7us+oKmkIArXt/",
+ "bcLt+p3iJd5HZNuV7hZS5Qn7Zss3VeltIuzPDxb/Bk//9Kx49PTxvy3+9OiLRzk8++KrR4/4V8/446+e",
+ "PoYnf/ri2SN4vPzyq8WT4smzJ4tnT559+cVX+dNnjxfPvvzq3x44PuRAJkBnIWno7H9nZ+VKZWevz7NL",
+ "B2yLE16J72FH5csdGYfC6DzHkwgbLsrZ8/DT/wwn7CRXm3b48OvM5yScra2tzPPT05ubm5O4y+kK/Xkz",
+ "q+p8fRrmGVROP3t93ryb07ML7mjjMUW+OJ4UzvDbz99cXLKz1+cnLcHMns8enTw6eezGVxVIXonZ89lT",
+ "/AlPzxr3/dQT2+z5+w/z2ekaeInhL+6PDVgt8vBJAy92/v/mhq9WoE98tXj30/WT0yBWnL73fs0f9n07",
+ "jQsvnr7vuH8XB3piYbbT9yHf+P7WnYTe3u096jARin3NTheYAm9qUzBR4/GloLJhTt+juDz6+6nP2ZX+",
+ "iGoLnYfTECORbtnB0nu7dbD2euTc5uu6On2P/0H6jMCiCPlTu5Wn+EBw+r6zGv95sJru7233uMX1RhUQ",
+ "AFbLJdVP2Pf59D39G00E2wq0cIIfRqX4Xyl68BSzmu6GP++kN6+XkIr5+EUaIMU0ZOzaybyNYW2O7HkR",
+ "Gl/sZB4k1BAJjgfxyaNHNP0z/M/M50vsRUac+hM3sSRRNyYd2VzvnbeBF1NgY1AAwvD448FwLjFoyvEv",
+ "Rvz5w3z2xcfEwrnT2SUvGbak6Z9+xE0AfS1yYJewqZTmWpQ79ots8mxFOdhTFHgl1Y0MkLvLvd5suN6h",
+ "0LxR12CYT+8eESfT4MQUes7DJ6eWhvF24SuDxnysfjebUwaCdygY2ZSMEOw1w5mCraodvHsqvjt4Jqbv",
+ "Qlf03BPyMQnOAw8dNPxQbh7ub9j7/vMETfUgtUGzfzKCfzKCe2QEttZy9IhG9xfGLULlPTxznq9hHz8Y",
+ "3pbRBT+rVMr9/WIPs/DZAcd4xUWXV0QFFp+/mZaV1z8wkO24ACN80SnUG5xQ3Ir1uuFI4cyjD0e01/vK",
+ "Znx493dxv7/gMpznzo5T6AzXpQDdUAGXw4SN/+QC/99wAco8y2lf58xCWZr47FuFZ58eW3w4uqRHsIl8",
+ "oOqVw079fPq+W0C2oySYdW0LdRP1RZM5vfcMdQdf+rv39+kNFzZbKu1D0bHAz7CzBV6e+ryTvV/bVE+D",
+ "L5i/KvoxdvBM/nra1E9Lfuyro6mvXh0baRR8xMLn1jQVm3qQQzZGnjfvHH/C6hyeebaWi+enpxjeuVbG",
+ "ns4+zN/3rBrxx3cNSYR03LNKi2vM7vXuw/8LAAD//9Mad+9M2AAA",
}
// 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 ed192588b..47db46103 100644
--- a/daemon/algod/api/server/v2/generated/experimental/routes.go
+++ b/daemon/algod/api/server/v2/generated/experimental/routes.go
@@ -75,181 +75,185 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
- "AAAA///KktDr7cgAAA==",
+ "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",
+ "1ZtnzgAA",
}
// 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 cddde547b..ae20c2896 100644
--- a/daemon/algod/api/server/v2/generated/model/types.go
+++ b/daemon/algod/api/server/v2/generated/model/types.go
@@ -407,6 +407,18 @@ type AssetParams struct {
UrlB64 *[]byte `json:"url-b64,omitempty"`
}
+// AvmValue Represents an AVM value.
+type AvmValue struct {
+ // Bytes bytes value.
+ Bytes *[]byte `json:"bytes,omitempty"`
+
+ // Type value type. Value `1` refers to **bytes**, value `2` refers to **uint64**
+ Type uint64 `json:"type"`
+
+ // Uint uint value.
+ Uint *uint64 `json:"uint,omitempty"`
+}
+
// Box Box name and its content.
type Box struct {
// Name \[name\] box name, base64 encoded
@@ -630,6 +642,15 @@ type PendingTransactionResponse struct {
Txn map[string]interface{} `json:"txn"`
}
+// ScratchChange A write operation into a scratch slot.
+type ScratchChange struct {
+ // NewValue Represents an AVM value.
+ NewValue AvmValue `json:"new-value"`
+
+ // Slot The scratch slot written.
+ Slot uint64 `json:"slot"`
+}
+
// SimulateRequest Request type for simulation endpoint.
type SimulateRequest struct {
// AllowEmptySignatures Allow transactions without signatures to be simulated as if they had correct signatures.
@@ -658,6 +679,12 @@ type SimulateRequestTransactionGroup struct {
type SimulateTraceConfig struct {
// Enable A boolean option for opting in execution trace features simulation endpoint.
Enable *bool `json:"enable,omitempty"`
+
+ // ScratchChange A boolean option enabling returning scratch slot changes together with execution trace during simulation.
+ ScratchChange *bool `json:"scratch-change,omitempty"`
+
+ // StackChange A boolean option enabling returning stack changes together with execution trace during simulation.
+ StackChange *bool `json:"stack-change,omitempty"`
}
// SimulateTransactionGroupResult Simulation result for an atomic transaction group
@@ -713,8 +740,17 @@ type SimulationOpcodeTraceUnit struct {
// Pc The program counter of the current opcode being evaluated.
Pc uint64 `json:"pc"`
+ // ScratchChanges The writes into scratch slots.
+ ScratchChanges *[]ScratchChange `json:"scratch-changes,omitempty"`
+
// SpawnedInners The indexes of the traces for inner transactions spawned by this opcode, if any.
SpawnedInners *[]uint64 `json:"spawned-inners,omitempty"`
+
+ // StackAdditions The values added by this opcode to the stack.
+ StackAdditions *[]AvmValue `json:"stack-additions,omitempty"`
+
+ // StackPopCount The number of deleted stack values by this opcode.
+ StackPopCount *uint64 `json:"stack-pop-count,omitempty"`
}
// SimulationTransactionExecTrace The execution trace of calling an app or a logic sig, containing the inner app call trace in a recursive way.
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 8c48f7975..08f34c9b0 100644
--- a/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go
+++ b/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go
@@ -130,186 +130,190 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
+ "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",
}
// 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 fb74d66b8..774d72558 100644
--- a/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go
+++ b/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go
@@ -702,259 +702,263 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
- "fAEA",
+ "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",
+ "Fs2Hdx/+/wAAAP//3P3na2WCAQA=",
}
// 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 323a358fa..77ebb098c 100644
--- a/daemon/algod/api/server/v2/generated/participating/private/routes.go
+++ b/daemon/algod/api/server/v2/generated/participating/private/routes.go
@@ -159,187 +159,191 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
var swaggerSpec = []string{
"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",
- "19/9FroBEiRBiZqZ2LtV+cseEY9Go9HoF7rfz3K1qZQEac3s6ftZxTXfgAWNf/E8V7W0mSjcXwWYXIvK",
- "CiVnT8M3ZqwWcjWbz4T7teJ2PZvPJN9A28b1n880/LMWGorZU6trmM9MvoYNdwPbXeVaNyNts5XK/BBn",
- "NMT589mHPR94UWgwZgjlT7LcMSHzsi6AWc2l4bn7ZNi1sGtm18Iw35kJyZQEppbMrjuN2VJAWZiTsMh/",
- "1qB30Sr95ONL+tCCmGlVwhDOZ2qzEBICVNAA1WwIs4oVsMRGa26Zm8HBGhpaxQxwna/ZUukDoBIQMbwg",
- "683s6ZuZAVmAxt3KQVzhf5ca4DfILNcrsLN389TilhZ0ZsUmsbRzj30Npi6tYdgW17gSVyCZ63XCfqiN",
- "ZQtgXLJX3z5jjx8//sotZMOthcIT2eiq2tnjNVH32dNZwS2Ez0Na4+VKaS6LrGn/6ttnOP9rv8Cprbgx",
- "kD4sZ+4LO38+toDQMUFCQlpY4T50qN/1SByK9ucFLJWGiXtCje90U+L5P+mu5Nzm60oJaRP7wvAro89J",
- "HhZ138fDGgA67SuHKe0GffMg++rd+4fzhw8+/Mebs+x//J9fPP4wcfnPmnEPYCDZMK+1BpnvspUGjqdl",
- "zeUQH688PZi1qsuCrfkVbj7fIKv3fZnrS6zzipe1oxORa3VWrpRh3JNRAUtel5aFiVktS8em3Gie2pkw",
- "rNLqShRQzB33vV6LfM1ybmgIbMeuRVk6GqwNFGO0ll7dnsP0IUaJg+tG+MAF/esio13XAUzAFrlBlpfK",
- "QGbVgesp3DhcFiy+UNq7yhx3WbGLNTCc3H2gyxZxJx1Nl+WOWdzXgnHDOAtX05yJJdupml3j5pTiEvv7",
- "1TisbZhDGm5O5x51h3cMfQNkJJC3UKoELhF54dwNUSaXYlVrMOx6DXbt7zwNplLSAFOLf0Bu3bb/r9c/",
- "/ciUZj+AMXwFL3l+yUDmqoDihJ0vmVQ2Ig1PS4hD13NsHR6u1CX/D6McTWzMquL5ZfpGL8VGJFb1A9+K",
- "Tb1hst4sQLstDVeIVUyDrbUcA4hGPECKG74dTnqha5nj/rfTdmQ5R23CVCXfIcI2fPuXB3MPjmG8LFkF",
- "shByxexWjspxbu7D4GVa1bKYIOZYt6fRxWoqyMVSQMGaUfZA4qc5BI+Qx8HTCl8ROGGQUXCaWQ6AI2Gb",
- "oBl3ut0XVvEVRCRzwn72zA2/WnUJsiF0ttjhp0rDlVC1aTqNwIhT75fApbKQVRqWIkFjrz06HIOhNp4D",
- "b7wMlCtpuZBQOOaMQCsLxKxGYYom3K/vDG/xBTfw5ZOxO779OnH3l6q/63t3fNJuY6OMjmTi6nRf/YFN",
- "S1ad/hP0w3huI1YZ/TzYSLG6cLfNUpR4E/3D7V9AQ22QCXQQEe4mI1aS21rD07fyvvuLZey15bLgunC/",
- "bOinH+rSitdi5X4q6acXaiXy12I1gswG1qTChd029I8bL82O7TapV7xQ6rKu4gXlHcV1sWPnz8c2mcY8",
- "ljDPGm03VjwutkEZObaH3TYbOQLkKO4q7hpewk6Dg5bnS/xnu0R64kv9m/unqkrX21bLFGodHfsrGc0H",
- "3qxwVlWlyLlD4iv/2X11TABIkeBti1O8UJ++j0CstKpAW0GD8qrKSpXzMjOWWxzpPzUsZ09n/3Ha2l9O",
- "qbs5jSZ/4Xq9xk5OZCUxKONVdcQYL53oY/YwC8eg8ROyCWJ7KDQJSZvoSEk4FlzCFZf2pFVZOvygOcBv",
- "/EwtvknaIXz3VLBRhDNquABDEjA1vGdYhHqGaGWIVhRIV6VaND98dlZVLQbx+1lVET5QegSBghlshbHm",
- "c1w+b09SPM/58xP2XTw2iuJKljt3OZCo4e6Gpb+1/C3W2Jb8GtoR7xmG26n0iduagAYn5t8FxaFasVal",
- "k3oO0opr/FffNiYz9/ukzv8eJBbjdpy4UNHymCMdB3+JlJvPepQzJBxv7jlhZ/2+NyMbN0qaYG5EK3v3",
- "k8bdg8cGhdeaVwSg/0J3qZCopFEjgvWW3HQio0vCHJ3hiNYQqhuftYPnIQkJkkIPhq9LlV/+lZv1HZz5",
- "RRhrePxwGrYGXoBma27WJ7OUlBEfr3a0KUfMNUQFny2iqU6aJd7V8g4sreCWR0vz8KbFEkI99kOmBzqh",
- "u/yE/+Elc5/d2Xasn4Y9YRfIwAwdZ+9kKJy2TwoCzeQaoBVCsQ0p+Mxp3UdB+aydPL1Pk/boG7Ip+B3y",
- "i8AdUts7PwZfq20Khq/VdnAE1BbMXdCHGwfFSAsbMwG+5x4yhfvv0ce15rshknHsKUh2C3Siq8HTIOMb",
- "383SGmfPFkrfjPv02IpkrcmZcTdqxHznPSRh07rKPCkmzFbUoDdQ6+XbzzT6w6cw1sHCa8t/BywYN+pd",
- "YKE70F1jQW0qUcIdkP46yfQX3MDjR+z1X8++ePjo10dffOlIstJqpfmGLXYWDPvM62bM2F0Jnw9XhtpR",
- "Xdr06F8+CYbK7ripcYyqdQ4bXg2HIgMoiUDUjLl2Q6x10YyrbgCccjgvwHFyQjsj274D7bkwTsLaLO5k",
- "M8YQVrSzFMxDUsBBYjp2ee00u3iJeqfru1BlQWulE/Y1PGJW5arMrkAboRLelJe+BfMtgnhb9X8naNk1",
- "N8zNjabfWqJAkaAsu5XT+T4NfbGVLW72cn5ab2J1ft4p+9JFfrAkGlaBzuxWsgIW9aqjCS212jDOCuyI",
- "d/R3YFEUuBAbeG35pvppubwbVVHhQAmVTWzAuJkYtXByvYFcSYqEOKCd+VGnoKePmGCis+MAeIy83skc",
- "7Yx3cWzHFdeNkOj0MDuZR1qsg7GEYtUhy9trq2PooKnumQQ4Dh0v8DMaOp5Dafm3Sl+0lsDvtKqrOxfy",
- "+nNOXQ73i/GmlML1DTq0kKuyG32zcrCfpNb4SRb0LBxfvwaEHinyhVitbaRWvNRKLe8extQsKUDxAyll",
- "peszVM1+VIVjJrY2dyCCtYO1HM7RbczX+ELVlnEmVQG4+bVJC2cj8RroKEb/to3lPbsmPWsBjrpyXrvV",
- "1hVD7+3gvmg7ZjynE5ohasyI76pxOlIrmo5iAUoNvNixBYBkauEdRN51hYvk6Hq2QbzxomGCX3TgqrTK",
- "wRgoMm+YOghaaEdXh92DJwQcAW5mYUaxJde3Bvby6iCcl7DLMFDCsM++/8V8/gngtcry8gBisU0KvY2a",
- "772AQ6inTb+P4PqTx2THNbBwrzCrUJotwcIYCo/Cyej+9SEa7OLt0XIFGv1xvyvFh0luR0ANqL8zvd8W",
- "2roaCf/z6q2T8NyGSS5VEKxSg5Xc2OwQW3aNOjq4W0HECVOcGAceEbxecGPJhyxkgaYvuk5wHhLC3BTj",
- "AI+qIW7kX4IGMhw7d/egNLVp1BFTV5XSForUGiRs98z1I2ybudQyGrvReaxitYFDI49hKRrfI4tWQgji",
- "tnG1+CCL4eLQIeHu+V0SlR0gWkTsA+R1aBVhNw6BGgFEmBbRRDjC9Cinibuaz4xVVeW4hc1q2fQbQ9Nr",
- "an1mf27bDomL2/beLhQYjLzy7T3k14RZCn5bc8M8HGzDL53sgWYQcnYPYXaHMTNC5pDto3xU8Vyr+Agc",
- "PKR1tdK8gKyAku+Gg/5Mnxl93jcA7nir7ioLGUUxpTe9peQQNLJnaIXjmZTwyPALy90RdKpASyC+94GR",
- "C8CxU8zJ09G9ZiicK7lFYTxcNm11YkS8Da+UdTvu6QFB9hx9CsAjeGiGvjkqsHPW6p79Kf4bjJ+gkSOO",
- "n2QHZmwJ7fhHLWDEhuoDxKPz0mPvPQ6cZJujbOwAHxk7siMG3ZdcW5GLCnWd72F356pff4Kkm5EVYLko",
- "oWDRB1IDq7g/o/ib/pg3UwUn2d6G4A+Mb4nllMKgyNMF/hJ2qHO/pMDOyNRxF7psYlR3P3HJENAQLuZE",
- "8LgJbHluy50T1OwaduwaNDBTLzbCWgrY7qq6VlVZPEDSr7FnRu/Eo6DIsANTvIqvcahoecOtmM9IJ9gP",
- "30VPMeigw+sClVLlBAvZABlJCCbFe7BKuV0XPnY8RA8HSuoA6Zk2enCb6/+e6aAZV8D+W9Us5xJVrtpC",
- "I9MojYICCpBuBieCNXP6yI4WQ1DCBkiTxC/37/cXfv++33Nh2BKuw4ML17CPjvv30Y7zUhnbOVx3YA91",
- "x+08cX2gw8ddfF4L6fOUw5EFfuQpO/myN3jjJXJnyhhPuG75t2YAvZO5nbL2mEamRVXguJN8OdHQqXXj",
- "vr8Wm7rk9i68VnDFy0xdgdaigIOc3E8slPzmipc/Nd3wMQnkjkZzyHJ8AjFxLLhwfejVxCHdsI0mE5sN",
- "FIJbKHes0pADRfk7kc80MJ4wiv/L11yuUNLXql75ADQaBzl1bcimoms5GCIpDdmtzNA6neLcPug4PPRw",
- "chBwp4v1TdukeVzzZj7/tmfKlRohr2/qT3q35rNRVdUh9apVVQk53dcqE7h4R1CL8NNOPNEHgqhzQssQ",
- "X/G2uFPgNvf3sbW3Q6egHE4chcS1H8ei4pyeXO7uQFqhgZiGSoPBuyW2Lxn6qpbxyzR/+ZidsbAZmuCp",
- "668jx+/VqKKnZCkkZBslYZd8jC0k/IAfk8cJ77eRzihpjPXtKw8d+HtgdeeZQo23xS/udv+E9l1N5lul",
- "78qXSQNOlssnuA4P+sn9lDd1cPKyTPgE/buVPgMw8+advNCMG6NygcLWeWHmdNC8G9E/cumi/2UTjXsH",
- "Z68/bs/5FT+JROMulBXjLC8Fmn6VNFbXuX0rORqXoqUmopaCFj1ubnwWmqTtmwnzox/qreQYsdaYnJKR",
- "FktI2Fe+BQhWR1OvVmBsT0lZAryVvpWQrJbC4lwbd1wyOi8VaAwdOqGWG75jS0cTVrHfQCu2qG1XbMdn",
- "WcaKsvSeODcNU8u3kltWAjeW/SDkxRaHC976cGQl2GulLxsspG/3FUgwwmTp6Krv6CsGvvrlr30QLD6j",
- "p8/ku3Hjt2+3dmh7ap+G/5/P/uvpm7Psf3j224Psq//v9N37Jx8+vz/48dGHv/zl/3Z/evzhL5//13+m",
- "dirAnno05CE/f+5V2vPnqLe0zpsB7B/NcL8RMksSWRyG0aMt9hk+kPUE9HnXqmXX8FbarXSEdMVLUTje",
- "chNy6N8wg7NIp6NHNZ2N6FmxwlqP1AZuwWVYgsn0WOONpahhQGL6eR56E/2LOzwvy1rSVgbpm16fhMAw",
- "tZw3TzApO8tThu/z1jxENfo/H33x5Wzevqtrvs/mM//1XYKSRbFNvZ4sYJtS8vwBwYNxz7CK7wzYNPdA",
- "2JMxcBSUEQ+7gc0CtFmL6uNzCmPFIs3hQky/NxZt5bmkYHt3ftA3ufMuD7X8+HBbDVBAZdeprA0dQQ1b",
- "tbsJ0IsXqbS6Ajln4gRO+saawumLPhqvBL7E7AGofaop2lBzDojQAlVEWI8XMskikqIfFHk8t/4wn/nL",
- "39y5OuQHTsHVn7NxRIa/rWL3vvvmgp16hmnu0UNeGjp6eplQpf3rok4kkeNmlKuGhLy38q18Dkshhfv+",
- "9K0suOWnC25Ebk5rA/prXnKZw8lKsafhwdJzbvlbOZC0RtNJRU/FWFUvSpGzy1ghacmTUoQMR3j79g0v",
- "V+rt23eDoIqh+uCnSvIXmiBzgrCqbeYTHGQarrlOOa1M88AdR6YMJvtmJSFb1WTZDAkU/PhpnseryvQf",
- "ug6XX1WlW35EhsY/43RbxoxVOsgiTkAhaHB/f1T+YtD8OthVagOG/X3DqzdC2ncse1s/ePAYWOfl59/9",
- "le9oclfBZOvK6EPcvlEFF05qJWyt5lnFVynf2Nu3byzwCncf5eUN2jjKkmG3zovTEFGPQ7ULCPgY3wCC",
- "4+jXc7i419QrJLNKLwE/4RZiGydutB77m+5X9Ab1xtvVe8c62KXarjN3tpOrMo7Ew840OW5WTsgKYRRG",
- "rFBb9emAFsDyNeSXPk8LbCq7m3e6h0gdL2gG1iEMZfChF2SYQwI9CwtgdVVwL4pzues/5jdgbYgHfgWX",
- "sLtQbQqKY17vdx+Tm7GDipQaSZeOWONj68fob74PB0PFvqrCm2x8nBfI4mlDF6HP+EEmkfcODnGKKDqP",
- "nccQwXUCEUT8Iyi4wULdeLci/dTynJaxoJsvkc0n8H7mm7TKk4/cileDVnf6vgFMB6auDVtwJ7crn8mK",
- "HkxHXKw2fAUjEnLs3Jn4LLnjEMJBDt17yZtOLfsX2uC+SYJMjTO35iSlgPviSAWVmV68XpiJ/IfeM4EJ",
- "Kj3CFiWKSU1gIzEdrjtONsq4NwZamoBBy1bgCGB0MRJLNmtuQpItzEUWzvIkGeB3TACwL+3LeRRqFiUc",
- "a5K6BJ7bP6cD7dInfwkZX0Kal1i1nJCyxUn4GN2e2g4lUQAqoIQVLZwaB0JpkxG0G+Tg+Gm5LIUElqWi",
- "1iIzaHTN+DnAycf3GSMLPJs8QoqMI7DRL44Dsx9VfDbl6hggpU+mwMPY6FGP/ob0uy+K43Yij6ocCxcj",
- "Xq08cADuQx2b+6sXcIvDMCHnzLG5K146Nuc1vnaQQfYRFFt7uUZ8ZMbnY+LsHgcIXSxHrYmuopusJpaZ",
- "AtBpgW4PxAu1zejhZ1LiXWwXjt6Toe34DDV1MCnPyz3DFmqL0T54tVAo9QFYxuEIYEQa/lYYpFfsN3ab",
- "EzD7pt0vTaWo0CDJeHNeQy5j4sSUqUckmDFy+SxK3XIjAHrGjjYPsld+DyqpXfFkeJm3t9q8TUkWXg2l",
- "jv/YEUru0gj+hlaYJtnKy77EkrRTdINWunlmIhEyRfSOTQydNENXkIESUCnIOkJUdpnynDrdBvDGeR26",
- "RcYLzGbD5e7zKBJKw0oYC60RPcRJfArzJMckekotx1dnK71063ulVHNNkRsRO3aW+dFXgKHES6GNzdAD",
- "kVyCa/StQaX6W9c0LSt1Y60o5awo0rwBp72EXVaIsk7Tq5/3++du2h8blmjqBfJbISlgZYEpkpMRmHum",
- "piDdvQt+QQt+we9svdNOg2vqJtaOXLpz/Jucix7n3ccOEgSYIo7hro2idA+DjF7ODrljJDdFPv6TfdbX",
- "wWEqwtgHo3bC+92xO4pGSq4lMhjsXYVAN5ETS4SNMgwPn7SOnAFeVaLY9myhNOqoxsyPMniEvGw9LODu",
- "+sEOYCCye6Ze1Wgw3RR8rYBPuaI7GXBOJmHmopsoL2YI8VTChEoHQ0Q1r+4O4eoCePk97H5xbXE5sw/z",
- "2e1Mpylc+xEP4Ppls71JPKNrnkxpHU/IkSjnVaXVFS8zb2AeI02trjxpYvNgj/7IrC5txrz45uzFSw/+",
- "h/ksL4HrrBEVRleF7ap/m1VRtr+RAxIyqTudL8jsJEpGm9+kKIuN0tdr8CmpI2l0kDuzdThER9EbqZfp",
- "CKGDJmfvG6El7vGRQNW4SFrzHXlIul4RfsVFGexmAdqRaB5c3LQErEmuEA9wa+9K5CTL7pTdDE53+nS0",
- "1HWAJ8Vz7UmavaG88IYp2XehY8zzrvJe9w3HzJdkFRkyJ1lv0JKQmVLkaRurXBhHHJJ8Z64xw8Yjwqgb",
- "sRYjrlhZi2gs12xKbpsekNEcSWSaZHqdFncL5Wv+1FL8swYmCpDWfdJ4KnsHFdOkeGv78Dp1ssNwLj8w",
- "Wejb4W8jY8RZX/s3HgKxX8CIPXUDcJ83KnNYaGORcj9ELokjHP7xjIMrcY+z3tOHp2YKXlx3PW5xiZ4h",
- "/3OEQbnaD9cHCsqrTz87Mkey3o8w2VKr3yCt56F6nHiwFPLcCoxy+Q3ihw5xlYsOi2msO23Zonb20e0e",
- "k25iK1Q3SGGE6nHnI7ccJtwMFmouaavpIUkn1i1NMHFU6SmN3xKMh3kQiVvy6wVPZSN1QoaD6ax1AHds",
- "6Vax0Dng3jSvLWh2FvmSm7aCHqNXoNu3hMPENjcUGGjayaJCKxkg1cYywZz8f6VRiWFqec0lVXFx/ego",
- "+d4GyPjlel0rjakkTNrsX0AuNrxMSw5FPjTxFmIlqEBJbSCqgOEHouJPREW+ikjzhsij5nzJHsyjMjx+",
- "NwpxJYxYlIAtHlKLBTfIyRtDVNPFLQ+kXRts/mhC83UtCw2FXRtCrFGsEepQvWmcVwuw1wCSPcB2D79i",
- "n6Hbzogr+Nxh0d/Ps6cPv0KjK/3xIHUB+AIz+7hJgezkb56dpOkY/ZY0hmPcftST5Kt7qjA3zrj2nCbq",
- "OuUsYUvP6w6fpQ2XfAXpSJHNAZioL+4mGtJ6eJEFlUcyVqsdEzY9P1ju+NNI9LljfwQGy9VmI+zGO3eM",
- "2jh6astb0KRhOKq15DMTB7jCR/SRVsFF1FMiP67RlO631KrRk/0j30AXrXPGKX9IKdrohZAvnZ2H9ESY",
- "qrnJ0Ey4cXO5paOYg8EMS1ZpIS0qFrVdZn9m+Zprnjv2dzIGbrb48kkiPXU3Tao8DvCPjncNBvRVGvV6",
- "hOyDDOH7ss+kktnGcZTi8/a1R3QqR525abfdmO9w/9BThTI3SjZKbnWH3HjEqW9FeHLPgLckxWY9R9Hj",
- "0Sv76JRZ6zR58Nrt0M+vXngpY6N0Kudge9y9xKHBagFXGLuX3iQ35i33QpeTduE20H9az0MQOSOxLJzl",
- "lCLwtUpopyFlemNJ97HqCevA2DF1HxwZLPxQc9ZNT/3x+ejdREGlPV3BsD10bLkvAQ/4Rx8Rn5hccANb",
- "Xz6tZIRQovT8SZIpmu+Rj52zr9V2KuH0TmEgnn8BFCVRUouy+KV9+dmrfqC5zNdJn9nCdfy1rdPWLI7u",
- "wGT6wDWXEsrkcCRv/hrk0oTk/A81dZ6NkBPb9gsy0HJ7i2sB74IZgAoTOvQKW7oJYqx2H9U1QdvlShUM",
- "52lz1bXHdVjII0q3/s8ajE09UMIPFDiGtlHHDijbNwNZoEZ6wr6jUsxrYJ1ERKgJhkwR3VfTdVUqXswx",
- "g8XFN2cvGM1KfajaEGUbX6Ei1F1FzyYWpeGcFoIcCgeln0dMH2d/vLZbtbFZkxw89QDVtWjTl4uenwBV",
- "pBg7J+x5VFSV3qq6IRgmMNEbp9U1o5F8hDTh/mMtz9eo9nVY6zjJT0+TH6jSRKUpmxJTTW5KPHcObp8p",
- "nxLlz5lyuvm1MFSBF66g++a1eQDuzQ7hDWx3ebqWkijl5IhbrslEeSzaA3B0RQZXQhKyHuKPFPqpysSx",
- "VQNeY69kqqx+CYJBTUp6QdmUDgqV1XMulRQ5JqpKXdG+VO8UP9uEnF59Q2444v6EJg5XsvBBE4rnsTha",
- "CiEwQo+4oaE/+uo2laiD/rRYE3bNLVuBNZ6zQTEP9Tu8rVFIAz7XKBZ2jvik0h3fJXLIpDs8a9wmR5IR",
- "Pr0ZUR6/dd9+9KYFjEm/FBKVCI82L/iRNRAriVqneQjLVgqMX0/3/bF54/qc4FPcArbvTkLlURyDXH9u",
- "2eTnHg51Frze3svs2j5zbX2CpObnTpQzTXpWVX7S8eouSXnAbuUoghPeyyy4jyLkNuPHo+0ht73hKnif",
- "OkKDK3R2Q4X38IAwmkonvSpaTmglisIWjMLEklkShEyA8UJIaOviJi6IPHkl4MbgeR3pZ3LNLYmAk3ja",
- "BfASPdwphmasd2/cdqh+eiiHElxjmGN8G9siLSOMo2nQCm5c7ppyvI66I2HiGdYB94gcllxBqcoLUQW+",
- "WugVYUkxDse4Q5mn7gUwPAZDmYi6Y660Y2+isYeoi7pYgc14UaRSv36NXxl+ZUWNkgNsIa+bFKFVxXLM",
- "u9JNRDOkNj9RrqSpN3vmCg1uOV1U1ShBDXFlpbDD+NBlscN/U/kxx3fGB3ocHWoYojqK47IvDUMnU1Kv",
- "o+nMiFU2HRN4p9weHe3UNyP0tv+dUnqpVl1APnL6iX1cLt6jFH/7xl0ccXaGQdJXulqa5AkY2KdCLUpU",
- "G5tnv12uhFfZIAssOpSaWnf7DRDjVevmePmNhPdGSTc43a/koRwL8s1HY9K59a/jLGd7WdDoiyOKEKK3",
- "RQhF2jo7FhVEQUHu86D3NMlwIGfbdOLDCKEh3GwI0PchlpVVXHj3e8sshpj1Ue/DdwhT4mHbDe4vwseS",
- "j1rsvr8ai/sOydjwe7+q1SX4J/OVhiuh6uDYDpFPQSWkXzs1oprI++T6h4ZXnOrTmkNHjbcXvroALdPr",
- "5N//QnFyDKTVu38BU+5g0wf1sobSLpmn2iasSUw9KVF151ackqgwlRPPy4adil0H6o0NyOr5FHFgWD9s",
- "PjsvjrowU3kVZzRK6tilq4GNp51qU03hEauUEW1++FSZsIkhhhdY6StKmzUcK8T3XEFusShAG7egAY5J",
- "ouUmiwqP/pF+akSdbiIxfdapfammhpUADtzxg9dg0YtGyqJ+Mj2x0lkTnYZ8GrMhr0D62p/ddx6To82X",
- "S8ituDrw+u5va5DRy655sMtQDe/oMZ5oopcxecvxVscWoH2P4/bCEyVRvDU4Y29vLmF3z7AONSTTus/D",
- "VXuTvB2IAeQOmSMRZVLRH2RI9g55YRrKQCyEaCvqDm0GtNGKUNFb0hvOFUjSXRzt+9I9U6ZL0kyay3U9",
- "6tU1BuKOPdAbVrQY1z+eYwER01RrDHk/Yi2dnQ+zI177vCH4VrLxnYQMImDCb+FhNM1SikuIa1ahp+qa",
- "6yK0SJpeglUn23MfDV7VhWoMfaCXzcyijY0dvqNK5NvCCOi8VE6MyMbCyLvhqE0sxz1DQTeU/h0DbR1c",
- "S9C+th/Kv6UykFkVYmn3wbEPFRRZdCMkmNEclwTcaOaZV21qHcz1yzHTDPcBRfECmYYNd9DpKAHO+Jz7",
- "kP2MvoeHQyHX60ELU0Ovh4sOhKhoYQZIjKl+yfxtefhB0k2MTUJKqh9tUtlwJOiuN6TSqqhzuqDjg9EY",
- "5CbnmtrDSpJ2mny4yp6OEL3qvITdKSlBoVpD2MEYaJKcCPQoi0Jvk+/U/GZScK/uBLxPabmazyqlymzE",
- "2XE+TOHTp/hLkV9CwdxNEaIHRyrosM/Qxt54s6/Xu5CypqpAQvH5CWNnkuK1g2O7m0O6N7m8Z/fNv8VZ",
- "i5qyanmj2slbmQ58xXxX+pbcLAyzn4cZcKzullPRIAcSxGxH0gdpfp2oJ3UyVSsfupr7NX5aoiIoUjJJ",
- "W77mQJxMEyLTVv5ow2SG0kFZqusMqShr8n+ldA7XrsskQ8bTtpvD9gKieBtu/AW6Y2tesFxpDXncI/3E",
- "gYDaKA1ZqTD8JuUZXFonD20wrlmyUq2YqpyaS2n0gg8lWZYmmuuuSvDQc12CICOHz0hCBDD+ea4HlxoP",
- "4d1TBef4CjsX64TdBjcs7NbRZXQ8wR1d/SICcwKhH7ZZnaWqBHXX1a9XNVY9zqqNyNPo/veKVhmNMUlR",
- "bwoVPgEtPYDDZnjAY57SOCfx9AzRDJIvypTHhvnj5500SOfuv3iD9cdlS/DMZYSfJR5g7lt1qvJTYleb",
- "qXxhqvCmcoRCkg7v/f5lqga4mOplbjJOT2QGEQDjfucODJO8z8eCscTqmhlPIPm8kfnnneLHosfxQjZA",
- "Otk5J51/DcyNXWvwb/yoDGCv7lDF7TrIAK75UDN3Wh4YfIBHxVO4ITtSsGf5GoR94UpVWQlX0HHH+4eH",
- "dZ6DMeIK4vqF1JkVABVad/s6R8rPHPP2niDq155Fnsop2E1KpoRY2il2QOxMCslbmdExMVOPkoPoShQ1",
- "7+DP3KKS21gRt8TlE2B9N41THM0k0ovbxyIORoYgzSfPpUwHhsTvXhuTEs5WNKZnIsL2ZJuKX8txFWxI",
- "lK3sNL0GYoTYb7aQ4z3UjXy4PU4YDsZM7037qNCkmx2+qSo/SmX7iGxQETIptRkIFX3j9DNB8PV9E9Iu",
- "GR2FSQwgTMsbMI4S2ji9qNmG71ghlkvQ5FYxlsuC6yJuLiTLQVsunI65MzdXMBy0uob5QR3DcWocNDCr",
- "lLaBFkICpNx55W1M/p8gt6MPLSGz07Vt1VixysGupB928K3TczDCbYQI/JN01HLosCqJIibb8Es4ch4j",
- "foP902CiGG+FtQpnnTLFh720/hOiDg/8z1LYvdROol8/5JB8QkSMgQblqnVM0+YMaTAVJXpBJZPiSNF+",
- "BYKw12SgovlgJKOi550Z8lSzx+ULJqqVlHuT3VAcGDBjAmbuI2iPkhb65ob8AFNKsuiRM9GV1dUSqRM3",
- "hS4mjBto2PG8H9HSvYKabcfqn3mtUYi65rvDidnaaygdDEwjB3UmxDg0UPutJgIzVFAimffsGPEkQfOp",
- "mgrDjFN3vxiKcm/9cL/fcrylPb2AuEL7fnprBflAKgla43KXOjrBlnyDBY5JJxPiNO9sq5rT8ntsUJJF",
- "3ywR6STQhjF7CWxGlYP3h1HEeYrbB9CaQj/R7Rr0oT6/+KHVk6bVMA4dDoAXR9dEVYyDo8OD84lfEv/Q",
- "ICVayrsxSugs/1DAjl9gq1hGW+RlNWuBssbT67PuvkTRWOZZE+Q0VnC7HwuFSYmdcFCWiRgqEh+pxG1E",
- "OO6e1Fe8/PhxUJit+gzxAcWrcc9pHEgTI5lQaW72jO8FnzR3FDRzd1PLlxi39Tdwe5S8FvxQXmMdMH8U",
- "/nlJVv5lqHd5BZJd45gU9P3wS7bwaU4qDbkwfU34OpSiauJGsDKjfzq5tQcCVQ6t8xdlb0HGy2BYYj+2",
- "ZW3QkL2SLYTtEf3ETGXk5CapPEV9A7JI4C/Fo+J8oweui8tONHgr1UU3mtJwx1Hh0fuuI6PCh5lUpy6P",
- "Ip/dpVMbGK5z8m3dwW3iom7XNvVJwxC5+2qfTHmJkC5p5LrjUwhCCNYDYwgq+/vDvzMNSyz4q9j9+zjB",
- "/ftz3/Tvj7qf3XG+fz+p5H20RxCEIz+GnzdFMb+MPYunp98jGRh6+1GLsjhEGJ18Gm3JbMwY8avP2vNJ",
- "inb/SoGZw6PqC6feIpqcEJNYa2fyaKooU8aEJBm+WyIlBgY95LUWdofJhIPGK35NPtf4rgn99aHjjQnP",
- "331WXUKTjroNFK5NuF2/U7zE+4gsi9LdQqo8Yd9s+aYqwR+Uv9xb/Ake//lJ8eDxwz8t/vzgiwc5PPni",
- "qwcP+FdP+MOvHj+ER3/+4skDeLj88qvFo+LRk0eLJ4+efPnFV/njJw8XT7786k/3HB9yIBOgs5C6bva/",
- "sbJ9dvbyPLtwwLY44ZX4HnZURNeRcSjPy3M8ibDhopw9DT/9/+GEneRq0w4ffp35zFiztbWVeXp6en19",
- "fRJ3OV1hZGBmVZ2vT8M8g/q9Zy/PGxckGf1xRympRHDmBFI4w2+vvnl9wc5enp+0BDN7Ontw8uDkoRtf",
- "VSB5JWZPZ4/xJzw9a9z3U09ss6fvP8xnp2vgJQbSuz82YLXIwycNvNj5/5trvlqBPvE1i91PV49Og1hx",
- "+t5HSH7Y9+00Lv91+r4TSFoc6InlgU7fh6y3+1t30sr6ANqow0Qo9jU7XWAyralNwUSNx5eCyoY5fY/i",
- "8ujvpz77T/ojqi10Hk5DtHW6ZQdL7+3WwdrrkXObr+vq9D3+B+kzAove2p7arTxF8/Tp+85q/OfBarq/",
- "t93jFlcbVUAAWC2XlMV73+fT9/RvNBFsK9DCCX4Y3+5/pXdIp5hbbzf8eSfz5I/DdQxKaCZN/a8o8Q9n",
- "pTA2XchnhueVjvp5gRzY9t+DUD0ucg/hMX704MFRpcWnRZf2X6EM77Qh89q3sg/z2ZMjAd1r/em83U0A",
- "8zUvWIhow7kffry5zyU+KnFcmdGtgxA8+XgQdIuffQ879qOy7FtUjz7MZ198zJ04l05Y4yXDllFu4+ER",
- "+VleSnUtQ0snrtSbDde7ycfH8pVBV4QWV9wLi1E9zNk7DLWlKMfuUTsrigHRk9gGxn6t8P4bw9jGrCqf",
- "qaNFWiu1CumWMFR7B6i6WEPiQRc9OwjBJlIVMIvlSatr+HBLntDzanFtzxNWHDRHYoXKZchGHoGafJ3U",
- "9xDRyEON4xAJt0n5Tb3YCBPUhT94yh88RdP0jz/e9K9BX4kc2AVsKqW5FuWO/SybPGs35nFnRZF80tk9",
- "+gd53Hy2zXJVwApk5hlYtlDFLtSr6ExwCaSgDgSZ0/fdonMk0s0KKMEmn6u53xlnK8yXOFzEYsfOnw8k",
- "HOrW57xf77BpVMzt6Zv3pOE59aVVwPogDjhjXEesz5vepbnmPrJ3C1kpywgLhV/UH4zoD0Z0K+Fm8uGZ",
- "It8ktQ/KYsoHd/Y8JCRNpbvmdgjKFB3lkx7fO9n4of6T0nfoaSwULPpAcYJ9NP/BIv5gEbdjEd9B4jDi",
- "qfVMI0F0x+lDUxkGBmwX/dLO6OQIzeuS6yg89JCZ4wxH9MaNj8E1PrZSl8QV6XRcttXvExt4t3reHyzv",
- "D5b378Pyzg4zmq5gcmvN6BJ2G141+pBZ17ZQ15GfA2GhGKShHdh9rE3/79NrLmy2VNonWsHSZ8POFnh5",
- "6rMq935tExkOvmB2xujH+MlL8tfTprJk8mPfRZL66l0EI41C1Hz43LpLY/cjsvbG8fjmnWPLWLfIc/3W",
- "m/b09BSTF6yVsaezD/P3PU9b/PFdQwLvm7vCk8KHdx/+XwAAAP//YEWO0mbdAAA=",
+ "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",
}
// 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 02b3d5b62..1b23d9839 100644
--- a/daemon/algod/api/server/v2/generated/participating/public/routes.go
+++ b/daemon/algod/api/server/v2/generated/participating/public/routes.go
@@ -177,197 +177,201 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
- "lJKtsJTC+4//LwAA//9Tf3Gr9esAAA==",
+ "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",
+ "s69YOiklW2EBlPcf/18AAAD//6Cbm1hv8QAA",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/daemon/algod/api/server/v2/handlers_test.go b/daemon/algod/api/server/v2/handlers_test.go
index 42de7293f..a0a50dddb 100644
--- a/daemon/algod/api/server/v2/handlers_test.go
+++ b/daemon/algod/api/server/v2/handlers_test.go
@@ -117,6 +117,8 @@ func makeTagGraph(rootType reflect.Type, seen map[reflect.Type]*tagNode) *tagNod
case reflect.Ptr:
// Directly embed value type graph
node = makeTagGraph(rootType.Elem(), seen)
+ // the node in seen for rootType should be refreshed from calculation.
+ seen[rootType] = node
case reflect.Struct:
for i := 0; i < rootType.NumField(); i++ {
field := rootType.Field(i)
@@ -141,8 +143,8 @@ func makeTagGraph(rootType reflect.Type, seen map[reflect.Type]*tagNode) *tagNod
} else {
tagValue = field.Name
}
- if len(tagValue) != 0 {
- // ignore any empty tags
+ if len(tagValue) != 0 && tagValue != "-" {
+ // ignore any empty tags and skipping fields
node.addChild(tagValue, subgraph)
}
}
diff --git a/daemon/algod/api/server/v2/utils.go b/daemon/algod/api/server/v2/utils.go
index a1748a64b..f476afa21 100644
--- a/daemon/algod/api/server/v2/utils.go
+++ b/daemon/algod/api/server/v2/utils.go
@@ -346,11 +346,43 @@ func ConvertInnerTxn(txn *transactions.SignedTxnWithAD) PreEncodedTxInfo {
return response
}
+func convertScratchChanges(scratchChanges []simulation.ScratchChange) *[]model.ScratchChange {
+ if len(scratchChanges) == 0 {
+ return nil
+ }
+ modelSC := make([]model.ScratchChange, len(scratchChanges))
+ for i, scratchChange := range scratchChanges {
+ modelSC[i] = model.ScratchChange{
+ Slot: scratchChange.Slot,
+ NewValue: model.AvmValue{
+ Type: uint64(scratchChange.NewValue.Type),
+ Uint: omitEmpty(scratchChange.NewValue.Uint),
+ Bytes: byteOrNil([]byte(scratchChange.NewValue.Bytes)),
+ },
+ }
+ }
+ return &modelSC
+}
+
+func convertTealValueSliceToModel(tvs []basics.TealValue) *[]model.AvmValue {
+ if len(tvs) == 0 {
+ return nil
+ }
+ modelTvs := make([]model.AvmValue, len(tvs))
+ for i := range tvs {
+ modelTvs[i] = model.AvmValue{
+ Type: uint64(tvs[i].Type),
+ Uint: omitEmpty(tvs[i].Uint),
+ Bytes: byteOrNil([]byte(tvs[i].Bytes)),
+ }
+ }
+ return &modelTvs
+}
+
func convertProgramTrace(programTrace []simulation.OpcodeTraceUnit) *[]model.SimulationOpcodeTraceUnit {
if len(programTrace) == 0 {
return nil
}
-
modelProgramTrace := make([]model.SimulationOpcodeTraceUnit, len(programTrace))
for i := range programTrace {
var spawnedInnersPtr *[]uint64
@@ -362,11 +394,13 @@ func convertProgramTrace(programTrace []simulation.OpcodeTraceUnit) *[]model.Sim
spawnedInnersPtr = &spawnedInners
}
modelProgramTrace[i] = model.SimulationOpcodeTraceUnit{
- Pc: programTrace[i].PC,
- SpawnedInners: spawnedInnersPtr,
+ Pc: programTrace[i].PC,
+ SpawnedInners: spawnedInnersPtr,
+ StackAdditions: convertTealValueSliceToModel(programTrace[i].StackAdded),
+ StackPopCount: omitEmpty(programTrace[i].StackPopCount),
+ ScratchChanges: convertScratchChanges(programTrace[i].ScratchSlotChanges),
}
}
-
return &modelProgramTrace
}
@@ -375,20 +409,18 @@ func convertTxnTrace(txnTrace *simulation.TransactionTrace) *model.SimulationTra
return nil
}
- var execTraceModel model.SimulationTransactionExecTrace
-
- execTraceModel.LogicSigTrace = convertProgramTrace(txnTrace.LogicSigTrace)
- execTraceModel.ClearStateProgramTrace = convertProgramTrace(txnTrace.ClearStateProgramTrace)
- execTraceModel.ApprovalProgramTrace = convertProgramTrace(txnTrace.ApprovalProgramTrace)
+ execTraceModel := model.SimulationTransactionExecTrace{
+ ApprovalProgramTrace: convertProgramTrace(txnTrace.ApprovalProgramTrace),
+ ClearStateProgramTrace: convertProgramTrace(txnTrace.ClearStateProgramTrace),
+ LogicSigTrace: convertProgramTrace(txnTrace.LogicSigTrace),
+ }
if len(txnTrace.InnerTraces) > 0 {
- innerTrace := make([]model.SimulationTransactionExecTrace, len(txnTrace.InnerTraces))
-
+ innerTraces := make([]model.SimulationTransactionExecTrace, len(txnTrace.InnerTraces))
for i := range txnTrace.InnerTraces {
- innerTrace[i] = *convertTxnTrace(&txnTrace.InnerTraces[i])
+ innerTraces[i] = *convertTxnTrace(&txnTrace.InnerTraces[i])
}
-
- execTraceModel.InnerTrace = &innerTrace
+ execTraceModel.InnerTrace = &innerTraces
}
return &execTraceModel
diff --git a/data/basics/teal.go b/data/basics/teal.go
index 52591b486..412de5902 100644
--- a/data/basics/teal.go
+++ b/data/basics/teal.go
@@ -163,10 +163,10 @@ func (sm StateSchema) MinBalance(proto *config.ConsensusParams) (res MicroAlgos)
type TealType uint64
const (
- // TealBytesType represents the type of a byte slice in a TEAL program
+ // TealBytesType represents the type of byte slice in a TEAL program
TealBytesType TealType = 1
- // TealUintType represents the type of a uint in a TEAL program
+ // TealUintType represents the type of uint in a TEAL program
TealUintType TealType = 2
)
diff --git a/data/transactions/logic/assembler.go b/data/transactions/logic/assembler.go
index f3ab4644e..20ba9563a 100644
--- a/data/transactions/logic/assembler.go
+++ b/data/transactions/logic/assembler.go
@@ -1751,6 +1751,7 @@ func isFullSpec(spec OpSpec) bool {
func mergeProtos(specs map[int]OpSpec) (Proto, uint64, bool) {
var args StackTypes
var returns StackTypes
+ var debugExplainFuncPtr debugStackExplain
var minVersion uint64
i := 0
for _, spec := range specs {
@@ -1776,9 +1777,16 @@ func mergeProtos(specs map[int]OpSpec) (Proto, uint64, bool) {
}
}
}
+ if debugExplainFuncPtr == nil {
+ debugExplainFuncPtr = spec.Explain
+ }
i++
}
- return Proto{typedList{args, ""}, typedList{returns, ""}}, minVersion, true
+ return Proto{
+ Arg: typedList{args, ""},
+ Return: typedList{returns, ""},
+ Explain: debugExplainFuncPtr,
+ }, minVersion, true
}
func prepareVersionedPseudoTable(version uint64) map[string]map[int]OpSpec {
diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go
index e5148e29c..fa0bcc133 100644
--- a/data/transactions/logic/assembler_test.go
+++ b/data/transactions/logic/assembler_test.go
@@ -2940,7 +2940,9 @@ func TestMergeProtos(t *testing.T) {
aaVa := OpSpec{Proto: proto("aa:a")}
aVaa := OpSpec{Proto: proto("a:aa")}
p, _, _ := mergeProtos(map[int]OpSpec{0: iVi, 1: bVb})
- require.Equal(t, proto("a:a"), p)
+ expected := proto("a:a")
+ require.Equal(t, expected.Arg, p.Arg)
+ require.Equal(t, expected.Return, p.Return)
_, _, ok := mergeProtos(map[int]OpSpec{0: aaVa, 1: iVi})
require.False(t, ok)
_, _, ok = mergeProtos(map[int]OpSpec{0: aVaa, 1: iVi})
@@ -2948,7 +2950,9 @@ func TestMergeProtos(t *testing.T) {
medley := OpSpec{Proto: proto("aibibabai:aibibabai")}
medley2 := OpSpec{Proto: proto("biabbaiia:biabbaiia")}
p, _, _ = mergeProtos(map[int]OpSpec{0: medley, 1: medley2})
- require.Equal(t, proto("aiaabaaaa:aiaabaaaa"), p)
+ expected = proto("aiaabaaaa:aiaabaaaa")
+ require.Equal(t, expected.Arg, p.Arg)
+ require.Equal(t, expected.Return, p.Return)
v1 := OpSpec{Version: 1, Proto: proto(":")}
v2 := OpSpec{Version: 2, Proto: proto(":")}
_, v, _ := mergeProtos(map[int]OpSpec{0: v2, 1: v1})
diff --git a/data/transactions/logic/box.go b/data/transactions/logic/box.go
index 388ae77fe..02b4d8cd2 100644
--- a/data/transactions/logic/box.go
+++ b/data/transactions/logic/box.go
@@ -105,11 +105,11 @@ func argCheck(cx *EvalContext, name string, size uint64) error {
}
func opBoxCreate(cx *EvalContext) error {
- last := len(cx.stack) - 1 // size
+ last := len(cx.Stack) - 1 // size
prev := last - 1 // name
- name := string(cx.stack[prev].Bytes)
- size := cx.stack[last].Uint
+ name := string(cx.Stack[prev].Bytes)
+ size := cx.Stack[last].Uint
err := argCheck(cx, name, size)
if err != nil {
@@ -127,19 +127,19 @@ func opBoxCreate(cx *EvalContext) error {
}
}
- cx.stack[prev] = boolToSV(!exists)
- cx.stack = cx.stack[:last]
+ cx.Stack[prev] = boolToSV(!exists)
+ cx.Stack = cx.Stack[:last]
return err
}
func opBoxExtract(cx *EvalContext) error {
- last := len(cx.stack) - 1 // length
+ last := len(cx.Stack) - 1 // length
prev := last - 1 // start
pprev := prev - 1 // name
- name := string(cx.stack[pprev].Bytes)
- start := cx.stack[prev].Uint
- length := cx.stack[last].Uint
+ name := string(cx.Stack[pprev].Bytes)
+ start := cx.Stack[prev].Uint
+ length := cx.Stack[last].Uint
err := argCheck(cx, name, basics.AddSaturate(start, length))
if err != nil {
@@ -154,19 +154,19 @@ func opBoxExtract(cx *EvalContext) error {
}
bytes, err := extractCarefully(contents, start, length)
- cx.stack[pprev].Bytes = bytes
- cx.stack = cx.stack[:prev]
+ cx.Stack[pprev].Bytes = bytes
+ cx.Stack = cx.Stack[:prev]
return err
}
func opBoxReplace(cx *EvalContext) error {
- last := len(cx.stack) - 1 // replacement
+ last := len(cx.Stack) - 1 // replacement
prev := last - 1 // start
pprev := prev - 1 // name
- replacement := cx.stack[last].Bytes
- start := cx.stack[prev].Uint
- name := string(cx.stack[pprev].Bytes)
+ replacement := cx.Stack[last].Bytes
+ start := cx.Stack[prev].Uint
+ name := string(cx.Stack[pprev].Bytes)
err := argCheck(cx, name, basics.AddSaturate(start, uint64(len(replacement))))
if err != nil {
@@ -185,13 +185,13 @@ func opBoxReplace(cx *EvalContext) error {
if err != nil {
return err
}
- cx.stack = cx.stack[:pprev]
+ cx.Stack = cx.Stack[:pprev]
return cx.Ledger.SetBox(cx.appID, name, bytes)
}
func opBoxDel(cx *EvalContext) error {
- last := len(cx.stack) - 1 // name
- name := string(cx.stack[last].Bytes)
+ last := len(cx.Stack) - 1 // name
+ name := string(cx.Stack[last].Bytes)
err := argCheck(cx, name, 0)
if err != nil {
@@ -208,13 +208,13 @@ func opBoxDel(cx *EvalContext) error {
return err
}
}
- cx.stack[last] = boolToSV(exists)
+ cx.Stack[last] = boolToSV(exists)
return nil
}
func opBoxLen(cx *EvalContext) error {
- last := len(cx.stack) - 1 // name
- name := string(cx.stack[last].Bytes)
+ last := len(cx.Stack) - 1 // name
+ name := string(cx.Stack[last].Bytes)
err := argCheck(cx, name, 0)
if err != nil {
@@ -225,14 +225,14 @@ func opBoxLen(cx *EvalContext) error {
return err
}
- cx.stack[last] = stackValue{Uint: uint64(len(contents))}
- cx.stack = append(cx.stack, boolToSV(exists))
+ cx.Stack[last] = stackValue{Uint: uint64(len(contents))}
+ cx.Stack = append(cx.Stack, boolToSV(exists))
return nil
}
func opBoxGet(cx *EvalContext) error {
- last := len(cx.stack) - 1 // name
- name := string(cx.stack[last].Bytes)
+ last := len(cx.Stack) - 1 // name
+ name := string(cx.Stack[last].Bytes)
err := argCheck(cx, name, 0)
if err != nil {
@@ -245,17 +245,17 @@ func opBoxGet(cx *EvalContext) error {
if !exists {
contents = []byte{}
}
- cx.stack[last].Bytes = contents // Will rightly panic if too big
- cx.stack = append(cx.stack, boolToSV(exists))
+ cx.Stack[last].Bytes = contents // Will rightly panic if too big
+ cx.Stack = append(cx.Stack, boolToSV(exists))
return nil
}
func opBoxPut(cx *EvalContext) error {
- last := len(cx.stack) - 1 // value
+ last := len(cx.Stack) - 1 // value
prev := last - 1 // name
- value := cx.stack[last].Bytes
- name := string(cx.stack[prev].Bytes)
+ value := cx.Stack[last].Bytes
+ name := string(cx.Stack[prev].Bytes)
err := argCheck(cx, name, uint64(len(value)))
if err != nil {
@@ -268,7 +268,7 @@ func opBoxPut(cx *EvalContext) error {
return err
}
- cx.stack = cx.stack[:prev]
+ cx.Stack = cx.Stack[:prev]
if exists {
/* the replacement must match existing size */
diff --git a/data/transactions/logic/debugger.go b/data/transactions/logic/debugger.go
index c7d04af29..eda022e72 100644
--- a/data/transactions/logic/debugger.go
+++ b/data/transactions/logic/debugger.go
@@ -285,13 +285,13 @@ func (a *debuggerEvalTracerAdaptor) refreshDebugState(cx *EvalContext, evalError
ds.Error = evalError.Error()
}
- stack := make([]basics.TealValue, len(cx.stack))
- for i, sv := range cx.stack {
+ stack := make([]basics.TealValue, len(cx.Stack))
+ for i, sv := range cx.Stack {
stack[i] = sv.toEncodedTealValue()
}
- scratch := make([]basics.TealValue, len(cx.scratch))
- for i, sv := range cx.scratch {
+ scratch := make([]basics.TealValue, len(cx.Scratch))
+ for i, sv := range cx.Scratch {
scratch[i] = sv.toEncodedTealValue()
}
diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go
index 7ed050ff7..3d64c5fbc 100644
--- a/data/transactions/logic/eval.go
+++ b/data/transactions/logic/eval.go
@@ -161,7 +161,8 @@ func (sv stackValue) string(limit int) (string, error) {
return string(sv.Bytes), nil
}
-func (sv stackValue) toTealValue() basics.TealValue {
+// ToTealValue converts a stack value instance into a basics.TealValue instance
+func (sv stackValue) ToTealValue() basics.TealValue {
if sv.avmType() == avmBytes {
return basics.TealValue{Type: basics.TealBytesType, Bytes: string(sv.Bytes)}
}
@@ -587,7 +588,7 @@ type EvalContext struct {
// keeping the running changes, the debugger can be changed to display them
// as the app runs.
- stack []stackValue
+ Stack []stackValue
callstack []frame
fromCallsub bool
@@ -598,7 +599,7 @@ type EvalContext struct {
intc []uint64
bytec [][]byte
version uint64
- scratch scratchSpace
+ Scratch scratchSpace
subtxns []transactions.SignedTxnWithAD // place to build for itxn_submit
cost int // cost incurred so far
@@ -630,6 +631,12 @@ func (cx *EvalContext) RunMode() RunMode {
// PC returns the program counter of the current application being evaluated
func (cx *EvalContext) PC() int { return cx.pc }
+// GetOpSpec queries for the OpSpec w.r.t. current program byte.
+func (cx *EvalContext) GetOpSpec() OpSpec { return opsByOpcode[cx.version][cx.program[cx.pc]] }
+
+// GetProgram queries for the current program
+func (cx *EvalContext) GetProgram() []byte { return cx.program }
+
// avmType describes the type of a value on the operand stack
// avmTypes are a subset of StackTypes
type avmType byte
@@ -860,6 +867,16 @@ func parseStackTypes(spec string) StackTypes {
return types
}
+func filterNoneTypes(sts StackTypes) StackTypes {
+ var filteredSts = make(StackTypes, 0, len(sts))
+ for i := range sts {
+ if sts[i].AVMType != avmNone {
+ filteredSts = append(filteredSts, sts[i])
+ }
+ }
+ return filteredSts
+}
+
// panicError wraps a recover() catching a panic()
type panicError struct {
PanicValue interface{}
@@ -995,7 +1012,7 @@ func EvalContract(program []byte, gi int, aid basics.AppIndex, params *EvalParam
// Save scratch for `gload`. We used to copy, but cx.scratch is quite large,
// about 8k, and caused measurable CPU and memory demands. Of course, these
// should never be changed by later transactions.
- cx.pastScratch[cx.groupIndex] = &cx.scratch
+ cx.pastScratch[cx.groupIndex] = &cx.Scratch
return pass, &cx, err
}
@@ -1064,7 +1081,7 @@ func eval(program []byte, cx *EvalContext) (pass bool, err error) {
cx.pc = vlen
// 16 is chosen to avoid growth for small programs, and so that repeated
// doublings lead to a number just a bit above 1000, the max stack height.
- cx.stack = make([]stackValue, 0, 16)
+ cx.Stack = make([]stackValue, 0, 16)
cx.program = program
cx.txn.EvalDelta.GlobalDelta = basics.StateDelta{}
cx.txn.EvalDelta.LocalDeltas = make(map[uint64]basics.StateDelta)
@@ -1119,20 +1136,20 @@ func eval(program []byte, cx *EvalContext) (pass bool, err error) {
return false, err
}
- if len(cx.stack) != 1 {
+ if len(cx.Stack) != 1 {
if cx.Trace != nil {
fmt.Fprintf(cx.Trace, "end stack:\n")
- for i, sv := range cx.stack {
+ for i, sv := range cx.Stack {
fmt.Fprintf(cx.Trace, "[%d] %s\n", i, sv)
}
}
- return false, fmt.Errorf("stack len is %d instead of 1", len(cx.stack))
+ return false, fmt.Errorf("stack len is %d instead of 1", len(cx.Stack))
}
- if cx.stack[0].Bytes != nil {
+ if cx.Stack[0].Bytes != nil {
return false, errors.New("stack finished with bytes not int")
}
- return cx.stack[0].Uint != 0, nil
+ return cx.Stack[0].Uint != 0, nil
}
// CheckContract should be faster than EvalContract. It can perform
@@ -1305,13 +1322,13 @@ func (cx *EvalContext) step() error {
}
// check args for stack underflow and types
- if len(cx.stack) < len(spec.Arg.Types) {
+ if len(cx.Stack) < len(spec.Arg.Types) {
return fmt.Errorf("stack underflow in %s", spec.Name)
}
- first := len(cx.stack) - len(spec.Arg.Types)
+ first := len(cx.Stack) - len(spec.Arg.Types)
for i, argType := range spec.Arg.Types {
- if !opCompat(argType.AVMType, cx.stack[first+i].avmType()) {
- return fmt.Errorf("%s arg %d wanted %s but got %s", spec.Name, i, argType, cx.stack[first+i].typeName())
+ if !opCompat(argType.AVMType, cx.Stack[first+i].avmType()) {
+ return fmt.Errorf("%s arg %d wanted %s but got %s", spec.Name, i, argType, cx.Stack[first+i].typeName())
}
}
@@ -1323,9 +1340,9 @@ func (cx *EvalContext) step() error {
// It's something like a 5-10% overhead on our simplest instructions to make
// the Cost() call without the FullCost.compute() short-circuit, even
// though Cost() tries to exit fast. Use BenchmarkUintMath to test changes.
- opcost := deets.FullCost.compute(cx.stack)
+ opcost := deets.FullCost.compute(cx.Stack)
if opcost <= 0 {
- opcost = deets.Cost(cx.program, cx.pc, cx.stack)
+ opcost = deets.Cost(cx.program, cx.pc, cx.Stack)
if opcost <= 0 {
return fmt.Errorf("%3d %s returned 0 cost", cx.pc, spec.Name)
}
@@ -1347,26 +1364,26 @@ func (cx *EvalContext) step() error {
cx.pc, spec.Name, cx.cost)
}
- preheight := len(cx.stack)
+ preheight := len(cx.Stack)
err := spec.op(cx)
if err == nil && !spec.trusted {
- postheight := len(cx.stack)
+ postheight := len(cx.Stack)
if postheight-preheight != len(spec.Return.Types)-len(spec.Arg.Types) && !spec.AlwaysExits() {
return fmt.Errorf("%s changed stack height improperly %d != %d",
spec.Name, postheight-preheight, len(spec.Return.Types)-len(spec.Arg.Types))
}
first = postheight - len(spec.Return.Types)
for i, argType := range spec.Return.Types {
- stackType := cx.stack[first+i].avmType()
+ stackType := cx.Stack[first+i].avmType()
if !opCompat(argType.AVMType, stackType) {
if spec.AlwaysExits() { // We test in the loop because it's the uncommon case.
break
}
- return fmt.Errorf("%s produced %s but intended %s", spec.Name, cx.stack[first+i].typeName(), argType)
+ return fmt.Errorf("%s produced %s but intended %s", spec.Name, cx.Stack[first+i].typeName(), argType)
}
- if stackType == avmBytes && len(cx.stack[first+i].Bytes) > maxStringSize {
- return fmt.Errorf("%s produced a too big (%d) byte-array", spec.Name, len(cx.stack[first+i].Bytes))
+ if stackType == avmBytes && len(cx.Stack[first+i].Bytes) > maxStringSize {
+ return fmt.Errorf("%s produced a too big (%d) byte-array", spec.Name, len(cx.Stack[first+i].Bytes))
}
}
}
@@ -1397,7 +1414,7 @@ func (cx *EvalContext) step() error {
return inner
}
var stackString string
- if len(cx.stack) == 0 {
+ if len(cx.Stack) == 0 {
stackString = "<empty stack>"
} else {
num := 1
@@ -1407,11 +1424,11 @@ func (cx *EvalContext) step() error {
// check for nil error here, because we might not return
// values if we encounter an error in the opcode
if err == nil {
- if len(cx.stack) < num {
- return fmt.Errorf("stack underflow: expected %d, have %d", num, len(cx.stack))
+ if len(cx.Stack) < num {
+ return fmt.Errorf("stack underflow: expected %d, have %d", num, len(cx.Stack))
}
for i := 1; i <= num; i++ {
- stackString += fmt.Sprintf("(%s) ", cx.stack[len(cx.stack)-i])
+ stackString += fmt.Sprintf("(%s) ", cx.Stack[len(cx.Stack)-i])
}
}
}
@@ -1422,7 +1439,7 @@ func (cx *EvalContext) step() error {
return err
}
- if len(cx.stack) > maxStackDepth {
+ if len(cx.Stack) > maxStackDepth {
return errors.New("stack overflow")
}
if cx.nextpc != 0 {
@@ -1487,11 +1504,11 @@ func (cx *EvalContext) checkStep() (int, error) {
}
func (cx *EvalContext) ensureStackCap(targetCap int) {
- if cap(cx.stack) < targetCap {
+ if cap(cx.Stack) < targetCap {
// Let's grow all at once, plus a little slack.
- newStack := make([]stackValue, len(cx.stack), targetCap+4)
- copy(newStack, cx.stack)
- cx.stack = newStack
+ newStack := make([]stackValue, len(cx.Stack), targetCap+4)
+ copy(newStack, cx.Stack)
+ cx.Stack = newStack
}
}
@@ -1503,64 +1520,64 @@ func opReturn(cx *EvalContext) error {
// Achieve the end condition:
// Take the last element on the stack and make it the return value (only element on the stack)
// Move the pc to the end of the program
- last := len(cx.stack) - 1
- cx.stack[0] = cx.stack[last]
- cx.stack = cx.stack[:1]
+ last := len(cx.Stack) - 1
+ cx.Stack[0] = cx.Stack[last]
+ cx.Stack = cx.Stack[:1]
cx.nextpc = len(cx.program)
return nil
}
func opAssert(cx *EvalContext) error {
- last := len(cx.stack) - 1
- if cx.stack[last].Uint != 0 {
- cx.stack = cx.stack[:last]
+ last := len(cx.Stack) - 1
+ if cx.Stack[last].Uint != 0 {
+ cx.Stack = cx.Stack[:last]
return nil
}
return fmt.Errorf("assert failed pc=%d", cx.pc)
}
func opSwap(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- cx.stack[last], cx.stack[prev] = cx.stack[prev], cx.stack[last]
+ cx.Stack[last], cx.Stack[prev] = cx.Stack[prev], cx.Stack[last]
return nil
}
func opSelect(cx *EvalContext) error {
- last := len(cx.stack) - 1 // condition on top
+ last := len(cx.Stack) - 1 // condition on top
prev := last - 1 // true is one down
pprev := prev - 1 // false below that
- if cx.stack[last].Uint != 0 {
- cx.stack[pprev] = cx.stack[prev]
+ if cx.Stack[last].Uint != 0 {
+ cx.Stack[pprev] = cx.Stack[prev]
}
- cx.stack = cx.stack[:prev]
+ cx.Stack = cx.Stack[:prev]
return nil
}
func opSHA256(cx *EvalContext) error {
- last := len(cx.stack) - 1
- hash := sha256.Sum256(cx.stack[last].Bytes)
- cx.stack[last].Bytes = hash[:]
+ last := len(cx.Stack) - 1
+ hash := sha256.Sum256(cx.Stack[last].Bytes)
+ cx.Stack[last].Bytes = hash[:]
return nil
}
// The NIST SHA3-256 is implemented for compatibility with ICON
func opSHA3_256(cx *EvalContext) error {
- last := len(cx.stack) - 1
- hash := sha3.Sum256(cx.stack[last].Bytes)
- cx.stack[last].Bytes = hash[:]
+ last := len(cx.Stack) - 1
+ hash := sha3.Sum256(cx.Stack[last].Bytes)
+ cx.Stack[last].Bytes = hash[:]
return nil
}
// The Keccak256 variant of SHA-3 is implemented for compatibility with Ethereum
func opKeccak256(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
hasher := sha3.NewLegacyKeccak256()
- hasher.Write(cx.stack[last].Bytes)
+ hasher.Write(cx.Stack[last].Bytes)
hv := make([]byte, 0, hasher.Size())
hv = hasher.Sum(hv)
- cx.stack[last].Bytes = hv
+ cx.Stack[last].Bytes = hv
return nil
}
@@ -1571,30 +1588,30 @@ func opKeccak256(cx *EvalContext) error {
// to a different default hash. For stability of this language, at
// that time a new opcode should be made with the new hash.
func opSHA512_256(cx *EvalContext) error {
- last := len(cx.stack) - 1
- hash := sha512.Sum512_256(cx.stack[last].Bytes)
- cx.stack[last].Bytes = hash[:]
+ last := len(cx.Stack) - 1
+ hash := sha512.Sum512_256(cx.Stack[last].Bytes)
+ cx.Stack[last].Bytes = hash[:]
return nil
}
func opPlus(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- sum, carry := bits.Add64(cx.stack[prev].Uint, cx.stack[last].Uint, 0)
+ sum, carry := bits.Add64(cx.Stack[prev].Uint, cx.Stack[last].Uint, 0)
if carry > 0 {
return errors.New("+ overflowed")
}
- cx.stack[prev].Uint = sum
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = sum
+ cx.Stack = cx.Stack[:last]
return nil
}
func opAddw(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- sum, carry := bits.Add64(cx.stack[prev].Uint, cx.stack[last].Uint, 0)
- cx.stack[prev].Uint = carry
- cx.stack[last].Uint = sum
+ sum, carry := bits.Add64(cx.Stack[prev].Uint, cx.Stack[last].Uint, 0)
+ cx.Stack[prev].Uint = carry
+ cx.Stack[last].Uint = sum
return nil
}
@@ -1617,83 +1634,83 @@ func opDivModwImpl(hiNum, loNum, hiDen, loDen uint64) (hiQuo uint64, loQuo uint6
}
func opDivModw(cx *EvalContext) error {
- loDen := len(cx.stack) - 1
+ loDen := len(cx.Stack) - 1
hiDen := loDen - 1
- if cx.stack[loDen].Uint == 0 && cx.stack[hiDen].Uint == 0 {
+ if cx.Stack[loDen].Uint == 0 && cx.Stack[hiDen].Uint == 0 {
return errors.New("/ 0")
}
loNum := loDen - 2
hiNum := loDen - 3
hiQuo, loQuo, hiRem, loRem :=
- opDivModwImpl(cx.stack[hiNum].Uint, cx.stack[loNum].Uint, cx.stack[hiDen].Uint, cx.stack[loDen].Uint)
- cx.stack[hiNum].Uint = hiQuo
- cx.stack[loNum].Uint = loQuo
- cx.stack[hiDen].Uint = hiRem
- cx.stack[loDen].Uint = loRem
+ opDivModwImpl(cx.Stack[hiNum].Uint, cx.Stack[loNum].Uint, cx.Stack[hiDen].Uint, cx.Stack[loDen].Uint)
+ cx.Stack[hiNum].Uint = hiQuo
+ cx.Stack[loNum].Uint = loQuo
+ cx.Stack[hiDen].Uint = hiRem
+ cx.Stack[loDen].Uint = loRem
return nil
}
func opMinus(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- if cx.stack[last].Uint > cx.stack[prev].Uint {
+ if cx.Stack[last].Uint > cx.Stack[prev].Uint {
return errors.New("- would result negative")
}
- cx.stack[prev].Uint -= cx.stack[last].Uint
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint -= cx.Stack[last].Uint
+ cx.Stack = cx.Stack[:last]
return nil
}
func opDiv(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- if cx.stack[last].Uint == 0 {
+ if cx.Stack[last].Uint == 0 {
return errors.New("/ 0")
}
- cx.stack[prev].Uint /= cx.stack[last].Uint
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint /= cx.Stack[last].Uint
+ cx.Stack = cx.Stack[:last]
return nil
}
func opModulo(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- if cx.stack[last].Uint == 0 {
+ if cx.Stack[last].Uint == 0 {
return errors.New("% 0")
}
- cx.stack[prev].Uint = cx.stack[prev].Uint % cx.stack[last].Uint
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = cx.Stack[prev].Uint % cx.Stack[last].Uint
+ cx.Stack = cx.Stack[:last]
return nil
}
func opMul(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- high, low := bits.Mul64(cx.stack[prev].Uint, cx.stack[last].Uint)
+ high, low := bits.Mul64(cx.Stack[prev].Uint, cx.Stack[last].Uint)
if high > 0 {
return errors.New("* overflowed")
}
- cx.stack[prev].Uint = low
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = low
+ cx.Stack = cx.Stack[:last]
return nil
}
func opMulw(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- high, low := bits.Mul64(cx.stack[prev].Uint, cx.stack[last].Uint)
- cx.stack[prev].Uint = high
- cx.stack[last].Uint = low
+ high, low := bits.Mul64(cx.Stack[prev].Uint, cx.Stack[last].Uint)
+ cx.Stack[prev].Uint = high
+ cx.Stack[last].Uint = low
return nil
}
func opDivw(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
pprev := last - 2
- hi := cx.stack[pprev].Uint
- lo := cx.stack[prev].Uint
- y := cx.stack[last].Uint
+ hi := cx.Stack[pprev].Uint
+ lo := cx.Stack[prev].Uint
+ y := cx.Stack[last].Uint
// These two clauses catch what will cause panics in bits.Div64, so we get
// nicer errors.
if y == 0 {
@@ -1703,17 +1720,17 @@ func opDivw(cx *EvalContext) error {
return fmt.Errorf("divw overflow: %d <= %d", y, hi)
}
quo, _ := bits.Div64(hi, lo, y)
- cx.stack = cx.stack[:prev] // pop 2
- cx.stack[pprev].Uint = quo
+ cx.Stack = cx.Stack[:prev] // pop 2
+ cx.Stack[pprev].Uint = quo
return nil
}
func opLt(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- cond := cx.stack[prev].Uint < cx.stack[last].Uint
- cx.stack[prev] = boolToSV(cond)
- cx.stack = cx.stack[:last]
+ cond := cx.Stack[prev].Uint < cx.Stack[last].Uint
+ cx.Stack[prev] = boolToSV(cond)
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -1735,39 +1752,39 @@ func opGe(cx *EvalContext) error {
}
func opAnd(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- cond := (cx.stack[prev].Uint != 0) && (cx.stack[last].Uint != 0)
- cx.stack[prev] = boolToSV(cond)
- cx.stack = cx.stack[:last]
+ cond := (cx.Stack[prev].Uint != 0) && (cx.Stack[last].Uint != 0)
+ cx.Stack[prev] = boolToSV(cond)
+ cx.Stack = cx.Stack[:last]
return nil
}
func opOr(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- cond := (cx.stack[prev].Uint != 0) || (cx.stack[last].Uint != 0)
- cx.stack[prev] = boolToSV(cond)
- cx.stack = cx.stack[:last]
+ cond := (cx.Stack[prev].Uint != 0) || (cx.Stack[last].Uint != 0)
+ cx.Stack[prev] = boolToSV(cond)
+ cx.Stack = cx.Stack[:last]
return nil
}
func opEq(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- ta := cx.stack[prev].avmType()
- tb := cx.stack[last].avmType()
+ ta := cx.Stack[prev].avmType()
+ tb := cx.Stack[last].avmType()
if ta != tb {
- return fmt.Errorf("cannot compare (%s to %s)", cx.stack[prev].typeName(), cx.stack[last].typeName())
+ return fmt.Errorf("cannot compare (%s to %s)", cx.Stack[prev].typeName(), cx.Stack[last].typeName())
}
var cond bool
if ta == avmBytes {
- cond = bytes.Equal(cx.stack[prev].Bytes, cx.stack[last].Bytes)
+ cond = bytes.Equal(cx.Stack[prev].Bytes, cx.Stack[last].Bytes)
} else {
- cond = cx.stack[prev].Uint == cx.stack[last].Uint
+ cond = cx.Stack[prev].Uint == cx.Stack[last].Uint
}
- cx.stack[prev] = boolToSV(cond)
- cx.stack = cx.stack[:last]
+ cx.Stack[prev] = boolToSV(cond)
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -1780,31 +1797,31 @@ func opNeq(cx *EvalContext) error {
}
func opNot(cx *EvalContext) error {
- last := len(cx.stack) - 1
- cx.stack[last] = boolToSV(cx.stack[last].Uint == 0)
+ last := len(cx.Stack) - 1
+ cx.Stack[last] = boolToSV(cx.Stack[last].Uint == 0)
return nil
}
func opLen(cx *EvalContext) error {
- last := len(cx.stack) - 1
- cx.stack[last].Uint = uint64(len(cx.stack[last].Bytes))
- cx.stack[last].Bytes = nil
+ last := len(cx.Stack) - 1
+ cx.Stack[last].Uint = uint64(len(cx.Stack[last].Bytes))
+ cx.Stack[last].Bytes = nil
return nil
}
func opItob(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
ibytes := make([]byte, 8)
- binary.BigEndian.PutUint64(ibytes, cx.stack[last].Uint)
+ binary.BigEndian.PutUint64(ibytes, cx.Stack[last].Uint)
// cx.stack[last].Uint is not cleared out as optimization
// stackValue.avmType() checks Bytes field first
- cx.stack[last].Bytes = ibytes
+ cx.Stack[last].Bytes = ibytes
return nil
}
func opBtoi(cx *EvalContext) error {
- last := len(cx.stack) - 1
- ibytes := cx.stack[last].Bytes
+ last := len(cx.Stack) - 1
+ ibytes := cx.Stack[last].Bytes
if len(ibytes) > 8 {
return fmt.Errorf("btoi arg too long, got [%d]bytes", len(ibytes))
}
@@ -1813,60 +1830,60 @@ func opBtoi(cx *EvalContext) error {
value = value << 8
value = value | (uint64(b) & 0x0ff)
}
- cx.stack[last].Uint = value
- cx.stack[last].Bytes = nil
+ cx.Stack[last].Uint = value
+ cx.Stack[last].Bytes = nil
return nil
}
func opBitOr(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- cx.stack[prev].Uint = cx.stack[prev].Uint | cx.stack[last].Uint
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = cx.Stack[prev].Uint | cx.Stack[last].Uint
+ cx.Stack = cx.Stack[:last]
return nil
}
func opBitAnd(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- cx.stack[prev].Uint = cx.stack[prev].Uint & cx.stack[last].Uint
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = cx.Stack[prev].Uint & cx.Stack[last].Uint
+ cx.Stack = cx.Stack[:last]
return nil
}
func opBitXor(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- cx.stack[prev].Uint = cx.stack[prev].Uint ^ cx.stack[last].Uint
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = cx.Stack[prev].Uint ^ cx.Stack[last].Uint
+ cx.Stack = cx.Stack[:last]
return nil
}
func opBitNot(cx *EvalContext) error {
- last := len(cx.stack) - 1
- cx.stack[last].Uint = cx.stack[last].Uint ^ 0xffffffffffffffff
+ last := len(cx.Stack) - 1
+ cx.Stack[last].Uint = cx.Stack[last].Uint ^ 0xffffffffffffffff
return nil
}
func opShiftLeft(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- if cx.stack[last].Uint > 63 {
- return fmt.Errorf("shl arg too big, (%d)", cx.stack[last].Uint)
+ if cx.Stack[last].Uint > 63 {
+ return fmt.Errorf("shl arg too big, (%d)", cx.Stack[last].Uint)
}
- cx.stack[prev].Uint = cx.stack[prev].Uint << cx.stack[last].Uint
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = cx.Stack[prev].Uint << cx.Stack[last].Uint
+ cx.Stack = cx.Stack[:last]
return nil
}
func opShiftRight(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- if cx.stack[last].Uint > 63 {
- return fmt.Errorf("shr arg too big, (%d)", cx.stack[last].Uint)
+ if cx.Stack[last].Uint > 63 {
+ return fmt.Errorf("shr arg too big, (%d)", cx.Stack[last].Uint)
}
- cx.stack[prev].Uint = cx.stack[prev].Uint >> cx.stack[last].Uint
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = cx.Stack[prev].Uint >> cx.Stack[last].Uint
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -1879,9 +1896,9 @@ func opSqrt(cx *EvalContext) error {
http://www.embedded.com/electronics-blogs/programmer-s-toolbox/4219659/Integer-Square-Roots
*/
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
- sq := cx.stack[last].Uint
+ sq := cx.Stack[last].Uint
var rem uint64 = 0
var root uint64 = 0
@@ -1894,27 +1911,27 @@ func opSqrt(cx *EvalContext) error {
root += 2
}
}
- cx.stack[last].Uint = root >> 1
+ cx.Stack[last].Uint = root >> 1
return nil
}
func opBitLen(cx *EvalContext) error {
- last := len(cx.stack) - 1
- if cx.stack[last].avmType() == avmUint64 {
- cx.stack[last].Uint = uint64(bits.Len64(cx.stack[last].Uint))
+ last := len(cx.Stack) - 1
+ if cx.Stack[last].avmType() == avmUint64 {
+ cx.Stack[last].Uint = uint64(bits.Len64(cx.Stack[last].Uint))
return nil
}
- length := len(cx.stack[last].Bytes)
+ length := len(cx.Stack[last].Bytes)
idx := 0
- for i, b := range cx.stack[last].Bytes {
+ for i, b := range cx.Stack[last].Bytes {
if b != 0 {
idx = bits.Len8(b) + (8 * (length - i - 1))
break
}
}
- cx.stack[last].Bytes = nil
- cx.stack[last].Uint = uint64(idx)
+ cx.Stack[last].Bytes = nil
+ cx.Stack[last].Uint = uint64(idx)
return nil
}
@@ -1947,17 +1964,17 @@ func opExpImpl(base uint64, exp uint64) (uint64, error) {
}
func opExp(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- exp := cx.stack[last].Uint
- base := cx.stack[prev].Uint
+ exp := cx.Stack[last].Uint
+ base := cx.Stack[prev].Uint
val, err := opExpImpl(base, exp)
if err != nil {
return err
}
- cx.stack[prev].Uint = val
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = val
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -1991,11 +2008,11 @@ func opExpwImpl(base uint64, exp uint64) (*big.Int, error) {
}
func opExpw(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- exp := cx.stack[last].Uint
- base := cx.stack[prev].Uint
+ exp := cx.Stack[last].Uint
+ base := cx.Stack[prev].Uint
val, err := opExpwImpl(base, exp)
if err != nil {
return err
@@ -2003,27 +2020,27 @@ func opExpw(cx *EvalContext) error {
hi := new(big.Int).Rsh(val, 64).Uint64()
lo := val.Uint64()
- cx.stack[prev].Uint = hi
- cx.stack[last].Uint = lo
+ cx.Stack[prev].Uint = hi
+ cx.Stack[last].Uint = lo
return nil
}
func opBytesBinOp(cx *EvalContext, result *big.Int, op func(x, y *big.Int) *big.Int) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- if len(cx.stack[last].Bytes) > maxByteMathSize || len(cx.stack[prev].Bytes) > maxByteMathSize {
+ if len(cx.Stack[last].Bytes) > maxByteMathSize || len(cx.Stack[prev].Bytes) > maxByteMathSize {
return errors.New("math attempted on large byte-array")
}
- rhs := new(big.Int).SetBytes(cx.stack[last].Bytes)
- lhs := new(big.Int).SetBytes(cx.stack[prev].Bytes)
+ rhs := new(big.Int).SetBytes(cx.Stack[last].Bytes)
+ lhs := new(big.Int).SetBytes(cx.Stack[prev].Bytes)
op(lhs, rhs) // op's receiver has already been bound to result
if result.Sign() < 0 {
return errors.New("byte math would have negative result")
}
- cx.stack[prev].Bytes = result.Bytes()
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Bytes = result.Bytes()
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -2060,15 +2077,15 @@ func opBytesMul(cx *EvalContext) error {
}
func opBytesSqrt(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
- if len(cx.stack[last].Bytes) > maxByteMathSize {
+ if len(cx.Stack[last].Bytes) > maxByteMathSize {
return errors.New("math attempted on large byte-array")
}
- val := new(big.Int).SetBytes(cx.stack[last].Bytes)
+ val := new(big.Int).SetBytes(cx.Stack[last].Bytes)
val.Sqrt(val)
- cx.stack[last].Bytes = val.Bytes()
+ cx.Stack[last].Bytes = val.Bytes()
return nil
}
@@ -2082,26 +2099,26 @@ func nonzero(b []byte) []byte {
}
func opBytesLt(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- if len(cx.stack[last].Bytes) > maxByteMathSize || len(cx.stack[prev].Bytes) > maxByteMathSize {
+ if len(cx.Stack[last].Bytes) > maxByteMathSize || len(cx.Stack[prev].Bytes) > maxByteMathSize {
return errors.New("math attempted on large byte-array")
}
- rhs := nonzero(cx.stack[last].Bytes)
- lhs := nonzero(cx.stack[prev].Bytes)
+ rhs := nonzero(cx.Stack[last].Bytes)
+ lhs := nonzero(cx.Stack[prev].Bytes)
switch {
case len(lhs) < len(rhs):
- cx.stack[prev] = boolToSV(true)
+ cx.Stack[prev] = boolToSV(true)
case len(lhs) > len(rhs):
- cx.stack[prev] = boolToSV(false)
+ cx.Stack[prev] = boolToSV(false)
default:
- cx.stack[prev] = boolToSV(bytes.Compare(lhs, rhs) < 0)
+ cx.Stack[prev] = boolToSV(bytes.Compare(lhs, rhs) < 0)
}
- cx.stack = cx.stack[:last]
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -2127,18 +2144,18 @@ func opBytesGe(cx *EvalContext) error {
}
func opBytesEq(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- if len(cx.stack[last].Bytes) > maxByteMathSize || len(cx.stack[prev].Bytes) > maxByteMathSize {
+ if len(cx.Stack[last].Bytes) > maxByteMathSize || len(cx.Stack[prev].Bytes) > maxByteMathSize {
return errors.New("math attempted on large byte-array")
}
- rhs := nonzero(cx.stack[last].Bytes)
- lhs := nonzero(cx.stack[prev].Bytes)
+ rhs := nonzero(cx.Stack[last].Bytes)
+ lhs := nonzero(cx.Stack[prev].Bytes)
- cx.stack[prev] = boolToSV(bytes.Equal(lhs, rhs))
- cx.stack = cx.stack[:last]
+ cx.Stack[prev] = boolToSV(bytes.Equal(lhs, rhs))
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -2179,20 +2196,20 @@ func zpad(smaller []byte, size int) []byte {
// must be newly allocated, and already in place at the top of stack
// (the original top having been popped).
func opBytesBinaryLogicPrep(cx *EvalContext) ([]byte, []byte) {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- llen := len(cx.stack[last].Bytes)
- plen := len(cx.stack[prev].Bytes)
+ llen := len(cx.Stack[last].Bytes)
+ plen := len(cx.Stack[prev].Bytes)
var fresh, other []byte
if llen > plen {
- fresh, other = zpad(cx.stack[prev].Bytes, llen), cx.stack[last].Bytes
+ fresh, other = zpad(cx.Stack[prev].Bytes, llen), cx.Stack[last].Bytes
} else {
- fresh, other = zpad(cx.stack[last].Bytes, plen), cx.stack[prev].Bytes
+ fresh, other = zpad(cx.Stack[last].Bytes, plen), cx.Stack[prev].Bytes
}
- cx.stack[prev].Bytes = fresh
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Bytes = fresh
+ cx.Stack = cx.Stack[:last]
return fresh, other
}
@@ -2221,23 +2238,23 @@ func opBytesBitXor(cx *EvalContext) error {
}
func opBytesBitNot(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
- fresh := make([]byte, len(cx.stack[last].Bytes))
- for i, b := range cx.stack[last].Bytes {
+ fresh := make([]byte, len(cx.Stack[last].Bytes))
+ for i, b := range cx.Stack[last].Bytes {
fresh[i] = ^b
}
- cx.stack[last].Bytes = fresh
+ cx.Stack[last].Bytes = fresh
return nil
}
func opBytesZero(cx *EvalContext) error {
- last := len(cx.stack) - 1
- length := cx.stack[last].Uint
+ last := len(cx.Stack) - 1
+ length := cx.Stack[last].Uint
if length > maxStringSize {
return fmt.Errorf("bzero attempted to create a too large string")
}
- cx.stack[last].Bytes = make([]byte, length)
+ cx.Stack[last].Bytes = make([]byte, length)
return nil
}
@@ -2251,7 +2268,7 @@ func opIntConstN(cx *EvalContext, n byte) error {
if int(n) >= len(cx.intc) {
return fmt.Errorf("intc %d beyond %d constants", n, len(cx.intc))
}
- cx.stack = append(cx.stack, stackValue{Uint: cx.intc[n]})
+ cx.Stack = append(cx.Stack, stackValue{Uint: cx.intc[n]})
return nil
}
func opIntConstLoad(cx *EvalContext) error {
@@ -2278,7 +2295,7 @@ func opPushInt(cx *EvalContext) error {
return fmt.Errorf("could not decode int at program[%d]", pos)
}
sv := stackValue{Uint: val}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
cx.nextpc = pos + bytesUsed
return nil
}
@@ -2288,11 +2305,11 @@ func opPushInts(cx *EvalContext) error {
if err != nil {
return err
}
- finalLen := len(cx.stack) + len(intc)
+ finalLen := len(cx.Stack) + len(intc)
cx.ensureStackCap(finalLen)
for _, cint := range intc {
sv := stackValue{Uint: cint}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
}
cx.nextpc = nextpc
return nil
@@ -2308,7 +2325,7 @@ func opByteConstN(cx *EvalContext, n uint) error {
if n >= uint(len(cx.bytec)) {
return fmt.Errorf("bytec %d beyond %d constants", n, len(cx.bytec))
}
- cx.stack = append(cx.stack, stackValue{Bytes: cx.bytec[n]})
+ cx.Stack = append(cx.Stack, stackValue{Bytes: cx.bytec[n]})
return nil
}
func opByteConstLoad(cx *EvalContext) error {
@@ -2340,7 +2357,7 @@ func opPushBytes(cx *EvalContext) error {
return fmt.Errorf("pushbytes too long at program[%d]", pos)
}
sv := stackValue{Bytes: cx.program[pos:end]}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
cx.nextpc = int(end)
return nil
}
@@ -2350,11 +2367,11 @@ func opPushBytess(cx *EvalContext) error {
if err != nil {
return err
}
- finalLen := len(cx.stack) + len(cbytess)
+ finalLen := len(cx.Stack) + len(cbytess)
cx.ensureStackCap(finalLen)
for _, cbytes := range cbytess {
sv := stackValue{Bytes: cbytes}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
}
cx.nextpc = nextpc
return nil
@@ -2365,7 +2382,7 @@ func opArgN(cx *EvalContext, n uint64) error {
return fmt.Errorf("cannot load arg[%d] of %d", n, len(cx.txn.Lsig.Args))
}
val := nilToEmpty(cx.txn.Lsig.Args[n])
- cx.stack = append(cx.stack, stackValue{Bytes: val})
+ cx.Stack = append(cx.Stack, stackValue{Bytes: val})
return nil
}
@@ -2386,10 +2403,10 @@ func opArg3(cx *EvalContext) error {
return opArgN(cx, 3)
}
func opArgs(cx *EvalContext) error {
- last := len(cx.stack) - 1
- n := cx.stack[last].Uint
+ last := len(cx.Stack) - 1
+ n := cx.Stack[last].Uint
// Pop the index and push the result back on the stack.
- cx.stack = cx.stack[:last]
+ cx.Stack = cx.Stack[:last]
return opArgN(cx, n)
}
@@ -2486,10 +2503,10 @@ func checkSwitch(cx *EvalContext) error {
}
func opBnz(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
cx.nextpc = cx.pc + 3
- isNonZero := cx.stack[last].Uint != 0
- cx.stack = cx.stack[:last] // pop
+ isNonZero := cx.Stack[last].Uint != 0
+ cx.Stack = cx.Stack[:last] // pop
if isNonZero {
target, err := branchTarget(cx)
if err != nil {
@@ -2501,10 +2518,10 @@ func opBnz(cx *EvalContext) error {
}
func opBz(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
cx.nextpc = cx.pc + 3
- isZero := cx.stack[last].Uint == 0
- cx.stack = cx.stack[:last] // pop
+ isZero := cx.Stack[last].Uint == 0
+ cx.Stack = cx.Stack[:last] // pop
if isZero {
target, err := branchTarget(cx)
if err != nil {
@@ -2525,10 +2542,10 @@ func opB(cx *EvalContext) error {
}
func opSwitch(cx *EvalContext) error {
- last := len(cx.stack) - 1
- branchIdx := cx.stack[last].Uint
+ last := len(cx.Stack) - 1
+ branchIdx := cx.Stack[last].Uint
- cx.stack = cx.stack[:last]
+ cx.Stack = cx.Stack[:last]
target, err := switchTarget(cx, branchIdx)
if err != nil {
return err
@@ -2540,17 +2557,17 @@ func opSwitch(cx *EvalContext) error {
func opMatch(cx *EvalContext) error {
n := int(cx.program[cx.pc+1])
// stack contains the n sized match list and the single match value
- if n+1 > len(cx.stack) {
- return fmt.Errorf("match expects %d stack args while stack only contains %d", n+1, len(cx.stack))
+ if n+1 > len(cx.Stack) {
+ return fmt.Errorf("match expects %d stack args while stack only contains %d", n+1, len(cx.Stack))
}
- last := len(cx.stack) - 1
- matchVal := cx.stack[last]
- cx.stack = cx.stack[:last]
+ last := len(cx.Stack) - 1
+ matchVal := cx.Stack[last]
+ cx.Stack = cx.Stack[:last]
- argBase := len(cx.stack) - n
- matchList := cx.stack[argBase:]
- cx.stack = cx.stack[:argBase]
+ argBase := len(cx.Stack) - n
+ matchList := cx.Stack[argBase:]
+ cx.Stack = cx.Stack[:argBase]
matchedIdx := n
for i, stackArg := range matchList {
@@ -2580,7 +2597,7 @@ const protoByte = 0x8a
func opCallSub(cx *EvalContext) error {
cx.callstack = append(cx.callstack, frame{
retpc: cx.pc + 3, // retpc is pc _after_ the callsub
- height: len(cx.stack),
+ height: len(cx.Stack),
})
err := opB(cx)
@@ -2605,20 +2622,20 @@ func opRetSub(cx *EvalContext) error {
topFrame := cx.callstack[top]
if topFrame.clear { // A `proto` was issued in the subroutine, so retsub cleans up.
expect := topFrame.height + topFrame.returns
- if len(cx.stack) < expect { // Check general error case first, only diffentiate when error is assured
+ if len(cx.Stack) < expect { // Check general error case first, only diffentiate when error is assured
switch {
- case len(cx.stack) < topFrame.height:
+ case len(cx.Stack) < topFrame.height:
return fmt.Errorf("retsub executed with stack below frame. Did you pop args?")
- case len(cx.stack) == topFrame.height:
+ case len(cx.Stack) == topFrame.height:
return fmt.Errorf("retsub executed with no return values on stack. proto declared %d", topFrame.returns)
default:
return fmt.Errorf("retsub executed with %d return values on stack. proto declared %d",
- len(cx.stack)-topFrame.height, topFrame.returns)
+ len(cx.Stack)-topFrame.height, topFrame.returns)
}
}
argstart := topFrame.height - topFrame.args
- copy(cx.stack[argstart:], cx.stack[topFrame.height:expect])
- cx.stack = cx.stack[:argstart+topFrame.returns]
+ copy(cx.Stack[argstart:], cx.Stack[topFrame.height:expect])
+ cx.Stack = cx.Stack[:argstart+topFrame.returns]
}
cx.callstack = cx.callstack[:top]
cx.nextpc = topFrame.retpc
@@ -2626,66 +2643,66 @@ func opRetSub(cx *EvalContext) error {
}
func opPop(cx *EvalContext) error {
- last := len(cx.stack) - 1
- cx.stack = cx.stack[:last]
+ last := len(cx.Stack) - 1
+ cx.Stack = cx.Stack[:last]
return nil
}
func opDup(cx *EvalContext) error {
- last := len(cx.stack) - 1
- sv := cx.stack[last]
- cx.stack = append(cx.stack, sv)
+ last := len(cx.Stack) - 1
+ sv := cx.Stack[last]
+ cx.Stack = append(cx.Stack, sv)
return nil
}
func opDup2(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- cx.stack = append(cx.stack, cx.stack[prev:]...)
+ cx.Stack = append(cx.Stack, cx.Stack[prev:]...)
return nil
}
func opDig(cx *EvalContext) error {
depth := int(cx.program[cx.pc+1])
- idx := len(cx.stack) - 1 - depth
+ idx := len(cx.Stack) - 1 - depth
// Need to check stack size explicitly here because checkArgs() doesn't understand dig
// so we can't expect our stack to be prechecked.
if idx < 0 {
- return fmt.Errorf("dig %d with stack size = %d", depth, len(cx.stack))
+ return fmt.Errorf("dig %d with stack size = %d", depth, len(cx.Stack))
}
- sv := cx.stack[idx]
- cx.stack = append(cx.stack, sv)
+ sv := cx.Stack[idx]
+ cx.Stack = append(cx.Stack, sv)
return nil
}
func opCover(cx *EvalContext) error {
depth := int(cx.program[cx.pc+1])
- topIdx := len(cx.stack) - 1
+ topIdx := len(cx.Stack) - 1
idx := topIdx - depth
// Need to check stack size explicitly here because checkArgs() doesn't understand cover
// so we can't expect our stack to be prechecked.
if idx < 0 {
- return fmt.Errorf("cover %d with stack size = %d", depth, len(cx.stack))
+ return fmt.Errorf("cover %d with stack size = %d", depth, len(cx.Stack))
}
- sv := cx.stack[topIdx]
- copy(cx.stack[idx+1:], cx.stack[idx:])
- cx.stack[idx] = sv
+ sv := cx.Stack[topIdx]
+ copy(cx.Stack[idx+1:], cx.Stack[idx:])
+ cx.Stack[idx] = sv
return nil
}
func opUncover(cx *EvalContext) error {
depth := int(cx.program[cx.pc+1])
- topIdx := len(cx.stack) - 1
+ topIdx := len(cx.Stack) - 1
idx := topIdx - depth
// Need to check stack size explicitly here because checkArgs() doesn't understand uncover
// so we can't expect our stack to be prechecked.
if idx < 0 {
- return fmt.Errorf("uncover %d with stack size = %d", depth, len(cx.stack))
+ return fmt.Errorf("uncover %d with stack size = %d", depth, len(cx.Stack))
}
- sv := cx.stack[idx]
- copy(cx.stack[idx:], cx.stack[idx+1:])
- cx.stack[topIdx] = sv
+ sv := cx.Stack[idx]
+ copy(cx.Stack[idx:], cx.Stack[idx+1:])
+ cx.Stack[topIdx] = sv
return nil
}
@@ -2780,7 +2797,7 @@ func TxnFieldToTealValue(txn *transactions.Transaction, groupIndex int, field Tx
return basics.TealValue{}, fmt.Errorf("invalid field %s", field)
}
sv, err := cx.txnFieldToStack(stxnad, &fs, arrayFieldIdx, groupIndex, inner)
- return sv.toTealValue(), err
+ return sv.ToTealValue(), err
}
// currentTxID is a convenience method to get the Txid for the txn being evaluated
@@ -3175,7 +3192,7 @@ func opTxn(cx *EvalContext) error {
return err
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
@@ -3189,23 +3206,23 @@ func opTxna(cx *EvalContext) error {
return err
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
func opTxnas(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
gi := uint64(cx.groupIndex)
field := TxnField(cx.program[cx.pc+1])
- ai := cx.stack[last].Uint
+ ai := cx.Stack[last].Uint
sv, err := cx.opTxnImpl(gi, srcGroup, field, ai, true)
if err != nil {
return err
}
- cx.stack[last] = sv
+ cx.Stack[last] = sv
return nil
}
@@ -3218,7 +3235,7 @@ func opGtxn(cx *EvalContext) error {
return err
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
@@ -3232,30 +3249,30 @@ func opGtxna(cx *EvalContext) error {
return err
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
func opGtxnas(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
gi := uint64(cx.program[cx.pc+1])
field := TxnField(cx.program[cx.pc+2])
- ai := cx.stack[last].Uint
+ ai := cx.Stack[last].Uint
sv, err := cx.opTxnImpl(gi, srcGroup, field, ai, true)
if err != nil {
return err
}
- cx.stack[last] = sv
+ cx.Stack[last] = sv
return nil
}
func opGtxns(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
- gi := cx.stack[last].Uint
+ gi := cx.Stack[last].Uint
field := TxnField(cx.program[cx.pc+1])
sv, err := cx.opTxnImpl(gi, srcGroup, field, 0, false)
@@ -3263,14 +3280,14 @@ func opGtxns(cx *EvalContext) error {
return err
}
- cx.stack[last] = sv
+ cx.Stack[last] = sv
return nil
}
func opGtxnsa(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
- gi := cx.stack[last].Uint
+ gi := cx.Stack[last].Uint
field := TxnField(cx.program[cx.pc+1])
ai := uint64(cx.program[cx.pc+2])
@@ -3279,25 +3296,25 @@ func opGtxnsa(cx *EvalContext) error {
return err
}
- cx.stack[last] = sv
+ cx.Stack[last] = sv
return nil
}
func opGtxnsas(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- gi := cx.stack[prev].Uint
+ gi := cx.Stack[prev].Uint
field := TxnField(cx.program[cx.pc+1])
- ai := cx.stack[last].Uint
+ ai := cx.Stack[last].Uint
sv, err := cx.opTxnImpl(gi, srcGroup, field, ai, true)
if err != nil {
return err
}
- cx.stack[prev] = sv
- cx.stack = cx.stack[:last]
+ cx.Stack[prev] = sv
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -3308,7 +3325,7 @@ func opItxn(cx *EvalContext) error {
if err != nil {
return err
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
@@ -3321,22 +3338,22 @@ func opItxna(cx *EvalContext) error {
return err
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
func opItxnas(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
field := TxnField(cx.program[cx.pc+1])
- ai := cx.stack[last].Uint
+ ai := cx.Stack[last].Uint
sv, err := cx.opTxnImpl(0, srcInner, field, ai, true)
if err != nil {
return err
}
- cx.stack[last] = sv
+ cx.Stack[last] = sv
return nil
}
@@ -3379,7 +3396,7 @@ func opGitxn(cx *EvalContext) error {
return err
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
@@ -3393,23 +3410,23 @@ func opGitxna(cx *EvalContext) error {
return err
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
func opGitxnas(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
gi := uint64(cx.program[cx.pc+1])
field := TxnField(cx.program[cx.pc+2])
- ai := cx.stack[last].Uint
+ ai := cx.Stack[last].Uint
sv, err := cx.opTxnImpl(gi, srcInnerGroup, field, ai, true)
if err != nil {
return err
}
- cx.stack[last] = sv
+ cx.Stack[last] = sv
return nil
}
@@ -3445,20 +3462,20 @@ func opGaid(cx *EvalContext) error {
return err
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
func opGaids(cx *EvalContext) error {
- last := len(cx.stack) - 1
- gi := cx.stack[last].Uint
+ last := len(cx.Stack) - 1
+ gi := cx.Stack[last].Uint
sv, err := opGaidImpl(cx, gi, "gaids")
if err != nil {
return err
}
- cx.stack[last] = sv
+ cx.Stack[last] = sv
return nil
}
@@ -3566,7 +3583,7 @@ func opGlobal(cx *EvalContext) error {
return err
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
@@ -3592,47 +3609,47 @@ func (cx *EvalContext) programHash() crypto.Digest {
}
func opEd25519Verify(cx *EvalContext) error {
- last := len(cx.stack) - 1 // index of PK
+ last := len(cx.Stack) - 1 // index of PK
prev := last - 1 // index of signature
pprev := prev - 1 // index of data
var sv crypto.SignatureVerifier
- if len(cx.stack[last].Bytes) != len(sv) {
+ if len(cx.Stack[last].Bytes) != len(sv) {
return errors.New("invalid public key")
}
- copy(sv[:], cx.stack[last].Bytes)
+ copy(sv[:], cx.Stack[last].Bytes)
var sig crypto.Signature
- if len(cx.stack[prev].Bytes) != len(sig) {
+ if len(cx.Stack[prev].Bytes) != len(sig) {
return errors.New("invalid signature")
}
- copy(sig[:], cx.stack[prev].Bytes)
+ copy(sig[:], cx.Stack[prev].Bytes)
- msg := Msg{ProgramHash: cx.programHash(), Data: cx.stack[pprev].Bytes}
- cx.stack[pprev] = boolToSV(sv.Verify(msg, sig))
- cx.stack = cx.stack[:prev]
+ msg := Msg{ProgramHash: cx.programHash(), Data: cx.Stack[pprev].Bytes}
+ cx.Stack[pprev] = boolToSV(sv.Verify(msg, sig))
+ cx.Stack = cx.Stack[:prev]
return nil
}
func opEd25519VerifyBare(cx *EvalContext) error {
- last := len(cx.stack) - 1 // index of PK
+ last := len(cx.Stack) - 1 // index of PK
prev := last - 1 // index of signature
pprev := prev - 1 // index of data
var sv crypto.SignatureVerifier
- if len(cx.stack[last].Bytes) != len(sv) {
+ if len(cx.Stack[last].Bytes) != len(sv) {
return errors.New("invalid public key")
}
- copy(sv[:], cx.stack[last].Bytes)
+ copy(sv[:], cx.Stack[last].Bytes)
var sig crypto.Signature
- if len(cx.stack[prev].Bytes) != len(sig) {
+ if len(cx.Stack[prev].Bytes) != len(sig) {
return errors.New("invalid signature")
}
- copy(sig[:], cx.stack[prev].Bytes)
+ copy(sig[:], cx.Stack[prev].Bytes)
- cx.stack[pprev] = boolToSV(sv.VerifyBytes(cx.stack[pprev].Bytes, sig))
- cx.stack = cx.stack[:prev]
+ cx.Stack[pprev] = boolToSV(sv.VerifyBytes(cx.Stack[pprev].Bytes, sig))
+ cx.Stack = cx.Stack[:prev]
return nil
}
@@ -3664,17 +3681,17 @@ func opEcdsaVerify(cx *EvalContext) error {
return fmt.Errorf("unsupported curve %d", fs.field)
}
- last := len(cx.stack) - 1 // index of PK y
+ last := len(cx.Stack) - 1 // index of PK y
prev := last - 1 // index of PK x
pprev := prev - 1 // index of signature s
fourth := pprev - 1 // index of signature r
fifth := fourth - 1 // index of data
- pkY := cx.stack[last].Bytes
- pkX := cx.stack[prev].Bytes
- sigS := cx.stack[pprev].Bytes
- sigR := cx.stack[fourth].Bytes
- msg := cx.stack[fifth].Bytes
+ pkY := cx.Stack[last].Bytes
+ pkX := cx.Stack[prev].Bytes
+ sigS := cx.Stack[pprev].Bytes
+ sigR := cx.Stack[fourth].Bytes
+ msg := cx.Stack[fifth].Bytes
if len(msg) != 32 {
return fmt.Errorf("the signed data must be 32 bytes long, not %d", len(msg))
@@ -3704,8 +3721,8 @@ func opEcdsaVerify(cx *EvalContext) error {
}
}
- cx.stack[fifth] = boolToSV(result)
- cx.stack = cx.stack[:fourth]
+ cx.Stack[fifth] = boolToSV(result)
+ cx.Stack = cx.Stack[:fourth]
return nil
}
@@ -3725,9 +3742,9 @@ func opEcdsaPkDecompress(cx *EvalContext) error {
return fmt.Errorf("unsupported curve %d", fs.field)
}
- last := len(cx.stack) - 1 // compressed PK
+ last := len(cx.Stack) - 1 // compressed PK
- pubkey := cx.stack[last].Bytes
+ pubkey := cx.Stack[last].Bytes
var x, y *big.Int
if fs.field == Secp256k1 {
x, y = secp256k1.DecompressPubkey(pubkey)
@@ -3742,8 +3759,8 @@ func opEcdsaPkDecompress(cx *EvalContext) error {
}
var err error
- cx.stack[last].Uint = 0
- cx.stack[last].Bytes, err = leadingZeros(32, x)
+ cx.Stack[last].Uint = 0
+ cx.Stack[last].Bytes, err = leadingZeros(32, x)
if err != nil {
return fmt.Errorf("x component zeroing failed: %w", err)
}
@@ -3754,7 +3771,7 @@ func opEcdsaPkDecompress(cx *EvalContext) error {
return fmt.Errorf("y component zeroing failed: %w", err)
}
- cx.stack = append(cx.stack, sv)
+ cx.Stack = append(cx.Stack, sv)
return nil
}
@@ -3769,15 +3786,15 @@ func opEcdsaPkRecover(cx *EvalContext) error {
return fmt.Errorf("unsupported curve %d", fs.field)
}
- last := len(cx.stack) - 1 // index of signature s
+ last := len(cx.Stack) - 1 // index of signature s
prev := last - 1 // index of signature r
pprev := prev - 1 // index of recovery id
fourth := pprev - 1 // index of data
- sigS := cx.stack[last].Bytes
- sigR := cx.stack[prev].Bytes
- recid := cx.stack[pprev].Uint
- msg := cx.stack[fourth].Bytes
+ sigS := cx.Stack[last].Bytes
+ sigR := cx.Stack[prev].Bytes
+ recid := cx.Stack[pprev].Uint
+ msg := cx.Stack[fourth].Bytes
if recid > 3 {
return fmt.Errorf("invalid recovery id: %d", recid)
@@ -3797,53 +3814,53 @@ func opEcdsaPkRecover(cx *EvalContext) error {
return fmt.Errorf("pubkey unmarshal failed")
}
- cx.stack[fourth].Uint = 0
- cx.stack[fourth].Bytes, err = leadingZeros(32, x)
+ cx.Stack[fourth].Uint = 0
+ cx.Stack[fourth].Bytes, err = leadingZeros(32, x)
if err != nil {
return fmt.Errorf("x component zeroing failed: %s", err.Error())
}
- cx.stack[pprev].Uint = 0
- cx.stack[pprev].Bytes, err = leadingZeros(32, y)
+ cx.Stack[pprev].Uint = 0
+ cx.Stack[pprev].Bytes, err = leadingZeros(32, y)
if err != nil {
return fmt.Errorf("y component zeroing failed: %s", err.Error())
}
- cx.stack = cx.stack[:prev]
+ cx.Stack = cx.Stack[:prev]
return nil
}
func opLoad(cx *EvalContext) error {
n := cx.program[cx.pc+1]
- cx.stack = append(cx.stack, cx.scratch[n])
+ cx.Stack = append(cx.Stack, cx.Scratch[n])
return nil
}
func opLoads(cx *EvalContext) error {
- last := len(cx.stack) - 1
- n := cx.stack[last].Uint
- if n >= uint64(len(cx.scratch)) {
+ last := len(cx.Stack) - 1
+ n := cx.Stack[last].Uint
+ if n >= uint64(len(cx.Scratch)) {
return fmt.Errorf("invalid Scratch index %d", n)
}
- cx.stack[last] = cx.scratch[n]
+ cx.Stack[last] = cx.Scratch[n]
return nil
}
func opStore(cx *EvalContext) error {
n := cx.program[cx.pc+1]
- last := len(cx.stack) - 1
- cx.scratch[n] = cx.stack[last]
- cx.stack = cx.stack[:last]
+ last := len(cx.Stack) - 1
+ cx.Scratch[n] = cx.Stack[last]
+ cx.Stack = cx.Stack[:last]
return nil
}
func opStores(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- n := cx.stack[prev].Uint
- if n >= uint64(len(cx.scratch)) {
+ n := cx.Stack[prev].Uint
+ if n >= uint64(len(cx.Scratch)) {
return fmt.Errorf("invalid Scratch index %d", n)
}
- cx.scratch[n] = cx.stack[last]
- cx.stack = cx.stack[:prev]
+ cx.Scratch[n] = cx.Stack[last]
+ cx.Stack = cx.Stack[:prev]
return nil
}
@@ -3852,7 +3869,7 @@ func opGloadImpl(cx *EvalContext, gi int, scratchIdx byte, opName string) (stack
if gi >= len(cx.TxnGroup) {
return none, fmt.Errorf("%s lookup TxnGroup[%d] but it only has %d", opName, gi, len(cx.TxnGroup))
}
- if int(scratchIdx) >= len(cx.scratch) {
+ if int(scratchIdx) >= len(cx.Scratch) {
return none, fmt.Errorf("invalid Scratch index %d", scratchIdx)
}
if cx.TxnGroup[gi].Txn.Type != protocol.ApplicationCallTx {
@@ -3876,13 +3893,13 @@ func opGload(cx *EvalContext) error {
return err
}
- cx.stack = append(cx.stack, scratchValue)
+ cx.Stack = append(cx.Stack, scratchValue)
return nil
}
func opGloads(cx *EvalContext) error {
- last := len(cx.stack) - 1
- gi := cx.stack[last].Uint
+ last := len(cx.Stack) - 1
+ gi := cx.Stack[last].Uint
if gi >= uint64(len(cx.TxnGroup)) {
return fmt.Errorf("gloads lookup TxnGroup[%d] but it only has %d", gi, len(cx.TxnGroup))
}
@@ -3892,19 +3909,19 @@ func opGloads(cx *EvalContext) error {
return err
}
- cx.stack[last] = scratchValue
+ cx.Stack[last] = scratchValue
return nil
}
func opGloadss(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- gi := cx.stack[prev].Uint
+ gi := cx.Stack[prev].Uint
if gi >= uint64(len(cx.TxnGroup)) {
return fmt.Errorf("gloadss lookup TxnGroup[%d] but it only has %d", gi, len(cx.TxnGroup))
}
- scratchIdx := cx.stack[last].Uint
+ scratchIdx := cx.Stack[last].Uint
if scratchIdx >= 256 {
return fmt.Errorf("gloadss scratch index >= 256 (%d)", scratchIdx)
}
@@ -3913,22 +3930,22 @@ func opGloadss(cx *EvalContext) error {
return err
}
- cx.stack[prev] = scratchValue
- cx.stack = cx.stack[:last]
+ cx.Stack[prev] = scratchValue
+ cx.Stack = cx.Stack[:last]
return nil
}
func opConcat(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- a := cx.stack[prev].Bytes
- b := cx.stack[last].Bytes
+ a := cx.Stack[prev].Bytes
+ b := cx.Stack[last].Bytes
newlen := len(a) + len(b)
newvalue := make([]byte, newlen)
copy(newvalue, a)
copy(newvalue[len(a):], b)
- cx.stack[prev].Bytes = newvalue
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Bytes = newvalue
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -3943,34 +3960,34 @@ func substring(x []byte, start, end int) ([]byte, error) {
}
func opSubstring(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
start := cx.program[cx.pc+1]
end := cx.program[cx.pc+2]
- bytes, err := substring(cx.stack[last].Bytes, int(start), int(end))
- cx.stack[last].Bytes = bytes
+ bytes, err := substring(cx.Stack[last].Bytes, int(start), int(end))
+ cx.Stack[last].Bytes = bytes
return err
}
func opSubstring3(cx *EvalContext) error {
- last := len(cx.stack) - 1 // end
+ last := len(cx.Stack) - 1 // end
prev := last - 1 // start
pprev := prev - 1 // bytes
- start := cx.stack[prev].Uint
- end := cx.stack[last].Uint
+ start := cx.Stack[prev].Uint
+ end := cx.Stack[last].Uint
if start > math.MaxInt32 || end > math.MaxInt32 {
return errors.New("substring range beyond length of string")
}
- bytes, err := substring(cx.stack[pprev].Bytes, int(start), int(end))
- cx.stack[pprev].Bytes = bytes
- cx.stack = cx.stack[:prev]
+ bytes, err := substring(cx.Stack[pprev].Bytes, int(start), int(end))
+ cx.Stack[pprev].Bytes = bytes
+ cx.Stack = cx.Stack[:prev]
return err
}
func opGetBit(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- idx := cx.stack[last].Uint
- target := cx.stack[prev]
+ idx := cx.Stack[last].Uint
+ target := cx.Stack[prev]
var bit uint64
if target.avmType() == avmUint64 {
@@ -3996,20 +4013,20 @@ func opGetBit(cx *EvalContext) error {
mask := byte(0x80) >> bitIdx
bit = uint64((byteVal & mask) >> (7 - bitIdx))
}
- cx.stack[prev].Uint = bit
- cx.stack[prev].Bytes = nil
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = bit
+ cx.Stack[prev].Bytes = nil
+ cx.Stack = cx.Stack[:last]
return nil
}
func opSetBit(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
pprev := prev - 1
- bit := cx.stack[last].Uint
- idx := cx.stack[prev].Uint
- target := cx.stack[pprev]
+ bit := cx.Stack[last].Uint
+ idx := cx.Stack[prev].Uint
+ target := cx.Stack[pprev]
if bit > 1 {
return errors.New("setbit value > 1")
@@ -4021,9 +4038,9 @@ func opSetBit(cx *EvalContext) error {
}
mask := uint64(1) << idx
if bit == uint64(1) {
- cx.stack[pprev].Uint |= mask // manipulate stack in place
+ cx.Stack[pprev].Uint |= mask // manipulate stack in place
} else {
- cx.stack[pprev].Uint &^= mask // manipulate stack in place
+ cx.Stack[pprev].Uint &^= mask // manipulate stack in place
}
} else {
// indexing into a byteslice
@@ -4046,42 +4063,42 @@ func opSetBit(cx *EvalContext) error {
} else {
scratch[byteIdx] &^= mask
}
- cx.stack[pprev].Bytes = scratch
+ cx.Stack[pprev].Bytes = scratch
}
- cx.stack = cx.stack[:prev]
+ cx.Stack = cx.Stack[:prev]
return nil
}
func opGetByte(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- idx := cx.stack[last].Uint
- target := cx.stack[prev]
+ idx := cx.Stack[last].Uint
+ target := cx.Stack[prev]
if idx >= uint64(len(target.Bytes)) {
return errors.New("getbyte index beyond array length")
}
- cx.stack[prev].Uint = uint64(target.Bytes[idx])
- cx.stack[prev].Bytes = nil
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = uint64(target.Bytes[idx])
+ cx.Stack[prev].Bytes = nil
+ cx.Stack = cx.Stack[:last]
return nil
}
func opSetByte(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
pprev := prev - 1
- if cx.stack[last].Uint > 255 {
+ if cx.Stack[last].Uint > 255 {
return errors.New("setbyte value > 255")
}
- if cx.stack[prev].Uint >= uint64(len(cx.stack[pprev].Bytes)) {
+ if cx.Stack[prev].Uint >= uint64(len(cx.Stack[pprev].Bytes)) {
return errors.New("setbyte index beyond array length")
}
// Copy to avoid modifying shared slice
- cx.stack[pprev].Bytes = append([]byte(nil), cx.stack[pprev].Bytes...)
- cx.stack[pprev].Bytes[cx.stack[prev].Uint] = byte(cx.stack[last].Uint)
- cx.stack = cx.stack[:prev]
+ cx.Stack[pprev].Bytes = append([]byte(nil), cx.Stack[pprev].Bytes...)
+ cx.Stack[pprev].Bytes[cx.Stack[prev].Uint] = byte(cx.Stack[last].Uint)
+ cx.Stack = cx.Stack[:prev]
return nil
}
@@ -4100,29 +4117,29 @@ func extractCarefully(x []byte, start, length uint64) ([]byte, error) {
}
func opExtract(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
start := uint64(cx.program[cx.pc+1])
length := uint64(cx.program[cx.pc+2])
// Shortcut: if length is 0, take bytes from start index to the end
if length == 0 {
// If length has wrapped, it's because start > len(), so extractCarefully will report
- length = uint64(len(cx.stack[last].Bytes) - int(start))
+ length = uint64(len(cx.Stack[last].Bytes) - int(start))
}
- bytes, err := extractCarefully(cx.stack[last].Bytes, start, length)
- cx.stack[last].Bytes = bytes
+ bytes, err := extractCarefully(cx.Stack[last].Bytes, start, length)
+ cx.Stack[last].Bytes = bytes
return err
}
func opExtract3(cx *EvalContext) error {
- last := len(cx.stack) - 1 // length
+ last := len(cx.Stack) - 1 // length
prev := last - 1 // start
pprev := prev - 1 // bytes
- start := cx.stack[prev].Uint
- length := cx.stack[last].Uint
- bytes, err := extractCarefully(cx.stack[pprev].Bytes, start, length)
- cx.stack[pprev].Bytes = bytes
- cx.stack = cx.stack[:prev]
+ start := cx.Stack[prev].Uint
+ length := cx.Stack[last].Uint
+ bytes, err := extractCarefully(cx.Stack[pprev].Bytes, start, length)
+ cx.Stack[pprev].Bytes = bytes
+ cx.Stack = cx.Stack[:prev]
return err
}
@@ -4151,37 +4168,37 @@ func replaceCarefully(original []byte, replacement []byte, start uint64) ([]byte
}
func opReplace2(cx *EvalContext) error {
- last := len(cx.stack) - 1 // replacement
+ last := len(cx.Stack) - 1 // replacement
prev := last - 1 // original
- replacement := cx.stack[last].Bytes
+ replacement := cx.Stack[last].Bytes
start := uint64(cx.program[cx.pc+1])
- original := cx.stack[prev].Bytes
+ original := cx.Stack[prev].Bytes
bytes, err := replaceCarefully(original, replacement, start)
if err != nil {
return err
}
- cx.stack[prev].Bytes = bytes
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Bytes = bytes
+ cx.Stack = cx.Stack[:last]
return err
}
func opReplace3(cx *EvalContext) error {
- last := len(cx.stack) - 1 // replacement
+ last := len(cx.Stack) - 1 // replacement
prev := last - 1 // start
pprev := prev - 1 // original
- replacement := cx.stack[last].Bytes
- start := cx.stack[prev].Uint
- original := cx.stack[pprev].Bytes
+ replacement := cx.Stack[last].Bytes
+ start := cx.Stack[prev].Uint
+ original := cx.Stack[pprev].Bytes
bytes, err := replaceCarefully(original, replacement, start)
if err != nil {
return err
}
- cx.stack[pprev].Bytes = bytes
- cx.stack = cx.stack[:prev]
+ cx.Stack[pprev].Bytes = bytes
+ cx.Stack = cx.Stack[:prev]
return err
}
@@ -4197,16 +4214,16 @@ func convertBytesToInt(x []byte) uint64 {
}
func opExtractNBytes(cx *EvalContext, n uint64) error {
- last := len(cx.stack) - 1 // start
+ last := len(cx.Stack) - 1 // start
prev := last - 1 // bytes
- start := cx.stack[last].Uint
- bytes, err := extractCarefully(cx.stack[prev].Bytes, start, n) // extract n bytes
+ start := cx.Stack[last].Uint
+ bytes, err := extractCarefully(cx.Stack[prev].Bytes, start, n) // extract n bytes
if err != nil {
return err
}
- cx.stack[prev].Uint = convertBytesToInt(bytes)
- cx.stack[prev].Bytes = nil
- cx.stack = cx.stack[:last]
+ cx.Stack[prev].Uint = convertBytesToInt(bytes)
+ cx.Stack[prev].Bytes = nil
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -4355,9 +4372,9 @@ func (cx *EvalContext) mutableAccountReference(account stackValue) (basics.Addre
}
func opBalance(cx *EvalContext) error {
- last := len(cx.stack) - 1 // account (index or actual address)
+ last := len(cx.Stack) - 1 // account (index or actual address)
- addr, _, err := cx.accountReference(cx.stack[last])
+ addr, _, err := cx.accountReference(cx.Stack[last])
if err != nil {
return err
}
@@ -4367,15 +4384,15 @@ func opBalance(cx *EvalContext) error {
return err
}
- cx.stack[last].Bytes = nil
- cx.stack[last].Uint = account.MicroAlgos.Raw
+ cx.Stack[last].Bytes = nil
+ cx.Stack[last].Uint = account.MicroAlgos.Raw
return nil
}
func opMinBalance(cx *EvalContext) error {
- last := len(cx.stack) - 1 // account (index or actual address)
+ last := len(cx.Stack) - 1 // account (index or actual address)
- addr, _, err := cx.accountReference(cx.stack[last])
+ addr, _, err := cx.accountReference(cx.Stack[last])
if err != nil {
return err
}
@@ -4385,16 +4402,16 @@ func opMinBalance(cx *EvalContext) error {
return err
}
- cx.stack[last].Bytes = nil
- cx.stack[last].Uint = account.MinBalance(cx.Proto).Raw
+ cx.Stack[last].Bytes = nil
+ cx.Stack[last].Uint = account.MinBalance(cx.Proto).Raw
return nil
}
func opAppOptedIn(cx *EvalContext) error {
- last := len(cx.stack) - 1 // app
+ last := len(cx.Stack) - 1 // app
prev := last - 1 // account
- addr, app, _, err := cx.localsReference(cx.stack[prev], cx.stack[last].Uint)
+ addr, app, _, err := cx.localsReference(cx.Stack[prev], cx.Stack[last].Uint)
if err != nil {
return err
}
@@ -4404,43 +4421,43 @@ func opAppOptedIn(cx *EvalContext) error {
return err
}
- cx.stack[prev] = boolToSV(optedIn)
- cx.stack = cx.stack[:last]
+ cx.Stack[prev] = boolToSV(optedIn)
+ cx.Stack = cx.Stack[:last]
return nil
}
func opAppLocalGet(cx *EvalContext) error {
- last := len(cx.stack) - 1 // state key
+ last := len(cx.Stack) - 1 // state key
prev := last - 1 // account
- key := cx.stack[last].Bytes
+ key := cx.Stack[last].Bytes
- result, _, err := opAppLocalGetImpl(cx, 0, key, cx.stack[prev])
+ result, _, err := opAppLocalGetImpl(cx, 0, key, cx.Stack[prev])
if err != nil {
return err
}
- cx.stack[prev] = result
- cx.stack = cx.stack[:last]
+ cx.Stack[prev] = result
+ cx.Stack = cx.Stack[:last]
return nil
}
func opAppLocalGetEx(cx *EvalContext) error {
- last := len(cx.stack) - 1 // state key
+ last := len(cx.Stack) - 1 // state key
prev := last - 1 // app id
pprev := prev - 1 // account
- key := cx.stack[last].Bytes
- appID := cx.stack[prev].Uint
+ key := cx.Stack[last].Bytes
+ appID := cx.Stack[prev].Uint
- result, ok, err := opAppLocalGetImpl(cx, appID, key, cx.stack[pprev])
+ result, ok, err := opAppLocalGetImpl(cx, appID, key, cx.Stack[pprev])
if err != nil {
return err
}
- cx.stack[pprev] = result
- cx.stack[prev] = boolToSV(ok)
- cx.stack = cx.stack[:last]
+ cx.Stack[pprev] = result
+ cx.Stack[prev] = boolToSV(ok)
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -4479,32 +4496,32 @@ func opAppGetGlobalStateImpl(cx *EvalContext, appIndex uint64, key []byte) (resu
}
func opAppGlobalGet(cx *EvalContext) error {
- last := len(cx.stack) - 1 // state key
+ last := len(cx.Stack) - 1 // state key
- key := cx.stack[last].Bytes
+ key := cx.Stack[last].Bytes
result, _, err := opAppGetGlobalStateImpl(cx, 0, key)
if err != nil {
return err
}
- cx.stack[last] = result
+ cx.Stack[last] = result
return nil
}
func opAppGlobalGetEx(cx *EvalContext) error {
- last := len(cx.stack) - 1 // state key
+ last := len(cx.Stack) - 1 // state key
prev := last - 1 // app
- key := cx.stack[last].Bytes
+ key := cx.Stack[last].Bytes
- result, ok, err := opAppGetGlobalStateImpl(cx, cx.stack[prev].Uint, key)
+ result, ok, err := opAppGetGlobalStateImpl(cx, cx.Stack[prev].Uint, key)
if err != nil {
return err
}
- cx.stack[prev] = result
- cx.stack[last] = boolToSV(ok)
+ cx.Stack[prev] = result
+ cx.Stack[last] = boolToSV(ok)
return nil
}
@@ -4535,12 +4552,12 @@ func (cx *EvalContext) ensureLocalDelta(accountIdx uint64, addr basics.Address)
}
func opAppLocalPut(cx *EvalContext) error {
- last := len(cx.stack) - 1 // value
+ last := len(cx.Stack) - 1 // value
prev := last - 1 // state key
pprev := prev - 1 // account
- sv := cx.stack[last]
- key := string(cx.stack[prev].Bytes)
+ sv := cx.Stack[last]
+ key := string(cx.Stack[prev].Bytes)
// Enforce key lengths. Now, this is the same as enforced by ledger, but if
// it ever to change in proto, we would need to isolate changes to different
@@ -4549,7 +4566,7 @@ func opAppLocalPut(cx *EvalContext) error {
return fmt.Errorf("key too long: length was %d, maximum is %d", len(key), cx.Proto.MaxAppKeyLen)
}
- addr, accountIdx, err := cx.mutableAccountReference(cx.stack[pprev])
+ addr, accountIdx, err := cx.mutableAccountReference(cx.Stack[pprev])
if err != nil {
return err
}
@@ -4568,7 +4585,7 @@ func opAppLocalPut(cx *EvalContext) error {
return err
}
- tv := sv.toTealValue()
+ tv := sv.ToTealValue()
if !ok || tv != etv {
accountIdx = cx.ensureLocalDelta(accountIdx, addr)
cx.txn.EvalDelta.LocalDeltas[accountIdx][key] = tv.ToValueDelta()
@@ -4589,16 +4606,16 @@ func opAppLocalPut(cx *EvalContext) error {
return err
}
- cx.stack = cx.stack[:pprev]
+ cx.Stack = cx.Stack[:pprev]
return nil
}
func opAppGlobalPut(cx *EvalContext) error {
- last := len(cx.stack) - 1 // value
+ last := len(cx.Stack) - 1 // value
prev := last - 1 // state key
- sv := cx.stack[last]
- key := string(cx.stack[prev].Bytes)
+ sv := cx.Stack[last]
+ key := string(cx.Stack[prev].Bytes)
// Enforce maximum key length. Currently this is the same as enforced by
// ledger. If it were ever to change in proto, we would need to isolate
@@ -4614,7 +4631,7 @@ func opAppGlobalPut(cx *EvalContext) error {
if err != nil {
return err
}
- tv := sv.toTealValue()
+ tv := sv.ToTealValue()
if !ok || tv != etv {
cx.txn.EvalDelta.GlobalDelta[key] = tv.ToValueDelta()
}
@@ -4634,17 +4651,17 @@ func opAppGlobalPut(cx *EvalContext) error {
return err
}
- cx.stack = cx.stack[:prev]
+ cx.Stack = cx.Stack[:prev]
return nil
}
func opAppLocalDel(cx *EvalContext) error {
- last := len(cx.stack) - 1 // key
+ last := len(cx.Stack) - 1 // key
prev := last - 1 // account
- key := string(cx.stack[last].Bytes)
+ key := string(cx.Stack[last].Bytes)
- addr, accountIdx, err := cx.mutableAccountReference(cx.stack[prev])
+ addr, accountIdx, err := cx.mutableAccountReference(cx.Stack[prev])
if err != nil {
return err
}
@@ -4673,14 +4690,14 @@ func opAppLocalDel(cx *EvalContext) error {
return err
}
- cx.stack = cx.stack[:prev]
+ cx.Stack = cx.Stack[:prev]
return nil
}
func opAppGlobalDel(cx *EvalContext) error {
- last := len(cx.stack) - 1 // key
+ last := len(cx.Stack) - 1 // key
- key := string(cx.stack[last].Bytes)
+ key := string(cx.Stack[last].Bytes)
// if deleting a non-existent value, don't record in EvalDelta, matching
// ledger behavior with previous BuildEvalDelta mechanism
@@ -4697,7 +4714,7 @@ func opAppGlobalDel(cx *EvalContext) error {
if err != nil {
return err
}
- cx.stack = cx.stack[:last]
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -4917,7 +4934,7 @@ func (cx *EvalContext) holdingReference(account stackValue, ref uint64) (basics.
}
func opAssetHoldingGet(cx *EvalContext) error {
- last := len(cx.stack) - 1 // asset
+ last := len(cx.Stack) - 1 // asset
prev := last - 1 // account
holdingField := AssetHoldingField(cx.program[cx.pc+1])
@@ -4926,7 +4943,7 @@ func opAssetHoldingGet(cx *EvalContext) error {
return fmt.Errorf("invalid asset_holding_get field %d", holdingField)
}
- addr, asset, err := cx.holdingReference(cx.stack[prev], cx.stack[last].Uint)
+ addr, asset, err := cx.holdingReference(cx.Stack[prev], cx.Stack[last].Uint)
if err != nil {
return err
}
@@ -4942,13 +4959,13 @@ func opAssetHoldingGet(cx *EvalContext) error {
}
}
- cx.stack[prev] = value
- cx.stack[last].Uint = exist
+ cx.Stack[prev] = value
+ cx.Stack[last].Uint = exist
return nil
}
func opAssetParamsGet(cx *EvalContext) error {
- last := len(cx.stack) - 1 // asset
+ last := len(cx.Stack) - 1 // asset
paramField := AssetParamsField(cx.program[cx.pc+1])
fs, ok := assetParamsFieldSpecByField(paramField)
@@ -4956,7 +4973,7 @@ func opAssetParamsGet(cx *EvalContext) error {
return fmt.Errorf("invalid asset_params_get field %d", paramField)
}
- asset, err := cx.assetReference(cx.stack[last].Uint, true)
+ asset, err := cx.assetReference(cx.Stack[last].Uint, true)
if err != nil {
return err
}
@@ -4972,13 +4989,13 @@ func opAssetParamsGet(cx *EvalContext) error {
}
}
- cx.stack[last] = value
- cx.stack = append(cx.stack, stackValue{Uint: exist})
+ cx.Stack[last] = value
+ cx.Stack = append(cx.Stack, stackValue{Uint: exist})
return nil
}
func opAppParamsGet(cx *EvalContext) error {
- last := len(cx.stack) - 1 // app
+ last := len(cx.Stack) - 1 // app
paramField := AppParamsField(cx.program[cx.pc+1])
fs, ok := appParamsFieldSpecByField(paramField)
@@ -4986,7 +5003,7 @@ func opAppParamsGet(cx *EvalContext) error {
return fmt.Errorf("invalid app_params_get field %d", paramField)
}
- app, err := cx.appReference(cx.stack[last].Uint, true)
+ app, err := cx.appReference(cx.Stack[last].Uint, true)
if err != nil {
return err
}
@@ -5011,15 +5028,15 @@ func opAppParamsGet(cx *EvalContext) error {
}
}
- cx.stack[last] = value
- cx.stack = append(cx.stack, stackValue{Uint: exist})
+ cx.Stack[last] = value
+ cx.Stack = append(cx.Stack, stackValue{Uint: exist})
return nil
}
func opAcctParamsGet(cx *EvalContext) error {
- last := len(cx.stack) - 1 // acct
+ last := len(cx.Stack) - 1 // acct
- addr, _, err := cx.accountReference(cx.stack[last])
+ addr, _, err := cx.accountReference(cx.Stack[last])
if err != nil {
return err
}
@@ -5065,24 +5082,24 @@ func opAcctParamsGet(cx *EvalContext) error {
case AcctTotalBoxBytes:
value.Uint = account.TotalBoxBytes
}
- cx.stack[last] = value
- cx.stack = append(cx.stack, boolToSV(account.MicroAlgos.Raw > 0))
+ cx.Stack[last] = value
+ cx.Stack = append(cx.Stack, boolToSV(account.MicroAlgos.Raw > 0))
return nil
}
func opLog(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
if uint64(len(cx.txn.EvalDelta.Logs)) >= cx.MaxLogCalls {
return fmt.Errorf("too many log calls in program. up to %d is allowed", cx.MaxLogCalls)
}
- log := cx.stack[last]
+ log := cx.Stack[last]
cx.logSize += len(log.Bytes)
if uint64(cx.logSize) > cx.MaxLogSize {
return fmt.Errorf("program logs too large. %d bytes > %d bytes limit", cx.logSize, cx.MaxLogSize)
}
cx.txn.EvalDelta.Logs = append(cx.txn.EvalDelta.Logs, string(log.Bytes))
- cx.stack = cx.stack[:last]
+ cx.Stack = cx.Stack[:last]
return nil
}
@@ -5492,15 +5509,15 @@ func opItxnField(cx *EvalContext) error {
if itx < 0 {
return errors.New("itxn_field without itxn_begin")
}
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
field := TxnField(cx.program[cx.pc+1])
fs, ok := txnFieldSpecByField(field)
if !ok || fs.itxVersion == 0 || fs.itxVersion > cx.version {
return fmt.Errorf("invalid itxn_field %s", field)
}
- sv := cx.stack[last]
+ sv := cx.Stack[last]
err := cx.stackIntoTxnField(sv, &fs, &cx.subtxns[itx].Txn)
- cx.stack = cx.stack[:last] // pop
+ cx.Stack = cx.Stack[:last] // pop
return err
}
@@ -5705,19 +5722,19 @@ func (rm rawMessage) ToBeHashed() (protocol.HashID, []byte) {
}
func opVrfVerify(cx *EvalContext) error {
- last := len(cx.stack) - 1 // PK
+ last := len(cx.Stack) - 1 // PK
prev := last - 1 // proof
pprev := prev - 1 // data
- data := rawMessage(cx.stack[pprev].Bytes)
- proofbytes := cx.stack[prev].Bytes
+ data := rawMessage(cx.Stack[pprev].Bytes)
+ proofbytes := cx.Stack[prev].Bytes
var proof crypto.VrfProof
if len(proofbytes) != len(proof) {
return fmt.Errorf("vrf proof wrong size %d != %d", len(proofbytes), len(proof))
}
copy(proof[:], proofbytes[:])
- pubkeybytes := cx.stack[last].Bytes
+ pubkeybytes := cx.Stack[last].Bytes
var pubkey crypto.VrfPubkey
if len(pubkeybytes) != len(pubkey) {
return fmt.Errorf("vrf pubkey wrong size %d != %d", len(pubkeybytes), len(pubkey))
@@ -5740,9 +5757,9 @@ func opVrfVerify(cx *EvalContext) error {
return fmt.Errorf("unsupported vrf_verify standard %s", std)
}
- cx.stack[pprev].Bytes = output[:]
- cx.stack[prev] = boolToSV(verified)
- cx.stack = cx.stack[:last] // pop 1 because we take 3 args and return 2
+ cx.Stack[pprev].Bytes = output[:]
+ cx.Stack[prev] = boolToSV(verified)
+ cx.Stack = cx.Stack[:last] // pop 1 because we take 3 args and return 2
return nil
}
@@ -5766,8 +5783,8 @@ func (cx *EvalContext) availableRound(r uint64) (basics.Round, error) {
}
func opBlock(cx *EvalContext) error {
- last := len(cx.stack) - 1 // round
- round, err := cx.availableRound(cx.stack[last].Uint)
+ last := len(cx.Stack) - 1 // round
+ round, err := cx.availableRound(cx.Stack[last].Uint)
if err != nil {
return err
}
@@ -5784,14 +5801,14 @@ func opBlock(cx *EvalContext) error {
switch fs.field {
case BlkSeed:
- cx.stack[last].Bytes = hdr.Seed[:]
+ cx.Stack[last].Bytes = hdr.Seed[:]
return nil
case BlkTimestamp:
- cx.stack[last].Bytes = nil
+ cx.Stack[last].Bytes = nil
if hdr.TimeStamp < 0 {
return fmt.Errorf("block(%d) timestamp %d < 0", round, hdr.TimeStamp)
}
- cx.stack[last].Uint = uint64(hdr.TimeStamp)
+ cx.Stack[last].Uint = uint64(hdr.TimeStamp)
return nil
default:
return fmt.Errorf("invalid block field %d", fs.field)
@@ -5851,7 +5868,7 @@ func base64padded(encoded []byte) bool {
}
func opBase64Decode(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
encodingField := Base64Encoding(cx.program[cx.pc+1])
fs, ok := base64EncodingSpecByField(encodingField)
if !ok || fs.version > cx.version {
@@ -5862,7 +5879,7 @@ func opBase64Decode(cx *EvalContext) error {
if encodingField == StdEncoding {
encoding = base64.StdEncoding
}
- encoded := cx.stack[last].Bytes
+ encoded := cx.Stack[last].Bytes
if !base64padded(encoded) {
encoding = encoding.WithPadding(base64.NoPadding)
}
@@ -5870,7 +5887,7 @@ func opBase64Decode(cx *EvalContext) error {
if err != nil {
return err
}
- cx.stack[last].Bytes = bytes
+ cx.Stack[last].Bytes = bytes
return nil
}
@@ -5921,9 +5938,9 @@ func parseJSON(jsonText []byte) (map[string]json.RawMessage, error) {
func opJSONRef(cx *EvalContext) error {
// get json key
- last := len(cx.stack) - 1
- key := string(cx.stack[last].Bytes)
- cx.stack = cx.stack[:last] // pop
+ last := len(cx.Stack) - 1
+ key := string(cx.Stack[last].Bytes)
+ cx.Stack = cx.Stack[:last] // pop
expectedType := JSONRefType(cx.program[cx.pc+1])
fs, ok := jsonRefSpecByField(expectedType)
@@ -5932,8 +5949,8 @@ func opJSONRef(cx *EvalContext) error {
}
// parse json text
- last = len(cx.stack) - 1
- parsed, err := parseJSON(cx.stack[last].Bytes)
+ last = len(cx.Stack) - 1
+ parsed, err := parseJSON(cx.Stack[last].Bytes)
if err != nil {
return fmt.Errorf("error while parsing JSON text, %v", err)
}
@@ -5945,7 +5962,7 @@ func opJSONRef(cx *EvalContext) error {
// if the key is not found, first check whether the JSON text is the null value
// by checking whether it is a primitive JSON value. Any other primitive
// (or array) would have thrown an error previously during `parseJSON`.
- isPrimitive, err := isPrimitiveJSON(cx.stack[last].Bytes)
+ isPrimitive, err := isPrimitiveJSON(cx.Stack[last].Bytes)
if err == nil && isPrimitive {
err = fmt.Errorf("invalid json text, only json object is allowed")
}
@@ -5981,6 +5998,6 @@ func opJSONRef(cx *EvalContext) error {
default:
return fmt.Errorf("unsupported json_ref return type %s", expectedType)
}
- cx.stack[last] = stval
+ cx.Stack[last] = stval
return nil
}
diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go
index 4a43c273e..17759ef67 100644
--- a/data/transactions/logic/evalStateful_test.go
+++ b/data/transactions/logic/evalStateful_test.go
@@ -2874,9 +2874,9 @@ func TestReturnTypes(t *testing.T) {
require.NoError(t, err, "%s: %s\n%s", name, err, ep.Trace)
}
}
- require.Len(t, cx.stack, len(spec.Return.Types), "%s", ep.Trace)
+ require.Len(t, cx.Stack, len(spec.Return.Types), "%s", ep.Trace)
for i := 0; i < len(spec.Return.Types); i++ {
- stackType := cx.stack[i].stackType()
+ stackType := cx.Stack[i].stackType()
retType := spec.Return.Types[i]
require.True(
t, stackType.overlaps(retType),
diff --git a/data/transactions/logic/frames.go b/data/transactions/logic/frames.go
index b8abc6057..07a8bf665 100644
--- a/data/transactions/logic/frames.go
+++ b/data/transactions/logic/frames.go
@@ -27,8 +27,8 @@ func opProto(cx *EvalContext) error {
}
cx.fromCallsub = false
nargs := int(cx.program[cx.pc+1])
- if nargs > len(cx.stack) {
- return fmt.Errorf("callsub to proto that requires %d args with stack height %d", nargs, len(cx.stack))
+ if nargs > len(cx.Stack) {
+ return fmt.Errorf("callsub to proto that requires %d args with stack height %d", nargs, len(cx.Stack))
}
top := len(cx.callstack) - 1
cx.callstack[top].clear = true
@@ -51,18 +51,18 @@ func opFrameDig(cx *EvalContext) error {
return fmt.Errorf("frame_dig %d in sub with %d args", i, topFrame.args)
}
idx := topFrame.height + int(i)
- if idx >= len(cx.stack) {
+ if idx >= len(cx.Stack) {
return errors.New("frame_dig above stack")
}
if idx < 0 {
return errors.New("frame_dig below stack")
}
- cx.stack = append(cx.stack, cx.stack[idx])
+ cx.Stack = append(cx.Stack, cx.Stack[idx])
return nil
}
func opFrameBury(cx *EvalContext) error {
- last := len(cx.stack) - 1 // value
+ last := len(cx.Stack) - 1 // value
i := int8(cx.program[cx.pc+1])
top := len(cx.callstack) - 1
@@ -82,42 +82,42 @@ func opFrameBury(cx *EvalContext) error {
if idx < 0 {
return errors.New("frame_bury below stack")
}
- cx.stack[idx] = cx.stack[last]
- cx.stack = cx.stack[:last] // pop value
+ cx.Stack[idx] = cx.Stack[last]
+ cx.Stack = cx.Stack[:last] // pop value
return nil
}
func opBury(cx *EvalContext) error {
- last := len(cx.stack) - 1 // value
+ last := len(cx.Stack) - 1 // value
i := int(cx.program[cx.pc+1])
idx := last - i
if idx < 0 || idx == last {
return errors.New("bury outside stack")
}
- cx.stack[idx] = cx.stack[last]
- cx.stack = cx.stack[:last] // pop value
+ cx.Stack[idx] = cx.Stack[last]
+ cx.Stack = cx.Stack[:last] // pop value
return nil
}
func opPopN(cx *EvalContext) error {
n := cx.program[cx.pc+1]
- top := len(cx.stack) - int(n)
+ top := len(cx.Stack) - int(n)
if top < 0 {
- return fmt.Errorf("popn %d while stack contains %d", n, len(cx.stack))
+ return fmt.Errorf("popn %d while stack contains %d", n, len(cx.Stack))
}
- cx.stack = cx.stack[:top] // pop value
+ cx.Stack = cx.Stack[:top] // pop value
return nil
}
func opDupN(cx *EvalContext) error {
- last := len(cx.stack) - 1 // value
+ last := len(cx.Stack) - 1 // value
n := int(cx.program[cx.pc+1])
- finalLen := len(cx.stack) + n
+ finalLen := len(cx.Stack) + n
cx.ensureStackCap(finalLen)
for i := 0; i < n; i++ {
// There will be enough room that this will not allocate
- cx.stack = append(cx.stack, cx.stack[last])
+ cx.Stack = append(cx.Stack, cx.Stack[last])
}
return nil
}
diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go
index 6410c8088..f0454be6b 100644
--- a/data/transactions/logic/opcodes.go
+++ b/data/transactions/logic/opcodes.go
@@ -361,11 +361,145 @@ type typedList struct {
Effects string
}
+// debugStackExplain explains the effect of an opcode over the stack
+// with 2 integers: deletions and additions, representing pops and inserts.
+// An opcode may delete a few variables from stack, then add a few to stack.
+type debugStackExplain func(*EvalContext) (int, int)
+
// Proto describes the "stack behavior" of an opcode, what it pops as arguments
// and pushes onto the stack as return values.
type Proto struct {
Arg typedList // what gets popped from the stack
Return typedList // what gets pushed to the stack
+
+ // Explain is the pointer to the function used in debugging process during simulation:
+ // - on default construction, Explain relies on Arg and Return count.
+ // - otherwise, we need to explicitly infer from EvalContext, by registering through explain function
+ Explain debugStackExplain
+}
+
+func (p Proto) stackExplain(e debugStackExplain) Proto {
+ p.Explain = e
+ return p
+}
+
+func defaultDebugExplain(argCount, retCount int) debugStackExplain {
+ return func(_ *EvalContext) (deletions, additions int) {
+ deletions = argCount
+ additions = retCount
+ return
+ }
+}
+
+func opPushIntsStackChange(cx *EvalContext) (deletions, additions int) {
+ // NOTE: WE ARE SWALLOWING THE ERROR HERE!
+ // FOR EVENTUALLY IT WOULD ERROR IN ASSEMBLY
+ intc, _, _ := parseIntImmArgs(cx.program, cx.pc+1)
+
+ additions = len(intc)
+ return
+}
+
+func opPushBytessStackChange(cx *EvalContext) (deletions, additions int) {
+ // NOTE: WE ARE SWALLOWING THE ERROR HERE!
+ // FOR EVENTUALLY IT WOULD ERROR IN ASSEMBLY
+ cbytess, _, _ := parseByteImmArgs(cx.program, cx.pc+1)
+
+ additions = len(cbytess)
+ return
+}
+
+func opReturnStackChange(cx *EvalContext) (deletions, additions int) {
+ deletions = len(cx.Stack)
+ additions = 1
+ return
+}
+
+func opBuryStackChange(cx *EvalContext) (deletions, additions int) {
+ depth := int(cx.program[cx.pc+1])
+
+ deletions = depth + 1
+ additions = depth
+ return
+}
+
+func opPopNStackChange(cx *EvalContext) (deletions, additions int) {
+ n := int(cx.program[cx.pc+1])
+
+ deletions = n
+ return
+}
+
+func opDupNStackChange(cx *EvalContext) (deletions, additions int) {
+ n := int(cx.program[cx.pc+1])
+
+ deletions = 1
+ additions = n + 1
+ return
+}
+
+func opDigStackChange(cx *EvalContext) (deletions, additions int) {
+ additions = 1
+ return
+}
+
+func opFrameDigStackChange(cx *EvalContext) (deletions, additions int) {
+ additions = 1
+ return
+}
+
+func opCoverStackChange(cx *EvalContext) (deletions, additions int) {
+ depth := int(cx.program[cx.pc+1])
+
+ deletions = depth + 1
+ additions = depth + 1
+ return
+}
+
+func opUncoverStackChange(cx *EvalContext) (deletions, additions int) {
+ depth := int(cx.program[cx.pc+1])
+
+ deletions = depth + 1
+ additions = depth + 1
+ return
+}
+
+func opRetSubStackChange(cx *EvalContext) (deletions, additions int) {
+ topFrame := cx.callstack[len(cx.callstack)-1]
+ // fast path, no proto case
+ if !topFrame.clear {
+ return
+ }
+
+ argStart := topFrame.height - topFrame.args
+ topStackIdx := len(cx.Stack) - 1
+
+ diff := topStackIdx - argStart + 1
+
+ deletions = diff
+ additions = topFrame.returns
+ return
+}
+
+func opFrameBuryStackChange(cx *EvalContext) (deletions, additions int) {
+ topFrame := cx.callstack[len(cx.callstack)-1]
+
+ immIndex := int8(cx.program[cx.pc+1])
+ idx := topFrame.height + int(immIndex)
+ topStackIdx := len(cx.Stack) - 1
+
+ diff := topStackIdx - idx + 1
+
+ deletions = diff
+ additions = diff - 1
+ return
+}
+
+func opMatchStackChange(cx *EvalContext) (deletions, additions int) {
+ labelNum := int(cx.program[cx.pc+1])
+
+ deletions = labelNum + 1
+ return
}
func proto(signature string, effects ...string) Proto {
@@ -385,9 +519,13 @@ func proto(signature string, effects ...string) Proto {
default:
panic(effects)
}
+ argTypes := parseStackTypes(parts[0])
+ retTypes := parseStackTypes(parts[1])
+ debugExplainFunc := defaultDebugExplain(len(filterNoneTypes(argTypes)), len(filterNoneTypes(retTypes)))
return Proto{
- Arg: typedList{parseStackTypes(parts[0]), argEffect},
- Return: typedList{parseStackTypes(parts[1]), retEffect},
+ Arg: typedList{argTypes, argEffect},
+ Return: typedList{retTypes, retEffect},
+ Explain: debugExplainFunc,
}
}
@@ -520,19 +658,19 @@ var OpSpecs = []OpSpec{
{0x40, "bnz", opBnz, proto("i:"), 1, detBranch()},
{0x41, "bz", opBz, proto("i:"), 2, detBranch()},
{0x42, "b", opB, proto(":"), 2, detBranch()},
- {0x43, "return", opReturn, proto("i:x"), 2, detDefault()},
+ {0x43, "return", opReturn, proto("i:x").stackExplain(opReturnStackChange), 2, detDefault()},
{0x44, "assert", opAssert, proto("i:"), 3, detDefault()},
- {0x45, "bury", opBury, proto("a:"), fpVersion, immediates("n").typed(typeBury)},
- {0x46, "popn", opPopN, proto(":", "[N items]", ""), fpVersion, immediates("n").typed(typePopN).trust()},
- {0x47, "dupn", opDupN, proto("a:", "", "A, [N copies of A]"), fpVersion, immediates("n").typed(typeDupN).trust()},
+ {0x45, "bury", opBury, proto("a:").stackExplain(opBuryStackChange), fpVersion, immediates("n").typed(typeBury)},
+ {0x46, "popn", opPopN, proto(":", "[N items]", "").stackExplain(opPopNStackChange), fpVersion, immediates("n").typed(typePopN).trust()},
+ {0x47, "dupn", opDupN, proto("a:", "", "A, [N copies of A]").stackExplain(opDupNStackChange), fpVersion, immediates("n").typed(typeDupN).trust()},
{0x48, "pop", opPop, proto("a:"), 1, detDefault()},
{0x49, "dup", opDup, proto("a:aa", "A, A"), 1, typed(typeDup)},
{0x4a, "dup2", opDup2, proto("aa:aaaa", "A, B, A, B"), 2, typed(typeDupTwo)},
- {0x4b, "dig", opDig, proto("a:aa", "A, [N items]", "A, [N items], A"), 3, immediates("n").typed(typeDig)},
+ {0x4b, "dig", opDig, proto("a:aa", "A, [N items]", "A, [N items], A").stackExplain(opDigStackChange), 3, immediates("n").typed(typeDig)},
{0x4c, "swap", opSwap, proto("aa:aa", "B, A"), 3, typed(typeSwap)},
{0x4d, "select", opSelect, proto("aai:a", "A or B"), 3, typed(typeSelect)},
- {0x4e, "cover", opCover, proto("a:a", "[N items], A", "A, [N items]"), 5, immediates("n").typed(typeCover)},
- {0x4f, "uncover", opUncover, proto("a:a", "A, [N items]", "[N items], A"), 5, immediates("n").typed(typeUncover)},
+ {0x4e, "cover", opCover, proto("a:a", "[N items], A", "A, [N items]").stackExplain(opCoverStackChange), 5, immediates("n").typed(typeCover)},
+ {0x4f, "uncover", opUncover, proto("a:a", "A, [N items]", "[N items], A").stackExplain(opUncoverStackChange), 5, immediates("n").typed(typeUncover)},
// byteslice processing / StringOps
{0x50, "concat", opConcat, proto("bb:b"), 2, detDefault()},
@@ -580,20 +718,20 @@ var OpSpecs = []OpSpec{
// Immediate bytes and ints. Smaller code size for single use of constant.
{0x80, "pushbytes", opPushBytes, proto(":b"), 3, constants(asmPushBytes, opPushBytes, "bytes", immBytes)},
{0x81, "pushint", opPushInt, proto(":i"), 3, constants(asmPushInt, opPushInt, "uint", immInt)},
- {0x82, "pushbytess", opPushBytess, proto(":", "", "[N items]"), 8, constants(asmPushBytess, checkByteImmArgs, "bytes ...", immBytess).typed(typePushBytess).trust()},
- {0x83, "pushints", opPushInts, proto(":", "", "[N items]"), 8, constants(asmPushInts, checkIntImmArgs, "uint ...", immInts).typed(typePushInts).trust()},
+ {0x82, "pushbytess", opPushBytess, proto(":", "", "[N items]").stackExplain(opPushBytessStackChange), 8, constants(asmPushBytess, checkByteImmArgs, "bytes ...", immBytess).typed(typePushBytess).trust()},
+ {0x83, "pushints", opPushInts, proto(":", "", "[N items]").stackExplain(opPushIntsStackChange), 8, constants(asmPushInts, checkIntImmArgs, "uint ...", immInts).typed(typePushInts).trust()},
{0x84, "ed25519verify_bare", opEd25519VerifyBare, proto("bbb:T"), 7, costly(1900)},
// "Function oriented"
{0x88, "callsub", opCallSub, proto(":"), 4, detBranch()},
- {0x89, "retsub", opRetSub, proto(":"), 4, detDefault().trust()},
+ {0x89, "retsub", opRetSub, proto(":").stackExplain(opRetSubStackChange), 4, detDefault().trust()},
// protoByte is a named constant because opCallSub needs to know it.
{protoByte, "proto", opProto, proto(":"), fpVersion, immediates("a", "r").typed(typeProto)},
- {0x8b, "frame_dig", opFrameDig, proto(":a"), fpVersion, immKinded(immInt8, "i").typed(typeFrameDig)},
- {0x8c, "frame_bury", opFrameBury, proto("a:"), fpVersion, immKinded(immInt8, "i").typed(typeFrameBury)},
+ {0x8b, "frame_dig", opFrameDig, proto(":a").stackExplain(opFrameDigStackChange), fpVersion, immKinded(immInt8, "i").typed(typeFrameDig)},
+ {0x8c, "frame_bury", opFrameBury, proto("a:").stackExplain(opFrameBuryStackChange), fpVersion, immKinded(immInt8, "i").typed(typeFrameBury)},
{0x8d, "switch", opSwitch, proto("i:"), 8, detSwitch()},
- {0x8e, "match", opMatch, proto(":", "[A1, A2, ..., AN], B", ""), 8, detSwitch().trust()},
+ {0x8e, "match", opMatch, proto(":", "[A1, A2, ..., AN], B", "").stackExplain(opMatchStackChange), 8, detSwitch().trust()},
// More math
{0x90, "shl", opShiftLeft, proto("ii:i"), 4, detDefault()},
diff --git a/data/transactions/logic/pairing.go b/data/transactions/logic/pairing.go
index 315caac70..2988c35ec 100644
--- a/data/transactions/logic/pairing.go
+++ b/data/transactions/logic/pairing.go
@@ -65,10 +65,10 @@ func bN254G1ToBytes(g1 *bn254.G1Affine) (ret []byte) {
}
func opBn256Add(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- aBytes := cx.stack[prev].Bytes
- bBytes := cx.stack[last].Bytes
+ aBytes := cx.Stack[prev].Bytes
+ bBytes := cx.Stack[last].Bytes
if len(aBytes) != 64 || len(bBytes) != 64 {
return errors.New("expect G1 in 64 bytes")
}
@@ -76,40 +76,40 @@ func opBn256Add(cx *EvalContext) error {
b := bytesToBN254G1(bBytes)
res := new(bn254.G1Affine).Add(&a, &b)
resBytes := bN254G1ToBytes(res)
- cx.stack = cx.stack[:last]
- cx.stack[prev].Bytes = resBytes
+ cx.Stack = cx.Stack[:last]
+ cx.Stack[prev].Bytes = resBytes
return nil
}
func opBn256ScalarMul(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- aBytes := cx.stack[prev].Bytes
+ aBytes := cx.Stack[prev].Bytes
if len(aBytes) != 64 {
return errors.New("expect G1 in 64 bytes")
}
a := bytesToBN254G1(aBytes)
- kBytes := cx.stack[last].Bytes
+ kBytes := cx.Stack[last].Bytes
k := new(big.Int).SetBytes(kBytes[:])
res := new(bn254.G1Affine).ScalarMultiplication(&a, k)
resBytes := bN254G1ToBytes(res)
- cx.stack = cx.stack[:last]
- cx.stack[prev].Bytes = resBytes
+ cx.Stack = cx.Stack[:last]
+ cx.Stack[prev].Bytes = resBytes
return nil
}
func opBn256Pairing(cx *EvalContext) error {
- last := len(cx.stack) - 1
+ last := len(cx.Stack) - 1
prev := last - 1
- g1Bytes := cx.stack[prev].Bytes
- g2Bytes := cx.stack[last].Bytes
+ g1Bytes := cx.Stack[prev].Bytes
+ g2Bytes := cx.Stack[last].Bytes
g1 := bytesToBN254G1s(g1Bytes)
g2 := bytesToBN254G2s(g2Bytes)
ok, err := bn254.PairingCheck(g1, g2)
if err != nil {
return errors.New("pairing failed")
}
- cx.stack = cx.stack[:last]
- cx.stack[prev] = boolToSV(ok)
+ cx.Stack = cx.Stack[:last]
+ cx.Stack[prev] = boolToSV(ok)
return nil
}
diff --git a/docker/Dockerfile b/docker/Dockerfile
index c4395ecd2..db01e6fad 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -2,7 +2,7 @@ FROM ubuntu:22.04
ARG GOLANG_VERSION
ENV DEBIAN_FRONTEND noninteractive
-RUN apt update && apt-get install -y git wget sqlite3 autoconf sudo tzdata bsdmainutils
+RUN apt update && apt-get install -y git wget autoconf sudo tzdata bsdmainutils
WORKDIR /root
RUN wget --quiet https://dl.google.com/go/go${GOLANG_VERSION}.linux-amd64.tar.gz && tar -xvf go${GOLANG_VERSION}.linux-amd64.tar.gz && mv go /usr/local
diff --git a/docker/build/Dockerfile b/docker/build/Dockerfile
index 68591b2b4..5d096cbab 100644
--- a/docker/build/Dockerfile
+++ b/docker/build/Dockerfile
@@ -1,7 +1,7 @@
FROM ubuntu:20.04
ARG GOLANG_VERSION
-RUN apt-get update && apt-get install -y git wget sqlite3 autoconf build-essential shellcheck
+RUN apt-get update && apt-get install -y git wget autoconf build-essential shellcheck
WORKDIR /root
RUN wget --quiet https://dl.google.com/go/go${GOLANG_VERSION}.linux-amd64.tar.gz && tar -xvf go${GOLANG_VERSION}.linux-amd64.tar.gz && mv go /usr/local
ENV GOROOT=/usr/local/go \
diff --git a/docker/build/Dockerfile-deploy b/docker/build/Dockerfile-deploy
index fa927cbae..d01b505f4 100644
--- a/docker/build/Dockerfile-deploy
+++ b/docker/build/Dockerfile-deploy
@@ -1,7 +1,7 @@
FROM --platform=linux/amd64 ubuntu:20.04
ARG GOLANG_VERSION
-RUN apt-get update && apt-get install -y git wget sqlite3 autoconf jq bsdmainutils shellcheck
+RUN apt-get update && apt-get install -y git wget autoconf jq bsdmainutils shellcheck
WORKDIR /root
RUN wget --quiet https://dl.google.com/go/go${GOLANG_VERSION}.linux-amd64.tar.gz && tar -xvf go${GOLANG_VERSION}.linux-amd64.tar.gz && mv go /usr/local
ENV GOROOT=/usr/local/go \
diff --git a/docker/build/cicd.alpine.Dockerfile b/docker/build/cicd.alpine.Dockerfile
index c166ca6ec..c3ef9698a 100644
--- a/docker/build/cicd.alpine.Dockerfile
+++ b/docker/build/cicd.alpine.Dockerfile
@@ -13,8 +13,7 @@ RUN apk update && \
apk add automake && \
apk add fmt && \
apk add build-base && \
- apk add musl-dev && \
- apk add sqlite
+ apk add musl-dev
RUN apk add dpkg && \
wget http://deb.debian.org/debian/pool/main/s/shellcheck/shellcheck_0.5.0-3_armhf.deb && \
diff --git a/docker/build/cicd.centos.Dockerfile b/docker/build/cicd.centos.Dockerfile
index 0445e6b4b..f292e3d22 100644
--- a/docker/build/cicd.centos.Dockerfile
+++ b/docker/build/cicd.centos.Dockerfile
@@ -5,7 +5,7 @@ ARG GOLANG_VERSION
ARG ARCH="amd64"
RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm && \
yum update -y && \
- yum install -y autoconf wget awscli git gnupg2 nfs-utils python3-devel sqlite3 expect jq \
+ yum install -y autoconf wget awscli git gnupg2 nfs-utils python3-devel expect jq \
libtool gcc-c++ libstdc++-devel libstdc++-static rpmdevtools createrepo rpm-sign bzip2 which ShellCheck \
libffi-devel openssl-devel
WORKDIR /root
diff --git a/docker/build/cicd.centos8.Dockerfile b/docker/build/cicd.centos8.Dockerfile
index 651fa0243..28ec63484 100644
--- a/docker/build/cicd.centos8.Dockerfile
+++ b/docker/build/cicd.centos8.Dockerfile
@@ -10,7 +10,6 @@ RUN dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.n
libffi-devel openssl-devel
RUN dnf install -y epel-release && \
dnf update && \
- dnf -y install sqlite && \
dnf -y --enablerepo=powertools install libstdc++-static && \
dnf -y install make
RUN echo "${BOLD}Downloading and installing binaries...${RESET}" && \
diff --git a/docker/build/cicd.ubuntu.Dockerfile b/docker/build/cicd.ubuntu.Dockerfile
index c8702743f..0b9fce77d 100644
--- a/docker/build/cicd.ubuntu.Dockerfile
+++ b/docker/build/cicd.ubuntu.Dockerfile
@@ -5,7 +5,7 @@ ARG GOLANG_VERSION
ARG ARCH="amd64"
ARG GOARCH="amd64"
ENV DEBIAN_FRONTEND noninteractive
-RUN apt-get update && apt-get install -y build-essential git wget sqlite3 autoconf jq bsdmainutils shellcheck awscli libtool
+RUN apt-get update && apt-get install -y build-essential git wget autoconf jq bsdmainutils shellcheck awscli libtool
WORKDIR /root
RUN wget https://dl.google.com/go/go${GOLANG_VERSION}.linux-${GOARCH}.tar.gz \
&& tar -xvf go${GOLANG_VERSION}.linux-${GOARCH}.tar.gz && \
diff --git a/docs/follower_node.md b/docs/follower_node.md
index 9c58a7a82..8df230641 100644
--- a/docs/follower_node.md
+++ b/docs/follower_node.md
@@ -25,6 +25,7 @@ Follower mode was initially created to be a data source for [Conduit](https://gi
Behavior is controlled with the `config.json` file:
| property | description |
+| -------- | ----------- |
| EnableFollowMode | When set to `true` the node starts as a network follower. |
| MaxAcctLookback | The number of additional `Ledger State Delta` objects available. The default can be used, increasing to 64 or higher could help performance. |
| CatchupParallelBlocks | The number of blocks that are fetched concurrently. The default can be used, increasing to 64 or higher could help performance. |
diff --git a/ledger/catchpointtracker.go b/ledger/catchpointtracker.go
index 97051656f..8baccf075 100644
--- a/ledger/catchpointtracker.go
+++ b/ledger/catchpointtracker.go
@@ -201,6 +201,23 @@ func (ct *catchpointTracker) GetLastCatchpointLabel() string {
return ct.lastCatchpointLabel
}
+func (ct *catchpointTracker) getSPVerificationData() (encodedData []byte, spVerificationHash crypto.Digest, err error) {
+ err = ct.dbs.Snapshot(func(ctx context.Context, tx trackerdb.SnapshotScope) error {
+ rawData, dbErr := tx.MakeSpVerificationCtxReader().GetAllSPContexts(ctx)
+ if dbErr != nil {
+ return dbErr
+ }
+
+ wrappedData := catchpointStateProofVerificationContext{Data: rawData}
+ spVerificationHash, encodedData = crypto.EncodeAndHash(wrappedData)
+ return nil
+ })
+ if err != nil {
+ return nil, crypto.Digest{}, err
+ }
+ return encodedData, spVerificationHash, nil
+}
+
func (ct *catchpointTracker) finishFirstStage(ctx context.Context, dbRound basics.Round, updatingBalancesDuration time.Duration) error {
ct.log.Infof("finishing catchpoint's first stage dbRound: %d", dbRound)
@@ -209,8 +226,16 @@ func (ct *catchpointTracker) finishFirstStage(ctx context.Context, dbRound basic
var totalChunks uint64
var biggestChunkLen uint64
var spVerificationHash crypto.Digest
+ var spVerificationEncodedData []byte
var catchpointGenerationStats telemetryspec.CatchpointGenerationEventDetails
+ // Generate the SP Verification hash and encoded data. The hash is used in the label when tracking catchpoints,
+ // and the encoded data for that hash will be added to the catchpoint file if catchpoint generation is enabled.
+ spVerificationEncodedData, spVerificationHash, err := ct.getSPVerificationData()
+ if err != nil {
+ return err
+ }
+
if ct.enableGeneratingCatchpointFiles {
// Generate the catchpoint file. This is done inline so that it will
// block any new accounts from being written. generateCatchpointData()
@@ -219,8 +244,8 @@ func (ct *catchpointTracker) finishFirstStage(ctx context.Context, dbRound basic
var err error
catchpointGenerationStats.BalancesWriteTime = uint64(updatingBalancesDuration.Nanoseconds())
- totalKVs, totalAccounts, totalChunks, biggestChunkLen, spVerificationHash, err = ct.generateCatchpointData(
- ctx, dbRound, &catchpointGenerationStats)
+ totalKVs, totalAccounts, totalChunks, biggestChunkLen, err = ct.generateCatchpointData(
+ ctx, dbRound, &catchpointGenerationStats, spVerificationEncodedData)
atomic.StoreInt32(&ct.catchpointDataWriting, 0)
if err != nil {
return err
@@ -1102,7 +1127,7 @@ func (ct *catchpointTracker) isWritingCatchpointDataFile() bool {
// - Balance and KV chunk (named balances.x.msgpack).
// ...
// - Balance and KV chunk (named balances.x.msgpack).
-func (ct *catchpointTracker) generateCatchpointData(ctx context.Context, accountsRound basics.Round, catchpointGenerationStats *telemetryspec.CatchpointGenerationEventDetails) (totalKVs, totalAccounts, totalChunks, biggestChunkLen uint64, spVerificationHash crypto.Digest, err error) {
+func (ct *catchpointTracker) generateCatchpointData(ctx context.Context, accountsRound basics.Round, catchpointGenerationStats *telemetryspec.CatchpointGenerationEventDetails, encodedSPData []byte) (totalKVs, totalAccounts, totalChunks, biggestChunkLen uint64, err error) {
ct.log.Debugf("catchpointTracker.generateCatchpointData() writing catchpoint accounts for round %d", accountsRound)
startTime := time.Now()
@@ -1126,13 +1151,13 @@ func (ct *catchpointTracker) generateCatchpointData(ctx context.Context, account
start := time.Now()
ledgerGeneratecatchpointCount.Inc(nil)
- err = ct.dbs.TransactionContext(ctx, func(dbCtx context.Context, tx trackerdb.TransactionScope) (err error) {
+ err = ct.dbs.SnapshotContext(ctx, func(dbCtx context.Context, tx trackerdb.SnapshotScope) (err error) {
catchpointWriter, err = makeCatchpointWriter(dbCtx, catchpointDataFilePath, tx, ResourcesPerCatchpointFileChunk)
if err != nil {
return
}
- spVerificationHash, err = catchpointWriter.WriteStateProofVerificationContext()
+ err = catchpointWriter.WriteStateProofVerificationContext(encodedSPData)
if err != nil {
return
}
@@ -1187,7 +1212,7 @@ func (ct *catchpointTracker) generateCatchpointData(ctx context.Context, account
ledgerGeneratecatchpointMicros.AddMicrosecondsSince(start, nil)
if err != nil {
ct.log.Warnf("catchpointTracker.generateCatchpointData() %v", err)
- return 0, 0, 0, 0, crypto.Digest{}, err
+ return 0, 0, 0, 0, err
}
catchpointGenerationStats.FileSize = uint64(catchpointWriter.writtenBytes)
@@ -1196,7 +1221,7 @@ func (ct *catchpointTracker) generateCatchpointData(ctx context.Context, account
catchpointGenerationStats.KVsCount = catchpointWriter.totalKVs
catchpointGenerationStats.AccountsRound = uint64(accountsRound)
- return catchpointWriter.totalKVs, catchpointWriter.totalAccounts, catchpointWriter.chunkNum, catchpointWriter.biggestChunkLen, spVerificationHash, nil
+ return catchpointWriter.totalKVs, catchpointWriter.totalAccounts, catchpointWriter.chunkNum, catchpointWriter.biggestChunkLen, nil
}
func (ct *catchpointTracker) recordFirstStageInfo(ctx context.Context, tx trackerdb.TransactionScope, catchpointGenerationStats *telemetryspec.CatchpointGenerationEventDetails, accountsRound basics.Round, totalKVs uint64, totalAccounts uint64, totalChunks uint64, biggestChunkLen uint64, stateProofVerificationHash crypto.Digest) error {
@@ -1316,7 +1341,7 @@ func (ct *catchpointTracker) GetCatchpointStream(round basics.Round) (ReadCloseS
ledgerGetcatchpointCount.Inc(nil)
// TODO: we need to generalize this, check @cce PoC PR, he has something
// somewhat broken for some KVs..
- err := ct.dbs.Transaction(func(ctx context.Context, tx trackerdb.TransactionScope) (err error) {
+ err := ct.dbs.Snapshot(func(ctx context.Context, tx trackerdb.SnapshotScope) (err error) {
cr, err := tx.MakeCatchpointReader()
if err != nil {
return err
diff --git a/ledger/catchpointtracker_test.go b/ledger/catchpointtracker_test.go
index f007217b0..6669eab4a 100644
--- a/ledger/catchpointtracker_test.go
+++ b/ledger/catchpointtracker_test.go
@@ -328,9 +328,12 @@ func TestRecordCatchpointFile(t *testing.T) {
}
func createCatchpoint(t *testing.T, ct *catchpointTracker, accountsRound basics.Round, ml *mockLedgerForTracker, round basics.Round) {
+ spVerificationEncodedData, stateProofVerificationHash, err := ct.getSPVerificationData()
+ require.NoError(t, err)
+
var catchpointGenerationStats telemetryspec.CatchpointGenerationEventDetails
- _, _, _, biggestChunkLen, stateProofVerificationHash, err := ct.generateCatchpointData(
- context.Background(), accountsRound, &catchpointGenerationStats)
+ _, _, _, biggestChunkLen, err := ct.generateCatchpointData(
+ context.Background(), accountsRound, &catchpointGenerationStats, spVerificationEncodedData)
require.NoError(t, err)
require.Equal(t, calculateStateProofVerificationHash(t, ml), stateProofVerificationHash)
@@ -460,8 +463,10 @@ func BenchmarkLargeCatchpointDataWriting(b *testing.B) {
require.NoError(b, err)
var catchpointGenerationStats telemetryspec.CatchpointGenerationEventDetails
+ encodedSPData, _, err := ct.getSPVerificationData()
+ require.NoError(b, err)
b.ResetTimer()
- ct.generateCatchpointData(context.Background(), basics.Round(0), &catchpointGenerationStats)
+ ct.generateCatchpointData(context.Background(), basics.Round(0), &catchpointGenerationStats, encodedSPData)
b.StopTimer()
b.ReportMetric(float64(accountsNumber), "accounts")
}
@@ -469,7 +474,7 @@ func BenchmarkLargeCatchpointDataWriting(b *testing.B) {
func TestCatchpointReproducibleLabels(t *testing.T) {
partitiontest.PartitionTest(t)
- if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
+ if runtime.GOARCH == "arm" {
t.Skip("This test is too slow on ARM and causes CI builds to time out")
}
@@ -592,7 +597,12 @@ func TestCatchpointReproducibleLabels(t *testing.T) {
ml2 := ledgerHistory[rnd]
require.NotNil(t, ml2)
- ct2 := newCatchpointTracker(t, ml2, cfg, ".")
+ cfg2 := cfg
+ // every other iteration modify CatchpointTracking to ensure labels generation does not depends on catchpoint file creation
+ if rnd%2 == 0 {
+ cfg2.CatchpointTracking = int64(crypto.RandUint63())%2 + 1 //values 1 or 2
+ }
+ ct2 := newCatchpointTracker(t, ml2, cfg2, ".")
defer ct2.close()
for i := rnd + 1; i <= lastRound; i++ {
blk := bookkeeping.Block{
diff --git a/ledger/catchpointwriter.go b/ledger/catchpointwriter.go
index 4c22e035b..763c6f9a3 100644
--- a/ledger/catchpointwriter.go
+++ b/ledger/catchpointwriter.go
@@ -24,7 +24,6 @@ import (
"os"
"path/filepath"
- "github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/ledger/encoded"
"github.com/algorand/go-algorand/ledger/ledgercore"
"github.com/algorand/go-algorand/ledger/store/trackerdb"
@@ -53,7 +52,7 @@ const (
// has the option of throttling the CPU utilization in between the calls.
type catchpointWriter struct {
ctx context.Context
- tx trackerdb.TransactionScope
+ tx trackerdb.SnapshotScope
filePath string
totalAccounts uint64
totalKVs uint64
@@ -107,7 +106,7 @@ func (data catchpointStateProofVerificationContext) ToBeHashed() (protocol.HashI
return protocol.StateProofVerCtx, protocol.Encode(&data)
}
-func makeCatchpointWriter(ctx context.Context, filePath string, tx trackerdb.TransactionScope, maxResourcesPerChunk int) (*catchpointWriter, error) {
+func makeCatchpointWriter(ctx context.Context, filePath string, tx trackerdb.SnapshotScope, maxResourcesPerChunk int) (*catchpointWriter, error) {
aw, err := tx.MakeAccountsReader()
if err != nil {
return nil, err
@@ -160,35 +159,27 @@ func (cw *catchpointWriter) Abort() error {
return os.Remove(cw.filePath)
}
-func (cw *catchpointWriter) WriteStateProofVerificationContext() (crypto.Digest, error) {
- rawData, err := cw.tx.MakeSpVerificationCtxReader().GetAllSPContexts(cw.ctx)
- if err != nil {
- return crypto.Digest{}, err
- }
-
- wrappedData := catchpointStateProofVerificationContext{Data: rawData}
- dataHash, encodedData := crypto.EncodeAndHash(wrappedData)
-
- err = cw.tar.WriteHeader(&tar.Header{
+func (cw *catchpointWriter) WriteStateProofVerificationContext(encodedData []byte) error {
+ err := cw.tar.WriteHeader(&tar.Header{
Name: catchpointSPVerificationFileName,
Mode: 0600,
Size: int64(len(encodedData)),
})
if err != nil {
- return crypto.Digest{}, err
+ return err
}
_, err = cw.tar.Write(encodedData)
if err != nil {
- return crypto.Digest{}, err
+ return err
}
if chunkLen := uint64(len(encodedData)); cw.biggestChunkLen < chunkLen {
cw.biggestChunkLen = chunkLen
}
- return dataHash, nil
+ return nil
}
// WriteStep works for a short period of time (determined by stepCtx) to get
diff --git a/ledger/catchpointwriter_test.go b/ledger/catchpointwriter_test.go
index 1f3c41e7c..d985317a1 100644
--- a/ledger/catchpointwriter_test.go
+++ b/ledger/catchpointwriter_test.go
@@ -151,7 +151,13 @@ func verifyStateProofVerificationContextWrite(t *testing.T, data []ledgercore.St
if err != nil {
return err
}
- _, err = writer.WriteStateProofVerificationContext()
+ rawData, err := tx.MakeSpVerificationCtxReader().GetAllSPContexts(ctx)
+ if err != nil {
+ return err
+ }
+ _, encodedData := crypto.EncodeAndHash(catchpointStateProofVerificationContext{Data: rawData})
+
+ err = writer.WriteStateProofVerificationContext(encodedData)
if err != nil {
return err
}
@@ -260,7 +266,12 @@ func TestBasicCatchpointWriter(t *testing.T) {
if err != nil {
return err
}
- _, err = writer.WriteStateProofVerificationContext()
+ rawData, err := tx.MakeSpVerificationCtxReader().GetAllSPContexts(ctx)
+ if err != nil {
+ return err
+ }
+ _, encodedData := crypto.EncodeAndHash(catchpointStateProofVerificationContext{Data: rawData})
+ err = writer.WriteStateProofVerificationContext(encodedData)
if err != nil {
return err
}
@@ -304,7 +315,12 @@ func testWriteCatchpoint(t *testing.T, rdb trackerdb.Store, datapath string, fil
if err != nil {
return err
}
- _, err = writer.WriteStateProofVerificationContext()
+ rawData, err := tx.MakeSpVerificationCtxReader().GetAllSPContexts(ctx)
+ if err != nil {
+ return err
+ }
+ _, encodedData := crypto.EncodeAndHash(catchpointStateProofVerificationContext{Data: rawData})
+ err = writer.WriteStateProofVerificationContext(encodedData)
if err != nil {
return err
}
diff --git a/ledger/catchupaccessor.go b/ledger/catchupaccessor.go
index 50755833d..b16d3a8fb 100644
--- a/ledger/catchupaccessor.go
+++ b/ledger/catchupaccessor.go
@@ -67,6 +67,9 @@ type CatchpointCatchupAccessor interface {
// GetCatchupBlockRound returns the latest block round matching the current catchpoint
GetCatchupBlockRound(ctx context.Context) (round basics.Round, err error)
+ // GetVerifyData returns the balances hash, spver hash and totals used by VerifyCatchpoint
+ GetVerifyData(ctx context.Context) (balancesHash crypto.Digest, spverHash crypto.Digest, totals ledgercore.AccountTotals, err error)
+
// VerifyCatchpoint verifies that the catchpoint is valid by reconstructing the label.
VerifyCatchpoint(ctx context.Context, blk *bookkeeping.Block) (err error)
@@ -927,34 +930,9 @@ func (c *catchpointCatchupAccessorImpl) GetCatchupBlockRound(ctx context.Context
return basics.Round(iRound), nil
}
-// VerifyCatchpoint verifies that the catchpoint is valid by reconstructing the label.
-func (c *catchpointCatchupAccessorImpl) VerifyCatchpoint(ctx context.Context, blk *bookkeeping.Block) (err error) {
- var balancesHash crypto.Digest
+func (c *catchpointCatchupAccessorImpl) GetVerifyData(ctx context.Context) (balancesHash crypto.Digest, spverHash crypto.Digest, totals ledgercore.AccountTotals, err error) {
var rawStateProofVerificationContext []ledgercore.StateProofVerificationContext
- var blockRound basics.Round
- var totals ledgercore.AccountTotals
- var catchpointLabel string
- var version uint64
-
- catchpointLabel, err = c.catchpointStore.ReadCatchpointStateString(ctx, trackerdb.CatchpointStateCatchupLabel)
- if err != nil {
- return fmt.Errorf("unable to read catchpoint catchup state '%s': %v", trackerdb.CatchpointStateCatchupLabel, err)
- }
-
- version, err = c.catchpointStore.ReadCatchpointStateUint64(ctx, trackerdb.CatchpointStateCatchupVersion)
- if err != nil {
- return fmt.Errorf("unable to retrieve catchpoint version: %v", err)
- }
-
- var iRound uint64
- iRound, err = c.catchpointStore.ReadCatchpointStateUint64(ctx, trackerdb.CatchpointStateCatchupBlockRound)
- if err != nil {
- return fmt.Errorf("unable to read catchpoint catchup state '%s': %v", trackerdb.CatchpointStateCatchupBlockRound, err)
- }
- blockRound = basics.Round(iRound)
- start := time.Now()
- ledgerVerifycatchpointCount.Inc(nil)
err = c.ledger.trackerDB().Transaction(func(ctx context.Context, tx trackerdb.TransactionScope) (err error) {
ar, err := tx.MakeAccountsReader()
if err != nil {
@@ -989,6 +967,42 @@ func (c *catchpointCatchupAccessorImpl) VerifyCatchpoint(ctx context.Context, bl
return
})
+ if err != nil {
+ return crypto.Digest{}, crypto.Digest{}, ledgercore.AccountTotals{}, err
+ }
+
+ wrappedContext := catchpointStateProofVerificationContext{Data: rawStateProofVerificationContext}
+ spverHash = crypto.HashObj(wrappedContext)
+
+ return balancesHash, spverHash, totals, err
+}
+
+// VerifyCatchpoint verifies that the catchpoint is valid by reconstructing the label.
+func (c *catchpointCatchupAccessorImpl) VerifyCatchpoint(ctx context.Context, blk *bookkeeping.Block) (err error) {
+ var blockRound basics.Round
+ var catchpointLabel string
+ var version uint64
+
+ catchpointLabel, err = c.catchpointStore.ReadCatchpointStateString(ctx, trackerdb.CatchpointStateCatchupLabel)
+ if err != nil {
+ return fmt.Errorf("unable to read catchpoint catchup state '%s': %v", trackerdb.CatchpointStateCatchupLabel, err)
+ }
+
+ version, err = c.catchpointStore.ReadCatchpointStateUint64(ctx, trackerdb.CatchpointStateCatchupVersion)
+ if err != nil {
+ return fmt.Errorf("unable to retrieve catchpoint version: %v", err)
+ }
+
+ var iRound uint64
+ iRound, err = c.catchpointStore.ReadCatchpointStateUint64(ctx, trackerdb.CatchpointStateCatchupBlockRound)
+ if err != nil {
+ return fmt.Errorf("unable to read catchpoint catchup state '%s': %v", trackerdb.CatchpointStateCatchupBlockRound, err)
+ }
+ blockRound = basics.Round(iRound)
+
+ start := time.Now()
+ ledgerVerifycatchpointCount.Inc(nil)
+ balancesHash, spVerificationHash, totals, err := c.GetVerifyData(ctx)
ledgerVerifycatchpointMicros.AddMicrosecondsSince(start, nil)
if err != nil {
return err
@@ -997,9 +1011,6 @@ func (c *catchpointCatchupAccessorImpl) VerifyCatchpoint(ctx context.Context, bl
return fmt.Errorf("block round in block header doesn't match block round in catchpoint: %d != %d", blockRound, blk.Round())
}
- wrappedContext := catchpointStateProofVerificationContext{Data: rawStateProofVerificationContext}
- spVerificationHash := crypto.HashObj(wrappedContext)
-
var catchpointLabelMaker ledgercore.CatchpointLabelMaker
blockDigest := blk.Digest()
if version <= CatchpointFileVersionV6 {
diff --git a/ledger/simulation/simulation_eval_test.go b/ledger/simulation/simulation_eval_test.go
index c05dd7f9e..63d46bf53 100644
--- a/ledger/simulation/simulation_eval_test.go
+++ b/ledger/simulation/simulation_eval_test.go
@@ -20,6 +20,7 @@ import (
"encoding/binary"
"encoding/hex"
"fmt"
+ "math"
"strings"
"testing"
@@ -267,6 +268,60 @@ func TestPayTxn(t *testing.T) {
})
}
+func TestIllFormedStackRequest(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ env := simulationtesting.PrepareSimulatorTest(t)
+ defer env.Close()
+
+ sender := env.Accounts[0]
+ futureAppID := basics.AppIndex(1001)
+
+ createTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: 0,
+ ApprovalProgram: `#pragma version 6
+txn ApplicationID
+bz create
+byte "app call"
+log
+b end
+create:
+byte "app creation"
+log
+end:
+int 1`,
+ ClearStateProgram: `#pragma version 6
+int 0`,
+ })
+ callTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: futureAppID,
+ })
+
+ txntest.Group(&createTxn, &callTxn)
+
+ signedCreateTxn := createTxn.Txn().Sign(sender.Sk)
+ signedCallTxn := callTxn.Txn().Sign(sender.Sk)
+
+ simRequest := simulation.Request{
+ TxnGroups: [][]transactions.SignedTxn{
+ {signedCreateTxn, signedCallTxn},
+ },
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: false,
+ Stack: true,
+ },
+ }
+
+ _, err := simulation.MakeSimulator(env.Ledger, true).Simulate(simRequest)
+ require.ErrorAs(t, err, &simulation.InvalidRequestError{})
+ require.ErrorContains(t, err, "basic trace must be enabled when enabling stack tracing")
+}
+
func TestWrongAuthorizerTxn(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()
@@ -2027,7 +2082,59 @@ func TestMaxDepthAppWithPCTrace(t *testing.T) {
})
}
-func TestLogicSigPCExposure(t *testing.T) {
+func goValuesToTealValues(goValues ...interface{}) []basics.TealValue {
+ if len(goValues) == 0 {
+ return nil
+ }
+
+ boolToUint64 := func(b bool) uint64 {
+ if b {
+ return 1
+ }
+ return 0
+ }
+
+ modelValues := make([]basics.TealValue, len(goValues))
+ for i, goValue := range goValues {
+ switch convertedValue := goValue.(type) {
+ case []byte:
+ modelValues[i] = basics.TealValue{
+ Type: basics.TealBytesType,
+ Bytes: string(convertedValue),
+ }
+ case string:
+ modelValues[i] = basics.TealValue{
+ Type: basics.TealBytesType,
+ Bytes: string(convertedValue),
+ }
+ case bool:
+ modelValues[i] = basics.TealValue{
+ Type: basics.TealUintType,
+ Uint: boolToUint64(convertedValue),
+ }
+ case int:
+ modelValues[i] = basics.TealValue{
+ Type: basics.TealUintType,
+ Uint: uint64(convertedValue),
+ }
+ case basics.AppIndex:
+ modelValues[i] = basics.TealValue{
+ Type: basics.TealUintType,
+ Uint: uint64(convertedValue),
+ }
+ case uint64:
+ modelValues[i] = basics.TealValue{
+ Type: basics.TealUintType,
+ Uint: convertedValue,
+ }
+ default:
+ panic("unexpected type inferred from interface{}")
+ }
+ }
+ return modelValues
+}
+
+func TestLogicSigPCandStackExposure(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()
@@ -2061,6 +2168,8 @@ byte "hello"; log; int 1`,
signedAppCallTxn := appCallTxn.SignedTxn()
signedAppCallTxn.Lsig = transactions.LogicSig{Logic: program}
+ keccakBytes := ":\xc2%\x16\x8d\xf5B\x12\xa2\\\x1c\x01\xfd5\xbe\xbf\xea@\x8f\xda\xc2\xe3\x1d\xddo\x80\xa4\xbb\xf9\xa5\xf1\xcb"
+
return simulationTestCase{
input: simulation.Request{
TxnGroups: [][]transactions.SignedTxn{
@@ -2068,6 +2177,7 @@ byte "hello"; log; int 1`,
},
TraceConfig: simulation.ExecTraceConfig{
Enable: true,
+ Stack: true,
},
},
developerAPI: true,
@@ -2076,6 +2186,7 @@ byte "hello"; log; int 1`,
LastRound: env.TxnInfo.LatestRound(),
TraceConfig: simulation.ExecTraceConfig{
Enable: true,
+ Stack: true,
},
TxnGroups: []simulation.TxnGroupResult{
{
@@ -2094,19 +2205,53 @@ byte "hello"; log; int 1`,
LogicSigBudgetConsumed: 266,
Trace: &simulation.TransactionTrace{
ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
- {PC: 1},
- {PC: 8},
- {PC: 9},
+ {
+ PC: 1,
+ StackAdded: goValuesToTealValues("hello"),
+ },
+ {
+ PC: 8,
+ StackPopCount: 1,
+ },
+ {
+ PC: 9,
+ StackAdded: goValuesToTealValues(1),
+ },
},
LogicSigTrace: []simulation.OpcodeTraceUnit{
- {PC: 1},
- {PC: 5},
- {PC: 6},
- {PC: 7},
- {PC: 8},
- {PC: 9},
- {PC: 10},
- {PC: 11},
+ {
+ PC: 1,
+ },
+ {
+ PC: 5,
+ StackAdded: goValuesToTealValues("a"),
+ },
+ {
+ PC: 6,
+ StackAdded: goValuesToTealValues(keccakBytes),
+ StackPopCount: 1,
+ },
+ {
+ PC: 7,
+ StackPopCount: 1,
+ },
+ {
+ PC: 8,
+ StackAdded: goValuesToTealValues("a"),
+ },
+ {
+ PC: 9,
+ StackAdded: goValuesToTealValues(keccakBytes),
+ StackPopCount: 1,
+ },
+ {
+ PC: 10,
+ StackPopCount: 1,
+ },
+ {
+ PC: 11,
+ StackAdded: goValuesToTealValues(1),
+ },
},
},
},
@@ -2120,13 +2265,13 @@ byte "hello"; log; int 1`,
})
}
-func TestFailingLogicSig(t *testing.T) {
+func TestFailingLogicSigPCandStack(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()
op, err := logic.AssembleString(`#pragma version 8
` + strings.Repeat(`byte "a"; keccak256; pop
-`, 2) + `int 0`)
+`, 2) + `int 0; int 1; -`)
require.NoError(t, err)
program := logic.Program(op.Program)
lsigAddr := basics.Address(crypto.HashObj(&program))
@@ -2154,6 +2299,8 @@ byte "hello"; log; int 1`,
signedAppCallTxn := appCallTxn.SignedTxn()
signedAppCallTxn.Lsig = transactions.LogicSig{Logic: program}
+ keccakBytes := ":\xc2%\x16\x8d\xf5B\x12\xa2\\\x1c\x01\xfd5\xbe\xbf\xea@\x8f\xda\xc2\xe3\x1d\xddo\x80\xa4\xbb\xf9\xa5\xf1\xcb"
+
return simulationTestCase{
input: simulation.Request{
TxnGroups: [][]transactions.SignedTxn{
@@ -2161,6 +2308,7 @@ byte "hello"; log; int 1`,
},
TraceConfig: simulation.ExecTraceConfig{
Enable: true,
+ Stack: true,
},
},
developerAPI: true,
@@ -2170,6 +2318,7 @@ byte "hello"; log; int 1`,
LastRound: env.TxnInfo.LatestRound(),
TraceConfig: simulation.ExecTraceConfig{
Enable: true,
+ Stack: true,
},
TxnGroups: []simulation.TxnGroupResult{
{
@@ -2180,17 +2329,50 @@ byte "hello"; log; int 1`,
Txn: transactions.SignedTxnWithAD{
ApplyData: transactions.ApplyData{},
},
- LogicSigBudgetConsumed: 266,
+ LogicSigBudgetConsumed: 268,
Trace: &simulation.TransactionTrace{
LogicSigTrace: []simulation.OpcodeTraceUnit{
- {PC: 1},
- {PC: 5},
- {PC: 6},
- {PC: 7},
- {PC: 8},
- {PC: 9},
- {PC: 10},
- {PC: 11},
+ {
+ PC: 1,
+ },
+ {
+ PC: 5,
+ StackAdded: goValuesToTealValues("a"),
+ },
+ {
+ PC: 6,
+ StackAdded: goValuesToTealValues(keccakBytes),
+ StackPopCount: 1,
+ },
+ {
+ PC: 7,
+ StackPopCount: 1,
+ },
+ {
+ PC: 8,
+ StackAdded: goValuesToTealValues("a"),
+ },
+ {
+ PC: 9,
+ StackAdded: goValuesToTealValues(keccakBytes),
+ StackPopCount: 1,
+ },
+ {
+ PC: 10,
+ StackPopCount: 1,
+ },
+ {
+ PC: 11,
+ StackAdded: goValuesToTealValues(0),
+ },
+ {
+ PC: 13,
+ StackAdded: goValuesToTealValues(1),
+ },
+ {
+ PC: 15,
+ StackPopCount: 2,
+ },
},
},
},
@@ -2297,6 +2479,391 @@ byte "hello"; log; int 0`,
})
}
+const FrameBuryDigProgram = `#pragma version 8
+txn ApplicationID // on creation, always approve
+bz end
+
+txn NumAppArgs
+int 1
+==
+assert
+
+txn ApplicationArgs 0
+btoi
+callsub subroutine_manipulating_stack
+itob
+log
+b end
+
+subroutine_manipulating_stack:
+ proto 1 1
+ int 0 // [0]
+ dup // [0, 0]
+ dupn 4 // [0, 0, 0, 0, 0, 0]
+ frame_dig -1 // [0, 0, 0, 0, 0, 0, arg_0]
+ frame_bury 0 // [arg_0, 0, 0, 0, 0, 0]
+ dig 5 // [arg_0, 0, 0, 0, 0, 0, arg_0]
+ cover 5 // [arg_0, arg_0, 0, 0, 0, 0, 0]
+ frame_dig 0 // [arg_0, arg_0, 0, 0, 0, 0, 0, arg_0]
+ frame_dig 1 // [arg_0, arg_0, 0, 0, 0, 0, 0, arg_0, arg_0]
+ + // [arg_0, arg_0, 0, 0, 0, 0, 0, arg_0 * 2]
+ bury 7 // [arg_0 * 2, arg_0, 0, 0, 0, 0, 0]
+ popn 5 // [arg_0 * 2, arg_0]
+ uncover 1 // [arg_0, arg_0 * 2]
+ swap // [arg_0 * 2, arg_0]
+ + // [arg_0 * 3]
+ pushbytess "1!" "5!" // [arg_0 * 3, "1!", "5!"]
+ pushints 0 2 1 1 5 18446744073709551615 // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1, 5, 18446744073709551615]
+ store 1 // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1, 5]
+ load 1 // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1, 5, 18446744073709551615]
+ stores // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1]
+ load 1 // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1, 18446744073709551615]
+ store 1 // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1]
+ retsub
+
+end:
+ int 1
+ return
+`
+
+func TestFrameBuryDigStackTrace(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ simulationTest(t, func(env simulationtesting.Environment) simulationTestCase {
+ sender := env.Accounts[0]
+
+ futureAppID := basics.AppIndex(1001)
+
+ applicationArg := 10
+
+ createTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: 0,
+ ApprovalProgram: FrameBuryDigProgram,
+ ClearStateProgram: `#pragma version 8
+int 1`,
+ })
+ payment := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.PaymentTx,
+ Sender: sender.Addr,
+ Receiver: futureAppID.Address(),
+ Amount: env.TxnInfo.CurrentProtocolParams().MinBalance,
+ })
+ callTxn := env.TxnInfo.NewTxn(txntest.Txn{
+ Type: protocol.ApplicationCallTx,
+ Sender: sender.Addr,
+ ApplicationID: futureAppID,
+ ApplicationArgs: [][]byte{{byte(applicationArg)}},
+ })
+ txntest.Group(&createTxn, &payment, &callTxn)
+
+ signedCreate := createTxn.Txn().Sign(sender.Sk)
+ signedPay := payment.Txn().Sign(sender.Sk)
+ signedAppCall := callTxn.Txn().Sign(sender.Sk)
+
+ return simulationTestCase{
+ input: simulation.Request{
+ TxnGroups: [][]transactions.SignedTxn{
+ {signedCreate, signedPay, signedAppCall},
+ },
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: true,
+ Stack: true,
+ Scratch: true,
+ },
+ },
+ developerAPI: true,
+ expected: simulation.Result{
+ Version: simulation.ResultLatestVersion,
+ LastRound: env.TxnInfo.LatestRound(),
+ TraceConfig: simulation.ExecTraceConfig{
+ Enable: true,
+ Stack: true,
+ Scratch: true,
+ },
+ TxnGroups: []simulation.TxnGroupResult{
+ {
+ Txns: []simulation.TxnResult{
+ {
+ Txn: transactions.SignedTxnWithAD{
+ ApplyData: transactions.ApplyData{
+ ApplicationID: futureAppID,
+ },
+ },
+ AppBudgetConsumed: 5,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ },
+ {
+ PC: 4,
+ StackAdded: goValuesToTealValues(0),
+ },
+ {
+ PC: 6,
+ StackPopCount: 1,
+ },
+ {
+ PC: 90,
+ StackAdded: goValuesToTealValues(1),
+ },
+ {
+ PC: 91,
+ StackAdded: goValuesToTealValues(1),
+ StackPopCount: 1,
+ },
+ },
+ },
+ },
+ {
+ Trace: &simulation.TransactionTrace{},
+ },
+ {
+ Txn: transactions.SignedTxnWithAD{
+ ApplyData: transactions.ApplyData{
+ EvalDelta: transactions.EvalDelta{
+ Logs: []string{
+ string(uint64ToBytes(uint64(applicationArg * 3))),
+ },
+ },
+ },
+ },
+ AppBudgetConsumed: 39,
+ Trace: &simulation.TransactionTrace{
+ ApprovalProgramTrace: []simulation.OpcodeTraceUnit{
+ {
+ PC: 1,
+ },
+ {
+ PC: 4,
+ StackAdded: goValuesToTealValues(futureAppID),
+ },
+ {
+ PC: 6,
+ StackPopCount: 1,
+ },
+ {
+ PC: 9,
+ StackAdded: goValuesToTealValues(1),
+ },
+ {
+ PC: 11,
+ StackAdded: goValuesToTealValues(1),
+ },
+ {
+ PC: 12,
+ StackAdded: goValuesToTealValues(1),
+ StackPopCount: 2,
+ },
+ {
+ PC: 13,
+ StackPopCount: 1,
+ },
+ {
+ PC: 14,
+ StackAdded: goValuesToTealValues([]byte{byte(applicationArg)}),
+ },
+ {
+ PC: 17,
+ StackAdded: goValuesToTealValues(applicationArg),
+ StackPopCount: 1,
+ },
+ // call sub
+ {
+ PC: 18,
+ },
+ // proto
+ {
+ PC: 26,
+ },
+ {
+ PC: 29,
+ StackAdded: goValuesToTealValues(0),
+ },
+ // dup
+ {
+ PC: 31,
+ StackAdded: goValuesToTealValues(0, 0),
+ StackPopCount: 1,
+ },
+ // dupn 4
+ {
+ PC: 32,
+ StackAdded: goValuesToTealValues(0, 0, 0, 0, 0),
+ StackPopCount: 1,
+ },
+ // frame_dig -1
+ {
+ PC: 34,
+ StackAdded: goValuesToTealValues(applicationArg),
+ StackPopCount: 0,
+ },
+ // frame_bury 0
+ {
+ PC: 36,
+ StackAdded: goValuesToTealValues(applicationArg, 0, 0, 0, 0, 0),
+ StackPopCount: 7,
+ },
+ // dig 5
+ {
+ PC: 38,
+ StackAdded: goValuesToTealValues(applicationArg),
+ StackPopCount: 0,
+ },
+ // cover 5
+ {
+ PC: 40,
+ StackAdded: goValuesToTealValues(applicationArg, 0, 0, 0, 0, 0),
+ StackPopCount: 6,
+ },
+ // frame_dig 0
+ {
+ PC: 42,
+ StackAdded: goValuesToTealValues(applicationArg),
+ StackPopCount: 0,
+ },
+ // frame_dig 1
+ {
+ PC: 44,
+ StackAdded: goValuesToTealValues(applicationArg),
+ StackPopCount: 0,
+ },
+ // +
+ {
+ PC: 46,
+ StackAdded: goValuesToTealValues(applicationArg * 2),
+ StackPopCount: 2,
+ },
+ // bury 7
+ {
+ PC: 47,
+ StackAdded: goValuesToTealValues(applicationArg*2, applicationArg, 0, 0, 0, 0, 0),
+ StackPopCount: 8,
+ },
+ // popn 5
+ {
+ PC: 49,
+ StackPopCount: 5,
+ },
+ // uncover 1
+ {
+ PC: 51,
+ StackPopCount: 2,
+ StackAdded: goValuesToTealValues(applicationArg, applicationArg*2),
+ },
+ // swap
+ {
+ PC: 53,
+ StackAdded: goValuesToTealValues(applicationArg*2, applicationArg),
+ StackPopCount: 2,
+ },
+ // +
+ {
+ PC: 54,
+ StackAdded: goValuesToTealValues(applicationArg * 3),
+ StackPopCount: 2,
+ },
+ // pushbytess "1!" "5!"
+ {
+ PC: 55,
+ StackAdded: goValuesToTealValues("1!", "5!"),
+ },
+ // pushints 0 2 1 1 5 18446744073709551615
+ {
+ PC: 63,
+ StackAdded: goValuesToTealValues(0, 2, 1, 1, 5, uint64(math.MaxUint64)),
+ },
+ // store 1
+ {
+ PC: 80,
+ StackPopCount: 1,
+ ScratchSlotChanges: []simulation.ScratchChange{
+ {
+ Slot: 1,
+ NewValue: goValuesToTealValues(uint64(math.MaxUint64))[0],
+ },
+ },
+ },
+ // load 1
+ {
+ PC: 82,
+ StackAdded: goValuesToTealValues(uint64(math.MaxUint64)),
+ },
+ // stores
+ {
+ PC: 84,
+ StackPopCount: 2,
+ ScratchSlotChanges: []simulation.ScratchChange{
+ {
+ Slot: 5,
+ NewValue: goValuesToTealValues(uint64(math.MaxUint64))[0],
+ },
+ },
+ },
+ // load 1
+ {
+ PC: 85,
+ StackAdded: goValuesToTealValues(uint64(math.MaxUint64)),
+ },
+ // store 1
+ {
+ PC: 87,
+ StackPopCount: 1,
+ ScratchSlotChanges: []simulation.ScratchChange{
+ {
+ Slot: 1,
+ NewValue: goValuesToTealValues(uint64(math.MaxUint64))[0],
+ },
+ },
+ },
+ // retsub
+ {
+ PC: 89,
+ StackAdded: goValuesToTealValues(applicationArg * 3),
+ StackPopCount: 8,
+ },
+ // itob
+ {
+ PC: 21,
+ StackAdded: goValuesToTealValues(uint64ToBytes(uint64(applicationArg) * 3)),
+ StackPopCount: 1,
+ },
+ // log
+ {
+ PC: 22,
+ StackPopCount: 1,
+ },
+ // b end
+ {
+ PC: 23,
+ },
+ // int 1
+ {
+ PC: 90,
+ StackAdded: goValuesToTealValues(1),
+ },
+ // return
+ {
+ PC: 91,
+ StackAdded: goValuesToTealValues(1),
+ StackPopCount: 1,
+ },
+ },
+ },
+ },
+ },
+ AppBudgetAdded: 1400,
+ AppBudgetConsumed: 44,
+ },
+ },
+ },
+ }
+ })
+}
+
// TestBalanceChangesWithApp sends a payment transaction to a new account and confirms its balance
// within a subsequent app call
func TestBalanceChangesWithApp(t *testing.T) {
diff --git a/ledger/simulation/trace.go b/ledger/simulation/trace.go
index 839ac248b..574836097 100644
--- a/ledger/simulation/trace.go
+++ b/ledger/simulation/trace.go
@@ -106,7 +106,11 @@ func (eo ResultEvalOverrides) LogicEvalConstants() logic.EvalConstants {
// ExecTraceConfig gathers all execution trace related configs for simulation result
type ExecTraceConfig struct {
- Enable bool `codec:"enable,omitempty"`
+ _struct struct{} `codec:",omitempty"`
+
+ Enable bool `codec:"enable"`
+ Stack bool `codec:"stack-change"`
+ Scratch bool `codec:"scratch-change"`
}
// Result contains the result from a call to Simulator.Simulate
@@ -124,6 +128,12 @@ type Result struct {
// The other invalid options would be eliminated in validateSimulateRequest early.
func (r Result) ReturnTrace() bool { return r.TraceConfig.Enable }
+// ReturnStackChange reads from Result object and decides if simulation return stack changes.
+func (r Result) ReturnStackChange() bool { return r.TraceConfig.Stack }
+
+// ReturnScratchChange tells if the simulation runs with scratch-change enabled.
+func (r Result) ReturnScratchChange() bool { return r.TraceConfig.Scratch }
+
// validateSimulateRequest first checks relation between request and config variables, including developerAPI:
// if `developerAPI` provided is turned off, this method would:
// - error on asking for exec trace
@@ -135,6 +145,22 @@ func validateSimulateRequest(request Request, developerAPI bool) error {
},
}
}
+ if !request.TraceConfig.Enable {
+ if request.TraceConfig.Stack {
+ return InvalidRequestError{
+ SimulatorError{
+ err: fmt.Errorf("basic trace must be enabled when enabling stack tracing"),
+ },
+ }
+ }
+ if request.TraceConfig.Scratch {
+ return InvalidRequestError{
+ SimulatorError{
+ err: fmt.Errorf("basic trace must be enabled when enabling scratch slot change tracing"),
+ },
+ }
+ }
+ }
return nil
}
@@ -163,7 +189,16 @@ func makeSimulationResult(lastRound basics.Round, request Request, developerAPI
}, nil
}
-// OpcodeTraceUnit contains the trace effects of a single opcode evaluation
+// ScratchChange represents a write operation into a scratch slot
+type ScratchChange struct {
+ // Slot stands for the scratch slot id get written to
+ Slot uint64
+
+ // NewValue is the stack value written to scratch slot
+ NewValue basics.TealValue
+}
+
+// OpcodeTraceUnit contains the trace effects of a single opcode evaluation.
type OpcodeTraceUnit struct {
// The PC of the opcode being evaluated
PC uint64
@@ -172,6 +207,15 @@ type OpcodeTraceUnit struct {
// if any. These indexes refer to the InnerTraces array of the TransactionTrace object containing
// this OpcodeTraceUnit.
SpawnedInners []int
+
+ // what has been added to stack
+ StackAdded []basics.TealValue
+
+ // deleted element number from stack
+ StackPopCount uint64
+
+ // ScratchSlotChanges stands for write operations into scratch slots
+ ScratchSlotChanges []ScratchChange
}
// TransactionTrace contains the trace effects of a single transaction evaluation (including its inners)
diff --git a/ledger/simulation/tracer.go b/ledger/simulation/tracer.go
index cc41281a3..b56e13e42 100644
--- a/ledger/simulation/tracer.go
+++ b/ledger/simulation/tracer.go
@@ -88,6 +88,18 @@ type evalTracer struct {
// from top level transaction to the current inner txn that contains latest TransactionTrace.
// NOTE: execTraceStack is used only for PC/Stack/Storage exposure.
execTraceStack []*TransactionTrace
+
+ // addCount and popCount keep track of the latest opcode change explanation from opcode.
+ addCount int
+ popCount int
+
+ // stackHeightAfterDeletion is calculated by stack height before opcode - stack element deletion number.
+ // NOTE: both stackChangeExplanation and stackHeightAfterDeletion are used only for Stack exposure.
+ stackHeightAfterDeletion int
+
+ // scratchSlots are the scratch slots changed on current opcode (currently either `store` or `stores`).
+ // NOTE: this field scratchSlots is used only for scratch change exposure.
+ scratchSlots []uint64
}
func makeEvalTracer(lastRound basics.Round, request Request, developerAPI bool) (*evalTracer, error) {
@@ -176,7 +188,7 @@ func (tracer *evalTracer) BeforeTxn(ep *logic.EvalParams, groupIndex int) {
if tracer.result.ReturnTrace() {
var txnTraceStackElem *TransactionTrace
- // The last question is, where should this transaction trace attach to:
+ // Where should the current transaction trace attach to:
// - if it is a top level transaction, then attach to TxnResult level
// - if it is an inner transaction, then refer to the stack for latest exec trace,
// and attach to inner array
@@ -245,6 +257,14 @@ func (tracer *evalTracer) makeOpcodeTraceUnit(cx *logic.EvalContext) OpcodeTrace
return OpcodeTraceUnit{PC: uint64(cx.PC())}
}
+func (o *OpcodeTraceUnit) computeStackValueDeletions(cx *logic.EvalContext, tracer *evalTracer) {
+ tracer.popCount, tracer.addCount = cx.GetOpSpec().Explain(cx)
+ o.StackPopCount = uint64(tracer.popCount)
+
+ stackHeight := len(cx.Stack)
+ tracer.stackHeightAfterDeletion = stackHeight - int(o.StackPopCount)
+}
+
func (tracer *evalTracer) BeforeOpcode(cx *logic.EvalContext) {
groupIndex := cx.GroupIndex()
@@ -267,10 +287,86 @@ func (tracer *evalTracer) BeforeOpcode(cx *logic.EvalContext) {
txnTrace = tracer.execTraceStack[len(tracer.execTraceStack)-1]
}
*txnTrace.programTraceRef = append(*txnTrace.programTraceRef, tracer.makeOpcodeTraceUnit(cx))
+
+ latestOpcodeTraceUnit := &(*txnTrace.programTraceRef)[len(*txnTrace.programTraceRef)-1]
+ if tracer.result.ReturnStackChange() {
+ latestOpcodeTraceUnit.computeStackValueDeletions(cx, tracer)
+ }
+ if tracer.result.ReturnScratchChange() {
+ tracer.recordChangedScratchSlots(cx)
+ }
+ }
+}
+
+func (o *OpcodeTraceUnit) appendAddedStackValue(cx *logic.EvalContext, tracer *evalTracer) {
+ for i := tracer.stackHeightAfterDeletion; i < len(cx.Stack); i++ {
+ tealValue := cx.Stack[i].ToTealValue()
+ o.StackAdded = append(o.StackAdded, basics.TealValue{
+ Type: tealValue.Type,
+ Uint: tealValue.Uint,
+ Bytes: tealValue.Bytes,
+ })
+ }
+}
+
+func (tracer *evalTracer) recordChangedScratchSlots(cx *logic.EvalContext) {
+ currentOpcodeName := cx.GetOpSpec().Name
+ last := len(cx.Stack) - 1
+ tracer.scratchSlots = nil
+
+ switch currentOpcodeName {
+ case "store":
+ slot := uint64(cx.GetProgram()[cx.PC()+1])
+ tracer.scratchSlots = append(tracer.scratchSlots, slot)
+ case "stores":
+ prev := last - 1
+ slot := cx.Stack[prev].Uint
+
+ // If something goes wrong for `stores`, we don't have to error here
+ // for in runtime already has evalError
+ if slot >= uint64(len(cx.Scratch)) {
+ return
+ }
+ tracer.scratchSlots = append(tracer.scratchSlots, slot)
+ }
+}
+
+func (tracer *evalTracer) recordUpdatedScratchVars(cx *logic.EvalContext) []ScratchChange {
+ if len(tracer.scratchSlots) == 0 {
+ return nil
}
+ changes := make([]ScratchChange, len(tracer.scratchSlots))
+ for i, slot := range tracer.scratchSlots {
+ changes[i] = ScratchChange{
+ Slot: slot,
+ NewValue: cx.Scratch[slot].ToTealValue(),
+ }
+ }
+ return changes
}
func (tracer *evalTracer) AfterOpcode(cx *logic.EvalContext, evalError error) {
+ groupIndex := cx.GroupIndex()
+
+ // NOTE: only when we have no evalError on current opcode,
+ // we can proceed for recording stack chaange
+ if evalError == nil && tracer.result.ReturnTrace() {
+ var txnTrace *TransactionTrace
+ if cx.RunMode() == logic.ModeSig {
+ txnTrace = tracer.result.TxnGroups[0].Txns[groupIndex].Trace
+ } else {
+ txnTrace = tracer.execTraceStack[len(tracer.execTraceStack)-1]
+ }
+
+ latestOpcodeTraceUnit := &(*txnTrace.programTraceRef)[len(*txnTrace.programTraceRef)-1]
+ if tracer.result.ReturnStackChange() {
+ latestOpcodeTraceUnit.appendAddedStackValue(cx, tracer)
+ }
+ if tracer.result.ReturnScratchChange() {
+ latestOpcodeTraceUnit.ScratchSlotChanges = tracer.recordUpdatedScratchVars(cx)
+ }
+ }
+
if cx.RunMode() != logic.ModeApp {
// do nothing for LogicSig ops
return
diff --git a/ledger/store/trackerdb/sqlitedriver/catchpoint.go b/ledger/store/trackerdb/sqlitedriver/catchpoint.go
index 388749858..ef63b7a7f 100644
--- a/ledger/store/trackerdb/sqlitedriver/catchpoint.go
+++ b/ledger/store/trackerdb/sqlitedriver/catchpoint.go
@@ -52,6 +52,10 @@ func NewCatchpointSQLReaderWriter(e db.Executable) *catchpointReaderWriter {
}
}
+func makeCatchpointReader(e db.Queryable) trackerdb.CatchpointReader {
+ return &catchpointReader{q: e}
+}
+
func (cr *catchpointReader) GetCatchpoint(ctx context.Context, round basics.Round) (fileName string, catchpoint string, fileSize int64, err error) {
err = cr.q.QueryRowContext(ctx, "SELECT filename, catchpoint, filesize FROM storedcatchpoints WHERE round=?", int64(round)).Scan(&fileName, &catchpoint, &fileSize)
return
diff --git a/ledger/store/trackerdb/sqlitedriver/sqlitedriver.go b/ledger/store/trackerdb/sqlitedriver/sqlitedriver.go
index a5fe393b4..34f4d363c 100644
--- a/ledger/store/trackerdb/sqlitedriver/sqlitedriver.go
+++ b/ledger/store/trackerdb/sqlitedriver/sqlitedriver.go
@@ -85,7 +85,7 @@ func (s *trackerSQLStore) Snapshot(fn trackerdb.SnapshotFn) (err error) {
func (s *trackerSQLStore) SnapshotContext(ctx context.Context, fn trackerdb.SnapshotFn) (err error) {
return s.pair.Rdb.AtomicContext(ctx, func(ctx context.Context, tx *sql.Tx) error {
- return fn(ctx, sqlSnapshotScope{tx, &sqlReader{tx}})
+ return fn(ctx, &sqlSnapshotScope{tx, &sqlReader{tx}})
})
}
@@ -183,6 +183,21 @@ func (r *sqlReader) MakeCatchpointPendingHashesIterator(hashCount int) trackerdb
return MakeCatchpointPendingHashesIterator(hashCount, r.q)
}
+// MakeCatchpointReader implements trackerdb.Reader
+func (r *sqlReader) MakeCatchpointReader() (trackerdb.CatchpointReader, error) {
+ return makeCatchpointReader(r.q), nil
+}
+
+// MakeEncodedAccoutsBatchIter implements trackerdb.Reader
+func (r *sqlReader) MakeEncodedAccoutsBatchIter() trackerdb.EncodedAccountsBatchIter {
+ return MakeEncodedAccoutsBatchIter(r.q)
+}
+
+// MakeKVsIter implements trackerdb.Reader
+func (r *sqlReader) MakeKVsIter(ctx context.Context) (trackerdb.KVsIter, error) {
+ return MakeKVsIter(ctx, r.q)
+}
+
type sqlWriter struct {
e db.Executable
}
@@ -236,11 +251,6 @@ type sqlCatchpoint struct {
e db.Executable
}
-// MakeCatchpointReader implements trackerdb.Catchpoint
-func (c *sqlCatchpoint) MakeCatchpointReader() (trackerdb.CatchpointReader, error) {
- return NewCatchpointSQLReaderWriter(c.e), nil
-}
-
// MakeCatchpointReaderWriter implements trackerdb.Catchpoint
func (c *sqlCatchpoint) MakeCatchpointReaderWriter() (trackerdb.CatchpointReaderWriter, error) {
return NewCatchpointSQLReaderWriter(c.e), nil
@@ -251,16 +261,6 @@ func (c *sqlCatchpoint) MakeCatchpointWriter() (trackerdb.CatchpointWriter, erro
return NewCatchpointSQLReaderWriter(c.e), nil
}
-// MakeEncodedAccoutsBatchIter implements trackerdb.Catchpoint
-func (c *sqlCatchpoint) MakeEncodedAccoutsBatchIter() trackerdb.EncodedAccountsBatchIter {
- return MakeEncodedAccoutsBatchIter(c.e)
-}
-
-// MakeKVsIter implements trackerdb.Catchpoint
-func (c *sqlCatchpoint) MakeKVsIter(ctx context.Context) (trackerdb.KVsIter, error) {
- return MakeKVsIter(ctx, c.e)
-}
-
// MakeMerkleCommitter implements trackerdb.Catchpoint
func (c *sqlCatchpoint) MakeMerkleCommitter(staging bool) (trackerdb.MerkleCommitter, error) {
return MakeMerkleCommitter(c.e, staging)
@@ -302,7 +302,11 @@ type sqlSnapshotScope struct {
trackerdb.Reader
}
-func (ss sqlSnapshotScope) Close() error {
+func (ss *sqlSnapshotScope) ResetTransactionWarnDeadline(ctx context.Context, deadline time.Time) (prevDeadline time.Time, err error) {
+ return db.ResetTransactionWarnDeadline(ctx, ss.tx, deadline)
+}
+
+func (ss *sqlSnapshotScope) Close() error {
return ss.tx.Rollback()
}
diff --git a/ledger/store/trackerdb/store.go b/ledger/store/trackerdb/store.go
index 5514c12a8..4140f5be1 100644
--- a/ledger/store/trackerdb/store.go
+++ b/ledger/store/trackerdb/store.go
@@ -59,6 +59,10 @@ type Reader interface {
// catchpoint
// Note: BuildMerkleTrie() needs this on the reader handle in sqlite to not get locked by write txns
MakeCatchpointPendingHashesIterator(hashCount int) CatchpointPendingHashesIter
+ // Note: Catchpoint tracker needs this on the reader handle in sqlite to not get locked by write txns
+ MakeCatchpointReader() (CatchpointReader, error)
+ MakeEncodedAccoutsBatchIter() EncodedAccountsBatchIter
+ MakeKVsIter(ctx context.Context) (KVsIter, error)
}
// Writer is the interface for the trackerdb write operations.
@@ -82,10 +86,7 @@ type Writer interface {
// we should split these two sets of methods into two separate interfaces
type Catchpoint interface {
// reader
- MakeCatchpointReader() (CatchpointReader, error)
MakeOrderedAccountsIter(accountCount int) OrderedAccountsIter
- MakeKVsIter(ctx context.Context) (KVsIter, error)
- MakeEncodedAccoutsBatchIter() EncodedAccountsBatchIter
// writer
MakeCatchpointWriter() (CatchpointWriter, error)
// reader/writer
@@ -122,6 +123,7 @@ type Batch interface {
// SnapshotScope is an atomic read-only scope to the store.
type SnapshotScope interface {
Reader
+ ResetTransactionWarnDeadline(ctx context.Context, deadline time.Time) (prevDeadline time.Time, err error)
}
// Snapshot is an atomic read-only accecssor to the store.
diff --git a/protocol/codec_tester.go b/protocol/codec_tester.go
index 6acfdea57..49cae937b 100644
--- a/protocol/codec_tester.go
+++ b/protocol/codec_tester.go
@@ -249,6 +249,9 @@ func randomizeValue(v reflect.Value, datapath string, tag string, remainingChang
// Don't generate empty strings for serializableError since nil values of *string type
// will serialize differently by msgp and go-codec
len = rand.Int()%63 + 1
+ } else if strings.HasSuffix(v.Type().PkgPath(), "go-algorand/protocol") && v.Type().Name() == "TxType" {
+ // protocol.TxType has allocbound defined as a custom msgp:allocbound directive so not supported by reflect
+ len = rand.Int()%6 + 1
} else if hasAllocBound {
len = 1
} else {
diff --git a/rpcs/ledgerService.go b/rpcs/ledgerService.go
index ec7220a28..8abf87e3b 100644
--- a/rpcs/ledgerService.go
+++ b/rpcs/ledgerService.go
@@ -117,7 +117,7 @@ func (ls *LedgerService) ServeHTTP(response http.ResponseWriter, request *http.R
genesisID, hasGenesisID := pathVars["genesisID"]
if hasVersionStr {
if versionStr != "1" {
- logging.Base().Debugf("http ledger bad version '%s'", versionStr)
+ logging.Base().Debugf("LedgerService.ServeHTTP: bad version '%s'", versionStr)
response.WriteHeader(http.StatusBadRequest)
response.Write([]byte(fmt.Sprintf("unsupported version '%s'", versionStr)))
return
@@ -125,13 +125,13 @@ func (ls *LedgerService) ServeHTTP(response http.ResponseWriter, request *http.R
}
if hasGenesisID {
if ls.genesisID != genesisID {
- logging.Base().Debugf("http ledger bad genesisID mine=%#v theirs=%#v", ls.genesisID, genesisID)
+ logging.Base().Debugf("LedgerService.ServeHTTP: bad genesisID mine=%#v theirs=%#v", ls.genesisID, genesisID)
response.WriteHeader(http.StatusBadRequest)
response.Write([]byte(fmt.Sprintf("mismatching genesisID '%s'", genesisID)))
return
}
} else {
- logging.Base().Debug("http ledger no genesisID")
+ logging.Base().Debug("LedgerService.ServeHTTP: no genesisID")
response.WriteHeader(http.StatusBadRequest)
response.Write([]byte("missing genesisID"))
return
@@ -141,14 +141,14 @@ func (ls *LedgerService) ServeHTTP(response http.ResponseWriter, request *http.R
request.Body = http.MaxBytesReader(response, request.Body, ledgerServerMaxBodyLength)
err := request.ParseForm()
if err != nil {
- logging.Base().Debugf("http ledger parse form err : %v", err)
+ logging.Base().Debugf("LedgerService.ServeHTTP: parse form err : %v", err)
response.WriteHeader(http.StatusBadRequest)
response.Write([]byte(fmt.Sprintf("unable to parse form body : %v", err)))
return
}
roundStrs, ok := request.Form["r"]
if !ok || len(roundStrs) != 1 {
- logging.Base().Debugf("http ledger bad round number form arg '%s'", roundStrs)
+ logging.Base().Debugf("LedgerService.ServeHTTP: bad round number form arg '%s'", roundStrs)
response.WriteHeader(http.StatusBadRequest)
response.Write([]byte("invalid round number specified in 'r' form argument"))
return
@@ -158,13 +158,13 @@ func (ls *LedgerService) ServeHTTP(response http.ResponseWriter, request *http.R
if ok {
if len(versionStrs) == 1 {
if versionStrs[0] != "1" {
- logging.Base().Debugf("http ledger bad version '%s'", versionStr)
+ logging.Base().Debugf("LedgerService.ServeHTTP: bad version '%s'", versionStr)
response.WriteHeader(http.StatusBadRequest)
response.Write([]byte(fmt.Sprintf("unsupported version specified '%s'", versionStrs[0])))
return
}
} else {
- logging.Base().Debugf("http ledger wrong number of v=%d args", len(versionStrs))
+ logging.Base().Debugf("LedgerService.ServeHTTP: wrong number of v=%d args", len(versionStrs))
response.WriteHeader(http.StatusBadRequest)
response.Write([]byte(fmt.Sprintf("invalid number of version specified %d", len(versionStrs))))
return
@@ -173,11 +173,13 @@ func (ls *LedgerService) ServeHTTP(response http.ResponseWriter, request *http.R
}
round, err := strconv.ParseUint(roundStr, 36, 64)
if err != nil {
- logging.Base().Debugf("http ledger round parse fail ('%s'): %v", roundStr, err)
+ logging.Base().Debugf("LedgerService.ServeHTTP: round parse fail ('%s'): %v", roundStr, err)
response.WriteHeader(http.StatusBadRequest)
response.Write([]byte(fmt.Sprintf("specified round number could not be parsed using base 36 : %v", err)))
return
}
+ logging.Base().Infof("LedgerService.ServeHTTP: serving catchpoint round %d", round)
+ start := time.Now()
cs, err := ls.ledger.GetCatchpointStream(basics.Round(round))
if err != nil {
switch err.(type) {
@@ -188,7 +190,7 @@ func (ls *LedgerService) ServeHTTP(response http.ResponseWriter, request *http.R
return
default:
// unexpected error.
- logging.Base().Warnf("ServeHTTP : failed to retrieve catchpoint %d %v", round, err)
+ logging.Base().Warnf("LedgerService.ServeHTTP : failed to retrieve catchpoint %d %v", round, err)
response.WriteHeader(http.StatusInternalServerError)
response.Write([]byte(fmt.Sprintf("catchpoint file for round %d could not be retrieved due to internal error : %v", round, err)))
return
@@ -221,6 +223,8 @@ func (ls *LedgerService) ServeHTTP(response http.ResponseWriter, request *http.R
if err != nil {
logging.Base().Infof("LedgerService.ServeHTTP : unable to write compressed catchpoint file for round %d, written bytes %d : %v", round, written, err)
}
+ elapsed := time.Since(start)
+ logging.Base().Infof("LedgerService.ServeHTTP: served catchpoint round %d in %d sec", round, int(elapsed.Seconds()))
return
}
decompressedGzip, err := gzip.NewReader(cs)
@@ -234,5 +238,8 @@ func (ls *LedgerService) ServeHTTP(response http.ResponseWriter, request *http.R
written, err := io.Copy(response, decompressedGzip)
if err != nil {
logging.Base().Infof("LedgerService.ServeHTTP : unable to write decompressed catchpoint file for round %d, written bytes %d : %v", round, written, err)
+ } else {
+ elapsed := time.Since(start)
+ logging.Base().Infof("LedgerService.ServeHTTP: served catchpoint round %d in %d sec", round, int(elapsed.Seconds()))
}
}
diff --git a/scripts/check_deps.sh b/scripts/check_deps.sh
index 95c7599f7..a296c11b9 100755
--- a/scripts/check_deps.sh
+++ b/scripts/check_deps.sh
@@ -73,12 +73,6 @@ check_deps() {
then
missing_dep shellcheck
fi
-
- # Don't print `sqlite3`s location.
- if ! which sqlite3 > /dev/null
- then
- missing_dep sqlite3
- fi
}
check_deps
diff --git a/scripts/release/common/docker/centos.Dockerfile b/scripts/release/common/docker/centos.Dockerfile
index e1bb0188f..a23b446ca 100644
--- a/scripts/release/common/docker/centos.Dockerfile
+++ b/scripts/release/common/docker/centos.Dockerfile
@@ -2,7 +2,7 @@ FROM centos:7
WORKDIR /root
RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
-RUN yum install -y autoconf awscli curl git gnupg2 nfs-utils python36 sqlite3 expect jq libtool gcc-c++ libstdc++-devel libstdc++-static rpmdevtools createrepo rpm-sign bzip2 which ShellCheck
+RUN yum install -y autoconf awscli curl git gnupg2 nfs-utils python36 expect jq libtool gcc-c++ libstdc++-devel libstdc++-static rpmdevtools createrepo rpm-sign bzip2 which ShellCheck
ENTRYPOINT ["/bin/bash"]
diff --git a/scripts/release/common/docker/centos8.Dockerfile b/scripts/release/common/docker/centos8.Dockerfile
index 0917aedc5..cf5474cfe 100644
--- a/scripts/release/common/docker/centos8.Dockerfile
+++ b/scripts/release/common/docker/centos8.Dockerfile
@@ -2,7 +2,7 @@ FROM quay.io/centos/centos:stream8
WORKDIR /root
RUN dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && \
- dnf install -y autoconf awscli curl git gnupg2 nfs-utils python36 sqlite expect jq libtool gcc-c++ libstdc++-devel rpmdevtools createrepo rpm-sign bzip2 which && \
+ dnf install -y autoconf awscli curl git gnupg2 nfs-utils python36 expect jq libtool gcc-c++ libstdc++-devel rpmdevtools createrepo rpm-sign bzip2 which && \
dnf -y --enablerepo=powertools install libstdc++-static
RUN echo "${BOLD}Downloading and installing binaries...${RESET}" && \
diff --git a/scripts/release/common/setup.sh b/scripts/release/common/setup.sh
index c4430e9ae..75683262d 100755
--- a/scripts/release/common/setup.sh
+++ b/scripts/release/common/setup.sh
@@ -25,7 +25,7 @@ sudo apt-get upgrade -y
# `apt-get` fails randomly when downloading package, this is a hack that "works" reasonably well.
sudo apt-get update
-sudo apt-get install -y build-essential automake autoconf awscli docker.io git gpg nfs-common python python3 rpm sqlite3 python3-boto3 g++ libtool rng-tools
+sudo apt-get install -y build-essential automake autoconf awscli docker.io git gpg nfs-common python python3 rpm python3-boto3 g++ libtool rng-tools
sudo rngd -r /dev/urandom
#umask 0077
diff --git a/shared/pingpong/pingpong.go b/shared/pingpong/pingpong.go
index 32352bcfc..112105679 100644
--- a/shared/pingpong/pingpong.go
+++ b/shared/pingpong/pingpong.go
@@ -295,17 +295,19 @@ func (pps *WorkerState) scheduleAction() bool {
}
pps.refreshPos = 0
}
- addr := pps.refreshAddrs[pps.refreshPos]
- ai, err := pps.client.AccountInformation(addr, true)
- if err == nil {
- ppa := pps.accounts[addr]
+ if pps.cfg.NumApp > 0 || pps.cfg.NumAsset > 0 {
+ addr := pps.refreshAddrs[pps.refreshPos]
+ ai, err := pps.client.AccountInformation(addr, true)
+ if err == nil {
+ ppa := pps.accounts[addr]
- pps.integrateAccountInfo(addr, ppa, ai)
- } else {
- if !pps.cfg.Quiet {
- fmt.Printf("background refresh err: %v\n", err)
+ pps.integrateAccountInfo(addr, ppa, ai)
+ } else {
+ if !pps.cfg.Quiet {
+ fmt.Printf("background refresh err: %v\n", err)
+ }
+ return false
}
- return false
}
pps.refreshPos++
return true
diff --git a/test/e2e-go/restAPI/restClient_test.go b/test/e2e-go/restAPI/restClient_test.go
index 0fb5076d5..5d14f64d2 100644
--- a/test/e2e-go/restAPI/restClient_test.go
+++ b/test/e2e-go/restAPI/restClient_test.go
@@ -2053,6 +2053,16 @@ int 1`
a.Equal(expectedResult, resp)
}
+func toPtr[T any](constVar T) *T { return &constVar }
+
+func valToNil[T comparable](v *T) *T {
+ var defaultV T
+ if v == nil || *v == defaultV {
+ return nil
+ }
+ return v
+}
+
// The program is copied from pyteal source for c2c test over betanet:
// source: https://github.com/ahangsu/c2c-testscript/blob/master/c2c_test/max_depth/app.py
const maxDepthTealApproval = `#pragma version 8
@@ -2145,7 +2155,57 @@ main_l6:
int 1
return`
-func TestMaxDepthAppWithPCTrace(t *testing.T) {
+func goValuesToAvmValues(goValues ...interface{}) *[]model.AvmValue {
+ if len(goValues) == 0 {
+ return nil
+ }
+
+ boolToUint64 := func(b bool) uint64 {
+ if b {
+ return 1
+ }
+ return 0
+ }
+
+ modelValues := make([]model.AvmValue, len(goValues))
+ for i, goValue := range goValues {
+ switch converted := goValue.(type) {
+ case []byte:
+ modelValues[i] = model.AvmValue{
+ Type: uint64(basics.TealBytesType),
+ Bytes: &converted,
+ }
+ case bool:
+ convertedUint := boolToUint64(converted)
+ modelValues[i] = model.AvmValue{
+ Type: uint64(basics.TealUintType),
+ Uint: valToNil(&convertedUint),
+ }
+ case int:
+ convertedUint := uint64(converted)
+ modelValues[i] = model.AvmValue{
+ Type: uint64(basics.TealUintType),
+ Uint: valToNil(&convertedUint),
+ }
+ case basics.AppIndex:
+ convertedUint := uint64(converted)
+ modelValues[i] = model.AvmValue{
+ Type: uint64(basics.TealUintType),
+ Uint: valToNil(&convertedUint),
+ }
+ case uint64:
+ modelValues[i] = model.AvmValue{
+ Type: uint64(basics.TealUintType),
+ Uint: valToNil(&converted),
+ }
+ default:
+ panic("unexpected type inferred from interface{}")
+ }
+ }
+ return &modelValues
+}
+
+func TestMaxDepthAppWithPCandStackTrace(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()
@@ -2209,9 +2269,15 @@ func TestMaxDepthAppWithPCTrace(t *testing.T) {
)
a.NoError(err)
+ uint64ToBytes := func(v uint64) []byte {
+ b := make([]byte, 8)
+ binary.BigEndian.PutUint64(b, v)
+ return b
+ }
+
// construct app calls
appCallTxn, err := testClient.MakeUnsignedAppNoOpTx(
- uint64(futureAppID), [][]byte{{byte(MaxDepth)}}, nil, nil, nil, nil,
+ uint64(futureAppID), [][]byte{uint64ToBytes(uint64(MaxDepth))}, nil, nil, nil, nil,
)
a.NoError(err)
appCallTxn, err = testClient.FillUnsignedTxTemplate(senderAddress, 0, 0, MinFee*uint64(3*MaxDepth+2), appCallTxn)
@@ -2231,6 +2297,7 @@ func TestMaxDepthAppWithPCTrace(t *testing.T) {
// The first simulation should not pass, for simulation return PC in config has not been activated
execTraceConfig := simulation.ExecTraceConfig{
Enable: true,
+ Stack: true,
}
simulateRequest := v2.PreEncodedSimulateRequest{
TxnGroups: []v2.PreEncodedSimulateRequestTransactionGroup{
@@ -2260,141 +2327,683 @@ func TestMaxDepthAppWithPCTrace(t *testing.T) {
// Check expected == actual
creationOpcodeTrace := []model.SimulationOpcodeTraceUnit{
- {Pc: 1},
- {Pc: 6},
- {Pc: 8},
- {Pc: 9},
- {Pc: 10},
- {Pc: 149},
- {Pc: 150},
- }
-
- recursiveLongOpcodeTrace := []model.SimulationOpcodeTraceUnit{
- {Pc: 1},
- {Pc: 6},
- {Pc: 8},
- {Pc: 9},
- {Pc: 10},
- {Pc: 13},
- {Pc: 15},
- {Pc: 16},
- {Pc: 17},
- {Pc: 21},
- {Pc: 23},
- {Pc: 25},
- {Pc: 27},
- {Pc: 29},
- {Pc: 31},
- {Pc: 33},
- {Pc: 35},
- {Pc: 37},
- {Pc: 39},
- {Pc: 41},
- {Pc: 43},
- {Pc: 45},
- {Pc: 47},
- {Pc: 48},
- {Pc: 50},
- {Pc: 51},
- {Pc: 53},
- {Pc: 54},
- {Pc: 56},
- {Pc: 59},
- {Pc: 60},
- {Pc: 61},
- {Pc: 62},
- {Pc: 63},
- {Pc: 66},
- {Pc: 67},
- {Pc: 68},
- {Pc: 69},
- {Pc: 74},
- {Pc: 75},
- {Pc: 76},
- {Pc: 78},
- {Pc: 79},
- {Pc: 81},
- {Pc: 83},
- {Pc: 85},
- {Pc: 87},
- {Pc: 89, SpawnedInners: &[]uint64{0}},
- {Pc: 90},
- {Pc: 91},
- {Pc: 92},
- {Pc: 94},
- {Pc: 95},
- {Pc: 97},
- {Pc: 99},
- {Pc: 103},
- {Pc: 104},
- {Pc: 106},
- {Pc: 113},
- {Pc: 116},
- {Pc: 117},
- {Pc: 118},
- {Pc: 119},
- {Pc: 121},
- {Pc: 122},
- {Pc: 123},
- {Pc: 125},
- {Pc: 128},
- {Pc: 129},
- {Pc: 130},
- {Pc: 131},
- {Pc: 132},
- {Pc: 134},
- {Pc: 136},
- {Pc: 138},
- {Pc: 139},
- {Pc: 141},
- {Pc: 143},
- {Pc: 145, SpawnedInners: &[]uint64{1, 2}},
- {Pc: 146},
- {Pc: 72},
- {Pc: 73},
- }
-
- finalDepthTrace := []model.SimulationOpcodeTraceUnit{
- {Pc: 1},
- {Pc: 6},
- {Pc: 8},
- {Pc: 9},
- {Pc: 10},
- {Pc: 13},
- {Pc: 15},
- {Pc: 16},
- {Pc: 17},
- {Pc: 21},
- {Pc: 23},
- {Pc: 25},
- {Pc: 27},
- {Pc: 29},
- {Pc: 31},
- {Pc: 33},
- {Pc: 35},
- {Pc: 37},
- {Pc: 39},
- {Pc: 41},
- {Pc: 43},
- {Pc: 45},
- {Pc: 47},
- {Pc: 48},
- {Pc: 50},
- {Pc: 51},
- {Pc: 53},
- {Pc: 54},
- {Pc: 56},
- {Pc: 59},
- {Pc: 60},
- {Pc: 61},
- {Pc: 62},
- {Pc: 63},
- {Pc: 66},
- {Pc: 67},
- {Pc: 68},
- {Pc: 69},
- {Pc: 72},
- {Pc: 73},
+ {
+ Pc: 1,
+ },
+ // txn ApplicationID
+ {
+ Pc: 6,
+ StackAdditions: goValuesToAvmValues(0),
+ },
+ // int 0
+ {
+ Pc: 8,
+ StackAdditions: goValuesToAvmValues(0),
+ },
+ // ==
+ {
+ Pc: 9,
+ StackPopCount: toPtr[uint64](2),
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // bnz main_l6
+ {
+ Pc: 10,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int 1
+ {
+ Pc: 149,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // return
+ {
+ Pc: 150,
+ StackAdditions: goValuesToAvmValues(1),
+ StackPopCount: toPtr[uint64](1),
+ },
+ }
+
+ const NumArgs = 1
+
+ recursiveLongOpcodeTrace := func(appID basics.AppIndex, layer int) *[]model.SimulationOpcodeTraceUnit {
+ return &[]model.SimulationOpcodeTraceUnit{
+ {
+ Pc: 1,
+ },
+ // txn ApplicationID
+ {
+ Pc: 6,
+ StackAdditions: goValuesToAvmValues(appID),
+ },
+ // int 0
+ {
+ Pc: 8,
+ StackAdditions: goValuesToAvmValues(0),
+ },
+ // ==
+ {
+ Pc: 9,
+ StackAdditions: goValuesToAvmValues(false),
+ StackPopCount: toPtr[uint64](2),
+ },
+ // bnz main_l6
+ {
+ Pc: 10,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // txn NumAppArgs
+ {
+ Pc: 13,
+ StackAdditions: goValuesToAvmValues(NumArgs),
+ },
+ // int 1
+ {
+ Pc: 15,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // ==
+ {
+ Pc: 16,
+ StackPopCount: toPtr[uint64](2),
+ StackAdditions: goValuesToAvmValues(true),
+ },
+ // bnz main_l3
+ {
+ Pc: 17,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // global CurrentApplicationID
+ {
+ Pc: 21,
+ StackAdditions: goValuesToAvmValues(appID),
+ },
+ // app_params_get AppApprovalProgram
+ {
+ Pc: 23,
+ StackAdditions: goValuesToAvmValues(approval, 1),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 1
+ {
+ Pc: 25,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 0
+ {
+ Pc: 27,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // global CurrentApplicationID
+ {
+ Pc: 29,
+ StackAdditions: goValuesToAvmValues(appID),
+ },
+ // app_params_get AppClearStateProgram
+ {
+ Pc: 31,
+ StackAdditions: goValuesToAvmValues(clearState, 1),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 3
+ {
+ Pc: 33,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 2
+ {
+ Pc: 35,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // global CurrentApplicationAddress
+ {
+ Pc: 37,
+ StackAdditions: goValuesToAvmValues(crypto.Digest(appID.Address()).ToSlice()),
+ },
+ // acct_params_get AcctBalance
+ {
+ Pc: 39,
+ StackAdditions: goValuesToAvmValues(uint64(3-layer)*MinBalance, 1),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 5
+ {
+ Pc: 41,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 4
+ {
+ Pc: 43,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // load 1
+ {
+ Pc: 45,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // assert
+ {
+ Pc: 47,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // load 3
+ {
+ Pc: 48,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // assert
+ {
+ Pc: 50,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // load 5
+ {
+ Pc: 51,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // assert
+ {
+ Pc: 53,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int 2
+ {
+ Pc: 54,
+ StackAdditions: goValuesToAvmValues(2),
+ },
+ // txna ApplicationArgs 0
+ {
+ Pc: 56,
+ StackAdditions: goValuesToAvmValues(uint64ToBytes(uint64(MaxDepth - layer))),
+ },
+ // btoi
+ {
+ Pc: 59,
+ StackAdditions: goValuesToAvmValues(uint64(MaxDepth - layer)),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // exp
+ {
+ Pc: 60,
+ StackAdditions: goValuesToAvmValues(1 << (MaxDepth - layer)),
+ StackPopCount: toPtr[uint64](2),
+ },
+ // itob
+ {
+ Pc: 61,
+ StackAdditions: goValuesToAvmValues(uint64ToBytes(1 << uint64(MaxDepth-layer))),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // log
+ {
+ Pc: 62,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // txna ApplicationArgs 0
+ {
+ Pc: 63,
+ StackAdditions: goValuesToAvmValues(uint64ToBytes(uint64(MaxDepth - layer))),
+ },
+ // btoi
+ {
+ Pc: 66,
+ StackAdditions: goValuesToAvmValues(MaxDepth - layer),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int 0
+ {
+ Pc: 67,
+ StackAdditions: goValuesToAvmValues(0),
+ },
+ // >
+ {
+ Pc: 68,
+ StackAdditions: goValuesToAvmValues(MaxDepth-layer > 0),
+ StackPopCount: toPtr[uint64](2),
+ },
+ // bnz main_l5
+ {
+ Pc: 69,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // itxn_begin
+ {
+ Pc: 74,
+ },
+ // int appl
+ {
+ Pc: 75,
+ StackAdditions: goValuesToAvmValues(6),
+ },
+ // itxn_field TypeEnum
+ {
+ Pc: 76,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int 0
+ {
+ Pc: 78,
+ StackAdditions: goValuesToAvmValues(0),
+ },
+ // itxn_field Fee
+ {
+ Pc: 79,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // load 0
+ {
+ Pc: 81,
+ StackAdditions: goValuesToAvmValues(approval),
+ },
+ // itxn_field ApprovalProgram
+ {
+ Pc: 83,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // load 2
+ {
+ Pc: 85,
+ StackAdditions: goValuesToAvmValues(clearState),
+ },
+ // itxn_field ClearStateProgram
+ {
+ Pc: 87,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // itxn_submit
+ {
+ Pc: 89,
+ SpawnedInners: &[]uint64{0},
+ },
+ // itxn_begin
+ {
+ Pc: 90,
+ },
+ // int pay
+ {
+ Pc: 91,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // itxn_field TypeEnum
+ {
+ Pc: 92,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int 0
+ {
+ Pc: 94,
+ StackAdditions: goValuesToAvmValues(0),
+ },
+ // itxn_field Fee
+ {
+ Pc: 95,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // load 4
+ {
+ Pc: 97,
+ StackAdditions: goValuesToAvmValues(uint64(3-layer) * MinBalance),
+ },
+ // int 100000
+ {
+ Pc: 99,
+ StackAdditions: goValuesToAvmValues(MinBalance),
+ },
+ // -
+ {
+ Pc: 103,
+ StackPopCount: toPtr[uint64](2),
+ StackAdditions: goValuesToAvmValues(uint64(2-layer) * MinBalance),
+ },
+ // itxn_field Amount
+ {
+ Pc: 104,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // byte "appID"
+ {
+ Pc: 106,
+ StackAdditions: goValuesToAvmValues([]byte("appID")),
+ },
+ // gitxn 0 CreatedApplicationID
+ {
+ Pc: 113,
+ StackAdditions: goValuesToAvmValues(appID + 3),
+ },
+ // itob
+ {
+ Pc: 116,
+ StackAdditions: goValuesToAvmValues(uint64ToBytes(uint64(appID) + 3)),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // concat
+ {
+ Pc: 117,
+ StackAdditions: goValuesToAvmValues([]byte("appID" + string(uint64ToBytes(uint64(appID)+3)))),
+ StackPopCount: toPtr[uint64](2),
+ },
+ // sha512_256
+ {
+ Pc: 118,
+ StackAdditions: goValuesToAvmValues(crypto.Digest(basics.AppIndex(uint64(appID) + 3).Address()).ToSlice()),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // itxn_field Receiver
+ {
+ Pc: 119,
+ StackPopCount: toPtr[uint64](1),
+ },
+ {
+ Pc: 121,
+ },
+ // int appl
+ {
+ Pc: 122,
+ StackAdditions: goValuesToAvmValues(6),
+ },
+ // itxn_field TypeEnum
+ {
+ Pc: 123,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // txna ApplicationArgs 0
+ {
+ Pc: 125,
+ StackAdditions: goValuesToAvmValues(uint64ToBytes(uint64(MaxDepth - layer))),
+ },
+ // btoi
+ {
+ Pc: 128,
+ StackAdditions: goValuesToAvmValues(MaxDepth - layer),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int 1
+ {
+ Pc: 129,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // -
+ {
+ Pc: 130,
+ StackAdditions: goValuesToAvmValues(MaxDepth - layer - 1),
+ StackPopCount: toPtr[uint64](2),
+ },
+ // itob
+ {
+ Pc: 131,
+ StackAdditions: goValuesToAvmValues(uint64ToBytes(uint64(MaxDepth - layer - 1))),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // itxn_field ApplicationArgs
+ {
+ Pc: 132,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // itxn CreatedApplicationID
+ {
+ Pc: 134,
+ StackAdditions: goValuesToAvmValues(appID + 3),
+ },
+ // itxn_field ApplicationID
+ {
+ Pc: 136,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int 0
+ {
+ Pc: 138,
+ StackAdditions: goValuesToAvmValues(0),
+ },
+ // itxn_field Fee
+ {
+ Pc: 139,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int DeleteApplication
+ {
+ Pc: 141,
+ StackAdditions: goValuesToAvmValues(5),
+ },
+ // itxn_field OnCompletion
+ {
+ Pc: 143,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // itxn_submit
+ {
+ Pc: 145,
+ SpawnedInners: &[]uint64{1, 2},
+ },
+ // b main_l4
+ {
+ Pc: 146,
+ },
+ // int 1
+ {
+ Pc: 72,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // return
+ {
+ Pc: 73,
+ StackAdditions: goValuesToAvmValues(1),
+ StackPopCount: toPtr[uint64](1),
+ },
+ }
+ }
+
+ finalDepthTrace := func(appID basics.AppIndex, layer int) *[]model.SimulationOpcodeTraceUnit {
+ return &[]model.SimulationOpcodeTraceUnit{
+ {
+ Pc: 1,
+ },
+ // txn ApplicationID
+ {
+ Pc: 6,
+ StackAdditions: goValuesToAvmValues(appID),
+ },
+ // int 0
+ {
+ Pc: 8,
+ StackAdditions: goValuesToAvmValues(0),
+ },
+ // ==
+ {
+ Pc: 9,
+ StackAdditions: goValuesToAvmValues(false),
+ StackPopCount: toPtr[uint64](2),
+ },
+ // bnz main_l6
+ {
+ Pc: 10,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // txn NumAppArgs
+ {
+ Pc: 13,
+ StackAdditions: goValuesToAvmValues(NumArgs),
+ },
+ // int 1
+ {
+ Pc: 15,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // ==
+ {
+ Pc: 16,
+ StackPopCount: toPtr[uint64](2),
+ StackAdditions: goValuesToAvmValues(true),
+ },
+ // bnz main_l3
+ {
+ Pc: 17,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // global CurrentApplicationID
+ {
+ Pc: 21,
+ StackAdditions: goValuesToAvmValues(appID),
+ },
+ // app_params_get AppApprovalProgram
+ {
+ Pc: 23,
+ StackAdditions: goValuesToAvmValues(approval, 1),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 1
+ {
+ Pc: 25,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 0
+ {
+ Pc: 27,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // global CurrentApplicationID
+ {
+ Pc: 29,
+ StackAdditions: goValuesToAvmValues(appID),
+ },
+ // app_params_get AppClearStateProgram
+ {
+ Pc: 31,
+ StackAdditions: goValuesToAvmValues(clearState, 1),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 3
+ {
+ Pc: 33,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 2
+ {
+ Pc: 35,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // global CurrentApplicationAddress
+ {
+ Pc: 37,
+ StackAdditions: goValuesToAvmValues(crypto.Digest(appID.Address()).ToSlice()),
+ },
+ // acct_params_get AcctBalance
+ {
+ Pc: 39,
+ StackAdditions: goValuesToAvmValues(uint64(3-layer)*MinBalance, 1),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 5
+ {
+ Pc: 41,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // store 4
+ {
+ Pc: 43,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // load 1
+ {
+ Pc: 45,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // assert
+ {
+ Pc: 47,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // load 3
+ {
+ Pc: 48,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // assert
+ {
+ Pc: 50,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // load 5
+ {
+ Pc: 51,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // assert
+ {
+ Pc: 53,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int 2
+ {
+ Pc: 54,
+ StackAdditions: goValuesToAvmValues(2),
+ },
+ // txna ApplicationArgs 0
+ {
+ Pc: 56,
+ StackAdditions: goValuesToAvmValues(uint64ToBytes(uint64(MaxDepth - layer))),
+ },
+ // btoi
+ {
+ Pc: 59,
+ StackAdditions: goValuesToAvmValues(uint64(MaxDepth - layer)),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // exp
+ {
+ Pc: 60,
+ StackAdditions: goValuesToAvmValues(1 << (MaxDepth - layer)),
+ StackPopCount: toPtr[uint64](2),
+ },
+ // itob
+ {
+ Pc: 61,
+ StackAdditions: goValuesToAvmValues(uint64ToBytes(1 << uint64(MaxDepth-layer))),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // log
+ {
+ Pc: 62,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // txna ApplicationArgs 0
+ {
+ Pc: 63,
+ StackAdditions: goValuesToAvmValues(uint64ToBytes(uint64(MaxDepth - layer))),
+ },
+ // btoi
+ {
+ Pc: 66,
+ StackAdditions: goValuesToAvmValues(MaxDepth - layer),
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int 0
+ {
+ Pc: 67,
+ StackAdditions: goValuesToAvmValues(0),
+ },
+ // >
+ {
+ Pc: 68,
+ StackAdditions: goValuesToAvmValues(MaxDepth-layer > 0),
+ StackPopCount: toPtr[uint64](2),
+ },
+ // bnz main_l5
+ {
+ Pc: 69,
+ StackPopCount: toPtr[uint64](1),
+ },
+ // int 1
+ {
+ Pc: 72,
+ StackAdditions: goValuesToAvmValues(1),
+ },
+ // return
+ {
+ Pc: 73,
+ StackAdditions: goValuesToAvmValues(1),
+ StackPopCount: toPtr[uint64](1),
+ },
+ }
}
a.Len(resp.TxnGroups[0].Txns, 2)
@@ -2404,16 +3013,16 @@ func TestMaxDepthAppWithPCTrace(t *testing.T) {
a.Nil(resp.TxnGroups[0].Txns[0].TransactionTrace)
expectedTraceSecondTxn := &model.SimulationTransactionExecTrace{
- ApprovalProgramTrace: &recursiveLongOpcodeTrace,
+ ApprovalProgramTrace: recursiveLongOpcodeTrace(futureAppID, 0),
InnerTrace: &[]model.SimulationTransactionExecTrace{
{ApprovalProgramTrace: &creationOpcodeTrace},
{},
{
- ApprovalProgramTrace: &recursiveLongOpcodeTrace,
+ ApprovalProgramTrace: recursiveLongOpcodeTrace(futureAppID+3, 1),
InnerTrace: &[]model.SimulationTransactionExecTrace{
{ApprovalProgramTrace: &creationOpcodeTrace},
{},
- {ApprovalProgramTrace: &finalDepthTrace},
+ {ApprovalProgramTrace: finalDepthTrace(futureAppID+6, 2)},
},
},
},
@@ -2422,3 +3031,174 @@ func TestMaxDepthAppWithPCTrace(t *testing.T) {
a.Equal(execTraceConfig, resp.ExecTraceConfig)
}
+
+func TestSimulateScratchSlotChange(t *testing.T) {
+ partitiontest.PartitionTest(t)
+ t.Parallel()
+
+ a := require.New(fixtures.SynchronizedTest(t))
+ var localFixture fixtures.RestClientFixture
+ localFixture.SetupNoStart(t, filepath.Join("nettemplates", "OneNodeFuture.json"))
+
+ // Get primary node
+ primaryNode, err := fixture.GetNodeController("Primary")
+ a.NoError(err)
+
+ fixture.Start()
+ defer primaryNode.FullStop()
+
+ // get lib goal client
+ testClient := fixture.LibGoalFixture.GetLibGoalClientFromNodeController(primaryNode)
+
+ _, err = testClient.WaitForRound(1)
+ a.NoError(err)
+
+ wh, err := testClient.GetUnencryptedWalletHandle()
+ a.NoError(err)
+ addresses, err := testClient.ListAddresses(wh)
+ a.NoError(err)
+ _, senderAddress := getMaxBalAddr(t, testClient, addresses)
+ a.NotEmpty(senderAddress, "no addr with funds")
+ a.NoError(err)
+
+ ops, err := logic.AssembleString(
+ `#pragma version 8
+ global CurrentApplicationID
+ bz end
+ int 1
+ store 1
+ load 1
+ dup
+ stores
+ end:
+ int 1`)
+ a.NoError(err)
+ approval := ops.Program
+ ops, err = logic.AssembleString("#pragma version 8\nint 1")
+ a.NoError(err)
+ clearState := ops.Program
+
+ gl := basics.StateSchema{}
+ lc := basics.StateSchema{}
+
+ MinFee := config.Consensus[protocol.ConsensusFuture].MinTxnFee
+ MinBalance := config.Consensus[protocol.ConsensusFuture].MinBalance
+
+ // create app and get the application ID
+ appCreateTxn, err := testClient.MakeUnsignedAppCreateTx(
+ transactions.NoOpOC, approval, clearState, gl,
+ lc, nil, nil, nil, nil, nil, 0)
+ a.NoError(err)
+ appCreateTxn, err = testClient.FillUnsignedTxTemplate(senderAddress, 0, 0, 0, appCreateTxn)
+ a.NoError(err)
+
+ appCreateTxID, err := testClient.SignAndBroadcastTransaction(wh, nil, appCreateTxn)
+ a.NoError(err)
+ submittedAppCreateTxn, err := waitForTransaction(t, testClient, senderAddress, appCreateTxID, 30*time.Second)
+ a.NoError(err)
+ futureAppID := basics.AppIndex(*submittedAppCreateTxn.ApplicationIndex)
+
+ // fund app account
+ appFundTxn, err := testClient.SendPaymentFromWallet(
+ wh, nil, senderAddress, futureAppID.Address().String(),
+ 0, MinBalance, nil, "", 0, 0,
+ )
+ a.NoError(err)
+
+ // construct app calls
+ appCallTxn, err := testClient.MakeUnsignedAppNoOpTx(
+ uint64(futureAppID), [][]byte{}, nil, nil, nil, nil,
+ )
+ a.NoError(err)
+ appCallTxn, err = testClient.FillUnsignedTxTemplate(senderAddress, 0, 0, MinFee, appCallTxn)
+ a.NoError(err)
+
+ // Group the transactions
+ gid, err := testClient.GroupID([]transactions.Transaction{appFundTxn, appCallTxn})
+ a.NoError(err)
+ appFundTxn.Group = gid
+ appCallTxn.Group = gid
+
+ appFundTxnSigned, err := testClient.SignTransactionWithWallet(wh, nil, appFundTxn)
+ a.NoError(err)
+ appCallTxnSigned, err := testClient.SignTransactionWithWallet(wh, nil, appCallTxn)
+ a.NoError(err)
+
+ // construct simulation request, with scratch slot change enabled
+ execTraceConfig := simulation.ExecTraceConfig{
+ Enable: true,
+ Scratch: true,
+ }
+ simulateRequest := v2.PreEncodedSimulateRequest{
+ TxnGroups: []v2.PreEncodedSimulateRequestTransactionGroup{
+ {Txns: []transactions.SignedTxn{appFundTxnSigned, appCallTxnSigned}},
+ },
+ ExecTraceConfig: execTraceConfig,
+ }
+
+ // update the configuration file to enable EnableDeveloperAPI
+ err = primaryNode.FullStop()
+ a.NoError(err)
+ cfg, err := config.LoadConfigFromDisk(primaryNode.GetDataDir())
+ a.NoError(err)
+ cfg.EnableDeveloperAPI = true
+ err = cfg.SaveToDisk(primaryNode.GetDataDir())
+ require.NoError(t, err)
+ fixture.Start()
+
+ // simulate with wrong config (not enabled trace), see expected error
+ _, err = testClient.SimulateTransactions(v2.PreEncodedSimulateRequest{
+ TxnGroups: []v2.PreEncodedSimulateRequestTransactionGroup{
+ {Txns: []transactions.SignedTxn{appFundTxnSigned, appCallTxnSigned}},
+ },
+ ExecTraceConfig: simulation.ExecTraceConfig{Scratch: true},
+ })
+ a.ErrorContains(err, "basic trace must be enabled when enabling scratch slot change tracing")
+
+ // start real simulating
+ resp, err := testClient.SimulateTransactions(simulateRequest)
+ a.NoError(err)
+
+ // check if resp match expected result
+ a.Equal(execTraceConfig, resp.ExecTraceConfig)
+ a.Len(resp.TxnGroups[0].Txns, 2)
+ a.Nil(resp.TxnGroups[0].Txns[0].TransactionTrace)
+ a.NotNil(resp.TxnGroups[0].Txns[1].TransactionTrace)
+
+ expectedTraceSecondTxn := &model.SimulationTransactionExecTrace{
+ ApprovalProgramTrace: &[]model.SimulationOpcodeTraceUnit{
+ {Pc: 1},
+ {Pc: 4},
+ {Pc: 6},
+ {Pc: 9},
+ {
+ Pc: 10,
+ ScratchChanges: &[]model.ScratchChange{
+ {
+ Slot: 1,
+ NewValue: model.AvmValue{
+ Type: 2,
+ Uint: toPtr[uint64](1),
+ },
+ },
+ },
+ },
+ {Pc: 12},
+ {Pc: 14},
+ {
+ Pc: 15,
+ ScratchChanges: &[]model.ScratchChange{
+ {
+ Slot: 1,
+ NewValue: model.AvmValue{
+ Type: 2,
+ Uint: toPtr[uint64](1),
+ },
+ },
+ },
+ },
+ {Pc: 16},
+ },
+ }
+ a.Equal(expectedTraceSecondTxn, resp.TxnGroups[0].Txns[1].TransactionTrace)
+}
diff --git a/test/heapwatch/client_ram_report.py b/test/heapwatch/client_ram_report.py
index 51f7bcb31..29642faf1 100644
--- a/test/heapwatch/client_ram_report.py
+++ b/test/heapwatch/client_ram_report.py
@@ -47,16 +47,28 @@ multipliers = {
'TB': 1024*1024*1024*1024,
}
-# d = {k:[v,...]}
-def dapp(d, k, v):
+# d = {k: {t: v},...}
+def dapp(d, k, t, v):
l = d.get(k)
if l is None:
- d[k] = [v]
+ d[k] = {t: v}
else:
- l.append(v)
+ l[t] = v
+
+# d = {k: {t: {m: v},...},...}
+def dapp_metric(d, k, t, m, v):
+ l = d.get(k)
+ if l is None:
+ d[k] = {t: {m: v}}
+ else:
+ l2 = l.get(t)
+ if l2 is None:
+ l[t] = {m: v}
+ else:
+ l2[m] = v
def get_heap_inuse_totals(dirpath):
- '''return {"node nickname":[(YYYYmmdd_HHMMSS, bytes), ...], ...}'''
+ '''return {"node nickname": {"YYYYmmdd_HHMMSS": bytes}, ...}'''
cache_mtime = 0
cache_path = os.path.join(dirpath, 'heap_inuse_totals.json')
if os.path.exists(cache_path):
@@ -88,21 +100,50 @@ def get_heap_inuse_totals(dirpath):
logger.error('could not find total in output: %s', text)
raise Exception('could not find total in output of: %s', ' '.join([repr(x) for x in cmd]))
bytesinuse = float(m.group(1)) * multipliers[m.group(2).upper()]
- dapp(bynick, nick, (timestamp, bytesinuse))
+ dapp(bynick, nick, timestamp, bytesinuse)
logger.debug('%s ok, %s %f', path, timestamp, bytesinuse)
logger.debug('%d skipped older than cache', skipcount)
for nick, recs in bynick.items():
old = cached.get(nick)
if old is None:
- cached[nick] = sorted(recs)
+ cached[nick] = recs
else:
- cached[nick] = sorted(old + recs)
+ cached[nick].update(recs)
if cached and bynick:
with open(cache_path, 'wt') as fout:
json.dump(cached, fout)
return cached
+def get_heap_metrics(dirpath):
+ '''return {"node nickname": {"YYYYmmdd_HHMMSS": {"metric": value}, ...}, ...}'''
+ metrics_name_re = re.compile(r'(.*)\.(.*).metrics')
+ bynick = {}
+ for path in glob.glob(os.path.join(dirpath, '*.*.metrics')):
+ fname = os.path.basename(path)
+ m = metrics_name_re.match(fname)
+ if not m:
+ logger.warning('could not parse heap filename: %r', path)
+ continue
+ nick = m.group(1)
+ timestamp = m.group(2)
+ with open(path, 'rt') as fin:
+ for line in fin.readlines():
+ if line.startswith('#'):
+ continue
+ elif line.startswith('algod_go_memory_classes_heap_objects_bytes'):
+ inuse = float(line.split()[1])
+ dapp_metric(bynick, nick, timestamp, 'inuse', inuse)
+ elif line.startswith('algod_go_memory_classes_total_bytes'):
+ total = float(line.split()[1])
+ dapp_metric(bynick, nick, timestamp, 'total', total)
+ elif line.startswith('algod_go_memory_classes_heap_free_bytes'):
+ free = float(line.split()[1])
+ dapp_metric(bynick, nick, timestamp, 'free', free)
+ elif line.startswith('algod_go_memory_classes_heap_released_bytes'):
+ released = float(line.split()[1])
+ dapp_metric(bynick, nick, timestamp, 'released', released)
+ return bynick
def maybe_load_tf_nicks(args):
tf_inventory_path = os.path.join(args.dir, 'terraform-inventory.host')
@@ -121,9 +162,11 @@ def maybe_load_tf_nicks(args):
return ip_to_name
-def hostports_to_nicks(args, hostports):
+def hostports_to_nicks(args, hostports, metrics=None):
ip_to_nick = maybe_load_tf_nicks(args)
if not ip_to_nick:
+ if metrics:
+ return ['{}#{}'.format(hp, m) for hp in hostports for m in metrics]
return hostports
out = []
for hp in hostports:
@@ -138,6 +181,8 @@ def hostports_to_nicks(args, hostports):
if not hit:
hit = hp
out.append(hit)
+ if metrics:
+ return ['{}#{}'.format(hp, m) for hp in hostports for m in metrics]
return out
@@ -154,6 +199,7 @@ def main():
logging.basicConfig(level=logging.INFO)
heap_totals = get_heap_inuse_totals(args.dir)
+ heap_details = get_heap_metrics(args.dir)
if args.csv:
if args.csv == '-':
@@ -162,12 +208,18 @@ def main():
csvf = open(args.csv, 'wt')
writer = csv.writer(csvf)
whens = set()
- for nick, recs in heap_totals.items():
- for ts, n in recs:
+ col_names_target = heap_totals if heap_totals else heap_details
+ for nick, recs in col_names_target.items():
+ # {k: {t: v}}
+ for ts in recs.keys():
whens.add(ts)
whens = sorted(whens)
- nodes = sorted(heap_totals.keys())
- writer.writerow(['when','dt','round'] + hostports_to_nicks(args, nodes))
+ nodes = sorted(col_names_target.keys())
+ metrics = list(heap_details[nodes[0]].values())[0]
+ writer.writerow(
+ ['when','dt','round'] +
+ hostports_to_nicks(args, nodes, metrics=['pprof_inuse_space'] + list(metrics.keys()))
+ )
first = None
for ts in whens:
tv = time.mktime(time.strptime(ts, '%Y%m%d_%H%M%S'))
@@ -179,13 +231,16 @@ def main():
bi = json.load(open(bipath))
rnd = str(bi['block']['rnd'])
except:
- rnd = ''
+ rnd = '0'
row = [ts, tv-first, rnd]
for nick in nodes:
- for rec in heap_totals[nick]:
- if rec[0] == ts:
- row.append(rec[1])
- break
+ # {k: {t: v}}
+ val = heap_totals.get(nick, {}).get(ts)
+ row.append(val if val else 0)
+ vals = heap_details[nick].get(ts)
+ # {k: {t: {m: v}}}
+ if vals:
+ row.extend(vals.values())
writer.writerow(row)
return 0
diff --git a/test/heapwatch/plot_crr_csv.py b/test/heapwatch/plot_crr_csv.py
index f4a46cf85..d546aaff3 100755
--- a/test/heapwatch/plot_crr_csv.py
+++ b/test/heapwatch/plot_crr_csv.py
@@ -6,8 +6,18 @@ import csv
import random
from matplotlib import pyplot as plt
+from matplotlib.ticker import MaxNLocator, FuncFormatter
_meta_cols = {'when', 'dt', 'round'}
+_metrics_cols = {'free', 'inuse', 'released', 'total'}
+
+# see https://matplotlib.org/stable/gallery/lines_bars_and_markers/linestyles.html
+plt_line_styles = [
+ 'solid', 'dotted', 'dashed', 'dashdot',
+ (5, (10, 3)), # long dash with offset
+ (0, (3, 5, 1, 5)), # dashdotted
+ (0, (3, 10, 1, 10, 1, 10)), # loosely dashdotted
+]
def smin(a,b):
if a is None:
@@ -22,6 +32,27 @@ def smax(a,b):
return a
return max(a,b)
+def add_metric(d, k, m, x, y):
+ """d: {k: {m: [(x,y)]}}"""
+ mt = d.get(k)
+ if mt is None:
+ d[k] = {m: [(x,y)]}
+ else:
+ klist = mt.get(m)
+ if klist is None:
+ mt[m] = [(x,y)]
+ else:
+ klist.append((x, y))
+
+
+def format_mem(x, _):
+ if x<0:
+ return ""
+ for unit in ['bytes', 'KB', 'MB', 'GB']:
+ if x < 1024:
+ return "%3.1f %s" % (x, unit)
+ x /= 1024
+
def main():
import argparse
ap = argparse.ArgumentParser()
@@ -36,29 +67,42 @@ def main():
reader = csv.DictReader(fin)
for rec in reader:
xround = int(rec['round'])
+ row_nick = None
for k,v in rec.items():
if k in _meta_cols:
continue
- klist = fvals.get(k)
- if klist is None:
- klist = []
- fvals[k] = klist
v = float(v)
- klist.append((xround, v))
+ parts = k.split('#')
+ if len(parts) == 2:
+ row_nick = parts[0]
+ metric = parts[1]
+ else :
+ print(f"unknown column {k}")
+ row_nick = k
+ metric = k
+ add_metric(fvals, row_nick, metric, xround, v)
+
minv = smin(minv, v)
maxv = smax(maxv, v)
if not fvals:
print(f"{fname} empty")
continue
- print("{} found series {}".format(fname, sorted(fvals.keys())))
+ nodes = sorted(fvals.keys())
+ print("{} found series {}".format(fname, nodes))
fig, ax = plt.subplots()
+ ax.xaxis.set_major_locator(MaxNLocator(integer=True))
+ ax.yaxis.set_major_formatter(FuncFormatter(format_mem))
ax.set_ylabel('bytes')
ax.set_xlabel('round')
ax.set_ylim(minv,maxv)
- for k in sorted(fvals.keys()):
- xy = fvals[k]
- #for k, xy in fvals.items():
- lc = None
+
+ max_val_color = max(map(len, nodes)) * ord('z')
+ for k in nodes:
+ lc = None # let matplotlib to pick a color if there is no standard nodes name pattern => probably because of a single local run
+ if len(nodes) > 1:
+ # if there are multiple nodes choose some color based on the node name
+ s = sum(map(ord, k))
+ lc = (s/max_val_color, s/max_val_color, s/max_val_color)
if k.startswith('r'):
# blueish
lc = (0.3*random.random(), 0.3*random.random(), 0.7+(0.3*random.random()))
@@ -68,7 +112,12 @@ def main():
elif k.startswith('n'):
# reddish
lc = (0.7+(0.3*random.random()), 0.3*random.random(), 0.3*random.random())
- ax.plot([p[0] for p in xy], [p[1] for p in xy], label=k, color=lc)
+
+ metrics = fvals[k]
+ for i, metric in enumerate(metrics.keys()):
+ xy = metrics[metric]
+
+ ax.plot([p[0] for p in xy], [p[1] for p in xy], label=f'{k}/{metric}', color=lc, linestyle=plt_line_styles[i%len(plt_line_styles)])
ax.legend(loc='upper left', ncol=2)
plt.savefig(fname + '.svg', format='svg')
plt.savefig(fname + '.png', format='png')
diff --git a/test/scripts/e2e_client_runner.py b/test/scripts/e2e_client_runner.py
index 7da46e2a8..7b425ef92 100755
--- a/test/scripts/e2e_client_runner.py
+++ b/test/scripts/e2e_client_runner.py
@@ -446,11 +446,25 @@ def main():
retcode = 0
capv = args.version.capitalize()
xrun(['goal', 'network', 'create', '-r', netdir, '-n', 'tbd', '-t', os.path.join(repodir, f'test/testdata/nettemplates/TwoNodes50Each{capv}.json')], timeout=90)
+ nodeDataDir = os.path.join(netdir, 'Node')
+ primaryDataDir = os.path.join(netdir, 'Primary')
+
+ # Set EnableDeveloperAPI to true for both nodes
+ for dataDir in (nodeDataDir, primaryDataDir):
+ configFile = os.path.join(dataDir, 'config.json')
+ with open(configFile, 'r') as f:
+ configOptions = json.load(f)
+
+ configOptions['EnableDeveloperAPI'] = True
+
+ with open(configFile, 'w') as f:
+ json.dump(configOptions, f)
+
xrun(['goal', 'network', 'start', '-r', netdir], timeout=90)
atexit.register(goal_network_stop, netdir, env)
- env['ALGORAND_DATA'] = os.path.join(netdir, 'Node')
- env['ALGORAND_DATA2'] = os.path.join(netdir, 'Primary')
+ env['ALGORAND_DATA'] = nodeDataDir
+ env['ALGORAND_DATA2'] = primaryDataDir
if args.unsafe_scrypt:
create_kmd_config_with_unsafe_scrypt(env['ALGORAND_DATA'])
diff --git a/test/scripts/e2e_subs/e2e-app-simulate.sh b/test/scripts/e2e_subs/e2e-app-simulate.sh
index 7efc7ae3c..0576e8aea 100755
--- a/test/scripts/e2e_subs/e2e-app-simulate.sh
+++ b/test/scripts/e2e_subs/e2e-app-simulate.sh
@@ -384,3 +384,50 @@ if [[ $(echo "$RES" | jq '."txn-groups"[0]."app-budget-consumed"') -ne 804 ]]; t
date '+app-simulate-test FAIL the app call to generated large TEAL should be consuming 804 budget %Y%m%d_%H%M%S'
false
fi
+
+###############################################################
+# WE WANT TO TEST STACK AND SCRATCH TRACE IN SIMULATION WORKS #
+###############################################################
+
+RES=$(${gcmd} app create --creator ${ACCOUNT} --approval-prog "${DIR}/tealprogs/stack-scratch.teal" --clear-prog "${TEMPDIR}/simple-v8.teal" --extra-pages 1 2>&1 || true)
+
+EXPSUCCESS='Created app with app index'
+if [[ $RES != *"${EXPSUCCESS}"* ]]; then
+ date '+app-simulate-test FAIL the app creation for generated large TEAL should succeed %Y%m%d_%H%M%S'
+ false
+fi
+
+APPID=$(echo "$RES" | grep Created | awk '{ print $6 }')
+
+${gcmd} app call --app-id $APPID --app-arg "int:10" --from $ACCOUNT 2>&1 -o "${TEMPDIR}/stack-and-scratch.tx"
+${gcmd} clerk sign -i "${TEMPDIR}/stack-and-scratch.tx" -o "${TEMPDIR}/stack-and-scratch.stx"
+RES=$(${gcmd} clerk simulate --trace --stack --scratch -t "${TEMPDIR}/stack-and-scratch.stx")
+
+if [[ $(echo "$RES" | jq '."txn-groups" | any(has("failure-message"))') != $CONST_FALSE ]]; then
+ date '+app-simulate-test FAIL the app call for stack and scratch trace should pass %Y%m%d_%H%M%S'
+ false
+fi
+
+SCRATCH_STORE_UNIT=$(echo "$RES" | jq '."txn-groups"[0]."txn-results"[0]."exec-trace"."approval-program-trace"[-7]')
+
+if [[ $(echo "$SCRATCH_STORE_UNIT" | jq 'has("scratch-changes")') != $CONST_TRUE ]]; then
+ data '+app-simulate-test FAIL the app call for stack and scratch trace should return scratch changes at this unit %Y%m%d_%H%M%S'
+ false
+fi
+
+if [[ $(echo "$SCRATCH_STORE_UNIT" | jq '."scratch-changes" | length') != 1 ]]; then
+ data '+app-simulate-test FAIL the app call for stack and scratch trace should return scratch changes with length 1 at this unit %Y%m%d_%H%M%S'
+ false
+fi
+
+if [[ $(echo "$SCRATCH_STORE_UNIT" | jq 'has("stack-pop-count")') != $CONST_TRUE ]]; then
+ data '+app-simulate-test FAIL the app call for stack and scratch trace should return stack pop count at this unit %Y%m%d_%H%M%S'
+ false
+fi
+
+if [[ $(echo "$SCRATCH_STORE_UNIT" | jq '."stack-pop-count"') != 1 ]]; then
+ data '+app-simulate-test FAIL the app call for stack and scratch trace should return stack pop count being 1 at this unit %Y%m%d_%H%M%S'
+ false
+fi
+
+# WE DON'T TEST IN DETAILS ABOUT SCRATCH AND TRACE IN E2E SCRIPT TESTS, SEE RESTCLIENT TEST FOR DETAILS
diff --git a/test/scripts/e2e_subs/tealprogs/stack-scratch.teal b/test/scripts/e2e_subs/tealprogs/stack-scratch.teal
new file mode 100644
index 000000000..d7d123f24
--- /dev/null
+++ b/test/scripts/e2e_subs/tealprogs/stack-scratch.teal
@@ -0,0 +1,45 @@
+#pragma version 8
+txn ApplicationID // on creation, always approve
+bz end
+
+txn NumAppArgs
+int 1
+==
+assert
+
+txn ApplicationArgs 0
+btoi
+callsub subroutine_manipulating_stack
+itob
+log
+b end
+
+subroutine_manipulating_stack:
+ proto 1 1
+ int 0 // [0]
+ dup // [0, 0]
+ dupn 4 // [0, 0, 0, 0, 0, 0]
+ frame_dig -1 // [0, 0, 0, 0, 0, 0, arg_0]
+ frame_bury 0 // [arg_0, 0, 0, 0, 0, 0]
+ dig 5 // [arg_0, 0, 0, 0, 0, 0, arg_0]
+ cover 5 // [arg_0, arg_0, 0, 0, 0, 0, 0]
+ frame_dig 0 // [arg_0, arg_0, 0, 0, 0, 0, 0, arg_0]
+ frame_dig 1 // [arg_0, arg_0, 0, 0, 0, 0, 0, arg_0, arg_0]
+ + // [arg_0, arg_0, 0, 0, 0, 0, 0, arg_0 * 2]
+ bury 7 // [arg_0 * 2, arg_0, 0, 0, 0, 0, 0]
+ popn 5 // [arg_0 * 2, arg_0]
+ uncover 1 // [arg_0, arg_0 * 2]
+ swap // [arg_0 * 2, arg_0]
+ + // [arg_0 * 3]
+ pushbytess "1!" "5!" // [arg_0 * 3, "1!", "5!"]
+ pushints 0 2 1 1 5 18446744073709551615 // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1, 5, 18446744073709551615]
+ store 1 // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1, 5]
+ load 1 // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1, 5, 18446744073709551615]
+ stores // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1]
+ load 1 // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1, 18446744073709551615]
+ store 1 // [arg_0 * 3, "1!", "5!", 0, 2, 1, 1]
+ retsub
+
+end:
+ int 1
+ return \ No newline at end of file
diff --git a/tools/block-generator/Makefile b/tools/block-generator/Makefile
index 496a7fc99..fdb575421 100644
--- a/tools/block-generator/Makefile
+++ b/tools/block-generator/Makefile
@@ -12,7 +12,7 @@ clean-generator:
rm -f block-generator
debug-blockgen:
- python run_runner.py \
+ python scripts/run_runner.py \
--conduit-binary ./conduit \
--scenario $(SCENARIO) \
--report-directory $(REPORTS) \
@@ -38,7 +38,7 @@ run-runner: block-generator
--report-directory $(REPORTS)
clean-reports:
- rm -rf $(REPORTS)
+ rm -rf $(REPORTS)
pre-git-push:
mv _go.mod go.mod
diff --git a/tools/block-generator/README.md b/tools/block-generator/README.md
index 544dc8009..a26328ec4 100644
--- a/tools/block-generator/README.md
+++ b/tools/block-generator/README.md
@@ -170,7 +170,7 @@ Flags:
-v, --verbose If set the runner will print debugging information from the generator and ledger.
```
-## Example Run using Conduit and Postgres in **bash** via `run_runner.sh`
+## Example Run using Conduit and Postgres
A typical **runner** scenario involves:
@@ -179,30 +179,30 @@ A typical **runner** scenario involves:
* a datastore -such as a postgres database- to collect `conduit`'s output
* a `conduit` config file to define its import/export behavior
-`run_runner.sh` makes the following choices for the previous bullet points:
-
-* it can accept any scenario as its second argument, but defaults to [test_config.yml](./test_config.yml) when this isn't provided (this is a scenario with a lifetime of ~30 seconds)
-* knows how to import through a mock Algod running on port 11112 (which is the port the runner avails)
-* sets up a dockerized postgres database to receive conduit's output
-* configures `conduit` for these specs using [this config template](./runner/template/conduit.yml.tmpl)
+The `block-generator runner` subcommand has a number of options to configure behavion.
### Sample Run
First you'll need to get a `conduit` binary. For example you can follow the [developer portal's instructions](https://developer.algorand.org/docs/get-details/conduit/GettingStarted/#installation) or run `go build .` inside of the directory `cmd/conduit` after downloading the `conduit` repo.
-Assume you've navigated to the `tools/block-generator` directory of
-the `go-algorand` repo, and:
+Run `make install` from the `go-algorand` root, this should add `block-generator` to your path.
-* saved the conduit binary to `tools/block-generator/conduit`
-* created a block generator scenario config at `tools/block-generator/scenario.yml`
+Start a postgres container using `scripts/run_postgres.sh`. This starts a container on port 15432 a database named generator_db and a user with credentials algorand/algorand.
-Then you can execute the following command to run the scenario:
+Now run `block-generator runner` to run the test:
```sh
-./run_runner.sh ./conduit scenario.yml
+block-generator runner \
+ --conduit-binary "$CONDUIT_BINARY" \
+ --report-directory reports \
+ --test-duration 30s \
+ --conduit-log-level trace \
+ --postgres-connection-string "host=localhost user=algorand password=algorand dbname=generator_db port=15432 sslmode=disable" \
+ --scenario generator/test_scenario.yml \
+ --reset-db
```
### Scenario Report
-If all goes well, the run will generate a directory `../../tmp/OUTPUT_RUN_RUNNER_TEST`
-and in that directory you can see the statistics of the run in `scenario.report`.
+If all goes well, the run will generate a directory named reports.
+In that directory you can see the statistics of the run in the file ending with `.report`.
diff --git a/tools/block-generator/generator/config_test.go b/tools/block-generator/generator/config_test.go
index bfdc69595..a595ad6d6 100644
--- a/tools/block-generator/generator/config_test.go
+++ b/tools/block-generator/generator/config_test.go
@@ -27,7 +27,7 @@ import (
func TestInitConfigFile(t *testing.T) {
partitiontest.PartitionTest(t)
- config, err := initializeConfigFile("../test_config.yml")
+ config, err := initializeConfigFile("test_scenario.yml")
require.NoError(t, err)
require.Equal(t, uint64(10), config.NumGenesisAccounts)
require.Equal(t, float32(0.25), config.AssetCloseFraction)
diff --git a/tools/block-generator/test_config.yml b/tools/block-generator/generator/test_scenario.yml
index 6d411e9ad..6d411e9ad 100644
--- a/tools/block-generator/test_config.yml
+++ b/tools/block-generator/generator/test_scenario.yml
diff --git a/tools/block-generator/run_tests.sh b/tools/block-generator/run_tests.sh
deleted file mode 100755
index 48c1490b4..000000000
--- a/tools/block-generator/run_tests.sh
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/usr/bin/env bash
-
-CONNECTION_STRING=""
-CONDUIT_BINARY=""
-REPORT_DIR=""
-DURATION="1h"
-LOG_LEVEL="error"
-SCENARIOS=""
-
-help() {
- echo "Usage:"
- echo " -v|--verbose enable verbose script output."
- echo " -c|--connection-string"
- echo " PostgreSQL connection string."
- echo " -i|--conduit path to conduit binary."
- echo " -s|--scenarios path to conduit test scenarios."
- echo " -r|--report-dir directory where the report should be written."
- echo " -d|--duration test duration."
- echo " -l|--level log level to pass to conduit."
- echo " -g|--generator block-generator binary to run the generator."
- exit
-}
-
-while :; do
- case "${1-}" in
- -h | --help) help ;;
- -v | --verbose) set -x ;;
- -c | --connection-string)
- CONNECTION_STRING="${2-}"
- shift
- ;;
- -g | --generator)
- GENERATOR_BINARY="${2-}"
- shift
- ;;
- -i | --conduit)
- CONDUIT_BINARY="${2-}"
- shift
- ;;
- -r | --report-dir)
- REPORT_DIR="${2-}"
- shift
- ;;
- -s | --scenarios)
- SCENARIOS="${2-}"
- shift
- ;;
- -d | --duration)
- DURATION="${2-}"
- shift
- ;;
- -l | --level)
- LOG_LEVEL="${2-}"
- shift
- ;;
- -?*) echo "Unknown option: $1" && exit 1;;
- *) break ;;
- esac
- shift
-done
-
-args=("$@")
-
-if [ -z "$CONNECTION_STRING" ]; then
- echo "Missing required connection string parameter (-c / --connection-string)."
- exit 1
-fi
-
-if [ -z "$CONDUIT_BINARY" ]; then
- echo "Missing required conduit binary parameter (-i / --conduit)."
- exit 1
-fi
-
-if [ -z "$SCENARIOS" ]; then
- echo "Missing required conduit test scenario parameter (-s / --scenarios)."
- exit 1
-fi
-
-if [ -z "$GENERATOR_BINARY" ]; then
- echo "path to block-generator binary is required"
- exit 1
-fi
-
-echo "Running with binary: $CONDUIT_BINARY"
-echo "Report directory: $REPORT_DIR"
-echo "Duration: $DURATION"
-echo "Log Level: $LOG_LEVEL"
-
-"$GENERATOR_BINARY" runner \
- -i "$CONDUIT_BINARY" \
- -s "$SCENARIOS" \
- -d "$DURATION" \
- -c "$CONNECTION_STRING" \
- --report-directory "$REPORT_DIR" \
- --conduit-log-level "$LOG_LEVEL" \
- --reset-report-dir
-
diff --git a/tools/block-generator/print_tps.py b/tools/block-generator/scripts/print_tps.py
index 3401c5515..3401c5515 100644
--- a/tools/block-generator/print_tps.py
+++ b/tools/block-generator/scripts/print_tps.py
diff --git a/tools/block-generator/run_postgres.sh b/tools/block-generator/scripts/run_postgres.sh
index 2c8175bb9..490404aff 100755
--- a/tools/block-generator/run_postgres.sh
+++ b/tools/block-generator/scripts/run_postgres.sh
@@ -14,8 +14,6 @@ set -e
POSTGRES_CONTAINER=generator-test-container
POSTGRES_PORT=15432
POSTGRES_DATABASE=generator_db
-CONFIG=${1:-"$(dirname $0)/test_config.yml"}
-echo "Using config file: $CONFIG"
function start_postgres() {
docker rm -f $POSTGRES_CONTAINER > /dev/null 2>&1 || true
diff --git a/tools/block-generator/run_runner.py b/tools/block-generator/scripts/run_runner.py
index 914a38d46..5f0753930 100644
--- a/tools/block-generator/run_runner.py
+++ b/tools/block-generator/scripts/run_runner.py
@@ -82,7 +82,7 @@ def parse_args():
parser.add_argument("--conduit-binary", help="Path to conduit binary")
parser.add_argument(
"--scenario",
- default=(default := CWD / "test_config.yml"),
+ default=(default := CWD.parents[1] / "test_scenario.yml"),
help=f"Scenario configuration file ({default=!s})",
)
parser.add_argument(
diff --git a/tools/block-generator/run_runner.sh b/tools/block-generator/scripts/run_runner.sh
index 236d7b2bb..5643ab9c8 100755
--- a/tools/block-generator/run_runner.sh
+++ b/tools/block-generator/scripts/run_runner.sh
@@ -15,7 +15,7 @@ fi
POSTGRES_CONTAINER=generator-test-container
POSTGRES_PORT=15432
POSTGRES_DATABASE=generator_db
-SCENARIO=${2:-"$(dirname $0)/test_config.yml"}
+SCENARIO=${2:-"$(dirname $0)/../test_scenario.yml"}
echo "Using scenario config file: $SCENARIO"
function start_postgres() {
@@ -51,10 +51,10 @@ echo "Starting postgres container."
start_postgres
echo "Starting test runner"
$(dirname "$0")/block-generator runner \
- --conduit-binary "$CONDUIT_BINARY" \
- --report-directory $OUTPUT \
- --test-duration 30s \
- --conduit-log-level trace \
- --postgres-connection-string "host=localhost user=algorand password=algorand dbname=generator_db port=15432 sslmode=disable" \
- --scenario ${SCENARIO} \
+ --conduit-binary "$CONDUIT_BINARY" \
+ --report-directory $OUTPUT \
+ --test-duration 30s \
+ --conduit-log-level trace \
+ --postgres-connection-string "host=localhost user=algorand password=algorand dbname=generator_db port=15432 sslmode=disable" \
+ --scenario ${SCENARIO} \
--reset-db