From 745c38ac72f7b6edf04d0fa242086f46729a91e8 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Thu, 24 Oct 2024 14:53:46 -0500 Subject: [PATCH 1/6] add getProposedValidators method --- vms/platformvm/client.go | 12 ++++++++++ vms/platformvm/service.go | 27 ++++++++++++++++++++++ vms/platformvm/service.md | 48 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index 505c545bdde..446f8f38be1 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -506,6 +506,18 @@ func (c *client) GetValidatorsAt( return res.Validators, err } +func (c *client) GetProposedValidators( + ctx context.Context, + subnetID ids.ID, + options ...rpc.Option, +) (map[ids.NodeID]*validators.GetValidatorOutput, error) { + res := &GetProposedValidatorsReply{} + err := c.requester.SendRequest(ctx, "platform.getProposedValidators", &GetProposedValidatorsArgs{ + SubnetID: subnetID, + }, res, options...) + return res.Validators, err +} + func (c *client) GetBlock(ctx context.Context, blockID ids.ID, options ...rpc.Option) ([]byte, error) { res := &api.FormattedBlock{} if err := c.requester.SendRequest(ctx, "platform.getBlock", &api.GetBlockArgs{ diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go index 22153a97ece..0d86509ed3a 100644 --- a/vms/platformvm/service.go +++ b/vms/platformvm/service.go @@ -1780,6 +1780,33 @@ func (s *Service) GetValidatorsAt(r *http.Request, args *GetValidatorsAtArgs, re return nil } +type GetProposedValidatorsArgs struct { + SubnetID ids.ID `json:"subnetID"` +} +type GetProposedValidatorsReply struct { + GetValidatorsAtReply +} + +func (s *Service) GetProposedValidators(r *http.Request, args *GetProposedValidatorsArgs, reply *GetProposedValidatorsReply) error { + s.vm.ctx.Log.Debug("API called", + zap.String("service", "platform"), + zap.String("method", "getProposedValidators"), + zap.Stringer("subnetID", args.SubnetID), + ) + s.vm.ctx.Lock.Lock() + defer s.vm.ctx.Lock.Unlock() + + ctx := r.Context() + proposerHeight, err := s.vm.GetMinimumHeight(ctx) + if err != nil { + return fmt.Errorf("failed to get proposer height: %w", err) + } + if reply.Validators, err = s.vm.GetValidatorSet(ctx, proposerHeight, args.SubnetID); err != nil { + return fmt.Errorf("failed to get validator set: %w", err) + } + return nil +} + func (s *Service) GetBlock(_ *http.Request, args *api.GetBlockArgs, response *api.GetBlockResponse) error { s.vm.ctx.Log.Debug("API called", zap.String("service", "platform"), diff --git a/vms/platformvm/service.md b/vms/platformvm/service.md index dbb12907694..f1961c5c7c6 100644 --- a/vms/platformvm/service.md +++ b/vms/platformvm/service.md @@ -1778,7 +1778,7 @@ platform.getValidatorsAt( ``` - `height` is the P-Chain height to get the validator set at. -- `subnetID` is the Subnet ID to get the validator set of. If not given, gets validator set of the +- `subnetID` is the Subnet ID to get the validator set of. If not given, gets the validator set of the Primary Network. **Example Call:** @@ -1812,6 +1812,52 @@ curl -X POST --data '{ } ``` +### `platform.getProposedValidators` + +Get the validators and their weights of a Subnet or the Primary Network at the current proposer VM height. + +**Signature:** + +```sh +platform.getProposedValidators( + { + subnetID: string, // optional + } +) +``` + +- `subnetID` is the Subnet ID to get the validator set of. If not given, gets the validator set of the + Primary Network. + +**Example Call:** + +```bash +curl -X POST --data '{ + "jsonrpc": "2.0", + "method": "platform.getValidatorsAt", + "params": {}, + "id": 1 +}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P +``` + +**Example Response:** + +```json +{ + "jsonrpc": "2.0", + "result": { + "validators": { + "NodeID-7Xhw2mDxuDS44j42TCB6U5579esbSt3Lg": 2000000000000000, + "NodeID-GWPcbFJZFfZreETSoWjPimr846mXEKCtu": 2000000000000000, + "NodeID-MFrZFVCXPv5iCn6M9K6XduxGTYp891xXZ": 2000000000000000, + "NodeID-NFBbbJ4qCmNaCzeW7sxErhvWqvEQMnYcN": 2000000000000000, + "NodeID-P7oB2McjBGgW2NXXWVYjV8JEDFoW9xDE5": 2000000000000000 + } + }, + "id": 1 +} +``` + ### `platform.issueTx` Issue a transaction to the Platform Chain. From 77f67fba01debf4a6da8b61623bbf31814dc8828 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Fri, 25 Oct 2024 11:12:13 -0500 Subject: [PATCH 2/6] add GetProposedValidators to client interface --- vms/platformvm/client.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index 446f8f38be1..4670804f449 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -120,6 +120,13 @@ type Client interface { height uint64, options ...rpc.Option, ) (map[ids.NodeID]*validators.GetValidatorOutput, error) + // GetProposedValidators returns the weights of the validator set of a provided + // subnet at the proposer's height. + GetProposedValidators( + ctx context.Context, + subnetID ids.ID, + options ...rpc.Option, + ) (map[ids.NodeID]*validators.GetValidatorOutput, error) // GetBlock returns the block with the given id. GetBlock(ctx context.Context, blockID ids.ID, options ...rpc.Option) ([]byte, error) // GetBlockByHeight returns the block at the given [height]. From c7e0aaf882c47f005e972eaefefec6a6a08892d8 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Fri, 25 Oct 2024 11:14:18 -0500 Subject: [PATCH 3/6] get proposed validators basic e2e --- tests/e2e/p/proposed_validators.go | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/e2e/p/proposed_validators.go diff --git a/tests/e2e/p/proposed_validators.go b/tests/e2e/p/proposed_validators.go new file mode 100644 index 00000000000..a185b20fbb1 --- /dev/null +++ b/tests/e2e/p/proposed_validators.go @@ -0,0 +1,36 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package p + +import ( + "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/tests/fixture/e2e" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/vms/platformvm" +) + +var _ = e2e.DescribePChain("[Proposed Validators]", func() { + var ( + tc = e2e.NewTestContext() + require = require.New(tc) + ) + + ginkgo.It("should be able to fetch proposed validators", func() { + var ( + env = e2e.GetEnv(tc) + network = env.GetNetwork() + ) + tc.By("fetching proposed validators", func() { + pvmClient := platformvm.NewClient(env.URIs[0].URI) + _, err := pvmClient.GetProposedValidators( + tc.DefaultContext(), + constants.PrimaryNetworkID, + ) + require.NoError(err) + }) + _ = e2e.CheckBootstrapIsPossible(tc, network) + }) +}) From 7c9c564a68bb917d8fc49786a1539dc5c53e7941 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Fri, 25 Oct 2024 14:09:56 -0500 Subject: [PATCH 4/6] compare against current vdrs --- tests/e2e/p/proposed_validators.go | 48 +++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/tests/e2e/p/proposed_validators.go b/tests/e2e/p/proposed_validators.go index a185b20fbb1..cbfd8709bc6 100644 --- a/tests/e2e/p/proposed_validators.go +++ b/tests/e2e/p/proposed_validators.go @@ -4,12 +4,15 @@ package p import ( - "github.com/onsi/ginkgo/v2" - "github.com/stretchr/testify/require" - + "github.com/ava-labs/avalanchego/config" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/tests/fixture/e2e" + "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/require" ) var _ = e2e.DescribePChain("[Proposed Validators]", func() { @@ -19,18 +22,43 @@ var _ = e2e.DescribePChain("[Proposed Validators]", func() { ) ginkgo.It("should be able to fetch proposed validators", func() { - var ( - env = e2e.GetEnv(tc) - network = env.GetNetwork() - ) + tc.By("creating a new private network to ensure isolation from other tests") + privateNetwork := tmpnet.NewDefaultNetwork("avalanchego-e2e-proposed-validators") + // Initialize config flags + privateNetwork.DefaultFlags = tmpnet.FlagsMap{} + // Ensure that the proposer uses the current height + privateNetwork.DefaultFlags.SetDefaults(tmpnet.FlagsMap{ + config.ProposerVMUseCurrentHeightKey: true, + }) + + e2e.GetEnv(tc).StartPrivateNetwork(privateNetwork) + tc.By("fetching proposed validators", func() { - pvmClient := platformvm.NewClient(env.URIs[0].URI) - _, err := pvmClient.GetProposedValidators( + pvmClient := platformvm.NewClient(privateNetwork.GetNodeURIs()[0].URI) + proposedVdrs, err := pvmClient.GetProposedValidators( tc.DefaultContext(), constants.PrimaryNetworkID, ) require.NoError(err) + + tc.By("confirming proposed validators are the same as current validators", func() { + proposedVdrNodes := set.NewSet[ids.NodeID](len(proposedVdrs)) + for _, vdr := range proposedVdrs { + proposedVdrNodes.Add(vdr.NodeID) + } + currentVdrs, err := pvmClient.GetCurrentValidators( + tc.DefaultContext(), + constants.PrimaryNetworkID, + nil, + ) + require.NoError(err) + currentVdrNodes := set.NewSet[ids.NodeID](len(currentVdrs)) + for _, vdr := range currentVdrs { + currentVdrNodes.Add(vdr.NodeID) + } + require.Equal(proposedVdrNodes, currentVdrNodes) + }) }) - _ = e2e.CheckBootstrapIsPossible(tc, network) + _ = e2e.CheckBootstrapIsPossible(tc, privateNetwork) }) }) From edb9dbaca4963592d12b8aaa88f613142f4c0070 Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Fri, 25 Oct 2024 14:24:10 -0500 Subject: [PATCH 5/6] lint --- tests/e2e/p/proposed_validators.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/e2e/p/proposed_validators.go b/tests/e2e/p/proposed_validators.go index cbfd8709bc6..651deedce0a 100644 --- a/tests/e2e/p/proposed_validators.go +++ b/tests/e2e/p/proposed_validators.go @@ -4,6 +4,9 @@ package p import ( + "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/require" + "github.com/ava-labs/avalanchego/config" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/tests/fixture/e2e" @@ -11,8 +14,6 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm" - "github.com/onsi/ginkgo/v2" - "github.com/stretchr/testify/require" ) var _ = e2e.DescribePChain("[Proposed Validators]", func() { From b30802b6ce5fae1cc1fd91483202e76b7f4f5c2c Mon Sep 17 00:00:00 2001 From: cam-schultz Date: Fri, 25 Oct 2024 15:55:50 -0500 Subject: [PATCH 6/6] use default network --- tests/e2e/p/proposed_validators.go | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/e2e/p/proposed_validators.go b/tests/e2e/p/proposed_validators.go index 651deedce0a..26658aec244 100644 --- a/tests/e2e/p/proposed_validators.go +++ b/tests/e2e/p/proposed_validators.go @@ -10,7 +10,6 @@ import ( "github.com/ava-labs/avalanchego/config" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/tests/fixture/e2e" - "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm" @@ -23,19 +22,13 @@ var _ = e2e.DescribePChain("[Proposed Validators]", func() { ) ginkgo.It("should be able to fetch proposed validators", func() { - tc.By("creating a new private network to ensure isolation from other tests") - privateNetwork := tmpnet.NewDefaultNetwork("avalanchego-e2e-proposed-validators") - // Initialize config flags - privateNetwork.DefaultFlags = tmpnet.FlagsMap{} - // Ensure that the proposer uses the current height - privateNetwork.DefaultFlags.SetDefaults(tmpnet.FlagsMap{ - config.ProposerVMUseCurrentHeightKey: true, - }) - - e2e.GetEnv(tc).StartPrivateNetwork(privateNetwork) + var ( + env = e2e.GetEnv(tc) + network = env.GetNetwork() + ) tc.By("fetching proposed validators", func() { - pvmClient := platformvm.NewClient(privateNetwork.GetNodeURIs()[0].URI) + pvmClient := platformvm.NewClient(env.URIs[0].URI) proposedVdrs, err := pvmClient.GetProposedValidators( tc.DefaultContext(), constants.PrimaryNetworkID, @@ -43,6 +36,11 @@ var _ = e2e.DescribePChain("[Proposed Validators]", func() { require.NoError(err) tc.By("confirming proposed validators are the same as current validators", func() { + // Ensure the network is configured to use the current height for the proposer + proposerVMUseCurrentHeight, err := network.DefaultFlags.GetBoolVal(config.ProposerVMUseCurrentHeightKey, true) + require.NoError(err) + require.True(proposerVMUseCurrentHeight) + proposedVdrNodes := set.NewSet[ids.NodeID](len(proposedVdrs)) for _, vdr := range proposedVdrs { proposedVdrNodes.Add(vdr.NodeID) @@ -60,6 +58,6 @@ var _ = e2e.DescribePChain("[Proposed Validators]", func() { require.Equal(proposedVdrNodes, currentVdrNodes) }) }) - _ = e2e.CheckBootstrapIsPossible(tc, privateNetwork) + _ = e2e.CheckBootstrapIsPossible(tc, network) }) })