From da03e64a5f52434f4f78d5936fa29fe53c05480c Mon Sep 17 00:00:00 2001 From: Gary Malouf <982483+gmalouf@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:49:13 -0400 Subject: [PATCH] Remove account rewind support. --- accounting/rewind.go | 188 -------------- accounting/rewind_test.go | 79 ------ api/error_messages.go | 2 - api/generated/v2/routes.go | 460 ++++++++++++++++----------------- api/generated/v2/types.go | 6 - api/handlers.go | 50 +--- api/handlers_test.go | 35 --- api/indexer.oas2.json | 10 - api/indexer.oas3.yml | 16 -- api/server.go | 16 +- cmd/algorand-indexer/daemon.go | 3 - cmd/idbtest/idbtest.go | 20 -- 12 files changed, 234 insertions(+), 651 deletions(-) delete mode 100644 accounting/rewind.go delete mode 100644 accounting/rewind_test.go 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 d9c339ada..b4514801a 100644 --- a/api/error_messages.go +++ b/api/error_messages.go @@ -36,8 +36,6 @@ 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" 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 14159f619..dbdab5522 100644 --- a/api/generated/v2/routes.go +++ b/api/generated/v2/routes.go @@ -146,13 +146,6 @@ func (w *ServerInterfaceWrapper) SearchForAccounts(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter auth-addr: %s", err)) } - // ------------- Optional query parameter "round" ------------- - - err = runtime.BindQueryParameter("form", true, false, "round", ctx.QueryParams(), ¶ms.Round) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter round: %s", err)) - } - // ------------- Optional query parameter "application-id" ------------- err = runtime.BindQueryParameter("form", true, false, "application-id", ctx.QueryParams(), ¶ms.ApplicationId) @@ -178,13 +171,6 @@ func (w *ServerInterfaceWrapper) LookupAccountByID(ctx echo.Context) error { // Parameter object where we will unmarshal all parameters from the context var params LookupAccountByIDParams - // ------------- Optional query parameter "round" ------------- - - err = runtime.BindQueryParameter("form", true, false, "round", ctx.QueryParams(), ¶ms.Round) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter round: %s", err)) - } - // ------------- Optional query parameter "include-all" ------------- err = runtime.BindQueryParameter("form", true, false, "include-all", ctx.QueryParams(), ¶ms.IncludeAll) @@ -1212,230 +1198,228 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+y9e3MbN5Yo/lVQ/G2V7fzYkuM8akdVqS0/xjeusTMu28nsrpV7B+wGSYyaQAdAS2Ry", - "/d1v4RwAje5Gk02JkuUN/7LFxuMAODg47/PHJJerSgomjJ6c/TGpqKIrZpiCv2iey1qYjBf2r4LpXPHK", - "cCkmZ/4b0UZxsZhMJ9z+WlGznEwngq5Y08b2n04U+63mihWTM6NqNp3ofMlW1A5sNpVt7Ub69Gk6oUWh", - "mNb9Wf8uyg3hIi/rghGjqNA0t580ueJmScySa+I6Ey6IFIzIOTHLVmMy56ws9IkH+reaqU0EtZt8GMTp", - "ZJ3RciEVFUU2l2pFzeRs8tT1+7Tzs5shU7Jk/TU+l6sZF8yviIUFhcMhRpKCzaHRkhpiobPr9A2NJJpR", - "lS/JXKody0Qg4rUyUa8mZx8nmomCKTi5nPFL+O9cMfY7ywxVC2Ymv05TZzc3TGWGrxJLe+VOTjFdl0YT", - "aAtrXPBLJojtdULe1NqQGSNUkHcvn5NvvvnmLwS30bDCIdzgqprZ4zWFUyioYf7zmEN99/I5zP/eLXBs", - "K1pVJc+pXXfy+jxtvpNXL4YW0x4kgZBcGLZgCjdea5a+q0/tly3T+I67JqjNMrNoM3yw7sZrkksx54ta", - "scJiY60Z3k1dMVFwsSAXbDN4hGGa27uBMzaXio3EUmx8UDSN5/+seDqT6wxh6iENmck1sd8sJV1IWmZU", - "LWCF5AETubTneHZJy5o9OCEvpSJcGD11Z81cQy7M2ddPvvnWNVH0isw2hvXazb7/9uzpDz+4ZpXiwtBZ", - "ydw29ppro86WrCyl6+CIWX9c++HsP//rv09OTh4MHQb8s98DlddKMZFvsoViFCjOkor+Hr5zGKSXsi4L", - "sqSXgC50BU+n60tsX7wesJsn5A3PlXxaLqQm1CFewea0Lg3xE5NalJbU29Hc9SVck0rJS16wYmrP7GrJ", - "8yXJqdsQaEeueFlarK01K4Y2JL26HdQhdLJwXWs/YEH3dzOade3YCbYG+tFf/l/XjkoWBbc/0ZJww1aa", - "6DpfEqodVEtZFoj00QNASpnTkhTUUKKNtIR1LpXjeJDqTl3/hokjORxgQWabbktRtEbf3cfuD1tXpbQr", - "m9NSs/R++dXHmwSrjHkLWpYT92JZRstNmYUfaFXpDFacaUMNi9tUlW0hpGAJBiT8QJWiG/u3NhvLZQFp", - "nTSnk+Wl1CwzcgcD5nkq2LCIZYp3bC92jHxYMgKT2w/IigJmC0uly3JDjDsAixDEM19TwudkI2tyBVen", - "5BfQ363G4vSK2MOHI2txipaaDSF3bzMSqD2TsmRUAGovGS2YyqQoN/19+xE+EvuRzEu6OCH/WDJ3me3b", - "b6FDcKZEMVMrYbGslPkFKSTTREhj+QZDueiy7HoA/hieHaA7qSGzqDfMv5T+SmJzy6rA3hSBtZmSgpUM", - "zqe5P/CrNkpu4NwsFk+JrCy+ytr077Uo3LD4uXvNAecHBZR4JTsWXfIVN/3lvqFrvqpXRNSrmT2xeeB1", - "jHRHA3iqGMkB3WYtolXRBdOEWVaIo3QF89hDtmeoGM2XwwQVYdpBQ1d0nSlZi2KEEGGIVDGTpiuW8zln", - "BQmjDMHSTLMLHi72g6cRbSJw/CCD4IRZdoAj2DpxrJay2C9wQNGpnpCf3bMHX428YCK8jkjnGakUu+Sy", - "1qHTELdkp97OHQlpWFYpNufrPpDv3XZY4oZt3Nu8cvy0IwGsII4O2OGQUA7CFE24r9Awo5p9/+0Qx9x8", - "VeyCbZLvRRcBcDlBS7G0X7Dv9lWEGXZc6pF4iOxBjH9bcW8U3kGjDMlGgr2zXx1RSWuEWv1HsNzx3KiP", - "yG6kG8Ix/Ms8tBWdmW5PDNV8keGIvVvCFx8sGzHnJbAY/7KXw59sre271D5bz3RovhDU1IqdnYuv7F8k", - "I+8NFQVVhf1lhT+9qUvD3/OF/anEn17LBc/f88XQpnhYk7oi6LbCf+x4ad2QWYflpqbwn1MzVNQ2vGAb", - "xewcNJ/DP+s5IBKdq9+RbYQn0VTzIQBS+pHXUl7UVbyheUtfONuQVy+GkAWG3EYPgXboSgrNAGufIiPx", - "zv1mf7Ikjwmg6BEvcPovLUGIasaulKyYMpzF+ln7339TbD45m/x/p40+9xS76VM34SQIaWboKcMLTI0j", - "YUi6HFFDZmBV1Qaf9hR1CNf5Y4CtO2dzLHL2L5Yb3KA2GA/ZqjKbRxZgB7s+3G7plkAyct+6QsUt7iM+", - "7hk80v2Rf9ZO8KvoggtY+JRcWTZ7RS8sVaBCmiVTxJ4F08Y/80j+8OUPimXHKzhZ4WSSujGJM9U3PtTm", - "1F5bdvc9sLuHOOKO2LjHWadAOp58OPnexh4SBRYHOvutGvfz84+0qnixPj//tSVxcVGwdfo8bvWwS7nI", - "Cmro9XB08cJ2TSDofcahtjXjUAh0WOTZ4xTu9kU91HYd+LJdi8YeKWviVtycqGrNzDNaUpEf5DmduaFG", - "n/AbLjgA8SOquo7H7I85bOUhjtjt7kEuMmrcR1/h4+Gm7nCwY9z4aA91pKMO8o4lQpjyEJv0uRD/iPGH", - "xfhnpcwvrnWW244KRt01s1wffl65Ts36TK4JF6j9c5zPM7lm91XkmVnYRl+LZ3L9wk0p1ZctjeDCx2Dw", - "M+cXo8HIK+KdtUv+q1JSHeB0vWzYgWc6WTGt6YKlbS/xGn3DMYvyAMOBMLsE0FD/yGhpls+X7BYuajT2", - "juv6oVHGHmBjb5VkR3rjXeuPVrVD2GsPuyeVjabR93337g+5aG35eILYOtMuORx/xnq/Q/7k7Q+xgSHh", - "0ud8tqPnyJ4UdW6NaB48F+fiBZtzAdb+s3Nh6dDpjGqe69NaM+UEzJOFJGfEDfmCGnouJtPuAzVkqwMX", - "LAdNVc9KnpMLtkmdAvqGJUaQhpaRA0PkJubMxo0Foo9nOGpm0UHWJnNeqZliV1QVCXh1MFrDyOivtm3W", - "KXFjo23deb268dO43/N56vvcb3UH46Ltr2UP8idpnAWaXhFEJFJrpsk/V7T6yIX5lWTn9ePH3zDytKoa", - "zfc/G+cyCyjYvg6qRofFwhlmbG0UzcCnJI0oul7BS1uWBNq2HdeUXCi6cj4pXZe4LTuNk497qaJlwYre", - "Y69P00iM6BwV/E6WrOw70u17MJHMfe1z2SG3b3Ht/hBFINAF5UJ72q75Qlisdt6cM0Zy+5az4oS8mhOg", - "TdNWAIMLxXB0LxAArtEBk3yw6wIXCZJTAY6ZVQGucFwQKjZdo6xmxnhL+Dt2wTYfIg+LPS31zh2L7njY", - "itoOFx635lTJFdVkJcFKnzNhyo3z8EqgYBqYmguDriYtV8ceIJHjob0Vkf5wyHUzcmajVUUWpZw52hFw", - "8Swgo+8zTCbeWgD0AUhEUp5uu4LuWj1esyGX1f1XZ8e70SXbuqZrI9ecKw1+gow6Uk/jy3ANHHNOjH1Q", - "/rFkwEVJBc58bTzS/vKm0Dv4KIGzJROGX7KMlXzBZ6k4p5y2Xkzv6eo8QsMImvA54UYTp0K1QHBBFBUL", - "ZrkXy3FITUuMykhCU1JtsiWjyswYHfCbg4NpHMVby7b9yZUlWVKUXLCp3Ry2tnjM7U4oJtgVK+xquHJt", - "iH3D64GnHgBCwFNHMAoe3x32EPYsPdeKi8xtXcIR1PMvYXc9g+rdAuOrBHDh9xWDAAZ5Zc/FQiGd733P", - "s7y2ImgatIoqw3NejbO7ISBvW33sILt4tyS3JuddpqzHPyVBxsaZXXN/plqj17Zdl3/s/Ogo9wDUJwRc", - "1dwmzUpw5A6RU3jeVIGHuV8qRhINgaOH2GM/eXvt8aVbUu0vHsRJ+HdiFMc6QMwa9LV0NMLfWO7gdt6S", - "XdKhnR72jQPf8K67G7AQ/TgH71SKkaDeJ847wnnvN/uvpXd1WVpqU4sLIa+sOLOPf9t0gle+D/ClBDYF", - "P3vEcCA+0NHRWDj+Pp8D/cgIF4W9RCB0UOPDVmTOMTqgocmWli/sjyd2AItddoDRI6TQ1g0JHLaUJQ5M", - "fpLx/ROLfYAUjMO7Qv3Y8MBEf7O0FA5sOnDs6E/PRRrjcn/LrZzQ4ooAMIg1mjEm0C2fcDEllpRd0tKS", - "MiORNQ2DpEWthy0pyTHu+tGQCJbWEOGKgHPZa03I61xnNTH774FOyyZbIJ7JdQaxe31YIQSvqrJAxKQo", - "Nxjp0pXTYQS7HpkDhngv5Qu2wSAbCPuCWwIaWUc/ZqyUltOXPQxrDmoH8DcF/IDQbGfwU9isAfWQ827Q", - "bkuo1s6pB/jrIbR7CDh0AwC6+vfgXO00PDuVMm1Wpv/wN6/htHFmR4qcJiNDV7GP8G0sSp7iwP721XjB", - "p/Vtl/tJKutarQg2mTk9VCQLpV4/S45yKTQTuoZoSCNzWZ70tHSalQzEiKzFkGUXLBHk9d43jvR25CGf", - "W/n8USQdKLbg2rBWnGKIP2jCKzYQ21dRY5iyw//vh/9x9vFp9t80+/1x9pf///TXP7799Oir3o9PPv3w", - "w/9t//TNpx8e/ce/TQaeZWbZbTlPr+mdlOHhg8YEGreWdudQX0rDMpD7sktapsx7L0EoTHJarYMkGEzL", - "B3TuMNEF22QFL+s0Lv4UqKCuZ0CpuSCMWkpITb4Ebro1o22zZTaQfwZW9ZoebFEj0FnZo28P/IXgdYee", - "brvECWRKHXv/cAb3cQtZA87oBSvReDmc9QIvWmEbnmwzHPQuRuHH3iYtRlAMvzw4UnItbX/Q4VWAJR34", - "Fm6iuFvdW9FYHdBVCJmNWdArGpRct67riVcX63vcKGkVi/t4g+X1hx+7vGR6onHeDnBg+6gskQHq4RTc", - "FTfYDnyK7CL9x9WKEdoJHHhBIuYS49FFl8ns4FkIKx53Fp5XcFHOsg4v4XZe9nA4xxLCFq49hX5kruQK", - "Lluf14wVkAN6iRbWNU9LZ1aXNqmPL5ZegoCy0w7MaPk3tvnFtoVTtb09hzn2ljRqGi/leYnjRkdzM5tX", - "CvPdiDsxH4MWhtAeEuygbaJlod7zBpRyoVMxfosmJDbGghmzQjFbs7w2jdqzo1wP+v+75QG7hoR0+GLk", - "c4BJnrZzCrA/bqwdJ/Y2kMfbPDBaVUpe0jJzttwkNYcW3tp7x7xW+kJ9+OvT128dxGBAZFRlQdZILwQa", - "NTLGvV2LZTXkDmMwKKK8AqD7pDtjLtctA/AVpJToiK6WeXJYhBvTGPGja+oMwnPPau9p3nVOBrjEbc4G", - "jcIHfQ3a/gX0kvLSq+w9jOmnApfUuHLs/VrEA9zYTyHyK8kOSv97lzd9E3YQmniGLRkjVpi3RBPpMkM0", - "h2WFUTAKAFqu6MZiC6pl+xRH1CvQ7GS65CmzWFtdSaDVgDxrh7JP67ZB7Hc9QifWASsaPLl93s9/aLdm", - "0jm71YL/VjPCCyaM/aTgznWuob11PoHWtaWXhAUbE23dofwCE+4jubi8PTdaXBjlOvKLlU8S1kQ8Nbee", - "cHY3kWMaFW6fjwMgtgsxsRNRD9wXQTXpsShYGKhomZH38C6MZ+yxDQOegdG9E9zZOa5xKrvTaXpByeV1", - "StOHveSgOE3UjaQfnc2V/D3lRXvVnzaaEHulBx0tvXTuyYAUwzvp7q5xRCHB1k1BClLvjYHqvo7BttHk", - "WG0OZ/CSDfHdsQ2m7ZI6QMjhvkEYCFXn57+iYOntvFTgBXsOuVpbIk/6msYOyqc4fnNNHcx9fQS9mtH8", - "IrGYxiuwZYk2kvhOIWVa+3ROSORgGNq67GMVUytu2uS+kaiuy9nitKN52oaFBWyKmVeXe7HUMjFMLa6o", - "MD6HnCNgrrdmaNKxva6k0gayWSZXWbCcr2g5YN5rCGTBFxyTvtWaRSnLXH9SSS4MIk3BdVXSDbpbNjvy", - "ak4eTyPi5Q6h4Jdc81nJoMXX2GJGNfAijYbJd7GrYsIsNTR/MqL5shaFYoVZumx6WpIgdICCJnh+zJi5", - "YkyQx9Du67+Qh+Dlovkle2Q3z/GUk7Ov/wIWRvzjcZqWQ97RQdrqSXoaa8GnB7vaR9ENlqa1mGd7rzuD", - "XcbcGGjpCP7uG7Oigi5S2b62wIJ9Grt+Zx9EgSkzgWUi3KTnZYZaqpMtqV6m0hPncrXiZuX8HbRcWWxp", - "EmLhXH4UtOkjuQ7g+I/ggVyRtHLtbjU+6VzMP9EVa2/ilFBNdG1BbZRWjridEJcKrsBcnI02EbYEUzqj", - "RxrqfOdRwuXazLN/J/mSKppbUnYyBGU2+/7bPqTPIF8egfzQrMC5xgN+59utmGbqctxF82yS60MeCimy", - "lSUPxSNHqdt3btCdKU2Wuw4n24ccyyPZUbLtWEUjKnsj/BJbBrwhxoVl7IV2e6/szhGwVgls+Pnda8cP", - "rKRibd3qzMcUtTgLxYzi7BJCL9JnY8e84RGoctTm3wT6z2tD98xhxED5G5ti1THQvL8dzn89LHtI6JXy", - "4oKxiovFKfpvAzONo3bZ6JkU9YDGspKWd+K0JNCIVHRjdzmwoFt8w+eM6SyXZcnypIzaib6yzUlFOV6b", - "OMOmd3zcMteCCaa5HnjOz88/LpZWQrGf7UscaVkwIAB97vTdX1EP+ECE/YIJC/erF7ug7g3cdqvAUKed", - "OpyWP9jPro8dzKXvzWDe4V227Sy8b326X4TTtr/7rXUxDGoAsd3XQL+72DVW+e8HyvBqDIWjmpqWPrYT", - "sHvOlCtg0gIHdDBQYoIxorm42OmbvzNdxTvXdtip/vz8oxKFPbnnLnwOfaTadmw8zCsKdgkmigb6fEn5", - "gE+qZiw9of1gZ3wvleHotMPYZ3bgM4rmF0kF5Af7RQcnPvS0j9z59OhALrBGvLV9PvjZUsZYvmLa0FWV", - "3Duj7c7hWwDvit2+0MUSTM1yKQptMShnhFVSL3dlFNDpqdYCJiu5Rl4npsy5VJh9FnhXIzvR3mO3ZGtc", - "exvGTElphgC1cLYSEkhpCK3N0j5hPo6AQa2A7kow+g3kVhEFPZE3lsvweXtpWW6mhJsHOI5ynp2UrJi6", - "KBkxijFytZSakZLRS9YUFYHRHmjyYc0LDSVDSrbmuVwoWi15TqQqmMJqM7Y5yNLYyc33+IS4qF4XB/Fh", - "LWB5obhBvE5cpo9eCRateMVTZOG6P0OtB83KS6ZPyIcriUDoJreBttxvq8esNhgzWPD5nAH1gOWAKA79", - "mg8RTFAeBUINwrBuTXdPA3oYluklffLd90OI9uS771O49v7Hp0+++95ywlQQWq95yanaxM1sqymZ1bw0", - "LtE2JZcsN1LFGgcutGG06OEWaqPcLMDLzGuROze00CUuYvP+x6ffff3k/zz57nunvopm8VHQLsCOiUuu", - "pLCfvMIwYIibMszG1lybz8AtmbXIQF5Over2aHI4lrV4jo2IC7xom3M7JGyF+il/8UtWLJiaNg+xpatN", - "zhEr3EkVccBzhiFi9l3kwihZ1DnDTBfvW3QjAov3QArlEyJ3G7jrvopQA6fXpAaehZBXIAE/RoFMyPYK", - "4Y6xS6YwpqcZ6CE+DhFc2lAFfkrgtuSWyopH6ae9rhaKFmycFwI8Vj9jj5C4wY9wKfcb4BfbvitgtWSA", - "FmedZmCjQA7Lo8RvburN2UIlBuW3d0MRlC+xMo9iJYa6QWUUaDvtSWdzxjLLCCYx3kpNkIArz1llMT2u", - "RMmYfWvwpsNdhgp5nmkLQdAYhJfWYAFMWU7LvC5RlNjCQl7ltARLUIPYJZsbaXEvrrTVmAK4nWsGHuJY", - "UgTnU/YNi3pA2qhLpjauBWpefAUPe29Ux3WnzypnJbtkZRJwRhXwDj/KK7KiYhPOwk7RgDGNIuMC5MgE", - "g4cInvbPTikUgY/3zCHkdiDtUQxsbhGfc8UUlwXPCRf/Yu6ix6IDYAyWApLCcFFD8SfFGrjxqScQotsN", - "w+1jgEq6FFu4qGEWsCaKQ7Cr1mkXkaDQDobQhl4wBNsHEzvuZuyZKqZ5UachmyuatyHbDxnd5X1HDTtV", - "4Wj1gfCyQ7zCJd926bq43EGbzmn1d2mQTrXo8hhiRUPEF3E0POEs7jJQ+ZYDGgNpJDzaUe6WMPYlU7rt", - "hhyZCdh6x9i2RWt8zMvlUxvsP0vm/dH04HwbJMcNznn+GQPvob9Lq5DawYGkZQEAfcVNvsxSgSMOAGxh", - "YXjXFeH7UyJ3AbeQzecsN2NggKgdrIg1CAV+tlC8YLSAiPEm6grjrbqgPPxJEju0jlgeoTkIEg3HA6M8", - "2iOhecCQXcj/ixyJ+y7gHjwhRlwDz+O4s09umWvjkOdViHqnZMM07ErwLo/uCGQmSZt4/aQFK+lm25TQ", - "oD1p4Hm9cRvfHEjgYR8U9GYfDEL2U7t7tm1y26S74HA9+7ciLrXTO0mZcHLzuTRDCJXLSpjw2UzasCwy", - "0xWgsS9XOyWzlkHi7o2Kh0mLkY5r9MEnvW2AL34f4I/uRnxm64ovs+veSVzJr2lEiZLKJlGmCN+jkGiM", - "M4D1++R71FWRHYlNHUuWx6h7sG+pffrrJS0HAi3fsUoxDXoCSj789elr5xQzFG6ZpyMdz88/UmNxCvqR", - "wWRTn6aTgcwQ5+cfZ0AxMe9DOI2+dTHpQ20JEbfd7ede7+u55A0lUY021Pvi9wH6mw8AIxXlztGriTXt", - "76wLOu5Hd48JImsOuLsIF9U7eIV+pHr5kuZGqk0/g6sVrQdS65yff7Tnvc8Wf/19mtxbENKTfIjy97RV", - "ZMH/D3zvPD8k5708PgQS+Syp05z5P62kHyXtCd8n00lPD9CcRZyHOOFntITPmNuQ+Epu/ZMeTNdczLIQ", - "NpKq6DiduHTLcY7ZnaFgXGcrvlDA8qRHHU4THT1RiRcGWe1EWWTH1gzz4h0kbS28A3EDXvQiuJlTCP1K", - "FGzNVGOZedOsrmMpR/URFAbWWaNMTdMmRPa75Q8wDt9OoQ0rtmhr5nteRfT4KS2bNmr88nrjiwzYZJFd", - "Mb5Ypjf27bWGtmz07kO7vPtDSxG4N6D1f2ovJGDkAKGdN2R4azL0iGKDb4AZsN+bJS7/voSkKmZlmGoA", - "XFPsiQj/PrDZ3cpCCUKt+aoq0fnTkZJe7qu9Ek00ASa3H6906KCPWw/fYNf2SDx81MZ1Ydmdkmp7rMbf", - "xXO5qko2zDxXVCD7POfCye1XS2riYureBiTzvFaNEbcbjfELLTlW+dWQxVBIWUHawspwYf8DCRxkbfD/", - "jCr7H3Qqav8PsSrik+xQEzgXSH7lB/KRnJPpBDtPPGYnuaikY1JvU9rprPx5ghM22NIEYwUEJDTZpE9p", - "btD+6Zw1BTNXUl0kxJiZBn1Sy68qLvvap6ZUmbqiKKLQ4EHhUriGrHABNAeZrjV617T8J3bSSrauLK7t", - "D2ChVpcjIQybJ8UlU872IV1OSbRyYJraXsIm4sDbZ00pUn3NBECj3FD6ElpimxsmEVWDad8mUGupWE6O", - "fIX6Lpu52lRGnkIbaHKqjapzo9Frs5mzh5V2o9F5aXf9vC5LYTkBqTnaM43MFLtkdEhND65a7Lea2UMG", - "U51tTMIAqYMdS7S7e4xjp7cWAIldYTBoCh3syo1Plkntnq9o9RFn+ZVk5B1CHEopgEfeSi+q/T23cKgU", - "6JqWJhuUchx/Sd7T0sRshAXI+XkED5nhxLXIwSZHzz+HyGFhuj4K2gWzYhu7f3UNdn+QdsC84aFADqx9", - "pS6Zwljo0ejwi+/xaTq503W8Cze2TxWi9Y1bRbwpEWlIq1j8V3+dmlTJVBQkml8TuBsJX0G4ukwYtblO", - "miG+yHQp91jee754bzvs2FLfrLenpbxiKrPzbjni0psaMd4GW7ZSSYdaLjgeekqwgtjF6OttBA681064", - "Lrv3ohm745RCy1yKrDX73VIdpJcZYFcWshzs2D26au9e5WXrfakWEIkNF4t05kdL6C/Y5n7oEhIex73z", - "BBPvsDIHBI2fgkNDZGS6ckZkNBK2GZ0dVSSsuAacpiuXs+Vemfa9avyLVjxXkoIzRpNymvU4WCfsgS9j", - "2I1tDiZp5TIm5sbOHzYVC065/VI7K1p5eQvkcMsEn9ym0oq8C+7IfY/SXApDORTUSTL36IzLygoIVaMb", - "P7lX6PtL9DJ3fE2270++AgSKDFex/7b9f3/LjGLs7j1cL9gmK/mcGT5gkC7ndiV/Yxvim50cjKcYypHU", - "MviB5qHEmIAm7xORCr8s4EucXoogHYUgae3/0qRghqmVRcWlvCKrOl8C704XzCdYAoMNeJZ3JmqN7jNS", - "tNODufhAXdEcB8Kw/5KqBVPEReKHuiTeALSiHO5J4w3cjc8FRzGaMsbtSvv0BlMBRLQLTKdRDqhEdikP", - "xgXbnKJlEH6/BiEZTiU1ABjklbpFkG6UnirOabYDXy9aRlUs9tVK/hbAP6Bx1cLnVAh7Glf72drGLg/W", - "Adeh1qy/zvHROPHeJkTcZm1jPQP6mztg0N9lxx8o2eLMvUDHoS8B+Mg/v/4nUWzOFOitvvoKhv/qq6nz", - "V/jnk/Zni21ffZV2akrenMP5DYRKAHYMN10SO9oFYDs2VHzkNYbTouOafdCkAJfNsuyEPImCQLIBYE8o", - "RICwUlYs2RqKlcUvKCSAU2xRlxRDfbgQTLU6jcn0g+K/WQun6oI/P6xFqm3MTkLraDtSBUKjKszXq5zb", - "KSeHeZZyyGh03RGbnEjNiJhd5SYjvsSULmFEH2F6kzE/uDF2lHA8P/+oFwLUcl4Zx32WAGCA8YTb2BQy", - "B/gyjz5TUQhnY7/VtHThegKC4z5A2p78ggms4GipnKu+S5jQtXIqQQsrjGdBccPI+DHXTZPr1nIcLgh2", - "fv5R5aj9dR7tLhkEZJ7CrpbNKOzhyO1FVWx7K2IOJaOznC21c7mGPr4YfEV3iV6Axmo1bMPvZIuOI0sg", - "46LvPzB8U7+kKYWezkXYJJXsvMyY//7hqxePCO8WQ4+zPkaC1u5lxyVUxkGEGUZ6sHRzT+4DxZyxoXCe", - "TmAhmbMBVfDW8h12LJAKsY4HtOq6YO+EcmRWhR+phiodrnkTSX8fUym0gCSvXiT5jFZ23L1LQkwnCyXr", - "dOT2QoFpqOsLaoUAYLBQgEfnstMn331PCr5g2pyQf0ByPXx8+3XR2qdJeFNvrVXKkwBgIUErskEuGDGa", - "c+kOtBcczF1QIgxz9yd8nfzk0wnwJZlZpwLcX/V4FlK5CE7ILRrRm5bb+yHC2rkwiiLxzeR8nsy3+3f4", - "vXGLUJ4mK9Y/9RFU+YJtFLsu7/I36BxKjA5TnhIoD9TauR7hKRkdiBwo14nr882TrLlBJ+S17U2YmEtl", - "pepVDZY+tobEfM7gFnOpkL7ONOWhIXOd+J0pCUoDQaQzbHfvWNhsiLKkOfDz2kURWxhCYt2gmHz4HriZ", - "KQL5CGXS/lUjtTAc2R+7jb9Eu1jZh8cC/Y8lLxNYUEn7XcdwTImQRIJzUNwS0xo0WRcRZhcW3kKku73m", - "cTrxIm3qt5gA8ZCvo9oajUYiX1LRVGzfXZKhj5PjajL3ihIlrnm6YoRdwAIXsDgInJ/XUU/IgfBQ+wHY", - "EMUwQ2LQnt1xMiC6WTFhrkn53mJv9E2AerZquwSgBiQA33tXHeALtsmMTI/N0LCEnHkQtUBPitQ2WuN0", - "QO4JMXa+Bn7Du+INsizCvAaDbmS69HpSJ9IFf7ILtmm8XeJagSg2XUPKwmcxrQX/wFeskUuQkUuxQHzU", - "k4jiZVquxZxISLIfbFlOGGY7VugBrMC+23FitJ03QtvI0NvLc3SNWxC5IUEuji1hHpuKtQP7wDExKOpa", - "SS5AZ3BCXoQkMeCHiLH2TeYY1Gd1vRUxI0rIksyV13tR5fXV4NAIzm5waxKEwDVA3si26XNJrgnN59Bg", - "SBHkm63nTDXtUsoY33Kufm8a9vVAvllVgWfBgEbLtdKmAuPQ0Ek3TpkV3Uw8MziZTuyy7D8WbPvvXP1u", - "/6mqEqqcVvO+T2b6AjucyGCeRIj7pC21thjJcBMb1NqhAd1aR88F7s6xBm94VfdVT8YKdExH3vzwnJbl", - "h7VwfoD9sLctnpe0wtC3187jMlBoS8ad+67XWjnqEFtiaJ5bFq9oUj5EcD7QpFs3BRNB9CunbPHG3Emh", - "uyxAjJtULQbXDQqrPhvKc0LVosb0Q3ewvh0rGJBsaMULl5CxX8jOsWxIFmrFCiKVS+XF5y5P21Alh91l", - "qnD3Kscz8rxhDZssFAOYPrXCD6tcsnUpsjx4ltt30kqYRpJz9Mg+n5yQV5gzRjFaIIFV3LBUHaXW+iH5", - "7RWDss4eo7NwulEVvBN7i1o1tzRgtmLgP5EokfZF1uOCE9P1wIkNUSXkqtqH9BlO6Hm/mBgUCxDSfEHn", - "NKoy1/n5R1bBxWqXvYjjKKoqFOsqmd3332oIgLMEG4Yd0NFKxfhCDNRiBwSZU/8Q6O5xJZ+DNpVy6Qbj", - "g9e9VyKw49cjomB5wcEwhQAtMihlv8XlO0Few14MFIdHAheSTeom9ka7VUY1MMYt0ZOZt9EKAbE9K3vI", - "9V2jpNqN66h1BmhRjV19WwFGicpr8VvYHXoXZxZZObdyZliyobQLR/qkWObfT0+xRIHVHOomXulcPCW/", - "MyWdsBqGshei0Y27NOAuP+pJolMorKJ73bpT7lmwBhe/hTscLAB1fv5xTXtcBsB0A/7iejW8dp7xy4FS", - "IvEZe1OZqyFyw0pAOOOWjW1iLvsWMVrAvkb1F2IfLyQyoaAA7rarqQLIQq8GyphsPc351tPcMn4rA9OV", - "lw4x/XCafDppEnNdXfkdxx6puM7hGMWmolR/6jGXPzgPjEINLyHfFDn8rFvQY9iUTil6iT5FI7qVyrRj", - "vDx8J8SRkHQib83Kuadm3jbnrccxptmXCd+1Fa0OWj1uJ/GIIB72OWCDHgdNXjP3MCdSmeMIjW+D5TW9", - "NTLBMu65dj96+gjhazedFY2rQuilrMsCC0OsIBdbI2MmTscVgAp8YVOQC904wOsiDrLW0QzxZhPyyo5M", - "yyu60V5R22DW8HB+V7F8REJJGCdrRO1yem9Ujm7iLOcVZ8IEn5v4XCySD6s30wM7NamlOphFjl8GrYVz", - "vKdNJbW26c1b3ly1KBq90FO3zbRsqwtwYK+Ktm2e+7H9isKRRg/a7pQiqXp6YUt3ED1nG91K7ZxecV8i", - "h72QyuE0w+RNSNEOAB4wygjbyB7aG6ouWo+gu6xuALHAdAKtUVs8RpQEQLMSU5F2YpCHImQ0K50p4209", - "K3kOZgRw+g6GBefxX5B3VBRyRV76ZD4Pf3n38hFRTNel8UjmMxtb5HOQfN5yAoMLr9Tcrfx9FC0Tls+F", - "s6gsuDYqobi881VBzsddDke20VybxusIDdaY7rEXEM4dFUw/QzDhBdtkBS/rQUS2rS6KdsJNXc+gLBwX", - "mJV3Rk0O3iw9EPSWqXd4ONg2JS4V3BxuutJxFwaW625Ma5aqc3/uGwLtECW8eXU79XSWm33Jp+uG9NPN", - "dD3+ENnDJkwiSgRsz9MXROk8/DfisqIpME7Lch/aVSVsmK22S2lT9FMEz9DIkLDT5bQ9Xtrt1PNZMAkU", - "PuN9jstOCK+/e1sazgj6F65YaRkxP/NaFLqzhU05/C321628j2N9fJutptwhpmAsJ9AKmm1DAoZLF3TS", - "xEtrLXPeGOGh1iRWlfy7KDcuKV23okezlZWSl7xIFaIv5YLnGlUw+1qMX/u+n6aTVV0afs1x3vi+aMJO", - "P4d84Z5CUVBVEFY8+e67r//SToVwj8hVf5OS7j1uWU7LSA3P23xsWN0IIuaP8mQh+yRr0NimFo3tIRjX", - "Uolbx9vIAJDh0HevaHUOIrMNoRGqS8u2l4Y3P03tb0uqlw3pjMoWQxlpShy96nr9QXxRZOi74/Bzh9jZ", - "jRwzOtdjiHA0l+Q+3I2YPCI+jCWJbyJK0lvhyi0R9a4WX3zQJex1VTLL2zU0cDCNjj8afPL9nO95v8p/", - "PF5616EBlA6UlhPBvKyWmWw4LlAQNFBdwzu4tz/vY7hSefGWimkLUdr7ZqmSmUa25d9sMh8m8qrvdbbv", - "O3vayUwC+zbI4VYXnymBzTYcuB9ZHNKOWNtZ5qFcDGRMYF5IRtVNQjXMPUdZYbeh/mC+1bb8PD6jiQOn", - "6+U25J6mK++g9iEKHY0zdJFXiP6NVyPwsQLz1biUe2j8dQUA2vt185D8TxAhMJeY3UAYmpsmtfjkqRtp", - "4or8TpbGVPrs9PTq6urET3OSy9XpAqKcMiPrfHnqB4I0kq3Uaa6Lq35ln91yY3iuydO3r4BJ5qZkEDAB", - "Rxcl1D2bPDl5jKkXmaAVn5xNvjl5fPI1XpEl4MUppjmenP3xaTo5vXxyGjtHLVKBD+8ZVfkS0di1PYE0", - "ggzF2VdFaPRSqqd+OGfoAhvx5OxjL0McqFYhTITbv3+rmdpMfGH0WO/XmF/79HB3AD3qpTR6/JpaYUoC", - "xUjuufbItwDcBwi7ZIJwxMSSr7jxKlHFaL50bFoCZmi7J8BNLRS6YBG8J+RnzaJaZPICYo5QvvARDL6U", - "Vug0AJgdIgVXQ+P60eO4a062AQdQKrytZQFRdmAmE5Gn8kmrmI/Tzfvyd5jtNN+QWpSWofQGJ7AT67A0", - "qPOE6Wxy6nbAhfd5N2k9fAJ+ksxBmFkI9zwRV1cbhGHgHpxjN6g1nazscHwaMrfGniJTNFjLDeS+08y2", - "C7lQOyaFqfP0sMPi58gVCXwQ0I9kaMHO5zyjZZlaZmRd7C7zr2u3zAb7cbW6zpfgk9QFtAsZZvN0mShC", - "QJHbm6nrH/mJ+NjM4B8SWorWBo7oY7eDratSFmxyNqelZuntYbjI1tYEjtB74OLeOVeYTlSqRudbnUX+", - "IJNWRK1tIaRI50rtpSQ0GyDd9tGZ7Hvr4Nrc3ytnp7jRffN+t5FThZFNaDlkYrWX0GVvSr4aITZ+mNrt", - "9Kbd/nkIfP/OeF8Wb6d0sWJYULZiCoYUOVjTNFALr6pGnPfuVAXXdFZiPlzQQ7V8ceB9AD6o7YIWe9/M", - "eQl3CE4R3z7MFBHsl6KwhCnjonnYyUvoZYeebUhEXlrDbBkBNiCQRTTewgUPM/wkReY6raigCwujRV37", - "wsYxNGhyxF0F3WaMvNtQMtSS3AML44S1w0xJ1xNrywy/WuEca0gAtXny+LHnH51+PRrt9F8aJcFmwGEP", - "9n3i4VJEyJfj2pprIBRZbZ0C8k2rqjbD3jFrkwG30h/5Z+0eioouuHA+ZXCyK3qBTD1GRjqXTk+hfGoJ", - "ywIFc6RjmtytGaE8bvjS9gb8muT325A/BNeuR3aB397oHAeLhwwX8eiswzccA/Y7h4Dolo7FRz5NJ999", - "6UuwSE0XGmq/gNwx+fVTR5o5/cP7VPPi06Bo81rKi7oKRpGoQFdfwsG27l492wCR2CrhBFOLf3eApEDB", - "h4aiBCAn8R4ZVbO9+PWxr9ABKeaRTz7yyXfDJ9/KU7rHA3qLD2b6kTq+UZNvH397fGbvzzNbwuO345k9", - "7VGAXe+uiBw9u3RUVkhuy43XoPvgKMwUtOV1flpVkIwCtNL6Pr3TBxcz/qzP8lHRey1F74Gf0s5930M8", - "bWZpbupRWI1Cvjobe+QIjhzBl8gRhADTz8IHeNHk/rz/t2L1PL75xzf/zt78cKPHPfRxLc/j++7f96BE", - "OT7qx0f9S3vUE/mk93vivbYyrcy80ZP/HId+GoN2lP+PvMCRF7gd+b9FAPYV/Y8MQSLHy5EtOLIFXzZb", - "sL/MHxiCji30IKzAUQlwfPiPD/9nVwIcH/uj9H985r/8Zz6OTBvrWNdONPShVfpOMUe2WUEEu7KXzUgi", - "S/sY7Xjh44F2PfDHd+MwkUFRPS47y5yvHXX2WaBcfePGh1tIwzAX/CAUkHcFBtvbcR8j6If89sPXP5IT", - "++zm8aSHS8ye2j2+gDhH75v/L7tpHhHrJj1IcNv0efpDXCzk0Nd8QbKQpcH+ssKfIPL3PV/Yn0r8CXIO", - "YMR1ags0XwzvgYZuK/zHjjdqke7yRwtpp1uYbRzznj6SNOd7L31f/ZTUQOTFHIPi4qlXXGRbpw8NDgLC", - "jM2liwKKYKDrHTD4BvsGTdyqIONXFq1pwS0Bhkrb5I2jN1SQdy+fk2+++eYvBO+9FWwQXYYWjENiTZMY", - "uEA3CmrC5zFU6N3L5wDA++DSOqrVzkMNGHWolcOI92/hf+J40z9l0N/njI3AVTsNhBMqscjTdi4llILa", - "qrA4rKD9JxGQp5OuVHHzqo4dQam9k50JjzFg/6Pk1jF26TirRdv4MpTYYg+T8u2beTFMF+WHVpmKcOmQ", - "YwiRuk2SvSRBx2bXY7yPGuej5uBoav4zmpr/R0cSR/t0+kebWO+OKI5q1Q3pMJsm6WjiFEvcfTJ2ssV/", - "OoPhrZGdPYnN3QWN3tCKdDTBfCGsbI8Inc7kepAQ/S9g/6z03+JF4RrO5JrYezV17Ivu5KENDaC10zk8", - "c781pYedfn8hXVW23FISqhZYXPoBDMbF4gwGeIAZcDhQk9rxIdiQC3P29ZNvvnVNFL0is41heurgAejI", - "998CNLbrg9n33z7w1gcK+eXtT2dPf/jBjVEpLgydlcxpGHpzaqPOlqwspevg+GPWa2g/nP3nf/33ycnJ", - "gzGkXK4tNX8qip/oit09UX/anB0XcDTZQU+k3e6uNj3JgOL+jlcM3fRl2Eb8n8l16rrbOxMlFTma7Y9v", - "xuHeDF2vVlRtLK1nBq59hGrOWw6VAB1u9NqPDdP7PjfNCwP14cMTAnleaZsL1FJZDrNka57LhaLVktsX", - "ZXMySifzDMC7c3p7VA7cL+XAcLXoihfrTuF2wkXB1mn5PaD7KE3DM7l+4aaUyYqkX4I6AG8DLnwMYXoW", - "X+f21T++dMeX7jZfOkS7EW/cXlqd01Iu9B6qHWLbjxAKXsuF/jw6nuPzdBivt8/s0vQn9S+CokvBUN8r", - "zI9pgV0lre32LWyVNVV1byc78P1na27V5lHKReZfjP3TAC1e2K5fNO90A1XsNiXg9oCq2JINLbcJTKOC", - "oY6G3ePjuMdr1fJFwIzfd+iFsHt2O/oOLeJB56sFN0Pz2W+Tu48WPIZ/HcO/jqLpXXoPwCGf/uGv526P", - "AbjmYzKQ24bjpcm4fvrRV+BWfQWAzI2lhXeYVBqmPJKbozLvfrs6dCnm6YyWVORsp0YOWW9tQA3ty9Bc", - "LSUQFJcPHwjMVorqJzvKRkfZ6FhI7xjYNDaw6WBM12G5kZh4jpLS3nDBj9k6U6/erHkajiLbn4kB2SfV", - "Rcs8AbpYR5+25bvALBf2ScXMF1tlvmO2i2O2i2O2i2O2i2O2i89jjT7mpTjmpTiKb/+z81KM8ThxRkwL", - "qBQMXZlbjfH5H+RCbtsJpbeo53I144I1ApBfQVN02kh7UNBoSU14h31DI4kOXgY71pUpWQ68r+CEA0Jx", - "zvgl/HeuGPudZYYqy1yPeW9bq/EAQmnMaP64NuZea7NMMSrciM8H4qtTqxWkoTUhVy2hxK9kavnkjazJ", - "FVyWkl9Af1dX0276ilgk7tT6NpIYVQ8ap133DODZmXlkehcGoGMSlWMSlWMSlT+BNmRWyvxCn/4BR52h", - "HmGnERs6DSkxntmPuxQXeBlxunRaqBigGxK1HxktmCLSPvrzki5OyD/s5YTbB66lxlPoaaOzgTWSQjLU", - "hTgFQJcH0AP0bwlTZnbK2yWBW6NV4CSOgeFf8PUcpZqMPEPHZuDtaiQ9u55mG7kGdrzLtAcxcb/cvsFL", - "9ajpPGo6j5rOo6bzqOk85vU96k+P+tOj/vSoPz3qT4/601vXn35Oneft1wo9alWPWtWj2uazhgXFR3v6", - "h5WJdgcGESs+lq0XckjFGmPdmOggJ5TdXQ61OyQh0XbtdVnHX85jDM2RvNwXrfCn6UQzdenveq3Kydlk", - "aUylz05P2ZquqpKd5HJ1CkkqXP8/At8vVyt4qMIvbuToF0fKbPd1JhW3b2+Z6Su6WDCV2ZkR5icnjyef", - "/l8AAAD//84PGZ5wfgEA", + "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", + "67nfY8CVmN+fDtw2HC9NxlWwT74Cd+orAGRuLC28x6TSMOWJ3JyUeZ+2q0OXYp7PaElFzvZq5JD11gbU", + "0L4WzHopgaC4fPhAYHZSVD/ZSTY6yUancminwKaxgU1HY7qOy43ExHOUlPaaC37K1pl69WbN03AS2f5M", + "DMghqS5a5gnQxTr6tCvfBWa5sE8qZr7YKfOdsl2csl2csl2csl2csl18HGv0KS/FKS/FSXz7n52XYozH", + "iTNiWkClYOjK3GqMz/8gF3LXTii9RT2TqxkXrBGA/AoCC2m5woLNodGSmvAO+4ZGEh28DPasK1OyHHhf", + "wQkHhOKc8Wv471wx9jvLDFWWuR7z3rZW4wGE0pjR/HFtzIPWZpliVLgRnw8EcVnYfS7LLTEhVy2hxK9k", + "avnkrazJGi5Lya+gv6uraTd9RSwSAwK1tt2oetA47bpnAM/ezCPT+zAAnZKonJKonJKo/Am0IbNS5lf6", + "/A846gz1CHuN2NBpSInx1H7cp7jAy4jTpdNCxQDdkqj9wGjBFJH20Z+XdHFG/mEvJ9w+cC01nkJPG50N", + "rJEUkqEuxCkAujyAHqB/S5gys1PeLQncGa0CJ3EKDP+Mr+co1WTkGTo2A29XI+nZ9TTbyDWw412mPYiJ", + "h+X2DV6qJ03nSdN50nSeNJ0nTecpr+9Jf3rSn570pyf96Ul/etKf3rn+9GPqPO++VuhJq3rSqp7UNh81", + "LCg+2vM/rEy0PzCIWPGxbL2QQyrWGOvGRAc5oez+cqjdIwmJtuugyzr+cp5iaE7k5VPRCn+YTjRT1/6u", + "16qcXEyWxlT64vycbeiqKtlZLlfnkKTC9f8j8P1ytYKHKvziRo5+caTMdt9kUnH79paZXtPFgqnMzoww", + "Pz57NPnw/wIAAP//FuSagzZ8AQA=", } // 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 eeef46d88..2be5731e0 100644 --- a/api/generated/v2/types.go +++ b/api/generated/v2/types.go @@ -1499,9 +1499,6 @@ 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 *uint64 `form:"round,omitempty" json:"round,omitempty"` - // ApplicationId Application ID ApplicationId *uint64 `form:"application-id,omitempty" json:"application-id,omitempty"` } @@ -1511,9 +1508,6 @@ type SearchForAccountsParamsExclude string // LookupAccountByIDParams defines parameters for LookupAccountByID. type LookupAccountByIDParams struct { - // Round Include results for the specified round. - 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. IncludeAll *bool `form:"include-all,omitempty" json:"include-all,omitempty"` diff --git a/api/handlers.go b/api/handlers.go index ca1333535..645e2808f 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,9 +188,6 @@ 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) - } addr, decodeErrors := decodeAddress(&accountID, "account-id", make([]string, 0)) if len(decodeErrors) != 0 { @@ -227,7 +216,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,15 +374,10 @@ 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) - } - spendingAddr, decodeErrors := decodeAddress(params.AuthAddr, "account-id", make([]string, 0)) if len(decodeErrors) != 0 { return badRequest(ctx, decodeErrors[0]) @@ -440,7 +424,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) { @@ -1389,9 +1373,8 @@ func (si *ServerImplementation) fetchBlock(ctx context.Context, round uint64, op return ret, nil } -// 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) { +// fetchAccounts queries for accounts and converts them into generated.Account objects. +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 +1387,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..669858ecd 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, diff --git a/api/indexer.oas2.json b/api/indexer.oas2.json index ae495ea16..b650ca9c3 100644 --- a/api/indexer.oas2.json +++ b/api/indexer.oas2.json @@ -78,13 +78,6 @@ { "$ref": "#/parameters/auth-addr" }, - { - "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.", - - "name": "round", - "in": "query" - }, { "$ref": "#/parameters/application-id" } @@ -119,9 +112,6 @@ { "$ref": "#/parameters/account-id" }, - { - "$ref": "#/parameters/round" - }, { "$ref": "#/parameters/include-all" }, diff --git a/api/indexer.oas3.yml b/api/indexer.oas3.yml index 9611bb81b..4b52d63ff 100644 --- a/api/indexer.oas3.yml +++ b/api/indexer.oas3.yml @@ -2479,14 +2479,6 @@ }, "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.", - "in": "query", - "name": "round", - "schema": { - "type": "integer" - } - }, { "description": "Application ID", "in": "query", @@ -2591,14 +2583,6 @@ "type": "string" } }, - { - "description": "Include results for the specified round.", - "in": "query", - "name": "round", - "schema": { - "type": "integer" - } - }, { "description": "Include all items including closed accounts, deleted applications, destroyed assets, opted-out asset holdings, and closed-out application localstates.", "in": "query", 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..345c9128c 100644 --- a/cmd/algorand-indexer/daemon.go +++ b/cmd/algorand-indexer/daemon.go @@ -25,7 +25,6 @@ import ( type daemonConfig struct { flags *pflag.FlagSet daemonServerAddr string - developerMode bool metricsMode string tokenString string writeTimeout time.Duration @@ -70,7 +69,6 @@ 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.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 +298,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..672eec413 100644 --- a/cmd/idbtest/idbtest.go +++ b/cmd/idbtest/idbtest.go @@ -9,14 +9,12 @@ 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" "github.com/algorand/indexer/v3/util" testutil "github.com/algorand/indexer/v3/util/test" - ajson "github.com/algorand/go-algorand-sdk/v2/encoding/json" sdk_types "github.com/algorand/go-algorand-sdk/v2/types" ) @@ -147,24 +145,6 @@ func main() { doAssetQueryTests(db) } - if false { - // account rewind debug - xa, _ := sdk_types.DecodeAddress("QRP4AJLQXHJ42VJ5PSGAH53IVVACYCI6ZDRJMF4JPRFY5VKSYKFWKKMFVU") - account, err := getAccount(db, xa[:]) - fmt.Printf("account %s\n", string(ajson.Encode(account))) - maybeFail(err, "addr lookup, %v", err) - round := uint64(5426258) - tf := idb.TransactionFilter{ - Address: xa[:], - MinRound: round - 100, - 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 { // txn query tests xa, _ := sdk_types.DecodeAddress("QRP4AJLQXHJ42VJ5PSGAH53IVVACYCI6ZDRJMF4JPRFY5VKSYKFWKKMFVU")