From 5c504735d46b6e0ad332fddb19f469fecb56173c Mon Sep 17 00:00:00 2001 From: Matthias Fasching <5011972+fasmat@users.noreply.github.com> Date: Mon, 27 Nov 2023 08:40:52 +0000 Subject: [PATCH 01/48] Fix flaky test in timesync package (#5303) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Motivation Fixes a flaky test in the `timesync` package. ## Changes `Test_NodeClock_Await_BeforeGenesis` checks that awaiting a layer happens timely (within one tick interval). The test occasionally fails, when the tick interval aligns with the layer timing causing it to be a few µs late. The fix is to increase the allowed "lateness" slightly to not fail when this happens. ## Test Plan n/a ## TODO - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [x] Update [changelog](../CHANGELOG.md) as needed --- timesync/clock_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/timesync/clock_test.go b/timesync/clock_test.go index e91cb97bb4..889bd7ac3a 100644 --- a/timesync/clock_test.go +++ b/timesync/clock_test.go @@ -155,7 +155,10 @@ func Test_NodeClock_Await_BeforeGenesis(t *testing.T) { select { case <-clock.AwaitLayer(types.LayerID(0)): - require.WithinRange(t, time.Now(), genesis, genesis.Add(tickInterval)) + min := genesis + // allow for some delay (if tick interval aligns with layer duration) + max := genesis.Add(tickInterval).Add(10 * time.Millisecond) + require.WithinRange(t, time.Now(), min, max) case <-time.After(5 * time.Second): require.Fail(t, "timeout") } From dbc1183c0ad34eb5be246edfacc49f8278741674 Mon Sep 17 00:00:00 2001 From: Matthias Fasching <5011972+fasmat@users.noreply.github.com> Date: Mon, 27 Nov 2023 08:40:54 +0000 Subject: [PATCH 02/48] Fix timings in e2e tests (#5304) ## Motivation Fix flaky tests in `activation/e2e`. Test would randomly fail with the NIPostBuilder failing to fetch a poet proof. ## Changes - ensure that the spawned PoET and the nipost builder use the same genesis time instead of `time.Now()` - update PoET config to ensure that there is enough time to fetch a proof from PoET and retry in case PoET is slightly slow to generate the proof and the first request by NIPostBuilder fails ## Test Plan n/a ## TODO - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [x] Update [changelog](../CHANGELOG.md) as needed --- activation/e2e/nipost_test.go | 24 ++++++++++++------------ activation/e2e/validation_test.go | 8 ++++---- common/types/poet.go | 6 +++--- config/presets/fastnet.go | 1 - 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/activation/e2e/nipost_test.go b/activation/e2e/nipost_test.go index eb780d32e4..645f9cea2f 100644 --- a/activation/e2e/nipost_test.go +++ b/activation/e2e/nipost_test.go @@ -134,10 +134,12 @@ func TestNIPostBuilderWithClients(t *testing.T) { opts.Scrypt.N = 2 // Speedup initialization in tests. initPost(t, logger.Named("manager"), mgr, opts) + // ensure that genesis aligns with layer timings + genesis := time.Now().Add(layerDuration).Round(layerDuration) epoch := layersPerEpoch * layerDuration poetCfg := activation.PoetConfig{ PhaseShift: epoch / 2, - CycleGap: epoch / 5, + CycleGap: epoch / 4, GracePeriod: epoch / 5, RequestTimeout: epoch / 5, RequestRetryDelay: epoch / 50, @@ -145,7 +147,7 @@ func TestNIPostBuilderWithClients(t *testing.T) { } poetProver := spawnPoet( t, - WithGenesis(time.Now()), + WithGenesis(genesis), WithEpochDuration(epoch), WithPhaseShift(poetCfg.PhaseShift), WithCycleGap(poetCfg.CycleGap), @@ -154,8 +156,6 @@ func TestNIPostBuilderWithClients(t *testing.T) { mclock := activation.NewMocklayerClock(ctrl) mclock.EXPECT().LayerToTime(gomock.Any()).AnyTimes().DoAndReturn( func(got types.LayerID) time.Time { - // time.Now() ~= currentLayer - genesis := time.Now().Add(-time.Duration(postGenesisEpoch.FirstLayer()) * layerDuration) return genesis.Add(layerDuration * time.Duration(got)) }, ) @@ -266,18 +266,20 @@ func TestNewNIPostBuilderNotInitialized(t *testing.T) { mgr, err := activation.NewPostSetupManager(sig.NodeID(), cfg, logger, cdb, goldenATX) require.NoError(t, err) + // ensure that genesis aligns with layer timings + genesis := time.Now().Add(layerDuration).Round(layerDuration) epoch := layersPerEpoch * layerDuration poetCfg := activation.PoetConfig{ - PhaseShift: epoch / 5, - CycleGap: epoch / 10, - GracePeriod: epoch / 10, - RequestTimeout: epoch / 10, - RequestRetryDelay: epoch / 100, + PhaseShift: epoch / 2, + CycleGap: epoch / 4, + GracePeriod: epoch / 5, + RequestTimeout: epoch / 5, + RequestRetryDelay: epoch / 50, MaxRequestRetries: 10, } poetProver := spawnPoet( t, - WithGenesis(time.Now()), + WithGenesis(genesis), WithEpochDuration(epoch), WithPhaseShift(poetCfg.PhaseShift), WithCycleGap(poetCfg.CycleGap), @@ -286,8 +288,6 @@ func TestNewNIPostBuilderNotInitialized(t *testing.T) { mclock := activation.NewMocklayerClock(ctrl) mclock.EXPECT().LayerToTime(gomock.Any()).AnyTimes().DoAndReturn( func(got types.LayerID) time.Time { - // time.Now() ~= currentLayer - genesis := time.Now().Add(-time.Duration(postGenesisEpoch.FirstLayer()) * layerDuration) return genesis.Add(layerDuration * time.Duration(got)) }, ) diff --git a/activation/e2e/validation_test.go b/activation/e2e/validation_test.go index 7e4b505a2c..4ba2ed8bf7 100644 --- a/activation/e2e/validation_test.go +++ b/activation/e2e/validation_test.go @@ -41,10 +41,12 @@ func TestValidator_Validate(t *testing.T) { opts.Scrypt.N = 2 // Speedup initialization in tests. initPost(t, logger.Named("manager"), mgr, opts) + // ensure that genesis aligns with layer timings + genesis := time.Now().Add(layerDuration).Round(layerDuration) epoch := layersPerEpoch * layerDuration poetCfg := activation.PoetConfig{ PhaseShift: epoch / 2, - CycleGap: epoch / 5, + CycleGap: epoch / 4, GracePeriod: epoch / 5, RequestTimeout: epoch / 5, RequestRetryDelay: epoch / 50, @@ -52,7 +54,7 @@ func TestValidator_Validate(t *testing.T) { } poetProver := spawnPoet( t, - WithGenesis(time.Now()), + WithGenesis(genesis), WithEpochDuration(epoch), WithPhaseShift(poetCfg.PhaseShift), WithCycleGap(poetCfg.CycleGap), @@ -61,8 +63,6 @@ func TestValidator_Validate(t *testing.T) { mclock := activation.NewMocklayerClock(ctrl) mclock.EXPECT().LayerToTime(gomock.Any()).AnyTimes().DoAndReturn( func(got types.LayerID) time.Time { - // time.Now() ~= currentLayer - genesis := time.Now().Add(-time.Duration(postGenesisEpoch.FirstLayer()) * layerDuration) return genesis.Add(layerDuration * time.Duration(got)) }, ) diff --git a/common/types/poet.go b/common/types/poet.go index 5e4ef821b0..167c3ec97c 100644 --- a/common/types/poet.go +++ b/common/types/poet.go @@ -111,11 +111,11 @@ func (p *PoetProofMessage) MarshalLogObject(encoder log.ObjectEncoder) error { } // Ref returns the reference to the PoET proof message. It's the blake3 sum of the entire proof message. -func (proofMessage *PoetProofMessage) Ref() (PoetProofRef, error) { - poetProofBytes, err := codec.Encode(&proofMessage.PoetProof) +func (p *PoetProofMessage) Ref() (PoetProofRef, error) { + poetProofBytes, err := codec.Encode(&p.PoetProof) if err != nil { return PoetProofRef{}, fmt.Errorf("failed to marshal poet proof for poetId %x round %v: %w", - proofMessage.PoetServiceID, proofMessage.RoundID, err) + p.PoetServiceID, p.RoundID, err) } h := CalcHash32(poetProofBytes) return (PoetProofRef)(h), nil diff --git a/config/presets/fastnet.go b/config/presets/fastnet.go index 767c838051..ac98f720f0 100644 --- a/config/presets/fastnet.go +++ b/config/presets/fastnet.go @@ -22,7 +22,6 @@ func fastnet() config.Config { conf.BaseConfig.OptFilterThreshold = 90 conf.BaseConfig.DatabasePruneInterval = time.Minute - conf.ATXGradeDelay = 1 * time.Second // set for systest TestEquivocation conf.BaseConfig.MinerGoodAtxsPercent = 50 From 9504894d9550f673c4227eea3facfc1815a52c37 Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Mon, 27 Nov 2023 11:12:25 +0000 Subject: [PATCH 03/48] use hare1 certificate comittee size (#5307) --- config/presets/testnet.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/presets/testnet.go b/config/presets/testnet.go index 9e46a08ad9..1aac18d5a0 100644 --- a/config/presets/testnet.go +++ b/config/presets/testnet.go @@ -13,6 +13,7 @@ import ( "github.com/spacemeshos/go-spacemesh/activation" "github.com/spacemeshos/go-spacemesh/api/grpcserver" "github.com/spacemeshos/go-spacemesh/beacon" + "github.com/spacemeshos/go-spacemesh/blocks" "github.com/spacemeshos/go-spacemesh/bootstrap" "github.com/spacemeshos/go-spacemesh/checkpoint" "github.com/spacemeshos/go-spacemesh/common/types" @@ -143,5 +144,11 @@ func testnet() config.Config { }, Recovery: checkpoint.DefaultConfig(), Cache: datastore.DefaultConfig(), + Certificate: blocks.CertConfig{ + // NOTE(dshulyak) this is intentional. we increased committee size with hare3 upgrade + // but certifier continues to use 200 committee size. + // this will be upgraded in future with scheduled upgrade. + CommitteeSize: 200, + }, } } From f76dc5adc3ed9c51d900494b9365a015dfd039f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:14:56 +0000 Subject: [PATCH 04/48] build(deps): Bump golang.org/x/time from 0.4.0 to 0.5.0 (#5308) Bumps https://github.com/golang/time from 0.4.0 to 0.5.0. Co-authored-by: Matthias <5011972+fasmat@users.noreply.github.com> --- activation/activation_test.go | 8 ++++---- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/activation/activation_test.go b/activation/activation_test.go index 10ec60f3da..c79e6d7662 100644 --- a/activation/activation_test.go +++ b/activation/activation_test.go @@ -1352,8 +1352,8 @@ func TestWaitPositioningAtx(t *testing.T) { targetEpoch types.EpochID }{ - {"no wait", 100 * time.Millisecond, 100 * time.Millisecond, 2}, - {"wait", 100 * time.Millisecond, 0, 2}, + {"no wait", 200 * time.Millisecond, 200 * time.Millisecond, 2}, + {"wait", 200 * time.Millisecond, 0, 2}, {"round started", 0, 0, 3}, } { tc := tc @@ -1365,7 +1365,7 @@ func TestWaitPositioningAtx(t *testing.T) { tab.mclock.EXPECT().CurrentLayer().Return(types.LayerID(0)).AnyTimes() tab.mclock.EXPECT().LayerToTime(gomock.Any()).DoAndReturn(func(lid types.LayerID) time.Time { // layer duration is 10ms to speed up test - return genesis.Add(time.Duration(lid) * 10 * time.Millisecond) + return genesis.Add(time.Duration(lid) * 20 * time.Millisecond) }).AnyTimes() // everything else are stubs that are irrelevant for the test @@ -1379,7 +1379,7 @@ func TestWaitPositioningAtx(t *testing.T) { func(_ context.Context, _ string, got []byte) error { var gotAtx types.ActivationTx require.NoError(t, codec.Decode(got, &gotAtx)) - require.Equal(t, gotAtx.TargetEpoch(), tc.targetEpoch) + require.Equal(t, tc.targetEpoch, gotAtx.TargetEpoch()) return nil }) diff --git a/go.mod b/go.mod index 0d162df076..22f34fabb1 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.5.0 - golang.org/x/time v0.4.0 + golang.org/x/time v0.5.0 google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 diff --git a/go.sum b/go.sum index 2b819139f5..18987a6497 100644 --- a/go.sum +++ b/go.sum @@ -952,8 +952,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= -golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 6499e0174403a4f57ee8842401e003fee578c54e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 08:43:06 +0000 Subject: [PATCH 05/48] build(deps): Bump github.com/spf13/afero from 1.10.0 to 1.11.0 (#5309) Bumps [github.com/spf13/afero](https://github.com/spf13/afero) from 1.10.0 to 1.11.0. --- go.mod | 24 ++++++------- go.sum | 109 +++++++++++++-------------------------------------------- 2 files changed, 36 insertions(+), 97 deletions(-) diff --git a/go.mod b/go.mod index 22f34fabb1..0ac81ca577 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/spacemeshos/merkle-tree v0.2.3 github.com/spacemeshos/poet v0.9.7 github.com/spacemeshos/post v0.10.2 - github.com/spf13/afero v1.10.0 + github.com/spf13/afero v1.11.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.17.0 @@ -52,7 +52,7 @@ require ( golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.5.0 golang.org/x/time v0.5.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 + google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 k8s.io/api v0.28.4 @@ -62,10 +62,10 @@ require ( ) require ( - cloud.google.com/go v0.110.9 // indirect - cloud.google.com/go/compute v1.23.2 // indirect + cloud.google.com/go v0.110.10 // indirect + cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.4 // indirect + cloud.google.com/go/iam v1.1.5 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/anacrolix/chansync v0.3.0 // indirect github.com/anacrolix/missinggo v1.2.1 // indirect @@ -198,20 +198,20 @@ require ( go.uber.org/dig v1.17.1 // indirect go.uber.org/fx v1.20.1 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.15.0 // indirect + golang.org/x/crypto v0.16.0 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.18.0 // indirect - golang.org/x/oauth2 v0.13.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/term v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.15.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect gonum.org/v1/gonum v0.13.0 // indirect - google.golang.org/api v0.150.0 // indirect + google.golang.org/api v0.152.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect + google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 18987a6497..74620c4e42 100644 --- a/go.sum +++ b/go.sum @@ -5,7 +5,6 @@ cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgo cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -16,25 +15,22 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.110.9 h1:e7ITSqGFFk4rbz/JFIqZh3G4VEHguhAL4BQcFlWtU68= -cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= +cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= +cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers= -cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v1.1.4 h1:K6n/GZHFTtEoKT5aUG3l9diPi0VduZNQ1PfdnpkkIFk= -cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= +cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -44,7 +40,6 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w= cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= @@ -101,7 +96,6 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= @@ -140,8 +134,6 @@ github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRr github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 h1:S92OBrGuLLZsyM5ybUzgc/mPjIYk2AZqufieooe98uw= @@ -252,7 +244,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -266,7 +257,6 @@ github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -276,9 +266,6 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -296,7 +283,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= @@ -344,7 +330,6 @@ github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63 github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -405,7 +390,6 @@ github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -555,7 +539,6 @@ github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -655,8 +638,8 @@ github.com/spacemeshos/sha256-simd v0.1.0 h1:G7Mfu5RYdQiuE+wu4ZyJ7I0TI74uqLhFnKb github.com/spacemeshos/sha256-simd v0.1.0/go.mod h1:O8CClVIilId7RtuCMV2+YzMj6qjVn75JsxOxaE8vcfM= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= -github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= @@ -714,7 +697,6 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= @@ -761,10 +743,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -790,7 +770,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -799,8 +778,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= @@ -837,17 +814,13 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 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-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= 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= @@ -855,13 +828,9 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -872,7 +841,6 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -914,38 +882,29 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/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.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.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.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1002,14 +961,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= @@ -1042,11 +994,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.150.0 h1:Z9k22qD289SZ8gCJrk4DrWXkNjtfvKAUo/l1ma8eBYE= -google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= +google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY= +google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1092,19 +1041,12 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U= -google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1120,10 +1062,7 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= From 4d49430e39b750c227b235316a29736a0103753b Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Wed, 29 Nov 2023 19:00:29 +0000 Subject: [PATCH 06/48] hare/eligibility: refactor expensive logging (#5312) mainly to remove encoding a set of ids if identity is inactive. it is very expensive to serialize to string thousands of 32 bytes values. i started to refactor oracle https://github.com/spacemeshos/go-spacemesh/pull/5283 but won't finish it for some time. --- hare/eligibility/oracle.go | 21 ++++++++------------- log/zap.go | 5 +++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/hare/eligibility/oracle.go b/hare/eligibility/oracle.go index 99d0612ece..44fc539578 100644 --- a/hare/eligibility/oracle.go +++ b/hare/eligibility/oracle.go @@ -160,11 +160,6 @@ func (o *Oracle) minerWeight(ctx context.Context, layer types.LayerID, id types. w, ok := actives.set[id] if !ok { - o.With().Debug("miner is not active in specified layer", - log.Int("active_set_size", len(actives.set)), - log.String("actives", fmt.Sprintf("%v", actives)), - layer, log.Stringer("id.Key", id), - ) return 0, fmt.Errorf("%w: %v", ErrNotActive, id) } return w, nil @@ -275,7 +270,7 @@ func (o *Oracle) Validate( defer func() { if msg := recover(); msg != nil { o.WithContext(ctx).With().Fatal("panic in validate", - log.String("msg", fmt.Sprint(msg)), + log.Any("msg", msg), log.Int("n", n), log.String("p", p.String()), log.String("vrf_frac", vrfFrac.String()), @@ -294,8 +289,8 @@ func (o *Oracle) Validate( id, log.Uint16("eligibility_count", eligibilityCount), log.Int("n", n), - log.String("p", p.String()), - log.String("vrf_frac", vrfFrac.String()), + log.Float64("p", p.Float()), + log.Float64("vrf_frac", vrfFrac.Float()), log.Int("x", x), ) return false, nil @@ -322,11 +317,11 @@ func (o *Oracle) CalcEligibility( layer, layer.GetEpoch(), log.Uint32("round_id", round), - log.String("msg", fmt.Sprint(msg)), + log.Any("msg", msg), log.Int("committee_size", committeeSize), log.Int("n", n), - log.String("p", fmt.Sprintf("%g", p.Float())), - log.String("vrf_frac", fmt.Sprintf("%g", vrfFrac.Float())), + log.Float64("p", p.Float()), + log.Float64("vrf_frac", vrfFrac.Float()), ) } }() @@ -337,8 +332,8 @@ func (o *Oracle) CalcEligibility( log.Uint32("round_id", round), log.Int("committee_size", committeeSize), log.Int("n", n), - log.String("p", fmt.Sprintf("%g", p.Float())), - log.String("vrf_frac", fmt.Sprintf("%g", vrfFrac.Float())), + log.Float64("p", p.Float()), + log.Float64("vrf_frac", vrfFrac.Float()), ) for x := 0; x < n; x++ { diff --git a/log/zap.go b/log/zap.go index ff13aa491e..9d5fd7d008 100644 --- a/log/zap.go +++ b/log/zap.go @@ -140,6 +140,11 @@ func Uint64(name string, val uint64) Field { return Field(zap.Uint64(name, val)) } +// Float64 returns a float64 Field. +func Float64(name string, val float64) Field { + return Field(zap.Float64(name, val)) +} + // Namespace make next fields be inside a namespace. func Namespace(name string) Field { return Field(zap.Namespace(name)) From 678080f0a5cce837b3f95b980780f2a2be47c006 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 22:15:05 +0000 Subject: [PATCH 07/48] build(deps): Bump github.com/libp2p/go-libp2p-kad-dht from 0.25.1 to 0.25.2 (#5310) Bumps [github.com/libp2p/go-libp2p-kad-dht](https://github.com/libp2p/go-libp2p-kad-dht) from 0.25.1 to 0.25.2. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0ac81ca577..58d55322c1 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/ipfs/go-log/v2 v2.5.1 github.com/jonboulle/clockwork v0.4.0 github.com/libp2p/go-libp2p v0.32.1 - github.com/libp2p/go-libp2p-kad-dht v0.25.1 + github.com/libp2p/go-libp2p-kad-dht v0.25.2 github.com/libp2p/go-libp2p-pubsub v0.10.0 github.com/libp2p/go-libp2p-record v0.2.0 github.com/mitchellh/mapstructure v1.5.0 diff --git a/go.sum b/go.sum index 74620c4e42..101d2422f1 100644 --- a/go.sum +++ b/go.sum @@ -410,8 +410,8 @@ github.com/libp2p/go-libp2p v0.32.1 h1:wy1J4kZIZxOaej6NveTWCZmHiJ/kY7GoAqXgqNCnP github.com/libp2p/go-libp2p v0.32.1/go.mod h1:hXXC3kXPlBZ1eu8Q2hptGrMB4mZ3048JUoS4EKaHW5c= github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= -github.com/libp2p/go-libp2p-kad-dht v0.25.1 h1:ofFNrf6MMEy4vi3R1VbJ7LOcTn3Csh0cDcaWHTxtWNA= -github.com/libp2p/go-libp2p-kad-dht v0.25.1/go.mod h1:6za56ncRHYXX4Nc2vn8z7CZK0P4QiMcrn77acKLM2Oo= +github.com/libp2p/go-libp2p-kad-dht v0.25.2 h1:FOIk9gHoe4YRWXTu8SY9Z1d0RILol0TrtApsMDPjAVQ= +github.com/libp2p/go-libp2p-kad-dht v0.25.2/go.mod h1:6za56ncRHYXX4Nc2vn8z7CZK0P4QiMcrn77acKLM2Oo= github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0= github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0= github.com/libp2p/go-libp2p-pubsub v0.10.0 h1:wS0S5FlISavMaAbxyQn3dxMOe2eegMfswM471RuHJwA= From 65b77b24f16b923fcce5b5dd8b971e9b14f64c89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:20:58 +0000 Subject: [PATCH 08/48] build(deps): Bump google-github-actions/auth from 1 to 2 (#5316) Bumps [google-github-actions/auth](https://github.com/google-github-actions/auth) from 1 to 2. --- .github/workflows/release.yml | 2 +- .github/workflows/systest.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 80b54a2e3c..ea3c455bf3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -68,7 +68,7 @@ jobs: zip -r $OUTNAME.zip $OUTNAME - name: 'Setup GCP Auth' - uses: 'google-github-actions/auth@v1' + uses: 'google-github-actions/auth@v2' with: credentials_json: '${{ secrets.GCP_SA_KEY }}' diff --git a/.github/workflows/systest.yml b/.github/workflows/systest.yml index 042b4f81e2..1a284bb9e3 100644 --- a/.github/workflows/systest.yml +++ b/.github/workflows/systest.yml @@ -62,7 +62,7 @@ jobs: - name: Setup gcloud authentication id: "auth" - uses: "google-github-actions/auth@v1" + uses: "google-github-actions/auth@v2" with: # GCP_CREDENTIALS is minified JSON of service account credentials_json: "${{ secrets.CI_GCP_CREDENTIALS }}" From 4f0520eb73e85ea85e0dd145953cf7520ef8bfc4 Mon Sep 17 00:00:00 2001 From: Matthias Fasching <5011972+fasmat@users.noreply.github.com> Date: Thu, 30 Nov 2023 22:50:49 +0000 Subject: [PATCH 09/48] Allow nodes to be started ready for remote smeshing (#5314) ## Motivation This changes the node startup in a way to allow a node to receive a remote PoST service connection. ## Changes - if `--smeshing-start` is provided, but no `--smeshing-coinbase` the node will panic during startup - if both are provided node operates in supervised mode (smapp usecase) - if the provided coinbase is not valid the node will also panic during startup - if `--smeshing-coinbase` is provided, but not `--smeshing-start` the node will be prepared to accept connections from remote PoST services - this additionally requires the following config parameters to be set to actually work (**TODO**: verify those during startup?) - `grpc-tls-listener` - `grpc-tls-ca-cert` - `grpc-tls-cert` - `grpc-tls-key` - if neither `--smeshing-start` nor `--smeshing-coinbase` are provided the node can still be instructed to start (and stop) the supervised PoST mode via GRPC (**required for system tests** - coinbase is passed as argument and verified by node) - if `--smeshing-coinbase` is not defined, but the TLS listener is set up correctly, remote connections should succeed but the node will not start smeshing (i.e. register at PoET, generate PoST proofs, publish ATXs, etc.) ## Test Plan TODO: add system tests with remote post service ## TODO - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [ ] Update [changelog](../CHANGELOG.md) as needed --- .github/workflows/release.yml | 2 +- activation/activation.go | 2 - activation/activation_test.go | 7 +-- api/grpcserver/config.go | 2 +- node/node.go | 104 +++++++++++++++------------------- systest/cluster/nodes.go | 2 +- 6 files changed, 50 insertions(+), 69 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ea3c455bf3..fdbe51d5a5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,7 +55,7 @@ jobs: shell: bash run: | make install - make build VERSION=${{ github.ref_name }} BIN_DIR_WIN=./build + make build VERSION=${{ github.ref_name }} - name: Create release archive shell: bash diff --git a/activation/activation.go b/activation/activation.go index 68ecdd6868..55e87f4cb9 100644 --- a/activation/activation.go +++ b/activation/activation.go @@ -58,7 +58,6 @@ const ( // Config defines configuration for Builder. type Config struct { - CoinbaseAccount types.Address GoldenATXID types.ATXID LayersPerEpoch uint32 RegossipInterval time.Duration @@ -143,7 +142,6 @@ func NewBuilder( b := &Builder{ parentCtx: context.Background(), signer: signer, - coinbaseAccount: conf.CoinbaseAccount, goldenATXID: conf.GoldenATXID, regossipInterval: conf.RegossipInterval, cdb: cdb, diff --git a/activation/activation_test.go b/activation/activation_test.go index c79e6d7662..f5940cf47d 100644 --- a/activation/activation_test.go +++ b/activation/activation_test.go @@ -107,7 +107,6 @@ type testAtxBuilder struct { cdb *datastore.CachedDB localDb *localsql.Database sig *signing.EdSigner - coinbase types.Address goldenATXID types.ATXID mpub *mocks.MockPublisher @@ -128,7 +127,6 @@ func newTestBuilder(tb testing.TB, opts ...BuilderOption) *testAtxBuilder { cdb: datastore.NewCachedDB(sql.InMemory(), lg), localDb: localsql.InMemory(), sig: edSigner, - coinbase: types.GenerateAddress([]byte("33333")), goldenATXID: types.ATXID(types.HexToHash32("77777")), mpub: mocks.NewMockPublisher(ctrl), mpostSvc: NewMockpostService(ctrl), @@ -142,9 +140,8 @@ func newTestBuilder(tb testing.TB, opts ...BuilderOption) *testAtxBuilder { opts = append(opts, WithValidator(tab.mValidator)) cfg := Config{ - CoinbaseAccount: tab.coinbase, - GoldenATXID: tab.goldenATXID, - LayersPerEpoch: layersPerEpoch, + GoldenATXID: tab.goldenATXID, + LayersPerEpoch: layersPerEpoch, } tab.msync.EXPECT().RegisterForATXSynced().DoAndReturn(closedChan).AnyTimes() diff --git a/api/grpcserver/config.go b/api/grpcserver/config.go index 89351a1f1a..4ae4a67d39 100644 --- a/api/grpcserver/config.go +++ b/api/grpcserver/config.go @@ -12,7 +12,7 @@ type Config struct { PrivateListener string `mapstructure:"grpc-private-listener"` TLSServices []Service TLSListener string `mapstructure:"grpc-tls-listener"` - TLSCACert string `mapstructure:"gprc-tls-ca-cert"` + TLSCACert string `mapstructure:"grpc-tls-ca-cert"` TLSCert string `mapstructure:"grpc-tls-cert"` TLSKey string `mapstructure:"grpc-tls-key"` GrpcSendMsgSize int `mapstructure:"grpc-send-msg-size"` diff --git a/node/node.go b/node/node.go index d4ada5741a..6e0a0e485a 100644 --- a/node/node.go +++ b/node/node.go @@ -191,7 +191,7 @@ func GetCommand() *cobra.Command { // os.Interrupt for all systems, especially windows, syscall.SIGTERM is mainly for docker. ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer cancel() - if err = run(ctx); err != nil { + if err := run(ctx); err != nil { app.log.With().Fatal(err.Error()) } }, @@ -665,7 +665,7 @@ func (app *App) initServices(ctx context.Context) error { mlog := app.addLogger(MeshLogger, lg) msh, err := mesh.NewMesh(app.cachedDB, app.atxsdata, app.clock, trtl, executor, app.conState, mlog) if err != nil { - return fmt.Errorf("failed to create mesh: %w", err) + return fmt.Errorf("create mesh: %w", err) } pruner := prune.New(app.db, app.Config.Tortoise.Hdist, app.Config.PruneActivesetsFrom, prune.WithLogger(mlog.Zap())) @@ -866,38 +866,34 @@ func (app *App) initServices(ctx context.Context) error { ) proposalBuilder.Register(app.edSgn) - if app.Config.SMESHING.Start { - u := url.URL{ - Scheme: "http", - Host: app.Config.API.PrivateListener, - } - app.Config.POSTService.NodeAddress = u.String() - - postSetupMgr, err := activation.NewPostSetupManager( - app.edSgn.NodeID(), - app.Config.POST, - app.addLogger(PostLogger, lg).Zap(), - app.cachedDB, goldenATXID, - ) - if err != nil { - app.log.Panic("failed to create post setup manager: %v", err) - } + u := url.URL{ + Scheme: "http", + Host: app.Config.API.PrivateListener, + } + app.Config.POSTService.NodeAddress = u.String() + postSetupMgr, err := activation.NewPostSetupManager( + app.edSgn.NodeID(), + app.Config.POST, + app.addLogger(PostLogger, lg).Zap(), + app.cachedDB, goldenATXID, + ) + if err != nil { + return fmt.Errorf("create post setup manager: %v", err) + } - app.postSupervisor, err = activation.NewPostSupervisor( - app.log.Zap(), - app.Config.POSTService, - app.Config.POST, - app.Config.SMESHING.ProvingOpts, - postSetupMgr, - newSyncer, - ) - if err != nil { - return fmt.Errorf("init post service: %w", err) - } + app.postSupervisor, err = activation.NewPostSupervisor( + app.log.Zap(), + app.Config.POSTService, + app.Config.POST, + app.Config.SMESHING.ProvingOpts, + postSetupMgr, + newSyncer, + ) + if err != nil { + return fmt.Errorf("init post service: %w", err) } app.grpcPostService = grpcserver.NewPostService(app.addLogger(PostServiceLogger, lg).Zap()) - nipostBuilder, err := activation.NewNIPostBuilder( poetDb, app.grpcPostService, @@ -909,29 +905,10 @@ func (app *App) initServices(ctx context.Context) error { app.clock, ) if err != nil { - app.log.Panic("failed to create nipost builder: %v", err) - } - - var coinbaseAddr types.Address - if app.Config.SMESHING.Start { - // TODO(mafa): this won't work with a remote-only setup, where `smeshing-start` is set to false - // TODO(mafa): also the way we handle coinbase means only 1 address can receive rewards, independent - // of the number of identities/post services that are managed by the node - coinbaseAddr, err = types.StringToAddress(app.Config.SMESHING.CoinbaseAccount) - if err != nil { - app.log.Panic( - "failed to parse CoinbaseAccount address `%s`: %v", - app.Config.SMESHING.CoinbaseAccount, - err, - ) - } - if coinbaseAddr.IsEmpty() { - app.log.Panic("invalid coinbase account") - } + return fmt.Errorf("create nipost builder: %w", err) } builderConfig := activation.Config{ - CoinbaseAccount: coinbaseAddr, GoldenATXID: goldenATXID, LayersPerEpoch: layersPerEpoch, RegossipInterval: app.Config.RegossipAtxInterval, @@ -1179,7 +1156,7 @@ func (app *App) listenToUpdates(ctx context.Context) { func (app *App) startServices(ctx context.Context) error { if err := app.fetcher.Start(); err != nil { - return fmt.Errorf("failed to start fetcher: %w", err) + return fmt.Errorf("start fetcher: %w", err) } app.syncer.Start() app.beaconProtocol.Start(ctx) @@ -1190,17 +1167,23 @@ func (app *App) startServices(ctx context.Context) error { return app.proposalBuilder.Run(ctx) }) - if app.Config.SMESHING.Start { + if app.Config.SMESHING.CoinbaseAccount != "" { coinbaseAddr, err := types.StringToAddress(app.Config.SMESHING.CoinbaseAccount) if err != nil { - app.log.Panic( - "failed to parse CoinbaseAccount address on start `%s`: %v", + return fmt.Errorf( + "parse CoinbaseAccount address on start `%s`: %w", app.Config.SMESHING.CoinbaseAccount, err, ) } if err := app.atxBuilder.StartSmeshing(coinbaseAddr); err != nil { - app.log.Panic("failed to start smeshing: %v", err) + return fmt.Errorf("start smeshing: %w", err) + } + } + + if app.Config.SMESHING.Start { + if app.Config.SMESHING.CoinbaseAccount == "" { + return fmt.Errorf("smeshing enabled but no coinbase account provided") } if err := app.postSupervisor.Start(app.Config.SMESHING.Opts); err != nil { return fmt.Errorf("start post service: %w", err) @@ -1352,6 +1335,9 @@ func (app *App) startAPIServices(ctx context.Context) error { if err != nil { return err } + if err := app.grpcTLSServer.Start(); err != nil { + return err + } } if len(app.Config.API.JSONListener) > 0 { @@ -1579,7 +1565,7 @@ func (app *App) setupDBs(ctx context.Context, lg log.Log) error { ) migrations, err = sql.LocalMigrations() if err != nil { - return fmt.Errorf("failed to load local migrations: %w", err) + return fmt.Errorf("load local migrations: %w", err) } localDB, err := localsql.Open("file:"+filepath.Join(dbPath, localDbFile), sql.WithMigrations(migrations), @@ -1709,14 +1695,14 @@ func (app *App) startSynchronous(ctx context.Context) (err error) { p2p.WithNodeReporter(events.ReportNodeStatusUpdate), ) if err != nil { - return fmt.Errorf("failed to initialize p2p host: %w", err) + return fmt.Errorf("initialize p2p host: %w", err) } if err := app.setupDBs(ctx, lg); err != nil { return err } if err := app.initServices(ctx); err != nil { - return fmt.Errorf("cannot start services: %w", err) + return fmt.Errorf("init services: %w", err) } if app.Config.CollectMetrics { @@ -1735,7 +1721,7 @@ func (app *App) startSynchronous(ctx context.Context) (err error) { } if err := app.startServices(ctx); err != nil { - return err + return fmt.Errorf("start services: %w", err) } // need post verifying service to start first diff --git a/systest/cluster/nodes.go b/systest/cluster/nodes.go index 04663e4d4b..27d4a8a8c8 100644 --- a/systest/cluster/nodes.go +++ b/systest/cluster/nodes.go @@ -106,7 +106,7 @@ const ( poetConfigMapName = "poet" spacemeshConfigMapName = "spacemesh" - // smeshers are splitted in 10 approximately equal buckets + // smeshers are split in 10 approximately equal buckets // to enable running chaos mesh tasks on the different parts of the cluster. buckets = 10 ) From c6ed5aad396cb825ecdef879b060910fd1a0d71a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowak?= Date: Fri, 1 Dec 2023 08:48:14 +0000 Subject: [PATCH 10/48] Raise the atx-size cache to 300_000 (#5320) To cache this and previous epoch ATXes. It should help with diskIO and CPU during the official poet CG & epochs. --- datastore/store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datastore/store.go b/datastore/store.go index a11c2eed00..c381b063d1 100644 --- a/datastore/store.go +++ b/datastore/store.go @@ -50,7 +50,7 @@ type Config struct { func DefaultConfig() Config { return Config{ - ATXSize: 150_000, + ATXSize: 300_000, MalfeasenceSize: 1_000, } } From 3ae2bf3ad3f9795a36d181c1ecf3526e3a882f2c Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Fri, 1 Dec 2023 11:09:39 +0000 Subject: [PATCH 11/48] Don't allow builds with "...nomain" git tag to run on mainnet (#5287) Some versions are test builds that are not intended for use on the mainnet. This PR makes it possible to enforce that by making any builds from git tags that contain `nomain` substring refuse to run on the mainnet. --- Makefile | 7 ++++++- cmd/base.go | 3 +++ cmd/node/main.go | 8 +++++--- node/node.go | 9 +++++++++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 688219d1ae..11aa256e4b 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,12 @@ DOCKER_HUB ?= spacemeshos DOCKER_IMAGE_REPO ?= go-spacemesh-dev DOCKER_IMAGE_VERSION ?= $(SHA) -LDFLAGS = -ldflags "-X main.version=${VERSION} -X main.commit=${COMMIT} -X main.branch=${BRANCH}" +C_LDFLAGS = -X main.version=${VERSION} -X main.commit=${COMMIT} -X main.branch=${BRANCH} +ifneq (,$(findstring nomain,$(VERSION))) + C_LDFLAGS += -X main.noMainNet=true +endif +LDFLAGS = -ldflags "$(C_LDFLAGS)" + include Makefile-libs.Inc UNIT_TESTS ?= $(shell go list ./... | grep -v systest/tests | grep -v cmd/node | grep -v cmd/gen-p2p-identity | grep -v cmd/trace | grep -v genvm/cmd) diff --git a/cmd/base.go b/cmd/base.go index 5b90131fa8..9867eb340b 100644 --- a/cmd/base.go +++ b/cmd/base.go @@ -24,6 +24,9 @@ var ( // Commit is the git commit used to build the app. Designed to be overwritten by make. Commit string + + // Prohibit this build from running on the mainnet. + NoMainNet bool ) // EnsureCLIFlags checks flag types and converts them. diff --git a/cmd/node/main.go b/cmd/node/main.go index 4fb931a48c..99ef2265e4 100644 --- a/cmd/node/main.go +++ b/cmd/node/main.go @@ -12,15 +12,17 @@ import ( ) var ( - version string - commit string - branch string + version string + commit string + branch string + noMainNet string ) func main() { // run the app cmd.Version = version cmd.Commit = commit cmd.Branch = branch + cmd.NoMainNet = noMainNet == "true" if err := node.GetCommand().Execute(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) diff --git a/node/node.go b/node/node.go index 6e0a0e485a..2e5ae85fce 100644 --- a/node/node.go +++ b/node/node.go @@ -131,6 +131,11 @@ func GetCommand() *cobra.Command { if conf.LOGGING.Encoder == config.JSONLogEncoder { log.JSONLog(true) } + + if cmd.NoMainNet && onMainNet(conf) { + log.With().Fatal("this is a testnet-only build not intended for mainnet") + } + app := New( WithConfig(conf), // NOTE(dshulyak) this needs to be max level so that child logger can can be current level or below. @@ -1819,3 +1824,7 @@ func (w tortoiseWeakCoin) Set(lid types.LayerID, value bool) error { w.tortoise.OnWeakCoin(lid, value) return nil } + +func onMainNet(conf *config.Config) bool { + return conf.Genesis.GenesisTime == config.MainnetConfig().Genesis.GenesisTime +} From d424b786fc9ff6ec0d9c0644f991eda9205db0e6 Mon Sep 17 00:00:00 2001 From: Lane Rettig Date: Sat, 2 Dec 2023 00:48:27 +0000 Subject: [PATCH 12/48] vm, api: add smesherID to rewards (#5199) ## Motivation See #4863 Based on #4850 Closes #4529 Closes #4850 Closes #4863 Closes #4964 Closes #5183 ## Changes - Refactors `rewards` table. Adds smesherID column, migrates data. Does not update old data (smesherID will be NULL for old data, unless resynced). - Updates database queries. - Returns smesherID in all API queries Co-authored-by: Piers Powlesland Co-authored-by: piersy Co-authored-by: Dmitry Shulyak --- CHANGELOG.md | 7 + api/grpcserver/globalstate_service.go | 20 +- api/grpcserver/globalstate_service_test.go | 10 +- api/grpcserver/grpcserver_test.go | 56 +++-- api/grpcserver/interface.go | 3 +- api/grpcserver/mocks.go | 63 ++++- cmd/bootstrapper/generator_test.go | 20 +- common/types/block.go | 7 +- common/types/transaction.go | 1 + common/types/transaction_scale.go | 14 ++ events/reporter.go | 1 + genvm/rewards.go | 1 + genvm/vm.go | 1 + genvm/vm_test.go | 5 +- mesh/executor.go | 5 +- mesh/executor_test.go | 36 +-- mesh/mesh.go | 11 +- sql/database.go | 7 - sql/functions.go | 20 -- sql/migrations/state/0008_next.sql | 15 ++ sql/migrations_test.go | 2 +- sql/rewards/rewards.go | 81 +++++-- sql/rewards/rewards_test.go | 261 ++++++++++++++++++++- 23 files changed, 496 insertions(+), 151 deletions(-) delete mode 100644 sql/functions.go create mode 100644 sql/migrations/state/0008_next.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index d7e352d816..9958920db6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,13 @@ See [RELEASE](./RELEASE.md) for workflow instructions. ### Improvements +* [#5199](https://github.com/spacemeshos/go-spacemesh/pull/5199) Adds smesherID to rewards table. Historically rewards + were keyed by (coinbase, layer). Now the primary key has changed to (smesherID, layer), which allows querying rewards + by any subset of layer, smesherID, and coinbase. While this change does add smesherID to existing API endpoints + (`GlobalStateService.{AccountDataQuery,AccountDataStream,GlobalStateStream}`), it does not yet expose an endpoint to + query rewards by smesherID. Additionally, it does not re-index old data. Rewards will contain smesherID going forward, + but to refresh data for all rewards, a node will have to delete its database and resync from genesis. + ## 1.3.0 ### Upgrade information diff --git a/api/grpcserver/globalstate_service.go b/api/grpcserver/globalstate_service.go index e0b5983826..7acf61404b 100644 --- a/api/grpcserver/globalstate_service.go +++ b/api/grpcserver/globalstate_service.go @@ -143,7 +143,7 @@ func (s GlobalStateService) AccountDataQuery( // if filterTxReceipt {} if filterReward { - dbRewards, err := s.mesh.GetRewards(addr) + dbRewards, err := s.mesh.GetRewardsByCoinbase(addr) if err != nil { return nil, status.Errorf(codes.Internal, "error getting rewards data") } @@ -153,10 +153,8 @@ func (s GlobalStateService) AccountDataQuery( Layer: &pb.LayerNumber{Number: r.Layer.Uint32()}, Total: &pb.Amount{Value: r.TotalReward}, LayerReward: &pb.Amount{Value: r.LayerReward}, - // Leave this out for now as this is changing - // See https://github.com/spacemeshos/go-spacemesh/issues/2275 - // LayerComputed: 0, - Coinbase: &pb.AccountId{Address: addr.String()}, + Coinbase: &pb.AccountId{Address: addr.String()}, + Smesher: &pb.SmesherId{Id: r.SmesherID[:]}, }, }}) } @@ -291,10 +289,8 @@ func (s GlobalStateService) AccountDataStream( Layer: &pb.LayerNumber{Number: reward.Layer.Uint32()}, Total: &pb.Amount{Value: reward.Total}, LayerReward: &pb.Amount{Value: reward.LayerReward}, - // Leave this out for now as this is changing - // See https://github.com/spacemeshos/go-spacemesh/issues/2275 - // LayerComputed: 0, - Coinbase: &pb.AccountId{Address: addr.String()}, + Coinbase: &pb.AccountId{Address: addr.String()}, + Smesher: &pb.SmesherId{Id: reward.SmesherID[:]}, }, }}} if err := stream.Send(resp); err != nil { @@ -424,10 +420,8 @@ func (s GlobalStateService) GlobalStateStream( Layer: &pb.LayerNumber{Number: reward.Layer.Uint32()}, Total: &pb.Amount{Value: reward.Total}, LayerReward: &pb.Amount{Value: reward.LayerReward}, - // Leave this out for now as this is changing - // See https://github.com/spacemeshos/go-spacemesh/issues/2275 - // LayerComputed: 0, - Coinbase: &pb.AccountId{Address: reward.Coinbase.String()}, + Coinbase: &pb.AccountId{Address: reward.Coinbase.String()}, + Smesher: &pb.SmesherId{Id: reward.SmesherID[:]}, }, }}} if err := stream.Send(resp); err != nil { diff --git a/api/grpcserver/globalstate_service_test.go b/api/grpcserver/globalstate_service_test.go index 4612c3e46e..0814d45e6a 100644 --- a/api/grpcserver/globalstate_service_test.go +++ b/api/grpcserver/globalstate_service_test.go @@ -100,7 +100,7 @@ func TestGlobalStateService(t *testing.T) { t.Parallel() c, ctx := setupGlobalStateService(t) - c.meshAPI.EXPECT().GetRewards(addr1).Return([]*types.Reward{ + c.meshAPI.EXPECT().GetRewardsByCoinbase(addr1).Return([]*types.Reward{ { Layer: layerFirst, TotalReward: rewardAmount, @@ -130,7 +130,7 @@ func TestGlobalStateService(t *testing.T) { t.Parallel() c, ctx := setupGlobalStateService(t) - c.meshAPI.EXPECT().GetRewards(addr1).Return([]*types.Reward{ + c.meshAPI.EXPECT().GetRewardsByCoinbase(addr1).Return([]*types.Reward{ { Layer: layerFirst, TotalReward: rewardAmount, @@ -159,12 +159,13 @@ func TestGlobalStateService(t *testing.T) { t.Parallel() c, ctx := setupGlobalStateService(t) - c.meshAPI.EXPECT().GetRewards(addr1).Return([]*types.Reward{ + c.meshAPI.EXPECT().GetRewardsByCoinbase(addr1).Return([]*types.Reward{ { Layer: layerFirst, TotalReward: rewardAmount, LayerReward: rewardAmount, Coinbase: addr1, + SmesherID: rewardSmesherID, }, }, nil) c.conStateAPI.EXPECT().GetBalance(addr1).Return(accountBalance, nil) @@ -188,12 +189,13 @@ func TestGlobalStateService(t *testing.T) { t.Parallel() c, ctx := setupGlobalStateService(t) - c.meshAPI.EXPECT().GetRewards(addr1).Return([]*types.Reward{ + c.meshAPI.EXPECT().GetRewardsByCoinbase(addr1).Return([]*types.Reward{ { Layer: layerFirst, TotalReward: rewardAmount, LayerReward: rewardAmount, Coinbase: addr1, + SmesherID: rewardSmesherID, }, }, nil) c.conStateAPI.EXPECT().GetBalance(addr1).Return(accountBalance, nil) diff --git a/api/grpcserver/grpcserver_test.go b/api/grpcserver/grpcserver_test.go index cfcf3ae356..f5e909d0f0 100644 --- a/api/grpcserver/grpcserver_test.go +++ b/api/grpcserver/grpcserver_test.go @@ -78,23 +78,24 @@ var ( postGenesisEpoch = types.EpochID(2) genesisID = types.Hash20{} - addr1 types.Address - addr2 types.Address - prevAtxID = types.ATXID(types.HexToHash32("44444")) - chlng = types.HexToHash32("55555") - poetRef = []byte("66666") - nipost = newNIPostWithChallenge(&chlng, poetRef) - challenge = newChallenge(1, prevAtxID, prevAtxID, postGenesisEpoch) - globalAtx *types.VerifiedActivationTx - globalAtx2 *types.VerifiedActivationTx - globalTx *types.Transaction - globalTx2 *types.Transaction - ballot1 = genLayerBallot(types.LayerID(11)) - block1 = genLayerBlock(types.LayerID(11), nil) - block2 = genLayerBlock(types.LayerID(11), nil) - block3 = genLayerBlock(types.LayerID(11), nil) - meshAPIMock = &MeshAPIMock{} - conStateAPI = &ConStateAPIMock{ + addr1 types.Address + addr2 types.Address + rewardSmesherID = types.RandomNodeID() + prevAtxID = types.ATXID(types.HexToHash32("44444")) + chlng = types.HexToHash32("55555") + poetRef = []byte("66666") + nipost = newNIPostWithChallenge(&chlng, poetRef) + challenge = newChallenge(1, prevAtxID, prevAtxID, postGenesisEpoch) + globalAtx *types.VerifiedActivationTx + globalAtx2 *types.VerifiedActivationTx + globalTx *types.Transaction + globalTx2 *types.Transaction + ballot1 = genLayerBallot(types.LayerID(11)) + block1 = genLayerBlock(types.LayerID(11), nil) + block2 = genLayerBlock(types.LayerID(11), nil) + block3 = genLayerBlock(types.LayerID(11), nil) + meshAPIMock = &MeshAPIMock{} + conStateAPI = &ConStateAPIMock{ returnTx: make(map[types.TransactionID]*types.Transaction), layerApplied: make(map[types.TransactionID]*types.LayerID), balances: make(map[types.Address]*big.Int), @@ -260,13 +261,26 @@ func (m *MeshAPIMock) ProcessedLayer() types.LayerID { return layerVerified } -func (m *MeshAPIMock) GetRewards(types.Address) (rewards []*types.Reward, err error) { +func (m *MeshAPIMock) GetRewardsByCoinbase(types.Address) (rewards []*types.Reward, err error) { return []*types.Reward{ { Layer: layerFirst, TotalReward: rewardAmount, LayerReward: rewardAmount, Coinbase: addr1, + SmesherID: rewardSmesherID, + }, + }, nil +} + +func (m *MeshAPIMock) GetRewardsBySmesherId(types.NodeID) (rewards []*types.Reward, err error) { + return []*types.Reward{ + { + Layer: layerFirst, + TotalReward: rewardAmount, + LayerReward: rewardAmount, + Coinbase: addr1, + SmesherID: rewardSmesherID, }, }, nil } @@ -1728,6 +1742,7 @@ func TestAccountDataStream_comprehensive(t *testing.T) { Total: rewardAmount, LayerReward: rewardAmount * 2, Coinbase: addr1, + SmesherID: rewardSmesherID, }) res, err := stream.Recv() @@ -1783,6 +1798,7 @@ func TestGlobalStateStream_comprehensive(t *testing.T) { Total: rewardAmount, LayerReward: rewardAmount * 2, Coinbase: addr1, + SmesherID: rewardSmesherID, }) res, err := stream.Recv() require.NoError(t, err, "got error from stream") @@ -1894,7 +1910,7 @@ func checkAccountDataQueryItemReward(t *testing.T, dataItem any) { require.Equal(t, uint64(rewardAmount), x.Reward.Total.Value) require.Equal(t, uint64(rewardAmount), x.Reward.LayerReward.Value) require.Equal(t, addr1.String(), x.Reward.Coinbase.Address) - require.Nil(t, x.Reward.Smesher) + require.Equal(t, rewardSmesherID.Bytes(), x.Reward.Smesher.Id) } func checkAccountMeshDataItemTx(t *testing.T, dataItem any) { @@ -1925,6 +1941,7 @@ func checkAccountDataItemReward(t *testing.T, dataItem any) { require.Equal(t, layerFirst.Uint32(), x.Reward.Layer.Number) require.Equal(t, uint64(rewardAmount*2), x.Reward.LayerReward.Value) require.Equal(t, addr1.String(), x.Reward.Coinbase.Address) + require.Equal(t, rewardSmesherID.Bytes(), x.Reward.Smesher.Id) } func checkAccountDataItemAccount(t *testing.T, dataItem any) { @@ -1946,6 +1963,7 @@ func checkGlobalStateDataReward(t *testing.T, dataItem any) { require.Equal(t, layerFirst.Uint32(), x.Reward.Layer.Number) require.Equal(t, uint64(rewardAmount*2), x.Reward.LayerReward.Value) require.Equal(t, addr1.String(), x.Reward.Coinbase.Address) + require.Equal(t, rewardSmesherID.Bytes(), x.Reward.Smesher.Id) } func checkGlobalStateDataAccountWrapper(t *testing.T, dataItem any) { diff --git a/api/grpcserver/interface.go b/api/grpcserver/interface.go index 033da8f5e9..e938c24435 100644 --- a/api/grpcserver/interface.go +++ b/api/grpcserver/interface.go @@ -79,7 +79,8 @@ type genesisTimeAPI interface { type meshAPI interface { GetATXs(context.Context, []types.ATXID) (map[types.ATXID]*types.VerifiedActivationTx, []types.ATXID) GetLayer(types.LayerID) (*types.Layer, error) - GetRewards(types.Address) ([]*types.Reward, error) + GetRewardsByCoinbase(types.Address) ([]*types.Reward, error) + GetRewardsBySmesherId(id types.NodeID) ([]*types.Reward, error) LatestLayer() types.LayerID LatestLayerInState() types.LayerID ProcessedLayer() types.LayerID diff --git a/api/grpcserver/mocks.go b/api/grpcserver/mocks.go index 088b026228..29f628f595 100644 --- a/api/grpcserver/mocks.go +++ b/api/grpcserver/mocks.go @@ -1368,41 +1368,80 @@ func (c *meshAPIGetLayerCall) DoAndReturn(f func(types.LayerID) (*types.Layer, e return c } -// GetRewards mocks base method. -func (m *MockmeshAPI) GetRewards(arg0 types.Address) ([]*types.Reward, error) { +// GetRewardsByCoinbase mocks base method. +func (m *MockmeshAPI) GetRewardsByCoinbase(arg0 types.Address) ([]*types.Reward, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRewards", arg0) + ret := m.ctrl.Call(m, "GetRewardsByCoinbase", arg0) ret0, _ := ret[0].([]*types.Reward) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetRewards indicates an expected call of GetRewards. -func (mr *MockmeshAPIMockRecorder) GetRewards(arg0 any) *meshAPIGetRewardsCall { +// GetRewardsByCoinbase indicates an expected call of GetRewardsByCoinbase. +func (mr *MockmeshAPIMockRecorder) GetRewardsByCoinbase(arg0 any) *meshAPIGetRewardsByCoinbaseCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRewards", reflect.TypeOf((*MockmeshAPI)(nil).GetRewards), arg0) - return &meshAPIGetRewardsCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRewardsByCoinbase", reflect.TypeOf((*MockmeshAPI)(nil).GetRewardsByCoinbase), arg0) + return &meshAPIGetRewardsByCoinbaseCall{Call: call} } -// meshAPIGetRewardsCall wrap *gomock.Call -type meshAPIGetRewardsCall struct { +// meshAPIGetRewardsByCoinbaseCall wrap *gomock.Call +type meshAPIGetRewardsByCoinbaseCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *meshAPIGetRewardsCall) Return(arg0 []*types.Reward, arg1 error) *meshAPIGetRewardsCall { +func (c *meshAPIGetRewardsByCoinbaseCall) Return(arg0 []*types.Reward, arg1 error) *meshAPIGetRewardsByCoinbaseCall { c.Call = c.Call.Return(arg0, arg1) return c } // Do rewrite *gomock.Call.Do -func (c *meshAPIGetRewardsCall) Do(f func(types.Address) ([]*types.Reward, error)) *meshAPIGetRewardsCall { +func (c *meshAPIGetRewardsByCoinbaseCall) Do(f func(types.Address) ([]*types.Reward, error)) *meshAPIGetRewardsByCoinbaseCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *meshAPIGetRewardsCall) DoAndReturn(f func(types.Address) ([]*types.Reward, error)) *meshAPIGetRewardsCall { +func (c *meshAPIGetRewardsByCoinbaseCall) DoAndReturn(f func(types.Address) ([]*types.Reward, error)) *meshAPIGetRewardsByCoinbaseCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// GetRewardsBySmesherId mocks base method. +func (m *MockmeshAPI) GetRewardsBySmesherId(id types.NodeID) ([]*types.Reward, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRewardsBySmesherId", id) + ret0, _ := ret[0].([]*types.Reward) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRewardsBySmesherId indicates an expected call of GetRewardsBySmesherId. +func (mr *MockmeshAPIMockRecorder) GetRewardsBySmesherId(id any) *meshAPIGetRewardsBySmesherIdCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRewardsBySmesherId", reflect.TypeOf((*MockmeshAPI)(nil).GetRewardsBySmesherId), id) + return &meshAPIGetRewardsBySmesherIdCall{Call: call} +} + +// meshAPIGetRewardsBySmesherIdCall wrap *gomock.Call +type meshAPIGetRewardsBySmesherIdCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *meshAPIGetRewardsBySmesherIdCall) Return(arg0 []*types.Reward, arg1 error) *meshAPIGetRewardsBySmesherIdCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *meshAPIGetRewardsBySmesherIdCall) Do(f func(types.NodeID) ([]*types.Reward, error)) *meshAPIGetRewardsBySmesherIdCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *meshAPIGetRewardsBySmesherIdCall) DoAndReturn(f func(types.NodeID) ([]*types.Reward, error)) *meshAPIGetRewardsBySmesherIdCall { c.Call = c.Call.DoAndReturn(f) return c } diff --git a/cmd/bootstrapper/generator_test.go b/cmd/bootstrapper/generator_test.go index 72b03841b2..b15a5526c3 100644 --- a/cmd/bootstrapper/generator_test.go +++ b/cmd/bootstrapper/generator_test.go @@ -15,6 +15,7 @@ import ( pb "github.com/spacemeshos/api/release/go/spacemesh/v1" "github.com/spf13/afero" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" "go.uber.org/zap/zaptest" "github.com/spacemeshos/go-spacemesh/api/grpcserver" @@ -44,22 +45,6 @@ var bitcoinResponse1 string //go:embed bitcoinResponse2.json var bitcoinResponse2 string -type MeshAPIMock struct{} - -func (m *MeshAPIMock) LatestLayer() types.LayerID { panic("not implemented") } -func (m *MeshAPIMock) LatestLayerInState() types.LayerID { panic("not implemented") } -func (m *MeshAPIMock) ProcessedLayer() types.LayerID { panic("not implemented") } -func (m *MeshAPIMock) GetRewards(types.Address) ([]*types.Reward, error) { panic("not implemented") } -func (m *MeshAPIMock) GetLayer(types.LayerID) (*types.Layer, error) { panic("not implemented") } - -func (m *MeshAPIMock) GetATXs( - context.Context, - []types.ATXID, -) (map[types.ATXID]*types.VerifiedActivationTx, []types.ATXID) { - panic("not implemented") -} -func (m *MeshAPIMock) MeshHash(types.LayerID) (types.Hash32, error) { panic("not implemented") } - func createAtxs(tb testing.TB, db sql.Executor, epoch types.EpochID, atxids []types.ATXID) { for _, id := range atxids { atx := &types.ActivationTx{InnerActivationTx: types.InnerActivationTx{ @@ -82,7 +67,8 @@ func launchServer(tb testing.TB, cdb *datastore.CachedDB) (grpcserver.Config, fu cfg := grpcserver.DefaultTestConfig() grpcService := grpcserver.New("127.0.0.1:0", zaptest.NewLogger(tb).Named("grpc"), cfg) jsonService := grpcserver.NewJSONHTTPServer("127.0.0.1:0", zaptest.NewLogger(tb).Named("grpc.JSON")) - s := grpcserver.NewMeshService(cdb, &MeshAPIMock{}, nil, nil, 0, types.Hash20{}, 0, 0, 0) + s := grpcserver.NewMeshService(cdb, grpcserver.NewMockmeshAPI(gomock.NewController(tb)), nil, nil, + 0, types.Hash20{}, 0, 0, 0) pb.RegisterMeshServiceServer(grpcService.GrpcServer, s) // start gRPC and json servers diff --git a/common/types/block.go b/common/types/block.go index ca866dec53..050c5a71bb 100644 --- a/common/types/block.go +++ b/common/types/block.go @@ -106,10 +106,11 @@ type AnyReward struct { Weight RatNum } -// CoinbaseReward contains the reward information by coinbase, used as an interface to VM. +// CoinbaseReward contains the reward information by coinbase and smesher, used as an interface to VM. type CoinbaseReward struct { - Coinbase Address - Weight RatNum + SmesherID NodeID + Coinbase Address + Weight RatNum } // Initialize calculates and sets the Block's cached blockID. diff --git a/common/types/transaction.go b/common/types/transaction.go index f559767d3c..6b43f60f38 100644 --- a/common/types/transaction.go +++ b/common/types/transaction.go @@ -148,6 +148,7 @@ type Reward struct { TotalReward uint64 LayerReward uint64 Coinbase Address + SmesherID NodeID } // NewRawTx computes id from raw bytes and returns the object. diff --git a/common/types/transaction_scale.go b/common/types/transaction_scale.go index a48ec0cec7..968fbf09c9 100644 --- a/common/types/transaction_scale.go +++ b/common/types/transaction_scale.go @@ -73,6 +73,13 @@ func (t *Reward) EncodeScale(enc *scale.Encoder) (total int, err error) { } total += n } + { + n, err := scale.EncodeByteArray(enc, t.SmesherID[:]) + if err != nil { + return total, err + } + total += n + } return total, nil } @@ -108,6 +115,13 @@ func (t *Reward) DecodeScale(dec *scale.Decoder) (total int, err error) { } total += n } + { + n, err := scale.DecodeByteArray(dec, t.SmesherID[:]) + if err != nil { + return total, err + } + total += n + } return total, nil } diff --git a/events/reporter.go b/events/reporter.go index e62e83af09..f3fe7c9280 100644 --- a/events/reporter.go +++ b/events/reporter.go @@ -387,6 +387,7 @@ type Reward struct { Total uint64 LayerReward uint64 Coinbase types.Address + SmesherID types.NodeID } // Transaction wraps a tx with its layer ID and validity info. diff --git a/genvm/rewards.go b/genvm/rewards.go index bebb22917b..a4c9294e8a 100644 --- a/genvm/rewards.go +++ b/genvm/rewards.go @@ -61,6 +61,7 @@ func (v *VM) addRewards( reward := types.Reward{ Layer: lctx.Layer, Coinbase: blockReward.Coinbase, + SmesherID: blockReward.SmesherID, TotalReward: totalReward.Uint64(), LayerReward: subsidyReward.Uint64(), } diff --git a/genvm/vm.go b/genvm/vm.go index 7b7b9f4aa5..128fc14781 100644 --- a/genvm/vm.go +++ b/genvm/vm.go @@ -267,6 +267,7 @@ func (v *VM) Apply( Total: reward.TotalReward, LayerReward: reward.LayerReward, Coinbase: reward.Coinbase, + SmesherID: reward.SmesherID, }) } diff --git a/genvm/vm_test.go b/genvm/vm_test.go index fd8bc546c1..2982341d44 100644 --- a/genvm/vm_test.go +++ b/genvm/vm_test.go @@ -429,8 +429,11 @@ func (t *tester) rewards(all ...reward) []types.CoinbaseReward { var rst []types.CoinbaseReward for _, rew := range all { rat := new(big.Rat).SetFloat64(rew.share) + address := t.accounts[rew.address].getAddress() rst = append(rst, types.CoinbaseReward{ - Coinbase: t.accounts[rew.address].getAddress(), + Coinbase: address, + // smesherID doesn't matter but must be set. Derive it arbitrarily from the coinbase. + SmesherID: types.BytesToNodeID(address.Bytes()), Weight: types.RatNum{ Num: rat.Num().Uint64(), Denom: rat.Denom().Uint64(), diff --git a/mesh/executor.go b/mesh/executor.go index cb7e22e183..9ac9e59950 100644 --- a/mesh/executor.go +++ b/mesh/executor.go @@ -181,8 +181,9 @@ func (e *Executor) convertRewards(rewards []types.AnyReward) ([]types.CoinbaseRe return nil, fmt.Errorf("exec convert rewards: %w", err) } res = append(res, types.CoinbaseReward{ - Coinbase: atx.Coinbase, - Weight: r.Weight, + SmesherID: atx.NodeID, + Coinbase: atx.Coinbase, + Weight: r.Weight, }) } sort.Slice(res, func(i, j int) bool { diff --git a/mesh/executor_test.go b/mesh/executor_test.go index 1ac09d2ca2..3564252c42 100644 --- a/mesh/executor_test.go +++ b/mesh/executor_test.go @@ -63,7 +63,7 @@ func makeResults(lid types.LayerID, txs ...types.Transaction) []types.Transactio return results } -func createATX(t testing.TB, db sql.Executor, cb types.Address) types.ATXID { +func createATX(t testing.TB, db sql.Executor, cb types.Address) (types.ATXID, types.NodeID) { sig, err := signing.NewEdSigner() require.NoError(t, err) nonce := types.VRFPostIndex(1) @@ -81,7 +81,7 @@ func createATX(t testing.TB, db sql.Executor, cb types.Address) types.ATXID { vAtx, err := atx.Verify(0, 1) require.NoError(t, err) require.NoError(t, atxs.Add(db, vAtx)) - return vAtx.ID() + return vAtx.ID(), sig.NodeID() } func TestExecutor_Execute(t *testing.T) { @@ -128,24 +128,28 @@ func TestExecutor_Execute(t *testing.T) { lid = lid.Add(1) cbs := []types.Address{{1, 2, 3}, {2, 3, 4}} + atxid1, nodeId1 := createATX(t, te.db, cbs[0]) + atxid2, nodeId2 := createATX(t, te.db, cbs[1]) rewards := []types.AnyReward{ { - AtxID: createATX(t, te.db, cbs[0]), + AtxID: atxid1, Weight: types.RatNum{Num: 1, Denom: 3}, }, { - AtxID: createATX(t, te.db, cbs[1]), + AtxID: atxid2, Weight: types.RatNum{Num: 2, Denom: 3}, }, } expRewards := []types.CoinbaseReward{ { - Coinbase: cbs[0], - Weight: rewards[0].Weight, + SmesherID: nodeId1, + Coinbase: cbs[0], + Weight: rewards[0].Weight, }, { - Coinbase: cbs[1], - Weight: rewards[1].Weight, + SmesherID: nodeId2, + Coinbase: cbs[1], + Weight: rewards[1].Weight, }, } sort.Slice(expRewards, func(i, j int) bool { @@ -254,24 +258,28 @@ func TestExecutor_ExecuteOptimistic(t *testing.T) { lid := types.GetEffectiveGenesis() tickHeight := uint64(111) cbs := []types.Address{{1, 2, 3}, {2, 3, 4}} + atxId1, nodeId1 := createATX(t, te.db, cbs[0]) + atxId2, nodeId2 := createATX(t, te.db, cbs[1]) rewards := []types.AnyReward{ { - AtxID: createATX(t, te.db, cbs[0]), + AtxID: atxId1, Weight: types.RatNum{Num: 1, Denom: 3}, }, { - AtxID: createATX(t, te.db, cbs[1]), + AtxID: atxId2, Weight: types.RatNum{Num: 2, Denom: 3}, }, } expRewards := []types.CoinbaseReward{ { - Coinbase: cbs[0], - Weight: rewards[0].Weight, + SmesherID: nodeId1, + Coinbase: cbs[0], + Weight: rewards[0].Weight, }, { - Coinbase: cbs[1], - Weight: rewards[1].Weight, + SmesherID: nodeId2, + Coinbase: cbs[1], + Weight: rewards[1].Weight, }, } sort.Slice(expRewards, func(i, j int) bool { diff --git a/mesh/mesh.go b/mesh/mesh.go index 920ef78b03..4f132dc232 100644 --- a/mesh/mesh.go +++ b/mesh/mesh.go @@ -620,9 +620,14 @@ func (msh *Mesh) GetATXs( return atxs, mIds } -// GetRewards retrieves account's rewards by the coinbase address. -func (msh *Mesh) GetRewards(coinbase types.Address) ([]*types.Reward, error) { - return rewards.List(msh.cdb, coinbase) +// GetRewardsByCoinbase retrieves account's rewards by the coinbase address. +func (msh *Mesh) GetRewardsByCoinbase(coinbase types.Address) ([]*types.Reward, error) { + return rewards.ListByCoinbase(msh.cdb, coinbase) +} + +// GetRewardsBySmesherId retrieves account's rewards by the smesher ID. +func (msh *Mesh) GetRewardsBySmesherId(smesherID types.NodeID) ([]*types.Reward, error) { + return rewards.ListBySmesherId(msh.cdb, smesherID) } // LastVerified returns the latest layer verified by tortoise. diff --git a/sql/database.go b/sql/database.go index 395a2df5b0..a477bfbdc6 100644 --- a/sql/database.go +++ b/sql/database.go @@ -198,13 +198,6 @@ func Open(uri string, opts ...Opt) (*Database, error) { } } } - for i := 0; i < config.connections; i++ { - conn := pool.Get(context.Background()) - if err := registerFunctions(conn); err != nil { - return nil, err - } - pool.Put(conn) - } return db, nil } diff --git a/sql/functions.go b/sql/functions.go deleted file mode 100644 index 07f2c21c85..0000000000 --- a/sql/functions.go +++ /dev/null @@ -1,20 +0,0 @@ -package sql - -import ( - "fmt" - - sqlite "github.com/go-llsqlite/crawshaw" -) - -func registerFunctions(conn *sqlite.Conn) error { - // sqlite doesn't provide native support for uint64, - // it is a problem if we want to sort items using actual uint64 value - // or do arithmetic operations on uint64 in database - // for that we have to add custom functions, another example https://stackoverflow.com/a/8503318 - if err := conn.CreateFunction("add_uint64", true, 2, func(ctx sqlite.Context, values ...sqlite.Value) { - ctx.ResultInt64(int64(uint64(values[0].Int64()) + uint64(values[1].Int64()))) - }, nil, nil); err != nil { - return fmt.Errorf("registering add_uint64: %w", err) - } - return nil -} diff --git a/sql/migrations/state/0008_next.sql b/sql/migrations/state/0008_next.sql new file mode 100644 index 0000000000..77c781b54e --- /dev/null +++ b/sql/migrations/state/0008_next.sql @@ -0,0 +1,15 @@ +DROP INDEX rewards_by_layer; +ALTER TABLE rewards RENAME TO rewards_old; +CREATE TABLE rewards +( + pubkey CHAR(32), + coinbase CHAR(24) NOT NULL, + layer INT NOT NULL, + total_reward UNSIGNED LONG INT, + layer_reward UNSIGNED LONG INT, + PRIMARY KEY (pubkey, layer) +); +CREATE INDEX rewards_by_coinbase ON rewards (coinbase, layer); +CREATE INDEX rewards_by_layer ON rewards (layer asc); +INSERT INTO rewards (coinbase, layer, total_reward, layer_reward) SELECT coinbase, layer, total_reward, layer_reward FROM rewards_old; +DROP TABLE rewards_old; diff --git a/sql/migrations_test.go b/sql/migrations_test.go index f1ff4435b0..31a16c9534 100644 --- a/sql/migrations_test.go +++ b/sql/migrations_test.go @@ -15,5 +15,5 @@ func TestMigrationsAppliedOnce(t *testing.T) { return true }) require.NoError(t, err) - require.Equal(t, version, 7) + require.Equal(t, version, 8) } diff --git a/sql/rewards/rewards.go b/sql/rewards/rewards.go index 5a6b525570..df5ec37b7c 100644 --- a/sql/rewards/rewards.go +++ b/sql/rewards/rewards.go @@ -10,16 +10,13 @@ import ( // Add reward to the database. func Add(db sql.Executor, reward *types.Reward) error { if _, err := db.Exec(` - insert into rewards (coinbase, layer, total_reward, layer_reward) values (?1, ?2, ?3, ?4) - on conflict(coinbase, layer) - do update set - total_reward=add_uint64(total_reward, ?3), - layer_reward=add_uint64(layer_reward, ?4);`, + insert into rewards (pubkey, coinbase, layer, total_reward, layer_reward) values (?1, ?2, ?3, ?4, ?5)`, func(stmt *sql.Statement) { - stmt.BindBytes(1, reward.Coinbase[:]) - stmt.BindInt64(2, int64(reward.Layer.Uint32())) - stmt.BindInt64(3, int64(reward.TotalReward)) - stmt.BindInt64(4, int64(reward.LayerReward)) + stmt.BindBytes(1, reward.SmesherID[:]) + stmt.BindBytes(2, reward.Coinbase[:]) + stmt.BindInt64(3, int64(reward.Layer.Uint32())) + stmt.BindInt64(4, int64(reward.TotalReward)) + stmt.BindInt64(5, int64(reward.LayerReward)) }, nil); err != nil { return fmt.Errorf("insert %+x: %w", reward, err) } @@ -37,20 +34,56 @@ func Revert(db sql.Executor, revertTo types.LayerID) error { return nil } -// List rewards from all layers for the coinbase address. -func List(db sql.Executor, coinbase types.Address) (rst []*types.Reward, err error) { - _, err = db.Exec("select layer, total_reward, layer_reward from rewards where coinbase = ?1 order by layer;", - func(stmt *sql.Statement) { +// ListByKey lists rewards from all layers for the specified smesherID and/or coinbase. +func ListByKey(db sql.Executor, coinbase *types.Address, smesherID *types.NodeID) (rst []*types.Reward, err error) { + var whereClause string + var binder func(*sql.Statement) + if coinbase != nil && smesherID != nil { + whereClause = "pubkey = ?1 and coinbase = ?2" + binder = func(stmt *sql.Statement) { + stmt.BindBytes(1, smesherID[:]) + stmt.BindBytes(2, coinbase[:]) + } + } else if coinbase != nil { + whereClause = "coinbase = ?1" + binder = func(stmt *sql.Statement) { stmt.BindBytes(1, coinbase[:]) - }, func(stmt *sql.Statement) bool { - reward := &types.Reward{ - Coinbase: coinbase, - Layer: types.LayerID(uint32(stmt.ColumnInt64(0))), - TotalReward: uint64(stmt.ColumnInt64(1)), - LayerReward: uint64(stmt.ColumnInt64(2)), - } - rst = append(rst, reward) - return true - }) - return + } + } else if smesherID != nil { + whereClause = "pubkey = ?1" + binder = func(stmt *sql.Statement) { + stmt.BindBytes(1, smesherID[:]) + } + } else { + return nil, fmt.Errorf("must specify coinbase and/or smesherID") + } + stmt := fmt.Sprintf( + "select pubkey, coinbase, layer, total_reward, layer_reward from rewards where %s order by layer;", + whereClause) + _, err = db.Exec(stmt, binder, func(stmt *sql.Statement) bool { + smID := types.NodeID{} + cbase := types.Address{} + stmt.ColumnBytes(0, smID[:]) + stmt.ColumnBytes(1, cbase[:]) + reward := &types.Reward{ + SmesherID: smID, + Coinbase: cbase, + Layer: types.LayerID(uint32(stmt.ColumnInt64(2))), + TotalReward: uint64(stmt.ColumnInt64(3)), + LayerReward: uint64(stmt.ColumnInt64(4)), + } + rst = append(rst, reward) + return true + }) + return rst, err +} + +// ListByCoinbase lists rewards from all layers for the coinbase address. +func ListByCoinbase(db sql.Executor, coinbase types.Address) (rst []*types.Reward, err error) { + return ListByKey(db, &coinbase, nil) +} + +// ListBySmesherId lists rewards from all layers for the smesher ID. +func ListBySmesherId(db sql.Executor, smesherID types.NodeID) (rst []*types.Reward, err error) { + return ListByKey(db, nil, &smesherID) } diff --git a/sql/rewards/rewards_test.go b/sql/rewards/rewards_test.go index 064c984264..6623c8f479 100644 --- a/sql/rewards/rewards_test.go +++ b/sql/rewards/rewards_test.go @@ -2,6 +2,7 @@ package rewards import ( "math" + "sort" "testing" "github.com/stretchr/testify/require" @@ -17,24 +18,30 @@ func TestRewards(t *testing.T) { lyrReward := part / 2 coinbase1 := types.Address{1} coinbase2 := types.Address{2} + smesherID1 := types.NodeID{1} + smesherID2 := types.NodeID{2} + smesherID3 := types.NodeID{3} lid1 := types.LayerID(1) rewards1 := []types.Reward{ { Layer: lid1, Coinbase: coinbase1, + SmesherID: smesherID1, TotalReward: part, LayerReward: lyrReward, }, { Layer: lid1, Coinbase: coinbase1, + SmesherID: smesherID2, TotalReward: part, LayerReward: lyrReward, }, { Layer: lid1, Coinbase: coinbase2, + SmesherID: smesherID3, TotalReward: part, LayerReward: lyrReward, }, @@ -44,6 +51,7 @@ func TestRewards(t *testing.T) { { Layer: lid2, Coinbase: coinbase2, + SmesherID: smesherID2, TotalReward: part, LayerReward: lyrReward, }, @@ -52,45 +60,278 @@ func TestRewards(t *testing.T) { require.NoError(t, Add(db, &reward)) } - got, err := List(db, coinbase1) + got, err := ListByCoinbase(db, coinbase1) require.NoError(t, err) - require.Len(t, got, 1) + require.Len(t, got, 2) require.Equal(t, coinbase1, got[0].Coinbase) require.Equal(t, lid1, got[0].Layer) - require.Equal(t, part*2, got[0].TotalReward) - require.Equal(t, lyrReward*2, got[0].LayerReward) + require.Equal(t, smesherID1, got[0].SmesherID) + require.Equal(t, part, got[0].TotalReward) + require.Equal(t, lyrReward, got[0].LayerReward) + require.Equal(t, coinbase1, got[1].Coinbase) + require.Equal(t, lid1, got[1].Layer) + require.Equal(t, smesherID2, got[1].SmesherID) + require.Equal(t, part, got[1].TotalReward) + require.Equal(t, lyrReward, got[1].LayerReward) - got, err = List(db, coinbase2) + got, err = ListByCoinbase(db, coinbase2) require.NoError(t, err) require.Len(t, got, 2) require.Equal(t, coinbase2, got[0].Coinbase) require.Equal(t, lid1, got[0].Layer) + require.Equal(t, smesherID3, got[0].SmesherID) require.Equal(t, part, got[0].TotalReward) require.Equal(t, lyrReward, got[0].LayerReward) require.Equal(t, coinbase2, got[1].Coinbase) require.Equal(t, lid2, got[1].Layer) + require.Equal(t, smesherID2, got[1].SmesherID) require.Equal(t, part, got[1].TotalReward) require.Equal(t, lyrReward, got[1].LayerReward) + got, err = ListBySmesherId(db, smesherID1) + require.NoError(t, err) + require.Len(t, got, 1) + require.Equal(t, coinbase1, got[0].Coinbase) + require.Equal(t, lid1, got[0].Layer) + require.Equal(t, smesherID1, got[0].SmesherID) + require.Equal(t, part, got[0].TotalReward) + require.Equal(t, lyrReward, got[0].LayerReward) + + got, err = ListBySmesherId(db, smesherID2) + require.NoError(t, err) + require.Len(t, got, 2) + require.Equal(t, coinbase1, got[0].Coinbase) + require.Equal(t, lid1, got[0].Layer) + require.Equal(t, smesherID2, got[0].SmesherID) + require.Equal(t, part, got[0].TotalReward) + require.Equal(t, lyrReward, got[0].LayerReward) + require.Equal(t, coinbase2, got[1].Coinbase) + require.Equal(t, lid2, got[1].Layer) + require.Equal(t, smesherID2, got[1].SmesherID) + require.Equal(t, part, got[1].TotalReward) + require.Equal(t, lyrReward, got[1].LayerReward) + + got, err = ListBySmesherId(db, smesherID3) + require.NoError(t, err) + require.Len(t, got, 1) + require.Equal(t, coinbase2, got[0].Coinbase) + require.Equal(t, lid1, got[0].Layer) + require.Equal(t, smesherID3, got[0].SmesherID) + require.Equal(t, part, got[0].TotalReward) + require.Equal(t, lyrReward, got[0].LayerReward) + unknownAddr := types.Address{1, 2, 3} - got, err = List(db, unknownAddr) + got, err = ListByCoinbase(db, unknownAddr) + require.NoError(t, err) + require.Len(t, got, 0) + + unknownSmesher := types.NodeID{1, 2, 3} + got, err = ListBySmesherId(db, unknownSmesher) require.NoError(t, err) require.Len(t, got, 0) require.NoError(t, Revert(db, lid1)) - got, err = List(db, coinbase1) + got, err = ListByCoinbase(db, coinbase1) + require.NoError(t, err) + require.Len(t, got, 2) + require.Equal(t, coinbase1, got[0].Coinbase) + require.Equal(t, lid1, got[0].Layer) + require.Equal(t, smesherID1, got[0].SmesherID) + require.Equal(t, part, got[0].TotalReward) + require.Equal(t, lyrReward, got[0].LayerReward) + require.Equal(t, coinbase1, got[1].Coinbase) + require.Equal(t, lid1, got[1].Layer) + require.Equal(t, smesherID2, got[1].SmesherID) + require.Equal(t, part, got[1].TotalReward) + require.Equal(t, lyrReward, got[1].LayerReward) + + got, err = ListByCoinbase(db, coinbase2) + require.NoError(t, err) + require.Len(t, got, 1) + require.Equal(t, coinbase2, got[0].Coinbase) + require.Equal(t, lid1, got[0].Layer) + require.Equal(t, smesherID3, got[0].SmesherID) + require.Equal(t, part, got[0].TotalReward) + require.Equal(t, lyrReward, got[0].LayerReward) + + got, err = ListBySmesherId(db, smesherID1) require.NoError(t, err) require.Len(t, got, 1) require.Equal(t, coinbase1, got[0].Coinbase) require.Equal(t, lid1, got[0].Layer) - require.Equal(t, part*2, got[0].TotalReward) - require.Equal(t, lyrReward*2, got[0].LayerReward) + require.Equal(t, smesherID1, got[0].SmesherID) + require.Equal(t, part, got[0].TotalReward) + require.Equal(t, lyrReward, got[0].LayerReward) - got, err = List(db, coinbase2) + got, err = ListBySmesherId(db, smesherID2) + require.NoError(t, err) + require.Len(t, got, 1) + require.Equal(t, coinbase1, got[0].Coinbase) + require.Equal(t, lid1, got[0].Layer) + require.Equal(t, smesherID2, got[0].SmesherID) + require.Equal(t, part, got[0].TotalReward) + require.Equal(t, lyrReward, got[0].LayerReward) + + got, err = ListBySmesherId(db, smesherID3) require.NoError(t, err) require.Len(t, got, 1) require.Equal(t, coinbase2, got[0].Coinbase) require.Equal(t, lid1, got[0].Layer) + require.Equal(t, smesherID3, got[0].SmesherID) require.Equal(t, part, got[0].TotalReward) require.Equal(t, lyrReward, got[0].LayerReward) + + // This should fail: there cannot be two (smesherID, layer) rows. + require.ErrorIs(t, Add(db, &types.Reward{ + Layer: lid1, + SmesherID: smesherID2, + }), sql.ErrObjectExists) + + // This should succeed. SmesherID can be NULL. + require.NoError(t, Add(db, &types.Reward{ + Layer: lid1, + })) + + // This should fail: there cannot be two (NULL, layer) rows. + require.ErrorIs(t, Add(db, &types.Reward{ + Layer: lid1, + }), sql.ErrObjectExists) +} + +func Test_0008Migration_EmptyDBIsNoOp(t *testing.T) { + migrations, err := sql.StateMigrations() + require.NoError(t, err) + sort.Slice(migrations, func(i, j int) bool { return migrations[i].Order() < migrations[j].Order() }) + + // apply previous migrations + db := sql.InMemory( + sql.WithMigrations(migrations[:7]), + ) + + // verify that the DB is empty + _, err = db.Exec("select count(*) from rewards;", func(stmt *sql.Statement) { + }, func(stmt *sql.Statement) bool { + require.Equal(t, int64(0), stmt.ColumnInt64(0)) + return true + }) + require.NoError(t, err) + + // apply the migration + err = migrations[7].Apply(db) + require.NoError(t, err) + + // verify that db is still empty + _, err = db.Exec("select count(*) from rewards;", func(stmt *sql.Statement) { + }, func(stmt *sql.Statement) bool { + require.Equal(t, int64(0), stmt.ColumnInt64(0)) + return true + }) + require.NoError(t, err) +} + +func Test_0008Migration(t *testing.T) { + migrations, err := sql.StateMigrations() + require.NoError(t, err) + sort.Slice(migrations, func(i, j int) bool { return migrations[i].Order() < migrations[j].Order() }) + + // apply previous migrations + db := sql.InMemory( + sql.WithMigrations(migrations[:7]), + ) + + // verify that the DB is empty + _, err = db.Exec("select count(*) from rewards;", func(stmt *sql.Statement) { + }, func(stmt *sql.Statement) bool { + require.Equal(t, int64(0), stmt.ColumnInt64(0)) + return true + }) + require.NoError(t, err) + + // attempt to insert some rewards data + reward := &types.Reward{ + Layer: 9000, + TotalReward: 10, + LayerReward: 20, + Coinbase: types.Address{1}, + } + err = Add(db, reward) + + // this should fail since the un-migrated table doesn't have this column yet + require.ErrorContains(t, err, "table rewards has no column named pubkey") + + // add the row manually + _, err = db.Exec(` + insert into rewards (coinbase, layer, total_reward, layer_reward) values (?1, ?2, ?3, ?4)`, + func(stmt *sql.Statement) { + stmt.BindBytes(1, reward.Coinbase[:]) + stmt.BindInt64(2, int64(reward.Layer.Uint32())) + stmt.BindInt64(3, int64(reward.TotalReward)) + stmt.BindInt64(4, int64(reward.LayerReward)) + }, nil) + require.NoError(t, err) + + // make sure one row was added successfully + _, err = db.Exec("select count(*) from rewards;", func(stmt *sql.Statement) { + }, func(stmt *sql.Statement) bool { + require.Equal(t, int64(1), stmt.ColumnInt64(0)) + return true + }) + require.NoError(t, err) + + // apply the migration + err = migrations[7].Apply(db) + require.NoError(t, err) + + // verify that one row is still present + _, err = db.Exec("select count(*) from rewards;", func(stmt *sql.Statement) { + }, func(stmt *sql.Statement) bool { + require.Equal(t, int64(1), stmt.ColumnInt64(0)) + return true + }) + require.NoError(t, err) + + // verify the data + rewards, err := ListByCoinbase(db, reward.Coinbase) + require.NoError(t, err) + require.Len(t, rewards, 1) + require.Equal(t, reward.Coinbase, rewards[0].Coinbase) + require.Equal(t, reward.TotalReward, rewards[0].TotalReward) + require.Equal(t, reward.LayerReward, rewards[0].LayerReward) + require.Equal(t, reward.Layer, rewards[0].Layer) + // this should not be set + require.Equal(t, types.NodeID{0}, rewards[0].SmesherID) + + // this should return nothing (since smesherID wasn't set) + rewards, err = ListBySmesherId(db, reward.SmesherID) + require.NoError(t, err) + require.Len(t, rewards, 0) + + // add more data and verify that we can read it both ways + reward = &types.Reward{ + Layer: 9001, + TotalReward: 11, + LayerReward: 21, + Coinbase: types.Address{1}, + SmesherID: types.NodeID{2}, + } + + err = Add(db, reward) + require.NoError(t, err) + rewards, err = ListByCoinbase(db, reward.Coinbase) + require.NoError(t, err) + require.Len(t, rewards, 2) + require.Equal(t, reward.Coinbase, rewards[1].Coinbase) + require.Equal(t, reward.TotalReward, rewards[1].TotalReward) + require.Equal(t, reward.LayerReward, rewards[1].LayerReward) + require.Equal(t, reward.Layer, rewards[1].Layer) + require.Equal(t, reward.SmesherID, rewards[1].SmesherID) + + rewards, err = ListBySmesherId(db, reward.SmesherID) + require.NoError(t, err) + require.Len(t, rewards, 1) + require.Equal(t, reward.Coinbase, rewards[0].Coinbase) + require.Equal(t, reward.TotalReward, rewards[0].TotalReward) + require.Equal(t, reward.LayerReward, rewards[0].LayerReward) + require.Equal(t, reward.Layer, rewards[0].Layer) + require.Equal(t, reward.SmesherID, rewards[0].SmesherID) } From 3d8eedfd44c6f9f8987e604b768596f6001fe703 Mon Sep 17 00:00:00 2001 From: Davi Mello <5011972+fasmat@users.noreply.github.com> Date: Mon, 4 Dec 2023 17:12:02 +0000 Subject: [PATCH 13/48] Improvements at Github Action: improve release names and add checksum (#5235) ## Motivation Closes issue #5230 Closes PR #5234 ## Changes Adjust the release pipeline to have better artifact names (more explicit From Windows to go-spacemesh-v1.2.4-win-amd64.zip ...) And add the sha256 of each artifact generated and publish in this release ## Test Plan manual testing ## TODO - [ ] Update [changelog](../CHANGELOG.md) as needed Co-authored-by: Davi Mello Co-authored-by: unknown --- .github/workflows/dockerhub.yml | 4 +- .github/workflows/release.yml | 97 +++++++++++++++++++++++++++------ .github/workflows/systest.yml | 5 +- 3 files changed, 84 insertions(+), 22 deletions(-) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 31db55be9a..75d7edb86d 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -28,7 +28,7 @@ jobs: run: | make dockerbuild-go make dockerbuild-bs - + - name: Push docker images to dockerhub run: | make dockerpush-only @@ -51,5 +51,3 @@ jobs: export DOCKER_IMAGE_REPO="go-spacemesh" make dockerpush-only make dockerpush-bs-only - - \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fdbe51d5a5..3ba42b707b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,19 +17,19 @@ jobs: matrix: include: - os: ubuntu-latest + outname_sufix: "linux-amd64" - os: [self-hosted, linux, arm64] + outname_sufix: "linux-arm64" - os: macos-latest + outname_sufix: "mac-amd64" - os: [self-hosted, macos, arm64] + outname_sufix: "mac-arm64" - os: windows-latest + outname_sufix: "win-amd64" steps: - shell: bash - run: | - if [[ ${{ runner.arch }} == "ARM64" ]]; then - echo "OUTNAME=${{ runner.os }}_${{ runner.arch }}" >> $GITHUB_ENV - else - echo "OUTNAME=${{ runner.os }}" >> $GITHUB_ENV - fi - + run: echo "OUTNAME=go-spacemesh-${{ github.ref_name }}-${{ matrix.outname_sufix }}" >> $GITHUB_ENV + - name: Install dependencies in windows if: ${{ matrix.os == 'windows-latest' }} run: choco install make wget zip @@ -67,8 +67,8 @@ jobs: rm -f $OUTNAME/post.h zip -r $OUTNAME.zip $OUTNAME - - name: 'Setup GCP Auth' - uses: 'google-github-actions/auth@v2' + - name: Setup gcloud authentication + uses: google-github-actions/auth@v2 with: credentials_json: '${{ secrets.GCP_SA_KEY }}' @@ -81,12 +81,69 @@ jobs: path: ${{ env.OUTNAME }}.zip destination: ${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/ + - name: Install coreutils + if: ${{ matrix.os == 'macos-latest' }} + run: brew install coreutils + + - name: Calculate the hashsum of the zip file + if: ${{ matrix.os != 'windows-latest' }} + shell: bash + run: | + sha256sum ${{ env.OUTNAME }}.zip | awk '{ print $1 }' > sha256-${{ matrix.outname_sufix }}.txt + + - name: Calculate the hashsum of the zip file (Windows) + if: ${{ matrix.os == 'windows-latest' }} + run: | + (Get-FileHash ${{ env.OUTNAME }}.zip -Algorithm SHA256).Hash > sha256-${{ matrix.outname_sufix }}.txt + + - uses: actions/upload-artifact@v3 + with: + name: sha256-${{ matrix.outname_sufix }} + path: sha256-${{ matrix.outname_sufix }}.txt + if-no-files-found: error + retention-days: 5 + release: runs-on: ubuntu-latest needs: build-and-upload steps: - - name: Check out Git repository - uses: actions/checkout@v4 + - name: Download the artifacts + uses: actions/download-artifact@v3 + + - name: Generate the env variables + shell: bash + run: | + echo "OUTNAME_WIN_AMD64=go-spacemesh-${{ github.ref_name }}-win-amd64" >> $GITHUB_ENV + echo "OUTNAME_LINUX_AMD64=go-spacemesh-${{ github.ref_name }}-linux-amd64" >> $GITHUB_ENV + echo "OUTNAME_LINUX_ARM64=go-spacemesh-${{ github.ref_name }}-linux-arm64" >> $GITHUB_ENV + echo "OUTNAME_MAC_AMD64=go-spacemesh-${{ github.ref_name }}-mac-amd64" >> $GITHUB_ENV + echo "OUTNAME_MAC_ARM64=go-spacemesh-${{ github.ref_name }}-mac-arm64" >> $GITHUB_ENV + + echo "SHA256_WIN_AMD64=$(cat sha256-win-amd64/sha256-win-amd64.txt)" >> $GITHUB_ENV + echo "SHA256_LINUX_AMD64=$(cat sha256-linux-amd64/sha256-linux-amd64.txt)" >> $GITHUB_ENV + echo "SHA256_LINUX_ARM64=$(cat sha256-linux-arm64/sha256-linux-arm64.txt)" >> $GITHUB_ENV + echo "SHA256_MAC_AMD64=$(cat sha256-mac-amd64/sha256-mac-amd64.txt)" >> $GITHUB_ENV + echo "SHA256_MAC_ARM64=$(cat sha256-mac-arm64/sha256-mac-arm64.txt)" >> $GITHUB_ENV + + echo "win-amd64: $(cat sha256-win-amd64/sha256-win-amd64.txt)" >> sha256sum.yaml + echo "linux-amd64: $(cat sha256-linux-amd64/sha256-linux-amd64.txt)" >> sha256sum.yaml + echo "linux-arm64: $(cat sha256-linux-arm64/sha256-linux-arm64.txt)" >> sha256sum.yaml + echo "mac-amd64: $(cat sha256-mac-amd64/sha256-mac-amd64.txt)" >> sha256sum.yaml + echo "mac-arm64: $(cat sha256-mac-arm64/sha256-mac-arm64.txt)" >> sha256sum.yaml + + - name: Setup gcloud authentication + uses: google-github-actions/auth@v2 + with: + credentials_json: '${{ secrets.GCP_SA_KEY }}' + + - name: Set up Cloud SDK + uses: google-github-actions/setup-gcloud@v1 + + - name: Upload sha256sums + uses: google-github-actions/upload-cloud-storage@v1 + with: + path: sha256sum.yaml + destination: ${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/ - name: Create Release uses: softprops/action-gh-release@v1 @@ -97,11 +154,19 @@ jobs: tag_name: ${{ github.ref_name }} body: | ## Zip Files - - Windows: https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/Windows.zip - - macOS: https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/macOS.zip - - macOS arm64: https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/macOS_ARM64.zip - - Linux: https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/Linux.zip - - Linux arm64: https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/Linux_ARM64.zip + - Windows amd64: https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/${{ env.OUTNAME_WIN_AMD64 }}.zip + - macOS amd64: https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/${{ env.OUTNAME_MAC_AMD64 }}.zip + - macOS arm64: https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/${{ env.OUTNAME_MAC_ARM64 }}.zip + - Linux amd64: https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/${{ env.OUTNAME_LINUX_AMD64 }}.zip + - Linux arm64: https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/${{ env.OUTNAME_LINUX_ARM64 }}.zip + + ## checksum - Zip files + YAML with all the checksums of this version : https://storage.googleapis.com/${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/sha256sum.yaml + - Windows amd64 - sha256 : ${{ env.SHA256_WIN_AMD64 }} + - Linux amd64 - sha256: ${{ env.SHA256_LINUX_AMD64 }} + - Linux arm64 - sha256: ${{ env.SHA256_LINUX_ARM64 }} + - macOS amd64 - sha256: ${{ env.SHA256_MAC_AMD64 }} + - macOS arm64 - sha256: ${{ env.SHA256_MAC_ARM64 }} For information about changes in this release see the [changelog](https://github.com/spacemeshos/go-spacemesh/blob/${{ github.ref_name }}/CHANGELOG.md). draft: false diff --git a/.github/workflows/systest.yml b/.github/workflows/systest.yml index 1a284bb9e3..f3b5983679 100644 --- a/.github/workflows/systest.yml +++ b/.github/workflows/systest.yml @@ -61,14 +61,13 @@ jobs: version: "v1.23.15" - name: Setup gcloud authentication - id: "auth" - uses: "google-github-actions/auth@v2" + uses: google-github-actions/auth@v2 with: # GCP_CREDENTIALS is minified JSON of service account credentials_json: "${{ secrets.CI_GCP_CREDENTIALS }}" - name: Configure gcloud - uses: "google-github-actions/setup-gcloud@v1" + uses: google-github-actions/setup-gcloud@v1 with: version: "450.0.0" From 8fafa7f5a79c1ca5786081b1b6f0091cb5339fb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 08:24:42 +0000 Subject: [PATCH 14/48] build(deps): Bump github.com/spf13/viper from 1.17.0 to 1.18.0 (#5331) Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.17.0 to 1.18.0. --- go.mod | 10 +++++----- go.sum | 21 ++++++++++----------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index 58d55322c1..482ac77c68 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/spf13/afero v1.11.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.17.0 + github.com/spf13/viper v1.18.0 github.com/stretchr/testify v1.8.4 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/zeebo/blake3 v0.2.3 @@ -87,7 +87,7 @@ require ( github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.2.4 // indirect @@ -183,12 +183,12 @@ require ( github.com/quic-go/webtransport-go v0.6.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect - github.com/sagikazarmark/locafero v0.3.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spacemeshos/sha256-simd v0.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/spf13/cast v1.5.1 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect go.opencensus.io v0.24.0 // indirect @@ -209,7 +209,7 @@ require ( golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect gonum.org/v1/gonum v0.13.0 // indirect - google.golang.org/api v0.152.0 // indirect + google.golang.org/api v0.153.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect diff --git a/go.sum b/go.sum index 101d2422f1..fcc2484c0f 100644 --- a/go.sum +++ b/go.sum @@ -153,8 +153,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= @@ -576,8 +576,8 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= -github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= -github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= @@ -640,14 +640,14 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= -github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= +github.com/spf13/viper v1.18.0 h1:pN6W1ub/G4OfnM+NR9p7xP9R6TltLUzp5JG9yZD3Qg0= +github.com/spf13/viper v1.18.0/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -891,7 +891,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/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.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= @@ -994,8 +993,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY= -google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= +google.golang.org/api v0.153.0 h1:N1AwGhielyKFaUqH07/ZSIQR3uNPcV7NVw0vj+j4iR4= +google.golang.org/api v0.153.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= From 95bc9b2caff8638b6c31145921d565980985b3bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowak?= Date: Thu, 7 Dec 2023 15:23:39 +0000 Subject: [PATCH 15/48] Adjust from 10k default to 50k as default for gossip (#5323) Better defaults for current network state. --- p2p/host.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/p2p/host.go b/p2p/host.go index e764d6d9b0..65b10799e2 100644 --- a/p2p/host.go +++ b/p2p/host.go @@ -64,9 +64,9 @@ func DefaultConfig() Config { // link local "fe80::/10", }, - GossipQueueSize: 10000, - GossipValidationThrottle: 10000, - GossipAtxValidationThrottle: 10000, + GossipQueueSize: 50000, + GossipValidationThrottle: 50000, + GossipAtxValidationThrottle: 50000, } } From a7737d17f500e18192bec89cc40768fd4fce0dea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:17:16 +0000 Subject: [PATCH 16/48] build(deps): Bump actions/setup-go from 4 to 5 (#5332) Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 5. --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/coverage.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/systest.yml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fcd15ae106..03ddb0af7b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,7 +63,7 @@ jobs: - name: checkout uses: actions/checkout@v4 - name: set up go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: check-latest: true go-version: ${{ env.go-version }} @@ -86,7 +86,7 @@ jobs: - name: checkout uses: actions/checkout@v4 - name: set up go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: check-latest: true go-version: ${{ env.go-version }} @@ -121,7 +121,7 @@ jobs: - name: checkout uses: actions/checkout@v4 - name: set up go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: check-latest: true go-version: ${{ env.go-version }} @@ -171,7 +171,7 @@ jobs: with: lfs: true - name: set up go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: check-latest: true go-version: ${{ env.go-version }} diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d96385a96a..d17c15b07e 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -20,7 +20,7 @@ jobs: with: lfs: true - name: set up go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: check-latest: true go-version-file: "go.mod" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ba42b707b..1be3eb9e7f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,7 +46,7 @@ jobs: with: lfs: true - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: check-latest: true go-version-file: "go.mod" diff --git a/.github/workflows/systest.yml b/.github/workflows/systest.yml index f3b5983679..e1160183ab 100644 --- a/.github/workflows/systest.yml +++ b/.github/workflows/systest.yml @@ -101,7 +101,7 @@ jobs: run: make -C systest push - name: set up go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: check-latest: true go-version-file: "go.mod" From bd059c908a6370b7b23379558b2c39c4d395be19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:43:12 +0000 Subject: [PATCH 17/48] build(deps): Bump github.com/spf13/viper from 1.18.0 to 1.18.1 (#5337) Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.18.0 to 1.18.1. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 482ac77c68..9877356f2d 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/spf13/afero v1.11.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.18.0 + github.com/spf13/viper v1.18.1 github.com/stretchr/testify v1.8.4 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/zeebo/blake3 v0.2.3 diff --git a/go.sum b/go.sum index fcc2484c0f..0dab502252 100644 --- a/go.sum +++ b/go.sum @@ -646,8 +646,8 @@ github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.18.0 h1:pN6W1ub/G4OfnM+NR9p7xP9R6TltLUzp5JG9yZD3Qg0= -github.com/spf13/viper v1.18.0/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.18.1 h1:rmuU42rScKWlhhJDyXZRKJQHXFX02chSVW1IvkPGiVM= +github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= From 7c9f9d31de33a5cee7ea8e3e84603eb7c27af1f1 Mon Sep 17 00:00:00 2001 From: Matthias Fasching <5011972+fasmat@users.noreply.github.com> Date: Mon, 11 Dec 2023 09:37:05 +0000 Subject: [PATCH 18/48] Update CHANGELOG.md (#5333) ## Motivation Several changes listed as part of the 1.3.0 release have already been released in prior versions. ## Changes - Updated CHANGELOG to list changes at the correct versions - renamed 1.3.0 back to UNRELEASED, since more changes might be added before it is officially released ## Test Plan - n/a ## TODO - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [x] Update [changelog](../CHANGELOG.md) as needed --- CHANGELOG.md | 140 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 98 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9958920db6..634bdac784 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,23 +6,6 @@ See [RELEASE](./RELEASE.md) for workflow instructions. ### Upgrade information -### Highlights - -### Features - -### Improvements - -* [#5199](https://github.com/spacemeshos/go-spacemesh/pull/5199) Adds smesherID to rewards table. Historically rewards - were keyed by (coinbase, layer). Now the primary key has changed to (smesherID, layer), which allows querying rewards - by any subset of layer, smesherID, and coinbase. While this change does add smesherID to existing API endpoints - (`GlobalStateService.{AccountDataQuery,AccountDataStream,GlobalStateStream}`), it does not yet expose an endpoint to - query rewards by smesherID. Additionally, it does not re-index old data. Rewards will contain smesherID going forward, - but to refresh data for all rewards, a node will have to delete its database and resync from genesis. - -## 1.3.0 - -### Upgrade information - This release is not backwards compatible with v1.2.x. Upgrading will migrate local state to a new database. The migration will take place at the first startup after the upgrade. Be aware that after a successful upgrade downgrading isn't supported and might result in at least one epoch of missed rewards. See change #5207 for more @@ -42,36 +25,17 @@ for more information on how to configure the node to work with the PoST service. ### Improvements -* [#5118](https://github.com/spacemeshos/go-spacemesh/pull/5118) reduce number of tortoise results returned after recovery. - - this is hotfix for a bug introduced in v1.2.0. in rare conditions node may loop with the following warning: - - > 2023-10-02T15:28:14.002+0200 WARN fd68b.sync mesh failed to process layer from sync {"node_id": - "fd68b9397572556c2f329f3e5af2faf23aef85dbbbb7e38447fae2f4ef38899f", "module": "sync", "sessionId": - "29422935-68d6-47d1-87a8-02293aa181f3", "layer_id": 23104, "errmsg": "requested layer 8063 is before evicted 13102", - "name": "sync"} - * [#5091](https://github.com/spacemeshos/go-spacemesh/pull/5091) Separating PoST from the node into its own service. + * [#5061](https://github.com/spacemeshos/go-spacemesh/pull/5061) Proof generation is now done via a dedicated service instead of the node. + * [#5154](https://github.com/spacemeshos/go-spacemesh/pull/5154) Enable TLS connections between node and PoST service. PoST proofs are now done via a dedicated process / service that the node communicates with via gRPC. Smapp users can continue to smesh as they used to. The node will automatically start the PoST service when it starts and will shut it down when it shuts down. -* [#5138](https://github.com/spacemeshos/go-spacemesh/pull/5138) Bump poet to v0.9.7 - - The submit proof of work should now be up to 40% faster thanks to [code optimization](https://github.com/spacemeshos/poet/pull/419). - -* [#5143](https://github.com/spacemeshos/go-spacemesh/pull/5143) Select good peers for sync requests. - - The change improves initial sync speed and any sync protocol requests required during consensus. - -* [#5109](https://github.com/spacemeshos/go-spacemesh/pull/5109) Limit number of layers that tortoise needs to read on startup. - - Bounds the time required to restart a node. - * [#5171](https://github.com/spacemeshos/go-spacemesh/pull/5171) Set minimal active set according to the observed number of atxs. @@ -118,6 +82,102 @@ for more information on how to configure the node to work with the PoST service. The private listener exposes the following services: "admin", "smesher", "post" The mTLS listener exposes only the "post" service. +* [#5199](https://github.com/spacemeshos/go-spacemesh/pull/5199) Adds smesherID to rewards table. Historically rewards + were keyed by (coinbase, layer). Now the primary key has changed to (smesherID, layer), which allows querying rewards + by any subset of layer, smesherID, and coinbase. While this change does add smesherID to existing API endpoints + (`GlobalStateService.{AccountDataQuery,AccountDataStream,GlobalStateStream}`), it does not yet expose an endpoint to + query rewards by smesherID. Additionally, it does not re-index old data. Rewards will contain smesherID going forward, + but to refresh data for all rewards, a node will have to delete its database and resync from genesis. + +## Release v1.2.9 + +### Improvements + +* increased default cache sizes to improve disk IO and queue sizes for gossip to better handle the increasing number of + nodes on the network. + +## Release v1.2.8 + +### Improvements + +* cherry picked migrations for active sets to enable easier pruning in the future + +## Release v1.2.7 + +### Improvements + +* [#5289](https://github.com/spacemeshos/go-spacemesh/pull/5289) build active set from activations received on time + + should decrease the state growth at the start of the epoch because of number of unique activets. + +* [#5291](https://github.com/spacemeshos/go-spacemesh/pull/5291) parametrize queue size and throttle limits in gossip + +* reduce log level for "atx omitted from active set" + +* [#5302](https://github.com/spacemeshos/go-spacemesh/pull/5302) improvements in transaction validation + +## Release v1.2.6 + +### Improvements + +* [#5263](https://github.com/spacemeshos/go-spacemesh/pull/5263) randomize peer selection + + without this change node can get stuck after restart on requesting data from peer that is misbehaving. + log below will be printed repeatedly: + + > 2023-11-15T08:00:17.937+0100 INFO fd68b.sync syncing atx from genesis + +* [#5264](https://github.com/spacemeshos/go-spacemesh/pull/5264) increase limits related to activations + + some of the limits were hardcoded and didn't account for growth in atx number. + this change is not required for node to work correct in the next epoch, but will be required later. + +## Release v1.2.5 + +### Improvements + +* [#5247](https://github.com/spacemeshos/go-spacemesh/pull/5247) exits cleanly without misleading spamming + +Fixes a bug that would spam with misleading log on exit, such as below: + + > 2023-11-09T11:13:27.835-0600 ERROR e524f.hare failed to update weakcoin {"node_id": + "e524fce96f0a87140ba895b56a2e37e29581075302778a05dd146f4b74fce72e", "module": "hare", "lid": 0, "error": + "set weak coin 0: database: no free connection"} + +## Release v1.2.4 + +### Upgrade information + +This release enables hare3 on testnet networks. And schedules planned upgrade on mainnet. +Network will have downtime if majority of nodes don't upgrade before layer 35117. +Starting at layer 35117 network is expected to start using hare3, which reduces total bandwidth +requirements. + +## Release v1.2.2 + +### Improvements + +* [#5118](https://github.com/spacemeshos/go-spacemesh/pull/5118) reduce number of tortoise results returned after recovery. + + this is hotfix for a bug introduced in v1.2.0. in rare conditions node may loop with the following warning: + + > 2023-10-02T15:28:14.002+0200 WARN fd68b.sync mesh failed to process layer from sync {"node_id": + "fd68b9397572556c2f329f3e5af2faf23aef85dbbbb7e38447fae2f4ef38899f", "module": "sync", "sessionId": + "29422935-68d6-47d1-87a8-02293aa181f3", "layer_id": 23104, "errmsg": "requested layer 8063 is before evicted 13102", + "name": "sync"} + +* [#5109](https://github.com/spacemeshos/go-spacemesh/pull/5109) Limit number of layers that tortoise needs to read on startup. + + Bounds the time required to restart a node. + +* [#5138](https://github.com/spacemeshos/go-spacemesh/pull/5138) Bump poet to v0.9.7 + + The submit proof of work should now be up to 40% faster thanks to [code optimization](https://github.com/spacemeshos/poet/pull/419). + +* [#5143](https://github.com/spacemeshos/go-spacemesh/pull/5143) Select good peers for sync requests. + + The change improves initial sync speed and any sync protocol requests required during consensus. + ## v1.2.0 ### Upgrade information @@ -140,8 +200,6 @@ mechanism since release v1.1.2. Support for old certificate sync protocol is dropped. This update is incompatible with v1.0.x series. -### Highlights - ### Features * [#5031](https://github.com/spacemeshos/go-spacemesh/pull/5031) Nodes will also fetch from PoET 112 for round 4 if they @@ -176,8 +234,6 @@ In order to enable provide following configuration: It is critical for most nodes in the network to use v1.1.5 when layer 20 000 starts. Starting from that layer active set will not be gossipped together with proposals. That was the main network bottleneck in epoch 4. -### Highlights - ### Features * [#4969](https://github.com/spacemeshos/go-spacemesh/pull/4969) Nodes will also fetch from PoET 111 for round 3 if they From f2727d9759d3c2223b226b0e645eec6f0638f385 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 09:37:06 +0000 Subject: [PATCH 19/48] build(deps): Bump google-github-actions/setup-gcloud from 1 to 2 (#5336) Bumps [google-github-actions/setup-gcloud](https://github.com/google-github-actions/setup-gcloud) from 1 to 2. --- .github/workflows/release.yml | 4 ++-- .github/workflows/systest.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1be3eb9e7f..d7002e6e61 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -73,7 +73,7 @@ jobs: credentials_json: '${{ secrets.GCP_SA_KEY }}' - name: Set up Cloud SDK - uses: google-github-actions/setup-gcloud@v1 + uses: google-github-actions/setup-gcloud@v2 - name: Upload zip uses: google-github-actions/upload-cloud-storage@v1 @@ -137,7 +137,7 @@ jobs: credentials_json: '${{ secrets.GCP_SA_KEY }}' - name: Set up Cloud SDK - uses: google-github-actions/setup-gcloud@v1 + uses: google-github-actions/setup-gcloud@v2 - name: Upload sha256sums uses: google-github-actions/upload-cloud-storage@v1 diff --git a/.github/workflows/systest.yml b/.github/workflows/systest.yml index e1160183ab..f9840c551c 100644 --- a/.github/workflows/systest.yml +++ b/.github/workflows/systest.yml @@ -67,7 +67,7 @@ jobs: credentials_json: "${{ secrets.CI_GCP_CREDENTIALS }}" - name: Configure gcloud - uses: google-github-actions/setup-gcloud@v1 + uses: google-github-actions/setup-gcloud@v2 with: version: "450.0.0" From 4fce1496a768933119bb8d1ebab85b8d3d28be5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowak?= Date: Mon, 11 Dec 2023 11:04:00 +0000 Subject: [PATCH 20/48] Increase default timeouts (#5338) We're seeing a lot of `I/O deadline` and general timeouts currently in the network. Increasing the timeouts to 25s from standard 10s could help with some of them. --- fetch/fetch.go | 2 +- p2p/host.go | 1 + p2p/server/server.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fetch/fetch.go b/fetch/fetch.go index 206dfc6436..f14236a705 100644 --- a/fetch/fetch.go +++ b/fetch/fetch.go @@ -125,7 +125,7 @@ func DefaultConfig() Config { BatchTimeout: 50 * time.Millisecond, QueueSize: 20, BatchSize: 20, - RequestTimeout: 10 * time.Second, + RequestTimeout: 25 * time.Second, MaxRetriesForRequest: 100, ServersConfig: map[string]ServerConfig{ // serves 1 MB of data diff --git a/p2p/host.go b/p2p/host.go index 65b10799e2..05c6b53821 100644 --- a/p2p/host.go +++ b/p2p/host.go @@ -165,6 +165,7 @@ func New( return nil, fmt.Errorf("p2p create conn mgr: %w", err) } streamer := *yamux.DefaultTransport + streamer.Config().ConnectionWriteTimeout = 25 * time.Second // should be NOT exposed in the config ps, err := pstoremem.NewPeerstore() if err != nil { return nil, fmt.Errorf("can't create peer store: %w", err) diff --git a/p2p/server/server.go b/p2p/server/server.go index cf8a8f6019..b44117bab9 100644 --- a/p2p/server/server.go +++ b/p2p/server/server.go @@ -120,7 +120,7 @@ func New(h Host, proto string, handler Handler, opts ...Opt) *Server { protocol: proto, handler: handler, h: h, - timeout: 10 * time.Second, + timeout: 25 * time.Second, requestLimit: 10240, queueSize: 1000, requestsPerInterval: 100, From 2ab4a9657d29b1d75ab0a983a1b189c80610daf6 Mon Sep 17 00:00:00 2001 From: Matthias Fasching <5011972+fasmat@users.noreply.github.com> Date: Mon, 11 Dec 2023 12:21:12 +0000 Subject: [PATCH 21/48] Prepare network for more nodes (#5339) ## Motivation This is in anticipation for upcoming epochs, so that nodes can handle 300k+ active identities. ## Changes - Increase sizes for various wire types - Increase ATXHeader Cache to be able to hold the ATXs for Epoch 11 and Epoch 12 at the same time ## Test Plan n/a ## TODO - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [x] Update [changelog](../CHANGELOG.md) as needed --- datastore/store.go | 4 +++- fetch/wire_types.go | 4 ++-- fetch/wire_types_scale.go | 8 ++++---- go.mod | 2 +- node/bad_peer_test.go | 17 +++++++++-------- p2p/server/server.go | 5 ++--- p2p/server/server_scale.go | 4 ++-- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/datastore/store.go b/datastore/store.go index c381b063d1..69f05cc0ba 100644 --- a/datastore/store.go +++ b/datastore/store.go @@ -44,13 +44,15 @@ type CachedDB struct { } type Config struct { + // ATXSize must be larger than the sum of all ATXs in last 2 epochs to be effective + // (Epoch 12: ~ 300k, Epoch 11: ~ 200k) ATXSize int `mapstructure:"atx-size"` MalfeasenceSize int `mapstructure:"malfeasence-size"` } func DefaultConfig() Config { return Config{ - ATXSize: 300_000, + ATXSize: 600_000, MalfeasenceSize: 1_000, } } diff --git a/fetch/wire_types.go b/fetch/wire_types.go index 8f4fc91ded..b711d29372 100644 --- a/fetch/wire_types.go +++ b/fetch/wire_types.go @@ -22,7 +22,7 @@ type RequestMessage struct { // ResponseMessage is sent to the node as a response. type ResponseMessage struct { Hash types.Hash32 - Data []byte `scale:"max=10485760"` // limit to 10MiB + Data []byte `scale:"max=20971520"` // limit to 20 MiB } // RequestBatch is a batch of requests and a hash of all requests as ID. @@ -105,7 +105,7 @@ type MaliciousIDs struct { } type EpochData struct { - AtxIDs []types.ATXID `scale:"max=200000"` // max. expected number of ATXs per epoch is 100_000 + AtxIDs []types.ATXID `scale:"max=500000"` // for epoch 12 > 300k ATXs are expected, added some safety margin } // LayerData is the data response for a given layer ID. diff --git a/fetch/wire_types_scale.go b/fetch/wire_types_scale.go index eb0a64fbb3..448044caa2 100644 --- a/fetch/wire_types_scale.go +++ b/fetch/wire_types_scale.go @@ -55,7 +55,7 @@ func (t *ResponseMessage) EncodeScale(enc *scale.Encoder) (total int, err error) total += n } { - n, err := scale.EncodeByteSliceWithLimit(enc, t.Data, 10485760) + n, err := scale.EncodeByteSliceWithLimit(enc, t.Data, 20971520) if err != nil { return total, err } @@ -73,7 +73,7 @@ func (t *ResponseMessage) DecodeScale(dec *scale.Decoder) (total int, err error) total += n } { - field, n, err := scale.DecodeByteSliceWithLimit(dec, 10485760) + field, n, err := scale.DecodeByteSliceWithLimit(dec, 20971520) if err != nil { return total, err } @@ -258,7 +258,7 @@ func (t *MaliciousIDs) DecodeScale(dec *scale.Decoder) (total int, err error) { func (t *EpochData) EncodeScale(enc *scale.Encoder) (total int, err error) { { - n, err := scale.EncodeStructSliceWithLimit(enc, t.AtxIDs, 200000) + n, err := scale.EncodeStructSliceWithLimit(enc, t.AtxIDs, 500000) if err != nil { return total, err } @@ -269,7 +269,7 @@ func (t *EpochData) EncodeScale(enc *scale.Encoder) (total int, err error) { func (t *EpochData) DecodeScale(dec *scale.Decoder) (total int, err error) { { - field, n, err := scale.DecodeStructSliceWithLimit[types.ATXID](dec, 200000) + field, n, err := scale.DecodeStructSliceWithLimit[types.ATXID](dec, 500000) if err != nil { return total, err } diff --git a/go.mod b/go.mod index 9877356f2d..f877582358 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,6 @@ require ( github.com/libp2p/go-libp2p-record v0.2.0 github.com/mitchellh/mapstructure v1.5.0 github.com/multiformats/go-multiaddr v0.12.0 - github.com/multiformats/go-varint v0.0.7 github.com/natefinch/atomic v1.0.1 github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a github.com/prometheus/client_golang v1.17.0 @@ -164,6 +163,7 @@ require ( github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multistream v0.5.0 // indirect + github.com/multiformats/go-varint v0.0.7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nullstyle/go-xdr v0.0.0-20180726165426-f4c839f75077 // indirect github.com/nxadm/tail v1.4.8 // indirect diff --git a/node/bad_peer_test.go b/node/bad_peer_test.go index 4313a8ab45..de3c6035cf 100644 --- a/node/bad_peer_test.go +++ b/node/bad_peer_test.go @@ -12,7 +12,6 @@ import ( "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" - varint "github.com/multiformats/go-varint" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" @@ -143,15 +142,17 @@ func rpcWithMessages(msgs ...*pubsubpb.Message) *pubsub.RPC { func writeRpc(rpc *pubsub.RPC, s network.Stream) error { size := uint64(rpc.Size()) - - buf := make([]byte, varint.UvarintSize(size)+int(size)) - - n := binary.PutUvarint(buf, size) - _, err := rpc.MarshalTo(buf[n:]) - if err != nil { + sizeBuf := make([]byte, binary.MaxVarintLen64) + n := binary.PutUvarint(sizeBuf, size) + sizeBuf = sizeBuf[:n] + if _, err := s.Write(sizeBuf); err != nil { return err } - _, err = s.Write(buf) + buf := make([]byte, size) + if _, err := rpc.MarshalTo(buf); err != nil { + return err + } + _, err := s.Write(buf) return err } diff --git a/p2p/server/server.go b/p2p/server/server.go index b44117bab9..bac619b178 100644 --- a/p2p/server/server.go +++ b/p2p/server/server.go @@ -12,7 +12,6 @@ import ( "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" - "github.com/multiformats/go-varint" "golang.org/x/sync/errgroup" "golang.org/x/time/rate" @@ -84,7 +83,7 @@ type Handler func(context.Context, []byte) ([]byte, error) // Response is a server response. type Response struct { - Data []byte `scale:"max=10485760"` // 10 MiB + Data []byte `scale:"max=20971520"` // 20 MiB Error string `scale:"max=1024"` // TODO(mafa): make error code instead of string } @@ -188,7 +187,7 @@ func (s *Server) queueHandler(ctx context.Context, stream network.Stream) { _ = stream.SetDeadline(time.Now().Add(s.timeout)) defer stream.SetDeadline(time.Time{}) rd := bufio.NewReader(stream) - size, err := varint.ReadUvarint(rd) + size, err := binary.ReadUvarint(rd) if err != nil { return } diff --git a/p2p/server/server_scale.go b/p2p/server/server_scale.go index 6001e1f7df..162eb225c8 100644 --- a/p2p/server/server_scale.go +++ b/p2p/server/server_scale.go @@ -9,7 +9,7 @@ import ( func (t *Response) EncodeScale(enc *scale.Encoder) (total int, err error) { { - n, err := scale.EncodeByteSliceWithLimit(enc, t.Data, 10485760) + n, err := scale.EncodeByteSliceWithLimit(enc, t.Data, 20971520) if err != nil { return total, err } @@ -27,7 +27,7 @@ func (t *Response) EncodeScale(enc *scale.Encoder) (total int, err error) { func (t *Response) DecodeScale(dec *scale.Decoder) (total int, err error) { { - field, n, err := scale.DecodeByteSliceWithLimit(dec, 10485760) + field, n, err := scale.DecodeByteSliceWithLimit(dec, 20971520) if err != nil { return total, err } From a0b850289fe659149b173d8708b87d1cfdee940c Mon Sep 17 00:00:00 2001 From: Matthias Fasching <5011972+fasmat@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:03:11 +0000 Subject: [PATCH 22/48] Revert part of #5339 (#5340) ## Motivation Reverts part of #5339 ## Changes `PutUvarint` from standard library and `github.com/multiformats/go-varint` do not behave exactly the same. With Go 1.20 to the stdlib implementation was fixed to detect short reads, but in contrast to `github.com/multiformats/go-varint` it will still not return an error when decoding non-minimal encodings of integers. ## Test Plan n/a ## TODO - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [x] Update [changelog](../CHANGELOG.md) as needed --- go.mod | 2 +- p2p/server/server.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index f877582358..9877356f2d 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/libp2p/go-libp2p-record v0.2.0 github.com/mitchellh/mapstructure v1.5.0 github.com/multiformats/go-multiaddr v0.12.0 + github.com/multiformats/go-varint v0.0.7 github.com/natefinch/atomic v1.0.1 github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a github.com/prometheus/client_golang v1.17.0 @@ -163,7 +164,6 @@ require ( github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multistream v0.5.0 // indirect - github.com/multiformats/go-varint v0.0.7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nullstyle/go-xdr v0.0.0-20180726165426-f4c839f75077 // indirect github.com/nxadm/tail v1.4.8 // indirect diff --git a/p2p/server/server.go b/p2p/server/server.go index bac619b178..4e467348fa 100644 --- a/p2p/server/server.go +++ b/p2p/server/server.go @@ -12,6 +12,7 @@ import ( "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" + "github.com/multiformats/go-varint" "golang.org/x/sync/errgroup" "golang.org/x/time/rate" @@ -187,7 +188,7 @@ func (s *Server) queueHandler(ctx context.Context, stream network.Stream) { _ = stream.SetDeadline(time.Now().Add(s.timeout)) defer stream.SetDeadline(time.Time{}) rd := bufio.NewReader(stream) - size, err := binary.ReadUvarint(rd) + size, err := varint.ReadUvarint(rd) if err != nil { return } From 730bda8ee21979e1a9c413d44b2801ac0d2f8f14 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 05:56:37 +0000 Subject: [PATCH 23/48] build(deps): Bump google.golang.org/grpc from 1.59.0 to 1.60.0 (#5342) Bumps google.golang.org/grpc from 1.59.0 to 1.60.0. --- go.mod | 4 ++-- go.sum | 20 ++++++++++++++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 9877356f2d..7414531821 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( golang.org/x/sync v0.5.0 golang.org/x/time v0.5.0 google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f - google.golang.org/grpc v1.59.0 + google.golang.org/grpc v1.60.0 google.golang.org/protobuf v1.31.0 k8s.io/api v0.28.4 k8s.io/apimachinery v0.28.4 @@ -210,7 +210,7 @@ require ( gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect gonum.org/v1/gonum v0.13.0 // indirect google.golang.org/api v0.153.0 // indirect - google.golang.org/appengine v1.6.7 // indirect + google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 0dab502252..838a38753c 100644 --- a/go.sum +++ b/go.sum @@ -685,6 +685,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= @@ -743,6 +744,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -779,6 +781,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -819,6 +822,7 @@ 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-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -842,6 +846,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -889,13 +894,17 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -904,6 +913,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -962,6 +973,7 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1003,8 +1015,8 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -1063,8 +1075,8 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k= +google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 92b7762a6b4ce854af08c8cf6e2473442b5764b9 Mon Sep 17 00:00:00 2001 From: Matthias Fasching <5011972+fasmat@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:29:20 +0000 Subject: [PATCH 24/48] Update certificates for tests using TLS (#5347) ## Motivation The mTLS certificates used in testing of the `grpcserver` package expired recently. This PR includes new certificates that are valid for another 60 days. This is a quick fix to unblock the failing CI, a proper fix (generating new certificates on every CI run) will follow. ## Changes - generated new certificates using the instructions in README.md ## Test Plan existing tests pass ## TODO - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [x] Update [changelog](../CHANGELOG.md) as needed --- api/grpcserver/testdata/README.md | 8 ++- api/grpcserver/testdata/ca.crt | 56 ++++++++-------- api/grpcserver/testdata/ca.key | 100 ++++++++++++++--------------- api/grpcserver/testdata/client.crt | 56 ++++++++-------- api/grpcserver/testdata/client.key | 100 ++++++++++++++--------------- api/grpcserver/testdata/server.crt | 56 ++++++++-------- api/grpcserver/testdata/server.key | 100 ++++++++++++++--------------- 7 files changed, 239 insertions(+), 237 deletions(-) diff --git a/api/grpcserver/testdata/README.md b/api/grpcserver/testdata/README.md index 0deb71a48c..aeb10effc0 100644 --- a/api/grpcserver/testdata/README.md +++ b/api/grpcserver/testdata/README.md @@ -25,14 +25,16 @@ openssl req -newkey rsa:4096 -nodes -keyout server.key -out server-req.pem \ -subj "/C=EN/ST=Spacemesh/L=Tel Aviv/O=Server/CN=server.spacemesh.io/emailAddress=info@spacemesh.io" # use CA private key to sign ser CRS and get back the signed certificate -openssl x509 -req -in server-req.pem -days 60 -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -extfile domains.ext -extensions v3_req +openssl x509 -req -in server-req.pem -days 60 -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt \ + -extfile domains.ext -extensions v3_req rm server-req.pem # create client private key and CSR openssl req -newkey rsa:4096 -nodes -keyout client.key -out client-req.pem \ - -subj "/C=EN/ST=Spacemesh/L=Tel Aviv/O=Client/CN=client.spacemesh.io/emailAddress=info@spacemesh.io" \ + -subj "/C=EN/ST=Spacemesh/L=Tel Aviv/O=Client/CN=client.spacemesh.io/emailAddress=info@spacemesh.io" # use CA private key to sign client CSR and get back the signed certificate -openssl x509 -req -in client-req.pem -days 60 -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -extfile domains.ext -extensions v3_req +openssl x509 -req -in client-req.pem -days 60 -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt \ + -extfile domains.ext -extensions v3_req rm client-req.pem ``` diff --git a/api/grpcserver/testdata/ca.crt b/api/grpcserver/testdata/ca.crt index 421119a474..70e50b6755 100644 --- a/api/grpcserver/testdata/ca.crt +++ b/api/grpcserver/testdata/ca.crt @@ -1,34 +1,34 @@ -----BEGIN CERTIFICATE----- -MIIF5TCCA82gAwIBAgIUXX1SBglREeOwJb/Z4tYWvY8M/6wwDQYJKoZIhvcNAQEL +MIIF5TCCA82gAwIBAgIUQ1mgEwthmZ0Ki+0HmoTGtoQpgbYwDQYJKoZIhvcNAQEL BQAwgYExCzAJBgNVBAYTAkVOMRIwEAYDVQQIDAlTcGFjZW1lc2gxETAPBgNVBAcM CFRlbCBBdml2MRIwEAYDVQQKDAlTcGFjZW1lc2gxFTATBgNVBAMMDHNwYWNlbWVz -aC5pbzEgMB4GCSqGSIb3DQEJARYRaW5mb0BzcGFjZW1lc2guaW8wHhcNMjMxMDEz -MTU1MjQwWhcNMjQxMDEyMTU1MjQwWjCBgTELMAkGA1UEBhMCRU4xEjAQBgNVBAgM +aC5pbzEgMB4GCSqGSIb3DQEJARYRaW5mb0BzcGFjZW1lc2guaW8wHhcNMjMxMjEz +MTcxMTA1WhcNMjQxMjEyMTcxMTA1WjCBgTELMAkGA1UEBhMCRU4xEjAQBgNVBAgM CVNwYWNlbWVzaDERMA8GA1UEBwwIVGVsIEF2aXYxEjAQBgNVBAoMCVNwYWNlbWVz aDEVMBMGA1UEAwwMc3BhY2VtZXNoLmlvMSAwHgYJKoZIhvcNAQkBFhFpbmZvQHNw -YWNlbWVzaC5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANDcnyfM -tBZjzbPh5pjn16twRucN01bb50P383y+fv87qOSrLLn/EVPu0K1BgI8yz4N1V6zX -IEMIhMT7qJxyroU0qtPBMLbfkBuQGUG60MZdwedocPLLK+KAT8khFiibFD45sBgc -S2oISQ80XZNUvkPybErXukqx4TSodquh6UO+ZuUYv+nebgoDroepx6tLFOuPezqt -gNuiz0KIarjXToUqb8fiUwTcXgSyeO+a/VVNhUHB1nXiJBRetyuZsu0C8JK+y/59 -YBo0zyeNAynG488FsEmUK5lDDUKseIjfY7I4YPrKR2kBd5AHI8UCSpNOmHrvc6yU -xWU6zVzI68VB3vNA9kVZTfXXvTrbo9Sa/TNUT+zqcxsbsoOXFsSmUL3I/7yBSiwQ -iPoQD4waMeAioYBJPQexTKy0vjCDVTdLTXQZe7CrXSSP7Iphnk0dlu+oaS+DLygf -pxlKBcg/vRiBhSb79nWkRgdlKsDtZEJ2IBBo23njt6fJGGUKAugaDQTugUolKXMW -puU3PNiTyHUWwLN5qQh2wWl2mgQAoYPw/CASC2dROD/WqOiVSqGs/zUGAthREiud -B9sB/OgwU2n53so07kcpZV10Cihc//Putuj7rnploOHTpNqFxObWByNKAZyZz0aM -G3DuIOHJEBnrotG2MnGvKvDex1siF/6YC53LAgMBAAGjUzBRMB0GA1UdDgQWBBR0 -wOO4u0m6cJxDCUrBUJl/IYz71zAfBgNVHSMEGDAWgBR0wOO4u0m6cJxDCUrBUJl/ -IYz71zAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQDBLx0O1VHc -GxoCcodT8TZVq6YVFOc3Hw3OszLh0RVvATd0FeHH5zmP49sp6NHeDwSUHkbMUm++ -Vf7Gx+n0THbp+9z8BXoBO4xXERkhO4y4J0yaooN7gWf2JsxHfAZjB+1dKxYTrrl+ -q9LriXiLMgQ0Oy9ccOI/D2MCqu3XEfAuyjq7oZXSVXgO0jW5kKlcI58XO4qLjryZ -yowBbcmaEORTwGcZslrIkh+rIu+VXkasm7JD/BeL3mi6gPb4emyq3zmorj5UXMwD -6gPrEG0gYezplWJkDcAdq1IVkfgPUMEoQfzhJUcIsc9t4YyGjNLLMDunUSh29XIV -CMiX4DL2X8zk7sn0jTgckTvio3LoNWN/BlkjflywJPkG3cjyvKe3KfTOw8LN+jYu -aD0YTROL+P9kOrc/nOevo4M7A8COzCQlMoF9+wnOCaSmg++Av30GIWpjpv5bC6e5 -jAK0o9WB2mMTD3+WexaSv6uKw3mtj9ekzp0PuR29iWHh3cisK8YdcFNcaxFzQ1Og -HUt+7ozC06akmdZpRuLJogSpB26mLji8EWzgNzYoxVHFKRR5z8UJHHDi65s2O0Mh -XayKiGLI9ja/SAkQwGqarL0u+r/Da9myZ+huGOkWtyzN24tPML3eT3Vc8KllLsWe -HhfhKsR8HA6pNLGlub4yjQ9YqpffBVfqlQ== +YWNlbWVzaC5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL3kQI5C +7rGpAq0NqOi0RJNdoyEfKkTVXRA8tRpH4MyiFZbDfvN0triXviNDnwqlp1ew4a5b +5ZiRDV+ze+pMVcDAvdeVYShXt3d+SM+Q2dSNpgi/NaU8OpBZcNOSoCjAL25CXqZr +oEK+1HgZUHGi3rLT3PwjBr1X4+gYQcif/k9pJp/zy8OUJ5wPni6tsxS8uVITWDcJ +jyT/Flp8vEuZhGm1s4XJjCh5bqAiHjMRsnFHrPT60rZ6gq2kCWYkCfv48nmYhIw7 +72vKOuc09p1TTiiKndRSViU5UcEyhQ+3Ip9JXqtZOPmlgNiYTHIGbi2bj09TZyzu +8XYa94+v0Bcr9I0ImnaGkDK7RXGPGG376nZcHY6MEmWXqHGT59Rxnf+zJujM4HoU +luZvDwQDV76O5qptst1DeMw3AqpLa8bHUHWoyK2I5aLXoe6SsDmma8tV81UqiNXV +Jp78s2P4MVqAB77Foj8UKYlf17Az2Kl9f8jzPUDFuWo+NmkuxNY7Ic0XpVnhIxXc +rG1RKSF60jlk5yHeilbo9z+dLM0FvfdAik0+IFOvAgYf3RBfjS0jabdaiUkgPccx +HEDxb8HmWhlQastsJ0ZuNXYJMMGaZJewIKCuUMA6BljAgMBpQYQIrdTdkL9lpQ7P +onvbEdde13GfhJzID8J+HUBWj9kuCHFJb/hnAgMBAAGjUzBRMB0GA1UdDgQWBBTU +sufzhC4ToM0h43+7jXZnJ50fTzAfBgNVHSMEGDAWgBTUsufzhC4ToM0h43+7jXZn +J50fTzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQBpyWjucPZf +GtUYX5OFlHca7z27lPdeUQ91+qz4TyoLcAwFEJKfD0Js+IjljvzBaPgvYESxEiVw +i924Gob3+ZqbcS73LZKjPX+Epzv18UvxMwSca28nkfHHYQ13QVQWga64q028NEkx +UG9snaM+3J8pfTgelxcWiQJoOMMgWfuiYEvGtB4z7BHN41BWrYUaeNknH6EuOFwr +7J+Sq1dVWZS6guV2QfLKJhseDof/4emtseYkg2FutGI2m4EetEntXe/HmSatNxfj +jAoZIa+RepWodzUXL+Rw4xud9+VfLjtZHVz7KtutQT7w8uHkT7sgBo61TjlLdkE1 +TRQaFUSmV+fqjFgZQdiFAvDFlg4V+YC+6PacwpkMBCgP7sZuPQokxwZrcm+eoZvc +rm5cNhm3iouc/sT90AqjMOkAnCAkkc28+6OlNyTgpoWT7GhijQdHq825KfpNpsF7 +9ZmSfEhRFOeiysJHKfM8X0SzinKf3061UW5lHOpxb/VPkzLwZSWVw2UzWn6TFRyt +IUZ+SEBRwJ5Q90cZ6gjQJI8r6ceFDXZRIVG2eXJ6pBfb+O+kOovAbp6fBTNQK1kR +FiLeWTYtJ1/g2JRBLhASeR+N95rFukQVtVT+0YMqYpCfemi8gY/YOojzZUlhnZyM +K1h1rLGJlyMnweY6DnF9XaQsX0Xo2Q/mjA== -----END CERTIFICATE----- diff --git a/api/grpcserver/testdata/ca.key b/api/grpcserver/testdata/ca.key index 3f44f819e7..2532d8d0ba 100644 --- a/api/grpcserver/testdata/ca.key +++ b/api/grpcserver/testdata/ca.key @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDQ3J8nzLQWY82z -4eaY59ercEbnDdNW2+dD9/N8vn7/O6jkqyy5/xFT7tCtQYCPMs+DdVes1yBDCITE -+6iccq6FNKrTwTC235AbkBlButDGXcHnaHDyyyvigE/JIRYomxQ+ObAYHEtqCEkP -NF2TVL5D8mxK17pKseE0qHaroelDvmblGL/p3m4KA66HqcerSxTrj3s6rYDbos9C -iGq4106FKm/H4lME3F4Esnjvmv1VTYVBwdZ14iQUXrcrmbLtAvCSvsv+fWAaNM8n -jQMpxuPPBbBJlCuZQw1CrHiI32OyOGD6ykdpAXeQByPFAkqTTph673OslMVlOs1c -yOvFQd7zQPZFWU31170626PUmv0zVE/s6nMbG7KDlxbEplC9yP+8gUosEIj6EA+M -GjHgIqGAST0HsUystL4wg1U3S010GXuwq10kj+yKYZ5NHZbvqGkvgy8oH6cZSgXI -P70YgYUm+/Z1pEYHZSrA7WRCdiAQaNt547enyRhlCgLoGg0E7oFKJSlzFqblNzzY -k8h1FsCzeakIdsFpdpoEAKGD8PwgEgtnUTg/1qjolUqhrP81BgLYURIrnQfbAfzo -MFNp+d7KNO5HKWVddAooXP/z7rbo+656ZaDh06TahcTm1gcjSgGcmc9GjBtw7iDh -yRAZ66LRtjJxryrw3sdbIhf+mAudywIDAQABAoICAA60Wagtq0ggQq01bEy7ld2G -DBfcS1LELKYGYOgZaUuC4cMnogB+SrQEDkEEaY6rXxy8OC38/1J42RAdP6O0F0Fd -keFSqqFVYAnwvTZ5dpVgqHQoUDtnvnE142gfojW9pVE0MoegBlcyuiIN58ClqLeT -67fhNEZp+5b/fUtcHNYeI5Rhh7FpbYna9ICsnVgb8x8afOyGppnP/pOKkyjsT6Tk -dfY2ou2mrh/aiNUlrkxBJu6YPQcTosKkYHT7XzN8j39lW2tRXGC78xGvxdc9H3DF -z8F+YwtpQxe8mMfaImS7v2gosZpc9hP3zLbkEGgKkoWlMhmmZ7dWynqL0r2Sg6Wv -94MVWZY5uPj1lbkoc/9Vd3MOq5GxVt1XjgNrDz95ZFCZDmzICkSFtFPsgpf+ZaMp -wnHQvym/UnxwMuzKwEWV0tACz4rZnjSDOQKyTq6lg7Nj+qjTcs5yIvOyJ3sNSOOn -E7X43FaPEEbo2uLpXmuvvMxo/4v7UN9Gzt97MaJkiK8s5xd9Ea932AxyLyvSX5Rp -Zq1Yy3YTc7DkkoVnWLZyx6j/uGZHJGtn1+4CuWdrygPOZFfC8lVi3OLVupprgNxP -ejC+Rh3nZi4rto2cuEdHN7PxdgzTtJgta0VU+oC2njyc7i2PBWzlxUASc/+wNCcg -Bn8Db0Py0yDhupcJTbGBAoIBAQD5n2uM96sys8mrHwCcZeZjWKl9ZP0AVIuPX7yg -1Pj+ZQNTRvrmvOWsDNtBB9IA+eGinbY8htf3ADR8R8N8UJ175kKKnjwUs8Yq5zq/ -henj94z8bbLjOOWGg3p9s4ap8NLpAbeiYZKUESjpQkRTsOzu727ZJN91b/vwWwJK -XyDSdPu2dSzMxv92OqKr2+W9jmgDG+LbqMW+uzsADvVtCArE/Hi7DErktg9mf7p2 -VNvgULKxYo/yMFOCZie53LFiQZmuTH605SU3WEitfVU7Wz+VD6btB18CYth6W4yE -/9O5h8CyRTVGJ8FzJhZ0lhiiHkzNcb8/jMaMS8fZeFZs2x+hAoIBAQDWMp4M4elB -GbdmhZBLianZnpJtdtmXEF2KlJPkC6muGQECkVlrGSuVkL+r3HYpxpqUHNhTUUnl -H1DEnm5HN2j5qffbv9CPIx7nu7ygyrpMlKZtkEFMNUg9fqaxGuyuaf+E9D158Oqy -UNtPYSVKpB9AMUcyTUNXRbp03LOmj0mGEolg7fSbs+zFXPcV/xdOzH6s3VWSnjHt -QhTHH9GL78RS0pQSfNoBcfxYOFMJbGu5M6rfQvaWpAW2R8Kl4K+ZGLSrHLjIdHKF -e/fFcQN/p1dQQv4Eh2hPWRh1hregKCyMNOFjVY2ZrVZOzob9sl5EFs94CBoVKiDi -kZAhCbLT0XXrAoIBAFP6bhRevhmwoogPRgVXwsppaZvl/be+ubTiYHM7Mwlislux -5Xb61cmsCZc3Kk9pwZ8Tr9ttAfr29rFY80s/U7v7GyfHVC8iy+hjIkCMrMMk5SmH -PkdzPMSkNvFTFFrXyhzZlw3qBYYKv9i5koMVYqB/rKsg3IyFwBx8gajDmCc1c/lO -MmQyDn+X+mIW+JNs9VEWcJu1i9E+6/p5DdhAfF8JERTcbdXD6ipxjimBIve0Lmm+ -3u57k5yrAXJl7MdBipI46eexr3OPH+Q95g6yBBIB0gasFCqZVnrTkdKsvm4MXaeb -4PBZL5utlKBkXqUrzGrReaXHloRcej+PXIQCtAECggEAOoDgwkwB1ZIckZfxbXBQ -P+wbumI31BbYNb2XFzZIRhD2QalJbwMU8Gj0sRAqBgcEuWeXfko5kKcY/Fr5a+Iq -feZ6mD6vzCifjFOulYxJjhkby9kWvKXg8UriZIUiGBFDhSDgmam/sKx8+hVihhyF -nJbZB1grCG83GiwdtWR1hHUTqLHVmaFvDgjyQ8PErfUUtEpP0Rf8Mv1Vh32dUkdO -rABwCQyozrQ/ZCkeJPjEA3WlOg2kJEjwdnTrKTtROtOQpRvXLIkBrovJhNf1SKyA -IJ/rmXkSeHmxQIhnJwtR/4mB9gur/UlmxWeLX0eUj6xbRkGQPi+fg8KWRy/K9CfF -uQKCAQEAvOwa/glYewheexMC4PQrgIh49aod63bW+Ji1KPx/A7hKDnV+hkOFOs6g -fZOIqYa+d9SraVJ1kD6hlrlwHRgll30tkWEbayShxXRDrSTMyW3eEE3Nh+8mnLn3 -T0Zb6arwa3ORjkNzu37vmfv8yU+UH41ePlqxSc7SBK9ahPaA9DajxbyCh9WBbUhc -49RzJsJjPSGE8/QZvQs0GOlByX530uL46DU1QdhjwjyJhXMARGbU5ngaBwXNG+Hd -MN8wgDtucToL2jeMV9bRXZYaB9AyFcBPpDxUU37EzltIN+7hlUZLcnXjBPepQEfN -dYnwa0fikpJSrEfWt1kHxPnaKd0aag== +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 +pjttZIVAnlp/EpJBaBEROW91c6mW488= -----END PRIVATE KEY----- diff --git a/api/grpcserver/testdata/client.crt b/api/grpcserver/testdata/client.crt index 55a7b09a21..c94d054cc8 100644 --- a/api/grpcserver/testdata/client.crt +++ b/api/grpcserver/testdata/client.crt @@ -1,34 +1,34 @@ -----BEGIN CERTIFICATE----- -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 -----END CERTIFICATE----- diff --git a/api/grpcserver/testdata/client.key b/api/grpcserver/testdata/client.key index e3135a84ad..29bdbd6027 100644 --- a/api/grpcserver/testdata/client.key +++ b/api/grpcserver/testdata/client.key @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -CCs1A3x1zKNck0SIhewqgJ6bpen1ew== +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC0WckhQFe4482h +6ZzQSvW2l2bpVczBaJ6hYQ5rhCJ9eM7Ste845kFcT2XYDtVB2YiPdbg5DDjaka+y +TqM92wSuqa3ERLYKzTDNl+nNFUdzqy0/usMM2w97oFCcoaRDRjCEJ5ovvzRYHTZS +PRx2UhF9VAmjl8l66vcoCySF7fckW99yTl004CyZtE0SSZ+ws0s5bqjKwm+Zvj1O +eVYZFuf8vvQEuiQYu9y/KnWipMTvQaPmZhFNRRGysBIPNQb8riPKuIwaZsEipO/7 +oiV3uWwEy3mh7hJIiiIC1K/2YZX1np0oatJ0bOVtFW8inyUvzlFiULlWWl3xkGG9 +cijiYIeuKe+Jt7+PvnE3ipuO8eL5Do04gQ0p1reYkv+dayqyUK5DVKXwGhVsG4L7 +koxL6Hu8DYz7je5LnYoaLvO10fj0X02YQI2qi34St1LFlq7/xdQH0KuNFoFOOsjz +4kpT9cI8d0xExFEKMw61QPBYnX0qaUtVIO652wnMgBgyW5gJ+TK5JGYO5UI82Ak0 +tJ6+UUfkalXrf+lxOK3S7qEJ/3qAYRJExFcnYOrvRNImOPLDXtW5v+r3Iv8KQgW/ +Gg2AstvrZKrC62BFqfsOGNPIXFtJ2Zb20hfukVxBBPp6LyqtzYZsnQBHa12MrUHD +M1dQl3NBPddfBWvB2ogakHLgnklO0QIDAQABAoICACAc+qzSjaws2AE0HUmTh2QP +WnJC5lYsAE8A/rXTTebkm4M2hRWvHkVHF/3cSknS57ePwRFbZUY5+bx4tyV8+bz2 +Fqxjhbyvo7iAC9AKMXJdsQ1vfmqsGPos5h21xI98EIh/mrtUwwfLj9Ad9JL28wlL +bPn1vZkG/KJjNYopgL+3Ijby0DLpldd6nNycQnSOwF7GHwUXkRKhpr3x6gxGoWFG +SSIMWQAUd26Mq2yeBTkLCZmtY/hLy6ZzJowRp6BXi6T9rmjHEi3Oi7LVQPGsERlb +d9mHEDddbUfuwjRPVQnqx9YaC0ZS25lMX0EdcFwuUxx7/jxrk92/FUBL8w64HIBw +jpmn9mSFG03T95SskxJNBcQuTOPaUyacBXDEg16rJ9I7BgXgSRwZUwAzS7m/dBag +TJltqWS1iEyB3fgZNmBYo6RyK09N6y7p7rtlydz5bwB5Y64YYoLudaasG2BMTuM6 +H5IquW8Ux1atji2xgPp7p9W+aGfPxoyZvCCnUVYkAJoTl3IbU3r7J6TuBOpOFC1g +608PwP2SNQqWlOVIf68x7kNLzvzmaSGQBtzKcM6ofinVT/m96ioPiu2z6ALUecsZ +IcBPepkt2vPtMfk563Jb8jy6jeUxTLjf3x/34vssIQ+8gnrfdkzvzO9zwnmgT3Ng +kTR4GDVkzn3UzOoj+jhHAoIBAQDXuNndRIRBawv+4kb8n32YEcW2jyY+vUEopCN7 +c9+kOc1GGd7jes6+C7DTE5zN58Jp25Vld5jS+10+Xnzl/LHDw52Q5/y6ZOpVgEFv +Dwu80MWPl2gsYZyjas7D87kmJ/k4MTWnhGbw3yjdkeyV+XW/F9o4od/WjA78epv+ +5MUVRHWCQoEtEcX4T5u4KboccfrvTE+pSpLjrXRZ2kVLEyo4fEjoiYwLYAwpE9mr +YcxR8aVP7/5dR+nG+CnZo9HCDlAjPtfM9wh10maELyKmqYVI2gqx4euenDfhUTDi +ktl1FR+dZl7M6lM7kIX/0ZzrPrmJdmkF4m9lMVJPxBab7hYfAoIBAQDWBj6DBo6W +Sf3M00u/9gM7bMdZBNEZh6dMFRr4RxoidQXnlJ02OzjODuQHqJKaYPJbz0iwsxsx +jdlEuY05SGdwumeLVcAKt6vJDqD4IqPsfpUolQFt3gcaulWmTljq44iDlo+a57Dj +VzDB5prOoG7mi1TGUNFITZnhn7Tu6gPe/Uz2qefYB5wkj+znk3KYnmwHW1kw1mg8 +7CtjIdWC28QHtqIDCwyZjyTDkS1zLFt8GJ/AknL/6uwDNWTtRp870NoCbmYNOZv2 +w4Qz/+MgTpfWTL2wS0CqStdy4LFs6H4S36Cn2KneL49v39QumVEGOWKYzS2PM46+ +CuAXpKqNm50PAoIBAFoMar1HpaGdKsO59wHrHcVF3e9n8AIOhE2PvtQAuaFXE44o +rHbuw7BnNufVbwYwsWH47HMPqnafwPuQ+7gRdK8QUAy2GjRAfeU1BZtzf2XRDDb1 +b+He2UEKC8eWTHpWA11mhUwpI8N2lBtxl32/RVyAe3JaeBKaIoNYNxf+rRpEmnzG +gB+tJKOTr5//oxXOqn4Lr9EuNQTfWgtL5tMA7AXqM5EGIbR54nmfNKSqzVyDb4tf +1iFgLIEHBIk6LgxAZ0lfKTwA/sIYEv0oo+FIMEAJ7J72fKGX+meOucZKoIWUTL8q +hXYqdpYNrTHtcQBuDYsJJ6vyKqfmH8L2Sq3Kg+cCggEASCBWlMVy7AcHdy2GC60W +rcIc9E0BQr9KjANY0W70ycPyN3cH/Cy9GgQ+qK4QqeIeCv6yGophkbOiEt0NUM6r +vXu0RWqii3oWdG1vpe/Wmm6WSdTdZG88qa8+CgvBP3dqnB3zS1rla9gIYHAcn6HF +fgBak3LM9LbiMv0ldpZ6s31doIrlzRHTdybhybERH4nUEi6gwiqfeliEzqWqVK1H +ROoxcyEYH+/zjcyxKm06b3nE7JruEnzTCMnHt4bjRr89mTAnSDGv89s0BGop2sth +tCCslGrn4fvS264JXRCE3Ets0uPbaztP9X3S/dlBSv2v0priza2sXzM/Dfi6WXql +1QKCAQBH6dT/m0uJhft2LikABaKauTf3f1H2UM3Xi4MLAmvetVPVuxWWc+2B3ltI +N6pDuFJvyB0DzW7Xdug3BOBGAZiKZI3Tes4kQqsKGfZRUCuWsrw/TOyaiPfjCRY6 +p7GNIRTc+2nzsUlaSrhqRIXi2S+XJnhkaoe2iw1/UBomjKw6xST0DAhx7rP9ctEN +BbjxNssxKKbROzzcSp05jBMF/LKQjyx/MHAffOVfIkIBsZ0Aez/owlNaZGCD/e8B +Ctcahhl3zct/B6pet6n11/Z4KtY1T/xmDK3+E42Cue63rWe4ejBuwHGVgnEaTV9A +DILdpI4JaU+XPuWHzg1dx/LZjrU0 -----END PRIVATE KEY----- diff --git a/api/grpcserver/testdata/server.crt b/api/grpcserver/testdata/server.crt index c7e5e4a91a..26bddbf5f7 100644 --- a/api/grpcserver/testdata/server.crt +++ b/api/grpcserver/testdata/server.crt @@ -1,34 +1,34 @@ -----BEGIN CERTIFICATE----- -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 -----END CERTIFICATE----- diff --git a/api/grpcserver/testdata/server.key b/api/grpcserver/testdata/server.key index 659d6b54c3..ea0337f795 100644 --- a/api/grpcserver/testdata/server.key +++ b/api/grpcserver/testdata/server.key @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -HKOzMNmxpT5p888BCcJiqZ3Vt74b +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 +rT6XdZjtY7yJIVnYg7jUx1hwEjjO -----END PRIVATE KEY----- From 69b26c63a6716e4969aabc6da79a6fa0befa70ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 08:34:15 +0000 Subject: [PATCH 25/48] build(deps): Bump k8s.io/client-go from 0.28.4 to 0.29.0 (#5351) Bumps k8s.io/client-go from 0.28.4 to 0.29.0. --- go.mod | 16 ++++++++-------- go.sum | 37 +++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index 7414531821..ad98df1c39 100644 --- a/go.mod +++ b/go.mod @@ -55,9 +55,9 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f google.golang.org/grpc v1.60.0 google.golang.org/protobuf v1.31.0 - k8s.io/api v0.28.4 - k8s.io/apimachinery v0.28.4 - k8s.io/client-go v0.28.4 + k8s.io/api v0.29.0 + k8s.io/apimachinery v0.29.0 + k8s.io/client-go v0.29.0 sigs.k8s.io/controller-runtime v0.16.3 ) @@ -88,7 +88,7 @@ require ( github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect @@ -220,11 +220,11 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.28.3 // indirect k8s.io/component-base v0.28.3 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect lukechampine.com/blake3 v1.2.1 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 838a38753c..8e8200d6c8 100644 --- a/go.sum +++ b/go.sum @@ -167,10 +167,10 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-llsqlite/crawshaw v0.5.0 h1:Olbqkth53vkkh4WvmkYjrtfOBcxXD3rMYBYuk6FNH3E= github.com/go-llsqlite/crawshaw v0.5.0/go.mod h1:/YJdV7uBQaYDE0fwe4z3wwJIZBJxdYzd38ICggWqtaE= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= @@ -245,6 +245,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= @@ -522,8 +523,8 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= +github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -1128,22 +1129,22 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= -k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= +k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= +k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08= k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc= -k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= -k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= -k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= -k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= +k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= +k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= +k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= +k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI= k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= @@ -1153,8 +1154,8 @@ sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigw sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= From 0d836886e5f10a3c35f5195433123f12a26239ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 12:24:56 +0000 Subject: [PATCH 26/48] build(deps): Bump cloud.google.com/go/storage from 1.35.1 to 1.36.0 (#5350) Bumps cloud.google.com/go/storage from 1.35.1 to 1.36.0. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ad98df1c39..a9342562a5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/spacemeshos/go-spacemesh go 1.21.3 require ( - cloud.google.com/go/storage v1.35.1 + cloud.google.com/go/storage v1.36.0 github.com/ALTree/bigfloat v0.2.0 github.com/chaos-mesh/chaos-mesh/api v0.0.0-20231115031015-f44a6888d1af github.com/cosmos/btcutil v1.0.5 diff --git a/go.sum b/go.sum index 8e8200d6c8..8fe6eaee92 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w= -cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= +cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= +cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= From 4f9a8bb75dbb223c222076a582bd9db5049f4675 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 14:20:02 +0000 Subject: [PATCH 27/48] build(deps): Bump github.com/google/uuid from 1.4.0 to 1.5.0 (#5345) Bumps github.com/google/uuid from 1.4.0 to 1.5.0. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a9342562a5..d35dc81a8c 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/gofrs/flock v0.8.1 github.com/google/go-cmp v0.6.0 github.com/google/gofuzz v1.2.0 - github.com/google/uuid v1.4.0 + github.com/google/uuid v1.5.0 github.com/grafana/pyroscope-go v1.0.4 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 diff --git a/go.sum b/go.sum index 8fe6eaee92..8e44a565a6 100644 --- a/go.sum +++ b/go.sum @@ -274,8 +274,8 @@ github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= From b8700d923574c14feabe451f7026069dda0305b9 Mon Sep 17 00:00:00 2001 From: Matthias Fasching <5011972+fasmat@users.noreply.github.com> Date: Thu, 14 Dec 2023 18:43:05 +0000 Subject: [PATCH 28/48] Update dependencies not covered by dependabot (#5355) ## Motivation Dependabot doesn't update dependencies that are not versioned. This PR updates those dependencies ## Changes - update unversioned dependencies ## Test Plan n/a ## TODO - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [x] Update [changelog](../CHANGELOG.md) as needed --- go.mod | 18 +++++++++--------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index d35dc81a8c..b81b6966b6 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ module github.com/spacemeshos/go-spacemesh -go 1.21.3 +go 1.21.5 require ( cloud.google.com/go/storage v1.36.0 github.com/ALTree/bigfloat v0.2.0 - github.com/chaos-mesh/chaos-mesh/api v0.0.0-20231115031015-f44a6888d1af + github.com/chaos-mesh/chaos-mesh/api v0.0.0-20231212132935-7a55558d8c33 github.com/cosmos/btcutil v1.0.5 github.com/go-llsqlite/crawshaw v0.5.0 github.com/gofrs/flock v0.8.1 @@ -20,7 +20,7 @@ require ( github.com/ipfs/go-ds-leveldb v0.5.0 github.com/ipfs/go-log/v2 v2.5.1 github.com/jonboulle/clockwork v0.4.0 - github.com/libp2p/go-libp2p v0.32.1 + github.com/libp2p/go-libp2p v0.32.2 github.com/libp2p/go-libp2p-kad-dht v0.25.2 github.com/libp2p/go-libp2p-pubsub v0.10.0 github.com/libp2p/go-libp2p-record v0.2.0 @@ -49,10 +49,10 @@ require ( github.com/zeebo/blake3 v0.2.3 go.uber.org/mock v0.3.0 go.uber.org/zap v1.26.0 - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa + golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb golang.org/x/sync v0.5.0 golang.org/x/time v0.5.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f + google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 google.golang.org/grpc v1.60.0 google.golang.org/protobuf v1.31.0 k8s.io/api v0.29.0 @@ -179,7 +179,7 @@ require ( github.com/prometheus/procfs v0.11.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.3.4 // indirect - github.com/quic-go/quic-go v0.39.3 // indirect + github.com/quic-go/quic-go v0.39.4 // indirect github.com/quic-go/webtransport-go v0.6.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect @@ -205,14 +205,14 @@ require ( golang.org/x/sys v0.15.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.15.0 // indirect + golang.org/x/tools v0.16.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect gonum.org/v1/gonum v0.13.0 // indirect google.golang.org/api v0.153.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect diff --git a/go.sum b/go.sum index 8e44a565a6..1e07cbe754 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,8 @@ github.com/c0mm4nd/go-ripemd v0.0.0-20200326052756-bd1759ad7d10/go.mod h1:mYPR+a github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chaos-mesh/chaos-mesh/api v0.0.0-20231115031015-f44a6888d1af h1:7UWqbwvi+Lm6lauY3o2IGgzxmkzHiIIh4M0zAc9nBLg= -github.com/chaos-mesh/chaos-mesh/api v0.0.0-20231115031015-f44a6888d1af/go.mod h1:x11iCbZV6hzzSQWMq610B6Wl5Lg1dhwqcVfeiWQQnQQ= +github.com/chaos-mesh/chaos-mesh/api v0.0.0-20231212132935-7a55558d8c33 h1:2zCcq2VyGp5i7ILmJpEbQSYlu4Wihf+9+PBKnLFzqOM= +github.com/chaos-mesh/chaos-mesh/api v0.0.0-20231212132935-7a55558d8c33/go.mod h1:x11iCbZV6hzzSQWMq610B6Wl5Lg1dhwqcVfeiWQQnQQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -407,8 +407,8 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.32.1 h1:wy1J4kZIZxOaej6NveTWCZmHiJ/kY7GoAqXgqNCnPps= -github.com/libp2p/go-libp2p v0.32.1/go.mod h1:hXXC3kXPlBZ1eu8Q2hptGrMB4mZ3048JUoS4EKaHW5c= +github.com/libp2p/go-libp2p v0.32.2 h1:s8GYN4YJzgUoyeYNPdW7JZeZ5Ee31iNaIBfGYMAY4FQ= +github.com/libp2p/go-libp2p v0.32.2/go.mod h1:E0LKe+diV/ZVJVnOJby8VC5xzHF0660osg71skcxJvk= github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= github.com/libp2p/go-libp2p-kad-dht v0.25.2 h1:FOIk9gHoe4YRWXTu8SY9Z1d0RILol0TrtApsMDPjAVQ= @@ -562,8 +562,8 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= -github.com/quic-go/quic-go v0.39.3 h1:o3YB6t2SR+HU/pgwF29kJ6g4jJIJEwEZ8CKia1h1TKg= -github.com/quic-go/quic-go v0.39.3/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q= +github.com/quic-go/quic-go v0.39.4 h1:PelfiuG7wXEffUT2yceiqz5V6Pc0TA5ruOd1LcmFc1s= +github.com/quic-go/quic-go v0.39.4/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q= github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY= github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= @@ -758,8 +758,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -975,8 +975,8 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= -golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1053,12 +1053,12 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= +google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg= +google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= +google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f h1:2yNACc1O40tTnrsbk9Cv6oxiW8pxI/pXj0wRtdlYmgY= +google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 h1:/jFB8jK5R3Sq3i/lmeZO0cATSzFfZaJq1J2Euan3XKU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= From d6357e5eac828fe428004938409673b7b2c3d28a Mon Sep 17 00:00:00 2001 From: Lane Rettig Date: Thu, 14 Dec 2023 21:32:50 +0000 Subject: [PATCH 29/48] Fix typo/misspelling (#5357) ## Motivation Fix a potentially confusing typo in a few places ## Changes Only fixes typo, no logic changes --- common/types/malfeasance.go | 2 +- datastore/store.go | 6 +++--- hare3/hare.go | 2 +- tortoise/algorithm.go | 2 +- tortoise/tracer.go | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/common/types/malfeasance.go b/common/types/malfeasance.go index e5f35506a1..c31b8abe3c 100644 --- a/common/types/malfeasance.go +++ b/common/types/malfeasance.go @@ -182,7 +182,7 @@ func (hp *HareProof) MarshalLogObject(encoder log.ObjectEncoder) error { return nil } -func (hp *HareProof) ToMalfeasenceProof() *MalfeasanceProof { +func (hp *HareProof) ToMalfeasanceProof() *MalfeasanceProof { return &MalfeasanceProof{ Layer: hp.Messages[0].InnerMsg.Layer, Proof: Proof{ diff --git a/datastore/store.go b/datastore/store.go index 69f05cc0ba..ad1bea5ee6 100644 --- a/datastore/store.go +++ b/datastore/store.go @@ -47,13 +47,13 @@ type Config struct { // ATXSize must be larger than the sum of all ATXs in last 2 epochs to be effective // (Epoch 12: ~ 300k, Epoch 11: ~ 200k) ATXSize int `mapstructure:"atx-size"` - MalfeasenceSize int `mapstructure:"malfeasence-size"` + MalfeasanceSize int `mapstructure:"malfeasance-size"` } func DefaultConfig() Config { return Config{ ATXSize: 600_000, - MalfeasenceSize: 1_000, + MalfeasanceSize: 1_000, } } @@ -89,7 +89,7 @@ func NewCachedDB(db *sql.Database, lg log.Log, opts ...Opt) *CachedDB { lg.Fatal("failed to create atx cache", err) } - malfeasanceCache, err := lru.New[types.NodeID, *types.MalfeasanceProof](o.cfg.MalfeasenceSize) + malfeasanceCache, err := lru.New[types.NodeID, *types.MalfeasanceProof](o.cfg.MalfeasanceSize) if err != nil { lg.Fatal("failed to create malfeasance cache", err) } diff --git a/hare3/hare.go b/hare3/hare.go index 8dfa95c4ce..b09af8e7b9 100644 --- a/hare3/hare.go +++ b/hare3/hare.go @@ -309,7 +309,7 @@ func (h *Hare) Handler(ctx context.Context, peer p2p.Peer, buf []byte) error { h.log.Debug("registered equivocation", zap.Uint32("lid", msg.Layer.Uint32()), zap.Stringer("sender", equivocation.Messages[0].SmesherID)) - proof := equivocation.ToMalfeasenceProof() + proof := equivocation.ToMalfeasanceProof() if err := identities.SetMalicious( h.db, equivocation.Messages[0].SmesherID, codec.MustEncode(proof), time.Now()); err != nil { h.log.Error("failed to save malicious identity", zap.Error(err)) diff --git a/tortoise/algorithm.go b/tortoise/algorithm.go index 240b34857c..181a133edd 100644 --- a/tortoise/algorithm.go +++ b/tortoise/algorithm.go @@ -187,7 +187,7 @@ func (t *Tortoise) OnMalfeasance(id types.NodeID) { if t.trtl.isMalfeasant(id) { return } - t.logger.Debug("on malfeasence", zap.Stringer("id", id)) + t.logger.Debug("on malfeasance", zap.Stringer("id", id)) t.trtl.makrMalfeasant(id) malfeasantNumber.Inc() if t.tracer != nil { diff --git a/tortoise/tracer.go b/tortoise/tracer.go index 260cbaac8e..da7929e628 100644 --- a/tortoise/tracer.go +++ b/tortoise/tracer.go @@ -123,7 +123,7 @@ const ( traceResults traceUpdates traceApplied - traceMalfeasence + traceMalfeasance ) type traceEvent interface { @@ -435,7 +435,7 @@ type MalfeasanceTrace struct { } func (m *MalfeasanceTrace) Type() eventType { - return traceMalfeasence + return traceMalfeasance } func (m *MalfeasanceTrace) New() traceEvent { From 78bf093248e41adc3b9caf9dedd2fb79aa7c4cba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Dec 2023 06:58:03 +0000 Subject: [PATCH 30/48] build(deps): Bump actions/download-artifact from 3 to 4 (#5358) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 3 to 4. --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d7002e6e61..6e37f36b4b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -108,7 +108,7 @@ jobs: needs: build-and-upload steps: - name: Download the artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Generate the env variables shell: bash From f30cf0bd04b92adb88e915636121e049a9b81968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Fri, 15 Dec 2023 12:24:08 +0000 Subject: [PATCH 31/48] Increase p2p response data size to 40MiB (#5361) ## Motivation Increase p2p response data size to 40MiB. Also added log to show the actual data size in case of encoding failure. --- p2p/server/server.go | 9 +++++++-- p2p/server/server_scale.go | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/p2p/server/server.go b/p2p/server/server.go index 4e467348fa..7b30f691be 100644 --- a/p2p/server/server.go +++ b/p2p/server/server.go @@ -84,7 +84,7 @@ type Handler func(context.Context, []byte) ([]byte, error) // Response is a server response. type Response struct { - Data []byte `scale:"max=20971520"` // 20 MiB + Data []byte `scale:"max=41943040"` // 40 MiB Error string `scale:"max=1024"` // TODO(mafa): make error code instead of string } @@ -220,7 +220,12 @@ func (s *Server) queueHandler(ctx context.Context, stream network.Stream) { wr := bufio.NewWriter(stream) if _, err := codec.EncodeTo(wr, &resp); err != nil { - s.logger.With().Warning("failed to write response", log.Err(err)) + s.logger.With().Warning( + "failed to write response", + log.Int("resp.Data len", len(resp.Data)), + log.Int("resp.Error len", len(resp.Error)), + log.Err(err), + ) return } if err := wr.Flush(); err != nil { diff --git a/p2p/server/server_scale.go b/p2p/server/server_scale.go index 162eb225c8..f7e3ebdd8d 100644 --- a/p2p/server/server_scale.go +++ b/p2p/server/server_scale.go @@ -9,7 +9,7 @@ import ( func (t *Response) EncodeScale(enc *scale.Encoder) (total int, err error) { { - n, err := scale.EncodeByteSliceWithLimit(enc, t.Data, 20971520) + n, err := scale.EncodeByteSliceWithLimit(enc, t.Data, 41943040) if err != nil { return total, err } @@ -27,7 +27,7 @@ func (t *Response) EncodeScale(enc *scale.Encoder) (total int, err error) { func (t *Response) DecodeScale(dec *scale.Decoder) (total int, err error) { { - field, n, err := scale.DecodeByteSliceWithLimit(dec, 20971520) + field, n, err := scale.DecodeByteSliceWithLimit(dec, 41943040) if err != nil { return total, err } From eb263c8e831d7d141e939e409d19b940be09972b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Dec 2023 14:37:57 +0000 Subject: [PATCH 32/48] build(deps): Bump google-github-actions/upload-cloud-storage from 1 to 2 (#5359) Bumps [google-github-actions/upload-cloud-storage](https://github.com/google-github-actions/upload-cloud-storage) from 1 to 2. --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6e37f36b4b..30b71b5b14 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -76,7 +76,7 @@ jobs: uses: google-github-actions/setup-gcloud@v2 - name: Upload zip - uses: google-github-actions/upload-cloud-storage@v1 + uses: google-github-actions/upload-cloud-storage@v2 with: path: ${{ env.OUTNAME }}.zip destination: ${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/ @@ -140,7 +140,7 @@ jobs: uses: google-github-actions/setup-gcloud@v2 - name: Upload sha256sums - uses: google-github-actions/upload-cloud-storage@v1 + uses: google-github-actions/upload-cloud-storage@v2 with: path: sha256sum.yaml destination: ${{ secrets.GCP_BUCKET }}/${{ github.ref_name }}/ From a06f7e8eff9fa2ce7d9bccdc15e8b40b21495c3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Dec 2023 20:50:52 +0000 Subject: [PATCH 33/48] build(deps): Bump actions/upload-artifact from 3 to 4 (#5360) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 30b71b5b14..4b95b07144 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,7 +96,7 @@ jobs: run: | (Get-FileHash ${{ env.OUTNAME }}.zip -Algorithm SHA256).Hash > sha256-${{ matrix.outname_sufix }}.txt - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: sha256-${{ matrix.outname_sufix }} path: sha256-${{ matrix.outname_sufix }}.txt From c57f0833a490076c4962367f5cf113d9ceb77e02 Mon Sep 17 00:00:00 2001 From: Matthias Fasching <5011972+fasmat@users.noreply.github.com> Date: Mon, 18 Dec 2023 09:54:17 +0000 Subject: [PATCH 34/48] Generate TLS certificates as part of the test (#5356) ## Motivation Follow up to #5347: instead of re-using generated templates create them as part of the test. ## Changes - Update test to generate the certificates it needs ## Test Plan - existing tests pass ## TODO - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [x] Update [changelog](../CHANGELOG.md) as needed --- README.md | 80 +++++++++++++- api/grpcserver/grpcserver_tls_test.go | 145 +++++++++++++++++++++++--- api/grpcserver/post_service_test.go | 61 ++++++----- api/grpcserver/testdata/README.md | 40 ------- api/grpcserver/testdata/ca.crt | 34 ------ api/grpcserver/testdata/ca.key | 52 --------- api/grpcserver/testdata/client.crt | 34 ------ api/grpcserver/testdata/client.key | 52 --------- api/grpcserver/testdata/domains.ext | 6 -- api/grpcserver/testdata/server.crt | 34 ------ api/grpcserver/testdata/server.key | 52 --------- 11 files changed, 243 insertions(+), 347 deletions(-) delete mode 100644 api/grpcserver/testdata/README.md delete mode 100644 api/grpcserver/testdata/ca.crt delete mode 100644 api/grpcserver/testdata/ca.key delete mode 100644 api/grpcserver/testdata/client.crt delete mode 100644 api/grpcserver/testdata/client.key delete mode 100644 api/grpcserver/testdata/domains.ext delete mode 100644 api/grpcserver/testdata/server.crt delete mode 100644 api/grpcserver/testdata/server.key diff --git a/README.md b/README.md index 894f75c301..cfad8f88b4 100644 --- a/README.md +++ b/README.md @@ -264,8 +264,6 @@ choco install opencl-intel-cpu-runtime #### Using a remote machine as provider for PoST proofs -**NOTE:** this feature is currently experimental and not fully tested yet. - To disable the internal PoST service and disable smeshing on your node you can use the following config: ```json @@ -275,7 +273,15 @@ To disable the internal PoST service and disable smeshing on your node you can u ``` or use the `--smeshing-start=false` flag. This will disable smeshing on your node causing it not generate any PoST -proofs until a remote post service connects. +proofs until a remote post service connects. Be aware that you still need to set your coinbase via + +```json +"smeshing": { + "smeshing-coinbase": "your coinbase address", +} +``` + +or use the `--smeshing-coinbase` CLI parameter, otherwise your node will not be able to receive rewards. If you want to allow connections from post services on other hosts to your node, you need to set a public endpoint via the `grpc-tls-listener` configuration parameter and setup TLS for the connection. @@ -298,6 +304,74 @@ To setup TLS-secured public connections the API config has been extended with th Ensure that remote PoST services are setup to connect to your node via TLS, that they trust your node's certificate and use a certificate that is signed by the same CA as your node's certificate. +### Configuring a remote PoST service + +The post service is at the moment configured exclusively via command line parameters: + +- `--dir` specifies the directory containing `postdata_metadata.json` and the `postdata_xxx.bin` files; other files in + the post directory need to stay with the node! +- `--address` specifies the address the post service should connect to +- `--ca-cert`, `--cert` and `--key` specify the location of the CA certificate, the post services certificate and the + post services key respectively. For more information see below. +- `--threads`, `--nonces` and `--randomx-mode` can be adapted to optimize proof generation. They are analogous to +`smeshing-opts-proving-threads`, `smeshing-opts-proving-nonces` and `smeshing-opts-proving-randomx-mode` respectively. +- `-h` or `--help` prints a help message with all available options and more details on their usage. + +### Keys and certificates + +The PoST service and the node talk to each other via mTLS and have to authenticate themselves at the opposite end. For +this both need keys and certificates. + +Here is a script that generates a key & certificate for a CA, a key for the client (PoST service) and a key for the +server (node). Then it uses the CAs key to generate certificates from the keys for both the client & server. + +Make sure to adjust the certificate extensions & subjects for your setup accordingly. + +`ca.crt` needs to be provided to both the PoST service and the node, `server.crt` & `server.key` are only needed by the +node and `client.crt` & `client.key` are only needed by the PoST service. + +```bash +# create certificate extensions to allow using them for localhost +cat > server-domains.ext < client-domains.ext < domains.ext < Date: Mon, 18 Dec 2023 15:30:27 +0000 Subject: [PATCH 35/48] Autoscale post verifying workers (#5354) ## Motivation Verifying POST proofs is CPU-intensive. By default, it uses 3/4 CPU cores. It is a problem during the cycle gap for the nodes that take longer to generate the POST proof than the others - new ATXs start to drop in and verifying them fights for CPU with the proving process. In such a situation, proving is more important so sacrificing ATX verification speed is an acceptable tradeoff. ## Changes Added a way to scale the number of workers that verify POST proofs (in incoming ATXs) up and down. There is an auto scaler that reacts to POST events (started/finished) by scaling the number of workers down/up respectively. The minimum and maximum number of workers is configurable with `smeshing-opts-verifying-min-workers` and `smeshing-opts-verifying-workers` respectively. ## Test Plan Added unit tests. ## TODO - [ ] Update [changelog](../CHANGELOG.md) as needed --- activation/interface.go | 5 + activation/metrics/metrics.go | 7 + activation/mocks.go | 59 ++++++++ activation/post.go | 8 +- activation/post_verifier.go | 183 ++++++++++++++++------- activation/post_verifier_scaling_test.go | 69 +++++++++ activation/post_verifier_test.go | 52 ++----- cmd/root.go | 6 + node/node.go | 10 +- 9 files changed, 297 insertions(+), 102 deletions(-) create mode 100644 activation/post_verifier_scaling_test.go diff --git a/activation/interface.go b/activation/interface.go index 9e4792cacd..31be6c84df 100644 --- a/activation/interface.go +++ b/activation/interface.go @@ -21,6 +21,11 @@ type PostVerifier interface { io.Closer Verify(ctx context.Context, p *shared.Proof, m *shared.ProofMetadata, opts ...verifying.OptionFunc) error } + +type scaler interface { + scale(int) +} + type nipostValidator interface { InitialNIPostChallenge(challenge *types.NIPostChallenge, atxs atxProvider, goldenATXID types.ATXID) error NIPostChallenge(challenge *types.NIPostChallenge, atxs atxProvider, nodeID types.NodeID) error diff --git a/activation/metrics/metrics.go b/activation/metrics/metrics.go index cdea67cb64..b1d68d0283 100644 --- a/activation/metrics/metrics.go +++ b/activation/metrics/metrics.go @@ -24,6 +24,13 @@ var PoetPowDuration = metrics.NewGauge( []string{}, ).WithLabelValues() +var PostVerificationQueue = metrics.NewGauge( + "post_verification_waiting_total", + namespace, + "the number of POSTs waiting to be verified", + []string{}, +).WithLabelValues() + var ( publishWindowLatency = metrics.NewHistogramWithBuckets( "publish_window_seconds", diff --git a/activation/mocks.go b/activation/mocks.go index c444376987..dd0987aaf8 100644 --- a/activation/mocks.go +++ b/activation/mocks.go @@ -182,6 +182,65 @@ func (c *PostVerifierVerifyCall) DoAndReturn(f func(context.Context, *shared.Pro return c } +// Mockscaler is a mock of scaler interface. +type Mockscaler struct { + ctrl *gomock.Controller + recorder *MockscalerMockRecorder +} + +// MockscalerMockRecorder is the mock recorder for Mockscaler. +type MockscalerMockRecorder struct { + mock *Mockscaler +} + +// NewMockscaler creates a new mock instance. +func NewMockscaler(ctrl *gomock.Controller) *Mockscaler { + mock := &Mockscaler{ctrl: ctrl} + mock.recorder = &MockscalerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *Mockscaler) EXPECT() *MockscalerMockRecorder { + return m.recorder +} + +// scale mocks base method. +func (m *Mockscaler) scale(arg0 int) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "scale", arg0) +} + +// scale indicates an expected call of scale. +func (mr *MockscalerMockRecorder) scale(arg0 any) *scalerscaleCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "scale", reflect.TypeOf((*Mockscaler)(nil).scale), arg0) + return &scalerscaleCall{Call: call} +} + +// scalerscaleCall wrap *gomock.Call +type scalerscaleCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *scalerscaleCall) Return() *scalerscaleCall { + c.Call = c.Call.Return() + return c +} + +// Do rewrite *gomock.Call.Do +func (c *scalerscaleCall) Do(f func(int)) *scalerscaleCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *scalerscaleCall) DoAndReturn(f func(int)) *scalerscaleCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // MocknipostValidator is a mock of nipostValidator interface. type MocknipostValidator struct { ctrl *gomock.Controller diff --git a/activation/post.go b/activation/post.go index 064201dc5f..cdf4346aff 100644 --- a/activation/post.go +++ b/activation/post.go @@ -81,6 +81,9 @@ func DefaultPostProvingOpts() PostProvingOpts { type PostProofVerifyingOpts struct { // Number of workers spawned to verify proofs. Workers int `mapstructure:"smeshing-opts-verifying-workers"` + // The minimum number of verifying workers to keep + // while POST is being generated in parallel. + MinWorkers int `mapstructure:"smeshing-opts-verifying-min-workers"` // Flags used for the PoW verification. Flags PostPowFlags `mapstructure:"smeshing-opts-verifying-powflags"` } @@ -91,8 +94,9 @@ func DefaultPostVerifyingOpts() PostProofVerifyingOpts { workers = 1 } return PostProofVerifyingOpts{ - Workers: workers, - Flags: PostPowFlags(config.DefaultVerifyingPowFlags()), + MinWorkers: 1, + Workers: workers, + Flags: PostPowFlags(config.DefaultVerifyingPowFlags()), } } diff --git a/activation/post_verifier.go b/activation/post_verifier.go index c3a3a6020a..25120b9b97 100644 --- a/activation/post_verifier.go +++ b/activation/post_verifier.go @@ -4,36 +4,77 @@ import ( "context" "fmt" + pb "github.com/spacemeshos/api/release/go/spacemesh/v1" "github.com/spacemeshos/post/config" "github.com/spacemeshos/post/shared" "github.com/spacemeshos/post/verifying" "go.uber.org/zap" "golang.org/x/sync/errgroup" + "github.com/spacemeshos/go-spacemesh/activation/metrics" "github.com/spacemeshos/go-spacemesh/common/types" - "github.com/spacemeshos/go-spacemesh/log" + "github.com/spacemeshos/go-spacemesh/events" ) type verifyPostJob struct { + ctx context.Context // context of Verify() call proof *shared.Proof metadata *shared.ProofMetadata opts []verifying.OptionFunc result chan error } +type autoscaler struct { + sub *events.BufferedSubscription[events.UserEvent] +} + +func newAutoscaler() (*autoscaler, error) { + sub, err := events.SubscribeMatched(func(t *events.UserEvent) bool { + switch t.Event.Details.(type) { + case (*pb.Event_PostStart): + return true + case (*pb.Event_PostComplete): + return true + default: + return false + } + }, events.WithBuffer(5)) + + return &autoscaler{sub: sub}, err +} + +func (a autoscaler) run(stop chan struct{}, s scaler, min, target int) { + for { + select { + case e := <-a.sub.Out(): + switch e.Event.Details.(type) { + case (*pb.Event_PostStart): + s.scale(min) + case (*pb.Event_PostComplete): + s.scale(target) + } + case <-stop: + a.sub.Close() + return + } + } +} + type OffloadingPostVerifier struct { - eg errgroup.Group - stop context.CancelFunc - stopped <-chan struct{} - log log.Log - workers []*postVerifierWorker - channel chan<- *verifyPostJob + eg errgroup.Group + log *zap.Logger + verifier PostVerifier + workers []*postVerifierWorker + jobs chan *verifyPostJob + stop chan struct{} // signal to stop all goroutines } type postVerifierWorker struct { verifier PostVerifier - log log.Log - channel <-chan *verifyPostJob + log *zap.Logger + jobs <-chan *verifyPostJob + stop chan struct{} // signal to stop this worker + shutdown chan struct{} // signal that the verifier is closing } type postVerifier struct { @@ -65,46 +106,66 @@ func NewPostVerifier(cfg PostConfig, logger *zap.Logger, opts ...verifying.Optio // NewOffloadingPostVerifier creates a new post proof verifier with the given number of workers. // The verifier will distribute incoming proofs between the workers. // It will block if all workers are busy. -func NewOffloadingPostVerifier(verifiers []PostVerifier, logger log.Log) *OffloadingPostVerifier { - numWorkers := len(verifiers) - channel := make(chan *verifyPostJob, numWorkers) - workers := make([]*postVerifierWorker, 0, numWorkers) - - for i, verifier := range verifiers { - workers = append(workers, &postVerifierWorker{ - verifier: verifier, - log: logger.Named(fmt.Sprintf("worker-%d", i)), - channel: channel, - }) - } - logger.With().Info("created post verifier", log.Int("num_workers", numWorkers)) - - ctx, cancel := context.WithCancel(context.Background()) - stopped := make(chan struct{}) +// +// SAFETY: The `verifier` must be safe to use concurrently. +// +// The verifier must be closed after use with Close(). +func NewOffloadingPostVerifier(verifier PostVerifier, numWorkers int, logger *zap.Logger) *OffloadingPostVerifier { v := &OffloadingPostVerifier{ - log: logger, - workers: workers, - channel: channel, - stopped: stopped, - stop: func() { - cancel() - select { - case <-stopped: - default: - close(stopped) - } - }, + log: logger, + workers: make([]*postVerifierWorker, 0, numWorkers), + jobs: make(chan *verifyPostJob, numWorkers), + stop: make(chan struct{}), + verifier: verifier, } v.log.Info("starting post verifier") - for _, worker := range v.workers { - worker := worker - v.eg.Go(func() error { return worker.start(ctx) }) - } + v.scale(numWorkers) v.log.Info("started post verifier") return v } +// Turn on automatic scaling of the number of workers. +// The number of workers will be scaled between `min` and `target` (inclusive). +func (v *OffloadingPostVerifier) Autoscale(min, target int) { + a, err := newAutoscaler() + if err != nil { + v.log.Panic("failed to create autoscaler", zap.Error(err)) + } + v.eg.Go(func() error { a.run(v.stop, v, min, target); return nil }) +} + +// Scale the number of workers to the given number. +// +// SAFETY: Must not be called concurrently. +// This is satisified by the fact that the only caller is the autoscaler, +// which executes scale() serially. +func (v *OffloadingPostVerifier) scale(target int) { + v.log.Info("scaling post verifier", zap.Int("current", len(v.workers)), zap.Int("new", target)) + + if target > len(v.workers) { + // scale up + for i := len(v.workers); i < target; i++ { + w := &postVerifierWorker{ + verifier: v.verifier, + log: v.log.Named(fmt.Sprintf("worker-%d", len(v.workers))), + jobs: v.jobs, + stop: make(chan struct{}), + shutdown: v.stop, + } + v.workers = append(v.workers, w) + v.eg.Go(func() error { w.start(); return nil }) + } + } else if target < len(v.workers) { + // scale down + toKeep, toStop := v.workers[:target], v.workers[target:] + v.workers = toKeep + for _, worker := range toStop { + close(worker.stop) + } + } +} + func (v *OffloadingPostVerifier) Verify( ctx context.Context, p *shared.Proof, @@ -112,15 +173,19 @@ func (v *OffloadingPostVerifier) Verify( opts ...verifying.OptionFunc, ) error { job := &verifyPostJob{ + ctx: ctx, proof: p, metadata: m, opts: opts, result: make(chan error, 1), } + metrics.PostVerificationQueue.Inc() + defer metrics.PostVerificationQueue.Dec() + select { - case v.channel <- job: - case <-v.stopped: + case v.jobs <- job: + case <-v.stop: return fmt.Errorf("verifier is closed") case <-ctx.Done(): return fmt.Errorf("submitting verifying job: %w", ctx.Err()) @@ -129,7 +194,7 @@ func (v *OffloadingPostVerifier) Verify( select { case res := <-job.result: return res - case <-v.stopped: + case <-v.stop: return fmt.Errorf("verifier is closed") case <-ctx.Done(): return fmt.Errorf("waiting for verification result: %w", ctx.Err()) @@ -137,28 +202,32 @@ func (v *OffloadingPostVerifier) Verify( } func (v *OffloadingPostVerifier) Close() error { + select { + case <-v.stop: + return nil + default: + } v.log.Info("stopping post verifier") - v.stop() + close(v.stop) v.eg.Wait() - for _, worker := range v.workers { - if err := worker.verifier.Close(); err != nil { - return err - } - } + v.verifier.Close() v.log.Info("stopped post verifier") return nil } -func (w *postVerifierWorker) start(ctx context.Context) error { - w.log.Info("starting post proof verifier worker") +func (w *postVerifierWorker) start() { + w.log.Info("starting") + defer w.log.Info("stopped") + for { select { - case <-ctx.Done(): - w.log.Info("stopped post proof verifier worker") - return ctx.Err() - case job := <-w.channel: - job.result <- w.verifier.Verify(ctx, job.proof, job.metadata, job.opts...) + case <-w.shutdown: + return + case <-w.stop: + return + case job := <-w.jobs: + job.result <- w.verifier.Verify(job.ctx, job.proof, job.metadata, job.opts...) } } } diff --git a/activation/post_verifier_scaling_test.go b/activation/post_verifier_scaling_test.go new file mode 100644 index 0000000000..8d0ff7c2d5 --- /dev/null +++ b/activation/post_verifier_scaling_test.go @@ -0,0 +1,69 @@ +package activation + +import ( + "context" + "sync/atomic" + "testing" + "time" + + "github.com/spacemeshos/post/shared" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + "go.uber.org/zap/zaptest" + "golang.org/x/sync/errgroup" + + "github.com/spacemeshos/go-spacemesh/events" +) + +func TestAutoScaling(t *testing.T) { + events.InitializeReporter() + t.Cleanup(events.CloseEventReporter) + + mockScaler := NewMockscaler(gomock.NewController(t)) + var done atomic.Bool + gomock.InOrder( + mockScaler.EXPECT().scale(1), // on start + mockScaler.EXPECT().scale(5), // on complete + mockScaler.EXPECT().scale(5).Do(func(int) { done.Store(true) }), // on failed + ) + + stop := make(chan struct{}) + var eg errgroup.Group + autoscaler, err := newAutoscaler() + require.NoError(t, err) + eg.Go(func() error { + autoscaler.run(stop, mockScaler, 1, 5) + return nil + }) + + events.EmitPostStart(nil) + events.EmitPostComplete(nil) + events.EmitPostFailure() + require.Eventually(t, done.Load, time.Second, 10*time.Millisecond) + + close(stop) + eg.Wait() +} + +func TestPostVerifierScaling(t *testing.T) { + // 0 workers - no one will verify the proof + mockVerifier := NewMockPostVerifier(gomock.NewController(t)) + v := NewOffloadingPostVerifier(mockVerifier, 0, zaptest.NewLogger(t)) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond) + defer cancel() + + err := v.Verify(ctx, &shared.Proof{}, &shared.ProofMetadata{}) + require.Error(t, err, context.Canceled) + + mockVerifier.EXPECT().Verify(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + v.scale(1) + err = v.Verify(context.Background(), &shared.Proof{}, &shared.ProofMetadata{}) + require.NoError(t, err) + + v.scale(0) + ctx, cancel = context.WithTimeout(context.Background(), 10*time.Millisecond) + defer cancel() + err = v.Verify(ctx, &shared.Proof{}, &shared.ProofMetadata{}) + require.Error(t, err, context.Canceled) +} diff --git a/activation/post_verifier_test.go b/activation/post_verifier_test.go index 158b9c0cff..d1d3cde9de 100644 --- a/activation/post_verifier_test.go +++ b/activation/post_verifier_test.go @@ -13,31 +13,23 @@ import ( "golang.org/x/sync/errgroup" "github.com/spacemeshos/go-spacemesh/activation" - "github.com/spacemeshos/go-spacemesh/log" - "github.com/spacemeshos/go-spacemesh/log/logtest" ) func TestOffloadingPostVerifier(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - proof := shared.Proof{} metadata := shared.ProofMetadata{} verifier := activation.NewMockPostVerifier(gomock.NewController(t)) - offloadingVerifier := activation.NewOffloadingPostVerifier( - []activation.PostVerifier{verifier}, - log.NewDefault(t.Name()), - ) + offloadingVerifier := activation.NewOffloadingPostVerifier(verifier, 1, zaptest.NewLogger(t)) defer offloadingVerifier.Close() verifier.EXPECT().Close().Return(nil) verifier.EXPECT().Verify(gomock.Any(), &proof, &metadata, gomock.Any()).Return(nil) - err := offloadingVerifier.Verify(ctx, &proof, &metadata) + err := offloadingVerifier.Verify(context.Background(), &proof, &metadata) require.NoError(t, err) verifier.EXPECT().Verify(gomock.Any(), &proof, &metadata, gomock.Any()).Return(errors.New("invalid proof!")) - err = offloadingVerifier.Verify(ctx, &proof, &metadata) + err = offloadingVerifier.Verify(context.Background(), &proof, &metadata) require.ErrorContains(t, err, "invalid proof!") } @@ -49,44 +41,31 @@ func TestPostVerifierDetectsInvalidProof(t *testing.T) { } func TestPostVerifierVerifyAfterStop(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - proof := shared.Proof{} metadata := shared.ProofMetadata{} verifier := activation.NewMockPostVerifier(gomock.NewController(t)) - offloadingVerifier := activation.NewOffloadingPostVerifier( - []activation.PostVerifier{verifier}, - log.NewDefault(t.Name()), - ) + offloadingVerifier := activation.NewOffloadingPostVerifier(verifier, 1, zaptest.NewLogger(t)) defer offloadingVerifier.Close() - verifier.EXPECT().Close().Return(nil) verifier.EXPECT().Verify(gomock.Any(), &proof, &metadata, gomock.Any()).Return(nil) - err := offloadingVerifier.Verify(ctx, &proof, &metadata) + err := offloadingVerifier.Verify(context.Background(), &proof, &metadata) require.NoError(t, err) // Stop the verifier verifier.EXPECT().Close().Return(nil) offloadingVerifier.Close() - err = offloadingVerifier.Verify(ctx, &proof, &metadata) + err = offloadingVerifier.Verify(context.Background(), &proof, &metadata) require.EqualError(t, err, "verifier is closed") } func TestPostVerifierNoRaceOnClose(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - var proof shared.Proof var metadata shared.ProofMetadata verifier := activation.NewMockPostVerifier(gomock.NewController(t)) - offloadingVerifier := activation.NewOffloadingPostVerifier( - []activation.PostVerifier{verifier}, - logtest.New(t), - ) + offloadingVerifier := activation.NewOffloadingPostVerifier(verifier, 1, zaptest.NewLogger(t)) defer offloadingVerifier.Close() verifier.EXPECT().Close().AnyTimes().Return(nil) verifier.EXPECT().Verify(gomock.Any(), &proof, &metadata, gomock.Any()).AnyTimes().Return(nil) @@ -102,24 +81,21 @@ func TestPostVerifierNoRaceOnClose(t *testing.T) { ms := 10 * i eg.Go(func() error { time.Sleep(time.Duration(ms) * time.Millisecond) - return offloadingVerifier.Verify(ctx, &proof, &metadata) + return offloadingVerifier.Verify(context.Background(), &proof, &metadata) }) } require.EqualError(t, eg.Wait(), "verifier is closed") } -func TestPostVerifierReturnsOnCtxCanceledWhenBlockedVerifying(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - v := activation.NewOffloadingPostVerifier( - []activation.PostVerifier{ - // empty list of verifiers - no one will verify the proof - }, log.NewDefault(t.Name())) +func TestPostVerifierClose(t *testing.T) { + verifier := activation.NewMockPostVerifier(gomock.NewController(t)) + // 0 workers - no one will verify the proof + v := activation.NewOffloadingPostVerifier(verifier, 0, zaptest.NewLogger(t)) + verifier.EXPECT().Close().Return(nil) require.NoError(t, v.Close()) - err := v.Verify(ctx, &shared.Proof{}, &shared.ProofMetadata{}) + err := v.Verify(context.Background(), &shared.Proof{}, &shared.ProofMetadata{}) require.EqualError(t, err, "verifier is closed") } diff --git a/cmd/root.go b/cmd/root.go index f1289cab0c..9ce236196d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -260,6 +260,12 @@ func AddCommands(cmd *cobra.Command) { /**======================== PoST Verifying Flags ========================== **/ + cmd.PersistentFlags().IntVar( + &cfg.SMESHING.VerifyingOpts.MinWorkers, + "smeshing-opts-verifying-min-threads", + cfg.SMESHING.VerifyingOpts.MinWorkers, + "Minimal number of threads to use for verifying PoSTs (used while PoST is generated)", + ) cmd.PersistentFlags().IntVar(&cfg.SMESHING.VerifyingOpts.Workers, "smeshing-opts-verifying-threads", cfg.SMESHING.VerifyingOpts.Workers, "") cmd.PersistentFlags().AddFlag(&pflag.Flag{ diff --git a/node/node.go b/node/node.go index 2e5ae85fce..f661d3f1e2 100644 --- a/node/node.go +++ b/node/node.go @@ -553,7 +553,7 @@ func (app *App) initServices(ctx context.Context) error { poetDb := activation.NewPoetDb(app.db, app.addLogger(PoetDbLogger, lg)) nipostValidatorLogger := app.addLogger(NipostValidatorLogger, lg) - postVerifiers := make([]activation.PostVerifier, 0, app.Config.SMESHING.VerifyingOpts.Workers) + lg.Debug("creating post verifier") verifier, err := activation.NewPostVerifier( app.Config.POST, @@ -564,10 +564,10 @@ func (app *App) initServices(ctx context.Context) error { if err != nil { return err } - for i := 0; i < app.Config.SMESHING.VerifyingOpts.Workers; i++ { - postVerifiers = append(postVerifiers, verifier) - } - app.postVerifier = activation.NewOffloadingPostVerifier(postVerifiers, nipostValidatorLogger) + minWorkers := app.Config.SMESHING.VerifyingOpts.MinWorkers + workers := app.Config.SMESHING.VerifyingOpts.Workers + app.postVerifier = activation.NewOffloadingPostVerifier(verifier, workers, nipostValidatorLogger.Zap()) + app.postVerifier.Autoscale(minWorkers, workers) validator := activation.NewValidator( poetDb, From 0d4a91fca1fe39aee72d7c7118a0243311aea1ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 08:04:08 +0000 Subject: [PATCH 36/48] build(deps): Bump github.com/spf13/viper from 1.18.1 to 1.18.2 (#5372) Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.18.1 to 1.18.2. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b81b6966b6..86e562fef4 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/spf13/afero v1.11.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.18.1 + github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.8.4 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/zeebo/blake3 v0.2.3 diff --git a/go.sum b/go.sum index 1e07cbe754..fa80f32e25 100644 --- a/go.sum +++ b/go.sum @@ -647,8 +647,8 @@ github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.18.1 h1:rmuU42rScKWlhhJDyXZRKJQHXFX02chSVW1IvkPGiVM= -github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= From d48328c218837002e85d239901c35528bf3862f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 10:15:03 +0000 Subject: [PATCH 37/48] build(deps): Bump golang.org/x/crypto from 0.16.0 to 0.17.0 (#5369) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.16.0 to 0.17.0. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 86e562fef4..d59461fa66 100644 --- a/go.mod +++ b/go.mod @@ -198,7 +198,7 @@ require ( go.uber.org/dig v1.17.1 // indirect go.uber.org/fx v1.20.1 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.16.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.15.0 // indirect diff --git a/go.sum b/go.sum index fa80f32e25..1f63e09d23 100644 --- a/go.sum +++ b/go.sum @@ -746,8 +746,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.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= From a75d290ec48c27f2a03960e00e2d8de73fe9c996 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Tue, 19 Dec 2023 11:43:03 +0000 Subject: [PATCH 38/48] P2P decentralization improvements (#5329) ## Motivation This PR implements changes needed for spacemeshos/pm#275, except for measurement ## Changes * Introduce Routing Discovery to contact peers behind NATs * Introduce dynamic v2 relay discovery which is needed for hole punching. The idea is to have a wider array of circuit-v2 passive relays which should be much safer than old libp2p active relays (which were disabled in e.g. Filecoin due to security concerns) * Introduce QUIC transport to improve chances at hole punching, with testnet-mainnet "crosstalk" protection based on a transport-level handshake mechanism * the handshake is not used on mainnet. That way, connections between mainnet and testnet nodes are still prevented, as testnet peers expect the handshake, but if/when my libp2p changes are merged (libp2p/go-libp2p#2658) or libp2p gets private network support * Make it possible to listen on multiple addresses and advertise multiple addresses * Extend DebugService with additional P2P info needed for hole punching diagnostics (needs spacemeshos/api#285) * Add `ping-peers` config option to facilitate P2P network issue diagnostics * Add `force-dht-server` config option that is useful during troubleshooting DHT and hole-punching issues `ping-peers` and `force-dht-server` were initially considered to be temporary features, but I think it might make sense to keep them for various P2P network troubleshooting scenarios. All of the changes are disabled in the config by default, except for: * libp2p Ping service is enabled by default to make diagnostics easier * DHT Values and Providers as these will make DHT Routing Peer discovery work efficiently from the beginning when we enable this feature in the configs * Bootnodes aren't used as relays by default anymore. v2 relays have very limited capacity by default and bootnode relay servers' reservations are very quickly exhausted. Need to either specify a static relay list or enable routing discovery, which searches for more available relays as needed ## Test Plan * Tested using k8s several clusters with cone NATs enabled via `bridge` CNI plugin (via Multus) -- backported to v1.2.8 * Added a Mac node for testing ## TODO - [x] Have spacemeshos/api#285 merged and updated to the new `api` release - [x] Retest using an image based on this branch (not backport) - [ ] Decide on whether/how to extend systests to include NAT testing - [ ] To check: TCP holepunching tends to happen more than QUIC (might be related to the handshake mechanism) - [ ] ~~To consider: try picking up some % (e.g.: 50%) of non-infra peers during routing discovery~~ (doesn't work too well, need something more involved for that) Maybe as a follow-up (depending on how soon this gets reviewed): - Include new metrics / check if they're already present - NAT type (UDP / TCP) - Cone / Symmetric / Unknown - Reachability - Public / Private / Unknown - N of "advertised" peers found via routing discovery - N of TCP and UDP (QUIC) peers - N of peers reached via relayed connections (these being present for a long time may indicate hole-punching troubles, usually relayed connections go away relatively quickly) - N of relay reservations this node managed to obtain - Whether routing discovery is active or suspended (e.g. b/c `low-peers` N of peers has been reached) - Whether DHT is in the `Server` or `Client` mode - systests checking NATed connections Co-authored-by: Ivan Shvedunov --- CHANGELOG.md | 9 + README.md | 43 ++++ api/grpcserver/debug_service.go | 46 +++- api/grpcserver/grpcserver_test.go | 36 ++- api/grpcserver/interface.go | 12 +- api/grpcserver/mocks.go | 233 +++++++++++++++-- cmd/base.go | 8 + cmd/root.go | 23 +- fetch/fetch_test.go | 6 +- go.mod | 6 +- go.sum | 4 +- node/adminservice_api_test.go | 3 +- node/bad_peer_test.go | 5 +- node/flags/addresslist.go | 94 +++++++ node/flags/addresslist_test.go | 29 +++ node/mapstructureutil/addresslist.go | 41 +++ node/node.go | 11 +- node/node_test.go | 33 ++- p2p/addresslist.go | 64 +++++ p2p/dhtdiscovery/discovery.go | 370 +++++++++++++++++++++------ p2p/dhtdiscovery/discovery_test.go | 115 ++++++++- p2p/handshake/handshake.go | 278 ++++++++++++++++++++ p2p/handshake/handshake_test.go | 156 +++++++++++ p2p/host.go | 268 +++++++++++++------ p2p/host_test.go | 82 ++++-- p2p/ping.go | 175 +++++++++++++ p2p/ping_test.go | 71 +++++ p2p/upgrade.go | 186 +++++++++++++- 28 files changed, 2182 insertions(+), 225 deletions(-) create mode 100644 node/flags/addresslist.go create mode 100644 node/flags/addresslist_test.go create mode 100644 node/mapstructureutil/addresslist.go create mode 100644 p2p/addresslist.go create mode 100644 p2p/handshake/handshake.go create mode 100644 p2p/handshake/handshake_test.go create mode 100644 p2p/ping.go create mode 100644 p2p/ping_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 634bdac784..ffd9116398 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,6 +89,15 @@ for more information on how to configure the node to work with the PoST service. query rewards by smesherID. Additionally, it does not re-index old data. Rewards will contain smesherID going forward, but to refresh data for all rewards, a node will have to delete its database and resync from genesis. +* [#5329](https://github.com/spacemeshos/go-spacemesh/pull/5329) P2P decentralization improvements. Added support for QUIC + transport and DHT routing discovery for finding peers and relays. Also, added the `ping-peers` feature which is useful + during connectivity troubleshooting. `static-relays` feature can be used to provide a static list of circuit v2 relays + nodes when automatic relay discovery is not desired. All of the relay server resource settings are now configurable. Most + of the new functionality is disabled by default unless explicitly enabled in the config via `enable-routing-discovery`, + `routing-discovery-advertise`, `enable-quic-transport`, `static-relays` and `ping-peers` options in the `p2p` config + section. The non-conditional changes include values/provides support on all of the nodes, which will enable DHT to + function efficiently for routing discovery. + ## Release v1.2.9 ### Improvements diff --git a/README.md b/README.md index cfad8f88b4..ef54a4e32f 100644 --- a/README.md +++ b/README.md @@ -439,6 +439,49 @@ as on UNIX-based systems. - This is a great way to get a feel for the protocol and the platform and to start hacking on Spacemesh. - Follow the steps in our [Local Testnet Guide](https://testnet.spacemesh.io/#/README) +### Improved decentralization and P2P diagnostic features + +**WARNING! THIS IS EXPERIMENTAL FUNCTIONALITY, USE WITH CARE!** + +In order to make the p2p network more decentralized, the following options are provided: +- `"enable-routing-discovery": true`: enables routing discovery for finding new peers, including those behind NAT, ans + also for discovering relay nodes which are used for NAT hole punching. Note that hole punching can be done when both + ends of the connection are behind an endpoint-independent ("cone") NAT. +- `"routing-discovery-advertise": true` advertises this node for discovery by other peers, even if it is behind NAT. +- `"enable-quic-transport": true`: enables QUIC transport which, together with TCP transport, heightens the changes of + successful NAT hole punching. +- `"enable-tcp-transport": false` disables TCP transport. This option is intended to be used for debugging purposes + only! +- `"static-relays": ["/dns4/relay.example.com/udp/5000/quic-v1/p2p/...", ...]` provides a static list of relay nodes for + use for NAT hole punching in case of routing discovery based relay search is not to be used. +- `"ping-peers": ["p2p_id_1", "p2p_id_2", ...]` runs P2P ping against the specified peers, logging the results. + +For the purpose of debugging P2P connectivity issues, the following command can also be used: +```console +$ grpcurl -plaintext 127.0.0.1:9093 spacemesh.v1.DebugService.NetworkInfo +{ + "id": "12D3Koo...", + "listenAddresses": [ + "/ip4/0.0.0.0/tcp/50212", + "/ip4/0.0.0.0/udp/59458/quic-v1", + "/p2p-circuit" + ], + "knownAddresses": [ + "/ip4/127.0.0.1/tcp/50212", + "/ip4/127.0.0.1/udp/59458/quic-v1", + "/ip4/192.168.33.5/tcp/50212", + "/ip4/192.168.33.5/udp/59458/quic-v1", + "/ip4/.../tcp/37670/p2p/12D3Koo.../p2p-circuit", + "/ip4/.../udp/37659/quic-v1/p2p/12D3Koo.../p2p-circuit", + "/ip4/.../tcp/31960/p2p/12D3Koo.../p2p-circuit", + "/ip4/.../udp/33377/quic-v1/p2p/12D3Koo.../p2p-circuit" + ], + "natTypeUdp": "Cone", + "natTypeTcp": "Cone", + "reachability": "Private" +} +``` + #### Next Steps - Please visit our [wiki](https://github.com/spacemeshos/go-spacemesh/wiki) diff --git a/api/grpcserver/debug_service.go b/api/grpcserver/debug_service.go index 2f42e4e347..28f58fc235 100644 --- a/api/grpcserver/debug_service.go +++ b/api/grpcserver/debug_service.go @@ -3,9 +3,11 @@ package grpcserver import ( "context" "fmt" + "sort" "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/libp2p/go-libp2p/core/network" pb "github.com/spacemeshos/api/release/go/spacemesh/v1" "go.uber.org/zap" "google.golang.org/grpc" @@ -24,7 +26,7 @@ import ( type DebugService struct { db *sql.Database conState conservativeState - identity networkIdentity + netInfo networkInfo oracle oracle } @@ -43,11 +45,11 @@ func (d DebugService) String() string { } // NewDebugService creates a new grpc service using config data. -func NewDebugService(db *sql.Database, conState conservativeState, host networkIdentity, oracle oracle) *DebugService { +func NewDebugService(db *sql.Database, conState conservativeState, host networkInfo, oracle oracle) *DebugService { return &DebugService{ db: db, conState: conState, - identity: host, + netInfo: host, oracle: oracle, } } @@ -91,7 +93,21 @@ func (d DebugService) Accounts(ctx context.Context, in *pb.AccountsRequest) (*pb // NetworkInfo query provides NetworkInfoResponse. func (d DebugService) NetworkInfo(ctx context.Context, _ *emptypb.Empty) (*pb.NetworkInfoResponse, error) { - return &pb.NetworkInfoResponse{Id: d.identity.ID().String()}, nil + resp := &pb.NetworkInfoResponse{Id: d.netInfo.ID().String()} + for _, a := range d.netInfo.ListenAddresses() { + resp.ListenAddresses = append(resp.ListenAddresses, a.String()) + } + sort.Strings(resp.ListenAddresses) + for _, a := range d.netInfo.KnownAddresses() { + resp.KnownAddresses = append(resp.KnownAddresses, a.String()) + } + sort.Strings(resp.KnownAddresses) + udpNATType, tcpNATType := d.netInfo.NATDeviceType() + resp.NatTypeUdp = convertNATType(udpNATType) + resp.NatTypeTcp = convertNATType(tcpNATType) + resp.Reachability = convertReachability(d.netInfo.Reachability()) + resp.DhtServerEnabled = d.netInfo.DHTServerEnabled() + return resp, nil } // ActiveSet query provides hare active set for the specified epoch. @@ -158,3 +174,25 @@ func castEventProposal(ev *events.EventProposal) *pb.Proposal { } return proposal } + +func convertNATType(natType network.NATDeviceType) pb.NetworkInfoResponse_NATType { + switch natType { + case network.NATDeviceTypeCone: + return pb.NetworkInfoResponse_Cone + case network.NATDeviceTypeSymmetric: + return pb.NetworkInfoResponse_Symmetric + default: + return pb.NetworkInfoResponse_NATTypeUnknown + } +} + +func convertReachability(r network.Reachability) pb.NetworkInfoResponse_Reachability { + switch r { + case network.ReachabilityPublic: + return pb.NetworkInfoResponse_Public + case network.ReachabilityPrivate: + return pb.NetworkInfoResponse_Private + default: + return pb.NetworkInfoResponse_ReachabilityUnknown + } +} diff --git a/api/grpcserver/grpcserver_test.go b/api/grpcserver/grpcserver_test.go index f5e909d0f0..84e5d280e7 100644 --- a/api/grpcserver/grpcserver_test.go +++ b/api/grpcserver/grpcserver_test.go @@ -17,6 +17,8 @@ import ( "testing" "time" + "github.com/libp2p/go-libp2p/core/network" + ma "github.com/multiformats/go-multiaddr" pb "github.com/spacemeshos/api/release/go/spacemesh/v1" "github.com/spacemeshos/merkle-tree" "github.com/spacemeshos/poet/shared" @@ -2043,10 +2045,10 @@ func TestMultiService(t *testing.T) { func TestDebugService(t *testing.T) { ctrl := gomock.NewController(t) - identity := NewMocknetworkIdentity(ctrl) + netInfo := NewMocknetworkInfo(ctrl) mOracle := NewMockoracle(ctrl) db := sql.InMemory() - svc := NewDebugService(db, conStateAPI, identity, mOracle) + svc := NewDebugService(db, conStateAPI, netInfo, mOracle) cfg, cleanup := launchServer(t, svc) t.Cleanup(cleanup) @@ -2097,13 +2099,33 @@ func TestDebugService(t *testing.T) { t.Run("networkID", func(t *testing.T) { id := p2p.Peer("test") - identity.EXPECT().ID().Return(id) + netInfo.EXPECT().ID().Return(id) + netInfo.EXPECT().ListenAddresses().Return([]ma.Multiaddr{ + mustParseMultiaddr("/ip4/0.0.0.0/tcp/5000"), + mustParseMultiaddr("/ip4/0.0.0.0/udp/5001/quic-v1"), + }) + netInfo.EXPECT().KnownAddresses().Return([]ma.Multiaddr{ + mustParseMultiaddr("/ip4/10.36.0.221/tcp/5000"), + mustParseMultiaddr("/ip4/10.36.0.221/udp/5001/quic-v1"), + }) + netInfo.EXPECT().NATDeviceType().Return(network.NATDeviceTypeCone, network.NATDeviceTypeSymmetric) + netInfo.EXPECT().Reachability().Return(network.ReachabilityPrivate) + netInfo.EXPECT().DHTServerEnabled().Return(true) response, err := c.NetworkInfo(context.Background(), &emptypb.Empty{}) require.NoError(t, err) require.NotNil(t, response) require.Equal(t, id.String(), response.Id) + require.Equal(t, []string{"/ip4/0.0.0.0/tcp/5000", "/ip4/0.0.0.0/udp/5001/quic-v1"}, + response.ListenAddresses) + require.Equal(t, []string{"/ip4/10.36.0.221/tcp/5000", "/ip4/10.36.0.221/udp/5001/quic-v1"}, + response.KnownAddresses) + require.Equal(t, pb.NetworkInfoResponse_Cone, response.NatTypeUdp) + require.Equal(t, pb.NetworkInfoResponse_Symmetric, response.NatTypeTcp) + require.Equal(t, pb.NetworkInfoResponse_Private, response.Reachability) + require.True(t, response.DhtServerEnabled) }) + t.Run("ActiveSet", func(t *testing.T) { epoch := types.EpochID(3) activeSet := types.RandomActiveSet(11) @@ -2445,3 +2467,11 @@ func TestMeshService_EpochStream(t *testing.T) { } require.ElementsMatch(t, expected, got) } + +func mustParseMultiaddr(s string) ma.Multiaddr { + maddr, err := ma.NewMultiaddr(s) + if err != nil { + panic("can't parse multiaddr: " + err.Error()) + } + return maddr +} diff --git a/api/grpcserver/interface.go b/api/grpcserver/interface.go index e938c24435..b4904eaf97 100644 --- a/api/grpcserver/interface.go +++ b/api/grpcserver/interface.go @@ -4,6 +4,9 @@ import ( "context" "time" + "github.com/libp2p/go-libp2p/core/network" + ma "github.com/multiformats/go-multiaddr" + "github.com/spacemeshos/go-spacemesh/activation" "github.com/spacemeshos/go-spacemesh/common/types" "github.com/spacemeshos/go-spacemesh/p2p" @@ -12,9 +15,14 @@ import ( //go:generate mockgen -typed -package=grpcserver -destination=./mocks.go -source=./interface.go -// networkIdentity interface. -type networkIdentity interface { +// networkInfo interface. +type networkInfo interface { ID() p2p.Peer + ListenAddresses() []ma.Multiaddr + KnownAddresses() []ma.Multiaddr + NATDeviceType() (udpNATType, tcpNATType network.NATDeviceType) + Reachability() network.Reachability + DHTServerEnabled() bool } // conservativeState is an API for reading state and transaction/mempool data. diff --git a/api/grpcserver/mocks.go b/api/grpcserver/mocks.go index 29f628f595..caeddb5a0e 100644 --- a/api/grpcserver/mocks.go +++ b/api/grpcserver/mocks.go @@ -13,6 +13,8 @@ import ( reflect "reflect" time "time" + network "github.com/libp2p/go-libp2p/core/network" + multiaddr "github.com/multiformats/go-multiaddr" activation "github.com/spacemeshos/go-spacemesh/activation" types "github.com/spacemeshos/go-spacemesh/common/types" p2p "github.com/spacemeshos/go-spacemesh/p2p" @@ -20,31 +22,69 @@ import ( gomock "go.uber.org/mock/gomock" ) -// MocknetworkIdentity is a mock of networkIdentity interface. -type MocknetworkIdentity struct { +// MocknetworkInfo is a mock of networkInfo interface. +type MocknetworkInfo struct { ctrl *gomock.Controller - recorder *MocknetworkIdentityMockRecorder + recorder *MocknetworkInfoMockRecorder } -// MocknetworkIdentityMockRecorder is the mock recorder for MocknetworkIdentity. -type MocknetworkIdentityMockRecorder struct { - mock *MocknetworkIdentity +// MocknetworkInfoMockRecorder is the mock recorder for MocknetworkInfo. +type MocknetworkInfoMockRecorder struct { + mock *MocknetworkInfo } -// NewMocknetworkIdentity creates a new mock instance. -func NewMocknetworkIdentity(ctrl *gomock.Controller) *MocknetworkIdentity { - mock := &MocknetworkIdentity{ctrl: ctrl} - mock.recorder = &MocknetworkIdentityMockRecorder{mock} +// NewMocknetworkInfo creates a new mock instance. +func NewMocknetworkInfo(ctrl *gomock.Controller) *MocknetworkInfo { + mock := &MocknetworkInfo{ctrl: ctrl} + mock.recorder = &MocknetworkInfoMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *MocknetworkIdentity) EXPECT() *MocknetworkIdentityMockRecorder { +func (m *MocknetworkInfo) EXPECT() *MocknetworkInfoMockRecorder { return m.recorder } +// DHTServerEnabled mocks base method. +func (m *MocknetworkInfo) DHTServerEnabled() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DHTServerEnabled") + ret0, _ := ret[0].(bool) + return ret0 +} + +// DHTServerEnabled indicates an expected call of DHTServerEnabled. +func (mr *MocknetworkInfoMockRecorder) DHTServerEnabled() *networkInfoDHTServerEnabledCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DHTServerEnabled", reflect.TypeOf((*MocknetworkInfo)(nil).DHTServerEnabled)) + return &networkInfoDHTServerEnabledCall{Call: call} +} + +// networkInfoDHTServerEnabledCall wrap *gomock.Call +type networkInfoDHTServerEnabledCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *networkInfoDHTServerEnabledCall) Return(arg0 bool) *networkInfoDHTServerEnabledCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *networkInfoDHTServerEnabledCall) Do(f func() bool) *networkInfoDHTServerEnabledCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *networkInfoDHTServerEnabledCall) DoAndReturn(f func() bool) *networkInfoDHTServerEnabledCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // ID mocks base method. -func (m *MocknetworkIdentity) ID() p2p.Peer { +func (m *MocknetworkInfo) ID() p2p.Peer { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ID") ret0, _ := ret[0].(p2p.Peer) @@ -52,31 +92,184 @@ func (m *MocknetworkIdentity) ID() p2p.Peer { } // ID indicates an expected call of ID. -func (mr *MocknetworkIdentityMockRecorder) ID() *networkIdentityIDCall { +func (mr *MocknetworkInfoMockRecorder) ID() *networkInfoIDCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MocknetworkInfo)(nil).ID)) + return &networkInfoIDCall{Call: call} +} + +// networkInfoIDCall wrap *gomock.Call +type networkInfoIDCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *networkInfoIDCall) Return(arg0 p2p.Peer) *networkInfoIDCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *networkInfoIDCall) Do(f func() p2p.Peer) *networkInfoIDCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *networkInfoIDCall) DoAndReturn(f func() p2p.Peer) *networkInfoIDCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// KnownAddresses mocks base method. +func (m *MocknetworkInfo) KnownAddresses() []multiaddr.Multiaddr { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KnownAddresses") + ret0, _ := ret[0].([]multiaddr.Multiaddr) + return ret0 +} + +// KnownAddresses indicates an expected call of KnownAddresses. +func (mr *MocknetworkInfoMockRecorder) KnownAddresses() *networkInfoKnownAddressesCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KnownAddresses", reflect.TypeOf((*MocknetworkInfo)(nil).KnownAddresses)) + return &networkInfoKnownAddressesCall{Call: call} +} + +// networkInfoKnownAddressesCall wrap *gomock.Call +type networkInfoKnownAddressesCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *networkInfoKnownAddressesCall) Return(arg0 []multiaddr.Multiaddr) *networkInfoKnownAddressesCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *networkInfoKnownAddressesCall) Do(f func() []multiaddr.Multiaddr) *networkInfoKnownAddressesCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *networkInfoKnownAddressesCall) DoAndReturn(f func() []multiaddr.Multiaddr) *networkInfoKnownAddressesCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ListenAddresses mocks base method. +func (m *MocknetworkInfo) ListenAddresses() []multiaddr.Multiaddr { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListenAddresses") + ret0, _ := ret[0].([]multiaddr.Multiaddr) + return ret0 +} + +// ListenAddresses indicates an expected call of ListenAddresses. +func (mr *MocknetworkInfoMockRecorder) ListenAddresses() *networkInfoListenAddressesCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListenAddresses", reflect.TypeOf((*MocknetworkInfo)(nil).ListenAddresses)) + return &networkInfoListenAddressesCall{Call: call} +} + +// networkInfoListenAddressesCall wrap *gomock.Call +type networkInfoListenAddressesCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *networkInfoListenAddressesCall) Return(arg0 []multiaddr.Multiaddr) *networkInfoListenAddressesCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *networkInfoListenAddressesCall) Do(f func() []multiaddr.Multiaddr) *networkInfoListenAddressesCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *networkInfoListenAddressesCall) DoAndReturn(f func() []multiaddr.Multiaddr) *networkInfoListenAddressesCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// NATDeviceType mocks base method. +func (m *MocknetworkInfo) NATDeviceType() (network.NATDeviceType, network.NATDeviceType) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NATDeviceType") + ret0, _ := ret[0].(network.NATDeviceType) + ret1, _ := ret[1].(network.NATDeviceType) + return ret0, ret1 +} + +// NATDeviceType indicates an expected call of NATDeviceType. +func (mr *MocknetworkInfoMockRecorder) NATDeviceType() *networkInfoNATDeviceTypeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NATDeviceType", reflect.TypeOf((*MocknetworkInfo)(nil).NATDeviceType)) + return &networkInfoNATDeviceTypeCall{Call: call} +} + +// networkInfoNATDeviceTypeCall wrap *gomock.Call +type networkInfoNATDeviceTypeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *networkInfoNATDeviceTypeCall) Return(udpNATType, tcpNATType network.NATDeviceType) *networkInfoNATDeviceTypeCall { + c.Call = c.Call.Return(udpNATType, tcpNATType) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *networkInfoNATDeviceTypeCall) Do(f func() (network.NATDeviceType, network.NATDeviceType)) *networkInfoNATDeviceTypeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *networkInfoNATDeviceTypeCall) DoAndReturn(f func() (network.NATDeviceType, network.NATDeviceType)) *networkInfoNATDeviceTypeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Reachability mocks base method. +func (m *MocknetworkInfo) Reachability() network.Reachability { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Reachability") + ret0, _ := ret[0].(network.Reachability) + return ret0 +} + +// Reachability indicates an expected call of Reachability. +func (mr *MocknetworkInfoMockRecorder) Reachability() *networkInfoReachabilityCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MocknetworkIdentity)(nil).ID)) - return &networkIdentityIDCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Reachability", reflect.TypeOf((*MocknetworkInfo)(nil).Reachability)) + return &networkInfoReachabilityCall{Call: call} } -// networkIdentityIDCall wrap *gomock.Call -type networkIdentityIDCall struct { +// networkInfoReachabilityCall wrap *gomock.Call +type networkInfoReachabilityCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *networkIdentityIDCall) Return(arg0 p2p.Peer) *networkIdentityIDCall { +func (c *networkInfoReachabilityCall) Return(arg0 network.Reachability) *networkInfoReachabilityCall { c.Call = c.Call.Return(arg0) return c } // Do rewrite *gomock.Call.Do -func (c *networkIdentityIDCall) Do(f func() p2p.Peer) *networkIdentityIDCall { +func (c *networkInfoReachabilityCall) Do(f func() network.Reachability) *networkInfoReachabilityCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *networkIdentityIDCall) DoAndReturn(f func() p2p.Peer) *networkIdentityIDCall { +func (c *networkInfoReachabilityCall) DoAndReturn(f func() network.Reachability) *networkInfoReachabilityCall { c.Call = c.Call.DoAndReturn(f) return c } diff --git a/cmd/base.go b/cmd/base.go index 9867eb340b..fb1a5a7eb7 100644 --- a/cmd/base.go +++ b/cmd/base.go @@ -13,6 +13,7 @@ import ( "github.com/spacemeshos/go-spacemesh/common/types" "github.com/spacemeshos/go-spacemesh/config" "github.com/spacemeshos/go-spacemesh/node/flags" + "github.com/spacemeshos/go-spacemesh/p2p" ) var ( @@ -88,6 +89,13 @@ func EnsureCLIFlags(cmd *cobra.Command, appCFG *config.Config) error { panic(err.Error()) } val = dst + case "p2p.AddressList": + var al p2p.AddressList + alv := flags.NewAddressListValue(al, &al) + if err := alv.Set(viper.GetString(name)); err != nil { + panic(err.Error()) + } + val = al default: val = viper.Get(name) } diff --git a/cmd/root.go b/cmd/root.go index 9ce236196d..02a43752ee 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -84,8 +84,8 @@ func AddCommands(cmd *cobra.Command) { /** ======================== P2P Flags ========================== **/ - cmd.PersistentFlags().StringVar(&cfg.P2P.Listen, "listen", - cfg.P2P.Listen, "address for listening") + cmd.PersistentFlags().Var(flags.NewAddressListValue(cfg.P2P.Listen, &cfg.P2P.Listen), + "listen", "address(es) for listening") cmd.PersistentFlags().BoolVar(&cfg.P2P.Flood, "flood", cfg.P2P.Flood, "flood created messages to all peers") cmd.PersistentFlags().BoolVar(&cfg.P2P.DisableNatPort, "disable-natport", cfg.P2P.DisableNatPort, @@ -114,12 +114,27 @@ func AddCommands(cmd *cobra.Command) { cfg.P2P.MinPeers, "actively search for peers until you get this much") cmd.PersistentFlags().StringSliceVar(&cfg.P2P.Bootnodes, "bootnodes", cfg.P2P.Bootnodes, "entrypoints into the network") - cmd.PersistentFlags().StringVar(&cfg.P2P.AdvertiseAddress, "advertise-address", - cfg.P2P.AdvertiseAddress, "libp2p address with identity (example: /dns4/bootnode.spacemesh.io/tcp/5003)") + cmd.PersistentFlags().StringSliceVar(&cfg.P2P.PingPeers, "ping-peers", cfg.P2P.Bootnodes, "peers to ping") + cmd.PersistentFlags().DurationVar(&cfg.P2P.PingInterval, "ping-interval", cfg.P2P.PingInterval, "ping interval") + cmd.PersistentFlags().StringSliceVar(&cfg.P2P.StaticRelays, "static-relays", + cfg.P2P.StaticRelays, "static relay list") + cmd.PersistentFlags().Var(flags.NewAddressListValue(cfg.P2P.AdvertiseAddress, &cfg.P2P.AdvertiseAddress), + "advertise-address", + "libp2p address(es) with identity (example: /dns4/bootnode.spacemesh.io/tcp/5003)") cmd.PersistentFlags().BoolVar(&cfg.P2P.Bootnode, "p2p-bootnode", cfg.P2P.Bootnode, "gossipsub and discovery will be running in a mode suitable for bootnode") cmd.PersistentFlags().BoolVar(&cfg.P2P.PrivateNetwork, "p2p-private-network", cfg.P2P.PrivateNetwork, "discovery will work in private mode. mostly useful for testing, don't set in public networks") + cmd.PersistentFlags().BoolVar(&cfg.P2P.ForceDHTServer, "force-dht-server", cfg.P2P.ForceDHTServer, + "force DHT server mode") + cmd.PersistentFlags().BoolVar(&cfg.P2P.EnableTCPTransport, "enable-tcp-transport", cfg.P2P.EnableTCPTransport, + "enable TCP transport") + cmd.PersistentFlags().BoolVar(&cfg.P2P.EnableQUICTransport, "enable-quic-transport", cfg.P2P.EnableQUICTransport, + "enable QUIC transport") + cmd.PersistentFlags().BoolVar(&cfg.P2P.EnableRoutingDiscovery, "enable-routing-discovery", cfg.P2P.EnableQUICTransport, + "enable routing discovery") + cmd.PersistentFlags().BoolVar(&cfg.P2P.RoutingDiscoveryAdvertise, "routing-discovery-advertise", + cfg.P2P.RoutingDiscoveryAdvertise, "advertise for routing discovery") /** ======================== TIME Flags ========================== **/ diff --git a/fetch/fetch_test.go b/fetch/fetch_test.go index ffe4943bc1..2cb76c62cd 100644 --- a/fetch/fetch_test.go +++ b/fetch/fetch_test.go @@ -339,17 +339,17 @@ func TestFetch_PeerDroppedWhenMessageResultsInValidationReject(t *testing.T) { MaxRetriesForRequest: 3, } p2pconf := p2p.DefaultConfig() - p2pconf.Listen = "/ip4/127.0.0.1/tcp/0" + p2pconf.Listen = p2p.MustParseAddresses("/ip4/127.0.0.1/tcp/0") p2pconf.DataDir = t.TempDir() // Good host - h, err := p2p.New(ctx, lg, p2pconf, []byte{}) + h, err := p2p.New(ctx, lg, p2pconf, []byte{}, []byte{}) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, h.Stop()) }) // Bad host, will send a message that results in validation reject p2pconf.DataDir = t.TempDir() - badPeerHost, err := p2p.New(ctx, lg, p2pconf, []byte{}) + badPeerHost, err := p2p.New(ctx, lg, p2pconf, []byte{}, []byte{}) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, badPeerHost.Stop()) }) diff --git a/go.mod b/go.mod index d59461fa66..c2c0120929 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/libp2p/go-libp2p-kad-dht v0.25.2 github.com/libp2p/go-libp2p-pubsub v0.10.0 github.com/libp2p/go-libp2p-record v0.2.0 + github.com/libp2p/go-msgio v0.3.0 github.com/mitchellh/mapstructure v1.5.0 github.com/multiformats/go-multiaddr v0.12.0 github.com/multiformats/go-varint v0.0.7 @@ -31,9 +32,10 @@ require ( github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a github.com/prometheus/client_golang v1.17.0 github.com/prometheus/common v0.45.0 + github.com/quic-go/quic-go v0.39.4 github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/seehuhn/mt19937 v1.0.0 - github.com/spacemeshos/api/release/go v1.24.0 + github.com/spacemeshos/api/release/go v1.25.0 github.com/spacemeshos/economics v0.1.1 github.com/spacemeshos/fixed v0.1.1 github.com/spacemeshos/go-scale v1.1.12 @@ -139,7 +141,6 @@ require ( github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect github.com/libp2p/go-libp2p-routing-helpers v0.7.2 // indirect - github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect @@ -179,7 +180,6 @@ require ( github.com/prometheus/procfs v0.11.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.3.4 // indirect - github.com/quic-go/quic-go v0.39.4 // indirect github.com/quic-go/webtransport-go v0.6.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 1f63e09d23..bc80bd6e01 100644 --- a/go.sum +++ b/go.sum @@ -621,8 +621,8 @@ github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:Udh github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= -github.com/spacemeshos/api/release/go v1.24.0 h1:uB4ZdmbHpodtpTyb7tDGxkTyb0nqr6fOIKv47SUChwk= -github.com/spacemeshos/api/release/go v1.24.0/go.mod h1:SwqQxbhAF7tN3Qr34eVzczCB3KyTbkHH12U82eqfy6M= +github.com/spacemeshos/api/release/go v1.25.0 h1:HqIykavooxUxZySiN7yiILRX+Kx6WxM1NF6w72PNmMc= +github.com/spacemeshos/api/release/go v1.25.0/go.mod h1:Ffvt8Zl5K6k0In0OF7PUJ2JoxrW8zBRXKF1kG0abigg= github.com/spacemeshos/economics v0.1.1 h1:BPgMoTaeQ05ME6wEA1+MvXMp+wvXr51bIuN23thrCAk= github.com/spacemeshos/economics v0.1.1/go.mod h1:76nTjugYRiQ5/eD/DQs2dXPPilp28URMswUKncfdanY= github.com/spacemeshos/fixed v0.1.1 h1:N1y4SUpq1EV+IdJrWJwUCt1oBFzeru/VKVcBsvPc2Fk= diff --git a/node/adminservice_api_test.go b/node/adminservice_api_test.go index c080b853a0..b082adbb7f 100644 --- a/node/adminservice_api_test.go +++ b/node/adminservice_api_test.go @@ -14,13 +14,14 @@ import ( "github.com/spacemeshos/go-spacemesh/api/grpcserver" "github.com/spacemeshos/go-spacemesh/config" "github.com/spacemeshos/go-spacemesh/log/logtest" + "github.com/spacemeshos/go-spacemesh/p2p" ) func TestPeerInfoApi(t *testing.T) { cfg := config.DefaultTestConfig() cfg.Genesis.Accounts = nil cfg.P2P.DisableNatPort = true - cfg.P2P.Listen = "/ip4/127.0.0.1/tcp/0" + cfg.P2P.Listen = p2p.MustParseAddresses("/ip4/127.0.0.1/tcp/0") cfg.API.PublicListener = "0.0.0.0:0" cfg.API.PrivateServices = nil diff --git a/node/bad_peer_test.go b/node/bad_peer_test.go index de3c6035cf..2270ee720f 100644 --- a/node/bad_peer_test.go +++ b/node/bad_peer_test.go @@ -19,6 +19,7 @@ import ( "github.com/spacemeshos/go-spacemesh/common/types" "github.com/spacemeshos/go-spacemesh/config" "github.com/spacemeshos/go-spacemesh/log/logtest" + "github.com/spacemeshos/go-spacemesh/p2p" ps "github.com/spacemeshos/go-spacemesh/p2p/pubsub" ) @@ -32,7 +33,7 @@ func TestPeerDisconnectForMessageResultValidationReject(t *testing.T) { conf1 := config.DefaultTestConfig() conf1.DataDirParent = t.TempDir() conf1.FileLock = filepath.Join(conf1.DataDirParent, "LOCK") - conf1.P2P.Listen = "/ip4/127.0.0.1/tcp/0" + conf1.P2P.Listen = p2p.MustParseAddresses("/ip4/127.0.0.1/tcp/0") // We setup the api to listen on an OS assigned port, which avoids the second instance getting stuck when conf1.API.PublicListener = "0.0.0.0:0" conf1.API.PrivateListener = "0.0.0.0:0" @@ -45,7 +46,7 @@ func TestPeerDisconnectForMessageResultValidationReject(t *testing.T) { *conf2.Genesis = *conf1.Genesis conf2.DataDirParent = t.TempDir() conf2.FileLock = filepath.Join(conf2.DataDirParent, "LOCK") - conf2.P2P.Listen = "/ip4/127.0.0.1/tcp/0" + conf2.P2P.Listen = p2p.MustParseAddresses("/ip4/127.0.0.1/tcp/0") conf2.API.PublicListener = "0.0.0.0:0" conf2.API.PrivateListener = "0.0.0.0:0" app2 := NewApp(t, &conf2, l) diff --git a/node/flags/addresslist.go b/node/flags/addresslist.go new file mode 100644 index 0000000000..d20178055c --- /dev/null +++ b/node/flags/addresslist.go @@ -0,0 +1,94 @@ +package flags + +import ( + "encoding/csv" + "strings" + + "github.com/spacemeshos/go-spacemesh/p2p" +) + +// AddressListValue wraps an AddressList to make it possible to use it +// like a slice value in pflag. +type AddressListValue struct { + value *p2p.AddressList + changed bool +} + +// NewAddressListValue creates an AddressListValue that wraps the +// specified AddressList. +func NewAddressListValue(val p2p.AddressList, p *p2p.AddressList) *AddressListValue { + alv := new(AddressListValue) + alv.value = p + *alv.value = val + return alv +} + +// Set implements pflag.Value. +func (alv *AddressListValue) Set(val string) error { + v, err := readAsCSV(val) + if err != nil { + return err + } + if !alv.changed { + *alv.value = v + } else { + *alv.value = append(*alv.value, v...) + } + alv.changed = true + return nil +} + +// String implements pflag.Value. +func (alv *AddressListValue) String() string { + return alv.value.String() +} + +// Type implements pflag.Value. +func (alv *AddressListValue) Type() string { + return "addressList" +} + +// Append implements pflag.SliceValue. +func (alv *AddressListValue) Append(val string) error { + al, err := p2p.AddressListFromString(val) + if err != nil { + return err + } + *alv.value = append(*alv.value, al...) + return nil +} + +// GetSlice implements pflag.SliceValue. +func (alv *AddressListValue) GetSlice() []string { + r := make([]string, len(*alv.value)) + for n, ma := range *alv.value { + r[n] = ma.String() + } + return r +} + +// Replace implements pflag.SliceValue. +func (alv *AddressListValue) Replace(val []string) error { + al, err := p2p.AddressListFromStringSlice(val) + if err != nil { + return err + } + *alv.value = al + return nil +} + +func readAsCSV(val string) (p2p.AddressList, error) { + if strings.HasPrefix(val, "[") && strings.HasSuffix(val, "]") { + val = val[1 : len(val)-1] + } + if val == "" { + return p2p.AddressList{}, nil + } + stringReader := strings.NewReader(val) + csvReader := csv.NewReader(stringReader) + l, err := csvReader.Read() + if err != nil { + return nil, err + } + return p2p.AddressListFromStringSlice(l) +} diff --git a/node/flags/addresslist_test.go b/node/flags/addresslist_test.go new file mode 100644 index 0000000000..9fdc8d6dea --- /dev/null +++ b/node/flags/addresslist_test.go @@ -0,0 +1,29 @@ +package flags + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/spacemeshos/go-spacemesh/p2p" +) + +func TestAddressList(t *testing.T) { + al := p2p.MustParseAddresses("/ip4/0.0.0.0/tcp/7513") + alv := NewAddressListValue(al, &al) + require.Equal(t, []string{"/ip4/0.0.0.0/tcp/7513"}, alv.GetSlice()) + require.Equal(t, "addressList", alv.Type()) + require.Equal(t, "[/ip4/0.0.0.0/tcp/7513]", alv.String()) + require.NoError(t, alv.Set("[/ip4/0.0.0.0/tcp/5000]")) // replace the default value + require.Equal(t, "[/ip4/0.0.0.0/tcp/5000]", alv.String()) + require.NoError(t, alv.Set("/ip4/0.0.0.0/udp/0/quic-v1,/ip4/0.0.0.0/tcp/5002")) // append more values + require.Equal(t, "[/ip4/0.0.0.0/tcp/5000,/ip4/0.0.0.0/udp/0/quic-v1,/ip4/0.0.0.0/tcp/5002]", alv.String()) + require.NoError(t, alv.Replace([]string{"/ip4/0.0.0.0/tcp/4999"})) + require.NoError(t, alv.Append("/ip4/0.0.0.0/tcp/5001")) + require.Equal(t, "[/ip4/0.0.0.0/tcp/4999,/ip4/0.0.0.0/tcp/5001]", alv.String()) + + require.Error(t, alv.Set("abc,def")) + require.Error(t, alv.Replace([]string{"foobar"})) + require.Error(t, alv.Append("barbaz")) + require.Equal(t, "[/ip4/0.0.0.0/tcp/4999,/ip4/0.0.0.0/tcp/5001]", alv.String()) +} diff --git a/node/mapstructureutil/addresslist.go b/node/mapstructureutil/addresslist.go new file mode 100644 index 0000000000..9dc9723d8a --- /dev/null +++ b/node/mapstructureutil/addresslist.go @@ -0,0 +1,41 @@ +package mapstructureutil + +import ( + "reflect" + + "github.com/mitchellh/mapstructure" + + "github.com/spacemeshos/go-spacemesh/p2p" +) + +// AddressListDecodeFunc mapstructure decode func for p2p.AddressList. +// AddressList can be represented either by a string or by a slice of strings. +func AddressListDecodeFunc() mapstructure.DecodeHookFunc { + return func(f, t reflect.Type, data any) (any, error) { + if t != reflect.TypeOf(p2p.AddressList(nil)) { + return data, nil + } + + switch f.Kind() { + case reflect.Slice: + v := reflect.ValueOf(data) + items := make([]string, v.Len()) + for n := 0; n < v.Len(); n++ { + item := v.Index(n).Interface() + switch s := item.(type) { + case string: + items[n] = s + default: + return data, nil + } + } + r, err := p2p.AddressListFromStringSlice(items) + return r, err + case reflect.String: + r, err := p2p.AddressListFromString(data.(string)) + return r, err + default: + return data, nil + } + } +} diff --git a/node/node.go b/node/node.go index f661d3f1e2..0f6f7fa489 100644 --- a/node/node.go +++ b/node/node.go @@ -58,6 +58,7 @@ import ( "github.com/spacemeshos/go-spacemesh/miner" "github.com/spacemeshos/go-spacemesh/node/mapstructureutil" "github.com/spacemeshos/go-spacemesh/p2p" + "github.com/spacemeshos/go-spacemesh/p2p/handshake" "github.com/spacemeshos/go-spacemesh/p2p/pubsub" "github.com/spacemeshos/go-spacemesh/proposals" "github.com/spacemeshos/go-spacemesh/prune" @@ -260,6 +261,7 @@ func LoadConfigFromFile() (*config.Config, error) { hook := mapstructure.ComposeDecodeHookFunc( mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), + mapstructureutil.AddressListDecodeFunc(), mapstructureutil.BigRatDecodeFunc(), mapstructureutil.PostProviderIDDecodeFunc(), mapstructure.TextUnmarshallerHookFunc(), @@ -1696,7 +1698,14 @@ func (app *App) startSynchronous(ctx context.Context) (err error) { app.Config.Genesis.GenesisID(), types.GetEffectiveGenesis(), ) - app.host, err = p2p.New(ctx, p2plog, cfg, []byte(prologue), + // Prevent testnet nodes from working on the mainnet, but + // don't use the network cookie on mainnet as this technique + // may be replaced later + nc := handshake.NoNetworkCookie + if !onMainNet(app.Config) { + nc = handshake.NetworkCookie(prologue) + } + app.host, err = p2p.New(ctx, p2plog, cfg, []byte(prologue), nc, p2p.WithNodeReporter(events.ReportNodeStatusUpdate), ) if err != nil { diff --git a/node/node_test.go b/node/node_test.go index 2f5e0cd026..e547994ded 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -11,6 +11,7 @@ import ( "os" "path/filepath" "strconv" + "strings" "sync" "testing" "time" @@ -581,7 +582,7 @@ func TestSpacemeshApp_TransactionService(t *testing.T) { app.Config.API.PrivateServices = nil // Prevent obnoxious warning in macOS - app.Config.P2P.Listen = "/ip4/127.0.0.1/tcp/7073" + app.Config.P2P.Listen = p2p.MustParseAddresses("/ip4/127.0.0.1/tcp/7073") // Avoid waiting for new connections. app.Config.P2P.MinPeers = 0 @@ -800,6 +801,32 @@ func TestConfig_CustomTypes(t *testing.T) { copy(c.POST.PowDifficulty[:], diff) }, }, + { + name: "address-list-single", + cli: "--listen=/ip4/0.0.0.0/tcp/5555 --advertise-address=/ip4/10.20.30.40/tcp/5555", + config: `{"p2p":{"listen":"/ip4/0.0.0.0/tcp/5555","advertise-address":"/ip4/10.20.30.40/tcp/5555"}}`, + updatePreset: func(t *testing.T, c *config.Config) { + c.P2P.Listen = p2p.MustParseAddresses("/ip4/0.0.0.0/tcp/5555") + c.P2P.AdvertiseAddress = p2p.MustParseAddresses("/ip4/10.20.30.40/tcp/5555") + }, + }, + { + name: "address-list-multiple", + cli: "--listen=/ip4/0.0.0.0/tcp/5555 --listen=/ip4/0.0.0.0/udp/5555/quic-v1" + + " --advertise-address=/ip4/10.20.30.40/tcp/5555" + + " --advertise-address=/ip4/10.20.30.40/udp/5555/quic-v1", + config: `{"p2p":{"listen":["/ip4/0.0.0.0/tcp/5555","/ip4/0.0.0.0/udp/5555/quic-v1"], + "advertise-address":[ + "/ip4/10.20.30.40/tcp/5555","/ip4/10.20.30.40/udp/5555/quic-v1"]}}`, + updatePreset: func(t *testing.T, c *config.Config) { + c.P2P.Listen = p2p.MustParseAddresses( + "/ip4/0.0.0.0/tcp/5555", + "/ip4/0.0.0.0/udp/5555/quic-v1") + c.P2P.AdvertiseAddress = p2p.MustParseAddresses( + "/ip4/10.20.30.40/tcp/5555", + "/ip4/10.20.30.40/udp/5555/quic-v1") + }, + }, } for _, tc := range tt { @@ -809,7 +836,7 @@ func TestConfig_CustomTypes(t *testing.T) { c := &cobra.Command{} cmd.AddCommands(c) - require.NoError(t, c.ParseFlags([]string{tc.cli})) + require.NoError(t, c.ParseFlags(strings.Fields(tc.cli))) t.Cleanup(viper.Reset) t.Cleanup(cmd.ResetConfig) @@ -847,7 +874,7 @@ func TestConfig_CustomTypes(t *testing.T) { c := &cobra.Command{} cmd.AddCommands(c) - require.NoError(t, c.ParseFlags([]string{tc.cli})) + require.NoError(t, c.ParseFlags(strings.Fields(tc.cli))) viper.Set("preset", name) t.Cleanup(viper.Reset) diff --git a/p2p/addresslist.go b/p2p/addresslist.go new file mode 100644 index 0000000000..c7cb361a0a --- /dev/null +++ b/p2p/addresslist.go @@ -0,0 +1,64 @@ +package p2p + +import ( + "bytes" + "encoding/csv" + "fmt" + "strings" + + "github.com/multiformats/go-multiaddr" +) + +// AddressList represents a list of addresses. +type AddressList []multiaddr.Multiaddr + +// AddressListFromStringSlice parses strings in the slice into +// Multiaddr values and returns them as an AddressList. +func AddressListFromStringSlice(s []string) (AddressList, error) { + al := make(AddressList, len(s)) + for n, s := range s { + ma, err := multiaddr.NewMultiaddr(s) + if err != nil { + return nil, fmt.Errorf("address %s is not a valid multiaddr: %w", s, err) + } + al[n] = ma + } + + return al, nil +} + +// AddressListFromString parses a string containing a Multiaddr +// and returns it as an AddressList. +func AddressListFromString(s string) (AddressList, error) { + return AddressListFromStringSlice([]string{s}) +} + +// MustParseAddresses parses multiaddr strings into AddressList, and +// panics upon any parse errors. +func MustParseAddresses(s ...string) AddressList { + al, err := AddressListFromStringSlice(s) + if err != nil { + panic(err) + } + return al +} + +// String implements Stringer. +func (al AddressList) String() string { + str, _ := writeAsCSV(al) + return "[" + str + "]" +} + +func writeAsCSV(vals AddressList) (string, error) { + strs := make([]string, len(vals)) + for n, v := range vals { + strs[n] = v.String() + } + var b bytes.Buffer + w := csv.NewWriter(&b) + if err := w.Write(strs); err != nil { + return "", err + } + w.Flush() + return strings.TrimSuffix(b.String(), "\n"), nil +} diff --git a/p2p/dhtdiscovery/discovery.go b/p2p/dhtdiscovery/discovery.go index 4cc27850c8..96c8e59fe6 100644 --- a/p2p/dhtdiscovery/discovery.go +++ b/p2p/dhtdiscovery/discovery.go @@ -2,20 +2,36 @@ package discovery import ( "context" + "errors" "fmt" + "sync" "time" levelds "github.com/ipfs/go-ds-leveldb" dht "github.com/libp2p/go-libp2p-kad-dht" record "github.com/libp2p/go-libp2p-record" + p2pdisc "github.com/libp2p/go-libp2p/core/discovery" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" + p2pdiscr "github.com/libp2p/go-libp2p/p2p/discovery/routing" ldbopts "github.com/syndtr/goleveldb/leveldb/opt" "go.uber.org/zap" "golang.org/x/sync/errgroup" ) +const ( + discoveryNS = "spacemesh-disc" + relayNS = "spacemesh-disc-relay" + discoveryTag = "spacemesh-disc" + discoveryTagValue = 10 // 5 is used for kbucket (DHT) + discoveryHighPeersDelay = 10 * time.Second + protocolPrefix = "/spacekad" + ProtocolID = protocolPrefix + "/kad/1.0.0" + findPeersRetryDelay = time.Second + advertiseRetryInterval = time.Second +) + type Opt func(*Discovery) func WithPeriod(period time.Duration) Opt { @@ -66,9 +82,9 @@ func WithLogger(logger *zap.Logger) Opt { } } -func Server() Opt { +func WithMode(mode dht.ModeOpt) Opt { return func(d *Discovery) { - d.server = true + d.mode = mode } } @@ -90,19 +106,47 @@ func DisableDHT() Opt { } } -func New(h host.Host, opts ...Opt) (*Discovery, error) { - ctx, cancel := context.WithCancel(context.Background()) +func WithRelayCandidateChannel(relayCh chan<- peer.AddrInfo) Opt { + return func(d *Discovery) { + d.relayCh = relayCh + } +} + +func EnableRoutingDiscovery() Opt { + return func(d *Discovery) { + d.enableRoutingDiscovery = true + } +} + +func AdvertiseForPeerDiscovery() Opt { + return func(d *Discovery) { + d.advertise = true + } +} + +func WithAdvertiseInterval(aint time.Duration) Opt { + return func(d *Discovery) { + d.advertiseInterval = aint + } +} + +type DiscoveryHost interface { + host.Host + NeedPeerDiscovery() bool + HaveRelay() bool +} + +func New(h DiscoveryHost, opts ...Opt) (*Discovery, error) { d := Discovery{ public: true, logger: zap.NewNop(), - ctx: ctx, - cancel: cancel, h: h, period: 10 * time.Second, timeout: 30 * time.Second, bootstrapDuration: 30 * time.Second, minPeers: 20, highPeers: 40, + advertiseInterval: time.Minute, } for _, opt := range opts { opt(&d) @@ -110,29 +154,27 @@ func New(h host.Host, opts ...Opt) (*Discovery, error) { if len(d.bootnodes) == 0 { d.logger.Warn("no bootnodes in the config") } - if !d.disableDht { - err := d.newDht(ctx, h, d.public, d.server, d.dir) - if err != nil { - return nil, err - } - } return &d, nil } type Discovery struct { - public bool - server bool - disableDht bool - dir string + public bool + mode dht.ModeOpt + disableDht bool + dir string + relayCh chan<- peer.AddrInfo + enableRoutingDiscovery bool + advertise bool logger *zap.Logger eg errgroup.Group - ctx context.Context cancel context.CancelFunc - h host.Host + h DiscoveryHost + dhtLock sync.Mutex dht *dht.IpfsDHT datastore *levelds.Datastore + disc *p2pdiscr.RoutingDiscovery // how often to check if we have enough peers period time.Duration @@ -141,53 +183,68 @@ type Discovery struct { bootstrapDuration time.Duration minPeers, highPeers int backup, bootnodes []peer.AddrInfo + advertiseInterval time.Duration +} + +func (d *Discovery) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) { + d.dhtLock.Lock() + dht := d.dht + d.dhtLock.Unlock() + if dht == nil { + return peer.AddrInfo{}, errors.New("discovery not started") + } + return dht.FindPeer(ctx, p) } -func (d *Discovery) Start() { +func (d *Discovery) Start() error { + if d.cancel != nil { + return nil + } + var startCtx context.Context + startCtx, d.cancel = context.WithCancel(context.Background()) + + if !d.disableDht { + if err := d.setupDHT(startCtx); err != nil { + return err + } + } + d.eg.Go(func() error { - var connEg errgroup.Group - disconnected := make(chan struct{}, 1) - disconnected <- struct{}{} // trigger bootstrap when node starts immediately - notifiee := &network.NotifyBundle{ - DisconnectedF: func(_ network.Network, c network.Conn) { - select { - case disconnected <- struct{}{}: - default: - } - }, + return d.ensureAtLeastMinPeers(startCtx) + }) + + if !d.disableDht { + d.disc = p2pdiscr.NewRoutingDiscovery(d.dht) + if d.advertise { + d.eg.Go(func() error { + return d.advertiseNS(startCtx, discoveryNS, nil) + }) } - d.h.Network().Notify(notifiee) - ticker := time.NewTicker(d.period) - for { - select { - case <-d.ctx.Done(): - ticker.Stop() - d.h.Network().StopNotify(notifiee) - return nil - case <-ticker.C: - case <-disconnected: - } - if connected := len(d.h.Network().Peers()); connected >= d.minPeers { - d.backup = nil // once got enough peers no need to keep backup, they are either already connected or unavailable - d.logger.Debug("node is connected with required number of peers. skipping bootstrap", - zap.Int("required", d.minPeers), - zap.Int("connected", connected), - ) - } else { - d.connect(&connEg, d.backup) - // no reason to spend more resources if we got enough from backup - if connected := len(d.h.Network().Peers()); connected >= d.minPeers { - continue - } - d.connect(&connEg, d.bootnodes) - d.bootstrap() + if d.enableRoutingDiscovery { + d.eg.Go(func() error { + return d.discoverPeers(startCtx) + }) + if d.relayCh != nil { + d.eg.Go(func() error { + d.discoverRelays(startCtx) + return nil + }) } } - }) + d.eg.Go(func() error { + return d.advertiseNS(startCtx, relayNS, d.h.HaveRelay) + }) + } + + return nil } func (d *Discovery) Stop() { + if d.cancel == nil { + return + } d.cancel() + d.cancel = nil d.eg.Wait() if !d.disableDht { if err := d.dht.Close(); err != nil { @@ -199,11 +256,11 @@ func (d *Discovery) Stop() { } } -func (d *Discovery) bootstrap() { +func (d *Discovery) bootstrap(ctx context.Context) { if d.dht == nil { return } - ctx, cancel := context.WithTimeout(d.ctx, d.bootstrapDuration) + ctx, cancel := context.WithTimeout(ctx, d.bootstrapDuration) defer cancel() if err := d.dht.Bootstrap(ctx); err != nil { d.logger.Error("unexpected error from discovery dht", zap.Error(err)) @@ -211,8 +268,8 @@ func (d *Discovery) bootstrap() { <-ctx.Done() } -func (d *Discovery) connect(eg *errgroup.Group, nodes []peer.AddrInfo) { - ctx, cancel := context.WithTimeout(d.ctx, d.timeout) +func (d *Discovery) connect(ctx context.Context, eg *errgroup.Group, nodes []peer.AddrInfo) { + conCtx, cancel := context.WithTimeout(ctx, d.timeout) defer cancel() for _, boot := range nodes { boot := boot @@ -221,7 +278,7 @@ func (d *Discovery) connect(eg *errgroup.Group, nodes []peer.AddrInfo) { continue } eg.Go(func() error { - if err := d.h.Connect(ctx, boot); err != nil { + if err := d.h.Connect(conCtx, boot); err != nil { d.logger.Warn("failed to connect", zap.Stringer("address", boot), zap.Error(err), @@ -233,33 +290,29 @@ func (d *Discovery) connect(eg *errgroup.Group, nodes []peer.AddrInfo) { eg.Wait() } -func (d *Discovery) newDht(ctx context.Context, h host.Host, public, server bool, dir string) error { - ds, err := levelds.NewDatastore(dir, &levelds.Options{ +func (d *Discovery) setupDHT(ctx context.Context) error { + d.dhtLock.Lock() + defer d.dhtLock.Unlock() + ds, err := levelds.NewDatastore(d.dir, &levelds.Options{ Compression: ldbopts.NoCompression, NoSync: false, Strict: ldbopts.StrictAll, ReadOnly: false, }) if err != nil { - return fmt.Errorf("open leveldb at %s: %w", dir, err) + return fmt.Errorf("open leveldb at %s: %w", d.dir, err) } opts := []dht.Option{ dht.Validator(record.PublicKeyValidator{}), dht.Datastore(ds), - dht.ProtocolPrefix("/spacekad"), - dht.DisableProviders(), - dht.DisableValues(), + dht.ProtocolPrefix(protocolPrefix), } - if public { + if d.public { opts = append(opts, dht.QueryFilter(dht.PublicQueryFilter), dht.RoutingTableFilter(dht.PublicRoutingTableFilter)) } - if server { - opts = append(opts, dht.Mode(dht.ModeServer)) - } else { - opts = append(opts, dht.Mode(dht.ModeAutoServer)) - } - dht, err := dht.New(ctx, h, opts...) + opts = append(opts, dht.Mode(d.mode)) + dht, err := dht.New(ctx, d.h, opts...) if err != nil { if err := ds.Close(); err != nil { d.logger.Error("error closing level datastore", zap.Error(err)) @@ -270,3 +323,174 @@ func (d *Discovery) newDht(ctx context.Context, h host.Host, public, server bool d.datastore = ds return nil } + +func (d *Discovery) ensureAtLeastMinPeers(ctx context.Context) error { + var connEg errgroup.Group + disconnected := make(chan struct{}, 1) + disconnected <- struct{}{} // trigger bootstrap when node starts immediately + // TODO: connectedF, disconnectedF: track enough rendezvous peers + notifiee := &network.NotifyBundle{ + DisconnectedF: func(_ network.Network, c network.Conn) { + select { + case disconnected <- struct{}{}: + default: + } + }, + } + d.h.Network().Notify(notifiee) + ticker := time.NewTicker(d.period) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + d.h.Network().StopNotify(notifiee) + return nil + case <-ticker.C: + case <-disconnected: + } + if connected := len(d.h.Network().Peers()); connected >= d.minPeers { + d.backup = nil // once got enough peers no need to keep backup, they are either already connected or unavailable + d.logger.Debug("node is connected with required number of peers. skipping bootstrap", + zap.Int("required", d.minPeers), + zap.Int("connected", connected), + ) + } else { + d.connect(ctx, &connEg, d.backup) + // no reason to spend more resources if we got enough from backup + if connected := len(d.h.Network().Peers()); connected >= d.minPeers { + continue + } + d.connect(ctx, &connEg, d.bootnodes) + d.bootstrap(ctx) + } + } +} + +func (d *Discovery) peerHasTag(p peer.ID) bool { + ti := d.h.ConnManager().GetTagInfo(p) + if ti == nil { + return false + } + _, found := ti.Tags[discoveryTag] + return found +} + +func (d *Discovery) advertiseNS(ctx context.Context, ns string, active func() bool) error { + for { + var ttl time.Duration + if active == nil || active() { + var err error + d.logger.Debug("advertising for routing discovery", zap.String("ns", ns)) + ttl, err = d.disc.Advertise(ctx, ns, p2pdisc.TTL(d.advertiseInterval)) + if err != nil { + d.logger.Error("failed to re-advertise for discovery", zap.String("ns", ns), zap.Error(err)) + ttl = advertiseRetryInterval + } + } else { + ttl = d.advertiseInterval + } + select { + case <-ctx.Done(): + return nil + case <-time.After(ttl): + } + } +} + +func (d *Discovery) discoverPeers(ctx context.Context) error { + for p := range d.findPeersContinuously(ctx, discoveryNS) { + wasSuspended := false + for !d.h.NeedPeerDiscovery() { + wasSuspended = true + d.logger.Info("suspending routing discovery", + zap.Duration("delay", discoveryHighPeersDelay)) + select { + case <-ctx.Done(): + return nil + case <-time.After(discoveryHighPeersDelay): + } + } + if wasSuspended { + d.logger.Info("resuming routing discovery") + } + + if p.ID == d.h.ID() { + continue + } + freshlyConnected := !d.peerHasTag(p.ID) + // trim open conns to free up some space + d.h.ConnManager().TrimOpenConns(ctx) + // tag peer to prioritize it over the peers found by other means + d.h.ConnManager().TagPeer(p.ID, discoveryTag, discoveryTagValue) + if d.h.Network().Connectedness(p.ID) != network.Connected { + if _, err := d.h.Network().DialPeer(ctx, p.ID); err != nil { + d.logger.Debug("error dialing peer", zap.Any("peer", p), + zap.Error(err)) + continue + } + freshlyConnected = true + } + if freshlyConnected { + d.logger.Info("found peer via rendezvous", zap.Any("peer", p)) + } + } + + return nil +} + +func (d *Discovery) discoverRelays(ctx context.Context) { + for p := range d.findPeersContinuously(ctx, relayNS) { + if len(p.Addrs) != 0 { + d.logger.Debug("found relay candidate", zap.Any("p", p)) + select { + case d.relayCh <- p: + case <-ctx.Done(): + return + } + } + } +} + +func (d *Discovery) findPeersContinuously(ctx context.Context, ns string) <-chan peer.AddrInfo { + r := make(chan peer.AddrInfo) + d.eg.Go(func() error { + defer close(r) + var peerCh <-chan peer.AddrInfo + for { + if peerCh == nil { + var err error + peerCh, err = d.disc.FindPeers(ctx, ns) + if err != nil { + d.logger.Error("error finding relay peers", zap.Error(err)) + select { + case <-ctx.Done(): + return nil + case <-time.After(findPeersRetryDelay): + } + peerCh = nil + continue + } + } + + select { + case <-ctx.Done(): + return nil + case p, ok := <-peerCh: + if !ok { + peerCh = nil + select { + case <-ctx.Done(): + return nil + case <-time.After(findPeersRetryDelay): + } + continue + } + select { + case r <- p: + case <-ctx.Done(): + } + } + } + }) + return r +} diff --git a/p2p/dhtdiscovery/discovery_test.go b/p2p/dhtdiscovery/discovery_test.go index ad4dc4ade5..38c3eb07e5 100644 --- a/p2p/dhtdiscovery/discovery_test.go +++ b/p2p/dhtdiscovery/discovery_test.go @@ -1,18 +1,44 @@ package discovery import ( + "fmt" "testing" "time" + dht "github.com/libp2p/go-libp2p-kad-dht" + "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" "github.com/spacemeshos/go-spacemesh/log/logtest" ) +type discHost struct { + host.Host + needPeerDiscovery bool + haveRelay bool +} + +var _ DiscoveryHost = &discHost{} + +func makeDiscHost(h host.Host, needPeerDiscovery, haveRelay bool) *discHost { + return &discHost{ + Host: h, + needPeerDiscovery: needPeerDiscovery, + haveRelay: haveRelay, + } +} + +func (h *discHost) NeedPeerDiscovery() bool { return h.needPeerDiscovery } +func (h *discHost) HaveRelay() bool { return h.haveRelay } + func TestSanity(t *testing.T) { - mock, err := mocknet.FullMeshLinked(4) + mock, err := mocknet.FullMeshLinked(7) + for n, h := range mock.Hosts() { + t.Logf("Host %d: %s", n, h.ID()) + } require.NoError(t, err) discs := make([]*Discovery, len(mock.Hosts())) t.Cleanup(func() { @@ -20,26 +46,81 @@ func TestSanity(t *testing.T) { disc.Stop() } }) - boot := mock.Hosts()[0] + // Let the bootnode have suspended peer discovery. + // It knows all the nodes anyway. Also, do not advertise + // it for routing discovery as all the nodes know about + // their bootnode, too. + boot := makeDiscHost(mock.Hosts()[0], false, false) logger := logtest.New(t).Zap() bootdisc, err := New(boot, WithPeriod(100*time.Microsecond), + EnableRoutingDiscovery(), Private(), - Server(), WithLogger(logger), + WithMode(dht.ModeServer), ) require.NoError(t, err) bootdisc.Start() + defer bootdisc.Stop() discs[0] = bootdisc require.NoError(t, err) + relayChans := make([]chan peer.AddrInfo, len(mock.Hosts())) + nodeOpts := []struct { + // Nodes that run DHT in client mode (/.../kad/... protocol not supported) + // are much harder to come by without enabling routing discovery + dhtMode dht.ModeOpt + relayService bool + lookForRelays bool + }{ + { + // 1 + dhtMode: dht.ModeServer, + relayService: true, + }, + { + // 2 + dhtMode: dht.ModeServer, + lookForRelays: true, + }, + { + // 3 + dhtMode: dht.ModeServer, + lookForRelays: true, + }, + { + // 4 + dhtMode: dht.ModeServer, + lookForRelays: true, + }, + { + // 5 + dhtMode: dht.ModeClient, + lookForRelays: true, + }, + { + // 6 + dhtMode: dht.ModeClient, + lookForRelays: true, + }, + } for i, h := range mock.Hosts()[1:] { - disc, err := New(h, + opts := []Opt{ Private(), WithLogger(logger), WithBootnodes([]peer.AddrInfo{{ID: boot.ID(), Addrs: boot.Addrs()}}), - ) + EnableRoutingDiscovery(), + AdvertiseForPeerDiscovery(), + WithMode(nodeOpts[i].dhtMode), + } + if nodeOpts[i].lookForRelays { + relayCh := make(chan peer.AddrInfo) + relayChans[1+i] = relayCh + opts = append(opts, WithRelayCandidateChannel(relayCh)) + } + disc, err := New(makeDiscHost(h, true, nodeOpts[i].relayService), opts...) require.NoError(t, err) disc.Start() + defer disc.Stop() discs[1+i] = disc } require.Eventually(t, func() bool { @@ -49,5 +130,27 @@ func TestSanity(t *testing.T) { } } return true - }, 3*time.Second, 50*time.Microsecond) + }, 15*time.Second, 100*time.Millisecond) + + // Wait till every node looking for relays have discovered + // the node 1 which has relay service enabled + var eg errgroup.Group + for n, ch := range relayChans { + n := n + ch := ch + if ch == nil { + continue + } + eg.Go(func() error { + select { + case p := <-ch: + require.Equal(t, mock.Hosts()[1].ID(), p.ID) + case <-time.After(3 * time.Second): + return fmt.Errorf("timed out waiting for relay id for peer %d", n) + } + return nil + }) + } + + require.NoError(t, eg.Wait()) } diff --git a/p2p/handshake/handshake.go b/p2p/handshake/handshake.go new file mode 100644 index 0000000000..b4230a6e93 --- /dev/null +++ b/p2p/handshake/handshake.go @@ -0,0 +1,278 @@ +package handshake + +import ( + "bytes" + "context" + "encoding/hex" + "fmt" + "io" + "time" + + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/transport" + "github.com/libp2p/go-msgio" + ma "github.com/multiformats/go-multiaddr" + + "github.com/spacemeshos/go-spacemesh/log" +) + +const ( + handshakeTimeout = 5 * time.Second + handshakeAttempts = 3 + handshakeRetryInterval = 1 * time.Second + maxCookieSize = 64 +) + +var cookieStreamPrefix = []byte{ + 0x21, 0x23, 0x42, 0x42, +} + +// NetworkCookie specifies a sequence of bytes that can be used to +// prevent peers from different networks from communicating with each +// other. +type NetworkCookie []byte + +// NoNetworkCookie represents an empty NetworkCookie. +var NoNetworkCookie NetworkCookie = nil + +// Empty returns true if the network cookie is empty. +func (nc NetworkCookie) Empty() bool { + return len(nc) == 0 +} + +// String returns string representation of the NetworkCookie, which is +// a hex string. +func (nc NetworkCookie) String() string { + return hex.EncodeToString(nc) +} + +// Equal returns true if this cookie is the same as the other cookie. +func (nc NetworkCookie) Equal(other NetworkCookie) bool { + return bytes.Equal(nc, other) +} + +// Option specifies a handshake option. +type Option func(w *transportWrapper) + +// WithLog specifies a logger for handshake. +func WithLog(logger log.Log) Option { + return func(w *transportWrapper) { + w.logger = logger + } +} + +// WithLog specifies handshake timeout. +func WithTimeout(t time.Duration) Option { + return func(w *transportWrapper) { + w.timeout = t + } +} + +// WithLog specifies handshake retry interval. +func WithRetryInterval(i time.Duration) Option { + return func(w *transportWrapper) { + w.retryInterval = i + } +} + +// WithAttempts specifies handshake retry count. +func WithAttempts(n int) Option { + return func(w *transportWrapper) { + w.attempts = n + } +} + +type transportWrapper struct { + transport.Transport + nc NetworkCookie + logger log.Log + timeout time.Duration + retryInterval time.Duration + attempts int +} + +var ( + _ transport.Transport = &transportWrapper{} + _ io.Closer = &transportWrapper{} +) + +// MaybeWrapTransport adds a handshake wrapper around the Transport if +// network cookie nc is not empty, otherwise it just returns the +// transport. +func MaybeWrapTransport(t transport.Transport, nc NetworkCookie, opts ...Option) transport.Transport { + if nc.Empty() { + return t + } + tr := &transportWrapper{ + Transport: t, + nc: nc, + logger: log.NewNop(), + timeout: handshakeTimeout, + retryInterval: handshakeRetryInterval, + attempts: handshakeAttempts, + } + for _, opt := range opts { + opt(tr) + } + return tr +} + +func (tr *transportWrapper) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (transport.CapableConn, error) { + c, err := tr.Transport.Dial(ctx, raddr, p) + if err != nil { + return nil, err + } + + for i := 0; i < tr.attempts; i++ { + var retry bool + retry, err = tr.handshake(ctx, c) + switch { + case err == nil: + return c, nil + case retry: + tr.logger.With().Error("transport wrapper handshake error", + log.Int("attempt", i+1), + log.Int("handshakeAttempts", tr.attempts), + log.Err(err)) + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(handshakeRetryInterval): + } + default: + return nil, err + } + } + + return nil, err +} + +func (tr *transportWrapper) handshake(ctx context.Context, c transport.CapableConn) (retry bool, err error) { + attemptCtx, cancel := context.WithTimeout(ctx, handshakeTimeout) + defer cancel() + s, err := c.OpenStream(attemptCtx) + if err != nil { + return true, err + } + + defer s.Close() + s.SetDeadline(time.Now().Add(tr.timeout)) + + if err := writeCookie(s, tr.nc); err != nil { + return true, err + } + + remoteCookie, mayHaveCookie, err := readCookie(s) + if err != nil { + return mayHaveCookie, err + } + + if !tr.nc.Equal(remoteCookie) { + return false, fmt.Errorf("cookie mismatch: %s instead of expected %s", remoteCookie, tr.nc) + } + + return false, nil +} + +func (tr *transportWrapper) Listen(laddr ma.Multiaddr) (transport.Listener, error) { + l, err := tr.Transport.Listen(laddr) + if err != nil { + return nil, ma.ErrProtocolNotFound + } + return &listenerWrapper{ + Listener: l, + nc: tr.nc, + logger: tr.logger, + timeout: tr.timeout, + attempts: tr.attempts, + }, nil +} + +func (tr *transportWrapper) Close() error { + if c, ok := tr.Transport.(io.Closer); ok { + return c.Close() + } + + return nil +} + +type listenerWrapper struct { + transport.Listener + nc NetworkCookie + logger log.Log + timeout time.Duration + attempts int +} + +var _ transport.Listener = &listenerWrapper{} + +func (l *listenerWrapper) Accept() (transport.CapableConn, error) { + for { + c, err := l.Listener.Accept() + if err != nil { + return nil, err + } + for i := 0; i < l.attempts; i++ { + retry, err := l.handshake(c) + switch { + case err == nil: + return c, nil + case retry: + l.logger.With().Error("transport wrapper handshake error", + log.Int("attempt", i+1), + log.Int("handshakeAttempts", l.attempts), + log.Err(err)) + default: + l.logger.With().Error("handshake failed", log.Err(err)) + } + } + } +} + +func (l *listenerWrapper) handshake(c transport.CapableConn) (retry bool, err error) { + s, err := c.AcceptStream() + if err != nil { + return true, err + } + defer s.Close() + s.SetDeadline(time.Now().Add(l.timeout)) + + remoteCookie, mayHaveCookie, err := readCookie(s) + if err != nil { + return mayHaveCookie, err + } + + // Write our cookie even in case of mismatch so that the + // peer sees the reason for disconnect immediately + if err := writeCookie(s, l.nc); err != nil { + return true, err + } + + if !l.nc.Equal(remoteCookie) { + return false, fmt.Errorf("cookie mismatch: %s instead of expected %s", remoteCookie, l.nc) + } + + return false, nil +} + +func writeCookie(w io.Writer, nc NetworkCookie) error { + if _, err := w.Write(cookieStreamPrefix); err != nil { + return err + } + return msgio.NewVarintWriter(w).WriteMsg(nc) +} + +func readCookie(r io.Reader) (nc NetworkCookie, mayHaveCookie bool, err error) { + buf := make([]byte, len(cookieStreamPrefix)) + if _, err := io.ReadFull(r, buf); err != nil { + return nil, true, err + } + if !bytes.Equal(cookieStreamPrefix, buf) { + return nil, false, fmt.Errorf("the remote endpoint doesn't have a cookie") + } + b, err := msgio.NewVarintReaderSize(r, maxCookieSize).ReadMsg() + if err != nil { + return nil, true, err + } + return NetworkCookie(b), true, err +} diff --git a/p2p/handshake/handshake_test.go b/p2p/handshake/handshake_test.go new file mode 100644 index 0000000000..a6a61827a6 --- /dev/null +++ b/p2p/handshake/handshake_test.go @@ -0,0 +1,156 @@ +package handshake + +import ( + "bytes" + "context" + "crypto/rand" + "encoding/hex" + "fmt" + "io" + "testing" + "time" + + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/transport" + quic "github.com/libp2p/go-libp2p/p2p/transport/quic" + "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" + ma "github.com/multiformats/go-multiaddr" + quicgo "github.com/quic-go/quic-go" + "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" + + "github.com/spacemeshos/go-spacemesh/log" + "github.com/spacemeshos/go-spacemesh/log/logtest" +) + +func createPeer(t *testing.T) (peer.ID, crypto.PrivKey) { + pk, _, err := crypto.GenerateECDSAKeyPair(rand.Reader) + require.NoError(t, err) + id, err := peer.IDFromPrivateKey(pk) + require.NoError(t, err) + return id, pk +} + +func newConnManager(t *testing.T, opts ...quicreuse.Option) *quicreuse.ConnManager { + t.Helper() + cm, err := quicreuse.NewConnManager(quicgo.StatelessResetKey{}, quicgo.TokenGeneratorKey{}, opts...) + require.NoError(t, err) + t.Cleanup(func() { cm.Close() }) + return cm +} + +func wrapTransport(t transport.Transport, nc NetworkCookie, logger log.Log) transport.Transport { + return MaybeWrapTransport(t, nc, WithLog(logger), WithTimeout(300*time.Millisecond), WithAttempts(2)) +} + +func TestTransportWrapper(t *testing.T) { + type testcase struct { + name string + clientCookie NetworkCookie + serverCookie NetworkCookie + dialError bool + readError bool + } + + testcases := []testcase{ + { + name: "no cookies", + }, + { + name: "matching cookies", + clientCookie: NetworkCookie{0, 1, 2, 3}, + serverCookie: NetworkCookie{0, 1, 2, 3}, + }, + { + name: "non-matching cookies", + clientCookie: NetworkCookie{0, 1, 2, 3}, + serverCookie: NetworkCookie{0, 1, 2, 0}, + dialError: true, + }, + { + name: "client cookie missing", + serverCookie: NetworkCookie{0, 1, 2, 3}, + readError: true, + }, + { + name: "server cookie missing", + clientCookie: NetworkCookie{0, 1, 2, 3}, + dialError: true, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + serverID, serverKey := createPeer(t) + _, clientKey := createPeer(t) + + logger := logtest.New(t) + + serverTransport, err := quic.NewTransport(serverKey, newConnManager(t), nil, nil, nil) + serverTransport = wrapTransport(serverTransport, tc.serverCookie, logger) + require.NoError(t, err) + defer serverTransport.(io.Closer).Close() + + ln, err := serverTransport.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1")) + require.NoError(t, err) + var eg errgroup.Group + eg.Go(func() error { + c, err := ln.Accept() + if err != nil { + return fmt.Errorf("Accept error: %w", err) + } + t.Logf("accepted") + s, err := c.AcceptStream() + if err != nil { + return fmt.Errorf("AcceptStream error: %w", err) + } + defer s.Close() + buf := make([]byte, 4) + _, err = io.ReadFull(s, buf) + if err != nil { + return fmt.Errorf("read error: %w", err) + } + exp := []byte{10, 20, 30, 40} + if !bytes.Equal(buf, exp) { + return fmt.Errorf("data mismatch: expected %s, got %s", + hex.EncodeToString(exp), hex.EncodeToString(buf)) + } + _, err = s.Write([]byte{11, 22, 33, 44}) + if err != nil { + return fmt.Errorf("write error: %w", err) + } + return nil + }) + + defer eg.Wait() + defer ln.Close() + + clientTransport, err := quic.NewTransport(clientKey, newConnManager(t), nil, nil, nil) + clientTransport = wrapTransport(clientTransport, tc.clientCookie, logger) + require.NoError(t, err) + defer clientTransport.(io.Closer).Close() + + c, err := clientTransport.Dial(context.Background(), ln.Multiaddr(), serverID) + if tc.dialError { + require.Error(t, err) + } else { + require.NoError(t, err) + s, err := c.OpenStream(context.Background()) + require.NoError(t, err) + defer s.Close() + _, err = s.Write([]byte{10, 20, 30, 40}) + require.NoError(t, err) + buf := make([]byte, 4) + _, err = io.ReadFull(s, buf) + if tc.readError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, buf, []byte{11, 22, 33, 44}) + require.NoError(t, eg.Wait()) + } + } + }) + } +} diff --git a/p2p/host.go b/p2p/host.go index 05c6b53821..8ea70e3f20 100644 --- a/p2p/host.go +++ b/p2p/host.go @@ -2,16 +2,20 @@ package p2p import ( "context" + "errors" "fmt" "time" lp2plog "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p" + ccmgr "github.com/libp2p/go-libp2p/core/connmgr" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/pnet" "github.com/libp2p/go-libp2p/core/protocol" "github.com/libp2p/go-libp2p/core/transport" + "github.com/libp2p/go-libp2p/p2p/host/autorelay" "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" "github.com/libp2p/go-libp2p/p2p/muxer/yamux" @@ -19,19 +23,22 @@ import ( tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader" "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay" "github.com/libp2p/go-libp2p/p2p/security/noise" + quic "github.com/libp2p/go-libp2p/p2p/transport/quic" + "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" "github.com/libp2p/go-libp2p/p2p/transport/tcp" "github.com/multiformats/go-multiaddr" "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" "github.com/spacemeshos/go-spacemesh/log" + "github.com/spacemeshos/go-spacemesh/p2p/handshake" p2pmetrics "github.com/spacemeshos/go-spacemesh/p2p/metrics" ) // DefaultConfig config. func DefaultConfig() Config { return Config{ - Listen: "/ip4/0.0.0.0/tcp/7513", + Listen: MustParseAddresses("/ip4/0.0.0.0/tcp/7513"), Flood: false, MinPeers: 20, LowPeers: 40, @@ -44,7 +51,19 @@ func DefaultConfig() Config { EnableHolepunching: true, InboundFraction: 0.8, OutboundFraction: 1.1, - RelayServer: RelayServer{TTL: 20 * time.Minute, Reservations: 512}, + RelayServer: RelayServer{ + TTL: 20 * time.Minute, + Reservations: 512, + ConnDurationLimit: 2 * time.Minute, + ConnDataLimit: 1 << 17, // 128K + + MaxCircuits: 16, + BufferSize: 2048, + + MaxReservationsPerPeer: 4, + MaxReservationsPerIP: 8, + MaxReservationsPerASN: 32, + }, IP4Blocklist: []string{ // localhost "127.0.0.0/8", @@ -67,6 +86,10 @@ func DefaultConfig() Config { GossipQueueSize: 50000, GossipValidationThrottle: 50000, GossipAtxValidationThrottle: 50000, + PingInterval: time.Second, + EnableTCPTransport: true, + EnableQUICTransport: false, + AdvertiseInterval: time.Minute, } } @@ -83,43 +106,73 @@ type Config struct { MaxMessageSize int // see https://lwn.net/Articles/542629/ for reuseport explanation - DisableReusePort bool `mapstructure:"disable-reuseport"` - DisableNatPort bool `mapstructure:"disable-natport"` - DisableConnectionManager bool `mapstructure:"disable-connection-manager"` - DisableResourceManager bool `mapstructure:"disable-resource-manager"` - DisableDHT bool `mapstructure:"disable-dht"` - Flood bool `mapstructure:"flood"` - Listen string `mapstructure:"listen"` - Bootnodes []string `mapstructure:"bootnodes"` - Direct []string `mapstructure:"direct"` - MinPeers int `mapstructure:"min-peers"` - LowPeers int `mapstructure:"low-peers"` - HighPeers int `mapstructure:"high-peers"` - InboundFraction float64 `mapstructure:"inbound-fraction"` - OutboundFraction float64 `mapstructure:"outbound-fraction"` - AutoscalePeers bool `mapstructure:"autoscale-peers"` - AdvertiseAddress string `mapstructure:"advertise-address"` - AcceptQueue int `mapstructure:"p2p-accept-queue"` - Metrics bool `mapstructure:"p2p-metrics"` - Bootnode bool `mapstructure:"p2p-bootnode"` - ForceReachability string `mapstructure:"p2p-reachability"` - EnableHolepunching bool `mapstructure:"p2p-holepunching"` - PrivateNetwork bool `mapstructure:"p2p-private-network"` - RelayServer RelayServer `mapstructure:"relay-server"` - IP4Blocklist []string `mapstructure:"ip4-blocklist"` - IP6Blocklist []string `mapstructure:"ip6-blocklist"` - GossipQueueSize int `mapstructure:"gossip-queue-size"` - GossipValidationThrottle int `mapstructure:"gossip-validation-throttle"` - GossipAtxValidationThrottle int `mapstructure:"gossip-atx-validation-throttle"` + DisableReusePort bool `mapstructure:"disable-reuseport"` + DisableNatPort bool `mapstructure:"disable-natport"` + DisableConnectionManager bool `mapstructure:"disable-connection-manager"` + DisableResourceManager bool `mapstructure:"disable-resource-manager"` + DisableDHT bool `mapstructure:"disable-dht"` + Flood bool `mapstructure:"flood"` + Listen AddressList `mapstructure:"listen"` + Bootnodes []string `mapstructure:"bootnodes"` + Direct []string `mapstructure:"direct"` + MinPeers int `mapstructure:"min-peers"` + LowPeers int `mapstructure:"low-peers"` + HighPeers int `mapstructure:"high-peers"` + InboundFraction float64 `mapstructure:"inbound-fraction"` + OutboundFraction float64 `mapstructure:"outbound-fraction"` + AutoscalePeers bool `mapstructure:"autoscale-peers"` + AdvertiseAddress AddressList `mapstructure:"advertise-address"` + AcceptQueue int `mapstructure:"p2p-accept-queue"` + Metrics bool `mapstructure:"p2p-metrics"` + Bootnode bool `mapstructure:"p2p-bootnode"` + ForceReachability string `mapstructure:"p2p-reachability"` + ForceDHTServer bool `mapstructure:"force-dht-server"` + EnableHolepunching bool `mapstructure:"p2p-holepunching"` + PrivateNetwork bool `mapstructure:"p2p-private-network"` + RelayServer RelayServer `mapstructure:"relay-server"` + IP4Blocklist []string `mapstructure:"ip4-blocklist"` + IP6Blocklist []string `mapstructure:"ip6-blocklist"` + GossipQueueSize int `mapstructure:"gossip-queue-size"` + GossipValidationThrottle int `mapstructure:"gossip-validation-throttle"` + GossipAtxValidationThrottle int `mapstructure:"gossip-atx-validation-throttle"` + PingPeers []string `mapstructure:"ping-peers"` + PingInterval time.Duration `mapstructure:"ping-interval"` + Relay bool `mapstructure:"relay"` + StaticRelays []string `mapstructure:"static-relays"` + EnableTCPTransport bool `mapstructure:"enable-tcp-transport"` + EnableQUICTransport bool `mapstructure:"enable-quic-transport"` + EnableRoutingDiscovery bool `mapstructure:"enable-routing-discovery"` + RoutingDiscoveryAdvertise bool `mapstructure:"routing-discovery-advertise"` + AdvertiseInterval time.Duration `mapstructure:"advertise-interval"` } type RelayServer struct { - Enable bool `mapstructure:"enable"` - Reservations int `mapstructure:"reservations"` - TTL time.Duration `mapstructure:"ttl"` + Enable bool `mapstructure:"enable"` + Reservations int `mapstructure:"reservations"` + TTL time.Duration `mapstructure:"ttl"` + ConnDurationLimit time.Duration `mapstructure:"conn-duration-limit"` + ConnDataLimit int64 `mapstructure:"conn-data-limit"` + MaxCircuits int `mapstructure:"max-circuits"` + BufferSize int `mapstructure:"buffer-size"` + MaxReservationsPerPeer int `mapstructure:"max-reservations-per-peer"` + MaxReservationsPerIP int `mapstructure:"max-reservations-per-ip"` + MaxReservationsPerASN int `mapstructure:"max-reservations-per-asn"` } func (cfg *Config) Validate() error { + if !cfg.EnableTCPTransport && !cfg.EnableQUICTransport { + return errors.New("no transports enabled") + } + + if !cfg.Relay { + if cfg.RelayServer.Enable { + return errors.New("cannot enable relay server without enabling relay") + } + if len(cfg.StaticRelays) != 0 { + return errors.New("cannot specify static-relays without enabling relay") + } + } + if len(cfg.ForceReachability) > 0 { if cfg.ForceReachability != PublicReachability && cfg.ForceReachability != PrivateReachability { @@ -128,12 +181,7 @@ func (cfg *Config) Validate() error { ) } } - if len(cfg.AdvertiseAddress) > 0 { - _, err := multiaddr.NewMultiaddr(cfg.AdvertiseAddress) - if err != nil { - return fmt.Errorf("address %s is not a valid multiaddr %w", cfg.AdvertiseAddress, err) - } - } + return nil } @@ -143,6 +191,7 @@ func New( logger log.Log, cfg Config, prologue []byte, + quicNetCookie handshake.NetworkCookie, opts ...Opt, ) (*Host, error) { if err := cfg.Validate(); err != nil { @@ -199,62 +248,101 @@ func New( g.direct = directMap lopts := []libp2p.Option{ libp2p.Identity(key), - libp2p.ListenAddrStrings(cfg.Listen), + libp2p.ListenAddrs(cfg.Listen...), libp2p.UserAgent("go-spacemesh"), - libp2p.Transport( - func(upgrader transport.Upgrader, rcmgr network.ResourceManager) (transport.Transport, error) { - opts := []tcp.Option{} - if cfg.DisableReusePort { - opts = append(opts, tcp.DisableReuseport()) - } - if cfg.Metrics { - opts = append(opts, tcp.WithMetrics()) - } - return tcp.NewTCPTransport(upgrader, rcmgr, opts...) - }, - ), - libp2p.Security( - noise.ID, - func(id protocol.ID, privkey crypto.PrivKey, muxers []tptu.StreamMuxer) (*noise.SessionTransport, error) { - tp, err := noise.New(id, privkey, muxers) - if err != nil { - return nil, err - } - return tp.WithSessionOptions(noise.Prologue(prologue)) - }, - ), libp2p.Muxer("/yamux/1.0.0", &streamer), libp2p.Peerstore(ps), libp2p.BandwidthReporter(p2pmetrics.NewBandwidthCollector()), libp2p.EnableNATService(), libp2p.ConnectionGater(g), - libp2p.Ping(false), + } + if cfg.EnableTCPTransport { + lopts = append(lopts, + libp2p.Transport( + func(upgrader transport.Upgrader, rcmgr network.ResourceManager) (transport.Transport, error) { + opts := []tcp.Option{} + if cfg.DisableReusePort { + opts = append(opts, tcp.DisableReuseport()) + } + if cfg.Metrics { + opts = append(opts, tcp.WithMetrics()) + } + return tcp.NewTCPTransport(upgrader, rcmgr, opts...) + }, + ), + libp2p.Security( + noise.ID, + func(id protocol.ID, privkey crypto.PrivKey, muxers []tptu.StreamMuxer) (*noise.SessionTransport, error) { + tp, err := noise.New(id, privkey, muxers) + if err != nil { + return nil, err + } + return tp.WithSessionOptions(noise.Prologue(prologue)) + }, + ), + ) + } + if cfg.EnableQUICTransport { + lopts = append(lopts, + libp2p.Transport( + func(key crypto.PrivKey, connManager *quicreuse.ConnManager, psk pnet.PSK, + gater ccmgr.ConnectionGater, + rcmgr network.ResourceManager, + ) (transport.Transport, error) { + tr, err := quic.NewTransport(key, connManager, psk, gater, rcmgr) + if err != nil { + return nil, err + } + return handshake.MaybeWrapTransport(tr, quicNetCookie, + handshake.WithLog(logger)), nil + }), + ) } if !cfg.DisableConnectionManager { lopts = append(lopts, libp2p.ConnectionManager(cm)) } if len(cfg.AdvertiseAddress) > 0 { - addr, err := multiaddr.NewMultiaddr(cfg.AdvertiseAddress) - if err != nil { - panic(err) // validated in config - } lopts = append( lopts, libp2p.AddrsFactory(func([]multiaddr.Multiaddr) []multiaddr.Multiaddr { - return []multiaddr.Multiaddr{addr} + return cfg.AdvertiseAddress }), ) } if cfg.EnableHolepunching { - lopts = append(lopts, - libp2p.EnableHolePunching(), - libp2p.EnableAutoRelayWithStaticRelays(bootnodes)) + lopts = append(lopts, libp2p.EnableHolePunching()) } - if cfg.RelayServer.Enable { - resources := relay.DefaultResources() - resources.MaxReservations = cfg.RelayServer.Reservations - resources.ReservationTTL = cfg.RelayServer.TTL - lopts = append(lopts, libp2p.EnableRelayService(relay.WithResources(resources))) + if cfg.Relay { + if cfg.RelayServer.Enable { + resources := relay.DefaultResources() + resources.Limit.Duration = cfg.RelayServer.ConnDurationLimit + resources.Limit.Data = cfg.RelayServer.ConnDataLimit + resources.ReservationTTL = cfg.RelayServer.TTL + resources.MaxReservations = cfg.RelayServer.Reservations + resources.MaxCircuits = cfg.RelayServer.MaxCircuits + resources.BufferSize = cfg.RelayServer.BufferSize + resources.MaxReservationsPerPeer = cfg.RelayServer.MaxReservationsPerPeer + resources.MaxReservationsPerIP = cfg.RelayServer.MaxReservationsPerIP + resources.MaxReservationsPerASN = cfg.RelayServer.MaxReservationsPerASN + lopts = append(lopts, libp2p.EnableRelayService(relay.WithResources(resources))) + } + + lopts = append(lopts, libp2p.EnableRelay()) + if len(cfg.StaticRelays) != 0 { + relays, err := parseIntoAddr(cfg.StaticRelays) + if err != nil { + return nil, err + } + lopts = append(lopts, libp2p.EnableAutoRelayWithStaticRelays(relays)) + } else if cfg.EnableRoutingDiscovery { + peerSrc, relayCh := relayPeerSource(logger) + lopts = append(lopts, libp2p.EnableAutoRelayWithPeerSource(peerSrc)) + opts = append(opts, WithRelayCandidateChannel(relayCh)) + } else { + lopts = append(lopts, libp2p.EnableAutoRelayWithStaticRelays(bootnodes)) + } + } else { + lopts = append(lopts, libp2p.DisableRelay()) } if cfg.ForceReachability == PublicReachability { lopts = append(lopts, libp2p.ForceReachabilityPublic()) @@ -345,3 +433,31 @@ func parseIntoAddr(nodes []string) ([]peer.AddrInfo, error) { } return addrs, nil } + +func relayPeerSource(logger log.Logger) (autorelay.PeerSource, chan<- peer.AddrInfo) { + relayCandidateCh := make(chan peer.AddrInfo) + return func(ctx context.Context, num int) <-chan peer.AddrInfo { + r := make(chan peer.AddrInfo) + go func() { + defer close(r) + for ; num != 0; num-- { + select { + case addrInfo, ok := <-relayCandidateCh: + if !ok { + return + } + select { + case r <- addrInfo: + logger.With().Debug("discovered relay candidate", + log.Stringer("addrInfo", addrInfo)) + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } + }() + return r + }, relayCandidateCh +} diff --git a/p2p/host_test.go b/p2p/host_test.go index 2cd39ffbf5..4d00e1a987 100644 --- a/p2p/host_test.go +++ b/p2p/host_test.go @@ -11,24 +11,66 @@ import ( ) func TestPrologue(t *testing.T) { - cfg1 := DefaultConfig() - cfg1.DataDir = t.TempDir() - cfg1.Listen = "/ip4/127.0.0.1/tcp/0" - cfg2 := DefaultConfig() - cfg2.DataDir = t.TempDir() - cfg2.Listen = "/ip4/127.0.0.1/tcp/0" - - h1, err := New(context.Background(), logtest.New(t), cfg1, []byte("red")) - require.NoError(t, err) - t.Cleanup(func() { h1.Stop() }) - - h2, err := New(context.Background(), logtest.New(t), cfg2, []byte("blue")) - require.NoError(t, err) - t.Cleanup(func() { h2.Stop() }) - - err = h1.Connect(context.Background(), peer.AddrInfo{ - ID: h2.ID(), - Addrs: h2.Addrs(), - }) - require.ErrorContains(t, err, "failed to negotiate security protocol") + type testcase struct { + desc string + listen AddressList + enableQUIC bool + errStr string + } + testcases := []testcase{ + { + desc: "tcp", + listen: MustParseAddresses("/ip4/127.0.0.1/tcp/0"), + errStr: "failed to negotiate security protocol", + }, + { + desc: "quic", + listen: MustParseAddresses("/ip4/0.0.0.0/udp/0/quic-v1"), + enableQUIC: true, + errStr: "cookie mismatch", + }, + } + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + cfg1 := DefaultConfig() + cfg1.DataDir = t.TempDir() + cfg1.Listen = tc.listen + cfg1.EnableQUICTransport = tc.enableQUIC + cfg2 := DefaultConfig() + cfg2.DataDir = t.TempDir() + cfg2.Listen = tc.listen + cfg2.EnableQUICTransport = tc.enableQUIC + cfg3 := DefaultConfig() + cfg3.DataDir = t.TempDir() + cfg3.Listen = tc.listen + cfg3.EnableQUICTransport = tc.enableQUIC + + nc1 := []byte("red") + h1, err := New(context.Background(), logtest.New(t), cfg1, nc1, nc1) + require.NoError(t, err) + t.Cleanup(func() { h1.Stop() }) + + nc2 := []byte("blue") + h2, err := New(context.Background(), logtest.New(t), cfg2, nc2, nc2) + require.NoError(t, err) + t.Cleanup(func() { h2.Stop() }) + + nc3 := []byte("red") + h3, err := New(context.Background(), logtest.New(t), cfg3, nc3, nc3) + require.NoError(t, err) + t.Cleanup(func() { h3.Stop() }) + + err = h1.Connect(context.Background(), peer.AddrInfo{ + ID: h2.ID(), + Addrs: h2.Addrs(), + }) + require.ErrorContains(t, err, tc.errStr) + + err = h1.Connect(context.Background(), peer.AddrInfo{ + ID: h3.ID(), + Addrs: h3.Addrs(), + }) + require.NoError(t, err) + }) + } } diff --git a/p2p/ping.go b/p2p/ping.go new file mode 100644 index 0000000000..c421f96963 --- /dev/null +++ b/p2p/ping.go @@ -0,0 +1,175 @@ +package p2p + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/routing" + "github.com/libp2p/go-libp2p/p2p/protocol/ping" + ma "github.com/multiformats/go-multiaddr" + "go.uber.org/zap" + "golang.org/x/sync/errgroup" +) + +const ( + pingProtectTag = "spacemesh-ping" +) + +type pingStat struct { + numSuccess int + numFail int +} + +type Ping struct { + sync.Mutex + logger *zap.Logger + h host.Host + peers []peer.ID + pr routing.PeerRouting + interval time.Duration + stats map[peer.ID]*pingStat + cancel context.CancelFunc + eg errgroup.Group +} + +type PingOpt func(p *Ping) + +func WithPingInterval(d time.Duration) PingOpt { + return func(p *Ping) { + p.interval = d + } +} + +func NewPing(logger *zap.Logger, h host.Host, peers []peer.ID, pr routing.PeerRouting, opts ...PingOpt) *Ping { + p := &Ping{ + logger: logger, + h: h, + peers: peers, + pr: pr, + stats: make(map[peer.ID]*pingStat), + interval: time.Second, + } + for _, opt := range opts { + opt(p) + } + return p +} + +func (p *Ping) Start() { + if p.cancel != nil { + return + } + var startCtx context.Context + startCtx, p.cancel = context.WithCancel(context.Background()) + for _, peer := range p.peers { + p.startForPeer(startCtx, peer) + } +} + +func (p *Ping) Stop() { + if p.cancel == nil { + return + } + p.cancel() + p.cancel = nil + p.eg.Wait() +} + +func (p *Ping) doPing(ctx context.Context, peerID peer.ID) (<-chan ping.Result, error) { + _, err := p.pr.FindPeer(ctx, peerID) + if err != nil { + return nil, fmt.Errorf("failed to find peer %s: %w", peerID, err) + } + + return ping.Ping(ctx, p.h, peerID), nil +} + +// runForPeer runs ping for the specific peer till an error occurs +// or the context is canceled. +func (p *Ping) runForPeer(ctx context.Context, peerID peer.ID, addrs []ma.Multiaddr) error { + // go-libp2p Ping tends to stop working after an error is received on the channel. + // This behavior is probably not intended and may change later. + // So, we create a child context here and cancel it when we receive an error + // on the channel returned by Ping, and then after a delay we restart + // Ping for this peer. + pingCtx, cancel := context.WithCancel(ctx) + defer cancel() + ch, err := p.doPing(pingCtx, peerID) + if err != nil { + return err + } + + for r := range ch { + p.record(peerID, r.Error == nil) + if r.Error != nil { + return r.Error + } else { + p.logger.Info("PING succeeded", + zap.Stringer("peer", peerID), + zap.Any("addrs", addrs), + zap.Duration("rtt", r.RTT)) + } + select { + case <-ctx.Done(): + return nil + case <-time.After(p.interval): + } + } + + return nil +} + +func (p *Ping) startForPeer(ctx context.Context, peerID peer.ID) { + p.h.ConnManager().Protect(peerID, pingProtectTag) + p.eg.Go(func() error { + for { + var addrs []ma.Multiaddr + for _, c := range p.h.Network().ConnsToPeer(peerID) { + addrs = append(addrs, c.RemoteMultiaddr()) + } + err := p.runForPeer(ctx, peerID, addrs) + if errors.Is(err, context.Canceled) { + return nil + } + p.logger.Error("PING failed", + zap.Stringer("peer", peerID), + zap.Any("addrs", addrs), + zap.Error(err)) + select { + case <-ctx.Done(): + return nil + case <-time.After(p.interval): + } + } + }) +} + +func (p *Ping) record(peerID peer.ID, success bool) { + p.Lock() + defer p.Unlock() + st := p.stats[peerID] + if st == nil { + st = &pingStat{} + p.stats[peerID] = st + } + if success { + p.stats[peerID].numSuccess++ + } else { + p.stats[peerID].numFail++ + } +} + +func (p *Ping) Stats(peerID peer.ID) (numSuccess, numFail int) { + p.Lock() + defer p.Unlock() + st, found := p.stats[peerID] + if !found { + return 0, 0 + } + return st.numSuccess, st.numFail +} diff --git a/p2p/ping_test.go b/p2p/ping_test.go new file mode 100644 index 0000000000..ad53bf41fb --- /dev/null +++ b/p2p/ping_test.go @@ -0,0 +1,71 @@ +package p2p + +import ( + "context" + "testing" + "time" + + "github.com/libp2p/go-libp2p/core/peer" + "github.com/stretchr/testify/require" + + "github.com/spacemeshos/go-spacemesh/log/logtest" +) + +func TestPing(t *testing.T) { + type testcase struct { + desc string + listen AddressList + enableQUIC bool + } + + testcases := []testcase{ + { + desc: "tcp", + listen: MustParseAddresses("/ip4/127.0.0.1/tcp/0"), + }, + { + desc: "quic", + listen: MustParseAddresses("/ip4/0.0.0.0/udp/0/quic-v1"), + enableQUIC: true, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + cfg1 := DefaultConfig() + cfg1.DataDir = t.TempDir() + cfg1.Listen = tc.listen + cfg1.EnableQUICTransport = tc.enableQUIC + nc := []byte("foobar") + h1, err := New(context.Background(), logtest.New(t), cfg1, nc, nc) + require.NoError(t, err) + h1.discovery.Start() + t.Cleanup(func() { h1.Stop() }) + + cfg2 := DefaultConfig() + cfg2.DataDir = t.TempDir() + cfg2.Listen = tc.listen + cfg2.EnableQUICTransport = tc.enableQUIC + cfg2.PingPeers = []string{h1.ID().String()} + h2, err := New(context.Background(), logtest.New(t), cfg2, nc, nc) + require.NoError(t, err) + h2.discovery.Start() + t.Cleanup(func() { h2.Stop() }) + + err = h2.Connect(context.Background(), peer.AddrInfo{ + ID: h1.ID(), + Addrs: h1.Addrs(), + }) + require.NoError(t, err) + + h2.Ping().Start() + t.Cleanup(h2.Ping().Stop) + + require.Eventually(t, func() bool { + numSuccess, numFail := h2.Ping().Stats(h1.ID()) + t.Logf("ping stats: success %d fail %d", numSuccess, numFail) + return numSuccess > 1 + }, 10*time.Second, 100*time.Millisecond, "waiting for ping to succeed") + }) + } +} diff --git a/p2p/upgrade.go b/p2p/upgrade.go index cd158aeb8b..3ddd029c22 100644 --- a/p2p/upgrade.go +++ b/p2p/upgrade.go @@ -4,14 +4,19 @@ import ( "context" "errors" "fmt" + "slices" "sync" "time" lp2plog "github.com/ipfs/go-log/v2" + dht "github.com/libp2p/go-libp2p-kad-dht" + "github.com/libp2p/go-libp2p/core/event" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" + "github.com/libp2p/go-libp2p/p2p/host/eventbus" + ma "github.com/multiformats/go-multiaddr" "go.uber.org/zap/zapcore" "golang.org/x/sync/errgroup" @@ -64,6 +69,12 @@ func WithBootnodes(bootnodes map[peer.ID]struct{}) Opt { } } +func WithRelayCandidateChannel(relayCh chan<- peer.AddrInfo) Opt { + return func(fh *Host) { + fh.relayCh = relayCh + } +} + // Host is a conveniency wrapper for all p2p related functionality required to run // a full spacemesh node. type Host struct { @@ -86,6 +97,21 @@ type Host struct { discovery *discovery.Discovery direct, bootnode map[peer.ID]struct{} + relayCh chan<- peer.AddrInfo + + natTypeSub event.Subscription + natType struct { + sync.Mutex + udpNATType network.NATDeviceType + tcpNATType network.NATDeviceType + } + reachSub event.Subscription + reachability struct { + sync.Mutex + value network.Reachability + } + + ping *Ping } // Upgrade creates Host instance from host.Host. @@ -112,6 +138,7 @@ func Upgrade(h host.Host, opts ...Opt) (*Host, error) { } for _, peer := range direct { h.ConnManager().Protect(peer.ID, "direct") + // TBD: also protect ping } if fh.PubSub, err = pubsub.New(fh.ctx, fh.logger, h, pubsub.Config{ Flood: cfg.Flood, @@ -130,6 +157,7 @@ func Upgrade(h host.Host, opts ...Opt) (*Host, error) { discovery.WithDir(cfg.DataDir), discovery.WithBootnodes(bootnodes), discovery.WithLogger(fh.logger.Zap()), + discovery.WithAdvertiseInterval(fh.cfg.AdvertiseInterval), } if cfg.PrivateNetwork { dopts = append(dopts, discovery.Private()) @@ -137,9 +165,10 @@ func Upgrade(h host.Host, opts ...Opt) (*Host, error) { if cfg.DisableDHT { dopts = append(dopts, discovery.DisableDHT()) } - if cfg.Bootnode { - dopts = append(dopts, discovery.Server()) + if cfg.Bootnode || cfg.ForceDHTServer { + dopts = append(dopts, discovery.WithMode(dht.ModeServer)) } else { + dopts = append(dopts, discovery.WithMode(dht.ModeAutoServer)) backup, err := loadPeers(cfg.DataDir) if err != nil { fh.logger.With().Warning("failed to to load backup peers", log.Err(err)) @@ -147,6 +176,16 @@ func Upgrade(h host.Host, opts ...Opt) (*Host, error) { dopts = append(dopts, discovery.WithBackup(backup)) } } + if fh.relayCh != nil { + dopts = append(dopts, discovery.WithRelayCandidateChannel(fh.relayCh)) + } + if fh.cfg.EnableRoutingDiscovery { + dopts = append(dopts, discovery.EnableRoutingDiscovery()) + } + if fh.cfg.RoutingDiscoveryAdvertise { + dopts = append(dopts, discovery.AdvertiseForPeerDiscovery()) + } + dhtdisc, err := discovery.New(fh, dopts...) if err != nil { return nil, err @@ -162,6 +201,31 @@ func Upgrade(h host.Host, opts ...Opt) (*Host, error) { }, }) } + + var peers []peer.ID + for _, p := range cfg.PingPeers { + peerID, err := peer.Decode(p) + if err != nil { + fh.logger.With().Warning("ignoring invalid ping peer", log.Err(err)) + continue + } + peers = append(peers, peerID) + } + if len(peers) != 0 { + fh.ping = NewPing(fh.logger.Zap(), fh, peers, fh.discovery, WithPingInterval(fh.cfg.PingInterval)) + } + + fh.natTypeSub, err = fh.EventBus().Subscribe(new(event.EvtNATDeviceTypeChanged), + eventbus.Name("nat type changed (Host)")) + if err != nil { + return nil, fmt.Errorf("failed to subscribe to reachability NAT type event: %s", err) + } + fh.reachSub, err = fh.EventBus().Subscribe(new(event.EvtLocalReachabilityChanged), + eventbus.Name("reachability changed (Host)")) + if err != nil { + return nil, fmt.Errorf("failed to subscribe to reachability NAT type event: %s", err) + } + return fh, nil } @@ -207,6 +271,75 @@ func (fh *Host) ConnectedPeerInfo(id peer.ID) *PeerInfo { } } +// ListenAddresses returns the addresses on which this host listens. +func (fh *Host) ListenAddresses() []ma.Multiaddr { + return fh.Network().ListenAddresses() +} + +// KnownAddresses returns the addresses by which the peers know this one. +func (fh *Host) KnownAddresses() []ma.Multiaddr { + return fh.Network().Peerstore().Addrs(fh.ID()) +} + +// NATDeviceType returns NATDeviceType returns the NAT device types for +// UDP and TCP so far for this host. +func (fh *Host) NATDeviceType() (udpNATType, tcpNATType network.NATDeviceType) { + fh.natType.Lock() + defer fh.natType.Unlock() + return fh.natType.udpNATType, fh.natType.tcpNATType +} + +// Reachability returns reachability of the host (public, private, unknown). +func (fh *Host) Reachability() network.Reachability { + fh.reachability.Lock() + defer fh.reachability.Unlock() + return fh.reachability.value +} + +// DHTServerEnabled returns true if the server has DHT running in server mode. +func (fh *Host) DHTServerEnabled() bool { + return slices.Contains(fh.Mux().Protocols(), discovery.ProtocolID) +} + +// NeedPeerDiscovery returns true if it makes sense to do additional +// discovery of non-DHT (NATed) peers. +func (fh *Host) NeedPeerDiscovery() bool { + // Once we get LowPeers, the discovery mechanism is no longer + // needed + if len(fh.Network().Peers()) >= fh.cfg.LowPeers { + return false + } + + // Check if this is a public-reachable node which can reach + // nodes behind Cone NAT + if fh.Reachability() == network.ReachabilityPublic { + return true + } + + // Check if we have Cone NAT for either TCP or UDP. If so, + // hole punching should work for other NATed nodes. Also, in + // case of an unknown NAT type, assume there's chance at hole + // punching + udpNATType, tcpNATType := fh.NATDeviceType() + if fh.cfg.EnableQUICTransport && udpNATType != network.NATDeviceTypeSymmetric { + return true + } + if fh.cfg.EnableTCPTransport && tcpNATType != network.NATDeviceTypeSymmetric { + return true + } + + // Symmetric NAT for both TCP and UDP, hole punching will not + // work so we're not looking for NATed peers. Will only + // connect to the nodes with DHT Server mode + return false +} + +// HaveRelay returns true if this host can be used as a relay, that +// is, it supports relay service and has public reachability. +func (fh *Host) HaveRelay() bool { + return fh.cfg.RelayServer.Enable && fh.Reachability() == network.ReachabilityPublic +} + // PeerCount returns number of connected peers. func (fh *Host) PeerCount() uint64 { return uint64(len(fh.Host.Network().Peers())) @@ -217,6 +350,12 @@ func (fh *Host) PeerProtocols(p Peer) ([]protocol.ID, error) { return fh.Peerstore().GetProtocols(p) } +// Ping returns Ping structure for this Host, if any PingPeers are +// specified in the config. Otherwise, it returns nil. +func (fh *Host) Ping() *Ping { + return fh.ping +} + func (fh *Host) Start() error { fh.closed.Lock() defer fh.closed.Unlock() @@ -224,12 +363,16 @@ func (fh *Host) Start() error { return errors.New("p2p: closed") } fh.discovery.Start() + if fh.ping != nil { + fh.ping.Start() + } if !fh.cfg.Bootnode { fh.eg.Go(func() error { persist(fh.ctx, fh.logger, fh.Host, fh.cfg.DataDir, 30*time.Minute) return nil }) } + fh.eg.Go(fh.trackNetEvents) return nil } @@ -243,6 +386,8 @@ func (fh *Host) Stop() error { fh.cancel() fh.closed.closed = true fh.discovery.Stop() + fh.reachSub.Close() + fh.natTypeSub.Close() fh.eg.Wait() if err := fh.Host.Close(); err != nil { return fmt.Errorf("failed to close libp2p host: %w", err) @@ -250,3 +395,40 @@ func (fh *Host) Stop() error { lp2plog.SetPrimaryCore(zapcore.NewNopCore()) return nil } + +func (fh *Host) trackNetEvents() error { + natEvCh := fh.natTypeSub.Out() + reachEvCh := fh.reachSub.Out() + for { + select { + case ev, ok := <-natEvCh: + if !ok { + return nil + } + natEv := ev.(event.EvtNATDeviceTypeChanged) + fh.logger.With().Info("NAT type changed", + log.Stringer("transportProtocol", natEv.TransportProtocol), + log.Stringer("type", natEv.NatDeviceType)) + fh.natType.Lock() + switch natEv.TransportProtocol { + case network.NATTransportUDP: + fh.natType.udpNATType = natEv.NatDeviceType + case network.NATTransportTCP: + fh.natType.tcpNATType = natEv.NatDeviceType + } + fh.natType.Unlock() + case ev, ok := <-reachEvCh: + if !ok { + return nil + } + reachEv := ev.(event.EvtLocalReachabilityChanged) + fh.logger.With().Info("local reachability changed", + log.Stringer("reachability", reachEv.Reachability)) + fh.reachability.Lock() + fh.reachability.value = reachEv.Reachability + fh.reachability.Unlock() + case <-fh.ctx.Done(): + return fh.ctx.Err() + } + } +} From 8d53d148eaa5ce8b692232cd8fce69267185f903 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 14:04:55 +0000 Subject: [PATCH 39/48] build(deps): Bump google.golang.org/grpc from 1.60.0 to 1.60.1 (#5371) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.60.0 to 1.60.1. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c2c0120929..c852b396ec 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,7 @@ require ( golang.org/x/sync v0.5.0 golang.org/x/time v0.5.0 google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 - google.golang.org/grpc v1.60.0 + google.golang.org/grpc v1.60.1 google.golang.org/protobuf v1.31.0 k8s.io/api v0.29.0 k8s.io/apimachinery v0.29.0 diff --git a/go.sum b/go.sum index bc80bd6e01..9b5f237f82 100644 --- a/go.sum +++ b/go.sum @@ -1076,8 +1076,8 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k= -google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= +google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 12cea5e95bba530476c09d52a28641d2db2f06da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 09:46:12 +0000 Subject: [PATCH 40/48] build(deps): Bump github.com/quic-go/quic-go from 0.39.4 to 0.40.1 (#5381) Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.39.4 to 0.40.1. --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index c852b396ec..890793bab1 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a github.com/prometheus/client_golang v1.17.0 github.com/prometheus/common v0.45.0 - github.com/quic-go/quic-go v0.39.4 + github.com/quic-go/quic-go v0.40.1 github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/seehuhn/mt19937 v1.0.0 github.com/spacemeshos/api/release/go v1.25.0 @@ -179,7 +179,7 @@ require ( github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/procfs v0.11.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.4 // indirect + github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/quic-go/webtransport-go v0.6.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 9b5f237f82..439c94e316 100644 --- a/go.sum +++ b/go.sum @@ -560,10 +560,10 @@ github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwa github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= -github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= -github.com/quic-go/quic-go v0.39.4 h1:PelfiuG7wXEffUT2yceiqz5V6Pc0TA5ruOd1LcmFc1s= -github.com/quic-go/quic-go v0.39.4/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q= +github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= +github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q= +github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c= github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY= github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= From 6dacda075c8e5d657abe4f8d95e4abdd8b643239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Wed, 20 Dec 2023 10:39:31 +0000 Subject: [PATCH 41/48] Avoid processing same ATX in parallel (#5379) ## Motivation There is no mechanism preventing duplicated processing of ATX in parallel. An ATX might be gossiped multiple times while the same one is already being processed. Related issue: https://github.com/spacemeshos/go-spacemesh/issues/4426 ## Changes The ATX handler now registers the ATXID when it starts processing it. The subsequent calls to `handleATX()` will find that the handler is already processing this ATX and will register themself for the result, which is sent over a channel after the ATX processing is finished. ## Test Plan Added a UT in which an ATX is gossiped 10x in parallel. The expectation is that it's processed only once. --- activation/handler.go | 42 +++++++++++++++++++++-- activation/handler_test.go | 69 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/activation/handler.go b/activation/handler.go index 55b7b90907..9fd4222778 100644 --- a/activation/handler.go +++ b/activation/handler.go @@ -49,6 +49,11 @@ type Handler struct { mu sync.Mutex fetcher system.Fetcher poetCfg PoetConfig + + // inProgress map gathers ATXs that are currently being processed. + // It's used to avoid processing the same ATX twice. + inProgress map[types.ATXID][]chan error + inProgressMu sync.Mutex } // NewHandler returns a data handler for ATX. @@ -83,6 +88,8 @@ func NewHandler( beacon: beacon, tortoise: tortoise, poetCfg: poetCfg, + + inProgress: make(map[types.ATXID][]chan error), } } @@ -502,12 +509,43 @@ func (h *Handler) handleAtx(ctx context.Context, expHash types.Hash32, peer p2p. if err := codec.Decode(msg, &atx); err != nil { return fmt.Errorf("%w: %w", errMalformedData, err) } - atx.SetReceived(receivedTime.Local()) if err := atx.Initialize(); err != nil { return fmt.Errorf("failed to derive ID from atx: %w", err) } + // Check if processing is already in progress + h.inProgressMu.Lock() + if sub, ok := h.inProgress[atx.ID()]; ok { + ch := make(chan error, 1) + h.inProgress[atx.ID()] = append(sub, ch) + h.inProgressMu.Unlock() + h.log.WithContext(ctx).With().Debug("atx is already being processed. waiting for result", atx.ID()) + select { + case err := <-ch: + h.log.WithContext(ctx).With().Debug("atx processed in other task", atx.ID(), log.Err(err)) + return err + case <-ctx.Done(): + return ctx.Err() + } + } + + h.inProgress[atx.ID()] = []chan error{} + h.inProgressMu.Unlock() + h.log.WithContext(ctx).With().Info("handling incoming atx", atx.ID(), log.Int("size", len(msg))) + + err := h.processAtx(ctx, expHash, peer, atx) + h.inProgressMu.Lock() + defer h.inProgressMu.Unlock() + for _, ch := range h.inProgress[atx.ID()] { + ch <- err + close(ch) + } + delete(h.inProgress, atx.ID()) + return err +} + +func (h *Handler) processAtx(ctx context.Context, expHash types.Hash32, peer p2p.Peer, atx types.ActivationTx) error { if !h.edVerifier.Verify(signing.ATX, atx.SmesherID, atx.SignedBytes(), atx.Signature) { return fmt.Errorf("failed to verify atx signature: %w", errMalformedData) } @@ -544,7 +582,7 @@ func (h *Handler) handleAtx(ctx context.Context, expHash types.Hash32, peer p2p. return fmt.Errorf("cannot process atx %v: %w", atx.ShortString(), err) } events.ReportNewActivation(vAtx) - h.log.WithContext(ctx).With().Info("new atx", log.Inline(vAtx), log.Int("size", len(msg))) + h.log.WithContext(ctx).With().Info("new atx", log.Inline(vAtx)) return nil } diff --git a/activation/handler_test.go b/activation/handler_test.go index 3879bcd795..2fbe20cd56 100644 --- a/activation/handler_test.go +++ b/activation/handler_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "golang.org/x/sync/errgroup" "github.com/spacemeshos/go-spacemesh/atxsdata" "github.com/spacemeshos/go-spacemesh/codec" @@ -1211,6 +1212,74 @@ func TestHandler_HandleGossipAtx(t *testing.T) { require.NoError(t, atxHdlr.HandleGossipAtx(context.Background(), "", secondData)) } +func TestHandler_HandleParallelGossipAtx(t *testing.T) { + goldenATXID := types.ATXID{2, 3, 4} + atxHdlr := newTestHandler(t, goldenATXID) + + sig, err := signing.NewEdSigner() + require.NoError(t, err) + nodeID := sig.NodeID() + nipost := newNIPostWithChallenge(t, types.HexToHash32("0x3333"), []byte{0xba, 0xbe}) + vrfNonce := types.VRFPostIndex(12345) + atx := &types.ActivationTx{ + InnerActivationTx: types.InnerActivationTx{ + NIPostChallenge: types.NIPostChallenge{ + PublishEpoch: 1, + PrevATXID: types.EmptyATXID, + PositioningATX: goldenATXID, + CommitmentATX: &goldenATXID, + InitialPost: nipost.Post, + }, + Coinbase: types.Address{2, 3, 4}, + NumUnits: 2, + NIPost: nipost, + NodeID: &nodeID, + VRFNonce: &vrfNonce, + }, + SmesherID: nodeID, + } + atx.Signature = sig.Sign(signing.ATX, atx.SignedBytes()) + atx.SetEffectiveNumUnits(atx.NumUnits) + atx.SetReceived(time.Now()) + _, err = atx.Verify(0, 2) + require.NoError(t, err) + + atxData, err := codec.Encode(atx) + require.NoError(t, err) + + atxHdlr.mclock.EXPECT().CurrentLayer().Return(atx.PublishEpoch.FirstLayer()) + atxHdlr.mValidator.EXPECT().VRFNonce(nodeID, goldenATXID, &vrfNonce, gomock.Any(), atx.NumUnits) + atxHdlr.mValidator.EXPECT().Post( + gomock.Any(), + atx.SmesherID, + goldenATXID, + atx.InitialPost, + gomock.Any(), + atx.NumUnits, + ).DoAndReturn( + func(_ context.Context, _ types.NodeID, _ types.ATXID, _ *types.Post, _ *types.PostMetadata, _ uint32) error { + time.Sleep(100 * time.Millisecond) + return nil + }, + ) + atxHdlr.mockFetch.EXPECT().RegisterPeerHashes(gomock.Any(), gomock.Any()) + atxHdlr.mockFetch.EXPECT().GetPoetProof(gomock.Any(), atx.GetPoetProofRef()) + atxHdlr.mValidator.EXPECT().InitialNIPostChallenge(&atx.NIPostChallenge, gomock.Any(), goldenATXID) + atxHdlr.mValidator.EXPECT().PositioningAtx(goldenATXID, gomock.Any(), goldenATXID, atx.PublishEpoch) + atxHdlr.mValidator.EXPECT().NIPost(gomock.Any(), nodeID, goldenATXID, atx.NIPost, gomock.Any(), atx.NumUnits) + atxHdlr.mbeacon.EXPECT().OnAtx(gomock.Any()) + atxHdlr.mtortoise.EXPECT().OnAtx(gomock.Any()) + + var eg errgroup.Group + for i := 0; i < 10; i++ { + eg.Go(func() error { + return atxHdlr.HandleGossipAtx(context.Background(), "", atxData) + }) + } + + require.NoError(t, eg.Wait()) +} + func TestHandler_HandleSyncedAtx(t *testing.T) { // Arrange goldenATXID := types.ATXID{2, 3, 4} From 96d87d6d505db683a2c395047dc9ebed170ae922 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Wed, 20 Dec 2023 14:14:48 +0000 Subject: [PATCH 42/48] Fix handling "fetcher" log level (#5368) "fetcher" key was being ignored in the "logging" section --- config/logging.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/logging.go b/config/logging.go index d132d6de3c..cd85fbe68b 100644 --- a/config/logging.go +++ b/config/logging.go @@ -35,6 +35,7 @@ type LoggerConfig struct { BlkEligibilityLoggerLevel string `mapstructure:"block-eligibility"` MeshLoggerLevel string `mapstructure:"mesh"` SyncLoggerLevel string `mapstructure:"sync"` + FetcherLoggerLevel string `mapstructure:"fetcher"` BlockOracleLevel string `mapstructure:"block-oracle"` HareOracleLoggerLevel string `mapstructure:"hare-oracle"` HareLoggerLevel string `mapstructure:"hare"` @@ -71,6 +72,7 @@ func DefaultLoggingConfig() LoggerConfig { BlkEligibilityLoggerLevel: defaultLoggingLevel.String(), MeshLoggerLevel: defaultLoggingLevel.String(), SyncLoggerLevel: defaultLoggingLevel.String(), + FetcherLoggerLevel: defaultLoggingLevel.String(), BlockOracleLevel: defaultLoggingLevel.String(), HareOracleLoggerLevel: defaultLoggingLevel.String(), HareLoggerLevel: defaultLoggingLevel.String(), From 65e36e99f29c73977255cb9f86ef93e25d5d54d7 Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Wed, 20 Dec 2023 21:16:46 +0000 Subject: [PATCH 43/48] Add no-main-override config option (#5367) This makes it possible to force "nomain" builds to run on mainnet. ## Motivation Sometimes it is necessary to try a "nomain" build with mainnet. ## Changes This adds `no-main-override` toplevel config option (bool) and also `--no-main-override` command line flag. --- CHANGELOG.md | 3 +++ cmd/root.go | 3 +++ config/config.go | 3 +++ node/node.go | 2 +- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffd9116398..25aef13914 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,9 @@ for more information on how to configure the node to work with the PoST service. section. The non-conditional changes include values/provides support on all of the nodes, which will enable DHT to function efficiently for routing discovery. +* [#5367](https://github.com/spacemeshos/go-spacemesh/pull/5367) Add `no-main-override` toplevel config option and + `--no-main-override` CLI option that makes it possible to run "nomain" builds on mainnet. + ## Release v1.2.9 ### Improvements diff --git a/cmd/root.go b/cmd/root.go index 02a43752ee..7e0c8c8313 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -82,6 +82,9 @@ func AddCommands(cmd *cobra.Command) { cmd.PersistentFlags().DurationVar(&cfg.DatabasePruneInterval, "db-prune-interval", cfg.DatabasePruneInterval, "configure interval for database pruning") + cmd.PersistentFlags().BoolVar(&cfg.NoMainOverride, "no-main-override", + cfg.NoMainOverride, "force 'nomain' builds to run on the mainnet") + /** ======================== P2P Flags ========================== **/ cmd.PersistentFlags().Var(flags.NewAddressListValue(cfg.P2P.Listen, &cfg.P2P.Listen), diff --git a/config/config.go b/config/config.go index 94efb384ed..15e8045af1 100644 --- a/config/config.go +++ b/config/config.go @@ -128,6 +128,9 @@ type BaseConfig struct { // ATXGradeDelay is used to grade ATXs for selection in tortoise active set. // See grading fuction in miner/proposals_builder.go ATXGradeDelay time.Duration `mapstructure:"atx-grade-delay"` + + // NoMainOverride forces the "nomain" builds to run on the mainnet + NoMainOverride bool `mapstructure:"no-main-override"` } type PublicMetrics struct { diff --git a/node/node.go b/node/node.go index 0f6f7fa489..cf7ac874ae 100644 --- a/node/node.go +++ b/node/node.go @@ -133,7 +133,7 @@ func GetCommand() *cobra.Command { log.JSONLog(true) } - if cmd.NoMainNet && onMainNet(conf) { + if cmd.NoMainNet && onMainNet(conf) && !conf.NoMainOverride { log.With().Fatal("this is a testnet-only build not intended for mainnet") } From 3c26d0b8236936bccbeefc798e7db42254bdfcda Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Wed, 20 Dec 2023 22:10:24 +0000 Subject: [PATCH 44/48] Make disable-connection-manager option really work (#5370) Need to provide `NullConnMgr` as the connection manager for no peer trimming to happen. This is useful for debugging problems that may be related to peer trimming by the libp2p `ConnectionManager`. --- p2p/host.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/p2p/host.go b/p2p/host.go index 8ea70e3f20..0fbaccb12f 100644 --- a/p2p/host.go +++ b/p2p/host.go @@ -205,14 +205,6 @@ func New( } lp2plog.SetPrimaryCore(logger.Core()) lp2plog.SetAllLoggers(lp2plog.LogLevel(cfg.LogLevel)) - cm, err := connmgr.NewConnManager( - cfg.LowPeers, - cfg.HighPeers, - connmgr.WithGracePeriod(cfg.GracePeersShutdown), - ) - if err != nil { - return nil, fmt.Errorf("p2p create conn mgr: %w", err) - } streamer := *yamux.DefaultTransport streamer.Config().ConnectionWriteTimeout = 25 * time.Second // should be NOT exposed in the config ps, err := pstoremem.NewPeerstore() @@ -299,7 +291,17 @@ func New( ) } if !cfg.DisableConnectionManager { + cm, err := connmgr.NewConnManager( + cfg.LowPeers, + cfg.HighPeers, + connmgr.WithGracePeriod(cfg.GracePeersShutdown), + ) + if err != nil { + return nil, fmt.Errorf("p2p create conn mgr: %w", err) + } lopts = append(lopts, libp2p.ConnectionManager(cm)) + } else { + lopts = append(lopts, libp2p.ConnectionManager(&ccmgr.NullConnMgr{})) } if len(cfg.AdvertiseAddress) > 0 { lopts = append( From 1f28eaec23f361d98b7a71ad91a0a47e44ee1ae9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:03:59 +0000 Subject: [PATCH 45/48] build(deps): Bump go.uber.org/mock from 0.3.0 to 0.4.0 (#5386) Bumps [go.uber.org/mock](https://github.com/uber/mock) from 0.3.0 to 0.4.0. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 890793bab1..cc5fd5e4c3 100644 --- a/go.mod +++ b/go.mod @@ -49,7 +49,7 @@ require ( github.com/stretchr/testify v1.8.4 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/zeebo/blake3 v0.2.3 - go.uber.org/mock v0.3.0 + go.uber.org/mock v0.4.0 go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb golang.org/x/sync v0.5.0 diff --git a/go.sum b/go.sum index 439c94e316..bd0f441873 100644 --- a/go.sum +++ b/go.sum @@ -720,8 +720,8 @@ go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpK go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= -go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= From c580fbac09987f86aa1f2d9ab8320e27d6188d04 Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Thu, 21 Dec 2023 10:37:25 +0000 Subject: [PATCH 46/48] spawn a process to download atxs hinted by a server (#5377) related: https://github.com/spacemeshos/go-spacemesh/issues/5366 this change disables sync reconciliation at the end and start of epoch, normal atx downloading works the way it was working. instead it will ask peers for atxs that are recorded in the set, shared by the server. --- config/mainnet.go | 1 + node/node.go | 15 ++++ syncer/atxsync/atxsync.go | 75 ++++++++++++++++++++ syncer/atxsync/atxsync_test.go | 126 +++++++++++++++++++++++++++++++++ syncer/atxsync/mocks/mocks.go | 78 ++++++++++++++++++++ syncer/syncer.go | 6 +- 6 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 syncer/atxsync/atxsync.go create mode 100644 syncer/atxsync/atxsync_test.go create mode 100644 syncer/atxsync/mocks/mocks.go diff --git a/config/mainnet.go b/config/mainnet.go index 6c42334c60..bc21d26410 100644 --- a/config/mainnet.go +++ b/config/mainnet.go @@ -172,6 +172,7 @@ func MainnetConfig() Config { Standalone: false, GossipDuration: 50 * time.Second, OutOfSyncThresholdLayers: 36, // 3h + DisableAtxReconciliation: true, }, Recovery: checkpoint.DefaultConfig(), Cache: datastore.DefaultConfig(), diff --git a/node/node.go b/node/node.go index cf7ac874ae..86ead1b394 100644 --- a/node/node.go +++ b/node/node.go @@ -69,6 +69,7 @@ import ( "github.com/spacemeshos/go-spacemesh/sql/localsql" dbmetrics "github.com/spacemeshos/go-spacemesh/sql/metrics" "github.com/spacemeshos/go-spacemesh/syncer" + "github.com/spacemeshos/go-spacemesh/syncer/atxsync" "github.com/spacemeshos/go-spacemesh/syncer/blockssync" "github.com/spacemeshos/go-spacemesh/system" "github.com/spacemeshos/go-spacemesh/timesync" @@ -1154,6 +1155,20 @@ func (app *App) listenToUpdates(ctx context.Context) { } if len(update.Data.ActiveSet) > 0 { app.hOracle.UpdateActiveSet(update.Data.Epoch, update.Data.ActiveSet) + set := update.Data.ActiveSet + app.eg.Go(func() error { + if err := atxsync.Download( + ctx, + 10*time.Second, + app.addLogger(SyncLogger, app.log).Zap(), + app.db, + app.fetcher, + set, + ); err != nil { + app.errCh <- err + } + return nil + }) } } } diff --git a/syncer/atxsync/atxsync.go b/syncer/atxsync/atxsync.go new file mode 100644 index 0000000000..c889157e6c --- /dev/null +++ b/syncer/atxsync/atxsync.go @@ -0,0 +1,75 @@ +package atxsync + +import ( + "context" + "math/rand" + "time" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + + "github.com/spacemeshos/go-spacemesh/common/types" + "github.com/spacemeshos/go-spacemesh/sql" + "github.com/spacemeshos/go-spacemesh/sql/atxs" +) + +//go:generate mockgen -typed -package=mocks -destination=./mocks/mocks.go -source=./atxsync.go +type atxFetcher interface { + GetAtxs(context.Context, []types.ATXID) error +} + +func getMissing(db *sql.Database, set []types.ATXID) ([]types.ATXID, error) { + missing := []types.ATXID{} + for _, atx := range set { + exist, err := atxs.Has(db, atx) + if err != nil { + return nil, err + } + if !exist { + missing = append(missing, atx) + } + } + return missing, nil +} + +// Download specified set of atxs from peers in the network. +// +// actual retry interval will be between [retryInterval, 2*retryInterval]. +func Download( + ctx context.Context, + retryInterval time.Duration, + logger *zap.Logger, + db *sql.Database, + fetcher atxFetcher, + set []types.ATXID, +) error { + total := len(set) + for { + missing, err := getMissing(db, set) + if err != nil { + return err + } + set = missing + downloaded := total - len(missing) + logger.Info("downloaded atxs", + zap.Int("total", total), + zap.Int("downloaded", downloaded), + zap.Array("missing", zapcore.ArrayMarshalerFunc(func(enc zapcore.ArrayEncoder) error { + for _, atx := range missing { + enc.AppendString(atx.ShortString()) + } + return nil + }))) + if len(missing) == 0 { + return nil + } + if err := fetcher.GetAtxs(ctx, missing); err != nil { + logger.Debug("failed to fetch atxs", zap.Error(err)) + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(retryInterval + time.Duration(rand.Int63n(int64(retryInterval)))): + } + } + } +} diff --git a/syncer/atxsync/atxsync_test.go b/syncer/atxsync/atxsync_test.go new file mode 100644 index 0000000000..14c11ef0d6 --- /dev/null +++ b/syncer/atxsync/atxsync_test.go @@ -0,0 +1,126 @@ +package atxsync + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/spacemeshos/go-spacemesh/common/types" + "github.com/spacemeshos/go-spacemesh/log/logtest" + "github.com/spacemeshos/go-spacemesh/sql" + "github.com/spacemeshos/go-spacemesh/sql/atxs" + "github.com/spacemeshos/go-spacemesh/syncer/atxsync/mocks" +) + +func atx(id types.ATXID) *types.VerifiedActivationTx { + atx := &types.ActivationTx{InnerActivationTx: types.InnerActivationTx{ + NIPostChallenge: types.NIPostChallenge{ + PublishEpoch: 1, + }, + NumUnits: 1, + }} + atx.SetID(id) + atx.SetEffectiveNumUnits(1) + atx.SetReceived(time.Now()) + copy(atx.SmesherID[:], id[:]) + vatx, err := atx.Verify(0, 1) + if err != nil { + panic(err) + } + return vatx +} + +func id(id ...byte) types.ATXID { + return types.BytesToATXID(id) +} + +type fetchRequest struct { + request []types.ATXID + result []*types.VerifiedActivationTx + error error +} + +func TestDownload(t *testing.T) { + canceled, cancel := context.WithCancel(context.Background()) + cancel() + for _, tc := range []struct { + desc string + ctx context.Context + retry time.Duration + existing []*types.VerifiedActivationTx + set []types.ATXID + fetched []fetchRequest + rst error + }{ + { + desc: "all existing", + ctx: context.Background(), + existing: []*types.VerifiedActivationTx{atx(id(1)), atx(id(2)), atx(id(3))}, + set: []types.ATXID{id(1), id(2), id(3)}, + }, + { + desc: "with multiple requests", + ctx: context.Background(), + existing: []*types.VerifiedActivationTx{atx(id(1))}, + retry: 1, + fetched: []fetchRequest{ + { + request: []types.ATXID{id(2), id(3)}, + error: errors.New("test"), + result: []*types.VerifiedActivationTx{atx(id(2))}, + }, + {request: []types.ATXID{id(3)}, result: []*types.VerifiedActivationTx{atx(id(3))}}, + }, + set: []types.ATXID{id(1), id(2), id(3)}, + }, + { + desc: "continue on error", + ctx: context.Background(), + retry: 1, + existing: []*types.VerifiedActivationTx{atx(id(1))}, + fetched: []fetchRequest{ + {request: []types.ATXID{id(2)}, error: errors.New("test")}, + {request: []types.ATXID{id(2)}, result: []*types.VerifiedActivationTx{atx(id(2))}}, + }, + set: []types.ATXID{id(1), id(2)}, + }, + { + desc: "exit on context", + ctx: canceled, + retry: 1, + existing: []*types.VerifiedActivationTx{atx(id(1))}, + fetched: []fetchRequest{ + {request: []types.ATXID{id(2)}, error: errors.New("test")}, + }, + set: []types.ATXID{id(1), id(2)}, + rst: context.Canceled, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + logger := logtest.New(t) + db := sql.InMemory() + ctrl := gomock.NewController(t) + fetcher := mocks.NewMockatxFetcher(ctrl) + for _, atx := range tc.existing { + require.NoError(t, atxs.Add(db, atx)) + } + for i := range tc.fetched { + req := tc.fetched[i] + fetcher.EXPECT(). + GetAtxs(tc.ctx, req.request). + Times(1). + DoAndReturn(func(_ context.Context, _ []types.ATXID) error { + for _, atx := range req.result { + require.NoError(t, atxs.Add(db, atx)) + } + return req.error + }) + } + require.Equal(t, tc.rst, Download(tc.ctx, tc.retry, logger.Zap(), db, fetcher, tc.set)) + }) + } +} diff --git a/syncer/atxsync/mocks/mocks.go b/syncer/atxsync/mocks/mocks.go new file mode 100644 index 0000000000..a5e86d876c --- /dev/null +++ b/syncer/atxsync/mocks/mocks.go @@ -0,0 +1,78 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./atxsync.go +// +// Generated by this command: +// +// mockgen -typed -package=mocks -destination=./mocks/mocks.go -source=./atxsync.go +// +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + types "github.com/spacemeshos/go-spacemesh/common/types" + gomock "go.uber.org/mock/gomock" +) + +// MockatxFetcher is a mock of atxFetcher interface. +type MockatxFetcher struct { + ctrl *gomock.Controller + recorder *MockatxFetcherMockRecorder +} + +// MockatxFetcherMockRecorder is the mock recorder for MockatxFetcher. +type MockatxFetcherMockRecorder struct { + mock *MockatxFetcher +} + +// NewMockatxFetcher creates a new mock instance. +func NewMockatxFetcher(ctrl *gomock.Controller) *MockatxFetcher { + mock := &MockatxFetcher{ctrl: ctrl} + mock.recorder = &MockatxFetcherMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockatxFetcher) EXPECT() *MockatxFetcherMockRecorder { + return m.recorder +} + +// GetAtxs mocks base method. +func (m *MockatxFetcher) GetAtxs(arg0 context.Context, arg1 []types.ATXID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAtxs", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// GetAtxs indicates an expected call of GetAtxs. +func (mr *MockatxFetcherMockRecorder) GetAtxs(arg0, arg1 any) *atxFetcherGetAtxsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAtxs", reflect.TypeOf((*MockatxFetcher)(nil).GetAtxs), arg0, arg1) + return &atxFetcherGetAtxsCall{Call: call} +} + +// atxFetcherGetAtxsCall wrap *gomock.Call +type atxFetcherGetAtxsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *atxFetcherGetAtxsCall) Return(arg0 error) *atxFetcherGetAtxsCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *atxFetcherGetAtxsCall) Do(f func(context.Context, []types.ATXID) error) *atxFetcherGetAtxsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *atxFetcherGetAtxsCall) DoAndReturn(f func(context.Context, []types.ATXID) error) *atxFetcherGetAtxsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/syncer/syncer.go b/syncer/syncer.go index 629665838a..840bdab45a 100644 --- a/syncer/syncer.go +++ b/syncer/syncer.go @@ -28,6 +28,7 @@ type Config struct { MaxStaleDuration time.Duration Standalone bool GossipDuration time.Duration + DisableAtxReconciliation bool `mapstructure:"disable-atx-reconciliation"` OutOfSyncThresholdLayers uint32 `mapstructure:"out-of-sync-threshold"` } @@ -440,7 +441,10 @@ func (s *Syncer) syncAtx(ctx context.Context) error { return err } } - + if s.cfg.DisableAtxReconciliation { + s.logger.Debug("atx sync disabled") + return nil + } // steady state atx syncing curr := s.ticker.CurrentLayer() if float64( From 3675992387f6dd9516579298e281c2d921dfb56c Mon Sep 17 00:00:00 2001 From: Matthias Fasching <5011972+fasmat@users.noreply.github.com> Date: Thu, 21 Dec 2023 13:16:24 +0000 Subject: [PATCH 47/48] Extend proposal builder to allow the use of a fallback active set. (#5378) ## Motivation related to #5366 Allow to set a fallback active set to be used by the proposal builder via the same mechanism as we use for the fallback beacon. ## Changes - some minor fixes in `bootstrap` cmd code - extend `ProposalBuilder` to be able to set a specific active set for an epoch - extend node routine listening for updates to fallback beacon / activeset to propagate a fallback to the `ProposalBuilder` ## Test Plan - added test case to `ProposalBuilder` to verify use of fallback active set if available - manual testing on `testnet-10` ## TODO - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [x] Update [changelog](../CHANGELOG.md) as needed --- CHANGELOG.md | 25 +++++++ bootstrap/updater.go | 8 +-- bootstrap/updater_test.go | 10 +-- cmd/bootstrapper/bootstrapper.go | 2 +- cmd/bootstrapper/generator.go | 13 ++-- cmd/bootstrapper/generator_test.go | 16 +++-- cmd/bootstrapper/server.go | 2 +- cmd/bootstrapper/server_test.go | 4 +- miner/proposal_builder.go | 108 +++++++++++++++++++++++------ miner/proposal_builder_test.go | 66 +++++++++++++++--- node/node.go | 26 +++++-- 11 files changed, 216 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25aef13914..798f783607 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -101,6 +101,31 @@ for more information on how to configure the node to work with the PoST service. * [#5367](https://github.com/spacemeshos/go-spacemesh/pull/5367) Add `no-main-override` toplevel config option and `--no-main-override` CLI option that makes it possible to run "nomain" builds on mainnet. +* [#5384](https://github.com/spacemeshos/go-spacemesh/pull/5384) to improve network stability and performance allow the + active set to be set in advance for an epoch. This allows the network to start consensus on the first layer of an epoch. + +## Release v1.2.12 + +### Improvements + +* [#5373](https://github.com/spacemeshos/go-spacemesh/pull/5373) automatic scaling of post verifying workers to a lower + value (1 by default) when POST proving starts. The workers are scaled up when POST proving finishes. + +* [#5382](https://github.com/spacemeshos/go-spacemesh/pull/5382) avoid processing same (gossiped/fetched) ATX many times + in parallel + +## Release v1.2.11 + +### Improvements + +* increased the max response data size in p2p to 40MiB + +## Release v1.2.10 + +### Improvements + +* further increased cache sizes and and p2p timeouts to compensate for the increased number of nodes on the network. + ## Release v1.2.9 ### Improvements diff --git a/bootstrap/updater.go b/bootstrap/updater.go index 42c5f31666..a8f030f526 100644 --- a/bootstrap/updater.go +++ b/bootstrap/updater.go @@ -41,7 +41,7 @@ const ( suffixLen = 2 SuffixBeacon = "bc" SuffixActiveSet = "as" - SuffixBoostrap = "bs" + SuffixBootstrap = "bs" httpTimeout = 5 * time.Second notifyTimeout = time.Second @@ -210,7 +210,7 @@ func (u *Updater) addUpdate(epoch types.EpochID, suffix string) { u.mu.Lock() defer u.mu.Unlock() switch suffix { - case SuffixActiveSet, SuffixBeacon, SuffixBoostrap: + case SuffixActiveSet, SuffixBeacon, SuffixBootstrap: default: return } @@ -242,7 +242,7 @@ func (u *Updater) DoIt(ctx context.Context) error { } }() for _, epoch := range requiredEpochs(current) { - verified, cached, err := u.checkEpochUpdate(ctx, epoch, SuffixBoostrap) + verified, cached, err := u.checkEpochUpdate(ctx, epoch, SuffixBootstrap) if err != nil { return err } @@ -324,8 +324,6 @@ func (u *Updater) get(ctx context.Context, uri string) (*VerifiedUpdate, []byte, return nil, nil, fmt.Errorf("scheme not supported %v", resource.Scheme) } - ctx, cancel := context.WithTimeout(ctx, httpTimeout) - defer cancel() t0 := time.Now() data, err := query(ctx, u.client, resource) if err != nil { diff --git a/bootstrap/updater_test.go b/bootstrap/updater_test.go index 54eab3c22e..ee66378972 100644 --- a/bootstrap/updater_test.go +++ b/bootstrap/updater_test.go @@ -163,7 +163,7 @@ func TestLoad(t *testing.T) { { desc: "recovery required", persisted: map[types.EpochID][]string{ - current - 2: {bootstrap.SuffixBoostrap, update1}, + current - 2: {bootstrap.SuffixBootstrap, update1}, current - 1: {bootstrap.SuffixActiveSet, update2}, current: {bootstrap.SuffixBeacon, update3}, current + 1: {bootstrap.SuffixActiveSet, update4}, @@ -234,7 +234,7 @@ func TestLoadedNotDownloadedAgain(t *testing.T) { cfg.DataDir, bootstrap.DirName, strconv.Itoa(int(epoch)), - bootstrap.UpdateName(epoch, bootstrap.SuffixBoostrap), + bootstrap.UpdateName(epoch, bootstrap.SuffixBootstrap), ) require.NoError(t, fs.MkdirAll(filepath.Dir(persisted), 0o700)) require.NoError(t, afero.WriteFile(fs, persisted, []byte(update), 0o400)) @@ -335,7 +335,7 @@ func TestDoIt(t *testing.T) { { desc: "in order", updates: map[string]string{ - "/" + bootstrap.UpdateName(1, bootstrap.SuffixBoostrap): update1, + "/" + bootstrap.UpdateName(1, bootstrap.SuffixBootstrap): update1, "/" + bootstrap.UpdateName(2, bootstrap.SuffixActiveSet): update2, "/" + bootstrap.UpdateName(3, bootstrap.SuffixBeacon): update3, "/" + bootstrap.UpdateName(4, bootstrap.SuffixActiveSet): update4, @@ -346,7 +346,7 @@ func TestDoIt(t *testing.T) { { desc: "bootstrap trumps others", updates: map[string]string{ - "/" + bootstrap.UpdateName(3, bootstrap.SuffixBoostrap): update1, + "/" + bootstrap.UpdateName(3, bootstrap.SuffixBootstrap): update1, "/" + bootstrap.UpdateName(3, bootstrap.SuffixActiveSet): update2, "/" + bootstrap.UpdateName(3, bootstrap.SuffixBeacon): update3, "/" + bootstrap.UpdateName(4, bootstrap.SuffixActiveSet): update4, @@ -507,7 +507,7 @@ func TestNoNewUpdate(t *testing.T) { numQ := 0 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { require.Equal(t, http.MethodGet, r.Method) - if r.URL.String() != "/"+bootstrap.UpdateName(3, bootstrap.SuffixBoostrap) { + if r.URL.String() != "/"+bootstrap.UpdateName(3, bootstrap.SuffixBootstrap) { w.WriteHeader(http.StatusNotFound) return } diff --git a/cmd/bootstrapper/bootstrapper.go b/cmd/bootstrapper/bootstrapper.go index 744c42b0df..42e9c8338f 100644 --- a/cmd/bootstrapper/bootstrapper.go +++ b/cmd/bootstrapper/bootstrapper.go @@ -76,7 +76,7 @@ var cmd = &cobra.Command{ Short: "generate bootstrapping data", RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { - return fmt.Errorf("epoch not specfiied") + return fmt.Errorf("epoch not specified") } var targetEpochs []types.EpochID epochs := strings.Split(args[0], ",") diff --git a/cmd/bootstrapper/generator.go b/cmd/bootstrapper/generator.go index 89f871e720..87bb77e77e 100644 --- a/cmd/bootstrapper/generator.go +++ b/cmd/bootstrapper/generator.go @@ -95,7 +95,7 @@ func (g *Generator) Generate( err error ) if genBeacon && genActiveSet { - suffix = bootstrap.SuffixBoostrap + suffix = bootstrap.SuffixBootstrap } else if genBeacon { suffix = bootstrap.SuffixBeacon } else if genActiveSet { @@ -181,7 +181,7 @@ func queryBitcoin(ctx context.Context, client *http.Client, targetUrl string) (* defer resp.Body.Close() data, err := io.ReadAll(resp.Body) if err != nil { - return nil, fmt.Errorf("bootstrap read resonse: %w", err) + return nil, fmt.Errorf("bootstrap read response: %w", err) } var br BitcoinResponse err = json.Unmarshal(data, &br) @@ -205,7 +205,7 @@ func getActiveSet(ctx context.Context, endpoint string, epoch types.EpochID) ([] if err != nil { return nil, fmt.Errorf("epoch stream %v: %w", endpoint, err) } - activeSet := make([]types.ATXID, 0, 10_000) + activeSet := make([]types.ATXID, 0, 300_000) for { resp, err := stream.Recv() if errors.Is(err, io.EOF) { @@ -227,7 +227,7 @@ func (g *Generator) GenUpdate( ) (string, error) { as := make([]string, 0, len(activeSet)) for _, atx := range activeSet { - as = append(as, hex.EncodeToString(atx.Hash32().Bytes())) // no leading 0x + as = append(as, hex.EncodeToString(atx.Bytes())) // no leading 0x } var update bootstrap.Update update.Version = SchemaVersion @@ -243,11 +243,11 @@ func (g *Generator) GenUpdate( } data, err := json.Marshal(update) if err != nil { - return "", fmt.Errorf("marshal data %v: %w", string(data), err) + return "", fmt.Errorf("marshal data: %w", err) } // make sure the data is valid if err = bootstrap.ValidateSchema(data); err != nil { - return "", fmt.Errorf("invalid data %v: %w", string(data), err) + return "", fmt.Errorf("invalid data: %w", err) } filename := PersistedFilename(epoch, suffix) err = afero.WriteFile(g.fs, filename, data, 0o600) @@ -255,7 +255,6 @@ func (g *Generator) GenUpdate( return "", fmt.Errorf("persist epoch update %v: %w", filename, err) } g.logger.With().Info("generated update", - log.String("update", string(data)), log.String("filename", filename), ) return filename, nil diff --git a/cmd/bootstrapper/generator_test.go b/cmd/bootstrapper/generator_test.go index b15a5526c3..c357e14001 100644 --- a/cmd/bootstrapper/generator_test.go +++ b/cmd/bootstrapper/generator_test.go @@ -91,14 +91,16 @@ func launchServer(tb testing.TB, cdb *datastore.CachedDB) (grpcserver.Config, fu } } -func verifyUpdate(t *testing.T, data []byte, epoch types.EpochID, expBeacon string, expAsSize int) { - require.NoError(t, bootstrap.ValidateSchema(data)) +func verifyUpdate(tb testing.TB, data []byte, epoch types.EpochID, expBeacon string, expAsSize int) { + tb.Helper() + require.NoError(tb, bootstrap.ValidateSchema(data)) + var update bootstrap.Update - require.NoError(t, json.Unmarshal(data, &update)) - require.Equal(t, SchemaVersion, update.Version) - require.EqualValues(t, epoch, update.Data.Epoch.ID) - require.Equal(t, expBeacon, update.Data.Epoch.Beacon) - require.Len(t, update.Data.Epoch.ActiveSet, expAsSize) + require.NoError(tb, json.Unmarshal(data, &update)) + require.Equal(tb, SchemaVersion, update.Version) + require.Equal(tb, epoch.Uint32(), update.Data.Epoch.ID) + require.Equal(tb, expBeacon, update.Data.Epoch.Beacon) + require.Len(tb, update.Data.Epoch.ActiveSet, expAsSize) } func TestGenerator_Generate(t *testing.T) { diff --git a/cmd/bootstrapper/server.go b/cmd/bootstrapper/server.go index 52320d98f1..bcc0da5416 100644 --- a/cmd/bootstrapper/server.go +++ b/cmd/bootstrapper/server.go @@ -150,7 +150,7 @@ func (s *Server) GenBootstrap(ctx context.Context, epoch types.EpochID) error { if err != nil { return err } - suffix := bootstrap.SuffixBoostrap + suffix := bootstrap.SuffixBootstrap _, err = s.gen.GenUpdate(epoch, epochBeacon(epoch), actives, suffix) return err } diff --git a/cmd/bootstrapper/server_test.go b/cmd/bootstrapper/server_test.go index ffa633aa09..73c908b51b 100644 --- a/cmd/bootstrapper/server_test.go +++ b/cmd/bootstrapper/server_test.go @@ -87,14 +87,14 @@ func TestServer(t *testing.T) { for _, epoch := range epochs { createAtxs(t, db, epoch-1, types.RandomActiveSet(activeSetSize)) - fname := PersistedFilename(epoch, bootstrap.SuffixBoostrap) + fname := PersistedFilename(epoch, bootstrap.SuffixBootstrap) require.Eventually(t, func() bool { _, err := fs.Stat(fname) return err == nil }, 5*time.Second, 100*time.Millisecond) require.Empty(t, ch) - data := query(t, ctx, bootstrap.UpdateName(epoch, bootstrap.SuffixBoostrap)) + data := query(t, ctx, bootstrap.UpdateName(epoch, bootstrap.SuffixBootstrap)) verifyUpdate(t, data, epoch, hex.EncodeToString(epochBeacon(epoch).Bytes()), activeSetSize) require.NoError(t, fs.Remove(fname)) } diff --git a/miner/proposal_builder.go b/miner/proposal_builder.go index c48ec799cf..16921d99fa 100644 --- a/miner/proposal_builder.go +++ b/miner/proposal_builder.go @@ -72,9 +72,16 @@ type ProposalBuilder struct { tortoise votesEncoder syncer system.SyncStateProvider - mu sync.Mutex - signers map[types.NodeID]*signerSession - shared sharedSession + signers struct { + mu sync.Mutex + signers map[types.NodeID]*signerSession + } + shared sharedSession + + fallback struct { + mu sync.Mutex + data map[types.EpochID][]types.ATXID + } } type signerSession struct { @@ -251,7 +258,18 @@ func New( tortoise: trtl, syncer: syncer, conState: conState, - signers: map[types.NodeID]*signerSession{}, + signers: struct { + mu sync.Mutex + signers map[types.NodeID]*signerSession + }{ + signers: map[types.NodeID]*signerSession{}, + }, + fallback: struct { + mu sync.Mutex + data map[types.EpochID][]types.ATXID + }{ + data: map[types.EpochID][]types.ATXID{}, + }, } for _, opt := range opts { opt(pb) @@ -260,11 +278,11 @@ func New( } func (pb *ProposalBuilder) Register(signer *signing.EdSigner) { - pb.mu.Lock() - defer pb.mu.Unlock() - _, exist := pb.signers[signer.NodeID()] + pb.signers.mu.Lock() + defer pb.signers.mu.Unlock() + _, exist := pb.signers.signers[signer.NodeID()] if !exist { - pb.signers[signer.NodeID()] = &signerSession{ + pb.signers.signers[signer.NodeID()] = &signerSession{ signer: signer, log: pb.logger.WithFields(log.String("signer", signer.NodeID().ShortString())), } @@ -368,6 +386,20 @@ func (pb *ProposalBuilder) decideMeshHash(ctx context.Context, current types.Lay return mesh } +func (pb *ProposalBuilder) UpdateActiveSet(epoch types.EpochID, activeSet []types.ATXID) { + pb.logger.With().Info("received activeset update", + epoch, + log.Int("size", len(activeSet)), + ) + pb.fallback.mu.Lock() + defer pb.fallback.mu.Unlock() + if _, ok := pb.fallback.data[epoch]; ok { + pb.logger.With().Debug("fallback active set already exists", epoch) + return + } + pb.fallback.data[epoch] = activeSet +} + func (pb *ProposalBuilder) initSharedData(ctx context.Context, lid types.LayerID) error { if pb.shared.epoch != lid.GetEpoch() { pb.shared = sharedSession{epoch: lid.GetEpoch()} @@ -379,21 +411,36 @@ func (pb *ProposalBuilder) initSharedData(ctx context.Context, lid types.LayerID } pb.shared.beacon = beacon } - if pb.shared.active.set == nil { - weight, set, err := generateActiveSet( - pb.logger, - pb.cdb, + if pb.shared.active.set != nil { + return nil + } + + if weight, set, err := pb.fallbackActiveSet(pb.shared.epoch); err == nil { + pb.logger.With().Info("using fallback active set", pb.shared.epoch, - pb.clock.LayerToTime(pb.shared.epoch.FirstLayer()), - pb.cfg.goodAtxPercent, - pb.cfg.networkDelay, + log.Int("size", len(set)), ) - if err != nil { - return err - } + sort.Slice(set, func(i, j int) bool { + return bytes.Compare(set[i].Bytes(), set[j].Bytes()) < 0 + }) pb.shared.active.set = set pb.shared.active.weight = weight + return nil } + + weight, set, err := generateActiveSet( + pb.logger, + pb.cdb, + pb.shared.epoch, + pb.clock.LayerToTime(pb.shared.epoch.FirstLayer()), + pb.cfg.goodAtxPercent, + pb.cfg.networkDelay, + ) + if err != nil { + return err + } + pb.shared.active.set = set + pb.shared.active.weight = weight return nil } @@ -482,10 +529,10 @@ func (pb *ProposalBuilder) build(ctx context.Context, lid types.LayerID) error { return err } - pb.mu.Lock() + pb.signers.mu.Lock() // don't accept registration in the middle of computing proposals - signers := maps.Values(pb.signers) - pb.mu.Unlock() + signers := maps.Values(pb.signers.signers) + pb.signers.mu.Unlock() var eg errgroup.Group eg.SetLimit(pb.cfg.workersLimit) @@ -710,6 +757,25 @@ func activesFromFirstBlock( return totalWeight, set, nil } +func (pb *ProposalBuilder) fallbackActiveSet(targetEpoch types.EpochID) (uint64, []types.ATXID, error) { + pb.fallback.mu.Lock() + defer pb.fallback.mu.Unlock() + set, ok := pb.fallback.data[targetEpoch] + if !ok { + return 0, nil, fmt.Errorf("no fallback active set for epoch %d", targetEpoch) + } + + var totalWeight uint64 + for _, id := range set { + atx, err := pb.cdb.GetAtxHeader(id) + if err != nil { + return 0, nil, err + } + totalWeight += atx.GetWeight() + } + return totalWeight, set, nil +} + func generateActiveSet( logger log.Log, cdb *datastore.CachedDB, diff --git a/miner/proposal_builder_test.go b/miner/proposal_builder_test.go index 0047f1f006..b792358430 100644 --- a/miner/proposal_builder_test.go +++ b/miner/proposal_builder_test.go @@ -204,15 +204,20 @@ type aggHash struct { } type step struct { - lid types.LayerID - beacon types.Beacon - atxs []*types.VerifiedActivationTx - ballots []*types.Ballot - activeset types.ATXIDList - identitities []identity - blocks []*types.Block - hare []types.LayerID - aggHashes []aggHash + lid types.LayerID + beacon types.Beacon + atxs []*types.VerifiedActivationTx + ballots []*types.Ballot + activeset types.ATXIDList + identities []identity + blocks []*types.Block + hare []types.LayerID + aggHashes []aggHash + + fallbackActiveSets []struct { + epoch types.EpochID + atxs types.ATXIDList + } txs []types.TransactionID latestComplete types.LayerID @@ -271,6 +276,42 @@ func TestBuild(t *testing.T) { }, }, }, + { + desc: "activeset fallback with all ATXs from fallback available", + steps: []step{ + { + lid: 15, + beacon: types.Beacon{1}, + atxs: []*types.VerifiedActivationTx{ + gatx(types.ATXID{1}, 2, signer.NodeID(), 1, genAtxWithNonce(777)), + gatx(types.ATXID{2}, 2, types.NodeID{2}, 1), + gatx(types.ATXID{3}, 2, types.NodeID{3}, 1), + gatx(types.ATXID{4}, 2, types.NodeID{4}, 1), + gatx(types.ATXID{5}, 2, types.NodeID{5}, 1), + gatx(types.ATXID{6}, 2, types.NodeID{6}, 1), + }, + fallbackActiveSets: []struct { + epoch types.EpochID + atxs types.ATXIDList + }{ + {3, types.ATXIDList{{1}, {2}, {3}, {4}}}, + }, + opinion: &types.Opinion{Hash: types.Hash32{1}}, + txs: []types.TransactionID{{1}, {2}}, + latestComplete: 14, + expectProposal: expectProposal( + signer, 15, types.ATXID{1}, types.Opinion{Hash: types.Hash32{1}}, + expectEpochData( + gactiveset(types.ATXID{1}, types.ATXID{2}, types.ATXID{3}, types.ATXID{4}), + 12, + types.Beacon{1}, + ), + expectTxs([]types.TransactionID{{1}, {2}}), + expectCounters(signer, 3, types.Beacon{1}, 777, 0, 6, 9), + ), + }, + }, + }, { desc: "min active weight", opts: []Opt{WithMinimalActiveSetWeight([]types.EpochMinimalActiveWeight{{Weight: 1000}})}, @@ -460,7 +501,7 @@ func TestBuild(t *testing.T) { gatx(types.ATXID{1}, 2, signer.NodeID(), 1, genAtxWithNonce(777)), gatx(types.ATXID{2}, 2, types.NodeID{2}, 1), }, - identitities: []identity{{ + identities: []identity{{ id: types.NodeID{2}, proof: types.MalfeasanceProof{Proof: types.Proof{ Type: types.HareEquivocation, @@ -716,7 +757,7 @@ func TestBuild(t *testing.T) { if step.beacon != types.EmptyBeacon { require.NoError(t, beacons.Add(cdb, step.lid.GetEpoch(), step.beacon)) } - for _, iden := range step.identitities { + for _, iden := range step.identities { require.NoError( t, identities.SetMalicious( @@ -754,6 +795,9 @@ func TestBuild(t *testing.T) { ), ) } + for _, activeSet := range step.fallbackActiveSets { + builder.UpdateActiveSet(activeSet.epoch, activeSet.atxs) + } } { if step.opinion != nil { diff --git a/node/node.go b/node/node.go index 86ead1b394..59ffe1b23c 100644 --- a/node/node.go +++ b/node/node.go @@ -2,6 +2,7 @@ package node import ( + "bytes" "context" "encoding/hex" "errors" @@ -12,6 +13,7 @@ import ( "os/signal" "path/filepath" "runtime" + "sort" "syscall" "time" @@ -64,6 +66,7 @@ import ( "github.com/spacemeshos/go-spacemesh/prune" "github.com/spacemeshos/go-spacemesh/signing" "github.com/spacemeshos/go-spacemesh/sql" + "github.com/spacemeshos/go-spacemesh/sql/activesets" "github.com/spacemeshos/go-spacemesh/sql/ballots/util" "github.com/spacemeshos/go-spacemesh/sql/layers" "github.com/spacemeshos/go-spacemesh/sql/localsql" @@ -1142,11 +1145,14 @@ func (app *App) listenToUpdates(ctx context.Context) { app.errCh <- err return nil } - for update := range ch { + for { select { case <-ctx.Done(): return nil - default: + case update, ok := <-ch: + if !ok { + return nil + } if update.Data.Beacon != types.EmptyBeacon { if err := app.beaconProtocol.UpdateBeacon(update.Data.Epoch, update.Data.Beacon); err != nil { app.errCh <- err @@ -1154,8 +1160,21 @@ func (app *App) listenToUpdates(ctx context.Context) { } } if len(update.Data.ActiveSet) > 0 { - app.hOracle.UpdateActiveSet(update.Data.Epoch, update.Data.ActiveSet) + epoch := update.Data.Epoch set := update.Data.ActiveSet + sort.Slice(set, func(i, j int) bool { + return bytes.Compare(set[i].Bytes(), set[j].Bytes()) < 0 + }) + id := types.ATXIDList(set).Hash() + activeSet := &types.EpochActiveSet{ + Epoch: epoch, + Set: set, + } + activesets.Add(app.db, id, activeSet) + + app.hOracle.UpdateActiveSet(epoch, set) + app.proposalBuilder.UpdateActiveSet(epoch, set) + app.eg.Go(func() error { if err := atxsync.Download( ctx, @@ -1172,7 +1191,6 @@ func (app *App) listenToUpdates(ctx context.Context) { } } } - return nil }) } From eb55894737514b456bbd4af4a41178639a6bda15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Dec 2023 09:00:44 +0000 Subject: [PATCH 48/48] build(deps): Bump google.golang.org/protobuf from 1.31.0 to 1.32.0 (#5392) Bumps google.golang.org/protobuf from 1.31.0 to 1.32.0. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index cc5fd5e4c3..e5f099b750 100644 --- a/go.mod +++ b/go.mod @@ -56,7 +56,7 @@ require ( golang.org/x/time v0.5.0 google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 google.golang.org/grpc v1.60.1 - google.golang.org/protobuf v1.31.0 + google.golang.org/protobuf v1.32.0 k8s.io/api v0.29.0 k8s.io/apimachinery v0.29.0 k8s.io/client-go v0.29.0 diff --git a/go.sum b/go.sum index bd0f441873..02815a0ff7 100644 --- a/go.sum +++ b/go.sum @@ -1091,8 +1091,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=