Skip to content

Commit 40eac34

Browse files
ceyonurStephenButtolphjoshua-kim
authored
ACP-77: Current validators API for SoV (#3404)
Signed-off-by: Ceyhun Onur <[email protected]> Signed-off-by: Joshua Kim <[email protected]> Signed-off-by: Ceyhun Onur <[email protected]> Co-authored-by: Stephen Buttolph <[email protected]> Co-authored-by: Joshua Kim <[email protected]>
1 parent 1c4a510 commit 40eac34

File tree

15 files changed

+874
-98
lines changed

15 files changed

+874
-98
lines changed

proto/pb/validatorstate/validator_state.pb.go

Lines changed: 274 additions & 73 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proto/pb/validatorstate/validator_state_grpc.pb.go

Lines changed: 45 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proto/validatorstate/validator_state.proto

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ service ValidatorState {
1717
// GetValidatorSet returns the weights of the nodeIDs for the provided
1818
// subnet at the requested P-chain height.
1919
rpc GetValidatorSet(GetValidatorSetRequest) returns (GetValidatorSetResponse);
20+
// GetCurrentValidatorSet returns the validator set for the provided subnet at
21+
// the current P-chain height.
22+
rpc GetCurrentValidatorSet(GetCurrentValidatorSetRequest) returns (GetCurrentValidatorSetResponse);
2023
}
2124

2225
message GetMinimumHeightResponse {
@@ -40,12 +43,26 @@ message GetValidatorSetRequest {
4043
bytes subnet_id = 2;
4144
}
4245

46+
message GetCurrentValidatorSetRequest {
47+
bytes subnet_id = 1;
48+
}
49+
4350
message Validator {
4451
bytes node_id = 1;
4552
uint64 weight = 2;
46-
bytes public_key = 3;
53+
bytes public_key = 3; // Uncompressed public key, can be empty
54+
uint64 start_time = 4; // can be empty
55+
uint64 min_nonce = 5; // can be empty
56+
bool is_active = 6; // can be empty
57+
bytes validation_id = 7; // can be empty
58+
bool is_sov = 8; // can be empty
4759
}
4860

4961
message GetValidatorSetResponse {
5062
repeated Validator validators = 1;
5163
}
64+
65+
message GetCurrentValidatorSetResponse {
66+
repeated Validator validators = 1;
67+
uint64 current_height = 2;
68+
}

snow/validators/gvalidators/validator_state_client.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,51 @@ func (c *Client) GetValidatorSet(
9494
}
9595
return vdrs, nil
9696
}
97+
98+
func (c *Client) GetCurrentValidatorSet(
99+
ctx context.Context,
100+
subnetID ids.ID,
101+
) (map[ids.ID]*validators.GetCurrentValidatorOutput, uint64, error) {
102+
resp, err := c.client.GetCurrentValidatorSet(ctx, &pb.GetCurrentValidatorSetRequest{
103+
SubnetId: subnetID[:],
104+
})
105+
if err != nil {
106+
return nil, 0, err
107+
}
108+
109+
vdrs := make(map[ids.ID]*validators.GetCurrentValidatorOutput, len(resp.Validators))
110+
for _, validator := range resp.Validators {
111+
nodeID, err := ids.ToNodeID(validator.NodeId)
112+
if err != nil {
113+
return nil, 0, err
114+
}
115+
var publicKey *bls.PublicKey
116+
if len(validator.PublicKey) > 0 {
117+
// PublicKeyFromValidUncompressedBytes is used rather than
118+
// PublicKeyFromCompressedBytes because it is significantly faster
119+
// due to the avoidance of decompression and key re-verification. We
120+
// can safely assume that the BLS Public Keys are verified before
121+
// being added to the P-Chain and served by the gRPC server.
122+
publicKey = bls.PublicKeyFromValidUncompressedBytes(validator.PublicKey)
123+
if publicKey == nil {
124+
return nil, 0, errFailedPublicKeyDeserialize
125+
}
126+
}
127+
validationID, err := ids.ToID(validator.ValidationId)
128+
if err != nil {
129+
return nil, 0, err
130+
}
131+
132+
vdrs[validationID] = &validators.GetCurrentValidatorOutput{
133+
ValidationID: validationID,
134+
NodeID: nodeID,
135+
PublicKey: publicKey,
136+
Weight: validator.Weight,
137+
StartTime: validator.StartTime,
138+
MinNonce: validator.MinNonce,
139+
IsActive: validator.IsActive,
140+
IsSoV: validator.IsSov,
141+
}
142+
}
143+
return vdrs, resp.GetCurrentHeight(), nil
144+
}

snow/validators/gvalidators/validator_state_server.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,42 @@ func (s *Server) GetValidatorSet(ctx context.Context, req *pb.GetValidatorSetReq
8080
}
8181
return resp, nil
8282
}
83+
84+
func (s *Server) GetCurrentValidatorSet(ctx context.Context, req *pb.GetCurrentValidatorSetRequest) (*pb.GetCurrentValidatorSetResponse, error) {
85+
subnetID, err := ids.ToID(req.SubnetId)
86+
if err != nil {
87+
return nil, err
88+
}
89+
90+
vdrs, currentHeight, err := s.state.GetCurrentValidatorSet(ctx, subnetID)
91+
if err != nil {
92+
return nil, err
93+
}
94+
95+
resp := &pb.GetCurrentValidatorSetResponse{
96+
Validators: make([]*pb.Validator, len(vdrs)),
97+
CurrentHeight: currentHeight,
98+
}
99+
100+
i := 0
101+
for _, vdr := range vdrs {
102+
vdrPB := &pb.Validator{
103+
NodeId: vdr.NodeID.Bytes(),
104+
StartTime: vdr.StartTime,
105+
IsActive: vdr.IsActive,
106+
ValidationId: vdr.ValidationID[:],
107+
Weight: vdr.Weight,
108+
MinNonce: vdr.MinNonce,
109+
IsSov: vdr.IsSoV,
110+
}
111+
if vdr.PublicKey != nil {
112+
// Passing in the uncompressed bytes is a performance optimization
113+
// to avoid the cost of calling PublicKeyFromCompressedBytes on the
114+
// client side.
115+
vdrPB.PublicKey = bls.PublicKeyToUncompressedBytes(vdr.PublicKey)
116+
}
117+
resp.Validators[i] = vdrPB
118+
i++
119+
}
120+
return resp, nil
121+
}

snow/validators/state.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ type State interface {
3232
height uint64,
3333
subnetID ids.ID,
3434
) (map[ids.NodeID]*GetValidatorOutput, error)
35+
36+
// GetCurrentValidatorSet returns the current validators of the provided subnet
37+
// and the current P-Chain height.
38+
// Map is keyed by ValidationID.
39+
GetCurrentValidatorSet(
40+
ctx context.Context,
41+
subnetID ids.ID,
42+
) (map[ids.ID]*GetCurrentValidatorOutput, uint64, error)
3543
}
3644

3745
type lockedState struct {
@@ -78,6 +86,16 @@ func (s *lockedState) GetValidatorSet(
7886
return s.s.GetValidatorSet(ctx, height, subnetID)
7987
}
8088

89+
func (s *lockedState) GetCurrentValidatorSet(
90+
ctx context.Context,
91+
subnetID ids.ID,
92+
) (map[ids.ID]*GetCurrentValidatorOutput, uint64, error) {
93+
s.lock.Lock()
94+
defer s.lock.Unlock()
95+
96+
return s.s.GetCurrentValidatorSet(ctx, subnetID)
97+
}
98+
8199
type noValidators struct {
82100
State
83101
}
@@ -91,3 +109,8 @@ func NewNoValidatorsState(state State) State {
91109
func (*noValidators) GetValidatorSet(context.Context, uint64, ids.ID) (map[ids.NodeID]*GetValidatorOutput, error) {
92110
return nil, nil
93111
}
112+
113+
func (n *noValidators) GetCurrentValidatorSet(ctx context.Context, _ ids.ID) (map[ids.ID]*GetCurrentValidatorOutput, uint64, error) {
114+
height, err := n.GetCurrentHeight(ctx)
115+
return nil, height, err
116+
}

snow/validators/traced_state.go

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,24 @@ import (
1717
var _ State = (*tracedState)(nil)
1818

1919
type tracedState struct {
20-
s State
21-
getMinimumHeightTag string
22-
getCurrentHeightTag string
23-
getSubnetIDTag string
24-
getValidatorSetTag string
25-
tracer trace.Tracer
20+
s State
21+
getMinimumHeightTag string
22+
getCurrentHeightTag string
23+
getSubnetIDTag string
24+
getValidatorSetTag string
25+
getCurrentValidatorSetTag string
26+
tracer trace.Tracer
2627
}
2728

2829
func Trace(s State, name string, tracer trace.Tracer) State {
2930
return &tracedState{
30-
s: s,
31-
getMinimumHeightTag: name + ".GetMinimumHeight",
32-
getCurrentHeightTag: name + ".GetCurrentHeight",
33-
getSubnetIDTag: name + ".GetSubnetID",
34-
getValidatorSetTag: name + ".GetValidatorSet",
35-
tracer: tracer,
31+
s: s,
32+
getMinimumHeightTag: name + ".GetMinimumHeight",
33+
getCurrentHeightTag: name + ".GetCurrentHeight",
34+
getSubnetIDTag: name + ".GetSubnetID",
35+
getValidatorSetTag: name + ".GetValidatorSet",
36+
getCurrentValidatorSetTag: name + ".GetCurrentValidatorSet",
37+
tracer: tracer,
3638
}
3739
}
3840

@@ -72,3 +74,15 @@ func (s *tracedState) GetValidatorSet(
7274

7375
return s.s.GetValidatorSet(ctx, height, subnetID)
7476
}
77+
78+
func (s *tracedState) GetCurrentValidatorSet(
79+
ctx context.Context,
80+
subnetID ids.ID,
81+
) (map[ids.ID]*GetCurrentValidatorOutput, uint64, error) {
82+
ctx, span := s.tracer.Start(ctx, s.getCurrentValidatorSetTag, oteltrace.WithAttributes(
83+
attribute.Stringer("subnetID", subnetID),
84+
))
85+
defer span.End()
86+
87+
return s.s.GetCurrentValidatorSet(ctx, subnetID)
88+
}

snow/validators/validator.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,14 @@ type GetValidatorOutput struct {
2929
PublicKey *bls.PublicKey
3030
Weight uint64
3131
}
32+
33+
type GetCurrentValidatorOutput struct {
34+
ValidationID ids.ID
35+
NodeID ids.NodeID
36+
PublicKey *bls.PublicKey
37+
Weight uint64
38+
StartTime uint64
39+
MinNonce uint64
40+
IsActive bool
41+
IsSoV bool
42+
}

snow/validators/validatorsmock/state.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)