diff --git a/.circleci/config.yml b/.circleci/config.yml index b9ac9f3faf..8208fe063b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -303,7 +303,7 @@ jobs: parameters: platform: type: string - executor: << parameters.platform >>_medium + executor: << parameters.platform >>_large working_directory: << pipeline.parameters.build_dir >>/project parallelism: 10 environment: @@ -319,7 +319,7 @@ jobs: parameters: platform: type: string - executor: << parameters.platform >>_medium + executor: << parameters.platform >>_large working_directory: << pipeline.parameters.build_dir >>/project parallelism: 2 environment: diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 5e11c6cac9..bd7c93f7e5 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -17,7 +17,7 @@ jobs: name: Performance regression check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4.0.1 with: go-version-file: 'go.mod' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 785304b0db..0c08e8abbb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: update: true path-type: inherit - name: Check out code - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Determine Go version diff --git a/.github/workflows/codegen_verification.yml b/.github/workflows/codegen_verification.yml index a01e3e5e9c..ad90754d10 100644 --- a/.github/workflows/codegen_verification.yml +++ b/.github/workflows/codegen_verification.yml @@ -14,7 +14,7 @@ jobs: - 8080:8080 steps: - name: Check out code - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v4 with: fetch-depth: 0 path: go-algorand diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 75134a6d6a..074196e01a 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v4 - name: Generate Container Metadata id: meta @@ -59,7 +59,7 @@ jobs: # if: github.ref == format('refs/heads/{0}', 'master') # steps: # - name: Checkout Code - # uses: actions/checkout@v3.5.3 + # uses: actions/checkout@v4 # - name: Update DockerHub Repository Description # uses: peter-evans/dockerhub-description@v3 diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index efa0d75217..1eff6ac578 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code into the Go module directory - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v4 with: fetch-depth: 0 # required for new-from-rev option in .golangci.yml # move go out of the way temporarily to avoid "go list ./..." from installing modules @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code into the Go module directory - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v4 with: fetch-depth: 0 # required for new-from-rev option in .golangci.yml # move go out of the way temporarily to avoid "go list ./..." from installing modules diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index 064f100f4a..95acb22474 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code into the Go module directory - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v4 # move go out of the way temporarily to avoid "go list ./..." from installing modules - name: Make libsodium.a run: sudo mv /usr/bin/go /usr/bin/go.bak && make crypto/libs/linux/amd64/lib/libsodium.a && sudo mv /usr/bin/go.bak /usr/bin/go diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index 3c88c6e71e..0000000000 --- a/CODEOWNERS +++ /dev/null @@ -1,2 +0,0 @@ -.github/ @algorand/devops -.circleci/ @algorand/devops diff --git a/agreement/proposal.go b/agreement/proposal.go index e696bfeb4b..e8d506c4b5 100644 --- a/agreement/proposal.go +++ b/agreement/proposal.go @@ -277,7 +277,7 @@ func verifyProposer(p unauthenticatedProposal, ledger LedgerReader) error { // the header lacks it, the returned balanceRecord will be the right record. func payoutEligible(rnd basics.Round, proposer basics.Address, ledger LedgerReader, cparams config.ConsensusParams) (bool, basics.OnlineAccountData, error) { // Check the balance from the agreement round - balanceRound := balanceRound(rnd, cparams) + balanceRound := BalanceRound(rnd, cparams) balanceRecord, err := ledger.LookupAgreement(balanceRound, proposer) if err != nil { return false, basics.OnlineAccountData{}, err diff --git a/agreement/proposalManager.go b/agreement/proposalManager.go index 6ec8d2e1b6..472e8bb975 100644 --- a/agreement/proposalManager.go +++ b/agreement/proposalManager.go @@ -245,7 +245,7 @@ func (m *proposalManager) handleMessageEvent(r routerHandle, p player, e filtera } } -// filterVote filters a vote, checking if it is both fresh and not a duplicate, returning +// filterProposalVote filters a vote, checking if it is both fresh and not a duplicate, returning // an errProposalManagerPVNotFresh or errProposalManagerPVDuplicate if so, else nil. // It also returns a bool indicating whether this proposal-vote should still be verified for tracking credential history. func (m *proposalManager) filterProposalVote(p player, r routerHandle, uv unauthenticatedVote, freshData freshnessData) (bool, error) { diff --git a/agreement/pseudonode.go b/agreement/pseudonode.go index fe5423c025..32e42cd374 100644 --- a/agreement/pseudonode.go +++ b/agreement/pseudonode.go @@ -220,7 +220,7 @@ func (n *asyncPseudonode) loadRoundParticipationKeys(voteRound basics.Round) []a n.participationKeys = nil return nil } - balanceRound := balanceRound(voteRound, cparams) + balanceRound := BalanceRound(voteRound, cparams) // measure the time it takes to acquire the voting keys. beforeVotingKeysTime := time.Now() @@ -422,6 +422,9 @@ func (t pseudonodeVotesTask) execute(verifier *AsyncVoteVerifier, quit chan stru Type: logspec.VoteBroadcast, Sender: vote.R.Sender.String(), Hash: vote.R.Proposal.BlockDigest.String(), + Round: uint64(t.round), + Period: uint64(t.period), + Step: uint64(t.step), ObjectRound: uint64(vote.R.Round), ObjectPeriod: uint64(vote.R.Period), ObjectStep: uint64(vote.R.Step), @@ -549,6 +552,8 @@ func (t pseudonodeProposalsTask) execute(verifier *AsyncVoteVerifier, quit chan logEvent := logspec.AgreementEvent{ Type: logspec.ProposalBroadcast, Hash: vote.R.Proposal.BlockDigest.String(), + Round: uint64(t.round), + Period: uint64(t.period), ObjectRound: uint64(vote.R.Round), ObjectPeriod: uint64(vote.R.Period), } diff --git a/agreement/pseudonode_test.go b/agreement/pseudonode_test.go index ee83061ba0..fdc92f1805 100644 --- a/agreement/pseudonode_test.go +++ b/agreement/pseudonode_test.go @@ -449,7 +449,7 @@ func TestPseudonodeLoadingOfParticipationKeys(t *testing.T) { for rnd := basics.Round(3); rnd < 1000; rnd += 43 { keyManagerProxy.target = func(votingRound, balanceRnd basics.Round) []account.ParticipationRecordForRound { require.Equal(t, rnd, votingRound) - require.Equal(t, balanceRound(rnd, cparams), balanceRnd) + require.Equal(t, BalanceRound(rnd, cparams), balanceRnd) return keyManager.VotingKeys(votingRound, balanceRnd) } pb.loadRoundParticipationKeys(basics.Round(rnd)) diff --git a/agreement/selector.go b/agreement/selector.go index 76f9d5a312..2d0f980ac3 100644 --- a/agreement/selector.go +++ b/agreement/selector.go @@ -47,7 +47,10 @@ func (sel selector) CommitteeSize(proto config.ConsensusParams) uint64 { return sel.Step.committeeSize(proto) } -func balanceRound(r basics.Round, cparams config.ConsensusParams) basics.Round { +// BalanceRound returns the round that should be considered by agreement when +// looking at online stake (and status and key material). It is exported so that +// AVM can provide opcodes that return the same data. +func BalanceRound(r basics.Round, cparams config.ConsensusParams) basics.Round { return r.SubSaturate(basics.Round(2 * cparams.SeedRefreshInterval * cparams.SeedLookback)) } @@ -61,7 +64,7 @@ func membership(l LedgerReader, addr basics.Address, r basics.Round, p period, s if err != nil { return } - balanceRound := balanceRound(r, cparams) + balanceRound := BalanceRound(r, cparams) seedRound := seedRound(r, cparams) record, err := l.LookupAgreement(balanceRound, addr) diff --git a/catchup/catchpointService.go b/catchup/catchpointService.go index 3954c1cd6c..974f5964f1 100644 --- a/catchup/catchpointService.go +++ b/catchup/catchpointService.go @@ -698,7 +698,7 @@ func (cs *CatchpointCatchupService) fetchBlock(round basics.Round, retryCount ui return blk, cert, downloadDuration, psp, false, nil } -// processStageLedgerDownload is the fifth catchpoint catchup stage. It completes the catchup process, swap the new tables and restart the node functionality. +// processStageSwitch is the fifth catchpoint catchup stage. It completes the catchup process, swap the new tables and restart the node functionality. func (cs *CatchpointCatchupService) processStageSwitch() (err error) { err = cs.ledgerAccessor.CompleteCatchup(cs.ctx) if err != nil { diff --git a/catchup/universalFetcher.go b/catchup/universalFetcher.go index 926c85bb48..31d82adc98 100644 --- a/catchup/universalFetcher.go +++ b/catchup/universalFetcher.go @@ -43,7 +43,7 @@ type universalBlockFetcher struct { log logging.Logger } -// makeUniversalFetcher returns a fetcher for http and ws peers. +// makeUniversalBlockFetcher returns a fetcher for http and ws peers. func makeUniversalBlockFetcher(log logging.Logger, net network.GossipNode, config config.Local) *universalBlockFetcher { return &universalBlockFetcher{ config: config, diff --git a/cmd/goal/application.go b/cmd/goal/application.go index 922540b726..0a42f65b5d 100644 --- a/cmd/goal/application.go +++ b/cmd/goal/application.go @@ -1179,7 +1179,7 @@ const maxAppArgs = 16 // minus 1 for the final app argument becoming a tuple of the remaining method args const methodArgsTupleThreshold = maxAppArgs - 2 -// parseArgJSONtoByteSlice convert input method arguments to ABI encoded bytes +// parseMethodArgJSONtoByteSlice convert input method arguments to ABI encoded bytes // it converts funcArgTypes into a tuple type and apply changes over input argument string (in JSON format) // if there are greater or equal to 15 inputs, then we compact the tailing inputs into one tuple func parseMethodArgJSONtoByteSlice(argTypes []string, jsonArgs []string, applicationArgs *[][]byte) error { diff --git a/cmd/netgoal/network.go b/cmd/netgoal/network.go index 69fecbac26..d4ed3c277c 100644 --- a/cmd/netgoal/network.go +++ b/cmd/netgoal/network.go @@ -168,9 +168,9 @@ func runBuildNetwork() error { return fmt.Errorf("error resolving bootstrap file: %v", err) } net.BootstrappedNet = fileTemplate - net.SetUseBoostrappedFiles(bootstrapLoadingFile) + net.SetUseBootstrappedFiles(bootstrapLoadingFile) } else { - net.SetUseBoostrappedFiles(false) + net.SetUseBootstrappedFiles(false) } net.SetUseExistingGenesisFiles(networkUseGenesisFiles) diff --git a/cmd/tealdbg/localLedger.go b/cmd/tealdbg/localLedger.go index d97c8df70f..d495fbb328 100644 --- a/cmd/tealdbg/localLedger.go +++ b/cmd/tealdbg/localLedger.go @@ -336,6 +336,34 @@ func (l *localLedger) LookupWithoutRewards(rnd basics.Round, addr basics.Address return ledgercore.ToAccountData(ad), rnd, nil } +func (l *localLedger) LookupAgreement(rnd basics.Round, addr basics.Address) (basics.OnlineAccountData, error) { + // tealdbg does not understand rewards, so no pending rewards are applied. + // Further, it has no history, so we return the _current_ information, + // ignoring the `rnd` argument. + ad := l.balances[addr] + if ad.Status != basics.Online { + return basics.OnlineAccountData{}, nil + } + + return basics.OnlineAccountData{ + MicroAlgosWithRewards: ad.MicroAlgos, + VotingData: basics.VotingData{ + VoteID: ad.VoteID, + SelectionID: ad.SelectionID, + StateProofID: ad.StateProofID, + VoteFirstValid: ad.VoteFirstValid, + VoteLastValid: ad.VoteLastValid, + VoteKeyDilution: ad.VoteKeyDilution, + }, + IncentiveEligible: ad.IncentiveEligible, + }, nil +} + +func (l *localLedger) OnlineCirculation(rnd basics.Round, voteRound basics.Round) (basics.MicroAlgos, error) { + // A constant is fine for tealdbg + return basics.Algos(1_000_000_000), nil // 1B +} + func (l *localLedger) GetCreatorForRound(rnd basics.Round, cidx basics.CreatableIndex, ctype basics.CreatableType) (basics.Address, bool, error) { switch ctype { case basics.AssetCreatable: diff --git a/config/version.go b/config/version.go index 643ac34e86..8716fbcdcb 100644 --- a/config/version.go +++ b/config/version.go @@ -33,7 +33,7 @@ const VersionMajor = 3 // VersionMinor is the Minor semantic version number (x.#.z) - changed when backwards-compatible features are introduced. // Not enforced until after initial public release (x > 0). -const VersionMinor = 24 +const VersionMinor = 25 // Version is the type holding our full version information. type Version struct { diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json index 704b8a4638..36e4f34861 100644 --- a/daemon/algod/api/algod.oas2.json +++ b/daemon/algod/api/algod.oas2.json @@ -178,6 +178,44 @@ } } }, + "/debug/settings/pprof": { + "get": { + "description": "Retrieves the current settings for blocking and mutex profiles", + "tags": [ + "private" + ], + "produces": [ + "application/json" + ], + "schemes": [ + "http" + ], + "operationId": "GetDebugSettingsProf", + "responses": { + "200": { + "$ref": "#/responses/DebugSettingsProfResponse" + } + } + }, + "put": { + "description": "Enables blocking and mutex profiles, and returns the old settings", + "tags": [ + "private" + ], + "produces": [ + "application/json" + ], + "schemes": [ + "http" + ], + "operationId": "PutDebugSettingsProf", + "responses": { + "200": { + "$ref": "#/responses/DebugSettingsProfResponse" + } + } + } + }, "/v2/accounts/{address}": { "get": { "description": "Given a specific account public key, this call returns the accounts status, balance and spendable amounts", @@ -4053,6 +4091,26 @@ } } }, + "DebugSettingsProf": { + "description": "algod mutex and blocking profiling state.", + "type": "object", + "title": "algod mutex and blocking profiling state.", + "tags": [ + "private" + ], + "properties": { + "block-rate": { + "description": "The rate of blocking events. The profiler aims to sample an average of one blocking event per rate nanoseconds spent blocked. To turn off profiling entirely, pass rate 0.", + "example": 1000, + "type": "integer" + }, + "mutex-rate": { + "description": "The rate of mutex events. On average 1/rate events are reported. To turn off profiling entirely, pass rate 0", + "example": 1000, + "type": "integer" + } + } + }, "BuildVersion": { "tags": [ "common" @@ -5500,6 +5558,12 @@ "schema": { "$ref": "#/definitions/Version" } + }, + "DebugSettingsProfResponse": { + "description": "DebugPprof is the response to the /debug/extra/pprof endpoint", + "schema": { + "$ref": "#/definitions/DebugSettingsProf" + } } }, "securityDefinitions": { diff --git a/daemon/algod/api/algod.oas3.yml b/daemon/algod/api/algod.oas3.yml index 734dc4667a..6737a95072 100644 --- a/daemon/algod/api/algod.oas3.yml +++ b/daemon/algod/api/algod.oas3.yml @@ -520,6 +520,16 @@ }, "description": "Teal compile Result" }, + "DebugSettingsProfResponse": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DebugSettingsProf" + } + } + }, + "description": "DebugPprof is the response to the /debug/extra/pprof endpoint" + }, "DisassembleResponse": { "content": { "application/json": { @@ -1790,6 +1800,23 @@ "title": "BuildVersion contains the current algod build version information.", "type": "object" }, + "DebugSettingsProf": { + "description": "algod mutex and blocking profiling state.", + "properties": { + "block-rate": { + "description": "The rate of blocking events. The profiler aims to sample an average of one blocking event per rate nanoseconds spent blocked. To turn off profiling entirely, pass rate 0.", + "example": 1000, + "type": "integer" + }, + "mutex-rate": { + "description": "The rate of mutex events. On average 1/rate events are reported. To turn off profiling entirely, pass rate 0", + "example": 1000, + "type": "integer" + } + }, + "title": "algod mutex and blocking profiling state.", + "type": "object" + }, "DryrunRequest": { "description": "Request data type for dryrun endpoint. Given the Transactions and simulated ledger state upload, run TEAL scripts and return debugging information.", "properties": { @@ -2748,6 +2775,46 @@ }, "openapi": "3.0.1", "paths": { + "/debug/settings/pprof": { + "get": { + "description": "Retrieves the current settings for blocking and mutex profiles", + "operationId": "GetDebugSettingsProf", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DebugSettingsProf" + } + } + }, + "description": "DebugPprof is the response to the /debug/extra/pprof endpoint" + } + }, + "tags": [ + "private" + ] + }, + "put": { + "description": "Enables blocking and mutex profiles, and returns the old settings", + "operationId": "PutDebugSettingsProf", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DebugSettingsProf" + } + } + }, + "description": "DebugPprof is the response to the /debug/extra/pprof endpoint" + } + }, + "tags": [ + "private" + ] + } + }, "/genesis": { "get": { "description": "Returns the entire genesis file in json.", diff --git a/daemon/algod/api/server/common/handlers.go b/daemon/algod/api/server/common/handlers.go index 308017e98b..c771e1443b 100644 --- a/daemon/algod/api/server/common/handlers.go +++ b/daemon/algod/api/server/common/handlers.go @@ -186,8 +186,6 @@ func VersionsHandler(ctx lib.ReqContext, context echo.Context) { }, } json.NewEncoder(w).Encode(response.Body) - - return } // CORS diff --git a/daemon/algod/api/server/v2/dryrun.go b/daemon/algod/api/server/v2/dryrun.go index 9c3355cd10..d3924eaf1d 100644 --- a/daemon/algod/api/server/v2/dryrun.go +++ b/daemon/algod/api/server/v2/dryrun.go @@ -308,6 +308,32 @@ func (dl *dryrunLedger) LookupWithoutRewards(rnd basics.Round, addr basics.Addre return ledgercore.ToAccountData(ad), rnd, nil } +func (dl *dryrunLedger) LookupAgreement(rnd basics.Round, addr basics.Address) (basics.OnlineAccountData, error) { + // dryrun does not understand rewards, so we build the result without adding pending rewards. + // we also have no history, so we return current values + ad, _, err := dl.lookup(rnd, addr) + if err != nil || ad.Status != basics.Online { + return basics.OnlineAccountData{}, err + } + return basics.OnlineAccountData{ + MicroAlgosWithRewards: ad.MicroAlgos, + VotingData: basics.VotingData{ + VoteID: ad.VoteID, + SelectionID: ad.SelectionID, + StateProofID: ad.StateProofID, + VoteFirstValid: ad.VoteFirstValid, + VoteLastValid: ad.VoteLastValid, + VoteKeyDilution: ad.VoteKeyDilution, + }, + IncentiveEligible: ad.IncentiveEligible, + }, nil +} + +func (dl *dryrunLedger) OnlineCirculation(rnd basics.Round, voteRnd basics.Round) (basics.MicroAlgos, error) { + // dryrun doesn't support setting the global online stake, so we'll just return a constant + return basics.Algos(1_000_000_000), nil // 1B +} + func (dl *dryrunLedger) LookupApplication(rnd basics.Round, addr basics.Address, aidx basics.AppIndex) (ledgercore.AppResource, error) { ad, _, err := dl.lookup(rnd, addr) if err != nil { diff --git a/daemon/algod/api/server/v2/generated/data/routes.go b/daemon/algod/api/server/v2/generated/data/routes.go index 7f5cfbeb7a..504ee50c69 100644 --- a/daemon/algod/api/server/v2/generated/data/routes.go +++ b/daemon/algod/api/server/v2/generated/data/routes.go @@ -114,221 +114,225 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "y8xbNdpOULPHJw9nH/93AAAA//8Oc6QNuAMBAA==", + "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", } // 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 e6472ca97a..f78cbd49a6 100644 --- a/daemon/algod/api/server/v2/generated/experimental/routes.go +++ b/daemon/algod/api/server/v2/generated/experimental/routes.go @@ -168,188 +168,192 @@ var swaggerSpec = []string{ "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", - "AwAA///pfgaenwQBAA==", + "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", + "j08ezj7+/wAAAP//hDzDXLsHAQA=", } // 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 1755e868ee..e2d32257ba 100644 --- a/daemon/algod/api/server/v2/generated/model/types.go +++ b/daemon/algod/api/server/v2/generated/model/types.go @@ -562,6 +562,15 @@ type BuildVersion struct { Minor uint64 `json:"minor"` } +// DebugSettingsProf algod mutex and blocking profiling state. +type DebugSettingsProf struct { + // BlockRate The rate of blocking events. The profiler aims to sample an average of one blocking event per rate nanoseconds spent blocked. To turn off profiling entirely, pass rate 0. + BlockRate *uint64 `json:"block-rate,omitempty"` + + // MutexRate The rate of mutex events. On average 1/rate events are reported. To turn off profiling entirely, pass rate 0 + MutexRate *uint64 `json:"mutex-rate,omitempty"` +} + // DryrunRequest Request data type for dryrun endpoint. Given the Transactions and simulated ledger state upload, run TEAL scripts and return debugging information. type DryrunRequest struct { Accounts []Account `json:"accounts"` @@ -1189,6 +1198,9 @@ type CompileResponse struct { Sourcemap *map[string]interface{} `json:"sourcemap,omitempty"` } +// DebugSettingsProfResponse algod mutex and blocking profiling state. +type DebugSettingsProfResponse = DebugSettingsProf + // DisassembleResponse defines model for DisassembleResponse. type DisassembleResponse struct { // Result disassembled Teal code 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 568ebbb8ae..bf31180ecc 100644 --- a/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go +++ b/daemon/algod/api/server/v2/generated/nonparticipating/private/routes.go @@ -21,6 +21,12 @@ import ( // ServerInterface represents all server handlers. type ServerInterface interface { + + // (GET /debug/settings/pprof) + GetDebugSettingsProf(ctx echo.Context) error + + // (PUT /debug/settings/pprof) + PutDebugSettingsProf(ctx echo.Context) error // Aborts a catchpoint catchup. // (DELETE /v2/catchup/{catchpoint}) AbortCatchup(ctx echo.Context, catchpoint string) error @@ -37,6 +43,28 @@ type ServerInterfaceWrapper struct { Handler ServerInterface } +// GetDebugSettingsProf converts echo context to params. +func (w *ServerInterfaceWrapper) GetDebugSettingsProf(ctx echo.Context) error { + var err error + + ctx.Set(Api_keyScopes, []string{""}) + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.GetDebugSettingsProf(ctx) + return err +} + +// PutDebugSettingsProf converts echo context to params. +func (w *ServerInterfaceWrapper) PutDebugSettingsProf(ctx echo.Context) error { + var err error + + ctx.Set(Api_keyScopes, []string{""}) + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.PutDebugSettingsProf(ctx) + return err +} + // AbortCatchup converts echo context to params. func (w *ServerInterfaceWrapper) AbortCatchup(ctx echo.Context) error { var err error @@ -130,6 +158,8 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL Handler: si, } + router.GET(baseURL+"/debug/settings/pprof", wrapper.GetDebugSettingsProf, m...) + router.PUT(baseURL+"/debug/settings/pprof", wrapper.PutDebugSettingsProf, m...) router.DELETE(baseURL+"/v2/catchup/:catchpoint", wrapper.AbortCatchup, m...) router.POST(baseURL+"/v2/catchup/:catchpoint", wrapper.StartCatchup, m...) router.POST(baseURL+"/v2/shutdown", wrapper.ShutdownNode, m...) @@ -139,224 +169,230 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "NYXFJk9OHk0+/t8AAAD//5YZK+EHBgEA", + "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", + "h/8fAAD//3HzSP3DCwEA", } // 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 815a346434..18ea670c4d 100644 --- a/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go +++ b/daemon/algod/api/server/v2/generated/nonparticipating/public/routes.go @@ -746,302 +746,306 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "IGsT4ujB5N7ow/8LAAD//5pnmKfruQEA", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/generated/participating/private/routes.go b/daemon/algod/api/server/v2/generated/participating/private/routes.go index d64047fe99..24f66d0cde 100644 --- a/daemon/algod/api/server/v2/generated/participating/private/routes.go +++ b/daemon/algod/api/server/v2/generated/participating/private/routes.go @@ -21,6 +21,12 @@ import ( // ServerInterface represents all server handlers. type ServerInterface interface { + + // (GET /debug/settings/pprof) + GetDebugSettingsProf(ctx echo.Context) error + + // (PUT /debug/settings/pprof) + PutDebugSettingsProf(ctx echo.Context) error // Return a list of participation keys // (GET /v2/participation) GetParticipationKeys(ctx echo.Context) error @@ -46,6 +52,28 @@ type ServerInterfaceWrapper struct { Handler ServerInterface } +// GetDebugSettingsProf converts echo context to params. +func (w *ServerInterfaceWrapper) GetDebugSettingsProf(ctx echo.Context) error { + var err error + + ctx.Set(Api_keyScopes, []string{""}) + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.GetDebugSettingsProf(ctx) + return err +} + +// PutDebugSettingsProf converts echo context to params. +func (w *ServerInterfaceWrapper) PutDebugSettingsProf(ctx echo.Context) error { + var err error + + ctx.Set(Api_keyScopes, []string{""}) + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.PutDebugSettingsProf(ctx) + return err +} + // GetParticipationKeys converts echo context to params. func (w *ServerInterfaceWrapper) GetParticipationKeys(ctx echo.Context) error { var err error @@ -191,6 +219,8 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL Handler: si, } + router.GET(baseURL+"/debug/settings/pprof", wrapper.GetDebugSettingsProf, m...) + router.PUT(baseURL+"/debug/settings/pprof", wrapper.PutDebugSettingsProf, m...) router.GET(baseURL+"/v2/participation", wrapper.GetParticipationKeys, m...) router.POST(baseURL+"/v2/participation", wrapper.AddParticipationKey, m...) router.POST(baseURL+"/v2/participation/generate/:address", wrapper.GenerateParticipationKeys, m...) @@ -203,227 +233,233 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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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 409fd4ca65..4548badf2c 100644 --- a/daemon/algod/api/server/v2/generated/participating/public/routes.go +++ b/daemon/algod/api/server/v2/generated/participating/public/routes.go @@ -177,233 +177,237 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "AAD//23D8FrbHAEA", + "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", + "8aePjk8nH/5/AAAA//9iOfQe9x8BAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/daemon/algod/api/server/v2/handlers.go b/daemon/algod/api/server/v2/handlers.go index 3d581dbd78..f338c38b1f 100644 --- a/daemon/algod/api/server/v2/handlers.go +++ b/daemon/algod/api/server/v2/handlers.go @@ -26,8 +26,10 @@ import ( "math" "net/http" "os" + "runtime" "strconv" "strings" + "sync/atomic" "time" "github.com/labstack/echo/v4" @@ -2083,3 +2085,66 @@ func (v2 *Handlers) SetBlockTimeStampOffset(ctx echo.Context, offset uint64) err } return ctx.NoContent(http.StatusOK) } + +// savedBlockingRate is the current blocking rate +var savedBlockingRate atomic.Int32 + +// GetDebugSettingsProf returns the current mutex and blocking rates. +func (v2 *Handlers) GetDebugSettingsProf(ctx echo.Context) error { + mutexRate := uint64(runtime.SetMutexProfileFraction(-1)) + blockingRate := uint64(savedBlockingRate.Load()) + + response := model.DebugSettingsProf{ + MutexRate: &mutexRate, + BlockRate: &blockingRate, + } + + return ctx.JSON(http.StatusOK, response) +} + +// PutDebugSettingsProf sets the mutex and blocking rates and returns the old values. +func (v2 *Handlers) PutDebugSettingsProf(ctx echo.Context) error { + req := ctx.Request() + buf := new(bytes.Buffer) + req.Body = http.MaxBytesReader(nil, req.Body, 128) + _, err := buf.ReadFrom(ctx.Request().Body) + if err != nil { + return badRequest(ctx, err, err.Error(), v2.Log) + } + data := buf.Bytes() + + var opts model.DebugSettingsProf + err = decode(protocol.JSONStrictHandle, data, &opts) + if err != nil { + return badRequest(ctx, err, err.Error(), v2.Log) + } + + var response model.DebugSettingsProf + + // validate input fiest + if opts.MutexRate != nil && *opts.MutexRate > math.MaxInt32 { + err = errors.New("blocking rate cannot be larger than max int32 value") + return badRequest(ctx, err, err.Error(), v2.Log) + } + if opts.BlockRate != nil && *opts.BlockRate > math.MaxInt32 { + err = errors.New("blocking rate cannot be larger than max int32 value") + return badRequest(ctx, err, err.Error(), v2.Log) + } + + if opts.MutexRate != nil { + newMutexRate := int(*opts.MutexRate) + oldMutexRate := uint64(runtime.SetMutexProfileFraction(newMutexRate)) + response.MutexRate = &oldMutexRate + } + + if opts.BlockRate != nil { + newBlockingRate := int(*opts.BlockRate) + runtime.SetBlockProfileRate(newBlockingRate) + + oldBlockingRate := uint64(savedBlockingRate.Load()) + response.BlockRate = &oldBlockingRate + savedBlockingRate.Store(int32(newBlockingRate)) + } + + return ctx.JSON(http.StatusOK, response) +} diff --git a/daemon/algod/api/server/v2/test/handlers_test.go b/daemon/algod/api/server/v2/test/handlers_test.go index 53ef65256c..1952c88e7a 100644 --- a/daemon/algod/api/server/v2/test/handlers_test.go +++ b/daemon/algod/api/server/v2/test/handlers_test.go @@ -2439,3 +2439,66 @@ func TestGeneratePartkeys(t *testing.T) { } } + +func TestDebugExtraPprofEndpoint(t *testing.T) { + partitiontest.PartitionTest(t) + + submit := func(t *testing.T, method string, body []byte, expectedCode int) []byte { + handler := v2.Handlers{ + Node: nil, + Log: logging.Base(), + } + e := echo.New() + + var bodyReader io.Reader + if body != nil { + bodyReader = bytes.NewReader(body) + } + + req := httptest.NewRequest(method, "/debug/extra/pprof", bodyReader) + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + + if method == http.MethodPut { + handler.PutDebugSettingsProf(c) + } else { + handler.GetDebugSettingsProf(c) + } + require.Equal(t, expectedCode, rec.Code) + + return rec.Body.Bytes() + } + + // check original values + body := submit(t, http.MethodGet, nil, http.StatusOK) + require.Contains(t, string(body), `"mutex-rate":0`) + require.Contains(t, string(body), `"block-rate":0`) + + // enable mutex and blocking profiling, should return the original zero values + body = submit(t, http.MethodPut, []byte(`{"mutex-rate":1000, "block-rate":2000}`), http.StatusOK) + require.Contains(t, string(body), `"mutex-rate":0`) + require.Contains(t, string(body), `"block-rate":0`) + + // check the new values + body = submit(t, http.MethodGet, nil, http.StatusOK) + require.Contains(t, string(body), `"mutex-rate":1000`) + require.Contains(t, string(body), `"block-rate":2000`) + + // set invalid values + body = submit(t, http.MethodPut, []byte(`{"mutex-rate":-1, "block-rate":2000}`), http.StatusBadRequest) + require.Contains(t, string(body), "failed to decode object") + + body = submit(t, http.MethodPut, []byte(`{"mutex-rate":1000, "block-rate":-2}`), http.StatusBadRequest) + require.Contains(t, string(body), "failed to decode object") + + // disable mutex and blocking profiling + body = submit(t, http.MethodPut, []byte(`{"mutex-rate":0, "block-rate":0}`), http.StatusOK) + require.Contains(t, string(body), `"mutex-rate":1000`) + require.Contains(t, string(body), `"block-rate":2000`) + + // check it is disabled + body = submit(t, http.MethodGet, nil, http.StatusOK) + require.Contains(t, string(body), `"mutex-rate":0`) + require.Contains(t, string(body), `"block-rate":0`) + +} diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index ec5537a701..79b37186df 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -427,6 +427,11 @@ match_label1: pushbytess "1" "2" "1" ` +const incentiveNonsense = ` +online_stake +voter_params_get VoterIncentiveEligible +` + const stateProofNonsense = ` pushbytes 0x0123456789abcd sumhash512 @@ -445,7 +450,7 @@ const spliceNonsence = ` const v10Nonsense = v9Nonsense + pairingNonsense + spliceNonsence -const v11Nonsense = v10Nonsense + stateProofNonsense +const v11Nonsense = v10Nonsense + incentiveNonsense + stateProofNonsense const v6Compiled = "2004010002b7a60c26050242420c68656c6c6f20776f726c6421070123456789abcd208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292b0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f2310231123122313231418191a1b1c28171615400003290349483403350222231d4a484848482b50512a632223524100034200004322602261222704634848222862482864286548482228246628226723286828692322700048482371004848361c0037001a0031183119311b311d311e311f312023221e312131223123312431253126312731283129312a312b312c312d312e312f447825225314225427042455220824564c4d4b0222382124391c0081e80780046a6f686e2281d00f23241f880003420001892224902291922494249593a0a1a2a3a4a5a6a7a8a9aaabacadae24af3a00003b003c003d816472064e014f012a57000823810858235b235a2359b03139330039b1b200b322c01a23c1001a2323c21a23c3233e233f8120af06002a494905002a49490700b400b53a03b6b7043cb8033a0c2349c42a9631007300810881088120978101c53a8101c6003a" @@ -467,9 +472,11 @@ const spliceCompiled = "d2d3" const v10Compiled = v9Compiled + pairingCompiled + spliceCompiled +const incentiveCompiled = "757401" + const stateProofCompiled = "80070123456789abcd86494985" -const V11Compiled = v10Compiled + stateProofCompiled +const V11Compiled = v10Compiled + incentiveCompiled + stateProofCompiled var nonsense = map[uint64]string{ 1: v1Nonsense, diff --git a/data/transactions/logic/crypto_test.go b/data/transactions/logic/crypto_test.go index 5aad230289..0ba695dce5 100644 --- a/data/transactions/logic/crypto_test.go +++ b/data/transactions/logic/crypto_test.go @@ -606,8 +606,8 @@ ecdsa_verify Secp256r1 ri, si, err := ecdsa.Sign(rand.Reader, key, msg[:]) require.NoError(t, err) - r := ri.Bytes() - s := si.Bytes() + r := ri.FillBytes(make([]byte, 32)) + s := si.FillBytes(make([]byte, 32)) rTampered := slices.Clone(r) rTampered[0] += byte(1) // intentional overflow @@ -826,8 +826,8 @@ func benchmarkEcdsaGenData(b *testing.B, curve EcdsaCurve) (data []benchmarkEcds } else if curve == Secp256r1 { r, s, err := ecdsa.Sign(rand.Reader, key, data[i].msg[:]) require.NoError(b, err) - data[i].r = r.Bytes() - data[i].s = s.Bytes() + data[i].r = r.FillBytes(make([]byte, 32)) + data[i].s = s.FillBytes(make([]byte, 32)) } } return data diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go index fde870a9d4..3bab156561 100644 --- a/data/transactions/logic/doc.go +++ b/data/transactions/logic/doc.go @@ -250,6 +250,8 @@ var opDescByName = map[string]OpDesc{ "asset_params_get": {"X is field F from asset A. Y is 1 if A exists, else 0", "params: Txn.ForeignAssets offset (or, since v4, an _available_ asset id. Return: did_exist flag (1 if the asset existed and 0 otherwise), value.", []string{"asset params field index"}}, "app_params_get": {"X is field F from app A. Y is 1 if A exists, else 0", "params: Txn.ForeignApps offset or an _available_ app id. Return: did_exist flag (1 if the application existed and 0 otherwise), value.", []string{"app params field index"}}, "acct_params_get": {"X is field F from account A. Y is 1 if A owns positive algos, else 0", "", []string{"account params field index"}}, + "voter_params_get": {"X is field F from online account A as of the balance round: 320 rounds before the current round. Y is 1 if A had positive algos online in the agreement round, else Y is 0 and X is a type specific zero-value", "", []string{"voter params field index"}}, + "online_stake": {"the total online stake in the agreement round", "", nil}, "assert": {"immediately fail unless A is a non-zero number", "", nil}, "callsub": {"branch unconditionally to TARGET, saving the next instruction on the call stack", "The call stack is separate from the data stack. Only `callsub`, `retsub`, and `proto` manipulate it.", []string{"branch offset"}}, "proto": {"Prepare top call frame for a retsub that will assume A args and R return values.", "Fails unless the last instruction executed was a `callsub`.", []string{"number of arguments", "number of return values"}}, @@ -355,7 +357,7 @@ var OpGroups = map[string][]string{ "Cryptography": {"sha256", "keccak256", "sha512_256", "sha3_256", "sumhash512", "falcon_verify", "ed25519verify", "ed25519verify_bare", "ecdsa_verify", "ecdsa_pk_recover", "ecdsa_pk_decompress", "vrf_verify", "ec_add", "ec_scalar_mul", "ec_pairing_check", "ec_multi_scalar_mul", "ec_subgroup_check", "ec_map_to"}, "Loading Values": {"intcblock", "intc", "intc_0", "intc_1", "intc_2", "intc_3", "pushint", "pushints", "bytecblock", "bytec", "bytec_0", "bytec_1", "bytec_2", "bytec_3", "pushbytes", "pushbytess", "bzero", "arg", "arg_0", "arg_1", "arg_2", "arg_3", "args", "txn", "gtxn", "txna", "txnas", "gtxna", "gtxnas", "gtxns", "gtxnsa", "gtxnsas", "global", "load", "loads", "store", "stores", "gload", "gloads", "gloadss", "gaid", "gaids"}, "Flow Control": {"err", "bnz", "bz", "b", "return", "pop", "popn", "dup", "dup2", "dupn", "dig", "bury", "cover", "uncover", "frame_dig", "frame_bury", "swap", "select", "assert", "callsub", "proto", "retsub", "switch", "match"}, - "State Access": {"balance", "min_balance", "app_opted_in", "app_local_get", "app_local_get_ex", "app_global_get", "app_global_get_ex", "app_local_put", "app_global_put", "app_local_del", "app_global_del", "asset_holding_get", "asset_params_get", "app_params_get", "acct_params_get", "log", "block"}, + "State Access": {"balance", "min_balance", "app_opted_in", "app_local_get", "app_local_get_ex", "app_global_get", "app_global_get_ex", "app_local_put", "app_global_put", "app_local_del", "app_global_del", "asset_holding_get", "asset_params_get", "app_params_get", "acct_params_get", "voter_params_get", "online_stake", "log", "block"}, "Box Access": {"box_create", "box_extract", "box_replace", "box_splice", "box_del", "box_len", "box_get", "box_put", "box_resize"}, "Inner Transactions": {"itxn_begin", "itxn_next", "itxn_field", "itxn_submit", "itxn", "itxna", "itxnas", "gitxn", "gitxna", "gitxnas"}, } diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 3008250a54..36ba3bb788 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -248,6 +248,11 @@ type LedgerForLogic interface { Round() basics.Round PrevTimestamp() int64 + // These are simplifications of the underlying Ledger methods that take a + // round argument. They implicitly use agreement's BalanceRound (320 back). + AgreementData(addr basics.Address) (basics.OnlineAccountData, error) + OnlineStake() (basics.MicroAlgos, error) + AssetHolding(addr basics.Address, assetIdx basics.AssetIndex) (basics.AssetHolding, error) AssetParams(aidx basics.AssetIndex) (basics.AssetParams, basics.Address, error) AppParams(aidx basics.AppIndex) (basics.AppParams, basics.Address, error) @@ -3736,7 +3741,7 @@ func (cx *EvalContext) globalFieldToValue(fs globalFieldSpec) (sv stackValue, er return sv, fmt.Errorf("invalid global field %s", fs.field) } - if fs.ftype.AVMType != sv.avmType() { + if err == nil && fs.ftype.AVMType != sv.avmType() { return sv, fmt.Errorf("%s expected field type is %s but got %s", fs.field, fs.ftype, sv.avmType()) } @@ -5019,12 +5024,62 @@ func opAcctParamsGet(cx *EvalContext) error { value.Uint = account.TotalBoxes case AcctTotalBoxBytes: value.Uint = account.TotalBoxBytes + case AcctIncentiveEligible: + value = boolToSV(account.IncentiveEligible) + case AcctLastHeartbeat: + value.Uint = uint64(account.LastHeartbeat) + case AcctLastProposed: + value.Uint = uint64(account.LastProposed) + default: + return fmt.Errorf("invalid account field %s", fs.field) } cx.Stack[last] = value cx.Stack = append(cx.Stack, boolToSV(account.MicroAlgos.Raw > 0)) return nil } +func opVoterParamsGet(cx *EvalContext) error { + last := len(cx.Stack) - 1 // acct + addr, _, err := cx.accountReference(cx.Stack[last]) + if err != nil { + return err + } + + paramField := VoterParamsField(cx.program[cx.pc+1]) + fs, ok := voterParamsFieldSpecByField(paramField) + if !ok || fs.version > cx.version { + return fmt.Errorf("invalid voter_params_get field %d", paramField) + } + + account, err := cx.Ledger.AgreementData(addr) + if err != nil { + return err + } + + var value stackValue + + switch fs.field { + case VoterBalance: + value.Uint = account.MicroAlgosWithRewards.Raw + case VoterIncentiveEligible: + value = boolToSV(account.IncentiveEligible) + default: + return fmt.Errorf("invalid voter field %s", fs.field) + } + cx.Stack[last] = value + cx.Stack = append(cx.Stack, boolToSV(account.MicroAlgosWithRewards.Raw > 0)) + return nil +} + +func opOnlineStake(cx *EvalContext) error { + amount, err := cx.Ledger.OnlineStake() + if err != nil { + return err + } + cx.Stack = append(cx.Stack, stackValue{Uint: amount.Raw}) + return nil +} + func opLog(cx *EvalContext) error { last := len(cx.Stack) - 1 diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index 91ad91d1fe..abff0ddb83 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -348,6 +348,8 @@ log "int 0; int 0; app_params_get AppApprovalProgram": 5, "byte 0x01; log": 5, sender + "acct_params_get AcctBalance": 7, + sender + "voter_params_get VoterBalance": 11, + "online_stake": 11, "byte 0x1234; int 12; box_create": 8, "byte 0x1234; int 12; int 4; box_extract": 8, @@ -487,6 +489,9 @@ func testApp(t *testing.T, program string, ep *EvalParams, problems ...string) ( return testAppBytes(t, ops.Program, ep, problems...) } +// testAppCreator is the creator of the 888 app that is inserted when testing an app call +const testAppCreator = "47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU" + func testAppBytes(t *testing.T, program []byte, ep *EvalParams, problems ...string) (transactions.EvalDelta, error) { t.Helper() if ep == nil { @@ -497,6 +502,12 @@ func testAppBytes(t *testing.T, program []byte, ep *EvalParams, problems ...stri aid := ep.TxnGroup[0].Txn.ApplicationID if aid == 0 { aid = basics.AppIndex(888) + // we're testing an app call without the caller specifying details about + // the app, so conjure up boring app params to make the `global + // AppCreator` work. + addr, err := basics.UnmarshalChecksumAddress(testAppCreator) + require.NoError(t, err) + ep.Ledger.(*Ledger).NewApp(addr, 888, basics.AppParams{}) } return testAppFull(t, program, 0, aid, ep, problems...) } @@ -1598,6 +1609,49 @@ func TestAcctParams(t *testing.T) { ledger.NewAsset(tx.Sender, 3000, basics.AssetParams{}) test("txn Sender; acct_params_get AcctTotalAssetsCreated; assert; int 1; ==") test("txn Sender; acct_params_get AcctTotalAssets; assert; int 1; ==") + + if ep.Proto.LogicSigVersion < 11 { + return // the rest uses fields that came at 11 + } + test("txn Sender; acct_params_get AcctIncentiveEligible; assert; !") + test("txn Sender; acct_params_get AcctLastHeartbeat; assert; !") + test("txn Sender; acct_params_get AcctLastProposed; assert; !") + }) +} + +func TestVoterParams(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + // start at 11 for acct_params_get + testLogicRange(t, 11, 0, func(t *testing.T, ep *EvalParams, tx *transactions.Transaction, ledger *Ledger) { + test := func(source string) { + t.Helper() + testApp(t, source, ep) + } + + test("txn Sender; voter_params_get VoterBalance; !; assert; int 0; ==") + test("txn Sender; voter_params_get VoterIncentiveEligible; !; assert; int 0; ==") + + // The logic package test ledger just returns current values + ledger.NewAccount(tx.Sender, 42) + test("txn Sender; voter_params_get VoterBalance; assert; int 42; ==") + test("txn Sender; voter_params_get VoterIncentiveEligible; assert; !") + }) +} + +func TestOnlineStake(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + // start at 11 for online_stake + testLogicRange(t, 11, 0, func(t *testing.T, ep *EvalParams, tx *transactions.Transaction, ledger *Ledger) { + test := func(source string) { + t.Helper() + testApp(t, source, ep) + } + + test("online_stake; int 3333000000; ==") // test ledger hard codes 3333 algos }) } diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go index 3ede2c134b..3a81a9cbef 100644 --- a/data/transactions/logic/eval_test.go +++ b/data/transactions/logic/eval_test.go @@ -1160,8 +1160,6 @@ int 1 && ` -const testAddr = "47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU" - const globalV2TestProgram = globalV1TestProgram + ` global LogicSigVersion int 1 @@ -1182,7 +1180,7 @@ int 888 ` const globalV3TestProgram = globalV2TestProgram + ` global CreatorAddress -addr ` + testAddr + ` +addr ` + testAppCreator + ` == && ` @@ -1239,10 +1237,10 @@ const globalV11TestProgram = globalV10TestProgram + ` // No new globals in v11 ` -func TestGlobal(t *testing.T) { +func TestAllGlobals(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + type desc struct { lastField GlobalField program string @@ -1270,10 +1268,6 @@ func TestGlobal(t *testing.T) { require.Equal(t, tests[AssemblerMaxVersion].lastField, invalidGlobalField-1, "did you add a new global field?") - ledger := NewLedger(nil) - addr, err := basics.UnmarshalChecksumAddress(testAddr) - require.NoError(t, err) - ledger.NewApp(addr, 888, basics.AppParams{}) for v := uint64(1); v <= AssemblerMaxVersion; v++ { _, ok := tests[v] require.True(t, ok) @@ -1294,7 +1288,6 @@ func TestGlobal(t *testing.T) { appcall.Txn.Group = crypto.Digest{0x07, 0x06} ep := defaultAppParams(appcall) - ep.Ledger = ledger testApp(t, tests[v].program, ep) }) } diff --git a/data/transactions/logic/fields.go b/data/transactions/logic/fields.go index d0603d0ffc..367967089b 100644 --- a/data/transactions/logic/fields.go +++ b/data/transactions/logic/fields.go @@ -23,7 +23,7 @@ import ( "github.com/algorand/go-algorand/protocol" ) -//go:generate stringer -type=TxnField,GlobalField,AssetParamsField,AppParamsField,AcctParamsField,AssetHoldingField,OnCompletionConstType,EcdsaCurve,EcGroup,Base64Encoding,JSONRefType,VrfStandard,BlockField -output=fields_string.go +//go:generate stringer -type=TxnField,GlobalField,AssetParamsField,AppParamsField,AcctParamsField,AssetHoldingField,OnCompletionConstType,EcdsaCurve,EcGroup,Base64Encoding,JSONRefType,VoterParamsField,VrfStandard,BlockField -output=fields_string.go // FieldSpec unifies the various specs for assembly, disassembly, and doc generation. type FieldSpec interface { @@ -1319,6 +1319,14 @@ const ( // AcctTotalBoxBytes is the number of bytes in all boxes of this app account AcctTotalBoxBytes + // AcctIncentiveEligible is whether this account opted into block payouts by + // paying extra in `keyreg`. Does not reflect eligibility based on balance. + AcctIncentiveEligible + // AcctLastProposed is the last time this account proposed. Does not include _this_ round. + AcctLastProposed + // AcctLastHeartbeat is the last heartbeat from this account. + AcctLastHeartbeat + // AcctTotalAppSchema - consider how to expose invalidAcctParamsField // compile-time constant for number of fields @@ -1363,6 +1371,10 @@ var acctParamsFieldSpecs = [...]acctParamsFieldSpec{ {AcctTotalAssets, StackUint64, 8, "The numbers of ASAs held by this account (including ASAs this account created)."}, {AcctTotalBoxes, StackUint64, boxVersion, "The number of existing boxes created by this account's app."}, {AcctTotalBoxBytes, StackUint64, boxVersion, "The total number of bytes used by this account's app's box keys and values."}, + + {AcctIncentiveEligible, StackBoolean, incentiveVersion, "Has this account opted into block payouts"}, + {AcctLastProposed, StackUint64, incentiveVersion, "The round number of the last block this account proposed."}, + {AcctLastHeartbeat, StackUint64, incentiveVersion, "The round number of the last block this account sent a heartbeat."}, } func acctParamsFieldSpecByField(f AcctParamsField) (acctParamsFieldSpec, bool) { @@ -1388,6 +1400,78 @@ var AcctParamsFields = FieldGroup{ acctParamsFieldSpecByName, } +// VoterParamsField is an enum for `voter_params_get` opcode +type VoterParamsField int + +const ( + // VoterBalance is the balance, with pending rewards, from the balance + // round. It is 0 if the account was offline then. + VoterBalance VoterParamsField = iota + + // expose voter keys? + + // VoterIncentiveEligible is whether this account opted into block payouts + // by paying extra in `keyreg`. Does not reflect eligibility based on + // balance. The value is returned for the balance round and is _false_ if + // the account was offline then. + VoterIncentiveEligible + + invalidVoterParamsField // compile-time constant for number of fields +) + +var voterParamsFieldNames [invalidVoterParamsField]string + +type voterParamsFieldSpec struct { + field VoterParamsField + ftype StackType + version uint64 + doc string +} + +func (fs voterParamsFieldSpec) Field() byte { + return byte(fs.field) +} +func (fs voterParamsFieldSpec) Type() StackType { + return fs.ftype +} +func (fs voterParamsFieldSpec) OpVersion() uint64 { + return incentiveVersion +} +func (fs voterParamsFieldSpec) Version() uint64 { + return fs.version +} +func (fs voterParamsFieldSpec) Note() string { + return fs.doc +} + +var voterParamsFieldSpecs = [...]voterParamsFieldSpec{ + {VoterBalance, StackUint64, 6, "Online stake in microalgos"}, + {VoterIncentiveEligible, StackBoolean, incentiveVersion, "Had this account opted into block payouts"}, +} + +func voterParamsFieldSpecByField(f VoterParamsField) (voterParamsFieldSpec, bool) { + if int(f) >= len(voterParamsFieldSpecs) { + return voterParamsFieldSpec{}, false + } + return voterParamsFieldSpecs[f], true +} + +var voterParamsFieldSpecByName = make(voterNameSpecMap, len(voterParamsFieldNames)) + +type voterNameSpecMap map[string]voterParamsFieldSpec + +func (s voterNameSpecMap) get(name string) (FieldSpec, bool) { + fs, ok := s[name] + return fs, ok +} + +// VoterParamsFields describes voter_params_get's immediates +var VoterParamsFields = FieldGroup{ + "voter_params", "Fields", + voterParamsFieldNames[:], + voterParamsFieldSpecByName, +} + func init() { equal := func(x int, y int) { if x != y { @@ -1479,6 +1563,13 @@ func init() { acctParamsFieldSpecByName[s.field.String()] = s } + equal(len(voterParamsFieldSpecs), len(voterParamsFieldNames)) + for i, s := range voterParamsFieldSpecs { + equal(int(s.field), i) + voterParamsFieldNames[i] = s.field.String() + voterParamsFieldSpecByName[s.field.String()] = s + } + txnTypeMap = make(map[string]uint64) for i, tt := range TxnTypeNames { txnTypeMap[tt] = uint64(i) diff --git a/data/transactions/logic/fields_string.go b/data/transactions/logic/fields_string.go index 5b92357909..d925e69ee1 100644 --- a/data/transactions/logic/fields_string.go +++ b/data/transactions/logic/fields_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=TxnField,GlobalField,AssetParamsField,AppParamsField,AcctParamsField,AssetHoldingField,OnCompletionConstType,EcdsaCurve,EcGroup,Base64Encoding,JSONRefType,VrfStandard,BlockField -output=fields_string.go"; DO NOT EDIT. +// Code generated by "stringer -type=TxnField,GlobalField,AssetParamsField,AppParamsField,AcctParamsField,AssetHoldingField,OnCompletionConstType,EcdsaCurve,EcGroup,Base64Encoding,JSONRefType,VoterParamsField,VrfStandard,BlockField -output=fields_string.go"; DO NOT EDIT. package logic @@ -195,12 +195,15 @@ func _() { _ = x[AcctTotalAssets-9] _ = x[AcctTotalBoxes-10] _ = x[AcctTotalBoxBytes-11] - _ = x[invalidAcctParamsField-12] + _ = x[AcctIncentiveEligible-12] + _ = x[AcctLastProposed-13] + _ = x[AcctLastHeartbeat-14] + _ = x[invalidAcctParamsField-15] } -const _AcctParamsField_name = "AcctBalanceAcctMinBalanceAcctAuthAddrAcctTotalNumUintAcctTotalNumByteSliceAcctTotalExtraAppPagesAcctTotalAppsCreatedAcctTotalAppsOptedInAcctTotalAssetsCreatedAcctTotalAssetsAcctTotalBoxesAcctTotalBoxBytesinvalidAcctParamsField" +const _AcctParamsField_name = "AcctBalanceAcctMinBalanceAcctAuthAddrAcctTotalNumUintAcctTotalNumByteSliceAcctTotalExtraAppPagesAcctTotalAppsCreatedAcctTotalAppsOptedInAcctTotalAssetsCreatedAcctTotalAssetsAcctTotalBoxesAcctTotalBoxBytesAcctIncentiveEligibleAcctLastProposedAcctLastHeartbeatinvalidAcctParamsField" -var _AcctParamsField_index = [...]uint8{0, 11, 25, 37, 53, 74, 96, 116, 136, 158, 173, 187, 204, 226} +var _AcctParamsField_index = [...]uint16{0, 11, 25, 37, 53, 74, 96, 116, 136, 158, 173, 187, 204, 225, 241, 258, 280} func (i AcctParamsField) String() string { if i < 0 || i >= AcctParamsField(len(_AcctParamsField_index)-1) { @@ -328,6 +331,25 @@ func (i JSONRefType) String() string { } return _JSONRefType_name[_JSONRefType_index[i]:_JSONRefType_index[i+1]] } +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[VoterBalance-0] + _ = x[VoterIncentiveEligible-1] + _ = x[invalidVoterParamsField-2] +} + +const _VoterParamsField_name = "VoterBalanceVoterIncentiveEligibleinvalidVoterParamsField" + +var _VoterParamsField_index = [...]uint8{0, 12, 34, 57} + +func (i VoterParamsField) String() string { + if i < 0 || i >= VoterParamsField(len(_VoterParamsField_index)-1) { + return "VoterParamsField(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _VoterParamsField_name[_VoterParamsField_index[i]:_VoterParamsField_index[i+1]] +} func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. diff --git a/data/transactions/logic/fields_test.go b/data/transactions/logic/fields_test.go index 7cec0b936f..ab2548c306 100644 --- a/data/transactions/logic/fields_test.go +++ b/data/transactions/logic/fields_test.go @@ -29,7 +29,8 @@ import ( // ensure v2+ fields fail in TEAL assembler and evaluator on a version before they introduced // ensure v2+ fields error in v1 program -func TestGlobalFieldsVersions(t *testing.T) { +// ensure the types of the returned values are correct +func TestGlobalVersionsAndTypes(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() @@ -42,7 +43,7 @@ func TestGlobalFieldsVersions(t *testing.T) { require.Greater(t, len(fields), 1) for _, field := range fields { - text := fmt.Sprintf("global %s", field.field.String()) + text := "global " + field.field.String() // check assembler fails if version before introduction testLine(t, text, assemblerNoVersion, "...was introduced in...") for v := uint64(0); v < field.version; v++ { @@ -50,6 +51,32 @@ func TestGlobalFieldsVersions(t *testing.T) { } testLine(t, text, field.version, "") + // tack on a type check, and return a value (`int` gets compiled + // differently in different versions, so use intc_0 explicitly + switch field.ftype.AVMType { + case avmUint64: // ensure the return type is uint64 by using ! + text = "intcblock 1;" + text + "; !; pop; intc_0" + case avmBytes: // ensure the return type is bytes by using len + text = "intcblock 1;" + text + "; len; pop; intc_0" + case avmAny: + text = "intcblock 1;" + text + "; pop; intc_0" + } + + // check success in AssemblerMaxVersion and fs.version + for _, ver := range []uint64{AssemblerMaxVersion, field.version} { + ops := testProg(t, text, ver) + switch field.mode { + case ModeSig: + testLogicBytes(t, ops.Program, defaultSigParamsWithVersion(ver)) + case ModeApp: + testAppBytes(t, ops.Program, defaultAppParamsWithVersion(ver)) + case modeAny: + testLogicBytes(t, ops.Program, defaultSigParamsWithVersion(ver)) + testAppBytes(t, ops.Program, defaultAppParamsWithVersion(ver)) + default: + t.Fail() + } + } ops := testProg(t, text, AssemblerMaxVersion) // check on a version before the field version diff --git a/data/transactions/logic/ledger_test.go b/data/transactions/logic/ledger_test.go index 0254a44678..3dcead5e51 100644 --- a/data/transactions/logic/ledger_test.go +++ b/data/transactions/logic/ledger_test.go @@ -216,6 +216,12 @@ func (l *Ledger) PrevTimestamp() int64 { return int64(rand.Uint32() + 1) } +// OnlineStake returns the online stake that applies to the latest round (so +// it's actually the online stake from 320 rounds ago) +func (l *Ledger) OnlineStake() (basics.MicroAlgos, error) { + return basics.Algos(3333), nil +} + // BlockHdr returns the block header for the given round, if it is available func (l *Ledger) BlockHdr(round basics.Round) (bookkeeping.BlockHeader, error) { hdr := bookkeeping.BlockHeader{} @@ -310,6 +316,31 @@ func (l *Ledger) AccountData(addr basics.Address) (ledgercore.AccountData, error }, nil } +// AgreementData is not a very high-fidelity fake. There's no time delay, it +// just returns the data that's in AccountData, reshaped into an +// OnlineAccountData. +func (l *Ledger) AgreementData(addr basics.Address) (basics.OnlineAccountData, error) { + ad, err := l.AccountData(addr) + if err != nil { + return basics.OnlineAccountData{}, err + } + // You might imagine this conversion function exists. It does, but requires + // rewards handling because OnlineAccountData should have rewards + // paid. Here, we ignore that for simple tests. + return basics.OnlineAccountData{ + MicroAlgosWithRewards: ad.MicroAlgos, + VotingData: basics.VotingData{ + VoteID: ad.VoteID, + SelectionID: ad.SelectionID, + StateProofID: ad.StateProofID, + VoteFirstValid: ad.VoteFirstValid, + VoteLastValid: ad.VoteLastValid, + VoteKeyDilution: ad.VoteKeyDilution, + }, + IncentiveEligible: ad.IncentiveEligible, + }, nil +} + // Authorizer returns the address that must authorize txns from a // given address. It's either the address itself, or the value it has // been rekeyed to. diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index bb5992ae44..f3f8bfe37d 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -641,6 +641,8 @@ var OpSpecs = []OpSpec{ {0x71, "asset_params_get", opAssetParamsGet, proto("i:aT"), 2, field("f", &AssetParamsFields).only(ModeApp)}, {0x72, "app_params_get", opAppParamsGet, proto("i:aT"), 5, field("f", &AppParamsFields).only(ModeApp)}, {0x73, "acct_params_get", opAcctParamsGet, proto("a:aT"), 6, field("f", &AcctParamsFields).only(ModeApp)}, + {0x74, "voter_params_get", opVoterParamsGet, proto("a:aT"), incentiveVersion, field("f", &VoterParamsFields).only(ModeApp)}, + {0x75, "online_stake", opOnlineStake, proto(":i"), incentiveVersion, only(ModeApp)}, {0x78, "min_balance", opMinBalance, proto("i:i"), 3, only(ModeApp)}, {0x78, "min_balance", opMinBalance, proto("a:i"), directRefEnabledVersion, only(ModeApp)}, diff --git a/data/transactions/logic/teal.tmLanguage.json b/data/transactions/logic/teal.tmLanguage.json index 915957f7f0..53984e8dd2 100644 --- a/data/transactions/logic/teal.tmLanguage.json +++ b/data/transactions/logic/teal.tmLanguage.json @@ -72,7 +72,7 @@ }, { "name": "keyword.other.unit.teal", - "match": "^(box_create|box_del|box_extract|box_get|box_len|box_put|box_replace|box_resize|box_splice|acct_params_get|app_global_del|app_global_get|app_global_get_ex|app_global_put|app_local_del|app_local_get|app_local_get_ex|app_local_put|app_opted_in|app_params_get|asset_holding_get|asset_params_get|balance|block|log|min_balance)\\b" + "match": "^(box_create|box_del|box_extract|box_get|box_len|box_put|box_replace|box_resize|box_splice|acct_params_get|app_global_del|app_global_get|app_global_get_ex|app_global_put|app_local_del|app_local_get|app_local_get_ex|app_local_put|app_opted_in|app_params_get|asset_holding_get|asset_params_get|balance|block|log|min_balance|online_stake|voter_params_get)\\b" }, { "name": "keyword.operator.teal", diff --git a/data/txHandler.go b/data/txHandler.go index 3d20e95acd..7851889378 100644 --- a/data/txHandler.go +++ b/data/txHandler.go @@ -599,6 +599,18 @@ func (handler *TxHandler) processIncomingTxn(rawmsg network.IncomingMessage) net var err error var capguard *util.ErlCapacityGuard + accepted := false + defer func() { + // if we failed to put the item onto the backlog, we should release the capacity if any + if !accepted { + if capguard != nil { + if capErr := capguard.Release(); capErr != nil { + logging.Base().Warnf("Failed to release capacity to ElasticRateLimiter: %v", capErr) + } + } + } + }() + if handler.erl != nil { congestedERL := float64(cap(handler.backlogQueue))*handler.backlogCongestionThreshold < float64(len(handler.backlogQueue)) // consume a capacity unit @@ -679,6 +691,7 @@ func (handler *TxHandler) processIncomingTxn(rawmsg network.IncomingMessage) net unverifiedTxGroupHash: canonicalKey, capguard: capguard, }: + accepted = true default: // if we failed here we want to increase the corresponding metric. It might suggest that we // want to increase the queue size. diff --git a/data/txHandler_test.go b/data/txHandler_test.go index 5eb40741ee..896fbb161d 100644 --- a/data/txHandler_test.go +++ b/data/txHandler_test.go @@ -28,6 +28,7 @@ import ( "runtime/pprof" "strings" "sync" + "sync/atomic" "testing" "time" @@ -794,7 +795,7 @@ func TestTxHandlerProcessIncomingCensoring(t *testing.T) { // makeTestTxHandlerOrphaned creates a tx handler without any backlog consumer. // It is caller responsibility to run a consumer thread. func makeTestTxHandlerOrphaned(backlogSize int) *TxHandler { - return makeTestTxHandlerOrphanedWithContext(context.Background(), txBacklogSize, txBacklogSize, txHandlerConfig{true, false}, 0) + return makeTestTxHandlerOrphanedWithContext(context.Background(), backlogSize, backlogSize, txHandlerConfig{true, false}, 0) } func makeTestTxHandlerOrphanedWithContext(ctx context.Context, backlogSize int, cacheSize int, txHandlerConfig txHandlerConfig, refreshInterval time.Duration) *TxHandler { @@ -2681,3 +2682,65 @@ func TestTxHandlerAppRateLimiter(t *testing.T) { msg := <-handler.backlogQueue require.Equal(t, msg.rawmsg.Data, blob, blob) } + +// TestTxHandlerCapGuard checks there is no cap guard leak in case of invalid input. +func TestTxHandlerCapGuard(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + const numUsers = 10 + addresses, secrets, genesis := makeTestGenesisAccounts(t, numUsers) + genBal := bookkeeping.MakeGenesisBalances(genesis, sinkAddr, poolAddr) + ledgerName := fmt.Sprintf("%s-mem", t.Name()) + const inMem = true + log := logging.TestingLog(t) + log.SetLevel(logging.Error) + + cfg := config.GetDefaultLocal() + cfg.EnableTxBacklogRateLimiting = true + cfg.EnableTxBacklogAppRateLimiting = false + cfg.TxIncomingFilteringFlags = 0 + cfg.TxBacklogServiceRateWindowSeconds = 1 + cfg.TxBacklogReservedCapacityPerPeer = 1 + cfg.IncomingConnectionsLimit = 1 + cfg.TxBacklogSize = 3 + + ledger, err := LoadLedger(log, ledgerName, inMem, protocol.ConsensusCurrentVersion, genBal, genesisID, genesisHash, nil, cfg) + require.NoError(t, err) + defer ledger.Close() + + handler, err := makeTestTxHandler(ledger, cfg) + require.NoError(t, err) + defer handler.txVerificationPool.Shutdown() + defer close(handler.streamVerifierDropped) + + tx := transactions.Transaction{ + Type: protocol.PaymentTx, + Header: transactions.Header{ + Sender: addresses[0], + Fee: basics.MicroAlgos{Raw: proto.MinTxnFee * 2}, + FirstValid: 0, + LastValid: basics.Round(proto.MaxTxnLife), + }, + PaymentTxnFields: transactions.PaymentTxnFields{ + Receiver: addresses[1], + Amount: basics.MicroAlgos{Raw: 1000}, + }, + } + + signedTx := tx.Sign(secrets[0]) + blob := protocol.Encode(&signedTx) + blob[0]++ // make it invalid + + var completed atomic.Bool + go func() { + for i := 0; i < 10; i++ { + outgoing := handler.processIncomingTxn(network.IncomingMessage{Data: blob, Sender: mockSender{}}) + require.Equal(t, network.OutgoingMessage{Action: network.Disconnect}, outgoing) + require.Equal(t, 0, len(handler.backlogQueue)) + } + completed.Store(true) + }() + + require.Eventually(t, func() bool { return completed.Load() }, 1*time.Second, 10*time.Millisecond) +} diff --git a/go.mod b/go.mod index c15195b54b..a32da9da8c 100644 --- a/go.mod +++ b/go.mod @@ -42,10 +42,10 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.5.0 github.com/stretchr/testify v1.8.4 - golang.org/x/crypto v0.19.0 + golang.org/x/crypto v0.21.0 golang.org/x/exp v0.0.0-20240213143201-ec583247a57a golang.org/x/sync v0.6.0 - golang.org/x/sys v0.17.0 + golang.org/x/sys v0.18.0 golang.org/x/text v0.14.0 gopkg.in/sohlich/elogrus.v3 v3.0.0-20180410122755-1fa29e2f2009 pgregory.net/rapid v0.6.2 @@ -151,8 +151,8 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/mod v0.15.0 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/term v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.18.0 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/go.sum b/go.sum index badf55816d..cdae303d5b 100644 --- a/go.sum +++ b/go.sum @@ -591,8 +591,8 @@ golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= @@ -632,8 +632,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -683,11 +683,11 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/ledger/acctonline.go b/ledger/acctonline.go index 667255fb51..0db04e92ad 100644 --- a/ledger/acctonline.go +++ b/ledger/acctonline.go @@ -118,6 +118,9 @@ type onlineAccounts struct { // disableCache (de)activates the LRU cache use in onlineAccounts disableCache bool + + // cache for expired online circulation stake since the underlying query is quite heavy + expiredCirculationCache *expiredCirculationCache } // initialize initializes the accountUpdates structure @@ -125,6 +128,9 @@ func (ao *onlineAccounts) initialize(cfg config.Local) { ao.accountsReadCond = sync.NewCond(ao.accountsMu.RLocker()) ao.acctLookback = cfg.MaxAcctLookback ao.disableCache = cfg.DisableLedgerLRUCache + // 2 pages * 256 entries look large enough to handle + // both early and late votes, and well as a current and previous stateproof periods + ao.expiredCirculationCache = makeExpiredCirculationCache(256) } // loadFromDisk is the 2nd level initialization, and is required before the onlineAccounts becomes functional @@ -549,7 +555,7 @@ func (ao *onlineAccounts) onlineCirculation(rnd basics.Round, voteRnd basics.Rou if rnd == 0 { return totalStake, nil } - expiredStake, err := ao.ExpiredOnlineCirculation(rnd, voteRnd) + expiredStake, err := ao.expiredOnlineCirculation(rnd, voteRnd) if err != nil { return basics.MicroAlgos{}, err } @@ -874,7 +880,7 @@ func (ao *onlineAccounts) TopOnlineAccounts(rnd basics.Round, voteRnd basics.Rou for uint64(len(candidates)) < n+uint64(len(modifiedAccounts)) { var accts map[basics.Address]*ledgercore.OnlineAccount start := time.Now() - ledgerAccountsonlinetopCount.Inc(nil) + ledgerAccountsOnlineTopCount.Inc(nil) err = ao.dbs.Snapshot(func(ctx context.Context, tx trackerdb.SnapshotScope) (err error) { ar, err := tx.MakeAccountsReader() if err != nil { @@ -888,7 +894,7 @@ func (ao *onlineAccounts) TopOnlineAccounts(rnd basics.Round, voteRnd basics.Rou dbRound, err = ar.AccountsRound() return }) - ledgerAccountsonlinetopMicros.AddMicrosecondsSince(start, nil) + ledgerAccountsOnlineTopMicros.AddMicrosecondsSince(start, nil) if err != nil { return nil, basics.MicroAlgos{}, err } @@ -965,7 +971,7 @@ func (ao *onlineAccounts) TopOnlineAccounts(rnd basics.Round, voteRnd basics.Rou // If set, return total online stake minus all future expired stake by voteRnd if params.ExcludeExpiredCirculation { - expiredStake, err := ao.ExpiredOnlineCirculation(rnd, voteRnd) + expiredStake, err := ao.expiredOnlineCirculation(rnd, voteRnd) if err != nil { return nil, basics.MicroAlgos{}, err } @@ -1027,6 +1033,9 @@ func (ao *onlineAccounts) onlineAcctsExpiredByRound(rnd, voteRnd basics.Round) ( rewardsParams := config.Consensus[roundParams.CurrentProtocol] rewardsLevel := roundParams.RewardsLevel + start := time.Now() + ledgerAccountExpiredByRoundCount.Inc(nil) + // Step 1: get all online accounts from DB for rnd // Not unlocking ao.accountsMu yet, to stay consistent with Step 2 var dbRound basics.Round @@ -1042,6 +1051,7 @@ func (ao *onlineAccounts) onlineAcctsExpiredByRound(rnd, voteRnd basics.Round) ( dbRound, err = ar.AccountsRound() return err }) + ledgerAccountsExpiredByRoundMicros.AddMicrosecondsSince(start, nil) if err != nil { return nil, err } @@ -1086,9 +1096,13 @@ func (ao *onlineAccounts) onlineAcctsExpiredByRound(rnd, voteRnd basics.Round) ( return expiredAccounts, nil } -// ExpiredOnlineCirculation returns the total online stake for accounts with participation keys registered +// expiredOnlineCirculation returns the total online stake for accounts with participation keys registered // at round `rnd` that are expired by round `voteRnd`. -func (ao *onlineAccounts) ExpiredOnlineCirculation(rnd, voteRnd basics.Round) (basics.MicroAlgos, error) { +func (ao *onlineAccounts) expiredOnlineCirculation(rnd, voteRnd basics.Round) (basics.MicroAlgos, error) { + if expiredStake, ok := ao.expiredCirculationCache.get(rnd, voteRnd); ok { + return expiredStake, nil + } + expiredAccounts, err := ao.onlineAcctsExpiredByRound(rnd, voteRnd) if err != nil { return basics.MicroAlgos{}, err @@ -1101,8 +1115,11 @@ func (ao *onlineAccounts) ExpiredOnlineCirculation(rnd, voteRnd basics.Round) (b return basics.MicroAlgos{}, fmt.Errorf("ExpiredOnlineCirculation: overflow totaling expired stake") } } + ao.expiredCirculationCache.put(rnd, voteRnd, expiredStake) return expiredStake, nil } -var ledgerAccountsonlinetopCount = metrics.NewCounter("ledger_accountsonlinetop_count", "calls") -var ledgerAccountsonlinetopMicros = metrics.NewCounter("ledger_accountsonlinetop_micros", "µs spent") +var ledgerAccountsOnlineTopCount = metrics.NewCounter("ledger_accountsonlinetop_count", "calls") +var ledgerAccountsOnlineTopMicros = metrics.NewCounter("ledger_accountsonlinetop_micros", "µs spent") +var ledgerAccountExpiredByRoundCount = metrics.NewCounter("ledger_accountsexpired_count", "calls") +var ledgerAccountsExpiredByRoundMicros = metrics.NewCounter("ledger_accountsexpired_micros", "µs spent") diff --git a/ledger/acctonline_expired_test.go b/ledger/acctonline_expired_test.go index e51494d184..25bfe3b11b 100644 --- a/ledger/acctonline_expired_test.go +++ b/ledger/acctonline_expired_test.go @@ -49,7 +49,7 @@ type onlineAcctModel interface { LookupAgreement(rnd basics.Round, addr basics.Address) onlineAcctModelAcct OnlineCirculation(rnd basics.Round, voteRnd basics.Round) basics.MicroAlgos - ExpiredOnlineCirculation(rnd, voteRnd basics.Round) basics.MicroAlgos + expiredOnlineCirculation(rnd, voteRnd basics.Round) basics.MicroAlgos } // mapOnlineAcctModel provides a reference implementation for tracking online accounts used @@ -133,7 +133,7 @@ func (m *mapOnlineAcctModel) OnlineCirculation(rnd basics.Round, voteRnd basics. return m.sumAcctStake(accts) } -func (m *mapOnlineAcctModel) ExpiredOnlineCirculation(rnd, voteRnd basics.Round) basics.MicroAlgos { +func (m *mapOnlineAcctModel) expiredOnlineCirculation(rnd, voteRnd basics.Round) basics.MicroAlgos { accts := m.onlineAcctsExpiredByRound(rnd, voteRnd) return m.sumAcctStake(accts) } @@ -385,7 +385,7 @@ func (m *doubleLedgerAcctModel) OnlineCirculation(rnd basics.Round, voteRnd basi // has already subtracted the expired stake. So to get the total, add // it back in by querying ExpiredOnlineCirculation. if m.params.ExcludeExpiredCirculation { - expiredStake := m.ExpiredOnlineCirculation(rnd, rnd+320) + expiredStake := m.expiredOnlineCirculation(rnd, rnd+320) valStake = m.ops.Add(valStake, expiredStake) } @@ -404,20 +404,26 @@ func (l *Ledger) OnlineTotalStake(rnd basics.Round) (basics.MicroAlgos, error) { return totalStake, err } -// ExpiredOnlineCirculation is a wrapper to call onlineAccounts.ExpiredOnlineCirculation safely. -func (l *Ledger) ExpiredOnlineCirculation(rnd, voteRnd basics.Round) (basics.MicroAlgos, error) { +// expiredOnlineCirculation is a wrapper to call onlineAccounts.expiredOnlineCirculation safely. +func (l *Ledger) expiredOnlineCirculation(rnd, voteRnd basics.Round) (basics.MicroAlgos, error) { l.trackerMu.RLock() defer l.trackerMu.RUnlock() - return l.acctsOnline.ExpiredOnlineCirculation(rnd, voteRnd) + return l.acctsOnline.expiredOnlineCirculation(rnd, voteRnd) } -// ExpiredOnlineCirculation returns the total expired stake at rnd this model produced, while +// expiredOnlineCirculation returns the total expired stake at rnd this model produced, while // also asserting that the validator and generator Ledgers both agree. -func (m *doubleLedgerAcctModel) ExpiredOnlineCirculation(rnd, voteRnd basics.Round) basics.MicroAlgos { - valStake, err := m.dl.validator.ExpiredOnlineCirculation(rnd, voteRnd) +func (m *doubleLedgerAcctModel) expiredOnlineCirculation(rnd, voteRnd basics.Round) basics.MicroAlgos { + valStake, err := m.dl.validator.expiredOnlineCirculation(rnd, voteRnd) require.NoError(m.t, err) - genStake, err := m.dl.generator.ExpiredOnlineCirculation(rnd, voteRnd) + valCachedStake, has := m.dl.validator.acctsOnline.expiredCirculationCache.get(rnd, voteRnd) + require.True(m.t, has) + require.Equal(m.t, valStake, valCachedStake) + genStake, err := m.dl.generator.expiredOnlineCirculation(rnd, voteRnd) require.NoError(m.t, err) + genCachedStake, has := m.dl.generator.acctsOnline.expiredCirculationCache.get(rnd, voteRnd) + require.True(m.t, has) + require.Equal(m.t, genStake, genCachedStake) require.Equal(m.t, valStake, genStake) return valStake } @@ -483,7 +489,7 @@ func testOnlineAcctModelSimple(t *testing.T, m onlineAcctModel) { a.Equal(basics.MicroAlgos{Raw: 43_210_000}, onlineStake) // expired stake is acct 2 + acct 4 - expiredStake := m.ExpiredOnlineCirculation(680, 1000) + expiredStake := m.expiredOnlineCirculation(680, 1000) a.Equal(basics.MicroAlgos{Raw: 22_110_000}, expiredStake) } @@ -519,15 +525,6 @@ type goOfflineAction struct{ addr basics.Address } func (a goOfflineAction) apply(t *testing.T, m onlineAcctModel) { m.goOffline(a.addr) } -type updateStakeAction struct { - addr basics.Address - stake uint64 -} - -func (a updateStakeAction) apply(t *testing.T, m onlineAcctModel) { - m.updateStake(a.addr, basics.MicroAlgos{Raw: a.stake}) -} - type checkOnlineStakeAction struct { rnd, voteRnd basics.Round online, expired uint64 @@ -535,7 +532,7 @@ type checkOnlineStakeAction struct { func (a checkOnlineStakeAction) apply(t *testing.T, m onlineAcctModel) { onlineStake := m.OnlineCirculation(a.rnd, a.voteRnd) - expiredStake := m.ExpiredOnlineCirculation(a.rnd, a.voteRnd) + expiredStake := m.expiredOnlineCirculation(a.rnd, a.voteRnd) require.Equal(t, basics.MicroAlgos{Raw: a.online}, onlineStake, "round %d, cur %d", a.rnd, m.currentRound()) require.Equal(t, basics.MicroAlgos{Raw: a.expired}, expiredStake, "rnd %d voteRnd %d, cur %d", a.rnd, a.voteRnd, m.currentRound()) } @@ -681,7 +678,7 @@ func BenchmarkExpiredOnlineCirculation(b *testing.B) { // query expired circulation across the available range (last 320 rounds, from ~680 to ~1000) startRnd := m.currentRound() - 320 offset := basics.Round(i % 320) - _, err := m.dl.validator.ExpiredOnlineCirculation(startRnd+offset, startRnd+offset+320) + _, err := m.dl.validator.expiredOnlineCirculation(startRnd+offset, startRnd+offset+320) require.NoError(b, err) //total, err := m.dl.validator.OnlineTotalStake(startRnd + offset) //b.Log("expired circulation", startRnd+offset, startRnd+offset+320, "returned", expiredStake, "total", total) diff --git a/ledger/acctonline_test.go b/ledger/acctonline_test.go index d60353e2ae..afc7244082 100644 --- a/ledger/acctonline_test.go +++ b/ledger/acctonline_test.go @@ -1939,7 +1939,7 @@ func TestAcctOnline_ExpiredOnlineCirculation(t *testing.T) { initialOnlineStake, err := oa.onlineCirculation(0, basics.Round(oa.maxBalLookback())) a.NoError(err) a.Equal(totalStake, initialOnlineStake) - initialExpired, err := oa.ExpiredOnlineCirculation(0, 1000) + initialExpired, err := oa.expiredOnlineCirculation(0, 1000) a.NoError(err) a.Equal(basics.MicroAlgos{Raw: 0}, initialExpired) @@ -2146,10 +2146,10 @@ func TestAcctOnline_ExpiredOnlineCirculation(t *testing.T) { a.Fail("unknown db seed") } a.Equal(targetVoteRnd, rnd+basics.Round(params.MaxBalLookback)) - _, err := oa.ExpiredOnlineCirculation(rnd, targetVoteRnd) + _, err := oa.expiredOnlineCirculation(rnd, targetVoteRnd) a.Error(err) a.Contains(err.Error(), fmt.Sprintf("round %d too high", rnd)) - expiredStake, err := oa.ExpiredOnlineCirculation(rnd-1, targetVoteRnd) + expiredStake, err := oa.expiredOnlineCirculation(rnd-1, targetVoteRnd) a.NoError(err) a.Equal(expectedExpiredStake, expiredStake) diff --git a/ledger/acctonlineexp.go b/ledger/acctonlineexp.go new file mode 100644 index 0000000000..83cdaea456 --- /dev/null +++ b/ledger/acctonlineexp.go @@ -0,0 +1,66 @@ +// Copyright (C) 2019-2024 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see . + +package ledger + +import ( + "github.com/algorand/go-algorand/data/basics" + "github.com/algorand/go-deadlock" +) + +type expiredCirculationCache struct { + cur map[expiredCirculationKey]basics.MicroAlgos + prev map[expiredCirculationKey]basics.MicroAlgos + + maxSize int + mu deadlock.RWMutex +} + +type expiredCirculationKey struct { + rnd basics.Round + voteRnd basics.Round +} + +func makeExpiredCirculationCache(maxSize int) *expiredCirculationCache { + return &expiredCirculationCache{ + cur: make(map[expiredCirculationKey]basics.MicroAlgos), + maxSize: maxSize, + } +} + +func (c *expiredCirculationCache) get(rnd basics.Round, voteRnd basics.Round) (basics.MicroAlgos, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + if stake, ok := c.cur[expiredCirculationKey{rnd: rnd, voteRnd: voteRnd}]; ok { + return stake, true + } + if stake, ok := c.prev[expiredCirculationKey{rnd: rnd, voteRnd: voteRnd}]; ok { + return stake, true + } + + return basics.MicroAlgos{}, false +} + +func (c *expiredCirculationCache) put(rnd basics.Round, voteRnd basics.Round, expiredStake basics.MicroAlgos) { + c.mu.Lock() + defer c.mu.Unlock() + if len(c.cur) >= c.maxSize { + c.prev = c.cur + c.cur = make(map[expiredCirculationKey]basics.MicroAlgos) + + } + c.cur[expiredCirculationKey{rnd: rnd, voteRnd: voteRnd}] = expiredStake +} diff --git a/ledger/acctonlineexp_test.go b/ledger/acctonlineexp_test.go new file mode 100644 index 0000000000..024a8c539c --- /dev/null +++ b/ledger/acctonlineexp_test.go @@ -0,0 +1,69 @@ +// Copyright (C) 2019-2024 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see . + +package ledger + +import ( + "testing" + + "github.com/algorand/go-algorand/data/basics" + "github.com/algorand/go-algorand/test/partitiontest" + "github.com/stretchr/testify/require" +) + +func TestAcctOnline_ExpiredCirculationCacheBasic(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + cache := makeExpiredCirculationCache(1) + + expStake1 := basics.MicroAlgos{Raw: 123} + cache.put(1, 2, expStake1) + stake, ok := cache.get(1, 2) + require.True(t, ok) + require.Equal(t, expStake1, stake) + + stake, ok = cache.get(3, 4) + require.False(t, ok) + require.Equal(t, basics.MicroAlgos{}, stake) + + expStake2 := basics.MicroAlgos{Raw: 345} + cache.put(3, 4, expStake2) + + stake, ok = cache.get(3, 4) + require.True(t, ok) + require.Equal(t, expStake2, stake) + + // ensure the old entry is still there + stake, ok = cache.get(1, 2) + require.True(t, ok) + require.Equal(t, expStake1, stake) + + // add one more, should evict the first and keep the second + expStake3 := basics.MicroAlgos{Raw: 567} + cache.put(5, 6, expStake3) + stake, ok = cache.get(5, 6) + require.True(t, ok) + require.Equal(t, expStake3, stake) + + stake, ok = cache.get(3, 4) + require.True(t, ok) + require.Equal(t, expStake2, stake) + + stake, ok = cache.get(1, 2) + require.False(t, ok) + require.Equal(t, basics.MicroAlgos{}, stake) +} diff --git a/ledger/apptxn_test.go b/ledger/apptxn_test.go index 8e40d327e9..a7b3b15214 100644 --- a/ledger/apptxn_test.go +++ b/ledger/apptxn_test.go @@ -1104,13 +1104,16 @@ func TestKeyreg(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() - app := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + // 31 allowed inner keyreg + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() + + app := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` txn ApplicationArgs 0 byte "pay" == @@ -1133,71 +1136,59 @@ nonpart: itxn_field Nonparticipation itxn_submit `), - } + } - // Create the app - eval := nextBlock(t, l) - txns(t, l, eval, &app) - vb := endBlock(t, l, eval) - appID := vb.Block().Payset[0].ApplicationID - require.NotZero(t, appID) - - // Give the app a lot of money - fund := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: appID.Address(), - Amount: 1_000_000_000, - } - eval = nextBlock(t, l) - txn(t, l, eval, &fund) - endBlock(t, l, eval) + // Create the app + vb := dl.fullBlock(&app) + appID := vb.Block().Payset[0].ApplicationID + require.NotZero(t, appID) - require.Equal(t, 1_000_000_000, int(micros(t, l, appID.Address()))) + // Give the app a lot of money + fund := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: appID.Address(), + Amount: 1_000_000_000, + } + dl.fullBlock(&fund) - // Build up Residue in RewardsState so it's ready to pay - for i := 1; i < 10; i++ { - eval := nextBlock(t, l) - endBlock(t, l, eval) - } + require.Equal(t, 1_000_000_000, int(micros(t, dl.generator, appID.Address()))) - // pay a little - pay := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApplicationID: appID, - ApplicationArgs: [][]byte{[]byte("pay")}, - } - eval = nextBlock(t, l) - txn(t, l, eval, &pay) - endBlock(t, l, eval) - // 2000 was earned in rewards (- 1000 fee, -1 pay) - require.Equal(t, 1_000_000_999, int(micros(t, l, appID.Address()))) - - // Go nonpart - nonpart := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApplicationID: appID, - ApplicationArgs: [][]byte{[]byte("nonpart")}, - } - eval = nextBlock(t, l) - txn(t, l, eval, &nonpart) - endBlock(t, l, eval) - require.Equal(t, 999_999_999, int(micros(t, l, appID.Address()))) - - // Build up Residue in RewardsState so it's ready to pay AGAIN - // But expect no rewards - for i := 1; i < 100; i++ { - eval := nextBlock(t, l) - endBlock(t, l, eval) - } - eval = nextBlock(t, l) - txn(t, l, eval, pay.Noted("again")) - txn(t, l, eval, nonpart.Noted("again"), "cannot change online/offline") - endBlock(t, l, eval) - // Paid fee + 1. Did not get rewards - require.Equal(t, 999_998_998, int(micros(t, l, appID.Address()))) + // Build up Residue in RewardsState so it's ready to pay + for i := 1; i < 10; i++ { + dl.fullBlock() + } + + // pay a little + pay := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: appID, + ApplicationArgs: [][]byte{[]byte("pay")}, + } + dl.fullBlock(&pay) + // 2000 was earned in rewards (- 1000 fee, -1 pay) + require.Equal(t, 1_000_000_999, int(micros(t, dl.generator, appID.Address()))) + + // Go nonpart + nonpart := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: appID, + ApplicationArgs: [][]byte{[]byte("nonpart")}, + } + dl.fullBlock(&nonpart) + require.Equal(t, 999_999_999, int(micros(t, dl.generator, appID.Address()))) + + // Build up Residue in RewardsState so it's ready to pay AGAIN + // But expect no rewards + for i := 1; i < 100; i++ { + dl.fullBlock() + } + dl.txn(pay.Noted("again")) + dl.txn(nonpart.Noted("again"), "cannot change online/offline") + require.Equal(t, 999_998_998, int(micros(t, dl.generator, appID.Address()))) + }) } func TestInnerAppCall(t *testing.T) { @@ -1205,13 +1196,16 @@ func TestInnerAppCall(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() - app0 := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + // 31 allowed inner appl. + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() + + app0 := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` itxn_begin int pay itxn_field TypeEnum @@ -1221,16 +1215,14 @@ func TestInnerAppCall(t *testing.T) { itxn_field Receiver itxn_submit `), - } - eval := nextBlock(t, l) - txn(t, l, eval, &app0) - vb := endBlock(t, l, eval) - id0 := vb.Block().Payset[0].ApplicationID + } + vb := dl.fullBlock(&app0) + id0 := vb.Block().Payset[0].ApplicationID - app1 := txntest.Txn{ - Type: "appl", - Sender: addrs[1], - ApprovalProgram: main(` + app1 := txntest.Txn{ + Type: "appl", + Sender: addrs[1], + ApprovalProgram: main(` itxn_begin int appl itxn_field TypeEnum @@ -1238,32 +1230,28 @@ func TestInnerAppCall(t *testing.T) { itxn_field ApplicationID itxn_submit `), - } + } - eval = nextBlock(t, l) - txns(t, l, eval, &app1) - vb = endBlock(t, l, eval) - id1 := vb.Block().Payset[0].ApplicationID + vb = dl.fullBlock(&app1) + id1 := vb.Block().Payset[0].ApplicationID - fund0 := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: id0.Address(), - Amount: 1_000_000_000, - } - fund1 := fund0 - fund1.Receiver = id1.Address() - - call1 := txntest.Txn{ - Type: "appl", - Sender: addrs[2], - ApplicationID: id1, - ForeignApps: []basics.AppIndex{id0}, - } - eval = nextBlock(t, l) - txns(t, l, eval, &fund0, &fund1, &call1) - endBlock(t, l, eval) + fund0 := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: id0.Address(), + Amount: 1_000_000_000, + } + fund1 := fund0 + fund1.Receiver = id1.Address() + call1 := txntest.Txn{ + Type: "appl", + Sender: addrs[2], + ApplicationID: id1, + ForeignApps: []basics.AppIndex{id0}, + } + dl.fullBlock(&fund0, &fund1, &call1) + }) } // TestInnerAppManipulate ensures that apps called from inner transactions make @@ -1496,13 +1484,16 @@ func TestIndirectReentry(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() - app0 := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + // 31 allowed inner appl. + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() + + app0 := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` itxn_begin int appl itxn_field TypeEnum @@ -1512,23 +1503,21 @@ func TestIndirectReentry(t *testing.T) { itxn_field Applications itxn_submit `), - } - eval := nextBlock(t, l) - txn(t, l, eval, &app0) - vb := endBlock(t, l, eval) - id0 := vb.Block().Payset[0].ApplicationID - - fund := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: id0.Address(), - Amount: 1_000_000, - } + } + vb := dl.fullBlock(&app0) + id0 := vb.Block().Payset[0].ApplicationID - app1 := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + fund := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: id0.Address(), + Amount: 1_000_000, + } + + app1 := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` itxn_begin int appl itxn_field TypeEnum @@ -1536,21 +1525,18 @@ func TestIndirectReentry(t *testing.T) { itxn_field ApplicationID itxn_submit `), - } - eval = nextBlock(t, l) - txns(t, l, eval, &app1, &fund) - vb = endBlock(t, l, eval) - id1 := vb.Block().Payset[0].ApplicationID - - call1 := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApplicationID: id0, - ForeignApps: []basics.AppIndex{id1, id0}, - } - eval = nextBlock(t, l) - txn(t, l, eval, &call1, "attempt to re-enter") - endBlock(t, l, eval) + } + vb = dl.fullBlock(&app1, &fund) + id1 := vb.Block().Payset[0].ApplicationID + + call1 := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: id0, + ForeignApps: []basics.AppIndex{id1, id0}, + } + dl.txn(&call1, "attempt to re-enter") + }) } // TestValidAppReentry tests a valid form of reentry (which may not be the correct word here). @@ -1561,13 +1547,16 @@ func TestValidAppReentry(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() - app0 := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + // 31 allowed inner appl. + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() + + app0 := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` itxn_begin int appl itxn_field TypeEnum @@ -1584,38 +1573,34 @@ func TestValidAppReentry(t *testing.T) { itxn_field Applications itxn_submit `), - } - eval := nextBlock(t, l) - txn(t, l, eval, &app0) - vb := endBlock(t, l, eval) - id0 := vb.Block().Payset[0].ApplicationID - - fund0 := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: id0.Address(), - Amount: 1_000_000, - } + } + vb := dl.fullBlock(&app0) + id0 := vb.Block().Payset[0].ApplicationID - app1 := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + fund0 := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: id0.Address(), + Amount: 1_000_000, + } + + app1 := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` int 3 int 3 == assert `), - } - eval = nextBlock(t, l) - txns(t, l, eval, &app1, &fund0) - vb = endBlock(t, l, eval) - id1 := vb.Block().Payset[0].ApplicationID + } + vb = dl.fullBlock(&app1, &fund0) + id1 := vb.Block().Payset[0].ApplicationID - app2 := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + app2 := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` itxn_begin int appl itxn_field TypeEnum @@ -1623,32 +1608,27 @@ func TestValidAppReentry(t *testing.T) { itxn_field ApplicationID itxn_submit `), - } - eval = nextBlock(t, l) - txn(t, l, eval, &app2) - vb = endBlock(t, l, eval) - id2 := vb.Block().Payset[0].ApplicationID - - fund2 := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: id2.Address(), - Amount: 1_000_000, - } + } + vb = dl.fullBlock(&app2) + id2 := vb.Block().Payset[0].ApplicationID + + fund2 := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: id2.Address(), + Amount: 1_000_000, + } - eval = nextBlock(t, l) - txn(t, l, eval, &fund2) - _ = endBlock(t, l, eval) + dl.txn(&fund2) - call1 := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApplicationID: id0, - ForeignApps: []basics.AppIndex{id2, id1, id0}, - } - eval = nextBlock(t, l) - txn(t, l, eval, &call1) - endBlock(t, l, eval) + call1 := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: id0, + ForeignApps: []basics.AppIndex{id2, id1, id0}, + } + dl.txn(&call1) + }) } func TestMaxInnerTxForSingleAppCall(t *testing.T) { @@ -1750,13 +1730,15 @@ func TestAbortWhenInnerAppCallFails(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() + // 31 allowed inner appl. + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() - app0 := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + app0 := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` itxn_begin int appl itxn_field TypeEnum @@ -1768,44 +1750,39 @@ int 1 == assert `), - } - eval := nextBlock(t, l) - txn(t, l, eval, &app0) - vb := endBlock(t, l, eval) - id0 := vb.Block().Payset[0].ApplicationID - - fund0 := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: id0.Address(), - Amount: 1_000_000, - } + } + vb := dl.fullBlock(&app0) + id0 := vb.Block().Payset[0].ApplicationID - app1 := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + fund0 := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: id0.Address(), + Amount: 1_000_000, + } + + app1 := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` int 3 int 2 == assert `), - } - eval = nextBlock(t, l) - txns(t, l, eval, &app1, &fund0) - vb = endBlock(t, l, eval) - id1 := vb.Block().Payset[0].ApplicationID - - callTx := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApplicationID: id0, - ForeignApps: []basics.AppIndex{id1}, - } + } + vb = dl.fullBlock(&app1, &fund0) + id1 := vb.Block().Payset[0].ApplicationID + + callTx := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: id0, + ForeignApps: []basics.AppIndex{id1}, + } - eval = nextBlock(t, l) - txn(t, l, eval, &callTx, "logic eval error") - endBlock(t, l, eval) + dl.txn(&callTx, "logic eval error") + }) } // TestSelfCheckHoldingNewApp checks whether a newly created app can check its @@ -2043,51 +2020,40 @@ func TestAppVersionMatching(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() - - four, err := logic.AssembleStringWithVersion("int 1", 4) - require.NoError(t, err) - five, err := logic.AssembleStringWithVersion("int 1", 5) - require.NoError(t, err) - six, err := logic.AssembleStringWithVersion("int 1", 6) - require.NoError(t, err) - create := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: five.Program, - ClearStateProgram: five.Program, - } - - eval := nextBlock(t, l) - txn(t, l, eval, &create) - endBlock(t, l, eval) - - create.ClearStateProgram = six.Program - - eval = nextBlock(t, l) - txn(t, l, eval, &create, "version mismatch") - endBlock(t, l, eval) + // matching required in v6 which is v31 + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() - create.ApprovalProgram = six.Program + four, err := logic.AssembleStringWithVersion("int 1", 4) + require.NoError(t, err) + five, err := logic.AssembleStringWithVersion("int 1", 5) + require.NoError(t, err) + six, err := logic.AssembleStringWithVersion("int 1", 6) + require.NoError(t, err) - eval = nextBlock(t, l) - txn(t, l, eval, &create) - endBlock(t, l, eval) + create := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: five.Program, + ClearStateProgram: five.Program, + } + dl.txn(&create) - create.ClearStateProgram = four.Program + create.ClearStateProgram = six.Program + dl.txn(&create, "version mismatch") - eval = nextBlock(t, l) - txn(t, l, eval, &create, "version mismatch") - endBlock(t, l, eval) + create.ApprovalProgram = six.Program + dl.txn(&create) - // four doesn't match five, but it doesn't have to - create.ApprovalProgram = five.Program + create.ClearStateProgram = four.Program + dl.txn(&create, "version mismatch") - eval = nextBlock(t, l) - txn(t, l, eval, &create) - endBlock(t, l, eval) + // four doesn't match five, but it doesn't have to + create.ApprovalProgram = five.Program + dl.txn(&create) + }) } func TestAppDowngrade(t *testing.T) { @@ -2453,34 +2419,34 @@ func TestInnerClearState(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() + // Inner apps start in v31 + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() - // inner will be an app that we opt into, then clearstate - // note that clearstate rejects - inner := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: "int 1", - ClearStateProgram: "int 0", - LocalStateSchema: basics.StateSchema{ - NumUint: 2, - NumByteSlice: 2, - }, - } + // inner will be an app that we opt into, then clearstate + // note that clearstate rejects + inner := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: "int 1", + ClearStateProgram: "int 0", + LocalStateSchema: basics.StateSchema{ + NumUint: 2, + NumByteSlice: 2, + }, + } - eval := nextBlock(t, l) - txn(t, l, eval, &inner) - vb := endBlock(t, l, eval) - innerID := vb.Block().Payset[0].ApplicationID + vb := dl.fullBlock(&inner) + innerID := vb.Block().Payset[0].ApplicationID - // Outer is a simple app that will invoke the given app (in ForeignApps[0]) - // with the given OnCompletion (in ApplicationArgs[0]). Goal is to use it - // to opt into, and the clear state, on the inner app. - outer := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + // Outer is a simple app that will invoke the given app (in ForeignApps[0]) + // with the given OnCompletion (in ApplicationArgs[0]). Goal is to use it + // to opt into, and the clear state, on the inner app. + outer := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` itxn_begin int appl itxn_field TypeEnum @@ -2491,48 +2457,42 @@ itxn_begin itxn_field OnCompletion itxn_submit `), - ForeignApps: []basics.AppIndex{innerID}, - } + ForeignApps: []basics.AppIndex{innerID}, + } - eval = nextBlock(t, l) - txn(t, l, eval, &outer) - vb = endBlock(t, l, eval) - outerID := vb.Block().Payset[0].ApplicationID + vb = dl.fullBlock(&outer) + outerID := vb.Block().Payset[0].ApplicationID - fund := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: outerID.Address(), - Amount: 1_000_000, - } + fund := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: outerID.Address(), + Amount: 1_000_000, + } - call := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApplicationID: outerID, - ApplicationArgs: [][]byte{{byte(transactions.OptInOC)}}, - ForeignApps: []basics.AppIndex{innerID}, - } - eval = nextBlock(t, l) - txns(t, l, eval, &fund, &call) - endBlock(t, l, eval) - - outerAcct := lookup(t, l, outerID.Address()) - require.Len(t, outerAcct.AppLocalStates, 1) - require.Equal(t, outerAcct.TotalAppSchema, basics.StateSchema{ - NumUint: 2, - NumByteSlice: 2, - }) + call := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: outerID, + ApplicationArgs: [][]byte{{byte(transactions.OptInOC)}}, + ForeignApps: []basics.AppIndex{innerID}, + } + dl.txns(&fund, &call) - call.ApplicationArgs = [][]byte{{byte(transactions.ClearStateOC)}} - eval = nextBlock(t, l) - txn(t, l, eval, &call) - endBlock(t, l, eval) + outerAcct := lookup(t, dl.generator, outerID.Address()) + require.Len(t, outerAcct.AppLocalStates, 1) + require.Equal(t, outerAcct.TotalAppSchema, basics.StateSchema{ + NumUint: 2, + NumByteSlice: 2, + }) - outerAcct = lookup(t, l, outerID.Address()) - require.Empty(t, outerAcct.AppLocalStates) - require.Empty(t, outerAcct.TotalAppSchema) + call.ApplicationArgs = [][]byte{{byte(transactions.ClearStateOC)}} + dl.txn(&call) + outerAcct = lookup(t, dl.generator, outerID.Address()) + require.Empty(t, outerAcct.AppLocalStates) + require.Empty(t, outerAcct.TotalAppSchema) + }) } // TestInnerClearStateBadCallee ensures that inner clear state programs are not @@ -2542,34 +2502,34 @@ func TestInnerClearStateBadCallee(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() + // Inner appls start in v31 + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() - // badCallee tries to run down your budget, so an inner clear must be - // protected from exhaustion - badCallee := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: "int 1", - ClearStateProgram: `top: + // badCallee tries to run down your budget, so an inner clear must be + // protected from exhaustion + badCallee := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: "int 1", + ClearStateProgram: `top: int 1 pop b top `, - } + } - eval := nextBlock(t, l) - txn(t, l, eval, &badCallee) - vb := endBlock(t, l, eval) - badID := vb.Block().Payset[0].ApplicationID + vb := dl.fullBlock(&badCallee) + badID := vb.Block().Payset[0].ApplicationID - // Outer is a simple app that will invoke the given app (in ForeignApps[0]) - // with the given OnCompletion (in ApplicationArgs[0]). Goal is to use it - // to opt into, and then clear state, the bad app - outer := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + // Outer is a simple app that will invoke the given app (in ForeignApps[0]) + // with the given OnCompletion (in ApplicationArgs[0]). Goal is to use it + // to opt into, and then clear state, the bad app + outer := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` itxn_begin int appl itxn_field TypeEnum @@ -2597,44 +2557,39 @@ bnz skip // Don't do budget checking during optin assert skip: `), - ForeignApps: []basics.AppIndex{badID}, - } + ForeignApps: []basics.AppIndex{badID}, + } - eval = nextBlock(t, l) - txn(t, l, eval, &outer) - vb = endBlock(t, l, eval) - outerID := vb.Block().Payset[0].ApplicationID + vb = dl.fullBlock(&outer) + outerID := vb.Block().Payset[0].ApplicationID - fund := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: outerID.Address(), - Amount: 1_000_000, - } + fund := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: outerID.Address(), + Amount: 1_000_000, + } - call := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApplicationID: outerID, - ApplicationArgs: [][]byte{{byte(transactions.OptInOC)}}, - ForeignApps: []basics.AppIndex{badID}, - } - eval = nextBlock(t, l) - txns(t, l, eval, &fund, &call) - endBlock(t, l, eval) - - outerAcct := lookup(t, l, outerID.Address()) - require.Len(t, outerAcct.AppLocalStates, 1) - - // When doing a clear state, `call` checks that budget wasn't stolen - call.ApplicationArgs = [][]byte{{byte(transactions.ClearStateOC)}} - eval = nextBlock(t, l) - txn(t, l, eval, &call) - endBlock(t, l, eval) - - // Clearstate took effect, despite failure from infinite loop - outerAcct = lookup(t, l, outerID.Address()) - require.Empty(t, outerAcct.AppLocalStates) + call := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: outerID, + ApplicationArgs: [][]byte{{byte(transactions.OptInOC)}}, + ForeignApps: []basics.AppIndex{badID}, + } + dl.fullBlock(&fund, &call) + + outerAcct := lookup(t, dl.generator, outerID.Address()) + require.Len(t, outerAcct.AppLocalStates, 1) + + // When doing a clear state, `call` checks that budget wasn't stolen + call.ApplicationArgs = [][]byte{{byte(transactions.ClearStateOC)}} + dl.fullBlock(&call) + + // Clearstate took effect, despite failure from infinite loop + outerAcct = lookup(t, dl.generator, outerID.Address()) + require.Empty(t, outerAcct.AppLocalStates) + }) } // TestInnerClearStateBadCaller ensures that inner clear state programs cannot @@ -2644,28 +2599,30 @@ func TestInnerClearStateBadCaller(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() + // Inner appls start in v31 + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() - inner := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: "int 1", - ClearStateProgram: `global OpcodeBudget + inner := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: "int 1", + ClearStateProgram: `global OpcodeBudget itob log int 1`, - LocalStateSchema: basics.StateSchema{ - NumUint: 1, - NumByteSlice: 2, - }, - } + LocalStateSchema: basics.StateSchema{ + NumUint: 1, + NumByteSlice: 2, + }, + } - // waster allows tries to get the budget down below 100 before returning - waster := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + // waster allows tries to get the budget down below 100 before returning + waster := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` global OpcodeBudget itob log @@ -2683,25 +2640,23 @@ global OpcodeBudget itob log `), - LocalStateSchema: basics.StateSchema{ - NumUint: 3, - NumByteSlice: 4, - }, - } + LocalStateSchema: basics.StateSchema{ + NumUint: 3, + NumByteSlice: 4, + }, + } - eval := nextBlock(t, l) - txns(t, l, eval, &inner, &waster) - vb := endBlock(t, l, eval) - innerID := vb.Block().Payset[0].ApplicationID - wasterID := vb.Block().Payset[1].ApplicationID + vb := dl.fullBlock(&inner, &waster) + innerID := vb.Block().Payset[0].ApplicationID + wasterID := vb.Block().Payset[1].ApplicationID - // Grouper is a simple app that will invoke the given apps (in - // ForeignApps[0,1]) as a group, with the given OnCompletion (in - // ApplicationArgs[0]). - grouper := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + // Grouper is a simple app that will invoke the given apps (in + // ForeignApps[0,1]) as a group, with the given OnCompletion (in + // ApplicationArgs[0]). + grouper := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` itxn_begin int appl itxn_field TypeEnum @@ -2720,43 +2675,37 @@ itxn_next itxn_field OnCompletion itxn_submit `), - } + } - eval = nextBlock(t, l) - txn(t, l, eval, &grouper) - vb = endBlock(t, l, eval) - grouperID := vb.Block().Payset[0].ApplicationID + vb = dl.fullBlock(&grouper) + grouperID := vb.Block().Payset[0].ApplicationID - fund := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: grouperID.Address(), - Amount: 1_000_000, - } + fund := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: grouperID.Address(), + Amount: 1_000_000, + } - call := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApplicationID: grouperID, - ApplicationArgs: [][]byte{{byte(transactions.OptInOC)}, {byte(transactions.OptInOC)}}, - ForeignApps: []basics.AppIndex{wasterID, innerID}, - } - eval = nextBlock(t, l) - txns(t, l, eval, &fund, &call) - endBlock(t, l, eval) - - gAcct := lookup(t, l, grouperID.Address()) - require.Len(t, gAcct.AppLocalStates, 2) - - call.ApplicationArgs = [][]byte{{byte(transactions.CloseOutOC)}, {byte(transactions.ClearStateOC)}} - eval = nextBlock(t, l) - txn(t, l, eval, &call, "ClearState execution with low OpcodeBudget") - vb = endBlock(t, l, eval) - require.Len(t, vb.Block().Payset, 0) - - // Clearstate did not take effect, since the caller tried to shortchange the CSP - gAcct = lookup(t, l, grouperID.Address()) - require.Len(t, gAcct.AppLocalStates, 2) + call := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: grouperID, + ApplicationArgs: [][]byte{{byte(transactions.OptInOC)}, {byte(transactions.OptInOC)}}, + ForeignApps: []basics.AppIndex{wasterID, innerID}, + } + dl.fullBlock(&fund, &call) + + gAcct := lookup(t, dl.generator, grouperID.Address()) + require.Len(t, gAcct.AppLocalStates, 2) + + call.ApplicationArgs = [][]byte{{byte(transactions.CloseOutOC)}, {byte(transactions.ClearStateOC)}} + dl.txn(&call, "ClearState execution with low OpcodeBudget") + + // Clearstate did not take effect, since the caller tried to shortchange the CSP + gAcct = lookup(t, dl.generator, grouperID.Address()) + require.Len(t, gAcct.AppLocalStates, 2) + }) } // TestClearStateInnerPay ensures that ClearState programs can run inner txns in @@ -2880,13 +2829,15 @@ func TestGlobalChangesAcrossApps(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() + // Inner appls start in v31 + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() - appA := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + appA := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` // Call B : No arguments means: set your global "X" to "ABC" itxn_begin int appl; itxn_field TypeEnum @@ -2916,12 +2867,12 @@ func TestGlobalChangesAcrossApps(t *testing.T) { == assert `), - } + } - appB := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + appB := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` txn NumAppArgs bnz check // 1 arg means check // set @@ -2937,15 +2888,15 @@ check: assert b end `), - GlobalStateSchema: basics.StateSchema{ - NumByteSlice: 1, - }, - } + GlobalStateSchema: basics.StateSchema{ + NumByteSlice: 1, + }, + } - appC := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + appC := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` txn Applications 1 byte "X" app_global_get_ex @@ -2954,32 +2905,29 @@ check: == assert `), - } + } - eval := nextBlock(t, l) - txns(t, l, eval, &appA, &appB, &appC) - vb := endBlock(t, l, eval) - idA := vb.Block().Payset[0].ApplicationID - idB := vb.Block().Payset[1].ApplicationID - idC := vb.Block().Payset[2].ApplicationID - - fundA := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: idA.Address(), - Amount: 1_000_000, - } + vb := dl.fullBlock(&appA, &appB, &appC) + idA := vb.Block().Payset[0].ApplicationID + idB := vb.Block().Payset[1].ApplicationID + idC := vb.Block().Payset[2].ApplicationID - callA := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApplicationID: idA, - ForeignApps: []basics.AppIndex{idB, idC}, - } + fundA := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: idA.Address(), + Amount: 1_000_000, + } - eval = nextBlock(t, l) - txns(t, l, eval, &fundA, &callA) - endBlock(t, l, eval) + callA := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: idA, + ForeignApps: []basics.AppIndex{idB, idC}, + } + + dl.fullBlock(&fundA, &callA) + }) } // TestLocalChangesAcrossApps ensures that state changes are seen by other app @@ -2989,13 +2937,15 @@ func TestLocalChangesAcrossApps(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis() - l := newTestLedger(t, genBalances) - defer l.Close() + // Inner appls start in v31 + ledgertesting.TestConsensusRange(t, 31, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() - appA := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + appA := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` // Call B : No arguments means: set caller's local "X" to "ABC" itxn_begin int appl; itxn_field TypeEnum @@ -3027,12 +2977,12 @@ func TestLocalChangesAcrossApps(t *testing.T) { == assert `), - } + } - appB := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + appB := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` txn NumAppArgs bnz check // 1 arg means check // set @@ -3050,15 +3000,15 @@ check: assert b end `), - LocalStateSchema: basics.StateSchema{ - NumByteSlice: 1, - }, - } + LocalStateSchema: basics.StateSchema{ + NumByteSlice: 1, + }, + } - appC := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApprovalProgram: main(` + appC := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` txn Sender txn Applications 1 byte "X" @@ -3068,32 +3018,29 @@ check: == assert `), - } + } - eval := nextBlock(t, l) - txns(t, l, eval, &appA, &appB, &appC) - vb := endBlock(t, l, eval) - idA := vb.Block().Payset[0].ApplicationID - idB := vb.Block().Payset[1].ApplicationID - idC := vb.Block().Payset[2].ApplicationID - - fundA := txntest.Txn{ - Type: "pay", - Sender: addrs[0], - Receiver: idA.Address(), - Amount: 1_000_000, - } + vb := dl.fullBlock(&appA, &appB, &appC) + idA := vb.Block().Payset[0].ApplicationID + idB := vb.Block().Payset[1].ApplicationID + idC := vb.Block().Payset[2].ApplicationID - callA := txntest.Txn{ - Type: "appl", - Sender: addrs[0], - ApplicationID: idA, - ForeignApps: []basics.AppIndex{idB, idC}, - } + fundA := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: idA.Address(), + Amount: 1_000_000, + } - eval = nextBlock(t, l) - txns(t, l, eval, &fundA, &callA) - endBlock(t, l, eval) + callA := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: idA, + ForeignApps: []basics.AppIndex{idB, idC}, + } + + dl.fullBlock(&fundA, &callA) + }) } func TestForeignAppAccountsAccessible(t *testing.T) { diff --git a/ledger/double_test.go b/ledger/double_test.go index 0854943636..c1cd09f97c 100644 --- a/ledger/double_test.go +++ b/ledger/double_test.go @@ -153,23 +153,24 @@ func (dl *DoubleLedger) endBlock(proposer ...basics.Address) *ledgercore.Validat return vb } -func (dl *DoubleLedger) fundedApp(sender basics.Address, amount uint64, source string) basics.AppIndex { +func (dl *DoubleLedger) createApp(sender basics.Address, source string) basics.AppIndex { createapp := txntest.Txn{ Type: "appl", Sender: sender, ApprovalProgram: source, } vb := dl.fullBlock(&createapp) - appIndex := vb.Block().Payset[0].ApplyData.ApplicationID + return vb.Block().Payset[0].ApplyData.ApplicationID +} - fund := txntest.Txn{ +func (dl *DoubleLedger) fundedApp(sender basics.Address, amount uint64, source string) basics.AppIndex { + appIndex := dl.createApp(sender, source) + dl.fullBlock(&txntest.Txn{ Type: "pay", Sender: sender, Receiver: appIndex.Address(), Amount: amount, - } - - dl.txn(&fund) + }) return appIndex } diff --git a/ledger/eval/appcow_test.go b/ledger/eval/appcow_test.go index 60ab1df25e..6f5e39b305 100644 --- a/ledger/eval/appcow_test.go +++ b/ledger/eval/appcow_test.go @@ -48,6 +48,14 @@ func (ml *emptyLedger) lookup(addr basics.Address) (ledgercore.AccountData, erro return ledgercore.AccountData{}, nil } +func (ml *emptyLedger) lookupAgreement(addr basics.Address) (basics.OnlineAccountData, error) { + return basics.OnlineAccountData{}, nil +} + +func (ml *emptyLedger) onlineStake() (basics.MicroAlgos, error) { + return basics.MicroAlgos{}, nil +} + func (ml *emptyLedger) lookupAppParams(addr basics.Address, aidx basics.AppIndex, cacheOnly bool) (ledgercore.AppParamsDelta, bool, error) { return ledgercore.AppParamsDelta{}, true, nil } diff --git a/ledger/eval/applications.go b/ledger/eval/applications.go index 3aa7bd3905..c1d5d6d619 100644 --- a/ledger/eval/applications.go +++ b/ledger/eval/applications.go @@ -38,6 +38,23 @@ func (cs *roundCowState) AccountData(addr basics.Address) (ledgercore.AccountDat return record, nil } +func (cs *roundCowState) AgreementData(addr basics.Address) (basics.OnlineAccountData, error) { + record, err := cs.lookupAgreement(addr) + if err != nil { + return basics.OnlineAccountData{}, err + } + return record, nil +} + +func (cs *roundCowState) OnlineStake() (basics.MicroAlgos, error) { + return cs.lookupParent.onlineStake() +} + +// onlineStake is needed to implement roundCowParent +func (cs *roundCowState) onlineStake() (basics.MicroAlgos, error) { + return cs.lookupParent.onlineStake() +} + func (cs *roundCowState) Authorizer(addr basics.Address) (basics.Address, error) { record, err := cs.Get(addr, false) // pending rewards unneeded if err != nil { diff --git a/ledger/eval/cow.go b/ledger/eval/cow.go index 23c415bbdf..9511af7ce7 100644 --- a/ledger/eval/cow.go +++ b/ledger/eval/cow.go @@ -44,6 +44,10 @@ type roundCowParent interface { // lookup retrieves data about an address, eventually querying the ledger if the address was not found in cache. lookup(basics.Address) (ledgercore.AccountData, error) + // lookup retrieves agreement data about an address, querying the ledger if necessary. + lookupAgreement(basics.Address) (basics.OnlineAccountData, error) + onlineStake() (basics.MicroAlgos, error) + // lookupAppParams, lookupAssetParams, lookupAppLocalState, and lookupAssetHolding retrieve data for a given address and ID. // If cacheOnly is set, the ledger DB will not be queried, and only the cache will be consulted. // This is used when we know a given value is already in cache (from a previous query for that same address and ID), @@ -182,6 +186,12 @@ func (cb *roundCowState) lookup(addr basics.Address) (data ledgercore.AccountDat return cb.lookupParent.lookup(addr) } +// lookupAgreement differs from other lookup methods because it need not +// maintain a local value because it cannot be modified by transactions. +func (cb *roundCowState) lookupAgreement(addr basics.Address) (data basics.OnlineAccountData, err error) { + return cb.lookupParent.lookupAgreement(addr) +} + func (cb *roundCowState) lookupAppParams(addr basics.Address, aidx basics.AppIndex, cacheOnly bool) (ledgercore.AppParamsDelta, bool, error) { params, ok := cb.mods.Accts.GetAppParams(addr, aidx) if ok { diff --git a/ledger/eval/cow_test.go b/ledger/eval/cow_test.go index 81224a8d0b..138e2562ad 100644 --- a/ledger/eval/cow_test.go +++ b/ledger/eval/cow_test.go @@ -44,6 +44,35 @@ func (ml *mockLedger) lookup(addr basics.Address) (ledgercore.AccountData, error return ledgercore.ToAccountData(ml.balanceMap[addr]), nil } +// convertToOnline is only suitable for test code because OnlineAccountData +// should have rewards paid. Here, we ignore that for simple tests. +func convertToOnline(ad ledgercore.AccountData) basics.OnlineAccountData { + return basics.OnlineAccountData{ + MicroAlgosWithRewards: ad.MicroAlgos, + VotingData: basics.VotingData{ + VoteID: ad.VoteID, + SelectionID: ad.SelectionID, + StateProofID: ad.StateProofID, + VoteFirstValid: ad.VoteFirstValid, + VoteLastValid: ad.VoteLastValid, + VoteKeyDilution: ad.VoteKeyDilution, + }, + IncentiveEligible: ad.IncentiveEligible, + } +} + +func (ml *mockLedger) lookupAgreement(addr basics.Address) (basics.OnlineAccountData, error) { + ad, err := ml.lookup(addr) + if err != nil { // impossible, see lookup() + return basics.OnlineAccountData{}, err + } + return convertToOnline(ad), nil +} + +func (ml *mockLedger) onlineStake() (basics.MicroAlgos, error) { + return basics.Algos(55_555), nil +} + func (ml *mockLedger) lookupAppParams(addr basics.Address, aidx basics.AppIndex, cacheOnly bool) (ledgercore.AppParamsDelta, bool, error) { params, ok := ml.balanceMap[addr].AppParams[aidx] return ledgercore.AppParamsDelta{Params: ¶ms}, ok, nil // XXX make a copy? diff --git a/ledger/eval/eval.go b/ledger/eval/eval.go index 6599dd5918..859b62922f 100644 --- a/ledger/eval/eval.go +++ b/ledger/eval/eval.go @@ -24,6 +24,7 @@ import ( "math/bits" "sync" + "github.com/algorand/go-algorand/agreement" "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" @@ -46,11 +47,13 @@ type LedgerForCowBase interface { GenesisHash() crypto.Digest CheckDup(config.ConsensusParams, basics.Round, basics.Round, basics.Round, transactions.Txid, ledgercore.Txlease) error LookupWithoutRewards(basics.Round, basics.Address) (ledgercore.AccountData, basics.Round, error) + LookupAgreement(basics.Round, basics.Address) (basics.OnlineAccountData, error) LookupAsset(basics.Round, basics.Address, basics.AssetIndex) (ledgercore.AssetResource, error) LookupApplication(basics.Round, basics.Address, basics.AppIndex) (ledgercore.AppResource, error) LookupKv(basics.Round, string) ([]byte, error) GetCreatorForRound(basics.Round, basics.CreatableIndex, basics.CreatableType) (basics.Address, bool, error) GetStateProofVerificationContext(stateProofLastAttestedRound basics.Round) (*ledgercore.StateProofVerificationContext, error) + OnlineCirculation(basics.Round, basics.Round) (basics.MicroAlgos, error) } // ErrRoundZero is self-explanatory @@ -129,6 +132,15 @@ type roundCowBase struct { // The account data store here is always the account data without the rewards. accounts map[basics.Address]ledgercore.AccountData + // The online accounts that we've already accessed during this round evaluation. This is a + // cache used to avoid looking up the same account data more than once during a single evaluator + // execution. The OnlineAccountData is historical and therefore won't be changing. + onlineAccounts map[basics.Address]basics.OnlineAccountData + + // totalOnline is the cached amount of online stake for rnd (so it's from + // rnd-320). The zero value indicates it is not yet cached. + totalOnline basics.MicroAlgos + // Similarly to accounts cache that stores base account data, there are caches for params, states, holdings. appParams map[ledgercore.AccountApp]cachedAppParams assetParams map[ledgercore.AccountAsset]cachedAssetParams @@ -150,6 +162,7 @@ func makeRoundCowBase(l LedgerForCowBase, rnd basics.Round, txnCount uint64, sta stateProofNextRnd: stateProofNextRnd, proto: proto, accounts: make(map[basics.Address]ledgercore.AccountData), + onlineAccounts: make(map[basics.Address]basics.OnlineAccountData), appParams: make(map[ledgercore.AccountApp]cachedAppParams), assetParams: make(map[ledgercore.AccountAsset]cachedAssetParams), appLocalStates: make(map[ledgercore.AccountApp]cachedAppLocalState), @@ -193,6 +206,56 @@ func (x *roundCowBase) lookup(addr basics.Address) (ledgercore.AccountData, erro return ad, err } +// balanceRound reproduces the way that the agreement package finds the round to +// consider for online accounts. +func (x *roundCowBase) balanceRound() (basics.Round, error) { + phdr, err := x.BlockHdr(agreement.ParamsRound(x.rnd)) + if err != nil { + return 0, err + } + agreementParams := config.Consensus[phdr.CurrentProtocol] + return agreement.BalanceRound(x.rnd, agreementParams), nil +} + +// lookupAgreement returns the online accountdata for the provided account address. It uses an internal cache +// to avoid repeated lookups against the ledger. +func (x *roundCowBase) lookupAgreement(addr basics.Address) (basics.OnlineAccountData, error) { + if accountData, found := x.onlineAccounts[addr]; found { + return accountData, nil + } + + brnd, err := x.balanceRound() + if err != nil { + return basics.OnlineAccountData{}, err + } + ad, err := x.l.LookupAgreement(brnd, addr) + if err != nil { + return basics.OnlineAccountData{}, err + } + + x.onlineAccounts[addr] = ad + return ad, err +} + +// onlineStake returns the total online stake as of the start of the round. It +// caches the result to prevent repeated calls to the ledger. +func (x *roundCowBase) onlineStake() (basics.MicroAlgos, error) { + if !x.totalOnline.IsZero() { + return x.totalOnline, nil + } + + brnd, err := x.balanceRound() + if err != nil { + return basics.MicroAlgos{}, err + } + total, err := x.l.OnlineCirculation(brnd, x.rnd) + if err != nil { + return basics.MicroAlgos{}, err + } + x.totalOnline = total + return x.totalOnline, err +} + func (x *roundCowBase) updateAssetResourceCache(aa ledgercore.AccountAsset, r ledgercore.AssetResource) { // cache AssetParams and AssetHolding returned by LookupResource if r.AssetParams == nil { diff --git a/ledger/eval/eval_test.go b/ledger/eval/eval_test.go index 994bedd561..77a477b3c0 100644 --- a/ledger/eval/eval_test.go +++ b/ledger/eval/eval_test.go @@ -180,6 +180,7 @@ ok: // and the usage counts correctly propagated from parent cow to child cow and back func TestEvalAppStateCountsWithTxnGroup(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() _, _, err := testEvalAppGroup(t, basics.StateSchema{NumByteSlice: 1}) require.ErrorContains(t, err, "store bytes count 2 exceeds schema bytes count 1") @@ -189,6 +190,7 @@ func TestEvalAppStateCountsWithTxnGroup(t *testing.T) { // produce correct results when a txn group has storage allocate and storage update actions func TestEvalAppAllocStateWithTxnGroup(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() eval, addr, err := testEvalAppGroup(t, basics.StateSchema{NumByteSlice: 2}) require.NoError(t, err) @@ -203,6 +205,7 @@ func TestEvalAppAllocStateWithTxnGroup(t *testing.T) { // see TestBlockEvaluator for more func TestTestTransactionGroup(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() var txgroup []transactions.SignedTxn eval := BlockEvaluator{} @@ -219,6 +222,7 @@ func TestTestTransactionGroup(t *testing.T) { // some trivial checks that require no setup func TestPrivateTransactionGroup(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() var txgroup []transactions.SignedTxnWithAD eval := BlockEvaluator{} @@ -675,56 +679,6 @@ func testnetFixupExecution(t *testing.T, headerRound basics.Round, poolBonus uin require.NoError(t, err) } -// newTestGenesis creates a bunch of accounts, splits up 10B algos -// between them and the rewardspool and feesink, and gives out the -// addresses and secrets it creates to enable tests. For special -// scenarios, manipulate these return values before using newTestLedger. -func newTestGenesis() (bookkeeping.GenesisBalances, []basics.Address, []*crypto.SignatureSecrets) { - // irrelevant, but deterministic - sink, err := basics.UnmarshalChecksumAddress("YTPRLJ2KK2JRFSZZNAF57F3K5Y2KCG36FZ5OSYLW776JJGAUW5JXJBBD7Q") - if err != nil { - panic(err) - } - rewards, err := basics.UnmarshalChecksumAddress("242H5OXHUEBYCGGWB3CQ6AZAMQB5TMCWJGHCGQOZPEIVQJKOO7NZXUXDQA") - if err != nil { - panic(err) - } - - const count = 10 - addrs := make([]basics.Address, count) - secrets := make([]*crypto.SignatureSecrets, count) - accts := make(map[basics.Address]basics.AccountData) - - // 10 billion microalgos, across N accounts and pool and sink - amount := 10 * 1000000000 * 1000000 / uint64(count+2) - - for i := 0; i < count; i++ { - // Create deterministic addresses, so that output stays the same, run to run. - var seed crypto.Seed - seed[0] = byte(i) - secrets[i] = crypto.GenerateSignatureSecrets(seed) - addrs[i] = basics.Address(secrets[i].SignatureVerifier) - - adata := basics.AccountData{ - MicroAlgos: basics.MicroAlgos{Raw: amount}, - } - accts[addrs[i]] = adata - } - - accts[sink] = basics.AccountData{ - MicroAlgos: basics.MicroAlgos{Raw: amount}, - Status: basics.NotParticipating, - } - - accts[rewards] = basics.AccountData{ - MicroAlgos: basics.MicroAlgos{Raw: amount}, - } - - genBalances := bookkeeping.MakeGenesisBalances(accts, sink, rewards) - - return genBalances, addrs, secrets -} - type evalTestLedger struct { blocks map[basics.Round]bookkeeping.Block roundBalances map[basics.Round]map[basics.Address]basics.AccountData @@ -827,11 +781,21 @@ func (ledger *evalTestLedger) LatestTotals() (basics.Round, ledgercore.AccountTo return basics.Round(len(ledger.blocks)).SubSaturate(1), ledger.latestTotals, nil } -// LookupWithoutRewards is like Lookup but does not apply pending rewards up -// to the requested round rnd. +// LookupWithoutRewards is like Lookup but is not supposed to apply pending +// rewards up to the requested round rnd. Here Lookup doesn't do that anyway. func (ledger *evalTestLedger) LookupWithoutRewards(rnd basics.Round, addr basics.Address) (ledgercore.AccountData, basics.Round, error) { - ad := ledger.roundBalances[rnd][addr] - return ledgercore.ToAccountData(ad), rnd, nil + ad, err := ledger.Lookup(rnd, addr) + return ledgercore.ToAccountData(ad), rnd, err +} + +func (ledger *evalTestLedger) LookupAgreement(rnd basics.Round, addr basics.Address) (basics.OnlineAccountData, error) { + ad, _, err := ledger.LookupWithoutRewards(rnd, addr) + return convertToOnline(ad), err +} + +// OnlineCirculation just returns a deterministic value for a given round. +func (ledger *evalTestLedger) OnlineCirculation(rnd, voteRound basics.Round) (basics.MicroAlgos, error) { + return basics.MicroAlgos{Raw: uint64(rnd) * 1_000_000}, nil } func (ledger *evalTestLedger) LookupApplication(rnd basics.Round, addr basics.Address, aidx basics.AppIndex) (ledgercore.AppResource, error) { @@ -1057,6 +1021,14 @@ func (l *testCowBaseLedger) LookupWithoutRewards(basics.Round, basics.Address) ( return ledgercore.AccountData{}, basics.Round(0), errors.New("not implemented") } +func (l *testCowBaseLedger) LookupAgreement(rnd basics.Round, addr basics.Address) (basics.OnlineAccountData, error) { + return basics.OnlineAccountData{}, errors.New("not implemented") +} + +func (l *testCowBaseLedger) OnlineCirculation(rnd, voteRnd basics.Round) (basics.MicroAlgos, error) { + return basics.MicroAlgos{}, errors.New("not implemented") +} + func (l *testCowBaseLedger) LookupApplication(rnd basics.Round, addr basics.Address, aidx basics.AppIndex) (ledgercore.AppResource, error) { return ledgercore.AppResource{}, errors.New("not implemented") } diff --git a/ledger/eval/prefetcher/prefetcher_alignment_test.go b/ledger/eval/prefetcher/prefetcher_alignment_test.go index cb4b165c94..734d84a661 100644 --- a/ledger/eval/prefetcher/prefetcher_alignment_test.go +++ b/ledger/eval/prefetcher/prefetcher_alignment_test.go @@ -18,6 +18,7 @@ package prefetcher_test import ( "context" + "errors" "fmt" "testing" @@ -118,6 +119,16 @@ func (l *prefetcherAlignmentTestLedger) LookupWithoutRewards(_ basics.Round, add } return ledgercore.AccountData{}, 0, nil } +func (l *prefetcherAlignmentTestLedger) LookupAgreement(_ basics.Round, addr basics.Address) (basics.OnlineAccountData, error) { + // prefetch alignment tests do not check for prefetching of online account data + // because it's quite different and can only occur in AVM opcodes, which + // aren't handled anyway (just as we don't know if a holding or app local + // will be accessed in AVM.) + return basics.OnlineAccountData{}, errors.New("not implemented") +} +func (l *prefetcherAlignmentTestLedger) OnlineCirculation(rnd, voteRnd basics.Round) (basics.MicroAlgos, error) { + return basics.MicroAlgos{}, errors.New("not implemented") +} func (l *prefetcherAlignmentTestLedger) LookupApplication(rnd basics.Round, addr basics.Address, aidx basics.AppIndex) (ledgercore.AppResource, error) { l.mu.Lock() if l.requestedApps == nil { diff --git a/ledger/eval_simple_test.go b/ledger/eval_simple_test.go index 9ac67d2fb7..972821c26c 100644 --- a/ledger/eval_simple_test.go +++ b/ledger/eval_simple_test.go @@ -406,34 +406,84 @@ func TestAbsentTracking(t *testing.T) { genBalances, addrs, _ := ledgertesting.NewTestGenesis(func(cfg *ledgertesting.GenesisCfg) { cfg.OnlineCount = 2 // So we know proposer should propose every 2 rounds, on average - }) + }, ledgertesting.TurnOffRewards) + getOnlineStake := ` + int 0; voter_params_get VoterBalance; itob; log; itob; log; + int 0; voter_params_get VoterIncentiveEligible; itob; log; itob; log; + int 1` + checkingBegins := 40 - ledgertesting.TestConsensusRange(t, checkingBegins-1, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + ledgertesting.TestConsensusRange(t, checkingBegins, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { dl := NewDoubleLedger(t, genBalances, cv, cfg) defer dl.Close() - // have addrs[1] go online, which makes it eligible for suspension - dl.txn(&txntest.Txn{ + // we use stakeChecker for testing `voter_params_get` on suspended accounts + stib := dl.txn(&txntest.Txn{ // #1 + Type: "appl", + Sender: addrs[3], // use non-online account, Totals unchanged + ApprovalProgram: getOnlineStake, + }) + stakeChecker := stib.ApplicationID + require.NotZero(t, stakeChecker) + + checkState := func(addr basics.Address, online bool, eligible bool, expected uint64) { + t.Helper() + if !online { + require.Zero(t, expected) + } + stib = dl.txn(&txntest.Txn{ + Type: "appl", + Sender: addr, + ApplicationID: stakeChecker, + }) + logs := stib.ApplyData.EvalDelta.Logs + require.Len(t, logs, 4) + tBytes := "\x00\x00\x00\x00\x00\x00\x00\x01" + fBytes := "\x00\x00\x00\x00\x00\x00\x00\x00" + onlBytes := fBytes + if online { + onlBytes = tBytes + } + elgBytes := fBytes + if eligible { + elgBytes = tBytes + } + require.Equal(t, onlBytes, logs[0], "online") + require.Equal(t, int(expected), int(binary.BigEndian.Uint64([]byte(logs[1])))) + require.Equal(t, onlBytes, logs[2], "online") + require.Equal(t, elgBytes, logs[3], "eligible") + } + + // have addrs[1] go online explicitly, which makes it eligible for suspension. + // use a large fee, so we can see IncentiveEligible change + dl.txn(&txntest.Txn{ // #2 Type: "keyreg", + Fee: 10_000_000, Sender: addrs[1], VotePK: [32]byte{1}, SelectionPK: [32]byte{1}, }) - totals, err := dl.generator.Totals(1) - require.NoError(t, err) - require.NotZero(t, totals.Online.Money.Raw) - // as configured above, only the first two accounts should be online require.True(t, lookup(t, dl.generator, addrs[0]).Status == basics.Online) require.True(t, lookup(t, dl.generator, addrs[1]).Status == basics.Online) require.False(t, lookup(t, dl.generator, addrs[2]).Status == basics.Online) + checkState(addrs[0], true, false, 833_333_333_333_333) // #3 + require.Equal(t, int(lookup(t, dl.generator, addrs[0]).MicroAlgos.Raw), 833_333_333_332_333) + // although addr[1] just paid to be eligible, it won't be for 320 rounds + checkState(addrs[1], true, false, 833_333_333_333_333) // #4 + checkState(addrs[2], false, false, 0) // #5 + // genesis accounts don't begin IncentiveEligible, even if online require.False(t, lookup(t, dl.generator, addrs[0]).IncentiveEligible) - require.False(t, lookup(t, dl.generator, addrs[1]).IncentiveEligible) + // but addr[1] paid extra fee. Note this is _current_ state, not really "online" + require.True(t, lookup(t, dl.generator, addrs[1]).IncentiveEligible) require.False(t, lookup(t, dl.generator, addrs[2]).IncentiveEligible) - dl.fullBlock() + vb := dl.fullBlock() // #6 + totals, err := dl.generator.Totals(vb.Block().Round()) + require.NoError(t, err) + require.NotZero(t, totals.Online.Money.Raw) // although it's not even online, we'll use addrs[7] as the proposer proposer := addrs[7] @@ -444,18 +494,14 @@ func TestAbsentTracking(t *testing.T) { Receiver: addrs[2], Amount: 100_000, }) - dl.endBlock(proposer) + dl.endBlock(proposer) // #7 prp := lookup(t, dl.validator, proposer) - if ver >= checkingBegins { - require.Equal(t, prp.LastProposed, dl.validator.Latest()) - } else { - require.Zero(t, prp.LastProposed) - } + require.Equal(t, prp.LastProposed, dl.validator.Latest()) require.Zero(t, prp.LastHeartbeat) require.False(t, prp.IncentiveEligible) - // addr[1] is spent to an offline account, so Online totals decrease + // addr[1] paid to an offline account, so Online totals decrease newtotals, err := dl.generator.Totals(dl.generator.Latest()) require.NoError(t, err) // payment and fee left the online account @@ -465,15 +511,15 @@ func TestAbsentTracking(t *testing.T) { dl.fullBlock() // addrs[2] was already offline - dl.txns(&txntest.Txn{Type: "keyreg", Sender: addrs[2]}) // OFFLINE keyreg + dl.txns(&txntest.Txn{Type: "keyreg", Sender: addrs[2]}) // OFFLINE keyreg #9 regger := lookup(t, dl.validator, addrs[2]) - // total were unchanged by an offline keyreg from an offline account + // totals were unchanged by an offline keyreg from an offline account newtotals, err = dl.generator.Totals(dl.generator.Latest()) require.NoError(t, err) require.Equal(t, totals.Online.Money.Raw, newtotals.Online.Money.Raw) - // an an offline keyreg transaction records no activity + // an offline keyreg transaction records no activity require.Zero(t, regger.LastProposed) require.Zero(t, regger.LastHeartbeat) @@ -483,8 +529,8 @@ func TestAbsentTracking(t *testing.T) { Sender: addrs[2], VotePK: [32]byte{1}, SelectionPK: [32]byte{1}, - }) - // online totals have grown + }) // #10 + // online totals have grown, addr[2] was added newtotals, err = dl.generator.Totals(dl.generator.Latest()) require.NoError(t, err) require.Greater(t, newtotals.Online.Money.Raw, totals.Online.Money.Raw) @@ -493,27 +539,30 @@ func TestAbsentTracking(t *testing.T) { require.Zero(t, regger.LastProposed) require.True(t, regger.Status == basics.Online) - if ver >= checkingBegins { - require.NotZero(t, regger.LastHeartbeat) // online keyreg caused update - } else { - require.Zero(t, regger.LastHeartbeat) - } + // But nothing has changed, since we're not past 320 + checkState(addrs[0], true, false, 833_333_333_333_333) // #11 + checkState(addrs[1], true, false, 833_333_333_333_333) // #12 + checkState(addrs[2], false, false, 0) // #13 + + require.NotZero(t, regger.LastHeartbeat) // online keyreg caused update require.False(t, regger.IncentiveEligible) // ONLINE keyreg with extra fee - dl.txns(&txntest.Txn{ + vb = dl.fullBlock(&txntest.Txn{ Type: "keyreg", Fee: 2_000_000, Sender: addrs[2], VotePK: [32]byte{1}, SelectionPK: [32]byte{1}, - }) + }) // #14 + twoEligible := vb.Block().Round() + require.EqualValues(t, 14, twoEligible) // sanity check regger = lookup(t, dl.validator, addrs[2]) - require.Equal(t, ver >= checkingBegins, regger.IncentiveEligible) + require.True(t, regger.IncentiveEligible) for i := 0; i < 5; i++ { - dl.fullBlock() + dl.fullBlock() // #15-19 require.True(t, lookup(t, dl.generator, addrs[0]).Status == basics.Online) require.True(t, lookup(t, dl.generator, addrs[1]).Status == basics.Online) require.True(t, lookup(t, dl.generator, addrs[2]).Status == basics.Online) @@ -525,7 +574,7 @@ func TestAbsentTracking(t *testing.T) { require.True(t, lookup(t, dl.generator, addrs[2]).Status == basics.Online) for i := 0; i < 30; i++ { - dl.fullBlock() + dl.fullBlock() // #20-49 } // addrs 0-2 all have about 1/3 of stake, so seemingly (see next block @@ -535,39 +584,46 @@ func TestAbsentTracking(t *testing.T) { require.Equal(t, basics.Online, lookup(t, dl.generator, addrs[0]).Status) require.Equal(t, basics.Online, lookup(t, dl.generator, addrs[1]).Status) require.Equal(t, basics.Online, lookup(t, dl.generator, addrs[2]).Status) - require.Equal(t, ver >= checkingBegins, lookup(t, dl.generator, addrs[2]).IncentiveEligible) + require.True(t, lookup(t, dl.generator, addrs[2]).IncentiveEligible) - // when 2 pays 0, they both get noticed but addr[0] is not considered absent - vb := dl.fullBlock(&txntest.Txn{ + // when 2 pays 0, they both get noticed but addr[0] is not considered + // absent because it is a genesis account + vb = dl.fullBlock(&txntest.Txn{ Type: "pay", Sender: addrs[2], Receiver: addrs[0], Amount: 0, - }) - if ver >= checkingBegins { - require.Equal(t, vb.Block().AbsentParticipationAccounts, []basics.Address{addrs[2]}) - } + }) // #50 + require.Equal(t, vb.Block().AbsentParticipationAccounts, []basics.Address{addrs[2]}) + + twoPaysZero := vb.Block().Round() + require.EqualValues(t, 50, twoPaysZero) // addr[0] has never proposed or heartbeat so it is not considered absent require.Equal(t, basics.Online, lookup(t, dl.generator, addrs[0]).Status) // addr[1] still hasn't been "noticed" require.Equal(t, basics.Online, lookup(t, dl.generator, addrs[1]).Status) - require.Equal(t, ver >= checkingBegins, lookup(t, dl.generator, addrs[2]).Status == basics.Offline) + require.Equal(t, basics.Offline, lookup(t, dl.generator, addrs[2]).Status) require.False(t, lookup(t, dl.generator, addrs[2]).IncentiveEligible) + // separate the payments by a few blocks so it will be easier to test + // when the changes go into effect + for i := 0; i < 4; i++ { + dl.fullBlock() // #51-54 + } // now, when 2 pays 1, 1 gets suspended (unlike 0, we had 1 keyreg early on, so LastHeartbeat>0) vb = dl.fullBlock(&txntest.Txn{ Type: "pay", Sender: addrs[2], Receiver: addrs[1], Amount: 0, - }) - if ver >= checkingBegins { - require.Equal(t, vb.Block().AbsentParticipationAccounts, []basics.Address{addrs[1]}) - } + }) // #55 + twoPaysOne := vb.Block().Round() + require.EqualValues(t, 55, twoPaysOne) + require.Equal(t, vb.Block().AbsentParticipationAccounts, []basics.Address{addrs[1]}) require.Equal(t, basics.Online, lookup(t, dl.generator, addrs[0]).Status) - require.Equal(t, ver >= checkingBegins, lookup(t, dl.generator, addrs[1]).Status == basics.Offline) + require.Equal(t, basics.Offline, lookup(t, dl.generator, addrs[1]).Status) require.False(t, lookup(t, dl.generator, addrs[1]).IncentiveEligible) - require.Equal(t, ver >= checkingBegins, lookup(t, dl.generator, addrs[2]).Status == basics.Offline) + require.Equal(t, basics.Offline, lookup(t, dl.generator, addrs[2]).Status) require.False(t, lookup(t, dl.generator, addrs[2]).IncentiveEligible) // now, addrs[2] proposes, so it gets back online, but stays ineligible @@ -575,6 +631,49 @@ func TestAbsentTracking(t *testing.T) { dl.fullBlock() require.Equal(t, basics.Online, lookup(t, dl.generator, addrs[2]).Status) require.False(t, lookup(t, dl.generator, addrs[2]).IncentiveEligible) + + // "synchronize" so the loop below ends on 320 + for dl.fullBlock().Block().Round()%4 != 3 { + } + // keep in mind that each call to checkState also advances the round, so + // each loop advances by 4. + for rnd := dl.fullBlock().Block().Round(); rnd < 320; rnd = dl.fullBlock().Block().Round() { + // STILL nothing has changed, as we're under 320 + checkState(addrs[0], true, false, 833_333_333_333_333) + checkState(addrs[1], true, false, 833_333_333_333_333) + checkState(addrs[2], false, false, 0) + } + // rnd was 320 in the last fullBlock + + // We will soon see effects visible to `vote_params_get` + // In first block, addr[3] created an app. No effect on 0-2 + checkState(addrs[1], true, false, 833_333_333_333_333) // 321 + // in second block, the checkstate app was created + checkState(addrs[1], true, false, 833_333_333_333_333) // 322 + // addr[1] spent 10A on a fee in rnd 3, so online stake and eligibility adjusted in 323 + checkState(addrs[1], true, true, 833_333_323_333_333) // 323 + + for rnd := dl.fullBlock().Block().Round(); rnd < 320+twoEligible-1; rnd = dl.fullBlock().Block().Round() { + } + checkState(addrs[2], true, false, 833_333_333_429_333) + checkState(addrs[2], true, true, 833_333_331_429_333) // after keyreg w/ 2A is effective + + for rnd := dl.fullBlock().Block().Round(); rnd < 320+twoPaysZero-1; rnd = dl.fullBlock().Block().Round() { + } + // we're at the round before two's suspension kicks in + checkState(addrs[2], true, true, 833_333_331_429_333) // still "online" + checkState(addrs[0], true, false, 833_333_333_331_333) // paid fee in #5 and #11, we're at ~371 + // 2 was noticed & suspended after paying 0, eligible and amount go to 0 + checkState(addrs[2], false, false, 0) + checkState(addrs[0], true, false, 833_333_333_331_333) // addr 0 didn't get suspended (genesis) + + // roughly the same check, except for addr 1, which was genesis, but + // after doing a keyreg, became susceptible to suspension + for rnd := dl.fullBlock().Block().Round(); rnd < 320+twoPaysOne-1; rnd = dl.fullBlock().Block().Round() { + } + checkState(addrs[1], true, true, 833_333_323_230_333) // still online, balance irrelevant + // 1 was noticed & suspended after being paid by 2, so eligible and amount go to 0 + checkState(addrs[1], false, false, 0) }) } @@ -585,7 +684,9 @@ func TestAbsenteeChallenges(t *testing.T) { t.Parallel() genBalances, addrs, _ := ledgertesting.NewTestGenesis(func(cfg *ledgertesting.GenesisCfg) { - cfg.OnlineCount = 5 // Make online stake big, so these accounts won't be expected to propose + // Get some big accounts online, so the accounts we create here will be + // a tiny fraction, not expected to propose often. + cfg.OnlineCount = 5 }) checkingBegins := 40 @@ -703,6 +804,105 @@ func TestAbsenteeChallenges(t *testing.T) { }) } +// TestVoterAccess ensures that the `voter` opcode works properly when hooked up +// to a real ledger. +func TestVoterAccess(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + genBalances, addrs, _ := ledgertesting.NewTestGenesis( + ledgertesting.TurnOffRewards, + func(cfg *ledgertesting.GenesisCfg) { + cfg.OnlineCount = 1 // So that one is online from the start + }) + getOnlineStake := `int 0; voter_params_get VoterBalance; itob; log; itob; log; online_stake; itob; log; int 1` + + // `voter_params_get` introduced in 40 + ledgertesting.TestConsensusRange(t, 40, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + dl := NewDoubleLedger(t, genBalances, cv, cfg) + defer dl.Close() + + stib := dl.txn(&txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: getOnlineStake, + }) + stakeChecker := stib.ApplicationID + require.NotZero(t, stakeChecker) + + // have addrs[1] go online, though it won't be visible right away + dl.txn(&txntest.Txn{ + Type: "keyreg", + Sender: addrs[1], + VotePK: [32]byte{0xaa}, + SelectionPK: [32]byte{0xbb}, + }) + + one := basics.Address{0xaa, 0x11} + two := basics.Address{0xaa, 0x22} + three := basics.Address{0xaa, 0x33} + + checkState := func(addr basics.Address, online bool, expected uint64, total uint64) { + t.Helper() + if !online { + require.Zero(t, expected) + } + stib = dl.txn(&txntest.Txn{ + Type: "appl", + Sender: addr, + ApplicationID: stakeChecker, + }) + logs := stib.ApplyData.EvalDelta.Logs + require.Len(t, logs, 3) + if online { + require.Equal(t, "\x00\x00\x00\x00\x00\x00\x00\x01", logs[0]) + require.Equal(t, int(expected), int(binary.BigEndian.Uint64([]byte(logs[1])))) + } else { + require.Equal(t, "\x00\x00\x00\x00\x00\x00\x00\x00", logs[0]) + require.Equal(t, int(expected), int(binary.BigEndian.Uint64([]byte(logs[1])))) + } + require.Equal(t, int(total), int(binary.BigEndian.Uint64([]byte(logs[2])))) + } + + checkState(addrs[0], true, 833_333_333_333_333, 833_333_333_333_333) + // checking again because addrs[0] just paid a fee, but we show online balance hasn't changed yet + checkState(addrs[0], true, 833_333_333_333_333, 833_333_333_333_333) + for i := 1; i < 10; i++ { + checkState(addrs[i], false, 0, 833_333_333_333_333) + } + + // Fund the new accounts and have them go online. + for i, addr := range []basics.Address{one, two, three} { + dl.txns(&txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: addr, + Amount: (uint64(i) + 1) * 1_000_000_000, + }, &txntest.Txn{ + Type: "keyreg", + Sender: addr, + VotePK: [32]byte{byte(i + 1)}, + SelectionPK: [32]byte{byte(i + 1)}, + }) + } + // they don't have online stake yet + for _, addr := range []basics.Address{one, two, three} { + checkState(addr, false, 0, 833_333_333_333_333) + } + for i := 0; i < 320; i++ { + dl.fullBlock() + } + // addr[1] is now visibly online. the total is across all five that are now online, minus various fees paid + checkState(addrs[1], true, 833_333_333_333_333-2000, 2*833_333_333_333_333-14000) + for i := 2; i < 10; i++ { // addrs[2-9] never came online + checkState(addrs[i], false, 0, 2*833_333_333_333_333-14000) + } + for i, addr := range []basics.Address{one, two, three} { + checkState(addr, true, (uint64(i)+1)*1_000_000_000-2000, 2*833_333_333_333_333-14000) + } + }) +} + // TestHoldingGet tests some of the corner cases for the asset_holding_get // opcode: the asset doesn't exist, the account doesn't exist, account not opted // in, vs it has none of the asset. This is tested here, even though it should diff --git a/ledger/evalindexer.go b/ledger/evalindexer.go deleted file mode 100644 index f83dbb9809..0000000000 --- a/ledger/evalindexer.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (C) 2019-2024 Algorand, Inc. -// This file is part of go-algorand -// -// go-algorand is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// go-algorand is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with go-algorand. If not, see . - -package ledger - -import ( - "errors" - "fmt" - - "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/data/transactions" - "github.com/algorand/go-algorand/ledger/eval" - "github.com/algorand/go-algorand/ledger/ledgercore" -) - -// A ledger interface that Indexer implements. This is a simplified version of the -// LedgerForEvaluator interface. Certain functions that the evaluator doesn't use -// in the trusting mode are excluded, and the present functions only request data -// at the latest round. However, functions below can be used for batch querying. -type indexerLedgerForEval interface { - LatestBlockHdr() (bookkeeping.BlockHeader, error) - // The value of the returned map is nil iff the account was not found. - LookupWithoutRewards(map[basics.Address]struct{}) (map[basics.Address]*ledgercore.AccountData, error) - // The returned map must have the same structure (elements) as the input map. - // If a resource is not found, it must be nil in `ledgercore.AccountResource`. - LookupResources(map[basics.Address]map[Creatable]struct{}) (map[basics.Address]map[Creatable]ledgercore.AccountResource, error) - GetAssetCreator(map[basics.AssetIndex]struct{}) (map[basics.AssetIndex]FoundAddress, error) - GetAppCreator(map[basics.AppIndex]struct{}) (map[basics.AppIndex]FoundAddress, error) - LatestTotals() (ledgercore.AccountTotals, error) - LookupKv(basics.Round, string) ([]byte, error) - - BlockHdr(basics.Round) (bookkeeping.BlockHeader, error) -} - -// FoundAddress is a wrapper for an address and a boolean. -type FoundAddress struct { - Address basics.Address - Exists bool -} - -// EvalForIndexerResources contains resources preloaded from the Indexer database. -// Indexer is able to do the preloading more efficiently than the evaluator loading -// resources one by one. -type EvalForIndexerResources struct { - // The map value is nil iff the account does not exist. The account data is owned here. - Accounts map[basics.Address]*ledgercore.AccountData - Resources map[basics.Address]map[Creatable]ledgercore.AccountResource - Creators map[Creatable]FoundAddress -} - -// Creatable represent a single creatable object. -type Creatable struct { - Index basics.CreatableIndex - Type basics.CreatableType -} - -// Converter between indexerLedgerForEval and ledgerForEvaluator interfaces. -type indexerLedgerConnector struct { - il indexerLedgerForEval - genesisHash crypto.Digest - genesisProto config.ConsensusParams - latestRound basics.Round - roundResources EvalForIndexerResources -} - -func (l indexerLedgerConnector) FlushCaches() {} - -// BlockHdr is part of LedgerForEvaluator interface. -func (l indexerLedgerConnector) BlockHdr(round basics.Round) (bookkeeping.BlockHeader, error) { - if round != l.latestRound { - return bookkeeping.BlockHeader{}, fmt.Errorf( - "BlockHdr() evaluator called this function for the wrong round %d, "+ - "latest round is %d", - round, l.latestRound) - } - return l.il.LatestBlockHdr() -} - -// CheckDup is part of LedgerForEvaluator interface. -func (l indexerLedgerConnector) CheckDup(config.ConsensusParams, basics.Round, basics.Round, basics.Round, transactions.Txid, ledgercore.Txlease) error { - // This function is not used by evaluator. - return errors.New("CheckDup() not implemented") -} - -// LookupWithoutRewards is part of LedgerForEvaluator interface. -func (l indexerLedgerConnector) LookupWithoutRewards(round basics.Round, address basics.Address) (ledgercore.AccountData, basics.Round, error) { - // check to see if the account data in the cache. - if pad, has := l.roundResources.Accounts[address]; has { - if pad == nil { - return ledgercore.AccountData{}, round, nil - } - return *pad, round, nil - } - - accountDataMap, err := l.il.LookupWithoutRewards(map[basics.Address]struct{}{address: {}}) - if err != nil { - return ledgercore.AccountData{}, basics.Round(0), err - } - - accountData := accountDataMap[address] - if accountData == nil { - return ledgercore.AccountData{}, round, nil - } - return *accountData, round, nil -} - -func (l indexerLedgerConnector) LookupApplication(rnd basics.Round, addr basics.Address, aidx basics.AppIndex) (ledgercore.AppResource, error) { - r, err := l.lookupResource(rnd, addr, basics.CreatableIndex(aidx), basics.AppCreatable) - return ledgercore.AppResource{AppParams: r.AppParams, AppLocalState: r.AppLocalState}, err -} - -func (l indexerLedgerConnector) LookupAsset(rnd basics.Round, addr basics.Address, aidx basics.AssetIndex) (ledgercore.AssetResource, error) { - r, err := l.lookupResource(rnd, addr, basics.CreatableIndex(aidx), basics.AssetCreatable) - return ledgercore.AssetResource{AssetParams: r.AssetParams, AssetHolding: r.AssetHolding}, err -} - -func (l indexerLedgerConnector) lookupResource(round basics.Round, address basics.Address, aidx basics.CreatableIndex, ctype basics.CreatableType) (ledgercore.AccountResource, error) { - // check to see if the account data in the cache. - if creatableMap, ok := l.roundResources.Resources[address]; ok { - if resource, ok := creatableMap[Creatable{aidx, ctype}]; ok { - return resource, nil - } - } - - accountResourceMap, err := - l.il.LookupResources(map[basics.Address]map[Creatable]struct{}{address: {{aidx, ctype}: {}}}) - if err != nil { - return ledgercore.AccountResource{}, err - } - - return accountResourceMap[address][Creatable{aidx, ctype}], nil -} - -// LookupKv delegates to the Ledger and marks the box key as touched for post-processing -func (l indexerLedgerConnector) LookupKv(rnd basics.Round, key string) ([]byte, error) { - value, err := l.il.LookupKv(rnd, key) - if err != nil { - return value, fmt.Errorf("LookupKv() in indexerLedgerConnector internal error: %w", err) - } - return value, nil -} - -// GetCreatorForRound is part of LedgerForEvaluator interface. -func (l indexerLedgerConnector) GetCreatorForRound(_ basics.Round, cindex basics.CreatableIndex, ctype basics.CreatableType) (basics.Address, bool, error) { - var foundAddress FoundAddress - var has bool - // check to see if the account data in the cache. - if foundAddress, has = l.roundResources.Creators[Creatable{Index: cindex, Type: ctype}]; has { - return foundAddress.Address, foundAddress.Exists, nil - } - - switch ctype { - case basics.AssetCreatable: - foundAddresses, err := - l.il.GetAssetCreator(map[basics.AssetIndex]struct{}{basics.AssetIndex(cindex): {}}) - if err != nil { - return basics.Address{}, false, err - } - foundAddress = foundAddresses[basics.AssetIndex(cindex)] - case basics.AppCreatable: - foundAddresses, err := - l.il.GetAppCreator(map[basics.AppIndex]struct{}{basics.AppIndex(cindex): {}}) - if err != nil { - return basics.Address{}, false, err - } - foundAddress = foundAddresses[basics.AppIndex(cindex)] - default: - return basics.Address{}, false, fmt.Errorf("unknown creatable type %v", ctype) - } - - return foundAddress.Address, foundAddress.Exists, nil -} - -// GenesisHash is part of LedgerForEvaluator interface. -func (l indexerLedgerConnector) GenesisHash() crypto.Digest { - return l.genesisHash -} - -// GenesisProto is part of LedgerForEvaluator interface. -func (l indexerLedgerConnector) GenesisProto() config.ConsensusParams { - return l.genesisProto -} - -// Totals is part of LedgerForEvaluator interface. -func (l indexerLedgerConnector) LatestTotals() (rnd basics.Round, totals ledgercore.AccountTotals, err error) { - totals, err = l.il.LatestTotals() - rnd = l.latestRound - return -} - -// VotersForStateProof is part of LedgerForEvaluator interface. -func (l indexerLedgerConnector) VotersForStateProof(_ basics.Round) (*ledgercore.VotersForRound, error) { - // This function is not used by evaluator. - return nil, errors.New("VotersForStateProof() not implemented") -} - -// GetStateProofVerificationContext is part of LedgerForEvaluator interface. -func (l indexerLedgerConnector) GetStateProofVerificationContext(_ basics.Round) (*ledgercore.StateProofVerificationContext, error) { - return nil, errors.New("GetStateProofVerificationContext() not implemented") -} - -func makeIndexerLedgerConnector(il indexerLedgerForEval, genesisHash crypto.Digest, genesisProto config.ConsensusParams, latestRound basics.Round, roundResources EvalForIndexerResources) indexerLedgerConnector { - return indexerLedgerConnector{ - il: il, - genesisHash: genesisHash, - genesisProto: genesisProto, - latestRound: latestRound, - roundResources: roundResources, - } -} - -// EvalForIndexer evaluates a block without validation using the given `proto`. -// Return the state delta and transactions with modified apply data according to `proto`. -// This function is used by Indexer which modifies `proto` to retrieve the asset -// close amount for each transaction even when the real consensus parameters do not -// support it. -func EvalForIndexer(il indexerLedgerForEval, block *bookkeeping.Block, proto config.ConsensusParams, resources EvalForIndexerResources) (ledgercore.StateDelta, []transactions.SignedTxnInBlock, error) { - ilc := makeIndexerLedgerConnector(il, block.GenesisHash(), proto, block.Round()-1, resources) - - eval, err := eval.StartEvaluator( - ilc, block.BlockHeader, - eval.EvaluatorOptions{ - PaysetHint: len(block.Payset), - ProtoParams: &proto, - Generate: false, - Validate: false, - }) - if err != nil { - return ledgercore.StateDelta{}, []transactions.SignedTxnInBlock{}, - fmt.Errorf("EvalForIndexer() err: %w", err) - } - - return eval.ProcessBlockForIndexer(block) -} diff --git a/ledger/evalindexer_test.go b/ledger/evalindexer_test.go deleted file mode 100644 index c85d5f0275..0000000000 --- a/ledger/evalindexer_test.go +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright (C) 2019-2024 Algorand, Inc. -// This file is part of go-algorand -// -// go-algorand is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// go-algorand is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with go-algorand. If not, see . - -package ledger - -import ( - "errors" - "fmt" - "math/rand" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "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/data/transactions" - "github.com/algorand/go-algorand/data/txntest" - "github.com/algorand/go-algorand/ledger/ledgercore" - ledgertesting "github.com/algorand/go-algorand/ledger/testing" - "github.com/algorand/go-algorand/logging" - "github.com/algorand/go-algorand/protocol" - "github.com/algorand/go-algorand/test/partitiontest" -) - -type indexerLedgerForEvalImpl struct { - l *Ledger - latestRound basics.Round -} - -func (il indexerLedgerForEvalImpl) LatestBlockHdr() (bookkeeping.BlockHeader, error) { - return il.l.BlockHdr(il.latestRound) -} - -func (il indexerLedgerForEvalImpl) BlockHdr(round basics.Round) (bookkeeping.BlockHeader, error) { - return il.l.BlockHdr(round) -} - -// The value of the returned map is nil iff the account was not found. -func (il indexerLedgerForEvalImpl) LookupWithoutRewards(addresses map[basics.Address]struct{}) (map[basics.Address]*ledgercore.AccountData, error) { - res := make(map[basics.Address]*ledgercore.AccountData) - - for address := range addresses { - accountData, _, err := il.l.LookupWithoutRewards(il.latestRound, address) - if err != nil { - return nil, err - } - - if accountData.IsZero() { - res[address] = nil - } else { - accountDataCopy := new(ledgercore.AccountData) - *accountDataCopy = accountData - res[address] = accountDataCopy - } - } - - return res, nil -} - -// The value of the returned map is nil iff the account was not found. -func (il indexerLedgerForEvalImpl) LookupResources(addresses map[basics.Address]map[Creatable]struct{}) (map[basics.Address]map[Creatable]ledgercore.AccountResource, error) { - res := make(map[basics.Address]map[Creatable]ledgercore.AccountResource) - - var err error - for address, creatables := range addresses { - for creatable := range creatables { - c, ok := res[address] - if !ok { - c = make(map[Creatable]ledgercore.AccountResource) - res[address] = c - } - - c[creatable], err = - il.l.lookupResource(il.latestRound, address, creatable.Index, creatable.Type) - if err != nil { - return nil, err - } - } - } - - return res, nil -} - -func (il indexerLedgerForEvalImpl) GetAssetCreator(map[basics.AssetIndex]struct{}) (map[basics.AssetIndex]FoundAddress, error) { - // This function is unused. - return nil, errors.New("GetAssetCreator() not implemented") -} - -func (il indexerLedgerForEvalImpl) GetAppCreator(map[basics.AppIndex]struct{}) (map[basics.AppIndex]FoundAddress, error) { - // This function is unused. - return nil, errors.New("GetAppCreator() not implemented") -} - -func (il indexerLedgerForEvalImpl) LookupKv(basics.Round, string) ([]byte, error) { - // This function is unused. - return nil, errors.New("LookupKv() not implemented") -} - -func (il indexerLedgerForEvalImpl) LatestTotals() (totals ledgercore.AccountTotals, err error) { - _, totals, err = il.l.LatestTotals() - return -} - -// Test that overriding the consensus parameters effects the generated apply data. -func TestEvalForIndexerCustomProtocolParams(t *testing.T) { - partitiontest.PartitionTest(t) - - genesisBalances, addrs, _ := ledgertesting.NewTestGenesis() - - var genHash crypto.Digest - crypto.RandBytes(genHash[:]) - block, err := bookkeeping.MakeGenesisBlock(protocol.ConsensusV24, - genesisBalances, "test", genHash) - require.NoError(t, err) - - dbName := t.Name() - cfg := config.GetDefaultLocal() - cfg.Archival = true - l, err := OpenLedger(logging.Base(), dbName, true, ledgercore.InitState{ - Block: block, - Accounts: genesisBalances.Balances, - GenesisHash: genHash, - }, cfg) - require.NoError(t, err) - defer l.Close() - - const assetid basics.AssetIndex = 1 - proto := config.Consensus[protocol.ConsensusV24] - - block = bookkeeping.MakeBlock(block.BlockHeader) - - createTxn := txntest.Txn{ - Type: "acfg", - Sender: addrs[0], - GenesisHash: block.GenesisHash(), - AssetParams: basics.AssetParams{ - Total: 200, - Decimals: 0, - Manager: addrs[0], - Reserve: addrs[0], - Freeze: addrs[0], - Clawback: addrs[0], - }, - } - createTxn.FillDefaults(proto) - createStib, err := block.BlockHeader.EncodeSignedTxn( - createTxn.SignedTxn(), transactions.ApplyData{}) - require.NoError(t, err) - - optInTxn := txntest.Txn{ - Type: "axfer", - Sender: addrs[1], - GenesisHash: block.GenesisHash(), - XferAsset: assetid, - AssetAmount: 0, - AssetReceiver: addrs[1], - } - optInTxn.FillDefaults(proto) - optInStib, err := block.BlockHeader.EncodeSignedTxn( - optInTxn.SignedTxn(), transactions.ApplyData{}) - require.NoError(t, err) - - fundTxn := txntest.Txn{ - Type: "axfer", - Sender: addrs[0], - GenesisHash: block.GenesisHash(), - XferAsset: assetid, - AssetAmount: 100, - AssetReceiver: addrs[1], - } - fundTxn.FillDefaults(proto) - fundStib, err := block.BlockHeader.EncodeSignedTxn( - fundTxn.SignedTxn(), transactions.ApplyData{}) - require.NoError(t, err) - - optOutTxn := txntest.Txn{ - Type: "axfer", - Sender: addrs[1], - GenesisHash: block.GenesisHash(), - XferAsset: assetid, - AssetAmount: 30, - AssetReceiver: addrs[0], - AssetCloseTo: addrs[0], - } - optOutTxn.FillDefaults(proto) - optOutStib, err := block.BlockHeader.EncodeSignedTxn( - optOutTxn.SignedTxn(), transactions.ApplyData{}) - require.NoError(t, err) - - block.Payset = []transactions.SignedTxnInBlock{ - createStib, optInStib, fundStib, optOutStib, - } - - il := indexerLedgerForEvalImpl{ - l: l, - latestRound: 0, - } - proto.EnableAssetCloseAmount = true - _, modifiedTxns, err := EvalForIndexer(il, &block, proto, EvalForIndexerResources{}) - require.NoError(t, err) - - require.Equal(t, 4, len(modifiedTxns)) - assert.Equal(t, uint64(70), modifiedTxns[3].AssetClosingAmount) -} - -// TestEvalForIndexerForExpiredAccounts tests that the EvalForIndexer function will correctly mark accounts offline -func TestEvalForIndexerForExpiredAccounts(t *testing.T) { - partitiontest.PartitionTest(t) - - genesisBalances, addrs, _ := ledgertesting.NewTestGenesis() - - var genHash crypto.Digest - crypto.RandBytes(genHash[:]) - block, err := bookkeeping.MakeGenesisBlock(protocol.ConsensusFuture, - genesisBalances, "test", genHash) - require.NoError(t, err) - - dbName := t.Name() - cfg := config.GetDefaultLocal() - cfg.Archival = true - l, err := OpenLedger(logging.Base(), dbName, true, ledgercore.InitState{ - Block: block, - Accounts: genesisBalances.Balances, - GenesisHash: genHash, - }, cfg) - require.NoError(t, err) - defer l.Close() - - proto := config.Consensus[protocol.ConsensusFuture] - - block = bookkeeping.MakeBlock(block.BlockHeader) - - il := indexerLedgerForEvalImpl{ - l: l, - latestRound: 0, - } - - _, _, err = EvalForIndexer(il, &block, proto, EvalForIndexerResources{}) - require.NoError(t, err) - - badBlock := block - // First validate that bad block is fine if we dont touch it... - _, _, err = EvalForIndexer(il, &badBlock, proto, EvalForIndexerResources{}) - require.NoError(t, err) - - // Introduce an unknown address, but this time the Eval function is called with parameters that - // don't necessarily mean that this will cause an error. Just that an empty address will be added - badBlock.ExpiredParticipationAccounts = append(badBlock.ExpiredParticipationAccounts, basics.Address{123}) - - _, _, err = EvalForIndexer(il, &badBlock, proto, EvalForIndexerResources{}) - require.NoError(t, err) - - badBlock = block - - // Now we add way too many accounts which will cause resetExpiredOnlineAccountsParticipationKeys() to fail - addressToCopy := addrs[0] - - for i := 0; i < proto.MaxProposedExpiredOnlineAccounts+1; i++ { - badBlock.ExpiredParticipationAccounts = append(badBlock.ExpiredParticipationAccounts, addressToCopy) - } - - _, _, err = EvalForIndexer(il, &badBlock, proto, EvalForIndexerResources{}) - require.Error(t, err) - - // Sanity Check - - badBlock = block - - _, _, err = EvalForIndexer(il, &badBlock, proto, EvalForIndexerResources{}) - require.NoError(t, err) -} - -func newTestLedger(t testing.TB, balances bookkeeping.GenesisBalances) *Ledger { - var genHash crypto.Digest - crypto.RandBytes(genHash[:]) - genBlock, err := bookkeeping.MakeGenesisBlock(protocol.ConsensusFuture, balances, "test", genHash) - require.NoError(t, err) - require.False(t, genBlock.FeeSink.IsZero()) - require.False(t, genBlock.RewardsPool.IsZero()) - dbName := fmt.Sprintf("%s.%d", t.Name(), crypto.RandUint64()) - cfg := config.GetDefaultLocal() - cfg.Archival = true - l, err := OpenLedger(logging.Base(), dbName, true, ledgercore.InitState{ - Block: genBlock, - Accounts: balances.Balances, - GenesisHash: genHash, - }, cfg) - require.NoError(t, err) - return l -} - -// Test that preloading data in cow base works as expected. -func TestResourceCaching(t *testing.T) { - partitiontest.PartitionTest(t) - - var address basics.Address - _, err := rand.Read(address[:]) - require.NoError(t, err) - - creatable := Creatable{ - Index: basics.CreatableIndex(7), - Type: basics.AssetCreatable, - } - - genesisInitState, _, _ := ledgertesting.GenesisWithProto(10, protocol.ConsensusFuture) - - genesisBalances := bookkeeping.GenesisBalances{ - Balances: genesisInitState.Accounts, - FeeSink: testSinkAddr, - RewardsPool: testPoolAddr, - Timestamp: 0, - } - l := newTestLedger(t, genesisBalances) - defer l.Close() - - genesisBlockHeader, err := l.BlockHdr(basics.Round(0)) - require.NoError(t, err) - block := bookkeeping.MakeBlock(genesisBlockHeader) - - resources := EvalForIndexerResources{ - Accounts: map[basics.Address]*ledgercore.AccountData{ - address: { - AccountBaseData: ledgercore.AccountBaseData{ - MicroAlgos: basics.MicroAlgos{Raw: 5}, - }, - }, - }, - Resources: map[basics.Address]map[Creatable]ledgercore.AccountResource{ - address: { - creatable: { - AssetParams: &basics.AssetParams{ - Total: 8, - }, - AssetHolding: &basics.AssetHolding{ - Amount: 9, - }, - }, - }, - }, - Creators: map[Creatable]FoundAddress{ - {Index: basics.CreatableIndex(6), Type: basics.AssetCreatable}: {Address: address, Exists: true}, - {Index: basics.CreatableIndex(6), Type: basics.AppCreatable}: {Address: address, Exists: false}, - }, - } - - proto := config.Consensus[protocol.ConsensusFuture] - ilc := makeIndexerLedgerConnector(indexerLedgerForEvalImpl{l: l, latestRound: basics.Round(0)}, block.GenesisHash(), proto, block.Round()-1, resources) - - { - accountData, rnd, err := ilc.LookupWithoutRewards(basics.Round(0), address) - require.NoError(t, err) - assert.Equal(t, ledgercore.AccountData{AccountBaseData: ledgercore.AccountBaseData{MicroAlgos: basics.MicroAlgos{Raw: 5}}}, accountData) - assert.Equal(t, basics.Round(0), rnd) - } - { - accountResource, err := ilc.LookupAsset( - basics.Round(0), address, basics.AssetIndex(7)) - require.NoError(t, err) - expected := ledgercore.AssetResource{ - AssetParams: &basics.AssetParams{ - Total: 8, - }, - AssetHolding: &basics.AssetHolding{ - Amount: 9, - }, - } - assert.Equal(t, expected, accountResource) - } - { - address, found, err := ilc.GetCreatorForRound(basics.Round(0), basics.CreatableIndex(6), basics.AssetCreatable) - require.NoError(t, err) - require.True(t, found) - assert.Equal(t, address, address) - } - { - _, found, err := ilc.GetCreatorForRound(basics.Round(0), basics.CreatableIndex(6), basics.AppCreatable) - require.NoError(t, err) - require.False(t, found) - } -} diff --git a/ledger/tracker.go b/ledger/tracker.go index 6d976a9763..d99f997ebe 100644 --- a/ledger/tracker.go +++ b/ledger/tracker.go @@ -908,6 +908,14 @@ func (aul *accountUpdatesLedgerEvaluator) LookupWithoutRewards(rnd basics.Round, return data, validThrough, err } +func (aul *accountUpdatesLedgerEvaluator) LookupAgreement(rnd basics.Round, addr basics.Address) (basics.OnlineAccountData, error) { + return aul.ao.LookupOnlineAccountData(rnd, addr) +} + +func (aul *accountUpdatesLedgerEvaluator) OnlineCirculation(rnd basics.Round, voteRnd basics.Round) (basics.MicroAlgos, error) { + return aul.ao.onlineCirculation(rnd, voteRnd) +} + func (aul *accountUpdatesLedgerEvaluator) LookupApplication(rnd basics.Round, addr basics.Address, aidx basics.AppIndex) (ledgercore.AppResource, error) { r, _, err := aul.au.lookupResource(rnd, addr, basics.CreatableIndex(aidx), basics.AppCreatable, false /* don't sync */) return ledgercore.AppResource{AppParams: r.AppParams, AppLocalState: r.AppLocalState}, err diff --git a/logging/log.go b/logging/log.go index d9b79eb9aa..48f83c1b9e 100644 --- a/logging/log.go +++ b/logging/log.go @@ -308,7 +308,7 @@ func (l logger) SetOutput(w io.Writer) { } func (l logger) setOutput(w io.Writer) { - l.entry.Logger.Out = w + l.entry.Logger.SetOutput(w) } func (l logger) getOutput() io.Writer { diff --git a/netdeploy/remote/deployedNetwork.go b/netdeploy/remote/deployedNetwork.go index 729409fe94..25de422026 100644 --- a/netdeploy/remote/deployedNetwork.go +++ b/netdeploy/remote/deployedNetwork.go @@ -75,12 +75,12 @@ type DeployedNetworkConfig struct { // DeployedNetwork represents the complete configuration specification for a deployed network type DeployedNetwork struct { - useExistingGenesis bool - createBoostrappedNetwork bool - GenesisData gen.GenesisData - Topology topology - Hosts []HostConfig - BootstrappedNet BootstrappedNetwork + useExistingGenesis bool + createBootstrappedNetwork bool + GenesisData gen.GenesisData + Topology topology + Hosts []HostConfig + BootstrappedNet BootstrappedNetwork } type netState struct { @@ -253,12 +253,12 @@ func (cfg *DeployedNetwork) SetUseExistingGenesisFiles(useExisting bool) bool { return old } -// SetUseBoostrappedFiles sets the override flag indicating we should use existing genesis +// SetUseBootstrappedFiles sets the override flag indicating we should use existing genesis // files instead of generating new ones. This is useful for permanent networks like devnet and testnet. // Returns the previous value. -func (cfg *DeployedNetwork) SetUseBoostrappedFiles(boostrappedFile bool) bool { - old := cfg.createBoostrappedNetwork - cfg.createBoostrappedNetwork = boostrappedFile +func (cfg *DeployedNetwork) SetUseBootstrappedFiles(bootstrappedFile bool) bool { + old := cfg.createBootstrappedNetwork + cfg.createBootstrappedNetwork = bootstrappedFile return old } @@ -346,7 +346,7 @@ func (cfg DeployedNetwork) BuildNetworkFromTemplate(buildCfg BuildConfig, rootDi return } - if cfg.createBoostrappedNetwork { + if cfg.createBootstrappedNetwork { fmt.Println("Generating db files ") cfg.GenerateDatabaseFiles(cfg.BootstrappedNet, genesisFolder) diff --git a/network/wsNetwork.go b/network/wsNetwork.go index 295bd71155..9c203d8839 100644 --- a/network/wsNetwork.go +++ b/network/wsNetwork.go @@ -1147,6 +1147,8 @@ func (wn *msgHandler) messageHandlerThread(wg *sync.WaitGroup, peersConnectivity networkIncomingBufferMicros.AddUint64(uint64(bufferNanos/1000), nil) handleTime := handled.Sub(start) networkHandleMicros.AddUint64(uint64(handleTime.Nanoseconds()/1000), nil) + networkHandleMicrosByTag.Add(string(msg.Tag), uint64(handleTime.Nanoseconds()/1000)) + networkHandleCountByTag.Add(string(msg.Tag), 1) switch outmsg.Action { case Disconnect: wg.Add(1) diff --git a/network/wsPeer.go b/network/wsPeer.go index adf211f592..c4b64bdec4 100644 --- a/network/wsPeer.go +++ b/network/wsPeer.go @@ -63,6 +63,8 @@ func init() { networkReceivedBytesByTag = metrics.NewTagCounterFiltered("algod_network_received_bytes_{TAG}", "Number of bytes that were received from the network for {TAG} messages", tagStringList, "UNK") networkMessageReceivedByTag = metrics.NewTagCounterFiltered("algod_network_message_received_{TAG}", "Number of complete messages that were received from the network for {TAG} messages", tagStringList, "UNK") networkMessageSentByTag = metrics.NewTagCounterFiltered("algod_network_message_sent_{TAG}", "Number of complete messages that were sent to the network for {TAG} messages", tagStringList, "UNK") + networkHandleCountByTag = metrics.NewTagCounterFiltered("algod_network_rx_handle_countbytag_{TAG}", "count of handler calls in the receive thread for {TAG} messages", tagStringList, "UNK") + networkHandleMicrosByTag = metrics.NewTagCounterFiltered("algod_network_rx_handle_microsbytag_{TAG}", "microseconds spent by protocol handlers in the receive thread for {TAG} messages", tagStringList, "UNK") matched := false for _, version := range SupportedProtocolVersions { @@ -91,6 +93,9 @@ var networkMessageReceivedByTag *metrics.TagCounter var networkMessageSentTotal = metrics.MakeCounter(metrics.NetworkMessageSentTotal) var networkMessageSentByTag *metrics.TagCounter +var networkHandleMicrosByTag *metrics.TagCounter +var networkHandleCountByTag *metrics.TagCounter + var networkConnectionsDroppedTotal = metrics.MakeCounter(metrics.NetworkConnectionsDroppedTotal) var networkMessageQueueMicrosTotal = metrics.MakeCounter(metrics.MetricName{Name: "algod_network_message_sent_queue_micros_total", Description: "Total microseconds message spent waiting in queue to be sent"}) diff --git a/test/heapwatch/requirements.txt b/test/heapwatch/requirements.txt index 9743ce85c1..d4d68874dd 100644 --- a/test/heapwatch/requirements.txt +++ b/test/heapwatch/requirements.txt @@ -1,6 +1,6 @@ dash==2.15.0 dash-table==5.0.0 -Jinja2==3.1.3 +Jinja2==3.1.4 matplotlib==3.7.2 plotly==5.16.0 py-algorand-sdk==2.3.0 diff --git a/test/packages/test_release.sh b/test/packages/test_release.sh index 1a66184eb2..e92f52e459 100755 --- a/test/packages/test_release.sh +++ b/test/packages/test_release.sh @@ -15,11 +15,12 @@ then fi OS_LIST=( - centos:7 - quay.io/centos/centos:stream8 - fedora:38 + quay.io/centos/centos:stream9 + fedora:39 + fedora:40 ubuntu:20.04 ubuntu:22.04 + ubuntu:24.04 ) BUCKET=algorand-builds @@ -68,7 +69,8 @@ EOF then WITH_PACMAN=$(echo -e "${TOKENIZED//\{\{PACMAN\}\}/RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y curl}") else - WITH_PACMAN=$(echo -e "${TOKENIZED//\{\{PACMAN\}\}/RUN yum install -y curl}") + # fedora and centos already have curl installed. + WITH_PACMAN=$(echo -e "${TOKENIZED//\{\{PACMAN\}\}/}") fi echo -e "$BLUE_FG[$0]$END_FG_COLOR Testing $item..." diff --git a/test/scripts/e2e_client_runner.py b/test/scripts/e2e_client_runner.py index 3d5888696f..2ff7f876cc 100755 --- a/test/scripts/e2e_client_runner.py +++ b/test/scripts/e2e_client_runner.py @@ -106,7 +106,7 @@ def _script_thread_inner(runset, scriptname, timeout): # create a wallet for the test walletname = base64.b16encode(os.urandom(16)).decode() - winfo = kmd.create_wallet(walletname, '') + winfo = kmd.create_wallet(walletname, '', timeout=120) # 2 minute timeout handle = kmd.init_wallet_handle(winfo['id'], '') addr = kmd.generate_key(handle) diff --git a/test/scripts/e2e_subs/goal/goal.py b/test/scripts/e2e_subs/goal/goal.py index 57d8b0acb5..c68c8cdc79 100755 --- a/test/scripts/e2e_subs/goal/goal.py +++ b/test/scripts/e2e_subs/goal/goal.py @@ -121,8 +121,8 @@ def open_wallet(self, name): wallet = w assert wallet, f"No wallet named '{name}'" - self.handle = self.kmd.init_wallet_handle(wallet["id"], "") - keys = self.kmd.list_keys(self.handle) + self.handle = self.kmd.init_wallet_handle(wallet["id"], "", timeout=120) + keys = self.kmd.list_keys(self.handle, timeout=120) assert len(keys) == 1 self.account = keys[0] diff --git a/test/scripts/e2e_subs/htlc-teal-test.sh b/test/scripts/e2e_subs/htlc-teal-test.sh index d2b70c533d..617e51d5cc 100755 --- a/test/scripts/e2e_subs/htlc-teal-test.sh +++ b/test/scripts/e2e_subs/htlc-teal-test.sh @@ -46,8 +46,9 @@ ${gcmd} clerk send --fee=1000 --from-program ${TEMPDIR}/atomic.teal -a=0 -t=${ZE # Check balance BALANCEB=$(${gcmd} account balance -a ${ACCOUNTB} | awk '{ print $1 }') -if [ $BALANCEB -ne 9999000 ]; then - date "+htlc-teal-test FAIL wanted balance=9999000 but got ${BALANCEB} %Y%m%d_%H%M%S" +# Use >= 9999000 to account for rewards which may have accumulated +if [ $BALANCEB -lt 9999000 ]; then + date "+htlc-teal-test FAIL wanted balance>=9999000 but got ${BALANCEB} %Y%m%d_%H%M%S" false fi diff --git a/test/testdata/deployednettemplates/recipes/bootstrappedScenario/Makefile b/test/testdata/deployednettemplates/recipes/bootstrappedScenario/Makefile index f5db1ebbc1..4611e30ed2 100644 --- a/test/testdata/deployednettemplates/recipes/bootstrappedScenario/Makefile +++ b/test/testdata/deployednettemplates/recipes/bootstrappedScenario/Makefile @@ -2,7 +2,7 @@ PARAMS=-w 20 -R 8 -N 20 -n 20 --npn-algod-nodes 10 --node-template node.json --relay-template relay.json --non-participating-node-template nonPartNode.json --last-part-key-round 50000 FILEPARAMS=--rounds 1600 --ntxns 20000 --naccounts 30000000 --nassets 20000 --napps 20000 --wallet-name "wallet1" --bal 50000000 --bal 50000001 --deterministic -all: net.json genesis.json topology.json boostrappedFile.json +all: net.json genesis.json topology.json bootstrappedFile.json net.json: node.json nonPartNode.json ${GOPATH}/bin/netgoal Makefile netgoal generate -t net -r /tmp/wat -o net.json ${PARAMS} @@ -15,8 +15,8 @@ genesis.json: ${GOPATH}/bin/netgoal Makefile topology.json: gen_topology.py python3 gen_topology.py -boostrappedFile.json: ${GOPATH}/bin/netgoal Makefile - netgoal generate -t loadingFile -r /tmp/wat -o boostrappedFile.json ${FILEPARAMS} +bootstrappedFile.json: ${GOPATH}/bin/netgoal Makefile + netgoal generate -t loadingFile -r /tmp/wat -o bootstrappedFile.json ${FILEPARAMS} clean: rm -f net.json genesis.json diff --git a/test/testdata/deployednettemplates/recipes/bootstrappedScenario/recipe.json b/test/testdata/deployednettemplates/recipes/bootstrappedScenario/recipe.json index 766328dbb3..55805a6eb9 100644 --- a/test/testdata/deployednettemplates/recipes/bootstrappedScenario/recipe.json +++ b/test/testdata/deployednettemplates/recipes/bootstrappedScenario/recipe.json @@ -1,8 +1,8 @@ { - "GenesisFile":"genesis.json", - "NetworkFile":"net.json", - "ConfigFile": "../../configs/reference.json", - "HostTemplatesFile": "../../hosttemplates/hosttemplates.json", - "TopologyFile": "topology.json", - "BootstrappedFile": "boostrappedFile.json" + "GenesisFile": "genesis.json", + "NetworkFile": "net.json", + "ConfigFile": "../../configs/reference.json", + "HostTemplatesFile": "../../hosttemplates/hosttemplates.json", + "TopologyFile": "topology.json", + "BootstrappedFile": "bootstrappedFile.json" } diff --git a/test/testdata/deployednettemplates/recipes/scenario1s/Makefile b/test/testdata/deployednettemplates/recipes/scenario1s/Makefile index f4b1910906..ed8a70132e 100644 --- a/test/testdata/deployednettemplates/recipes/scenario1s/Makefile +++ b/test/testdata/deployednettemplates/recipes/scenario1s/Makefile @@ -1,7 +1,7 @@ # scenario1s is scenario1 but smaller, (100 nodes, 100 wallets) -> (20 nodes, 20 wallets), each algod gets single tenancy on a smaller ec2 instance PARAMS=-w 20 -R 8 -N 20 -n 20 --npn-algod-nodes 10 --node-template node.json --relay-template relay.json --non-participating-node-template nonPartNode.json -all: net.json genesis.json topology.json boostrappedFile.json +all: net.json genesis.json topology.json bootstrappedFile.json net.json: node.json nonPartNode.json ${GOPATH}/bin/netgoal Makefile netgoal generate -t net -r /tmp/wat -o net.json ${PARAMS} diff --git a/tools/block-generator/go.mod b/tools/block-generator/go.mod index 29bdbdb4e8..cfeb442668 100644 --- a/tools/block-generator/go.mod +++ b/tools/block-generator/go.mod @@ -125,12 +125,12 @@ require ( go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect golang.org/x/mod v0.15.0 // indirect - golang.org/x/net v0.21.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.18.0 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/tools/block-generator/go.sum b/tools/block-generator/go.sum index e34dae4485..dbd7cdeb72 100644 --- a/tools/block-generator/go.sum +++ b/tools/block-generator/go.sum @@ -541,8 +541,8 @@ golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= @@ -582,8 +582,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -629,8 +629,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/tools/network/cloudflare/createRecord.go b/tools/network/cloudflare/createRecord.go index efaa840575..d115e8b059 100644 --- a/tools/network/cloudflare/createRecord.go +++ b/tools/network/cloudflare/createRecord.go @@ -38,11 +38,9 @@ type createDNSRecord struct { // https://community.cloudflare.com/t/cloudflare-api-v4-srv-dns-creation-failure-in-php/25677/7 type createSRVRecord struct { Type string `json:"type"` + Name string `json:"name"` Data struct { - Name string `json:"name"` TTL uint `json:"ttl"` - Service string `json:"service"` - Proto string `json:"proto"` Weight uint `json:"weight"` Port uint `json:"port"` Priority uint `json:"priority"` @@ -90,10 +88,8 @@ func createSRVRecordRequest(zoneID string, authToken string, name string, servic requestJSON := createSRVRecord{ Type: "SRV", } - requestJSON.Data.Name = name + requestJSON.Name = service + "." + protocol + "." + name requestJSON.Data.TTL = ttl - requestJSON.Data.Service = service - requestJSON.Data.Proto = protocol requestJSON.Data.Weight = weight requestJSON.Data.Port = port requestJSON.Data.Priority = priority diff --git a/tools/network/cloudflare/updateRecord.go b/tools/network/cloudflare/updateRecord.go index 269c48f11a..7ad2b188f1 100644 --- a/tools/network/cloudflare/updateRecord.go +++ b/tools/network/cloudflare/updateRecord.go @@ -63,11 +63,9 @@ func updateSRVRecordRequest(zoneID string, authToken string, recordID string, na requestJSON := createSRVRecord{ Type: "SRV", + Name: fmt.Sprintf("%s.%s.%s", service, protocol, name), } - requestJSON.Data.Name = name requestJSON.Data.TTL = ttl - requestJSON.Data.Service = service - requestJSON.Data.Proto = protocol requestJSON.Data.Weight = weight requestJSON.Data.Port = port requestJSON.Data.Priority = priority