mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
306 Commits
audit1
...
v1.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
802bdf5561 | ||
|
|
523fc621d9 | ||
|
|
472fbd3949 | ||
|
|
cd439adfc7 | ||
|
|
0bfa1ecd03 | ||
|
|
af3122a9e8 | ||
|
|
4740f7ed57 | ||
|
|
213be4cfbe | ||
|
|
5fa3bbb991 | ||
|
|
fe2f8a1c04 | ||
|
|
ed883c9fff | ||
|
|
4c143f4ed4 | ||
|
|
8097eea607 | ||
|
|
4b4a7459d9 | ||
|
|
bf548d1670 | ||
|
|
e59ee2f203 | ||
|
|
83d1aa8fa2 | ||
|
|
9d42148b93 | ||
|
|
87084ec9f1 | ||
|
|
ebd45ba336 | ||
|
|
9d8420b20c | ||
|
|
a9070ad725 | ||
|
|
f4e9e2f49c | ||
|
|
1dfeb645b6 | ||
|
|
933ab6808b | ||
|
|
f9d80e4a28 | ||
|
|
f6ecf66d1a | ||
|
|
caf61bd824 | ||
|
|
87ba5a5993 | ||
|
|
0067e52b1e | ||
|
|
4c66edf2c2 | ||
|
|
c29cccf78e | ||
|
|
298955c92b | ||
|
|
de45a54991 | ||
|
|
87ca73d605 | ||
|
|
bc76c95d62 | ||
|
|
c461c72777 | ||
|
|
c725a9c8f2 | ||
|
|
412da8e7cc | ||
|
|
82f4d6a14a | ||
|
|
89762492c8 | ||
|
|
1a6edbbaa2 | ||
|
|
409b167899 | ||
|
|
abec538fda | ||
|
|
898cd8b42b | ||
|
|
ec6309a928 | ||
|
|
2fb485598b | ||
|
|
cf3260b948 | ||
|
|
83242466f4 | ||
|
|
7f3dc5a2dd | ||
|
|
260847e92f | ||
|
|
8815f6ced8 | ||
|
|
28e61fa40c | ||
|
|
edeb359ded | ||
|
|
f40a7575de | ||
|
|
a9e3ea3ccc | ||
|
|
61855bc596 | ||
|
|
d66570c72b | ||
|
|
1ffd13c4f5 | ||
|
|
89e1b0f6bb | ||
|
|
ae4a8b3aeb | ||
|
|
1f20cbb3f0 | ||
|
|
8188fc0f9e | ||
|
|
d1a1043ef1 | ||
|
|
47dacb88f7 | ||
|
|
50af507407 | ||
|
|
187e08d38d | ||
|
|
568d8c7825 | ||
|
|
c956905cf0 | ||
|
|
bea2b3420e | ||
|
|
0387641662 | ||
|
|
ba63186c92 | ||
|
|
cb2813fa05 | ||
|
|
8ffe9858ec | ||
|
|
323a272a80 | ||
|
|
113a49b61e | ||
|
|
0b70c3ea85 | ||
|
|
a1e3fc9500 | ||
|
|
c06d61c3d0 | ||
|
|
6af7664a56 | ||
|
|
6c0fbcc622 | ||
|
|
302b0f8c80 | ||
|
|
e37c9d1334 | ||
|
|
fd3cb0be55 | ||
|
|
92f23df368 | ||
|
|
a4f4ab2b1a | ||
|
|
edbeb9022b | ||
|
|
d3494045a2 | ||
|
|
1372391b77 | ||
|
|
c3ff5ecb23 | ||
|
|
1022d9dba8 | ||
|
|
53b0c0f7ab | ||
|
|
84ae840b5d | ||
|
|
24d315c6d1 | ||
|
|
9c13e78dbd | ||
|
|
a8c13dcaf8 | ||
|
|
2eff8704a5 | ||
|
|
c94511223b | ||
|
|
b2b78c8a79 | ||
|
|
c4afb8e2e7 | ||
|
|
d2337d0ec1 | ||
|
|
4e96cbeae7 | ||
|
|
80539d9028 | ||
|
|
75aaa5e07b | ||
|
|
7429221f3f | ||
|
|
e79ba096d6 | ||
|
|
ac138eae7b | ||
|
|
469499873b | ||
|
|
fd19fd10a9 | ||
|
|
d152b48815 | ||
|
|
afbe494e55 | ||
|
|
e715339aab | ||
|
|
4ed0e432e3 | ||
|
|
db9e02d7d1 | ||
|
|
31ef6befde | ||
|
|
c23ac8547f | ||
|
|
261a343ea5 | ||
|
|
ceaceeb33c | ||
|
|
6598c38625 | ||
|
|
6e514b96fd | ||
|
|
6e3b78b99e | ||
|
|
49a0d3caf0 | ||
|
|
d35531cb17 | ||
|
|
213f8ef088 | ||
|
|
d1e2901b95 | ||
|
|
0243bdcf37 | ||
|
|
a0bf8cba52 | ||
|
|
0eaf0cf27b | ||
|
|
ac862d1e7e | ||
|
|
cde127354c | ||
|
|
0b64db5e21 | ||
|
|
88aaee36bf | ||
|
|
3fe47c0043 | ||
|
|
7dd187c2ae | ||
|
|
e3180cf977 | ||
|
|
9e8eafda6a | ||
|
|
9a2c684628 | ||
|
|
979c0074c7 | ||
|
|
a139b75dc5 | ||
|
|
4c2ed410b0 | ||
|
|
ebf7122d6f | ||
|
|
b7c856af6f | ||
|
|
7be8942079 | ||
|
|
29e4594783 | ||
|
|
f4778048ac | ||
|
|
0c3586a8ea | ||
|
|
5afee4ba3a | ||
|
|
0f7cf212a2 | ||
|
|
ecea979b60 | ||
|
|
ad1d8074d0 | ||
|
|
c70c52b40a | ||
|
|
b724b20828 | ||
|
|
b3f005fe94 | ||
|
|
3b65cb6d0b | ||
|
|
497307decd | ||
|
|
f81c8c6825 | ||
|
|
277fa3300a | ||
|
|
b810243f41 | ||
|
|
5a3114cdc9 | ||
|
|
f9d847991c | ||
|
|
6aabea2d80 | ||
|
|
230659467d | ||
|
|
c875dd458b | ||
|
|
6a9112bfae | ||
|
|
8eb7c7a0bc | ||
|
|
4fb3307de3 | ||
|
|
881ad77c52 | ||
|
|
52988a0805 | ||
|
|
5267fe607c | ||
|
|
9fc6be8b74 | ||
|
|
5f72d28057 | ||
|
|
020c481a46 | ||
|
|
e3d07489dc | ||
|
|
49edcb099b | ||
|
|
17169e5a2d | ||
|
|
2de4f86277 | ||
|
|
ea02edba29 | ||
|
|
8241b7e20d | ||
|
|
aa6190235a | ||
|
|
5e6a5902ae | ||
|
|
62b617fa9a | ||
|
|
aad1b93f70 | ||
|
|
fe7a123bd9 | ||
|
|
2a1a0ce43f | ||
|
|
c07f1600e9 | ||
|
|
678347e64b | ||
|
|
ca26745720 | ||
|
|
52105e6083 | ||
|
|
eb77f56d8a | ||
|
|
e16f384286 | ||
|
|
5d8b5a3c30 | ||
|
|
5bb9278a88 | ||
|
|
343bee35bc | ||
|
|
590016085d | ||
|
|
d79950ab3b | ||
|
|
337ae6941f | ||
|
|
150f8beccd | ||
|
|
8b168aa450 | ||
|
|
1cc7d67025 | ||
|
|
272f794868 | ||
|
|
5515c20ffd | ||
|
|
9333ede9a1 | ||
|
|
320bb46f35 | ||
|
|
007a98b711 | ||
|
|
f461f586a1 | ||
|
|
52c302307a | ||
|
|
a7b441270d | ||
|
|
2f27966b44 | ||
|
|
7a8e85af9e | ||
|
|
6e9839f987 | ||
|
|
f6d8633965 | ||
|
|
20c2d78731 | ||
|
|
7630f1852f | ||
|
|
471779e4fc | ||
|
|
34c02ffd34 | ||
|
|
f831a799c5 | ||
|
|
dc20f3d72b | ||
|
|
70c6dbeb68 | ||
|
|
8ce01acbcf | ||
|
|
ffa08f5a85 | ||
|
|
08762af5a2 | ||
|
|
ca7e057ca7 | ||
|
|
578703fa05 | ||
|
|
d5f43a8214 | ||
|
|
6488ab4a26 | ||
|
|
cd1a4f18f4 | ||
|
|
9ffc6b71d6 | ||
|
|
4242581f1e | ||
|
|
ab23fadc5e | ||
|
|
baf9ec60eb | ||
|
|
79ce15df63 | ||
|
|
96219fc9fa | ||
|
|
edfb32021b | ||
|
|
40591924c2 | ||
|
|
946a2caafd | ||
|
|
b5e7f9dd6d | ||
|
|
4c9ff7012c | ||
|
|
42278359d9 | ||
|
|
1110a5caab | ||
|
|
6840afb45e | ||
|
|
34f28a31b1 | ||
|
|
bfe694c4f3 | ||
|
|
c000509bdb | ||
|
|
e53452a437 | ||
|
|
aeb6dc13ac | ||
|
|
c82f2d5657 | ||
|
|
419343123a | ||
|
|
a25354adf0 | ||
|
|
26eead0d1c | ||
|
|
c6cac96a3b | ||
|
|
87e0fe5928 | ||
|
|
5b134239e3 | ||
|
|
c590029e48 | ||
|
|
b00bbfeec7 | ||
|
|
7a27d89e68 | ||
|
|
ad8716a58e | ||
|
|
03c7a6c0e2 | ||
|
|
6fed51d380 | ||
|
|
c1a8b41347 | ||
|
|
63e2e8acd7 | ||
|
|
9a1157465e | ||
|
|
574bf3deac | ||
|
|
40c29744e3 | ||
|
|
f0c0ed80cb | ||
|
|
f6090d0a38 | ||
|
|
87c3599c33 | ||
|
|
4d9da25d02 | ||
|
|
b2ee466f79 | ||
|
|
c4eb8c7a16 | ||
|
|
38f2ec6d7d | ||
|
|
ef4dead3fe | ||
|
|
d5b1f9f1f9 | ||
|
|
67a2698463 | ||
|
|
ae66f63ec2 | ||
|
|
bf2a37b27f | ||
|
|
aea7a8d291 | ||
|
|
840bfc5f6b | ||
|
|
f29ea77a14 | ||
|
|
2b7865cb3b | ||
|
|
3a677ef342 | ||
|
|
1a27c21d9c | ||
|
|
45f2447e6a | ||
|
|
2eac24cb79 | ||
|
|
bbde2a6820 | ||
|
|
0b8ee54076 | ||
|
|
eb2abbdd8b | ||
|
|
eb27f35982 | ||
|
|
9ea3f58a5e | ||
|
|
9be8a456eb | ||
|
|
4958c0372c | ||
|
|
1fa495afc1 | ||
|
|
e8da03a6b2 | ||
|
|
d3cb4b3059 | ||
|
|
140aff4398 | ||
|
|
c614412885 | ||
|
|
1432332923 | ||
|
|
b5c4dc2a75 | ||
|
|
17df25f3d7 | ||
|
|
af5b9222da | ||
|
|
42961277e1 | ||
|
|
973fa9f326 | ||
|
|
37f2a04e51 | ||
|
|
125d022518 | ||
|
|
b42cc724c5 | ||
|
|
436d545f80 | ||
|
|
2c3f974361 |
43
.bazelrc
43
.bazelrc
@@ -5,6 +5,9 @@ test --test_verbose_timeout_warnings
|
||||
test --build_tests_only
|
||||
test --test_output=errors
|
||||
|
||||
# Clearly indicate that coverage is enabled to disable certain nogo checks.
|
||||
coverage --define=coverage_enabled=1
|
||||
|
||||
# Fix for rules_docker. See: https://github.com/bazelbuild/rules_docker/issues/842
|
||||
build --host_force_python=PY2
|
||||
test --host_force_python=PY2
|
||||
@@ -30,20 +33,60 @@ build --define kafka_enabled=false
|
||||
test --define kafka_enabled=false
|
||||
run --define kafka_enabled=false
|
||||
|
||||
build:kafka_enabled --define kafka_enabled=true
|
||||
build:kafka_enabled --define gotags=kafka_enabled
|
||||
|
||||
# Release flags
|
||||
build:release --workspace_status_command=./scripts/workspace_status.sh
|
||||
build:release --stamp
|
||||
build:release --compilation_mode=opt
|
||||
build:release --config=llvm
|
||||
|
||||
# LLVM compiler for building C/C++ dependencies.
|
||||
build:llvm --crosstool_top=@llvm_toolchain//:toolchain
|
||||
build:llvm --define compiler=llvm
|
||||
build:llvm --copt -fno-sanitize=vptr,function
|
||||
build:llvm --linkopt -fno-sanitize=vptr,function
|
||||
|
||||
build:asan --copt -fsanitize=address,undefined
|
||||
build:asan --copt -fno-omit-frame-pointer
|
||||
build:asan --linkopt -fsanitize=address,undefined
|
||||
build:asan --copt -fno-sanitize=vptr,function
|
||||
build:asan --linkopt -fno-sanitize=vptr,function
|
||||
build:asan --copt -DADDRESS_SANITIZER=1
|
||||
build:asan --copt -D__SANITIZE_ADDRESS__
|
||||
build:asan --linkopt -ldl
|
||||
|
||||
build:llvm-asan --config=llvm
|
||||
build:llvm-asan --config=asan
|
||||
build:llvm-asan --linkopt -fuse-ld=ld.lld
|
||||
|
||||
build:fuzz --define=gotags=libfuzzer
|
||||
build:fuzz --config=llvm-asan
|
||||
build:fuzz --copt=-fsanitize=fuzzer-no-link
|
||||
build:fuzz --linkopt=-fsanitize=fuzzer
|
||||
build:fuzz --copt=-fno-omit-frame-pointer
|
||||
build:fuzz --define=FUZZING_ENGINE=libfuzzer
|
||||
build:fuzz --copt=-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
build:fuzz --linkopt -Wl,--no-as-needed
|
||||
build:fuzz --define=gc_goopts=-d=libfuzzer
|
||||
build:fuzz --run_under=//tools:fuzz_wrapper
|
||||
build:fuzz --compilation_mode=opt
|
||||
|
||||
test:fuzz --local_test_jobs="HOST_CPUS*.5"
|
||||
|
||||
test:fuzzit --config=fuzz
|
||||
test:fuzzit --test_env=FUZZIT_API_KEY
|
||||
test:fuzzit --test_env=PRYSM_BUILD_IMAGE=gcr.io/prysmaticlabs/prysm-fuzzit:v0.11.0
|
||||
test:fuzzit --test_timeout=1200
|
||||
test:fuzzit --run_under=//tools:fuzzit_wrapper
|
||||
|
||||
# Build binary with cgo symbolizer for debugging / profiling.
|
||||
build:cgo_symbolizer --config=llvm
|
||||
build:cgo_symbolizer --copt=-g
|
||||
build:cgo_symbolizer --define=USE_CGO_SYMBOLIZER=true
|
||||
build:cgo_symbolizer -c dbg
|
||||
build:cgo_symbolizer --define=gotags=cgosymbolizer_enabled
|
||||
|
||||
# multi-arch cross-compiling toolchain configs:
|
||||
-----------------------------------------------
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.0.0
|
||||
3.2.0
|
||||
|
||||
@@ -45,7 +45,15 @@ build --flaky_test_attempts=5
|
||||
# build --features=race
|
||||
|
||||
# Enable kafka for CI tests only.
|
||||
test --define kafka_enabled=true
|
||||
test --config=kafka_enabled
|
||||
|
||||
build --bes_backend=grpcs://builds.prylabs.net:1985
|
||||
build --bes_results_url=https://builds.prylabs.net/invocation/
|
||||
|
||||
# Disable flaky test detection for fuzzing.
|
||||
test:fuzz --flaky_test_attempts=1
|
||||
|
||||
# Expose test environment variables in CI
|
||||
test:fuzzit --test_env=GITHUB_REF
|
||||
test:fuzzit --test_env=GITHUB_SHA
|
||||
test:fuzzit --test_env=DOCKER_HOST
|
||||
|
||||
38
.github/ISSUE_TEMPLATE/feature_flag.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/feature_flag.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: "\U0001F984Feature Flag Tracking"
|
||||
about: Track a new feature, in development, in Prysm. This issue template should only be used by developers or contributors!
|
||||
labels: Tracking
|
||||
---
|
||||
<!--💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎
|
||||
|
||||
Hellooo! 😄
|
||||
|
||||
Thanks for taking the time to file a tracking issue for your new feature. These issues really help
|
||||
us track progress of features as they work their way through development. Be sure to review
|
||||
shared/featureconfig/README.md for the latest documentation around feature flags.
|
||||
|
||||
💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎-->
|
||||
|
||||
# 🦄 Feature Tracking
|
||||
|
||||
**Current status** (opt-in or opt-out):
|
||||
|
||||
**Opt-in feature flag name**:
|
||||
|
||||
**Opt-out feature flag name**:
|
||||
|
||||
### Feature Description
|
||||
|
||||
<!-- ✍️--> A clear and concise description of the new feature. Provide links to your technical
|
||||
design document or other supporting information.
|
||||
|
||||
### Tasks
|
||||
|
||||
- [ ] Feature flag created as opt-in
|
||||
- [ ] Feature implemented / code complete
|
||||
- [ ] Feature tested in production for adequate amount of time
|
||||
- [ ] Feature flag is inverted to be opt-out and the opt-in flag is deprecated
|
||||
- [ ] Feature has made it to a tagged production release as an opt-out flag
|
||||
- [ ] Opt-out feature flag is deprecated and old code paths are cleaned up
|
||||
|
||||
This issue should be closed after all of the above tasks are complete.
|
||||
5
.github/actions/gofmt/Dockerfile
vendored
Normal file
5
.github/actions/gofmt/Dockerfile
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM cytopia/gofmt
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
12
.github/actions/gofmt/action.yml
vendored
Normal file
12
.github/actions/gofmt/action.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
name: 'Gofmt checker'
|
||||
description: 'Checks that all project files have been properly formatted.'
|
||||
inputs:
|
||||
path:
|
||||
description: 'Path to check'
|
||||
required: true
|
||||
default: './'
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
args:
|
||||
- ${{ inputs.path }}
|
||||
15
.github/actions/gofmt/entrypoint.sh
vendored
Executable file
15
.github/actions/gofmt/entrypoint.sh
vendored
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh -l
|
||||
set -e
|
||||
|
||||
cd $GITHUB_WORKSPACE
|
||||
|
||||
# Check if any files are not formatted.
|
||||
nonformatted="$(gofmt -l $1 2>&1)"
|
||||
|
||||
# Return if `go fmt` passes.
|
||||
[ -z "$nonformatted" ] && exit 0
|
||||
|
||||
# Notify of issues with formatting.
|
||||
echo "Following files need to be properly formatted:"
|
||||
echo "$nonformatted"
|
||||
exit 1
|
||||
5
.github/actions/gomodtidy/Dockerfile
vendored
Normal file
5
.github/actions/gomodtidy/Dockerfile
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM golang:alpine
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
5
.github/actions/gomodtidy/action.yml
vendored
Normal file
5
.github/actions/gomodtidy/action.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
name: 'Go mod tidy checker'
|
||||
description: 'Checks that `go mod tidy` has been applied.'
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
34
.github/actions/gomodtidy/entrypoint.sh
vendored
Executable file
34
.github/actions/gomodtidy/entrypoint.sh
vendored
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/bin/sh -l
|
||||
set -e
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
|
||||
cd $GITHUB_WORKSPACE
|
||||
|
||||
cp go.mod go.mod.orig
|
||||
cp go.sum go.sum.orig
|
||||
|
||||
go mod tidy
|
||||
|
||||
echo "Checking go.mod and go.sum:"
|
||||
checks=0
|
||||
if [ "$(diff -s go.mod.orig go.mod | grep -c 'Files go.mod.orig and go.mod are identical')" = 1 ]; then
|
||||
echo "- go.mod is up to date."
|
||||
checks=$((checks + 1))
|
||||
else
|
||||
echo "- go.mod is NOT up to date."
|
||||
fi
|
||||
|
||||
if [ "$(diff -s go.sum.orig go.sum | grep -c 'Files go.sum.orig and go.sum are identical')" = 1 ]; then
|
||||
echo "- go.sum is up to date."
|
||||
checks=$((checks + 1))
|
||||
else
|
||||
echo "- go.sum is NOT up to date."
|
||||
fi
|
||||
|
||||
if [ $checks -eq 2 ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Notify of any issues.
|
||||
echo "Run 'go mod tidy' to update."
|
||||
exit 1
|
||||
50
.github/workflows/go.yml
vendored
Normal file
50
.github/workflows/go.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ '*' ]
|
||||
|
||||
jobs:
|
||||
|
||||
check:
|
||||
name: Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Go mod tidy checker
|
||||
id: gomodtidy
|
||||
uses: ./.github/actions/gomodtidy
|
||||
|
||||
- name: Gofmt checker
|
||||
id: gofmt
|
||||
uses: ./.github/actions/gofmt
|
||||
with:
|
||||
path: ./
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.14
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
|
||||
# Tests run via Bazel for now...
|
||||
# - name: Test
|
||||
# run: go test -v ./...
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -27,9 +27,5 @@ yarn-error.log
|
||||
# Ignore password file
|
||||
password.txt
|
||||
|
||||
# go dependancy
|
||||
/go.mod
|
||||
/go.sum
|
||||
|
||||
# Dist files
|
||||
dist
|
||||
|
||||
31
BUILD.bazel
31
BUILD.bazel
@@ -4,6 +4,7 @@ load("@com_github_atlassian_bazel_tools//goimports:def.bzl", "goimports")
|
||||
load("@io_kubernetes_build//defs:run_in_workspace.bzl", "workspace_binary")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "nogo")
|
||||
load("@graknlabs_bazel_distribution//common:rules.bzl", "assemble_targz", "assemble_versioned")
|
||||
load("@bazel_skylib//rules:common_settings.bzl", "string_setting")
|
||||
|
||||
prefix = "github.com/prysmaticlabs/prysm"
|
||||
|
||||
@@ -12,6 +13,8 @@ exports_files([
|
||||
])
|
||||
|
||||
# gazelle:prefix github.com/prysmaticlabs/prysm
|
||||
# gazelle:map_kind go_library go_library @prysm//tools/go:def.bzl
|
||||
# gazelle:map_kind go_repository go_repository @prysm//tools/go:def.bzl
|
||||
gazelle(
|
||||
name = "gazelle",
|
||||
prefix = prefix,
|
||||
@@ -43,7 +46,7 @@ alias(
|
||||
# Protobuf gRPC gateway compiler
|
||||
alias(
|
||||
name = "grpc_gateway_proto_compiler",
|
||||
actual = "@grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway:go_gen_grpc_gateway",
|
||||
actual = "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway:go_gen_grpc_gateway",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
@@ -85,15 +88,12 @@ nogo(
|
||||
"@org_golang_x_tools//go/analysis/passes/pkgfact:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/nilness:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/nilfunc:go_tool_library",
|
||||
# lost cancel ignore doesn't seem to work when running with coverage
|
||||
#"@org_golang_x_tools//go/analysis/passes/lostcancel:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/loopclosure:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/httpresponse:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/findcall:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/deepequalerrors:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/ctrlflow:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/copylock:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/composite:go_tool_library",
|
||||
# "@org_golang_x_tools//go/analysis/passes/cgocall:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/buildtag:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/buildssa:go_tool_library",
|
||||
@@ -107,7 +107,19 @@ nogo(
|
||||
"//tools/analyzers/roughtime:go_tool_library",
|
||||
"//tools/analyzers/errcheck:go_tool_library",
|
||||
"//tools/analyzers/featureconfig:go_tool_library",
|
||||
],
|
||||
] + select({
|
||||
# nogo checks that fail with coverage enabled.
|
||||
":coverage_enabled": [],
|
||||
"//conditions:default": [
|
||||
"@org_golang_x_tools//go/analysis/passes/lostcancel:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/composite:go_tool_library",
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "coverage_enabled",
|
||||
values = {"define": "coverage_enabled=1"},
|
||||
)
|
||||
|
||||
common_files = {
|
||||
@@ -120,3 +132,12 @@ toolchain(
|
||||
toolchain = "@rules_foreign_cc//tools/build_defs/native_tools:built_cmake",
|
||||
toolchain_type = "@rules_foreign_cc//tools/build_defs:cmake_toolchain",
|
||||
)
|
||||
|
||||
string_setting(
|
||||
name = "gotags",
|
||||
build_setting_default = "",
|
||||
values = [
|
||||
"",
|
||||
"libfuzzer",
|
||||
],
|
||||
)
|
||||
|
||||
69
DEPENDENCIES.md
Normal file
69
DEPENDENCIES.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Dependency Managagement in Prysm
|
||||
|
||||
Prysm is go project with many complicated dependencies, including some c++ based libraries. There
|
||||
are two parts to Prysm's dependency management. Go modules and bazel managed dependencies. Be sure
|
||||
to read [Why Bazel?](https://github.com/prysmaticlabs/documentation/issues/138) to fully
|
||||
understand the reasoning behind an additional layer of build tooling via Bazel rather than a pure
|
||||
"go build" project.
|
||||
|
||||
## Go Module support
|
||||
|
||||
The Prysm project officially supports go modules with some caveats.
|
||||
|
||||
### Caveat 1: Some c++ libraries are precompiled archives
|
||||
|
||||
Given some of Prysm's c++ dependencies have very complicated project structures which make building
|
||||
difficult or impossible with "go build" alone. Additionally, building c++ dependencies with certain
|
||||
compilers, like clang / LLVM, offer a significant performance improvement. To get around this
|
||||
issue, c++ dependencies have been precompiled as linkable archives. While there isn't necessarily
|
||||
anything bad about precompiled archives, these files are a "blackbox" which a 3rd party author
|
||||
could have compiled anything for this archive and detecting undesired behavior would be nearly
|
||||
impossible. If your risk tolerance is low, always compile everything from source yourself,
|
||||
including complicated c++ dependencies.
|
||||
|
||||
*Recommendation: Use go build only for local development and use bazel build for production.*
|
||||
|
||||
### Caveat 2: Generated gRPC protobuf libraries
|
||||
|
||||
One key advantage of Bazel over vanilla `go build` is that Bazel automatically (re)builds generated
|
||||
pb.go files at build time when file changes are present in any protobuf definition file or after
|
||||
any updates to the protobuf compiler or other relevant dependencies. Vanilla go users should run
|
||||
the following scripts often to ensure their generated files are up to date. Further more, Prysm
|
||||
generates SSZ marshal related code based on defined data structures. These generated files must
|
||||
also be updated and checked in as frequently.
|
||||
|
||||
```bash
|
||||
./scripts/update-go-pbs.sh
|
||||
./scripts/update-go-ssz.sh
|
||||
```
|
||||
|
||||
*Recommendation: Use go build only for local development and use bazel build for production.*
|
||||
|
||||
### Caveat 3: Compile-time optimizations
|
||||
|
||||
When Prysmatic Labs builds production binaries, they use the "release" configuration of bazel to
|
||||
compile with several compiler optimizations and recommended production build configurations.
|
||||
Additionally, the release build properly stamps the built binaries to include helpful metadata
|
||||
about how and when the binary was built.
|
||||
|
||||
*Recommendation: Use go build only for local development and use bazel build for production.*
|
||||
|
||||
```bash
|
||||
bazel build //beacon-chain --config=release
|
||||
```
|
||||
|
||||
## Adding / updating dependencies
|
||||
|
||||
1. Add your dependency as you would with go modules. I.e. `go get ...`
|
||||
1. Run `gazelle update-repos -from_file=go.mod` to update the bazel managed dependencies.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
go get github.com/prysmaticlabs/example@v1.2.3
|
||||
bazel run //:gazelle -- update-repos -from_file=go.mod -to_macro=deps.bzl%prysm_deps
|
||||
```
|
||||
|
||||
The deps.bzl file should have been updated with the dependency and any transitive dependencies.
|
||||
|
||||
Do NOT add new `go_repository` to the WORKSPACE file. All dependencies should live in deps.bzl.
|
||||
@@ -1,7 +1,8 @@
|
||||
# Prysm: An Ethereum 2.0 Client Written in Go
|
||||
|
||||
[](https://buildkite.com/prysmatic-labs/prysm)
|
||||
[](https://github.com/ethereum/eth2.0-specs/tree/v0.11.1)
|
||||
[](https://app.fuzzit.dev/orgs/prysmaticlabs-gh/dashboard)
|
||||
[](https://github.com/ethereum/eth2.0-specs/tree/v0.12.1)
|
||||
[](https://discord.gg/KSA7rPr)
|
||||
[](https://gitter.im/prysmaticlabs/geth-sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_test")
|
||||
load("@io_bazel_rules_docker//go:image.bzl", "go_image")
|
||||
load("@io_bazel_rules_docker//container:container.bzl", "container_bundle")
|
||||
load("//tools:go_image.bzl", "go_image_alpine", "go_image_debug")
|
||||
@@ -21,13 +22,12 @@ go_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_ipfs_go_log_v2//:go_default_library",
|
||||
"@com_github_joonix_log//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_whyrusleeping_go_logging//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//altsrc:go_default_library",
|
||||
"@com_github_x_cray_logrus_prefixed_formatter//:go_default_library",
|
||||
"@in_gopkg_urfave_cli_v2//:go_default_library",
|
||||
"@in_gopkg_urfave_cli_v2//altsrc:go_default_library",
|
||||
"@org_uber_go_automaxprocs//:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -59,13 +59,12 @@ go_image(
|
||||
"//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_ipfs_go_log_v2//:go_default_library",
|
||||
"@com_github_joonix_log//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_whyrusleeping_go_logging//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//altsrc:go_default_library",
|
||||
"@com_github_x_cray_logrus_prefixed_formatter//:go_default_library",
|
||||
"@in_gopkg_urfave_cli_v2//:go_default_library",
|
||||
"@in_gopkg_urfave_cli_v2//altsrc:go_default_library",
|
||||
"@org_uber_go_automaxprocs//:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -75,6 +74,8 @@ container_bundle(
|
||||
images = {
|
||||
"gcr.io/prysmaticlabs/prysm/beacon-chain:latest": ":image",
|
||||
"gcr.io/prysmaticlabs/prysm/beacon-chain:{DOCKER_TAG}": ":image",
|
||||
"index.docker.io/prysmaticlabs/prysm-beacon-chain:latest": ":image",
|
||||
"index.docker.io/prysmaticlabs/prysm-beacon-chain:{DOCKER_TAG}": ":image",
|
||||
},
|
||||
tags = ["manual"],
|
||||
)
|
||||
@@ -90,6 +91,8 @@ container_bundle(
|
||||
images = {
|
||||
"gcr.io/prysmaticlabs/prysm/beacon-chain:latest-debug": ":image_debug",
|
||||
"gcr.io/prysmaticlabs/prysm/beacon-chain:{DOCKER_TAG}-debug": ":image_debug",
|
||||
"index.docker.io/prysmaticlabs/prysm-beacon-chain:latest-debug": ":image_debug",
|
||||
"index.docker.io/prysmaticlabs/prysm-beacon-chain:{DOCKER_TAG}-debug": ":image_debug",
|
||||
},
|
||||
tags = ["manual"],
|
||||
)
|
||||
@@ -105,6 +108,8 @@ container_bundle(
|
||||
images = {
|
||||
"gcr.io/prysmaticlabs/prysm/beacon-chain:latest-alpine": ":image_alpine",
|
||||
"gcr.io/prysmaticlabs/prysm/beacon-chain:{DOCKER_TAG}-alpine": ":image_alpine",
|
||||
"index.docker.io/prysmaticlabs/prysm-beacon-chain:latest-alpine": ":image_alpine",
|
||||
"index.docker.io/prysmaticlabs/prysm-beacon-chain:{DOCKER_TAG}-alpine": ":image_alpine",
|
||||
},
|
||||
tags = ["manual"],
|
||||
)
|
||||
@@ -143,6 +148,6 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"@in_gopkg_urfave_cli_v2//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
|
||||
@@ -119,13 +119,13 @@ func (s *Service) archiveActiveSetChanges(ctx context.Context, headState *state.
|
||||
// We compute participation metrics by first retrieving the head state and
|
||||
// matching validator attestations during the epoch.
|
||||
func (s *Service) archiveParticipation(ctx context.Context, epoch uint64) error {
|
||||
p := s.participationFetcher.Participation(epoch)
|
||||
pBal := s.participationFetcher.Participation(epoch)
|
||||
participation := ðpb.ValidatorParticipation{}
|
||||
if p != nil {
|
||||
if pBal != nil {
|
||||
participation = ðpb.ValidatorParticipation{
|
||||
EligibleEther: p.PrevEpoch,
|
||||
VotedEther: p.PrevEpochTargetAttesters,
|
||||
GlobalParticipationRate: float32(p.PrevEpochTargetAttesters) / float32(p.PrevEpoch),
|
||||
EligibleEther: pBal.ActivePrevEpoch,
|
||||
VotedEther: pBal.PrevEpochTargetAttested,
|
||||
GlobalParticipationRate: float32(pBal.PrevEpochTargetAttested) / float32(pBal.ActivePrevEpoch),
|
||||
}
|
||||
}
|
||||
return s.beaconDB.SaveArchivedValidatorParticipation(ctx, epoch, participation)
|
||||
|
||||
@@ -31,8 +31,7 @@ func init() {
|
||||
|
||||
func TestArchiverService_ReceivesBlockProcessedEvent(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
svc, beaconDB := setupService(t)
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
svc, _ := setupService(t)
|
||||
st := testutil.NewBeaconState()
|
||||
if err := st.SetSlot(1); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -55,8 +54,7 @@ func TestArchiverService_ReceivesBlockProcessedEvent(t *testing.T) {
|
||||
|
||||
func TestArchiverService_OnlyArchiveAtEpochEnd(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
svc, beaconDB := setupService(t)
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
svc, _ := setupService(t)
|
||||
// The head state is NOT an epoch end.
|
||||
st := testutil.NewBeaconState()
|
||||
if err := st.SetSlot(params.BeaconConfig().SlotsPerEpoch - 2); err != nil {
|
||||
@@ -86,13 +84,12 @@ func TestArchiverService_OnlyArchiveAtEpochEnd(t *testing.T) {
|
||||
|
||||
func TestArchiverService_ArchivesEvenThroughSkipSlot(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
svc, beaconDB := setupService(t)
|
||||
svc, _ := setupService(t)
|
||||
validatorCount := uint64(100)
|
||||
headState, err := setupState(validatorCount)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
event := &feed.Event{
|
||||
Type: statefeed.BlockProcessed,
|
||||
Data: &statefeed.BlockProcessedData{
|
||||
@@ -146,8 +143,7 @@ func TestArchiverService_ComputesAndSavesParticipation(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
svc, beaconDB := setupService(t)
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
svc, _ := setupService(t)
|
||||
svc.headFetcher = &mock.ChainService{
|
||||
State: headState,
|
||||
}
|
||||
@@ -187,8 +183,7 @@ func TestArchiverService_SavesIndicesAndBalances(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
svc, beaconDB := setupService(t)
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
svc, _ := setupService(t)
|
||||
svc.headFetcher = &mock.ChainService{
|
||||
State: headState,
|
||||
}
|
||||
@@ -223,8 +218,7 @@ func TestArchiverService_SavesCommitteeInfo(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
svc, beaconDB := setupService(t)
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
svc, _ := setupService(t)
|
||||
svc.headFetcher = &mock.ChainService{
|
||||
State: headState,
|
||||
}
|
||||
@@ -274,7 +268,6 @@ func TestArchiverService_SavesActivatedValidatorChanges(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
svc, beaconDB := setupService(t)
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
svc.headFetcher = &mock.ChainService{
|
||||
State: headState,
|
||||
}
|
||||
@@ -326,7 +319,6 @@ func TestArchiverService_SavesSlashedValidatorChanges(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
svc, beaconDB := setupService(t)
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
svc.headFetcher = &mock.ChainService{
|
||||
State: headState,
|
||||
}
|
||||
@@ -377,7 +369,6 @@ func TestArchiverService_SavesExitedValidatorChanges(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
svc, beaconDB := setupService(t)
|
||||
defer dbutil.TeardownDB(t, beaconDB)
|
||||
svc.headFetcher = &mock.ChainService{
|
||||
State: headState,
|
||||
}
|
||||
@@ -456,7 +447,7 @@ func setupService(t *testing.T) (*Service, db.Database) {
|
||||
cancel: cancel,
|
||||
stateNotifier: mockChainService.StateNotifier(),
|
||||
participationFetcher: &mock.ChainService{
|
||||
Balance: &precompute.Balance{PrevEpoch: totalBalance, PrevEpochTargetAttesters: 1}},
|
||||
Balance: &precompute.Balance{ActivePrevEpoch: totalBalance, PrevEpochTargetAttested: 1}},
|
||||
}, beaconDB
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
@@ -54,7 +55,6 @@ go_library(
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto: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",
|
||||
],
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
"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/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -21,6 +21,7 @@ type ChainInfoFetcher interface {
|
||||
HeadFetcher
|
||||
FinalizationFetcher
|
||||
GenesisFetcher
|
||||
CanonicalFetcher
|
||||
}
|
||||
|
||||
// TimeFetcher retrieves the Eth2 data that's related to time.
|
||||
@@ -44,6 +45,8 @@ type HeadFetcher interface {
|
||||
HeadValidatorsIndices(epoch uint64) ([]uint64, error)
|
||||
HeadSeed(epoch uint64) ([32]byte, error)
|
||||
HeadGenesisValidatorRoot() [32]byte
|
||||
HeadETH1Data() *ethpb.Eth1Data
|
||||
ProtoArrayStore() *protoarray.Store
|
||||
}
|
||||
|
||||
// ForkFetcher retrieves the current fork information of the Ethereum beacon chain.
|
||||
@@ -51,6 +54,11 @@ type ForkFetcher interface {
|
||||
CurrentFork() *pb.Fork
|
||||
}
|
||||
|
||||
// CanonicalFetcher retrieves the current chain's canonical information.
|
||||
type CanonicalFetcher interface {
|
||||
IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error)
|
||||
}
|
||||
|
||||
// FinalizationFetcher defines a common interface for methods in blockchain service which
|
||||
// directly retrieves finalization and justification related data.
|
||||
type FinalizationFetcher interface {
|
||||
@@ -71,12 +79,6 @@ func (s *Service) FinalizedCheckpt() *ethpb.Checkpoint {
|
||||
return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
}
|
||||
|
||||
// If head state exists but there hasn't been a finalized check point,
|
||||
// the check point's root should refer to genesis block root.
|
||||
if bytes.Equal(s.finalizedCheckpt.Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
return ðpb.Checkpoint{Root: s.genesisRoot[:]}
|
||||
}
|
||||
|
||||
return state.CopyCheckpoint(s.finalizedCheckpt)
|
||||
}
|
||||
|
||||
@@ -86,12 +88,6 @@ func (s *Service) CurrentJustifiedCheckpt() *ethpb.Checkpoint {
|
||||
return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
}
|
||||
|
||||
// If head state exists but there hasn't been a justified check point,
|
||||
// the check point root should refer to genesis block root.
|
||||
if bytes.Equal(s.justifiedCheckpt.Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
return ðpb.Checkpoint{Root: s.genesisRoot[:]}
|
||||
}
|
||||
|
||||
return state.CopyCheckpoint(s.justifiedCheckpt)
|
||||
}
|
||||
|
||||
@@ -101,12 +97,6 @@ func (s *Service) PreviousJustifiedCheckpt() *ethpb.Checkpoint {
|
||||
return ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
}
|
||||
|
||||
// If head state exists but there hasn't been a justified check point,
|
||||
// the check point root should refer to genesis block root.
|
||||
if bytes.Equal(s.prevJustifiedCheckpt.Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
return ðpb.Checkpoint{Root: s.genesisRoot[:]}
|
||||
}
|
||||
|
||||
return state.CopyCheckpoint(s.prevJustifiedCheckpt)
|
||||
}
|
||||
|
||||
@@ -134,7 +124,7 @@ func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) {
|
||||
return params.BeaconConfig().ZeroHash[:], nil
|
||||
}
|
||||
|
||||
r, err := ssz.HashTreeRoot(b.Block)
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -190,6 +180,19 @@ func (s *Service) HeadGenesisValidatorRoot() [32]byte {
|
||||
return s.headGenesisValidatorRoot()
|
||||
}
|
||||
|
||||
// HeadETH1Data returns the eth1data of the current head state.
|
||||
func (s *Service) HeadETH1Data() *ethpb.Eth1Data {
|
||||
if !s.hasHeadState() {
|
||||
return ðpb.Eth1Data{}
|
||||
}
|
||||
return s.head.state.Eth1Data()
|
||||
}
|
||||
|
||||
// ProtoArrayStore returns the proto array store object.
|
||||
func (s *Service) ProtoArrayStore() *protoarray.Store {
|
||||
return s.forkChoiceStore.Store()
|
||||
}
|
||||
|
||||
// GenesisTime returns the genesis time of beacon chain.
|
||||
func (s *Service) GenesisTime() time.Time {
|
||||
return s.genesisTime
|
||||
@@ -222,3 +225,17 @@ func (s *Service) Participation(epoch uint64) *precompute.Balance {
|
||||
|
||||
return s.epochParticipation[epoch]
|
||||
}
|
||||
|
||||
// IsCanonical returns true if the input block root is part of the canonical chain.
|
||||
func (s *Service) IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error) {
|
||||
// If the block has been finalized, the block will always be part of the canonical chain.
|
||||
if s.beaconDB.IsFinalizedBlock(ctx, blockRoot) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// If the block has not been finalized, the block must be recent. Check recent canonical roots
|
||||
// mapping which uses proto array fork choice.
|
||||
s.recentCanonicalBlocksLock.RLock()
|
||||
defer s.recentCanonicalBlocksLock.RUnlock()
|
||||
return s.recentCanonicalBlocks[blockRoot], nil
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
|
||||
func TestHeadSlot_DataRace(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
}
|
||||
@@ -26,7 +25,6 @@ func TestHeadSlot_DataRace(t *testing.T) {
|
||||
|
||||
func TestHeadRoot_DataRace(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
head: &head{root: [32]byte{'A'}},
|
||||
@@ -44,7 +42,6 @@ func TestHeadRoot_DataRace(t *testing.T) {
|
||||
|
||||
func TestHeadBlock_DataRace(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
head: &head{block: ðpb.SignedBeaconBlock{}},
|
||||
@@ -62,7 +59,6 @@ func TestHeadBlock_DataRace(t *testing.T) {
|
||||
|
||||
func TestHeadState_DataRace(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
stateGen: stategen.New(db, cache.NewStateSummaryCache()),
|
||||
|
||||
@@ -22,7 +22,6 @@ var _ = ForkFetcher(&Service{})
|
||||
|
||||
func TestFinalizedCheckpt_Nil(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
c := setupBeaconChain(t, db)
|
||||
if !bytes.Equal(c.FinalizedCheckpt().Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Error("Incorrect pre chain start value")
|
||||
@@ -31,7 +30,6 @@ func TestFinalizedCheckpt_Nil(t *testing.T) {
|
||||
|
||||
func TestHeadRoot_Nil(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
c := setupBeaconChain(t, db)
|
||||
headRoot, err := c.HeadRoot(context.Background())
|
||||
if err != nil {
|
||||
@@ -44,7 +42,6 @@ func TestHeadRoot_Nil(t *testing.T) {
|
||||
|
||||
func TestFinalizedCheckpt_CanRetrieve(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cp := ðpb.Checkpoint{Epoch: 5, Root: []byte("foo")}
|
||||
c := setupBeaconChain(t, db)
|
||||
@@ -57,7 +54,6 @@ func TestFinalizedCheckpt_CanRetrieve(t *testing.T) {
|
||||
|
||||
func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
genesisRoot := [32]byte{'A'}
|
||||
cp := ðpb.Checkpoint{Root: genesisRoot[:]}
|
||||
@@ -72,7 +68,6 @@ func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
|
||||
func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cp := ðpb.Checkpoint{Epoch: 6, Root: []byte("foo")}
|
||||
c := setupBeaconChain(t, db)
|
||||
@@ -85,7 +80,6 @@ func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
|
||||
|
||||
func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
genesisRoot := [32]byte{'B'}
|
||||
cp := ðpb.Checkpoint{Root: genesisRoot[:]}
|
||||
@@ -100,7 +94,6 @@ func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
|
||||
func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cp := ðpb.Checkpoint{Epoch: 7, Root: []byte("foo")}
|
||||
c := setupBeaconChain(t, db)
|
||||
@@ -113,7 +106,6 @@ func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) {
|
||||
|
||||
func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
genesisRoot := [32]byte{'C'}
|
||||
cp := ðpb.Checkpoint{Root: genesisRoot[:]}
|
||||
@@ -218,3 +210,24 @@ func TestGenesisValidatorRoot_CanRetrieve(t *testing.T) {
|
||||
t.Error("Did not get correct genesis validator root")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeadETH1Data_Nil(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
c := setupBeaconChain(t, db)
|
||||
if !reflect.DeepEqual(c.HeadETH1Data(), ðpb.Eth1Data{}) {
|
||||
t.Error("Incorrect pre chain start value")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeadETH1Data_CanRetrieve(t *testing.T) {
|
||||
d := ðpb.Eth1Data{DepositCount: 999}
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{Eth1Data: d})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
if !proto.Equal(c.HeadETH1Data(), d) {
|
||||
t.Error("Received incorrect eth1 data")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,20 @@ package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -32,16 +38,29 @@ func (s *Service) updateHead(ctx context.Context, balances []uint64) error {
|
||||
// ensure head gets its best justified info.
|
||||
if s.bestJustifiedCheckpt.Epoch > s.justifiedCheckpt.Epoch {
|
||||
s.justifiedCheckpt = s.bestJustifiedCheckpt
|
||||
if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Get head from the fork choice service.
|
||||
f := s.finalizedCheckpt
|
||||
j := s.justifiedCheckpt
|
||||
headRoot, err := s.forkChoiceStore.Head(ctx, j.Epoch, bytesutil.ToBytes32(j.Root), balances, f.Epoch)
|
||||
// To get head before the first justified epoch, the fork choice will start with genesis root
|
||||
// instead of zero hashes.
|
||||
headStartRoot := bytesutil.ToBytes32(j.Root)
|
||||
if headStartRoot == params.BeaconConfig().ZeroHash {
|
||||
headStartRoot = s.genesisRoot
|
||||
}
|
||||
headRoot, err := s.forkChoiceStore.Head(ctx, j.Epoch, headStartRoot, balances, f.Epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.updateRecentCanonicalBlocks(ctx, headRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save head to the local service cache.
|
||||
return s.saveHead(ctx, headRoot)
|
||||
}
|
||||
@@ -100,6 +119,23 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error {
|
||||
return errors.New("cannot save nil head state")
|
||||
}
|
||||
|
||||
// A chain re-org occurred, so we fire an event notifying the rest of the services.
|
||||
if bytesutil.ToBytes32(newHeadBlock.Block.ParentRoot) != s.headRoot() {
|
||||
log.WithFields(logrus.Fields{
|
||||
"newSlot": fmt.Sprintf("%d", newHeadBlock.Block.Slot),
|
||||
"oldSlot": fmt.Sprintf("%d", s.headSlot()),
|
||||
}).Debug("Chain reorg occurred")
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.Reorg,
|
||||
Data: &statefeed.ReorgData{
|
||||
NewSlot: newHeadBlock.Block.Slot,
|
||||
OldSlot: s.headSlot(),
|
||||
},
|
||||
})
|
||||
|
||||
reorgCount.Inc()
|
||||
}
|
||||
|
||||
// Cache the new head info.
|
||||
s.setHead(headRoot, newHeadBlock, newHeadState)
|
||||
|
||||
@@ -122,7 +158,7 @@ func (s *Service) saveHeadNoDB(ctx context.Context, b *ethpb.SignedBeaconBlock,
|
||||
var headState *state.BeaconState
|
||||
var err error
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
headState, err = s.stateGen.StateByRoot(ctx, r)
|
||||
headState, err = s.stateGen.StateByRootInitialSync(ctx, r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve head state in DB")
|
||||
}
|
||||
@@ -144,7 +180,7 @@ func (s *Service) saveHeadNoDB(ctx context.Context, b *ethpb.SignedBeaconBlock,
|
||||
return errors.New("nil head state")
|
||||
}
|
||||
|
||||
s.setHead(r, stateTrie.CopySignedBeaconBlock(b), headState)
|
||||
s.setHeadInitialSync(r, stateTrie.CopySignedBeaconBlock(b), headState)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -163,6 +199,22 @@ func (s *Service) setHead(root [32]byte, block *ethpb.SignedBeaconBlock, state *
|
||||
}
|
||||
}
|
||||
|
||||
// This sets head view object which is used to track the head slot, root, block and state. The method
|
||||
// assumes that state being passed into the method will not be modified by any other alternate
|
||||
// caller which holds the state's reference.
|
||||
func (s *Service) setHeadInitialSync(root [32]byte, block *ethpb.SignedBeaconBlock, state *state.BeaconState) {
|
||||
s.headLock.Lock()
|
||||
defer s.headLock.Unlock()
|
||||
|
||||
// This does a full copy of the block only.
|
||||
s.head = &head{
|
||||
slot: block.Block.Slot,
|
||||
root: root,
|
||||
block: stateTrie.CopySignedBeaconBlock(block),
|
||||
state: state,
|
||||
}
|
||||
}
|
||||
|
||||
// This returns the head slot.
|
||||
func (s *Service) headSlot() uint64 {
|
||||
s.headLock.RLock()
|
||||
@@ -217,3 +269,72 @@ func (s *Service) hasHeadState() bool {
|
||||
|
||||
return s.head != nil && s.head.state != nil
|
||||
}
|
||||
|
||||
// This updates recent canonical block mapping. It uses input head root and retrieves
|
||||
// all the canonical block roots that are ancestor of the input head block root.
|
||||
func (s *Service) updateRecentCanonicalBlocks(ctx context.Context, headRoot [32]byte) error {
|
||||
s.recentCanonicalBlocksLock.Lock()
|
||||
defer s.recentCanonicalBlocksLock.Unlock()
|
||||
|
||||
s.recentCanonicalBlocks = make(map[[32]byte]bool)
|
||||
s.recentCanonicalBlocks[headRoot] = true
|
||||
nodes := s.forkChoiceStore.Nodes()
|
||||
node := s.forkChoiceStore.Node(headRoot)
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for node.Parent != protoarray.NonExistentNode {
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
node = nodes[node.Parent]
|
||||
s.recentCanonicalBlocks[node.Root] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// This caches justified state balances to be used for fork choice.
|
||||
func (s *Service) cacheJustifiedStateBalances(ctx context.Context, justifiedRoot [32]byte) error {
|
||||
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
return err
|
||||
}
|
||||
s.clearInitSyncBlocks()
|
||||
|
||||
var justifiedState *stateTrie.BeaconState
|
||||
var err error
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
justifiedState, err = s.stateGen.StateByRoot(ctx, justifiedRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
justifiedState, err = s.beaconDB.State(ctx, justifiedRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
epoch := helpers.CurrentEpoch(justifiedState)
|
||||
validators := justifiedState.Validators()
|
||||
justifiedBalances := make([]uint64, len(validators))
|
||||
for i, validator := range validators {
|
||||
if helpers.IsActiveValidator(validator, epoch) {
|
||||
justifiedBalances[i] = validator.EffectiveBalance
|
||||
} else {
|
||||
justifiedBalances[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
s.justifiedBalancesLock.Lock()
|
||||
defer s.justifiedBalancesLock.Unlock()
|
||||
s.justifiedBalances = justifiedBalances
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) getJustifiedBalances() []uint64 {
|
||||
s.justifiedBalancesLock.RLock()
|
||||
defer s.justifiedBalancesLock.RUnlock()
|
||||
return s.justifiedBalances
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@ import (
|
||||
"testing"
|
||||
|
||||
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/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
|
||||
func TestSaveHead_Same(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
service := setupBeaconChain(t, db)
|
||||
|
||||
r := [32]byte{'A'}
|
||||
@@ -36,7 +36,6 @@ func TestSaveHead_Same(t *testing.T) {
|
||||
|
||||
func TestSaveHead_Different(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
service := setupBeaconChain(t, db)
|
||||
|
||||
oldRoot := [32]byte{'A'}
|
||||
@@ -48,7 +47,7 @@ func TestSaveHead_Different(t *testing.T) {
|
||||
if err := service.beaconDB.SaveBlock(context.Background(), newHeadSignedBlock); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newRoot, err := ssz.HashTreeRoot(newHeadBlock)
|
||||
newRoot, err := stateutil.BlockRoot(newHeadBlock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -84,3 +83,136 @@ func TestSaveHead_Different(t *testing.T) {
|
||||
t.Error("Head did not change")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveHead_Different_Reorg(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
db := testDB.SetupDB(t)
|
||||
service := setupBeaconChain(t, db)
|
||||
|
||||
oldRoot := [32]byte{'A'}
|
||||
service.head = &head{slot: 0, root: oldRoot}
|
||||
|
||||
reorgChainParent := [32]byte{'B'}
|
||||
newHeadBlock := ðpb.BeaconBlock{
|
||||
Slot: 1,
|
||||
ParentRoot: reorgChainParent[:],
|
||||
}
|
||||
newHeadSignedBlock := ðpb.SignedBeaconBlock{Block: newHeadBlock}
|
||||
|
||||
if err := service.beaconDB.SaveBlock(context.Background(), newHeadSignedBlock); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newRoot, err := stateutil.BlockRoot(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)
|
||||
}
|
||||
|
||||
if service.HeadSlot() != 1 {
|
||||
t.Error("Head did not change")
|
||||
}
|
||||
|
||||
cachedRoot, err := service.HeadRoot(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(cachedRoot, newRoot[:]) {
|
||||
t.Error("Head did not change")
|
||||
}
|
||||
if !reflect.DeepEqual(service.headBlock(), newHeadSignedBlock) {
|
||||
t.Error("Head did not change")
|
||||
}
|
||||
if !reflect.DeepEqual(service.headState().CloneInnerState(), headState.CloneInnerState()) {
|
||||
t.Error("Head did not change")
|
||||
}
|
||||
testutil.AssertLogsContain(t, hook, "Chain reorg occurred")
|
||||
}
|
||||
|
||||
func TestUpdateRecentCanonicalBlocks_CanUpdateWithoutParent(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
service := setupBeaconChain(t, db)
|
||||
|
||||
r := [32]byte{'a'}
|
||||
if err := service.updateRecentCanonicalBlocks(context.Background(), r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
canonical, err := service.IsCanonical(context.Background(), r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !canonical {
|
||||
t.Error("Block should be canonical")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateRecentCanonicalBlocks_CanUpdateWithParent(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
service := setupBeaconChain(t, db)
|
||||
oldHead := [32]byte{'a'}
|
||||
if err := service.forkChoiceStore.ProcessBlock(context.Background(), 1, oldHead, [32]byte{'g'}, [32]byte{}, 0, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
currentHead := [32]byte{'b'}
|
||||
if err := service.forkChoiceStore.ProcessBlock(context.Background(), 3, currentHead, oldHead, [32]byte{}, 0, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
forkedRoot := [32]byte{'c'}
|
||||
if err := service.forkChoiceStore.ProcessBlock(context.Background(), 2, forkedRoot, oldHead, [32]byte{}, 0, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := service.updateRecentCanonicalBlocks(context.Background(), currentHead); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
canonical, err := service.IsCanonical(context.Background(), currentHead)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !canonical {
|
||||
t.Error("Block should be canonical")
|
||||
}
|
||||
canonical, err = service.IsCanonical(context.Background(), oldHead)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !canonical {
|
||||
t.Error("Block should be canonical")
|
||||
}
|
||||
canonical, err = service.IsCanonical(context.Background(), forkedRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if canonical {
|
||||
t.Error("Block should not be canonical")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheJustifiedStateBalances_CanCache(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
service := setupBeaconChain(t, db)
|
||||
|
||||
state, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
r := [32]byte{'a'}
|
||||
if err := service.beaconDB.SaveState(context.Background(), state, r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := service.cacheJustifiedStateBalances(context.Background(), r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(state.Balances(), service.getJustifiedBalances()) {
|
||||
t.Fatal("Incorrect justified balances")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -53,9 +54,10 @@ func (s *Service) TreeHandler(w http.ResponseWriter, _ *http.Request) {
|
||||
slot := strconv.Itoa(int(nodes[i].Slot))
|
||||
weight := strconv.Itoa(int(nodes[i].Weight / 1e9)) // Convert unit Gwei to unit ETH.
|
||||
votes := strconv.Itoa(int(nodes[i].Weight / 1e9 / avgBalance))
|
||||
bestDescendent := strconv.Itoa(int(nodes[i].BestDescendent))
|
||||
index := strconv.Itoa(int(i))
|
||||
label := "slot: " + slot + "\n index: " + index + "\n bestDescendent: " + bestDescendent + "\n votes: " + votes + "\n weight: " + weight
|
||||
index := strconv.Itoa(i)
|
||||
g := nodes[i].Graffiti[:]
|
||||
graffiti := hex.EncodeToString(g[:8])
|
||||
label := "slot: " + slot + "\n votes: " + votes + "\n weight: " + weight + "\n graffiti: " + graffiti
|
||||
var dotN dot.Node
|
||||
if nodes[i].Parent != ^uint64(0) {
|
||||
dotN = graph.Node(index).Box().Attr("label", label)
|
||||
|
||||
@@ -7,23 +7,22 @@ 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/core/state"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
messagediff "gopkg.in/d4l3k/messagediff.v1"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
func TestFilterBoundaryCandidates_FilterCorrect(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -87,7 +86,6 @@ func TestFilterBoundaryCandidates_FilterCorrect(t *testing.T) {
|
||||
func TestFilterBoundaryCandidates_HandleSkippedSlots(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -161,7 +159,6 @@ func TestFilterBoundaryCandidates_HandleSkippedSlots(t *testing.T) {
|
||||
func TestPruneOldStates_AlreadyFinalized(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -200,7 +197,6 @@ func TestPruneOldStates_AlreadyFinalized(t *testing.T) {
|
||||
func TestPruneNonBoundary_CanPrune(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -238,7 +234,6 @@ func TestPruneNonBoundary_CanPrune(t *testing.T) {
|
||||
|
||||
func TestGenerateState_CorrectlyGenerated(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
cfg := &Config{BeaconDB: db, StateGen: stategen.New(db, cache.NewStateSummaryCache())}
|
||||
service, err := NewService(context.Background(), cfg)
|
||||
if err != nil {
|
||||
@@ -246,8 +241,8 @@ func TestGenerateState_CorrectlyGenerated(t *testing.T) {
|
||||
}
|
||||
|
||||
beaconState, privs := testutil.DeterministicGenesisState(t, 32)
|
||||
genesisBlock := blocks.NewGenesisBlock([]byte{})
|
||||
bodyRoot, err := ssz.HashTreeRoot(genesisBlock.Block)
|
||||
genesisBlock := testutil.NewBeaconBlock()
|
||||
bodyRoot, err := stateutil.BlockRoot(genesisBlock.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -277,7 +272,7 @@ func TestGenerateState_CorrectlyGenerated(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
genRoot, err := ssz.HashTreeRoot(genesisBlock)
|
||||
genRoot, err := stateutil.BlockRoot(genesisBlock.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -302,7 +297,7 @@ func TestGenerateState_CorrectlyGenerated(t *testing.T) {
|
||||
}
|
||||
lastBlock = block
|
||||
}
|
||||
root, err := ssz.HashTreeRoot(lastBlock.Block)
|
||||
root, err := stateutil.BlockRoot(lastBlock.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -23,10 +27,7 @@ var (
|
||||
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",
|
||||
})
|
||||
|
||||
headFinalizedEpoch = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "head_finalized_epoch",
|
||||
Help: "Last finalized epoch of the head state",
|
||||
@@ -83,6 +84,24 @@ var (
|
||||
Name: "total_voted_target_balances",
|
||||
Help: "The total amount of ether, in gwei, that is eligible for voting of previous epoch",
|
||||
})
|
||||
reorgCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "beacon_reorg_total",
|
||||
Help: "Count the number of times beacon chain has a reorg",
|
||||
})
|
||||
sentBlockPropagationHistogram = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "block_sent_latency_milliseconds",
|
||||
Help: "Captures blocks broadcast time. Blocks sent in milliseconds distribution",
|
||||
Buckets: []float64{1000, 2000, 3000, 4000, 5000, 6000},
|
||||
},
|
||||
)
|
||||
attestationInclusionDelay = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "attestation_inclusion_delay_slots",
|
||||
Help: "The number of slots between att.Slot and block.Slot",
|
||||
Buckets: []float64{1, 2, 3, 4, 6, 32, 64},
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
// reportSlotMetrics reports slot related metrics.
|
||||
@@ -179,7 +198,25 @@ func reportEpochMetrics(state *stateTrie.BeaconState) {
|
||||
currentEth1DataDepositCount.Set(float64(state.Eth1Data().DepositCount))
|
||||
|
||||
if precompute.Balances != nil {
|
||||
totalEligibleBalances.Set(float64(precompute.Balances.PrevEpoch))
|
||||
totalVotedTargetBalances.Set(float64(precompute.Balances.PrevEpochTargetAttesters))
|
||||
totalEligibleBalances.Set(float64(precompute.Balances.ActivePrevEpoch))
|
||||
totalVotedTargetBalances.Set(float64(precompute.Balances.PrevEpochTargetAttested))
|
||||
}
|
||||
}
|
||||
|
||||
// This captures metrics for block sent time by subtracts slot start time.
|
||||
func captureSentTimeMetric(genesisTime uint64, currentSlot uint64) error {
|
||||
startTime, err := helpers.SlotToTime(genesisTime, currentSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
diffMs := roughtime.Now().Sub(startTime) / time.Millisecond
|
||||
sentBlockPropagationHistogram.Observe(float64(diffMs))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func reportAttestationInclusion(blk *ethpb.BeaconBlock) {
|
||||
for _, att := range blk.Body.Attestations {
|
||||
attestationInclusionDelay.Observe(float64(blk.Slot - att.Data.Slot))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,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/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -35,14 +36,12 @@ var ErrTargetRootNotInDB = errors.New("target root does not exist in db")
|
||||
// current_epoch = compute_epoch_at_slot(get_current_slot(store))
|
||||
// # Use GENESIS_EPOCH for previous when genesis to avoid underflow
|
||||
// previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else GENESIS_EPOCH
|
||||
// # If attestation target is from a future epoch, delay consideration until the epoch arrives
|
||||
// assert target.epoch in [current_epoch, previous_epoch]
|
||||
// assert target.epoch == compute_epoch_at_slot(attestation.data.slot)
|
||||
//
|
||||
// # Attestations target be for a known block. If target block is unknown, delay consideration until the block is found
|
||||
// assert target.root in store.blocks
|
||||
// # Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives
|
||||
// base_state = store.block_states[target.root].copy()
|
||||
// assert store.time >= base_state.genesis_time + compute_start_slot_at_epoch(target.epoch) * SECONDS_PER_SLOT
|
||||
//
|
||||
// # Attestations must be for a known block. If block is unknown, delay consideration until the block is found
|
||||
// assert attestation.data.beacon_block_root in store.blocks
|
||||
@@ -67,6 +66,7 @@ var ErrTargetRootNotInDB = errors.New("target root does not exist in db")
|
||||
// for i in indexed_attestation.attesting_indices:
|
||||
// if i not in store.latest_messages or target.epoch > store.latest_messages[i].epoch:
|
||||
// store.latest_messages[i] = LatestMessage(epoch=target.epoch, root=attestation.data.beacon_block_root)
|
||||
// TODO(#6072): This code path is highly untested. Requires comprehensive tests and simpler refactoring.
|
||||
func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]uint64, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockchain.onAttestation")
|
||||
defer span.End()
|
||||
@@ -82,7 +82,6 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
|
||||
}
|
||||
|
||||
tgt := stateTrie.CopyCheckpoint(a.Data.Target)
|
||||
tgtSlot := helpers.StartSlot(tgt.Epoch)
|
||||
|
||||
if helpers.SlotToEpoch(a.Data.Slot) != a.Data.Target.Epoch {
|
||||
return nil, fmt.Errorf("data slot is not in the same epoch as target %d != %d", helpers.SlotToEpoch(a.Data.Slot), a.Data.Target.Epoch)
|
||||
@@ -107,18 +106,18 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify Attestations cannot be from future epochs.
|
||||
if err := helpers.VerifySlotTime(genesisTime, tgtSlot, helpers.TimeShiftTolerance); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify attestation target slot")
|
||||
}
|
||||
|
||||
// Verify attestation beacon block is known and not from the future.
|
||||
if err := s.verifyBeaconBlock(ctx, a.Data); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify attestation beacon block")
|
||||
}
|
||||
|
||||
// Verify LMG GHOST and FFG votes are consistent with each other.
|
||||
if err := s.verifyLMDFFGConsistent(ctx, a.Data.Target.Epoch, a.Data.Target.Root, a.Data.BeaconBlockRoot); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify attestation beacon block")
|
||||
}
|
||||
|
||||
// Verify attestations can only affect the fork choice of subsequent slots.
|
||||
if err := helpers.VerifySlotTime(genesisTime, a.Data.Slot, helpers.TimeShiftTolerance); err != nil {
|
||||
if err := helpers.VerifySlotTime(genesisTime, a.Data.Slot+1, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -145,6 +145,20 @@ func (s *Service) verifyBeaconBlock(ctx context.Context, data *ethpb.Attestation
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifyLMDFFGConsistent verifies LMD GHOST and FFG votes are consistent with each other.
|
||||
func (s *Service) verifyLMDFFGConsistent(ctx context.Context, ffgEpoch uint64, ffgRoot []byte, lmdRoot []byte) error {
|
||||
ffgSlot := helpers.StartSlot(ffgEpoch)
|
||||
r, err := s.ancestor(ctx, lmdRoot, ffgSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(ffgRoot, r) {
|
||||
return errors.New("FFG and LMD votes are not consistent")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifyAttestation validates input attestation is valid.
|
||||
func (s *Service) verifyAttestation(ctx context.Context, baseState *stateTrie.BeaconState, a *ethpb.Attestation) (*ethpb.IndexedAttestation, error) {
|
||||
committee, err := helpers.BeaconCommitteeFromState(baseState, a.Data.Slot, a.Data.CommitteeIndex)
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"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"
|
||||
@@ -15,6 +14,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
func TestStore_OnAttestation(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
@@ -45,7 +44,7 @@ func TestStore_OnAttestation(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, BlkWithOutState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
BlkWithOutStateRoot, err := ssz.HashTreeRoot(BlkWithOutState.Block)
|
||||
BlkWithOutStateRoot, err := stateutil.BlockRoot(BlkWithOutState.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -54,7 +53,7 @@ func TestStore_OnAttestation(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, BlkWithStateBadAtt); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
BlkWithStateBadAttRoot, err := ssz.HashTreeRoot(BlkWithStateBadAtt.Block)
|
||||
BlkWithStateBadAttRoot, err := stateutil.BlockRoot(BlkWithStateBadAtt.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -72,7 +71,7 @@ func TestStore_OnAttestation(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
BlkWithValidStateRoot, err := ssz.HashTreeRoot(BlkWithValidState.Block)
|
||||
BlkWithValidStateRoot, err := stateutil.BlockRoot(BlkWithValidState.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -164,7 +163,6 @@ func TestStore_OnAttestation(t *testing.T) {
|
||||
func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
@@ -285,7 +283,6 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
func TestStore_UpdateCheckpointState(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
@@ -350,7 +347,6 @@ func TestStore_UpdateCheckpointState(t *testing.T) {
|
||||
func TestAttEpoch_MatchPrevEpoch(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -370,7 +366,6 @@ func TestAttEpoch_MatchPrevEpoch(t *testing.T) {
|
||||
func TestAttEpoch_MatchCurrentEpoch(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -390,7 +385,6 @@ func TestAttEpoch_MatchCurrentEpoch(t *testing.T) {
|
||||
func TestAttEpoch_NotMatch(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -411,7 +405,6 @@ func TestAttEpoch_NotMatch(t *testing.T) {
|
||||
func TestVerifyBeaconBlock_NoBlock(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -428,7 +421,6 @@ func TestVerifyBeaconBlock_NoBlock(t *testing.T) {
|
||||
func TestVerifyBeaconBlock_futureBlock(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -440,7 +432,7 @@ func TestVerifyBeaconBlock_futureBlock(t *testing.T) {
|
||||
if err := service.beaconDB.SaveBlock(ctx, b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, err := ssz.HashTreeRoot(b.Block)
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -455,7 +447,6 @@ func TestVerifyBeaconBlock_futureBlock(t *testing.T) {
|
||||
func TestVerifyBeaconBlock_OK(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -467,7 +458,7 @@ func TestVerifyBeaconBlock_OK(t *testing.T) {
|
||||
if err := service.beaconDB.SaveBlock(ctx, b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, err := ssz.HashTreeRoot(b.Block)
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -477,3 +468,68 @@ func TestVerifyBeaconBlock_OK(t *testing.T) {
|
||||
t.Error("Did not receive the wanted error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyLMDFFGConsistent_NotOK(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
b32 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 32}}
|
||||
if err := service.beaconDB.SaveBlock(ctx, b32); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r32, err := stateutil.BlockRoot(b32.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b33 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 33, ParentRoot: r32[:]}}
|
||||
if err := service.beaconDB.SaveBlock(ctx, b33); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r33, err := stateutil.BlockRoot(b33.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wanted := "FFG and LMD votes are not consistent"
|
||||
if err := service.verifyLMDFFGConsistent(context.Background(), 1, []byte{'a'}, r33[:]); err.Error() != wanted {
|
||||
t.Error("Did not get wanted error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyLMDFFGConsistent_OK(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
b32 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 32}}
|
||||
if err := service.beaconDB.SaveBlock(ctx, b32); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r32, err := stateutil.BlockRoot(b32.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b33 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 33, ParentRoot: r32[:]}}
|
||||
if err := service.beaconDB.SaveBlock(ctx, b33); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r33, err := stateutil.BlockRoot(b33.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := service.verifyLMDFFGConsistent(context.Background(), 1, r32[:], r33[:]); err != nil {
|
||||
t.Errorf("Could not verify LMD and FFG votes to be consistent: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/flags"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
@@ -24,6 +23,8 @@ import (
|
||||
var initialSyncBlockCacheSize = 2 * params.BeaconConfig().SlotsPerEpoch
|
||||
|
||||
// onBlock is called when a gossip block is received. It runs regular state transition on the block.
|
||||
// The block's signing root should be computed before calling this method to avoid redundant
|
||||
// computation in this method and methods it calls into.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def on_block(store: Store, block: BeaconBlock) -> None:
|
||||
@@ -54,7 +55,7 @@ var initialSyncBlockCacheSize = 2 * params.BeaconConfig().SlotsPerEpoch
|
||||
// # Update finalized checkpoint
|
||||
// if state.finalized_checkpoint.epoch > store.finalized_checkpoint.epoch:
|
||||
// store.finalized_checkpoint = state.finalized_checkpoint
|
||||
func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock) (*stateTrie.BeaconState, error) {
|
||||
func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock, blockRoot [32]byte) (*stateTrie.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockchain.onBlock")
|
||||
defer span.End()
|
||||
|
||||
@@ -70,13 +71,9 @@ func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
root, err := stateutil.BlockRoot(b)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get signing root of block %d", b.Slot)
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": b.Slot,
|
||||
"root": fmt.Sprintf("0x%s...", hex.EncodeToString(root[:])[:8]),
|
||||
"root": fmt.Sprintf("0x%s...", hex.EncodeToString(blockRoot[:])[:8]),
|
||||
}).Debug("Executing state transition on block")
|
||||
|
||||
postState, err := state.ExecuteStateTransition(ctx, preState, signed)
|
||||
@@ -88,16 +85,16 @@ func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock)
|
||||
return nil, errors.Wrapf(err, "could not save block from slot %d", b.Slot)
|
||||
}
|
||||
|
||||
if err := s.insertBlockToForkChoiceStore(ctx, b, root, postState); err != nil {
|
||||
if err := s.insertBlockToForkChoiceStore(ctx, b, blockRoot, postState); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not insert block %d to fork choice store", b.Slot)
|
||||
}
|
||||
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
if err := s.stateGen.SaveState(ctx, root, postState); err != nil {
|
||||
if err := s.stateGen.SaveState(ctx, blockRoot, postState); err != nil {
|
||||
return nil, errors.Wrap(err, "could not save state")
|
||||
}
|
||||
} else {
|
||||
if err := s.beaconDB.SaveState(ctx, postState, root); err != nil {
|
||||
if err := s.beaconDB.SaveState(ctx, postState, blockRoot); err != nil {
|
||||
return nil, errors.Wrap(err, "could not save state")
|
||||
}
|
||||
}
|
||||
@@ -185,13 +182,17 @@ func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock)
|
||||
s.slashingPool.MarkIncludedAttesterSlashing(b.Body.AttesterSlashings[i])
|
||||
}
|
||||
|
||||
defer reportAttestationInclusion(b)
|
||||
|
||||
return postState, nil
|
||||
}
|
||||
|
||||
// onBlockInitialSyncStateTransition is called when an initial sync block is received.
|
||||
// It runs state transition on the block and without any BLS verification. The excluded BLS verification
|
||||
// includes attestation's aggregated signature. It also does not save attestations.
|
||||
func (s *Service) onBlockInitialSyncStateTransition(ctx context.Context, signed *ethpb.SignedBeaconBlock) error {
|
||||
// The block's signing root should be computed before calling this method to avoid redundant
|
||||
// computation in this method and methods it calls into.
|
||||
func (s *Service) onBlockInitialSyncStateTransition(ctx context.Context, signed *ethpb.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockchain.onBlock")
|
||||
defer span.End()
|
||||
|
||||
@@ -206,42 +207,45 @@ func (s *Service) onBlockInitialSyncStateTransition(ctx context.Context, signed
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// To invalidate cache for parent root because pre state will get mutated.
|
||||
s.stateGen.DeleteHotStateInCache(bytesutil.ToBytes32(b.ParentRoot))
|
||||
|
||||
// Exit early if the pre state slot is higher than incoming block's slot.
|
||||
if preState.Slot() >= signed.Block.Slot {
|
||||
return nil
|
||||
}
|
||||
|
||||
postState, err := state.ExecuteStateTransitionNoVerifyAttSigs(ctx, preState, signed)
|
||||
var postState *stateTrie.BeaconState
|
||||
if featureconfig.Get().InitSyncNoVerify {
|
||||
postState, err = state.ExecuteStateTransitionNoVerifyAttSigs(ctx, preState, signed)
|
||||
} else {
|
||||
postState, err = state.ExecuteStateTransition(ctx, preState, signed)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not execute state transition")
|
||||
}
|
||||
|
||||
root, err := stateutil.BlockRoot(b)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get signing root of block %d", b.Slot)
|
||||
}
|
||||
if !featureconfig.Get().NoInitSyncBatchSaveBlocks {
|
||||
s.saveInitSyncBlock(root, signed)
|
||||
s.saveInitSyncBlock(blockRoot, signed)
|
||||
} else {
|
||||
if err := s.beaconDB.SaveBlock(ctx, signed); err != nil {
|
||||
return errors.Wrapf(err, "could not save block from slot %d", b.Slot)
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.insertBlockToForkChoiceStore(ctx, b, root, postState); err != nil {
|
||||
if err := s.insertBlockToForkChoiceStore(ctx, b, blockRoot, postState); err != nil {
|
||||
return errors.Wrapf(err, "could not insert block %d to fork choice store", b.Slot)
|
||||
}
|
||||
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
if err := s.stateGen.SaveState(ctx, root, postState); err != nil {
|
||||
if err := s.stateGen.SaveState(ctx, blockRoot, postState); err != nil {
|
||||
return errors.Wrap(err, "could not save state")
|
||||
}
|
||||
} else {
|
||||
s.initSyncStateLock.Lock()
|
||||
defer s.initSyncStateLock.Unlock()
|
||||
s.initSyncState[root] = postState.Copy()
|
||||
s.filterBoundaryCandidates(ctx, root, postState)
|
||||
s.initSyncState[blockRoot] = postState.Copy()
|
||||
s.filterBoundaryCandidates(ctx, blockRoot, postState)
|
||||
}
|
||||
|
||||
if flags.Get().EnableArchive {
|
||||
@@ -251,13 +255,6 @@ func (s *Service) onBlockInitialSyncStateTransition(ctx context.Context, signed
|
||||
}
|
||||
}
|
||||
|
||||
// Update justified check point.
|
||||
if postState.CurrentJustifiedCheckpoint().Epoch > s.justifiedCheckpt.Epoch {
|
||||
if err := s.updateJustified(ctx, postState); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Rate limit how many blocks (2 epochs worth of blocks) a node keeps in the memory.
|
||||
if len(s.getInitSyncBlocks()) > int(initialSyncBlockCacheSize) {
|
||||
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
@@ -297,10 +294,6 @@ func (s *Service) onBlockInitialSyncStateTransition(ctx context.Context, signed
|
||||
s.prevFinalizedCheckpt = s.finalizedCheckpt
|
||||
s.finalizedCheckpt = postState.FinalizedCheckpoint()
|
||||
|
||||
if err := s.finalizedImpliesNewJustified(ctx, postState); err != nil {
|
||||
return errors.Wrap(err, "could not save new justified")
|
||||
}
|
||||
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
fRoot := bytesutil.ToBytes32(postState.FinalizedCheckpoint().Root)
|
||||
fBlock, err := s.beaconDB.Block(ctx, fRoot)
|
||||
@@ -339,7 +332,7 @@ func (s *Service) onBlockInitialSyncStateTransition(ctx context.Context, signed
|
||||
}
|
||||
|
||||
if !featureconfig.Get().NewStateMgmt && helpers.IsEpochStart(postState.Slot()) {
|
||||
if err := s.beaconDB.SaveState(ctx, postState, root); err != nil {
|
||||
if err := s.beaconDB.SaveState(ctx, postState, blockRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save state")
|
||||
}
|
||||
}
|
||||
@@ -357,7 +350,7 @@ func (s *Service) insertBlockToForkChoiceStore(ctx context.Context, blk *ethpb.B
|
||||
|
||||
// Feed in block to fork choice store.
|
||||
if err := s.forkChoiceStore.ProcessBlock(ctx,
|
||||
blk.Slot, root, bytesutil.ToBytes32(blk.ParentRoot),
|
||||
blk.Slot, root, bytesutil.ToBytes32(blk.ParentRoot), bytesutil.ToBytes32(blk.Body.Graffiti),
|
||||
state.CurrentJustifiedCheckpoint().Epoch,
|
||||
state.FinalizedCheckpointEpoch()); err != nil {
|
||||
return errors.Wrap(err, "could not process block for proto array fork choice")
|
||||
|
||||
@@ -7,10 +7,11 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -42,8 +43,20 @@ func (s *Service) getBlockPreState(ctx context.Context, b *ethpb.BeaconBlock) (*
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// For new state management, this ensures the state does not get mutated since initial syncing
|
||||
// uses verifyBlkPreState.
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
preState, err = s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(b.ParentRoot))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for slot %d", b.Slot)
|
||||
}
|
||||
if preState == nil {
|
||||
return nil, errors.Wrapf(err, "nil pre state for slot %d", b.Slot)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify block slot time is not from the feature.
|
||||
if err := helpers.VerifySlotTime(preState.GenesisTime(), b.Slot, helpers.TimeShiftTolerance); err != nil {
|
||||
if err := helpers.VerifySlotTime(preState.GenesisTime(), b.Slot, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -79,13 +92,14 @@ func (s *Service) verifyBlkPreState(ctx context.Context, b *ethpb.BeaconBlock) (
|
||||
}
|
||||
s.clearInitSyncBlocks()
|
||||
}
|
||||
preState, err := s.stateGen.StateByRoot(ctx, parentRoot)
|
||||
preState, err := s.stateGen.StateByRootInitialSync(ctx, parentRoot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for slot %d", b.Slot)
|
||||
}
|
||||
if preState == nil {
|
||||
return nil, errors.Wrapf(err, "nil pre state for slot %d", b.Slot)
|
||||
}
|
||||
|
||||
return preState, nil // No copy needed from newly hydrated state gen object.
|
||||
}
|
||||
|
||||
@@ -225,7 +239,7 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified
|
||||
return true, nil
|
||||
}
|
||||
var newJustifiedBlockSigned *ethpb.SignedBeaconBlock
|
||||
justifiedRoot := bytesutil.ToBytes32(newJustifiedCheckpt.Root)
|
||||
justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(newJustifiedCheckpt.Root))
|
||||
var err error
|
||||
if !featureconfig.Get().NoInitSyncBatchSaveBlocks && s.hasInitSyncBlock(justifiedRoot) {
|
||||
newJustifiedBlockSigned = s.getInitSyncBlock(justifiedRoot)
|
||||
@@ -244,7 +258,7 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified
|
||||
return false, nil
|
||||
}
|
||||
var justifiedBlockSigned *ethpb.SignedBeaconBlock
|
||||
cachedJustifiedRoot := bytesutil.ToBytes32(s.justifiedCheckpt.Root)
|
||||
cachedJustifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root))
|
||||
if !featureconfig.Get().NoInitSyncBatchSaveBlocks && s.hasInitSyncBlock(cachedJustifiedRoot) {
|
||||
justifiedBlockSigned = s.getInitSyncBlock(cachedJustifiedRoot)
|
||||
} else {
|
||||
@@ -258,7 +272,7 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified
|
||||
return false, errors.New("nil justified block")
|
||||
}
|
||||
justifiedBlock := justifiedBlockSigned.Block
|
||||
b, err := s.ancestor(ctx, newJustifiedCheckpt.Root, justifiedBlock.Slot)
|
||||
b, err := s.ancestor(ctx, justifiedRoot[:], justifiedBlock.Slot)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -281,11 +295,13 @@ func (s *Service) updateJustified(ctx context.Context, state *stateTrie.BeaconSt
|
||||
if canUpdate {
|
||||
s.prevJustifiedCheckpt = s.justifiedCheckpt
|
||||
s.justifiedCheckpt = cpt
|
||||
if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !featureconfig.Get().NewStateMgmt {
|
||||
justifiedRoot := bytesutil.ToBytes32(cpt.Root)
|
||||
|
||||
justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(cpt.Root))
|
||||
justifiedState := s.initSyncState[justifiedRoot]
|
||||
// If justified state is nil, resume back to normal syncing process and save
|
||||
// justified check point.
|
||||
@@ -348,7 +364,7 @@ func (s *Service) filterBlockRoots(ctx context.Context, roots [][32]byte) ([][32
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hRoot, err := ssz.HashTreeRoot(h.Block)
|
||||
hRoot, err := stateutil.BlockRoot(h.Block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -367,14 +383,15 @@ func (s *Service) filterBlockRoots(ctx context.Context, roots [][32]byte) ([][32
|
||||
// ancestor returns the block root of an ancestry block from the input block root.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_ancestor(store: Store, root: Hash, slot: Slot) -> Hash:
|
||||
// def get_ancestor(store: Store, root: Root, slot: Slot) -> Root:
|
||||
// block = store.blocks[root]
|
||||
// if block.slot > slot:
|
||||
// return get_ancestor(store, block.parent_root, slot)
|
||||
// return get_ancestor(store, block.parent_root, slot)
|
||||
// elif block.slot == slot:
|
||||
// return root
|
||||
// return root
|
||||
// else:
|
||||
// return Bytes32() # root is older than queried slot: no results.
|
||||
// # root is older than queried slot, thus a skip slot. Return most recent root prior to slot
|
||||
// return root
|
||||
func (s *Service) ancestor(ctx context.Context, root []byte, slot uint64) ([]byte, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "forkchoice.ancestor")
|
||||
defer span.End()
|
||||
@@ -398,13 +415,7 @@ func (s *Service) ancestor(ctx context.Context, root []byte, slot uint64) ([]byt
|
||||
}
|
||||
b := signed.Block
|
||||
|
||||
// If we dont have the ancestor in the DB, simply return nil so rest of fork choice
|
||||
// operation can proceed. This is not an error condition.
|
||||
if b == nil || b.Slot < slot {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if b.Slot == slot {
|
||||
if b.Slot == slot || b.Slot < slot {
|
||||
return root, nil
|
||||
}
|
||||
|
||||
@@ -415,28 +426,42 @@ func (s *Service) ancestor(ctx context.Context, root []byte, slot uint64) ([]byt
|
||||
// the store's justified is not in chain with finalized check point.
|
||||
//
|
||||
// Spec definition:
|
||||
// if (
|
||||
// state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch
|
||||
// or get_ancestor(store, store.justified_checkpoint.root, finalized_slot) != store.finalized_checkpoint.root
|
||||
// ):
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
// # Potentially update justified if different from store
|
||||
// if store.justified_checkpoint != state.current_justified_checkpoint:
|
||||
// # Update justified if new justified is later than store justified
|
||||
// if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
// return
|
||||
// # Update justified if store justified is not in chain with finalized checkpoint
|
||||
// finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
// ancestor_at_finalized_slot = get_ancestor(store, store.justified_checkpoint.root, finalized_slot)
|
||||
// if ancestor_at_finalized_slot != store.finalized_checkpoint.root:
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
func (s *Service) finalizedImpliesNewJustified(ctx context.Context, state *stateTrie.BeaconState) error {
|
||||
finalizedBlkSigned, err := s.beaconDB.Block(ctx, bytesutil.ToBytes32(s.finalizedCheckpt.Root))
|
||||
if err != nil || finalizedBlkSigned == nil || finalizedBlkSigned.Block == nil {
|
||||
return errors.Wrap(err, "could not get finalized block")
|
||||
}
|
||||
finalizedBlk := finalizedBlkSigned.Block
|
||||
// Update justified if it's different than the one cached in the store.
|
||||
if !attestationutil.CheckPointIsEqual(s.justifiedCheckpt, state.CurrentJustifiedCheckpoint()) {
|
||||
if state.CurrentJustifiedCheckpoint().Epoch > s.justifiedCheckpt.Epoch {
|
||||
s.justifiedCheckpt = state.CurrentJustifiedCheckpoint()
|
||||
if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
anc, err := s.ancestor(ctx, s.justifiedCheckpt.Root, finalizedBlk.Slot)
|
||||
if err != nil {
|
||||
return err
|
||||
// Update justified if store justified is not in chain with finalized check point.
|
||||
finalizedSlot := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root))
|
||||
anc, err := s.ancestor(ctx, justifiedRoot[:], finalizedSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(anc, s.finalizedCheckpt.Root) {
|
||||
s.justifiedCheckpt = state.CurrentJustifiedCheckpoint()
|
||||
if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Either the new justified is later than stored justified or not in chain with finalized check pint.
|
||||
if cpt := state.CurrentJustifiedCheckpoint(); cpt != nil && cpt.Epoch > s.justifiedCheckpt.Epoch || !bytes.Equal(anc, s.finalizedCheckpt.Root) {
|
||||
s.justifiedCheckpt = state.CurrentJustifiedCheckpoint()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -466,13 +491,13 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk *ethpb.
|
||||
// Lower slots should be at the end of the list.
|
||||
for i := len(pendingNodes) - 1; i >= 0; i-- {
|
||||
b := pendingNodes[i]
|
||||
r, err := ssz.HashTreeRoot(b)
|
||||
r, err := stateutil.BlockRoot(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.forkChoiceStore.ProcessBlock(ctx,
|
||||
b.Slot, r, bytesutil.ToBytes32(b.ParentRoot),
|
||||
b.Slot, r, bytesutil.ToBytes32(b.ParentRoot), bytesutil.ToBytes32(b.Body.Graffiti),
|
||||
state.CurrentJustifiedCheckpoint().Epoch,
|
||||
state.FinalizedCheckpointEpoch()); err != nil {
|
||||
return errors.Wrap(err, "could not process block for proto array fork choice")
|
||||
@@ -498,3 +523,12 @@ func (s *Service) deletePoolAtts(atts []*ethpb.Attestation) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// This ensures that the input root defaults to using genesis root instead of zero hashes. This is needed for handling
|
||||
// fork choice justification routine.
|
||||
func (s *Service) ensureRootNotZeros(root [32]byte) [32]byte {
|
||||
if root == params.BeaconConfig().ZeroHash {
|
||||
return s.genesisRoot
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
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/params"
|
||||
@@ -28,7 +30,6 @@ import (
|
||||
func TestStore_OnBlock(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
@@ -44,7 +45,7 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, genesis); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
validGenesisRoot, err := ssz.HashTreeRoot(genesis.Block)
|
||||
validGenesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -60,7 +61,7 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, random); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
randomParentRoot, err := ssz.HashTreeRoot(random.Block)
|
||||
randomParentRoot, err := stateutil.BlockRoot(random.Block)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -92,10 +93,10 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
wantErrString: "provided block root does not have block saved in the db",
|
||||
},
|
||||
{
|
||||
name: "block is from the feature",
|
||||
name: "block is from the future",
|
||||
blk: ðpb.BeaconBlock{ParentRoot: randomParentRoot[:], Slot: params.BeaconConfig().FarFutureEpoch},
|
||||
s: st.Copy(),
|
||||
wantErrString: "could not process slot from the future",
|
||||
wantErrString: "far distant future",
|
||||
},
|
||||
{
|
||||
name: "could not get finalized block",
|
||||
@@ -119,7 +120,11 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
service.prevFinalizedCheckpt = ðpb.Checkpoint{Root: validGenesisRoot[:]}
|
||||
service.finalizedCheckpt.Root = roots[0]
|
||||
|
||||
_, err := service.onBlock(ctx, ðpb.SignedBeaconBlock{Block: tt.blk})
|
||||
root, err := stateutil.BlockRoot(tt.blk)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = service.onBlock(ctx, ðpb.SignedBeaconBlock{Block: tt.blk}, root)
|
||||
if err == nil || !strings.Contains(err.Error(), tt.wantErrString) {
|
||||
t.Errorf("Store.OnBlock() error = %v, wantErr = %v", err, tt.wantErrString)
|
||||
}
|
||||
@@ -130,7 +135,6 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
func TestRemoveStateSinceLastFinalized(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
params.UseMinimalConfig()
|
||||
defer params.UseMainnetConfig()
|
||||
|
||||
@@ -150,7 +154,7 @@ func TestRemoveStateSinceLastFinalized(t *testing.T) {
|
||||
Slot: uint64(i),
|
||||
},
|
||||
}
|
||||
r, err := ssz.HashTreeRoot(totalBlocks[i].Block)
|
||||
r, err := stateutil.BlockRoot(totalBlocks[i].Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -210,7 +214,6 @@ func TestRemoveStateSinceLastFinalized(t *testing.T) {
|
||||
func TestRemoveStateSinceLastFinalized_EmptyStartSlot(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
params.UseMinimalConfig()
|
||||
defer params.UseMainnetConfig()
|
||||
|
||||
@@ -228,14 +231,16 @@ func TestRemoveStateSinceLastFinalized_EmptyStartSlot(t *testing.T) {
|
||||
if !update {
|
||||
t.Error("Should be able to update justified, received false")
|
||||
}
|
||||
|
||||
lastJustifiedBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{ParentRoot: []byte{'G'}}}
|
||||
lastJustifiedRoot, err := ssz.HashTreeRoot(lastJustifiedBlk.Block)
|
||||
lastJustifiedBlk := testutil.NewBeaconBlock()
|
||||
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
|
||||
lastJustifiedRoot, err := stateutil.BlockRoot(lastJustifiedBlk.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newJustifiedBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1, ParentRoot: lastJustifiedRoot[:]}}
|
||||
newJustifiedRoot, err := ssz.HashTreeRoot(newJustifiedBlk.Block)
|
||||
newJustifiedBlk := testutil.NewBeaconBlock()
|
||||
newJustifiedBlk.Block.Slot = 1
|
||||
newJustifiedBlk.Block.ParentRoot = bytesutil.PadTo(lastJustifiedRoot[:], 32)
|
||||
newJustifiedRoot, err := stateutil.BlockRoot(newJustifiedBlk.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -261,7 +266,6 @@ func TestRemoveStateSinceLastFinalized_EmptyStartSlot(t *testing.T) {
|
||||
func TestShouldUpdateJustified_ReturnFalse(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
params.UseMinimalConfig()
|
||||
defer params.UseMainnetConfig()
|
||||
|
||||
@@ -270,13 +274,15 @@ func TestShouldUpdateJustified_ReturnFalse(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
lastJustifiedBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{ParentRoot: []byte{'G'}}}
|
||||
lastJustifiedRoot, err := ssz.HashTreeRoot(lastJustifiedBlk.Block)
|
||||
lastJustifiedBlk := testutil.NewBeaconBlock()
|
||||
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
|
||||
lastJustifiedRoot, err := stateutil.BlockRoot(lastJustifiedBlk.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newJustifiedBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{ParentRoot: lastJustifiedRoot[:]}}
|
||||
newJustifiedRoot, err := ssz.HashTreeRoot(newJustifiedBlk.Block)
|
||||
newJustifiedBlk := testutil.NewBeaconBlock()
|
||||
newJustifiedBlk.Block.ParentRoot = bytesutil.PadTo(lastJustifiedRoot[:], 32)
|
||||
newJustifiedRoot, err := stateutil.BlockRoot(newJustifiedBlk.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -306,7 +312,6 @@ func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
@@ -342,7 +347,6 @@ func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
|
||||
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()
|
||||
|
||||
@@ -388,7 +392,6 @@ func TestCachedPreState_CanGetFromDB(t *testing.T) {
|
||||
func TestSaveInitState_CanSaveDelete(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -436,7 +439,6 @@ func TestSaveInitState_CanSaveDelete(t *testing.T) {
|
||||
func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -448,7 +450,7 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, signedBlock); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, err := ssz.HashTreeRoot(signedBlock.Block)
|
||||
r, err := stateutil.BlockRoot(signedBlock.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -487,7 +489,6 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
|
||||
func TestFilterBlockRoots_CanFilter(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -496,12 +497,12 @@ func TestFilterBlockRoots_CanFilter(t *testing.T) {
|
||||
}
|
||||
|
||||
fBlock := ðpb.BeaconBlock{}
|
||||
fRoot, err := ssz.HashTreeRoot(fBlock)
|
||||
fRoot, err := stateutil.BlockRoot(fBlock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hBlock := ðpb.BeaconBlock{Slot: 1}
|
||||
headRoot, err := ssz.HashTreeRoot(hBlock)
|
||||
headRoot, err := stateutil.BlockRoot(hBlock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -541,7 +542,6 @@ func TestFilterBlockRoots_CanFilter(t *testing.T) {
|
||||
func TestPersistCache_CanSave(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -583,7 +583,6 @@ func TestPersistCache_CanSave(t *testing.T) {
|
||||
func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -598,7 +597,7 @@ func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, genesis); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
validGenesisRoot, err := ssz.HashTreeRoot(genesis.Block)
|
||||
validGenesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -613,7 +612,7 @@ func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
|
||||
}
|
||||
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 32)
|
||||
block := ðpb.BeaconBlock{Slot: 9, ParentRoot: roots[8]}
|
||||
block := ðpb.BeaconBlock{Slot: 9, ParentRoot: roots[8], Body: ðpb.BeaconBlockBody{Graffiti: []byte{}}}
|
||||
if err := service.fillInForkChoiceMissingBlocks(context.Background(), block, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -637,7 +636,6 @@ func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
|
||||
func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
@@ -653,7 +651,7 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
|
||||
if err := db.SaveBlock(ctx, genesis); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
validGenesisRoot, err := ssz.HashTreeRoot(genesis.Block)
|
||||
validGenesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -664,23 +662,23 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
|
||||
}
|
||||
|
||||
// Define a tree branch, slot 63 <- 64 <- 65
|
||||
b63 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 63}}
|
||||
b63 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 63, Body: ðpb.BeaconBlockBody{}}}
|
||||
if err := service.beaconDB.SaveBlock(ctx, b63); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r63, err := ssz.HashTreeRoot(b63.Block)
|
||||
r63, err := stateutil.BlockRoot(b63.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b64 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 64, ParentRoot: r63[:]}}
|
||||
b64 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 64, ParentRoot: r63[:], Body: ðpb.BeaconBlockBody{}}}
|
||||
if err := service.beaconDB.SaveBlock(ctx, b64); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r64, err := ssz.HashTreeRoot(b64.Block)
|
||||
r64, err := stateutil.BlockRoot(b64.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b65 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 65, ParentRoot: r64[:]}}
|
||||
b65 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 65, ParentRoot: r64[:], Body: ðpb.BeaconBlockBody{}}}
|
||||
if err := service.beaconDB.SaveBlock(ctx, b65); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -750,10 +748,14 @@ func blockTree1(db db.Database, genesisRoot []byte) ([][]byte, error) {
|
||||
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 {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
|
||||
beaconBlock.Block.Body = ðpb.BeaconBlockBody{}
|
||||
if err := db.SaveBlock(context.Background(), beaconBlock); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(b.ParentRoot)); err != nil {
|
||||
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(beaconBlock.Block.ParentRoot)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -778,3 +780,159 @@ func TestCurrentSlot_HandlesOverflow(t *testing.T) {
|
||||
t.Fatalf("Expected slot to be 0, got %d", slot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAncestor_HandleSkipSlot(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: []byte{'a'}}
|
||||
r1, err := ssz.HashTreeRoot(b1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b100 := ðpb.BeaconBlock{Slot: 100, ParentRoot: r1[:]}
|
||||
r100, err := ssz.HashTreeRoot(b100)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b200 := ðpb.BeaconBlock{Slot: 200, ParentRoot: r100[:]}
|
||||
r200, err := ssz.HashTreeRoot(b200)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, b := range []*ethpb.BeaconBlock{b1, b100, b200} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
|
||||
beaconBlock.Block.Body = ðpb.BeaconBlockBody{}
|
||||
if err := db.SaveBlock(context.Background(), beaconBlock); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Slots 100 to 200 are skip slots. Requesting root at 150 will yield root at 100. The last physical block.
|
||||
r, err := service.ancestor(context.Background(), r200[:], 150)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytesutil.ToBytes32(r) != r100 {
|
||||
t.Error("Did not get correct root")
|
||||
}
|
||||
|
||||
// Slots 1 to 100 are skip slots. Requesting root at 50 will yield root at 1. The last physical block.
|
||||
r, err = service.ancestor(context.Background(), r200[:], 50)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytesutil.ToBytes32(r) != r1 {
|
||||
t.Error("Did not get correct root")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureRootNotZeroHashes(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cfg := &Config{}
|
||||
service, err := NewService(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service.genesisRoot = [32]byte{'a'}
|
||||
|
||||
r := service.ensureRootNotZeros(params.BeaconConfig().ZeroHash)
|
||||
if r != service.genesisRoot {
|
||||
t.Error("Did not get wanted justified root")
|
||||
}
|
||||
root := [32]byte{'b'}
|
||||
r = service.ensureRootNotZeros(root)
|
||||
if r != root {
|
||||
t.Error("Did not get wanted justified root")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFinalizedImpliesNewJustified(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
type args struct {
|
||||
cachedCheckPoint *ethpb.Checkpoint
|
||||
stateCheckPoint *ethpb.Checkpoint
|
||||
diffFinalizedCheckPoint bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *ethpb.Checkpoint
|
||||
}{
|
||||
{
|
||||
name: "Same justified, do nothing",
|
||||
args: args{
|
||||
cachedCheckPoint: ðpb.Checkpoint{Epoch: 1, Root: []byte{'a'}},
|
||||
stateCheckPoint: ðpb.Checkpoint{Epoch: 1, Root: []byte{'a'}},
|
||||
},
|
||||
want: ðpb.Checkpoint{Epoch: 1, Root: []byte{'a'}},
|
||||
},
|
||||
{
|
||||
name: "Different justified, higher epoch, cache new justified",
|
||||
args: args{
|
||||
cachedCheckPoint: ðpb.Checkpoint{Epoch: 1, Root: []byte{'a'}},
|
||||
stateCheckPoint: ðpb.Checkpoint{Epoch: 2, Root: []byte{'b'}},
|
||||
},
|
||||
want: ðpb.Checkpoint{Epoch: 2, Root: []byte{'b'}},
|
||||
},
|
||||
{
|
||||
name: "finalized has different justified, cache new justified",
|
||||
args: args{
|
||||
cachedCheckPoint: ðpb.Checkpoint{Epoch: 1, Root: []byte{'a'}},
|
||||
stateCheckPoint: ðpb.Checkpoint{Epoch: 1, Root: []byte{'b'}},
|
||||
diffFinalizedCheckPoint: true,
|
||||
},
|
||||
want: ðpb.Checkpoint{Epoch: 1, Root: []byte{'b'}},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
beaconState := testutil.NewBeaconState()
|
||||
if err := beaconState.SetCurrentJustifiedCheckpoint(test.args.stateCheckPoint); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service, err := NewService(ctx, &Config{BeaconDB: db})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service.justifiedCheckpt = test.args.cachedCheckPoint
|
||||
|
||||
if test.args.diffFinalizedCheckPoint {
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: []byte{'a'}}
|
||||
r1, err := ssz.HashTreeRoot(b1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b100 := ðpb.BeaconBlock{Slot: 100, ParentRoot: r1[:]}
|
||||
r100, err := ssz.HashTreeRoot(b100)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, b := range []*ethpb.BeaconBlock{b1, b100} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
|
||||
if err := service.beaconDB.SaveBlock(context.Background(), beaconBlock); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: []byte{'c'}, Epoch: 1}
|
||||
service.justifiedCheckpt.Root = r100[:]
|
||||
}
|
||||
|
||||
if err := service.finalizedImpliesNewJustified(ctx, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !attestationutil.CheckPointIsEqual(test.want, service.justifiedCheckpt) {
|
||||
t.Error("Did not get wanted check point")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -22,6 +23,7 @@ import (
|
||||
type AttestationReceiver interface {
|
||||
ReceiveAttestationNoPubsub(ctx context.Context, att *ethpb.Attestation) error
|
||||
IsValidAttestation(ctx context.Context, att *ethpb.Attestation) bool
|
||||
AttestationPreState(ctx context.Context, att *ethpb.Attestation) (*state.BeaconState, error)
|
||||
}
|
||||
|
||||
// ReceiveAttestationNoPubsub is a function that defines the operations that are preformed on
|
||||
@@ -39,15 +41,10 @@ func (s *Service) ReceiveAttestationNoPubsub(ctx context.Context, att *ethpb.Att
|
||||
}
|
||||
|
||||
if !featureconfig.Get().DisableUpdateHeadPerAttestation {
|
||||
baseState, err := s.getAttPreState(ctx, att.Data.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This updates fork choice head, if a new head could not be updated due to
|
||||
// long range or intermediate forking. It simply logs a warning and returns nil
|
||||
// as that's more appropriate than returning errors.
|
||||
if err := s.updateHead(ctx, baseState.Balances()); err != nil {
|
||||
if err := s.updateHead(ctx, s.getJustifiedBalances()); err != nil {
|
||||
log.Warnf("Resolving fork due to new attestation: %v", err)
|
||||
return nil
|
||||
}
|
||||
@@ -58,7 +55,7 @@ func (s *Service) ReceiveAttestationNoPubsub(ctx context.Context, att *ethpb.Att
|
||||
|
||||
// IsValidAttestation returns true if the attestation can be verified against its pre-state.
|
||||
func (s *Service) IsValidAttestation(ctx context.Context, att *ethpb.Attestation) bool {
|
||||
baseState, err := s.getAttPreState(ctx, att.Data.Target)
|
||||
baseState, err := s.AttestationPreState(ctx, att)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get attestation pre state")
|
||||
return false
|
||||
@@ -72,6 +69,11 @@ func (s *Service) IsValidAttestation(ctx context.Context, att *ethpb.Attestation
|
||||
return true
|
||||
}
|
||||
|
||||
// AttestationPreState returns the pre state of attestation.
|
||||
func (s *Service) AttestationPreState(ctx context.Context, att *ethpb.Attestation) (*state.BeaconState, error) {
|
||||
return s.getAttPreState(ctx, att.Data.Target)
|
||||
}
|
||||
|
||||
// This processes attestations from the attestation pool to account for validator votes and fork choice.
|
||||
func (s *Service) processAttestation(subscribedToStateEvents chan struct{}) {
|
||||
// Wait for state to be initialized.
|
||||
@@ -90,6 +92,14 @@ func (s *Service) processAttestation(subscribedToStateEvents chan struct{}) {
|
||||
ctx := context.Background()
|
||||
atts := s.attPool.ForkchoiceAttestations()
|
||||
for _, a := range atts {
|
||||
// Based on the spec, don't process the attestation until the subsequent slot.
|
||||
// This delays consideration in the fork choice until their slot is in the past.
|
||||
// https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/fork-choice.md#validate_on_attestation
|
||||
nextSlot := a.Data.Slot + 1
|
||||
if err := helpers.VerifySlotTime(uint64(s.genesisTime.Unix()), nextSlot, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var hasState bool
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
hasState = s.stateGen.StateSummaryExists(ctx, bytesutil.ToBytes32(a.Data.BeaconBlockRoot))
|
||||
|
||||
@@ -5,12 +5,13 @@ import (
|
||||
"time"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
)
|
||||
|
||||
func TestVerifyCheckpointEpoch_Ok(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
chainService := setupBeaconChain(t, db)
|
||||
chainService.genesisTime = time.Now()
|
||||
|
||||
@@ -7,13 +7,11 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/traceutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -22,10 +20,9 @@ import (
|
||||
|
||||
// BlockReceiver interface defines the methods of chain service receive and processing new blocks.
|
||||
type BlockReceiver interface {
|
||||
ReceiveBlock(ctx context.Context, block *ethpb.SignedBeaconBlock) error
|
||||
ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedBeaconBlock) error
|
||||
ReceiveBlockNoPubsubForkchoice(ctx context.Context, block *ethpb.SignedBeaconBlock) error
|
||||
ReceiveBlockNoVerify(ctx context.Context, block *ethpb.SignedBeaconBlock) error
|
||||
ReceiveBlock(ctx context.Context, block *ethpb.SignedBeaconBlock, blockRoot [32]byte) error
|
||||
ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedBeaconBlock, blockRoot [32]byte) error
|
||||
ReceiveBlockInitialSync(ctx context.Context, block *ethpb.SignedBeaconBlock, blockRoot [32]byte) error
|
||||
HasInitSyncBlock(root [32]byte) bool
|
||||
}
|
||||
|
||||
@@ -35,24 +32,24 @@ type BlockReceiver interface {
|
||||
// 2. Validate block, apply state transition and update check points
|
||||
// 3. Apply fork choice to the processed block
|
||||
// 4. Save latest head info
|
||||
func (s *Service) ReceiveBlock(ctx context.Context, block *ethpb.SignedBeaconBlock) error {
|
||||
func (s *Service) ReceiveBlock(ctx context.Context, block *ethpb.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.blockchain.ReceiveBlock")
|
||||
defer span.End()
|
||||
|
||||
root, err := ssz.HashTreeRoot(block.Block)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root on received block")
|
||||
}
|
||||
|
||||
// Broadcast the new block to the network.
|
||||
if err := s.p2p.Broadcast(ctx, block); err != nil {
|
||||
return errors.Wrap(err, "could not broadcast block")
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"blockRoot": hex.EncodeToString(root[:]),
|
||||
"blockRoot": hex.EncodeToString(blockRoot[:]),
|
||||
}).Debug("Broadcasting block")
|
||||
|
||||
if err := s.ReceiveBlockNoPubsub(ctx, block); err != nil {
|
||||
if err := captureSentTimeMetric(uint64(s.genesisTime.Unix()), block.Block.Slot); err != nil {
|
||||
// If a node fails to capture metric, this shouldn't cause the block processing to fail.
|
||||
log.Warnf("Could not capture block sent time metric: %v", err)
|
||||
}
|
||||
|
||||
if err := s.ReceiveBlockNoPubsub(ctx, block, blockRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -64,13 +61,13 @@ func (s *Service) ReceiveBlock(ctx context.Context, block *ethpb.SignedBeaconBlo
|
||||
// 1. Validate block, apply state transition and update check points
|
||||
// 2. Apply fork choice to the processed block
|
||||
// 3. Save latest head info
|
||||
func (s *Service) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedBeaconBlock) error {
|
||||
func (s *Service) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.blockchain.ReceiveBlockNoPubsub")
|
||||
defer span.End()
|
||||
blockCopy := stateTrie.CopySignedBeaconBlock(block)
|
||||
|
||||
// Apply state transition on the new block.
|
||||
postState, err := s.onBlock(ctx, blockCopy)
|
||||
_, err := s.onBlock(ctx, blockCopy, blockRoot)
|
||||
if err != nil {
|
||||
err := errors.Wrap(err, "could not process block")
|
||||
traceutil.AnnotateError(span, err)
|
||||
@@ -90,17 +87,12 @@ func (s *Service) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedB
|
||||
defer s.epochParticipationLock.Unlock()
|
||||
s.epochParticipation[helpers.SlotToEpoch(blockCopy.Block.Slot)] = precompute.Balances
|
||||
|
||||
root, err := stateutil.BlockRoot(blockCopy.Block)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root on received block")
|
||||
}
|
||||
|
||||
if featureconfig.Get().DisableForkChoice && block.Block.Slot > s.headSlot() {
|
||||
if err := s.saveHead(ctx, root); err != nil {
|
||||
if err := s.saveHead(ctx, blockRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save head")
|
||||
}
|
||||
} else {
|
||||
if err := s.updateHead(ctx, postState.Balances()); err != nil {
|
||||
if err := s.updateHead(ctx, s.getJustifiedBalances()); err != nil {
|
||||
return errors.Wrap(err, "could not save head")
|
||||
}
|
||||
}
|
||||
@@ -110,7 +102,7 @@ func (s *Service) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedB
|
||||
Type: statefeed.BlockProcessed,
|
||||
Data: &statefeed.BlockProcessedData{
|
||||
Slot: blockCopy.Block.Slot,
|
||||
BlockRoot: root,
|
||||
BlockRoot: blockRoot,
|
||||
Verified: true,
|
||||
},
|
||||
})
|
||||
@@ -119,7 +111,7 @@ func (s *Service) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedB
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
|
||||
// Log block sync status.
|
||||
logBlockSyncStatus(blockCopy.Block, root, s.finalizedCheckpt)
|
||||
logBlockSyncStatus(blockCopy.Block, blockRoot, s.finalizedCheckpt)
|
||||
|
||||
// Log state transition data.
|
||||
logStateTransitionData(blockCopy.Block)
|
||||
@@ -127,90 +119,27 @@ func (s *Service) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedB
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReceiveBlockNoPubsubForkchoice is a function that defines the all operations (minus pubsub and forkchoice)
|
||||
// that are preformed blocks that is received from initial sync service. The operations consists of:
|
||||
// 1. Validate block, apply state transition and update check points
|
||||
// 2. Save latest head info
|
||||
func (s *Service) ReceiveBlockNoPubsubForkchoice(ctx context.Context, block *ethpb.SignedBeaconBlock) error {
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.blockchain.ReceiveBlockNoForkchoice")
|
||||
defer span.End()
|
||||
blockCopy := stateTrie.CopySignedBeaconBlock(block)
|
||||
|
||||
// Apply state transition on the new block.
|
||||
_, err := s.onBlock(ctx, blockCopy)
|
||||
if err != nil {
|
||||
err := errors.Wrap(err, "could not process block")
|
||||
traceutil.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
|
||||
root, err := stateutil.BlockRoot(blockCopy.Block)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root on received block")
|
||||
}
|
||||
cachedHeadRoot, err := s.HeadRoot(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get head root from cache")
|
||||
}
|
||||
if !bytes.Equal(root[:], cachedHeadRoot) {
|
||||
if err := s.saveHead(ctx, root); err != nil {
|
||||
return errors.Wrap(err, "could not save head")
|
||||
}
|
||||
}
|
||||
|
||||
// Send notification of the processed block to the state feed.
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.BlockProcessed,
|
||||
Data: &statefeed.BlockProcessedData{
|
||||
Slot: blockCopy.Block.Slot,
|
||||
BlockRoot: root,
|
||||
Verified: true,
|
||||
},
|
||||
})
|
||||
|
||||
// Reports on block and fork choice metrics.
|
||||
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)
|
||||
|
||||
s.epochParticipationLock.Lock()
|
||||
defer s.epochParticipationLock.Unlock()
|
||||
s.epochParticipation[helpers.SlotToEpoch(blockCopy.Block.Slot)] = precompute.Balances
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReceiveBlockNoVerify runs state transition on a input block without verifying the block's BLS contents.
|
||||
// Depends on the security model, this is the "minimal" work a node can do to sync the chain.
|
||||
// It simulates light client behavior and assumes 100% trust with the syncing peer.
|
||||
func (s *Service) ReceiveBlockNoVerify(ctx context.Context, block *ethpb.SignedBeaconBlock) error {
|
||||
// ReceiveBlockInitialSync processes the input block for the purpose of initial syncing.
|
||||
// This method should only be used on blocks during initial syncing phase.
|
||||
func (s *Service) ReceiveBlockInitialSync(ctx context.Context, block *ethpb.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.blockchain.ReceiveBlockNoVerify")
|
||||
defer span.End()
|
||||
blockCopy := stateTrie.CopySignedBeaconBlock(block)
|
||||
|
||||
// Apply state transition on the incoming newly received blockCopy without verifying its BLS contents.
|
||||
if err := s.onBlockInitialSyncStateTransition(ctx, blockCopy); err != nil {
|
||||
if err := s.onBlockInitialSyncStateTransition(ctx, blockCopy, blockRoot); err != nil {
|
||||
err := errors.Wrap(err, "could not process block")
|
||||
traceutil.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
|
||||
root, err := stateutil.BlockRoot(blockCopy.Block)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root on received blockCopy")
|
||||
}
|
||||
|
||||
cachedHeadRoot, err := s.HeadRoot(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get head root from cache")
|
||||
}
|
||||
|
||||
if !bytes.Equal(root[:], cachedHeadRoot) {
|
||||
if err := s.saveHeadNoDB(ctx, blockCopy, root); err != nil {
|
||||
if !bytes.Equal(blockRoot[:], cachedHeadRoot) {
|
||||
if err := s.saveHeadNoDB(ctx, blockCopy, blockRoot); err != nil {
|
||||
err := errors.Wrap(err, "could not save head")
|
||||
traceutil.AnnotateError(span, err)
|
||||
return err
|
||||
@@ -222,7 +151,7 @@ func (s *Service) ReceiveBlockNoVerify(ctx context.Context, block *ethpb.SignedB
|
||||
Type: statefeed.BlockProcessed,
|
||||
Data: &statefeed.BlockProcessedData{
|
||||
Slot: blockCopy.Block.Slot,
|
||||
BlockRoot: root,
|
||||
BlockRoot: blockRoot,
|
||||
Verified: false,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
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/cache/depositcache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
@@ -33,50 +32,56 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
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/slotutil"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// Service represents a service that handles the internal
|
||||
// logic of managing the full PoS beacon chain.
|
||||
type Service struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
beaconDB db.HeadAccessDatabase
|
||||
depositCache *depositcache.DepositCache
|
||||
chainStartFetcher powchain.ChainStartFetcher
|
||||
attPool attestations.Pool
|
||||
slashingPool *slashings.Pool
|
||||
exitPool *voluntaryexits.Pool
|
||||
genesisTime time.Time
|
||||
p2p p2p.Broadcaster
|
||||
maxRoutines int64
|
||||
head *head
|
||||
headLock sync.RWMutex
|
||||
stateNotifier statefeed.Notifier
|
||||
genesisRoot [32]byte
|
||||
epochParticipation map[uint64]*precompute.Balance
|
||||
epochParticipationLock sync.RWMutex
|
||||
forkChoiceStore f.ForkChoicer
|
||||
justifiedCheckpt *ethpb.Checkpoint
|
||||
prevJustifiedCheckpt *ethpb.Checkpoint
|
||||
bestJustifiedCheckpt *ethpb.Checkpoint
|
||||
finalizedCheckpt *ethpb.Checkpoint
|
||||
prevFinalizedCheckpt *ethpb.Checkpoint
|
||||
nextEpochBoundarySlot uint64
|
||||
voteLock sync.RWMutex
|
||||
initSyncState map[[32]byte]*stateTrie.BeaconState
|
||||
boundaryRoots [][32]byte
|
||||
initSyncStateLock sync.RWMutex
|
||||
checkpointState *cache.CheckpointStateCache
|
||||
checkpointStateLock sync.Mutex
|
||||
stateGen *stategen.State
|
||||
opsService *attestations.Service
|
||||
initSyncBlocks map[[32]byte]*ethpb.SignedBeaconBlock
|
||||
initSyncBlocksLock sync.RWMutex
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
beaconDB db.HeadAccessDatabase
|
||||
depositCache *depositcache.DepositCache
|
||||
chainStartFetcher powchain.ChainStartFetcher
|
||||
attPool attestations.Pool
|
||||
slashingPool *slashings.Pool
|
||||
exitPool *voluntaryexits.Pool
|
||||
genesisTime time.Time
|
||||
p2p p2p.Broadcaster
|
||||
maxRoutines int64
|
||||
head *head
|
||||
headLock sync.RWMutex
|
||||
stateNotifier statefeed.Notifier
|
||||
genesisRoot [32]byte
|
||||
epochParticipation map[uint64]*precompute.Balance
|
||||
epochParticipationLock sync.RWMutex
|
||||
forkChoiceStore f.ForkChoicer
|
||||
justifiedCheckpt *ethpb.Checkpoint
|
||||
prevJustifiedCheckpt *ethpb.Checkpoint
|
||||
bestJustifiedCheckpt *ethpb.Checkpoint
|
||||
finalizedCheckpt *ethpb.Checkpoint
|
||||
prevFinalizedCheckpt *ethpb.Checkpoint
|
||||
nextEpochBoundarySlot uint64
|
||||
voteLock sync.RWMutex
|
||||
initSyncState map[[32]byte]*stateTrie.BeaconState
|
||||
boundaryRoots [][32]byte
|
||||
initSyncStateLock sync.RWMutex
|
||||
checkpointState *cache.CheckpointStateCache
|
||||
checkpointStateLock sync.Mutex
|
||||
stateGen *stategen.State
|
||||
opsService *attestations.Service
|
||||
initSyncBlocks map[[32]byte]*ethpb.SignedBeaconBlock
|
||||
initSyncBlocksLock sync.RWMutex
|
||||
recentCanonicalBlocks map[[32]byte]bool
|
||||
recentCanonicalBlocksLock sync.RWMutex
|
||||
justifiedBalances []uint64
|
||||
justifiedBalancesLock sync.RWMutex
|
||||
}
|
||||
|
||||
// Config options for the service.
|
||||
@@ -101,25 +106,27 @@ type Config struct {
|
||||
func NewService(ctx context.Context, cfg *Config) (*Service, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
return &Service{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
beaconDB: cfg.BeaconDB,
|
||||
depositCache: cfg.DepositCache,
|
||||
chainStartFetcher: cfg.ChainStartFetcher,
|
||||
attPool: cfg.AttPool,
|
||||
exitPool: cfg.ExitPool,
|
||||
slashingPool: cfg.SlashingPool,
|
||||
p2p: cfg.P2p,
|
||||
maxRoutines: cfg.MaxRoutines,
|
||||
stateNotifier: cfg.StateNotifier,
|
||||
epochParticipation: make(map[uint64]*precompute.Balance),
|
||||
forkChoiceStore: cfg.ForkChoiceStore,
|
||||
initSyncState: make(map[[32]byte]*stateTrie.BeaconState),
|
||||
boundaryRoots: [][32]byte{},
|
||||
checkpointState: cache.NewCheckpointStateCache(),
|
||||
opsService: cfg.OpsService,
|
||||
stateGen: cfg.StateGen,
|
||||
initSyncBlocks: make(map[[32]byte]*ethpb.SignedBeaconBlock),
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
beaconDB: cfg.BeaconDB,
|
||||
depositCache: cfg.DepositCache,
|
||||
chainStartFetcher: cfg.ChainStartFetcher,
|
||||
attPool: cfg.AttPool,
|
||||
exitPool: cfg.ExitPool,
|
||||
slashingPool: cfg.SlashingPool,
|
||||
p2p: cfg.P2p,
|
||||
maxRoutines: cfg.MaxRoutines,
|
||||
stateNotifier: cfg.StateNotifier,
|
||||
epochParticipation: make(map[uint64]*precompute.Balance),
|
||||
forkChoiceStore: cfg.ForkChoiceStore,
|
||||
initSyncState: make(map[[32]byte]*stateTrie.BeaconState),
|
||||
boundaryRoots: [][32]byte{},
|
||||
checkpointState: cache.NewCheckpointStateCache(),
|
||||
opsService: cfg.OpsService,
|
||||
stateGen: cfg.StateGen,
|
||||
initSyncBlocks: make(map[[32]byte]*ethpb.SignedBeaconBlock),
|
||||
recentCanonicalBlocks: make(map[[32]byte]bool),
|
||||
justifiedBalances: make([]uint64, 0),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -164,6 +171,10 @@ func (s *Service) Start() {
|
||||
if err := s.initializeChainInfo(ctx); err != nil {
|
||||
log.Fatalf("Could not set up chain info: %v", err)
|
||||
}
|
||||
|
||||
// We start a counter to genesis, if needed.
|
||||
go slotutil.CountdownToGenesis(ctx, s.genesisTime, uint64(beaconState.NumValidators()))
|
||||
|
||||
justifiedCheckpoint, err := s.beaconDB.JustifiedCheckpoint(ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not get justified checkpoint: %v", err)
|
||||
@@ -175,6 +186,9 @@ func (s *Service) Start() {
|
||||
|
||||
// Resume fork choice.
|
||||
s.justifiedCheckpt = stateTrie.CopyCheckpoint(justifiedCheckpoint)
|
||||
if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
|
||||
log.Fatalf("Could not cache justified state balances: %v", err)
|
||||
}
|
||||
s.prevJustifiedCheckpt = stateTrie.CopyCheckpoint(justifiedCheckpoint)
|
||||
s.bestJustifiedCheckpt = stateTrie.CopyCheckpoint(justifiedCheckpoint)
|
||||
s.finalizedCheckpt = stateTrie.CopyCheckpoint(finalizedCheckpoint)
|
||||
@@ -242,6 +256,11 @@ func (s *Service) processChainStartTime(ctx context.Context, genesisTime time.Ti
|
||||
if err != nil {
|
||||
log.Fatalf("Could not initialize beacon chain: %v", err)
|
||||
}
|
||||
// We start a counter to genesis, if needed.
|
||||
go slotutil.CountdownToGenesis(ctx, genesisTime, uint64(initializedState.NumValidators()))
|
||||
|
||||
// We send out a state initialized event to the rest of the services
|
||||
// running in the beacon node.
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.Initialized,
|
||||
Data: &statefeed.InitializedData{
|
||||
@@ -319,10 +338,11 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState *stateTrie.B
|
||||
return err
|
||||
}
|
||||
genesisBlk := blocks.NewGenesisBlock(stateRoot[:])
|
||||
genesisBlkRoot, err := ssz.HashTreeRoot(genesisBlk.Block)
|
||||
genesisBlkRoot, err := stateutil.BlockRoot(genesisBlk.Block)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get genesis block root")
|
||||
}
|
||||
s.genesisRoot = genesisBlkRoot
|
||||
|
||||
if err := s.beaconDB.SaveBlock(ctx, genesisBlk); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis block")
|
||||
@@ -349,10 +369,13 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState *stateTrie.B
|
||||
return errors.Wrap(err, "could save genesis block root")
|
||||
}
|
||||
|
||||
genesisCheckpoint := ðpb.Checkpoint{Root: genesisBlkRoot[:]}
|
||||
// Finalized checkpoint at genesis is a zero hash.
|
||||
genesisCheckpoint := genesisState.FinalizedCheckpoint()
|
||||
|
||||
// Add the genesis block to the fork choice store.
|
||||
s.justifiedCheckpt = stateTrie.CopyCheckpoint(genesisCheckpoint)
|
||||
if err := s.cacheJustifiedStateBalances(ctx, genesisBlkRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
s.prevJustifiedCheckpt = stateTrie.CopyCheckpoint(genesisCheckpoint)
|
||||
s.bestJustifiedCheckpt = stateTrie.CopyCheckpoint(genesisCheckpoint)
|
||||
s.finalizedCheckpt = stateTrie.CopyCheckpoint(genesisCheckpoint)
|
||||
@@ -362,6 +385,7 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState *stateTrie.B
|
||||
genesisBlk.Block.Slot,
|
||||
genesisBlkRoot,
|
||||
params.BeaconConfig().ZeroHash,
|
||||
[32]byte{},
|
||||
genesisCheckpoint.Epoch,
|
||||
genesisCheckpoint.Epoch); err != nil {
|
||||
log.Fatalf("Could not process genesis block for fork choice: %v", err)
|
||||
@@ -381,7 +405,7 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
if genesisBlock == nil {
|
||||
return errors.New("no genesis block in db")
|
||||
}
|
||||
genesisBlkRoot, err := ssz.HashTreeRoot(genesisBlock.Block)
|
||||
genesisBlkRoot, err := stateutil.BlockRoot(genesisBlock.Block)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root of genesis block")
|
||||
}
|
||||
@@ -392,7 +416,7 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve head block")
|
||||
}
|
||||
headRoot, err := ssz.HashTreeRoot(headBlock.Block)
|
||||
headRoot, err := stateutil.BlockRoot(headBlock.Block)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not hash head block")
|
||||
}
|
||||
@@ -415,14 +439,18 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
}
|
||||
finalizedRoot := bytesutil.ToBytes32(finalized.Root)
|
||||
var finalizedState *stateTrie.BeaconState
|
||||
|
||||
if featureconfig.Get().NewStateMgmt {
|
||||
finalizedRoot = s.beaconDB.LastArchivedIndexRoot(ctx)
|
||||
finalizedState, err = s.stateGen.Resume(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get finalized state from db")
|
||||
}
|
||||
if finalizedRoot == params.BeaconConfig().ZeroHash {
|
||||
finalizedRoot = bytesutil.ToBytes32(finalized.Root)
|
||||
if !featureconfig.Get().SkipRegenHistoricalStates {
|
||||
// Since historical states were skipped, the node should start from last finalized check point.
|
||||
finalizedRoot = s.beaconDB.LastArchivedIndexRoot(ctx)
|
||||
if finalizedRoot == params.BeaconConfig().ZeroHash {
|
||||
finalizedRoot = bytesutil.ToBytes32(finalized.Root)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
finalizedState, err = s.beaconDB.State(ctx, bytesutil.ToBytes32(finalized.Root))
|
||||
@@ -430,12 +458,25 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
return errors.Wrap(err, "could not get finalized state from db")
|
||||
}
|
||||
}
|
||||
|
||||
finalizedBlock, err := s.beaconDB.Block(ctx, finalizedRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get finalized block from db")
|
||||
}
|
||||
|
||||
// To skip the regeneration of historical state, the node has to generate the parent of the last finalized state.
|
||||
// We don't need to do this for genesis.
|
||||
atGenesis := s.CurrentSlot() == 0
|
||||
if featureconfig.Get().NewStateMgmt && featureconfig.Get().SkipRegenHistoricalStates && !atGenesis {
|
||||
parentRoot := bytesutil.ToBytes32(finalizedBlock.Block.ParentRoot)
|
||||
parentState, err := s.generateState(ctx, finalizedRoot, parentRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.beaconDB.SaveState(ctx, parentState, parentRoot) != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if finalizedState == nil || finalizedBlock == nil {
|
||||
return errors.New("finalized state and block can't be nil")
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ func init() {
|
||||
|
||||
func TestChainService_SaveHead_DataRace(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
ssz "github.com/prysmaticlabs/go-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"
|
||||
@@ -28,8 +28,10 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
protodb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@@ -42,42 +44,6 @@ func init() {
|
||||
logrus.SetOutput(ioutil.Discard)
|
||||
}
|
||||
|
||||
type store struct {
|
||||
headRoot []byte
|
||||
}
|
||||
|
||||
func (s *store) OnBlock(ctx context.Context, b *ethpb.SignedBeaconBlock) (*beaconstate.BeaconState, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *store) OnBlockCacheFilteredTree(ctx context.Context, b *ethpb.SignedBeaconBlock) (*beaconstate.BeaconState, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *store) OnBlockInitialSyncStateTransition(ctx context.Context, b *ethpb.SignedBeaconBlock) (*beaconstate.BeaconState, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *store) OnAttestation(ctx context.Context, a *ethpb.Attestation) ([]uint64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *store) GenesisStore(ctx context.Context, justifiedCheckpoint *ethpb.Checkpoint, finalizedCheckpoint *ethpb.Checkpoint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *store) FinalizedCheckpt() *ethpb.Checkpoint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *store) JustifiedCheckpt() *ethpb.Checkpoint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *store) Head(ctx context.Context) ([]byte, error) {
|
||||
return s.headRoot, nil
|
||||
}
|
||||
|
||||
type mockBeaconNode struct {
|
||||
stateFeed *event.Feed
|
||||
}
|
||||
@@ -99,10 +65,15 @@ func (mb *mockBroadcaster) Broadcast(_ context.Context, _ proto.Message) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mb *mockBroadcaster) BroadcastAttestation(_ context.Context, _ uint64, _ *ethpb.Attestation) error {
|
||||
mb.broadcastCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ = p2p.Broadcaster(&mockBroadcaster{})
|
||||
|
||||
func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
||||
endpoint := "ws://127.0.0.1"
|
||||
endpoint := "http://127.0.0.1"
|
||||
ctx := context.Background()
|
||||
var web3Service *powchain.Service
|
||||
var err error
|
||||
@@ -127,7 +98,7 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
||||
}
|
||||
web3Service, err = powchain.NewService(ctx, &powchain.Web3ServiceConfig{
|
||||
BeaconDB: beaconDB,
|
||||
ETH1Endpoint: endpoint,
|
||||
HTTPEndPoint: endpoint,
|
||||
DepositContract: common.Address{},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -163,7 +134,6 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
||||
func TestChainStartStop_Uninitialized(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
chainService := setupBeaconChain(t, db)
|
||||
|
||||
// Listen for state events.
|
||||
@@ -219,12 +189,11 @@ func TestChainStartStop_Initialized(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
|
||||
chainService := setupBeaconChain(t, db)
|
||||
|
||||
genesisBlk := b.NewGenesisBlock([]byte{})
|
||||
blkRoot, err := ssz.HashTreeRoot(genesisBlk.Block)
|
||||
genesisBlk := testutil.NewBeaconBlock()
|
||||
blkRoot, err := stateutil.BlockRoot(genesisBlk.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -263,8 +232,8 @@ func TestChainStartStop_Initialized(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestChainService_InitializeBeaconChain(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
bc := setupBeaconChain(t, db)
|
||||
@@ -319,11 +288,10 @@ func TestChainService_InitializeBeaconChain(t *testing.T) {
|
||||
|
||||
func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
genesis := b.NewGenesisBlock([]byte{})
|
||||
genesisRoot, err := ssz.HashTreeRoot(genesis.Block)
|
||||
genesis := testutil.NewBeaconBlock()
|
||||
genesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -335,7 +303,9 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1
|
||||
headBlock := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: finalizedSlot, ParentRoot: genesisRoot[:]}}
|
||||
headBlock := testutil.NewBeaconBlock()
|
||||
headBlock.Block.Slot = finalizedSlot
|
||||
headBlock.Block.ParentRoot = bytesutil.PadTo(genesisRoot[:], 32)
|
||||
headState := testutil.NewBeaconState()
|
||||
if err := headState.SetSlot(finalizedSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -343,7 +313,7 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
if err := headState.SetGenesisValidatorRoot(params.BeaconConfig().ZeroHash[:]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
headRoot, err := ssz.HashTreeRoot(headBlock.Block)
|
||||
headRoot, err := stateutil.BlockRoot(headBlock.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -362,9 +332,6 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.SaveBlock(ctx, headBlock); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c := &Service{beaconDB: db, stateGen: stategen.New(db, cache.NewStateSummaryCache())}
|
||||
if err := c.initializeChainInfo(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -400,7 +367,6 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
|
||||
func TestChainService_SaveHeadNoDB(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
@@ -431,7 +397,6 @@ func TestChainService_SaveHeadNoDB(t *testing.T) {
|
||||
|
||||
func TestChainService_PruneOldStates(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
@@ -442,7 +407,7 @@ func TestChainService_PruneOldStates(t *testing.T) {
|
||||
if err := s.beaconDB.SaveBlock(ctx, ðpb.SignedBeaconBlock{Block: block}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, err := ssz.HashTreeRoot(block)
|
||||
r, err := stateutil.BlockRoot(block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -480,14 +445,13 @@ func TestChainService_PruneOldStates(t *testing.T) {
|
||||
func TestHasBlock_ForkChoiceAndDB(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(t)
|
||||
defer testDB.TeardownDB(t, db)
|
||||
s := &Service{
|
||||
forkChoiceStore: protoarray.New(0, 0, [32]byte{}),
|
||||
finalizedCheckpt: ðpb.Checkpoint{},
|
||||
beaconDB: db,
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}
|
||||
r, err := ssz.HashTreeRoot(block.Block)
|
||||
r, err := stateutil.BlockRoot(block.Block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -511,7 +475,6 @@ func TestHasBlock_ForkChoiceAndDB(t *testing.T) {
|
||||
|
||||
func BenchmarkHasBlockDB(b *testing.B) {
|
||||
db := testDB.SetupDB(b)
|
||||
defer testDB.TeardownDB(b, db)
|
||||
ctx := context.Background()
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
@@ -520,7 +483,7 @@ func BenchmarkHasBlockDB(b *testing.B) {
|
||||
if err := s.beaconDB.SaveBlock(ctx, block); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
r, err := ssz.HashTreeRoot(block.Block)
|
||||
r, err := stateutil.BlockRoot(block.Block)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -536,14 +499,13 @@ func BenchmarkHasBlockDB(b *testing.B) {
|
||||
func BenchmarkHasBlockForkChoiceStore(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
db := testDB.SetupDB(b)
|
||||
defer testDB.TeardownDB(b, db)
|
||||
s := &Service{
|
||||
forkChoiceStore: protoarray.New(0, 0, [32]byte{}),
|
||||
finalizedCheckpt: ðpb.Checkpoint{},
|
||||
beaconDB: db,
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}
|
||||
r, err := ssz.HashTreeRoot(block.Block)
|
||||
r, err := stateutil.BlockRoot(block.Block)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
testonly = True,
|
||||
srcs = ["mock.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//fuzz:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/feed/block:go_default_library",
|
||||
@@ -13,13 +16,14 @@ go_library(
|
||||
"//beacon-chain/core/feed/state:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/forkchoice/protoarray:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/event:go_default_library",
|
||||
"//shared/params:go_default_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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -9,14 +9,15 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block"
|
||||
opfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
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/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -36,11 +37,13 @@ type ChainService struct {
|
||||
Genesis time.Time
|
||||
ValidatorsRoot [32]byte
|
||||
Fork *pb.Fork
|
||||
ETH1Data *ethpb.Eth1Data
|
||||
DB db.Database
|
||||
stateNotifier statefeed.Notifier
|
||||
blockNotifier blockfeed.Notifier
|
||||
opNotifier opfeed.Notifier
|
||||
ValidAttestation bool
|
||||
ForkChoiceStore *protoarray.Store
|
||||
}
|
||||
|
||||
// StateNotifier mocks the same method in the chain service.
|
||||
@@ -107,22 +110,12 @@ func (mon *MockOperationNotifier) OperationFeed() *event.Feed {
|
||||
}
|
||||
|
||||
// ReceiveBlock mocks ReceiveBlock method in chain service.
|
||||
func (ms *ChainService) ReceiveBlock(ctx context.Context, block *ethpb.SignedBeaconBlock) error {
|
||||
func (ms *ChainService) ReceiveBlock(ctx context.Context, block *ethpb.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReceiveBlockNoVerify mocks ReceiveBlockNoVerify method in chain service.
|
||||
func (ms *ChainService) ReceiveBlockNoVerify(ctx context.Context, block *ethpb.SignedBeaconBlock) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReceiveBlockNoPubsub mocks ReceiveBlockNoPubsub method in chain service.
|
||||
func (ms *ChainService) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedBeaconBlock) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReceiveBlockNoPubsubForkchoice mocks ReceiveBlockNoPubsubForkchoice method in chain service.
|
||||
func (ms *ChainService) ReceiveBlockNoPubsubForkchoice(ctx context.Context, block *ethpb.SignedBeaconBlock) error {
|
||||
// ReceiveBlockInitialSync mocks ReceiveBlockInitialSync method in chain service.
|
||||
func (ms *ChainService) ReceiveBlockInitialSync(ctx context.Context, block *ethpb.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
if ms.State == nil {
|
||||
ms.State = &stateTrie.BeaconState{}
|
||||
}
|
||||
@@ -133,7 +126,34 @@ func (ms *ChainService) ReceiveBlockNoPubsubForkchoice(ctx context.Context, bloc
|
||||
return err
|
||||
}
|
||||
ms.BlocksReceived = append(ms.BlocksReceived, block)
|
||||
signingRoot, err := ssz.HashTreeRoot(block.Block)
|
||||
signingRoot, err := stateutil.BlockRoot(block.Block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ms.DB != nil {
|
||||
if err := ms.DB.SaveBlock(ctx, block); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Infof("Saved block with root: %#x at slot %d", signingRoot, block.Block.Slot)
|
||||
}
|
||||
ms.Root = signingRoot[:]
|
||||
ms.Block = block
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReceiveBlockNoPubsub mocks ReceiveBlockNoPubsub method in chain service.
|
||||
func (ms *ChainService) ReceiveBlockNoPubsub(ctx context.Context, block *ethpb.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
if ms.State == nil {
|
||||
ms.State = &stateTrie.BeaconState{}
|
||||
}
|
||||
if !bytes.Equal(ms.Root, block.Block.ParentRoot) {
|
||||
return errors.Errorf("wanted %#x but got %#x", ms.Root, block.Block.ParentRoot)
|
||||
}
|
||||
if err := ms.State.SetSlot(block.Block.Slot); err != nil {
|
||||
return err
|
||||
}
|
||||
ms.BlocksReceived = append(ms.BlocksReceived, block)
|
||||
signingRoot, err := stateutil.BlockRoot(block.Block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -202,6 +222,11 @@ func (ms *ChainService) ReceiveAttestationNoPubsub(context.Context, *ethpb.Attes
|
||||
return nil
|
||||
}
|
||||
|
||||
// AttestationPreState mocks AttestationPreState method in chain service.
|
||||
func (ms *ChainService) AttestationPreState(ctx context.Context, att *ethpb.Attestation) (*stateTrie.BeaconState, error) {
|
||||
return ms.State, nil
|
||||
}
|
||||
|
||||
// HeadValidatorsIndices mocks the same method in the chain service.
|
||||
func (ms *ChainService) HeadValidatorsIndices(epoch uint64) ([]uint64, error) {
|
||||
if ms.State == nil {
|
||||
@@ -215,6 +240,16 @@ func (ms *ChainService) HeadSeed(epoch uint64) ([32]byte, error) {
|
||||
return helpers.Seed(ms.State, epoch, params.BeaconConfig().DomainBeaconAttester)
|
||||
}
|
||||
|
||||
// HeadETH1Data provides the current ETH1Data of the head state.
|
||||
func (ms *ChainService) HeadETH1Data() *ethpb.Eth1Data {
|
||||
return ms.ETH1Data
|
||||
}
|
||||
|
||||
// ProtoArrayStore mocks the same method in the chain service.
|
||||
func (ms *ChainService) ProtoArrayStore() *protoarray.Store {
|
||||
return ms.ForkChoiceStore
|
||||
}
|
||||
|
||||
// GenesisTime mocks the same method in the chain service.
|
||||
func (ms *ChainService) GenesisTime() time.Time {
|
||||
return ms.Genesis
|
||||
@@ -240,6 +275,12 @@ func (ms *ChainService) IsValidAttestation(ctx context.Context, att *ethpb.Attes
|
||||
return ms.ValidAttestation
|
||||
}
|
||||
|
||||
// IsCanonical returns and determines whether a block with the provided root is part of
|
||||
// the canonical chain.
|
||||
func (ms *ChainService) IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ClearCachedStates does nothing.
|
||||
func (ms *ChainService) ClearCachedStates() {}
|
||||
|
||||
|
||||
11
beacon-chain/cache/BUILD.bazel
vendored
11
beacon-chain/cache/BUILD.bazel
vendored
@@ -1,4 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
@@ -6,17 +7,17 @@ go_library(
|
||||
"attestation_data.go",
|
||||
"checkpoint_state.go",
|
||||
"committee.go",
|
||||
"committee_ids.go",
|
||||
"common.go",
|
||||
"doc.go",
|
||||
"eth1_data.go",
|
||||
"hot_state_cache.go",
|
||||
"skip_slot_cache.go",
|
||||
"state_summary.go",
|
||||
"subnet_ids.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/cache",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//fuzz:__pkg__",
|
||||
"//tools:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
@@ -27,6 +28,7 @@ go_library(
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
"@com_github_hashicorp_golang_lru//:go_default_library",
|
||||
"@com_github_patrickmn_go_cache//:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
@@ -42,12 +44,11 @@ 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",
|
||||
"hot_state_cache_test.go",
|
||||
"skip_slot_cache_test.go",
|
||||
"subnet_ids_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
|
||||
8
beacon-chain/cache/attestation_data.go
vendored
8
beacon-chain/cache/attestation_data.go
vendored
@@ -11,6 +11,8 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
@@ -97,6 +99,9 @@ func (c *AttestationCache) Get(ctx context.Context, req *ethpb.AttestationDataRe
|
||||
|
||||
if exists && item != nil && item.(*attestationReqResWrapper).res != nil {
|
||||
attestationCacheHit.Inc()
|
||||
if featureconfig.Get().ReduceAttesterStateCopy {
|
||||
return state.CopyAttestationData(item.(*attestationReqResWrapper).res), nil
|
||||
}
|
||||
return item.(*attestationReqResWrapper).res, nil
|
||||
}
|
||||
attestationCacheMiss.Inc()
|
||||
@@ -162,6 +167,9 @@ func wrapperToKey(i interface{}) (string, error) {
|
||||
}
|
||||
|
||||
func reqToKey(req *ethpb.AttestationDataRequest) (string, error) {
|
||||
if featureconfig.Get().ReduceAttesterStateCopy {
|
||||
return fmt.Sprintf("%d", req.Slot), nil
|
||||
}
|
||||
return fmt.Sprintf("%d-%d", req.CommitteeIndex, req.Slot), nil
|
||||
}
|
||||
|
||||
|
||||
24
beacon-chain/cache/committee.go
vendored
24
beacon-chain/cache/committee.go
vendored
@@ -169,6 +169,30 @@ func (c *CommitteeCache) ActiveIndices(seed [32]byte) ([]uint64, error) {
|
||||
return item.SortedIndices, nil
|
||||
}
|
||||
|
||||
// ActiveIndicesCount returns the active indices count of a given seed stored in cache.
|
||||
func (c *CommitteeCache) ActiveIndicesCount(seed [32]byte) (int, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.CommitteeCache.GetByKey(key(seed))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
CommitteeCacheHit.Inc()
|
||||
} else {
|
||||
CommitteeCacheMiss.Inc()
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
item, ok := obj.(*Committees)
|
||||
if !ok {
|
||||
return 0, ErrNotCommittee
|
||||
}
|
||||
|
||||
return len(item.SortedIndices), nil
|
||||
}
|
||||
|
||||
// ProposerIndices returns the proposer indices of a given seed.
|
||||
func (c *CommitteeCache) ProposerIndices(seed [32]byte) ([]uint64, error) {
|
||||
c.lock.RLock()
|
||||
|
||||
87
beacon-chain/cache/committee_ids.go
vendored
87
beacon-chain/cache/committee_ids.go
vendored
@@ -1,87 +0,0 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||||
)
|
||||
|
||||
type committeeIDs struct {
|
||||
attester *lru.Cache
|
||||
attesterLock sync.RWMutex
|
||||
aggregator *lru.Cache
|
||||
aggregatorLock sync.RWMutex
|
||||
}
|
||||
|
||||
// CommitteeIDs for attester and aggregator.
|
||||
var CommitteeIDs = newCommitteeIDs()
|
||||
|
||||
func newCommitteeIDs() *committeeIDs {
|
||||
// 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)
|
||||
}
|
||||
aggregatorCache, err := lru.New(cacheSize)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &committeeIDs{attester: attesterCache, aggregator: aggregatorCache}
|
||||
}
|
||||
|
||||
// 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{}
|
||||
}
|
||||
return val.([]uint64)
|
||||
}
|
||||
56
beacon-chain/cache/committee_ids_test.go
vendored
56
beacon-chain/cache/committee_ids_test.go
vendored
@@ -1,56 +0,0 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
25
beacon-chain/cache/committee_test.go
vendored
25
beacon-chain/cache/committee_test.go
vendored
@@ -97,6 +97,31 @@ func TestCommitteeCache_ActiveIndices(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitteeCache_ActiveCount(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
|
||||
item := &Committees{Seed: [32]byte{'A'}, SortedIndices: []uint64{1, 2, 3, 4, 5, 6}}
|
||||
count, err := cache.ActiveIndicesCount(item.Seed)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count != 0 {
|
||||
t.Error("Expected active count not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddCommitteeShuffledList(item); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
count, err = cache.ActiveIndicesCount(item.Seed)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count != len(item.SortedIndices) {
|
||||
t.Error("Did not receive correct active acount from cache")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitteeCache_AddProposerIndicesList(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
|
||||
|
||||
3
beacon-chain/cache/depositcache/BUILD.bazel
vendored
3
beacon-chain/cache/depositcache/BUILD.bazel
vendored
@@ -1,4 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
|
||||
@@ -72,7 +72,7 @@ func (dc *DepositCache) InsertDeposit(ctx context.Context, d *ethpb.Deposit, blo
|
||||
}
|
||||
dc.depositsLock.Lock()
|
||||
defer dc.depositsLock.Unlock()
|
||||
// keep the slice sorted on insertion in order to avoid costly sorting on retrival.
|
||||
// Keep the slice sorted on insertion in order to avoid costly sorting on retrieval.
|
||||
heightIdx := sort.Search(len(dc.deposits), func(i int) bool { return dc.deposits[i].Index >= index })
|
||||
newDeposits := append([]*dbpb.DepositContainer{{Deposit: d, Eth1BlockHeight: blockNum, DepositRoot: depositRoot[:], Index: index}}, dc.deposits[heightIdx:]...)
|
||||
dc.deposits = append(dc.deposits[:heightIdx], newDeposits...)
|
||||
|
||||
139
beacon-chain/cache/eth1_data.go
vendored
139
beacon-chain/cache/eth1_data.go
vendored
@@ -1,139 +0,0 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotEth1DataVote will be returned when a cache object is not a pointer to
|
||||
// a Eth1DataVote struct.
|
||||
ErrNotEth1DataVote = errors.New("object is not a eth1 data vote obj")
|
||||
|
||||
// maxEth1DataVoteSize defines the max number of eth1 data votes can cache.
|
||||
maxEth1DataVoteSize = 1000
|
||||
|
||||
// Metrics.
|
||||
eth1DataVoteCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "eth1_data_vote_cache_miss",
|
||||
Help: "The number of eth1 data vote count requests that aren't present in the cache.",
|
||||
})
|
||||
eth1DataVoteCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "eth1_data_vote_cache_hit",
|
||||
Help: "The number of eth1 data vote count requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// Eth1DataVote defines the struct which keeps track of the vote count of individual deposit root.
|
||||
type Eth1DataVote struct {
|
||||
Eth1DataHash [32]byte
|
||||
VoteCount uint64
|
||||
}
|
||||
|
||||
// Eth1DataVoteCache is a struct with 1 queue for looking up eth1 data vote count by deposit root.
|
||||
type Eth1DataVoteCache struct {
|
||||
eth1DataVoteCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// eth1DataVoteKeyFn takes the eth1data hash as the key for the eth1 data vote count of a given eth1data object.
|
||||
func eth1DataVoteKeyFn(obj interface{}) (string, error) {
|
||||
eInfo, ok := obj.(*Eth1DataVote)
|
||||
if !ok {
|
||||
return "", ErrNotEth1DataVote
|
||||
}
|
||||
|
||||
return string(eInfo.Eth1DataHash[:]), nil
|
||||
}
|
||||
|
||||
// NewEth1DataVoteCache creates a new eth1 data vote count cache for storing/accessing Eth1DataVote.
|
||||
func NewEth1DataVoteCache() *Eth1DataVoteCache {
|
||||
return &Eth1DataVoteCache{
|
||||
eth1DataVoteCache: cache.NewFIFO(eth1DataVoteKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// Eth1DataVote fetches eth1 data vote count by the eth1data hash. Returns vote count,
|
||||
// if exists. Otherwise returns false, nil.
|
||||
func (c *Eth1DataVoteCache) Eth1DataVote(eth1DataHash [32]byte) (uint64, error) {
|
||||
if !featureconfig.Get().EnableEth1DataVoteCache {
|
||||
// Return a miss result if cache is not enabled.
|
||||
eth1DataVoteCacheMiss.Inc()
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.eth1DataVoteCache.GetByKey(string(eth1DataHash[:]))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
eth1DataVoteCacheHit.Inc()
|
||||
} else {
|
||||
eth1DataVoteCacheMiss.Inc()
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
eInfo, ok := obj.(*Eth1DataVote)
|
||||
if !ok {
|
||||
return 0, ErrNotEth1DataVote
|
||||
}
|
||||
|
||||
return eInfo.VoteCount, nil
|
||||
}
|
||||
|
||||
// AddEth1DataVote adds eth1 data vote object to the cache. This method also trims the least
|
||||
// recently added Eth1DataVoteByEpoch object if the cache size has ready the max cache size limit.
|
||||
func (c *Eth1DataVoteCache) AddEth1DataVote(eth1DataVote *Eth1DataVote) error {
|
||||
if !featureconfig.Get().EnableEth1DataVoteCache {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.eth1DataVoteCache.Add(eth1DataVote); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.eth1DataVoteCache, maxEth1DataVoteSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IncrementEth1DataVote increments the existing eth1 data object's vote count by 1,
|
||||
// and returns the vote count.
|
||||
func (c *Eth1DataVoteCache) IncrementEth1DataVote(eth1DataHash [32]byte) (uint64, error) {
|
||||
if !featureconfig.Get().EnableEth1DataVoteCache {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.eth1DataVoteCache.GetByKey(string(eth1DataHash[:]))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !exists {
|
||||
return 0, errors.New("eth1 data vote object does not exist")
|
||||
}
|
||||
|
||||
eth1DataVoteCacheHit.Inc()
|
||||
|
||||
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 {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return eInfo.VoteCount, nil
|
||||
}
|
||||
113
beacon-chain/cache/eth1_data_test.go
vendored
113
beacon-chain/cache/eth1_data_test.go
vendored
@@ -1,113 +0,0 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEth1DataVoteKeyFn_OK(t *testing.T) {
|
||||
eInfo := &Eth1DataVote{
|
||||
VoteCount: 44,
|
||||
Eth1DataHash: [32]byte{'A'},
|
||||
}
|
||||
|
||||
key, err := eth1DataVoteKeyFn(eInfo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != string(eInfo.Eth1DataHash[:]) {
|
||||
t.Errorf("Incorrect hash key: %s, expected %s", key, string(eInfo.Eth1DataHash[:]))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1DataVoteKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := eth1DataVoteKeyFn("bad")
|
||||
if err != ErrNotEth1DataVote {
|
||||
t.Errorf("Expected error %v, got %v", ErrNotEth1DataVote, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1DataVoteCache_CanAdd(t *testing.T) {
|
||||
cache := NewEth1DataVoteCache()
|
||||
|
||||
eInfo := &Eth1DataVote{
|
||||
VoteCount: 55,
|
||||
Eth1DataHash: [32]byte{'B'},
|
||||
}
|
||||
count, err := cache.Eth1DataVote(eInfo.Eth1DataHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count != 0 {
|
||||
t.Error("Expected seed not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddEth1DataVote(eInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
count, err = cache.Eth1DataVote(eInfo.Eth1DataHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count != eInfo.VoteCount {
|
||||
t.Errorf(
|
||||
"Expected vote count to be %d, got %d",
|
||||
eInfo.VoteCount,
|
||||
count,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1DataVoteCache_CanIncrement(t *testing.T) {
|
||||
cache := NewEth1DataVoteCache()
|
||||
|
||||
eInfo := &Eth1DataVote{
|
||||
VoteCount: 55,
|
||||
Eth1DataHash: [32]byte{'B'},
|
||||
}
|
||||
|
||||
if err := cache.AddEth1DataVote(eInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err := cache.IncrementEth1DataVote(eInfo.Eth1DataHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = cache.IncrementEth1DataVote(eInfo.Eth1DataHash)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
count, err := cache.IncrementEth1DataVote(eInfo.Eth1DataHash)
|
||||
|
||||
if count != 58 {
|
||||
t.Errorf(
|
||||
"Expected vote count to be %d, got %d",
|
||||
58,
|
||||
count,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1Data_MaxSize(t *testing.T) {
|
||||
cache := NewEth1DataVoteCache()
|
||||
|
||||
for i := 0; i < maxEth1DataVoteSize+1; i++ {
|
||||
var hash [32]byte
|
||||
copy(hash[:], strconv.Itoa(i))
|
||||
eInfo := &Eth1DataVote{
|
||||
Eth1DataHash: hash,
|
||||
}
|
||||
if err := cache.AddEth1DataVote(eInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.eth1DataVoteCache.ListKeys()) != maxEth1DataVoteSize {
|
||||
t.Errorf(
|
||||
"Expected hash cache key size to be %d, got %d",
|
||||
maxEth1DataVoteSize,
|
||||
len(cache.eth1DataVoteCache.ListKeys()),
|
||||
)
|
||||
}
|
||||
}
|
||||
18
beacon-chain/cache/hot_state_cache.go
vendored
18
beacon-chain/cache/hot_state_cache.go
vendored
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
var (
|
||||
// hotStateCacheSize defines the max number of hot state this can cache.
|
||||
hotStateCacheSize = 16
|
||||
hotStateCacheSize = 32
|
||||
// Metrics
|
||||
hotStateCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "hot_state_cache_hit",
|
||||
@@ -50,6 +50,17 @@ func (c *HotStateCache) Get(root [32]byte) *stateTrie.BeaconState {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetWithoutCopy returns a non-copied cached response via input block root.
|
||||
func (c *HotStateCache) GetWithoutCopy(root [32]byte) *stateTrie.BeaconState {
|
||||
item, exists := c.cache.Get(root)
|
||||
if exists && item != nil {
|
||||
hotStateCacheHit.Inc()
|
||||
return item.(*stateTrie.BeaconState)
|
||||
}
|
||||
hotStateCacheMiss.Inc()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Put the response in the cache.
|
||||
func (c *HotStateCache) Put(root [32]byte, state *stateTrie.BeaconState) {
|
||||
c.cache.Add(root, state)
|
||||
@@ -59,3 +70,8 @@ func (c *HotStateCache) Put(root [32]byte, state *stateTrie.BeaconState) {
|
||||
func (c *HotStateCache) Has(root [32]byte) bool {
|
||||
return c.cache.Contains(root)
|
||||
}
|
||||
|
||||
// Delete deletes the key exists in the cache.
|
||||
func (c *HotStateCache) Delete(root [32]byte) bool {
|
||||
return c.cache.Remove(root)
|
||||
}
|
||||
|
||||
5
beacon-chain/cache/hot_state_cache_test.go
vendored
5
beacon-chain/cache/hot_state_cache_test.go
vendored
@@ -38,4 +38,9 @@ func TestHotStateCache_RoundTrip(t *testing.T) {
|
||||
if !reflect.DeepEqual(state.CloneInnerState(), res.CloneInnerState()) {
|
||||
t.Error("Expected equal protos to return from cache")
|
||||
}
|
||||
|
||||
c.Delete(root)
|
||||
if c.Has(root) {
|
||||
t.Error("Cache not suppose to have the object")
|
||||
}
|
||||
}
|
||||
|
||||
134
beacon-chain/cache/subnet_ids.go
vendored
Normal file
134
beacon-chain/cache/subnet_ids.go
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/patrickmn/go-cache"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||||
)
|
||||
|
||||
type subnetIDs struct {
|
||||
attester *lru.Cache
|
||||
attesterLock sync.RWMutex
|
||||
aggregator *lru.Cache
|
||||
aggregatorLock sync.RWMutex
|
||||
persistentSubnets *cache.Cache
|
||||
subnetsLock sync.RWMutex
|
||||
}
|
||||
|
||||
// SubnetIDs for attester and aggregator.
|
||||
var SubnetIDs = newSubnetIDs()
|
||||
|
||||
func newSubnetIDs() *subnetIDs {
|
||||
// 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)
|
||||
}
|
||||
aggregatorCache, err := lru.New(cacheSize)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
epochDuration := time.Duration(params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().SecondsPerSlot)
|
||||
subLength := epochDuration * time.Duration(params.BeaconNetworkConfig().EpochsPerRandomSubnetSubscription)
|
||||
persistentCache := cache.New(subLength*time.Second, epochDuration*time.Second)
|
||||
return &subnetIDs{attester: attesterCache, aggregator: aggregatorCache, persistentSubnets: persistentCache}
|
||||
}
|
||||
|
||||
// AddAttesterSubnetID adds the subnet index for subscribing subnet for the attester of a given slot.
|
||||
func (c *subnetIDs) AddAttesterSubnetID(slot uint64, subnetID uint64) {
|
||||
c.attesterLock.Lock()
|
||||
defer c.attesterLock.Unlock()
|
||||
|
||||
ids := []uint64{subnetID}
|
||||
val, exists := c.attester.Get(slot)
|
||||
if exists {
|
||||
ids = sliceutil.UnionUint64(append(val.([]uint64), ids...))
|
||||
}
|
||||
c.attester.Add(slot, ids)
|
||||
}
|
||||
|
||||
// GetAttesterSubnetIDs gets the subnet IDs for subscribed subnets for attesters of the slot.
|
||||
func (c *subnetIDs) GetAttesterSubnetIDs(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
|
||||
}
|
||||
|
||||
// AddAggregatorSubnetID adds the subnet ID for subscribing subnet for the aggregator of a given slot.
|
||||
func (c *subnetIDs) AddAggregatorSubnetID(slot uint64, subnetID uint64) {
|
||||
c.aggregatorLock.Lock()
|
||||
defer c.aggregatorLock.Unlock()
|
||||
|
||||
ids := []uint64{subnetID}
|
||||
val, exists := c.aggregator.Get(slot)
|
||||
if exists {
|
||||
ids = sliceutil.UnionUint64(append(val.([]uint64), ids...))
|
||||
}
|
||||
c.aggregator.Add(slot, ids)
|
||||
}
|
||||
|
||||
// GetAggregatorSubnetIDs gets the subnet IDs for subscribing subnet for aggregator of the slot.
|
||||
func (c *subnetIDs) GetAggregatorSubnetIDs(slot uint64) []uint64 {
|
||||
c.aggregatorLock.RLock()
|
||||
defer c.aggregatorLock.RUnlock()
|
||||
|
||||
val, exists := c.aggregator.Get(slot)
|
||||
if !exists {
|
||||
return []uint64{}
|
||||
}
|
||||
return val.([]uint64)
|
||||
}
|
||||
|
||||
// GetPersistentSubnets retrieves the persistent subnet and expiration time of that validator's
|
||||
// subscription.
|
||||
func (c *subnetIDs) GetPersistentSubnets(pubkey []byte) ([]uint64, bool, time.Time) {
|
||||
c.subnetsLock.RLock()
|
||||
defer c.subnetsLock.RUnlock()
|
||||
|
||||
id, duration, ok := c.persistentSubnets.GetWithExpiration(string(pubkey))
|
||||
if !ok {
|
||||
return []uint64{}, ok, time.Time{}
|
||||
}
|
||||
return id.([]uint64), ok, duration
|
||||
}
|
||||
|
||||
// GetAllSubnets retrieves all the non-expired subscribed subnets of all the validators
|
||||
// in the cache.
|
||||
func (c *subnetIDs) GetAllSubnets() []uint64 {
|
||||
c.subnetsLock.RLock()
|
||||
defer c.subnetsLock.RUnlock()
|
||||
|
||||
itemsMap := c.persistentSubnets.Items()
|
||||
committees := []uint64{}
|
||||
|
||||
for _, v := range itemsMap {
|
||||
if v.Expired() {
|
||||
continue
|
||||
}
|
||||
committees = append(committees, v.Object.([]uint64)...)
|
||||
}
|
||||
return sliceutil.SetUint64(committees)
|
||||
}
|
||||
|
||||
// AddPersistentCommittee adds the relevant committee for that particular validator along with its
|
||||
// expiration period.
|
||||
func (c *subnetIDs) AddPersistentCommittee(pubkey []byte, comIndex []uint64, duration time.Duration) {
|
||||
c.subnetsLock.Lock()
|
||||
defer c.subnetsLock.Unlock()
|
||||
|
||||
c.persistentSubnets.Set(string(pubkey), comIndex, duration)
|
||||
}
|
||||
84
beacon-chain/cache/subnet_ids_test.go
vendored
Normal file
84
beacon-chain/cache/subnet_ids_test.go
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSubnetIDsCache_RoundTrip(t *testing.T) {
|
||||
c := newSubnetIDs()
|
||||
slot := uint64(100)
|
||||
committeeIDs := c.GetAggregatorSubnetIDs(slot)
|
||||
if len(committeeIDs) != 0 {
|
||||
t.Errorf("Empty cache returned an object: %v", committeeIDs)
|
||||
}
|
||||
|
||||
c.AddAggregatorSubnetID(slot, 1)
|
||||
res := c.GetAggregatorSubnetIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{1}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
|
||||
c.AddAggregatorSubnetID(slot, 2)
|
||||
res = c.GetAggregatorSubnetIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{1, 2}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
|
||||
c.AddAggregatorSubnetID(slot, 3)
|
||||
res = c.GetAggregatorSubnetIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{1, 2, 3}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
|
||||
committeeIDs = c.GetAttesterSubnetIDs(slot)
|
||||
if len(committeeIDs) != 0 {
|
||||
t.Errorf("Empty cache returned an object: %v", committeeIDs)
|
||||
}
|
||||
|
||||
c.AddAttesterSubnetID(slot, 11)
|
||||
res = c.GetAttesterSubnetIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{11}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
|
||||
c.AddAttesterSubnetID(slot, 22)
|
||||
res = c.GetAttesterSubnetIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{11, 22}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
|
||||
c.AddAttesterSubnetID(slot, 33)
|
||||
res = c.GetAttesterSubnetIDs(slot)
|
||||
if !reflect.DeepEqual(res, []uint64{11, 22, 33}) {
|
||||
t.Error("Expected equal value to return from cache")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubnetIDsCache_PersistentCommitteeRoundtrip(t *testing.T) {
|
||||
pubkeySet := [][48]byte{}
|
||||
c := newSubnetIDs()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
pubkey := [48]byte{byte(i)}
|
||||
pubkeySet = append(pubkeySet, pubkey)
|
||||
c.AddPersistentCommittee(pubkey[:], []uint64{uint64(i)}, 0)
|
||||
}
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
pubkey := [48]byte{byte(i)}
|
||||
|
||||
idxs, ok, _ := c.GetPersistentSubnets(pubkey[:])
|
||||
if !ok {
|
||||
t.Errorf("Couldn't find entry in cache for pubkey %#x", pubkey)
|
||||
continue
|
||||
}
|
||||
if int(idxs[0]) != i {
|
||||
t.Fatalf("Wanted index of %d but got %d", i, idxs[0])
|
||||
}
|
||||
}
|
||||
coms := c.GetAllSubnets()
|
||||
if len(coms) != 20 {
|
||||
t.Errorf("Number of committees is not %d but is %d", 20, len(coms))
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
@@ -9,10 +10,10 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//fuzz:__pkg__",
|
||||
"//shared/testutil:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
@@ -21,7 +22,6 @@ go_library(
|
||||
"//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/mathutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
|
||||
@@ -5,14 +5,12 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pkg/errors"
|
||||
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"
|
||||
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
@@ -21,7 +19,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -33,8 +30,6 @@ import (
|
||||
|
||||
var log = logrus.WithField("prefix", "blocks")
|
||||
|
||||
var eth1DataCache = cache.NewEth1DataVoteCache()
|
||||
|
||||
// Deprecated: This method uses deprecated ssz.SigningRoot.
|
||||
func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, pub []byte, signature []byte, domain []byte) error {
|
||||
publicKey, err := bls.PublicKeyFromBytes(pub)
|
||||
@@ -49,15 +44,15 @@ func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, pub []byte, signature
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root")
|
||||
}
|
||||
sigRoot := &pb.SigningRoot{
|
||||
signingData := &pb.SigningData{
|
||||
ObjectRoot: root[:],
|
||||
Domain: domain,
|
||||
}
|
||||
ctrRoot, err := ssz.HashTreeRoot(sigRoot)
|
||||
ctrRoot, err := ssz.HashTreeRoot(signingData)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get container root")
|
||||
}
|
||||
if !sig.Verify(ctrRoot[:], publicKey) {
|
||||
if !sig.Verify(publicKey, ctrRoot[:]) {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
@@ -72,15 +67,15 @@ func verifySignature(signedData []byte, pub []byte, signature []byte, domain []b
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
ctr := &pb.SigningRoot{
|
||||
signingData := &pb.SigningData{
|
||||
ObjectRoot: signedData,
|
||||
Domain: domain,
|
||||
}
|
||||
root, err := ssz.HashTreeRoot(ctr)
|
||||
root, err := ssz.HashTreeRoot(signingData)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not hash container")
|
||||
}
|
||||
if !sig.Verify(root[:], publicKey) {
|
||||
if !sig.Verify(publicKey, root[:]) {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
@@ -132,35 +127,11 @@ func areEth1DataEqual(a, b *ethpb.Eth1Data) bool {
|
||||
// votes to see if they match the eth1data.
|
||||
func Eth1DataHasEnoughSupport(beaconState *stateTrie.BeaconState, data *ethpb.Eth1Data) (bool, error) {
|
||||
voteCount := uint64(0)
|
||||
var eth1DataHash [32]byte
|
||||
var err error
|
||||
data = stateTrie.CopyETH1Data(data)
|
||||
if featureconfig.Get().EnableEth1DataVoteCache {
|
||||
eth1DataHash, err = hashutil.HashProto(data)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "could not hash eth1data")
|
||||
}
|
||||
voteCount, err = eth1DataCache.Eth1DataVote(eth1DataHash)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "could not retrieve eth1 data vote cache")
|
||||
}
|
||||
}
|
||||
if voteCount == 0 {
|
||||
for _, vote := range beaconState.Eth1DataVotes() {
|
||||
if areEth1DataEqual(vote, data) {
|
||||
voteCount++
|
||||
}
|
||||
}
|
||||
} else {
|
||||
voteCount++
|
||||
}
|
||||
|
||||
if featureconfig.Get().EnableEth1DataVoteCache {
|
||||
if err := eth1DataCache.AddEth1DataVote(&cache.Eth1DataVote{
|
||||
Eth1DataHash: eth1DataHash,
|
||||
VoteCount: voteCount,
|
||||
}); err != nil {
|
||||
return false, errors.Wrap(err, "could not save eth1 data vote cache")
|
||||
for _, vote := range beaconState.Eth1DataVotes() {
|
||||
if areEth1DataEqual(vote, data) {
|
||||
voteCount++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,15 +175,15 @@ func ProcessBlockHeader(
|
||||
}
|
||||
|
||||
// Verify proposer signature.
|
||||
if err := VerifyBlockHeaderSignature(beaconState, block); err != nil {
|
||||
if err := VerifyBlockSignature(beaconState, block); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// VerifyBlockHeaderSignature verifies the proposer signature of a beacon block.
|
||||
func VerifyBlockHeaderSignature(beaconState *stateTrie.BeaconState, block *ethpb.SignedBeaconBlock) error {
|
||||
// VerifyBlockSignature verifies the proposer signature of a beacon block.
|
||||
func VerifyBlockSignature(beaconState *stateTrie.BeaconState, block *ethpb.SignedBeaconBlock) error {
|
||||
proposer, err := beaconState.ValidatorAtIndex(block.Block.ProposerIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -223,7 +194,8 @@ func VerifyBlockHeaderSignature(beaconState *stateTrie.BeaconState, block *ethpb
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return helpers.VerifySigningRoot(block.Block, proposer.PublicKey, block.Signature, domain)
|
||||
proposerPubKey := proposer.PublicKey
|
||||
return helpers.VerifyBlockSigningRoot(block.Block, proposerPubKey[:], block.Signature, domain)
|
||||
}
|
||||
|
||||
// ProcessBlockHeaderNoVerify validates a block by its header but skips proposer
|
||||
@@ -268,7 +240,11 @@ func ProcessBlockHeaderNoVerify(
|
||||
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())
|
||||
parentHeader := beaconState.LatestBlockHeader()
|
||||
if parentHeader.Slot >= block.Slot {
|
||||
return nil, fmt.Errorf("block.Slot %d must be greater than state.LatestBlockHeader.Slot %d", block.Slot, parentHeader.Slot)
|
||||
}
|
||||
parentRoot, err := stateutil.BlockHeaderRoot(parentHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -279,11 +255,11 @@ func ProcessBlockHeaderNoVerify(
|
||||
block.ParentRoot, parentRoot)
|
||||
}
|
||||
|
||||
proposer, err := beaconState.ValidatorAtIndex(idx)
|
||||
proposer, err := beaconState.ValidatorAtIndexReadOnly(idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if proposer.Slashed {
|
||||
if proposer.Slashed() {
|
||||
return nil, fmt.Errorf("proposer at index %d was previously slashed", idx)
|
||||
}
|
||||
|
||||
@@ -421,7 +397,7 @@ func ProcessProposerSlashings(
|
||||
return nil, errors.Wrapf(err, "could not verify proposer slashing %d", idx)
|
||||
}
|
||||
beaconState, err = v.SlashValidator(
|
||||
beaconState, slashing.Header_1.Header.ProposerIndex, 0, /* proposer is whistleblower */
|
||||
beaconState, slashing.Header_1.Header.ProposerIndex,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not slash proposer index %d", slashing.Header_1.Header.ProposerIndex)
|
||||
@@ -447,12 +423,12 @@ func VerifyProposerSlashing(
|
||||
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)
|
||||
proposer, err := beaconState.ValidatorAtIndexReadOnly(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)
|
||||
if !helpers.IsSlashableValidatorUsingTrie(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.SlotToEpoch(slashing.Header_1.Header.Slot), params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot())
|
||||
@@ -461,7 +437,8 @@ func VerifyProposerSlashing(
|
||||
}
|
||||
headers := []*ethpb.SignedBeaconBlockHeader{slashing.Header_1, slashing.Header_2}
|
||||
for _, header := range headers {
|
||||
if err := helpers.VerifySigningRoot(header.Header, proposer.PublicKey, header.Signature, domain); err != nil {
|
||||
proposerPubKey := proposer.PublicKey()
|
||||
if err := helpers.VerifySigningRoot(header.Header, proposerPubKey[:], header.Signature, domain); err != nil {
|
||||
return errors.Wrap(err, "could not verify beacon block header")
|
||||
}
|
||||
}
|
||||
@@ -510,7 +487,7 @@ func ProcessAttesterSlashings(
|
||||
return nil, err
|
||||
}
|
||||
if helpers.IsSlashableValidator(val, currentEpoch) {
|
||||
beaconState, err = v.SlashValidator(beaconState, validatorIndex, 0)
|
||||
beaconState, err = v.SlashValidator(beaconState, validatorIndex)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not slash validator index %d",
|
||||
validatorIndex)
|
||||
@@ -569,7 +546,7 @@ func IsSlashableAttestationData(data1 *ethpb.AttestationData, data2 *ethpb.Attes
|
||||
if data1 == nil || data2 == nil || data1.Target == nil || data2.Target == nil || data1.Source == nil || data2.Source == nil {
|
||||
return false
|
||||
}
|
||||
isDoubleVote := !proto.Equal(data1, data2) && data1.Target.Epoch == data2.Target.Epoch
|
||||
isDoubleVote := !attestationutil.AttDataIsEqual(data1, data2) && data1.Target.Epoch == data2.Target.Epoch
|
||||
isSurroundVote := data1.Source.Epoch < data2.Source.Epoch && data2.Target.Epoch < data1.Target.Epoch
|
||||
return isDoubleVote || isSurroundVote
|
||||
}
|
||||
@@ -785,35 +762,15 @@ func ProcessAttestationNoVerify(
|
||||
func VerifyIndexedAttestation(ctx context.Context, beaconState *stateTrie.BeaconState, indexedAtt *ethpb.IndexedAttestation) error {
|
||||
ctx, span := trace.StartSpan(ctx, "core.VerifyIndexedAttestation")
|
||||
defer span.End()
|
||||
if indexedAtt == nil || indexedAtt.Data == nil || indexedAtt.Data.Target == nil {
|
||||
return errors.New("nil or missing indexed attestation data")
|
||||
}
|
||||
indices := indexedAtt.AttestingIndices
|
||||
|
||||
if uint64(len(indices)) > params.BeaconConfig().MaxValidatorsPerCommittee {
|
||||
return fmt.Errorf("validator indices count exceeds MAX_VALIDATORS_PER_COMMITTEE, %d > %d", len(indices), params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
if err := attestationutil.IsValidAttestationIndices(ctx, indexedAtt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
set := make(map[uint64]bool)
|
||||
setIndices := make([]uint64, 0, len(indices))
|
||||
for _, i := range indices {
|
||||
if ok := set[i]; ok {
|
||||
continue
|
||||
}
|
||||
setIndices = append(setIndices, i)
|
||||
set[i] = true
|
||||
}
|
||||
sort.SliceStable(setIndices, func(i, j int) bool {
|
||||
return setIndices[i] < setIndices[j]
|
||||
})
|
||||
if !reflect.DeepEqual(setIndices, indices) {
|
||||
return errors.New("attesting indices is not uniquely sorted")
|
||||
}
|
||||
|
||||
domain, err := helpers.Domain(beaconState.Fork(), indexedAtt.Data.Target.Epoch, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indices := indexedAtt.AttestingIndices
|
||||
pubkeys := []*bls.PublicKey{}
|
||||
if len(indices) > 0 {
|
||||
for i := 0; i < len(indices); i++ {
|
||||
@@ -825,22 +782,8 @@ func VerifyIndexedAttestation(ctx context.Context, beaconState *stateTrie.Beacon
|
||||
pubkeys = append(pubkeys, pk)
|
||||
}
|
||||
}
|
||||
return attestationutil.VerifyIndexedAttestationSig(ctx, indexedAtt, pubkeys, domain)
|
||||
|
||||
messageHash, err := helpers.ComputeSigningRoot(indexedAtt.Data, domain)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root of object")
|
||||
}
|
||||
|
||||
sig, err := bls.SignatureFromBytes(indexedAtt.Signature)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
|
||||
voted := len(indices) > 0
|
||||
if voted && !sig.FastAggregateVerify(pubkeys, messageHash) {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyAttestation converts and attestation into an indexed attestation and verifies
|
||||
@@ -857,6 +800,109 @@ func VerifyAttestation(ctx context.Context, beaconState *stateTrie.BeaconState,
|
||||
return VerifyIndexedAttestation(ctx, beaconState, indexedAtt)
|
||||
}
|
||||
|
||||
// VerifyAttestations will verify the signatures of the provided attestations. This method performs
|
||||
// a single BLS verification call to verify the signatures of all of the provided attestations. All
|
||||
// of the provided attestations must have valid signatures or this method will return an error.
|
||||
// This method does not determine which attestation signature is invalid, only that one or more
|
||||
// attestation signatures were not valid.
|
||||
func VerifyAttestations(ctx context.Context, beaconState *stateTrie.BeaconState, atts []*ethpb.Attestation) error {
|
||||
ctx, span := trace.StartSpan(ctx, "core.VerifyAttestations")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("attestations", int64(len(atts))))
|
||||
|
||||
if len(atts) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
fork := beaconState.Fork()
|
||||
gvr := beaconState.GenesisValidatorRoot()
|
||||
dt := params.BeaconConfig().DomainBeaconAttester
|
||||
|
||||
// Split attestations by fork. Note: the signature domain will differ based on the fork.
|
||||
var preForkAtts []*ethpb.Attestation
|
||||
var postForkAtts []*ethpb.Attestation
|
||||
for _, a := range atts {
|
||||
if helpers.SlotToEpoch(a.Data.Slot) < fork.Epoch {
|
||||
preForkAtts = append(preForkAtts, a)
|
||||
} else {
|
||||
postForkAtts = append(postForkAtts, a)
|
||||
}
|
||||
}
|
||||
|
||||
// Check attestations from before the fork.
|
||||
if fork.Epoch > 0 { // Check to prevent underflow.
|
||||
prevDomain, err := helpers.Domain(fork, fork.Epoch-1, dt, gvr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := verifyAttestationsWithDomain(ctx, beaconState, preForkAtts, prevDomain); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(preForkAtts) > 0 {
|
||||
// This is a sanity check that preForkAtts were not ignored when fork.Epoch == 0. This
|
||||
// condition is not possible, but it doesn't hurt to check anyway.
|
||||
return errors.New("some attestations were not verified from previous fork before genesis")
|
||||
}
|
||||
|
||||
// Then check attestations from after the fork.
|
||||
currDomain, err := helpers.Domain(fork, fork.Epoch, dt, gvr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return verifyAttestationsWithDomain(ctx, beaconState, postForkAtts, currDomain)
|
||||
}
|
||||
|
||||
// Inner method to verify attestations. This abstraction allows for the domain to be provided as an
|
||||
// argument.
|
||||
func verifyAttestationsWithDomain(ctx context.Context, beaconState *stateTrie.BeaconState, atts []*ethpb.Attestation, domain []byte) error {
|
||||
if len(atts) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
sigs := make([]*bls.Signature, len(atts))
|
||||
pks := make([]*bls.PublicKey, len(atts))
|
||||
msgs := make([][32]byte, len(atts))
|
||||
for i, a := range atts {
|
||||
sig, err := bls.SignatureFromBytes(a.Signature)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sigs[i] = sig
|
||||
c, err := helpers.BeaconCommitteeFromState(beaconState, a.Data.Slot, a.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ia := attestationutil.ConvertToIndexed(ctx, a, c)
|
||||
indices := ia.AttestingIndices
|
||||
var pk *bls.PublicKey
|
||||
for i := 0; i < len(indices); i++ {
|
||||
pubkeyAtIdx := beaconState.PubkeyAtIndex(indices[i])
|
||||
p, err := bls.PublicKeyFromBytes(pubkeyAtIdx[:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not deserialize validator public key")
|
||||
}
|
||||
if pk == nil {
|
||||
pk = p
|
||||
} else {
|
||||
pk.Aggregate(p)
|
||||
}
|
||||
}
|
||||
pks[i] = pk
|
||||
|
||||
root, err := helpers.ComputeSigningRoot(ia.Data, domain)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root of object")
|
||||
}
|
||||
msgs[i] = root
|
||||
}
|
||||
as := bls.AggregateSignatures(sigs)
|
||||
if !as.AggregateVerify(pks, msgs) {
|
||||
return errors.New("one or more attestation signatures did not verify")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProcessDeposits is one of the operations performed on each processed
|
||||
// beacon block to verify queued validators from the Ethereum 1.0 Deposit Contract
|
||||
// into the beacon chain.
|
||||
@@ -913,7 +959,7 @@ func ProcessPreGenesisDeposit(
|
||||
validator.ActivationEligibilityEpoch = 0
|
||||
validator.ActivationEpoch = 0
|
||||
}
|
||||
if err := beaconState.UpdateValidatorAtIndex(uint64(index), validator); err != nil {
|
||||
if err := beaconState.UpdateValidatorAtIndex(index, validator); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, nil
|
||||
@@ -978,7 +1024,6 @@ func ProcessDeposit(
|
||||
pubKey := deposit.Data.PublicKey
|
||||
amount := deposit.Data.Amount
|
||||
index, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey))
|
||||
numVals := beaconState.NumValidators()
|
||||
if !ok {
|
||||
domain, err := helpers.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
|
||||
if err != nil {
|
||||
@@ -1009,10 +1054,8 @@ func ProcessDeposit(
|
||||
if err := beaconState.AppendBalance(amount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
numVals++
|
||||
beaconState.SetValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey), uint64(numVals-1))
|
||||
} else {
|
||||
if err := helpers.IncreaseBalance(beaconState, uint64(index), amount); err != nil {
|
||||
if err := helpers.IncreaseBalance(beaconState, index, amount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -1089,7 +1132,7 @@ func ProcessVoluntaryExits(
|
||||
beaconState.NumValidators(),
|
||||
)
|
||||
}
|
||||
val, err := beaconState.ValidatorAtIndex(exit.Exit.ValidatorIndex)
|
||||
val, err := beaconState.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1144,7 +1187,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, genesisRoot []byte) error {
|
||||
func VerifyExit(validator *stateTrie.ReadOnlyValidator, currentSlot uint64, fork *pb.Fork, signed *ethpb.SignedVoluntaryExit, genesisRoot []byte) error {
|
||||
if signed == nil || signed.Exit == nil {
|
||||
return errors.New("nil exit")
|
||||
}
|
||||
@@ -1152,36 +1195,32 @@ func VerifyExit(validator *ethpb.Validator, currentSlot uint64, fork *pb.Fork, s
|
||||
exit := signed.Exit
|
||||
currentEpoch := helpers.SlotToEpoch(currentSlot)
|
||||
// Verify the validator is active.
|
||||
if !helpers.IsActiveValidator(validator, currentEpoch) {
|
||||
if !helpers.IsActiveValidatorUsingTrie(validator, currentEpoch) {
|
||||
return errors.New("non-active validator cannot exit")
|
||||
}
|
||||
// Verify the validator has not yet exited.
|
||||
if validator.ExitEpoch != params.BeaconConfig().FarFutureEpoch {
|
||||
return fmt.Errorf("validator has already exited at epoch: %v", validator.ExitEpoch)
|
||||
if validator.ExitEpoch() != params.BeaconConfig().FarFutureEpoch {
|
||||
return fmt.Errorf("validator has already exited at epoch: %v", validator.ExitEpoch())
|
||||
}
|
||||
// Exits must specify an epoch when they become valid; they are not valid before then.
|
||||
if currentEpoch < exit.Epoch {
|
||||
return fmt.Errorf("expected current epoch >= exit epoch, received %d < %d", currentEpoch, exit.Epoch)
|
||||
}
|
||||
// Verify the validator has been active long enough.
|
||||
if currentEpoch < validator.ActivationEpoch+params.BeaconConfig().PersistentCommitteePeriod {
|
||||
if currentEpoch < validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod {
|
||||
return fmt.Errorf(
|
||||
"validator has not been active long enough to exit, wanted epoch %d >= %d",
|
||||
currentEpoch,
|
||||
validator.ActivationEpoch+params.BeaconConfig().PersistentCommitteePeriod,
|
||||
validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod,
|
||||
)
|
||||
}
|
||||
domain, err := helpers.Domain(fork, exit.Epoch, params.BeaconConfig().DomainVoluntaryExit, genesisRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := helpers.VerifySigningRoot(exit, validator.PublicKey, signed.Signature, domain); err != nil {
|
||||
valPubKey := validator.PublicKey()
|
||||
if err := helpers.VerifySigningRoot(exit, valPubKey[:], signed.Signature, domain); err != nil {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearEth1DataVoteCache clears the eth1 data vote count cache.
|
||||
func ClearEth1DataVoteCache() {
|
||||
eth1DataCache = cache.NewEth1DataVoteCache()
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ func TestFuzzProcessVoluntaryExitsNoVerify_10000(t *testing.T) {
|
||||
func TestFuzzVerifyExit_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
ve := ð.SignedVoluntaryExit{}
|
||||
val := ð.Validator{}
|
||||
val := &beaconstate.ReadOnlyValidator{}
|
||||
fork := &pb.Fork{}
|
||||
var slot uint64
|
||||
|
||||
|
||||
@@ -38,6 +38,9 @@ func TestProcessBlockHeader_WrongProposerSig(t *testing.T) {
|
||||
if err := beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{Slot: 9}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := beaconState.SetSlot(10); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
lbhdr, err := stateutil.BlockHeaderRoot(beaconState.LatestBlockHeader())
|
||||
if err != nil {
|
||||
@@ -52,7 +55,7 @@ func TestProcessBlockHeader_WrongProposerSig(t *testing.T) {
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: proposerIdx,
|
||||
Slot: 0,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
@@ -89,7 +92,7 @@ func TestProcessBlockHeader_DifferentSlots(t *testing.T) {
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 0,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
@@ -146,7 +149,7 @@ func TestProcessBlockHeader_PreviousBlockRootNotSignedRoot(t *testing.T) {
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 0,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
@@ -170,10 +173,14 @@ func TestProcessBlockHeader_PreviousBlockRootNotSignedRoot(t *testing.T) {
|
||||
}
|
||||
blockSig := priv.Sign(root[:])
|
||||
validators[5896].PublicKey = priv.PublicKey().Marshal()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: 5669,
|
||||
Slot: 0,
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
@@ -200,7 +207,7 @@ func TestProcessBlockHeader_SlashedProposer(t *testing.T) {
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 0,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
@@ -227,11 +234,16 @@ func TestProcessBlockHeader_SlashedProposer(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
blockSig := priv.Sign(root[:])
|
||||
|
||||
validators[12683].PublicKey = priv.PublicKey().Marshal()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: 5669,
|
||||
Slot: 0,
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
@@ -258,7 +270,7 @@ func TestProcessBlockHeader_OK(t *testing.T) {
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 0,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
@@ -281,10 +293,14 @@ func TestProcessBlockHeader_OK(t *testing.T) {
|
||||
t.Fatalf("Failed to get domain form state: %v", err)
|
||||
}
|
||||
priv := bls.RandKey()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: 5669,
|
||||
Slot: 0,
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
@@ -297,7 +313,7 @@ func TestProcessBlockHeader_OK(t *testing.T) {
|
||||
}
|
||||
blockSig := priv.Sign(signingRoot[:])
|
||||
block.Signature = blockSig.Marshal()[:]
|
||||
bodyRoot, err := ssz.HashTreeRoot(block.Block.Body)
|
||||
bodyRoot, err := stateutil.BlockBodyRoot(block.Block.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to hash block bytes got: %v", err)
|
||||
}
|
||||
@@ -320,7 +336,7 @@ func TestProcessBlockHeader_OK(t *testing.T) {
|
||||
var zeroHash [32]byte
|
||||
nsh := newState.LatestBlockHeader()
|
||||
expected := ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 5669,
|
||||
ProposerIndex: pID,
|
||||
Slot: block.Block.Slot,
|
||||
ParentRoot: latestBlockSignedRoot[:],
|
||||
BodyRoot: bodyRoot[:],
|
||||
@@ -331,6 +347,78 @@ func TestProcessBlockHeader_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessBlockHeader_ImproperBlockSlot(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,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 10}, // Must be less than block.Slot
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
latestBlockSignedRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get domain form state: %v", err)
|
||||
}
|
||||
priv := bls.RandKey()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: latestBlockSignedRoot[:],
|
||||
},
|
||||
}
|
||||
signingRoot, err := helpers.ComputeSigningRoot(block.Block, dt)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get signing root of block: %v", err)
|
||||
}
|
||||
blockSig := priv.Sign(signingRoot[:])
|
||||
block.Signature = blockSig.Marshal()[:]
|
||||
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
validators[proposerIdx].Slashed = false
|
||||
validators[proposerIdx].PublicKey = priv.PublicKey().Marshal()
|
||||
err = state.UpdateValidatorAtIndex(proposerIdx, validators[proposerIdx])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(state, block)
|
||||
if err == nil || err.Error() != "block.Slot 10 must be greater than state.LatestBlockHeader.Slot 10" {
|
||||
t.Fatalf("did not get expected error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessRandao_IncorrectProposerFailsVerification(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
|
||||
// We fetch the proposer's index as that is whom the RANDAO will be verified against.
|
||||
@@ -345,7 +433,7 @@ func TestProcessRandao_IncorrectProposerFailsVerification(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root, err := ssz.HashTreeRoot(&pb.SigningRoot{ObjectRoot: buf, Domain: domain})
|
||||
root, err := ssz.HashTreeRoot(&pb.SigningData{ObjectRoot: buf, Domain: domain})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -549,7 +637,7 @@ func TestProcessProposerSlashings_ValidatorNotSlashable(t *testing.T) {
|
||||
}
|
||||
want := fmt.Sprintf(
|
||||
"validator with key %#x is not slashable",
|
||||
beaconState.Validators()[0].PublicKey,
|
||||
bytesutil.ToBytes48(beaconState.Validators()[0].PublicKey),
|
||||
)
|
||||
|
||||
_, err = blocks.ProcessProposerSlashings(context.Background(), beaconState, block.Body)
|
||||
@@ -1930,7 +2018,7 @@ func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = state.SetSlot(state.Slot() + (params.BeaconConfig().PersistentCommitteePeriod * params.BeaconConfig().SlotsPerEpoch))
|
||||
err = state.SetSlot(state.Slot() + (params.BeaconConfig().ShardCommitteePeriod * params.BeaconConfig().SlotsPerEpoch))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1970,3 +2058,167 @@ func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) {
|
||||
helpers.ActivationExitEpoch(state.Slot()/params.BeaconConfig().SlotsPerEpoch), newRegistry[0].ExitEpoch)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyAttestations_VerifiesMultipleAttestations(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
numOfValidators := 4 * params.BeaconConfig().SlotsPerEpoch
|
||||
validators := make([]*ethpb.Validator, numOfValidators)
|
||||
_, keys, err := testutil.DeterministicDepositsAndKeys(numOfValidators)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
}
|
||||
}
|
||||
|
||||
st, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: 5,
|
||||
Validators: validators,
|
||||
Fork: &pb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
|
||||
comm1, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att1 := ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
CommitteeIndex: 0,
|
||||
},
|
||||
Signature: nil,
|
||||
}
|
||||
domain, err := helpers.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root, err := helpers.ComputeSigningRoot(att1.Data, domain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var sigs []*bls.Signature
|
||||
for i, u := range comm1 {
|
||||
att1.AggregationBits.SetBitAt(uint64(i), true)
|
||||
sigs = append(sigs, keys[u].Sign(root[:]))
|
||||
}
|
||||
att1.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
comm2, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 1 /*committeeIndex*/)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att2 := ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm2))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
CommitteeIndex: 1,
|
||||
},
|
||||
Signature: nil,
|
||||
}
|
||||
root, err = helpers.ComputeSigningRoot(att2.Data, domain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sigs = nil
|
||||
for i, u := range comm2 {
|
||||
att2.AggregationBits.SetBitAt(uint64(i), true)
|
||||
sigs = append(sigs, keys[u].Sign(root[:]))
|
||||
}
|
||||
att2.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
if err := blocks.VerifyAttestations(ctx, st, []*ethpb.Attestation{att1, att2}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) {
|
||||
// In this test, att1 is from the prior fork and att2 is from the new fork.
|
||||
ctx := context.Background()
|
||||
numOfValidators := 4 * params.BeaconConfig().SlotsPerEpoch
|
||||
validators := make([]*ethpb.Validator, numOfValidators)
|
||||
_, keys, err := testutil.DeterministicDepositsAndKeys(numOfValidators)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
}
|
||||
}
|
||||
|
||||
st, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: 35,
|
||||
Validators: validators,
|
||||
Fork: &pb.Fork{
|
||||
Epoch: 1,
|
||||
CurrentVersion: []byte{0, 1, 2, 3},
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
|
||||
comm1, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att1 := ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
CommitteeIndex: 0,
|
||||
},
|
||||
Signature: nil,
|
||||
}
|
||||
prevDomain, err := helpers.Domain(st.Fork(), st.Fork().Epoch-1, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root, err := helpers.ComputeSigningRoot(att1.Data, prevDomain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var sigs []*bls.Signature
|
||||
for i, u := range comm1 {
|
||||
att1.AggregationBits.SetBitAt(uint64(i), true)
|
||||
sigs = append(sigs, keys[u].Sign(root[:]))
|
||||
}
|
||||
att1.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
comm2, err := helpers.BeaconCommitteeFromState(st, 1*params.BeaconConfig().SlotsPerEpoch+1 /*slot*/, 1 /*committeeIndex*/)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att2 := ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm2))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
CommitteeIndex: 1,
|
||||
},
|
||||
Signature: nil,
|
||||
}
|
||||
currDomain, err := helpers.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot())
|
||||
root, err = helpers.ComputeSigningRoot(att2.Data, currDomain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sigs = nil
|
||||
for i, u := range comm2 {
|
||||
att2.AggregationBits.SetBitAt(uint64(i), true)
|
||||
sigs = append(sigs, keys[u].Sign(root[:]))
|
||||
}
|
||||
att2.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
if err := blocks.VerifyAttestations(ctx, st, []*ethpb.Attestation{att1, att2}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
params.SetupTestConfigCleanup(t)
|
||||
for i, tt := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
c := params.BeaconConfig()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
|
||||
@@ -5,14 +5,13 @@ import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
func runAttestationTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -25,7 +24,7 @@ func runAttestationTest(t *testing.T, config string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att := ðpb.Attestation{}
|
||||
if err := ssz.Unmarshal(attestationFile, att); err != nil {
|
||||
if err := att.UnmarshalSSZ(attestationFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,13 @@ import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
func runAttesterSlashingTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -25,7 +24,7 @@ func runAttesterSlashingTest(t *testing.T, config string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
attSlashing := ðpb.AttesterSlashing{}
|
||||
if err := ssz.Unmarshal(attSlashingFile, attSlashing); err != nil {
|
||||
if err := attSlashing.UnmarshalSSZ(attSlashingFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,8 @@ import (
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@@ -19,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
func runBlockHeaderTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -31,7 +30,7 @@ func runBlockHeaderTest(t *testing.T, config string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := ðpb.BeaconBlock{}
|
||||
if err := ssz.Unmarshal(blockFile, block); err != nil {
|
||||
if err := block.UnmarshalSSZ(blockFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
@@ -40,10 +39,10 @@ func runBlockHeaderTest(t *testing.T, config string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
preBeaconStateBase := &pb.BeaconState{}
|
||||
if err := ssz.Unmarshal(preBeaconStateFile, preBeaconStateBase); err != nil {
|
||||
if err := preBeaconStateBase.UnmarshalSSZ(preBeaconStateFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
preBeaconState, err := beaconstate.InitializeFromProto(preBeaconStateBase)
|
||||
preBeaconState, err := stateTrie.InitializeFromProto(preBeaconStateBase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -70,7 +69,7 @@ func runBlockHeaderTest(t *testing.T, config string) {
|
||||
}
|
||||
|
||||
postBeaconState := &pb.BeaconState{}
|
||||
if err := ssz.Unmarshal(postBeaconStateFile, postBeaconState); err != nil {
|
||||
if err := postBeaconState.UnmarshalSSZ(postBeaconStateFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
if !proto.Equal(beaconState.CloneInnerState(), postBeaconState) {
|
||||
|
||||
@@ -13,10 +13,9 @@ import (
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@@ -28,7 +27,7 @@ func init() {
|
||||
}
|
||||
|
||||
func runBlockProcessingTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -41,10 +40,10 @@ func runBlockProcessingTest(t *testing.T, config string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconStateBase := &pb.BeaconState{}
|
||||
if err := ssz.Unmarshal(preBeaconStateFile, beaconStateBase); err != nil {
|
||||
if err := beaconStateBase.UnmarshalSSZ(preBeaconStateFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
beaconState, err := beaconstate.InitializeFromProto(beaconStateBase)
|
||||
beaconState, err := stateTrie.InitializeFromProto(beaconStateBase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -67,7 +66,7 @@ func runBlockProcessingTest(t *testing.T, config string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{}
|
||||
if err := ssz.Unmarshal(blockFile, block); err != nil {
|
||||
if err := block.UnmarshalSSZ(blockFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
beaconState, transitionError = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
@@ -96,7 +95,7 @@ func runBlockProcessingTest(t *testing.T, config string) {
|
||||
}
|
||||
|
||||
postBeaconState := &pb.BeaconState{}
|
||||
if err := ssz.Unmarshal(postBeaconStateFile, postBeaconState); err != nil {
|
||||
if err := postBeaconState.UnmarshalSSZ(postBeaconStateFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,13 @@ import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
func runDepositTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -25,7 +24,7 @@ func runDepositTest(t *testing.T, config string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
deposit := ðpb.Deposit{}
|
||||
if err := ssz.Unmarshal(depositFile, deposit); err != nil {
|
||||
if err := deposit.UnmarshalSSZ(depositFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,13 @@ import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
func runProposerSlashingTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -25,7 +24,7 @@ func runProposerSlashingTest(t *testing.T, config string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
proposerSlashing := ðpb.ProposerSlashing{}
|
||||
if err := ssz.Unmarshal(proposerSlashingFile, proposerSlashing); err != nil {
|
||||
if err := proposerSlashing.UnmarshalSSZ(proposerSlashingFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,13 @@ import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
func runVoluntaryExitTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -25,7 +24,7 @@ func runVoluntaryExitTest(t *testing.T, config string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
voluntaryExit := ðpb.SignedVoluntaryExit{}
|
||||
if err := ssz.Unmarshal(exitFile, voluntaryExit); err != nil {
|
||||
if err := voluntaryExit.UnmarshalSSZ(exitFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
|
||||
@@ -80,10 +80,12 @@ func ProcessRegistryUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconStat
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
vals := state.Validators()
|
||||
var err error
|
||||
ejectionBal := params.BeaconConfig().EjectionBalance
|
||||
activationEligibilityEpoch := helpers.CurrentEpoch(state) + 1
|
||||
for idx, validator := range vals {
|
||||
// Process the validators for activation eligibility.
|
||||
if helpers.IsEligibleForActivationQueue(validator) {
|
||||
validator.ActivationEligibilityEpoch = helpers.CurrentEpoch(state) + 1
|
||||
validator.ActivationEligibilityEpoch = activationEligibilityEpoch
|
||||
if err := state.UpdateValidatorAtIndex(uint64(idx), validator); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -91,7 +93,7 @@ func ProcessRegistryUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconStat
|
||||
|
||||
// Process the validators for ejection.
|
||||
isActive := helpers.IsActiveValidator(validator, currentEpoch)
|
||||
belowEjectionBalance := validator.EffectiveBalance <= params.BeaconConfig().EjectionBalance
|
||||
belowEjectionBalance := validator.EffectiveBalance <= ejectionBal
|
||||
if isActive && belowEjectionBalance {
|
||||
state, err = validators.InitiateValidatorExit(state, uint64(idx))
|
||||
if err != nil {
|
||||
@@ -127,12 +129,13 @@ func ProcessRegistryUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconStat
|
||||
limit = int(churnLimit)
|
||||
}
|
||||
|
||||
activationExitEpoch := helpers.ActivationExitEpoch(currentEpoch)
|
||||
for _, index := range activationQ[:limit] {
|
||||
validator, err := state.ValidatorAtIndex(index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
validator.ActivationEpoch = helpers.ActivationExitEpoch(currentEpoch)
|
||||
validator.ActivationEpoch = activationExitEpoch
|
||||
if err := state.UpdateValidatorAtIndex(index, validator); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -170,11 +173,11 @@ func ProcessSlashings(state *stateTrie.BeaconState) (*stateTrie.BeaconState, err
|
||||
|
||||
// a callback is used here to apply the following actions to all validators
|
||||
// below equally.
|
||||
increment := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
err = state.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, error) {
|
||||
correctEpoch := (currentEpoch + exitLength/2) == val.WithdrawableEpoch
|
||||
if val.Slashed && correctEpoch {
|
||||
minSlashing := mathutil.Min(totalSlashing*3, totalBalance)
|
||||
increment := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
penaltyNumerator := val.EffectiveBalance / increment * minSlashing
|
||||
penalty := penaltyNumerator / totalBalance * increment
|
||||
if err := helpers.DecreaseBalance(state, uint64(idx), penalty); err != nil {
|
||||
@@ -237,6 +240,12 @@ func ProcessFinalUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconState,
|
||||
}
|
||||
}
|
||||
|
||||
effBalanceInc := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
maxEffBalance := params.BeaconConfig().MaxEffectiveBalance
|
||||
hysteresisInc := effBalanceInc / params.BeaconConfig().HysteresisQuotient
|
||||
downwardThreshold := hysteresisInc * params.BeaconConfig().HysteresisDownwardMultiplier
|
||||
upwardThreshold := hysteresisInc * params.BeaconConfig().HysteresisUpwardMultiplier
|
||||
|
||||
bals := state.Balances()
|
||||
// Update effective balances with hysteresis.
|
||||
validatorFunc := func(idx int, val *ethpb.Validator) (bool, error) {
|
||||
@@ -247,14 +256,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]
|
||||
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
|
||||
val.EffectiveBalance = maxEffBalance
|
||||
if val.EffectiveBalance > balance-balance%effBalanceInc {
|
||||
val.EffectiveBalance = balance - balance%effBalanceInc
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
@@ -357,11 +363,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++ {
|
||||
v, err := state.ValidatorAtIndex(setIndices[i])
|
||||
v, err := state.ValidatorAtIndexReadOnly(setIndices[i])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to look up validator")
|
||||
}
|
||||
if v != nil && v.Slashed {
|
||||
if v != nil && v.Slashed() {
|
||||
setIndices = append(setIndices[:i], setIndices[i+1:]...)
|
||||
}
|
||||
}
|
||||
@@ -385,11 +391,11 @@ func BaseReward(state *stateTrie.BeaconState, index uint64) (uint64, error) {
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not calculate active balance")
|
||||
}
|
||||
val, err := state.ValidatorAtIndex(index)
|
||||
val, err := state.ValidatorAtIndexReadOnly(index)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
effectiveBalance := val.EffectiveBalance
|
||||
effectiveBalance := val.EffectiveBalance()
|
||||
baseReward := effectiveBalance * params.BeaconConfig().BaseRewardFactor /
|
||||
mathutil.IntegerSquareRoot(totalBalance) / params.BeaconConfig().BaseRewardsPerEpoch
|
||||
return baseReward, nil
|
||||
|
||||
@@ -13,13 +13,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// TODO(2312): remove this and use the mainnet count.
|
||||
c := params.BeaconConfig()
|
||||
c.MinGenesisActiveValidatorCount = 16384
|
||||
params.OverrideBeaconConfig(c)
|
||||
}
|
||||
|
||||
func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) {
|
||||
// Generate 2 attestations.
|
||||
atts := make([]*pb.PendingAttestation, 2)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
@@ -42,6 +43,7 @@ go_test(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/mathutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/traceutil"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -23,7 +24,7 @@ func ProcessAttestations(
|
||||
ctx context.Context,
|
||||
state *stateTrie.BeaconState,
|
||||
vp []*Validator,
|
||||
bp *Balance,
|
||||
pBal *Balance,
|
||||
) ([]*Validator, *Balance, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "precomputeEpoch.ProcessAttestations")
|
||||
defer span.End()
|
||||
@@ -51,10 +52,10 @@ func ProcessAttestations(
|
||||
vp = UpdateValidator(vp, v, indices, a, a.Data.Slot)
|
||||
}
|
||||
|
||||
bp = UpdateBalance(vp, bp)
|
||||
Balances = bp
|
||||
pBal = UpdateBalance(vp, pBal)
|
||||
Balances = pBal
|
||||
|
||||
return vp, bp, nil
|
||||
return vp, pBal, nil
|
||||
}
|
||||
|
||||
// AttestedCurrentEpoch returns true if attestation `a` attested once in current epoch and/or epoch boundary block.
|
||||
@@ -90,12 +91,14 @@ func AttestedPrevEpoch(s *stateTrie.BeaconState, a *pb.PendingAttestation) (bool
|
||||
votedTarget = true
|
||||
}
|
||||
|
||||
same, err = SameHead(s, a)
|
||||
if err != nil {
|
||||
return false, false, false, errors.Wrap(err, "could not check same head")
|
||||
}
|
||||
if same {
|
||||
votedHead = true
|
||||
if votedTarget {
|
||||
same, err = SameHead(s, a)
|
||||
if err != nil {
|
||||
return false, false, false, errors.Wrap(err, "could not check same head")
|
||||
}
|
||||
if same {
|
||||
votedHead = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return votedPrevEpoch, votedTarget, votedHead, nil
|
||||
@@ -156,25 +159,54 @@ func UpdateValidator(vp []*Validator, record *Validator, indices []uint64, a *pb
|
||||
}
|
||||
|
||||
// UpdateBalance updates pre computed balance store.
|
||||
func UpdateBalance(vp []*Validator, bp *Balance) *Balance {
|
||||
func UpdateBalance(vp []*Validator, bBal *Balance) *Balance {
|
||||
for _, v := range vp {
|
||||
if !v.IsSlashed {
|
||||
if v.IsCurrentEpochAttester {
|
||||
bp.CurrentEpochAttesters += v.CurrentEpochEffectiveBalance
|
||||
bBal.CurrentEpochAttested += v.CurrentEpochEffectiveBalance
|
||||
}
|
||||
if v.IsCurrentEpochTargetAttester {
|
||||
bp.CurrentEpochTargetAttesters += v.CurrentEpochEffectiveBalance
|
||||
bBal.CurrentEpochTargetAttested += v.CurrentEpochEffectiveBalance
|
||||
}
|
||||
if v.IsPrevEpochAttester {
|
||||
bp.PrevEpochAttesters += v.CurrentEpochEffectiveBalance
|
||||
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
|
||||
}
|
||||
if v.IsPrevEpochTargetAttester {
|
||||
bp.PrevEpochTargetAttesters += v.CurrentEpochEffectiveBalance
|
||||
bBal.PrevEpochTargetAttested += v.CurrentEpochEffectiveBalance
|
||||
}
|
||||
if v.IsPrevEpochHeadAttester {
|
||||
bp.PrevEpochHeadAttesters += v.CurrentEpochEffectiveBalance
|
||||
bBal.PrevEpochHeadAttested += v.CurrentEpochEffectiveBalance
|
||||
}
|
||||
}
|
||||
}
|
||||
return bp
|
||||
|
||||
return EnsureBalancesLowerBound(bBal)
|
||||
}
|
||||
|
||||
// EnsureBalancesLowerBound ensures all the balances such as active current epoch, active previous epoch and more
|
||||
// have EffectiveBalanceIncrement(1 eth) as a lower bound.
|
||||
func EnsureBalancesLowerBound(bBal *Balance) *Balance {
|
||||
ebi := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
if ebi > bBal.ActiveCurrentEpoch {
|
||||
bBal.ActiveCurrentEpoch = ebi
|
||||
}
|
||||
if ebi > bBal.ActivePrevEpoch {
|
||||
bBal.ActivePrevEpoch = ebi
|
||||
}
|
||||
if ebi > bBal.CurrentEpochAttested {
|
||||
bBal.CurrentEpochAttested = ebi
|
||||
}
|
||||
if ebi > bBal.CurrentEpochTargetAttested {
|
||||
bBal.CurrentEpochTargetAttested = ebi
|
||||
}
|
||||
if ebi > bBal.PrevEpochAttested {
|
||||
bBal.PrevEpochAttested = ebi
|
||||
}
|
||||
if ebi > bBal.PrevEpochTargetAttested {
|
||||
bBal.PrevEpochTargetAttested = ebi
|
||||
}
|
||||
if ebi > bBal.PrevEpochHeadAttested {
|
||||
bBal.PrevEpochHeadAttested = ebi
|
||||
}
|
||||
return bBal
|
||||
}
|
||||
|
||||
@@ -50,24 +50,26 @@ func TestUpdateValidator_InclusionOnlyCountsPrevEpoch(t *testing.T) {
|
||||
|
||||
func TestUpdateBalance(t *testing.T) {
|
||||
vp := []*precompute.Validator{
|
||||
{IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100},
|
||||
{IsCurrentEpochTargetAttester: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100},
|
||||
{IsCurrentEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100},
|
||||
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 100},
|
||||
{IsPrevEpochAttester: true, IsPrevEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100},
|
||||
{IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100},
|
||||
{IsPrevEpochAttester: true, IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100},
|
||||
{IsSlashed: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100},
|
||||
{IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
|
||||
{IsCurrentEpochTargetAttester: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
|
||||
{IsCurrentEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
|
||||
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
|
||||
{IsPrevEpochAttester: true, IsPrevEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
|
||||
{IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
|
||||
{IsPrevEpochAttester: true, IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
|
||||
{IsSlashed: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
|
||||
}
|
||||
wantedBp := &precompute.Balance{
|
||||
CurrentEpochAttesters: 200,
|
||||
CurrentEpochTargetAttesters: 200,
|
||||
PrevEpochAttesters: 300,
|
||||
PrevEpochTargetAttesters: 100,
|
||||
PrevEpochHeadAttesters: 200,
|
||||
wantedPBal := &precompute.Balance{
|
||||
ActiveCurrentEpoch: params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
ActivePrevEpoch: params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
CurrentEpochAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
CurrentEpochTargetAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
PrevEpochAttested: 300 * params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
PrevEpochTargetAttested: 100 * params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
PrevEpochHeadAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
}
|
||||
bp := precompute.UpdateBalance(vp, &precompute.Balance{})
|
||||
if !reflect.DeepEqual(bp, wantedBp) {
|
||||
pBal := precompute.UpdateBalance(vp, &precompute.Balance{})
|
||||
if !reflect.DeepEqual(pBal, wantedPBal) {
|
||||
t.Error("Incorrect balance calculations")
|
||||
}
|
||||
}
|
||||
@@ -220,7 +222,7 @@ func TestProcessAttestations(t *testing.T) {
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
att2.Data.Target.Root = rt[:]
|
||||
att2.Data.Target.Root = newRt[:]
|
||||
att2.Data.BeaconBlockRoot = newRt[:]
|
||||
err := beaconState.SetPreviousEpochAttestations([]*pb.PendingAttestation{{Data: att1.Data, AggregationBits: bf}})
|
||||
if err != nil {
|
||||
@@ -231,12 +233,12 @@ func TestProcessAttestations(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vp := make([]*precompute.Validator, validators)
|
||||
for i := 0; i < len(vp); i++ {
|
||||
vp[i] = &precompute.Validator{CurrentEpochEffectiveBalance: 100}
|
||||
pVals := make([]*precompute.Validator, validators)
|
||||
for i := 0; i < len(pVals); i++ {
|
||||
pVals[i] = &precompute.Validator{CurrentEpochEffectiveBalance: 100}
|
||||
}
|
||||
bp := &precompute.Balance{}
|
||||
vp, bp, err = precompute.ProcessAttestations(context.Background(), beaconState, vp, bp)
|
||||
pBal := &precompute.Balance{}
|
||||
pVals, pBal, err = precompute.ProcessAttestations(context.Background(), beaconState, pVals, pBal)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -247,7 +249,7 @@ func TestProcessAttestations(t *testing.T) {
|
||||
}
|
||||
indices := attestationutil.AttestingIndices(att1.AggregationBits, committee)
|
||||
for _, i := range indices {
|
||||
if !vp[i].IsPrevEpochAttester {
|
||||
if !pVals[i].IsPrevEpochAttester {
|
||||
t.Error("Not a prev epoch attester")
|
||||
}
|
||||
}
|
||||
@@ -257,11 +259,40 @@ func TestProcessAttestations(t *testing.T) {
|
||||
}
|
||||
indices = attestationutil.AttestingIndices(att2.AggregationBits, committee)
|
||||
for _, i := range indices {
|
||||
if !vp[i].IsPrevEpochAttester {
|
||||
if !pVals[i].IsPrevEpochAttester {
|
||||
t.Error("Not a prev epoch attester")
|
||||
}
|
||||
if !vp[i].IsPrevEpochHeadAttester {
|
||||
if !pVals[i].IsPrevEpochTargetAttester {
|
||||
t.Error("Not a prev epoch target attester")
|
||||
}
|
||||
if !pVals[i].IsPrevEpochHeadAttester {
|
||||
t.Error("Not a prev epoch head attester")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureBalancesLowerBound(t *testing.T) {
|
||||
b := &precompute.Balance{}
|
||||
b = precompute.EnsureBalancesLowerBound(b)
|
||||
if b.ActiveCurrentEpoch != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted active current balance")
|
||||
}
|
||||
if b.ActivePrevEpoch != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted active previous balance")
|
||||
}
|
||||
if b.CurrentEpochAttested != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted current attested balance")
|
||||
}
|
||||
if b.CurrentEpochTargetAttested != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted target attested balance")
|
||||
}
|
||||
if b.PrevEpochAttested != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted prev attested balance")
|
||||
}
|
||||
if b.PrevEpochTargetAttested != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted prev target attested balance")
|
||||
}
|
||||
if b.PrevEpochHeadAttested != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted prev head attested balance")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
// ProcessJustificationAndFinalizationPreCompute processes justification and finalization during
|
||||
// epoch processing. This is where a beacon node can justify and finalize a new epoch.
|
||||
// Note: this is an optimized version by passing in precomputed total and attesting balances.
|
||||
func ProcessJustificationAndFinalizationPreCompute(state *stateTrie.BeaconState, p *Balance) (*stateTrie.BeaconState, error) {
|
||||
func ProcessJustificationAndFinalizationPreCompute(state *stateTrie.BeaconState, pBal *Balance) (*stateTrie.BeaconState, error) {
|
||||
if state.Slot() <= helpers.StartSlot(2) {
|
||||
return state, nil
|
||||
}
|
||||
@@ -34,7 +34,7 @@ func ProcessJustificationAndFinalizationPreCompute(state *stateTrie.BeaconState,
|
||||
// We will use that paradigm here for consistency with the godoc spec definition.
|
||||
|
||||
// If 2/3 or more of total balance attested in the previous epoch.
|
||||
if 3*p.PrevEpochTargetAttesters >= 2*p.CurrentEpoch {
|
||||
if 3*pBal.PrevEpochTargetAttested >= 2*pBal.ActiveCurrentEpoch {
|
||||
blockRoot, err := helpers.BlockRoot(state, prevEpoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get block root for previous epoch %d", prevEpoch)
|
||||
@@ -50,7 +50,7 @@ func ProcessJustificationAndFinalizationPreCompute(state *stateTrie.BeaconState,
|
||||
}
|
||||
|
||||
// If 2/3 or more of the total balance attested in the current epoch.
|
||||
if 3*p.CurrentEpochTargetAttesters >= 2*p.CurrentEpoch {
|
||||
if 3*pBal.CurrentEpochTargetAttested >= 2*pBal.ActiveCurrentEpoch {
|
||||
blockRoot, err := helpers.BlockRoot(state, currentEpoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get block root for current epoch %d", prevEpoch)
|
||||
|
||||
@@ -40,7 +40,7 @@ func TestProcessJustificationAndFinalizationPreCompute_ConsecutiveEpochs(t *test
|
||||
t.Fatal(err)
|
||||
}
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
b := &precompute.Balance{PrevEpochTargetAttesters: attestedBalance}
|
||||
b := &precompute.Balance{PrevEpochTargetAttested: attestedBalance}
|
||||
newState, err := precompute.ProcessJustificationAndFinalizationPreCompute(state, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -95,7 +95,7 @@ func TestProcessJustificationAndFinalizationPreCompute_JustifyCurrentEpoch(t *te
|
||||
t.Fatal(err)
|
||||
}
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
b := &precompute.Balance{PrevEpochTargetAttesters: attestedBalance}
|
||||
b := &precompute.Balance{PrevEpochTargetAttested: attestedBalance}
|
||||
newState, err := precompute.ProcessJustificationAndFinalizationPreCompute(state, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -149,7 +149,7 @@ func TestProcessJustificationAndFinalizationPreCompute_JustifyPrevEpoch(t *testi
|
||||
t.Fatal(err)
|
||||
}
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
b := &precompute.Balance{PrevEpochTargetAttesters: attestedBalance}
|
||||
b := &precompute.Balance{PrevEpochTargetAttested: attestedBalance}
|
||||
newState, err := precompute.ProcessJustificationAndFinalizationPreCompute(state, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -19,39 +19,39 @@ import (
|
||||
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())
|
||||
bp := &Balance{}
|
||||
pValidators := make([]*Validator, state.NumValidators())
|
||||
pBal := &Balance{}
|
||||
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
|
||||
if err := state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
|
||||
// Was validator withdrawable or slashed
|
||||
withdrawable := currentEpoch >= val.WithdrawableEpoch()
|
||||
p := &Validator{
|
||||
withdrawable := prevEpoch+1 >= val.WithdrawableEpoch()
|
||||
pVal := &Validator{
|
||||
IsSlashed: val.Slashed(),
|
||||
IsWithdrawableCurrentEpoch: withdrawable,
|
||||
CurrentEpochEffectiveBalance: val.EffectiveBalance(),
|
||||
}
|
||||
// Was validator active current epoch
|
||||
if helpers.IsActiveValidatorUsingTrie(val, currentEpoch) {
|
||||
p.IsActiveCurrentEpoch = true
|
||||
bp.CurrentEpoch += val.EffectiveBalance()
|
||||
pVal.IsActiveCurrentEpoch = true
|
||||
pBal.ActiveCurrentEpoch += val.EffectiveBalance()
|
||||
}
|
||||
// Was validator active previous epoch
|
||||
if helpers.IsActiveValidatorUsingTrie(val, prevEpoch) {
|
||||
p.IsActivePrevEpoch = true
|
||||
bp.PrevEpoch += val.EffectiveBalance()
|
||||
pVal.IsActivePrevEpoch = true
|
||||
pBal.ActivePrevEpoch += val.EffectiveBalance()
|
||||
}
|
||||
// Set inclusion slot and inclusion distance to be max, they will be compared and replaced
|
||||
// with the lower values
|
||||
p.InclusionSlot = params.BeaconConfig().FarFutureEpoch
|
||||
p.InclusionDistance = params.BeaconConfig().FarFutureEpoch
|
||||
pVal.InclusionSlot = params.BeaconConfig().FarFutureEpoch
|
||||
pVal.InclusionDistance = params.BeaconConfig().FarFutureEpoch
|
||||
|
||||
vp[idx] = p
|
||||
pValidators[idx] = pVal
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, nil, errors.Wrap(err, "failed to initialize precompute")
|
||||
}
|
||||
return vp, bp, nil
|
||||
return pValidators, pBal, nil
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ func TestNew(t *testing.T) {
|
||||
}
|
||||
|
||||
wantedBalances := &precompute.Balance{
|
||||
CurrentEpoch: 100,
|
||||
PrevEpoch: 200,
|
||||
ActiveCurrentEpoch: 100,
|
||||
ActivePrevEpoch: 200,
|
||||
}
|
||||
if !reflect.DeepEqual(b, wantedBalances) {
|
||||
t.Error("Incorrect wanted balance")
|
||||
|
||||
@@ -2,7 +2,6 @@ package precompute
|
||||
|
||||
import (
|
||||
"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/mathutil"
|
||||
@@ -13,7 +12,7 @@ import (
|
||||
// This is an optimized version by passing in precomputed validator attesting records and and total epoch balances.
|
||||
func ProcessRewardsAndPenaltiesPrecompute(
|
||||
state *stateTrie.BeaconState,
|
||||
bp *Balance,
|
||||
pBal *Balance,
|
||||
vp []*Validator,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
// Can't process rewards and penalties in genesis epoch.
|
||||
@@ -27,117 +26,167 @@ func ProcessRewardsAndPenaltiesPrecompute(
|
||||
return state, errors.New("precomputed registries not the same length as state registries")
|
||||
}
|
||||
|
||||
attsRewards, attsPenalties, err := attestationDeltas(state, bp, vp)
|
||||
attsRewards, attsPenalties, err := AttestationsDelta(state, pBal, vp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get attestation delta")
|
||||
}
|
||||
proposerRewards, err := proposerDeltaPrecompute(state, bp, vp)
|
||||
proposerRewards, err := ProposersDelta(state, pBal, vp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get attestation delta")
|
||||
}
|
||||
validatorBals := state.Balances()
|
||||
for i := 0; i < numOfVals; i++ {
|
||||
vp[i].BeforeEpochTransitionBalance, err = state.BalanceAtIndex(uint64(i))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get validator balance before epoch")
|
||||
}
|
||||
vp[i].BeforeEpochTransitionBalance = validatorBals[i]
|
||||
|
||||
if err := helpers.IncreaseBalance(state, uint64(i), attsRewards[i]+proposerRewards[i]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := helpers.DecreaseBalance(state, uint64(i), attsPenalties[i]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Compute the post balance of the validator after accounting for the
|
||||
// attester and proposer rewards and penalties.
|
||||
validatorBals[i] = helpers.IncreaseBalanceWithVal(validatorBals[i], attsRewards[i]+proposerRewards[i])
|
||||
validatorBals[i] = helpers.DecreaseBalanceWithVal(validatorBals[i], attsPenalties[i])
|
||||
|
||||
vp[i].AfterEpochTransitionBalance, err = state.BalanceAtIndex(uint64(i))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get validator balance after epoch")
|
||||
}
|
||||
vp[i].AfterEpochTransitionBalance = validatorBals[i]
|
||||
}
|
||||
|
||||
if err := state.SetBalances(validatorBals); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set validator balances")
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// This computes the rewards and penalties differences for individual validators based on the
|
||||
// AttestationsDelta computes and returns the rewards and penalties differences for individual validators based on the
|
||||
// voting records.
|
||||
func attestationDeltas(state *stateTrie.BeaconState, bp *Balance, vp []*Validator) ([]uint64, []uint64, error) {
|
||||
func AttestationsDelta(state *stateTrie.BeaconState, pBal *Balance, vp []*Validator) ([]uint64, []uint64, error) {
|
||||
numOfVals := state.NumValidators()
|
||||
rewards := make([]uint64, numOfVals)
|
||||
penalties := make([]uint64, numOfVals)
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
finalizedEpoch := state.FinalizedCheckpointEpoch()
|
||||
|
||||
for i, v := range vp {
|
||||
rewards[i], penalties[i] = attestationDelta(state, bp, v)
|
||||
rewards[i], penalties[i] = attestationDelta(pBal, v, prevEpoch, finalizedEpoch)
|
||||
}
|
||||
return rewards, penalties, nil
|
||||
}
|
||||
|
||||
func attestationDelta(state *stateTrie.BeaconState, bp *Balance, v *Validator) (uint64, uint64) {
|
||||
func attestationDelta(pBal *Balance, v *Validator, prevEpoch uint64, finalizedEpoch uint64) (uint64, uint64) {
|
||||
eligible := v.IsActivePrevEpoch || (v.IsSlashed && !v.IsWithdrawableCurrentEpoch)
|
||||
if !eligible || bp.CurrentEpoch == 0 {
|
||||
if !eligible || pBal.ActiveCurrentEpoch == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
e := helpers.PrevEpoch(state)
|
||||
baseRewardsPerEpoch := params.BeaconConfig().BaseRewardsPerEpoch
|
||||
effectiveBalanceIncrement := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
vb := v.CurrentEpochEffectiveBalance
|
||||
br := vb * params.BeaconConfig().BaseRewardFactor / mathutil.IntegerSquareRoot(bp.CurrentEpoch) / params.BeaconConfig().BaseRewardsPerEpoch
|
||||
br := vb * params.BeaconConfig().BaseRewardFactor / mathutil.IntegerSquareRoot(pBal.ActiveCurrentEpoch) / baseRewardsPerEpoch
|
||||
r, p := uint64(0), uint64(0)
|
||||
currentEpochBalance := pBal.ActiveCurrentEpoch / effectiveBalanceIncrement
|
||||
|
||||
// Process source reward / penalty
|
||||
if v.IsPrevEpochAttester && !v.IsSlashed {
|
||||
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
|
||||
maxAttesterReward := br - proposerReward
|
||||
r += maxAttesterReward / v.InclusionDistance
|
||||
|
||||
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
|
||||
// Since full base reward will be canceled out by inactivity penalty deltas,
|
||||
// optimal participation receives full base reward compensation here.
|
||||
r += br
|
||||
} else {
|
||||
rewardNumerator := br * (pBal.PrevEpochAttested / effectiveBalanceIncrement)
|
||||
r += rewardNumerator / currentEpochBalance
|
||||
|
||||
}
|
||||
} else {
|
||||
p += br
|
||||
}
|
||||
|
||||
// Process target reward / penalty
|
||||
if v.IsPrevEpochTargetAttester && !v.IsSlashed {
|
||||
inc := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
rewardNumerator := br * bp.PrevEpochAttesters / inc
|
||||
r += rewardNumerator / (bp.CurrentEpoch / inc)
|
||||
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
|
||||
// Since full base reward will be canceled out by inactivity penalty deltas,
|
||||
// optimal participation receives full base reward compensation here.
|
||||
r += br
|
||||
} else {
|
||||
rewardNumerator := br * (pBal.PrevEpochTargetAttested / effectiveBalanceIncrement)
|
||||
r += rewardNumerator / currentEpochBalance
|
||||
}
|
||||
} else {
|
||||
p += br
|
||||
}
|
||||
|
||||
// Process head reward / penalty
|
||||
if v.IsPrevEpochHeadAttester && !v.IsSlashed {
|
||||
inc := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
rewardNumerator := br * bp.PrevEpochAttesters / inc
|
||||
r += rewardNumerator / (bp.CurrentEpoch / inc)
|
||||
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
|
||||
// Since full base reward will be canceled out by inactivity penalty deltas,
|
||||
// optimal participation receives full base reward compensation here.
|
||||
r += br
|
||||
} else {
|
||||
rewardNumerator := br * (pBal.PrevEpochHeadAttested / effectiveBalanceIncrement)
|
||||
r += rewardNumerator / currentEpochBalance
|
||||
}
|
||||
} else {
|
||||
p += br
|
||||
}
|
||||
|
||||
// Process finality delay penalty
|
||||
finalizedEpoch := state.FinalizedCheckpointEpoch()
|
||||
finalityDelay := e - finalizedEpoch
|
||||
if finalityDelay > params.BeaconConfig().MinEpochsToInactivityPenalty {
|
||||
p += params.BeaconConfig().BaseRewardsPerEpoch * br
|
||||
if !v.IsPrevEpochTargetAttester {
|
||||
finalityDelay := finalityDelay(prevEpoch, finalizedEpoch)
|
||||
|
||||
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
|
||||
// If validator is performing optimally, this cancels all rewards for a neutral balance.
|
||||
proposerReward := br / params.BeaconConfig().ProposerRewardQuotient
|
||||
p += baseRewardsPerEpoch*br - proposerReward
|
||||
// Apply an additional penalty to validators that did not vote on the correct target or has been slashed.
|
||||
// Equivalent to the following condition from the spec:
|
||||
// `index not in get_unslashed_attesting_indices(state, matching_target_attestations)`
|
||||
if !v.IsPrevEpochTargetAttester || v.IsSlashed {
|
||||
p += vb * finalityDelay / params.BeaconConfig().InactivityPenaltyQuotient
|
||||
}
|
||||
}
|
||||
return r, p
|
||||
}
|
||||
|
||||
// This computes the rewards and penalties differences for individual validators based on the
|
||||
// ProposersDelta computes and returns the rewards and penalties differences for individual validators based on the
|
||||
// proposer inclusion records.
|
||||
func proposerDeltaPrecompute(state *stateTrie.BeaconState, bp *Balance, vp []*Validator) ([]uint64, error) {
|
||||
func ProposersDelta(state *stateTrie.BeaconState, pBal *Balance, vp []*Validator) ([]uint64, error) {
|
||||
numofVals := state.NumValidators()
|
||||
rewards := make([]uint64, numofVals)
|
||||
|
||||
totalBalance := bp.CurrentEpoch
|
||||
totalBalance := pBal.ActiveCurrentEpoch
|
||||
balanceSqrt := mathutil.IntegerSquareRoot(totalBalance)
|
||||
// Balance square root cannot be 0, this prevents division by 0.
|
||||
if balanceSqrt == 0 {
|
||||
balanceSqrt = 1
|
||||
}
|
||||
|
||||
baseRewardFactor := params.BeaconConfig().BaseRewardFactor
|
||||
baseRewardsPerEpoch := params.BeaconConfig().BaseRewardsPerEpoch
|
||||
proposerRewardQuotient := params.BeaconConfig().ProposerRewardQuotient
|
||||
for _, v := range vp {
|
||||
if v.IsPrevEpochAttester {
|
||||
// Only apply inclusion rewards to proposer only if the attested hasn't been slashed.
|
||||
if v.IsPrevEpochAttester && !v.IsSlashed {
|
||||
vBalance := v.CurrentEpochEffectiveBalance
|
||||
baseReward := vBalance * params.BeaconConfig().BaseRewardFactor / mathutil.IntegerSquareRoot(totalBalance) / params.BeaconConfig().BaseRewardsPerEpoch
|
||||
proposerReward := baseReward / params.BeaconConfig().ProposerRewardQuotient
|
||||
baseReward := vBalance * baseRewardFactor / balanceSqrt / baseRewardsPerEpoch
|
||||
proposerReward := baseReward / proposerRewardQuotient
|
||||
rewards[v.ProposerIndex] += proposerReward
|
||||
}
|
||||
}
|
||||
return rewards, nil
|
||||
}
|
||||
|
||||
// isInInactivityLeak returns true if the state is experiencing inactivity leak.
|
||||
//
|
||||
// Spec code:
|
||||
// def is_in_inactivity_leak(state: BeaconState) -> bool:
|
||||
// return get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY
|
||||
func isInInactivityLeak(prevEpoch uint64, finalizedEpoch uint64) bool {
|
||||
return finalityDelay(prevEpoch, finalizedEpoch) > params.BeaconConfig().MinEpochsToInactivityPenalty
|
||||
}
|
||||
|
||||
// finalityDelay returns the finality delay using the beacon state.
|
||||
//
|
||||
// Spec code:
|
||||
// def get_finality_delay(state: BeaconState) -> uint64:
|
||||
// return get_previous_epoch(state) - state.finalized_checkpoint.epoch
|
||||
func finalityDelay(prevEpoch uint64, finalizedEpoch uint64) uint64 {
|
||||
return prevEpoch - finalizedEpoch
|
||||
}
|
||||
|
||||
@@ -10,6 +10,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/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
@@ -90,6 +91,14 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
slashedAttestedIndices := []uint64{1413}
|
||||
for _, i := range slashedAttestedIndices {
|
||||
vs := state.Validators()
|
||||
vs[i].Slashed = true
|
||||
if state.SetValidators(vs) != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
vp, bp, err := New(context.Background(), state)
|
||||
if err != nil {
|
||||
@@ -100,7 +109,11 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rewards, penalties, err := attestationDeltas(state, bp, vp)
|
||||
// Add some variances to target and head balances.
|
||||
// See: https://github.com/prysmaticlabs/prysm/issues/5593
|
||||
bp.PrevEpochTargetAttested = bp.PrevEpochTargetAttested / 2
|
||||
bp.PrevEpochHeadAttested = bp.PrevEpochHeadAttested * 2 / 3
|
||||
rewards, penalties, err := AttestationsDelta(state, bp, vp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -113,18 +126,21 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
attestedIndices := []uint64{55, 1339, 1746, 1811, 1569, 1413}
|
||||
attestedIndices := []uint64{55, 1339, 1746, 1811, 1569}
|
||||
for _, i := range attestedIndices {
|
||||
base, err := epoch.BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
|
||||
// Base rewards for getting source right
|
||||
wanted := 3 * (base * attestedBalance / totalBalance)
|
||||
wanted := attestedBalance*base/totalBalance +
|
||||
bp.PrevEpochTargetAttested*base/totalBalance +
|
||||
bp.PrevEpochHeadAttested*base/totalBalance
|
||||
// Base rewards for proposer and attesters working together getting attestation
|
||||
// on chain in the fatest manner
|
||||
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
|
||||
wanted += (base - proposerReward) * params.BeaconConfig().MinAttestationInclusionDelay
|
||||
wanted += (base-proposerReward)*params.BeaconConfig().MinAttestationInclusionDelay - 1
|
||||
if rewards[i] != wanted {
|
||||
t.Errorf("Wanted reward balance %d, got %d for validator with index %d", wanted, rewards[i], i)
|
||||
}
|
||||
@@ -134,6 +150,19 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
for _, i := range slashedAttestedIndices {
|
||||
base, err := epoch.BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
if rewards[i] != 0 {
|
||||
t.Errorf("Wanted slashed indices reward balance 0, got %d", penalties[i])
|
||||
}
|
||||
if penalties[i] != 3*base {
|
||||
t.Errorf("Wanted slashed indices penalty balance %d, got %d", 3*base, penalties[i])
|
||||
}
|
||||
}
|
||||
|
||||
nonAttestedIndices := []uint64{434, 677, 872, 791}
|
||||
for _, i := range nonAttestedIndices {
|
||||
base, err := epoch.BaseReward(state, i)
|
||||
@@ -179,6 +208,57 @@ func TestAttestationDeltas_ZeroEpoch(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pVals, pBal, err := New(context.Background(), state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
pVals, pBal, err = ProcessAttestations(context.Background(), state, pVals, pBal)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pBal.ActiveCurrentEpoch = 0 // Could cause a divide by zero panic.
|
||||
|
||||
_, _, err = AttestationsDelta(state, pBal, pVals)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessRewardsAndPenaltiesPrecompute_SlashedInactivePenalty(t *testing.T) {
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := uint64(2048)
|
||||
base := buildState(e+3, validatorCount)
|
||||
atts := make([]*pb.PendingAttestation, 3)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
|
||||
InclusionDelay: 1,
|
||||
}
|
||||
}
|
||||
base.PreviousEpochAttestations = atts
|
||||
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := state.SetSlot(params.BeaconConfig().SlotsPerEpoch * 10); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
slashedAttestedIndices := []uint64{14, 37, 68, 77, 139}
|
||||
for _, i := range slashedAttestedIndices {
|
||||
vs := state.Validators()
|
||||
vs[i].Slashed = true
|
||||
if state.SetValidators(vs) != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
vp, bp, err := New(context.Background(), state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -187,13 +267,29 @@ func TestAttestationDeltas_ZeroEpoch(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bp.CurrentEpoch = 0 // Could cause a divide by zero panic.
|
||||
|
||||
_, _, err = attestationDeltas(state, bp, vp)
|
||||
rewards, penalties, err := AttestationsDelta(state, bp, vp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finalityDelay := helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
|
||||
for _, i := range slashedAttestedIndices {
|
||||
base, err := epoch.BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
penalty := 3 * base
|
||||
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
|
||||
penalty += params.BeaconConfig().BaseRewardsPerEpoch*base - proposerReward
|
||||
penalty += vp[i].CurrentEpochEffectiveBalance * finalityDelay / params.BeaconConfig().InactivityPenaltyQuotient
|
||||
if penalties[i] != penalty {
|
||||
t.Errorf("Wanted slashed indices penalty balance %d, got %d", penalty, penalties[i])
|
||||
}
|
||||
|
||||
if rewards[i] != 0 {
|
||||
t.Errorf("Wanted slashed indices reward balance 0, got %d", penalties[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func buildState(slot uint64, validatorCount uint64) *pb.BeaconState {
|
||||
@@ -234,3 +330,133 @@ func buildState(slot uint64, validatorCount uint64) *pb.BeaconState {
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
}
|
||||
}
|
||||
|
||||
func TestProposerDeltaPrecompute_HappyCase(t *testing.T) {
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := uint64(10)
|
||||
base := buildState(e, validatorCount)
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
proposerIndex := uint64(1)
|
||||
b := &Balance{ActiveCurrentEpoch: 1000}
|
||||
v := []*Validator{
|
||||
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex},
|
||||
}
|
||||
r, err := ProposersDelta(state, b, v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
baseReward := v[0].CurrentEpochEffectiveBalance * params.BeaconConfig().BaseRewardFactor /
|
||||
mathutil.IntegerSquareRoot(b.ActiveCurrentEpoch) / params.BeaconConfig().BaseRewardsPerEpoch
|
||||
proposerReward := baseReward / params.BeaconConfig().ProposerRewardQuotient
|
||||
|
||||
if r[proposerIndex] != proposerReward {
|
||||
t.Errorf("Wanted proposer reward %d, got %d", proposerReward, r[proposerIndex])
|
||||
}
|
||||
}
|
||||
|
||||
func TestProposerDeltaPrecompute_SlashedCase(t *testing.T) {
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := uint64(10)
|
||||
base := buildState(e, validatorCount)
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
proposerIndex := uint64(1)
|
||||
b := &Balance{ActiveCurrentEpoch: 1000}
|
||||
v := []*Validator{
|
||||
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex, IsSlashed: true},
|
||||
}
|
||||
r, err := ProposersDelta(state, b, v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if r[proposerIndex] != 0 {
|
||||
t.Errorf("Wanted proposer reward for slashed %d, got %d", 0, r[proposerIndex])
|
||||
}
|
||||
}
|
||||
|
||||
func TestFinalityDelay(t *testing.T) {
|
||||
base := buildState(params.BeaconConfig().SlotsPerEpoch*10, 1)
|
||||
base.FinalizedCheckpoint = ðpb.Checkpoint{Epoch: 3}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
prevEpoch := uint64(0)
|
||||
finalizedEpoch := uint64(0)
|
||||
// Set values for each test case
|
||||
setVal := func() {
|
||||
prevEpoch = helpers.PrevEpoch(state)
|
||||
finalizedEpoch = state.FinalizedCheckpointEpoch()
|
||||
}
|
||||
setVal()
|
||||
d := finalityDelay(prevEpoch, finalizedEpoch)
|
||||
w := helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
|
||||
if d != w {
|
||||
t.Error("Did not get wanted finality delay")
|
||||
}
|
||||
|
||||
if err := state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 4}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setVal()
|
||||
d = finalityDelay(prevEpoch, finalizedEpoch)
|
||||
w = helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
|
||||
if d != w {
|
||||
t.Error("Did not get wanted finality delay")
|
||||
}
|
||||
|
||||
if err := state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 5}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setVal()
|
||||
d = finalityDelay(prevEpoch, finalizedEpoch)
|
||||
w = helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
|
||||
if d != w {
|
||||
t.Error("Did not get wanted finality delay")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsInInactivityLeak(t *testing.T) {
|
||||
base := buildState(params.BeaconConfig().SlotsPerEpoch*10, 1)
|
||||
base.FinalizedCheckpoint = ðpb.Checkpoint{Epoch: 3}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
prevEpoch := uint64(0)
|
||||
finalizedEpoch := uint64(0)
|
||||
// Set values for each test case
|
||||
setVal := func() {
|
||||
prevEpoch = helpers.PrevEpoch(state)
|
||||
finalizedEpoch = state.FinalizedCheckpointEpoch()
|
||||
}
|
||||
setVal()
|
||||
if !isInInactivityLeak(prevEpoch, finalizedEpoch) {
|
||||
t.Error("Wanted inactivity leak true")
|
||||
}
|
||||
|
||||
if err := state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 4}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setVal()
|
||||
if !isInInactivityLeak(prevEpoch, finalizedEpoch) {
|
||||
t.Error("Wanted inactivity leak true")
|
||||
}
|
||||
|
||||
if err := state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 5}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setVal()
|
||||
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
|
||||
t.Error("Wanted inactivity leak false")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
// ProcessSlashingsPrecompute processes the slashed validators during epoch processing.
|
||||
// This is an optimized version by passing in precomputed total epoch balances.
|
||||
func ProcessSlashingsPrecompute(state *stateTrie.BeaconState, p *Balance) error {
|
||||
func ProcessSlashingsPrecompute(state *stateTrie.BeaconState, pBal *Balance) error {
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
exitLength := params.BeaconConfig().EpochsPerSlashingsVector
|
||||
|
||||
@@ -21,13 +21,14 @@ func ProcessSlashingsPrecompute(state *stateTrie.BeaconState, p *Balance) error
|
||||
totalSlashing += slashing
|
||||
}
|
||||
|
||||
minSlashing := mathutil.Min(totalSlashing*3, pBal.ActiveCurrentEpoch)
|
||||
epochToWithdraw := currentEpoch + exitLength/2
|
||||
increment := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
validatorFunc := func(idx int, val *ethpb.Validator) (bool, error) {
|
||||
correctEpoch := (currentEpoch + exitLength/2) == val.WithdrawableEpoch
|
||||
correctEpoch := epochToWithdraw == val.WithdrawableEpoch
|
||||
if val.Slashed && correctEpoch {
|
||||
minSlashing := mathutil.Min(totalSlashing*3, p.CurrentEpoch)
|
||||
increment := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
penaltyNumerator := val.EffectiveBalance / increment * minSlashing
|
||||
penalty := penaltyNumerator / p.CurrentEpoch * increment
|
||||
penalty := penaltyNumerator / pBal.ActiveCurrentEpoch * increment
|
||||
if err := helpers.DecreaseBalance(state, uint64(idx), penalty); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ func TestProcessSlashingsPrecompute_NotSlashed(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bp := &precompute.Balance{CurrentEpoch: params.BeaconConfig().MaxEffectiveBalance}
|
||||
if err := precompute.ProcessSlashingsPrecompute(s, bp); err != nil {
|
||||
pBal := &precompute.Balance{ActiveCurrentEpoch: params.BeaconConfig().MaxEffectiveBalance}
|
||||
if err := precompute.ProcessSlashingsPrecompute(s, pBal); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -110,14 +110,14 @@ func TestProcessSlashingsPrecompute_SlashedLess(t *testing.T) {
|
||||
}
|
||||
ab += b
|
||||
}
|
||||
bp := &precompute.Balance{CurrentEpoch: ab}
|
||||
pBal := &precompute.Balance{ActiveCurrentEpoch: ab}
|
||||
|
||||
original := proto.Clone(tt.state)
|
||||
state, err := beaconstate.InitializeFromProto(tt.state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := precompute.ProcessSlashingsPrecompute(state, bp); err != nil {
|
||||
if err := precompute.ProcessSlashingsPrecompute(state, pBal); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
76
beacon-chain/core/epoch/precompute/spectest/BUILD.bazel
Normal file
76
beacon-chain/core/epoch/precompute/spectest/BUILD.bazel
Normal file
@@ -0,0 +1,76 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
test_suite(
|
||||
name = "go_default_test",
|
||||
tags = ["spectest"],
|
||||
tests = [
|
||||
":go_mainnet_test",
|
||||
# Minimal tests must be run with --define ssz=minimal
|
||||
#":go_minimal_test",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_mainnet_test",
|
||||
size = "small",
|
||||
srcs = glob(
|
||||
["*_test.go"],
|
||||
exclude = ["*_minimal_test.go"],
|
||||
),
|
||||
data = [
|
||||
"@eth2_spec_tests_mainnet//:test_data",
|
||||
],
|
||||
shard_count = 4,
|
||||
tags = [
|
||||
"spectest",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/core/epoch:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
"@com_github_ghodss_yaml//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
# Requires --define ssz=minimal
|
||||
go_test(
|
||||
name = "go_minimal_test",
|
||||
size = "small",
|
||||
srcs = glob(
|
||||
["*_test.go"],
|
||||
exclude = ["*_mainnet_test.go"],
|
||||
),
|
||||
data = [
|
||||
"@eth2_spec_tests_minimal//:test_data",
|
||||
],
|
||||
tags = [
|
||||
"manual",
|
||||
"minimal",
|
||||
"spectest",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/core/epoch:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
"@com_github_ghodss_yaml//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRewardsPenaltiesMainnet(t *testing.T) {
|
||||
runPrecomputeRewardsAndPenaltiesTests(t, "mainnet")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRewardsPenaltiesMinimal(t *testing.T) {
|
||||
runPrecomputeRewardsAndPenaltiesTests(t, "minimal")
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
type Delta struct {
|
||||
Rewards []uint64 `json:"rewards"`
|
||||
Penalties []uint64 `json:"penalties"`
|
||||
}
|
||||
|
||||
var deltaFiles = []string{"source_deltas.yaml", "target_deltas.yaml", "head_deltas.yaml", "inactivity_penalty_deltas.yaml", "inclusion_delay_deltas.yaml"}
|
||||
|
||||
func runPrecomputeRewardsAndPenaltiesTests(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testPath := "rewards/core/pyspec_tests"
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, testPath)
|
||||
for _, folder := range testFolders {
|
||||
helpers.ClearCache()
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
runPrecomputeRewardsAndPenaltiesTest(t, folderPath)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func runPrecomputeRewardsAndPenaltiesTest(t *testing.T, testFolderPath string) {
|
||||
ctx := context.Background()
|
||||
preBeaconStateFile, err := testutil.BazelFileBytes(path.Join(testFolderPath, "pre.ssz"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
preBeaconStateBase := &pb.BeaconState{}
|
||||
if err := ssz.Unmarshal(preBeaconStateFile, preBeaconStateBase); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
preBeaconState, err := beaconstate.InitializeFromProto(preBeaconStateBase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vp, bp, err := precompute.New(ctx, preBeaconState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
vp, bp, err = precompute.ProcessAttestations(ctx, preBeaconState, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rewards, penalties, err := precompute.AttestationsDelta(preBeaconState, bp, vp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pRewards, err := precompute.ProposersDelta(preBeaconState, bp, vp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(rewards) != len(penalties) && len(pRewards) != len(pRewards) {
|
||||
t.Fatal("Incorrect lengths")
|
||||
}
|
||||
for i, reward := range rewards {
|
||||
rewards[i] = reward + pRewards[i]
|
||||
}
|
||||
|
||||
totalSpecTestRewards := make([]uint64, len(rewards))
|
||||
totalSpecTestPenalties := make([]uint64, len(penalties))
|
||||
|
||||
for _, dFile := range deltaFiles {
|
||||
sourceFile, err := testutil.BazelFileBytes(path.Join(testFolderPath, dFile))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
d := &Delta{}
|
||||
err = yaml.Unmarshal(sourceFile, &d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for i, reward := range d.Rewards {
|
||||
totalSpecTestRewards[i] += reward
|
||||
}
|
||||
for i, penalty := range d.Penalties {
|
||||
totalSpecTestPenalties[i] += penalty
|
||||
}
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(rewards, totalSpecTestRewards) {
|
||||
t.Error("Rewards don't match")
|
||||
t.Log(rewards)
|
||||
t.Log(totalSpecTestRewards)
|
||||
}
|
||||
if !reflect.DeepEqual(penalties, totalSpecTestPenalties) {
|
||||
t.Error("Penalties don't match")
|
||||
t.Log(penalties)
|
||||
t.Log(totalSpecTestPenalties)
|
||||
}
|
||||
}
|
||||
@@ -40,21 +40,21 @@ type Validator struct {
|
||||
// Balance stores the pre computation of the total participated balances for a given epoch
|
||||
// Pre computing and storing such record is essential for process epoch optimizations.
|
||||
type Balance struct {
|
||||
// CurrentEpoch is the total effective balance of all active validators during current epoch.
|
||||
CurrentEpoch uint64
|
||||
// PrevEpoch is the total effective balance of all active validators during prev epoch.
|
||||
PrevEpoch uint64
|
||||
// CurrentEpochAttesters is the total effective balance of all validators who attested during current epoch.
|
||||
CurrentEpochAttesters uint64
|
||||
// CurrentEpochTargetAttesters is the total effective balance of all validators who attested
|
||||
// ActiveCurrentEpoch is the total effective balance of all active validators during current epoch.
|
||||
ActiveCurrentEpoch uint64
|
||||
// ActivePrevEpoch is the total effective balance of all active validators during prev epoch.
|
||||
ActivePrevEpoch uint64
|
||||
// CurrentEpochAttested is the total effective balance of all validators who attested during current epoch.
|
||||
CurrentEpochAttested uint64
|
||||
// CurrentEpochTargetAttested is the total effective balance of all validators who attested
|
||||
// for epoch boundary block during current epoch.
|
||||
CurrentEpochTargetAttesters uint64
|
||||
// PrevEpochAttesters is the total effective balance of all validators who attested during prev epoch.
|
||||
PrevEpochAttesters uint64
|
||||
// PrevEpochTargetAttesters is the total effective balance of all validators who attested
|
||||
CurrentEpochTargetAttested uint64
|
||||
// PrevEpochAttested is the total effective balance of all validators who attested during prev epoch.
|
||||
PrevEpochAttested uint64
|
||||
// PrevEpochTargetAttested is the total effective balance of all validators who attested
|
||||
// for epoch boundary block during prev epoch.
|
||||
PrevEpochTargetAttesters uint64
|
||||
// PrevEpochHeadAttesters is the total effective balance of all validators who attested
|
||||
PrevEpochTargetAttested uint64
|
||||
// PrevEpochHeadAttested is the total effective balance of all validators who attested
|
||||
// correctly for head block during prev epoch.
|
||||
PrevEpochHeadAttesters uint64
|
||||
PrevEpochHeadAttested uint64
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ go_test(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
@@ -62,6 +63,7 @@ go_test(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func runFinalUpdatesTests(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func runJustificationAndFinalizationTests(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func runRegistryUpdatesTests(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRewardsAndPenaltiesMinimal(t *testing.T) {
|
||||
runRewardsAndPenaltiesTests(t, "minimal")
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
func runRewardsAndPenaltiesTests(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testPath := "epoch_processing/rewards_and_penalties/pyspec_tests"
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, testPath)
|
||||
for _, folder := range testFolders {
|
||||
helpers.ClearCache()
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
testutil.RunEpochOperationTest(t, folderPath, processRewardsAndPenaltiesPrecomputeWrapper)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func processRewardsAndPenaltiesPrecomputeWrapper(t *testing.T, state *state.BeaconState) (*state.BeaconState, error) {
|
||||
ctx := context.Background()
|
||||
vp, bp, err := precompute.New(ctx, state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
vp, bp, err = precompute.ProcessAttestations(ctx, state, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
state, err = precompute.ProcessRewardsAndPenaltiesPrecompute(state, bp, vp)
|
||||
if err != nil {
|
||||
t.Fatalf("could not process reward: %v", err)
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func runSlashingsTests(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(config); err != nil {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
20
beacon-chain/core/epoch/spectest/spectest_test.go
Normal file
20
beacon-chain/core/epoch/spectest/spectest_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
prevConfig := params.BeaconConfig().Copy()
|
||||
c := params.BeaconConfig()
|
||||
// TODO(2312): remove this and use the mainnet count.
|
||||
c.MinGenesisActiveValidatorCount = 16384
|
||||
params.OverrideBeaconConfig(c)
|
||||
|
||||
retVal := m.Run()
|
||||
params.OverrideBeaconConfig(prevConfig)
|
||||
os.Exit(retVal)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user