Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ledger Deltas: AccountDelta retrieval through ledger/catchup service #4658

Merged
merged 71 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
0e234dc
Add AccountDeltas to ledger interface
Eric-Warehime Oct 17, 2022
2a4677c
Add EnableSyncMode config variable
Eric-Warehime Oct 17, 2022
f9d9ab9
Add NodeInterface/LedgerForAPI changes
Eric-Warehime Oct 17, 2022
2eb0d40
Stop synching blocks in catchup service when sync round is set
Eric-Warehime Oct 17, 2022
d1206f2
Add comments, fix interface naming
Eric-Warehime Oct 17, 2022
ab0ded3
Fix handler tests
Eric-Warehime Oct 18, 2022
5331665
Fix catchup service syncRound, add test
Eric-Warehime Oct 18, 2022
023626f
Fix race condition
Eric-Warehime Oct 18, 2022
bae0275
Fix sanity
Eric-Warehime Oct 18, 2022
539db38
Fix mock interface
Eric-Warehime Oct 18, 2022
745fddb
Add /v2/accountdelta/{round} API
Eric-Warehime Oct 20, 2022
a36b6e2
Merge upstream
Eric-Warehime Oct 21, 2022
229d2f8
Add tests for handler
Eric-Warehime Oct 21, 2022
c25e4b8
Fix race condition
Eric-Warehime Oct 21, 2022
853714e
Add RoundDeltas API
Eric-Warehime Oct 21, 2022
14158ea
Add mutex to catchup service
Eric-Warehime Oct 21, 2022
00c8558
Add SyncRound APIs
Eric-Warehime Oct 21, 2022
56b54e1
Fix code gen
Eric-Warehime Oct 21, 2022
e17e6ff
Add node unset sync round implementation
Eric-Warehime Oct 21, 2022
e00355e
Add comments to exports
Eric-Warehime Oct 22, 2022
d3b3a15
Add descriptions to API changes
Eric-Warehime Oct 22, 2022
9e91dab
Fix race condition in catchup service_test
Eric-Warehime Oct 22, 2022
01d6135
Fix error msg, lint imports
Eric-Warehime Oct 24, 2022
24cc272
PR comments
Eric-Warehime Oct 24, 2022
c5dbed5
Merge remote-tracking branch 'upstream/master' into statedelta-ledger…
Eric-Warehime Oct 24, 2022
db39ddb
Update merged fields
Eric-Warehime Oct 24, 2022
cd03056
Merge remote-tracking branch 'upstream/master' into statedelta-ledger…
Eric-Warehime Nov 1, 2022
0cc41e0
Add KV Deltas to RoundDeltas response
Eric-Warehime Nov 2, 2022
67b722d
Remove EnableSyncMode
Eric-Warehime Nov 2, 2022
0f2dfb9
Fix index bug, add tests
Eric-Warehime Nov 3, 2022
9821bde
Merge remote-tracking branch 'upstream/master' into statedelta-ledger…
Eric-Warehime Nov 9, 2022
93ef0b9
Update algod spec to return StateDelta
Eric-Warehime Nov 9, 2022
a9185e6
Consolidate acctupdates deltas into single cache
Eric-Warehime Nov 10, 2022
13508ff
Fix handlers interfaces
Eric-Warehime Nov 10, 2022
4c9c4e5
Update required fields, fix acctupdates totals
Eric-Warehime Nov 14, 2022
59199e3
Mark acctupdates test non parallel
Eric-Warehime Nov 14, 2022
7cedca2
Merge remote-tracking branch 'upstream/master' into statedelta-ledger…
Eric-Warehime Nov 14, 2022
ab97557
Add PR comments
Eric-Warehime Nov 14, 2022
0460b1a
Fix mock node
Eric-Warehime Nov 14, 2022
98e9f43
Merge remote-tracking branch 'upstream/master' into statedelta-ledger…
Eric-Warehime Nov 14, 2022
4fd5d8f
Update catchup/service_test.go
Eric-Warehime Nov 14, 2022
a15da3c
Fix model imports
Eric-Warehime Nov 14, 2022
7e29b90
Update catchup service test
Eric-Warehime Nov 14, 2022
9ca4d60
Refactor account conversion to use factory method
michaeldiamant Nov 21, 2022
e45e409
Merge pull request #2 from michaeldiamant/statedelta_factory_method
Eric-Warehime Nov 23, 2022
233cef2
Prototype approval test for GetRoundStateDelta
michaeldiamant Nov 23, 2022
534066d
Fix lint error
michaeldiamant Nov 23, 2022
6b669a3
Merge pull request #3 from michaeldiamant/approval_test_example
Eric-Warehime Nov 28, 2022
ba7c1ce
Revert "Prototype approval test for GetRoundStateDelta"
michaeldiamant Nov 28, 2022
15372b4
Merge pull request #4 from michaeldiamant/revert_approvals_test
Eric-Warehime Nov 28, 2022
456f377
PR feedback
Eric-Warehime Nov 29, 2022
b811356
Merge remote-tracking branch 'upstream/master' into statedelta-ledger…
Eric-Warehime Nov 29, 2022
a819ed7
Merge remote-tracking branch 'upstream/master' into statedelta-ledger…
Eric-Warehime Nov 29, 2022
1cd6f82
PR feedback
Eric-Warehime Nov 29, 2022
62fffea
Fix tests
Eric-Warehime Nov 29, 2022
d114060
Move Delta creation, add test
Eric-Warehime Nov 30, 2022
4273a07
Lint import order
Eric-Warehime Nov 30, 2022
c425f4f
Update catchup/service.go
Eric-Warehime Nov 30, 2022
3fd1d1a
gofmt
Eric-Warehime Nov 30, 2022
2c40cca
Reuse ApplicationParams and AssetParameters converters
michaeldiamant Dec 1, 2022
18d3664
Expose AppLocalState converter
michaeldiamant Dec 1, 2022
6d8b516
Expose AssetHolding converter
michaeldiamant Dec 1, 2022
da723a5
Merge pull request #5 from michaeldiamant/reuse_converters
Eric-Warehime Dec 1, 2022
4114c3b
Remove error returns
Eric-Warehime Dec 1, 2022
2d91a96
Update ledger/acctupdates.go
Eric-Warehime Dec 1, 2022
ce09bf8
Update daemon/algod/api/server/v2/handlers.go
Eric-Warehime Dec 1, 2022
01349d8
PR feedback
Eric-Warehime Dec 2, 2022
a377e3f
Fix new API code gen
Eric-Warehime Dec 2, 2022
844ffd6
Change mutex to atomic uint64
Eric-Warehime Dec 2, 2022
41cdeee
cleanup
Eric-Warehime Dec 2, 2022
59563ba
Move MaxAcctLookback access out of catchup service
Eric-Warehime Dec 5, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion catchup/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const blockQueryPeerLimit = 10
// this should be at least the number of relays
const catchupRetryLimit = 500

// ErrSyncRoundInvalid is returned when the sync round requested is behind the current ledger round
var ErrSyncRoundInvalid = errors.New("requested sync round cannot be less than the latest round")

// PendingUnmatchedCertificate is a single certificate that is being waited upon to have its corresponding block fetched.
type PendingUnmatchedCertificate struct {
Cert agreement.Certificate
Expand All @@ -64,7 +67,10 @@ type Ledger interface {

// Service represents the catchup service. Once started and until it is stopped, it ensures that the ledger is up to date with network.
type Service struct {
syncStartNS int64 // at top of struct to keep 64 bit aligned for atomic.* ops
syncStartNS int64 // at top of struct to keep 64 bit aligned for atomic.* ops
// disableSyncRound, provided externally, is the first round we will _not_ fetch from the network
// any round >= disableSyncRound will not be fetched. If set to 0, it will be disregarded.
disableSyncRound uint64
cfg config.Local
ledger Ledger
ctx context.Context
Expand Down Expand Up @@ -147,6 +153,26 @@ func (s *Service) IsSynchronizing() (synchronizing bool, initialSync bool) {
return
}

// SetDisableSyncRound attempts to set the first round we _do_not_ want to fetch from the network
// Blocks from disableSyncRound or any round after disableSyncRound will not be fetched while this is set
func (s *Service) SetDisableSyncRound(rnd uint64) error {
if basics.Round(rnd) < s.ledger.LastRound() {
return ErrSyncRoundInvalid
}
atomic.StoreUint64(&s.disableSyncRound, rnd)
return nil
}

// UnsetDisableSyncRound removes any previously set disabled sync round
func (s *Service) UnsetDisableSyncRound() {
atomic.StoreUint64(&s.disableSyncRound, 0)
}

// GetDisableSyncRound returns the disabled sync round
func (s *Service) GetDisableSyncRound() uint64 {
return atomic.LoadUint64(&s.disableSyncRound)
}

// SynchronizingTime returns the time we've been performing a catchup operation (0 if not currently catching up)
func (s *Service) SynchronizingTime() time.Duration {
startNS := atomic.LoadInt64(&s.syncStartNS)
Expand Down Expand Up @@ -202,6 +228,10 @@ func (s *Service) innerFetch(r basics.Round, peer network.Peer) (blk *bookkeepin
// - If the block is already in the ledger (e.g. if agreement service has already written it)
// - If the retrieval of the previous block was unsuccessful
func (s *Service) fetchAndWrite(r basics.Round, prevFetchCompleteChan chan bool, lookbackComplete chan bool, peerSelector *peerSelector) bool {
// If sync-ing this round is not intended, don't fetch it
if dontSyncRound := s.GetDisableSyncRound(); dontSyncRound != 0 && r >= basics.Round(dontSyncRound) {
return false
}
i := 0
hasLookback := false
for true {
Expand Down
90 changes: 90 additions & 0 deletions catchup/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,96 @@ func (cl *periodicSyncLogger) Warnf(s string, args ...interface{}) {
cl.Logger.Warnf(s, args...)
}

func TestSyncRound(t *testing.T) {
partitiontest.PartitionTest(t)

// Make Ledger
local := new(mockedLedger)
local.blocks = append(local.blocks, bookkeeping.Block{})

remote, _, blk, err := buildTestLedger(t, bookkeeping.Block{})
if err != nil {
t.Fatal(err)
return
}
addBlocks(t, remote, blk, 10)

// Create a network and block service
blockServiceConfig := config.GetDefaultLocal()
net := &httpTestPeerSource{}
ls := rpcs.MakeBlockService(logging.Base(), blockServiceConfig, remote, net, "test genesisID")

nodeA := basicRPCNode{}
nodeA.RegisterHTTPHandler(rpcs.BlockServiceBlockPath, ls)
nodeA.start()
defer nodeA.stop()
rootURL := nodeA.rootURL()
net.addPeer(rootURL)

auth := &mockedAuthenticator{fail: true}
initialLocalRound := local.LastRound()
require.True(t, 0 == initialLocalRound)

// Make Service
localCfg := config.GetDefaultLocal()
s := MakeService(logging.Base(), localCfg, net, local, auth, nil, nil)
s.log = &periodicSyncLogger{Logger: logging.Base()}
s.deadlineTimeout = 2 * time.Second

// Set disable round success
err = s.SetDisableSyncRound(3)
require.NoError(t, err)

s.Start()
defer s.Stop()
// wait past the initial sync - which is known to fail due to the above "auth"
time.Sleep(s.deadlineTimeout*2 - 200*time.Millisecond)
require.Equal(t, initialLocalRound, local.LastRound())
auth.alter(-1, false)

// wait until the catchup is done. Since we've might have missed the sleep window, we need to wait
// until the synchronization is complete.
waitStart := time.Now()
for time.Since(waitStart) < 2*s.deadlineTimeout {
if remote.LastRound() == local.LastRound() {
break
}
time.Sleep(20 * time.Millisecond)
}
Comment on lines +231 to +239
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: not sure if our version has it, I think this is what require.Eventually is for:

require.Eventually(
    func() bool { return remote.LastRound() == local.LastRound()},
    2*s.deadlineTimeout,
    20*time.Millisecond)

// Assert that the last block is the one we expect--i.e. disableSyncRound - 1
rnd := s.GetDisableSyncRound()
rr, lr := basics.Round(rnd-1), local.LastRound()
require.Equal(t, rr, lr)

for r := basics.Round(1); r < rr; r++ {
localBlock, err := local.Block(r)
require.NoError(t, err)
remoteBlock, err := remote.Block(r)
require.NoError(t, err)
require.Equal(t, remoteBlock.Hash(), localBlock.Hash())
}

// unset syncRound and make sure we finish catching up
s.UnsetDisableSyncRound()
// wait until the catchup is done
waitStart = time.Now()
for time.Now().Sub(waitStart) < 8*s.deadlineTimeout {
if remote.LastRound() == local.LastRound() {
break
}
time.Sleep(20 * time.Millisecond)
}
rr, lr = remote.LastRound(), local.LastRound()
require.Equal(t, rr, lr)
for r := basics.Round(1); r < remote.LastRound(); r++ {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
for r := basics.Round(1); r < remote.LastRound(); r++ {
for r := basics.Round(1); r < rr; r++ {

and should it be r<=rr?

localBlock, err := local.Block(r)
require.NoError(t, err)
remoteBlock, err := remote.Block(r)
require.NoError(t, err)
require.Equal(t, remoteBlock.Hash(), localBlock.Hash())
}
}

func TestPeriodicSync(t *testing.T) {
partitiontest.PartitionTest(t)

Expand Down
8 changes: 6 additions & 2 deletions daemon/algod/api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ GOPATH := $(shell go env GOPATH)
GOPATH1 := $(firstword $(subst :, ,$(GOPATH)))

# `make all` or just `make` should be appropriate for dev work
all: server/v2/generated/model/types.go server/v2/generated/nonparticipating/public/routes.go server/v2/generated/nonparticipating/private/routes.go server/v2/generated/participating/public/routes.go server/v2/generated/participating/private/routes.go
all: server/v2/generated/model/types.go server/v2/generated/nonparticipating/public/routes.go server/v2/generated/nonparticipating/private/routes.go server/v2/generated/participating/public/routes.go server/v2/generated/participating/private/routes.go server/v2/generated/data/routes.go

# `make generate` should be able to replace old `generate.sh` script and be appropriate for build system use
generate: oapi-codegen all
Expand All @@ -19,6 +19,10 @@ server/v2/generated/participating/public/routes.go: algod.oas3.yml
server/v2/generated/participating/private/routes.go: algod.oas3.yml
$(GOPATH1)/bin/oapi-codegen -config ./server/v2/generated/participating/private/private_routes.yml algod.oas3.yml


server/v2/generated/data/routes.go: algod.oas3.yml
$(GOPATH1)/bin/oapi-codegen -config ./server/v2/generated/data/data_routes.yml algod.oas3.yml

server/v2/generated/model/types.go: algod.oas3.yml
$(GOPATH1)/bin/oapi-codegen -config ./server/v2/generated/model/model_types.yml algod.oas3.yml

Expand All @@ -31,6 +35,6 @@ oapi-codegen: .PHONY
../../../scripts/buildtools/install_buildtools.sh -o github.com/algorand/oapi-codegen -c github.com/algorand/oapi-codegen/cmd/oapi-codegen

clean:
rm -rf server/v2/generated/model/types.go server/v2/generated/nonparticipating/public/routes.go server/v2/generated/nonparticipating/private/routes.go server/v2/generated/participating/public/routes.go server/v2/generated/participating/private/routes.go algod.oas3.yml
rm -rf server/v2/generated/model/types.go server/v2/generated/nonparticipating/public/routes.go server/v2/generated/nonparticipating/private/routes.go server/v2/generated/participating/public/routes.go server/v2/generated/participating/private/routes.go server/v2/generated/data/routes.go algod.oas3.yml

.PHONY:
Loading