-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Implement Eth1Data RPC Server Functionality #1615
Changes from all commits
51d3ea5
fee3597
b4f6652
70dc1b0
6fede2e
7b7eca1
d34b82a
787981e
ce1c508
dbe44e6
8ce79c1
8d81c1e
36ad4a4
ee98205
de816c9
3a8c9c6
434cdd5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ import ( | |
"math/big" | ||
"time" | ||
|
||
"github.com/prysmaticlabs/prysm/shared/bytesutil" | ||
|
||
ptypes "github.com/gogo/protobuf/types" | ||
"github.com/prysmaticlabs/prysm/beacon-chain/db" | ||
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" | ||
|
@@ -97,24 +99,122 @@ func (bs *BeaconServer) LatestAttestation(req *ptypes.Empty, stream pb.BeaconSer | |
} | ||
} | ||
|
||
// Eth1Data fetches the current ETH 1 data which should be used when voting via | ||
// block proposal. | ||
// TODO(1463): Implement this. | ||
// Eth1Data is a mechanism used by block proposers vote on a recent Ethereum 1.0 block hash and an | ||
// associated deposit root found in the Ethereum 1.0 deposit contract. When consensus is formed, | ||
// state.latest_eth1_data is updated, and validator deposits up to this root can be processed. | ||
// The deposit root can be calculated by calling the get_deposit_root() function of | ||
// the deposit contract using the post-state of the block hash. | ||
func (bs *BeaconServer) Eth1Data(ctx context.Context, _ *ptypes.Empty) (*pb.Eth1DataResponse, error) { | ||
return &pb.Eth1DataResponse{}, nil | ||
beaconState, err := bs.beaconDB.State() | ||
if err != nil { | ||
return nil, fmt.Errorf("could not fetch beacon state: %v", err) | ||
} | ||
dataVotes := []*pbp2p.Eth1DataVote{} | ||
eth1FollowDistance := int64(params.BeaconConfig().Eth1FollowDistance) | ||
for _, vote := range beaconState.Eth1DataVotes { | ||
eth1Hash := bytesutil.ToBytes32(vote.Eth1Data.BlockHash32) | ||
// Verify the block from the vote's block hash exists in the eth1.0 chain and fetch its height. | ||
blockExists, blockHeight, err := bs.powChainService.BlockExists(eth1Hash) | ||
if err != nil { | ||
log.Errorf("Could not verify block with hash exists in Eth1 chain: %#x: %v", eth1Hash, err) | ||
continue | ||
} | ||
if !blockExists { | ||
continue | ||
} | ||
// Fetch the current canonical chain height from the eth1.0 chain. | ||
currentHeight := bs.powChainService.LatestBlockHeight() | ||
// Fetch the height of the block pointed to by the beacon state's latest_eth1_data.block_hash | ||
// in the canonical, eth1.0 chain. | ||
stateLatestEth1Hash := bytesutil.ToBytes32(beaconState.LatestEth1Data.BlockHash32) | ||
_, stateLatestEth1Height, err := bs.powChainService.BlockExists(stateLatestEth1Hash) | ||
if err != nil { | ||
log.Errorf("Could not verify block with hash exists in Eth1 chain: %#x: %v", eth1Hash, err) | ||
continue | ||
} | ||
// Let dataVotes be the set of Eth1DataVote objects vote in state.eth1_data_votes where: | ||
// vote.eth1_data.block_hash is the hash of an eth1.0 block that is: | ||
// (i) part of the canonical chain | ||
// (ii) >= ETH1_FOLLOW_DISTANCE blocks behind the head | ||
// (iii) newer than state.latest_eth1_data.block_data. | ||
// vote.eth1_data.deposit_root is the deposit root of the eth1.0 deposit contract | ||
// at the block defined by vote.eth1_data.block_hash. | ||
isBehindFollowDistance := blockHeight.Add(blockHeight, big.NewInt(eth1FollowDistance)).Cmp(currentHeight) >= -1 | ||
isAheadStateLatestEth1Data := blockHeight.Cmp(stateLatestEth1Height) == 1 | ||
if blockExists && isBehindFollowDistance && isAheadStateLatestEth1Data { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this whole check could use some better verbosity. If a |
||
dataVotes = append(dataVotes, vote) | ||
} | ||
} | ||
|
||
// Now we handle the following two scenarios: | ||
// If dataVotes is empty: | ||
// Let block_hash be the block hash of the ETH1_FOLLOW_DISTANCE'th ancestor of the head of | ||
// the canonical eth1.0 chain. | ||
// Let deposit_root be the deposit root of the eth1.0 deposit contract in the | ||
// post-state of the block referenced by block_hash. | ||
if len(dataVotes) == 0 { | ||
// Fetch the current canonical chain height from the eth1.0 chain. | ||
currentHeight := bs.powChainService.LatestBlockHeight() | ||
ancestorHeight := currentHeight.Sub(currentHeight, big.NewInt(eth1FollowDistance)) | ||
blockHash, err := bs.powChainService.BlockHashByHeight(ancestorHeight) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not fetch ETH1_FOLLOW_DISTANCE ancestor: %v", err) | ||
} | ||
// TODO(#1656): Fetch the deposit root of the post-state deposit contract of the block | ||
// references by the block hash of the ancestor instead. | ||
depositRoot := bs.powChainService.DepositRoot() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is correct. We should get the bs.powChainService.DepositRoot() just returns you the latest deposit root right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @terenc3t there is no way to actually do that now, we dont keep a list of all the previous deposit roots. When we get a deposit log we just update the deposit trie and create a new root. Also deposit root is dependant on the merkle index of the deposit not the block number. We could have multiple deposits in a block , generating multiple deposit roots There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's fine we can't do this now but where is the comment or note saying our implementation does diverge from the spec |
||
return &pb.Eth1DataResponse{ | ||
Eth1Data: &pbp2p.Eth1Data{ | ||
DepositRootHash32: depositRoot[:], | ||
BlockHash32: blockHash[:], | ||
}, | ||
}, nil | ||
} | ||
|
||
// If dataVotes is non-empty: | ||
// Let best_vote be the member of D that has the highest vote.eth1_data.vote_count, | ||
// breaking ties by favoring block hashes with higher associated block height. | ||
// Let block_hash = best_vote.eth1_data.block_hash. | ||
// Let deposit_root = best_vote.eth1_data.deposit_root. | ||
bestVote := dataVotes[0] | ||
for i := 1; i < len(dataVotes); i++ { | ||
vote := dataVotes[i] | ||
if vote.VoteCount > bestVote.VoteCount { | ||
bestVote = vote | ||
} else if vote.VoteCount == bestVote.VoteCount { | ||
bestVoteHash := bytesutil.ToBytes32(bestVote.Eth1Data.BlockHash32) | ||
voteHash := bytesutil.ToBytes32(vote.Eth1Data.BlockHash32) | ||
_, bestVoteHeight, err := bs.powChainService.BlockExists(bestVoteHash) | ||
if err != nil { | ||
log.Errorf("Could not fetch block height: %v", err) | ||
continue | ||
} | ||
_, voteHeight, err := bs.powChainService.BlockExists(voteHash) | ||
if err != nil { | ||
log.Errorf("Could not fetch block height: %v", err) | ||
continue | ||
} | ||
if voteHeight.Cmp(bestVoteHeight) == 1 { | ||
bestVote = vote | ||
} | ||
} | ||
} | ||
return &pb.Eth1DataResponse{ | ||
Eth1Data: &pbp2p.Eth1Data{ | ||
BlockHash32: bestVote.Eth1Data.BlockHash32, | ||
DepositRootHash32: bestVote.Eth1Data.DepositRootHash32, | ||
}, | ||
}, nil | ||
} | ||
|
||
// PendingDeposits returns a list of pending deposits that are ready for | ||
// inclusion in the next beacon block. | ||
func (bs *BeaconServer) PendingDeposits(ctx context.Context, _ *ptypes.Empty) (*pb.PendingDepositsResponse, error) { | ||
bNum := bs.powChainService.LatestBlockNumber() | ||
|
||
bNum := bs.powChainService.LatestBlockHeight() | ||
if bNum == nil { | ||
return nil, errors.New("latest PoW block number is unknown") | ||
} | ||
|
||
// Only request deposits that have passed the ETH1 follow distance window. | ||
bNum = bNum.Sub(bNum, big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))) | ||
|
||
return &pb.PendingDepositsResponse{PendingDeposits: bs.beaconDB.PendingDeposits(ctx, bNum)}, 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.
the code below represents
> ETH1_FOLLOW_DISTANCE blocks behind the head
not>= ETH1_FOLLOW_DISTANCE blocks behind the head
.