Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Update Attester to Use Beacon Node RPC, Replacing SMC Completely #365

Merged
merged 67 commits into from
Aug 9, 2018

Conversation

rauljordan
Copy link
Contributor

@rauljordan rauljordan commented Aug 1, 2018

Hi all,

This PR is part of the greater effort of #315 and we are beginning with updating the attester package in our client project to interact with the beacon chain completely via RPC for shuffling and determining attestation height responsibility. This eliminates the need for the Sharding Manager Contract and completely deprecates it within the attester package. Similar work will need to be done for the proposer package.

This PR ensures attester is aligned with the latest beacon chain + sharding specification.

Design Decisions

This package defines server-side RPC methods for the beacon chain and leverages gomock for testing the client side requests to these methods. The attester service has two responsibilities:

  1. Listen for the latest crystallized state from a beacon node via gRPC stream, use the active validator list, cutoffs, and more to determine the height the attester should perform its responsibility
  2. Listen for the latest canonical beacon block from a beacon node via a gRPC stream, check the height against the assigned attestation height from step 1 and perform an attestation

Mocks

This package leverages gRPC mocks through gomock and mockgen for testing. We check in the mocks into client/internal for now until we are able to generate them with Bazel. To regenerate the mocks, run

mockgen github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1 BeaconServiceClient,BeaconService_LatestBeaconBlockClient,BeaconService_LatestCrystallizedStateClient > ./client/internal/beacon_service_mock.go

Requirements for Merge

  • Tests
  • Fetching Beacon Block Height + Hash Via RPC Stream
  • Fetch Crystallized State and Determine Attester Assigned Height via RPC

@@ -18,34 +16,6 @@ go_library(
],
)

go_image(
Copy link
Member

Choose a reason for hiding this comment

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

Why did you remove the docker image support for the client?

Please revert this change

activeValidators := crystallizedState.GetActiveValidators()
validatorCount := len(activeValidators)

validatorIndexSet := false
Copy link
Member

Choose a reason for hiding this comment

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

Please change to a Boolean like name: isValidatorIndexSet.

Otherwise I think of this as a set of validator indices.

for i, val := range activeValidators {
// TODO: Check the public key instead of withdrawal address. This will
// use BLS.
if bytes.Equal(val.GetWithdrawalAddress(), []byte{}) {
Copy link
Member

Choose a reason for hiding this comment

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

Can you create a constant for this so it’s been easier to understand?

var ZERO_ADDRESS = []byte{}

Or something like that

And/or maybe a helper on ValidatorRecord IsWithdrawalAddressSet()

}
for {
block, err := stream.Recv()
if err == io.EOF {
Copy link
Member

Choose a reason for hiding this comment

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

Please add comment for clarity. This means the stream was closed but it is not intuitive.

// its responsibilities.

if at.isHeightAssigned && block.GetSlotNumber() == at.assignedHeight {
log.Info("Assigned attestation height reached, performing attestation responsibility")
Copy link
Member

Choose a reason for hiding this comment

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

Should there be a TODO here?

@@ -67,8 +71,8 @@ func (s *Service) Stop() error {
}

// ShuffleValidators shuffles the validators into attesters/proposers.
func (s *Service) ShuffleValidators(req *pb.ShuffleRequest, stream pb.BeaconService_ShuffleValidatorsServer) error {
return stream.Send(&pb.ShuffleResponse{IsProposer: true, IsAttester: false})
func (s *Service) ShuffleValidators(ctx context.Context, req *pb.ShuffleRequest) (*pb.ShuffleResponse, error) {
Copy link
Member

Choose a reason for hiding this comment

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

So why this no longer a stream? Are validators shuffled on demand or periodically? Doesn't a client want a stream of events?

Could you add some more detail on what this service method is supposed to do?

return
}
for {
crystallizedState, err := stream.Recv()
if err == io.EOF {
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a comment here to clarify that this is a closed stream.

log.Fatalf("Could not parse endpoint URL: %s, %v", s.endpoint, err)
return
}
conn, err := grpc.Dial(fmt.Sprintf("localhost:%s", endpointURL.Port()), grpc.WithInsecure())
Copy link
Member

Choose a reason for hiding this comment

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

Localhost?

Copy link
Member

@prestonvanloon prestonvanloon left a comment

Choose a reason for hiding this comment

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

Why move Travis file?

Copy link
Member

@prestonvanloon prestonvanloon left a comment

Choose a reason for hiding this comment

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

Also, please do not generate a mock with the_test.go suffix. Otherwise this leaks into the production binary.

@@ -36,9 +38,14 @@ func NewRPCClient(ctx context.Context, cfg *Config) *Service {
// Start the grpc connection.
func (s *Service) Start() {
log.Info("Starting service")
conn, err := grpc.Dial(s.endpoint, grpc.WithInsecure())
endpointURL, err := url.Parse(s.endpoint)
Copy link
Member

Choose a reason for hiding this comment

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

Is this necessary?

@codecov
Copy link

codecov bot commented Aug 9, 2018

Codecov Report

Merging #365 into master will increase coverage by 2.96%.
The diff coverage is 88.46%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #365      +/-   ##
==========================================
+ Coverage   49.15%   52.12%   +2.96%     
==========================================
  Files          35       34       -1     
  Lines        2836     2826      -10     
==========================================
+ Hits         1394     1473      +79     
+ Misses       1245     1163      -82     
+ Partials      197      190       -7
Impacted Files Coverage Δ
beacon-chain/utils/shuffle.go 100% <100%> (ø) ⬆️
beacon-chain/node/node.go 40.17% <100%> (ø) ⬆️
client/attester/service.go 100% <100%> (+100%) ⬆️
beacon-chain/rpc/service.go 100% <100%> (+31.7%) ⬆️
beacon-chain/blockchain/core.go 65.78% <100%> (-1.06%) ⬇️
client/node/node.go 36.49% <14.28%> (+0.46%) ⬆️
beacon-chain/blockchain/service.go 22% <28.57%> (-0.69%) ⬇️
client/rpcclient/service.go 87.09% <50%> (+29.03%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 390ac62...9d2e409. Read the comment docs.

Copy link
Member

@prestonvanloon prestonvanloon left a comment

Choose a reason for hiding this comment

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

LGTM

I was hesitant about putting the mocks in internal as it might be used in production code, but that target is marked as test only so I am happy.

Thanks

func TestRPCMethods(t *testing.T) {
s := &Service{}
if _, err := s.FetchShuffledValidatorIndices(context.Background(), nil); err == nil {
t.Error("Wanted error: unimplemented, received nil")
Copy link
Member

Choose a reason for hiding this comment

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

This is OK, but a better pattern is to check that the error returned was the error you expect.

This assertion is that any error returns.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This will be changed very soon once we implement the logic of the beacon RPC server

@rauljordan rauljordan merged commit cd90598 into prysmaticlabs:master Aug 9, 2018
Copy link
Member

@terencechain terencechain left a comment

Choose a reason for hiding this comment

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

just one typo, we can fix it in the next pr.

// FetchShuffledValidatorIndices retrieves the shuffled validator indices, cutoffs, and
// assigned attestation heights at a given crystallized state hash.
// This function can be called by clients to fetch a historical list of shuffled
// validators ata point in time corresponding to a certain crystallized state.
Copy link
Member

Choose a reason for hiding this comment

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

s/ata/at

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants