Repository: algorand/indexer (go)

Issue:
Requesting an account at a round in the future should return an error.
## Summary
Currently it is silently ignored:
https://github.com/algorand/indexer/pull/373#discussion_r588331654

## Scope/Requirements
Check for error in `fetchAccounts`

## Urgency/Relative Priority
Low priority but would be nice to add in.

Pull request description:
Return an error when rewinding to a future round
## Summary
Closes #380.

## Test Plan
Added a unit test.

Patch:
diff --git a/api/handlers.go b/api/handlers.go
index 66a9509..0c5079b 100644
--- a/api/handlers.go
+++ b/api/handlers.go
@@ -627,6 +627,11 @@ func (si *ServerImplementation) fetchBlock(ctx context.Context, round uint64) (g
 func (si *ServerImplementation) fetchAccounts(ctx context.Context, options idb.AccountQueryOptions, atRound *uint64) ([]generated.Account, uint64 /*round*/, error) {
 	accountchan, round := si.db.GetAccounts(ctx, options)
 
+	if (atRound != nil) && (*atRound > round) {
+		return nil, round, fmt.Errorf(
+			"%s: the requested round %d > the current round %d", errRewindingAccount, *atRound, round)
+	}
+
 	accounts := make([]generated.Account, 0)
 	for row := range accountchan {
 		if row.Error != nil {
@@ -645,7 +650,7 @@ func (si *ServerImplementation) fetchAccounts(ctx context.Context, options idb.A
 
 		// Compute for a given round if requested.
 		var account generated.Account
-		if (atRound != nil) && (*atRound < row.Account.Round) {
+		if atRound != nil {
 			acct, err := accounting.AccountAtRound(row.Account, *atRound, si.db)
 			if err != nil {
 				// Ignore the error if this is an account search rewind error


Test patch:
diff --git a/api/handlers_test.go b/api/handlers_test.go
index dbc3f06..c03d6c5 100644
--- a/api/handlers_test.go
+++ b/api/handlers_test.go
@@ -6,6 +6,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
+	"strings"
 	"testing"
 	"time"
 
@@ -483,3 +484,21 @@ 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 := ServerImplementation{
+		EnableAddressSearchRoundRewind: true,
+		db:                             db,
+	}
+	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())
+}