mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-11 06:18:05 -05:00
Compare commits
168 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bea237397 | ||
|
|
c877efd90e | ||
|
|
2e33595187 | ||
|
|
e1ac1d3d80 | ||
|
|
fdad7e67b0 | ||
|
|
cc07494e67 | ||
|
|
5f53f9fde1 | ||
|
|
3a295fb3ec | ||
|
|
2f88174d0d | ||
|
|
546196a6fa | ||
|
|
4d30519dda | ||
|
|
2c1e3aa4ee | ||
|
|
3416962fc2 | ||
|
|
3fc6afa02e | ||
|
|
05fcb1073a | ||
|
|
81a7bc7e05 | ||
|
|
84e51a5236 | ||
|
|
3b2c514c06 | ||
|
|
94155191b7 | ||
|
|
5636cd3ed8 | ||
|
|
44611e0fb2 | ||
|
|
5ed72d4ef9 | ||
|
|
d0e30ceab2 | ||
|
|
9e79809586 | ||
|
|
9d173dcad2 | ||
|
|
e30349d410 | ||
|
|
6700383863 | ||
|
|
f84e5ad6ef | ||
|
|
44b93d9df9 | ||
|
|
8327c9d371 | ||
|
|
e9191e7d6c | ||
|
|
f19aa93de2 | ||
|
|
f70635a992 | ||
|
|
b6353da793 | ||
|
|
4da7701249 | ||
|
|
e3e9863d92 | ||
|
|
7d7480527e | ||
|
|
eb5513f8c2 | ||
|
|
07e8609b69 | ||
|
|
08a9fe98fc | ||
|
|
3782e70e6f | ||
|
|
258d0412c1 | ||
|
|
d0f3bea8d2 | ||
|
|
0806807d61 | ||
|
|
aca9691a0d | ||
|
|
faa5b309a2 | ||
|
|
8a9c9607a5 | ||
|
|
5fbf38c98f | ||
|
|
07f6894db1 | ||
|
|
3ac15e36a1 | ||
|
|
ffdf248738 | ||
|
|
cf98de86f4 | ||
|
|
f9eb54661a | ||
|
|
921263848a | ||
|
|
a33bd94ffb | ||
|
|
2ebd684924 | ||
|
|
37b68ba983 | ||
|
|
a78035d6ed | ||
|
|
a3eeced194 | ||
|
|
d1b0348cdb | ||
|
|
a6a2ad4409 | ||
|
|
49ca0751b6 | ||
|
|
2f2124973b | ||
|
|
8b058b51d4 | ||
|
|
9c012cc0c8 | ||
|
|
9e6b6bc009 | ||
|
|
db6dbdcde4 | ||
|
|
482a054ee1 | ||
|
|
1480d2bfa8 | ||
|
|
793c3d27f2 | ||
|
|
f880fb4ee4 | ||
|
|
7b38e97e83 | ||
|
|
e753cbb04b | ||
|
|
c2daf8d82e | ||
|
|
480ddb7c3d | ||
|
|
0f08bd288c | ||
|
|
8cba109350 | ||
|
|
199c50be47 | ||
|
|
c69f561fb9 | ||
|
|
19b879ec17 | ||
|
|
54faf8564f | ||
|
|
c8fa31ac97 | ||
|
|
25102e0978 | ||
|
|
60bf3edf0a | ||
|
|
982d93547a | ||
|
|
7b89b17ed2 | ||
|
|
2a0711ab01 | ||
|
|
9255a2b3c1 | ||
|
|
61c96f50a0 | ||
|
|
b663086a88 | ||
|
|
37cba662f1 | ||
|
|
fae307e5a2 | ||
|
|
639e3072fe | ||
|
|
984644257e | ||
|
|
9ae492e2cd | ||
|
|
1c6d1fabf3 | ||
|
|
b61d320613 | ||
|
|
62da94bd0b | ||
|
|
7d8516cd71 | ||
|
|
95f1676d5f | ||
|
|
42e6532d5b | ||
|
|
acd7dd137f | ||
|
|
626b3e0c66 | ||
|
|
dee3f02e2c | ||
|
|
f2d88ea920 | ||
|
|
33774721bb | ||
|
|
0ed0cb58f8 | ||
|
|
62fa6ed2e9 | ||
|
|
c3217abb83 | ||
|
|
fb26177a2a | ||
|
|
0078f42554 | ||
|
|
1224e75ba1 | ||
|
|
b0af12d5dc | ||
|
|
c0ca567175 | ||
|
|
9cec33fe24 | ||
|
|
62213ca602 | ||
|
|
ce6ce5a397 | ||
|
|
7a65e0ee3f | ||
|
|
475d428fce | ||
|
|
2f15f16650 | ||
|
|
46b19072f4 | ||
|
|
50d67f52bb | ||
|
|
62c25eaedb | ||
|
|
28733f2c9e | ||
|
|
0803f0f0ff | ||
|
|
52b46d4570 | ||
|
|
8a3ea1e936 | ||
|
|
17c1fc3250 | ||
|
|
3763a8ce5d | ||
|
|
075d29f5b4 | ||
|
|
c70103bdb3 | ||
|
|
0ecd2a6dc2 | ||
|
|
4fbcedf541 | ||
|
|
5a1a768135 | ||
|
|
21f51993c5 | ||
|
|
5eb6485e14 | ||
|
|
ea84f44307 | ||
|
|
144f37e994 | ||
|
|
046a00aa87 | ||
|
|
497fa6ed50 | ||
|
|
899670e1e9 | ||
|
|
ef21456c8a | ||
|
|
92131695b1 | ||
|
|
24fc67a6dd | ||
|
|
dc5ed7a80e | ||
|
|
cb045dd0e3 | ||
|
|
748d513c62 | ||
|
|
3b9a03d517 | ||
|
|
d5ddd012bc | ||
|
|
a85bf9305d | ||
|
|
c76034147e | ||
|
|
d8c57541e4 | ||
|
|
28a9adc49b | ||
|
|
e59721f264 | ||
|
|
40f7b258eb | ||
|
|
8c9ae8e3bf | ||
|
|
29f43190fc | ||
|
|
b69c76c879 | ||
|
|
ca0912e5d8 | ||
|
|
2e570d7427 | ||
|
|
973a0a89b5 | ||
|
|
1d8b207d7c | ||
|
|
7a5010ecea | ||
|
|
7b8bad35e7 | ||
|
|
fa435d39bb | ||
|
|
159ef3d702 | ||
|
|
06db5f6471 | ||
|
|
a7bee79988 |
2
.bazelrc
2
.bazelrc
@@ -15,7 +15,7 @@ run --host_force_python=PY2
|
||||
# Network sandboxing only works on linux.
|
||||
--experimental_sandbox_default_allow_network=false
|
||||
|
||||
# Use minimal protobufs at runtime
|
||||
# Use mainnet protobufs at runtime
|
||||
run --define ssz=mainnet
|
||||
test --define ssz=mainnet
|
||||
build --define ssz=mainnet
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.1.1
|
||||
3.0.0
|
||||
|
||||
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@@ -1,2 +1,5 @@
|
||||
# Automatically require code review from core-team.
|
||||
* @prysmaticlabs/core-team
|
||||
|
||||
# Starlark code owners
|
||||
*.bzl @prestonvanloon
|
||||
|
||||
59
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
59
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
name: "\U0001F41EBug report"
|
||||
about: Report a bug or problem with running Prysm
|
||||
---
|
||||
<!--💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎
|
||||
|
||||
Hellooo! 😄
|
||||
|
||||
To help us tend to your issue faster, please search our currently open issues before submitting a new one.
|
||||
Existing issues often contain information about workarounds, resolution, or progress updates.
|
||||
|
||||
💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎-->
|
||||
|
||||
# 🐞 Bug Report
|
||||
|
||||
### Description
|
||||
|
||||
<!-- ✍️--> A clear and concise description of the problem...
|
||||
|
||||
### Has this worked before in a previous version?
|
||||
|
||||
<!-- Did this behavior use to work in the previous version? -->
|
||||
<!-- ✍️--> Yes, the previous version in which this bug was not present was: ....
|
||||
|
||||
## 🔬 Minimal Reproduction
|
||||
|
||||
<!--
|
||||
Please let us know how we can reproduce this issue. Include the exact method you used to run Prysm along with any flags used in your beacon chain and/or validator. Make sure you don't upload any confidential files or private keys.
|
||||
-->
|
||||
|
||||
## 🔥 Error
|
||||
|
||||
<pre><code>
|
||||
<!-- If the issue is accompanied by an error, please share the error logs with us below. If you have a lot of logs, place make a paste bin with your logs and share the link with us here: -->
|
||||
<!-- ✍️-->
|
||||
|
||||
</code></pre>
|
||||
|
||||
|
||||
## 🌍 Your Environment
|
||||
|
||||
**Operating System:**
|
||||
|
||||
<pre>
|
||||
<code>
|
||||
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
**What version of Prysm are you running? (Which release)**
|
||||
|
||||
<pre>
|
||||
<code>
|
||||
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
**Anything else relevant (validator index / public key)?**
|
||||
|
||||
21
.github/ISSUE_TEMPLATE/discussion.md
vendored
Normal file
21
.github/ISSUE_TEMPLATE/discussion.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: "\U0001F48EGeneral issue / discussion"
|
||||
about: Any other type of general issue or discussion
|
||||
|
||||
---
|
||||
<!--💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎
|
||||
|
||||
Hellooo! 😄
|
||||
|
||||
To help us tend to your issue faster, please search our currently open issues before submitting a new one.
|
||||
Existing issues often contain information about workarounds, resolution, or progress updates.
|
||||
|
||||
💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎-->
|
||||
|
||||
# 💎 Issue
|
||||
|
||||
### Background
|
||||
|
||||
<!-- ✍️--> Context and background information on the discussion...
|
||||
|
||||
### Description
|
||||
27
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
27
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: "\U0001F680Feature request"
|
||||
about: Suggest a feature for Prysm
|
||||
|
||||
---
|
||||
<!--💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎
|
||||
|
||||
Hellooo! 😄
|
||||
|
||||
To help us tend to your issue faster, please search our currently open issues before submitting a new one.
|
||||
Existing issues often contain information about workarounds, resolution, or progress updates.
|
||||
|
||||
💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎-->
|
||||
|
||||
# 🚀 Feature Request
|
||||
|
||||
### Description
|
||||
|
||||
<!-- ✍️--> A clear and concise description of the problem or missing capability...
|
||||
|
||||
### Describe the solution you'd like
|
||||
|
||||
<!-- ✍️--> If you have a solution in mind, please describe it.
|
||||
|
||||
### Describe alternatives you've considered
|
||||
|
||||
<!-- ✍️--> Have you considered any alternative solutions or workarounds?
|
||||
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<!-- Thanks for sending a PR! Before submitting:
|
||||
|
||||
1. If this is your first PR, please read CONTRIBUTING.md and sign the CLA
|
||||
first. We cannot review code without a signed CLA.
|
||||
2. Please file an issue *first*. All features and most bug fixes should have
|
||||
an associated issue with a design discussed and decided upon. Small bug
|
||||
fixes and documentation improvements don't need issues.
|
||||
3. New features and bug fixes must have tests. Documentation may need to
|
||||
be updated. If you're unsure what to update, send the PR, and we'll discuss
|
||||
in review.
|
||||
4. Note that PRs updating dependencies and new Go versions are not accepted.
|
||||
Please file an issue instead.
|
||||
-->
|
||||
|
||||
**What type of PR is this?**
|
||||
|
||||
> Uncomment one line below and remove others.
|
||||
>
|
||||
> Bug fix
|
||||
> Feature
|
||||
> Documentation
|
||||
> Other
|
||||
|
||||
**What does this PR do? Why is it needed?**
|
||||
|
||||
**Which issues(s) does this PR fix?**
|
||||
|
||||
Fixes #
|
||||
|
||||
**Other notes for review**
|
||||
13
.github/no-response.yml
vendored
Normal file
13
.github/no-response.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Configuration for probot-no-response - https://github.com/probot/no-response
|
||||
|
||||
# Number of days of inactivity before an Issue is closed for lack of response
|
||||
daysUntilClose: 14
|
||||
# Label requiring a response
|
||||
responseRequiredLabel: Need-Info
|
||||
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
|
||||
closeComment: >
|
||||
This issue has been automatically closed because there has been no response
|
||||
to our request for more information from the original author. With only the
|
||||
information that is currently in the issue, we don't have enough information
|
||||
to take action. Please reach out if you have or find the answers we need so
|
||||
that we can investigate further.
|
||||
41
.github/workflows/dappnode-release-trigger.yml
vendored
Normal file
41
.github/workflows/dappnode-release-trigger.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Update DAppNodePackages
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
dappnode-update-beacon-chain:
|
||||
name: Trigger a beacon-chain release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get latest tag
|
||||
id: get_tag
|
||||
run: echo ::set-output name=TAG::${GITHUB_REF/refs\/tags\//}
|
||||
- name: Send dispatch event to DAppNodePackage-prysm-beacon-chain
|
||||
env:
|
||||
DISPATCH_REPO: dappnode/DAppNodePackage-prysm-beacon-chain
|
||||
run: |
|
||||
curl -v -X POST -u "${{ secrets.PAT_GITHUB }}" \
|
||||
-H "Accept: application/vnd.github.everest-preview+json" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"event_type":"new_release", "client_payload": { "tag":"${{ steps.get_tag.outputs.TAG }}"}}' \
|
||||
https://api.github.com/repos/$DISPATCH_REPO/dispatches
|
||||
|
||||
dappnode-update-validator:
|
||||
name: Trigger a validator release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get latest tag
|
||||
id: get_tag
|
||||
run: echo ::set-output name=TAG::${GITHUB_REF/refs\/tags\//}
|
||||
- name: Send dispatch event to DAppNodePackage validator repository
|
||||
env:
|
||||
DISPATCH_REPO: dappnode/DAppNodePackage-prysm-validator
|
||||
run: |
|
||||
curl -v -X POST -u "${{ secrets.PAT_GITHUB }}" \
|
||||
-H "Accept: application/vnd.github.everest-preview+json" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"event_type":"new_release", "client_payload": { "tag":"${{ steps.get_tag.outputs.TAG }}"}}' \
|
||||
https://api.github.com/repos/$DISPATCH_REPO/dispatches
|
||||
@@ -104,6 +104,9 @@ nogo(
|
||||
"@org_golang_x_tools//go/analysis/passes/inspect:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/asmdecl:go_tool_library",
|
||||
"//tools/analyzers/maligned:go_tool_library",
|
||||
"//tools/analyzers/roughtime:go_tool_library",
|
||||
"//tools/analyzers/errcheck:go_tool_library",
|
||||
"//tools/analyzers/featureconfig:go_tool_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
TODO(you): choose "part of" or "resolves" and the associated github issue #.
|
||||
|
||||
[Part of|Resolves] #531
|
||||
|
||||
---
|
||||
|
||||
# Description
|
||||
|
||||
**Write why you are making the changes in this pull request**
|
||||
|
||||
**Write a summary of the changes you are making**
|
||||
|
||||
**Link anything that would be helpful or relevant to the reviewers**
|
||||
223
README.md
223
README.md
@@ -1,232 +1,17 @@
|
||||
# Prysm: An Ethereum 2.0 Client Written in Go
|
||||
|
||||
[](https://buildkite.com/prysmatic-labs/prysm)
|
||||
[](https://github.com/ethereum/eth2.0-specs/tree/v0.9.3)
|
||||
[](https://github.com/ethereum/eth2.0-specs/tree/v0.11.1)
|
||||
[](https://discord.gg/KSA7rPr)
|
||||
[](https://gitter.im/prysmaticlabs/geth-sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
This is the core repository for Prysm, a [Golang](https://golang.org/) implementation of the Ethereum 2.0 client specifications developed by [Prysmatic Labs](https://prysmaticlabs.com).
|
||||
|
||||
### Need assistance?
|
||||
A more detailed set of installation and usage instructions as well as breakdowns of each individual component are available in the [official documentation portal](https://docs.prylabs.network). If you still have questions, feel free to stop by either our [Discord](https://discord.gg/KSA7rPr) or [Gitter](https://gitter.im/prysmaticlabs/geth-sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) and a member of the team or our community will be happy to assist you.
|
||||
### Getting Started
|
||||
A detailed set of installation and usage instructions as well as breakdowns of each individual component are available in the [official documentation portal](https://docs.prylabs.network). If you still have questions, feel free to stop by either our [Discord](https://discord.gg/KSA7rPr) or [Gitter](https://gitter.im/prysmaticlabs/geth-sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) and a member of the team or our community will be happy to assist you.
|
||||
|
||||
### Come join the testnet!
|
||||
Participation is now open to the public for our Ethereum 2.0 phase 0 testnet release. Visit [prylabs.net](https://prylabs.net) for more information on the project or to sign up as a validator on the network.
|
||||
|
||||
# Table of Contents
|
||||
|
||||
- [Dependencies](#dependencies)
|
||||
- [Installation](#installing-prysm)
|
||||
- [Build via Docker](#build-via-docker)
|
||||
- [Build via Bazel](#build-via-bazel)
|
||||
- [Connecting to the public testnet: running a beacon node](#connecting-to-the-testnet-running-a-beacon-node)
|
||||
- [Running via Docker](#running-via-docker)
|
||||
- [Running via Bazel](#running-via-bazel)
|
||||
- [Staking ETH: running a validator client](#staking-eth-running-a-validator-client)
|
||||
- [Activating your validator: depositing 3.2 Goerli ETH](#activating-your-validator-depositing-32-gerli-eth)
|
||||
- [Starting the validator with Bazel](#starting-the-validator-with-bazel)
|
||||
- [Setting up a local ETH2 development chain](#setting-up-a-local-eth2-development-chain)
|
||||
- [Installation and dependencies](#installation-and-dependencies)
|
||||
- [Running a local beacon node and validator client](#running-a-local-beacon-node-and-validator-client)
|
||||
- [Testing Prysm](#testing-prysm)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
## Dependencies
|
||||
|
||||
Prysm can be installed either with Docker **\(recommended\)** or using our build tool, Bazel. The below instructions include sections for performing both.
|
||||
|
||||
#### **For Docker installations:**
|
||||
|
||||
* The latest release of [Docker](https://docs.docker.com/install/)
|
||||
|
||||
#### **For Bazel installations:**
|
||||
|
||||
* The latest release of [Bazel](https://docs.bazel.build/versions/master/install.html)
|
||||
* The latest release of `cmake`
|
||||
* The latest release of `git`
|
||||
* A modern UNIX operating system \(macOS included\)
|
||||
|
||||
## Installing Prysm
|
||||
|
||||
### Build via Docker
|
||||
|
||||
1. Ensure you are running the most recent version of Docker by issuing the command:
|
||||
|
||||
```text
|
||||
docker -v
|
||||
```
|
||||
|
||||
2. To pull the Prysm images, issue the following commands:
|
||||
|
||||
```text
|
||||
docker pull gcr.io/prysmaticlabs/prysm/validator:latest
|
||||
docker pull gcr.io/prysmaticlabs/prysm/beacon-chain:latest
|
||||
```
|
||||
|
||||
This process will also install any related dependencies.
|
||||
|
||||
### Build via Bazel
|
||||
|
||||
1. Open a terminal window. Ensure you are running the most recent version of Bazel by issuing the command:
|
||||
|
||||
```text
|
||||
bazel version
|
||||
```
|
||||
|
||||
2. Clone Prysm's [main repository](https://github.com/prysmaticlabs/prysm) and enter the directory:
|
||||
|
||||
```text
|
||||
git clone https://github.com/prysmaticlabs/prysm
|
||||
cd prysm
|
||||
```
|
||||
|
||||
3. Build both the beacon chain node and the validator client:
|
||||
|
||||
```text
|
||||
bazel build //beacon-chain:beacon-chain
|
||||
bazel build //validator:validator
|
||||
```
|
||||
|
||||
Bazel will automatically pull and install any dependencies as well, including Go and necessary compilers.
|
||||
|
||||
## Connecting to the testnet: running a beacon node
|
||||
|
||||
Below are instructions for initialising a beacon node and connecting to the public testnet. To further understand the role that the beacon node plays in Prysm, see [this section of the documentation.](https://docs.prylabs.network/docs/how-prysm-works/architecture-overview/)
|
||||
|
||||
|
||||
**NOTE:** It is recommended to open up port 13000 on your local router to improve connectivity and receive more peers from the network. To do so, navigate to `192.168.0.1` in your browser and login if required. Follow along with the interface to modify your routers firewall settings. When this task is completed, append the parameter`--p2p-host-ip=$(curl -s ident.me)` to your selected beacon startup command presented in this section to use the newly opened port.
|
||||
|
||||
### Running via Docker
|
||||
|
||||
#### **Docker on Linux/macOS:**
|
||||
|
||||
To start your beacon node, issue the following command:
|
||||
|
||||
```text
|
||||
docker run -it -v $HOME/prysm:/data -p 4000:4000 -p 13000:13000 --name beacon-node \
|
||||
gcr.io/prysmaticlabs/prysm/beacon-chain:latest \
|
||||
--datadir=/data
|
||||
```
|
||||
|
||||
The beacon node can be halted by either using `Ctrl+c` or with the command:
|
||||
|
||||
```text
|
||||
docker stop beacon-node
|
||||
```
|
||||
|
||||
To restart the beacon node, issue the following command:
|
||||
|
||||
```text
|
||||
docker start -ai beacon-node
|
||||
```
|
||||
|
||||
To delete a corrupted container, issue the following command:
|
||||
|
||||
```text
|
||||
docker rm beacon-node
|
||||
```
|
||||
|
||||
To recreate a deleted container and refresh the chain database, issue the start command with an additional `--clear-db` parameter:
|
||||
|
||||
```text
|
||||
docker run -it -v $HOME/prysm:/data -p 4000:4000 -p 13000:13000 --name beacon-node \
|
||||
gcr.io/prysmaticlabs/prysm/beacon-chain:latest \
|
||||
--datadir=/data \
|
||||
--clear-db
|
||||
```
|
||||
|
||||
#### **Docker on Windows:**
|
||||
|
||||
1. You will need to 'share' the local drive you wish to mount to \(e.g. C:\).
|
||||
1. Enter Docker settings \(right click the tray icon\)
|
||||
2. Click 'Shared Drives'
|
||||
3. Select a drive to share
|
||||
4. Click 'Apply'
|
||||
|
||||
2. You will next need to create a directory named `/prysm/` within your selected shared Drive. This folder will be used as a local data directory for Beacon Node chain data as well as account and keystore information required by the validator. Docker will **not** create this directory if it does not exist already. For the purposes of these instructions, it is assumed that `C:` is your prior-selected shared Drive.
|
||||
3. To run the beacon node, issue the following command:
|
||||
|
||||
```text
|
||||
docker run -it -v c:/prysm/:/data -p 4000:4000 -p 13000:13000 --name beacon-node gcr.io/prysmaticlabs/prysm/beacon-chain:latest --datadir=/data --clear-db
|
||||
```
|
||||
|
||||
### Running via Bazel
|
||||
|
||||
To start your Beacon Node with Bazel, issue the following command:
|
||||
|
||||
```text
|
||||
bazel run //beacon-chain -- --clear-db --datadir=$HOME/prysm
|
||||
```
|
||||
|
||||
This will sync up the beacon node with the latest head block in the network.
|
||||
|
||||
|
||||
**NOTE:** The beacon node must be **completely synced** before attempting to initialise a validator client, otherwise the validator will not be able to complete the deposit and **funds will lost**.
|
||||
|
||||
|
||||
## Staking ETH: Running a validator client
|
||||
|
||||
Once your beacon node is up, the chain will be waiting for you to deposit 3.2 Goerli ETH into a [validator deposit contract](https://docs.prylabs.network/docs/how-prysm-works/validator-deposit-contract) in order to activate your validator \(discussed in the section below\). First though, you will need to create this validator and connect to this node to participate in consensus.
|
||||
|
||||
Each validator represents 3.2 Goerli ETH being staked in the system, and it is possible to spin up as many as you desire in order to have more stake in the network.
|
||||
|
||||
### Activating your validator: depositing 3.2 Göerli ETH
|
||||
|
||||
To begin setting up a validator, follow the instructions found on [prylabs.net](https://prylabs.net) to use the Göerli ETH faucet and make a deposit. For step-by-step assistance with the deposit page, see the [Activating a Validator ](https://docs.prylabs.network/docs/prysm-usage/activating-a-validator)section of this documentation.
|
||||
|
||||
It will take a while for the nodes in the network to process a deposit. Once the node is active, the validator will immediately begin performing its responsibilities.
|
||||
|
||||
In your validator client, you will be able to frequently see your validator balance as it goes up over time. Note that, should your node ever go offline for a long period, a validator will start gradually losing its deposit until it is removed from the network entirely.
|
||||
|
||||
**Congratulations, you are now running Ethereum 2.0 Phase 0!**
|
||||
|
||||
## Setting up a local ETH2 development chain
|
||||
|
||||
This section outlines the process of setting up Prysm for local testing with other Ethereum 2.0 client implementations. See the [INTEROP.md](https://github.com/prysmaticlabs/prysm/blob/master/INTEROP.md) file for advanced configuration options. For more background information on interoperability development, see [this blog post](https://blog.ethereum.org/2019/09/19/eth2-interop-in-review/).
|
||||
|
||||
### Installation and dependencies
|
||||
|
||||
To begin setting up a local ETH2 development chain, follow the **Bazel** instructions found in the [dependencies](https://github.com/prysmaticlabs/prysm#dependencies) and [installation](https://github.com/prysmaticlabs/prysm#installation) sections respectively.
|
||||
|
||||
### Running a local beacon node and validator client
|
||||
|
||||
The example below will generate a beacon genesis state and initiate Prysm with 64 validators with the genesis time set to your machines UNIX time.
|
||||
|
||||
Open up two terminal windows. In the first, issue the command:
|
||||
|
||||
```text
|
||||
bazel run //beacon-chain -- \
|
||||
--custom-genesis-delay=0 \
|
||||
--bootstrap-node= \
|
||||
--deposit-contract $(curl https://prylabs.net/contract) \
|
||||
--clear-db \
|
||||
--interop-num-validators 64 \
|
||||
--interop-eth1data-votes
|
||||
```
|
||||
|
||||
Wait a moment for the beacon chain to start. In the other terminal, issue the command:
|
||||
|
||||
```text
|
||||
bazel run //validator -- --keymanager=interop --keymanageropts='{"keys":64}'
|
||||
```
|
||||
|
||||
This command will kickstart the system with your 64 validators performing their duties accordingly.
|
||||
|
||||
## Testing Prysm
|
||||
|
||||
To run the unit tests of our system, issue the command:
|
||||
|
||||
```text
|
||||
bazel test //...
|
||||
```
|
||||
|
||||
To run our linter, make sure you have [golangci-lint](https://github.com/golangci/golangci-lint) installed and then issue the command:
|
||||
|
||||
```text
|
||||
golangci-lint run
|
||||
```
|
||||
|
||||
Participation is now open to the public for our Ethereum 2.0 phase 0 testnet release. Visit [prylabs.net](https://prylabs.net) for more information on the project or to sign up as a validator on the network. You can visualize the nodes in the network on [eth2stats.io](https://eth2stats.io), explore validator rewards/penalties via Bitfly's block explorer: [beaconcha.in](https://beaconcha.in), and follow the latest blocks added to the chain on [Etherscan](https://beacon.etherscan.io).
|
||||
|
||||
## Contributing
|
||||
Want to get involved? Check out our [Contribution Guide](https://docs.prylabs.network/docs/contribute/contribution-guidelines/) to learn more!
|
||||
|
||||
137
WORKSPACE
137
WORKSPACE
@@ -5,11 +5,11 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
http_archive(
|
||||
name = "bazel_toolchains",
|
||||
sha256 = "b5a8039df7119d618402472f3adff8a1bd0ae9d5e253f53fcc4c47122e91a3d2",
|
||||
strip_prefix = "bazel-toolchains-2.1.1",
|
||||
sha256 = "144290c4166bd67e76a54f96cd504ed86416ca3ca82030282760f0823c10be48",
|
||||
strip_prefix = "bazel-toolchains-3.1.1",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/bazel-toolchains/releases/download/2.1.1/bazel-toolchains-2.1.1.tar.gz",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/2.1.1.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-toolchains/releases/download/3.1.1/bazel-toolchains-3.1.1.tar.gz",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/3.1.1.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -45,11 +45,17 @@ rbe_toolchains_config()
|
||||
|
||||
http_archive(
|
||||
name = "bazel_skylib",
|
||||
sha256 = "2ea8a5ed2b448baf4a6855d3ce049c4c452a6470b1efd1504fdb7c1c134d220a",
|
||||
strip_prefix = "bazel-skylib-0.8.0",
|
||||
url = "https://github.com/bazelbuild/bazel-skylib/archive/0.8.0.tar.gz",
|
||||
sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
||||
|
||||
bazel_skylib_workspace()
|
||||
|
||||
http_archive(
|
||||
name = "bazel_gazelle",
|
||||
sha256 = "d8c45ee70ec39a57e7a05e5027c32b1576cc7f16d9dd37135b0eddde45cf1b10",
|
||||
@@ -75,19 +81,13 @@ http_archive(
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_rules_go",
|
||||
sha256 = "e6a6c016b0663e06fa5fccf1cd8152eab8aa8180c583ec20c872f4f9953a7ac5",
|
||||
sha256 = "7b9bbe3ea1fccb46dcfa6c3f3e29ba7ec740d8733370e21cdc8937467b4a4349",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.22.1/rules_go-v0.22.1.tar.gz",
|
||||
"https://github.com/bazelbuild/rules_go/releases/download/v0.22.1/rules_go-v0.22.1.tar.gz",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.22.4/rules_go-v0.22.4.tar.gz",
|
||||
"https://github.com/bazelbuild/rules_go/releases/download/v0.22.4/rules_go-v0.22.4.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "build_bazel_rules_nodejs",
|
||||
sha256 = "0942d188f4d0de6ddb743b9f6642a26ce1ad89f09c0035a9a5ca5ba9615c96aa",
|
||||
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.38.1/rules_nodejs-0.38.1.tar.gz"],
|
||||
)
|
||||
|
||||
git_repository(
|
||||
name = "graknlabs_bazel_distribution",
|
||||
commit = "962f3a7e56942430c0ec120c24f9e9f2a9c2ce1a",
|
||||
@@ -197,8 +197,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "72c6ee3c20d19736b1203f364a6eb0ddee2c173073e20bee2beccd288fdc42be",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.9.4/general.tar.gz",
|
||||
sha256 = "b90221d87b3b4cb17d7f195f8852f5dd8fec1cf623d42443b97bdb5a216ae61d",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.11.1/general.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -213,8 +213,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "a3cc860a3679f6f62ee57b65677a9b48a65fdebb151cdcbf50f23852632845ef",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.9.4/minimal.tar.gz",
|
||||
sha256 = "316b227c0198f55872e46d601a578afeac88aab36ed38e3f01af753e98db156f",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.11.1/minimal.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -229,8 +229,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "8fc1b6220973ca30fa4ddc4ed24d66b1719abadca8bedb5e06c3bd9bc0df28e9",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.9.4/mainnet.tar.gz",
|
||||
sha256 = "b9c52f60293bcc1acfd4f8ab7ddf8bf8222ddd6a105e93d384542d1396e1b07a",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.11.1/mainnet.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -252,7 +252,7 @@ go_repository(
|
||||
|
||||
git_repository(
|
||||
name = "com_google_protobuf",
|
||||
commit = "4cf5bfee9546101d98754d23ff378ff718ba8438",
|
||||
commit = "4059c61f27eb1b06c4ee979546a238be792df0a4",
|
||||
remote = "https://github.com/protocolbuffers/protobuf",
|
||||
shallow_since = "1558721209 -0700",
|
||||
)
|
||||
@@ -289,7 +289,7 @@ http_archive(
|
||||
|
||||
go_repository(
|
||||
name = "com_github_ethereum_go_ethereum",
|
||||
commit = "861ae1b1875c17d86a6a5d68118708ab2b099658",
|
||||
commit = "0beb54b2147b3473a4c55e5ce6f02643ce403b14",
|
||||
importpath = "github.com/ethereum/go-ethereum",
|
||||
# Note: go-ethereum is not bazel-friendly with regards to cgo. We have a
|
||||
# a fork that has resolved these issues by disabling HID/USB support and
|
||||
@@ -933,8 +933,8 @@ go_repository(
|
||||
go_repository(
|
||||
name = "com_github_google_gofuzz",
|
||||
importpath = "github.com/google/gofuzz",
|
||||
sum = "h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=",
|
||||
version = "v1.0.0",
|
||||
sum = "h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=",
|
||||
version = "v1.1.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
@@ -1110,8 +1110,9 @@ go_repository(
|
||||
|
||||
go_repository(
|
||||
name = "grpc_ecosystem_grpc_gateway",
|
||||
commit = "da7a886035e25b2f274f89b6f3c64bf70a9f6780",
|
||||
importpath = "github.com/grpc-ecosystem/grpc-gateway",
|
||||
sum = "h1:IOPK2xMPP3aV6/NPt4jt//ELFo3Vv8sDVD8j3+tleDU=",
|
||||
version = "v1.14.4",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
@@ -1305,12 +1306,8 @@ go_repository(
|
||||
|
||||
go_repository(
|
||||
name = "com_github_prysmaticlabs_ethereumapis",
|
||||
commit = "62fd1d2ec119bc93b0473fde17426c63a85197ed",
|
||||
commit = "ba9042096e9fc49606279513d3e24e5e8cdbd5a0",
|
||||
importpath = "github.com/prysmaticlabs/ethereumapis",
|
||||
patch_args = ["-p1"],
|
||||
patches = [
|
||||
"//third_party:com_github_prysmaticlabs_ethereumapis-tags.patch",
|
||||
],
|
||||
)
|
||||
|
||||
go_repository(
|
||||
@@ -1508,74 +1505,89 @@ go_repository(
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_eth2_wallet",
|
||||
commit = "6970d62e60d86fdae3c3e510e800e8a60d755a7d",
|
||||
importpath = "github.com/wealdtech/go-eth2-wallet",
|
||||
sum = "h1:Hna/w4EKBJIs86VprIq7ez063A6kwk31d/O3Gs+MpYc=",
|
||||
version = "v1.9.3",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_eth2_wallet_hd",
|
||||
commit = "ce0a252a01c621687e9786a64899cfbfe802ba73",
|
||||
importpath = "github.com/wealdtech/go-eth2-wallet-hd",
|
||||
name = "com_github_wealdtech_go_eth2_wallet_hd_v2",
|
||||
importpath = "github.com/wealdtech/go-eth2-wallet-hd/v2",
|
||||
sum = "h1:kiCvdexK3zRC2GwZHSHq+hS+irVNtMs5pNADyumeeRM=",
|
||||
version = "v2.0.1",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_eth2_wallet_nd",
|
||||
commit = "12c8c41cdbd16797ff292e27f58e126bb89e9706",
|
||||
importpath = "github.com/wealdtech/go-eth2-wallet-nd",
|
||||
name = "com_github_wealdtech_go_eth2_wallet_nd_v2",
|
||||
importpath = "github.com/wealdtech/go-eth2-wallet-nd/v2",
|
||||
sum = "h1:4lB6GY5oHQn5xwn/Sxm1e9SeVCaxa7q/0hqXUQYUNwU=",
|
||||
version = "v2.0.1",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_eth2_wallet_store_filesystem",
|
||||
commit = "1eea6a48d75380047d2ebe7c8c4bd8985bcfdeca",
|
||||
importpath = "github.com/wealdtech/go-eth2-wallet-store-filesystem",
|
||||
sum = "h1:Lc6wVTjIYeD+2hLAIzq1SugTWR527vEX4tEr5v3zxJc=",
|
||||
version = "v1.7.2",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_eth2_wallet_store_s3",
|
||||
commit = "1c821b5161f7bb0b3efa2030eff687eea5e70e53",
|
||||
importpath = "github.com/wealdtech/go-eth2-wallet-store-s3",
|
||||
sum = "h1:xzyQDxbe5nr7xG0ByevTV2S8qkeOZvvjp+leBJcpxXQ=",
|
||||
version = "v1.6.2",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_eth2_wallet_encryptor_keystorev4",
|
||||
commit = "0c11c07b9544eb662210fadded94f40f309d8c8f",
|
||||
importpath = "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4",
|
||||
sum = "h1:IcpS4VpXhYz+TVupB5n6C6IQzaKwG+Rc8nvgCa/da4c=",
|
||||
version = "v1.0.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_eth2_wallet_types",
|
||||
commit = "af67d8101be61e7c4dd8126d2b3eba20cff5dab2",
|
||||
importpath = "github.com/wealdtech/go-eth2-wallet-types",
|
||||
name = "com_github_wealdtech_go_eth2_wallet_types_v2",
|
||||
importpath = "github.com/wealdtech/go-eth2-wallet-types/v2",
|
||||
sum = "h1:Ct3RrNJTapBiG2GxVl53Kfgy96f0GEUV7bediTu91u8=",
|
||||
version = "v2.0.1",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_eth2_types",
|
||||
commit = "f9c31ddf180537dd5712d5998a3d56c45864d71f",
|
||||
importpath = "github.com/wealdtech/go-eth2-types",
|
||||
name = "com_github_wealdtech_go_eth2_types_v2",
|
||||
build_directives = [
|
||||
"gazelle:resolve go github.com/herumi/bls-eth-go-binary/bls @herumi_bls_eth_go_binary//:go_default_library",
|
||||
],
|
||||
importpath = "github.com/wealdtech/go-eth2-types/v2",
|
||||
sum = "h1:qfmgaCBkH2N11LHCXsRWYz7OOxc+1QXrKHlS9yDnFsw=",
|
||||
version = "v2.3.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_eth2_util",
|
||||
commit = "326ebb1755651131bb8f4506ea9a23be6d9ad1dd",
|
||||
importpath = "github.com/wealdtech/go-eth2-util",
|
||||
sum = "h1:MyM16V7Qhd9q2ZaRa0WteBg2bWb8UplIKjZr8aeBZP0=",
|
||||
version = "v1.1.4",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_ecodec",
|
||||
commit = "7473d835445a3490e61a5fcf48fe4e9755a37957",
|
||||
importpath = "github.com/wealdtech/go-ecodec",
|
||||
sum = "h1:yggrTSckcPJRaxxOxQF7FPm21kgE8WA6+f5jdq5Kr8o=",
|
||||
version = "v1.1.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_bytesutil",
|
||||
commit = "e564d0ade555b9f97494f0f669196ddcc6bc531d",
|
||||
importpath = "github.com/wealdtech/go-bytesutil",
|
||||
sum = "h1:ocEg3Ke2GkZ4vQw5lp46rmO+pfqCCTgq35gqOy8JKVc=",
|
||||
version = "v1.1.1",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_go_indexer",
|
||||
commit = "334862c32b1e3a5c6738a2618f5c0a8ebeb8cd51",
|
||||
importpath = "github.com/wealdtech/go-indexer",
|
||||
sum = "h1:/S4rfWQbSOnnYmwnvuTVatDibZ8o1s9bmTCHO16XINg=",
|
||||
version = "v1.0.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
@@ -1639,6 +1651,14 @@ go_repository(
|
||||
version = "v1.20.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_wealdtech_eth2_signer_api",
|
||||
build_file_proto_mode = "disable_global",
|
||||
importpath = "github.com/wealdtech/eth2-signer-api",
|
||||
sum = "h1:Fs0GfrdhboBKW7zaMvIvUHJaOB1ibpAmRG3lkB53in4=",
|
||||
version = "v1.3.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_prysmaticlabs_prombbolt",
|
||||
importpath = "github.com/prysmaticlabs/prombbolt",
|
||||
@@ -1656,3 +1676,16 @@ go_repository(
|
||||
sum = "h1:GWsU1WjSE2rtvyTYGcndqmPPkQkBNV7pEuZdnGtwtu4=",
|
||||
version = "v0.0.0-20200321040036-d43e30eacb43",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "org_golang_x_mod",
|
||||
importpath = "golang.org/x/mod",
|
||||
sum = "h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=",
|
||||
version = "v0.2.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_golang_gddo",
|
||||
commit = "3c2cc9a6329d9842b3bbdaf307a8110d740cf94c",
|
||||
importpath = "github.com/golang/gddo",
|
||||
)
|
||||
|
||||
@@ -20,6 +20,7 @@ go_library(
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/logutil:go_default_library",
|
||||
"//shared/version:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//log:go_default_library",
|
||||
"@com_github_ipfs_go_log//:go_default_library",
|
||||
"@com_github_joonix_log//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
@@ -57,6 +58,7 @@ go_image(
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/logutil:go_default_library",
|
||||
"//shared/version:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//log:go_default_library",
|
||||
"@com_github_ipfs_go_log//:go_default_library",
|
||||
"@com_github_joonix_log//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
|
||||
@@ -39,7 +39,6 @@ go_test(
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
],
|
||||
|
||||
@@ -147,7 +147,11 @@ func (s *Service) run(ctx context.Context) {
|
||||
select {
|
||||
case event := <-stateChannel:
|
||||
if event.Type == statefeed.BlockProcessed {
|
||||
data := event.Data.(*statefeed.BlockProcessedData)
|
||||
data, ok := event.Data.(*statefeed.BlockProcessedData)
|
||||
if !ok {
|
||||
log.Error("Event feed data is not type *statefeed.BlockProcessedData")
|
||||
continue
|
||||
}
|
||||
log.WithField("headRoot", fmt.Sprintf("%#x", data.BlockRoot)).Debug("Received block processed event")
|
||||
headState, err := s.headFetcher.HeadState(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
@@ -34,10 +33,8 @@ func TestArchiverService_ReceivesBlockProcessedEvent(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
svc, beaconDB := setupService(t)
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
st, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: 1,
|
||||
})
|
||||
if err != nil {
|
||||
st := testutil.NewBeaconState()
|
||||
if err := st.SetSlot(1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
svc.headFetcher = &mock.ChainService{
|
||||
@@ -61,10 +58,8 @@ func TestArchiverService_OnlyArchiveAtEpochEnd(t *testing.T) {
|
||||
svc, beaconDB := setupService(t)
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
// The head state is NOT an epoch end.
|
||||
st, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch - 2,
|
||||
})
|
||||
if err != nil {
|
||||
st := testutil.NewBeaconState()
|
||||
if err := st.SetSlot(params.BeaconConfig().SlotsPerEpoch - 2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
svc.headFetcher = &mock.ChainService{
|
||||
@@ -317,8 +312,8 @@ func TestArchiverService_SavesActivatedValidatorChanges(t *testing.T) {
|
||||
if retrieved == nil {
|
||||
t.Fatal("Retrieved indices are nil")
|
||||
}
|
||||
if !reflect.DeepEqual(retrieved.Activated, []uint64{4, 5}) {
|
||||
t.Errorf("Wanted indices 4 5 activated, received %v", retrieved.Activated)
|
||||
if len(retrieved.Activated) != 98 {
|
||||
t.Error("Did not get wanted active length")
|
||||
}
|
||||
testutil.AssertLogsContain(t, hook, "Successfully archived")
|
||||
}
|
||||
@@ -433,18 +428,20 @@ func setupState(validatorCount uint64) (*stateTrie.BeaconState, error) {
|
||||
|
||||
// We initialize a head state that has attestations from participated
|
||||
// validators in a simulated fashion.
|
||||
return stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: (2 * params.BeaconConfig().SlotsPerEpoch) - 1,
|
||||
Validators: validators,
|
||||
Balances: balances,
|
||||
BlockRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
|
||||
Slashings: []uint64{0, 1e9, 1e9},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
CurrentEpochAttestations: atts,
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
JustificationBits: bitfield.Bitvector4{0x00},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
})
|
||||
st := testutil.NewBeaconState()
|
||||
if err := st.SetSlot((2 * params.BeaconConfig().SlotsPerEpoch) - 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := st.SetValidators(validators); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := st.SetBalances(balances); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := st.SetCurrentEpochAttestations(atts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
func setupService(t *testing.T) (*Service, db.Database) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
type ChainInfoFetcher interface {
|
||||
HeadFetcher
|
||||
FinalizationFetcher
|
||||
GenesisFetcher
|
||||
}
|
||||
|
||||
// TimeFetcher retrieves the Eth2 data that's related to time.
|
||||
@@ -27,6 +29,11 @@ type TimeFetcher interface {
|
||||
CurrentSlot() uint64
|
||||
}
|
||||
|
||||
// GenesisFetcher retrieves the eth2 data related to its genesis.
|
||||
type GenesisFetcher interface {
|
||||
GenesisValidatorRoot() [32]byte
|
||||
}
|
||||
|
||||
// HeadFetcher defines a common interface for methods in blockchain service which
|
||||
// directly retrieves head related data.
|
||||
type HeadFetcher interface {
|
||||
@@ -36,6 +43,7 @@ type HeadFetcher interface {
|
||||
HeadState(ctx context.Context) (*state.BeaconState, error)
|
||||
HeadValidatorsIndices(epoch uint64) ([]uint64, error)
|
||||
HeadSeed(epoch uint64) ([32]byte, error)
|
||||
HeadGenesisValidatorRoot() [32]byte
|
||||
}
|
||||
|
||||
// ForkFetcher retrieves the current fork information of the Ethereum beacon chain.
|
||||
@@ -173,11 +181,29 @@ func (s *Service) HeadSeed(epoch uint64) ([32]byte, error) {
|
||||
return helpers.Seed(s.headState(), epoch, params.BeaconConfig().DomainBeaconAttester)
|
||||
}
|
||||
|
||||
// HeadGenesisValidatorRoot returns genesis validator root of the head state.
|
||||
func (s *Service) HeadGenesisValidatorRoot() [32]byte {
|
||||
if !s.hasHeadState() {
|
||||
return [32]byte{}
|
||||
}
|
||||
|
||||
return s.headGenesisValidatorRoot()
|
||||
}
|
||||
|
||||
// GenesisTime returns the genesis time of beacon chain.
|
||||
func (s *Service) GenesisTime() time.Time {
|
||||
return s.genesisTime
|
||||
}
|
||||
|
||||
// GenesisValidatorRoot returns the genesis validator
|
||||
// root of the chain.
|
||||
func (s *Service) GenesisValidatorRoot() [32]byte {
|
||||
if !s.hasHeadState() {
|
||||
return [32]byte{}
|
||||
}
|
||||
return bytesutil.ToBytes32(s.head.state.GenesisValidatorRoot())
|
||||
}
|
||||
|
||||
// CurrentFork retrieves the latest fork information of the beacon chain.
|
||||
func (s *Service) CurrentFork() *pb.Fork {
|
||||
if !s.hasHeadState() {
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
)
|
||||
|
||||
func TestHeadSlot_DataRace(t *testing.T) {
|
||||
@@ -15,10 +17,9 @@ func TestHeadSlot_DataRace(t *testing.T) {
|
||||
beaconDB: db,
|
||||
}
|
||||
go func() {
|
||||
s.saveHead(
|
||||
context.Background(),
|
||||
[32]byte{},
|
||||
)
|
||||
if err := s.saveHead(context.Background(), [32]byte{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
s.HeadSlot()
|
||||
}
|
||||
@@ -29,12 +30,12 @@ func TestHeadRoot_DataRace(t *testing.T) {
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
head: &head{root: [32]byte{'A'}},
|
||||
stateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
}
|
||||
go func() {
|
||||
s.saveHead(
|
||||
context.Background(),
|
||||
[32]byte{},
|
||||
)
|
||||
if err := s.saveHead(context.Background(), [32]byte{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
if _, err := s.HeadRoot(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -47,14 +48,16 @@ func TestHeadBlock_DataRace(t *testing.T) {
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
head: &head{block: ðpb.SignedBeaconBlock{}},
|
||||
stateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
}
|
||||
go func() {
|
||||
s.saveHead(
|
||||
context.Background(),
|
||||
[32]byte{},
|
||||
)
|
||||
if err := s.saveHead(context.Background(), [32]byte{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
s.HeadBlock(context.Background())
|
||||
if _, err := s.HeadBlock(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeadState_DataRace(t *testing.T) {
|
||||
@@ -62,12 +65,14 @@ func TestHeadState_DataRace(t *testing.T) {
|
||||
defer testDB.TeardownDB(t, db)
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
stateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
}
|
||||
go func() {
|
||||
s.saveHead(
|
||||
context.Background(),
|
||||
[32]byte{},
|
||||
)
|
||||
if err := s.saveHead(context.Background(), [32]byte{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
s.HeadState(context.Background())
|
||||
if _, err := s.HeadState(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,10 @@ func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
|
||||
func TestHeadSlot_CanRetrieve(t *testing.T) {
|
||||
c := &Service{}
|
||||
s, _ := state.InitializeFromProto(&pb.BeaconState{})
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.head = &head{slot: 100, state: s}
|
||||
if c.HeadSlot() != 100 {
|
||||
t.Errorf("Wanted head slot: %d, got: %d", 100, c.HeadSlot())
|
||||
@@ -145,7 +148,10 @@ func TestHeadRoot_CanRetrieve(t *testing.T) {
|
||||
|
||||
func TestHeadBlock_CanRetrieve(t *testing.T) {
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
||||
s, _ := state.InitializeFromProto(&pb.BeaconState{})
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c := &Service{}
|
||||
c.head = &head{block: b, state: s}
|
||||
|
||||
@@ -160,7 +166,7 @@ func TestHeadBlock_CanRetrieve(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHeadState_CanRetrieve(t *testing.T) {
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{Slot: 2})
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{Slot: 2, GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:]})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -170,7 +176,7 @@ func TestHeadState_CanRetrieve(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(s.InnerStateUnsafe(), headState.InnerStateUnsafe()) {
|
||||
if !proto.Equal(s.InnerStateUnsafe(), headState.InnerStateUnsafe()) {
|
||||
t.Error("incorrect head state received")
|
||||
}
|
||||
}
|
||||
@@ -195,3 +201,20 @@ func TestCurrentFork_CanRetrieve(t *testing.T) {
|
||||
t.Error("Received incorrect fork version")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenesisValidatorRoot_CanRetrieve(t *testing.T) {
|
||||
// Should not panic if head state is nil.
|
||||
c := &Service{}
|
||||
if c.GenesisValidatorRoot() != [32]byte{} {
|
||||
t.Error("Did not get correct genesis validator root")
|
||||
}
|
||||
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{GenesisValidatorsRoot: []byte{'a'}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.head = &head{state: s}
|
||||
if c.GenesisValidatorRoot() != [32]byte{'a'} {
|
||||
t.Error("Did not get correct genesis validator root")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,6 +202,14 @@ func (s *Service) headState() *state.BeaconState {
|
||||
return s.head.state.Copy()
|
||||
}
|
||||
|
||||
// This returns the genesis validator root of the head state.
|
||||
func (s *Service) headGenesisValidatorRoot() [32]byte {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return bytesutil.ToBytes32(s.head.state.GenesisValidatorRoot())
|
||||
}
|
||||
|
||||
// Returns true if head state exists.
|
||||
func (s *Service) hasHeadState() bool {
|
||||
s.headLock.RLock()
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
func TestSaveHead_Same(t *testing.T) {
|
||||
@@ -44,10 +44,24 @@ func TestSaveHead_Different(t *testing.T) {
|
||||
|
||||
newHeadBlock := ðpb.BeaconBlock{Slot: 1}
|
||||
newHeadSignedBlock := ðpb.SignedBeaconBlock{Block: newHeadBlock}
|
||||
service.beaconDB.SaveBlock(context.Background(), newHeadSignedBlock)
|
||||
newRoot, _ := ssz.HashTreeRoot(newHeadBlock)
|
||||
headState, _ := state.InitializeFromProto(&pb.BeaconState{Slot: 1})
|
||||
service.beaconDB.SaveState(context.Background(), headState, newRoot)
|
||||
|
||||
if err := service.beaconDB.SaveBlock(context.Background(), newHeadSignedBlock); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newRoot, err := ssz.HashTreeRoot(newHeadBlock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
headState := testutil.NewBeaconState()
|
||||
if err := headState.SetSlot(1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveStateSummary(context.Background(), &pb.StateSummary{Slot: 1, Root: newRoot[:]}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveState(context.Background(), headState, newRoot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.saveHead(context.Background(), newRoot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -170,6 +170,12 @@ func (s *Service) generateState(ctx context.Context, startRoot [32]byte, endRoot
|
||||
return nil, err
|
||||
}
|
||||
if preState == nil {
|
||||
if !s.stateGen.HasState(ctx, startRoot) {
|
||||
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
return nil, errors.Wrap(err, "could not save initial sync blocks")
|
||||
}
|
||||
s.clearInitSyncBlocks()
|
||||
}
|
||||
preState, err = s.stateGen.StateByRoot(ctx, startRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -30,10 +30,15 @@ func TestFilterBoundaryCandidates_FilterCorrect(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st, _ := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := uint64(0); i < 500; i++ {
|
||||
st.SetSlot(i)
|
||||
if err := st.SetSlot(i); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root := [32]byte{}
|
||||
copy(root[:], bytesutil.Bytes32(i))
|
||||
service.initSyncState[root] = st.Copy()
|
||||
@@ -43,14 +48,18 @@ func TestFilterBoundaryCandidates_FilterCorrect(t *testing.T) {
|
||||
}
|
||||
lastIndex := len(service.boundaryRoots) - 1
|
||||
for i := uint64(500); i < 2000; i++ {
|
||||
st.SetSlot(i)
|
||||
if err := st.SetSlot(i); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root := [32]byte{}
|
||||
copy(root[:], bytesutil.Bytes32(i))
|
||||
service.initSyncState[root] = st.Copy()
|
||||
}
|
||||
// Set current state.
|
||||
latestSlot := helpers.RoundUpToNearestEpoch(2000)
|
||||
st.SetSlot(latestSlot)
|
||||
if err := st.SetSlot(latestSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
lastRoot := [32]byte{}
|
||||
copy(lastRoot[:], bytesutil.Bytes32(latestSlot))
|
||||
|
||||
@@ -85,10 +94,15 @@ func TestFilterBoundaryCandidates_HandleSkippedSlots(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st, _ := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := uint64(0); i < 500; i++ {
|
||||
st.SetSlot(i)
|
||||
if err := st.SetSlot(i); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root := [32]byte{}
|
||||
copy(root[:], bytesutil.Bytes32(i))
|
||||
service.initSyncState[root] = st.Copy()
|
||||
@@ -98,7 +112,9 @@ func TestFilterBoundaryCandidates_HandleSkippedSlots(t *testing.T) {
|
||||
}
|
||||
lastIndex := len(service.boundaryRoots) - 1
|
||||
for i := uint64(500); i < 2000; i++ {
|
||||
st.SetSlot(i)
|
||||
if err := st.SetSlot(i); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root := [32]byte{}
|
||||
copy(root[:], bytesutil.Bytes32(i))
|
||||
// save only for offsetted slots
|
||||
@@ -108,7 +124,9 @@ func TestFilterBoundaryCandidates_HandleSkippedSlots(t *testing.T) {
|
||||
}
|
||||
// Set current state.
|
||||
latestSlot := helpers.RoundUpToNearestEpoch(2000)
|
||||
st.SetSlot(latestSlot)
|
||||
if err := st.SetSlot(latestSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
lastRoot := [32]byte{}
|
||||
copy(lastRoot[:], bytesutil.Bytes32(latestSlot))
|
||||
|
||||
@@ -150,10 +168,15 @@ func TestPruneOldStates_AlreadyFinalized(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st, _ := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := uint64(100); i < 200; i++ {
|
||||
st.SetSlot(i)
|
||||
if err := st.SetSlot(i); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root := [32]byte{}
|
||||
copy(root[:], bytesutil.Bytes32(i))
|
||||
service.initSyncState[root] = st.Copy()
|
||||
@@ -184,10 +207,15 @@ func TestPruneNonBoundary_CanPrune(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st, _ := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := uint64(0); i < 2000; i++ {
|
||||
st.SetSlot(i)
|
||||
if err := st.SetSlot(i); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root := [32]byte{}
|
||||
copy(root[:], bytesutil.Bytes32(i))
|
||||
service.initSyncState[root] = st.Copy()
|
||||
@@ -223,19 +251,28 @@ func TestGenerateState_CorrectlyGenerated(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
err = beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: genesisBlock.Block.Slot,
|
||||
ParentRoot: genesisBlock.Block.ParentRoot,
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
BodyRoot: bodyRoot[:],
|
||||
})
|
||||
beaconState.SetSlashings(make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := beaconState.SetSlashings(make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cp := beaconState.CurrentJustifiedCheckpoint()
|
||||
mockRoot := [32]byte{}
|
||||
copy(mockRoot[:], "hello-world")
|
||||
cp.Root = mockRoot[:]
|
||||
beaconState.SetCurrentJustifiedCheckpoint(cp)
|
||||
beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{})
|
||||
if err := beaconState.SetCurrentJustifiedCheckpoint(cp); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = db.SaveBlock(context.Background(), genesisBlock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -15,13 +16,24 @@ var log = logrus.WithField("prefix", "blockchain")
|
||||
// logs state transition related data every slot.
|
||||
func logStateTransitionData(b *ethpb.BeaconBlock) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": b.Slot,
|
||||
"attestations": len(b.Body.Attestations),
|
||||
"deposits": len(b.Body.Deposits),
|
||||
"attesterSlashings": len(b.Body.AttesterSlashings),
|
||||
"proposerSlashings": len(b.Body.ProposerSlashings),
|
||||
"voluntaryExits": len(b.Body.VoluntaryExits),
|
||||
}).Info("Finished applying state transition")
|
||||
}
|
||||
|
||||
func logBlockSyncStatus(block *ethpb.BeaconBlock, blockRoot [32]byte, finalized *ethpb.Checkpoint) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": block.Slot,
|
||||
"block": fmt.Sprintf("0x%s...", hex.EncodeToString(blockRoot[:])[:8]),
|
||||
"epoch": helpers.SlotToEpoch(block.Slot),
|
||||
"finalizedEpoch": finalized.Epoch,
|
||||
"finalizedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(finalized.Root[:])[:8]),
|
||||
}).Info("Synced new block")
|
||||
}
|
||||
|
||||
func logEpochData(beaconState *stateTrie.BeaconState) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"epoch": helpers.CurrentEpoch(beaconState),
|
||||
|
||||
@@ -19,6 +19,10 @@ var (
|
||||
Name: "beacon_head_slot",
|
||||
Help: "Slot of the head block of the beacon chain",
|
||||
})
|
||||
clockTimeSlot = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "beacon_clock_time_slot",
|
||||
Help: "The current slot based on the genesis time and current clock",
|
||||
})
|
||||
competingBlks = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "competing_blocks",
|
||||
Help: "The # of blocks received and processed from a competing chain",
|
||||
@@ -82,8 +86,9 @@ var (
|
||||
)
|
||||
|
||||
// reportSlotMetrics reports slot related metrics.
|
||||
func reportSlotMetrics(currentSlot uint64, headSlot uint64, finalizedCheckpoint *ethpb.Checkpoint) {
|
||||
beaconSlot.Set(float64(currentSlot))
|
||||
func reportSlotMetrics(stateSlot uint64, headSlot uint64, clockSlot uint64, finalizedCheckpoint *ethpb.Checkpoint) {
|
||||
clockTimeSlot.Set(float64(clockSlot))
|
||||
beaconSlot.Set(float64(stateSlot))
|
||||
beaconHeadSlot.Set(float64(headSlot))
|
||||
if finalizedCheckpoint != nil {
|
||||
headFinalizedEpoch.Set(float64(finalizedCheckpoint.Epoch))
|
||||
|
||||
@@ -3,7 +3,6 @@ package blockchain
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -11,6 +10,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/flags"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -71,6 +71,16 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
|
||||
ctx, span := trace.StartSpan(ctx, "blockchain.onAttestation")
|
||||
defer span.End()
|
||||
|
||||
if a == nil {
|
||||
return nil, errors.New("nil attestation")
|
||||
}
|
||||
if a.Data == nil {
|
||||
return nil, errors.New("nil attestation.Data field")
|
||||
}
|
||||
if a.Data.Target == nil {
|
||||
return nil, errors.New("nil attestation.Data.Target field")
|
||||
}
|
||||
|
||||
tgt := stateTrie.CopyCheckpoint(a.Data.Target)
|
||||
tgtSlot := helpers.StartSlot(tgt.Epoch)
|
||||
|
||||
@@ -93,12 +103,12 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
|
||||
genesisTime := baseState.GenesisTime()
|
||||
|
||||
// Verify attestation target is from current epoch or previous epoch.
|
||||
if err := s.verifyAttTargetEpoch(ctx, genesisTime, uint64(time.Now().Unix()), tgt); err != nil {
|
||||
if err := s.verifyAttTargetEpoch(ctx, genesisTime, uint64(roughtime.Now().Unix()), tgt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify Attestations cannot be from future epochs.
|
||||
if err := helpers.VerifySlotTime(genesisTime, tgtSlot); err != nil {
|
||||
if err := helpers.VerifySlotTime(genesisTime, tgtSlot, helpers.TimeShiftTolerance); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify attestation target slot")
|
||||
}
|
||||
|
||||
@@ -108,7 +118,7 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
|
||||
}
|
||||
|
||||
// Verify attestations can only affect the fork choice of subsequent slots.
|
||||
if err := helpers.VerifySlotTime(genesisTime, a.Data.Slot+1); err != nil {
|
||||
if err := helpers.VerifySlotTime(genesisTime, a.Data.Slot, helpers.TimeShiftTolerance); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -125,6 +135,10 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
|
||||
}
|
||||
}
|
||||
|
||||
if indexedAtt.AttestingIndices == nil {
|
||||
return nil, errors.New("nil attesting indices")
|
||||
}
|
||||
|
||||
// Update forkchoice store with the new attestation for updating weight.
|
||||
s.forkChoiceStore.ProcessAttestation(ctx, indexedAtt.AttestingIndices, bytesutil.ToBytes32(a.Data.BeaconBlockRoot), a.Data.Target.Epoch)
|
||||
|
||||
|
||||
@@ -31,48 +31,78 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (*sta
|
||||
return cachedState, nil
|
||||
}
|
||||
|
||||
var baseState *stateTrie.BeaconState
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
baseState, err = s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(c.Root))
|
||||
if !s.stateGen.HasState(ctx, bytesutil.ToBytes32(c.Root)) {
|
||||
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
return nil, errors.Wrap(err, "could not save initial sync blocks")
|
||||
}
|
||||
s.clearInitSyncBlocks()
|
||||
}
|
||||
|
||||
baseState, err := s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(c.Root))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for slot %d", helpers.StartSlot(c.Epoch))
|
||||
}
|
||||
} else {
|
||||
if featureconfig.Get().CheckHeadState {
|
||||
headRoot, err := s.HeadRoot(ctx)
|
||||
|
||||
if helpers.StartSlot(c.Epoch) > baseState.Slot() {
|
||||
baseState = baseState.Copy()
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, helpers.StartSlot(c.Epoch))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get head root")
|
||||
}
|
||||
if bytes.Equal(headRoot, c.Root) {
|
||||
st, err := s.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get head state")
|
||||
}
|
||||
if err := s.checkpointState.AddCheckpointState(&cache.CheckpointState{
|
||||
Checkpoint: c,
|
||||
State: st.Copy(),
|
||||
}); err != nil {
|
||||
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
||||
}
|
||||
return st, nil
|
||||
return nil, errors.Wrapf(err, "could not process slots up to %d", helpers.StartSlot(c.Epoch))
|
||||
}
|
||||
}
|
||||
|
||||
baseState, err = s.beaconDB.State(ctx, bytesutil.ToBytes32(c.Root))
|
||||
if err := s.checkpointState.AddCheckpointState(&cache.CheckpointState{
|
||||
Checkpoint: c,
|
||||
State: baseState,
|
||||
}); err != nil {
|
||||
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
||||
}
|
||||
|
||||
return baseState, nil
|
||||
}
|
||||
|
||||
if featureconfig.Get().CheckHeadState {
|
||||
headRoot, err := s.HeadRoot(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for slot %d", helpers.StartSlot(c.Epoch))
|
||||
return nil, errors.Wrapf(err, "could not get head root")
|
||||
}
|
||||
if bytes.Equal(headRoot, c.Root) {
|
||||
st, err := s.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get head state")
|
||||
}
|
||||
if err := s.checkpointState.AddCheckpointState(&cache.CheckpointState{
|
||||
Checkpoint: c,
|
||||
State: st.Copy(),
|
||||
}); err != nil {
|
||||
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
}
|
||||
|
||||
baseState, err := s.beaconDB.State(ctx, bytesutil.ToBytes32(c.Root))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for slot %d", helpers.StartSlot(c.Epoch))
|
||||
}
|
||||
if baseState == nil {
|
||||
return nil, fmt.Errorf("pre state of target block %d does not exist", helpers.StartSlot(c.Epoch))
|
||||
}
|
||||
|
||||
if helpers.StartSlot(c.Epoch) > baseState.Slot() {
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, helpers.StartSlot(c.Epoch))
|
||||
savedState := baseState.Copy()
|
||||
savedState, err = state.ProcessSlots(ctx, savedState, helpers.StartSlot(c.Epoch))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not process slots up to %d", helpers.StartSlot(c.Epoch))
|
||||
}
|
||||
if err := s.checkpointState.AddCheckpointState(&cache.CheckpointState{
|
||||
Checkpoint: c,
|
||||
State: savedState.Copy(),
|
||||
}); err != nil {
|
||||
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
||||
}
|
||||
return savedState, nil
|
||||
}
|
||||
|
||||
if err := s.checkpointState.AddCheckpointState(&cache.CheckpointState{
|
||||
@@ -123,21 +153,31 @@ func (s *Service) verifyAttestation(ctx context.Context, baseState *stateTrie.Be
|
||||
}
|
||||
indexedAtt := attestationutil.ConvertToIndexed(ctx, a, committee)
|
||||
if err := blocks.VerifyIndexedAttestation(ctx, baseState, indexedAtt); err != nil {
|
||||
if err == blocks.ErrSigFailedToVerify {
|
||||
if err == helpers.ErrSigFailedToVerify {
|
||||
// When sig fails to verify, check if there's a differences in committees due to
|
||||
// different seeds.
|
||||
var aState *stateTrie.BeaconState
|
||||
var err error
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
if !s.stateGen.HasState(ctx, bytesutil.ToBytes32(a.Data.BeaconBlockRoot)) {
|
||||
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
return nil, errors.Wrap(err, "could not save initial sync blocks")
|
||||
}
|
||||
s.clearInitSyncBlocks()
|
||||
}
|
||||
aState, err = s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(a.Data.BeaconBlockRoot))
|
||||
return nil, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
aState, err = s.beaconDB.State(ctx, bytesutil.ToBytes32(a.Data.BeaconBlockRoot))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
aState, err = s.beaconDB.State(ctx, bytesutil.ToBytes32(a.Data.BeaconBlockRoot))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if aState == nil {
|
||||
return nil, fmt.Errorf("nil state for block root %#x", a.Data.BeaconBlockRoot)
|
||||
}
|
||||
|
||||
epoch := helpers.SlotToEpoch(a.Data.Slot)
|
||||
origSeed, err := helpers.Seed(baseState, epoch, params.BeaconConfig().DomainBeaconAttester)
|
||||
if err != nil {
|
||||
|
||||
@@ -2,18 +2,19 @@ package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -25,7 +26,11 @@ func TestStore_OnAttestation(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db, ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
ForkChoiceStore: protoarray.New(0, 0, [32]byte{}),
|
||||
StateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -40,15 +45,21 @@ func TestStore_OnAttestation(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, BlkWithOutState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
BlkWithOutStateRoot, _ := ssz.HashTreeRoot(BlkWithOutState.Block)
|
||||
BlkWithOutStateRoot, err := ssz.HashTreeRoot(BlkWithOutState.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
BlkWithStateBadAtt := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
||||
if err := db.SaveBlock(ctx, BlkWithStateBadAtt); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
BlkWithStateBadAttRoot, _ := ssz.HashTreeRoot(BlkWithStateBadAtt.Block)
|
||||
BlkWithStateBadAttRoot, err := ssz.HashTreeRoot(BlkWithStateBadAtt.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := beaconstate.InitializeFromProto(&pb.BeaconState{})
|
||||
s := testutil.NewBeaconState()
|
||||
if err := s.SetSlot(100 * params.BeaconConfig().SlotsPerEpoch); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -60,15 +71,19 @@ func TestStore_OnAttestation(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, BlkWithValidState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
BlkWithValidStateRoot, _ := ssz.HashTreeRoot(BlkWithValidState.Block)
|
||||
s, _ = stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Fork: &pb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
|
||||
BlkWithValidStateRoot, err := ssz.HashTreeRoot(BlkWithValidState.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s = testutil.NewBeaconState()
|
||||
if err := s.SetFork(&pb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveState(ctx, s, BlkWithValidStateRoot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -109,13 +124,34 @@ func TestStore_OnAttestation(t *testing.T) {
|
||||
wantErr: true,
|
||||
wantErrString: "does not match current epoch",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: nil,
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "nil attestation",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Data) in attestation",
|
||||
a: ðpb.Attestation{},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "nil attestation.Data field",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{}},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "nil attestation.Data.Target field",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := service.onAttestation(ctx, tt.a)
|
||||
if tt.wantErr {
|
||||
if !strings.Contains(err.Error(), tt.wantErrString) {
|
||||
if err == nil || !strings.Contains(err.Error(), tt.wantErrString) {
|
||||
t.Errorf("Store.onAttestation() error = %v, wantErr = %v", err, tt.wantErrString)
|
||||
}
|
||||
} else {
|
||||
@@ -129,15 +165,17 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
params.UseDemoBeaconConfig()
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
StateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, _ := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
s, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Fork: &pb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
@@ -150,18 +188,30 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
JustificationBits: []byte{0},
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)},
|
||||
Validators: []*ethpb.Validator{{PublicKey: bytesutil.PadTo([]byte("foo"), 48)}},
|
||||
Balances: []uint64{0},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r := [32]byte{'g'}
|
||||
if err := service.beaconDB.SaveState(ctx, s, r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
service.justifiedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
service.bestJustifiedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
service.prevFinalizedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
|
||||
r = bytesutil.ToBytes32([]byte{'A'})
|
||||
cp1 := ðpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'A'}, 32)}
|
||||
service.beaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'A'}))
|
||||
if err := service.beaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'A'})); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: bytesutil.PadTo([]byte{'A'}, 32)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s1, err := service.getAttPreState(ctx, cp1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -171,7 +221,12 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
}
|
||||
|
||||
cp2 := ðpb.Checkpoint{Epoch: 2, Root: bytesutil.PadTo([]byte{'B'}, 32)}
|
||||
service.beaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'B'}))
|
||||
if err := service.beaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'B'})); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: bytesutil.PadTo([]byte{'B'}, 32)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s2, err := service.getAttPreState(ctx, cp2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -204,13 +259,20 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
t.Errorf("Wanted state slot: %d, got: %d", 2*params.BeaconConfig().SlotsPerEpoch, s2.Slot())
|
||||
}
|
||||
|
||||
s.SetSlot(params.BeaconConfig().SlotsPerEpoch + 1)
|
||||
if err := s.SetSlot(params.BeaconConfig().SlotsPerEpoch + 1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service.justifiedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
service.bestJustifiedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
service.prevFinalizedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
cp3 := ðpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'C'}, 32)}
|
||||
service.beaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'C'}))
|
||||
if err := service.beaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'C'})); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: bytesutil.PadTo([]byte{'C'}, 32)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s3, err := service.getAttPreState(ctx, cp3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -225,7 +287,10 @@ func TestStore_UpdateCheckpointState(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
StateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -233,9 +298,13 @@ func TestStore_UpdateCheckpointState(t *testing.T) {
|
||||
|
||||
epoch := uint64(1)
|
||||
baseState, _ := testutil.DeterministicGenesisState(t, 1)
|
||||
baseState.SetSlot(epoch * params.BeaconConfig().SlotsPerEpoch)
|
||||
if err := baseState.SetSlot(epoch * params.BeaconConfig().SlotsPerEpoch); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkpoint := ðpb.Checkpoint{Epoch: epoch}
|
||||
service.beaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(checkpoint.Root))
|
||||
if err := service.beaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(checkpoint.Root)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
returned, err := service.getAttPreState(ctx, checkpoint)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -254,7 +323,9 @@ func TestStore_UpdateCheckpointState(t *testing.T) {
|
||||
|
||||
epoch = uint64(2)
|
||||
newCheckpoint := ðpb.Checkpoint{Epoch: epoch}
|
||||
service.beaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(newCheckpoint.Root))
|
||||
if err := service.beaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(newCheckpoint.Root)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
returned, err = service.getAttPreState(ctx, newCheckpoint)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -271,7 +342,7 @@ func TestStore_UpdateCheckpointState(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(returned, cached) {
|
||||
if !proto.Equal(returned.InnerStateUnsafe(), cached.InnerStateUnsafe()) {
|
||||
t.Error("Incorrectly cached base state")
|
||||
}
|
||||
}
|
||||
@@ -366,11 +437,17 @@ func TestVerifyBeaconBlock_futureBlock(t *testing.T) {
|
||||
}
|
||||
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 2}}
|
||||
service.beaconDB.SaveBlock(ctx, b)
|
||||
r, _ := ssz.HashTreeRoot(b.Block)
|
||||
if err := service.beaconDB.SaveBlock(ctx, b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, err := ssz.HashTreeRoot(b.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
d := ðpb.AttestationData{Slot: 1, BeaconBlockRoot: r[:]}
|
||||
|
||||
if err := service.verifyBeaconBlock(ctx, d); !strings.Contains(err.Error(), "could not process attestation for future block") {
|
||||
err = service.verifyBeaconBlock(ctx, d)
|
||||
if err == nil || !strings.Contains(err.Error(), "could not process attestation for future block") {
|
||||
t.Error("Did not receive the wanted error")
|
||||
}
|
||||
}
|
||||
@@ -387,8 +464,13 @@ func TestVerifyBeaconBlock_OK(t *testing.T) {
|
||||
}
|
||||
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 2}}
|
||||
service.beaconDB.SaveBlock(ctx, b)
|
||||
r, _ := ssz.HashTreeRoot(b.Block)
|
||||
if err := service.beaconDB.SaveBlock(ctx, b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, err := ssz.HashTreeRoot(b.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
d := ðpb.AttestationData{Slot: 2, BeaconBlockRoot: r[:]}
|
||||
|
||||
if err := service.verifyBeaconBlock(ctx, d); err != nil {
|
||||
|
||||
@@ -69,7 +69,6 @@ func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
preStateValidatorCount := preState.NumValidators()
|
||||
|
||||
root, err := stateutil.BlockRoot(b)
|
||||
if err != nil {
|
||||
@@ -78,7 +77,7 @@ func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock)
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": b.Slot,
|
||||
"root": fmt.Sprintf("0x%s...", hex.EncodeToString(root[:])[:8]),
|
||||
}).Info("Executing state transition on block")
|
||||
}).Debug("Executing state transition on block")
|
||||
|
||||
postState, err := state.ExecuteStateTransition(ctx, preState, signed)
|
||||
if err != nil {
|
||||
@@ -137,7 +136,9 @@ func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock)
|
||||
|
||||
// Prune proto array fork choice nodes, all nodes before finalized check point will
|
||||
// be pruned.
|
||||
s.forkChoiceStore.Prune(ctx, fRoot)
|
||||
if err := s.forkChoiceStore.Prune(ctx, fRoot); err != nil {
|
||||
return nil, errors.Wrap(err, "could not prune proto array fork choice nodes")
|
||||
}
|
||||
|
||||
s.prevFinalizedCheckpt = s.finalizedCheckpt
|
||||
s.finalizedCheckpt = postState.FinalizedCheckpoint()
|
||||
@@ -158,11 +159,6 @@ func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock)
|
||||
}
|
||||
}
|
||||
|
||||
// Update validator indices in database as needed.
|
||||
if err := s.saveNewValidators(ctx, preStateValidatorCount, postState); err != nil {
|
||||
return nil, errors.Wrap(err, "could not save new validators")
|
||||
}
|
||||
|
||||
// Epoch boundary bookkeeping such as logging epoch summaries.
|
||||
if postState.Slot() >= s.nextEpochBoundarySlot {
|
||||
logEpochData(postState)
|
||||
@@ -216,7 +212,6 @@ func (s *Service) onBlockInitialSyncStateTransition(ctx context.Context, signed
|
||||
return nil
|
||||
}
|
||||
|
||||
preStateValidatorCount := preState.NumValidators()
|
||||
postState, err := state.ExecuteStateTransitionNoVerifyAttSigs(ctx, preState, signed)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not execute state transition")
|
||||
@@ -318,11 +313,6 @@ func (s *Service) onBlockInitialSyncStateTransition(ctx context.Context, signed
|
||||
}
|
||||
}
|
||||
|
||||
// Update validator indices in database as needed.
|
||||
if err := s.saveNewValidators(ctx, preStateValidatorCount, postState); err != nil {
|
||||
return errors.Wrap(err, "could not save new validators")
|
||||
}
|
||||
|
||||
if !featureconfig.Get().NewStateMgmt {
|
||||
numOfStates := len(s.boundaryRoots)
|
||||
if numOfStates > initialSyncCacheSize {
|
||||
|
||||
@@ -16,13 +16,17 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/traceutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// CurrentSlot returns the current slot based on time.
|
||||
func (s *Service) CurrentSlot() uint64 {
|
||||
return uint64(roughtime.Now().Unix()-s.genesisTime.Unix()) / params.BeaconConfig().SecondsPerSlot
|
||||
now := roughtime.Now().Unix()
|
||||
genesis := s.genesisTime.Unix()
|
||||
if now < genesis {
|
||||
return 0
|
||||
}
|
||||
return uint64(now-genesis) / params.BeaconConfig().SecondsPerSlot
|
||||
}
|
||||
|
||||
// getBlockPreState returns the pre state of an incoming block. It uses the parent root of the block
|
||||
@@ -39,7 +43,7 @@ func (s *Service) getBlockPreState(ctx context.Context, b *ethpb.BeaconBlock) (*
|
||||
}
|
||||
|
||||
// Verify block slot time is not from the feature.
|
||||
if err := helpers.VerifySlotTime(preState.GenesisTime(), b.Slot); err != nil {
|
||||
if err := helpers.VerifySlotTime(preState.GenesisTime(), b.Slot, helpers.TimeShiftTolerance); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -62,7 +66,20 @@ func (s *Service) verifyBlkPreState(ctx context.Context, b *ethpb.BeaconBlock) (
|
||||
defer span.End()
|
||||
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
preState, err := s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(b.ParentRoot))
|
||||
parentRoot := bytesutil.ToBytes32(b.ParentRoot)
|
||||
// Loosen the check to HasBlock because state summary gets saved in batches
|
||||
// during initial syncing. There's no risk given a state summary object is just a
|
||||
// a subset of the block object.
|
||||
if !s.stateGen.StateSummaryExists(ctx, parentRoot) && !s.beaconDB.HasBlock(ctx, parentRoot) {
|
||||
return nil, errors.New("could not reconstruct parent state")
|
||||
}
|
||||
if !s.stateGen.HasState(ctx, parentRoot) {
|
||||
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
return nil, errors.Wrap(err, "could not save initial sync blocks")
|
||||
}
|
||||
s.clearInitSyncBlocks()
|
||||
}
|
||||
preState, err := s.stateGen.StateByRoot(ctx, parentRoot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for slot %d", b.Slot)
|
||||
}
|
||||
@@ -141,28 +158,6 @@ func (s *Service) verifyBlkFinalizedSlot(b *ethpb.BeaconBlock) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveNewValidators saves newly added validator indices from the state to db.
|
||||
// Does nothing if validator count has not changed.
|
||||
func (s *Service) saveNewValidators(ctx context.Context, preStateValidatorCount int, postState *stateTrie.BeaconState) error {
|
||||
postStateValidatorCount := postState.NumValidators()
|
||||
if preStateValidatorCount != postStateValidatorCount {
|
||||
indices := make([]uint64, 0)
|
||||
pubKeys := make([][48]byte, 0)
|
||||
for i := preStateValidatorCount; i < postStateValidatorCount; i++ {
|
||||
indices = append(indices, uint64(i))
|
||||
pubKeys = append(pubKeys, postState.PubkeyAtIndex(uint64(i)))
|
||||
}
|
||||
if err := s.beaconDB.SaveValidatorIndices(ctx, pubKeys, indices); err != nil {
|
||||
return errors.Wrapf(err, "could not save activated validators: %v", indices)
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"indices": indices,
|
||||
"totalValidatorCount": postStateValidatorCount - preStateValidatorCount,
|
||||
}).Trace("Validator indices saved in DB")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// rmStatesOlderThanLastFinalized deletes the states in db since last finalized check point.
|
||||
func (s *Service) rmStatesOlderThanLastFinalized(ctx context.Context, startSlot uint64, endSlot uint64) error {
|
||||
ctx, span := trace.StartSpan(ctx, "forkchoice.rmStatesBySlots")
|
||||
@@ -215,7 +210,7 @@ func (s *Service) rmStatesOlderThanLastFinalized(ctx context.Context, startSlot
|
||||
}
|
||||
|
||||
if err := s.beaconDB.DeleteStates(ctx, roots); err != nil {
|
||||
return err
|
||||
log.Warnf("Could not delete states: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -9,15 +9,19 @@ import (
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
@@ -26,7 +30,10 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
StateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -41,10 +48,7 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st := testutil.NewBeaconState()
|
||||
if err := service.beaconDB.SaveState(ctx, st.Copy(), validGenesisRoot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -60,10 +64,16 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: st.Slot(), Root: randomParentRoot[:]}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveState(ctx, st.Copy(), randomParentRoot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
randomParentRoot2 := roots[1]
|
||||
if err := service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: st.Slot(), Root: randomParentRoot2[:]}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveState(ctx, st.Copy(), bytesutil.ToBytes32(randomParentRoot2)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -110,45 +120,13 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
service.finalizedCheckpt.Root = roots[0]
|
||||
|
||||
_, err := service.onBlock(ctx, ðpb.SignedBeaconBlock{Block: tt.blk})
|
||||
if !strings.Contains(err.Error(), tt.wantErrString) {
|
||||
if err == nil || !strings.Contains(err.Error(), tt.wantErrString) {
|
||||
t.Errorf("Store.OnBlock() error = %v, wantErr = %v", err, tt.wantErrString)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_SaveNewValidators(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
preCount := 2 // validators 0 and validators 1
|
||||
s, _ := stateTrie.InitializeFromProto(&pb.BeaconState{Validators: []*ethpb.Validator{
|
||||
{PublicKey: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{PublicKey: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
|
||||
{PublicKey: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}},
|
||||
{PublicKey: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}},
|
||||
}})
|
||||
if err := service.saveNewValidators(ctx, preCount, s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !db.HasValidatorIndex(ctx, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}) {
|
||||
t.Error("Wanted validator saved in db")
|
||||
}
|
||||
if !db.HasValidatorIndex(ctx, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}) {
|
||||
t.Error("Wanted validator saved in db")
|
||||
}
|
||||
if db.HasValidatorIndex(ctx, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}) {
|
||||
t.Error("validator not suppose to be saved in db")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveStateSinceLastFinalized(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
@@ -176,7 +154,10 @@ func TestRemoveStateSinceLastFinalized(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s, _ := stateTrie.InitializeFromProto(&pb.BeaconState{Slot: uint64(i)})
|
||||
s := testutil.NewBeaconState()
|
||||
if err := s.SetSlot(uint64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveState(ctx, s, r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -249,9 +230,15 @@ func TestRemoveStateSinceLastFinalized_EmptyStartSlot(t *testing.T) {
|
||||
}
|
||||
|
||||
lastJustifiedBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{ParentRoot: []byte{'G'}}}
|
||||
lastJustifiedRoot, _ := ssz.HashTreeRoot(lastJustifiedBlk.Block)
|
||||
lastJustifiedRoot, err := ssz.HashTreeRoot(lastJustifiedBlk.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newJustifiedBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1, ParentRoot: lastJustifiedRoot[:]}}
|
||||
newJustifiedRoot, _ := ssz.HashTreeRoot(newJustifiedBlk.Block)
|
||||
newJustifiedRoot, err := ssz.HashTreeRoot(newJustifiedBlk.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveBlock(ctx, newJustifiedBlk); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -284,9 +271,15 @@ func TestShouldUpdateJustified_ReturnFalse(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
lastJustifiedBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{ParentRoot: []byte{'G'}}}
|
||||
lastJustifiedRoot, _ := ssz.HashTreeRoot(lastJustifiedBlk.Block)
|
||||
lastJustifiedRoot, err := ssz.HashTreeRoot(lastJustifiedBlk.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newJustifiedBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{ParentRoot: lastJustifiedRoot[:]}}
|
||||
newJustifiedRoot, _ := ssz.HashTreeRoot(newJustifiedBlk.Block)
|
||||
newJustifiedRoot, err := ssz.HashTreeRoot(newJustifiedBlk.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveBlock(ctx, newJustifiedBlk); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -307,21 +300,35 @@ func TestShouldUpdateJustified_ReturnFalse(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCachedPreState_CanGetFromCache(t *testing.T) {
|
||||
func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{NewStateMgmt: true})
|
||||
defer resetCfg()
|
||||
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
StateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, _ := stateTrie.InitializeFromProto(&pb.BeaconState{Slot: 1})
|
||||
s, err := stateTrie.InitializeFromProto(&pb.BeaconState{Slot: 1, GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:]})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r := [32]byte{'A'}
|
||||
b := ðpb.BeaconBlock{Slot: 1, ParentRoot: r[:]}
|
||||
service.initSyncState[r] = s
|
||||
if err := service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: r[:]}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.stateGen.SaveState(ctx, r, s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
received, err := service.verifyBlkPreState(ctx, b)
|
||||
if err != nil {
|
||||
@@ -336,8 +343,13 @@ func TestCachedPreState_CanGetFromDB(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{NewStateMgmt: true})
|
||||
defer resetCfg()
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
StateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -348,19 +360,27 @@ func TestCachedPreState_CanGetFromDB(t *testing.T) {
|
||||
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
_, err = service.verifyBlkPreState(ctx, b)
|
||||
wanted := "pre state of slot 1 does not exist"
|
||||
wanted := "could not reconstruct parent state"
|
||||
if err.Error() != wanted {
|
||||
t.Error("Did not get wanted error")
|
||||
}
|
||||
|
||||
s, _ := stateTrie.InitializeFromProto(&pb.BeaconState{Slot: 1})
|
||||
service.beaconDB.SaveState(ctx, s, r)
|
||||
s, err := stateTrie.InitializeFromProto(&pb.BeaconState{Slot: 1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: r[:]}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.stateGen.SaveState(ctx, r, s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
received, err := service.verifyBlkPreState(ctx, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(s, received) {
|
||||
if s.Slot() != received.Slot() {
|
||||
t.Error("cached state not the same")
|
||||
}
|
||||
}
|
||||
@@ -378,16 +398,27 @@ func TestSaveInitState_CanSaveDelete(t *testing.T) {
|
||||
|
||||
for i := uint64(0); i < 64; i++ {
|
||||
b := ðpb.BeaconBlock{Slot: i}
|
||||
s, _ := stateTrie.InitializeFromProto(&pb.BeaconState{Slot: i})
|
||||
r, _ := ssz.HashTreeRoot(b)
|
||||
s := testutil.NewBeaconState()
|
||||
if err := s.SetSlot(i); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, err := ssz.HashTreeRoot(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service.initSyncState[r] = s
|
||||
}
|
||||
|
||||
// Set finalized root as slot 32
|
||||
finalizedRoot, _ := ssz.HashTreeRoot(ðpb.BeaconBlock{Slot: 32})
|
||||
|
||||
s, _ := stateTrie.InitializeFromProto(&pb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 1, Root: finalizedRoot[:]}})
|
||||
finalizedRoot, err := ssz.HashTreeRoot(ðpb.BeaconBlock{Slot: 32})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s := testutil.NewBeaconState()
|
||||
if err := s.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
||||
Epoch: 1, Root: finalizedRoot[:]}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.saveInitState(ctx, s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -423,17 +454,17 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
|
||||
}
|
||||
service.justifiedCheckpt = ðpb.Checkpoint{Root: []byte{'A'}}
|
||||
service.bestJustifiedCheckpt = ðpb.Checkpoint{Root: []byte{'A'}}
|
||||
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st := testutil.NewBeaconState()
|
||||
service.initSyncState[r] = st.Copy()
|
||||
if err := db.SaveState(ctx, st.Copy(), r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Could update
|
||||
s, _ := stateTrie.InitializeFromProto(&pb.BeaconState{CurrentJustifiedCheckpoint: ðpb.Checkpoint{Epoch: 1, Root: r[:]}})
|
||||
s := testutil.NewBeaconState()
|
||||
if err := s.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{Epoch: 1, Root: r[:]}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := service.updateJustified(context.Background(), s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -465,10 +496,16 @@ func TestFilterBlockRoots_CanFilter(t *testing.T) {
|
||||
}
|
||||
|
||||
fBlock := ðpb.BeaconBlock{}
|
||||
fRoot, _ := ssz.HashTreeRoot(fBlock)
|
||||
fRoot, err := ssz.HashTreeRoot(fBlock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hBlock := ðpb.BeaconBlock{Slot: 1}
|
||||
headRoot, _ := ssz.HashTreeRoot(hBlock)
|
||||
st, _ := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
headRoot, err := ssz.HashTreeRoot(hBlock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st := testutil.NewBeaconState()
|
||||
if err := service.beaconDB.SaveBlock(ctx, ðpb.SignedBeaconBlock{Block: fBlock}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -511,10 +548,12 @@ func TestPersistCache_CanSave(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st, _ := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
st := testutil.NewBeaconState()
|
||||
|
||||
for i := uint64(0); i < initialSyncCacheSize; i++ {
|
||||
st.SetSlot(i)
|
||||
if err := st.SetSlot(i); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root := [32]byte{}
|
||||
copy(root[:], bytesutil.Bytes32(i))
|
||||
service.initSyncState[root] = st.Copy()
|
||||
@@ -563,7 +602,8 @@ func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
st, _ := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
st := testutil.NewBeaconState()
|
||||
|
||||
if err := service.beaconDB.SaveState(ctx, st.Copy(), validGenesisRoot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -617,7 +657,8 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
st, _ := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
st := testutil.NewBeaconState()
|
||||
|
||||
if err := service.beaconDB.SaveState(ctx, st.Copy(), validGenesisRoot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -627,12 +668,18 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
|
||||
if err := service.beaconDB.SaveBlock(ctx, b63); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r63, _ := ssz.HashTreeRoot(b63.Block)
|
||||
r63, err := ssz.HashTreeRoot(b63.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b64 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 64, ParentRoot: r63[:]}}
|
||||
if err := service.beaconDB.SaveBlock(ctx, b64); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r64, _ := ssz.HashTreeRoot(b64.Block)
|
||||
r64, err := ssz.HashTreeRoot(b64.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b65 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 65, ParentRoot: r64[:]}}
|
||||
if err := service.beaconDB.SaveBlock(ctx, b65); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -661,25 +708,47 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
|
||||
// (B1, and B3 are all from the same slots)
|
||||
func blockTree1(db db.Database, genesisRoot []byte) ([][]byte, error) {
|
||||
b0 := ðpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
|
||||
r0, _ := ssz.HashTreeRoot(b0)
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: r0[:]}
|
||||
r1, _ := ssz.HashTreeRoot(b1)
|
||||
b3 := ðpb.BeaconBlock{Slot: 3, ParentRoot: r0[:]}
|
||||
r3, _ := ssz.HashTreeRoot(b3)
|
||||
b4 := ðpb.BeaconBlock{Slot: 4, ParentRoot: r3[:]}
|
||||
r4, _ := ssz.HashTreeRoot(b4)
|
||||
b5 := ðpb.BeaconBlock{Slot: 5, ParentRoot: r4[:]}
|
||||
r5, _ := ssz.HashTreeRoot(b5)
|
||||
b6 := ðpb.BeaconBlock{Slot: 6, ParentRoot: r4[:]}
|
||||
r6, _ := ssz.HashTreeRoot(b6)
|
||||
b7 := ðpb.BeaconBlock{Slot: 7, ParentRoot: r5[:]}
|
||||
r7, _ := ssz.HashTreeRoot(b7)
|
||||
b8 := ðpb.BeaconBlock{Slot: 8, ParentRoot: r6[:]}
|
||||
r8, _ := ssz.HashTreeRoot(b8)
|
||||
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
||||
r0, err := ssz.HashTreeRoot(b0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: r0[:]}
|
||||
r1, err := ssz.HashTreeRoot(b1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3 := ðpb.BeaconBlock{Slot: 3, ParentRoot: r0[:]}
|
||||
r3, err := ssz.HashTreeRoot(b3)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4 := ðpb.BeaconBlock{Slot: 4, ParentRoot: r3[:]}
|
||||
r4, err := ssz.HashTreeRoot(b4)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b5 := ðpb.BeaconBlock{Slot: 5, ParentRoot: r4[:]}
|
||||
r5, err := ssz.HashTreeRoot(b5)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b6 := ðpb.BeaconBlock{Slot: 6, ParentRoot: r4[:]}
|
||||
r6, err := ssz.HashTreeRoot(b6)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b7 := ðpb.BeaconBlock{Slot: 7, ParentRoot: r5[:]}
|
||||
r7, err := ssz.HashTreeRoot(b7)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b8 := ðpb.BeaconBlock{Slot: 8, ParentRoot: r6[:]}
|
||||
r8, err := ssz.HashTreeRoot(b8)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st := testutil.NewBeaconState()
|
||||
|
||||
for _, b := range []*ethpb.BeaconBlock{b0, b1, b3, b4, b5, b6, b7, b8} {
|
||||
if err := db.SaveBlock(context.Background(), ðpb.SignedBeaconBlock{Block: b}); err != nil {
|
||||
return nil, err
|
||||
@@ -699,3 +768,13 @@ func blockTree1(db db.Database, genesisRoot []byte) ([][]byte, error) {
|
||||
}
|
||||
return [][]byte{r0[:], r1[:], nil, r3[:], r4[:], r5[:], r6[:], r7[:], r8[:]}, nil
|
||||
}
|
||||
|
||||
func TestCurrentSlot_HandlesOverflow(t *testing.T) {
|
||||
svc := Service{genesisTime: roughtime.Now().Add(1 * time.Hour)}
|
||||
|
||||
slot := svc.CurrentSlot()
|
||||
|
||||
if slot != 0 {
|
||||
t.Fatalf("Expected slot to be 0, got %d", slot)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package blockchain
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -13,6 +12,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -60,7 +60,7 @@ func (s *Service) ReceiveAttestationNoPubsub(ctx context.Context, att *ethpb.Att
|
||||
func (s *Service) IsValidAttestation(ctx context.Context, att *ethpb.Attestation) bool {
|
||||
baseState, err := s.getAttPreState(ctx, att.Data.Target)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to validate attestation")
|
||||
log.WithError(err).Error("Failed to get attestation pre state")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ func (s *Service) processAttestation(subscribedToStateEvents chan struct{}) {
|
||||
// This verifies the epoch of input checkpoint is within current epoch and previous epoch
|
||||
// with respect to current time. Returns true if it's within, false if it's not.
|
||||
func (s *Service) verifyCheckpointEpoch(c *ethpb.Checkpoint) bool {
|
||||
now := uint64(time.Now().Unix())
|
||||
now := uint64(roughtime.Now().Unix())
|
||||
genesisTime := uint64(s.genesisTime.Unix())
|
||||
currentSlot := (now - genesisTime) / params.BeaconConfig().SecondsPerSlot
|
||||
currentEpoch := helpers.SlotToEpoch(currentSlot)
|
||||
|
||||
@@ -116,7 +116,10 @@ func (s *Service) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedB
|
||||
})
|
||||
|
||||
// Reports on block and fork choice metrics.
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.finalizedCheckpt)
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
|
||||
// Log block sync status.
|
||||
logBlockSyncStatus(blockCopy.Block, root, s.finalizedCheckpt)
|
||||
|
||||
// Log state transition data.
|
||||
logStateTransitionData(blockCopy.Block)
|
||||
@@ -166,7 +169,10 @@ func (s *Service) ReceiveBlockNoPubsubForkchoice(ctx context.Context, block *eth
|
||||
})
|
||||
|
||||
// Reports on block and fork choice metrics.
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.finalizedCheckpt)
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
|
||||
// Log block sync status.
|
||||
logBlockSyncStatus(blockCopy.Block, root, s.finalizedCheckpt)
|
||||
|
||||
// Log state transition data.
|
||||
logStateTransitionData(blockCopy.Block)
|
||||
@@ -222,7 +228,7 @@ func (s *Service) ReceiveBlockNoVerify(ctx context.Context, block *ethpb.SignedB
|
||||
})
|
||||
|
||||
// Reports on blockCopy and fork choice metrics.
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.finalizedCheckpt)
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
|
||||
// Log state transition data.
|
||||
log.WithFields(logrus.Fields{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package blockchain defines the life-cycle and status of the beacon chain
|
||||
// as well as the Ethereum Serenity beacon chain fork-choice rule based on
|
||||
// Casper Proof of Stake finality.
|
||||
// Package blockchain defines the life-cycle of the blockchain at the core of
|
||||
// eth2, including processing of new blocks and attestations using casper
|
||||
// proof of stake.
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
@@ -192,7 +192,8 @@ func (s *Service) Start() {
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.Initialized,
|
||||
Data: &statefeed.InitializedData{
|
||||
StartTime: s.genesisTime,
|
||||
StartTime: s.genesisTime,
|
||||
GenesisValidatorsRoot: beaconState.GenesisValidatorRoot(),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
@@ -210,7 +211,11 @@ func (s *Service) Start() {
|
||||
select {
|
||||
case event := <-stateChannel:
|
||||
if event.Type == statefeed.ChainStarted {
|
||||
data := event.Data.(*statefeed.ChainStartedData)
|
||||
data, ok := event.Data.(*statefeed.ChainStartedData)
|
||||
if !ok {
|
||||
log.Error("event data is not type *statefeed.ChainStartedData")
|
||||
return
|
||||
}
|
||||
log.WithField("starttime", data.StartTime).Debug("Received chain start event")
|
||||
s.processChainStartTime(ctx, data.StartTime)
|
||||
return
|
||||
@@ -233,13 +238,15 @@ func (s *Service) Start() {
|
||||
// deposit contract, initializes the beacon chain's state, and kicks off the beacon chain.
|
||||
func (s *Service) processChainStartTime(ctx context.Context, genesisTime time.Time) {
|
||||
preGenesisState := s.chainStartFetcher.PreGenesisState()
|
||||
if err := s.initializeBeaconChain(ctx, genesisTime, preGenesisState, s.chainStartFetcher.ChainStartEth1Data()); err != nil {
|
||||
initializedState, err := s.initializeBeaconChain(ctx, genesisTime, preGenesisState, s.chainStartFetcher.ChainStartEth1Data())
|
||||
if err != nil {
|
||||
log.Fatalf("Could not initialize beacon chain: %v", err)
|
||||
}
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.Initialized,
|
||||
Data: &statefeed.InitializedData{
|
||||
StartTime: genesisTime,
|
||||
StartTime: genesisTime,
|
||||
GenesisValidatorsRoot: initializedState.GenesisValidatorRoot(),
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -251,7 +258,7 @@ func (s *Service) initializeBeaconChain(
|
||||
ctx context.Context,
|
||||
genesisTime time.Time,
|
||||
preGenesisState *stateTrie.BeaconState,
|
||||
eth1data *ethpb.Eth1Data) error {
|
||||
eth1data *ethpb.Eth1Data) (*stateTrie.BeaconState, error) {
|
||||
_, span := trace.StartSpan(context.Background(), "beacon-chain.Service.initializeBeaconChain")
|
||||
defer span.End()
|
||||
s.genesisTime = genesisTime
|
||||
@@ -259,11 +266,11 @@ func (s *Service) initializeBeaconChain(
|
||||
|
||||
genesisState, err := state.OptimizedGenesisBeaconState(unixTime, preGenesisState, eth1data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not initialize genesis state")
|
||||
return nil, errors.Wrap(err, "could not initialize genesis state")
|
||||
}
|
||||
|
||||
if err := s.saveGenesisData(ctx, genesisState); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis data")
|
||||
return nil, errors.Wrap(err, "could not save genesis data")
|
||||
}
|
||||
|
||||
log.Info("Initialized beacon chain genesis state")
|
||||
@@ -273,15 +280,15 @@ func (s *Service) initializeBeaconChain(
|
||||
|
||||
// Update committee shuffled indices for genesis epoch.
|
||||
if err := helpers.UpdateCommitteeCache(genesisState, 0 /* genesis epoch */); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if err := helpers.UpdateProposerIndicesInCache(genesisState, 0 /* genesis epoch */); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.opsService.SetGenesisTime(genesisState.GenesisTime())
|
||||
|
||||
return nil
|
||||
return genesisState, nil
|
||||
}
|
||||
|
||||
// Stop the blockchain service's main event loop and associated goroutines.
|
||||
@@ -305,18 +312,6 @@ func (s *Service) ClearCachedStates() {
|
||||
s.initSyncState = map[[32]byte]*stateTrie.BeaconState{}
|
||||
}
|
||||
|
||||
// This gets called when beacon chain is first initialized to save validator indices and public keys in db.
|
||||
func (s *Service) saveGenesisValidators(ctx context.Context, state *stateTrie.BeaconState) error {
|
||||
pubkeys := make([][48]byte, state.NumValidators())
|
||||
indices := make([]uint64, state.NumValidators())
|
||||
|
||||
for i := 0; i < state.NumValidators(); i++ {
|
||||
pubkeys[i] = state.PubkeyAtIndex(uint64(i))
|
||||
indices[i] = uint64(i)
|
||||
}
|
||||
return s.beaconDB.SaveValidatorIndices(ctx, pubkeys, indices)
|
||||
}
|
||||
|
||||
// This gets called when beacon chain is first initialized to save genesis data (state, block, and more) in db.
|
||||
func (s *Service) saveGenesisData(ctx context.Context, genesisState *stateTrie.BeaconState) error {
|
||||
stateRoot, err := genesisState.HashTreeRoot(ctx)
|
||||
@@ -353,9 +348,6 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState *stateTrie.B
|
||||
if err := s.beaconDB.SaveGenesisBlockRoot(ctx, genesisBlkRoot); err != nil {
|
||||
return errors.Wrap(err, "could save genesis block root")
|
||||
}
|
||||
if err := s.saveGenesisValidators(ctx, genesisState); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis validators")
|
||||
}
|
||||
|
||||
genesisCheckpoint := ðpb.Checkpoint{Root: genesisBlkRoot[:]}
|
||||
|
||||
|
||||
@@ -21,13 +21,11 @@ func TestChainService_SaveHead_DataRace(t *testing.T) {
|
||||
beaconDB: db,
|
||||
}
|
||||
go func() {
|
||||
s.saveHead(
|
||||
context.Background(),
|
||||
[32]byte{},
|
||||
)
|
||||
if err := s.saveHead(context.Background(), [32]byte{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
s.saveHead(
|
||||
context.Background(),
|
||||
[32]byte{},
|
||||
)
|
||||
if err := s.saveHead(context.Background(), [32]byte{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package blockchain
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
@@ -13,6 +12,7 @@ import (
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
ssz "github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
protodb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
@@ -145,12 +146,10 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
||||
P2p: &mockBroadcaster{},
|
||||
StateNotifier: &mockBeaconNode{},
|
||||
AttPool: attestations.NewPool(),
|
||||
StateGen: stategen.New(beaconDB, cache.NewStateSummaryCache()),
|
||||
ForkChoiceStore: protoarray.New(0, 0, params.BeaconConfig().ZeroHash),
|
||||
OpsService: opsService,
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("could not register blockchain service: %v", err)
|
||||
}
|
||||
|
||||
chainService, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
@@ -232,8 +231,8 @@ func TestChainStartStop_Initialized(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, genesisBlk); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s, err := beaconstate.InitializeFromProto(&pb.BeaconState{Slot: 1})
|
||||
if err != nil {
|
||||
s := testutil.NewBeaconState()
|
||||
if err := s.SetSlot(1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.SaveState(ctx, s, blkRoot); err != nil {
|
||||
@@ -273,7 +272,10 @@ func TestChainService_InitializeBeaconChain(t *testing.T) {
|
||||
|
||||
// Set up 10 deposits pre chain start for validators to register
|
||||
count := uint64(10)
|
||||
deposits, _, _ := testutil.DeterministicDepositsAndKeys(count)
|
||||
deposits, _, err := testutil.DeterministicDepositsAndKeys(count)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trie, _, err := testutil.DepositTrieFromDeposits(deposits)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -283,31 +285,23 @@ func TestChainService_InitializeBeaconChain(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
genState.SetEth1Data(ðpb.Eth1Data{
|
||||
err = genState.SetEth1Data(ðpb.Eth1Data{
|
||||
DepositRoot: hashTreeRoot[:],
|
||||
DepositCount: uint64(len(deposits)),
|
||||
})
|
||||
genState, err = b.ProcessDeposits(ctx, genState, ðpb.BeaconBlockBody{Deposits: deposits})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
for _, deposit := range deposits {
|
||||
genState, err = b.ProcessPreGenesisDeposit(ctx, genState, deposit)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if err := bc.initializeBeaconChain(ctx, time.Unix(0, 0), genState, ðpb.Eth1Data{
|
||||
|
||||
if _, err := bc.initializeBeaconChain(ctx, time.Unix(0, 0), genState, ðpb.Eth1Data{
|
||||
DepositRoot: hashTreeRoot[:],
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := bc.beaconDB.State(ctx, bc.headRoot())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, v := range s.Validators() {
|
||||
if !db.HasValidatorIndex(ctx, v.PublicKey) {
|
||||
t.Errorf("Validator %s missing from db", hex.EncodeToString(v.PublicKey))
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := bc.HeadState(ctx); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -342,14 +336,23 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
|
||||
finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1
|
||||
headBlock := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: finalizedSlot, ParentRoot: genesisRoot[:]}}
|
||||
headState, err := beaconstate.InitializeFromProto(&pb.BeaconState{Slot: finalizedSlot})
|
||||
headState := testutil.NewBeaconState()
|
||||
if err := headState.SetSlot(finalizedSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := headState.SetGenesisValidatorRoot(params.BeaconConfig().ZeroHash[:]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
headRoot, err := ssz.HashTreeRoot(headBlock.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
headRoot, _ := ssz.HashTreeRoot(headBlock.Block)
|
||||
if err := db.SaveState(ctx, headState, headRoot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.SaveState(ctx, headState, genesisRoot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.SaveBlock(ctx, headBlock); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -362,7 +365,7 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, headBlock); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c := &Service{beaconDB: db}
|
||||
c := &Service{beaconDB: db, stateGen: stategen.New(db, cache.NewStateSummaryCache())}
|
||||
if err := c.initializeChainInfo(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -401,12 +404,18 @@ func TestChainService_SaveHeadNoDB(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
stateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
}
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
||||
r, _ := ssz.HashTreeRoot(b)
|
||||
state := &pb.BeaconState{}
|
||||
newState, err := beaconstate.InitializeFromProto(state)
|
||||
s.beaconDB.SaveState(ctx, newState, r)
|
||||
r, err := ssz.HashTreeRoot(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState := testutil.NewBeaconState()
|
||||
if err := s.stateGen.SaveState(ctx, r, newState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := s.saveHeadNoDB(ctx, b, r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -437,9 +446,8 @@ func TestChainService_PruneOldStates(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
state := &pb.BeaconState{Slot: uint64(i)}
|
||||
newState, err := beaconstate.InitializeFromProto(state)
|
||||
if err != nil {
|
||||
newState := testutil.NewBeaconState()
|
||||
if err := newState.SetSlot(uint64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := s.beaconDB.SaveState(ctx, newState, r); err != nil {
|
||||
@@ -479,9 +487,15 @@ func TestHasBlock_ForkChoiceAndDB(t *testing.T) {
|
||||
beaconDB: db,
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}
|
||||
r, _ := ssz.HashTreeRoot(block.Block)
|
||||
r, err := ssz.HashTreeRoot(block.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bs := &pb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{}}
|
||||
state, _ := beaconstate.InitializeFromProto(bs)
|
||||
state, err := beaconstate.InitializeFromProto(bs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := s.insertBlockToForkChoiceStore(ctx, block.Block, r, state); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -506,7 +520,10 @@ func BenchmarkHasBlockDB(b *testing.B) {
|
||||
if err := s.beaconDB.SaveBlock(ctx, block); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
r, _ := ssz.HashTreeRoot(block.Block)
|
||||
r, err := ssz.HashTreeRoot(block.Block)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@@ -526,9 +543,15 @@ func BenchmarkHasBlockForkChoiceStore(b *testing.B) {
|
||||
beaconDB: db,
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}
|
||||
r, _ := ssz.HashTreeRoot(block.Block)
|
||||
r, err := ssz.HashTreeRoot(block.Block)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
bs := &pb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{}}
|
||||
state, _ := beaconstate.InitializeFromProto(bs)
|
||||
state, err := beaconstate.InitializeFromProto(bs)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if err := s.insertBlockToForkChoiceStore(ctx, block.Block, r, state); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package testing includes useful mocks for writing unit
|
||||
// tests which depend on logic from the blockchain package.
|
||||
package testing
|
||||
|
||||
import (
|
||||
@@ -32,6 +34,7 @@ type ChainService struct {
|
||||
BlocksReceived []*ethpb.SignedBeaconBlock
|
||||
Balance *precompute.Balance
|
||||
Genesis time.Time
|
||||
ValidatorsRoot [32]byte
|
||||
Fork *pb.Fork
|
||||
DB db.Database
|
||||
stateNotifier statefeed.Notifier
|
||||
@@ -217,6 +220,11 @@ func (ms *ChainService) GenesisTime() time.Time {
|
||||
return ms.Genesis
|
||||
}
|
||||
|
||||
// GenesisValidatorRoot mocks the same method in the chain service.
|
||||
func (ms *ChainService) GenesisValidatorRoot() [32]byte {
|
||||
return ms.ValidatorsRoot
|
||||
}
|
||||
|
||||
// CurrentSlot mocks the same method in the chain service.
|
||||
func (ms *ChainService) CurrentSlot() uint64 {
|
||||
return uint64(time.Now().Unix()-ms.Genesis.Unix()) / params.BeaconConfig().SecondsPerSlot
|
||||
@@ -239,3 +247,8 @@ func (ms *ChainService) ClearCachedStates() {}
|
||||
func (ms *ChainService) HasInitSyncBlock(root [32]byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// HeadGenesisValidatorRoot mocks HeadGenesisValidatorRoot method in chain service.
|
||||
func (ms *ChainService) HeadGenesisValidatorRoot() [32]byte {
|
||||
return [32]byte{}
|
||||
}
|
||||
|
||||
2
beacon-chain/cache/BUILD.bazel
vendored
2
beacon-chain/cache/BUILD.bazel
vendored
@@ -8,6 +8,7 @@ go_library(
|
||||
"committee.go",
|
||||
"committee_ids.go",
|
||||
"common.go",
|
||||
"doc.go",
|
||||
"eth1_data.go",
|
||||
"hot_state_cache.go",
|
||||
"skip_slot_cache.go",
|
||||
@@ -41,6 +42,7 @@ go_test(
|
||||
"attestation_data_test.go",
|
||||
"checkpoint_state_test.go",
|
||||
"committee_fuzz_test.go",
|
||||
"committee_ids_test.go",
|
||||
"committee_test.go",
|
||||
"eth1_data_test.go",
|
||||
"feature_flag_test.go",
|
||||
|
||||
5
beacon-chain/cache/attestation_data.go
vendored
5
beacon-chain/cache/attestation_data.go
vendored
@@ -148,7 +148,10 @@ func (c *AttestationCache) Put(ctx context.Context, req *ethpb.AttestationDataRe
|
||||
}
|
||||
|
||||
func wrapperToKey(i interface{}) (string, error) {
|
||||
w := i.(*attestationReqResWrapper)
|
||||
w, ok := i.(*attestationReqResWrapper)
|
||||
if !ok {
|
||||
return "", errors.New("key is not of type *attestationReqResWrapper")
|
||||
}
|
||||
if w == nil {
|
||||
return "", errors.New("nil wrapper")
|
||||
}
|
||||
|
||||
3
beacon-chain/cache/checkpoint_state.go
vendored
3
beacon-chain/cache/checkpoint_state.go
vendored
@@ -93,7 +93,8 @@ func (c *CheckpointStateCache) StateByCheckpoint(cp *ethpb.Checkpoint) (*stateTr
|
||||
return nil, ErrNotCheckpointState
|
||||
}
|
||||
|
||||
return info.State.Copy(), nil
|
||||
// Copy here is unnecessary since the return will only be used to verify attestation signature.
|
||||
return info.State, nil
|
||||
}
|
||||
|
||||
// AddCheckpointState adds CheckpointState object to the cache. This method also trims the least
|
||||
|
||||
9
beacon-chain/cache/checkpoint_state_test.go
vendored
9
beacon-chain/cache/checkpoint_state_test.go
vendored
@@ -4,11 +4,13 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestCheckpointStateCacheKeyFn_OK(t *testing.T) {
|
||||
@@ -48,7 +50,8 @@ func TestCheckpointStateCache_StateByCheckpoint(t *testing.T) {
|
||||
|
||||
cp1 := ðpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'A'}, 32)}
|
||||
st, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: 64,
|
||||
GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:],
|
||||
Slot: 64,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -72,7 +75,7 @@ func TestCheckpointStateCache_StateByCheckpoint(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(state.InnerStateUnsafe(), info1.State.InnerStateUnsafe()) {
|
||||
if !proto.Equal(state.InnerStateUnsafe(), info1.State.InnerStateUnsafe()) {
|
||||
t.Error("incorrectly cached state")
|
||||
}
|
||||
|
||||
|
||||
79
beacon-chain/cache/committee_ids.go
vendored
79
beacon-chain/cache/committee_ids.go
vendored
@@ -4,39 +4,82 @@ import (
|
||||
"sync"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||||
)
|
||||
|
||||
type committeeIDs struct {
|
||||
cache *lru.Cache
|
||||
lock sync.RWMutex
|
||||
attester *lru.Cache
|
||||
attesterLock sync.RWMutex
|
||||
aggregator *lru.Cache
|
||||
aggregatorLock sync.RWMutex
|
||||
}
|
||||
|
||||
// CommitteeIDs for attestations.
|
||||
// CommitteeIDs for attester and aggregator.
|
||||
var CommitteeIDs = newCommitteeIDs()
|
||||
|
||||
func newCommitteeIDs() *committeeIDs {
|
||||
cache, err := lru.New(8)
|
||||
// Given a node can calculate committee assignments of current epoch and next epoch.
|
||||
// Max size is set to 2 epoch length.
|
||||
cacheSize := int(params.BeaconConfig().MaxCommitteesPerSlot * params.BeaconConfig().SlotsPerEpoch * 2)
|
||||
attesterCache, err := lru.New(cacheSize)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &committeeIDs{cache: cache}
|
||||
}
|
||||
|
||||
// AddIDs to the cache for attestation committees by epoch.
|
||||
func (t *committeeIDs) AddIDs(indices []uint64, epoch uint64) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
val, exists := t.cache.Get(epoch)
|
||||
if exists {
|
||||
indices = sliceutil.UnionUint64(append(indices, val.([]uint64)...))
|
||||
aggregatorCache, err := lru.New(cacheSize)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t.cache.Add(epoch, indices)
|
||||
return &committeeIDs{attester: attesterCache, aggregator: aggregatorCache}
|
||||
}
|
||||
|
||||
// GetIDs from the cache for attestation committees by epoch.
|
||||
func (t *committeeIDs) GetIDs(epoch uint64) []uint64 {
|
||||
val, exists := t.cache.Get(epoch)
|
||||
// AddAttesterCommiteeID adds committee ID for subscribing subnet for the attester of a given slot.
|
||||
func (c *committeeIDs) AddAttesterCommiteeID(slot uint64, committeeID uint64) {
|
||||
c.attesterLock.Lock()
|
||||
defer c.attesterLock.Unlock()
|
||||
|
||||
ids := []uint64{committeeID}
|
||||
val, exists := c.attester.Get(slot)
|
||||
if exists {
|
||||
ids = sliceutil.UnionUint64(append(val.([]uint64), ids...))
|
||||
}
|
||||
c.attester.Add(slot, ids)
|
||||
}
|
||||
|
||||
// GetAttesterCommitteeIDs gets the committee ID for subscribing subnet for attester of the slot.
|
||||
func (c *committeeIDs) GetAttesterCommitteeIDs(slot uint64) []uint64 {
|
||||
c.attesterLock.RLock()
|
||||
defer c.attesterLock.RUnlock()
|
||||
|
||||
val, exists := c.attester.Get(slot)
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
if v, ok := val.([]uint64); ok {
|
||||
return v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddAggregatorCommiteeID adds committee ID for subscribing subnet for the aggregator of a given slot.
|
||||
func (c *committeeIDs) AddAggregatorCommiteeID(slot uint64, committeeID uint64) {
|
||||
c.aggregatorLock.Lock()
|
||||
defer c.aggregatorLock.Unlock()
|
||||
|
||||
ids := []uint64{committeeID}
|
||||
val, exists := c.aggregator.Get(slot)
|
||||
if exists {
|
||||
ids = sliceutil.UnionUint64(append(val.([]uint64), ids...))
|
||||
}
|
||||
c.aggregator.Add(slot, ids)
|
||||
}
|
||||
|
||||
// GetAggregatorCommitteeIDs gets the committee ID for subscribing subnet for aggregator of the slot.
|
||||
func (c *committeeIDs) GetAggregatorCommitteeIDs(slot uint64) []uint64 {
|
||||
c.aggregatorLock.RLock()
|
||||
defer c.aggregatorLock.RUnlock()
|
||||
|
||||
val, exists := c.aggregator.Get(slot)
|
||||
if !exists {
|
||||
return []uint64{}
|
||||
}
|
||||
|
||||
56
beacon-chain/cache/committee_ids_test.go
vendored
Normal file
56
beacon-chain/cache/committee_ids_test.go
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCommitteeIDCache_RoundTrip(t *testing.T) {
|
||||
c := newCommitteeIDs()
|
||||
slot := uint64(100)
|
||||
committeeIDs := c.GetAggregatorCommitteeIDs(slot)
|
||||
if len(committeeIDs) != 0 {
|
||||
t.Errorf("Empty cache returned an object: %v", committeeIDs)
|
||||
}
|
||||
|
||||
c.AddAggregatorCommiteeID(slot, 1)
|
||||
res := c.GetAggregatorCommitteeIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{1}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
|
||||
c.AddAggregatorCommiteeID(slot, 2)
|
||||
res = c.GetAggregatorCommitteeIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{1, 2}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
|
||||
c.AddAggregatorCommiteeID(slot, 3)
|
||||
res = c.GetAggregatorCommitteeIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{1, 2, 3}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
|
||||
committeeIDs = c.GetAttesterCommitteeIDs(slot)
|
||||
if len(committeeIDs) != 0 {
|
||||
t.Errorf("Empty cache returned an object: %v", committeeIDs)
|
||||
}
|
||||
|
||||
c.AddAttesterCommiteeID(slot, 11)
|
||||
res = c.GetAttesterCommitteeIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{11}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
|
||||
c.AddAttesterCommiteeID(slot, 22)
|
||||
res = c.GetAttesterCommitteeIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{11, 22}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
|
||||
c.AddAttesterCommiteeID(slot, 33)
|
||||
res = c.GetAttesterCommitteeIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{11, 22, 33}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
}
|
||||
7
beacon-chain/cache/committee_test.go
vendored
7
beacon-chain/cache/committee_test.go
vendored
@@ -177,14 +177,17 @@ func TestCommitteeCache_CanRotate(t *testing.T) {
|
||||
func TestCommitteeCacheOutOfRange(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
seed := bytesutil.ToBytes32([]byte("foo"))
|
||||
cache.CommitteeCache.Add(&Committees{
|
||||
err := cache.CommitteeCache.Add(&Committees{
|
||||
CommitteeCount: 1,
|
||||
Seed: seed,
|
||||
ShuffledIndices: []uint64{0},
|
||||
SortedIndices: []uint64{},
|
||||
ProposerIndices: []uint64{},
|
||||
})
|
||||
_, err := cache.Committee(0, seed, math.MaxUint64) // Overflow!
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = cache.Committee(0, seed, math.MaxUint64) // Overflow!
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail as expected")
|
||||
}
|
||||
|
||||
8
beacon-chain/cache/common.go
vendored
8
beacon-chain/cache/common.go
vendored
@@ -14,8 +14,12 @@ var (
|
||||
// trim the FIFO queue to the maxSize.
|
||||
func trim(queue *cache.FIFO, maxSize int) {
|
||||
for s := len(queue.ListKeys()); s > maxSize; s-- {
|
||||
// #nosec G104 popProcessNoopFunc never returns an error
|
||||
_, _ = queue.Pop(popProcessNoopFunc)
|
||||
_, err := queue.Pop(popProcessNoopFunc)
|
||||
if err != nil {
|
||||
// popProcessNoopFunc never returns an error, but we handle this anyway to make linter
|
||||
// happy.
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Package depositcache is the source of validator deposits maintained
|
||||
// in-memory by the beacon node – deposits processed from the
|
||||
// eth1 powchain are then stored in this cache to be accessed by
|
||||
// any other service during a beacon node's runtime.
|
||||
package depositcache
|
||||
|
||||
import (
|
||||
@@ -35,12 +39,11 @@ type DepositFetcher interface {
|
||||
// stores all the deposit related data that is required by the beacon-node.
|
||||
type DepositCache struct {
|
||||
// Beacon chain deposits in memory.
|
||||
pendingDeposits []*dbpb.DepositContainer
|
||||
deposits []*dbpb.DepositContainer
|
||||
depositsLock sync.RWMutex
|
||||
chainStartDeposits []*ethpb.Deposit
|
||||
chainstartPubkeys map[string]bool
|
||||
chainstartPubkeysLock sync.RWMutex
|
||||
pendingDeposits []*dbpb.DepositContainer
|
||||
deposits []*dbpb.DepositContainer
|
||||
depositsLock sync.RWMutex
|
||||
chainStartDeposits []*ethpb.Deposit
|
||||
chainStartPubkeys map[string]bool
|
||||
}
|
||||
|
||||
// NewDepositCache instantiates a new deposit cache
|
||||
@@ -48,7 +51,7 @@ func NewDepositCache() *DepositCache {
|
||||
return &DepositCache{
|
||||
pendingDeposits: []*dbpb.DepositContainer{},
|
||||
deposits: []*dbpb.DepositContainer{},
|
||||
chainstartPubkeys: make(map[string]bool),
|
||||
chainStartPubkeys: make(map[string]bool),
|
||||
chainStartDeposits: make([]*ethpb.Deposit, 0),
|
||||
}
|
||||
}
|
||||
@@ -102,21 +105,17 @@ func (dc *DepositCache) AllDepositContainers(ctx context.Context) []*dbpb.Deposi
|
||||
func (dc *DepositCache) MarkPubkeyForChainstart(ctx context.Context, pubkey string) {
|
||||
ctx, span := trace.StartSpan(ctx, "DepositsCache.MarkPubkeyForChainstart")
|
||||
defer span.End()
|
||||
dc.chainstartPubkeysLock.Lock()
|
||||
defer dc.chainstartPubkeysLock.Unlock()
|
||||
dc.chainstartPubkeys[pubkey] = true
|
||||
dc.chainStartPubkeys[pubkey] = true
|
||||
}
|
||||
|
||||
// PubkeyInChainstart returns bool for whether the pubkey passed in has deposited.
|
||||
func (dc *DepositCache) PubkeyInChainstart(ctx context.Context, pubkey string) bool {
|
||||
ctx, span := trace.StartSpan(ctx, "DepositsCache.PubkeyInChainstart")
|
||||
defer span.End()
|
||||
dc.chainstartPubkeysLock.Lock()
|
||||
defer dc.chainstartPubkeysLock.Unlock()
|
||||
if dc.chainstartPubkeys != nil {
|
||||
return dc.chainstartPubkeys[pubkey]
|
||||
if dc.chainStartPubkeys != nil {
|
||||
return dc.chainStartPubkeys[pubkey]
|
||||
}
|
||||
dc.chainstartPubkeys = make(map[string]bool)
|
||||
dc.chainStartPubkeys = make(map[string]bool)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
5
beacon-chain/cache/doc.go
vendored
Normal file
5
beacon-chain/cache/doc.go
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// Package cache includes all important caches for the runtime
|
||||
// of an eth2 beacon node, ensuring the node does not spend
|
||||
// resources computing duplicate operations such as committee
|
||||
// calculations for validators during the same epoch, etc.
|
||||
package cache
|
||||
5
beacon-chain/cache/eth1_data.go
vendored
5
beacon-chain/cache/eth1_data.go
vendored
@@ -125,7 +125,10 @@ func (c *Eth1DataVoteCache) IncrementEth1DataVote(eth1DataHash [32]byte) (uint64
|
||||
|
||||
eth1DataVoteCacheHit.Inc()
|
||||
|
||||
eInfo, _ := obj.(*Eth1DataVote)
|
||||
eInfo, ok := obj.(*Eth1DataVote)
|
||||
if !ok {
|
||||
return 0, errors.New("cached value is not of type *Eth1DataVote")
|
||||
}
|
||||
eInfo.VoteCount++
|
||||
|
||||
if err := c.eth1DataVoteCache.Add(eInfo); err != nil {
|
||||
|
||||
7
beacon-chain/cache/eth1_data_test.go
vendored
7
beacon-chain/cache/eth1_data_test.go
vendored
@@ -74,8 +74,11 @@ func TestEth1DataVoteCache_CanIncrement(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, _ = cache.IncrementEth1DataVote(eInfo.Eth1DataHash)
|
||||
count, _ := cache.IncrementEth1DataVote(eInfo.Eth1DataHash)
|
||||
_, err = cache.IncrementEth1DataVote(eInfo.Eth1DataHash)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
count, err := cache.IncrementEth1DataVote(eInfo.Eth1DataHash)
|
||||
|
||||
if count != 58 {
|
||||
t.Errorf(
|
||||
|
||||
15
beacon-chain/cache/feature_flag_test.go
vendored
15
beacon-chain/cache/feature_flag_test.go
vendored
@@ -1,9 +1,14 @@
|
||||
package cache
|
||||
|
||||
import "github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
func init() {
|
||||
featureconfig.Init(&featureconfig.Flags{
|
||||
EnableEth1DataVoteCache: true,
|
||||
})
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{EnableEth1DataVoteCache: true})
|
||||
defer resetCfg()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ go_test(
|
||||
srcs = [
|
||||
"block_operations_fuzz_test.go",
|
||||
"block_operations_test.go",
|
||||
"block_regression_test.go",
|
||||
"block_test.go",
|
||||
"eth1_data_test.go",
|
||||
],
|
||||
@@ -49,6 +50,7 @@ go_test(
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Package blocks contains block processing libraries. These libraries
|
||||
// process and verify block specific messages such as PoW receipt root,
|
||||
// RANDAO, validator deposits, exits and slashing proofs.
|
||||
// Package blocks contains block processing libraries according to
|
||||
// the eth2spec.
|
||||
package blocks
|
||||
|
||||
import (
|
||||
|
||||
@@ -35,50 +35,8 @@ var log = logrus.WithField("prefix", "blocks")
|
||||
|
||||
var eth1DataCache = cache.NewEth1DataVoteCache()
|
||||
|
||||
// ErrSigFailedToVerify returns when a signature of a block object(ie attestation, slashing, exit... etc)
|
||||
// failed to verify.
|
||||
var ErrSigFailedToVerify = errors.New("signature did not verify")
|
||||
|
||||
func verifySigningRoot(obj interface{}, pub []byte, signature []byte, domain uint64) error {
|
||||
publicKey, err := bls.PublicKeyFromBytes(pub)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to public key")
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(signature)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
root, err := ssz.HashTreeRoot(obj)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root")
|
||||
}
|
||||
if !sig.Verify(root[:], publicKey, domain) {
|
||||
return ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyBlockRoot(blk *ethpb.BeaconBlock, pub []byte, signature []byte, domain uint64) error {
|
||||
publicKey, err := bls.PublicKeyFromBytes(pub)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to public key")
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(signature)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
root, err := stateutil.BlockRoot(blk)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root")
|
||||
}
|
||||
if !sig.Verify(root[:], publicKey, domain) {
|
||||
return ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deprecated: This method uses deprecated ssz.SigningRoot.
|
||||
func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, pub []byte, signature []byte, domain uint64) error {
|
||||
func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, pub []byte, signature []byte, domain []byte) error {
|
||||
publicKey, err := bls.PublicKeyFromBytes(pub)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to public key")
|
||||
@@ -91,13 +49,21 @@ func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, pub []byte, signature
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root")
|
||||
}
|
||||
if !sig.Verify(root[:], publicKey, domain) {
|
||||
return ErrSigFailedToVerify
|
||||
sigRoot := &pb.SigningRoot{
|
||||
ObjectRoot: root[:],
|
||||
Domain: domain,
|
||||
}
|
||||
ctrRoot, err := ssz.HashTreeRoot(sigRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get container root")
|
||||
}
|
||||
if !sig.Verify(ctrRoot[:], publicKey) {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifySignature(signedData []byte, pub []byte, signature []byte, domain uint64) error {
|
||||
func verifySignature(signedData []byte, pub []byte, signature []byte, domain []byte) error {
|
||||
publicKey, err := bls.PublicKeyFromBytes(pub)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to public key")
|
||||
@@ -106,8 +72,16 @@ func verifySignature(signedData []byte, pub []byte, signature []byte, domain uin
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
if !sig.Verify(signedData, publicKey, domain) {
|
||||
return ErrSigFailedToVerify
|
||||
ctr := &pb.SigningRoot{
|
||||
ObjectRoot: signedData,
|
||||
Domain: domain,
|
||||
}
|
||||
root, err := ssz.HashTreeRoot(ctr)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not hash container")
|
||||
}
|
||||
if !sig.Verify(root[:], publicKey) {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -119,7 +93,7 @@ func verifySignature(signedData []byte, pub []byte, signature []byte, domain uin
|
||||
// Official spec definition:
|
||||
// def process_eth1_data(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||
// state.eth1_data_votes.append(body.eth1_data)
|
||||
// if state.eth1_data_votes.count(body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD:
|
||||
// if state.eth1_data_votes.count(body.eth1_data) * 2 > EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH:
|
||||
// state.latest_eth1_data = body.eth1_data
|
||||
func ProcessEth1DataInBlock(beaconState *stateTrie.BeaconState, block *ethpb.BeaconBlock) (*stateTrie.BeaconState, error) {
|
||||
if beaconState == nil {
|
||||
@@ -170,7 +144,6 @@ func Eth1DataHasEnoughSupport(beaconState *stateTrie.BeaconState, data *ethpb.Et
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "could not retrieve eth1 data vote cache")
|
||||
}
|
||||
|
||||
}
|
||||
if voteCount == 0 {
|
||||
for _, vote := range beaconState.Eth1DataVotes() {
|
||||
@@ -193,7 +166,8 @@ func Eth1DataHasEnoughSupport(beaconState *stateTrie.BeaconState, data *ethpb.Et
|
||||
|
||||
// If 50+% majority converged on the same eth1data, then it has enough support to update the
|
||||
// state.
|
||||
return voteCount*2 > params.BeaconConfig().SlotsPerEth1VotingPeriod, nil
|
||||
support := params.BeaconConfig().EpochsPerEth1VotingPeriod * params.BeaconConfig().SlotsPerEpoch
|
||||
return voteCount*2 > support, nil
|
||||
}
|
||||
|
||||
// ProcessBlockHeader validates a block by its header.
|
||||
@@ -203,6 +177,8 @@ func Eth1DataHasEnoughSupport(beaconState *stateTrie.BeaconState, data *ethpb.Et
|
||||
// def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
|
||||
// # Verify that the slots match
|
||||
// assert block.slot == state.slot
|
||||
// # Verify that proposer index is the correct index
|
||||
// assert block.proposer_index == get_beacon_proposer_index(state)
|
||||
// # Verify that the parent matches
|
||||
// assert block.parent_root == signing_root(state.latest_block_header)
|
||||
// # Save current block as the new latest block
|
||||
@@ -227,28 +203,29 @@ func ProcessBlockHeader(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idx, err := helpers.BeaconProposerIndex(beaconState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proposer, err := beaconState.ValidatorAtIndex(idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify proposer signature.
|
||||
currentEpoch := helpers.SlotToEpoch(beaconState.Slot())
|
||||
domain, err := helpers.Domain(beaconState.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer)
|
||||
if err != nil {
|
||||
if err := VerifyBlockHeaderSignature(beaconState, block); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := verifyBlockRoot(block.Block, proposer.PublicKey, block.Signature, domain); err != nil {
|
||||
return nil, ErrSigFailedToVerify
|
||||
}
|
||||
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// VerifyBlockHeaderSignature verifies the proposer signature of a beacon block.
|
||||
func VerifyBlockHeaderSignature(beaconState *stateTrie.BeaconState, block *ethpb.SignedBeaconBlock) error {
|
||||
proposer, err := beaconState.ValidatorAtIndex(block.Block.ProposerIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
currentEpoch := helpers.SlotToEpoch(beaconState.Slot())
|
||||
domain, err := helpers.Domain(beaconState.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return helpers.VerifySigningRoot(block.Block, proposer.PublicKey, block.Signature, domain)
|
||||
}
|
||||
|
||||
// ProcessBlockHeaderNoVerify validates a block by its header but skips proposer
|
||||
// signature verification.
|
||||
//
|
||||
@@ -259,6 +236,8 @@ func ProcessBlockHeader(
|
||||
// def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
|
||||
// # Verify that the slots match
|
||||
// assert block.slot == state.slot
|
||||
// # Verify that proposer index is the correct index
|
||||
// assert block.proposer_index == get_beacon_proposer_index(state)
|
||||
// # Verify that the parent matches
|
||||
// assert block.parent_root == signing_root(state.latest_block_header)
|
||||
// # Save current block as the new latest block
|
||||
@@ -280,7 +259,14 @@ func ProcessBlockHeaderNoVerify(
|
||||
return nil, errors.New("nil block")
|
||||
}
|
||||
if beaconState.Slot() != block.Slot {
|
||||
return nil, fmt.Errorf("state slot: %d is different then block slot: %d", beaconState.Slot(), block.Slot)
|
||||
return nil, fmt.Errorf("state slot: %d is different than block slot: %d", beaconState.Slot(), block.Slot)
|
||||
}
|
||||
idx, err := helpers.BeaconProposerIndex(beaconState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if block.ProposerIndex != idx {
|
||||
return nil, fmt.Errorf("proposer index: %d is different than calculated: %d", block.ProposerIndex, idx)
|
||||
}
|
||||
parentRoot, err := stateutil.BlockHeaderRoot(beaconState.LatestBlockHeader())
|
||||
if err != nil {
|
||||
@@ -293,10 +279,6 @@ func ProcessBlockHeaderNoVerify(
|
||||
block.ParentRoot, parentRoot)
|
||||
}
|
||||
|
||||
idx, err := helpers.BeaconProposerIndex(beaconState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proposer, err := beaconState.ValidatorAtIndex(idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -310,10 +292,11 @@ func ProcessBlockHeaderNoVerify(
|
||||
return nil, err
|
||||
}
|
||||
if err := beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: block.Slot,
|
||||
ParentRoot: block.ParentRoot,
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
BodyRoot: bodyRoot[:],
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: block.ParentRoot,
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
BodyRoot: bodyRoot[:],
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -353,7 +336,7 @@ func ProcessRandao(
|
||||
buf := make([]byte, 32)
|
||||
binary.LittleEndian.PutUint64(buf, currentEpoch)
|
||||
|
||||
domain, err := helpers.Domain(beaconState.Fork(), currentEpoch, params.BeaconConfig().DomainRandao)
|
||||
domain, err := helpers.Domain(beaconState.Fork(), currentEpoch, params.BeaconConfig().DomainRandao, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -396,7 +379,7 @@ func ProcessRandaoNoVerify(
|
||||
for i, x := range blockRandaoReveal {
|
||||
latestMixSlice[i] ^= x
|
||||
}
|
||||
if err := beaconState.UpdateRandaoMixesAtIndex(latestMixSlice, currentEpoch%latestMixesLength); err != nil {
|
||||
if err := beaconState.UpdateRandaoMixesAtIndex(currentEpoch%latestMixesLength, latestMixSlice); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, nil
|
||||
@@ -434,51 +417,51 @@ func ProcessProposerSlashings(
|
||||
if slashing == nil {
|
||||
return nil, errors.New("nil proposer slashings in block body")
|
||||
}
|
||||
if int(slashing.ProposerIndex) >= beaconState.NumValidators() {
|
||||
return nil, fmt.Errorf("invalid proposer index given in slashing %d", slashing.ProposerIndex)
|
||||
}
|
||||
if err = VerifyProposerSlashing(beaconState, slashing); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify proposer slashing %d", idx)
|
||||
}
|
||||
beaconState, err = v.SlashValidator(
|
||||
beaconState, slashing.ProposerIndex, 0, /* proposer is whistleblower */
|
||||
beaconState, slashing.Header_1.Header.ProposerIndex, 0, /* proposer is whistleblower */
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not slash proposer index %d", slashing.ProposerIndex)
|
||||
return nil, errors.Wrapf(err, "could not slash proposer index %d", slashing.Header_1.Header.ProposerIndex)
|
||||
}
|
||||
}
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// VerifyProposerSlashing verifies that the data provided fro slashing is valid.
|
||||
// VerifyProposerSlashing verifies that the data provided from slashing is valid.
|
||||
func VerifyProposerSlashing(
|
||||
beaconState *stateTrie.BeaconState,
|
||||
slashing *ethpb.ProposerSlashing,
|
||||
) error {
|
||||
proposer, err := beaconState.ValidatorAtIndex(slashing.ProposerIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if slashing.Header_1 == nil || slashing.Header_1.Header == nil || slashing.Header_2 == nil || slashing.Header_2.Header == nil {
|
||||
return errors.New("nil header cannot be verified")
|
||||
}
|
||||
if slashing.Header_1.Header.Slot != slashing.Header_2.Header.Slot {
|
||||
return fmt.Errorf("mismatched header slots, received %d == %d", slashing.Header_1.Header.Slot, slashing.Header_2.Header.Slot)
|
||||
}
|
||||
if slashing.Header_1.Header.ProposerIndex != slashing.Header_2.Header.ProposerIndex {
|
||||
return fmt.Errorf("mismatched indices, received %d == %d", slashing.Header_1.Header.ProposerIndex, slashing.Header_2.Header.ProposerIndex)
|
||||
}
|
||||
if proto.Equal(slashing.Header_1, slashing.Header_2) {
|
||||
return errors.New("expected slashing headers to differ")
|
||||
}
|
||||
proposer, err := beaconState.ValidatorAtIndex(slashing.Header_1.Header.ProposerIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !helpers.IsSlashableValidator(proposer, helpers.SlotToEpoch(beaconState.Slot())) {
|
||||
return fmt.Errorf("validator with key %#x is not slashable", proposer.PublicKey)
|
||||
}
|
||||
// Using headerEpoch1 here because both of the headers should have the same epoch.
|
||||
domain, err := helpers.Domain(beaconState.Fork(), helpers.StartSlot(slashing.Header_1.Header.Slot), params.BeaconConfig().DomainBeaconProposer)
|
||||
domain, err := helpers.Domain(beaconState.Fork(), helpers.SlotToEpoch(slashing.Header_1.Header.Slot), params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headers := []*ethpb.SignedBeaconBlockHeader{slashing.Header_1, slashing.Header_2}
|
||||
for _, header := range headers {
|
||||
if err := verifySigningRoot(header.Header, proposer.PublicKey, header.Signature, domain); err != nil {
|
||||
if err := helpers.VerifySigningRoot(header.Header, proposer.PublicKey, header.Signature, domain); err != nil {
|
||||
return errors.Wrap(err, "could not verify beacon block header")
|
||||
}
|
||||
}
|
||||
@@ -596,7 +579,7 @@ func slashableAttesterIndices(slashing *ethpb.AttesterSlashing) []uint64 {
|
||||
return nil
|
||||
}
|
||||
indices1 := slashing.Attestation_1.AttestingIndices
|
||||
indices2 := slashing.Attestation_1.AttestingIndices
|
||||
indices2 := slashing.Attestation_2.AttestingIndices
|
||||
return sliceutil.IntersectionUint64(indices1, indices2)
|
||||
}
|
||||
|
||||
@@ -827,30 +810,25 @@ func VerifyIndexedAttestation(ctx context.Context, beaconState *stateTrie.Beacon
|
||||
return errors.New("attesting indices is not uniquely sorted")
|
||||
}
|
||||
|
||||
domain, err := helpers.Domain(beaconState.Fork(), indexedAtt.Data.Target.Epoch, params.BeaconConfig().DomainBeaconAttester)
|
||||
domain, err := helpers.Domain(beaconState.Fork(), indexedAtt.Data.Target.Epoch, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var pubkey *bls.PublicKey
|
||||
pubkeys := []*bls.PublicKey{}
|
||||
if len(indices) > 0 {
|
||||
pubkeyAtIdx := beaconState.PubkeyAtIndex(indices[0])
|
||||
pubkey, err = bls.PublicKeyFromBytes(pubkeyAtIdx[:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not deserialize validator public key")
|
||||
}
|
||||
for i := 1; i < len(indices); i++ {
|
||||
pubkeyAtIdx = beaconState.PubkeyAtIndex(indices[i])
|
||||
for i := 0; i < len(indices); i++ {
|
||||
pubkeyAtIdx := beaconState.PubkeyAtIndex(indices[i])
|
||||
pk, err := bls.PublicKeyFromBytes(pubkeyAtIdx[:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not deserialize validator public key")
|
||||
}
|
||||
pubkey.Aggregate(pk)
|
||||
pubkeys = append(pubkeys, pk)
|
||||
}
|
||||
}
|
||||
|
||||
messageHash, err := ssz.HashTreeRoot(indexedAtt.Data)
|
||||
messageHash, err := helpers.ComputeSigningRoot(indexedAtt.Data, domain)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not tree hash att data")
|
||||
return errors.Wrap(err, "could not get signing root of object")
|
||||
}
|
||||
|
||||
sig, err := bls.SignatureFromBytes(indexedAtt.Signature)
|
||||
@@ -859,8 +837,8 @@ func VerifyIndexedAttestation(ctx context.Context, beaconState *stateTrie.Beacon
|
||||
}
|
||||
|
||||
voted := len(indices) > 0
|
||||
if voted && !sig.Verify(messageHash[:], pubkey, domain) {
|
||||
return ErrSigFailedToVerify
|
||||
if voted && !sig.FastAggregateVerify(pubkeys, messageHash) {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1002,11 +980,14 @@ func ProcessDeposit(
|
||||
index, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey))
|
||||
numVals := beaconState.NumValidators()
|
||||
if !ok {
|
||||
domain := bls.ComputeDomain(params.BeaconConfig().DomainDeposit)
|
||||
domain, err := helpers.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
depositSig := deposit.Data.Signature
|
||||
if err := verifyDepositDataSigningRoot(deposit.Data, pubKey, depositSig, domain); err != nil {
|
||||
// Ignore this error as in the spec pseudo code.
|
||||
log.Errorf("Skipping deposit: could not verify deposit data signature: %v", err)
|
||||
log.Debugf("Skipping deposit: could not verify deposit data signature: %v", err)
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
@@ -1112,7 +1093,7 @@ func ProcessVoluntaryExits(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := VerifyExit(val, beaconState.Slot(), beaconState.Fork(), exit); err != nil {
|
||||
if err := VerifyExit(val, beaconState.Slot(), beaconState.Fork(), exit, beaconState.GenesisValidatorRoot()); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify exit %d", idx)
|
||||
}
|
||||
beaconState, err = v.InitiateValidatorExit(beaconState, exit.Exit.ValidatorIndex)
|
||||
@@ -1163,7 +1144,7 @@ func ProcessVoluntaryExitsNoVerify(
|
||||
// # Verify signature
|
||||
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, exit.epoch)
|
||||
// assert bls_verify(validator.pubkey, signing_root(exit), exit.signature, domain)
|
||||
func VerifyExit(validator *ethpb.Validator, currentSlot uint64, fork *pb.Fork, signed *ethpb.SignedVoluntaryExit) error {
|
||||
func VerifyExit(validator *ethpb.Validator, currentSlot uint64, fork *pb.Fork, signed *ethpb.SignedVoluntaryExit, genesisRoot []byte) error {
|
||||
if signed == nil || signed.Exit == nil {
|
||||
return errors.New("nil exit")
|
||||
}
|
||||
@@ -1190,12 +1171,12 @@ func VerifyExit(validator *ethpb.Validator, currentSlot uint64, fork *pb.Fork, s
|
||||
validator.ActivationEpoch+params.BeaconConfig().PersistentCommitteePeriod,
|
||||
)
|
||||
}
|
||||
domain, err := helpers.Domain(fork, exit.Epoch, params.BeaconConfig().DomainVoluntaryExit)
|
||||
domain, err := helpers.Domain(fork, exit.Epoch, params.BeaconConfig().DomainVoluntaryExit, genesisRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := verifySigningRoot(exit, validator.PublicKey, signed.Signature, domain); err != nil {
|
||||
return ErrSigFailedToVerify
|
||||
if err := helpers.VerifySigningRoot(exit, validator.PublicKey, signed.Signature, domain); err != nil {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
|
||||
//"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
@@ -25,8 +24,9 @@ func TestFuzzProcessAttestationNoVerify_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(att)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
_, _ = ProcessAttestationNoVerify(ctx, s, att)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
_, err = ProcessAttestationNoVerify(ctx, s, att)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,33 +39,9 @@ func TestFuzzProcessBlockHeader_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(block)
|
||||
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
_, _ = ProcessBlockHeader(s, block)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzverifySigningRoot_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
pubkey := [48]byte{}
|
||||
sig := [96]byte{}
|
||||
domain := [4]byte{}
|
||||
p := []byte{}
|
||||
s := []byte{}
|
||||
d := uint64(0)
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(&pubkey)
|
||||
fuzzer.Fuzz(&sig)
|
||||
fuzzer.Fuzz(&domain)
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(&p)
|
||||
fuzzer.Fuzz(&s)
|
||||
fuzzer.Fuzz(&d)
|
||||
domain := bytesutil.FromBytes4(domain[:])
|
||||
verifySigningRoot(state, pubkey[:], sig[:], domain)
|
||||
verifySigningRoot(state, p, s, d)
|
||||
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
_, err = ProcessBlockHeader(s, block)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +53,7 @@ func TestFuzzverifyDepositDataSigningRoot_10000(t *testing.T) {
|
||||
domain := [4]byte{}
|
||||
p := []byte{}
|
||||
s := []byte{}
|
||||
d := uint64(0)
|
||||
d := []byte{}
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(&ba)
|
||||
fuzzer.Fuzz(&pubkey)
|
||||
@@ -86,9 +62,9 @@ func TestFuzzverifyDepositDataSigningRoot_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(&p)
|
||||
fuzzer.Fuzz(&s)
|
||||
fuzzer.Fuzz(&d)
|
||||
domain := bytesutil.FromBytes4(domain[:])
|
||||
verifySignature(ba, pubkey[:], sig[:], domain)
|
||||
verifySignature(ba, p, s, d)
|
||||
err := verifySignature(ba, pubkey[:], sig[:], domain[:])
|
||||
err = verifySignature(ba, p, s, d)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,10 +102,11 @@ func TestFuzzEth1DataHasEnoughSupport_10000(t *testing.T) {
|
||||
for i := 0; i < 100000; i++ {
|
||||
fuzzer.Fuzz(eth1data)
|
||||
fuzzer.Fuzz(&stateVotes)
|
||||
s, _ := beaconstate.InitializeFromProto(ðereum_beacon_p2p_v1.BeaconState{
|
||||
s, err := beaconstate.InitializeFromProto(ðereum_beacon_p2p_v1.BeaconState{
|
||||
Eth1DataVotes: stateVotes,
|
||||
})
|
||||
Eth1DataHasEnoughSupport(s, eth1data)
|
||||
_, err = Eth1DataHasEnoughSupport(s, eth1data)
|
||||
_ = err
|
||||
}
|
||||
|
||||
}
|
||||
@@ -142,8 +119,9 @@ func TestFuzzProcessBlockHeaderNoVerify_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(block)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
_, _ = ProcessBlockHeaderNoVerify(s, block)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
_, err = ProcessBlockHeaderNoVerify(s, block)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +133,7 @@ func TestFuzzProcessRandao_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessRandao(s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -171,7 +149,7 @@ func TestFuzzProcessRandaoNoVerify_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessRandaoNoVerify(s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -187,7 +165,7 @@ func TestFuzzProcessProposerSlashings_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessProposerSlashings(ctx, s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -202,8 +180,9 @@ func TestFuzzVerifyProposerSlashing_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(proposerSlashing)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
VerifyProposerSlashing(s, proposerSlashing)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
err = VerifyProposerSlashing(s, proposerSlashing)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +194,7 @@ func TestFuzzProcessAttesterSlashings_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessAttesterSlashings(ctx, s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -231,8 +210,9 @@ func TestFuzzVerifyAttesterSlashing_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attesterSlashing)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
VerifyAttesterSlashing(ctx, s, attesterSlashing)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
err = VerifyAttesterSlashing(ctx, s, attesterSlashing)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +246,7 @@ func TestFuzzProcessAttestations_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessAttestations(ctx, s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -282,7 +262,7 @@ func TestFuzzProcessAttestationsNoVerify_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessAttestationsNoVerify(ctx, s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -298,7 +278,7 @@ func TestFuzzProcessAttestation_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attestation)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessAttestation(ctx, s, attestation)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, attestation)
|
||||
@@ -314,8 +294,9 @@ func TestFuzzVerifyIndexedAttestationn_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(idxAttestation)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
VerifyIndexedAttestation(ctx, s, idxAttestation)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
err = VerifyIndexedAttestation(ctx, s, idxAttestation)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,8 +308,9 @@ func TestFuzzVerifyAttestation_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attestation)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
VerifyAttestation(ctx, s, attestation)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
err = VerifyAttestation(ctx, s, attestation)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +322,7 @@ func TestFuzzProcessDeposits_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessDeposits(ctx, s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -357,7 +339,7 @@ func TestFuzzProcessPreGenesisDeposit_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessPreGenesisDeposit(ctx, s, deposit)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, deposit)
|
||||
@@ -373,7 +355,7 @@ func TestFuzzProcessDeposit_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessDeposit(s, deposit)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, deposit)
|
||||
@@ -388,8 +370,9 @@ func TestFuzzverifyDeposit_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
verifyDeposit(s, deposit)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
err = verifyDeposit(s, deposit)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,7 +384,7 @@ func TestFuzzProcessVoluntaryExits_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessVoluntaryExits(ctx, s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -416,7 +399,7 @@ func TestFuzzProcessVoluntaryExitsNoVerify_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, _ := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessVoluntaryExitsNoVerify(s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -436,6 +419,7 @@ func TestFuzzVerifyExit_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(val)
|
||||
fuzzer.Fuzz(fork)
|
||||
fuzzer.Fuzz(&slot)
|
||||
VerifyExit(val, slot, fork, ve)
|
||||
err := VerifyExit(val, slot, fork, ve, params.BeaconConfig().ZeroHash[:])
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
113
beacon-chain/core/blocks/block_regression_test.go
Normal file
113
beacon-chain/core/blocks/block_regression_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package blocks_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) {
|
||||
testutil.ResetCache()
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 5500)
|
||||
for _, vv := range beaconState.Validators() {
|
||||
vv.WithdrawableEpoch = 1 * params.BeaconConfig().SlotsPerEpoch
|
||||
}
|
||||
// This set of indices is very similar to the one from our sapphire testnet
|
||||
// when close to 100 validators were incorrectly slashed. The set is from 0 -5500,
|
||||
// instead of 55000 as it would take too long to generate a state.
|
||||
setA := []uint64{21, 92, 236, 244, 281, 321, 510, 524,
|
||||
538, 682, 828, 858, 913, 920, 922, 959, 1176, 1207,
|
||||
1222, 1229, 1354, 1394, 1436, 1454, 1510, 1550,
|
||||
1552, 1576, 1645, 1704, 1842, 1967, 2076, 2111, 2134, 2307,
|
||||
2343, 2354, 2417, 2524, 2532, 2555, 2740, 2749, 2759, 2762,
|
||||
2800, 2809, 2824, 2987, 3110, 3125, 3559, 3583, 3599, 3608,
|
||||
3657, 3685, 3723, 3756, 3759, 3761, 3820, 3826, 3979, 4030,
|
||||
4141, 4170, 4205, 4247, 4257, 4479, 4492, 4569, 5091,
|
||||
}
|
||||
// Only 2800 is the slashable index.
|
||||
setB := []uint64{1361, 1438, 2383, 2800}
|
||||
expectedSlashedVal := 2800
|
||||
|
||||
root1 := [32]byte{'d', 'o', 'u', 'b', 'l', 'e', '1'}
|
||||
att1 := ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root1[:]},
|
||||
},
|
||||
AttestingIndices: setA,
|
||||
}
|
||||
domain, err := helpers.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
signingRoot, err := helpers.ComputeSigningRoot(att1.Data, domain)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get signing root of beacon block header: %v", err)
|
||||
}
|
||||
aggSigs := []*bls.Signature{}
|
||||
for _, index := range setA {
|
||||
sig := privKeys[index].Sign(signingRoot[:])
|
||||
aggSigs = append(aggSigs, sig)
|
||||
}
|
||||
aggregateSig := bls.AggregateSignatures(aggSigs)
|
||||
att1.Signature = aggregateSig.Marshal()[:]
|
||||
|
||||
root2 := [32]byte{'d', 'o', 'u', 'b', 'l', 'e', '2'}
|
||||
att2 := ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root2[:]},
|
||||
},
|
||||
AttestingIndices: setB,
|
||||
}
|
||||
signingRoot, err = helpers.ComputeSigningRoot(att2.Data, domain)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get signing root of beacon block header: %v", err)
|
||||
}
|
||||
aggSigs = []*bls.Signature{}
|
||||
for _, index := range setB {
|
||||
sig := privKeys[index].Sign(signingRoot[:])
|
||||
aggSigs = append(aggSigs, sig)
|
||||
}
|
||||
aggregateSig = bls.AggregateSignatures(aggSigs)
|
||||
att2.Signature = aggregateSig.Marshal()[:]
|
||||
|
||||
slashings := []*ethpb.AttesterSlashing{
|
||||
{
|
||||
Attestation_1: att1,
|
||||
Attestation_2: att2,
|
||||
},
|
||||
}
|
||||
|
||||
currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
|
||||
if err := beaconState.SetSlot(currentSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
AttesterSlashings: slashings,
|
||||
},
|
||||
}
|
||||
|
||||
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, block.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newRegistry := newState.Validators()
|
||||
if !newRegistry[expectedSlashedVal].Slashed {
|
||||
t.Errorf("Validator with index %d was not slashed despite performing a double vote", expectedSlashedVal)
|
||||
}
|
||||
|
||||
for idx, val := range newRegistry {
|
||||
if val.Slashed && idx != expectedSlashedVal {
|
||||
t.Errorf("validator with index: %d was unintentionally slashed", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,17 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func FakeDeposits(n int) []*ethpb.Eth1Data {
|
||||
deposits := make([]*ethpb.Eth1Data, n)
|
||||
for i := 0; i < n; i++ {
|
||||
deposits[i] = ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}
|
||||
}
|
||||
return deposits
|
||||
}
|
||||
|
||||
func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
tests := []struct {
|
||||
stateVotes []*ethpb.Eth1Data
|
||||
@@ -19,21 +30,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
votingPeriodLength uint64
|
||||
}{
|
||||
{
|
||||
stateVotes: []*ethpb.Eth1Data{
|
||||
{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
},
|
||||
},
|
||||
stateVotes: FakeDeposits(4 * int(params.BeaconConfig().SlotsPerEpoch)),
|
||||
data: ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
@@ -41,21 +38,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
hasSupport: true,
|
||||
votingPeriodLength: 7,
|
||||
}, {
|
||||
stateVotes: []*ethpb.Eth1Data{
|
||||
{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
},
|
||||
},
|
||||
stateVotes: FakeDeposits(4 * int(params.BeaconConfig().SlotsPerEpoch)),
|
||||
data: ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
@@ -63,21 +46,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
hasSupport: false,
|
||||
votingPeriodLength: 8,
|
||||
}, {
|
||||
stateVotes: []*ethpb.Eth1Data{
|
||||
{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
},
|
||||
},
|
||||
stateVotes: FakeDeposits(4 * int(params.BeaconConfig().SlotsPerEpoch)),
|
||||
data: ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
@@ -90,12 +59,15 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
for i, tt := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
c := params.BeaconConfig()
|
||||
c.SlotsPerEth1VotingPeriod = tt.votingPeriodLength
|
||||
c.EpochsPerEth1VotingPeriod = tt.votingPeriodLength
|
||||
params.OverrideBeaconConfig(c)
|
||||
|
||||
s, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
s, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Eth1DataVotes: tt.stateVotes,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result, err := blocks.Eth1DataHasEnoughSupport(s, tt.data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -103,8 +75,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
|
||||
if result != tt.hasSupport {
|
||||
t.Errorf(
|
||||
"blocks.Eth1DataHasEnoughSupport(%+v, %+v) = %t, wanted %t",
|
||||
s,
|
||||
"blocks.Eth1DataHasEnoughSupport(%+v) = %t, wanted %t",
|
||||
tt.data,
|
||||
result,
|
||||
tt.hasSupport,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package spectest contains all comformity specification tests
|
||||
// for block processing according to the eth2 spec.
|
||||
package spectest
|
||||
|
||||
import (
|
||||
@@ -98,8 +100,8 @@ func runBlockProcessingTest(t *testing.T, config string) {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if !proto.Equal(beaconState.CloneInnerState(), postBeaconState) {
|
||||
diff, _ := messagediff.PrettyDiff(beaconState.CloneInnerState(), postBeaconState)
|
||||
if !proto.Equal(beaconState.InnerStateUnsafe(), postBeaconState) {
|
||||
diff, _ := messagediff.PrettyDiff(beaconState.InnerStateUnsafe(), postBeaconState)
|
||||
t.Log(diff)
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package epoch contains epoch processing libraries. These libraries
|
||||
// process new balance for the validators, justify and finalize new
|
||||
// check points, shuffle and reassign validators to different slots and
|
||||
// Package epoch contains epoch processing libraries according to spec, able to
|
||||
// process new balance for validators, justify and finalize new
|
||||
// check points, and shuffle validators to different slots and
|
||||
// shards.
|
||||
package epoch
|
||||
|
||||
@@ -194,15 +194,18 @@ func ProcessSlashings(state *stateTrie.BeaconState) (*stateTrie.BeaconState, err
|
||||
// current_epoch = get_current_epoch(state)
|
||||
// next_epoch = Epoch(current_epoch + 1)
|
||||
// # Reset eth1 data votes
|
||||
// if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0:
|
||||
// if next_epoch % EPOCHS_PER_ETH1_VOTING_PERIOD == 0:
|
||||
// state.eth1_data_votes = []
|
||||
// # Update effective balances with hysteresis
|
||||
// for index, validator in enumerate(state.validators):
|
||||
// balance = state.balances[index]
|
||||
// HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2
|
||||
// if balance < validator.effective_balance or validator.effective_balance + 3 * HALF_INCREMENT < balance:
|
||||
// validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
|
||||
// # Set active index root
|
||||
// HYSTERESIS_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT
|
||||
// DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER
|
||||
// UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER
|
||||
// if (
|
||||
// balance + DOWNWARD_THRESHOLD < validator.effective_balance
|
||||
// or validator.effective_balance + UPWARD_THRESHOLD < balance
|
||||
// ):
|
||||
// index_epoch = Epoch(next_epoch + ACTIVATION_EXIT_DELAY)
|
||||
// index_root_position = index_epoch % EPOCHS_PER_HISTORICAL_VECTOR
|
||||
// indices_list = List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, index_epoch))
|
||||
@@ -228,7 +231,7 @@ func ProcessFinalUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconState,
|
||||
nextEpoch := currentEpoch + 1
|
||||
|
||||
// Reset ETH1 data votes.
|
||||
if (state.Slot()+1)%params.BeaconConfig().SlotsPerEth1VotingPeriod == 0 {
|
||||
if nextEpoch%params.BeaconConfig().EpochsPerEth1VotingPeriod == 0 {
|
||||
if err := state.SetEth1DataVotes([]*ethpb.Eth1Data{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -244,8 +247,11 @@ func ProcessFinalUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconState,
|
||||
return false, fmt.Errorf("validator index exceeds validator length in state %d >= %d", idx, len(state.Balances()))
|
||||
}
|
||||
balance := bals[idx]
|
||||
halfInc := params.BeaconConfig().EffectiveBalanceIncrement / 2
|
||||
if balance < val.EffectiveBalance || val.EffectiveBalance+3*halfInc < balance {
|
||||
hysteresisInc := params.BeaconConfig().EffectiveBalanceIncrement / params.BeaconConfig().HysteresisQuotient
|
||||
downwardThreshold := hysteresisInc * params.BeaconConfig().HysteresisDownwardMultiplier
|
||||
upwardThreshold := hysteresisInc * params.BeaconConfig().HysteresisUpwardMultiplier
|
||||
|
||||
if balance+downwardThreshold < val.EffectiveBalance || val.EffectiveBalance+upwardThreshold < balance {
|
||||
val.EffectiveBalance = params.BeaconConfig().MaxEffectiveBalance
|
||||
if val.EffectiveBalance > balance-balance%params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
val.EffectiveBalance = balance - balance%params.BeaconConfig().EffectiveBalanceIncrement
|
||||
@@ -287,7 +293,7 @@ func ProcessFinalUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconState,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := state.UpdateRandaoMixesAtIndex(mix, nextEpoch%randaoMixLength); err != nil {
|
||||
if err := state.UpdateRandaoMixesAtIndex(nextEpoch%randaoMixLength, mix); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -351,7 +357,11 @@ func unslashedAttestingIndices(state *stateTrie.BeaconState, atts []*pb.PendingA
|
||||
sort.Slice(setIndices, func(i, j int) bool { return setIndices[i] < setIndices[j] })
|
||||
// Remove the slashed validator indices.
|
||||
for i := 0; i < len(setIndices); i++ {
|
||||
if v, _ := state.ValidatorAtIndex(setIndices[i]); v != nil && v.Slashed {
|
||||
v, err := state.ValidatorAtIndex(setIndices[i])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to look up validator")
|
||||
}
|
||||
if v != nil && v.Slashed {
|
||||
setIndices = append(setIndices[:i], setIndices[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,6 @@ func TestFuzzFinalUpdates_10000(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, _ = ProcessFinalUpdates(s)
|
||||
_, err = ProcessFinalUpdates(s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,9 @@ func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) {
|
||||
slashedValidator := indices[0]
|
||||
validators = state.Validators()
|
||||
validators[slashedValidator].Slashed = true
|
||||
state.SetValidators(validators)
|
||||
if err = state.SetValidators(validators); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
indices, err = unslashedAttestingIndices(state, atts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -311,25 +313,38 @@ func TestProcessFinalUpdates_CanProcess(t *testing.T) {
|
||||
s := buildState(params.BeaconConfig().SlotsPerHistoricalRoot-1, params.BeaconConfig().SlotsPerEpoch)
|
||||
ce := helpers.CurrentEpoch(s)
|
||||
ne := ce + 1
|
||||
s.SetEth1DataVotes([]*ethpb.Eth1Data{})
|
||||
if err := s.SetEth1DataVotes([]*ethpb.Eth1Data{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
balances := s.Balances()
|
||||
balances[0] = 29 * 1e9
|
||||
s.SetBalances(balances)
|
||||
balances[0] = 31.75 * 1e9
|
||||
balances[1] = 31.74 * 1e9
|
||||
if err := s.SetBalances(balances); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
slashings := s.Slashings()
|
||||
slashings[ce] = 0
|
||||
s.SetSlashings(slashings)
|
||||
if err := s.SetSlashings(slashings); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mixes := s.RandaoMixes()
|
||||
mixes[ce] = []byte{'A'}
|
||||
s.SetRandaoMixes(mixes)
|
||||
if err := s.SetRandaoMixes(mixes); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newS, err := ProcessFinalUpdates(s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Verify effective balance is correctly updated.
|
||||
if newS.Validators()[0].EffectiveBalance != 29*1e9 {
|
||||
if newS.Validators()[0].EffectiveBalance != params.BeaconConfig().MaxEffectiveBalance {
|
||||
t.Errorf("effective balance incorrectly updated, got %d", s.Validators()[0].EffectiveBalance)
|
||||
}
|
||||
if newS.Validators()[1].EffectiveBalance != 31*1e9 {
|
||||
t.Errorf("effective balance incorrectly updated, got %d", s.Validators()[1].EffectiveBalance)
|
||||
}
|
||||
|
||||
// Verify slashed balances correctly updated.
|
||||
if newS.Slashings()[ce] != newS.Slashings()[ne] {
|
||||
@@ -339,7 +354,7 @@ func TestProcessFinalUpdates_CanProcess(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify randao is correctly updated in the right position.
|
||||
if mix, _ := newS.RandaoMixAtIndex(ne); bytes.Equal(mix, params.BeaconConfig().ZeroHash[:]) {
|
||||
if mix, err := newS.RandaoMixAtIndex(ne); err != nil || bytes.Equal(mix, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Error("latest RANDAO still zero hashes")
|
||||
}
|
||||
|
||||
|
||||
@@ -74,13 +74,17 @@ func TestUpdateBalance(t *testing.T) {
|
||||
|
||||
func TestSameHead(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
beaconState.SetSlot(1)
|
||||
if err := beaconState.SetSlot(1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0}}}
|
||||
r := [32]byte{'A'}
|
||||
br := beaconState.BlockRoots()
|
||||
br[0] = r[:]
|
||||
beaconState.SetBlockRoots(br)
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att.Data.BeaconBlockRoot = r[:]
|
||||
same, err := precompute.SameHead(beaconState, &pb.PendingAttestation{Data: att.Data})
|
||||
if err != nil {
|
||||
@@ -102,13 +106,17 @@ func TestSameHead(t *testing.T) {
|
||||
|
||||
func TestSameTarget(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
beaconState.SetSlot(1)
|
||||
if err := beaconState.SetSlot(1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0}}}
|
||||
r := [32]byte{'A'}
|
||||
br := beaconState.BlockRoots()
|
||||
br[0] = r[:]
|
||||
beaconState.SetBlockRoots(br)
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att.Data.Target.Root = r[:]
|
||||
same, err := precompute.SameTarget(beaconState, &pb.PendingAttestation{Data: att.Data}, 0)
|
||||
if err != nil {
|
||||
@@ -130,13 +138,17 @@ func TestSameTarget(t *testing.T) {
|
||||
|
||||
func TestAttestedPrevEpoch(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch)
|
||||
if err := beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0}}}
|
||||
r := [32]byte{'A'}
|
||||
br := beaconState.BlockRoots()
|
||||
br[0] = r[:]
|
||||
beaconState.SetBlockRoots(br)
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att.Data.Target.Root = r[:]
|
||||
att.Data.BeaconBlockRoot = r[:]
|
||||
votedEpoch, votedTarget, votedHead, err := precompute.AttestedPrevEpoch(beaconState, &pb.PendingAttestation{Data: att.Data})
|
||||
@@ -156,14 +168,18 @@ func TestAttestedPrevEpoch(t *testing.T) {
|
||||
|
||||
func TestAttestedCurrentEpoch(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch + 1)
|
||||
if err := beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch + 1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 1}}}
|
||||
r := [32]byte{'A'}
|
||||
|
||||
br := beaconState.BlockRoots()
|
||||
br[params.BeaconConfig().SlotsPerEpoch] = r[:]
|
||||
beaconState.SetBlockRoots(br)
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att.Data.Target.Root = r[:]
|
||||
att.Data.BeaconBlockRoot = r[:]
|
||||
votedEpoch, votedTarget, err := precompute.AttestedCurrentEpoch(beaconState, &pb.PendingAttestation{Data: att.Data})
|
||||
@@ -184,7 +200,9 @@ func TestProcessAttestations(t *testing.T) {
|
||||
|
||||
validators := uint64(64)
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, validators)
|
||||
beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch)
|
||||
if err := beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bf := []byte{0xff}
|
||||
att1 := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
@@ -199,18 +217,26 @@ func TestProcessAttestations(t *testing.T) {
|
||||
br := beaconState.BlockRoots()
|
||||
newRt := [32]byte{'B'}
|
||||
br[0] = newRt[:]
|
||||
beaconState.SetBlockRoots(br)
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att2.Data.Target.Root = rt[:]
|
||||
att2.Data.BeaconBlockRoot = newRt[:]
|
||||
beaconState.SetPreviousEpochAttestations([]*pb.PendingAttestation{{Data: att1.Data, AggregationBits: bf}})
|
||||
beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{{Data: att2.Data, AggregationBits: bf}})
|
||||
err := beaconState.SetPreviousEpochAttestations([]*pb.PendingAttestation{{Data: att1.Data, AggregationBits: bf}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{{Data: att2.Data, AggregationBits: bf}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vp := make([]*precompute.Validator, validators)
|
||||
for i := 0; i < len(vp); i++ {
|
||||
vp[i] = &precompute.Validator{CurrentEpochEffectiveBalance: 100}
|
||||
}
|
||||
bp := &precompute.Balance{}
|
||||
vp, bp, err := precompute.ProcessAttestations(context.Background(), beaconState, vp, bp)
|
||||
vp, bp, err = precompute.ProcessAttestations(context.Background(), beaconState, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
// Package precompute provides gathering of nicely-structured
|
||||
// data important to feed into epoch processing, such as attesting
|
||||
// records and balances, for faster computation.
|
||||
package precompute
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -12,7 +16,7 @@ import (
|
||||
// New gets called at the beginning of process epoch cycle to return
|
||||
// pre computed instances of validators attesting records and total
|
||||
// balances attested in an epoch.
|
||||
func New(ctx context.Context, state *stateTrie.BeaconState) ([]*Validator, *Balance) {
|
||||
func New(ctx context.Context, state *stateTrie.BeaconState) ([]*Validator, *Balance, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "precomputeEpoch.New")
|
||||
defer span.End()
|
||||
vp := make([]*Validator, state.NumValidators())
|
||||
@@ -21,7 +25,7 @@ func New(ctx context.Context, state *stateTrie.BeaconState) ([]*Validator, *Bala
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
|
||||
state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
if err := state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
// Was validator withdrawable or slashed
|
||||
withdrawable := currentEpoch >= val.WithdrawableEpoch()
|
||||
p := &Validator{
|
||||
@@ -46,6 +50,8 @@ func New(ctx context.Context, state *stateTrie.BeaconState) ([]*Validator, *Bala
|
||||
|
||||
vp[idx] = p
|
||||
return nil
|
||||
})
|
||||
return vp, bp
|
||||
}); err != nil {
|
||||
return nil, nil, errors.Wrap(err, "failed to initialize precompute")
|
||||
}
|
||||
return vp, bp, nil
|
||||
}
|
||||
|
||||
@@ -31,7 +31,10 @@ func TestNew(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
v, b := precompute.New(context.Background(), s)
|
||||
v, b, err := precompute.New(context.Background(), s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(v[0], &precompute.Validator{IsSlashed: true, CurrentEpochEffectiveBalance: 100,
|
||||
InclusionDistance: e, InclusionSlot: e}) {
|
||||
t.Error("Incorrect validator 0 status")
|
||||
|
||||
@@ -83,7 +83,9 @@ func attestationDelta(state *stateTrie.BeaconState, bp *Balance, v *Validator) (
|
||||
|
||||
// Process source reward / penalty
|
||||
if v.IsPrevEpochAttester && !v.IsSlashed {
|
||||
r += br * bp.PrevEpochAttesters / bp.CurrentEpoch
|
||||
inc := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
rewardNumerator := br * bp.PrevEpochAttesters / inc
|
||||
r += rewardNumerator / (bp.CurrentEpoch / inc)
|
||||
proposerReward := br / params.BeaconConfig().ProposerRewardQuotient
|
||||
maxAtteserReward := br - proposerReward
|
||||
r += maxAtteserReward / v.InclusionDistance
|
||||
@@ -93,14 +95,18 @@ func attestationDelta(state *stateTrie.BeaconState, bp *Balance, v *Validator) (
|
||||
|
||||
// Process target reward / penalty
|
||||
if v.IsPrevEpochTargetAttester && !v.IsSlashed {
|
||||
r += br * bp.PrevEpochTargetAttesters / bp.CurrentEpoch
|
||||
inc := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
rewardNumerator := br * bp.PrevEpochAttesters / inc
|
||||
r += rewardNumerator / (bp.CurrentEpoch / inc)
|
||||
} else {
|
||||
p += br
|
||||
}
|
||||
|
||||
// Process head reward / penalty
|
||||
if v.IsPrevEpochHeadAttester && !v.IsSlashed {
|
||||
r += br * bp.PrevEpochHeadAttesters / bp.CurrentEpoch
|
||||
inc := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
rewardNumerator := br * bp.PrevEpochAttesters / inc
|
||||
r += rewardNumerator / (bp.CurrentEpoch / inc)
|
||||
} else {
|
||||
p += br
|
||||
}
|
||||
|
||||
@@ -35,7 +35,10 @@ func TestProcessRewardsAndPenaltiesPrecompute(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vp, bp := New(context.Background(), state)
|
||||
vp, bp, err := New(context.Background(), state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vp, bp, err = ProcessAttestations(context.Background(), state, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -88,7 +91,10 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vp, bp := New(context.Background(), state)
|
||||
vp, bp, err := New(context.Background(), state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vp, bp, err = ProcessAttestations(context.Background(), state, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -173,7 +179,10 @@ func TestAttestationDeltas_ZeroEpoch(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vp, bp := New(context.Background(), state)
|
||||
vp, bp, err := New(context.Background(), state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vp, bp, err = ProcessAttestations(context.Background(), state, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -28,8 +28,11 @@ func runJustificationAndFinalizationTests(t *testing.T, config string) {
|
||||
|
||||
func processJustificationAndFinalizationPrecomputeWrapper(t *testing.T, state *state.BeaconState) (*state.BeaconState, error) {
|
||||
ctx := context.Background()
|
||||
vp, bp := precompute.New(ctx, state)
|
||||
_, bp, err := precompute.ProcessAttestations(ctx, state, vp, bp)
|
||||
vp, bp, err := precompute.New(ctx, state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, bp, err = precompute.ProcessAttestations(ctx, state, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package spectest contains all conformity specification tests
|
||||
// for epoch processing according to the eth2 spec.
|
||||
package spectest
|
||||
|
||||
import (
|
||||
|
||||
@@ -37,8 +37,11 @@ func processSlashingsWrapper(t *testing.T, state *beaconstate.BeaconState) (*bea
|
||||
|
||||
func processSlashingsPrecomputeWrapper(t *testing.T, state *beaconstate.BeaconState) (*beaconstate.BeaconState, error) {
|
||||
ctx := context.Background()
|
||||
vp, bp := precompute.New(ctx, state)
|
||||
_, bp, err := precompute.ProcessAttestations(ctx, state, vp, bp)
|
||||
vp, bp, err := precompute.New(ctx, state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, bp, err = precompute.ProcessAttestations(ctx, state, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package block contains types for block-specific events fired
|
||||
// during the runtime of a beacon node.
|
||||
package block
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package feed defines event feed types for inter-service communication
|
||||
// during a beacon node's runtime.
|
||||
package feed
|
||||
|
||||
// How to add a new event to the feed:
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Package operation contains types for block operation-specific events fired
|
||||
// during the runtime of a beacon node such as attestations, voluntary
|
||||
// exits, and slashings.
|
||||
package operation
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Package state contains types for state operation-specific events fired
|
||||
// during the runtime of a beacon node such state initialization, state updates,
|
||||
// and chain start.
|
||||
package state
|
||||
|
||||
import "time"
|
||||
@@ -9,6 +12,8 @@ const (
|
||||
ChainStarted
|
||||
// Initialized is sent when the internal beacon node's state is ready to be accessed.
|
||||
Initialized
|
||||
// Synced is sent when the beacon node has completed syncing and is ready to participate in the network.
|
||||
Synced
|
||||
)
|
||||
|
||||
// BlockProcessedData is the data sent with BlockProcessed events.
|
||||
@@ -27,8 +32,16 @@ type ChainStartedData struct {
|
||||
StartTime time.Time
|
||||
}
|
||||
|
||||
// SyncedData is the data sent with Synced events.
|
||||
type SyncedData struct {
|
||||
// StartTime is the time at which the chain started.
|
||||
StartTime time.Time
|
||||
}
|
||||
|
||||
// InitializedData is the data sent with Initialized events.
|
||||
type InitializedData struct {
|
||||
// StartTime is the time at which the chain started.
|
||||
StartTime time.Time
|
||||
// GenesisValidatorsRoot represents ssz.HashTreeRoot(state.validators).
|
||||
GenesisValidatorsRoot []byte
|
||||
}
|
||||
|
||||
@@ -9,13 +9,18 @@ go_library(
|
||||
"randao.go",
|
||||
"rewards_penalties.go",
|
||||
"shuffle.go",
|
||||
"signing_root.go",
|
||||
"slot_epoch.go",
|
||||
"validators.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//endtoend/evaluators:__pkg__",
|
||||
"//shared/benchutil/benchmark_files:__subpackages__",
|
||||
"//shared/interop:__pkg__",
|
||||
"//shared/keystore:__pkg__",
|
||||
"//shared/p2putils:__pkg__",
|
||||
"//shared/testutil:__pkg__",
|
||||
"//slasher:__subpackages__",
|
||||
"//tools:__subpackages__",
|
||||
@@ -48,6 +53,7 @@ go_test(
|
||||
"randao_test.go",
|
||||
"rewards_penalties_test.go",
|
||||
"shuffle_test.go",
|
||||
"signing_root_test.go",
|
||||
"slot_epoch_test.go",
|
||||
"validators_test.go",
|
||||
],
|
||||
@@ -59,11 +65,11 @@ go_test(
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_google_gofuzz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
@@ -124,15 +123,15 @@ func AggregateAttestation(a1 *ethpb.Attestation, a2 *ethpb.Attestation) (*ethpb.
|
||||
// domain = get_domain(state, DOMAIN_BEACON_ATTESTER, compute_epoch_at_slot(slot))
|
||||
// return bls_sign(privkey, hash_tree_root(slot), domain)
|
||||
func SlotSignature(state *stateTrie.BeaconState, slot uint64, privKey *bls.SecretKey) (*bls.Signature, error) {
|
||||
d, err := Domain(state.Fork(), CurrentEpoch(state), params.BeaconConfig().DomainBeaconAttester)
|
||||
d, err := Domain(state.Fork(), CurrentEpoch(state), params.BeaconConfig().DomainBeaconAttester, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := ssz.HashTreeRoot(slot)
|
||||
s, err := ComputeSigningRoot(slot, d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return privKey.Sign(s[:], d), nil
|
||||
return privKey.Sign(s[:]), nil
|
||||
}
|
||||
|
||||
// IsAggregator returns true if the signature is from the input validator. The committee
|
||||
|
||||
@@ -202,7 +202,7 @@ func TestAggregateAttestations(t *testing.T) {
|
||||
atts := make([]*ethpb.Attestation, len(bl))
|
||||
for i, b := range bl {
|
||||
sk := bls.RandKey()
|
||||
sig := sk.Sign([]byte("dummy_test_data"), 0 /*domain*/)
|
||||
sig := sk.Sign([]byte("dummy_test_data"))
|
||||
atts[i] = ðpb.Attestation{
|
||||
AggregationBits: b,
|
||||
Data: nil,
|
||||
@@ -240,7 +240,7 @@ func TestAggregateAttestations(t *testing.T) {
|
||||
func TestSlotSignature_Verify(t *testing.T) {
|
||||
priv := bls.RandKey()
|
||||
pub := priv.PublicKey()
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Fork: &pb.Fork{
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
@@ -248,6 +248,9 @@ func TestSlotSignature_Verify(t *testing.T) {
|
||||
},
|
||||
Slot: 100,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
slot := uint64(101)
|
||||
|
||||
sig, err := helpers.SlotSignature(state, slot, priv)
|
||||
@@ -255,12 +258,15 @@ func TestSlotSignature_Verify(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
domain, err := helpers.Domain(state.Fork(), helpers.CurrentEpoch(state), params.BeaconConfig().DomainBeaconAttester)
|
||||
domain, err := helpers.Domain(state.Fork(), helpers.CurrentEpoch(state), params.BeaconConfig().DomainBeaconAttester, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
msg, _ := ssz.HashTreeRoot(slot)
|
||||
if !sig.Verify(msg[:], pub, domain) {
|
||||
msg, err := helpers.ComputeSigningRoot(slot, domain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !sig.Verify(msg[:], pub) {
|
||||
t.Error("Could not verify slot signature")
|
||||
}
|
||||
}
|
||||
@@ -272,7 +278,7 @@ func TestIsAggregator_True(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig := privKeys[0].Sign([]byte{}, 0)
|
||||
sig := privKeys[0].Sign([]byte{'A'})
|
||||
agg, err := helpers.IsAggregator(uint64(len(committee)), sig.Marshal())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -291,7 +297,7 @@ func TestIsAggregator_False(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig := privKeys[0].Sign([]byte{}, 0)
|
||||
sig := privKeys[0].Sign([]byte{'A'})
|
||||
agg, err := helpers.IsAggregator(uint64(len(committee)), sig.Marshal())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -304,11 +310,11 @@ func TestIsAggregator_False(t *testing.T) {
|
||||
func TestAggregateSignature_True(t *testing.T) {
|
||||
pubkeys := make([]*bls.PublicKey, 0, 100)
|
||||
atts := make([]*ethpb.Attestation, 0, 100)
|
||||
msg := []byte("hello")
|
||||
msg := bytesutil.ToBytes32([]byte("hello"))
|
||||
for i := 0; i < 100; i++ {
|
||||
priv := bls.RandKey()
|
||||
pub := priv.PublicKey()
|
||||
sig := priv.Sign(msg[:], 0)
|
||||
sig := priv.Sign(msg[:])
|
||||
pubkeys = append(pubkeys, pub)
|
||||
att := ðpb.Attestation{Signature: sig.Marshal()}
|
||||
atts = append(atts, att)
|
||||
@@ -317,7 +323,7 @@ func TestAggregateSignature_True(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !aggSig.VerifyAggregateCommon(pubkeys, bytesutil.ToBytes32(msg), 0) {
|
||||
if !aggSig.FastAggregateVerify(pubkeys, msg) {
|
||||
t.Error("Signature did not verify")
|
||||
}
|
||||
}
|
||||
@@ -329,7 +335,7 @@ func TestAggregateSignature_False(t *testing.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
priv := bls.RandKey()
|
||||
pub := priv.PublicKey()
|
||||
sig := priv.Sign(msg[:], 0)
|
||||
sig := priv.Sign(msg[:])
|
||||
pubkeys = append(pubkeys, pub)
|
||||
att := ðpb.Attestation{Signature: sig.Marshal()}
|
||||
atts = append(atts, att)
|
||||
@@ -338,7 +344,7 @@ func TestAggregateSignature_False(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if aggSig.VerifyAggregateCommon(pubkeys, bytesutil.ToBytes32(msg), 0) {
|
||||
if aggSig.FastAggregateVerify(pubkeys, bytesutil.ToBytes32(msg)) {
|
||||
t.Error("Signature not suppose to verify")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,10 @@ func TestBlockRootAtSlot_CorrectBlockRoot(t *testing.T) {
|
||||
for i, tt := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
s.Slot = tt.stateSlot
|
||||
state, _ := beaconstate.InitializeFromProto(s)
|
||||
state, err := beaconstate.InitializeFromProto(s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantedSlot := tt.slot
|
||||
result, err := helpers.BlockRootAtSlot(state, wantedSlot)
|
||||
if err != nil {
|
||||
@@ -111,8 +114,11 @@ func TestBlockRootAtSlot_OutOfBounds(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state.Slot = tt.stateSlot
|
||||
s, _ := beaconstate.InitializeFromProto(state)
|
||||
_, err := helpers.BlockRootAtSlot(s, tt.slot)
|
||||
s, err := beaconstate.InitializeFromProto(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = helpers.BlockRootAtSlot(s, tt.slot)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error %s, got nil", tt.expectedErr)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Package helpers contains helper functions outlined in ETH2.0 spec beacon chain spec
|
||||
// Package helpers contains helper functions outlined in the eth2 beacon chain spec, such as
|
||||
// computing committees, randao, rewards/penalties, and more.
|
||||
package helpers
|
||||
|
||||
import (
|
||||
@@ -181,7 +182,10 @@ type CommitteeAssignmentContainer struct {
|
||||
// 2. Compute all committees.
|
||||
// 3. Determine the attesting slot for each committee.
|
||||
// 4. Construct a map of validator indices pointing to the respective committees.
|
||||
func CommitteeAssignments(state *stateTrie.BeaconState, epoch uint64) (map[uint64]*CommitteeAssignmentContainer, map[uint64]uint64, error) {
|
||||
func CommitteeAssignments(
|
||||
state *stateTrie.BeaconState,
|
||||
epoch uint64,
|
||||
) (map[uint64]*CommitteeAssignmentContainer, map[uint64][]uint64, error) {
|
||||
nextEpoch := NextEpoch(state)
|
||||
if epoch > nextEpoch {
|
||||
return nil, nil, fmt.Errorf(
|
||||
@@ -191,9 +195,11 @@ func CommitteeAssignments(state *stateTrie.BeaconState, epoch uint64) (map[uint6
|
||||
)
|
||||
}
|
||||
|
||||
// Track which slot has which proposer.
|
||||
// We determine the slots in which proposers are supposed to act.
|
||||
// Some validators may need to propose multiple times per epoch, so
|
||||
// we use a map of proposer idx -> []slot to keep track of this possibility.
|
||||
startSlot := StartSlot(epoch)
|
||||
proposerIndexToSlot := make(map[uint64]uint64)
|
||||
proposerIndexToSlots := make(map[uint64][]uint64)
|
||||
for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ {
|
||||
if err := state.SetSlot(slot); err != nil {
|
||||
return nil, nil, err
|
||||
@@ -202,7 +208,7 @@ func CommitteeAssignments(state *stateTrie.BeaconState, epoch uint64) (map[uint6
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "could not check proposer at slot %d", state.Slot())
|
||||
}
|
||||
proposerIndexToSlot[i] = slot
|
||||
proposerIndexToSlots[i] = append(proposerIndexToSlots[i], slot)
|
||||
}
|
||||
|
||||
activeValidatorIndices, err := ActiveValidatorIndices(state, epoch)
|
||||
@@ -235,85 +241,7 @@ func CommitteeAssignments(state *stateTrie.BeaconState, epoch uint64) (map[uint6
|
||||
}
|
||||
}
|
||||
|
||||
return validatorIndexToCommittee, proposerIndexToSlot, nil
|
||||
}
|
||||
|
||||
// CommitteeAssignment is used to query committee assignment from
|
||||
// current and previous epoch.
|
||||
//
|
||||
// Deprecated: Consider using CommitteeAssignments, especially when computing more than one
|
||||
// validator assignment as this method is O(n^2) in computational complexity. This method exists to
|
||||
// ensure spec definition conformance and otherwise should probably not be used.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_committee_assignment(state: BeaconState,
|
||||
// epoch: Epoch,
|
||||
// validator_index: ValidatorIndex
|
||||
// ) -> Optional[Tuple[Sequence[ValidatorIndex], CommitteeIndex, Slot]]:
|
||||
// """
|
||||
// Return the committee assignment in the ``epoch`` for ``validator_index``.
|
||||
// ``assignment`` returned is a tuple of the following form:
|
||||
// * ``assignment[0]`` is the list of validators in the committee
|
||||
// * ``assignment[1]`` is the index to which the committee is assigned
|
||||
// * ``assignment[2]`` is the slot at which the committee is assigned
|
||||
// Return None if no assignment.
|
||||
// """
|
||||
// next_epoch = get_current_epoch(state) + 1
|
||||
// assert epoch <= next_epoch
|
||||
//
|
||||
// start_slot = compute_start_slot_at_epoch(epoch)
|
||||
// for slot in range(start_slot, start_slot + SLOTS_PER_EPOCH):
|
||||
// for index in range(get_committee_count_at_slot(state, Slot(slot))):
|
||||
// committee = get_beacon_committee(state, Slot(slot), CommitteeIndex(index))
|
||||
// if validator_index in committee:
|
||||
// return committee, CommitteeIndex(index), Slot(slot)
|
||||
// return None
|
||||
func CommitteeAssignment(
|
||||
state *stateTrie.BeaconState,
|
||||
epoch uint64,
|
||||
validatorIndex uint64,
|
||||
) ([]uint64, uint64, uint64, uint64, error) {
|
||||
nextEpoch := NextEpoch(state)
|
||||
if epoch > nextEpoch {
|
||||
return nil, 0, 0, 0, fmt.Errorf(
|
||||
"epoch %d can't be greater than next epoch %d",
|
||||
epoch, nextEpoch)
|
||||
}
|
||||
|
||||
// Track which slot has which proposer.
|
||||
startSlot := StartSlot(epoch)
|
||||
proposerIndexToSlot := make(map[uint64]uint64)
|
||||
for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ {
|
||||
if err := state.SetSlot(slot); err != nil {
|
||||
return nil, 0, 0, 0, err
|
||||
}
|
||||
i, err := BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
return nil, 0, 0, 0, errors.Wrapf(err, "could not check proposer at slot %d", state.Slot())
|
||||
}
|
||||
proposerIndexToSlot[i] = slot
|
||||
}
|
||||
|
||||
activeValidatorIndices, err := ActiveValidatorIndices(state, epoch)
|
||||
if err != nil {
|
||||
return nil, 0, 0, 0, err
|
||||
}
|
||||
for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ {
|
||||
countAtSlot := SlotCommitteeCount(uint64(len(activeValidatorIndices)))
|
||||
for i := uint64(0); i < countAtSlot; i++ {
|
||||
committee, err := BeaconCommitteeFromState(state, slot, i)
|
||||
if err != nil {
|
||||
return nil, 0, 0, 0, errors.Wrapf(err, "could not get crosslink committee at slot %d", slot)
|
||||
}
|
||||
for _, v := range committee {
|
||||
if validatorIndex == v {
|
||||
proposerSlot, _ := proposerIndexToSlot[v]
|
||||
return committee, i, slot, proposerSlot, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return []uint64{}, 0, 0, 0, fmt.Errorf("validator with index %d not found in assignments", validatorIndex)
|
||||
return validatorIndexToCommittee, proposerIndexToSlots, nil
|
||||
}
|
||||
|
||||
// VerifyBitfieldLength verifies that a bitfield length matches the given committee size.
|
||||
@@ -354,12 +282,14 @@ func ShuffledIndices(state *stateTrie.BeaconState, epoch uint64) ([]uint64, erro
|
||||
}
|
||||
|
||||
indices := make([]uint64, 0, state.NumValidators())
|
||||
state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
if err := state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
if IsActiveValidatorUsingTrie(val, epoch) {
|
||||
indices = append(indices, uint64(idx))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return UnshuffleList(indices, seed)
|
||||
}
|
||||
@@ -407,7 +337,6 @@ func UpdateCommitteeCache(state *stateTrie.BeaconState, epoch uint64) error {
|
||||
|
||||
// UpdateProposerIndicesInCache updates proposer indices entry of the committee cache.
|
||||
func UpdateProposerIndicesInCache(state *stateTrie.BeaconState, epoch uint64) error {
|
||||
|
||||
indices, err := ActiveValidatorIndices(state, epoch)
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -444,11 +373,10 @@ func precomputeProposerIndices(state *stateTrie.BeaconState, activeIndices []uin
|
||||
return nil, errors.Wrap(err, "could not generate seed")
|
||||
}
|
||||
slot := StartSlot(e)
|
||||
vals := state.Validators()
|
||||
for i := uint64(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {
|
||||
seedWithSlot := append(seed[:], bytesutil.Bytes8(slot+i)...)
|
||||
seedWithSlotHash := hashFunc(seedWithSlot)
|
||||
index, err := ComputeProposerIndex(vals, activeIndices, seedWithSlotHash)
|
||||
index, err := ComputeProposerIndex(state, activeIndices, seedWithSlotHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -13,7 +12,6 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||||
@@ -96,11 +94,14 @@ func TestAttestationParticipants_NoCommitteeCache(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
attestationData := ðpb.AttestationData{}
|
||||
|
||||
@@ -157,10 +158,13 @@ func TestAttestationParticipants_EmptyBitfield(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
attestationData := ðpb.AttestationData{Target: ðpb.Checkpoint{}}
|
||||
|
||||
committee, err := BeaconCommitteeFromState(state, attestationData.Slot, attestationData.CommitteeIndex)
|
||||
@@ -168,10 +172,6 @@ func TestAttestationParticipants_EmptyBitfield(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
indices := attestationutil.AttestingIndices(bitfield.NewBitlist(128), committee)
|
||||
if err != nil {
|
||||
t.Fatalf("attesting indices failed: %v", err)
|
||||
}
|
||||
|
||||
if len(indices) != 0 {
|
||||
t.Errorf("Attesting indices are non-zero despite an empty bitfield being provided; Size %d", len(indices))
|
||||
}
|
||||
@@ -191,148 +191,6 @@ func TestVerifyBitfieldLength_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitteeAssignment_CanRetrieve(t *testing.T) {
|
||||
ClearCache()
|
||||
// Initialize test with 128 validators, each slot and each index gets 2 validators.
|
||||
validators := make([]*ethpb.Validator, 2*params.BeaconConfig().SlotsPerEpoch)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
index uint64
|
||||
slot uint64
|
||||
committee []uint64
|
||||
committeeIndex uint64
|
||||
isProposer bool
|
||||
proposerSlot uint64
|
||||
}{
|
||||
{
|
||||
index: 0,
|
||||
slot: 78,
|
||||
committee: []uint64{0, 38},
|
||||
committeeIndex: 0,
|
||||
isProposer: false,
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
slot: 71,
|
||||
committee: []uint64{1, 4},
|
||||
committeeIndex: 0,
|
||||
isProposer: true,
|
||||
proposerSlot: 79,
|
||||
},
|
||||
{
|
||||
index: 11,
|
||||
slot: 90,
|
||||
committee: []uint64{31, 11},
|
||||
committeeIndex: 0,
|
||||
isProposer: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
committee, committeeIndex, slot, proposerSlot, err := CommitteeAssignment(state, tt.slot/params.BeaconConfig().SlotsPerEpoch, tt.index)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to execute NextEpochCommitteeAssignment: %v", err)
|
||||
}
|
||||
if committeeIndex != tt.committeeIndex {
|
||||
t.Errorf("wanted committeeIndex %d, got committeeIndex %d for validator index %d",
|
||||
tt.committeeIndex, committeeIndex, tt.index)
|
||||
}
|
||||
if slot != tt.slot {
|
||||
t.Errorf("wanted slot %d, got slot %d for validator index %d",
|
||||
tt.slot, slot, tt.index)
|
||||
}
|
||||
if proposerSlot != tt.proposerSlot {
|
||||
t.Errorf("wanted proposer slot %d, got proposer slot %d for validator index %d",
|
||||
tt.proposerSlot, proposerSlot, tt.index)
|
||||
}
|
||||
if !reflect.DeepEqual(committee, tt.committee) {
|
||||
t.Errorf("wanted committee %v, got committee %v for validator index %d",
|
||||
tt.committee, committee, tt.index)
|
||||
}
|
||||
if proposerSlot != tt.proposerSlot {
|
||||
t.Errorf("wanted proposer slot slot %d, got slot %d for validator index %d",
|
||||
tt.slot, slot, tt.index)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitteeAssignment_CantFindValidator(t *testing.T) {
|
||||
ClearCache()
|
||||
validators := make([]*ethpb.Validator, 1)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
|
||||
index := uint64(10000)
|
||||
_, _, _, _, err := CommitteeAssignment(state, 1, index)
|
||||
if err != nil && !strings.Contains(err.Error(), "not found in assignments") {
|
||||
t.Errorf("Wanted 'not found in assignments', received %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test helpers.CommitteeAssignments against the results of helpers.CommitteeAssignment by validator
|
||||
// index. Warning: this test is a bit slow!
|
||||
func TestCommitteeAssignments_AgreesWithSpecDefinitionMethod(t *testing.T) {
|
||||
ClearCache()
|
||||
// Initialize test with 256 validators, each slot and each index gets 4 validators.
|
||||
validators := make([]*ethpb.Validator, 4*params.BeaconConfig().SlotsPerEpoch)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
// Test for 2 epochs.
|
||||
for epoch := uint64(0); epoch < 2; epoch++ {
|
||||
state, _ := beaconstate.InitializeFromProto(state.CloneInnerState())
|
||||
assignments, proposers, err := CommitteeAssignments(state, epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := uint64(0); int(i) < len(validators); i++ {
|
||||
committee, committeeIndex, slot, proposerSlot, err := CommitteeAssignment(state, epoch, i)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(committee, assignments[i].Committee) {
|
||||
t.Errorf("Computed different committees for validator %d", i)
|
||||
}
|
||||
if committeeIndex != assignments[i].CommitteeIndex {
|
||||
t.Errorf("Computed different committee index for validator %d", i)
|
||||
}
|
||||
if slot != assignments[i].AttesterSlot {
|
||||
t.Errorf("Computed different attesting slot for validator %d", i)
|
||||
}
|
||||
if proposerSlot != proposers[i] {
|
||||
t.Errorf("Computed different proposing slot for validator %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitteeAssignments_CanRetrieve(t *testing.T) {
|
||||
// Initialize test with 256 validators, each slot and each index gets 4 validators.
|
||||
validators := make([]*ethpb.Validator, 4*params.BeaconConfig().SlotsPerEpoch)
|
||||
@@ -348,11 +206,14 @@ func TestCommitteeAssignments_CanRetrieve(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 2 * params.BeaconConfig().SlotsPerEpoch, // epoch 2
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
index uint64
|
||||
@@ -395,7 +256,7 @@ func TestCommitteeAssignments_CanRetrieve(t *testing.T) {
|
||||
for i, tt := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
ClearCache()
|
||||
validatorIndexToCommittee, proposerIndexToSlot, err := CommitteeAssignments(state, SlotToEpoch(tt.slot))
|
||||
validatorIndexToCommittee, proposerIndexToSlots, err := CommitteeAssignments(state, SlotToEpoch(tt.slot))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to determine CommitteeAssignments: %v", err)
|
||||
}
|
||||
@@ -408,9 +269,9 @@ func TestCommitteeAssignments_CanRetrieve(t *testing.T) {
|
||||
t.Errorf("wanted slot %d, got slot %d for validator index %d",
|
||||
tt.slot, cac.AttesterSlot, tt.index)
|
||||
}
|
||||
if proposerIndexToSlot[tt.index] != tt.proposerSlot {
|
||||
if len(proposerIndexToSlots[tt.index]) > 0 && proposerIndexToSlots[tt.index][0] != tt.proposerSlot {
|
||||
t.Errorf("wanted proposer slot %d, got proposer slot %d for validator index %d",
|
||||
tt.proposerSlot, proposerIndexToSlot[tt.index], tt.index)
|
||||
tt.proposerSlot, proposerIndexToSlots[tt.index][0], tt.index)
|
||||
}
|
||||
if !reflect.DeepEqual(cac.Committee, tt.committee) {
|
||||
t.Errorf("wanted committee %v, got committee %v for validator index %d",
|
||||
@@ -429,10 +290,13 @@ func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: activeRoots,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
attestation *ethpb.Attestation
|
||||
@@ -506,7 +370,9 @@ func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
|
||||
|
||||
for i, tt := range tests {
|
||||
ClearCache()
|
||||
state.SetSlot(tt.stateSlot)
|
||||
if err := state.SetSlot(tt.stateSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := VerifyAttestationBitfieldLengths(state, tt.attestation)
|
||||
if tt.verificationFailure {
|
||||
if err == nil {
|
||||
@@ -567,10 +433,6 @@ func TestShuffledIndices_ShuffleRightLength(t *testing.T) {
|
||||
|
||||
func TestUpdateCommitteeCache_CanUpdate(t *testing.T) {
|
||||
ClearCache()
|
||||
c := featureconfig.Get()
|
||||
featureconfig.Init(c)
|
||||
defer featureconfig.Init(nil)
|
||||
|
||||
validatorCount := int(params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
validators := make([]*ethpb.Validator, validatorCount)
|
||||
indices := make([]uint64, validatorCount)
|
||||
@@ -655,10 +517,13 @@ func BenchmarkComputeCommittee3000000_WithPreCache(b *testing.B) {
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
epoch := CurrentEpoch(state)
|
||||
indices, err := ActiveValidatorIndices(state, epoch)
|
||||
@@ -692,10 +557,13 @@ func BenchmarkComputeCommittee128000_WithOutPreCache(b *testing.B) {
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
epoch := CurrentEpoch(state)
|
||||
indices, err := ActiveValidatorIndices(state, epoch)
|
||||
@@ -730,10 +598,13 @@ func BenchmarkComputeCommittee1000000_WithOutCache(b *testing.B) {
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
epoch := CurrentEpoch(state)
|
||||
indices, err := ActiveValidatorIndices(state, epoch)
|
||||
@@ -768,10 +639,13 @@ func BenchmarkComputeCommittee4000000_WithOutCache(b *testing.B) {
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
epoch := CurrentEpoch(state)
|
||||
indices, err := ActiveValidatorIndices(state, epoch)
|
||||
@@ -800,10 +674,6 @@ func BenchmarkComputeCommittee4000000_WithOutCache(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestBeaconCommitteeFromState_UpdateCacheForPreviousEpoch(t *testing.T) {
|
||||
c := featureconfig.Get()
|
||||
featureconfig.Init(c)
|
||||
defer featureconfig.Init(nil)
|
||||
|
||||
committeeSize := uint64(16)
|
||||
validators := make([]*ethpb.Validator, committeeSize*params.BeaconConfig().SlotsPerEpoch)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
@@ -812,11 +682,14 @@ func TestBeaconCommitteeFromState_UpdateCacheForPreviousEpoch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := BeaconCommitteeFromState(state, 1 /* previous epoch */, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -844,10 +717,13 @@ func TestPrecomputeProposerIndices_Ok(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
indices, err := ActiveValidatorIndices(state, 0)
|
||||
if err != nil {
|
||||
@@ -867,7 +743,7 @@ func TestPrecomputeProposerIndices_Ok(t *testing.T) {
|
||||
for i := uint64(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {
|
||||
seedWithSlot := append(seed[:], bytesutil.Bytes8(i)...)
|
||||
seedWithSlotHash := hashutil.Hash(seedWithSlot)
|
||||
index, err := ComputeProposerIndex(state.Validators(), indices, seedWithSlotHash)
|
||||
index, err := ComputeProposerIndex(state, indices, seedWithSlotHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,10 @@ func TestRandaoMix_OK(t *testing.T) {
|
||||
binary.LittleEndian.PutUint64(intInBytes, uint64(i))
|
||||
randaoMixes[i] = intInBytes
|
||||
}
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{RandaoMixes: randaoMixes})
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{RandaoMixes: randaoMixes})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tests := []struct {
|
||||
epoch uint64
|
||||
randaoMix []byte
|
||||
@@ -37,7 +40,9 @@ func TestRandaoMix_OK(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
state.SetSlot((test.epoch + 1) * params.BeaconConfig().SlotsPerEpoch)
|
||||
if err := state.SetSlot((test.epoch + 1) * params.BeaconConfig().SlotsPerEpoch); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mix, err := RandaoMix(state, test.epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -56,7 +61,10 @@ func TestRandaoMix_CopyOK(t *testing.T) {
|
||||
binary.LittleEndian.PutUint64(intInBytes, uint64(i))
|
||||
randaoMixes[i] = intInBytes
|
||||
}
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{RandaoMixes: randaoMixes})
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{RandaoMixes: randaoMixes})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tests := []struct {
|
||||
epoch uint64
|
||||
randaoMix []byte
|
||||
@@ -75,7 +83,9 @@ func TestRandaoMix_CopyOK(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
state.SetSlot((test.epoch + 1) * params.BeaconConfig().SlotsPerEpoch)
|
||||
if err := state.SetSlot((test.epoch + 1) * params.BeaconConfig().SlotsPerEpoch); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mix, err := RandaoMix(state, test.epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -101,9 +111,13 @@ func TestGenerateSeed_OK(t *testing.T) {
|
||||
randaoMixes[i] = intInBytes
|
||||
}
|
||||
slot := 10 * params.BeaconConfig().MinSeedLookahead * params.BeaconConfig().SlotsPerEpoch
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
RandaoMixes: randaoMixes,
|
||||
Slot: slot})
|
||||
Slot: slot,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got, err := Seed(state, 10, params.BeaconConfig().DomainBeaconAttester)
|
||||
if err != nil {
|
||||
|
||||
@@ -2,6 +2,7 @@ package helpers
|
||||
|
||||
import (
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// TotalBalance returns the total amount at stake in Gwei
|
||||
@@ -10,9 +11,10 @@ import (
|
||||
// Spec pseudocode definition:
|
||||
// def get_total_balance(state: BeaconState, indices: Set[ValidatorIndex]) -> Gwei:
|
||||
// """
|
||||
// Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.)
|
||||
// Return the combined effective balance of the ``indices``.
|
||||
// ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
|
||||
// """
|
||||
// return Gwei(max(1, sum([state.validators[index].effective_balance for index in indices])))
|
||||
// return Gwei(max(EFFECTIVE_BALANCE_INCREMENT, sum([state.validators[index].effective_balance for index in indices])))
|
||||
func TotalBalance(state *stateTrie.BeaconState, indices []uint64) uint64 {
|
||||
total := uint64(0)
|
||||
|
||||
@@ -24,9 +26,9 @@ func TotalBalance(state *stateTrie.BeaconState, indices []uint64) uint64 {
|
||||
total += val.EffectiveBalance()
|
||||
}
|
||||
|
||||
// Return 1 Gwei minimum to avoid divisions by zero
|
||||
// Return EFFECTIVE_BALANCE_INCREMENT to avoid divisions by zero.
|
||||
if total == 0 {
|
||||
return 1
|
||||
return params.BeaconConfig().EffectiveBalanceIncrement
|
||||
}
|
||||
|
||||
return total
|
||||
@@ -43,12 +45,14 @@ func TotalBalance(state *stateTrie.BeaconState, indices []uint64) uint64 {
|
||||
// return get_total_balance(state, set(get_active_validator_indices(state, get_current_epoch(state))))
|
||||
func TotalActiveBalance(state *stateTrie.BeaconState) (uint64, error) {
|
||||
total := uint64(0)
|
||||
state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
if err := state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
if IsActiveValidatorUsingTrie(val, SlotToEpoch(state.Slot())) {
|
||||
total += val.EffectiveBalance()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,13 @@ import (
|
||||
)
|
||||
|
||||
func TestTotalBalance_OK(t *testing.T) {
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{Validators: []*ethpb.Validator{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{Validators: []*ethpb.Validator{
|
||||
{EffectiveBalance: 27 * 1e9}, {EffectiveBalance: 28 * 1e9},
|
||||
{EffectiveBalance: 32 * 1e9}, {EffectiveBalance: 40 * 1e9},
|
||||
}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
balance := TotalBalance(state, []uint64{0, 1, 2, 3})
|
||||
wanted := state.Validators()[0].EffectiveBalance + state.Validators()[1].EffectiveBalance +
|
||||
@@ -24,11 +27,14 @@ func TestTotalBalance_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalBalance_ReturnsOne(t *testing.T) {
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{Validators: []*ethpb.Validator{}})
|
||||
func TestTotalBalance_ReturnsEffectiveBalanceIncrement(t *testing.T) {
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{Validators: []*ethpb.Validator{}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
balance := TotalBalance(state, []uint64{})
|
||||
wanted := uint64(1)
|
||||
wanted := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
|
||||
if balance != wanted {
|
||||
t.Errorf("Incorrect TotalBalance. Wanted: %d, got: %d", wanted, balance)
|
||||
@@ -36,7 +42,7 @@ func TestTotalBalance_ReturnsOne(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTotalActiveBalance_OK(t *testing.T) {
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{Validators: []*ethpb.Validator{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{Validators: []*ethpb.Validator{
|
||||
{
|
||||
EffectiveBalance: 32 * 1e9,
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
@@ -54,6 +60,9 @@ func TestTotalActiveBalance_OK(t *testing.T) {
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
},
|
||||
}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
balance, err := TotalActiveBalance(state)
|
||||
if err != nil {
|
||||
@@ -79,7 +88,10 @@ func TestGetBalance_OK(t *testing.T) {
|
||||
{i: 2, b: []uint64{0, 0, 0}},
|
||||
}
|
||||
for _, test := range tests {
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{Balances: test.b})
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{Balances: test.b})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if state.Balances()[test.i] != test.b[test.i] {
|
||||
t.Errorf("Incorrect Validator balance. Wanted: %d, got: %d", test.b[test.i], state.Balances()[test.i])
|
||||
}
|
||||
@@ -98,11 +110,14 @@ func TestIncreaseBalance_OK(t *testing.T) {
|
||||
{i: 2, b: []uint64{27 * 1e9, 28 * 1e9, 32 * 1e9}, nb: 33 * 1e9, eb: 65 * 1e9},
|
||||
}
|
||||
for _, test := range tests {
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: []*ethpb.Validator{
|
||||
{EffectiveBalance: 4}, {EffectiveBalance: 4}, {EffectiveBalance: 4}},
|
||||
Balances: test.b,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := IncreaseBalance(state, test.i, test.nb); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -125,11 +140,14 @@ func TestDecreaseBalance_OK(t *testing.T) {
|
||||
{i: 3, b: []uint64{27 * 1e9, 28 * 1e9, 1, 28 * 1e9}, nb: 28 * 1e9, eb: 0},
|
||||
}
|
||||
for _, test := range tests {
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: []*ethpb.Validator{
|
||||
{EffectiveBalance: 4}, {EffectiveBalance: 4}, {EffectiveBalance: 4}, {EffectiveBalance: 3}},
|
||||
Balances: test.b,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := DecreaseBalance(state, test.i, test.nb); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -101,7 +101,9 @@ func BenchmarkShuffledIndex(b *testing.B) {
|
||||
for _, listSize := range listSizes {
|
||||
b.Run(fmt.Sprintf("ShuffledIndex_%d", listSize), func(ib *testing.B) {
|
||||
for i := uint64(0); i < uint64(ib.N); i++ {
|
||||
ShuffledIndex(i%listSize, listSize, seed)
|
||||
if _, err := ShuffledIndex(i%listSize, listSize, seed); err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -115,7 +117,9 @@ func BenchmarkIndexComparison(b *testing.B) {
|
||||
for i := 0; i < ib.N; i++ {
|
||||
// Simulate a list-shuffle by running shuffle-index listSize times.
|
||||
for j := uint64(0); j < listSize; j++ {
|
||||
ShuffledIndex(j, listSize, seed)
|
||||
if _, err := ShuffledIndex(j, listSize, seed); err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -132,7 +136,9 @@ func BenchmarkShuffleList(b *testing.B) {
|
||||
}
|
||||
b.Run(fmt.Sprintf("ShuffleList_%d", listSize), func(ib *testing.B) {
|
||||
for i := 0; i < ib.N; i++ {
|
||||
ShuffleList(testIndices, seed)
|
||||
if _, err := ShuffleList(testIndices, seed); err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
146
beacon-chain/core/helpers/signing_root.go
Normal file
146
beacon-chain/core/helpers/signing_root.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
p2ppb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// ForkVersionByteLength length of fork version byte array.
|
||||
const ForkVersionByteLength = 4
|
||||
|
||||
// DomainByteLength length of domain byte array.
|
||||
const DomainByteLength = 4
|
||||
|
||||
// ErrSigFailedToVerify returns when a signature of a block object(ie attestation, slashing, exit... etc)
|
||||
// failed to verify.
|
||||
var ErrSigFailedToVerify = errors.New("signature did not verify")
|
||||
|
||||
// ComputeSigningRoot computes the root of the object by calculating the root of the object domain tree.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root:
|
||||
// """
|
||||
// Return the signing root of an object by calculating the root of the object-domain tree.
|
||||
// """
|
||||
// domain_wrapped_object = SigningRoot(
|
||||
// object_root=hash_tree_root(ssz_object),
|
||||
// domain=domain,
|
||||
// )
|
||||
// return hash_tree_root(domain_wrapped_object)
|
||||
func ComputeSigningRoot(object interface{}, domain []byte) ([32]byte, error) {
|
||||
objRoot, err := ssz.HashTreeRoot(object)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
container := &p2ppb.SigningRoot{
|
||||
ObjectRoot: objRoot[:],
|
||||
Domain: domain,
|
||||
}
|
||||
return ssz.HashTreeRoot(container)
|
||||
}
|
||||
|
||||
// VerifySigningRoot verifies the signing root of an object given it's public key, signature and domain.
|
||||
func VerifySigningRoot(obj interface{}, pub []byte, signature []byte, domain []byte) error {
|
||||
publicKey, err := bls.PublicKeyFromBytes(pub)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to public key")
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(signature)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
root, err := ComputeSigningRoot(obj, domain)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not compute signing root")
|
||||
}
|
||||
if !sig.Verify(root[:], publicKey) {
|
||||
return ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ComputeDomain returns the domain version for BLS private key to sign and verify with a zeroed 4-byte
|
||||
// array as the fork version.
|
||||
//
|
||||
// def compute_domain(domain_type: DomainType, fork_version: Version=None, genesis_validators_root: Root=None) -> Domain:
|
||||
// """
|
||||
// Return the domain for the ``domain_type`` and ``fork_version``.
|
||||
// """
|
||||
// if fork_version is None:
|
||||
// fork_version = GENESIS_FORK_VERSION
|
||||
// if genesis_validators_root is None:
|
||||
// genesis_validators_root = Root() # all bytes zero by default
|
||||
// fork_data_root = compute_fork_data_root(fork_version, genesis_validators_root)
|
||||
// return Domain(domain_type + fork_data_root[:28])
|
||||
func ComputeDomain(domainType [DomainByteLength]byte, forkVersion []byte, genesisValidatorsRoot []byte) ([]byte, error) {
|
||||
if forkVersion == nil {
|
||||
forkVersion = params.BeaconConfig().GenesisForkVersion
|
||||
}
|
||||
if genesisValidatorsRoot == nil {
|
||||
genesisValidatorsRoot = params.BeaconConfig().ZeroHash[:]
|
||||
}
|
||||
forkBytes := [ForkVersionByteLength]byte{}
|
||||
copy(forkBytes[:], forkVersion)
|
||||
|
||||
forkDataRoot, err := computeForkDataRoot(forkBytes[:], genesisValidatorsRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return domain(domainType, forkDataRoot[:]), nil
|
||||
}
|
||||
|
||||
// This returns the bls domain given by the domain type and fork data root.
|
||||
func domain(domainType [DomainByteLength]byte, forkDataRoot []byte) []byte {
|
||||
b := []byte{}
|
||||
b = append(b, domainType[:4]...)
|
||||
b = append(b, forkDataRoot[:28]...)
|
||||
return b
|
||||
}
|
||||
|
||||
// this returns the 32byte fork data root for the ``current_version`` and ``genesis_validators_root``.
|
||||
// This is used primarily in signature domains to avoid collisions across forks/chains.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def compute_fork_data_root(current_version: Version, genesis_validators_root: Root) -> Root:
|
||||
// """
|
||||
// Return the 32-byte fork data root for the ``current_version`` and ``genesis_validators_root``.
|
||||
// This is used primarily in signature domains to avoid collisions across forks/chains.
|
||||
// """
|
||||
// return hash_tree_root(ForkData(
|
||||
// current_version=current_version,
|
||||
// genesis_validators_root=genesis_validators_root,
|
||||
// ))
|
||||
func computeForkDataRoot(version []byte, root []byte) ([32]byte, error) {
|
||||
r, err := ssz.HashTreeRoot(&pb.ForkData{
|
||||
CurrentVersion: version,
|
||||
GenesisValidatorsRoot: root,
|
||||
})
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// ComputeForkDigest returns the fork for the current version and genesis validator root
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def compute_fork_digest(current_version: Version, genesis_validators_root: Root) -> ForkDigest:
|
||||
// """
|
||||
// Return the 4-byte fork digest for the ``current_version`` and ``genesis_validators_root``.
|
||||
// This is a digest primarily used for domain separation on the p2p layer.
|
||||
// 4-bytes suffices for practical separation of forks/chains.
|
||||
// """
|
||||
// return ForkDigest(compute_fork_data_root(current_version, genesis_validators_root)[:4])
|
||||
func ComputeForkDigest(version []byte, genesisValidatorsRoot []byte) ([4]byte, error) {
|
||||
dataRoot, err := computeForkDataRoot(version, genesisValidatorsRoot)
|
||||
if err != nil {
|
||||
return [4]byte{}, nil
|
||||
}
|
||||
return bytesutil.ToBytes4(dataRoot[:]), nil
|
||||
}
|
||||
83
beacon-chain/core/helpers/signing_root_test.go
Normal file
83
beacon-chain/core/helpers/signing_root_test.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
ethereum_beacon_p2p_v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestSigningRoot_ComputeOK(t *testing.T) {
|
||||
emptyBlock := ðpb.BeaconBlock{}
|
||||
_, err := ComputeSigningRoot(emptyBlock, []byte{'T', 'E', 'S', 'T'})
|
||||
if err != nil {
|
||||
t.Errorf("Could not compute signing root of block: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeDomain_OK(t *testing.T) {
|
||||
tests := []struct {
|
||||
epoch uint64
|
||||
domainType [4]byte
|
||||
domain []byte
|
||||
}{
|
||||
{epoch: 1, domainType: [4]byte{4, 0, 0, 0}, domain: []byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{epoch: 2, domainType: [4]byte{4, 0, 0, 0}, domain: []byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{epoch: 2, domainType: [4]byte{5, 0, 0, 0}, domain: []byte{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{epoch: 3, domainType: [4]byte{4, 0, 0, 0}, domain: []byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{epoch: 3, domainType: [4]byte{5, 0, 0, 0}, domain: []byte{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if !bytes.Equal(domain(tt.domainType, params.BeaconConfig().ZeroHash[:]), tt.domain) {
|
||||
t.Errorf("wanted domain version: %d, got: %d", tt.domain, domain(tt.domainType, params.BeaconConfig().ZeroHash[:]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeForkDigest_OK(t *testing.T) {
|
||||
tests := []struct {
|
||||
version []byte
|
||||
root [32]byte
|
||||
result [4]byte
|
||||
}{
|
||||
{version: []byte{'A', 'B', 'C', 'D'}, root: [32]byte{'i', 'o', 'p'}, result: [4]byte{0x69, 0x5c, 0x26, 0x47}},
|
||||
{version: []byte{'i', 'm', 'n', 'a'}, root: [32]byte{'z', 'a', 'b'}, result: [4]byte{0x1c, 0x38, 0x84, 0x58}},
|
||||
{version: []byte{'b', 'w', 'r', 't'}, root: [32]byte{'r', 'd', 'c'}, result: [4]byte{0x83, 0x34, 0x38, 0x88}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
digest, err := ComputeForkDigest(tt.version, tt.root[:])
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if digest != tt.result {
|
||||
t.Errorf("wanted domain version: %#x, got: %#x", digest, tt.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzverifySigningRoot_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
pubkey := [48]byte{}
|
||||
sig := [96]byte{}
|
||||
domain := [4]byte{}
|
||||
p := []byte{}
|
||||
s := []byte{}
|
||||
d := []byte{}
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(&pubkey)
|
||||
fuzzer.Fuzz(&sig)
|
||||
fuzzer.Fuzz(&domain)
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(&p)
|
||||
fuzzer.Fuzz(&s)
|
||||
fuzzer.Fuzz(&d)
|
||||
err := VerifySigningRoot(state, pubkey[:], sig[:], domain[:])
|
||||
err = VerifySigningRoot(state, p, s, d)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
@@ -89,15 +89,17 @@ func SlotsSinceEpochStarts(slot uint64) uint64 {
|
||||
return slot - StartSlot(SlotToEpoch(slot))
|
||||
}
|
||||
|
||||
// Allow for slots "from the future" within a certain tolerance.
|
||||
const timeShiftTolerance = 10 // ms
|
||||
// TimeShiftTolerance specifies the tolerance threshold for slots "from the future".
|
||||
const TimeShiftTolerance = 500 * time.Millisecond // ms
|
||||
|
||||
// VerifySlotTime validates the input slot is not from the future.
|
||||
func VerifySlotTime(genesisTime uint64, slot uint64) error {
|
||||
slotTime := genesisTime + slot*params.BeaconConfig().SecondsPerSlot
|
||||
currentTime := uint64(roughtime.Now().Unix())
|
||||
if slotTime > currentTime+timeShiftTolerance {
|
||||
return fmt.Errorf("could not process slot from the future, slot time %d > current time %d", slotTime, currentTime)
|
||||
func VerifySlotTime(genesisTime uint64, slot uint64, timeTolerance time.Duration) error {
|
||||
// denominate everything in milliseconds
|
||||
slotTime := 1000 * (genesisTime + slot*params.BeaconConfig().SecondsPerSlot)
|
||||
currentTime := 1000 * uint64(roughtime.Now().Unix())
|
||||
tolerance := uint64(timeTolerance.Milliseconds())
|
||||
if slotTime > currentTime+tolerance {
|
||||
return fmt.Errorf("could not process slot from the future, slot time(ms) %d > current time(ms) %d", slotTime, currentTime)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -38,7 +38,10 @@ func TestCurrentEpoch_OK(t *testing.T) {
|
||||
{slot: 200, epoch: 6},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{Slot: tt.slot})
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{Slot: tt.slot})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if tt.epoch != CurrentEpoch(state) {
|
||||
t.Errorf("CurrentEpoch(%d) = %d, wanted: %d", state.Slot(), CurrentEpoch(state), tt.epoch)
|
||||
}
|
||||
@@ -55,7 +58,10 @@ func TestPrevEpoch_OK(t *testing.T) {
|
||||
{slot: 2 * params.BeaconConfig().SlotsPerEpoch, epoch: 1},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{Slot: tt.slot})
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{Slot: tt.slot})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if tt.epoch != PrevEpoch(state) {
|
||||
t.Errorf("PrevEpoch(%d) = %d, wanted: %d", state.Slot(), PrevEpoch(state), tt.epoch)
|
||||
}
|
||||
@@ -74,7 +80,10 @@ func TestNextEpoch_OK(t *testing.T) {
|
||||
{slot: 200, epoch: 200/params.BeaconConfig().SlotsPerEpoch + 1},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{Slot: tt.slot})
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{Slot: tt.slot})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if tt.epoch != NextEpoch(state) {
|
||||
t.Errorf("NextEpoch(%d) = %d, wanted: %d", state.Slot(), NextEpoch(state), tt.epoch)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package spectest contains all conformity specification tests
|
||||
// for validator shuffling logic according to the eth2 beacon spec.
|
||||
package spectest
|
||||
|
||||
import (
|
||||
|
||||
@@ -74,12 +74,14 @@ func ActiveValidatorIndices(state *stateTrie.BeaconState, epoch uint64) ([]uint6
|
||||
return activeIndices, nil
|
||||
}
|
||||
var indices []uint64
|
||||
state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
if err := state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
if IsActiveValidatorUsingTrie(val, epoch) {
|
||||
indices = append(indices, uint64(idx))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := UpdateCommitteeCache(state, epoch); err != nil {
|
||||
return nil, errors.Wrap(err, "could not update committee cache")
|
||||
@@ -92,12 +94,14 @@ func ActiveValidatorIndices(state *stateTrie.BeaconState, epoch uint64) ([]uint6
|
||||
// at the given epoch.
|
||||
func ActiveValidatorCount(state *stateTrie.BeaconState, epoch uint64) (uint64, error) {
|
||||
count := uint64(0)
|
||||
state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
if err := state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
if IsActiveValidatorUsingTrie(val, epoch) {
|
||||
count++
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
@@ -175,11 +179,63 @@ func BeaconProposerIndex(state *stateTrie.BeaconState) (uint64, error) {
|
||||
return 0, errors.Wrap(err, "could not update committee cache")
|
||||
}
|
||||
|
||||
return ComputeProposerIndex(state.Validators(), indices, seedWithSlotHash)
|
||||
return ComputeProposerIndex(state, indices, seedWithSlotHash)
|
||||
}
|
||||
|
||||
// ComputeProposerIndex returns the index sampled by effective balance, which is used to calculate proposer.
|
||||
//
|
||||
// This method is more efficient than ComputeProposerIndexWithValidators as it uses the read only validator
|
||||
// abstraction to retrieve validator related data. Whereas the other method requires a whole copy of the validator
|
||||
// set.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Hash) -> ValidatorIndex:
|
||||
// """
|
||||
// Return from ``indices`` a random index sampled by effective balance.
|
||||
// """
|
||||
// assert len(indices) > 0
|
||||
// MAX_RANDOM_BYTE = 2**8 - 1
|
||||
// i = 0
|
||||
// while True:
|
||||
// candidate_index = indices[compute_shuffled_index(ValidatorIndex(i % len(indices)), len(indices), seed)]
|
||||
// random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32]
|
||||
// effective_balance = state.validators[candidate_index].effective_balance
|
||||
// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
||||
// return ValidatorIndex(candidate_index)
|
||||
// i += 1
|
||||
func ComputeProposerIndex(bState *stateTrie.BeaconState, activeIndices []uint64, seed [32]byte) (uint64, error) {
|
||||
length := uint64(len(activeIndices))
|
||||
if length == 0 {
|
||||
return 0, errors.New("empty active indices list")
|
||||
}
|
||||
maxRandomByte := uint64(1<<8 - 1)
|
||||
hashFunc := hashutil.CustomSHA256Hasher()
|
||||
|
||||
for i := uint64(0); ; i++ {
|
||||
candidateIndex, err := ComputeShuffledIndex(i%length, length, seed, true /* shuffle */)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
candidateIndex = activeIndices[candidateIndex]
|
||||
if int(candidateIndex) >= bState.NumValidators() {
|
||||
return 0, errors.New("active index out of range")
|
||||
}
|
||||
b := append(seed[:], bytesutil.Bytes8(i/32)...)
|
||||
randomByte := hashFunc(b)[i%32]
|
||||
v, err := bState.ValidatorAtIndexReadOnly(candidateIndex)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
effectiveBal := v.EffectiveBalance()
|
||||
|
||||
if effectiveBal*maxRandomByte >= params.BeaconConfig().MaxEffectiveBalance*uint64(randomByte) {
|
||||
return candidateIndex, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ComputeProposerIndexWithValidators returns the index sampled by effective balance, which is used to calculate proposer.
|
||||
//
|
||||
// Note: This method signature deviates slightly from the spec recommended definition. The full
|
||||
// state object is not required to compute the proposer index.
|
||||
//
|
||||
@@ -198,7 +254,8 @@ func BeaconProposerIndex(state *stateTrie.BeaconState) (uint64, error) {
|
||||
// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
||||
// return ValidatorIndex(candidate_index)
|
||||
// i += 1
|
||||
func ComputeProposerIndex(validators []*ethpb.Validator, activeIndices []uint64, seed [32]byte) (uint64, error) {
|
||||
// Deprecated: Prefer using the beacon state with ComputeProposerIndex to avoid an unnecessary copy of the validator set.
|
||||
func ComputeProposerIndexWithValidators(validators []*ethpb.Validator, activeIndices []uint64, seed [32]byte) (uint64, error) {
|
||||
length := uint64(len(activeIndices))
|
||||
if length == 0 {
|
||||
return 0, errors.New("empty active indices list")
|
||||
@@ -231,18 +288,16 @@ func ComputeProposerIndex(validators []*ethpb.Validator, activeIndices []uint64,
|
||||
// Domain returns the domain version for BLS private key to sign and verify.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_domain(state: BeaconState,
|
||||
// domain_type: int,
|
||||
// message_epoch: Epoch=None) -> int:
|
||||
// def get_domain(state: BeaconState, domain_type: DomainType, epoch: Epoch=None) -> Domain:
|
||||
// """
|
||||
// Return the signature domain (fork version concatenated with domain type) of a message.
|
||||
// """
|
||||
// epoch = get_current_epoch(state) if message_epoch is None else message_epoch
|
||||
// epoch = get_current_epoch(state) if epoch is None else epoch
|
||||
// fork_version = state.fork.previous_version if epoch < state.fork.epoch else state.fork.current_version
|
||||
// return bls_domain(domain_type, fork_version)
|
||||
func Domain(fork *pb.Fork, epoch uint64, domainType [bls.DomainByteLength]byte) (uint64, error) {
|
||||
// return compute_domain(domain_type, fork_version, state.genesis_validators_root)
|
||||
func Domain(fork *pb.Fork, epoch uint64, domainType [bls.DomainByteLength]byte, genesisRoot []byte) ([]byte, error) {
|
||||
if fork == nil {
|
||||
return 0, errors.New("nil fork or domain type")
|
||||
return []byte{}, errors.New("nil fork or domain type")
|
||||
}
|
||||
var forkVersion []byte
|
||||
if epoch < fork.Epoch {
|
||||
@@ -251,11 +306,11 @@ func Domain(fork *pb.Fork, epoch uint64, domainType [bls.DomainByteLength]byte)
|
||||
forkVersion = fork.CurrentVersion
|
||||
}
|
||||
if len(forkVersion) != 4 {
|
||||
return 0, errors.New("fork version length is not 4 byte")
|
||||
return []byte{}, errors.New("fork version length is not 4 byte")
|
||||
}
|
||||
var forkVersionArray [4]byte
|
||||
copy(forkVersionArray[:], forkVersion[:4])
|
||||
return bls.Domain(domainType, forkVersionArray), nil
|
||||
return ComputeDomain(domainType, forkVersionArray[:], genesisRoot)
|
||||
}
|
||||
|
||||
// IsEligibleForActivationQueue checks if the validator is eligible to
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
@@ -128,11 +131,14 @@ func TestBeaconProposerIndex_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 0,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
slot uint64
|
||||
@@ -162,7 +168,9 @@ func TestBeaconProposerIndex_OK(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
ClearCache()
|
||||
state.SetSlot(tt.slot)
|
||||
if err := state.SetSlot(tt.slot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result, err := BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get shard and committees at slot: %v", err)
|
||||
@@ -178,6 +186,62 @@ func TestBeaconProposerIndex_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeProposerIndex_Compatibility(t *testing.T) {
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
indices, err := ActiveValidatorIndices(state, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var proposerIndices []uint64
|
||||
seed, err := Seed(state, 0, params.BeaconConfig().DomainBeaconProposer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := uint64(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {
|
||||
seedWithSlot := append(seed[:], bytesutil.Bytes8(i)...)
|
||||
seedWithSlotHash := hashutil.Hash(seedWithSlot)
|
||||
index, err := ComputeProposerIndex(state, indices, seedWithSlotHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
proposerIndices = append(proposerIndices, index)
|
||||
}
|
||||
|
||||
var wantedProposerIndices []uint64
|
||||
seed, err = Seed(state, 0, params.BeaconConfig().DomainBeaconProposer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := uint64(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {
|
||||
seedWithSlot := append(seed[:], bytesutil.Bytes8(i)...)
|
||||
seedWithSlotHash := hashutil.Hash(seedWithSlot)
|
||||
index, err := ComputeProposerIndexWithValidators(state.Validators(), indices, seedWithSlotHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantedProposerIndices = append(wantedProposerIndices, index)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(wantedProposerIndices, proposerIndices) {
|
||||
t.Error("Wanted proposer indices from ComputeProposerIndexWithValidators does not match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelayedActivationExitEpoch_OK(t *testing.T) {
|
||||
epoch := uint64(9999)
|
||||
got := ActivationExitEpoch(epoch)
|
||||
@@ -205,11 +269,14 @@ func TestChurnLimit_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
beaconState, _ := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: 1,
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
validatorCount, err := ActiveValidatorCount(beaconState, CurrentEpoch(beaconState))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -235,22 +302,22 @@ func TestDomain_OK(t *testing.T) {
|
||||
}
|
||||
tests := []struct {
|
||||
epoch uint64
|
||||
domainType uint64
|
||||
version uint64
|
||||
domainType [4]byte
|
||||
result []byte
|
||||
}{
|
||||
{epoch: 1, domainType: 4, version: 144115188075855876},
|
||||
{epoch: 2, domainType: 4, version: 144115188075855876},
|
||||
{epoch: 2, domainType: 5, version: 144115188075855877},
|
||||
{epoch: 3, domainType: 4, version: 216172782113783812},
|
||||
{epoch: 3, domainType: 5, version: 216172782113783813},
|
||||
{epoch: 1, domainType: bytesutil.ToBytes4(bytesutil.Bytes4(4)), result: bytesutil.ToBytes(947067381421703172, 32)},
|
||||
{epoch: 2, domainType: bytesutil.ToBytes4(bytesutil.Bytes4(4)), result: bytesutil.ToBytes(947067381421703172, 32)},
|
||||
{epoch: 2, domainType: bytesutil.ToBytes4(bytesutil.Bytes4(5)), result: bytesutil.ToBytes(947067381421703173, 32)},
|
||||
{epoch: 3, domainType: bytesutil.ToBytes4(bytesutil.Bytes4(4)), result: bytesutil.ToBytes(9369798235163459588, 32)},
|
||||
{epoch: 3, domainType: bytesutil.ToBytes4(bytesutil.Bytes4(5)), result: bytesutil.ToBytes(9369798235163459589, 32)},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
domain, err := Domain(state.Fork, tt.epoch, bytesutil.ToBytes4(bytesutil.Bytes4(tt.domainType)))
|
||||
domain, err := Domain(state.Fork, tt.epoch, tt.domainType, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if domain != tt.version {
|
||||
t.Errorf("wanted domain version: %d, got: %d", tt.version, domain)
|
||||
if !bytes.Equal(domain[:8], tt.result[:8]) {
|
||||
t.Errorf("wanted domain version: %d, got: %d", tt.result, domain)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -404,7 +471,10 @@ func TestActiveValidatorIndices(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s, _ := beaconstate.InitializeFromProto(tt.args.state)
|
||||
s, err := beaconstate.InitializeFromProto(tt.args.state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := ActiveValidatorIndices(s, tt.args.epoch)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ActiveValidatorIndices() error = %v, wantErr %v", err, tt.wantErr)
|
||||
@@ -529,7 +599,13 @@ func TestComputeProposerIndex(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ComputeProposerIndex(tt.args.validators, tt.args.indices, tt.args.seed)
|
||||
bState := &pb.BeaconState{Validators: tt.args.validators}
|
||||
stTrie, err := beaconstate.InitializeFromProtoUnsafe(bState)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
got, err := ComputeProposerIndex(stTrie, tt.args.indices, tt.args.seed)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ComputeProposerIndex() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
@@ -588,7 +664,10 @@ func TestIsIsEligibleForActivation(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s, _ := beaconstate.InitializeFromProto(tt.state)
|
||||
s, err := beaconstate.InitializeFromProto(tt.state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := IsEligibleForActivation(s, tt.validator); got != tt.want {
|
||||
t.Errorf("IsEligibleForActivation() = %v, want %v", got, tt.want)
|
||||
}
|
||||
|
||||
@@ -12,11 +12,12 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/state",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//endtoend:__pkg__",
|
||||
"//shared/interop:__pkg__",
|
||||
"//shared/testutil:__pkg__",
|
||||
"//tools/benchmark-files-gen:__pkg__",
|
||||
"//tools/genesis-state-gen:__pkg__",
|
||||
"//endtoend:__pkg__",
|
||||
"//tools/pcli:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
@@ -35,6 +36,7 @@ go_library(
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -56,6 +58,7 @@ go_test(
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
|
||||
@@ -27,9 +27,14 @@ func TestBenchmarkExecuteStateTransition(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := state.ExecuteStateTransition(context.Background(), beaconState, block); err != nil {
|
||||
oldSlot := beaconState.Slot()
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to process block, benchmarks will fail: %v", err)
|
||||
}
|
||||
if oldSlot == beaconState.Slot() {
|
||||
t.Fatal("Expected slots to be different")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExecuteStateTransition_FullBlock(b *testing.B) {
|
||||
@@ -69,11 +74,15 @@ func BenchmarkExecuteStateTransition_WithCache(b *testing.B) {
|
||||
// We have to reset slot back to last epoch to hydrate cache. Since
|
||||
// some attestations in block are from previous epoch
|
||||
currentSlot := beaconState.Slot()
|
||||
beaconState.SetSlot(beaconState.Slot() - params.BeaconConfig().SlotsPerEpoch)
|
||||
if err := beaconState.SetSlot(beaconState.Slot() - params.BeaconConfig().SlotsPerEpoch); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if err := helpers.UpdateCommitteeCache(beaconState, helpers.CurrentEpoch(beaconState)); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
beaconState.SetSlot(currentSlot)
|
||||
if err := beaconState.SetSlot(currentSlot); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
// Run the state transition once to populate the cache.
|
||||
if _, err := state.ExecuteStateTransition(context.Background(), beaconState, block); err != nil {
|
||||
b.Fatalf("failed to process block, benchmarks will fail: %v", err)
|
||||
@@ -98,11 +107,15 @@ func BenchmarkProcessEpoch_2FullEpochs(b *testing.B) {
|
||||
// We have to reset slot back to last epoch to hydrate cache. Since
|
||||
// some attestations in block are from previous epoch
|
||||
currentSlot := beaconState.Slot()
|
||||
beaconState.SetSlot(beaconState.Slot() - params.BeaconConfig().SlotsPerEpoch)
|
||||
if err := beaconState.SetSlot(beaconState.Slot() - params.BeaconConfig().SlotsPerEpoch); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if err := helpers.UpdateCommitteeCache(beaconState, helpers.CurrentEpoch(beaconState)); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
beaconState.SetSlot(currentSlot)
|
||||
if err := beaconState.SetSlot(currentSlot); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Package interop contains useful utilities for persisting
|
||||
// ssz-encoded states and blocks to disk during each state
|
||||
// transition for development purposes.
|
||||
package interop
|
||||
|
||||
import (
|
||||
|
||||
@@ -15,7 +15,10 @@ func TestSkipSlotCache_OK(t *testing.T) {
|
||||
state.SkipSlotCache.Enable()
|
||||
defer state.SkipSlotCache.Disable()
|
||||
bState, privs := testutil.DeterministicGenesisState(t, params.MinimalSpecConfig().MinGenesisActiveValidatorCount)
|
||||
originalState, _ := beaconstate.InitializeFromProto(bState.CloneInnerState())
|
||||
originalState, err := beaconstate.InitializeFromProto(bState.CloneInnerState())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
blkCfg := testutil.DefaultBlockGenConfig()
|
||||
blkCfg.NumAttestations = 1
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Package spectest contains all conformity specification tests
|
||||
// for slot processing logic according to the eth2 beacon spec.
|
||||
package spectest
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Package state implements the whole state transition
|
||||
// function which consists of per slot, per-epoch transitions.
|
||||
// It also bootstraps the genesis beacon state for slot 0.
|
||||
// function which consists of per slot, per-epoch transitions, and
|
||||
// bootstrapping the genesis state according to the eth2 spec.
|
||||
package state
|
||||
|
||||
import (
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
@@ -137,10 +138,16 @@ func OptimizedGenesisBeaconState(genesisTime uint64, preState *stateTrie.BeaconS
|
||||
|
||||
slashings := make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector)
|
||||
|
||||
genesisValidatorsRoot, err := stateutil.ValidatorRegistryRoot(preState.Validators())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not hash tree root genesis validators %v", err)
|
||||
}
|
||||
|
||||
state := &pb.BeaconState{
|
||||
// Misc fields.
|
||||
Slot: 0,
|
||||
GenesisTime: genesisTime,
|
||||
Slot: 0,
|
||||
GenesisTime: genesisTime,
|
||||
GenesisValidatorsRoot: genesisValidatorsRoot[:],
|
||||
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
|
||||
@@ -42,7 +42,10 @@ func TestGenesisBeaconState_OK(t *testing.T) {
|
||||
}
|
||||
|
||||
genesisTime := uint64(99999)
|
||||
deposits, _, _ := testutil.DeterministicDepositsAndKeys(uint64(depositsForChainStart))
|
||||
deposits, _, err := testutil.DeterministicDepositsAndKeys(uint64(depositsForChainStart))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
eth1Data, err := testutil.DeterministicEth1Data(len(deposits))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -68,10 +71,18 @@ func TestGenesisBeaconState_OK(t *testing.T) {
|
||||
if len(newState.Validators()) != depositsForChainStart {
|
||||
t.Error("Validators was not correctly initialized")
|
||||
}
|
||||
if v, _ := newState.ValidatorAtIndex(0); v.ActivationEpoch != 0 {
|
||||
v, err := newState.ValidatorAtIndex(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v.ActivationEpoch != 0 {
|
||||
t.Error("Validators was not correctly initialized")
|
||||
}
|
||||
if v, _ := newState.ValidatorAtIndex(0); v.ActivationEligibilityEpoch != 0 {
|
||||
v, err = newState.ValidatorAtIndex(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v.ActivationEligibilityEpoch != 0 {
|
||||
t.Error("Validators was not correctly initialized")
|
||||
}
|
||||
if len(newState.Balances()) != depositsForChainStart {
|
||||
@@ -82,7 +93,11 @@ func TestGenesisBeaconState_OK(t *testing.T) {
|
||||
if len(newState.RandaoMixes()) != latestRandaoMixesLength {
|
||||
t.Error("Length of RandaoMixes was not correctly initialized")
|
||||
}
|
||||
if mix, _ := newState.RandaoMixAtIndex(0); !bytes.Equal(mix, eth1Data.BlockHash) {
|
||||
mix, err := newState.RandaoMixAtIndex(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(mix, eth1Data.BlockHash) {
|
||||
t.Error("RandaoMixes was not correctly initialized")
|
||||
}
|
||||
|
||||
@@ -130,7 +145,10 @@ func TestGenesisBeaconState_OK(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGenesisState_HashEquality(t *testing.T) {
|
||||
deposits, _, _ := testutil.DeterministicDepositsAndKeys(100)
|
||||
deposits, _, err := testutil.DeterministicDepositsAndKeys(100)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
state1, err := state.GenesisBeaconState(deposits, 0, ðpb.Eth1Data{BlockHash: make([]byte, 32)})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Package stateutils contains useful tools for faster computation
|
||||
// of state transitions using maps to represent validators instead
|
||||
// of slices.
|
||||
package stateutils
|
||||
|
||||
import (
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/traceutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -295,14 +296,21 @@ func ProcessSlots(ctx context.Context, state *stateTrie.BeaconState, slot uint64
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer SkipSlotCache.MarkNotInProgress(key)
|
||||
defer func() {
|
||||
if err := SkipSlotCache.MarkNotInProgress(key); err != nil {
|
||||
traceutil.AnnotateError(span, err)
|
||||
logrus.WithError(err).Error("Failed to mark skip slot no longer in progress")
|
||||
}
|
||||
}()
|
||||
|
||||
for state.Slot() < slot {
|
||||
if ctx.Err() != nil {
|
||||
traceutil.AnnotateError(span, ctx.Err())
|
||||
// Cache last best value.
|
||||
if highestSlot < state.Slot() {
|
||||
SkipSlotCache.Put(ctx, key, state)
|
||||
if err := SkipSlotCache.Put(ctx, key, state); err != nil {
|
||||
logrus.WithError(err).Error("Failed to put skip slot cache value")
|
||||
}
|
||||
}
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
@@ -318,11 +326,17 @@ func ProcessSlots(ctx context.Context, state *stateTrie.BeaconState, slot uint64
|
||||
return nil, errors.Wrap(err, "could not process epoch with optimizations")
|
||||
}
|
||||
}
|
||||
state.SetSlot(state.Slot() + 1)
|
||||
if err := state.SetSlot(state.Slot() + 1); err != nil {
|
||||
traceutil.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(err, "failed to increment state slot")
|
||||
}
|
||||
}
|
||||
|
||||
if highestSlot < state.Slot() {
|
||||
SkipSlotCache.Put(ctx, key, state)
|
||||
if err := SkipSlotCache.Put(ctx, key, state); err != nil {
|
||||
logrus.WithError(err).Error("Failed to put skip slot cache value")
|
||||
traceutil.AnnotateError(span, err)
|
||||
}
|
||||
}
|
||||
|
||||
return state, nil
|
||||
@@ -605,8 +619,11 @@ func ProcessEpochPrecompute(ctx context.Context, state *stateTrie.BeaconState) (
|
||||
if state == nil {
|
||||
return nil, errors.New("nil state")
|
||||
}
|
||||
vp, bp := precompute.New(ctx, state)
|
||||
vp, bp, err := precompute.ProcessAttestations(ctx, state, vp, bp)
|
||||
vp, bp, err := precompute.New(ctx, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vp, bp, err = precompute.ProcessAttestations(ctx, state, vp, bp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user