diff --git a/accounting/rewind.go b/accounting/rewind.go deleted file mode 100644 index cfc6cdcf7..000000000 --- a/accounting/rewind.go +++ /dev/null @@ -1,188 +0,0 @@ -package accounting - -import ( - "context" - "fmt" - - models "github.com/algorand/indexer/v3/api/generated/v2" - "github.com/algorand/indexer/v3/idb" - "github.com/algorand/indexer/v3/types" - - sdk "github.com/algorand/go-algorand-sdk/v2/types" -) - -// ConsistencyError is returned when the database returns inconsistent (stale) results. -type ConsistencyError struct { - msg string -} - -func (e ConsistencyError) Error() string { - return e.msg -} - -func assetUpdate(account *models.Account, assetid uint64, add, sub uint64) { - if account.Assets == nil { - account.Assets = new([]models.AssetHolding) - } - assets := *account.Assets - for i, ah := range assets { - if ah.AssetId == assetid { - ah.Amount += add - ah.Amount -= sub - assets[i] = ah - // found and updated asset, done - return - } - } - // add asset to list - assets = append(assets, models.AssetHolding{ - Amount: add - sub, - AssetId: assetid, - //Creator: base32 addr string of asset creator, TODO - //IsFrozen: leave nil? // TODO: on close record frozen state for rewind - }) - *account.Assets = assets -} - -// SpecialAccountRewindError indicates that an attempt was made to rewind one of the special accounts. -type SpecialAccountRewindError struct { - account string -} - -// MakeSpecialAccountRewindError helper to initialize a SpecialAccountRewindError. -func MakeSpecialAccountRewindError(account string) *SpecialAccountRewindError { - return &SpecialAccountRewindError{account: account} -} - -// Error is part of the error interface. -func (sare *SpecialAccountRewindError) Error() string { - return fmt.Sprintf("unable to rewind the %s", sare.account) -} - -var specialAccounts *types.SpecialAddresses - -// AccountAtRound queries the idb.IndexerDb object for transactions and rewinds most fields of the account back to -// their values at the requested round. -// `round` must be <= `account.Round` -func AccountAtRound(ctx context.Context, account models.Account, round uint64, db idb.IndexerDb) (acct models.Account, err error) { - // Make sure special accounts cache has been initialized. - if specialAccounts == nil { - var accounts types.SpecialAddresses - accounts, err = db.GetSpecialAccounts(ctx) - if err != nil { - return models.Account{}, fmt.Errorf("unable to get special accounts: %v", err) - } - specialAccounts = &accounts - } - - acct = account - var addr sdk.Address - addr, err = sdk.DecodeAddress(account.Address) - if err != nil { - return - } - - // ensure that the don't attempt to rewind a special account. - if specialAccounts.FeeSink == addr { - err = MakeSpecialAccountRewindError("FeeSink") - return - } - if specialAccounts.RewardsPool == addr { - err = MakeSpecialAccountRewindError("RewardsPool") - return - } - - // Get transactions and rewind account. - tf := idb.TransactionFilter{ - Address: addr[:], - MinRound: round + 1, - MaxRound: account.Round, - } - ctx2, cf := context.WithCancel(ctx) - // In case of a panic before the next defer, call cf() here. - defer cf() - txns, r := db.Transactions(ctx2, tf) - // In case of an error, make sure the context is cancelled, and the channel is cleaned up. - defer func() { - cf() - for range txns { - } - }() - if r < account.Round { - err = ConsistencyError{fmt.Sprintf("queried round r: %d < account.Round: %d", r, account.Round)} - return - } - txcount := 0 - for txnrow := range txns { - if txnrow.Error != nil { - err = txnrow.Error - return - } - txcount++ - stxn := txnrow.Txn - if stxn == nil { - return models.Account{}, - fmt.Errorf("rewinding past inner transactions is not supported") - } - if addr == stxn.Txn.Sender { - acct.AmountWithoutPendingRewards += uint64(stxn.Txn.Fee) - acct.AmountWithoutPendingRewards -= uint64(stxn.SenderRewards) - } - switch stxn.Txn.Type { - case sdk.PaymentTx: - if addr == stxn.Txn.Sender { - acct.AmountWithoutPendingRewards += uint64(stxn.Txn.Amount) - } - if addr == stxn.Txn.Receiver { - acct.AmountWithoutPendingRewards -= uint64(stxn.Txn.Amount) - acct.AmountWithoutPendingRewards -= uint64(stxn.ReceiverRewards) - } - if addr == stxn.Txn.CloseRemainderTo { - // unwind receiving a close-to - acct.AmountWithoutPendingRewards -= uint64(stxn.ClosingAmount) - acct.AmountWithoutPendingRewards -= uint64(stxn.CloseRewards) - } else if !stxn.Txn.CloseRemainderTo.IsZero() { - // unwind sending a close-to - acct.AmountWithoutPendingRewards += uint64(stxn.ClosingAmount) - } - case sdk.KeyRegistrationTx: - // TODO: keyreg does not rewind. workaround: query for txns on an account with typeenum=2 to find previous values it was set to. - case sdk.AssetConfigTx: - if stxn.Txn.ConfigAsset == 0 { - // create asset, unwind the application of the value - assetUpdate(&acct, txnrow.AssetID, 0, stxn.Txn.AssetParams.Total) - } - case sdk.AssetTransferTx: - if addr == stxn.Txn.AssetSender || addr == stxn.Txn.Sender { - assetUpdate(&acct, uint64(stxn.Txn.XferAsset), stxn.Txn.AssetAmount+txnrow.Extra.AssetCloseAmount, 0) - } - if addr == stxn.Txn.AssetReceiver { - assetUpdate(&acct, uint64(stxn.Txn.XferAsset), 0, stxn.Txn.AssetAmount) - } - if addr == stxn.Txn.AssetCloseTo { - assetUpdate(&acct, uint64(stxn.Txn.XferAsset), 0, txnrow.Extra.AssetCloseAmount) - } - case sdk.AssetFreezeTx: - default: - err = fmt.Errorf("%s[%d,%d]: rewinding past txn type %s is not currently supported", account.Address, txnrow.Round, txnrow.Intra, stxn.Txn.Type) - return - } - } - - acct.Round = round - - // Due to accounts being closed and re-opened, we cannot always rewind Rewards. So clear it out. - acct.Rewards = 0 - - // Computing pending rewards is not supported. - acct.PendingRewards = 0 - acct.Amount = acct.AmountWithoutPendingRewards - - // MinBalance is not supported. - acct.MinBalance = 0 - - // TODO: Clear out the closed-at field as well. Like Rewards we cannot know this value for all accounts. - //acct.ClosedAt = 0 - - return -} diff --git a/accounting/rewind_test.go b/accounting/rewind_test.go deleted file mode 100644 index caa77a960..000000000 --- a/accounting/rewind_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package accounting - -import ( - "context" - "errors" - "testing" - - sdk "github.com/algorand/go-algorand-sdk/v2/types" - "github.com/algorand/indexer/v3/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - models "github.com/algorand/indexer/v3/api/generated/v2" - "github.com/algorand/indexer/v3/idb" - "github.com/algorand/indexer/v3/idb/mocks" -) - -func TestBasic(t *testing.T) { - var a sdk.Address - a[0] = 'a' - - account := models.Account{ - Address: a.String(), - Amount: 100, - AmountWithoutPendingRewards: 100, - Round: 8, - } - - txnRow := idb.TxnRow{ - Round: 7, - Txn: &sdk.SignedTxnWithAD{ - SignedTxn: sdk.SignedTxn{ - Txn: sdk.Transaction{ - Type: sdk.PaymentTx, - PaymentTxnFields: sdk.PaymentTxnFields{ - Receiver: a, - Amount: sdk.MicroAlgos(2), - }, - }, - }, - }, - } - - ch := make(chan idb.TxnRow, 1) - ch <- txnRow - close(ch) - var outCh <-chan idb.TxnRow = ch - - db := &mocks.IndexerDb{} - db.On("GetSpecialAccounts", mock.Anything).Return(types.SpecialAddresses{}, nil) - db.On("Transactions", mock.Anything, mock.Anything).Return(outCh, uint64(8)) - - account, err := AccountAtRound(context.Background(), account, 6, db) - assert.NoError(t, err) - - assert.Equal(t, uint64(98), account.Amount) -} - -// Test that when idb.Transactions() returns stale data the first time, we return an error. -func TestStaleTransactions1(t *testing.T) { - var a sdk.Address - a[0] = 'a' - - account := models.Account{ - Address: a.String(), - Round: 8, - } - - ch := make(chan idb.TxnRow) - var outCh <-chan idb.TxnRow = ch - close(ch) - - db := &mocks.IndexerDb{} - db.On("GetSpecialAccounts", mock.Anything).Return(types.SpecialAddresses{}, nil) - db.On("Transactions", mock.Anything, mock.Anything).Return(outCh, uint64(7)).Once() - - account, err := AccountAtRound(context.Background(), account, 6, db) - assert.True(t, errors.As(err, &ConsistencyError{}), "err: %v", err) -} diff --git a/api/error_messages.go b/api/error_messages.go index 28548153a..71401b0d4 100644 --- a/api/error_messages.go +++ b/api/error_messages.go @@ -37,8 +37,7 @@ const ( errMultipleApplications = "multiple applications found for this id, please contact us, this shouldn't happen" ErrMultipleBoxes = "multiple application boxes found for this app id and box name, please contact us, this shouldn't happen" ErrFailedLookingUpBoxes = "failed while looking up application boxes" - errMultiAcctRewind = "multiple accounts rewind is not supported by this server" - errRewindingAccount = "error while rewinding account" + errRewindingAccountNotSupported = "rewinding account is no longer supported, please remove the `round=` query parameter and try again" errLookingUpBlockForRound = "error while looking up block for round" errTransactionSearch = "error while searching for transaction" errZeroAddressCloseRemainderToRole = "searching transactions by zero address with close address role is not supported" diff --git a/api/generated/v2/routes.go b/api/generated/v2/routes.go index 06c51c779..67a7e76c7 100644 --- a/api/generated/v2/routes.go +++ b/api/generated/v2/routes.go @@ -1219,232 +1219,231 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "FV0smMrszAjzk5PHk4//PwAA//9SW782m4ABAA==", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/api/generated/v2/types.go b/api/generated/v2/types.go index 92ade58e5..b234ab79c 100644 --- a/api/generated/v2/types.go +++ b/api/generated/v2/types.go @@ -1502,7 +1502,7 @@ type SearchForAccountsParams struct { // AuthAddr Include accounts configured to use this spending key. AuthAddr *string `form:"auth-addr,omitempty" json:"auth-addr,omitempty"` - // Round Include results for the specified round. For performance reasons, this parameter may be disabled on some configurations. Using application-id or asset-id filters will return both creator and opt-in accounts. Filtering by include-all will return creator and opt-in accounts for deleted assets and accounts. Non-opt-in managers are not included in the results when asset-id is used. + // Round Deprecated and disallowed. This parameter used to include results for a specified round. Requests with this parameter set are now rejected. Round *uint64 `form:"round,omitempty" json:"round,omitempty"` // ApplicationId Application ID @@ -1514,7 +1514,7 @@ type SearchForAccountsParamsExclude string // LookupAccountByIDParams defines parameters for LookupAccountByID. type LookupAccountByIDParams struct { - // Round Include results for the specified round. + // Round Deprecated and disallowed. This parameter used to include results for a specified round. Requests with this parameter set are now rejected. Round *uint64 `form:"round,omitempty" json:"round,omitempty"` // IncludeAll Include all items including closed accounts, deleted applications, destroyed assets, opted-out asset holdings, and closed-out application localstates. @@ -1838,7 +1838,7 @@ type SearchForTransactionsParams struct { // * lsig - LogicSig SigType *SearchForTransactionsParamsSigType `form:"sig-type,omitempty" json:"sig-type,omitempty"` - // GroupId Lookup transactions by group ID. + // GroupId Lookup transactions by group ID. This field must be base64-encoded, and afterwards, base64 characters like +, / and = must be URL-encoded GroupId *string `form:"group-id,omitempty" json:"group-id,omitempty"` // Txid Lookup the specific transaction by ID. diff --git a/api/handlers.go b/api/handlers.go index ca1333535..78f15ef7c 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -17,7 +17,6 @@ import ( log "github.com/sirupsen/logrus" "github.com/algorand/avm-abi/apps" - "github.com/algorand/indexer/v3/accounting" "github.com/algorand/indexer/v3/api/generated/common" "github.com/algorand/indexer/v3/api/generated/v2" "github.com/algorand/indexer/v3/idb" @@ -29,13 +28,6 @@ import ( // ServerImplementation implements the handler interface used by the generated route definitions. type ServerImplementation struct { - // EnableAddressSearchRoundRewind is allows configuring whether or not the - // 'accounts' endpoint allows specifying a round number. This is done for - // performance reasons, because requesting many accounts at a particular - // round could put a lot of strain on the system (especially if the round - // is from long ago). - EnableAddressSearchRoundRewind bool - db idb.IndexerDb dataError func() error @@ -196,8 +188,9 @@ func (si *ServerImplementation) LookupAccountByID(ctx echo.Context, accountID st if err := si.verifyHandler("LookupAccountByID", ctx); err != nil { return badRequest(ctx, err.Error()) } - if params.Round != nil && uint64(*params.Round) > math.MaxInt64 { - return notFound(ctx, errValueExceedingInt64) + // The Round parameter is no longer supported (as it was used to request account rewinding) + if params.Round != nil { + return badRequest(ctx, errRewindingAccountNotSupported) } addr, decodeErrors := decodeAddress(&accountID, "account-id", make([]string, 0)) @@ -227,7 +220,7 @@ func (si *ServerImplementation) LookupAccountByID(ctx echo.Context, accountID st } } - accounts, round, err := si.fetchAccounts(ctx.Request().Context(), options, params.Round) + accounts, round, err := si.fetchAccounts(ctx.Request().Context(), options) if err != nil { var maxErr idb.MaxAPIResourcesPerAccountError if errors.As(err, &maxErr) { @@ -385,13 +378,13 @@ func (si *ServerImplementation) SearchForAccounts(ctx echo.Context, params gener return badRequest(ctx, err.Error()) } if (params.AssetId != nil && uint64(*params.AssetId) > math.MaxInt64) || - (params.ApplicationId != nil && uint64(*params.ApplicationId) > math.MaxInt64) || - (params.Round != nil && uint64(*params.Round) > math.MaxInt64) { + (params.ApplicationId != nil && uint64(*params.ApplicationId) > math.MaxInt64) { return notFound(ctx, errValueExceedingInt64) } - if !si.EnableAddressSearchRoundRewind && params.Round != nil { - return badRequest(ctx, errMultiAcctRewind) + // The Round parameter is no longer supported (as it was used to request account rewinding) + if params.Round != nil { + return badRequest(ctx, errRewindingAccountNotSupported) } spendingAddr, decodeErrors := decodeAddress(params.AuthAddr, "account-id", make([]string, 0)) @@ -440,7 +433,7 @@ func (si *ServerImplementation) SearchForAccounts(ctx echo.Context, params gener options.GreaterThanAddress = addr[:] } - accounts, round, err := si.fetchAccounts(ctx.Request().Context(), options, params.Round) + accounts, round, err := si.fetchAccounts(ctx.Request().Context(), options) if err != nil { var maxErr idb.MaxAPIResourcesPerAccountError if errors.As(err, &maxErr) { @@ -1391,7 +1384,7 @@ func (si *ServerImplementation) fetchBlock(ctx context.Context, round uint64, op // fetchAccounts queries for accounts and converts them into generated.Account // objects, optionally rewinding their value back to a particular round. -func (si *ServerImplementation) fetchAccounts(ctx context.Context, options idb.AccountQueryOptions, atRound *uint64) ([]generated.Account, uint64 /*round*/, error) { +func (si *ServerImplementation) fetchAccounts(ctx context.Context, options idb.AccountQueryOptions) ([]generated.Account, uint64 /*round*/, error) { var round uint64 accounts := make([]generated.Account, 0) err := callWithTimeout(ctx, si.log, si.timeout, func(ctx context.Context) error { @@ -1404,33 +1397,12 @@ func (si *ServerImplementation) fetchAccounts(ctx context.Context, options idb.A } }() - if (atRound != nil) && (*atRound > round) { - return fmt.Errorf("%s: the requested round %d > the current round %d", - errRewindingAccount, *atRound, round) - } - for row := range accountchan { if row.Error != nil { return row.Error } - // Compute for a given round if requested. - var account generated.Account - if atRound != nil { - acct, err := accounting.AccountAtRound(ctx, row.Account, *atRound, si.db) - if err != nil { - // Ignore the error if this is an account search rewind error - _, isSpecialAccountRewindError := err.(*accounting.SpecialAccountRewindError) - if len(options.EqualToAddress) != 0 || !isSpecialAccountRewindError { - return fmt.Errorf("%s: %v", errRewindingAccount, err) - } - // If we didn't return, continue to the next account - continue - } - account = acct - } else { - account = row.Account - } + account := row.Account // match the algod equivalent which includes pending rewards account.Rewards += account.PendingRewards diff --git a/api/handlers_test.go b/api/handlers_test.go index 18c152698..c5b2e40da 100644 --- a/api/handlers_test.go +++ b/api/handlers_test.go @@ -9,7 +9,6 @@ import ( "math" "net/http" "net/http/httptest" - "strings" "testing" "time" @@ -664,7 +663,6 @@ func TestFetchTransactions(t *testing.T) { // Setup the mocked responses mockIndexer := &mocks.IndexerDb{} si := testServerImplementation(mockIndexer) - si.EnableAddressSearchRoundRewind = true si.timeout = 1 * time.Second roundTime := time.Now() @@ -740,26 +738,9 @@ func TestFetchTransactions(t *testing.T) { } } -func TestFetchAccountsRewindRoundTooLarge(t *testing.T) { - ch := make(chan idb.AccountRow) - close(ch) - var outCh <-chan idb.AccountRow = ch - - db := &mocks.IndexerDb{} - db.On("GetAccounts", mock.Anything, mock.Anything).Return(outCh, uint64(7)).Once() - - si := testServerImplementation(db) - si.EnableAddressSearchRoundRewind = true - atRound := uint64(8) - _, _, err := si.fetchAccounts(context.Background(), idb.AccountQueryOptions{}, &atRound) - assert.Error(t, err) - assert.True(t, strings.HasPrefix(err.Error(), errRewindingAccount), err.Error()) -} - func TestLookupApplicationLogsByID(t *testing.T) { mockIndexer := &mocks.IndexerDb{} si := testServerImplementation(mockIndexer) - si.EnableAddressSearchRoundRewind = true txnBytes := loadResourceFileOrPanic("test_resources/app_call_logs.txn") var stxn sdk.SignedTxnWithAD @@ -1119,13 +1100,6 @@ func TestBigNumbers(t *testing.T) { return si.SearchForApplications(ctx, generated.SearchForApplicationsParams{ApplicationId: uint64Ptr(uint64(math.MaxInt64 + 1))}) }, }, - { - name: "SearchForAccountInvalidRound", - errString: errValueExceedingInt64, - callHandler: func(ctx echo.Context, si ServerImplementation) error { - return si.SearchForAccounts(ctx, generated.SearchForAccountsParams{Round: uint64Ptr(uint64(math.MaxInt64 + 1))}) - }, - }, { name: "SearchForAccountInvalidAppID", errString: errValueExceedingInt64, @@ -1140,15 +1114,6 @@ func TestBigNumbers(t *testing.T) { return si.SearchForAccounts(ctx, generated.SearchForAccountsParams{AssetId: uint64Ptr(uint64(math.MaxInt64 + 1))}) }, }, - { - name: "LookupAccountByID", - errString: errValueExceedingInt64, - callHandler: func(ctx echo.Context, si ServerImplementation) error { - return si.LookupAccountByID(ctx, - "PBH2JQNVP5SBXLTOWNHHPGU6FUMBVS4ZDITPK5RA5FG2YIIFS6UYEMFM2Y", - generated.LookupAccountByIDParams{Round: uint64Ptr(uint64(math.MaxInt64 + 1))}) - }, - }, { name: "SearchForAssets", errString: errValueExceedingInt64, @@ -1230,6 +1195,53 @@ func TestBigNumbers(t *testing.T) { } } +func TestRewindRoundParameterRejected(t *testing.T) { + testcases := []struct { + name string + errString string + callHandler func(ctx echo.Context, si ServerImplementation) error + }{ + { + name: "SearchForAccountInvalidRound", + errString: errRewindingAccountNotSupported, + callHandler: func(ctx echo.Context, si ServerImplementation) error { + return si.SearchForAccounts(ctx, generated.SearchForAccountsParams{Round: uint64Ptr(uint64(math.MaxInt64 + 1))}) + }, + }, + { + name: "LookupAccountByID", + errString: errRewindingAccountNotSupported, + callHandler: func(ctx echo.Context, si ServerImplementation) error { + return si.LookupAccountByID(ctx, + "PBH2JQNVP5SBXLTOWNHHPGU6FUMBVS4ZDITPK5RA5FG2YIIFS6UYEMFM2Y", + generated.LookupAccountByIDParams{Round: uint64Ptr(uint64(math.MaxInt64 + 1))}) + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + + // Make a mock indexer. + mockIndexer := &mocks.IndexerDb{} + + si := testServerImplementation(mockIndexer) + + // Setup context... + e := echo.New() + req := httptest.NewRequest(http.MethodGet, "/", nil) + rec1 := httptest.NewRecorder() + c := e.NewContext(req, rec1) + + // call handler + tc.callHandler(c, *si) + assert.Equal(t, http.StatusBadRequest, rec1.Code) + bodyStr := rec1.Body.String() + require.Contains(t, bodyStr, tc.errString) + }) + } +} + func TestFetchBlock(t *testing.T) { testcases := []struct { name string diff --git a/api/indexer.oas2.json b/api/indexer.oas2.json index e663bc2de..2deec1b49 100644 --- a/api/indexer.oas2.json +++ b/api/indexer.oas2.json @@ -80,7 +80,7 @@ }, { "type": "integer", - "description": "Include results for the specified round. For performance reasons, this parameter may be disabled on some configurations. Using application-id or asset-id filters will return both creator and opt-in accounts. Filtering by include-all will return creator and opt-in accounts for deleted assets and accounts. Non-opt-in managers are not included in the results when asset-id is used.", + "description": "Deprecated and disallowed. This parameter used to include results for a specified round. Requests with this parameter set are now rejected.", "name": "round", "in": "query" }, @@ -119,7 +119,10 @@ "$ref": "#/parameters/account-id" }, { - "$ref": "#/parameters/round" + "type": "integer", + "description": "Deprecated and disallowed. This parameter used to include results for a specified round. Requests with this parameter set are now rejected.", + "name": "round", + "in": "query" }, { "$ref": "#/parameters/include-all" diff --git a/api/indexer.oas3.yml b/api/indexer.oas3.yml index d3b6d5ccd..63382e00a 100644 --- a/api/indexer.oas3.yml +++ b/api/indexer.oas3.yml @@ -2490,7 +2490,7 @@ "x-algorand-format": "Address" }, { - "description": "Include results for the specified round. For performance reasons, this parameter may be disabled on some configurations. Using application-id or asset-id filters will return both creator and opt-in accounts. Filtering by include-all will return creator and opt-in accounts for deleted assets and accounts. Non-opt-in managers are not included in the results when asset-id is used.", + "description": "Deprecated and disallowed. This parameter used to include results for a specified round. Requests with this parameter set are now rejected.", "in": "query", "name": "round", "schema": { @@ -2602,7 +2602,7 @@ } }, { - "description": "Include results for the specified round.", + "description": "Deprecated and disallowed. This parameter used to include results for a specified round. Requests with this parameter set are now rejected.", "in": "query", "name": "round", "schema": { diff --git a/api/server.go b/api/server.go index 94d19ba32..0f4d402d5 100644 --- a/api/server.go +++ b/api/server.go @@ -23,9 +23,6 @@ type ExtraOptions struct { // Tokens are the access tokens which can access the API. Tokens []string - // DeveloperMode turns on features like AddressSearchRoundRewind - DeveloperMode bool - // MetricsEndpoint turns on the /metrics endpoint for prometheus metrics. MetricsEndpoint bool @@ -133,13 +130,12 @@ func Serve(ctx context.Context, serveAddr string, db idb.IndexerDb, dataError fu } api := ServerImplementation{ - EnableAddressSearchRoundRewind: options.DeveloperMode, - db: db, - dataError: dataError, - timeout: options.handlerTimeout(), - log: log, - disabledParams: disabledMap, - opts: options, + db: db, + dataError: dataError, + timeout: options.handlerTimeout(), + log: log, + disabledParams: disabledMap, + opts: options, } generated.RegisterHandlers(e, &api, middleware...) diff --git a/cmd/algorand-indexer/daemon.go b/cmd/algorand-indexer/daemon.go index d724601ee..ce73ea764 100644 --- a/cmd/algorand-indexer/daemon.go +++ b/cmd/algorand-indexer/daemon.go @@ -70,7 +70,7 @@ func DaemonCmd() *cobra.Command { cfg.flags = daemonCmd.Flags() cfg.flags.StringVarP(&cfg.daemonServerAddr, "server", "S", ":8980", "host:port to serve API on (default :8980)") cfg.flags.StringVarP(&cfg.tokenString, "token", "t", "", "an optional auth token, when set REST calls must use this token in a bearer format, or in a 'X-Indexer-API-Token' header") - cfg.flags.BoolVarP(&cfg.developerMode, "dev-mode", "", false, "allow performance intensive operations like searching for accounts at a particular round") + cfg.flags.BoolVarP(&cfg.developerMode, "dev-mode", "", false, "has no effect currently, reserved for future performance intensive operations") cfg.flags.StringVarP(&cfg.metricsMode, "metrics-mode", "", "OFF", "configure the /metrics endpoint to [ON, OFF, VERBOSE]") cfg.flags.DurationVarP(&cfg.writeTimeout, "write-timeout", "", 30*time.Second, "set the maximum duration to wait before timing out writes to a http response, breaking connection") cfg.flags.DurationVarP(&cfg.readTimeout, "read-timeout", "", 5*time.Second, "set the maximum duration for reading the entire request") @@ -300,7 +300,6 @@ func runDaemon(daemonConfig *daemonConfig) error { // makeOptions converts CLI options to server options func makeOptions(daemonConfig *daemonConfig) (options api.ExtraOptions) { - options.DeveloperMode = daemonConfig.developerMode if daemonConfig.tokenString != "" { options.Tokens = append(options.Tokens, daemonConfig.tokenString) } diff --git a/cmd/idbtest/idbtest.go b/cmd/idbtest/idbtest.go index e6a62554e..b2f6c3df1 100644 --- a/cmd/idbtest/idbtest.go +++ b/cmd/idbtest/idbtest.go @@ -9,7 +9,6 @@ import ( "os" "time" - "github.com/algorand/indexer/v3/accounting" models "github.com/algorand/indexer/v3/api/generated/v2" "github.com/algorand/indexer/v3/idb" _ "github.com/algorand/indexer/v3/idb/postgres" @@ -160,9 +159,6 @@ func main() { MaxRound: account.Round, } printTxnQuery(db, tf) - raccount, err := accounting.AccountAtRound(context.Background(), account, round, db) - maybeFail(err, "AccountAtRound, %v", err) - fmt.Printf("raccount %s\n", string(ajson.Encode(raccount))) } if txntest {