-
Notifications
You must be signed in to change notification settings - Fork 922
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
Blinded block APIs #10331
Blinded block APIs #10331
Conversation
# Conflicts: # beacon-chain/rpc/apimiddleware/custom_hooks.go
} | ||
|
||
var actualRespContainer interface{} | ||
if strings.EqualFold(respContainer.Version, strings.ToLower(ethpbv2.Version_PHASE0.String())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a switch
statement on respContainer.Version
will look much nicer than if else if else if else
|
||
root, err := phase0Blk.HashTreeRoot() | ||
if err != nil { | ||
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err) | ||
} | ||
|
||
// Do not block proposal critical path with debug logging or block feed updates. | ||
defer func() { | ||
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(root[:]))).Debugf( | ||
"Block proposal received via RPC") | ||
bs.BlockNotifier.BlockFeed().Send(&feed.Event{ | ||
Type: blockfeed.ReceivedBlock, | ||
Data: &blockfeed.ReceivedBlockData{SignedBlock: wrappedPhase0Blk}, | ||
}) | ||
}() | ||
|
||
// Broadcast the new block to the network. | ||
if err := bs.Broadcaster.Broadcast(ctx, wrappedPhase0Blk.Proto()); err != nil { | ||
return status.Errorf(codes.Internal, "Could not broadcast block: %v", err) | ||
} | ||
|
||
if err := bs.BlockReceiver.ReceiveBlock(ctx, wrappedPhase0Blk, root); err != nil { | ||
return status.Errorf(codes.Internal, "Could not process beacon block: %v", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (bs *Server) submitAltairBlock(ctx context.Context, altairBlk *ethpbv2.BeaconBlockAltair, sig []byte) error { | ||
v1alpha1Blk, err := migration.AltairToV1Alpha1SignedBlock(ðpbv2.SignedBeaconBlockAltair{Message: altairBlk, Signature: sig}) | ||
if err != nil { | ||
return status.Errorf(codes.InvalidArgument, "Could not convert block to v1 block") | ||
} | ||
wrappedAltairBlk, err := wrapper.WrappedAltairSignedBeaconBlock(v1alpha1Blk) | ||
if err != nil { | ||
return status.Errorf(codes.InvalidArgument, "Could not prepare Altair block") | ||
} | ||
|
||
root, err := altairBlk.HashTreeRoot() | ||
if err != nil { | ||
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err) | ||
} | ||
|
||
// Do not block proposal critical path with debug logging or block feed updates. | ||
defer func() { | ||
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(root[:]))).Debugf( | ||
"Block proposal received via RPC") | ||
bs.BlockNotifier.BlockFeed().Send(&feed.Event{ | ||
Type: blockfeed.ReceivedBlock, | ||
Data: &blockfeed.ReceivedBlockData{SignedBlock: wrappedAltairBlk}, | ||
}) | ||
}() | ||
|
||
// Broadcast the new block to the network. | ||
if err := bs.Broadcaster.Broadcast(ctx, wrappedAltairBlk.Proto()); err != nil { | ||
return status.Errorf(codes.Internal, "Could not broadcast block: %v", err) | ||
} | ||
|
||
if err := bs.BlockReceiver.ReceiveBlock(ctx, wrappedAltairBlk, root); err != nil { | ||
return status.Errorf(codes.Internal, "Could not process beacon block: %v", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (bs *Server) submitBellatrixBlock(ctx context.Context, bellatrixBlk *ethpbv2.BeaconBlockBellatrix, sig []byte) error { | ||
v1alpha1Blk, err := migration.BellatrixToV1Alpha1SignedBlock(ðpbv2.SignedBeaconBlockBellatrix{Message: bellatrixBlk, Signature: sig}) | ||
if err != nil { | ||
return status.Errorf(codes.InvalidArgument, "Could not convert block to v1 block") | ||
} | ||
wrappedBellatrixBlk, err := wrapper.WrappedBellatrixSignedBeaconBlock(v1alpha1Blk) | ||
if err != nil { | ||
return status.Errorf(codes.InvalidArgument, "Could not prepare bellatrix block") | ||
} | ||
|
||
root, err := bellatrixBlk.HashTreeRoot() | ||
if err != nil { | ||
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err) | ||
} | ||
|
||
// Do not block proposal critical path with debug logging or block feed updates. | ||
defer func() { | ||
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(root[:]))).Debugf( | ||
"Block proposal received via RPC") | ||
bs.BlockNotifier.BlockFeed().Send(&feed.Event{ | ||
Type: blockfeed.ReceivedBlock, | ||
Data: &blockfeed.ReceivedBlockData{SignedBlock: wrappedBellatrixBlk}, | ||
}) | ||
}() | ||
|
||
// Broadcast the new block to the network. | ||
if err := bs.Broadcaster.Broadcast(ctx, wrappedBellatrixBlk.Proto()); err != nil { | ||
return status.Errorf(codes.Internal, "Could not broadcast block: %v", err) | ||
} | ||
|
||
if err := bs.BlockReceiver.ReceiveBlock(ctx, wrappedBellatrixBlk, root); err != nil { | ||
return status.Errorf(codes.Internal, "Could not process beacon block: %v", err) | ||
} | ||
|
||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you dedup it the same way that is similar to #10368 ?
It'll make @prestonvanloon very happy :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You had similar feedback in #10324 (comment). Can I merge the two into a separate PR?
# Conflicts: # beacon-chain/rpc/apimiddleware/custom_hooks.go # beacon-chain/rpc/eth/validator/validator.go
} | ||
if b.ExecutionPayloadHeader == nil { | ||
b.ExecutionPayloadHeader = &enginev1.ExecutionPayloadHeader{ | ||
ParentHash: make([]byte, 32), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use named constants for these numbers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated all roots to constants. Although you could argue that hashes should use the same constant, we are not doing this at the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another pass. I am ~33% there
if currentEpoch < params.BeaconConfig().AltairForkEpoch { | ||
endpoint.PostRequest = &signedBeaconBlockContainerJson{} | ||
} else if currentEpoch < params.BeaconConfig().BellatrixForkEpoch { | ||
endpoint.PostRequest = &signedBeaconBlockAltairContainerJson{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the blocks before Bellatrix blinded as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, we return regular blocks in that case.
@@ -270,6 +270,12 @@ type produceBlockResponseV2Json struct { | |||
Data *beaconBlockContainerV2Json `json:"data"` | |||
} | |||
|
|||
// produceBlindedBlockResponseJson is used in /v1/validator/blinded_blocks/{slot} API endpoint. | |||
type produceBlindedBlockResponseJson struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the difference between bellatrixProduceBlindedBlockResponseJson
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
produceBlindedBlockResponseJson
comes back from gRPC and includes a Data
field, which itself has 3 fields:
Phase0Block
AltairBlock
BellatrixBlock
This is because we use a oneof
in protobuf. The purpose of bellatrixProduceBlindedBlockResponseJson
is to contain only one field (apart from version) which gets returned from HTTP - the bellatrix block.
root, err := phase0Blk.HashTreeRoot() | ||
if err != nil { | ||
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err) | ||
} | ||
|
||
// Do not block proposal critical path with debug logging or block feed updates. | ||
defer func() { | ||
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(root[:]))).Debugf( | ||
"Block proposal received via RPC") | ||
bs.BlockNotifier.BlockFeed().Send(&feed.Event{ | ||
Type: blockfeed.ReceivedBlock, | ||
Data: &blockfeed.ReceivedBlockData{SignedBlock: wrappedPhase0Blk}, | ||
}) | ||
}() | ||
|
||
// Broadcast the new block to the network. | ||
if err := bs.Broadcaster.Broadcast(ctx, wrappedPhase0Blk.Proto()); err != nil { | ||
return status.Errorf(codes.Internal, "Could not broadcast block: %v", err) | ||
} | ||
|
||
if err := bs.BlockReceiver.ReceiveBlock(ctx, wrappedPhase0Blk, root); err != nil { | ||
return status.Errorf(codes.Internal, "Could not process beacon block: %v", err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if you could share these four calls among phase0, altair and bellatrix (not blinded)
cf92f28
to
27504ea
Compare
// gRPC expects either an XXX_block field in the JSON object, but we have a message field at this point. | ||
// We do a simple conversion depending on the type of endpoint.PostRequest | ||
// (which was filled out previously in setInitialPublishBlockPostRequest). | ||
func preparePublishedBlindedBlock(endpoint *apimiddleware.Endpoint, _ http.ResponseWriter, _ *http.Request) apimiddleware.ErrorJson { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we have checks for phase0 and altair blocks here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The spec allows publishing regular blocks through this endpoint for these forks. See https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Beacon/publishBlindedBlock (you need to click the Schema
button and expand the oneOf
)
// `BeaconBlock`, and a successful response (20X) only indicates that the broadcast has been | ||
// successful. The beacon node is expected to integrate the new block into its state, and | ||
// therefore validate the block internally, however blocks which fail the validation are still | ||
// broadcast but a different status code is returned (202). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't 20X cover 202?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I copied this description from the spec. I think what this tries to say is that a code different than 200
is returned.
root, err := wsb.Block().HashTreeRoot() | ||
if err != nil { | ||
return nil, status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err) | ||
phase0BlkContainer, ok := req.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_Phase0Block) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: does it make sense to invert the order of these requests? I suppose we are more likely to submit a blinded bellatrix block.
root, err := blindedBellatrixBlk.HashTreeRoot() | ||
if err != nil { | ||
return status.Errorf(codes.Internal, "Could not calculate block root: %v", err) | ||
} | ||
signedBlk, err := bs.BeaconDB.Block(ctx, root) | ||
if err != nil { | ||
return status.Errorf(codes.Internal, "Could not calculate get non-blinded block from DB: %v", err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not quite right. We won't have the block in DB.
We have to process the blinded block. I have a PR for this, I can open it next week, so this makes the right ReceiveBlock
call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not quite right. We won't have the block in DB.
Wow, of course. This would come up while testing on a testnet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use #10473 :)
# Conflicts: # proto/eth/v2/generated.ssz.go
Signature: sig, | ||
}) | ||
if err != nil { | ||
return status.Errorf(codes.Internal, "Could not get non-blinded block: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these error messages correct? These are blinded blocks no?
# Conflicts: # proto/eth/v2/beacon_state.pb.go # proto/eth/v2/beacon_state.proto # proto/eth/v2/generated.ssz.go # proto/migration/v1alpha1_to_v2.go
What type of PR is this?
Feature
What does this PR do? Why is it needed?
Implements
publishBlindedBlock
andproduceBlindedBlock
API endpoints as described in ethereum/beacon-APIs#194