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

Implement Eth1Data RPC Server Functionality #1615

Merged
merged 17 commits into from
Feb 20, 2019
Merged

Implement Eth1Data RPC Server Functionality #1615

merged 17 commits into from
Feb 20, 2019

Conversation

rauljordan
Copy link
Contributor

This is part of #1565 and resolves #1463, and is related to #1456


Description

This PR implements the Eth1Data RPC server functionality in our beacon server for proposers necessary information related to Eth1Data votes to include in their blocks. This PR uses an interface for required information from the powchain service such as CurrentHeight and BlockExists. Those functions will be implemented in a separate PR. This PR only concerns itself with the beacon-chain/rpc package to keep the scope small and easier to review.

This PR implements the logic found in the honest validator specification as of commit hash 375659dc6c92ddcbf1682a024f9afc4fb24335c6 below:

Eth1 Data

block.eth1_data 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.

  • Let D 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, and (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.
  • If D 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 D is nonempty:
    • 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.
  • Set block.eth1_data = Eth1Data(deposit_root=deposit_root, block_hash=block_hash).

@rauljordan rauljordan added this to the Sapphire milestone Feb 15, 2019
@rauljordan rauljordan self-assigned this Feb 15, 2019
@codecov
Copy link

codecov bot commented Feb 16, 2019

Codecov Report

Merging #1615 into master will decrease coverage by 0.41%.
The diff coverage is 22.22%.

@@            Coverage Diff             @@
##           master    #1615      +/-   ##
==========================================
- Coverage   71.56%   71.15%   -0.42%     
==========================================
  Files          94       94              
  Lines        6500     6562      +62     
==========================================
+ Hits         4652     4669      +17     
- Misses       1439     1482      +43     
- Partials      409      411       +2

@codecov
Copy link

codecov bot commented Feb 16, 2019

Codecov Report

Merging #1615 into master will increase coverage by 0.34%.
The diff coverage is 63.15%.

@@            Coverage Diff             @@
##           master    #1615      +/-   ##
==========================================
+ Coverage   70.77%   71.12%   +0.34%     
==========================================
  Files          98       94       -4     
  Lines        7060     6652     -408     
==========================================
- Hits         4997     4731     -266     
+ Misses       1626     1498     -128     
+ Partials      437      423      -14

@rauljordan rauljordan marked this pull request as ready for review February 16, 2019 01:43
@rauljordan rauljordan requested review from prestonvanloon, nisdas and terencechain and removed request for prestonvanloon, nisdas and terencechain February 16, 2019 01:43
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.

One comment on how we get depositRoot when dataVoteObjects is empty

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, blockNumber, err := bs.powChainService.BlockExists(eth1Hash)
Copy link
Member

Choose a reason for hiding this comment

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

instead of blockNumber, we should try to use blockHeight so its consistent with the rest

// at the block defined by vote.eth1_data.block_hash.
isBehindFollowDistance := blockNumber.Add(blockNumber, big.NewInt(eth1FollowDistance)).Cmp(currentHeight) == -1
isAheadStateLatestEth1Data := blockNumber.Cmp(stateLatestEth1Height) == 1
if blockExists && isBehindFollowDistance && isAheadStateLatestEth1Data {
Copy link
Member

Choose a reason for hiding this comment

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

I think this whole check could use some better verbosity. If a Eth1DataVote does not get included, which condition failed and what are the numbers (how many blocks it needs to wait for it to get included.. etc)

func (w *Web3Service) DepositRoot() [32]byte {
return w.depositTrie.Root()
}

// LatestBlockNumber in the ETH1.0 chain.
func (w *Web3Service) LatestBlockNumber() *big.Int {
Copy link
Member

Choose a reason for hiding this comment

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

I think LatestBlockHeight sounds better here...

if err != nil {
return nil, fmt.Errorf("could not fetch ETH1_FOLLOW_DISTANCE ancestor: %v", err)
}
depositRoot := bs.powChainService.DepositRoot()
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is correct. We should get the depositRoot that is referenced by blockHash from ancestorHeight.

bs.powChainService.DepositRoot() just returns you the latest deposit root right?

Copy link
Member

Choose a reason for hiding this comment

The 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

Copy link
Member

Choose a reason for hiding this comment

The 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

if err != nil {
return nil, fmt.Errorf("could not fetch beacon state: %v", err)
}
dataVoteObjects := []*pbp2p.Eth1DataVote{}
Copy link
Member

Choose a reason for hiding this comment

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

optional:
s/dataVoteObjects/voteObjects
or
s/dataVoteOBjects/dataVotes

Copy link
Member

Choose a reason for hiding this comment

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

dataVotes sounds better imo

@@ -199,6 +205,18 @@ func (w *Web3Service) LatestBlockHash() common.Hash {
return w.blockHash
}

// BlockExists --
// Unimplemented, Work in Progress.
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 the issue number referencing the work here as a TODO, same as below

if err != nil {
return nil, fmt.Errorf("could not fetch beacon state: %v", err)
}
dataVoteObjects := []*pbp2p.Eth1DataVote{}
Copy link
Member

Choose a reason for hiding this comment

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

dataVotes sounds better imo

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, blockNumber, err := bs.powChainService.BlockExists(eth1Hash)
Copy link
Member

Choose a reason for hiding this comment

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

if blockExists == false we can skip the operations below

// Let dataVoteObjects 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
Copy link
Member

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 .

if err != nil {
return nil, fmt.Errorf("could not fetch ETH1_FOLLOW_DISTANCE ancestor: %v", err)
}
depositRoot := bs.powChainService.DepositRoot()
Copy link
Member

Choose a reason for hiding this comment

The 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

@terencechain
Copy link
Member

@rauljordan let me know when this is ready again

@rauljordan rauljordan merged commit 9bee695 into master Feb 20, 2019
@nisdas nisdas deleted the eth1server branch April 20, 2019 03:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Priority: High High priority item
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement BeaconService.Eth1Data (server-side)
3 participants